/* CSL - Common Sound Layer
 * Copyright (C) 2000-2001 Stefan Westerfeld and Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include	"artsmcopglobalcomm.h"

#include	"cslutils.h"
#include	<errno.h>
#include	<fcntl.h>
#include	<unistd.h>
#include	<stdlib.h>
#include	<sys/stat.h>
#include	<string.h>


/* --- functions --- */
static char*
uglify (const char *prefix1,
	const char *prefix2,
	const char *ident)
{
  char *result, *r;
  const char *p;
  unsigned int l, j;
  
  if (!ident)
    return NULL;
  
  j = strlen (prefix1) + strlen (prefix2);
  l = strlen (ident);
  result = csl_malloc (j + l * 3 + 1);
  result[0] = 0;
  strcat (result, prefix1);
  strcat (result, prefix2);
  r = result + j;
  for (p = ident; *p; p++)
    if ((*p >= 'a' && *p <= 'z') ||
	(*p >= 'A' && *p <= 'Z') ||
	(*p >= '0' && *p <= '9') ||
	*p == '_' || *p == '-')
      *(r++) = *p;
    else
      {
	char hex[17] = "0123456789ABCDEF";
	
	*(r++) = '=';
	*(r++) = hex[(*p >> 4) & 0xf];
	*(r++) = hex[*p & 0xf];
      }
  *(r++) = 0;
  
  return result;
}

static char*
create_file_path (const char *file_name,
		  int         prepare_write)
{
  char *tmp, *tmp_dir = uglify ("/tmp/mcop-", "", getenv ("LOGNAME"));
  
  csl_return_val_if_fail (file_name != NULL, NULL);
  
  if (!tmp_dir)
    return NULL;
  
  if (prepare_write)
    {
      struct stat stat_buffer;
      
      if (mkdir (tmp_dir, 0700) != 0 && errno != EEXIST)
	csl_error ("can't create %s (%s)", tmp_dir, strerror (errno));
      
      /* check that /tmp/mcop-<username>/ is a secure temporary dir */
      if (lstat (tmp_dir, &stat_buffer) != 0)
	csl_error ("can't stat %s (%s)", tmp_dir, strerror (errno));
      if (stat_buffer.st_uid != getuid ())
	csl_error ("%s is not owned by user", tmp_dir);
      if (stat_buffer.st_mode & 0077)
	csl_error ("%s is accessible owned by user", tmp_dir);
      if (!S_ISDIR (stat_buffer.st_mode))
	csl_error ("%s is not a directory", tmp_dir);
    }
  
  tmp = uglify (tmp_dir, "/", file_name);
  csl_free (tmp_dir);
  
  return tmp;
}

char*
_arts_mcop_global_comm_get_tmp (const char *var_name)
{
  char *file_name, buffer[8192], *value = "";
  int fd = -1;
  
  csl_return_val_if_fail (var_name != NULL, NULL);
  
  file_name = create_file_path (var_name, FALSE);
  if (file_name)
    {
      fd = open (file_name, O_RDONLY);
      csl_free (file_name);
    }
  if (fd >= 0)
    {
      int size;		
      
      do
        size = read (fd, buffer, 8192);
      while (size < 0 && errno == EINTR);
      
      if (size > 0 && size < 8192)
	{
	  buffer[size] = 0;
	  value = buffer;
	}
      close (fd);
    }
  
  return csl_strdup (value);
}

CslBool
_arts_mcop_global_comm_put_tmp (const char *var_name,
				const char *value)
{
  char *file_name;
  int fd = -1;
  
  csl_return_val_if_fail (var_name != NULL, FALSE);
  csl_return_val_if_fail (value != NULL, FALSE);
  
  file_name = create_file_path (var_name, TRUE);
  if (file_name)
    {
      fd = open (file_name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
      csl_free (file_name);
    }
  if (fd >= 0)
    {
      int result;		
      
      do
	result = write (fd, value, strlen (value));
      while (result == -1 && errno == EINTR);
      
      close (fd);
      return TRUE;
    }
  
  return FALSE;
}

void
_arts_mcop_global_comm_erase_tmp (const char *var_name)
{
  char *file_name;
  
  csl_return_if_fail (var_name != NULL);
  
  file_name = create_file_path (var_name, TRUE);
  if (file_name)
    {
      unlink (file_name);
      csl_free (file_name);
    }
}
