ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.7
Committed: Thu Nov 6 13:33:41 2003 UTC (20 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +148 -32 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of uudeview, the simple and friendly multi-part multi-
3 * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
4 * be contacted at fp@fpx.de
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17 /*
18 * These are very central functions of UUDeview. Here, we scan a file
19 * and decide whether it contains encoded data or not. ScanPart() must
20 * be called repeatedly on the same file until feof(file). Each time,
21 * it returns information about the next part found within.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #ifdef SYSTEM_WINDLL
29 #include <windows.h>
30 #endif
31 #ifdef SYSTEM_OS2
32 #include <os2.h>
33 #endif
34
35 #include <stdio.h>
36 #include <ctype.h>
37
38 #ifdef STDC_HEADERS
39 #include <stdlib.h>
40 #include <string.h>
41 #endif
42 #ifdef HAVE_MALLOC_H
43 #include <malloc.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #ifdef HAVE_MEMORY_H
49 #include <memory.h>
50 #endif
51 #ifdef HAVE_ERRNO_H
52 #include <errno.h>
53 #endif
54
55 #include <uudeview.h>
56 #include <uuint.h>
57 #include <fptools.h>
58 #include <uustring.h>
59
60 char * uuscan_id = "$Id$";
61
62 /*
63 * Header fields we recognize as such. See RFC822. We add "From ",
64 * the usual marker for a beginning of a new message, and a couple
65 * of usual MDA, News and MIME headers.
66 * We make a distinction of MIME headers as we need the difference
67 * to scan the bodies from partial multipart messages.
68 */
69
70 static char *knownmsgheaders[] = {
71 "From ", "Return-Path:", "Received:", "Reply-To:",
72 "From:", "Sender:", "Resent-Reply-To:", "Resent-From:",
73 "Resent-Sender:", "Date:", "Resent-Date:", "To:",
74 "Resent-To:", "Cc:", "Bcc:", "Resent-bcc:",
75 "Message-ID:", "Resent-Message-Id:", "In-Reply-To:",
76 "References:", "Keywords:", "Subject:", "Comments:",
77
78 "Delivery-Date:", "Posted-Date:", "Received-Date:",
79 "Precedence:",
80
81 "Path:", "Newsgroups:", "Organization:", "Lines:",
82 "NNTP-Posting-Host:",
83 NULL
84 };
85
86 static char *knownmimeheaders[] = {
87 "Mime-Version:", "Content-Transfer-Encoding:",
88 "Content-Type:", "Content-Disposition:",
89 "Content-Description:", "Content-Length:",
90 NULL
91 };
92
93 /*
94 * for MIME (plaintext) parts without filename
95 */
96 int mimseqno;
97
98 /*
99 * how many lines do we read when checking for headers
100 */
101 #define WAITHEADER 10
102
103 /*
104 * The stack for encapsulated Multipart messages
105 */
106 #define MSMAXDEPTH 3
107
108 int mssdepth = 0;
109 scanstate multistack[MSMAXDEPTH+1];
110
111 /*
112 * The state and the local envelope
113 */
114 headers localenv;
115 scanstate sstate;
116
117 /*
118 * mallocable areas
119 */
120
121 char *uuscan_shlline;
122 char *uuscan_shlline2;
123 char *uuscan_pvvalue;
124 char *uuscan_phtext;
125 char *uuscan_sdline;
126 char *uuscan_sdbhds1;
127 char *uuscan_sdbhds2;
128 char *uuscan_spline;
129
130 /*
131 * Macro: print cancellation message in UUScanPart
132 */
133
134 #define SPCANCEL() {UUMessage(uuscan_id,__LINE__,UUMSG_NOTE,uustring(S_SCAN_CANCEL));*errcode=UURET_CANCEL;goto ScanPartEmergency;}
135
136 /*
137 * Is line empty? A line is empty if it is composed of whitespace.
138 */
139
140 static int
141 IsLineEmpty (char *data)
142 {
143 if (data == NULL) return 0;
144 while (*data && isspace (*data)) data++;
145 return ((*data)?0:1);
146 }
147
148 /*
149 * Is this a header line? A header line has alphanumeric characters
150 * followed by a colon.
151 */
152
153 static int
154 IsHeaderLine (char *data)
155 {
156 if (data == NULL) return 0;
157 if (*data == ':') return 0;
158 while (*data && isalnum (*data)) data++;
159 return (*data == ':') ? 1 : 0;
160 }
161
162 /*
163 * Scans a potentially folded header line from the input file. If
164 * initial is non-NULL, it is the first line of the header, useful
165 * if the calling function just coincidentally noticed that this is
166 * a header.
167 * RFC0822 does not specify a maximum length for headers, but we
168 * truncate everything beyond an insane value of 1024 characters.
169 */
170
171 static char *
172 ScanHeaderLine (FILE *datei, char *initial)
173 {
174 char *ptr=uuscan_shlline;
175 char *ptr2, *p1, *p2, *p3;
176 int llength, c;
177 long curpos;
178 int hadcr;
179
180 if (initial) {
181 _FP_strncpy (uuscan_shlline, initial, 1024);
182 }
183 else {
184 /* read first line */
185 if (feof (datei) || ferror (datei))
186 return NULL;
187 if (_FP_fgets (uuscan_shlline, 1023, datei) == NULL)
188 return NULL;
189 uuscan_shlline[1023] = '\0';
190 }
191
192 llength = strlen (uuscan_shlline);
193 hadcr = 0;
194
195 /* strip whitespace at end */
196 ptr = uuscan_shlline + llength;
197 while (llength && isspace(*(ptr-1))) {
198 if (*(ptr-1) == '\012' || *(ptr-1) == '\015')
199 hadcr = 1;
200 ptr--; llength--;
201 }
202 if (llength == 0) {
203 uuscan_shlline[0] = '\0';
204 return uuscan_shlline;
205 }
206
207 while (!feof (datei)) {
208 c = fgetc (datei);
209 if (feof (datei))
210 break;
211
212 /*
213 * If the line didn't have a CR, it was longer than 256 characters
214 * and is continued anyway.
215 */
216
217 if (hadcr==1 && c != ' ' && c != '\t') {
218 /* no LWSP-char, header line does not continue */
219 ungetc (c, datei);
220 break;
221 }
222 while (!feof (datei) && (c == ' ' || c == '\t'))
223 c = fgetc (datei);
224
225 if (!feof (datei))
226 ungetc (c, datei); /* push back for fgets() */
227
228 /* insert a single LWSP */
229 if (hadcr==1 && llength < 1023) {
230 *ptr++ = ' ';
231 llength++;
232 }
233 *ptr = '\0'; /* make lint happier */
234
235 if (feof (datei))
236 break;
237
238 /* read next line */
239 curpos = ftell (datei);
240 if (_FP_fgets (uugen_inbuffer, 255, datei) == NULL)
241 break;
242 uugen_inbuffer[255] = '\0';
243
244 if (IsLineEmpty (uugen_inbuffer)) { /* oops */
245 fseek (datei, curpos, SEEK_SET);
246 break;
247 }
248
249 _FP_strncpy (ptr, uugen_inbuffer, 1024-llength);
250
251 /*
252 * see if line was terminated with CR. Otherwise, it continues ...
253 */
254 c = strlen (ptr);
255 if (c>0 && (ptr[c-1] == '\012' || ptr[c-1] == '\015'))
256 hadcr = 1;
257 else
258 hadcr = 0;
259
260 /*
261 * strip whitespace
262 */
263
264 ptr += c;
265 llength += c;
266 while (llength && isspace(*(ptr-1))) {
267 ptr--; llength--;
268 }
269 }
270
271 *ptr = '\0';
272
273 if (llength == 0)
274 return NULL;
275
276 /*
277 * Now that we've read the header line, we can RFC 1522-decode it
278 */
279
280 ptr = uuscan_shlline;
281 ptr2 = uuscan_shlline2;
282
283 while (*ptr) {
284 /*
285 * Look for =? magic
286 */
287
288 if (*ptr == '=' && *(ptr+1) == '?') {
289 /*
290 * Let p1 point to the charset, look for next question mark
291 */
292
293 p1 = p2 = ptr+2;
294
295 while (*p2 && *p2 != '?') {
296 p2++;
297 }
298
299 if (*p2 == '?' &&
300 (*(p2+1) == 'q' || *(p2+1) == 'Q' ||
301 *(p2+1) == 'b' || *(p2+1) == 'B') &&
302 *(p2+2) == '?') {
303 /*
304 * Let p2 point to the encoding, look for ?= magic
305 */
306
307 p2++;
308 p3=p2+2;
309
310 while (*p3 && (*p3 != '?' || *(p3+1) != '=')) {
311 p3++;
312 }
313
314 if (*p3 == '?' && *(p3+1) == '=') {
315 /*
316 * Alright, we've found an RFC 1522 header field
317 */
318 if (*p2 == 'q' || *p2 == 'Q') {
319 c = UUDecodeField (p2+2, ptr2, QP_ENCODED);
320 }
321 else if (*p2 == 'b' || *p2 == 'B') {
322 c = UUDecodeField (p2+2, ptr2, B64ENCODED);
323 }
324 if (c >= 0) {
325 ptr2 += c;
326 ptr = p3+2;
327 continue;
328 }
329 }
330 }
331 }
332
333 *ptr2++ = *ptr++;
334 }
335
336 *ptr2 = 0;
337
338 return uuscan_shlline2;
339 }
340
341 /*
342 * Extract the value from a MIME attribute=value pair. This function
343 * receives a pointer to the attribute.
344 */
345 static char *
346 ParseValue (char *attribute)
347 {
348 char *ptr=uuscan_pvvalue;
349 int length=0;
350
351 if (attribute == NULL)
352 return NULL;
353
354 while ((isalnum(*attribute) || *attribute=='_') && *attribute != '=')
355 attribute++;
356
357 while (isspace(*attribute))
358 attribute++;
359
360 if (*attribute == '=') {
361 attribute++;
362 while (isspace (*attribute))
363 attribute++;
364 }
365 else
366 return NULL;
367
368 if (*attribute == '"') {
369 /* quoted-string */
370 attribute++;
371 while (*attribute && *attribute != '"' && length < 255) {
372 if (*attribute == '\\'
373 && (attribute[1] == '"'
374 || attribute[1] == '\015'
375 || attribute[1] == '\\'))
376 /* we dequote only the three characters that MUST be quoted, since
377 * microsoft is obviously unable to correctly implement even mime headers:
378 * filename="c:\xxx". *sigh*
379 */
380 *ptr++ = *++attribute;
381 else
382 *ptr++ = *attribute;
383 attribute++;
384 length++;
385 }
386 *ptr = '\0';
387 }
388 else {
389 /* tspecials from RFC1521 */
390 /*
391 * Note - exclude '[', ']' and ';' on popular request; these are
392 * used in some Content-Type fields by the Klez virus, and people
393 * who feed their virus scanners with the output of UUDeview would
394 * like to catch it!
395 */
396
397 while (*attribute && !isspace (*attribute) &&
398 *attribute != '(' && *attribute != ')' &&
399 *attribute != '<' && *attribute != '>' &&
400 *attribute != '@' && *attribute != ',' &&
401 /* *attribute != ';' && */ *attribute != ':' &&
402 *attribute != '\\' &&*attribute != '"' &&
403 *attribute != '/' && /* *attribute != '[' &&
404 *attribute != ']' && */ *attribute != '?' &&
405 *attribute != '=' && length < 255)
406 *ptr++ = *attribute++;
407
408 *ptr = '\0';
409 }
410 return uuscan_pvvalue;
411 }
412
413 /*
414 * Extract the information we need from header fields
415 */
416
417 static headers *
418 ParseHeader (headers *theheaders, char *line)
419 {
420 char **variable=NULL;
421 char *value, *ptr, *thenew;
422 int delimit, length;
423
424 value = 0; delimit = 0; /* calm down gcc */
425
426 if (line == NULL)
427 return theheaders;
428
429 if (_FP_strnicmp (line, "From:", 5) == 0) {
430 if (theheaders->from) return theheaders;
431 variable = &theheaders->from;
432 value = line+5;
433 delimit = 0;
434 }
435 else if (_FP_strnicmp (line, "Subject:", 8) == 0) {
436 if (theheaders->subject) return theheaders;
437 variable = &theheaders->subject;
438 value = line+8;
439 delimit = 0;
440 }
441 else if (_FP_strnicmp (line, "To:", 3) == 0) {
442 if (theheaders->rcpt) return theheaders;
443 variable = &theheaders->rcpt;
444 value = line+3;
445 delimit = 0;
446 }
447 else if (_FP_strnicmp (line, "Date:", 5) == 0) {
448 if (theheaders->date) return theheaders;
449 variable = &theheaders->date;
450 value = line+5;
451 delimit = 0;
452 }
453 else if (_FP_strnicmp (line, "Mime-Version:", 13) == 0) {
454 if (theheaders->mimevers) return theheaders;
455 variable = &theheaders->mimevers;
456 value = line+13;
457 delimit = 0;
458 }
459 else if (_FP_strnicmp (line, "Content-Type:", 13) == 0) {
460 if (theheaders->ctype) return theheaders;
461 variable = &theheaders->ctype;
462 value = line+13;
463 delimit = ';';
464
465 /* we can probably extract more information */
466 if ((ptr = _FP_stristr (line, "boundary")) != NULL) {
467 if ((thenew = ParseValue (ptr))) {
468 if (theheaders->boundary) free (theheaders->boundary);
469 theheaders->boundary = _FP_strdup (thenew);
470 }
471 }
472 if ((ptr = _FP_stristr (line, "name")) != NULL) {
473 if ((thenew = ParseValue (ptr))) {
474 if (theheaders->fname) free (theheaders->fname);
475 theheaders->fname = _FP_strdup (thenew);
476 }
477 }
478 if ((ptr = _FP_stristr (line, "id")) != NULL) {
479 if ((thenew = ParseValue (ptr))) {
480 if (theheaders->mimeid) free (theheaders->mimeid);
481 theheaders->mimeid = _FP_strdup (thenew);
482 }
483 }
484 if ((ptr = _FP_stristr (line, "number")) != NULL) {
485 if ((thenew = ParseValue (ptr))) {
486 theheaders->partno = atoi (thenew);
487 }
488 }
489 if ((ptr = _FP_stristr (line, "total")) != NULL) {
490 if ((thenew = ParseValue (ptr))) {
491 theheaders->numparts = atoi (thenew);
492 }
493 }
494 }
495 else if (_FP_strnicmp (line, "Content-Transfer-Encoding:", 26) == 0) {
496 if (theheaders->ctenc) return theheaders;
497 variable = &theheaders->ctenc;
498 value = line+26;
499 delimit = ';';
500 }
501 else if (_FP_strnicmp (line, "Content-Disposition:", 20) == 0) {
502 /*
503 * Some encoders mention the original filename as parameter to
504 * Content-Type, others as parameter to Content-Disposition. We
505 * do prefer the first solution, but accept this situation, too.
506 * TODO: Read RFC1806
507 */
508 if ((ptr = _FP_stristr (line, "name")) != NULL) {
509 if (theheaders->fname == NULL && (thenew=ParseValue(ptr)) != NULL) {
510 theheaders->fname = _FP_strdup (thenew);
511 }
512 }
513 variable = NULL;
514 }
515 else {
516 /*
517 * nothing interesting
518 */
519 return theheaders;
520 }
521
522 /*
523 * okay, so extract the actual data
524 */
525 if (variable) {
526 length = 0;
527 ptr = uuscan_phtext;
528
529 while (isspace (*value))
530 value++;
531 while (*value && (delimit==0 || *value!=delimit) &&
532 *value != '\012' && *value != '\015' && length < 255) {
533 *ptr++ = *value++;
534 length++;
535 }
536 while (length && isspace(*(ptr-1))) {
537 ptr--; length--;
538 }
539 *ptr = '\0';
540
541 if ((*variable = _FP_strdup (uuscan_phtext)) == NULL)
542 return NULL;
543 }
544
545 return theheaders;
546 }
547
548 /*
549 * is this a header line we know about?
550 */
551
552 static int
553 IsKnownHeader (char *line)
554 {
555 char **iter = knownmsgheaders;
556
557 while (iter && *iter) {
558 if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
559 return 1;
560 iter++;
561 }
562
563 iter = knownmimeheaders;
564
565 while (iter && *iter) {
566 if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
567 return 2;
568 iter++;
569 }
570
571 return 0;
572 }
573
574 /*
575 * Scan a header
576 */
577
578 int
579 UUScanHeader (FILE *datei, headers *envelope)
580 {
581 char *ptr;
582
583 while (!feof (datei)) {
584 if ((ptr = ScanHeaderLine (datei, NULL)) == NULL)
585 break;
586 if (*ptr == '\0' || *ptr == '\012' || *ptr == '\015')
587 break;
588 ParseHeader (envelope, ptr);
589 }
590 return 0;
591 }
592
593 /*
594 * Scan something for encoded data and fill the fileread* structure.
595 * If boundary is non-NULL, we stop after having read it. If Check-
596 * Headers != 0, we also stop after we've found uu_headercount recog-
597 * nized header lines.
598 * If we have a boundary, then we also don't accept Base64; MIME mails
599 * really should handle this properly.
600 * We return -1 if something went wrong, 0 if everything is normal,
601 * 1 if we found a new header and 2 if we found a boundary.
602 * In MIME message bodies (not multiparts), we also disable our reduced
603 * MIME handling.
604 */
605
606 static int
607 ScanData (FILE *datei, char *fname, int *errcode,
608 char *boundary, int ismime, int checkheaders,
609 fileread *result)
610 {
611 char *line=uuscan_sdline, *bhds1=uuscan_sdbhds1, *bhds2=uuscan_sdbhds2;
612 static char *ptr, *p2, *p3=NULL, *bhdsp, bhl;
613 int islen[10], isb64[10], isuue[10], isxxe[10], isbhx[10], iscnt;
614 int cbb64, cbuue, cbxxe, cbbhx;
615 int bhflag=0, vflag, haddh=0, hadct=0;
616 int bhrpc=0, bhnf=0, c, hcount, lcount, blen=0;
617 int encoding=0, dflag=0, ctline=42;
618 int dontcare=0, hadnl=0;
619 long preheaders=0, oldposition;
620 long yefilesize=0, yepartends=0;
621 size_t dcc, bhopc;
622
623 blen = 0; preheaders = 0; /* calm down gcc */
624
625 *errcode = UURET_OK;
626 (void) UUDecodeLine (NULL, NULL, 0); /* init */
627 bhdsp = bhds2;
628
629 if (datei == NULL || feof (datei))
630 return -1;
631
632 result->startpos = ftell (datei);
633 hcount = lcount = 0;
634
635 for (iscnt=0; iscnt<10; iscnt++) {
636 isb64[iscnt] = isuue[iscnt] = isxxe[iscnt] = isbhx[iscnt] = 0;
637 islen[iscnt] = -1;
638 }
639
640 iscnt = 0;
641
642 if (boundary)
643 blen = strlen (boundary);
644
645 while (!feof (datei)) {
646 oldposition = ftell (datei);
647 if (_FP_fgets (line, 299, datei) == NULL)
648 break;
649 if (ferror (datei))
650 break;
651
652 line[299] = '\0'; /* For Safety of string functions */
653
654 /*
655 * Make Busy Polls
656 */
657
658 if (UUBUSYPOLL(ftell(datei),progress.fsize)) {
659 UUMessage (uuscan_id, __LINE__, UUMSG_NOTE,
660 uustring (S_SCAN_CANCEL));
661 *errcode = UURET_CANCEL;
662 break;
663 }
664
665 if (IsLineEmpty (line)) { /* line empty? */
666 hcount = 0;
667 hadnl = 1;
668 continue; /* then ignore */
669 }
670
671 if (checkheaders) {
672 if (IsKnownHeader (line)) {
673 (void) ScanHeaderLine (datei, line);
674
675 if (hcount == 0) {
676 preheaders = oldposition;
677 lcount = 0;
678 }
679 hcount++;
680 lcount++;
681
682 /*
683 * check for the various restart counters
684 */
685
686 if ((hcount >= hlcount.restart) ||
687 (hcount >= hlcount.afterdata && ismime == 0) ||
688 (hcount >= hlcount.afterdata && result->uudet) ||
689 (hcount >= hlcount.afternl && result->uudet && hadnl)) {
690 /*
691 * Hey, a new header starts here
692 */
693 fseek (datei, preheaders, SEEK_SET);
694 break;
695 }
696 /* continue; */
697 }
698 else if (lcount > WAITHEADER) {
699 hcount = 0;
700 lcount = 0;
701 dontcare=0;
702 }
703 else if (hcount) {
704 lcount++;
705 dontcare=1;
706 }
707 else {
708 dontcare=0;
709 }
710 }
711 else {
712 dontcare=0;
713 }
714
715 if (boundary != NULL &&
716 line[0] == '-' && line[1] == '-' &&
717 strncmp (line+2, boundary, blen) == 0) {
718 fseek (datei, oldposition, SEEK_SET);
719 break;
720 }
721 if (boundary != NULL && line[0] == 'C' && line[1] == 'o' &&
722 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
723 ptr = ScanHeaderLine (datei, line);
724 p2 = (ptr)?_FP_stristr(ptr,"boundary"):NULL;
725 p3 = (p2)?ParseValue(p2):NULL;
726
727 if (p3 && strcmp (p3, boundary) == 0) {
728 fseek (datei, oldposition, SEEK_SET);
729 break;
730 }
731 else {
732 p3 = NULL;
733 }
734 }
735
736 if (strncmp (line, "begin ", 6) == 0 ||
737 _FP_strnicmp (line, "<pre>begin ", 11) == 0) {
738 if ((result->begin || result->end ||
739 result->uudet == B64ENCODED ||
740 result->uudet == BH_ENCODED) && !uu_more_mime) {
741 fseek (datei, oldposition, SEEK_SET);
742 break;
743 }
744
745 if (*line == '<')
746 ptr = line + 10;
747 else
748 ptr = line + 5;
749
750 while (*ptr == ' ') ptr++;
751 while (isdigit (*ptr))
752 result->mode = result->mode * 8 + *ptr++ - '0';
753 while (*ptr == ' ') ptr++;
754
755 /*
756 * We may have picked up a filename from a uuenview-style header
757 */
758 _FP_free (result->filename);
759 result->filename = _FP_strdup (ptr);
760 result->begin = 1;
761
762 while (isspace (result->filename[strlen(result->filename)-1]))
763 result->filename[strlen(result->filename)-1] = '\0';
764
765 continue;
766 }
767
768 if ((strncmp (line, "end", 3) == 0) &&
769 result->uudet != BH_ENCODED &&
770 result->uudet != YENC_ENCODED) {
771 if (result->uudet == B64ENCODED && result->begin)
772 result->uudet = XX_ENCODED;
773
774 if (result->uudet != B64ENCODED) {
775 result->end = 1;
776 if (dflag && encoding)
777 result->uudet = encoding;
778 continue;
779 }
780 }
781
782 hadnl = 0;
783
784 /*
785 * Detect a UUDeview-Style header
786 */
787
788 if (_FP_strnicmp (line, "_=_ Part ", 9) == 0 &&
789 result->uudet != YENC_ENCODED) {
790 if (result->uudet) {
791 fseek (datei, oldposition, SEEK_SET);
792 break;
793 }
794 result->partno = atoi (line + 8);
795 if ((ptr = _FP_stristr (line, "of file ")) != NULL) {
796 ptr += 8;
797 while (isspace (*ptr)) ptr++;
798 p2 = ptr;
799 while (isalnum(*p2) ||
800 *p2 == '.' || *p2=='_' || *p2 == '-' ||
801 *p2 == '!' || *p2=='@' || *p2 == '$')
802 p2++;
803 c = *p2; *p2 = '\0';
804 if (p2 != ptr && result->filename == NULL)
805 result->filename = _FP_strdup (ptr);
806 else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL) {
807 /*
808 * This file name looks good, too. Let's use it
809 */
810 _FP_free (result->filename);
811 result->filename = _FP_strdup (ptr);
812 }
813 *p2 = c;
814 }
815 }
816
817 /*
818 * Some reduced MIME handling. Only use if boundary == NULL. Also
819 * accept the "X-Orcl-Content-Type" used by some braindead program.
820 */
821 if (boundary == NULL && !ismime && !uu_more_mime &&
822 result->uudet != YENC_ENCODED) {
823 if (_FP_strnicmp (line, "Content-Type", 12) == 0 ||
824 _FP_strnicmp (line, "X-Orcl-Content-Type", 19) == 0) {
825 /*
826 * We use Content-Type to mark a new attachment and split the file.
827 * However, we do not split if we haven't found anything encoded yet.
828 */
829 if (result->uudet) {
830 fseek (datei, oldposition, SEEK_SET);
831 break;
832 }
833 if ((ptr = strchr (line, ':')) != NULL) {
834 ptr++;
835 while (isspace (*ptr)) ptr++; p2 = ptr;
836 while (!isspace (*p2) && *p2 != ';') p2++;
837 c = *p2; *p2 = '\0';
838 if (p2 != ptr) {
839 _FP_free (result->mimetype);
840 result->mimetype = _FP_strdup (ptr);
841 }
842 *p2 = c;
843 }
844 ctline=0;
845 hadct=1;
846 }
847 if ((ptr = _FP_stristr (line, "number=")) && ctline<4) {
848 ptr += 7; if (*ptr == '"') ptr++;
849 result->partno = atoi (ptr);
850 }
851 if ((ptr = _FP_stristr (line, "total=")) && ctline<4) {
852 ptr += 6; if (*ptr == '"') ptr++;
853 result->maxpno = atoi (ptr);
854 }
855 if ((ptr = _FP_stristr (line, "name=")) && ctline<4) {
856 ptr += 5;
857 while (isspace (*ptr)) ptr++;
858 if (*ptr == '"' && *(ptr+1) && (p2 = strchr (ptr+2, '"')) != NULL) {
859 c = *p2; *p2 = '\0';
860 _FP_free (result->filename);
861 result->filename = _FP_strdup (ptr+1);
862 *p2 = c;
863 }
864 else if (*ptr=='\''&&*(ptr+1)&&(p2 = strchr(ptr+2, '\'')) != NULL) {
865 c = *p2; *p2 = '\0';
866 _FP_free (result->filename);
867 result->filename = _FP_strdup (ptr+1);
868 *p2 = c;
869 }
870 else {
871 p2 = ptr;
872 while (isalnum(*p2) ||
873 *p2 == '.' || *p2=='_' || *p2 == '-' ||
874 *p2 == '!' || *p2=='@' || *p2 == '$')
875 p2++;
876 c = *p2; *p2 = '\0';
877 if (p2 != ptr && result->filename == NULL)
878 result->filename = _FP_strdup (ptr);
879 else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL) {
880 /*
881 * This file name looks good, too. Let's use it
882 */
883 _FP_free (result->filename);
884 result->filename = _FP_strdup (ptr);
885 }
886 *p2 = c;
887 }
888 }
889 if ((ptr = _FP_stristr (line, "id=")) && ctline<4) {
890 p2 = ptr += 3;
891 if (*p2 == '"') {
892 p2 = strchr (++ptr, '"');
893 }
894 else {
895 while (*p2 && isprint(*p2) && !isspace(*p2) && *p2 != ';')
896 p2++;
897 }
898 if (p2 && *p2 && p2!=ptr) {
899 c = *p2; *p2 = '\0';
900 if (result->mimeid)
901 _FP_free (result->mimeid);
902 result->mimeid = _FP_strdup (ptr);
903 *p2 = c;
904 }
905 }
906
907 /*
908 * Handling for very short Base64 files.
909 */
910 if (uu_tinyb64 && !ismime && !uu_more_mime) {
911 if (line[0] == '-' && line[1] == '-') {
912 if (dflag && (encoding==B64ENCODED || result->uudet==B64ENCODED)) {
913 if (encoding==B64ENCODED && result->uudet==0 && (haddh||hadct)) {
914 result->uudet = encoding;
915 encoding = dflag = 0;
916 }
917 haddh = 1;
918 continue;
919 }
920 hadct = 0;
921 }
922 }
923 } /* end of reduced MIME handling */
924
925 /*
926 * If we're in "freestyle" mode, have not encountered anything
927 * interesting yet, and stumble upon something that looks like
928 * a boundary, followed by a Content-* line, try to use it.
929 */
930
931 if (boundary == NULL && !ismime && !uu_more_mime && dflag <= 1 &&
932 line[0] == '-' && line[1] == '-' && strlen(line+2)>10 &&
933 (((ptr = _FP_strrstr (line+2, "--")) == NULL) ||
934 (*(ptr+2) != '\012' && *(ptr+2) != '\015')) &&
935 _FP_strstr (line+2, "_=_") != NULL) {
936 if (_FP_fgets (line, 255, datei) == NULL) {
937 break;
938 }
939 if (_FP_strnicmp (line, "Content-", 8) == 0) {
940 /*
941 * Okay, let's do it. This breaks out of ScanData. ScanPart will
942 * recognize the boundary on the next call and use it.
943 */
944 fseek (datei, oldposition, SEEK_SET);
945 break;
946 }
947 }
948
949 /*
950 * Detection for yEnc encoding
951 */
952
953 if (strncmp (line, "=ybegin ", 8) == 0 &&
954 _FP_strstr (line, " name=") != NULL) {
955 if ((result->begin || result->end || result->uudet) && !uu_more_mime) {
956 fseek (datei, oldposition, SEEK_SET);
957 break;
958 }
959
960 /*
961 * name continues to the end of the line
962 */
963
964 _FP_free (result->filename);
965 ptr = _FP_strstr (line, " name=") + 6;
966 result->filename = _FP_strdup (ptr);
967
968 while (isspace (result->filename[strlen(result->filename)-1]))
969 result->filename[strlen(result->filename)-1] = '\0';
970
971 /*
972 * Determine size
973 */
974
975 if ((ptr = _FP_strstr (line, " size=")) != NULL) {
976 ptr += 6;
977 yefilesize = atoi (ptr);
978 }
979 else {
980 yefilesize = -1;
981 }
982
983 /*
984 * check for multipart file and read =ypart line
985 */
986
987 if ((ptr = _FP_strstr (line, " part=")) != NULL) {
988 result->partno = atoi (ptr + 6);
989
990 if (result->partno == 1) {
991 result->begin = 1;
992 }
993
994 if (_FP_fgets (line, 255, datei) == NULL) {
995 break;
996 }
997
998 line[255] = '\0';
999
1000 if (strncmp (line, "=ypart ", 7) != 0) {
1001 break;
1002 }
1003
1004 if ((ptr = _FP_strstr (line, " end=")) == NULL) {
1005 break;
1006 }
1007
1008 yepartends = atoi (ptr + 5);
1009 }
1010 else {
1011 result->partno = 1;
1012 result->begin = 1;
1013 }
1014
1015 /*
1016 * Don't want auto-detection
1017 */
1018
1019 result->uudet = YENC_ENCODED;
1020 continue;
1021 }
1022
1023 if (strncmp (line, "=yend ", 6) == 0 &&
1024 result->uudet == YENC_ENCODED) {
1025 if (yepartends == 0 || yepartends >= yefilesize) {
1026 result->end = 1;
1027 }
1028 #if 0
1029 if (!uu_more_mime)
1030 break;
1031 #endif
1032 continue;
1033 }
1034
1035 /*
1036 * if we haven't yet found anything encoded, try to find something
1037 */
1038
1039 if (!(result->uudet)) {
1040 /*
1041 * Netscape-Repair code is the same as in uunconc.c
1042 */
1043
1044 if ((vflag = UUValidData (line, 0, &bhflag)) == 0 && !ismime)
1045 vflag = UURepairData (datei, line, 0, &bhflag);
1046
1047 /*
1048 * Check data against all possible encodings
1049 */
1050
1051 islen[iscnt%10] = strlen(line);
1052 isb64[iscnt%10] = (UUValidData (line, B64ENCODED, &bhflag)==B64ENCODED);
1053 isuue[iscnt%10] = (UUValidData (line, UU_ENCODED, &bhflag)==UU_ENCODED);
1054 isxxe[iscnt%10] = (UUValidData (line, XX_ENCODED, &bhflag)==XX_ENCODED);
1055 isbhx[iscnt%10] = (UUValidData (line, BH_ENCODED, &bhflag)==BH_ENCODED);
1056
1057 /*
1058 * If we've got a first valid encoded line, we get suspicious if
1059 * it's shorter than, say, 40 characters.
1060 */
1061
1062 if (vflag == B64ENCODED &&
1063 (dflag == 0 || encoding != B64ENCODED) &&
1064 strlen (line) < 40 && !result->begin && !uu_tinyb64) {
1065 isb64[iscnt%10] = 0;
1066 vflag = 0;
1067 }
1068
1069 if ((vflag == UU_ENCODED || vflag == XX_ENCODED) &&
1070 (dflag == 0 || encoding != vflag) &&
1071 strlen (line) < 40 && !result->begin) {
1072 isuue[iscnt%10] = isxxe[iscnt%10] = 0;
1073 vflag = 0;
1074 }
1075
1076 iscnt++;
1077
1078 /*
1079 * Ah, so we got an encoded line? How interesting!
1080 */
1081
1082 if (vflag) {
1083 /*
1084 * For BinHex data, we can use the initial colon ':' as begin
1085 * and the terminating colon as ':'.
1086 * If (vflag && !bhflag), this is the last line,
1087 */
1088 if (vflag == BH_ENCODED) {
1089 if (line[0] == ':' && result->end) {
1090 fseek (datei, oldposition, SEEK_SET);
1091 break;
1092 }
1093 if (line[0] == ':')
1094 result->begin = 1;
1095 if (bhflag == 0) {
1096 result->uudet = BH_ENCODED;
1097 result->end = 1;
1098 }
1099 }
1100 /*
1101 * For BinHex files, the file name is encoded in the first encoded
1102 * data bytes. We try to extract it here
1103 */
1104 if (vflag == BH_ENCODED && bhnf == 0 && result->filename == NULL) {
1105 if (bhdsp == bhds2 ||
1106 ((bhdsp-bhds2) <= (int) bhds2[0] &&
1107 (bhdsp-bhds2) < 256)) {
1108 dcc = UUDecodeLine (line, bhds1, BH_ENCODED);
1109 UUbhdecomp (bhds1, bhdsp, &bhl, &bhrpc,
1110 dcc, 256-(bhdsp-bhds2), &bhopc);
1111 bhdsp += bhopc;
1112 }
1113 if ((bhdsp-bhds2) > (int) bhds2[0] && bhds2[0]>0 &&
1114 result->filename==NULL) {
1115 memcpy (bhds1, bhds2+1, (int) bhds2[0]);
1116 bhds1[(int)bhds2[0]]='\0';
1117 result->filename = _FP_strdup (bhds1);
1118 bhnf = 1;
1119 }
1120 else if (bhdsp-bhds2 >= 256 && bhds2[0]>0) {
1121 memcpy (bhds1, bhds2+1, 255);
1122 bhds1[255] = '\0';
1123 result->filename = _FP_strdup (bhds1);
1124 bhnf = 1;
1125 }
1126 else if (bhds2[0] <= 0)
1127 bhnf = 1;
1128 }
1129
1130 /*
1131 * We accept an encoding if it has been true for four consecutive
1132 * lines. Check the is<enc> arrays to avoid mistaking one encoding
1133 * for the other. Uuencoded data is rather easily mistaken for
1134 * Base 64. If the data matches more than one encoding, we need to
1135 * scan further.
1136 *
1137 * Since text can also rather easily be mistaken for UUencoded
1138 * data if it just happens to have 4 lines in a row that have the
1139 * correct first character for the length of the line, we also add
1140 * a check that the first 3 lines must be the same length, and the
1141 * 4th line must be less than or equal to that length. (since
1142 * uuencoders use the same length for all lines except the last,
1143 * this shouldn't increase the minimum size of UUdata we can
1144 * detect, as it would if we tested all 4 lines for being the same
1145 * length.) - Matthew Mueller, 20030109
1146 */
1147
1148 if (iscnt > 3) {
1149 cbb64 = (isb64[(iscnt-1)%10] && isb64[(iscnt-2)%10] &&
1150 isb64[(iscnt-3)%10] && isb64[(iscnt-4)%10]);
1151 cbuue = (isuue[(iscnt-1)%10] && isuue[(iscnt-2)%10] &&
1152 isuue[(iscnt-3)%10] && isuue[(iscnt-4)%10] &&
1153 islen[(iscnt-1)%10] <= islen[(iscnt-2)%10] &&
1154 islen[(iscnt-2)%10] == islen[(iscnt-3)%10] &&
1155 islen[(iscnt-3)%10] == islen[(iscnt-4)%10]);
1156 cbxxe = (isxxe[(iscnt-1)%10] && isxxe[(iscnt-2)%10] &&
1157 isxxe[(iscnt-3)%10] && isxxe[(iscnt-4)%10] &&
1158 islen[(iscnt-1)%10] <= islen[(iscnt-2)%10] &&
1159 islen[(iscnt-2)%10] == islen[(iscnt-3)%10] &&
1160 islen[(iscnt-3)%10] == islen[(iscnt-4)%10]);
1161 cbbhx = (isbhx[(iscnt-1)%10] && isbhx[(iscnt-2)%10] &&
1162 isbhx[(iscnt-3)%10] && isbhx[(iscnt-4)%10]);
1163 }
1164 else {
1165 cbb64 = cbuue = cbxxe = cbbhx = 0;
1166 }
1167
1168 if (cbb64 && !cbuue && !cbxxe && !cbbhx) {
1169 result->uudet = B64ENCODED;
1170 }
1171 else if (!cbb64 && cbuue && !cbxxe && !cbbhx) {
1172 result->uudet = UU_ENCODED;
1173 }
1174 else if (!cbb64 && !cbuue && cbxxe && !cbbhx) {
1175 result->uudet = XX_ENCODED;
1176 }
1177 else if (!cbb64 && !cbuue && !cbxxe && cbbhx) {
1178 result->uudet = BH_ENCODED;
1179 }
1180
1181 if (result->uudet) {
1182 encoding = dflag = 0;
1183
1184 /*
1185 * If we're in fast mode, we're told we don't have to look
1186 * for anything below, so we can as well break out of every-
1187 * thing
1188 * We cannot fast-scan if we have a boundary to look after.
1189 */
1190
1191 if (uu_fast_scanning && boundary == NULL)
1192 break;
1193
1194 /*
1195 * Skip the encoded data. We simply wait for a boundary, for
1196 * a header or for an empty line. But we also try to pick up
1197 * an "end"
1198 */
1199
1200 hcount = lcount = 0;
1201
1202 while (!feof (datei)) {
1203 /*
1204 * Make Busy Polls
1205 */
1206 if (UUBUSYPOLL(ftell(datei),progress.fsize)) {
1207 UUMessage (uuscan_id, __LINE__, UUMSG_NOTE,
1208 uustring (S_SCAN_CANCEL));
1209 *errcode = UURET_CANCEL;
1210 break;
1211 }
1212
1213 oldposition = ftell (datei);
1214 if (_FP_fgets (line, 255, datei) == NULL)
1215 break;
1216 if (ferror (datei))
1217 break;
1218
1219 line[255] = '\0';
1220
1221 /*
1222 * Stop scanning at an empty line or a MIME-boundary.
1223 */
1224 if (IsLineEmpty (line))
1225 break;
1226 if (boundary && line[0] == '-' && line[1] == '-' &&
1227 strncmp (line+2, boundary, blen) == 0) {
1228 fseek (datei, oldposition, SEEK_SET);
1229 break;
1230 }
1231 else if (line[0] == 'e' && (result->uudet == UU_ENCODED ||
1232 result->uudet == XX_ENCODED)) {
1233 if (strncmp (line, "end", 3) == 0) {
1234 result->end = 1;
1235 break;
1236 }
1237 }
1238 else if (line[0] == 'b') {
1239 if (strncmp (line, "begin ", 6) == 0) {
1240 fseek (datei, oldposition, SEEK_SET);
1241 break;
1242 }
1243 }
1244
1245 if (checkheaders) {
1246 if (IsKnownHeader (line)) {
1247 (void) ScanHeaderLine (datei, line);
1248 if (hcount == 0)
1249 preheaders = oldposition;
1250 hcount++;
1251 lcount++;
1252 if ((hcount >= hlcount.restart) ||
1253 (hcount >= hlcount.afterdata && result->uudet)) {
1254 /*
1255 * Hey, a new header starts here
1256 */
1257 fseek (datei, preheaders, SEEK_SET);
1258 break;
1259 }
1260 }
1261 else if (lcount > WAITHEADER) {
1262 hcount = 0;
1263 lcount = 0;
1264 }
1265 else if (hcount) {
1266 lcount++;
1267 }
1268 }
1269 if (result->uudet == BH_ENCODED) {
1270 /* pick up ``EOF'' for BinHex files. Slow :-< */
1271 if (line[0] && strchr (line+1, ':') != NULL) {
1272 result->end = 1;
1273 bhflag = 0;
1274 break;
1275 }
1276 }
1277 }
1278
1279 if (ferror (datei) || *errcode == UURET_CANCEL)
1280 break;
1281
1282 if (line[0] == '-' && line[1] == '-')
1283 haddh = 1;
1284
1285 /*
1286 * Okay, got everything we need. If we had headers or a
1287 * boundary, we break out of the outer loop immediately.
1288 */
1289
1290 if (IsKnownHeader (line) ||
1291 (boundary && line[0] == '-' && line[1] == '-' &&
1292 strncmp (line+2, boundary, blen) == 0)) {
1293 break;
1294 }
1295
1296 /*
1297 * Otherwise, we wait until finding something more interesting
1298 * in the outer loop
1299 */
1300
1301 continue;
1302 }
1303
1304 /*
1305 * Select the encoding with the best "history"
1306 */
1307
1308 cbb64 = isb64[(iscnt-1)%10];
1309 cbuue = isuue[(iscnt-1)%10];
1310 cbxxe = isxxe[(iscnt-1)%10];
1311 cbbhx = isbhx[(iscnt-1)%10];
1312 dflag = 0;
1313
1314 if (cbb64 || cbuue || cbxxe || cbbhx) {
1315 for (dflag=2; dflag<iscnt && dflag<4; dflag++) {
1316 if ((!cbb64 || !isb64[(iscnt-dflag)%10]) &&
1317 (!cbuue || !isuue[(iscnt-dflag)%10]) &&
1318 (!cbxxe || !isxxe[(iscnt-dflag)%10]) &&
1319 (!cbbhx || !isbhx[(iscnt-dflag)%10])) {
1320 dflag--;
1321 break;
1322 }
1323 cbb64 &= isb64[(iscnt-dflag)%10];
1324 cbuue &= isuue[(iscnt-dflag)%10];
1325 cbxxe &= isxxe[(iscnt-dflag)%10];
1326 cbbhx &= isbhx[(iscnt-dflag)%10];
1327 }
1328 }
1329
1330 /*
1331 * clear-cut cases
1332 */
1333
1334 if (cbb64 && !cbuue && !cbxxe && !cbbhx) {
1335 encoding = B64ENCODED;
1336 }
1337 else if (!cbb64 && cbuue && !cbxxe && !cbbhx) {
1338 encoding = UU_ENCODED;
1339 }
1340 else if (!cbb64 && !cbuue && cbxxe && !cbbhx) {
1341 encoding = XX_ENCODED;
1342 }
1343 else if (!cbb64 && !cbuue && !cbxxe && cbbhx) {
1344 encoding = BH_ENCODED;
1345 }
1346 else {
1347 encoding = 0;
1348 }
1349
1350 /*
1351 * Check a few common non-clear-cut cases
1352 */
1353
1354 if (!encoding && cbuue && result->begin) {
1355 encoding = UU_ENCODED;
1356 }
1357 else if (!encoding && cbxxe && result->begin) {
1358 encoding = XX_ENCODED;
1359 }
1360 else if (!encoding && cbb64) {
1361 encoding = B64ENCODED;
1362 }
1363 else if (!encoding && cbuue) {
1364 encoding = UU_ENCODED;
1365 }
1366 else if (!encoding && cbxxe) {
1367 encoding = XX_ENCODED;
1368 }
1369 else if (!encoding && cbbhx) {
1370 encoding = BH_ENCODED;
1371 }
1372 }
1373 else if (!dontcare) {
1374 encoding = 0;
1375 dflag = 0;
1376 haddh = 0;
1377 }
1378 } /* if (!uudet) */
1379 /*
1380 * End of scanning loop
1381 */
1382 } /* while (!feof (datei)) */
1383
1384 if (feof (datei))
1385 oldposition = ftell (datei);
1386
1387 if (dflag && encoding == B64ENCODED && haddh)
1388 result->uudet = B64ENCODED;
1389 else if (dflag && encoding == BH_ENCODED)
1390 result->uudet = BH_ENCODED;
1391
1392 /* Base64 doesn't have begin or end, so it was probably XX */
1393 if (result->uudet == B64ENCODED && result->begin && result->end)
1394 result->uudet = XX_ENCODED;
1395
1396 /* Base64 doesn't have begin or end */
1397 if (result->uudet == B64ENCODED)
1398 result->begin = result->end = 0;
1399
1400 /* Base64 and BinHex don't have a file mode */
1401 if (result->uudet == B64ENCODED || result->uudet == BH_ENCODED ||
1402 result->uudet == YENC_ENCODED)
1403 result->mode = 6*64+4*8+4;
1404
1405 /*
1406 * When strict MIME adherance is set, throw out suspicious attachments
1407 */
1408
1409 if (uu_more_mime) {
1410 /*
1411 * In a MIME message, Base64 should be appropriately tagged
1412 */
1413
1414 if (result->uudet == B64ENCODED) {
1415 result->uudet = 0;
1416 }
1417
1418 /*
1419 * Do not accept incomplete UU or XX encoded messages
1420 */
1421
1422 if ((result->uudet != 0 && result->uudet != B64ENCODED) &&
1423 (!result->begin || !result->end)) {
1424 result->uudet = 0;
1425 }
1426 }
1427
1428 /*
1429 * In fast mode, this length will yield a false value. We don't care.
1430 * This must be checked for in uunconc(), where we usually stop decoding
1431 * after reaching startpos+length
1432 */
1433
1434 if (uu_fast_scanning)
1435 result->length = progress.fsize-result->startpos;
1436 else
1437 result->length = ftell(datei)-result->startpos;
1438
1439 if (ferror (datei)) {
1440 *errcode = UURET_IOERR;
1441 uu_errno = errno;
1442 return -1;
1443 }
1444 if (*errcode != UURET_OK) {
1445 return -1;
1446 }
1447
1448 if (boundary && line[0] == '-' && line[1] == '-' &&
1449 strncmp (line+2, boundary, blen) == 0)
1450 return 2;
1451 else if (boundary && p3 &&
1452 line[0] == 'C' && line[1] == 'o' &&
1453 _FP_strnicmp (line, "Content-Type:", 13) == 0 &&
1454 strcmp (p3, boundary) == 0)
1455 return 2;
1456 else if (IsKnownHeader (line))
1457 return 1;
1458
1459 return 0;
1460 }
1461
1462 /*
1463 * This is the main scanning function.
1464 */
1465
1466 fileread *
1467 ScanPart (FILE *datei, char *fname, int *errcode)
1468 {
1469 int ecount, hcount, lcount;
1470 int bhflag, begflag, vflag, blen=0, res;
1471 long preheaders, prevpos=0, preenc, before;
1472 char *line=uuscan_spline;
1473 fileread *result;
1474 char *ptr1, *ptr2;
1475
1476 blen = 0; prevpos = 0; /* calm down gcc */
1477
1478 (void) UUDecodeLine (NULL, NULL, 0); /* init */
1479 if (datei == NULL || feof (datei)) {
1480 *errcode = UURET_OK;
1481 return NULL;
1482 }
1483
1484 *errcode = UURET_OK;
1485
1486 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
1487 *errcode = UURET_NOMEM;
1488 return NULL;
1489 }
1490 memset (result, 0, sizeof (fileread));
1491 result->startpos = ftell (datei);
1492 preheaders = result->startpos;
1493 before = result->startpos;
1494
1495 /* if this is a new file, reset our scanning state */
1496 if (sstate.source == NULL || strcmp (fname, sstate.source) != 0) {
1497 sstate.isfolder = 1; /* assume yes */
1498 sstate.ismime = 0; /* wait for MIME-Version */
1499 sstate.mimestate = MS_HEADERS; /* assume headers follow */
1500 /* mimseqno = 1; */
1501
1502 while (mssdepth) {
1503 mssdepth--;
1504 UUkillheaders (&(multistack[mssdepth].envelope));
1505 _FP_free (multistack[mssdepth].source);
1506 }
1507
1508 UUkillheaders (&sstate.envelope);
1509 memset (&sstate.envelope, 0, sizeof (headers));
1510
1511 _FP_free (sstate.source);
1512 if ((sstate.source = _FP_strdup (fname)) == NULL) {
1513 *errcode = UURET_NOMEM;
1514 _FP_free (result);
1515 return NULL;
1516 }
1517
1518 /* ignore empty lines at the beginning of a file */
1519 preheaders = ftell (datei);
1520 while (!feof (datei)) {
1521 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1522 if (_FP_fgets (line, 255, datei) == NULL)
1523 break;
1524 line[255] = '\0';
1525 if (!IsLineEmpty (line)) {
1526 fseek (datei, preheaders, SEEK_SET);
1527 break;
1528 }
1529 preheaders = ftell (datei);
1530 }
1531 }
1532
1533 if (ferror(datei) || feof(datei)) {
1534 _FP_free (result);
1535 return NULL;
1536 }
1537
1538 /*
1539 * If we are confident that this is a mail folder and are at the
1540 * beginning of the file, expecting to read some headers, scan
1541 * the envelope.
1542 */
1543
1544 if (sstate.isfolder && sstate.mimestate == MS_HEADERS) {
1545 hcount = 0;
1546 lcount = 0;
1547 UUkillheaders (&sstate.envelope);
1548
1549 /*
1550 * clean up leftovers from invalid messages
1551 */
1552
1553 while (mssdepth) {
1554 mssdepth--;
1555 UUkillheaders (&(multistack[mssdepth].envelope));
1556 _FP_free (multistack[mssdepth].source);
1557 }
1558
1559 prevpos = ftell (datei);
1560 if (_FP_fgets (line, 255, datei) == NULL) {
1561 _FP_free (result);
1562 return NULL;
1563 }
1564 line[255] = '\0';
1565
1566 /*
1567 * Special handling for AOL folder files, which start off with a boundary.
1568 * We recognize them by a valid boundary line as the first line of a file.
1569 * Note that the rest of the scanning code becomes suspicious if a boun-
1570 * dary does never appear in a file -- this should save us from grave
1571 * false detection errors
1572 */
1573
1574 if (!feof (datei) && line[0] == '-' && line[1] == '-' && line[2]) {
1575 while (line[strlen(line)-1] == '\012' ||
1576 line[strlen(line)-1] == '\015') {
1577 line[strlen(line)-1] = '\0';
1578 }
1579
1580 sstate.ismime = 1;
1581 sstate.envelope.mimevers = _FP_strdup ("1.0");
1582 sstate.envelope.boundary = _FP_strdup (line+2);
1583 sstate.envelope.ctype = _FP_strdup ("multipart/mixed");
1584 sstate.mimestate = MS_SUBPART;
1585
1586 *errcode = UURET_CONT;
1587 _FP_free (result);
1588 return NULL;
1589 }
1590
1591 /*
1592 * Normal behavior: look for a RFC 822 header
1593 */
1594
1595 while (!feof (datei) && !IsLineEmpty (line)) {
1596 if (IsKnownHeader (line))
1597 hcount++;
1598 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1599 if (IsHeaderLine (line)) {
1600 ptr1 = ScanHeaderLine (datei, line);
1601 if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
1602 *errcode = UURET_NOMEM;
1603 _FP_free (result);
1604 return NULL;
1605 }
1606 }
1607 /*
1608 * if we've read too many lines without finding headers, then
1609 * this probably isn't a mail folder after all
1610 */
1611 lcount++;
1612 if (lcount > WAITHEADER && hcount < hlcount.afternl) {
1613 fseek (datei, prevpos, SEEK_SET);
1614 line[0] = '\0';
1615 break;
1616 }
1617
1618 if (_FP_fgets (line, 255, datei) == NULL)
1619 break;
1620 line[255] = '\0';
1621 }
1622
1623 /* skip empty lines */
1624 prevpos = ftell (datei);
1625 if (IsLineEmpty (line)) {
1626 while (!feof (datei)) {
1627 if (_FP_fgets (line, 255, datei) == NULL)
1628 break;
1629 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1630 if (!IsLineEmpty (line)) {
1631 fseek (datei, prevpos, SEEK_SET);
1632 line[255] = '\0';
1633 break;
1634 }
1635 prevpos = ftell (datei);
1636 }
1637 }
1638
1639 /*
1640 * If we don't have all valid MIME headers yet, but the following
1641 * line is a MIME header, accept it anyway.
1642 */
1643
1644 if (!uu_more_mime &&
1645 sstate.envelope.mimevers == NULL &&
1646 sstate.envelope.ctype == NULL &&
1647 sstate.envelope.ctenc == NULL &&
1648 IsKnownHeader (line)) {
1649 /*
1650 * see above
1651 */
1652 if (_FP_fgets (line, 255, datei) == NULL) {
1653 line[0] = '\012';
1654 line[1] = '\0';
1655 }
1656 line[255] = '\0';
1657
1658 while (!feof (datei) && !IsLineEmpty (line)) {
1659 if (IsKnownHeader (line))
1660 hcount++;
1661 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1662 ptr1 = ScanHeaderLine (datei, line);
1663 if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
1664 *errcode = UURET_NOMEM;
1665 _FP_free (result);
1666 return NULL;
1667 }
1668
1669 if (_FP_fgets (line, 255, datei) == NULL)
1670 break;
1671 line[255] = '\0';
1672 }
1673 /* skip empty lines */
1674 prevpos = ftell (datei);
1675 while (!feof (datei)) {
1676 if (_FP_fgets (line, 255, datei) == NULL)
1677 break;
1678 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1679 if (!IsLineEmpty (line)) {
1680 fseek (datei, prevpos, SEEK_SET);
1681 line[255] = '\0';
1682 break;
1683 }
1684 prevpos = ftell (datei);
1685 }
1686 }
1687
1688 /*
1689 * A partial multipart message probably has only a Content-Type
1690 * header but nothing else. In this case, at least simulate a
1691 * MIME message
1692 * if mimevers is not set but there are other well-known MIME
1693 * headers, don't be too picky about it.
1694 */
1695 if (sstate.envelope.ctype && sstate.envelope.mimevers==NULL &&
1696 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL &&
1697 sstate.envelope.boundary != NULL) {
1698 sstate.envelope.mimevers = _FP_strdup ("1.0");
1699 hcount = hlcount.afternl;
1700 }
1701 else if (sstate.envelope.mimevers==NULL && sstate.envelope.ctype &&
1702 sstate.envelope.fname && sstate.envelope.ctenc) {
1703 sstate.envelope.mimevers = _FP_strdup ("1.0");
1704 hcount = hlcount.afternl;
1705 }
1706
1707 if (sstate.envelope.mimevers != NULL) {
1708 /* this is a MIME file. check the Content-Type */
1709 sstate.ismime = 1;
1710 if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL) {
1711 if (sstate.envelope.boundary == NULL) {
1712 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1713 uustring (S_MIME_NO_BOUNDARY));
1714 sstate.mimestate = MS_BODY;
1715 _FP_free (sstate.envelope.ctype);
1716 sstate.envelope.ctype = _FP_strdup ("text/plain");
1717 }
1718 else {
1719 sstate.mimestate = MS_PREAMBLE;
1720 }
1721 }
1722 else {
1723 sstate.mimestate = MS_BODY; /* just a `simple' message */
1724 }
1725 }
1726 else {
1727 /* not a folder after all */
1728 fseek (datei, prevpos, SEEK_SET);
1729 sstate.isfolder = 0;
1730 sstate.ismime = 0;
1731 }
1732 }
1733
1734 if (feof (datei) || ferror (datei)) { /* oops */
1735 _FP_free (result);
1736 return NULL;
1737 }
1738
1739 /*
1740 * Handle MIME stuff
1741 */
1742
1743 /*
1744 * Read Preamble. This must be ended by a sstate.envelope.boundary line.
1745 * If uu_usepreamble is set, we produce a result from this one
1746 */
1747
1748 if (sstate.ismime && sstate.mimestate == MS_PREAMBLE) {
1749 result->startpos = ftell (datei); /* remember start of preamble */
1750 prevpos = ftell (datei);
1751 preheaders = ftell (datei);
1752
1753 blen = strlen (sstate.envelope.boundary);
1754 lcount = 0;
1755
1756 while (!feof (datei)) {
1757 if (_FP_fgets (line, 255, datei) == NULL) {
1758 line[0] = '\0';
1759 break;
1760 }
1761 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1762 if (line[0] == '-' && line[1] == '-' &&
1763 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
1764 break;
1765 if (!IsLineEmpty (line))
1766 lcount++;
1767
1768 prevpos = ftell (datei);
1769 }
1770 if (feof (datei) || ferror (datei)) {
1771 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1772 uustring (S_MIME_B_NOT_FOUND));
1773 /*
1774 * restart and try again; don't restart if uu_fast_scanning
1775 */
1776 sstate.isfolder = 0;
1777 sstate.ismime = 0;
1778 sstate.mimestate = MS_BODY;
1779
1780 if (!uu_fast_scanning) {
1781 *errcode = UURET_CONT;
1782 fseek (datei, preheaders, SEEK_SET);
1783 }
1784 _FP_free (result);
1785 return NULL;
1786 }
1787 if (line[0] == '-' && line[1] == '-' &&
1788 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
1789 ptr1 = line + 2 + blen;
1790 if (*ptr1 == '-' && *(ptr1+1) == '-') {
1791 /* Empty Multipart Message. Duh. */
1792 sstate.mimestate = MS_EPILOGUE;
1793 }
1794 else {
1795 sstate.mimestate = MS_SUBPART;
1796 }
1797 }
1798 else { /* shouldn't happen */
1799 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1800 uustring (S_MIME_B_NOT_FOUND));
1801 /*
1802 * restart and try again; don't restart if uu_fast_scanning
1803 */
1804 sstate.isfolder = 0;
1805 sstate.ismime = 0;
1806 sstate.mimestate = MS_BODY;
1807
1808 if (!uu_fast_scanning) {
1809 *errcode = UURET_CONT;
1810 fseek (datei, preheaders, SEEK_SET);
1811 }
1812 _FP_free (result);
1813 return NULL;
1814 }
1815 /* produce result if uu_usepreamble is set */
1816 if (uu_usepreamble && lcount) {
1817 sprintf (line, "%04d.txt", ++mimseqno);
1818 result->subject = _FP_strdup (sstate.envelope.subject);
1819 result->filename = _FP_strdup (line);
1820 result->origin = _FP_strdup (sstate.envelope.from);
1821 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
1822 result->mimetype = _FP_strdup ("text/plain");
1823 result->mode = 0644;
1824 result->uudet = PT_ENCODED; /* plain text */
1825 result->sfname = _FP_strdup (fname);
1826 result->flags = FL_SINGLE | FL_PROPER;
1827 /* result->startpos set from above */
1828 result->length = prevpos - result->startpos;
1829 result->partno = 1;
1830
1831 /* MIME message, let's continue */
1832 *errcode = UURET_CONT;
1833
1834 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
1835 result->filename == NULL || result->sfname == NULL) {
1836 *errcode = UURET_NOMEM;
1837 }
1838
1839 return result;
1840 }
1841 /* MIME message, let's continue */
1842 if (*errcode == UURET_OK)
1843 *errcode = UURET_CONT;
1844
1845 /* otherwise, just return NULL */
1846 _FP_free (result);
1847 return NULL;
1848 }
1849
1850 /*
1851 * Read Epilogue, the plain text after the last boundary.
1852 * This can either end with new headers from the next message of a
1853 * mail folder or with a `parent' boundary if we are inside an
1854 * encapsulated Multipart message. Oh yes, and of course the file
1855 * may also simply end :-)
1856 * Another possibility is that we might find plain encoded data
1857 * without encapsulating message. We're not _too_ flexible here,
1858 * we won't detect Base64, and require a proper `begin' line for
1859 * uuencoding and xxencoding
1860 * If uu_usepreamble is set, we produce a result from this one
1861 */
1862
1863 if (sstate.ismime && sstate.mimestate == MS_EPILOGUE) {
1864 result->startpos = ftell (datei); /* remember start of epilogue */
1865 prevpos = ftell (datei);
1866 preheaders = ftell (datei);
1867 preenc = ftell (datei);
1868 hcount = lcount = 0;
1869 ecount = bhflag = 0;
1870 begflag = vflag = 0;
1871 res = 0;
1872
1873 /*
1874 * If we are in the outermost message and uu_fast_scanning, we
1875 * know (or assume) that no more messages will follow, so there's
1876 * no need to scan the rest.
1877 */
1878 if (uu_fast_scanning && mssdepth == 0) {
1879 /*
1880 * check if the epilogue is empty
1881 */
1882 while (!feof (datei) && !ferror (datei) && lcount<10 && res==0) {
1883 if (_FP_fgets (line, 255, datei) == NULL)
1884 break;
1885 if (!IsLineEmpty (line))
1886 res++;
1887 lcount++;
1888 }
1889 if (uu_usepreamble && res) {
1890 sprintf (line, "%04d.txt", ++mimseqno);
1891 result->subject = _FP_strdup (sstate.envelope.subject);
1892 result->filename = _FP_strdup (line);
1893 result->origin = _FP_strdup (sstate.envelope.from);
1894 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
1895 result->mimetype = _FP_strdup ("text/plain");
1896 result->mode = 0644;
1897 result->uudet = PT_ENCODED; /* plain text */
1898 result->sfname = _FP_strdup (fname);
1899 result->flags = FL_SINGLE | FL_PROPER | FL_TOEND;
1900 result->partno = 1;
1901 /* result->startpos set from above */
1902 result->length = progress.fsize - result->startpos;
1903
1904 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
1905 result->filename == NULL || result->sfname == NULL) {
1906 *errcode = UURET_NOMEM;
1907 }
1908
1909 return result;
1910 }
1911 _FP_free (result);
1912 return NULL;
1913 }
1914
1915 if (mssdepth > 0)
1916 blen = strlen (multistack[mssdepth-1].envelope.boundary);
1917
1918 while (!feof (datei)) {
1919 if (_FP_fgets (line, 255, datei) == NULL) {
1920 line[0] = '\0';
1921 break;
1922 }
1923 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1924 line[255] = '\0';
1925 /* check for parent boundary */
1926 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
1927 strncmp (line+2,
1928 multistack[mssdepth-1].envelope.boundary, blen) == 0)
1929 break;
1930
1931 /* check for next headers only at outermost level */
1932 if (mssdepth == 0 && IsKnownHeader (line)) {
1933 (void) ScanHeaderLine (datei, line);
1934 if (hcount == 0) {
1935 preheaders = prevpos;
1936 lcount = 0;
1937 }
1938 hcount++;
1939 lcount++;
1940
1941 if (hcount >= hlcount.restart) {
1942 /* okay, new headers */
1943 break;
1944 }
1945 }
1946 else if (lcount > WAITHEADER) {
1947 hcount = 0;
1948 lcount = 0;
1949 }
1950 else if (hcount) {
1951 lcount++;
1952 }
1953 else {
1954 hcount = lcount = 0;
1955 }
1956
1957 /* check for begin and encoded data only at outermost level */
1958 if (mssdepth == 0 && !uu_more_mime) {
1959 if (strncmp (line, "begin ", 6) == 0 ||
1960 _FP_strnicmp (line, "<pre>begin ", 11) == 0) {
1961 preenc = prevpos;
1962 begflag = 1;
1963 }
1964 else if (strncmp (line, "end", 3) == 0 && begflag) {
1965 ecount = ELC_COUNT;
1966 break;
1967 }
1968 else if ((vflag = UUValidData (line, 0, &bhflag)) != 0) {
1969 if (vflag == BH_ENCODED && bhflag == 0) {
1970 /* very short BinHex file follows */
1971 preenc = prevpos;
1972 break;
1973 }
1974 /* remember that XX can easily be mistaken as Base64 */
1975 if ((vflag == UU_ENCODED || vflag == XX_ENCODED ||
1976 vflag == B64ENCODED) && begflag) {
1977 if (++ecount >= ELC_COUNT)
1978 break;
1979 }
1980 else {
1981 begflag = 0;
1982 ecount = 0;
1983 }
1984 }
1985 else {
1986 begflag = 0;
1987 ecount = 0;
1988 }
1989 }
1990
1991 if (!IsLineEmpty (line))
1992 res++;
1993
1994 prevpos = ftell (datei);
1995 }
1996
1997 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
1998 strncmp (line+2,
1999 multistack[mssdepth-1].envelope.boundary, blen) == 0) {
2000 /* restore previous state */
2001 mssdepth--;
2002 UUkillheaders (&sstate.envelope);
2003 _FP_free (sstate.source);
2004 memcpy (&sstate, &(multistack[mssdepth]), sizeof (scanstate));
2005
2006 ptr1 = line + 2 + strlen (sstate.envelope.boundary);
2007
2008 if (*ptr1 == '-' && *(ptr1+1) == '-') {
2009 sstate.mimestate = MS_EPILOGUE;
2010 }
2011 else {
2012 sstate.mimestate = MS_SUBPART;
2013 }
2014 result->length = prevpos - result->startpos;
2015 *errcode = UURET_CONT;
2016 }
2017 else if (mssdepth > 0) {
2018 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2019 uustring (S_MIME_B_NOT_FOUND));
2020 /*
2021 * restart and try again; don't restart if uu_fast_scanning
2022 */
2023 sstate.isfolder = 0;
2024 sstate.ismime = 0;
2025 sstate.mimestate = MS_BODY;
2026
2027 while (mssdepth) {
2028 mssdepth--;
2029 UUkillheaders (&(multistack[mssdepth].envelope));
2030 _FP_free (multistack[mssdepth].source);
2031 }
2032
2033 if (!uu_fast_scanning) {
2034 *errcode = UURET_CONT;
2035 fseek (datei, preheaders, SEEK_SET);
2036 }
2037 _FP_free (result);
2038 return NULL;
2039 }
2040 else if (IsKnownHeader (line)) {
2041 /* new message follows */
2042 sstate.isfolder = 1;
2043 sstate.ismime = 0;
2044 sstate.mimestate = MS_HEADERS;
2045 result->length = preheaders - result->startpos;
2046 fseek (datei, preheaders, SEEK_SET);
2047 }
2048 else if (ecount >= ELC_COUNT) {
2049 /* new plain encoding */
2050 sstate.isfolder = 0;
2051 sstate.ismime = 0;
2052 sstate.mimestate = MS_BODY;
2053 result->length = preenc - result->startpos;
2054 fseek (datei, preenc, SEEK_SET);
2055 }
2056
2057 /* produce result if uu_usepreamble is set */
2058 if (uu_usepreamble && res) {
2059 sprintf (line, "%04d.txt", ++mimseqno);
2060 result->subject = _FP_strdup (sstate.envelope.subject);
2061 result->filename = _FP_strdup (line);
2062 result->origin = _FP_strdup (sstate.envelope.from);
2063 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2064 result->mimetype = _FP_strdup ("text/plain");
2065 result->mode = 0644;
2066 result->uudet = PT_ENCODED; /* plain text */
2067 result->sfname = _FP_strdup (fname);
2068 result->flags = FL_SINGLE | FL_PROPER;
2069 result->partno = 1;
2070 /* result->startpos set from above */
2071 /* result->length set from above */
2072
2073 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
2074 result->filename == NULL || result->sfname == NULL) {
2075 *errcode = UURET_NOMEM;
2076 }
2077
2078 return result;
2079 }
2080 /* otherwise, just return NULL */
2081 _FP_free (result);
2082 return NULL;
2083 }
2084
2085 /*
2086 * Scan a new part from a Multipart message. Check for a new local
2087 * envelope (which defaults to `Content-Type: text/plain') and
2088 * evaluate its Content-Type and Content-Transfer-Encoding. If this
2089 * is another Multipart/something, push the current state onto our
2090 * stack and dive into the new environment, starting with another
2091 * preamble.
2092 */
2093
2094 if (sstate.ismime && sstate.mimestate == MS_SUBPART) {
2095 memset (&localenv, 0, sizeof (headers));
2096 result->startpos = ftell (datei);
2097 prevpos = ftell (datei);
2098 hcount = 0;
2099 lcount = 0;
2100
2101 /*
2102 * Duplicate some data from outer envelope
2103 */
2104
2105 localenv.mimevers = _FP_strdup (sstate.envelope.mimevers);
2106 localenv.from = _FP_strdup (sstate.envelope.from);
2107 localenv.subject = _FP_strdup (sstate.envelope.subject);
2108 localenv.rcpt = _FP_strdup (sstate.envelope.rcpt);
2109 localenv.date = _FP_strdup (sstate.envelope.date);
2110
2111 if ((sstate.envelope.mimevers != NULL && localenv.mimevers == NULL) ||
2112 (sstate.envelope.from != NULL && localenv.from == NULL) ||
2113 (sstate.envelope.subject != NULL && localenv.subject == NULL) ||
2114 (sstate.envelope.rcpt != NULL && localenv.rcpt == NULL) ||
2115 (sstate.envelope.date != NULL && localenv.date == NULL)) {
2116
2117 while (mssdepth) {
2118 mssdepth--;
2119 UUkillheaders (&(multistack[mssdepth].envelope));
2120 _FP_free (multistack[mssdepth].source);
2121 }
2122 sstate.isfolder = 0;
2123 sstate.ismime = 0;
2124
2125 UUkillheaders (&localenv);
2126 *errcode = UURET_NOMEM;
2127 _FP_free (result);
2128 return NULL;
2129 }
2130
2131 /* Scan subheader. But what if there is no subheader? */
2132 hcount = 0;
2133 lcount = 0;
2134 preheaders = prevpos;
2135
2136 if (_FP_fgets (line, 255, datei) == NULL) {
2137 sstate.isfolder = 0;
2138 sstate.ismime = 0;
2139 while (mssdepth) {
2140 mssdepth--;
2141 UUkillheaders (&(multistack[mssdepth].envelope));
2142 _FP_free (multistack[mssdepth].source);
2143 }
2144 UUkillheaders (&localenv);
2145 _FP_free (result);
2146 return NULL;
2147 }
2148 line[255] = '\0';
2149
2150 while (!feof (datei) && !IsLineEmpty (line)) {
2151 if (IsKnownHeader (line))
2152 hcount++;
2153 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2154 if (lcount > WAITHEADER && hcount == 0) {
2155 fseek (datei, preheaders, SEEK_SET);
2156 prevpos = preheaders;
2157 break;
2158 }
2159 ptr1 = ScanHeaderLine (datei, line);
2160 if (ParseHeader (&localenv, ptr1) == NULL)
2161 *errcode = UURET_NOMEM;
2162
2163 if (line[0] == '-' && line[1] == '-')
2164 break;
2165
2166 prevpos = ftell (datei);
2167
2168 if (_FP_fgets (line, 255, datei) == NULL)
2169 break;
2170 line[255] = '\0';
2171 lcount++;
2172 }
2173 if (line[0] == '-' && line[1] == '-') {
2174 /*
2175 * this shouldn't happen, there must always be an empty line,
2176 * but let's accept it anyway. Just skip back to before the
2177 * boundary, so that it gets handled below
2178 */
2179 fseek (datei, prevpos, SEEK_SET);
2180 }
2181
2182 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2183 /* oh no, not again */
2184 if (mssdepth >= MSMAXDEPTH) {
2185 /* Argh, what an isane message. Treat as plain text */
2186 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2187 uustring (S_MIME_MULTI_DEPTH));
2188 }
2189 else if (localenv.boundary == NULL) {
2190 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2191 uustring (S_MIME_NO_BOUNDARY));
2192 }
2193 else {
2194 memcpy (&multistack[mssdepth], &sstate, sizeof (scanstate));
2195 memcpy (&sstate.envelope, &localenv, sizeof (headers));
2196 memset (&localenv, 0, sizeof (headers));
2197 sstate.mimestate = MS_PREAMBLE;
2198 if ((sstate.source = _FP_strdup (sstate.source)) == NULL)
2199 *errcode = UURET_NOMEM;
2200
2201 if (*errcode == UURET_OK)
2202 *errcode = UURET_CONT;
2203
2204 mssdepth++;
2205 /* need a restart */
2206 _FP_free (result);
2207 return NULL;
2208 }
2209 }
2210
2211 /*
2212 * So this subpart is either plain text or something else. Check
2213 * the Content-Type and Content-Transfer-Encoding. If the latter
2214 * is a defined value, we know what to do and just copy everything
2215 * up to the boundary.
2216 * If Content-Transfer-Encoding is unknown or missing, look at the
2217 * Content-Type. If it's "text/plain" or undefined, we subject the
2218 * message to our encoding detection. Otherwise, treat as plain
2219 * text.
2220 * This is done because users might `attach' a uuencoded file, which
2221 * would then be correctly typed as `text/plain'.
2222 */
2223
2224 if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2225 result->uudet = B64ENCODED;
2226 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2227 result->uudet = UU_ENCODED;
2228 result->begin = result->end = 1;
2229 }
2230 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2231 result->uudet = YENC_ENCODED;
2232 result->begin = result->end = 1;
2233 }
2234 else if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2235 result->uudet = QP_ENCODED;
2236 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2237 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2238 result->uudet = PT_ENCODED;
2239 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2240 _FP_stristr (localenv.ctype, "message") != NULL)
2241 result->uudet = PT_ENCODED;
2242
2243 /*
2244 * If we're switched to MIME-only mode, handle as text
2245 */
2246
2247 if (uu_more_mime >= 2 && !result->uudet) {
2248 result->uudet = PT_ENCODED;
2249 }
2250
2251 if (result->uudet) {
2252 /*
2253 * Oh-kay, go ahead. Just read and wait for the boundary
2254 */
2255 result->startpos = ftell (datei);
2256 prevpos = ftell (datei);
2257 blen = strlen (sstate.envelope.boundary);
2258 lcount = 0;
2259
2260 while (!feof (datei)) {
2261 if (_FP_fgets (line, 255, datei) == NULL) {
2262 line[0] = '\0';
2263 break;
2264 }
2265 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2266 line[255] = '\0';
2267 if (line[0] == '-' && line[1] == '-' &&
2268 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2269 break;
2270 /*
2271 * I've had a report of someone who tried to decode a huge file
2272 * that had an early truncated multipart message and later another
2273 * multipart message with the *same* boundary. Consequently, all
2274 * some hundred messages inbetween were ignored ...
2275 * This check here doesn't cover folded header lines, but we don't
2276 * want to slow down scanning too much. We just check for
2277 * Content-Type: multipart/... boundary="same-boundary"
2278 */
2279 if (line[0] == 'C' && line[1] == 'o' &&
2280 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2281 ptr1 = ScanHeaderLine (datei, line);
2282 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2283 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2284 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2285 break;
2286 for (res=0; ptr1 && res<mssdepth; res++)
2287 if (strcmp (ptr1, multistack[res].envelope.boundary) == 0)
2288 break;
2289 if (res<mssdepth)
2290 break;
2291 }
2292 if (!IsLineEmpty (line))
2293 lcount++;
2294 prevpos = ftell (datei);
2295 }
2296 if (line[0] == '-' && line[1] == '-' &&
2297 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2298 ptr1 = line + 2 + blen;
2299 if (*ptr1 == '-' && *(ptr1+1) == '-')
2300 sstate.mimestate = MS_EPILOGUE;
2301 else
2302 sstate.mimestate = MS_SUBPART;
2303 }
2304 else {
2305 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2306 uustring (S_MIME_B_NOT_FOUND));
2307
2308 while (mssdepth) {
2309 mssdepth--;
2310 UUkillheaders (&(multistack[mssdepth].envelope));
2311 _FP_free (multistack[mssdepth].source);
2312 }
2313 /*
2314 * Don't retry if uu_fast_scanning
2315 */
2316
2317 if (uu_fast_scanning) {
2318 UUkillheaders (&localenv);
2319 sstate.isfolder = 0;
2320 sstate.ismime = 0;
2321 sstate.mimestate = MS_BODY;
2322 _FP_free (result);
2323 return NULL;
2324 }
2325
2326 /*
2327 * Retry, but listening to headers this time
2328 */
2329 fseek (datei, result->startpos, SEEK_SET);
2330
2331 UUkillfread (result);
2332 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2333 *errcode = UURET_NOMEM;
2334 sstate.isfolder = 0;
2335 sstate.ismime = 0;
2336 UUkillheaders (&localenv);
2337 return NULL;
2338 }
2339 memset (result, 0, sizeof (fileread));
2340
2341 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2342 /* oops, something went wrong */
2343 sstate.isfolder = 0;
2344 sstate.ismime = 0;
2345 UUkillfread (result);
2346 UUkillheaders (&localenv);
2347 return NULL;
2348 }
2349 if (res == 1) {
2350 /*
2351 * new headers found
2352 */
2353 sstate.isfolder = 1;
2354 sstate.ismime = 0;
2355 sstate.mimestate = MS_HEADERS;
2356 }
2357 else {
2358 sstate.isfolder = 0;
2359 sstate.ismime = 0;
2360 }
2361 }
2362 /* produce result if uu_handletext is set */
2363 /* or if the file is explicitely named */
2364 if (result->uudet == B64ENCODED || lcount) {
2365 if (localenv.fname) {
2366 _FP_free (result->filename);
2367 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2368 *errcode = UURET_NOMEM;
2369 }
2370 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
2371 result->filename == NULL && uu_handletext) {
2372 sprintf (line, "%04d.txt", ++mimseqno);
2373 if ((result->filename = _FP_strdup (line)) == NULL)
2374 *errcode = UURET_NOMEM;
2375 }
2376 result->subject = _FP_strdup (localenv.subject);
2377 result->origin = _FP_strdup (localenv.from);
2378 result->mimeid = _FP_strdup (localenv.mimeid);
2379 result->mimetype = _FP_strdup (localenv.ctype);
2380 result->mode = 0644;
2381 result->sfname = _FP_strdup (fname);
2382 result->flags = FL_SINGLE | FL_PROPER;
2383 result->partno = 1;
2384 /* result->uudet determined above */
2385 /* result->startpos set from above */
2386 result->length = prevpos - result->startpos;
2387
2388 if ((localenv.subject != NULL && result->subject == NULL) ||
2389 result->filename == NULL || result->sfname == NULL) {
2390 *errcode = UURET_NOMEM;
2391 }
2392 }
2393 else {
2394 /* don't produce a result */
2395 _FP_free (result);
2396 result = NULL;
2397 }
2398 if (*errcode == UURET_OK)
2399 *errcode = UURET_CONT;
2400 /*
2401 * destroy local envelope
2402 */
2403 UUkillheaders (&localenv);
2404 return result;
2405 }
2406
2407 /*
2408 * we're in a subpart, but the local headers don't give us any
2409 * clue about what's to find here. So look for encoded data by
2410 * ourselves.
2411 */
2412
2413 if ((res = ScanData (datei, fname, errcode,
2414 sstate.envelope.boundary,
2415 1, 0, result)) == -1) {
2416 /* oops, something went wrong */
2417 sstate.isfolder = 0;
2418 sstate.ismime = 0;
2419 UUkillfread (result);
2420 UUkillheaders (&localenv);
2421 return NULL;
2422 }
2423 /*
2424 * we should really be at a boundary here, but check again
2425 */
2426 blen = strlen (sstate.envelope.boundary);
2427 prevpos = ftell (datei);
2428
2429 while (!feof (datei)) {
2430 if (_FP_fgets (line, 255, datei) == NULL) {
2431 line[0] = '\0';
2432 break;
2433 }
2434 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2435 line[255] = '\0';
2436 if (line[0] == '-' && line[1] == '-' &&
2437 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2438 break;
2439 if (line[0] == 'C' && line[1] == 'o' &&
2440 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2441 ptr1 = ScanHeaderLine (datei, line);
2442 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2443 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2444 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2445 break;
2446 }
2447 prevpos = ftell (datei);
2448 }
2449 /*
2450 * check if this was the last subpart
2451 */
2452 if (line[0] == '-' && line[1] == '-' &&
2453 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2454 ptr1 = line + 2 + blen;
2455 if (*ptr1 == '-' && *(ptr1+1) == '-')
2456 sstate.mimestate = MS_EPILOGUE;
2457 else
2458 sstate.mimestate = MS_SUBPART;
2459 }
2460 else {
2461 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2462 uustring (S_MIME_B_NOT_FOUND));
2463
2464 while (mssdepth) {
2465 mssdepth--;
2466 UUkillheaders (&(multistack[mssdepth].envelope));
2467 _FP_free (multistack[mssdepth].source);
2468 }
2469
2470 if (uu_fast_scanning) {
2471 UUkillheaders (&localenv);
2472 sstate.isfolder = 0;
2473 sstate.ismime = 0;
2474 sstate.mimestate = MS_BODY;
2475 _FP_free (result);
2476 return NULL;
2477 }
2478
2479 /*
2480 * Retry, listening to headers this time
2481 */
2482 fseek (datei, result->startpos, SEEK_SET);
2483
2484 UUkillfread (result);
2485 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2486 *errcode = UURET_NOMEM;
2487 sstate.isfolder = 0;
2488 sstate.ismime = 0;
2489 UUkillheaders (&localenv);
2490 return NULL;
2491 }
2492 memset (result, 0, sizeof (fileread));
2493
2494 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2495 /* oops, something went wrong */
2496 sstate.isfolder = 0;
2497 sstate.ismime = 0;
2498 UUkillfread (result);
2499 UUkillheaders (&localenv);
2500 return NULL;
2501 }
2502 if (res == 1) {
2503 /*
2504 * new headers found
2505 */
2506 sstate.isfolder = 1;
2507 sstate.ismime = 0;
2508 sstate.mimestate = MS_HEADERS;
2509 }
2510 else {
2511 sstate.isfolder = 0;
2512 sstate.ismime = 0;
2513 }
2514 }
2515
2516 /*
2517 * If this file has been nicely MIME so far, then be very suspicious
2518 * if ScanData reports anything else. So do a double check, and if
2519 * it doesn't hold up, handle as plain text instead.
2520 */
2521
2522 if (sstate.ismime && sstate.mimestate == MS_SUBPART &&
2523 strcmp (localenv.mimevers, "1.0") == 0 &&
2524 _FP_stristr (localenv.ctype, "text") != NULL &&
2525 !uu_desperate) {
2526 if (result->uudet == UU_ENCODED && !(result->begin || result->end)) {
2527 result->uudet = 0;
2528 }
2529 }
2530
2531 /*
2532 * produce result
2533 */
2534
2535 if (result->uudet == 0) {
2536 result->uudet = PT_ENCODED; /* plain text */
2537 }
2538
2539 if (localenv.fname) {
2540 _FP_free (result->filename);
2541 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2542 *errcode = UURET_NOMEM;
2543 }
2544 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2545 result->filename==NULL && uu_handletext) {
2546 sprintf (line, "%04d.txt", ++mimseqno);
2547 if ((result->filename = _FP_strdup (line)) == NULL)
2548 *errcode = UURET_NOMEM;
2549 }
2550 else {
2551 /* assign a filename lateron */
2552 }
2553 if (result->mimetype) _FP_free (result->mimetype);
2554 if (result->uudet) {
2555 if (_FP_stristr (localenv.ctype, "text") != NULL &&
2556 result->uudet != QP_ENCODED && result->uudet != PT_ENCODED)
2557 result->mimetype = NULL; /* better don't set it */
2558 else
2559 result->mimetype = _FP_strdup (localenv.ctype);
2560 }
2561 if (result->origin) _FP_free (result->origin);
2562 result->origin = _FP_strdup (localenv.from);
2563
2564 if (result->subject) _FP_free (result->subject);
2565 result->subject = _FP_strdup (localenv.subject);
2566
2567 if (result->sfname == NULL)
2568 if ((result->sfname = _FP_strdup (fname)) == NULL)
2569 *errcode = UURET_NOMEM;
2570
2571 result->length = prevpos - result->startpos;
2572 result->flags = FL_SINGLE | FL_PROPER;
2573 result->partno = 1;
2574
2575 if (result->mode == 0)
2576 result->mode = 0644;
2577
2578 /*
2579 * the other fields should already be set appropriately
2580 */
2581
2582 if (*errcode == UURET_OK)
2583 *errcode = UURET_CONT;
2584
2585 /*
2586 * kill local envelope
2587 */
2588 UUkillheaders (&localenv);
2589
2590 return result;
2591 }
2592
2593 /*
2594 * All right, so we're not in a Multipart message. Phew, took quite
2595 * long to figure this out. But this might still be a MIME message
2596 * body. And if it's a message/partial, we need more special handling
2597 */
2598
2599 if (sstate.isfolder && sstate.ismime && sstate.mimestate == MS_BODY &&
2600 _FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2601 _FP_stristr (sstate.envelope.ctype, "partial") != NULL) {
2602
2603 result->startpos = ftell (datei);
2604
2605 if (sstate.envelope.partno == 1) {
2606 /* read local envelope */
2607 UUkillheaders (&localenv);
2608 memset (&localenv, 0, sizeof (headers));
2609
2610 /* skip over blank lines first */
2611 prevpos = ftell (datei);
2612 while (!feof (datei)) {
2613 if (_FP_fgets (line, 255, datei) == NULL)
2614 break;
2615 line[255] = '\0';
2616 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2617 if (!IsLineEmpty (line))
2618 break;
2619 prevpos = ftell (datei);
2620 }
2621 /* Next, read header. But what if there is no subheader? */
2622 hcount = 0;
2623 lcount = 0;
2624 preheaders = prevpos;
2625
2626 while (!feof (datei) && !IsLineEmpty (line)) {
2627 if (IsKnownHeader (line))
2628 hcount++;
2629 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2630 if (lcount > WAITHEADER && hcount == 0) {
2631 fseek (datei, preheaders, SEEK_SET);
2632 break;
2633 }
2634 ptr1 = ScanHeaderLine (datei, line);
2635 if (ParseHeader (&localenv, ptr1) == NULL)
2636 *errcode = UURET_NOMEM;
2637
2638 if (_FP_fgets (line, 255, datei) == NULL)
2639 break;
2640 line[255] = '\0';
2641 lcount++;
2642 }
2643 prevpos = ftell (datei);
2644 /*
2645 * Examine local header. We're mostly interested in the Content-Type
2646 * and the Content-Transfer-Encoding.
2647 */
2648 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2649 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2650 uustring (S_MIME_PART_MULTI));
2651 }
2652 if (localenv.subject)
2653 result->subject = _FP_strdup (localenv.subject);
2654 else
2655 result->subject = _FP_strdup (sstate.envelope.subject);
2656
2657 if (localenv.from)
2658 result->origin = _FP_strdup (localenv.from);
2659 else
2660 result->origin = _FP_strdup (sstate.envelope.from);
2661
2662 if (localenv.ctype)
2663 result->mimetype = _FP_strdup (localenv.ctype);
2664 else
2665 result->mimetype = _FP_strdup ("text/plain");
2666
2667 if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2668 result->uudet = QP_ENCODED;
2669 else if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2670 result->uudet = B64ENCODED;
2671 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2672 result->uudet = UU_ENCODED;
2673 result->begin = result->end = 1;
2674 }
2675 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2676 result->uudet = YENC_ENCODED;
2677 result->begin = result->end = 1;
2678 }
2679 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2680 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2681 result->uudet = PT_ENCODED;
2682 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2683 _FP_stristr (localenv.ctype, "message") != NULL)
2684 result->uudet = PT_ENCODED;
2685
2686 /*
2687 * If we're switched to MIME-only mode, handle as text
2688 */
2689
2690 if (uu_more_mime >= 2 && !result->uudet) {
2691 result->uudet = PT_ENCODED;
2692 }
2693 }
2694 else {
2695 memset (&localenv, 0, sizeof (headers));
2696 }
2697
2698 /*
2699 * If this is Quoted-Printable or Plain Text, just try looking
2700 * for the next message header. If uu_fast_scanning, and the
2701 * encoding is known, there's no need to look below. Otherwise,
2702 * we check the type of encoding first.
2703 * The encoding type is determined on the first part; in all
2704 * others, we also don't read on.
2705 * If we have a partial multipart message, scan for headers, but
2706 * do not react on standard MIME headers, as they are probably
2707 * from the subparts. However, we're stuck if there's an embedded
2708 * message/rfc822 :-(
2709 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2710 * the message header and then start looking for the next header.
2711 */
2712 if (uu_fast_scanning && (result->uudet!=0||sstate.envelope.partno!=1)) {
2713 /* do nothing */
2714 res = 0;
2715 }
2716 else if (result->uudet != 0) {
2717 hcount = lcount = 0;
2718 prevpos = ftell (datei);
2719
2720 if (_FP_stristr (localenv.ctype, "message") != NULL &&
2721 _FP_stristr (localenv.ctype, "rfc822") != NULL) {
2722 /*
2723 * skip over empty lines and local header
2724 */
2725 preheaders = ftell (datei);
2726 while (!feof (datei)) {
2727 if (_FP_fgets (line, 255, datei) == NULL)
2728 break;
2729 line[255] = '\0';
2730 if (!IsLineEmpty (line)) {
2731 break;
2732 }
2733 }
2734
2735 while (!feof (datei) && !IsLineEmpty (line)) {
2736 if (IsKnownHeader (line))
2737 hcount++;
2738 lcount++;
2739 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2740 break;
2741
2742 if (_FP_fgets (line, 255, datei) == NULL)
2743 break;
2744 line[255] = '\0';
2745 }
2746 if (hcount < hlcount.afternl)
2747 fseek (datei, preheaders, SEEK_SET);
2748 hcount = lcount = 0;
2749 }
2750
2751 /*
2752 * look for next header
2753 */
2754
2755 while (!feof (datei)) {
2756 if (_FP_fgets (line, 255, datei) == NULL)
2757 break;
2758 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2759 if (ferror (datei))
2760 break;
2761 line[255] = '\0';
2762
2763 if ((vflag = IsKnownHeader (line))) {
2764 (void) ScanHeaderLine (datei, line);
2765
2766 if (result->uudet != PT_ENCODED || vflag == 1) {
2767 if (hcount == 0)
2768 preheaders = prevpos;
2769 hcount++;
2770 lcount++;
2771 if (hcount >= hlcount.restart) {
2772 /*
2773 * Hey, a new header starts here
2774 */
2775 fseek (datei, preheaders, SEEK_SET);
2776 prevpos = preheaders;
2777 break;
2778 }
2779 }
2780 }
2781 else if (lcount > WAITHEADER) {
2782 hcount = 0;
2783 lcount = 0;
2784 }
2785 else if (hcount) {
2786 lcount++;
2787 }
2788 prevpos = ftell (datei);
2789 }
2790 res = 1;
2791 }
2792 else {
2793 /*
2794 * Otherwise, let's see what we can find ourself. No
2795 * boundary (NULL) but MIME, and respect new headers.
2796 */
2797 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
2798 /* oops, something went wrong */
2799 sstate.isfolder = 0;
2800 sstate.ismime = 0;
2801 UUkillfread (result);
2802 UUkillheaders (&localenv);
2803 return NULL;
2804 }
2805 if (result->uudet == 0 && uu_handletext)
2806 result->uudet = PT_ENCODED;
2807
2808 prevpos = ftell (datei);
2809 }
2810 /*
2811 * produce result
2812 */
2813 if (localenv.fname) {
2814 _FP_free (result->filename);
2815 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2816 *errcode = UURET_NOMEM;
2817 }
2818 else if (sstate.envelope.fname) {
2819 _FP_free (result->filename);
2820 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
2821 *errcode = UURET_NOMEM;
2822 }
2823 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2824 result->filename == NULL) {
2825 sprintf (line, "%04d.txt", ++mimseqno);
2826 if ((result->filename = _FP_strdup (line)) == NULL)
2827 *errcode = UURET_NOMEM;
2828 }
2829 else {
2830 /* assign a filename lateron */
2831 }
2832 if (result->subject == NULL) {
2833 if (sstate.envelope.subject)
2834 result->subject = _FP_strdup (sstate.envelope.subject);
2835 }
2836 result->partno = sstate.envelope.partno;
2837 result->maxpno = sstate.envelope.numparts;
2838 result->flags = FL_PARTIAL |
2839 ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) |
2840 ((uu_fast_scanning) ? FL_TOEND : 0);
2841 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2842 if (result->partno == 1)
2843 result->begin = 1;
2844
2845 if (uu_fast_scanning)
2846 result->length = progress.fsize - result->startpos;
2847 else
2848 result->length = prevpos - result->startpos;
2849
2850 if (result->sfname == NULL)
2851 result->sfname = _FP_strdup (fname);
2852
2853 if (result->mode == 0)
2854 result->mode = 0644;
2855
2856 /*
2857 * the other fields should already be set appropriately
2858 */
2859
2860 if (res == 1) {
2861 /*
2862 * new headers found
2863 */
2864 sstate.isfolder = 1;
2865 sstate.ismime = 0;
2866 sstate.mimestate = MS_HEADERS;
2867
2868 UUkillheaders (&sstate.envelope);
2869 memset (&sstate.envelope, 0, sizeof (headers));
2870 }
2871 else {
2872 /*
2873 * otherwise, this can't be a mail folder
2874 */
2875 sstate.isfolder = 0;
2876 sstate.ismime = 0;
2877 }
2878 /*
2879 * kill local envelope
2880 */
2881 UUkillheaders (&localenv);
2882 return result;
2883 }
2884
2885 /*
2886 * If this is a MIME body, honor a Content-Type different than
2887 * text/plain or a proper Content-Transfer-Encoding.
2888 * We also go in here if we have an assigned filename - this means
2889 * that we've had a Content-Disposition field, and we should probably
2890 * decode a plain-text segment with a filename.
2891 */
2892
2893 if (sstate.isfolder && sstate.ismime &&
2894 sstate.mimestate == MS_BODY &&
2895 (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL ||
2896 _FP_stristr (sstate.envelope.ctenc, "base64") != NULL ||
2897 _FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL ||
2898 _FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL ||
2899 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2900 sstate.envelope.fname != NULL)) {
2901
2902 if (sstate.envelope.subject)
2903 result->subject = _FP_strdup (sstate.envelope.subject);
2904 if (sstate.envelope.from)
2905 result->origin = _FP_strdup (sstate.envelope.from);
2906
2907 if (sstate.envelope.ctype)
2908 result->mimetype = _FP_strdup (sstate.envelope.ctype);
2909 else
2910 result->mimetype = _FP_strdup ("text/plain");
2911
2912 if (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL)
2913 result->uudet = QP_ENCODED;
2914 else if (_FP_stristr (sstate.envelope.ctenc, "base64") != NULL)
2915 result->uudet = B64ENCODED;
2916 else if (_FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL) {
2917 result->uudet = UU_ENCODED;
2918 result->begin = result->end = 1;
2919 }
2920 else if (_FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL) {
2921 result->uudet = YENC_ENCODED;
2922 }
2923 else if (_FP_stristr (sstate.envelope.ctenc, "7bit") != NULL ||
2924 _FP_stristr (sstate.envelope.ctenc, "8bit") != NULL)
2925 result->uudet = PT_ENCODED;
2926 else if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL ||
2927 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2928 sstate.envelope.fname != NULL)
2929 result->uudet = PT_ENCODED;
2930
2931 /*
2932 * If we're switched to MIME-only mode, handle as text
2933 */
2934
2935 if (uu_more_mime >= 2 && !result->uudet) {
2936 result->uudet = PT_ENCODED;
2937 }
2938
2939 result->startpos = prevpos = ftell (datei);
2940
2941 /*
2942 * If this is Quoted-Printable or Plain Text, just try looking
2943 * for the next message header. If uu_fast_scanning, we know
2944 * there won't be more headers.
2945 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2946 * the message header and then start looking for the next header.
2947 */
2948 if (result->uudet != 0 && uu_fast_scanning) {
2949 /* do nothing */
2950 res = 0;
2951 }
2952 else if (result->uudet != 0) {
2953 hcount = lcount = 0;
2954 prevpos = ftell (datei);
2955
2956 if (_FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2957 _FP_stristr (sstate.envelope.ctype, "rfc822") != NULL) {
2958 /*
2959 * skip over empty lines and local header
2960 */
2961 preheaders = ftell (datei);
2962 while (!feof (datei)) {
2963 if (_FP_fgets (line, 255, datei) == NULL)
2964 break;
2965 line[255] = '\0';
2966 if (!IsLineEmpty (line)) {
2967 break;
2968 }
2969 }
2970
2971 while (!feof (datei) && !IsLineEmpty (line)) {
2972 if (IsKnownHeader (line))
2973 hcount++;
2974 lcount++;
2975 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2976 break;
2977
2978 if (_FP_fgets (line, 255, datei) == NULL)
2979 break;
2980 line[255] = '\0';
2981 }
2982 if (hcount < hlcount.afternl)
2983 fseek (datei, preheaders, SEEK_SET);
2984 hcount = lcount = 0;
2985 }
2986
2987 /*
2988 * look for next header
2989 */
2990
2991 while (!feof (datei)) {
2992 if (_FP_fgets (line, 255, datei) == NULL)
2993 break;
2994 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2995 if (ferror (datei))
2996 break;
2997 line[255] = '\0';
2998
2999 if (IsKnownHeader (line)) {
3000 (void) ScanHeaderLine (datei, line);
3001 if (hcount == 0)
3002 preheaders = prevpos;
3003 hcount++;
3004 lcount++;
3005 if (hcount >= hlcount.restart) {
3006 /*
3007 * Hey, a new header starts here
3008 */
3009 fseek (datei, preheaders, SEEK_SET);
3010 prevpos = preheaders;
3011 break;
3012 }
3013 }
3014 else if (lcount > WAITHEADER) {
3015 hcount = 0;
3016 lcount = 0;
3017 }
3018 else if (hcount) {
3019 lcount++;
3020 }
3021 prevpos = ftell (datei);
3022 }
3023 res = 1;
3024 }
3025 else {
3026 /*
3027 * Otherwise, let's see what we can find ourself. No
3028 * boundary (NULL) but MIME, and respect new headers.
3029 */
3030 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
3031 /* oops, something went wrong */
3032 sstate.isfolder = 0;
3033 sstate.ismime = 0;
3034 UUkillfread (result);
3035 return NULL;
3036 }
3037 if (result->uudet == 0 && uu_handletext) {
3038 result->startpos = before; /* display headers */
3039 result->uudet = PT_ENCODED;
3040 }
3041
3042 prevpos = ftell (datei);
3043 }
3044 /*
3045 * produce result
3046 */
3047 if (sstate.envelope.fname) {
3048 _FP_free (result->filename);
3049 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3050 *errcode = UURET_NOMEM;
3051 }
3052 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3053 result->filename == NULL) {
3054 sprintf (line, "%04d.txt", ++mimseqno);
3055 if ((result->filename = _FP_strdup (line)) == NULL)
3056 *errcode = UURET_NOMEM;
3057 }
3058 else {
3059 /* assign a filename lateron */
3060 }
3061 if (result->subject == NULL) {
3062 if (sstate.envelope.subject)
3063 result->subject = _FP_strdup (sstate.envelope.subject);
3064 }
3065 result->flags = ((res==1||uu_fast_scanning)?FL_PROPER:0) |
3066 ((uu_fast_scanning) ? FL_TOEND : 0);
3067 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3068
3069 if (uu_fast_scanning)
3070 result->length = progress.fsize - result->startpos;
3071 else
3072 result->length = prevpos - result->startpos;
3073
3074 if (result->sfname == NULL)
3075 result->sfname = _FP_strdup (fname);
3076
3077 if (result->mode == 0)
3078 result->mode = 0644;
3079
3080 /*
3081 * the other fields should already be set appropriately
3082 */
3083
3084 if (res == 1) {
3085 /*
3086 * new headers found
3087 */
3088 sstate.isfolder = 1;
3089 sstate.ismime = 0;
3090 sstate.mimestate = MS_HEADERS;
3091
3092 UUkillheaders (&sstate.envelope);
3093 memset (&sstate.envelope, 0, sizeof (headers));
3094 }
3095 else {
3096 /*
3097 * otherwise, this can't be a mail folder
3098 */
3099 sstate.isfolder = 0;
3100 sstate.ismime = 0;
3101 }
3102
3103 return result;
3104 }
3105
3106 /*
3107 * Some files have reduced headers, and what should be a multipart
3108 * message is missing the proper Content-Type. If the first thing
3109 * we find after a couple of empty lines is a boundary, try it!
3110 * But make sure that this is indeed intended as being a boundary.
3111 *
3112 * Only accept it if there was indeed no Content-Type header line
3113 * and if the following line is a proper Content-Type header. BTW,
3114 * we know that sstate.envelope.boundary is NULL, or we wouldn't
3115 * be here!
3116 */
3117
3118 if ((sstate.envelope.ctype == NULL ||
3119 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL) &&
3120 !uu_more_mime) {
3121 prevpos = ftell (datei);
3122 while (!feof (datei)) {
3123 if (_FP_fgets (line, 255, datei) == NULL) {
3124 line[0] = '\0';
3125 break;
3126 }
3127 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
3128 if (!IsLineEmpty (line))
3129 break;
3130 }
3131 if (line[0] == '-' && line[1] == '-' &&
3132 !IsLineEmpty (line+2) && !feof (datei)) {
3133 ptr1 = _FP_strrstr (line+2, "--");
3134 ptr2 = ScanHeaderLine (datei, NULL);
3135 if ((ptr1 == NULL || (*(ptr1+2) != '\012' && *(ptr1+2) != '\015')) &&
3136 ptr2 && _FP_strnicmp (ptr2, "Content-", 8) == 0) {
3137 /*
3138 * hmm, okay, let's do it!
3139 */
3140 sstate.isfolder = 1;
3141 sstate.ismime = 1;
3142 sstate.mimestate = MS_PREAMBLE;
3143 /*
3144 * get boundary
3145 */
3146 ptr1 = line+2;
3147 while (*ptr1 && !isspace(*ptr1))
3148 ptr1++;
3149 *ptr1 = '\0';
3150
3151 sstate.envelope.mimevers = _FP_strdup ("1.0");
3152 sstate.envelope.boundary = _FP_strdup (line+2);
3153
3154 /*
3155 * need restart
3156 */
3157
3158 fseek (datei, prevpos, SEEK_SET);
3159
3160 _FP_free (result);
3161 return NULL;
3162 }
3163 }
3164 fseek (datei, prevpos, SEEK_SET);
3165 }
3166
3167 /*
3168 * Hmm, we're not in a ''special'' state, so it's more or less
3169 * Freestyle time. Anyway, if this seems to be a Mime message,
3170 * don't allow the minimal Base64 handling.
3171 */
3172
3173 if (sstate.envelope.subject)
3174 result->subject = _FP_strdup (sstate.envelope.subject);
3175 if (sstate.envelope.from)
3176 result->origin = _FP_strdup (sstate.envelope.from);
3177
3178 if (sstate.envelope.ctype)
3179 result->mimetype = _FP_strdup (sstate.envelope.ctype);
3180
3181 if ((res=ScanData (datei, fname, errcode, NULL,
3182 sstate.ismime, 1, result))==-1) {
3183 /* oops, something went wrong */
3184 sstate.isfolder = 0;
3185 sstate.ismime = 0;
3186 UUkillfread (result);
3187 return NULL;
3188 }
3189
3190 /*
3191 * produce result
3192 */
3193
3194 if (result->uudet == 0 && uu_handletext) {
3195 result->startpos = before; /* display headers */
3196 result->uudet = PT_ENCODED;
3197 result->partno = 1;
3198 }
3199
3200 if (result->uudet == YENC_ENCODED && result->filename != NULL) {
3201 /*
3202 * prevent replacing the filename found on the =ybegin line
3203 */
3204 }
3205 else if (sstate.envelope.fname) {
3206 _FP_free (result->filename);
3207 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3208 *errcode = UURET_NOMEM;
3209 }
3210 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3211 result->filename == NULL) {
3212 sprintf (line, "%04d.txt", ++mimseqno);
3213 if ((result->filename = _FP_strdup (line)) == NULL)
3214 *errcode = UURET_NOMEM;
3215 }
3216 else {
3217 /* assign a filename lateron */
3218 }
3219
3220 if (result->subject == NULL) {
3221 if (sstate.envelope.subject)
3222 result->subject = _FP_strdup (sstate.envelope.subject);
3223 }
3224
3225 result->flags = (result->uudet==PT_ENCODED)?FL_SINGLE:0;
3226 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3227 result->length = ftell (datei) - result->startpos;
3228
3229 if (result->mode == 0)
3230 result->mode = 0644;
3231
3232 if (result->sfname == NULL)
3233 result->sfname = _FP_strdup (fname);
3234
3235 if (res == 1) {
3236 /*
3237 * new headers found
3238 */
3239 sstate.isfolder = 1;
3240 sstate.ismime = 0;
3241 sstate.mimestate = MS_HEADERS;
3242
3243 UUkillheaders (&sstate.envelope);
3244 memset (&sstate.envelope, 0, sizeof (headers));
3245 }
3246 else {
3247 /*
3248 * otherwise, this can't be a mail folder
3249 */
3250 sstate.isfolder = 0;
3251 sstate.ismime = 0;
3252 }
3253
3254 return result;
3255
3256 /*
3257 * Emergency handling. Set errcode before jumping here.
3258 */
3259 ScanPartEmergency:
3260 UUkillfread (result);
3261 UUkillheaders (&localenv);
3262
3263 while (mssdepth) {
3264 mssdepth--;
3265 UUkillheaders (&(multistack[mssdepth].envelope));
3266 _FP_free (multistack[mssdepth].source);
3267 }
3268
3269 return NULL;
3270 }
3271