/* Notice of Copyright, License and Warranty
**
** This software is Copyright 2004, 2006 Jeffrey S. Dutky
** Updated February 2005 to fix off-by-one error reported by Oscan Esteban
** Updated May 2006 to restrict byte values in 7-bit endcoded data
** Updated May 2006 to fix filename header contents, thanks to Sergey Lapin
** Updated June 2006 (manpage and README.txt files) for Chris Hemphill
** Updated June 2006 to better handle long filenames (quote and fold)
** Updated July 2008 by Phillip J. Brooke:
**       - Minor cleanup (stop warning about err variable)
**       - Added Makefile.
**       - Corrected docs/info re: -c and -t options.
**       - Added -p (copy thru') option (for use by Topal).
**       - Boundary option not honoured -- fixed.
**       - Added -o to omit disposition line.
**       - Added -O to give an overall content type.
**       - Added -m to omit content-transfer-encoding.
**       - Fixed quoted-printable encoder (at least, to what I 
**         understand RFC2045 requires).
**       - Added subpart (-s) switch.
**       - Escape a single `.' on a line, and 'From ' at line-start, as 
**         suggested by RFC2049.
** Updated April 2009 by Phillip J. Brooke:
**       - Correct a typo in comments.
**       - Add option to force name in disposition (-n).
**       - Add no-op option (-0 -- that's a zero).
** Updated June 2009 by Phillip J. Brooke:
**       - Add option to omit disposition name (-N).
**       - Man page update.
**       - Typo corrections.
** Updated March 2011 by Phillip J. Brooke:
**       - Bug fix in base64() where very short files (1 or 2 byte) 
**         weren't processed.
** Updated September 2019, PJB, applying typo fixes from Nicolas Boulenguez.
**
** This software is licensed for use under the terms of the GNU General
** Public License (also called the GPL), a copy of which must be included
** with any distribution of this software. You may also find a copy of the
** GPL at the Free Software Foundation's web site at http://www.fsf.org/
** or http://www.gnu.org.
**
** This software is provided "as is" and without any express or implied
** warranties, including, without limitation, the implied waranties of
** merchantability and fitness for a particular purpose.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MT_VERSION "1.5.topal3"
#define MT_DATE "June 2009"

/*
** A simple mime message utility: create MIME encoded messages with attached
** files.  The program can be used to construct input to the standard unix
** mail and mailx commands.
**
** mime [-dDvV] [-S subject] [-F from-address] [-T to-address]
**      [-C carbon-copy address] [-P prolog-text] [-E epiplogue-text]
**      [-O overall content-type] [-B boundary] -s
**      {[-78abiquxtpom] [-c content-type] [-n filename] filename}
**
**   -d   low detail debugging
**   -D   high detail debugging
**   -v   verbose messages
**   -V   very verbose messages
**   -s   write this as a subpart (makes little sense if more than
**        one filename given)
**
**   -O   overall content-type (e.g., multipart/signed)
**   -7   7-bit ASCII encoding
**   -8   8-bit ASCII encoding
**   -a   application/octet-stream content type
**   -b   binary encoding
**   -i   disposition: inline (instead of the default of attachment)
**   -q   quoted-printable encoding
**   -t   text/plain content type
**   -c   explicit content-type
**   -n   override filename in disposition header
**   -N   don't include the filename parameter in the disposition header
**   -u   unknown encoding, auto-detect
**   -x   base64 encoding
**   -p   copy part already containing relevant headers and encoding
**   -o   omit disposition
**   -m   omit content-transfer-encoding
**
** The program will construct a MIME encoded message from a list of filenames
** and other specified values (subject, from address, to address, boundary,
** prolog text, epilog-text, and carbon-copy list). All of the files are
** flagged with type "application/octet-stream" and encoded using base64,
** regardless of actual file contents (unless explicity flagged for another
** encoding using the -7, -8,-b, -q, or -u flags).
**
** The program has been written in K&R C, so that it can be compiled with the
** bundled HP-UX compiler (a limited K&R compiler). The program will, probably,
** compile with similar bundled compilers on other comercial unices. The program
** will also compile using modern ANSI/ISO C compilers (such as gcc).
*/

