/* $Header: subs.c,v 2.6 90/03/06 12:21:17 chip Exp $
 *
 * Miscellaneous subroutines.
 *
 * $Log:	subs.c,v $
 * Revision 2.6  90/03/06  12:21:17  chip
 * Move logging into log.c and address parsing into addr.c.
 * New: error delivery file for messages that fail.
 * Major rearrangement of delivery file code.
 * 
 * Revision 2.5  90/02/23  14:16:56  chip
 * Support "#!" in delivery files.
 * Support "user|program" and "user?error" from delivery files.
 * Improve debugging and error message formatting.
 * Rearrange code for clarity.
 * 
 * Revision 2.4  90/02/06  11:56:46  chip
 * Enforce MBX_MODE regardless of UMASK.
 * Enforce ordered logging with a log lockfile.
 * Revise log format.
 * 
 * Revision 2.3  89/11/01  10:37:58  network
 * Add exists() function.
 * 
 * Revision 2.2  89/09/29  18:18:05  network
 * Save message when delivery file produces no output,
 * unless delivery file output the "DROP" string.
 * Don't recopy temp files for sys and post-user delfiles.
 * 
 * Revision 2.1  89/06/09  12:25:39  network
 * Update RCS revisions.
 * 
 * Revision 1.8  89/06/09  12:23:58  network
 * Baseline for 2.0 release.
 * 
 */

#include "deliver.h"
#include <sys/stat.h>

/*----------------------------------------------------------------------
 * Report as to whether a file exists or not.
 */

int
exists(path)
char    *path;
{
	struct stat st;

	return (stat(path, &st) == 0);
}

/*----------------------------------------------------------------------
 * Return a pointer to a temporary filename, or NULL if error.
 */

char *
tempfile()
{
	static char template[] = "/tmp/dl.XXXXXX";
	char    *f;

	f = zalloc(32);
	(void) strcpy(f, template);
	if (mktemp(f) == NULL)
	{
		error("can't create temporary file");
		return NULL;
	}
	return f;
}

/*----------------------------------------------------------------------
 * Create a file and return an fd, or complain if it doesn't work.
 * The file is opened for read/write.
 */

int
tcreate(name)
char    *name;
{
	int     fd;

#ifdef O_CREAT
	fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0);
#else
	fd = creat(name, 0);
#endif
	if (fd == -1)
	{
		syserr("can't create %s", name);
		return -1;
	}

#ifndef O_CREAT
	(void) close(fd);
	if ((fd = open(name, 2)) == -1)
	{
		syserr("can't re-open %s", name);
		return -1;
	}
#endif

	return fd;
}

/*----------------------------------------------------------------------
 * Create a file and return a FILE *, or complain if it doesn't work.
 * The file is opened for read/write.
 */

FILE *
ftcreate(name)
char    *name;
{
	FILE	*fp;
	int	fd;

	if ((fd = tcreate(name)) == -1)
		return NULL;

	if ((fp = fdopen(fd, "r+")) == NULL)
		(void) close(fd);

	return fp;
}

/*----------------------------------------------------------------------
 * Allocate memory for an environment variable, and putenv() it.
 */

alloc_env(name, value)
char    *name;
char    *value;
{
	char    *s;

	if (!name || !value)
		return;

	/* If it's the same value it already has, don't bother. */

	if ((s = getenv(name)) != NULL && strcmp(s, value) == 0)
		return;

	s = zalloc((unsigned) (strlen(name) + strlen(value) + 2));
	(void) sprintf(s, "%s=%s", name, value);
	if (putenv(s))
		nomem();
}

/*----------------------------------------------------------------------
 * Remove an environment variable.
 */

del_env(name)
char    *name;
{
	int     len;
	char    **e;

	if (!name)
		return;

	len = strlen(name);

	for (e = environ; *e; ++e)
	{
		char    c;

		if (strncmp(*e, name, len) != 0)
			continue;

		c = (*e)[len];
		if (c == '=' || c == '\0')
			break;
	}

	for (; *e; ++e)
		*e = *(e + 1);
}

/*----------------------------------------------------------------------
 * Allocate and clear.  If it fails, it takes the emergency exit.
 */

char *
zalloc(size)
unsigned size;
{
	char    *p;

	if ((p = malloc(size)) == NULL)
		nomem();

	Zero(p, size);
	return p;
}

/*----------------------------------------------------------------------
 * Reallocate to new size.  If it fails, it takes the emergency exit.
 */

char *
srealloc(ptr, size)
char    *ptr;
unsigned size;
{
	char    *p;

	if ((p = realloc(ptr, size)) == NULL)
		nomem();

	return p;
}

/*----------------------------------------------------------------------
 * Make an allocated copy of a string.
 */

char *
copystr(s)
char    *s;
{
	char    *p;

	if (s == NULL)
		return NULL;

	if ((p = malloc((unsigned) strlen(s) + 1)) == NULL)
		nomem();

	(void) strcpy(p, s);
	return p;
}

/*----------------------------------------------------------------------
 * Emergency exit for memory loss.
 */

nomem()
{
	error("out of memory\n");
	leave(1);
}

/*----------------------------------------------------------------------
 * Return the last component of the given pathname.
 */

char *
basename(name)
char    *name;
{
	char    *b;

	if ((b = strrchr(name, '/')) != NULL)
		++b;
	else
		b = name;

	return (b);
}

/*----------------------------------------------------------------------
 * Return the given pathname relative to the given directory.
 * No fancy checking for "." and ".." -- sorry.
 */

char *
relpath(dir, file)
char    *dir, *file;
{
	static  char    *path;
	static  unsigned pathsize;
	unsigned n;

	if (file[0] == '/')
		return file;

	n = strlen(dir) + strlen(file) + 2;
	if (pathsize < n)
	{
		pathsize = n + 64;      /* gas */
		if (path)
			path = srealloc(path, pathsize);
		else
			path = zalloc(pathsize);
	}

	(void) strcpy(path, dir);
	n = strlen(path);
	if (n == 0 || path[n - 1] != '/')
		path[n++] = '/';
	(void) strcpy(path + n, file);

	return path;
}
