File indexing completed on 2018-03-02 18:44:46 UTC
view on githubraw file Latest commit e768bd12 on 2008-02-26 17:05:00 UTC
ec6cf3b09d Ed H*0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <stdio.h>
e768bd1221 Jean*0029 #include <stdlib.h>
ec6cf3b09d Ed H*0030 #include <string.h>
0031 #include <ctype.h>
e768bd1221 Jean*0032 #include <unistd.h>
ec6cf3b09d Ed H*0033 #include "xmalloc.h"
0034 #include "common.h"
0035 #include "part.h"
0036 #include "md5.h"
0037
0038 extern char *os_idtodir(char *id);
0039 extern FILE *os_newtypedfile(char *fname, char *contentType, int flags, params contentParams);
0040 extern FILE *os_createnewfile(char *fname);
0041 extern char *md5contextTo64(MD5_CTX *context);
e768bd1221 Jean*0042 extern void warn(char *s);
0043 extern void os_perror(char *str);
0044 extern void chat(char *s);
0045 extern void os_donewithdir(char *dir);
0046 extern void os_warnMD5mismatch(void);
0047 extern void os_closetypedfile(FILE *outfile);
0048
0049 extern int part_depth(struct part *part);
0050 extern void part_ungets(char *s, struct part *part);
0051 extern void part_close(struct part *part);
0052 extern int part_fill(struct part *part);
0053 extern void part_addboundary(struct part *part, char *boundary);
0054 extern int part_readboundary(struct part *part);
ec6cf3b09d Ed H*0055
0056
0057 enum encoding { enc_none, enc_qp, enc_base64 };
0058
0059 char *ParseHeaders(struct part *inpart, char **subjectp, char **contentTypep, enum encoding *contentEncodingp, char **contentDispositionp, char **contentMD5p);
0060 enum encoding parseEncoding(char *s);
0061 params ParseContent(char **headerp);
0062 char *getParam(params cParams, char *key);
0063 char *getDispositionFilename(char *disposition);
0064 void from64(struct part *inpart, FILE *outfile, char **digestp, int suppressCR);
0065 void fromqp(struct part *inpart, FILE *outfile, char **digestp);
0066 void fromnone(struct part *inpart, FILE *outfile, char **digestp);
e768bd1221 Jean*0067 int handlePartial(struct part *inpart, char *headers, params contentParams,
0068 int extractText);
0069 int ignoreMessage(struct part *inpart);
0070 int handleMultipart(struct part *inpart, char *contentType,
0071 params contentParams, int extractText);
0072 int handleUuencode(struct part *inpart, char *subject, int extractText);
0073 int handleText(struct part *inpart, enum encoding contentEncoding);
0074 int saveToFile(struct part *inpart, int inAppleDouble, char *contentType,
0075 params contentParams, enum encoding contentEncoding,
0076 char *contentDisposition, char *contentMD5);
0077
ec6cf3b09d Ed H*0078
0079
0080
0081 int handleMessage(struct part *inpart, char *defaultContentType, int inAppleDouble, int extractText)
0082 {
0083 char *headers, *subject, *contentType, *contentDisposition, *contentMD5;
0084 enum encoding contentEncoding;
0085 params contentParams;
0086
0087
0088 headers = ParseHeaders(inpart, &subject, &contentType, &contentEncoding,
0089 &contentDisposition, &contentMD5);
0090 if (!headers) return 1;
0091
0092
0093 if (!contentType || !strchr(contentType, '/')) {
0094 contentType = defaultContentType;
0095 }
0096 contentParams = ParseContent(&contentType);
0097
0098 if (!strcasecmp(contentType, "message/rfc822")) {
0099 if (contentEncoding != enc_none) {
0100 warn("ignoring invalid content encoding on message/rfc822");
0101 }
0102
0103
0104 return handleMessage(inpart, "text/plain", 0, extractText);
0105 }
0106 else if (!strcasecmp(contentType, "message/partial")) {
0107 if (contentEncoding != enc_none) {
0108 warn("ignoring invalid content encoding on message/partial");
0109 }
0110 return handlePartial(inpart, headers, contentParams, extractText);
0111 }
0112 else if (!strncasecmp(contentType, "message/", 8)) {
0113
0114 return ignoreMessage(inpart);
0115 }
0116 else if (!strncasecmp(contentType, "multipart/", 10)) {
0117 if (contentEncoding != enc_none) {
0118 warn("ignoring invalid content encoding on multipart");
0119 }
0120 return handleMultipart(inpart, contentType, contentParams,
0121 extractText);
0122 }
0123 else if (part_depth(inpart) == 0 &&
0124 !strncasecmp(contentType, "text/", 5) &&
0125 contentEncoding == enc_none &&
0126 !getDispositionFilename(contentDisposition) &&
0127 !getParam(contentParams, "name")) {
0128
0129 return handleUuencode(inpart, subject, extractText);
0130 }
0131 else if (!extractText && !inAppleDouble &&
0132 !strncasecmp(contentType, "text/", 5) &&
0133 !getDispositionFilename(contentDisposition) &&
0134 !getParam(contentParams, "name")) {
0135 return handleText(inpart, contentEncoding);
0136 }
0137 else {
0138
0139 return saveToFile(inpart, inAppleDouble, contentType, contentParams,
0140 contentEncoding, contentDisposition, contentMD5);
0141 }
0142 }
0143
0144
0145
0146
0147 void SkipWhitespace(char **s)
0148 {
0149 char *p = *s;
0150 int commentlevel = 0;
0151
0152 while (*p && (isspace(*p) || *p == '(')) {
0153 if (*p == '\n') {
0154 p++;
0155 if (*p != ' ' && *p != '\t') {
0156 *s = 0;
0157 return;
0158 }
0159 }
0160 else if (*p == '(') {
0161 p++;
0162 commentlevel++;
0163 while (commentlevel) {
0164 switch (*p) {
0165 case '\n':
0166 p++;
0167 if (*p == ' ' || *p == '\t') break;
0168
0169 case '\0':
0170 *s = 0;
0171 return;
0172
0173 case '\\':
0174 p++;
0175 break;
0176
0177 case '(':
0178 commentlevel++;
0179 break;
0180
0181 case ')':
0182 commentlevel--;
0183 break;
0184 }
0185 p++;
0186 }
0187 }
0188 else p++;
0189 }
0190 if (*p == 0) {
0191 *s = 0;
0192 }
0193 else {
0194 *s = p;
0195 }
0196 }
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 #define HEADGROWSIZE 1000
0208 char *ParseHeaders(struct part *inpart, char **subjectp, char **contentTypep, enum encoding *contentEncodingp, char **contentDispositionp, char **contentMD5p)
0209 {
0210 static int alloced = 0;
0211 static char *headers;
0212 int left, len, i;
0213 char *next, *val;
0214
0215
0216 if (!alloced) {
0217 headers = xmalloc(alloced = HEADGROWSIZE);
0218 }
0219 next = headers;
0220 *next++ = '\n';
0221 left = alloced - 2;
0222
0223 while (part_gets(next, left, inpart) && (*next != '\n' || next[-1] != '\n')) {
0224 len = strlen(next);
0225
0226 if (next[-1] == '\n') {
0227
0228 for (i = 0; i < len; i++) {
0229 if (next[i] == ':' ||
0230 next[i] <= ' ' || next[i] >= '\177') break;
0231 }
0232 if (i == 0 || next[i] != ':') {
0233
0234 if (next == headers+1 || (next[0] != ' ' && next[0] != '\t')) {
0235
0236
0237
0238
0239 part_ungets(next, inpart);
0240 break;
0241 }
0242 }
0243 }
0244
0245 left -= len;
0246 next += len;
0247
0248 if (left < 100) {
0249 len = next - headers;
0250 alloced += HEADGROWSIZE;
0251 left += HEADGROWSIZE;
0252 headers = xrealloc(headers, alloced);
0253 next = headers + len;
0254 }
0255 }
0256
0257 *next = '\0';
0258
0259
0260 *subjectp = *contentTypep = *contentDispositionp = *contentMD5p = 0;
0261 *contentEncodingp = enc_none;
0262 for (next = headers; *next; next++) {
0263 if (*next == '\n') {
0264 switch(next[1]) {
0265 case 's':
0266 case 'S':
0267 if (!strncasecmp(next+2, "ubject:", 7)) {
0268 val = next+9;
0269 SkipWhitespace(&val);
0270 if (val) *subjectp = val;
0271 }
0272 break;
0273
0274 case 'c':
0275 case 'C':
0276 if (!strncasecmp(next+2, "ontent-type:", 12)) {
0277 val = next+14;
0278 SkipWhitespace(&val);
0279 if (val) *contentTypep = val;
0280 }
0281 else if (!strncasecmp(next+2, "ontent-transfer-encoding:", 25)) {
0282 *contentEncodingp = parseEncoding(next+27);
0283 }
0284 else if (!strncasecmp(next+2, "ontent-disposition:", 19)) {
0285 val = next+21;
0286 SkipWhitespace(&val);
0287 if (val) *contentDispositionp = val;
0288 }
0289 else if (!strncasecmp(next+2, "ontent-md5:", 11)) {
0290 val = next+13;
0291 SkipWhitespace(&val);
0292 if (val) *contentMD5p = val;
0293 }
0294 }
0295 }
0296 }
0297 return headers;
0298 }
0299
0300
0301
0302
0303
0304 enum encoding parseEncoding(char *s)
0305 {
0306 SkipWhitespace(&s);
0307 if (s) {
0308 switch (*s) {
0309 case 'q':
0310 case 'Q':
0311 if (!strncasecmp(s+1, "uoted-printable", 15) &&
0312 (isspace(s[16]) || s[16] == '(')) {
0313 return enc_qp;
0314 }
0315 break;
0316
0317 case '7':
0318 case '8':
0319 if (!strncasecmp(s+1, "bit", 3) &&
0320 (isspace(s[4]) || s[4] == '(')) {
0321 return enc_none;
0322 }
0323 break;
0324
0325 case 'b':
0326 case 'B':
0327 if (!strncasecmp(s+1, "ase64", 5) &&
0328 (isspace(s[6]) || s[6] == '(')) {
0329 return enc_base64;
0330 }
0331 if (!strncasecmp(s+1, "inary", 5) &&
0332 (isspace(s[6]) || s[6] == '(')) {
0333 return enc_none;
0334 }
0335 }
0336 warn("ignoring unknown content transfer encoding\n");
0337 }
0338 return enc_none;
0339 }
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 #define PARAMGROWSIZE 10
0350 params ParseContent(char **headerp)
0351 {
0352 char *header;
0353 static int palloced = 0;
0354 static char **param;
0355 static int calloced = 0;
0356 static char *cbuf;
0357 char *p;
0358 int nparam;
0359
0360 p = header = *headerp;
0361
0362
0363 do {
0364 p = strchr(p+1, '\n');
0365 } while (p && isspace(p[1]));
0366 if (!p) {
0367 p = header + strlen(header);
0368 }
0369
0370
0371 if (p - header >= calloced) {
0372 calloced = p - header + 1;
0373 if (calloced < 200) calloced = 200;
0374 cbuf = xrealloc(cbuf, calloced);
0375 }
0376
0377
0378 strncpy(cbuf, header, p - header);
0379 cbuf[p - header] = 0;
0380 header = *headerp = cbuf;
0381
0382 nparam = 0;
0383
0384
0385
0386 p = header;
0387 while (header && *header && *header != ';') {
0388 while (*header && !isspace(*header) && *header != '(' &&
0389 *header != ';') {
0390 *p++ = *header++;
0391 }
0392 SkipWhitespace(&header);
0393 }
0394 if (!header || !*header) return 0;
0395 header++;
0396 *p = '\0';
0397
0398
0399 while (*header) {
0400 SkipWhitespace(&header);
0401 if (!header) break;
0402
0403 if (nparam+1 >= palloced) {
0404 palloced += PARAMGROWSIZE;
0405 param = (char **) xrealloc((char *)param, palloced * sizeof(char *));
0406 }
0407 param[nparam++] = header;
0408
0409
0410 while (*header && *header != ';') {
0411 if (*header == '\"') {
0412 ++header;
0413 while (*header && *header != '\"') {
0414 if (*header == '\\') {
0415 ++header;
0416 if (!*header) break;
0417 }
0418 ++header;
0419 }
0420 if (!*header) break;
0421 }
0422 else if (*header == '(') {
0423
0424 p = header;
0425 SkipWhitespace(&p);
0426 if (!p) {
0427 break;
0428 }
0429 while (header < p) *header++ = ' ';
0430 header--;
0431 }
0432 header++;
0433 }
0434 if (*header) *header++ = '\0';
0435 }
0436
0437 if (nparam == 0)
0438 return 0;
0439
0440 param[nparam] = 0;
0441 return param;
0442 }
0443
0444
0445
0446
0447
0448
0449 #define VALUEGROWSIZE 100
0450 char *getParam(params cParams, char *key)
0451 {
0452 static char *value;
0453 static int alloced = 0;
0454 int left;
0455 int keylen = strlen(key);
0456 char *from, *to;
0457
0458 if (!cParams) return 0;
0459
0460 if (!alloced) {
0461 value = xmalloc(alloced = VALUEGROWSIZE);
0462 }
0463
0464
0465 while (*cParams) {
0466 if (!strncasecmp(key, *cParams, keylen) &&
0467 ((*cParams)[keylen] == '=' || isspace((*cParams)[keylen]))) break;
0468 cParams++;
0469 }
0470 if (!*cParams) return 0;
0471
0472
0473 from = *cParams + keylen;
0474 while (*from && isspace(*from)) from++;
0475 if (*from++ != '=') return 0;
0476 while (*from && isspace(*from)) from++;
0477 if (!*from) return 0;
0478
0479
0480 to = value;
0481 left = alloced - 1;
0482 if (*from == '\"') {
0483
0484 from++;
0485 while (*from && *from != '\"') {
0486 if (!--left) {
0487 alloced += VALUEGROWSIZE;
0488 left += VALUEGROWSIZE;
0489 value = xrealloc(value, alloced);
0490 to = value + alloced - left - 2;
0491 }
0492 if (*from == '\\') {
0493 from++;
0494 if (!*from) return 0;
0495 }
0496 *to++ = *from++;
0497 }
0498 if (!*from) return 0;
0499 }
0500 else {
0501
0502 while (*from && !isspace(*from)) {
0503 if (!--left) {
0504 alloced += VALUEGROWSIZE;
0505 left += VALUEGROWSIZE;
0506 value = xrealloc(value, alloced);
0507 to = value + alloced - left - 2;
0508 }
0509 *to++ = *from++;
0510 }
0511 }
0512 *to = '\0';
0513 return value;
0514 }
0515
0516
0517
0518
0519
0520
0521 char *
0522 getDispositionFilename(char *disposition)
0523 {
0524 static char *value;
0525 static int alloced = 0;
0526 int left;
0527 char *to;
0528
0529 if (!disposition) return 0;
0530
0531
0532 for (;;) {
0533
0534 while (*disposition != ';') {
0535 if (!*disposition) return 0;
0536 else if (*disposition == '\"') {
0537 ++disposition;
0538 while (*disposition && *disposition != '\"') {
0539 if (*disposition == '\\') {
0540 ++disposition;
0541 if (!*disposition) return 0;
0542 }
0543 ++disposition;
0544 }
0545 if (!*disposition) return 0;
0546 }
0547 else if (*disposition == '(') {
0548 SkipWhitespace(&disposition);
0549 if (!disposition) return 0;
0550 disposition--;
0551 }
0552 disposition++;
0553 }
0554
0555
0556 disposition++;
0557 SkipWhitespace(&disposition);
0558 if (!disposition) return 0;
0559
0560
0561
0562
0563
0564
0565 if (strncasecmp(disposition, "filename", 8) != 0) continue;
0566 disposition += 8;
0567 if (!isspace(*disposition) && *disposition != '=' &&
0568 *disposition != '(') {
0569 continue;
0570 }
0571 SkipWhitespace(&disposition);
0572 if (!disposition) return 0;
0573
e768bd1221 Jean*0574
0575 if (*disposition++ == '=') break;
ec6cf3b09d Ed H*0576 }
0577
0578 SkipWhitespace(&disposition);
0579 if (!disposition) return 0;
0580
0581 if (!alloced) {
0582 value = xmalloc(alloced = VALUEGROWSIZE);
0583 }
0584
0585
0586 to = value;
0587 left = alloced - 1;
0588 if (*disposition == '\"') {
0589
0590 disposition++;
0591 while (*disposition && *disposition != '\"') {
0592 if (!--left) {
0593 alloced += VALUEGROWSIZE;
0594 left += VALUEGROWSIZE;
0595 value = xrealloc(value, alloced);
0596 to = value + alloced - left - 2;
0597 }
0598 if (*disposition == '\\') {
0599 disposition++;
0600 if (!*disposition) return 0;
0601 }
0602 *to++ = *disposition++;
0603 }
0604 if (!*disposition) return 0;
0605 }
0606 else {
0607
0608 while (*disposition && !isspace(*disposition) &&
0609 *disposition != '(') {
0610 if (!--left) {
0611 alloced += VALUEGROWSIZE;
0612 left += VALUEGROWSIZE;
0613 value = xrealloc(value, alloced);
0614 to = value + alloced - left - 2;
0615 }
0616 *to++ = *disposition++;
0617 }
0618 }
0619 *to = '\0';
0620 return value;
0621 }
0622
0623
0624
0625
0626 int handlePartial(struct part *inpart, char *headers, params contentParams, int extractText)
0627 {
0628 char *id, *dir, *p;
0629 int thispart;
0630 int nparts = 0;
0631 char buf[1024];
0632 FILE *partfile, *outfile;
0633 struct part *outpart;
0634 int i, docopy;
0635
0636 id = getParam(contentParams, "id");
0637 if (!id) {
0638 warn("partial message has no id parameter");
0639 goto ignore;
0640 }
0641
0642
0643 dir = os_idtodir(id);
0644 if (!dir) goto ignore;
0645
0646 p = getParam(contentParams, "number");
0647 if (!p) {
0648 warn("partial message doesn't have number parameter");
0649 goto ignore;
0650 }
0651 thispart = atoi(p);
0652
e768bd1221 Jean*0653 if ((p = getParam(contentParams, "total"))) {
ec6cf3b09d Ed H*0654 nparts = atoi(p);
0655 if (nparts <= 0) {
0656 warn("partial message has invalid number of parts");
0657 goto ignore;
0658 }
0659
0660 sprintf(buf, "%sCT", dir);
0661 partfile = os_createnewfile(buf);
0662 if (!partfile) {
0663 os_perror(buf);
0664 goto ignore;
0665 }
0666 fprintf(partfile, "%d\n", nparts);
0667 fclose(partfile);
0668 }
0669 else {
0670
0671 sprintf(buf, "%sCT", dir);
e768bd1221 Jean*0672 if ((partfile = fopen(buf, "r"))) {
ec6cf3b09d Ed H*0673 if (fgets(buf, sizeof(buf), partfile)) {
0674 nparts = atoi(buf);
0675 if (nparts < 0) nparts = 0;
0676 }
0677 fclose(partfile);
0678 }
0679 }
0680
0681
0682 if (thispart <= 0 || (nparts && thispart > nparts)) {
0683 warn("partial message has invalid number");
0684 goto ignore;
0685 }
0686
0687 sprintf(buf, "Saving part %d ", thispart);
0688 if (nparts) sprintf(buf+strlen(buf), "of %d ", nparts);
0689 strcat(buf, getParam(contentParams, "id"));
0690 chat(buf);
0691
0692
0693 sprintf(buf, "%s%d", dir, thispart);
0694 partfile = os_createnewfile(buf);
0695 if (!partfile) {
0696 os_perror(buf);
0697 goto ignore;
0698 }
0699
0700
0701 if (thispart == 1) {
0702 int skippedfirstbyte = 0;
0703
0704 while (*headers) {
0705 if (*headers == '\n' &&
0706 (!strncasecmp(headers, "\ncontent-", 9) ||
0707 !strncasecmp(headers, "\nmessage-id:", 12))) {
0708
0709 headers++;
0710 while (*headers && (*headers != '\n' || isspace(headers[1]))) {
0711 headers++;
0712 }
0713 }
0714 else {
0715
0716 if (skippedfirstbyte++) putc(*headers, partfile);
0717 headers++;
0718 }
0719 }
0720 docopy = 0;
0721
0722 while (part_gets(buf, sizeof(buf), inpart)) {
0723 if (*buf == '\n') {
0724 putc('\n', partfile);
0725 break;
0726 }
0727 if (!strncasecmp(buf, "content-", 8) || !strncasecmp(buf, "message-id:", 11)) {
0728 docopy = 1;
0729 }
0730 else if (!isspace(*buf)) {
0731 docopy = 0;
0732 }
0733
0734 if (docopy) fputs(buf, partfile);
0735 while(buf[strlen(buf)-1] != '\n' && part_gets(buf, sizeof(buf), inpart)) {
0736 if (docopy) fputs(buf, partfile);
0737 }
0738 }
0739 }
0740
0741
0742 while (part_gets(buf, sizeof(buf), inpart)) {
0743 fputs(buf, partfile);
0744 }
0745 fclose(partfile);
0746
0747
0748
0749
0750 for (i = nparts; i; i--) {
0751 sprintf(buf, "%s%d", dir, i);
0752 partfile = fopen(buf, "r");
0753 if (partfile) {
0754 fclose(partfile);
0755 }
0756 else {
0757 break;
0758 }
0759 }
0760
0761 if (i || !nparts) {
0762
0763 return 0;
0764 }
0765
0766
0767 sprintf(buf, "%sFULL", dir);
0768 outfile = os_createnewfile(buf);
0769 if (!outfile) {
0770 os_perror(buf);
0771 return 1;
0772 }
0773 for (i=1; i<=nparts; i++) {
0774 sprintf(buf, "%s%d", dir, i);
0775 partfile = fopen(buf, "r");
0776 if (!partfile) {
0777 os_perror(buf);
0778 return 1;
0779 }
0780 while (fgets(buf, sizeof(buf), partfile)) {
0781 fputs(buf, outfile);
0782 }
0783 fclose(partfile);
0784
0785
0786 sprintf(buf, "%s%d", dir, i);
0787 remove(buf);
0788 }
0789
0790
0791 fclose(outfile);
0792 sprintf(buf, "%sFULL", dir);
0793 outfile = fopen(buf, "r");
0794 if (!outfile) {
0795 os_perror(buf);
0796 return 1;
0797 }
0798 outpart = part_init(outfile);
0799 handleMessage(outpart, "text/plain", 0, extractText);
0800 part_close(outpart);
0801
0802
0803 sprintf(buf, "%sFULL", dir);
0804 remove(buf);
0805 sprintf(buf, "%sCT", dir);
0806 remove(buf);
0807 os_donewithdir(dir);
0808
0809 return 0;
0810
0811 ignore:
0812 ignoreMessage(inpart);
0813 return 1;
0814 }
0815
0816
0817
0818
0819 int ignoreMessage(struct part *inpart)
0820 {
0821 while (part_getc(inpart) != EOF);
0822 return 0;
0823 }
0824
0825
0826
0827
0828 int handleMultipart(struct part *inpart, char *contentType, params contentParams, int extractText)
0829 {
0830 char *id;
0831 char *defaultContentType = "text/plain";
0832 int isAppleDouble = 0;
0833
0834
0835 if (!strcasecmp(contentType, "multipart/digest")) {
0836 defaultContentType = "message/rfc822";
0837 }
0838 if (!strcasecmp(contentType, "multipart/appledouble")) {
0839 isAppleDouble++;
0840 }
0841
0842 if (!(id = getParam(contentParams, "boundary"))) {
0843 warn("multipart message has no boundary parameter");
0844 id="";
0845 }
0846
0847
0848 part_addboundary(inpart, id);
0849
0850 #ifdef __riscos
0851
0852
0853
0854
0855
0856 os_boundaryhookopen(part_depth(inpart));
0857 #endif
0858
0859
0860
0861
0862
0863
0864
0865 part_ungetc('\n', inpart);
0866 ignoreMessage(inpart);
0867
0868
0869 while (!part_readboundary(inpart)) {
0870 handleMessage(inpart, defaultContentType, isAppleDouble, extractText);
0871 }
0872
0873 #ifdef __riscos
0874 os_boundaryhookclose(part_depth(inpart));
0875 #endif
0876
0877
0878 ignoreMessage(inpart);
0879
0880
0881 (void) remove(TEMPFILENAME);
0882
0883 return 0;
0884 }
0885
0886
0887
0888
0889
0890 int handleText(struct part *inpart, enum encoding contentEncoding)
0891 {
0892 FILE *descfile;
0893
0894 descfile = os_createnewfile(TEMPFILENAME);
0895 if (!descfile) {
0896 os_perror(TEMPFILENAME);
0897 ignoreMessage(inpart);
0898 return 1;
0899 }
0900
0901
0902 switch (contentEncoding) {
0903 case enc_none:
0904 fromnone(inpart, descfile, (char **)0);
0905 break;
0906
0907 case enc_qp:
0908 fromqp(inpart, descfile, (char **)0);
0909 break;
0910
0911 case enc_base64:
0912 from64(inpart, descfile, (char **)0, 1);
0913 break;
0914 }
0915
0916 fclose(descfile);
0917 return 0;
0918 }
0919
0920
0921
0922
0923 int saveToFile(struct part *inpart, int inAppleDouble, char *contentType, params contentParams, enum encoding contentEncoding, char *contentDisposition, char *contentMD5)
0924 {
0925 FILE *outfile = 0;
0926 int flags = 0;
0927 int suppressCR = 0;
0928 char *outputmd5;
0929 char *fname;
0930
0931 if (!strncasecmp(contentType, "text/", 5)) {
0932 suppressCR = 1;
0933 }
0934 else if (contentEncoding == enc_base64) {
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946 flags |= FILE_BINARY;
0947 }
0948
0949 if (inAppleDouble) flags |= FILE_INAPPLEDOUBLE;
0950
0951
0952 fname = getDispositionFilename(contentDisposition);
0953 if (!fname) fname = getParam(contentParams, "name");
0954 if (fname) fname = strsave(fname);
0955 outfile = os_newtypedfile(fname, contentType, flags, contentParams);
0956 if (fname) free(fname);
0957 if (!outfile) {
0958 ignoreMessage(inpart);
0959 return 1;
0960 }
0961
0962
0963 switch (contentEncoding) {
0964 case enc_none:
0965 fromnone(inpart, outfile, &outputmd5);
0966 break;
0967
0968 case enc_qp:
0969 fromqp(inpart, outfile, &outputmd5);
0970 break;
0971
0972 case enc_base64:
0973 from64(inpart, outfile, &outputmd5, suppressCR);
0974 break;
0975 }
0976 rewind(outfile);
0977
0978
0979 if (contentMD5) {
0980 if (strncmp(outputmd5, contentMD5, strlen(outputmd5)) != 0) {
0981 os_warnMD5mismatch();
0982 }
0983 }
0984 free(outputmd5);
0985
0986 os_closetypedfile(outfile);
0987 return 0;
0988 }
0989
0990 #define XX 127
0991
0992
0993
0994 static char index_hex[256] = {
0995 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
0996 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
0997 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
0998 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX, XX,XX,XX,XX,
0999 XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1000 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1001 XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1002 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1003 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1004 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1005 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1006 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1007 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1008 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1009 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1010 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1011 };
1012 #define HEXCHAR(c) (index_hex[(unsigned char)(c)])
1013
1014
1015
1016
1017 static char index_64[256] = {
1018 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1019 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1020 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
1021 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX,
1022 XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
1023 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
1024 XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
1025 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
1026 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1027 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1028 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1029 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1030 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1031 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1032 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1033 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1034 };
1035 #define CHAR64(c) (index_64[(unsigned char)(c)])
1036
1037 void from64(struct part *inpart, FILE *outfile, char **digestp, int suppressCR)
1038 {
1039 int c1, c2, c3, c4;
1040 int DataDone = 0;
1041 char buf[3];
1042 MD5_CTX context;
1043
1044 if (digestp) MD5Init(&context);
1045 while ((c1 = part_getc(inpart)) != EOF) {
1046 if (c1 != '=' && CHAR64(c1) == XX) {
1047 continue;
1048 }
1049 if (DataDone) continue;
1050 do {
1051 c2 = part_getc(inpart);
1052 } while (c2 != EOF && c2 != '=' && CHAR64(c2) == XX);
1053 do {
1054 c3 = part_getc(inpart);
1055 } while (c3 != EOF && c3 != '=' && CHAR64(c3) == XX);
1056 do {
1057 c4 = part_getc(inpart);
1058 } while (c4 != EOF && c4 != '=' && CHAR64(c4) == XX);
1059 if (c2 == EOF || c3 == EOF || c4 == EOF) {
1060 warn("Premature EOF");
1061 break;
1062 }
1063 if (c1 == '=' || c2 == '=') {
1064 DataDone=1;
1065 continue;
1066 }
1067 c1 = CHAR64(c1);
1068 c2 = CHAR64(c2);
1069 buf[0] = ((c1<<2) | ((c2&0x30)>>4));
1070 if (!suppressCR || buf[0] != '\r') putc(buf[0], outfile);
1071 if (c3 == '=') {
1072 if (digestp) MD5Update(&context, buf, 1);
1073 DataDone = 1;
1074 } else {
1075 c3 = CHAR64(c3);
1076 buf[1] = (((c2&0x0F) << 4) | ((c3&0x3C) >> 2));
1077 if (!suppressCR || buf[1] != '\r') putc(buf[1], outfile);
1078 if (c4 == '=') {
1079 if (digestp) MD5Update(&context, buf, 2);
1080 DataDone = 1;
1081 } else {
1082 c4 = CHAR64(c4);
1083 buf[2] = (((c3&0x03) << 6) | c4);
1084 if (!suppressCR || buf[2] != '\r') putc(buf[2], outfile);
1085 if (digestp) MD5Update(&context, buf, 3);
1086 }
1087 }
1088 }
1089 if (digestp) *digestp = md5contextTo64(&context);
1090 }
1091
1092 void fromqp(struct part *inpart, FILE *outfile, char **digestp)
1093 {
1094 int c1, c2;
1095 MD5_CTX context;
1096 char c;
1097
1098 if (digestp) MD5Init(&context);
1099
1100 while ((c1 = part_getc(inpart)) != EOF) {
1101 if (c1 == '=') {
1102 c1 = part_getc(inpart);
1103 if (c1 != '\n') {
1104 c1 = HEXCHAR(c1);
1105 c2 = part_getc(inpart);
1106 c2 = HEXCHAR(c2);
1107 c = c1<<4 | c2;
1108 if (c != '\r') putc(c, outfile);
1109 if (digestp) MD5Update(&context, &c, 1);
1110 }
1111 } else {
1112 putc(c1, outfile);
1113 if (c1 == '\n') {
1114 if (digestp) MD5Update(&context, "\r", 1);
1115 }
1116 c = c1;
1117 if (digestp) MD5Update(&context, &c, 1);
1118 }
1119 }
1120 if (digestp) *digestp=md5contextTo64(&context);
1121 }
1122
1123 void fromnone(struct part *inpart, FILE *outfile, char **digestp)
1124 {
1125 int c;
1126 char ch;
1127 MD5_CTX context;
1128
1129 if (digestp) MD5Init(&context);
1130
1131 while ((c = part_getc(inpart)) != EOF) {
1132 putc(c, outfile);
1133 if (c == '\n') {
1134 if (digestp) MD5Update(&context, "\r", 1);
1135 }
1136 ch = c;
1137 if (digestp) MD5Update(&context, &ch, 1);
1138 }
1139 if (digestp) *digestp=md5contextTo64(&context);
1140 }
1141