/* (C) Copyright 1993 by John G. Myers
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that the above copyright notice appear in all copies
 * and that both that copyright notice and this permission notice
 * appear in supporting documentation, and that the name of John G.
 * Myers not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior
 * permission.  John G. Myers makes no representations about the
 * suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * JOHN G. MYERS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS, IN NO EVENT SHALL JOHN G. MYERS BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include "xmalloc.h"
#include "common.h"

extern int errno;

int overwrite_files = 0;

/* The name of the file we're writing */
static char *output_fname = 0;

/* Characters that can be in filenames */
#define GOODCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

/* Generate a message-id */
char *os_genid()
{
    static time_t curtime;
    static char *hostname;
    char *result;

    if (curtime == 0) {
	time(&curtime);

	hostname = getenv("HOSTNAME");
	if (!hostname) hostname="random-pc";
    }

    result = malloc(25+strlen(hostname));
    sprintf(result, "%lu@%s", curtime++, hostname);
    return result;
}

/* Create and return directory for a message-id */
char *os_idtodir(id)
char *id;
{
    static char buf[4096];
    int len = 0;
    char *p;

    if (getenv("TMP")) {
	strcpy(buf, getenv("TMP"));
    }
    else {
	strcpy(buf, "\\tmp");
	(void)mkdir(buf);
    }
    strcat(buf, "\\parts");
    (void)mkdir(buf);

    p = buf + strlen(buf);
    *p++ = '\\';

    while (*id && len < 11) {
	if (strchr(GOODCHARS, *id)) {
	    if (len++ == 8) *p++ = '.';
	    *p++ = *id;
	}
	id++;
    }
    *p = '\0';
    if (mkdir(buf) == -1 && errno != EACCES) {
	perror(buf);
	return 0;
    }
    *p++ = '\\';
    *p = '\0';
    return buf;
}

/*
 * We are done with the directory returned by os_idtodir()
 * Remove it
 */
os_donewithdir(dir)
char *dir;
{
    char *p;

    /* Remove trailing slash */
    p = dir + strlen(dir) - 1;
    *p = '\0';

    rmdir(dir);
}

/*
 * Create a new file, with suggested filename "fname".
 * "fname" may have come from an insecure source, so clean it up first.
 * It may also be null.
 * "contentType" is passed in for use by systems that have typed filesystems.
 * "binary" is nonzero if the new file should be opened in binary mode.
 */
FILE *os_newtypedfile(fname, contentType, binary)
char *fname;
char *contentType;
int binary;
{
    char *p, *q;
    int len, sawdot;
    static int filesuffix=0;
    char buf[128], *descfname=0;
    FILE *outfile = 0;

    if (!fname) fname = "";

    /* Chop off any drive specifier, convert / to \ */
    if (*fname && fname[1] == ':') fname +=2;
    for (p = fname; *p; p++) if (*p == '/') *p = '\\';

    /* If absolute path name, chop to tail */
    if (*fname == '\\') {
	p = strrchr(fname, '\\');
	fname = p+1;
    }

    /* Clean out bad characters, create directories along path */
    for (p=q=fname, len=sawdot=0; *p; p++) {
	if (*p == '\\') {
	    if (!strncmp(p, "\\..\\", 4)) {
		p[1] = p[2] = 'X';
	    }
	    *q = '\0';
	    (void) mkdir(fname);
	    *q++ = '\\';
	    len = sawdot = 0;
	}
	else if (*p == '.' && !sawdot) {
	    *q++ = '.';
	    sawdot++;
	    len = 0;
	}
	else if (len < (sawdot ? 3 : 8) && strchr(GOODCHARS, *p)) {
	    *q++ = *p;
	    len++;
	}
    }
    *q = '\0';

    if (!fname[0]) {
	do {
	    if (outfile) fclose(outfile);
	    sprintf(buf, "part%d", ++filesuffix);
	} while (outfile = fopen(buf, "r"));
	fname = buf;
    }
    else if (!overwrite_files && (outfile = fopen(fname, "r"))) {
	/* chop off suffix */
	p = strrchr(fname, '\\');
	if (!p) p = fname;
	p = strchr(p, '.');
	if (*p) *p = '\0';

	/* append unique number */
	do {
	    fclose(outfile);
	    sprintf(buf, "%s.%d", fname, ++filesuffix);
	 
	} while (outfile = fopen(buf, "r"));
	fname = buf;
    }

    outfile = fopen(fname, binary ? "wb" : "w");
    if (!outfile) {
	perror(fname);
    }

    if (output_fname) free(output_fname);
    output_fname = strsave(fname);

    if (strlen(fname) > sizeof(buf)-6) {
	descfname = xmalloc(strlen(fname)+6);
    }
    else {
	descfname = buf;
    }
    strcpy(descfname, fname);

    p = strrchr(descfname, '\\');
    if (!p) p = descfname;
    if (p = strrchr(p, '.')) *p = '\0';

    strcat(descfname, ".dsc");
    (void) rename(TEMPFILENAME, descfname);
    if (descfname != buf) free(descfname);
    
    fprintf(stdout, "%s (%s)\n", output_fname, contentType);

    return outfile;
}

/*
 * Warn user that the MD5 digest of the last file created by os_newtypedfile()
 * did not match that supplied in the Content-MD5: header.
 */
os_warnMD5mismatch()
{
    char *warning;

    warning = xmalloc(strlen(output_fname) + 100);
    sprintf(warning, "%s was corrupted in transit",
	    output_fname);
    warn(warning);
    free(warning);
}

/*
 * Report an error (in errno) concerning a filename
 */
os_perror(file)
char *file;
{
    perror(file);
}