/*
** Print the usage message for the MIME-tool program, showing how the program
** should be called and what the command line options and parameters are.
*/
#ifdef __STDC__
int printusage(FILE *f)
#else
int printusage(f) FILE *f;
#endif
{
	fprintf(f, "\nMIME message utility (ver. %s, %s) - create MIME ",
		MT_VERSION, MT_DATE);
	fprintf(f, "email messages \nwith file attachments. The program can ");
	fprintf(f, "be used to construct input to the \nstandard unix mail and ");
	fprintf(f, "mailx commands.\n\n");
	fprintf(f, "Usage:\n");
	fprintf(f, "\tmime [-dDvV] [-S subject] [-F from-address] [-T to-address]\n");
	fprintf(f, "\t\t[-C carbon-copy-addresses] [-P prolog-text] [-E epilog-text]\n");
	fprintf(f, "\t\t[-B boundary] -s [-O overall content-type]\n");
	fprintf(f, "\t\t{[-78abiqtuxo] [-c content-type] [-n filename] filename}\n");
	fprintf(f, "\n\t-d   debugging (low detail level)\n");
	fprintf(f, "\t-D   debugging (high detail level)\n");
	fprintf(f, "\t-v   verbose messages\n");
	fprintf(f, "\t-V   very verbose messages\n");
	fprintf(f, "\t-s   subpart mode\n\n");
	fprintf(f, "\t-7   7-bit ASCII encoding\n");
	fprintf(f, "\t-8   8-bit ASCII encoding\n");
	fprintf(f, "\t-a   application/octet-stream content\n");
	fprintf(f, "\t-b   binary encoding\n");
	fprintf(f, "\t-i   disposition: inline (instead of attachment)\n");
	fprintf(f, "\t-q   quoted-printable encoding\n");
	fprintf(f, "\t-t   text/plain content\n");
	fprintf(f, "\t-c   explicit content-type\n");
	fprintf(f, "\t-n   override filename in disposition \n");
	fprintf(f, "\t-u   unknown encoding (auto-detect)\n");
	fprintf(f, "\t-x   base64 encoding\n");
	fprintf(f, "\t-p   copy part already containing relevant headers and encoding\n");
	fprintf(f, "\t-o   omit disposition line\n");
	fprintf(f, "\t-m   omit content-transfer-encoding\n");
	fprintf(f, "\nThis program is free software distributed under the terms");
	fprintf(f, "of the GNU General \nPublic License (GPL), and comes with ");
	fprintf(f, "ABSOLUTELY NO WARRANTY. See the GPL \nfor details. ");
	fprintf(f, "You should have received a copy of the GPL with this ");
	fprintf(f, "program, \nif not, you can get a copy at the Free Software ");
	fprintf(f, "Foundation's website at \n<http://www.fsf.org> or ");
	fprintf(f, "<http://www.gnu.org>.\n");
	return 0;
}

#define ENC_UNKNOWN 0
#define ENC_ASCII7 1
#define ENC_ASCII8 2
#define ENC_BINARY 3
#define ENC_BASE64 4
#define ENC_QUOTED 5
#define ENC_COPYTHRU 6

#define DISP_ATTACHED 0
#define DISP_INLINE 1
#define DISP_OMIT 2

#define MAX_LINE_LENGTH 75

#define DEBUG(X) if(debug){X;}

/*
** flags to indicate debugging and verbosity levels
*/
static int debug=0, verbose=0;

/*
** wrapped text buffer, used by wrap() function
*/
static char *wbuf=NULL;

