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