/* (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 <string.h>

extern char *magic_look();
extern char *os_genid();
extern char *md5digest();

#define NUMREFERENCES 4

/*
 * Encode a file named into one or more MIME messages, each
 * no larger than 'maxsize'.  A 'maxsize' of zero means no size limit.
 */
int encode(fname, descfname, subject, headers, maxsize, typeoverride, outfname)
char *fname, *descfname, *subject, *headers;
long maxsize;
char *typeoverride, *outfname;
{
    char *type;
    FILE *infile, *descfile, *outfile;
    char *cleanfname, *p;
    char *digest;
    long filesize, l, written;
    int thispart, numparts = 1;
    char *multipartid, *msgid, *referenceid[NUMREFERENCES];
    char buf[1024];
    int i;

    /* Open files */
    infile = fopen(fname, "rb");
    if (!infile) {
	os_perror(fname);
	return 1;
    }
    if (descfname) {
	descfile = fopen(descfname, "r");
	if (!descfile) {
	    os_perror(descfname);
	    return 1;
	}
    }

    /* Clean up fname for printing */
    cleanfname = fname;
    if (p = strrchr(cleanfname, '/')) cleanfname = p+1;
    if (p = strrchr(cleanfname, '\\')) cleanfname = p+1;
    if (p = strrchr(cleanfname, ':')) cleanfname = p+1;

    /* Find file type */
    if (typeoverride) {
	type = typeoverride;
    }
    else {
	type = magic_look(infile);
    }

    /* Compute MD5 digest */
    digest = md5digest(infile, &filesize);

    /* See if we have to do multipart */
    if (maxsize) {
	filesize = (filesize / 54) * 73; /* Allow for base64 expansion */

	/* Add in size of desc file */
	if (descfname) {
	    free(md5digest(descfile, &l)); 	/* XXX */
	    filesize += l;
	}

	numparts = (filesize-1000)/maxsize + 1;
	if (numparts < 1) numparts = 1;
    }

    multipartid = os_genid();
    for (i=0; i<NUMREFERENCES; i++) {
	referenceid[i] = 0;
    }

    for (thispart=1; thispart <= numparts; thispart++) {
	written = 0;

	/* Open output file */
	if (numparts == 1) {
	    outfile = fopen(outfname, "w");
	    if (!outfile) os_perror(outfname);
	}
	else {
	    sprintf(buf, "%s.%02d", outfname, thispart);
	    outfile = fopen(buf, "w");
	    if (!outfile) os_perror(buf);
	}
	if (!outfile) return 1;
	
	msgid = os_genid();
	fprintf(outfile, "Message-ID: <%s>\n", msgid);
	fprintf(outfile, "Mime-Version: 1.0\n");
	if (headers) fputs(headers, outfile);
	if (numparts > 1) {
	    fprintf(outfile, "Subject: %s (%02d/%02d)\n", subject,
		    thispart, numparts);
	    if (thispart == 1) {
		referenceid[0] = msgid;
	    }
	    else {
		/* Put out References: header pointing to previous parts */
		fprintf(outfile, "References: <%s>\n", referenceid[0]);
		for (i=1; i<NUMREFERENCES; i++) {
		    if (referenceid[i]) fprintf(outfile, "\t<%s>\n",
						referenceid[i]);
		}
		for (i=2; i<NUMREFERENCES; i++) {
		    referenceid[i-1] = referenceid[i];
		}
		referenceid[NUMREFERENCES-1] = msgid;
	    }
	    fprintf(outfile,
		    "Content-Type: message/partial; number=%d; total=%d;\n",
		    thispart, numparts);
	    fprintf(outfile, "\tid=\"%s\"\n", multipartid);
	    fprintf(outfile, "\n");
	}

	if (thispart == 1) {
	    if (numparts > 1) {
		fprintf(outfile, "Message-ID: <%s>\n", multipartid);
		fprintf(outfile, "MIME-Version: 1.0\n");
	    }
	    fprintf(outfile, "Subject: %s\n", subject);
	    fprintf(outfile,
		    "Content-Type: multipart/mixed; boundary=\"-\"\n");
	    fprintf(outfile,
"\nThis is a MIME encoded message.  Decode it with \"munpack\"\n");
	    fprintf(outfile,
"or any other MIME reading software.  Mpack/munpack is available\n");
	    fprintf(outfile,
"in Volume 3 of comp.sources.reviewed or via anonymous FTP in\n");
	    fprintf(outfile, "export.acs.cmu.edu:pub/mpack/\n");
	    written = 300;

	    /* Spit out description section */
	    if (descfname) {
		fprintf(outfile, "---\n\n");
		while (fgets(buf, sizeof(buf), descfile)) {
		    /* Strip multiple leading dashes as they may become MIME
		     * boundaries
		     */
		    p = buf;
		    if (*p == '-') {
			while (p[1] == '-') p++;
		    }

		    fputs(p, outfile);
		    written += strlen(p);
		}
		fprintf(outfile, "\n");
		fclose(descfile);
	    }
    
	    fprintf(outfile, "---\n");
	    fprintf(outfile, "Content-Type: %s; name=\"%s\"\n", type, cleanfname);
	    fprintf(outfile, "Content-Transfer-Encoding: base64\n");
	    fprintf(outfile, "Content-Disposition: inline; filename=\"%s\"\n",
		    cleanfname);
	    fprintf(outfile, "Content-MD5: %s\n\n", digest);
	    free(digest);
	    written += 80;
	}

	if (written == maxsize) written--; /* avoid a nasty fencepost error */

	to64(infile, outfile, (thispart == numparts) ? 0 : (maxsize-written));

	if (thispart == numparts) {
	    fprintf(outfile, "\n-----\n");
	}
	
	fclose(outfile);    
    }

    return 0;
}