/*
** wrap input text to the specified maximum width
*/
#ifdef __STDC__
char *wrap(char *text, int max, int margin)
#else
char *wrap(text, max, margin) char *text; int max, margin;
#endif
{
	int width=0, i, j;
	
	if(wbuf)
		free(wbuf);
	wbuf=malloc(strlen(text)+2+(strlen(text)/max));
	if(wbuf==NULL)
		return NULL;
	
	for(i=0, j=0; text[i]; i++)
	{
		if(text[i]=='\n')
		{ /* if we see a newline, start a new line */
			wbuf[j++]='\n';
			width=0;
		}else if(width>max && !isspace(text[i]))
		{ /* if we have run over the maximum length, put in a newline */
			wbuf[j++]='\n';
			width=1;
			wbuf[j++]=text[i];
		}else if(width>max-margin && (isspace(text[i]) || !isalnum(text[i])))
		{ /* if we see a space in the margin, put in a newline */
			if(!isspace(text[i]))
				wbuf[j++]=text[i];
			wbuf[j++]='\n';
			width=0;
		}else
		{ /* in allo ther cases, just copy the text to wbuf */
			wbuf[j++]=text[i];
			width++;
		}
	}
	wbuf[j]='\0';
	return wbuf;
}

/*
** convert the contents of the input file to base64 encoding.
*/
#ifdef __STDC__
int base64(FILE *f)
#else
int base64(f) FILE *f;
#endif
{
	int i, n;
	char buf[100];
	char *b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	
	do
	{ /* write out blocks of 4 base64 characters (3 input bytes) */
		n=fread(buf, sizeof(char), 57, f);
		DEBUG(fprintf(stderr, "%d chars read from file\n", n));
		for(i=0; i<=n-3; i+=3)
		{
			int b0, b1, b2, b3; /* output base64 characters */

			b0=(buf[i]>>2)&0x3f;
			b1=(((buf[i]<<4)&0x30)|((buf[i+1]>>4)&0xf))&0x3f;
			b2=(((buf[i+1]<<2)&0x3c)|((buf[i+2]>>6)&3))&0x3f;
			b3=(buf[i+2]&0x3f)&0x3f;
			printf("%c%c%c%c", b64[b0], b64[b1],
				b64[b2], b64[b3]);
		}
		if(n<57)
			break;
		printf("\n");
	}while(!feof(f));
	if(ferror(f)) {
		DEBUG(fprintf(stderr, "ferror in base64 encode\n"));
		return 1;
	}
	else
	{ /* handle any trailing input bytes (1 or 2 trailing bytes) */
		int b0, b1, b2; /* output base64 characters */

		DEBUG(fprintf(stderr, "Handling trailing bytes.  n=%d, i=%d\n", n, i));

			if(n-i==1)
			{ /* write out a single input byte as 2 base64 characters */
				b0=(buf[i]>>2)&0x3f;
				b1=((buf[i]<<4)&0x30)&0x3f;
				printf("%c%c==", b64[b0], b64[b1]);
			}
			if(n-i==2)
			{ /* write out two input bytes as 3 base64 characters */
				b0=(buf[i]>>2)&0x3f;
				b1=(((buf[i]<<4)&0x30)|((buf[i+1]>>4)&0xf))&0x3f;
				b2=((buf[i+1]<<2)&0x3c)&0x3f;
				printf("%c%c%c=", b64[b0], b64[b1],
					b64[b2]);
			}
		
	}
	return 0;
}

