1 /* (C) Copyright 1993,1994 by Carnegie Mellon University
2  * All Rights Reserved.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software
5  * and its documentation for any purpose is hereby granted without
6  * fee, provided that the above copyright notice appear in all copies
7  * and that both that copyright notice and this permission notice
8  * appear in supporting documentation, and that the name of Carnegie
9  * Mellon University not be used in advertising or publicity
10  * pertaining to distribution of the software without specific,
11  * written prior permission.  Carnegie Mellon University makes no
12  * representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied
14  * warranty.
15  *
16  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
17  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
19  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
22  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23  * SOFTWARE.
24  */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 extern char *magic_look(FILE *infile);
30 extern char *os_genid(void);
31 extern FILE *os_createnewfile(char *fname);
32 extern char *md5digest(FILE *infile, long int *len);
33 extern void os_perror(char *str);
34 extern int to64(FILE *infile, FILE *outfile, long int limit);
35 
36 #define NUMREFERENCES 4
37 
38 /*
39  * Encode a file into one or more MIME messages, each
40  * no larger than 'maxsize'.  A 'maxsize' of zero means no size limit.
41  * If 'applefile' is non-null, it is the first part of a multipart/appledouble
42  * pair.
43  */
encode(FILE * infile,FILE * applefile,char * fname,FILE * descfile,char * subject,char * headers,long int maxsize,char * typeoverride,char * outfname)44 int encode(FILE *infile, FILE *applefile, char *fname, FILE *descfile, char *subject, char *headers, long int maxsize, char *typeoverride, char *outfname)
45 {
46     char *type;
47     FILE *outfile;
48     char *cleanfname, *p;
49     char *digest, *appledigest = NULL;
50     long filesize, l, written;
51     int thispart, numparts = 1;
52     int wrotefiletype = 0;
53     char *multipartid, *msgid, *referenceid[NUMREFERENCES];
54     char buf[1024];
55     int i;
56 
57     /* Clean up fname for printing */
58     cleanfname = fname;
59 #ifdef __riscos
60     /* This filename-cleaning knowledge will probably
61      * be moved to the os layer in a future version.
62      */
63     if (p = strrchr(cleanfname, '.')) cleanfname = p+1;
64 #else
65     if ((p = strrchr(cleanfname, '/'))) cleanfname = p+1;
66     if ((p = strrchr(cleanfname, '\\'))) cleanfname = p+1;
67 #endif
68     if ((p = strrchr(cleanfname, ':'))) cleanfname = p+1;
69 
70     /* Find file type */
71     if (typeoverride) {
72 	type = typeoverride;
73     }
74     else {
75 	type = magic_look(infile);
76     }
77 
78     /* Compute MD5 digests */
79     digest = md5digest(infile, &filesize);
80     if (applefile) {
81 	appledigest = md5digest(applefile, &l);
82 	filesize += l;
83     }
84 
85     /* See if we have to do multipart */
86     if (maxsize) {
87 	filesize = (filesize / 54) * 73; /* Allow for base64 expansion */
88 
89 	/* Add in size of desc file */
90 	if (descfile) {
91 	    free(md5digest(descfile, &l)); 	/* XXX */
92 	    filesize += l;
93 	}
94 
95 	numparts = (filesize-1000)/maxsize + 1;
96 	if (numparts < 1) numparts = 1;
97     }
98 
99     multipartid = os_genid();
100     for (i=0; i<NUMREFERENCES; i++) {
101 	referenceid[i] = 0;
102     }
103 
104     for (thispart=1; thispart <= numparts; thispart++) {
105 	written = 0;
106 
107 	/* Open output file */
108 	if (numparts == 1) {
109 	    outfile = os_createnewfile(outfname);
110 	}
111 	else {
112 #ifdef __riscos
113 	    /* Arrgh, riscos uses '.' as directory separator */
114 	    sprintf(buf, "%s/%02d", outfname, thispart);
115 #else
116 	    sprintf(buf, "%s.%02d", outfname, thispart);
117 #endif
118 	    outfile = os_createnewfile(buf);
119 	}
120 	if (!outfile) {
121 	    os_perror(buf);
122             return 1;
123         }
124 
125 	msgid = os_genid();
126 	fprintf(outfile, "Message-ID: <%s>\n", msgid);
127 	fprintf(outfile, "Mime-Version: 1.0\n");
128 	if (headers) fputs(headers, outfile);
129 	if (numparts > 1) {
130 	    fprintf(outfile, "Subject: %s (%02d/%02d)\n", subject,
131 		    thispart, numparts);
132 	    if (thispart == 1) {
133 		referenceid[0] = msgid;
134 	    }
135 	    else {
136 		/* Put out References: header pointing to previous parts */
137 		fprintf(outfile, "References: <%s>\n", referenceid[0]);
138 		for (i=1; i<NUMREFERENCES; i++) {
139 		    if (referenceid[i]) fprintf(outfile, "\t <%s>\n",
140 						referenceid[i]);
141 		}
142 		for (i=2; i<NUMREFERENCES; i++) {
143 		    referenceid[i-1] = referenceid[i];
144 		}
145 		referenceid[NUMREFERENCES-1] = msgid;
146 	    }
147 	    fprintf(outfile,
148 		    "Content-Type: message/partial; number=%d; total=%d;\n",
149 		    thispart, numparts);
150 	    fprintf(outfile, "\t id=\"%s\"\n", multipartid);
151 	    fprintf(outfile, "\n");
152 	}
153 
154 	if (thispart == 1) {
155 	    if (numparts > 1) {
156 		fprintf(outfile, "Message-ID: <%s>\n", multipartid);
157 		fprintf(outfile, "MIME-Version: 1.0\n");
158 	    }
159 	    fprintf(outfile, "Subject: %s\n", subject);
160 	    fprintf(outfile,
161 		    "Content-Type: multipart/mixed; boundary=\"-\"\n");
162 	    fprintf(outfile,
163 "\nThis is a MIME encoded message.  Decode it with \"munpack\"\n");
164 	    fprintf(outfile,
165 "or any other MIME reading software.  Mpack/munpack is available\n");
166 	    fprintf(outfile,
167 "via anonymous FTP in ftp.andrew.cmu.edu:pub/mpack/\n");
168 	    written = 300;
169 
170 	    /* Spit out description section */
171 	    if (descfile) {
172 		fprintf(outfile, "---\n\n");
173 		while (fgets(buf, sizeof(buf), descfile)) {
174 		    /* Strip multiple leading dashes as they may become MIME
175 		     * boundaries
176 		     */
177 		    p = buf;
178 		    if (*p == '-') {
179 			while (p[1] == '-') p++;
180 		    }
181 
182 		    fputs(p, outfile);
183 		    written += strlen(p);
184 		}
185 		fprintf(outfile, "\n");
186 	    }
187 
188 	    fprintf(outfile, "---\n");
189 
190 	    if (applefile) {
191 		fprintf(outfile,
192 	"Content-Type: multipart/appledouble; boundary=\"=\"; name=\"%s\"\n",
193 			cleanfname);
194 		fprintf(outfile,
195 			"Content-Disposition: inline; filename=\"%s\"\n",
196 			cleanfname);
197 		fprintf(outfile, "\n\n--=\n");
198 		fprintf(outfile, "Content-Type: application/applefile\n");
199 		fprintf(outfile, "Content-Transfer-Encoding: base64\n");
200 		fprintf(outfile, "Content-MD5: %s\n\n", appledigest);
201 		free(appledigest);
202 		written += 100;
203 	    }
204 
205 	}
206 
207 	if (applefile && !feof(applefile)) {
208 	    if (written == maxsize) written--; /* avoid a nasty fencepost error */
209 	    written += to64(applefile, outfile,
210 			    (thispart == numparts) ? 0 : (maxsize-written));
211 
212 	    if (!feof(applefile)) {
213 		fclose(outfile);
214 		continue;
215 	    }
216 
217 	    fprintf(outfile, "\n--=\n");
218 	}
219 
220 
221 	if (!wrotefiletype++) {
222 	    fprintf(outfile, "Content-Type: %s; name=\"%s\"\n", type,
223 		    cleanfname);
224 	    fprintf(outfile, "Content-Transfer-Encoding: base64\n");
225 	    fprintf(outfile, "Content-Disposition: inline; filename=\"%s\"\n",
226 		    cleanfname);
227 	    fprintf(outfile, "Content-MD5: %s\n\n", digest);
228 	    free(digest);
229 	    written += 80;
230 	}
231 
232 	if (written == maxsize) written--; /* avoid a nasty fencepost error */
233 
234 	written += to64(infile, outfile,
235 			(thispart == numparts) ? 0 : (maxsize-written));
236 
237 	if (thispart == numparts) {
238 	    if (applefile) fprintf(outfile, "\n--=--\n");
239 	    fprintf(outfile, "\n-----\n");
240 	}
241 
242 	fclose(outfile);
243     }
244 
245     return 0;
246 }
247