/*
** quote the input file, replacing newlines and white space with escape
** sequences.
*/
#ifdef __STDC__
int quoted(FILE *f)
#else
int quoted(f) FILE *f;
#endif
{
  int width=0, ch;
  int fstate=0;
  /* 'From ' state.
     0 => Normal
     1 => Have read F at start of line
     2 => Fr
     3 => Fro
     4 => From
     If reading ' ' when in fstate=4, write "=46rom " instead. */
	
  while((ch=fgetc(f))!=EOF)
    {
      if (fstate==0 && width==0 && ch=='F') fstate=1;
      else if (fstate==1) {
	if (ch=='r') fstate=2;
	else { printf("F"); width++; fstate=0; }
      } 
      else if (fstate==2) {
	if (ch=='o') fstate=3;
	else { printf("Fr"); width=width+2; fstate=0; }
      } 
      else if (fstate==3) {
	if (ch=='m') fstate=4;
	else { printf("Fro"); width=width+3; fstate=0; }
      } 
      else if (fstate==4) {
	if (ch==' ') {printf("=46rom"); width=width+6; fstate=0; }
	else { printf("From"); width=width+4; fstate=0; }
      } 
      if (fstate==0) {
	if(width>MAX_LINE_LENGTH && ch!='\n')
	  { /* soft line break at 75 characters */
	    printf("=\015\012");
	    width=0;
	  }
	else if(ch=='\n')
	  { /* emit this one without problem (as CR LF */
	    printf("\015\012");
	    width=0;
	  }
	else if(ch==' ' || ch=='\t' || (ch=='.' && width==0)) {
	  /* tabs, spaces and full-stops at line-ends are escaped */
	  /* full-stops only escaped at start of line */
	  int nextch = fgetc(f);
	  if (nextch != EOF) {
	    ungetc(nextch, f);
	  }
	  if (nextch=='\n') {
	    printf("=%2.2X", ch);
	    width+=3;
	  } else {
	    printf("%c", ch);
	    width++;
	  }
	}
	else if((!isprint(ch)) || ch=='=')
	  { /* escape non-printable characters and equal signs (=) */
	    printf("=%2.2X", ch);
	    width+=3;
	  }
	else
	  { 
	    /* emit all other characters without ado */
	    printf("%c", ch);
	    width++;
	  }
      }
    }
	
  if(ferror(f))
    return 1;
		
  return 0;
}

/*
** copy the input file without modification
*/
#ifdef __STDC__
int copy(FILE *f)
#else
int copy(f) FILE *f;
#endif
{
	int ch;
	
	while((ch=fgetc(f))!=EOF)
		printf("%c", ch);
	if(ferror(f))
		return 1;
	return 0;
}

/*
** copy the input file, restricting output to 7-bit ASCII
*/
#ifdef __STDC__
int copy7(FILE *f)
#else
int copy7(f) FILE *f;
#endif
{
	int ch;
	
	while((ch=fgetc(f))!=EOF)
	{
		if(ch >= 0 && ch < 128)
			printf("%c", ch);
		else /* convert 8-bit characters to question marks (?) */
			printf("?");
	}
	if(ferror(f))
		return 1;
	return 0;
}

/*
** detect an appropriate encoding for the input file
*/
#ifdef __STDC__
int fencode(FILE *f)
#else
int fencode(f) FILE *f;
#endif
{
	int ch, ascii=1, hibit=0, maxline=0, line=0, ctrl=0; /* content flags */
	
	while((ch=fgetc(f))!=EOF)
	{ /* search the file for the follwoing: */
		if(!isascii(ch)) /* non-ASCII characters */
			ascii=0;
		if(ch>127 || ch<0) /* 8-bit characters (bit-7 set) */
			hibit=1;
		if(iscntrl(ch) && !isspace(ch)) /* control characters */
			ctrl=1;
		if(ch=='\n')
		{ /* long lines */
			if(line>maxline)
				maxline=line;
			line=0;
		}else
			line++;
	}
	
	if(ferror(f))
		return -1;
	
	if(fseek(f, 0, SEEK_SET))
		return -2;
	
	if(maxline>998 || ctrl)
		return ENC_BASE64;
	
	if(hibit)
		return ENC_ASCII8;
	
	if(ascii)
		return ENC_ASCII7;
	
	return ENC_BASE64;
}

char *qstr = NULL;
int qstrlen = 0;

/*
** fold and quote the string parameter, given that the parameter starts
** at the nth column.
**
** NOTE: every call to foldquote() overwrites the return value from the
** previous call, so you can't call this function several times in another
** functions argument list or you will get corrupt output.
*/
#ifdef __STDC__
char *foldquote(char *str, int col, int margin)
#else
char *foldquote(str, col, margin) char *str; int col, int margin;
#endif
{
	int needsquotes = 0;
	int needsescapes = 0;
	int needsfolding = 0;
	int qcol = 0, len = 0, i, j;
	
	if(str == NULL)
		return NULL;
	
	/* count chars in str, noticing special chars and fold points */
	for(i = 0, qcol = col; str[i] != '\0'; i++)
	{
		if(str[i] == '"')
			needsescapes++, needsquotes = 1;
		switch(str[i]) /* RFC-822 special characters: "\()[]<>@.,:; */
		{
		case '"': case '\\': case '(': case ')': case '[': case ']':
		case '<': case '>': case '@': case '.': case ',': case ';': case ':':
			needsquotes = 1;
		}
		if(str[i] == ' ' || str[i] == '\t') /* white space */
			needsquotes = 1;
		if(qcol++ > MAX_LINE_LENGTH) /* line too long, folding needed */
			needsfolding++, qcol = 1;
		len++;
	}
	if(needsquotes || needsescapes || needsfolding)
	{
		len = len+needsquotes*2+needsescapes+needsfolding*3+1;
		if(qstrlen < len)
		{
			if(qstr != NULL)
				free(qstr);
			qstr = (char*)malloc(len);
			if(qstr == NULL)
				return NULL;
			qstrlen = len;
		}
		if(qstr == NULL)
			return NULL;
		i = j = 0;
		qcol = col;
		if(needsquotes)
			qstr[i++] = '"';
		/* copy str into qstr applying quotes, escapes and folding */
		while(str[j] != '\0')
		{
			if(str[j] == '"')
				qstr[i++] = '\\'; /* escape quotes */
			qstr[i++] = str[j];
			if(needsfolding && qcol++ >= MAX_LINE_LENGTH-margin
			&& (str[j] == ' ' || str[j] == '\t'))
			{ /* fold at spaces in the margin */
				qstr[i++] = '\n';
				qstr[i++] = ' ';
				qcol = 1;
			}
			j++;
		}
		if(qstr[0] == '"')
			qstr[i++] = '"';
		qstr[i] = '\0';
		
		return qstr;
	}
	
	return str;
}

#ifdef __STDC__
int main(int args, char **arg)
#else
int main(args, arg) int args; char **arg;
#endif
{
	FILE *f;
	int i, err=0, headerneeded=1, encoding=ENC_BASE64, disposition=DISP_ATTACHED, omitCTE=0, subpart=0, omitDisponame=0;
	char *prolog=NULL, *epilog=NULL, *boundary="MIME_CONTENT_BREAK", *p;
	char *subject=NULL, *fromaddress=NULL, *toaddress=NULL, *carboncopy=NULL;
	char *contenttype="application/octet-stream";
	char *overallcontenttype="multipart/mixed";
	char *disponame=NULL;
	
	if(args<2)
	{
		printusage(stderr);
		return 1;
	}
	
	for(i=1; i<args; i++)
	{
		if(arg[i][0]=='-')
		{ /* interpret command line option flags */
			DEBUG(fprintf(stderr, "argument #%d: %s\n", i, arg[i]));
			switch(arg[i][1])
			{
			case '0':
			  DEBUG(fprintf(stderr, "No-op switch\n"));
			  break;
			case '7':
				DEBUG(fprintf(stderr, "ASCII 7-bit encoding\n"));
				encoding=ENC_ASCII7;
				break;
			case '8':
				DEBUG(fprintf(stderr, "ASCII 8-bit encoding\n"));
				encoding=ENC_ASCII8;
				break;
			case 'a':
				DEBUG(fprintf(stderr, "type = application/octet-stream\n"));
				contenttype="application/octet-stream";
				break;
			case 'b':
				DEBUG(fprintf(stderr, "binary encoding\n"));
				encoding=ENC_BINARY;
				break;
			case 'B':
			  DEBUG(fprintf(stderr, "explicit boundary\n"));
			  if (i+1<args) {
			    boundary=arg[++i];
			  }
			  break;
                        case 'c':
                                DEBUG(fprintf(stderr, "explicit content type\n"));
                                if(i+1<args)
                                {
                                        contenttype=arg[++i];
                                }
                                break;
			case 'C':
				DEBUG(fprintf(stderr, "carbon-copies\n"));
				if(i+1<args)
					carboncopy=arg[++i];
				break;
			case 'd':
				fprintf(stderr, "debugging on (low)\n");
				debug=1;
				break;
			case 'D':
				fprintf(stderr, "debugging on (high)\n");
				debug=2;
				break;
			case 'E':
				DEBUG(fprintf(stderr, "epilog text\n"));
				if(i+1<args)
					epilog=arg[++i];
				break;
			case 'F':
				DEBUG(fprintf(stderr, "from address\n"));
				if(i+1<args)
					fromaddress=arg[++i];
				break;
			case 'i':
				DEBUG(fprintf(stderr, "disposition: inline\n"));
				disposition=DISP_INLINE;
				break;
			case 'm':
			  DEBUG(fprintf(stderr, "omit content-transfer-encoding\n"));
			  omitCTE=1;
			  break;
                        case 'n':
                                DEBUG(fprintf(stderr, "force disposition name\n"));
                                if(i+1<args)
                                {
                                        disponame=arg[++i];
                                }
                                break;
                        case 'N':
                                DEBUG(fprintf(stderr, "omit disposition name\n"));
				omitDisponame=1;
                                break;
			case 'o':
			  DEBUG(fprintf(stderr, "omit disposition\n"));
			  disposition=DISP_OMIT;
			  break;
                        case 'O':
                                DEBUG(fprintf(stderr, "explicit overall content type\n"));
                                if(i+1<args)
                                {
                                        overallcontenttype=arg[++i];
                                }
                                break;
			case 'p':
				DEBUG(fprintf(stderr, "copy thru' encoding\n"));
				encoding=ENC_COPYTHRU;
				break;
			case 'P':
				DEBUG(fprintf(stderr, "prolog text\n"));
				if(i+1<args)
					prolog=arg[++i];
				break;
			case 'q':
				DEBUG(fprintf(stderr, "quoted printable encoding\n"));
				encoding=ENC_QUOTED;
				break;
			case 's':
			  DEBUG(fprintf(stderr, "subpart mode\n"));
			  subpart=1;
			  break;
			case 'S':
				DEBUG(fprintf(stderr, "message subject\n"));
				if(i+1<args)
					subject=arg[++i];
				break;
			case 't':
				DEBUG(fprintf(stderr, "explicit text/plain content type\n"));
				contenttype="text/plain";
				break;
			case 'T':
				DEBUG(fprintf(stderr, "to address\n"));
				if(i+1<args)
					toaddress=arg[++i];
				break;
			case 'u':
				DEBUG(fprintf(stderr, "auto-detect unknown encoding\n"));
				encoding=ENC_UNKNOWN;
				contenttype="application/octet-stream";
				break;
			case 'v':
				DEBUG(fprintf(stderr, "verbose errors\n"));
				verbose=1;
				break;
			case 'V':
				DEBUG(fprintf(stderr, "very verbose errors\n"));
				verbose=2;
				break;
			case 'x':
				DEBUG(fprintf(stderr, "base64 encoding\n"));
				encoding=ENC_BASE64;
				break;
			default:
				printusage(stderr);
				return 2;
			}
		}else
		{ /* process non-flag arguments as file attachments */
			char *path, *file;
			
			path=arg[i]; /* each file parameter is possibly a pathname */
			file = strrchr(path, '/'); /* find the basename of the path */
			if(file == NULL)
				file = path; /* path is just a file, not a pathname */
			else
				file++; /* found a slash, step forward one char */
			/* file now points to the basename of the path, thanks Sergey Lapin */
			
			/* Now set the disposition name if it's still NULL. */
			if (!disponame) {
			  disponame = file;
			}
			
			DEBUG(fprintf(stderr, "opening file %s\n", path));
			f=fopen(path, "r");
			if(f)
			{
				DEBUG(fprintf(stderr, "file opened\n"));
				if(headerneeded && (!subpart))
				{ /* if this the first attachment, print headers and prolog */
					DEBUG(fprintf(stderr, "printing header\n"));
					if(fromaddress)
						printf("From: %s\n", fromaddress);
					if(toaddress)
						printf("To: %s\n", toaddress);
					if(carboncopy)
						printf("Cc: %s\n", carboncopy);
					if(subject)
						printf("Subject: %s\n", subject);
					printf("MIME-Version: 1.0 (produced by MIME-tool ver. %s)\n", MT_VERSION);
					
					printf("Content-Type: %s; boundary=\"=_%s_=\"\n\n", overallcontenttype, boundary);
					if(prolog)
					{
						DEBUG(fprintf(stderr, "wrapping prolog\n"));
						p=wrap(prolog, MAX_LINE_LENGTH, 5);
						if(p)
							printf("%s\n\n", p);
						else
						{
							fprintf(stderr, "Failed to allocate buffer for prolog\n");
							return 3;
						}
					}
					printf("--=_%s_=", boundary);
					headerneeded=0;
				}
				if(encoding==ENC_UNKNOWN){
					DEBUG(fprintf(stderr, "Auto-detecting transfer encoding\n"));
					encoding=fencode(f);
					if(encoding<0)
					{
						fprintf(stderr, "Error auto-detecting encoding of file %s\n", path);
						return 4;
					}
				}
				if (encoding==ENC_COPYTHRU) {
				  DEBUG(fprintf(stderr, "Copy-thru\n"));
				  printf("\n");
				  err=copy(f);
				} else {
				DEBUG(fprintf(stderr, "Using encoding "));
				if (!subpart) printf("\n");
				printf("Content-Type: %s\n", contenttype);
				if (disposition == DISP_INLINE && (!omitDisponame)){
					printf("Content-Disposition: inline; filename=%s\n",
						foldquote(disponame, 38, 10));
				} else if (disposition == DISP_INLINE && omitDisponame){
					printf("Content-Disposition: inline\n");
				} else if (disposition == DISP_ATTACHED && (!omitDisponame)){
					printf("Content-Disposition: attachment; filename=%s\n",
						foldquote(disponame, 42, 10));
				} else if (disposition == DISP_ATTACHED && omitDisponame){
					printf("Content-Disposition: attachment\n");
				}
				if (omitCTE) {
				  printf("\n");
				} else {
				  printf("Content-Transfer-Encoding: ");
				}
				switch(encoding)
				{
				case ENC_ASCII7:
					DEBUG(fprintf(stderr, "7bit\n"));
					if (!omitCTE) printf("7bit\n\n");
					err=copy7(f);
					break;
				case ENC_ASCII8:
					DEBUG(fprintf(stderr, "8bit\n"));
					if (!omitCTE) printf("8bit\n\n");
					err=copy(f);
					break;
				case ENC_BINARY:
					DEBUG(fprintf(stderr, "binary\n"));
					if (!omitCTE) printf("binary\n\n");
					err=copy(f);
					break;
				case ENC_QUOTED:
					DEBUG(fprintf(stderr, "quoted-printable\n"));
					if (!omitCTE) printf("quoted-printable\n\n");
					err=quoted(f);
					break;
				case ENC_BASE64:
					DEBUG(fprintf(stderr, "base64\n"));
					if (!omitCTE) printf("base64\n\n");
					err=base64(f);
					break;
				default:
					fprintf(stderr, "Program flaw at content encoding phase\n");
					fprintf(stderr, "unable to process file %s\n", path);
				}
				}
				
				if(err)
					fprintf(stderr, "Error while processing file %s: %s",
						path, strerror(ferror(f)));
				else if (!subpart) 
					printf("\n--=_%s_=", boundary);
				fclose(f);
			}else
			{
				fprintf(stderr, "Failed to open file %s\n", path);
			}
			disposition = DISP_ATTACHED;
			disponame = NULL;
			omitDisponame = 0;
		}
	}
	
	if (!subpart) printf("--\n");
	if(epilog && (!subpart))
	{
		DEBUG(fprintf(stderr, "wrapping epilog\n"));
		p=wrap(epilog, MAX_LINE_LENGTH, 5);
		if(p)
			printf("%s\n", p);
		else
		{
			fprintf(stderr, "Failed to allocate buffer for epilog\n");
			return 5;
		}
	}
	
	return 0;
}
