ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.9
Committed: Sun Apr 18 20:08:11 2004 UTC (20 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_04
Changes since 1.8: +6 -4 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=='-')) 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 length++;
408 }
409
410 *ptr = '\0';
411 }
412 return uuscan_pvvalue;
413 }
414
415 /*
416 * Extract the information we need from header fields
417 */
418
419 static headers *
420 ParseHeader (headers *theheaders, char *line)
421 {
422 char **variable=NULL;
423 char *value, *ptr, *thenew;
424 int delimit, length;
425
426 value = 0; delimit = 0; /* calm down gcc */
427
428 if (line == NULL)
429 return theheaders;
430
431 if (_FP_strnicmp (line, "From:", 5) == 0) {
432 if (theheaders->from) return theheaders;
433 variable = &theheaders->from;
434 value = line+5;
435 delimit = 0;
436 }
437 else if (_FP_strnicmp (line, "Subject:", 8) == 0) {
438 if (theheaders->subject) return theheaders;
439 variable = &theheaders->subject;
440 value = line+8;
441 delimit = 0;
442 }
443 else if (_FP_strnicmp (line, "To:", 3) == 0) {
444 if (theheaders->rcpt) return theheaders;
445 variable = &theheaders->rcpt;
446 value = line+3;
447 delimit = 0;
448 }
449 else if (_FP_strnicmp (line, "Date:", 5) == 0) {
450 if (theheaders->date) return theheaders;
451 variable = &theheaders->date;
452 value = line+5;
453 delimit = 0;
454 }
455 else if (_FP_strnicmp (line, "Mime-Version:", 13) == 0) {
456 if (theheaders->mimevers) return theheaders;
457 variable = &theheaders->mimevers;
458 value = line+13;
459 delimit = 0;
460 }
461 else if (_FP_strnicmp (line, "Content-Type:", 13) == 0) {
462 if (theheaders->ctype) return theheaders;
463 variable = &theheaders->ctype;
464 value = line+13;
465 delimit = ';';
466
467 /* we can probably extract more information */
468 if ((ptr = _FP_stristr (line, "boundary")) != NULL) {
469 if ((thenew = ParseValue (ptr))) {
470 if (theheaders->boundary) free (theheaders->boundary);
471 theheaders->boundary = _FP_strdup (thenew);
472 }
473 }
474 if ((ptr = _FP_stristr (line, "name")) != NULL) {
475 if ((thenew = ParseValue (ptr))) {
476 if (theheaders->fname) free (theheaders->fname);
477 theheaders->fname = _FP_strdup (thenew);
478 }
479 }
480 if ((ptr = _FP_stristr (line, "id")) != NULL) {
481 if ((thenew = ParseValue (ptr))) {
482 if (theheaders->mimeid) free (theheaders->mimeid);
483 theheaders->mimeid = _FP_strdup (thenew);
484 }
485 }
486 if ((ptr = _FP_stristr (line, "number")) != NULL) {
487 if ((thenew = ParseValue (ptr))) {
488 theheaders->partno = atoi (thenew);
489 }
490 }
491 if ((ptr = _FP_stristr (line, "total")) != NULL) {
492 if ((thenew = ParseValue (ptr))) {
493 theheaders->numparts = atoi (thenew);
494 }
495 }
496 }
497 else if (_FP_strnicmp (line, "Content-Transfer-Encoding:", 26) == 0) {
498 if (theheaders->ctenc) return theheaders;
499 variable = &theheaders->ctenc;
500 value = line+26;
501 delimit = ';';
502 }
503 else if (_FP_strnicmp (line, "Content-Disposition:", 20) == 0) {
504 /*
505 * Some encoders mention the original filename as parameter to
506 * Content-Type, others as parameter to Content-Disposition. We
507 * do prefer the first solution, but accept this situation, too.
508 * TODO: Read RFC1806
509 */
510 if ((ptr = _FP_stristr (line, "name")) != NULL) {
511 if (theheaders->fname == NULL && (thenew=ParseValue(ptr)) != NULL) {
512 theheaders->fname = _FP_strdup (thenew);
513 }
514 }
515 variable = NULL;
516 }
517 else {
518 /*
519 * nothing interesting
520 */
521 return theheaders;
522 }
523
524 /*
525 * okay, so extract the actual data
526 */
527 if (variable) {
528 length = 0;
529 ptr = uuscan_phtext;
530
531 while (isspace (*value))
532 value++;
533 while (*value && (delimit==0 || *value!=delimit) &&
534 *value != '\012' && *value != '\015' && length < 255) {
535 *ptr++ = *value++;
536 length++;
537 }
538 while (length && isspace(*(ptr-1))) {
539 ptr--; length--;
540 }
541 *ptr = '\0';
542
543 if ((*variable = _FP_strdup (uuscan_phtext)) == NULL)
544 return NULL;
545 }
546
547 return theheaders;
548 }
549
550 /*
551 * is this a header line we know about?
552 */
553
554 static int
555 IsKnownHeader (char *line)
556 {
557 char **iter = knownmsgheaders;
558
559 while (iter && *iter) {
560 if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
561 return 1;
562 iter++;
563 }
564
565 iter = knownmimeheaders;
566
567 while (iter && *iter) {
568 if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
569 return 2;
570 iter++;
571 }
572
573 return 0;
574 }
575
576 /*
577 * Scan a header
578 */
579
580 int
581 UUScanHeader (FILE *datei, headers *envelope)
582 {
583 char *ptr;
584
585 while (!feof (datei)) {
586 if ((ptr = ScanHeaderLine (datei, NULL)) == NULL)
587 break;
588 if (*ptr == '\0' || *ptr == '\012' || *ptr == '\015')
589 break;
590 ParseHeader (envelope, ptr);
591 }
592 return 0;
593 }
594
595 /*
596 * Scan something for encoded data and fill the fileread* structure.
597 * If boundary is non-NULL, we stop after having read it. If Check-
598 * Headers != 0, we also stop after we've found uu_headercount recog-
599 * nized header lines.
600 * If we have a boundary, then we also don't accept Base64; MIME mails
601 * really should handle this properly.
602 * We return -1 if something went wrong, 0 if everything is normal,
603 * 1 if we found a new header and 2 if we found a boundary.
604 * In MIME message bodies (not multiparts), we also disable our reduced
605 * MIME handling.
606 */
607
608 static int
609 ScanData (FILE *datei, char *fname, int *errcode,
610 char *boundary, int ismime, int checkheaders,
611 fileread *result)
612 {
613 char *line=uuscan_sdline, *bhds1=uuscan_sdbhds1, *bhds2=uuscan_sdbhds2;
614 static char *ptr, *p2, *p3=NULL, *bhdsp, bhl;
615 int islen[10], isb64[10], isuue[10], isxxe[10], isbhx[10], iscnt;
616 int cbb64, cbuue, cbxxe, cbbhx;
617 int bhflag=0, vflag, haddh=0, hadct=0;
618 int bhrpc=0, bhnf=0, c, hcount, lcount, blen=0;
619 int encoding=0, dflag=0, ctline=42;
620 int dontcare=0, hadnl=0;
621 long preheaders=0, oldposition;
622 long yefilesize=0, yepartends=0;
623 size_t dcc, bhopc;
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, 255, datei) == NULL)
648 break;
649 if (ferror (datei))
650 break;
651
652 line[255] = '\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 (void) UUDecodeLine (NULL, NULL, 0); /* init */
1477 if (datei == NULL || feof (datei)) {
1478 *errcode = UURET_OK;
1479 return NULL;
1480 }
1481
1482 *errcode = UURET_OK;
1483
1484 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
1485 *errcode = UURET_NOMEM;
1486 return NULL;
1487 }
1488 memset (result, 0, sizeof (fileread));
1489 result->startpos = ftell (datei);
1490 preheaders = result->startpos;
1491 before = result->startpos;
1492
1493 /* if this is a new file, reset our scanning state */
1494 if (sstate.source == NULL || strcmp (fname, sstate.source) != 0) {
1495 sstate.isfolder = 1; /* assume yes */
1496 sstate.ismime = 0; /* wait for MIME-Version */
1497 sstate.mimestate = MS_HEADERS; /* assume headers follow */
1498 /* mimseqno = 1; */
1499
1500 while (mssdepth) {
1501 mssdepth--;
1502 UUkillheaders (&(multistack[mssdepth].envelope));
1503 _FP_free (multistack[mssdepth].source);
1504 }
1505
1506 UUkillheaders (&sstate.envelope);
1507 memset (&sstate.envelope, 0, sizeof (headers));
1508
1509 _FP_free (sstate.source);
1510 if ((sstate.source = _FP_strdup (fname)) == NULL) {
1511 *errcode = UURET_NOMEM;
1512 _FP_free (result);
1513 return NULL;
1514 }
1515
1516 /* ignore empty lines at the beginning of a file */
1517 preheaders = ftell (datei);
1518 while (!feof (datei)) {
1519 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1520 if (_FP_fgets (line, 255, datei) == NULL)
1521 break;
1522 line[255] = '\0';
1523 if (!IsLineEmpty (line)) {
1524 fseek (datei, preheaders, SEEK_SET);
1525 break;
1526 }
1527 preheaders = ftell (datei);
1528 }
1529 }
1530
1531 if (ferror(datei) || feof(datei)) {
1532 _FP_free (result);
1533 return NULL;
1534 }
1535
1536 /*
1537 * If we are confident that this is a mail folder and are at the
1538 * beginning of the file, expecting to read some headers, scan
1539 * the envelope.
1540 */
1541
1542 if (sstate.isfolder && sstate.mimestate == MS_HEADERS) {
1543 hcount = 0;
1544 lcount = 0;
1545 UUkillheaders (&sstate.envelope);
1546
1547 /*
1548 * clean up leftovers from invalid messages
1549 */
1550
1551 while (mssdepth) {
1552 mssdepth--;
1553 UUkillheaders (&(multistack[mssdepth].envelope));
1554 _FP_free (multistack[mssdepth].source);
1555 }
1556
1557 prevpos = ftell (datei);
1558 if (_FP_fgets (line, 255, datei) == NULL) {
1559 _FP_free (result);
1560 return NULL;
1561 }
1562 line[255] = '\0';
1563
1564 /*
1565 * Special handling for AOL folder files, which start off with a boundary.
1566 * We recognize them by a valid boundary line as the first line of a file.
1567 * Note that the rest of the scanning code becomes suspicious if a boun-
1568 * dary does never appear in a file -- this should save us from grave
1569 * false detection errors
1570 */
1571
1572 if (!feof (datei) && line[0] == '-' && line[1] == '-' && line[2]) {
1573 while (line[strlen(line)-1] == '\012' ||
1574 line[strlen(line)-1] == '\015') {
1575 line[strlen(line)-1] = '\0';
1576 }
1577
1578 sstate.ismime = 1;
1579 sstate.envelope.mimevers = _FP_strdup ("1.0");
1580 sstate.envelope.boundary = _FP_strdup (line+2);
1581 sstate.envelope.ctype = _FP_strdup ("multipart/mixed");
1582 sstate.mimestate = MS_SUBPART;
1583
1584 *errcode = UURET_CONT;
1585 _FP_free (result);
1586 return NULL;
1587 }
1588
1589 /*
1590 * Normal behavior: look for a RFC 822 header
1591 */
1592
1593 while (!feof (datei) && !IsLineEmpty (line)) {
1594 if (IsKnownHeader (line))
1595 hcount++;
1596 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1597 if (IsHeaderLine (line)) {
1598 ptr1 = ScanHeaderLine (datei, line);
1599 if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
1600 *errcode = UURET_NOMEM;
1601 _FP_free (result);
1602 return NULL;
1603 }
1604 }
1605 /*
1606 * if we've read too many lines without finding headers, then
1607 * this probably isn't a mail folder after all
1608 */
1609 lcount++;
1610 if (lcount > WAITHEADER && hcount < hlcount.afternl) {
1611 fseek (datei, prevpos, SEEK_SET);
1612 line[0] = '\0';
1613 break;
1614 }
1615
1616 if (_FP_fgets (line, 255, datei) == NULL) {
1617 /* If we are at eof without finding headers, there probably isn't */
1618 if (hcount < hlcount.afternl) {
1619 fseek (datei, prevpos, SEEK_SET);
1620 line[0] = '\0';
1621 }
1622 break;
1623 }
1624 line[255] = '\0';
1625 }
1626
1627 /* skip empty lines */
1628 prevpos = ftell (datei);
1629 if (IsLineEmpty (line)) {
1630 while (!feof (datei)) {
1631 if (_FP_fgets (line, 255, datei) == NULL)
1632 break;
1633 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1634 if (!IsLineEmpty (line)) {
1635 fseek (datei, prevpos, SEEK_SET);
1636 line[255] = '\0';
1637 break;
1638 }
1639 prevpos = ftell (datei);
1640 }
1641 }
1642
1643 /*
1644 * If we don't have all valid MIME headers yet, but the following
1645 * line is a MIME header, accept it anyway.
1646 */
1647
1648 if (!uu_more_mime &&
1649 sstate.envelope.mimevers == NULL &&
1650 sstate.envelope.ctype == NULL &&
1651 sstate.envelope.ctenc == NULL &&
1652 IsKnownHeader (line)) {
1653 /*
1654 * see above
1655 */
1656 if (_FP_fgets (line, 255, datei) == NULL) {
1657 line[0] = '\012';
1658 line[1] = '\0';
1659 }
1660 line[255] = '\0';
1661
1662 while (!feof (datei) && !IsLineEmpty (line)) {
1663 if (IsKnownHeader (line))
1664 hcount++;
1665 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1666 ptr1 = ScanHeaderLine (datei, line);
1667 if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
1668 *errcode = UURET_NOMEM;
1669 _FP_free (result);
1670 return NULL;
1671 }
1672
1673 if (_FP_fgets (line, 255, datei) == NULL)
1674 break;
1675 line[255] = '\0';
1676 }
1677 /* skip empty lines */
1678 prevpos = ftell (datei);
1679 while (!feof (datei)) {
1680 if (_FP_fgets (line, 255, datei) == NULL)
1681 break;
1682 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1683 if (!IsLineEmpty (line)) {
1684 fseek (datei, prevpos, SEEK_SET);
1685 line[255] = '\0';
1686 break;
1687 }
1688 prevpos = ftell (datei);
1689 }
1690 }
1691
1692 /*
1693 * A partial multipart message probably has only a Content-Type
1694 * header but nothing else. In this case, at least simulate a
1695 * MIME message
1696 * if mimevers is not set but there are other well-known MIME
1697 * headers, don't be too picky about it.
1698 */
1699 if (sstate.envelope.ctype && sstate.envelope.mimevers==NULL &&
1700 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL &&
1701 sstate.envelope.boundary != NULL) {
1702 sstate.envelope.mimevers = _FP_strdup ("1.0");
1703 hcount = hlcount.afternl;
1704 }
1705 else if (sstate.envelope.mimevers==NULL && sstate.envelope.ctype &&
1706 sstate.envelope.fname && sstate.envelope.ctenc) {
1707 sstate.envelope.mimevers = _FP_strdup ("1.0");
1708 hcount = hlcount.afternl;
1709 }
1710
1711 if (sstate.envelope.mimevers != NULL) {
1712 /* this is a MIME file. check the Content-Type */
1713 sstate.ismime = 1;
1714 if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL) {
1715 if (sstate.envelope.boundary == NULL) {
1716 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1717 uustring (S_MIME_NO_BOUNDARY));
1718 sstate.mimestate = MS_BODY;
1719 _FP_free (sstate.envelope.ctype);
1720 sstate.envelope.ctype = _FP_strdup ("text/plain");
1721 }
1722 else {
1723 sstate.mimestate = MS_PREAMBLE;
1724 }
1725 }
1726 else {
1727 sstate.mimestate = MS_BODY; /* just a `simple' message */
1728 }
1729 }
1730 else {
1731 /* not a folder after all */
1732 fseek (datei, prevpos, SEEK_SET);
1733 sstate.isfolder = 0;
1734 sstate.ismime = 0;
1735 }
1736 }
1737
1738 if (feof (datei) || ferror (datei)) { /* oops */
1739 _FP_free (result);
1740 return NULL;
1741 }
1742
1743 /*
1744 * Handle MIME stuff
1745 */
1746
1747 /*
1748 * Read Preamble. This must be ended by a sstate.envelope.boundary line.
1749 * If uu_usepreamble is set, we produce a result from this one
1750 */
1751
1752 if (sstate.ismime && sstate.mimestate == MS_PREAMBLE) {
1753 result->startpos = ftell (datei); /* remember start of preamble */
1754 prevpos = ftell (datei);
1755 preheaders = ftell (datei);
1756
1757 blen = strlen (sstate.envelope.boundary);
1758 lcount = 0;
1759
1760 while (!feof (datei)) {
1761 if (_FP_fgets (line, 255, datei) == NULL) {
1762 line[0] = '\0';
1763 break;
1764 }
1765 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1766 if (line[0] == '-' && line[1] == '-' &&
1767 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
1768 break;
1769 if (!IsLineEmpty (line))
1770 lcount++;
1771
1772 prevpos = ftell (datei);
1773 }
1774 if (feof (datei) || ferror (datei)) {
1775 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1776 uustring (S_MIME_B_NOT_FOUND));
1777 /*
1778 * restart and try again; don't restart if uu_fast_scanning
1779 */
1780 sstate.isfolder = 0;
1781 sstate.ismime = 0;
1782 sstate.mimestate = MS_BODY;
1783
1784 if (!uu_fast_scanning) {
1785 *errcode = UURET_CONT;
1786 fseek (datei, preheaders, SEEK_SET);
1787 }
1788 _FP_free (result);
1789 return NULL;
1790 }
1791 if (line[0] == '-' && line[1] == '-' &&
1792 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
1793 ptr1 = line + 2 + blen;
1794 if (*ptr1 == '-' && *(ptr1+1) == '-') {
1795 /* Empty Multipart Message. Duh. */
1796 sstate.mimestate = MS_EPILOGUE;
1797 }
1798 else {
1799 sstate.mimestate = MS_SUBPART;
1800 }
1801 }
1802 else { /* shouldn't happen */
1803 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1804 uustring (S_MIME_B_NOT_FOUND));
1805 /*
1806 * restart and try again; don't restart if uu_fast_scanning
1807 */
1808 sstate.isfolder = 0;
1809 sstate.ismime = 0;
1810 sstate.mimestate = MS_BODY;
1811
1812 if (!uu_fast_scanning) {
1813 *errcode = UURET_CONT;
1814 fseek (datei, preheaders, SEEK_SET);
1815 }
1816 _FP_free (result);
1817 return NULL;
1818 }
1819 /* produce result if uu_usepreamble is set */
1820 if (uu_usepreamble && lcount) {
1821 sprintf (line, "%04d.txt", ++mimseqno);
1822 result->subject = _FP_strdup (sstate.envelope.subject);
1823 result->filename = _FP_strdup (line);
1824 result->origin = _FP_strdup (sstate.envelope.from);
1825 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
1826 result->mimetype = _FP_strdup ("text/plain");
1827 result->mode = 0644;
1828 result->uudet = PT_ENCODED; /* plain text */
1829 result->sfname = _FP_strdup (fname);
1830 result->flags = FL_SINGLE | FL_PROPER;
1831 /* result->startpos set from above */
1832 result->length = prevpos - result->startpos;
1833 result->partno = 1;
1834
1835 /* MIME message, let's continue */
1836 *errcode = UURET_CONT;
1837
1838 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
1839 result->filename == NULL || result->sfname == NULL) {
1840 *errcode = UURET_NOMEM;
1841 }
1842
1843 return result;
1844 }
1845 /* MIME message, let's continue */
1846 if (*errcode == UURET_OK)
1847 *errcode = UURET_CONT;
1848
1849 /* otherwise, just return NULL */
1850 _FP_free (result);
1851 return NULL;
1852 }
1853
1854 /*
1855 * Read Epilogue, the plain text after the last boundary.
1856 * This can either end with new headers from the next message of a
1857 * mail folder or with a `parent' boundary if we are inside an
1858 * encapsulated Multipart message. Oh yes, and of course the file
1859 * may also simply end :-)
1860 * Another possibility is that we might find plain encoded data
1861 * without encapsulating message. We're not _too_ flexible here,
1862 * we won't detect Base64, and require a proper `begin' line for
1863 * uuencoding and xxencoding
1864 * If uu_usepreamble is set, we produce a result from this one
1865 */
1866
1867 if (sstate.ismime && sstate.mimestate == MS_EPILOGUE) {
1868 result->startpos = ftell (datei); /* remember start of epilogue */
1869 prevpos = ftell (datei);
1870 preheaders = ftell (datei);
1871 preenc = ftell (datei);
1872 hcount = lcount = 0;
1873 ecount = bhflag = 0;
1874 begflag = vflag = 0;
1875 res = 0;
1876
1877 /*
1878 * If we are in the outermost message and uu_fast_scanning, we
1879 * know (or assume) that no more messages will follow, so there's
1880 * no need to scan the rest.
1881 */
1882 if (uu_fast_scanning && mssdepth == 0) {
1883 /*
1884 * check if the epilogue is empty
1885 */
1886 while (!feof (datei) && !ferror (datei) && lcount<10 && res==0) {
1887 if (_FP_fgets (line, 255, datei) == NULL)
1888 break;
1889 if (!IsLineEmpty (line))
1890 res++;
1891 lcount++;
1892 }
1893 if (uu_usepreamble && res) {
1894 sprintf (line, "%04d.txt", ++mimseqno);
1895 result->subject = _FP_strdup (sstate.envelope.subject);
1896 result->filename = _FP_strdup (line);
1897 result->origin = _FP_strdup (sstate.envelope.from);
1898 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
1899 result->mimetype = _FP_strdup ("text/plain");
1900 result->mode = 0644;
1901 result->uudet = PT_ENCODED; /* plain text */
1902 result->sfname = _FP_strdup (fname);
1903 result->flags = FL_SINGLE | FL_PROPER | FL_TOEND;
1904 result->partno = 1;
1905 /* result->startpos set from above */
1906 result->length = progress.fsize - result->startpos;
1907
1908 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
1909 result->filename == NULL || result->sfname == NULL) {
1910 *errcode = UURET_NOMEM;
1911 }
1912
1913 return result;
1914 }
1915 _FP_free (result);
1916 return NULL;
1917 }
1918
1919 if (mssdepth > 0)
1920 blen = strlen (multistack[mssdepth-1].envelope.boundary);
1921
1922 while (!feof (datei)) {
1923 if (_FP_fgets (line, 255, datei) == NULL) {
1924 line[0] = '\0';
1925 break;
1926 }
1927 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1928 line[255] = '\0';
1929 /* check for parent boundary */
1930 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
1931 strncmp (line+2,
1932 multistack[mssdepth-1].envelope.boundary, blen) == 0)
1933 break;
1934
1935 /* check for next headers only at outermost level */
1936 if (mssdepth == 0 && IsKnownHeader (line)) {
1937 (void) ScanHeaderLine (datei, line);
1938 if (hcount == 0) {
1939 preheaders = prevpos;
1940 lcount = 0;
1941 }
1942 hcount++;
1943 lcount++;
1944
1945 if (hcount >= hlcount.restart) {
1946 /* okay, new headers */
1947 break;
1948 }
1949 }
1950 else if (lcount > WAITHEADER) {
1951 hcount = 0;
1952 lcount = 0;
1953 }
1954 else if (hcount) {
1955 lcount++;
1956 }
1957 else {
1958 hcount = lcount = 0;
1959 }
1960
1961 /* check for begin and encoded data only at outermost level */
1962 if (mssdepth == 0 && !uu_more_mime) {
1963 if (strncmp (line, "begin ", 6) == 0 ||
1964 _FP_strnicmp (line, "<pre>begin ", 11) == 0) {
1965 preenc = prevpos;
1966 begflag = 1;
1967 }
1968 else if (strncmp (line, "end", 3) == 0 && begflag) {
1969 ecount = ELC_COUNT;
1970 break;
1971 }
1972 else if ((vflag = UUValidData (line, 0, &bhflag)) != 0) {
1973 if (vflag == BH_ENCODED && bhflag == 0) {
1974 /* very short BinHex file follows */
1975 preenc = prevpos;
1976 break;
1977 }
1978 /* remember that XX can easily be mistaken as Base64 */
1979 if ((vflag == UU_ENCODED || vflag == XX_ENCODED ||
1980 vflag == B64ENCODED) && begflag) {
1981 if (++ecount >= ELC_COUNT)
1982 break;
1983 }
1984 else {
1985 begflag = 0;
1986 ecount = 0;
1987 }
1988 }
1989 else {
1990 begflag = 0;
1991 ecount = 0;
1992 }
1993 }
1994
1995 if (!IsLineEmpty (line))
1996 res++;
1997
1998 prevpos = ftell (datei);
1999 }
2000
2001 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
2002 strncmp (line+2,
2003 multistack[mssdepth-1].envelope.boundary, blen) == 0) {
2004 /* restore previous state */
2005 mssdepth--;
2006 UUkillheaders (&sstate.envelope);
2007 _FP_free (sstate.source);
2008 memcpy (&sstate, &(multistack[mssdepth]), sizeof (scanstate));
2009
2010 ptr1 = line + 2 + strlen (sstate.envelope.boundary);
2011
2012 if (*ptr1 == '-' && *(ptr1+1) == '-') {
2013 sstate.mimestate = MS_EPILOGUE;
2014 }
2015 else {
2016 sstate.mimestate = MS_SUBPART;
2017 }
2018 result->length = prevpos - result->startpos;
2019 *errcode = UURET_CONT;
2020 }
2021 else if (mssdepth > 0) {
2022 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2023 uustring (S_MIME_B_NOT_FOUND));
2024 /*
2025 * restart and try again; don't restart if uu_fast_scanning
2026 */
2027 sstate.isfolder = 0;
2028 sstate.ismime = 0;
2029 sstate.mimestate = MS_BODY;
2030
2031 while (mssdepth) {
2032 mssdepth--;
2033 UUkillheaders (&(multistack[mssdepth].envelope));
2034 _FP_free (multistack[mssdepth].source);
2035 }
2036
2037 if (!uu_fast_scanning) {
2038 *errcode = UURET_CONT;
2039 fseek (datei, preheaders, SEEK_SET);
2040 }
2041 _FP_free (result);
2042 return NULL;
2043 }
2044 else if (IsKnownHeader (line)) {
2045 /* new message follows */
2046 sstate.isfolder = 1;
2047 sstate.ismime = 0;
2048 sstate.mimestate = MS_HEADERS;
2049 result->length = preheaders - result->startpos;
2050 fseek (datei, preheaders, SEEK_SET);
2051 }
2052 else if (ecount >= ELC_COUNT) {
2053 /* new plain encoding */
2054 sstate.isfolder = 0;
2055 sstate.ismime = 0;
2056 sstate.mimestate = MS_BODY;
2057 result->length = preenc - result->startpos;
2058 fseek (datei, preenc, SEEK_SET);
2059 }
2060
2061 /* produce result if uu_usepreamble is set */
2062 if (uu_usepreamble && res) {
2063 sprintf (line, "%04d.txt", ++mimseqno);
2064 result->subject = _FP_strdup (sstate.envelope.subject);
2065 result->filename = _FP_strdup (line);
2066 result->origin = _FP_strdup (sstate.envelope.from);
2067 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2068 result->mimetype = _FP_strdup ("text/plain");
2069 result->mode = 0644;
2070 result->uudet = PT_ENCODED; /* plain text */
2071 result->sfname = _FP_strdup (fname);
2072 result->flags = FL_SINGLE | FL_PROPER;
2073 result->partno = 1;
2074 /* result->startpos set from above */
2075 /* result->length set from above */
2076
2077 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
2078 result->filename == NULL || result->sfname == NULL) {
2079 *errcode = UURET_NOMEM;
2080 }
2081
2082 return result;
2083 }
2084 /* otherwise, just return NULL */
2085 _FP_free (result);
2086 return NULL;
2087 }
2088
2089 /*
2090 * Scan a new part from a Multipart message. Check for a new local
2091 * envelope (which defaults to `Content-Type: text/plain') and
2092 * evaluate its Content-Type and Content-Transfer-Encoding. If this
2093 * is another Multipart/something, push the current state onto our
2094 * stack and dive into the new environment, starting with another
2095 * preamble.
2096 */
2097
2098 if (sstate.ismime && sstate.mimestate == MS_SUBPART) {
2099 memset (&localenv, 0, sizeof (headers));
2100 result->startpos = ftell (datei);
2101 prevpos = ftell (datei);
2102 hcount = 0;
2103 lcount = 0;
2104
2105 /*
2106 * Duplicate some data from outer envelope
2107 */
2108
2109 localenv.mimevers = _FP_strdup (sstate.envelope.mimevers);
2110 localenv.from = _FP_strdup (sstate.envelope.from);
2111 localenv.subject = _FP_strdup (sstate.envelope.subject);
2112 localenv.rcpt = _FP_strdup (sstate.envelope.rcpt);
2113 localenv.date = _FP_strdup (sstate.envelope.date);
2114
2115 if ((sstate.envelope.mimevers != NULL && localenv.mimevers == NULL) ||
2116 (sstate.envelope.from != NULL && localenv.from == NULL) ||
2117 (sstate.envelope.subject != NULL && localenv.subject == NULL) ||
2118 (sstate.envelope.rcpt != NULL && localenv.rcpt == NULL) ||
2119 (sstate.envelope.date != NULL && localenv.date == NULL)) {
2120
2121 while (mssdepth) {
2122 mssdepth--;
2123 UUkillheaders (&(multistack[mssdepth].envelope));
2124 _FP_free (multistack[mssdepth].source);
2125 }
2126 sstate.isfolder = 0;
2127 sstate.ismime = 0;
2128
2129 UUkillheaders (&localenv);
2130 *errcode = UURET_NOMEM;
2131 _FP_free (result);
2132 return NULL;
2133 }
2134
2135 /* Scan subheader. But what if there is no subheader? */
2136 hcount = 0;
2137 lcount = 0;
2138 preheaders = prevpos;
2139
2140 if (_FP_fgets (line, 255, datei) == NULL) {
2141 sstate.isfolder = 0;
2142 sstate.ismime = 0;
2143 while (mssdepth) {
2144 mssdepth--;
2145 UUkillheaders (&(multistack[mssdepth].envelope));
2146 _FP_free (multistack[mssdepth].source);
2147 }
2148 UUkillheaders (&localenv);
2149 _FP_free (result);
2150 return NULL;
2151 }
2152 line[255] = '\0';
2153
2154 while (!feof (datei) && !IsLineEmpty (line)) {
2155 if (IsKnownHeader (line))
2156 hcount++;
2157 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2158 if (lcount > WAITHEADER && hcount == 0) {
2159 fseek (datei, preheaders, SEEK_SET);
2160 prevpos = preheaders;
2161 break;
2162 }
2163 ptr1 = ScanHeaderLine (datei, line);
2164 if (ParseHeader (&localenv, ptr1) == NULL)
2165 *errcode = UURET_NOMEM;
2166
2167 if (line[0] == '-' && line[1] == '-')
2168 break;
2169
2170 prevpos = ftell (datei);
2171
2172 if (_FP_fgets (line, 255, datei) == NULL)
2173 break;
2174 line[255] = '\0';
2175 lcount++;
2176 }
2177 if (line[0] == '-' && line[1] == '-') {
2178 /*
2179 * this shouldn't happen, there must always be an empty line,
2180 * but let's accept it anyway. Just skip back to before the
2181 * boundary, so that it gets handled below
2182 */
2183 fseek (datei, prevpos, SEEK_SET);
2184 }
2185
2186 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2187 /* oh no, not again */
2188 if (mssdepth >= MSMAXDEPTH) {
2189 /* Argh, what an isane message. Treat as plain text */
2190 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2191 uustring (S_MIME_MULTI_DEPTH));
2192 }
2193 else if (localenv.boundary == NULL) {
2194 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2195 uustring (S_MIME_NO_BOUNDARY));
2196 }
2197 else {
2198 memcpy (&multistack[mssdepth], &sstate, sizeof (scanstate));
2199 memcpy (&sstate.envelope, &localenv, sizeof (headers));
2200 memset (&localenv, 0, sizeof (headers));
2201 sstate.mimestate = MS_PREAMBLE;
2202 if ((sstate.source = _FP_strdup (sstate.source)) == NULL)
2203 *errcode = UURET_NOMEM;
2204
2205 if (*errcode == UURET_OK)
2206 *errcode = UURET_CONT;
2207
2208 mssdepth++;
2209 /* need a restart */
2210 _FP_free (result);
2211 return NULL;
2212 }
2213 }
2214
2215 /*
2216 * So this subpart is either plain text or something else. Check
2217 * the Content-Type and Content-Transfer-Encoding. If the latter
2218 * is a defined value, we know what to do and just copy everything
2219 * up to the boundary.
2220 * If Content-Transfer-Encoding is unknown or missing, look at the
2221 * Content-Type. If it's "text/plain" or undefined, we subject the
2222 * message to our encoding detection. Otherwise, treat as plain
2223 * text.
2224 * This is done because users might `attach' a uuencoded file, which
2225 * would then be correctly typed as `text/plain'.
2226 */
2227
2228 if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2229 result->uudet = B64ENCODED;
2230 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2231 result->uudet = UU_ENCODED;
2232 result->begin = result->end = 1;
2233 }
2234 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2235 result->uudet = YENC_ENCODED;
2236 result->begin = result->end = 1;
2237 }
2238 else if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2239 result->uudet = QP_ENCODED;
2240 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2241 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2242 result->uudet = PT_ENCODED;
2243 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2244 _FP_stristr (localenv.ctype, "message") != NULL)
2245 result->uudet = PT_ENCODED;
2246
2247 /*
2248 * If we're switched to MIME-only mode, handle as text
2249 */
2250
2251 if (uu_more_mime >= 2 && !result->uudet) {
2252 result->uudet = PT_ENCODED;
2253 }
2254
2255 if (result->uudet) {
2256 /*
2257 * Oh-kay, go ahead. Just read and wait for the boundary
2258 */
2259 result->startpos = ftell (datei);
2260 prevpos = ftell (datei);
2261 blen = strlen (sstate.envelope.boundary);
2262 lcount = 0;
2263
2264 while (!feof (datei)) {
2265 if (_FP_fgets (line, 255, datei) == NULL) {
2266 line[0] = '\0';
2267 break;
2268 }
2269 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2270 line[255] = '\0';
2271 if (line[0] == '-' && line[1] == '-' &&
2272 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2273 break;
2274 /*
2275 * I've had a report of someone who tried to decode a huge file
2276 * that had an early truncated multipart message and later another
2277 * multipart message with the *same* boundary. Consequently, all
2278 * some hundred messages inbetween were ignored ...
2279 * This check here doesn't cover folded header lines, but we don't
2280 * want to slow down scanning too much. We just check for
2281 * Content-Type: multipart/... boundary="same-boundary"
2282 */
2283 if (line[0] == 'C' && line[1] == 'o' &&
2284 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2285 ptr1 = ScanHeaderLine (datei, line);
2286 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2287 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2288 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2289 break;
2290 for (res=0; ptr1 && res<mssdepth; res++)
2291 if (strcmp (ptr1, multistack[res].envelope.boundary) == 0)
2292 break;
2293 if (res<mssdepth)
2294 break;
2295 }
2296 if (!IsLineEmpty (line))
2297 lcount++;
2298 prevpos = ftell (datei);
2299 }
2300 if (line[0] == '-' && line[1] == '-' &&
2301 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2302 ptr1 = line + 2 + blen;
2303 if (*ptr1 == '-' && *(ptr1+1) == '-')
2304 sstate.mimestate = MS_EPILOGUE;
2305 else
2306 sstate.mimestate = MS_SUBPART;
2307 }
2308 else {
2309 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2310 uustring (S_MIME_B_NOT_FOUND));
2311
2312 while (mssdepth) {
2313 mssdepth--;
2314 UUkillheaders (&(multistack[mssdepth].envelope));
2315 _FP_free (multistack[mssdepth].source);
2316 }
2317 /*
2318 * Don't retry if uu_fast_scanning
2319 */
2320
2321 if (uu_fast_scanning) {
2322 UUkillheaders (&localenv);
2323 sstate.isfolder = 0;
2324 sstate.ismime = 0;
2325 sstate.mimestate = MS_BODY;
2326 _FP_free (result);
2327 return NULL;
2328 }
2329
2330 /*
2331 * Retry, but listening to headers this time
2332 */
2333 fseek (datei, result->startpos, SEEK_SET);
2334
2335 UUkillfread (result);
2336 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2337 *errcode = UURET_NOMEM;
2338 sstate.isfolder = 0;
2339 sstate.ismime = 0;
2340 UUkillheaders (&localenv);
2341 return NULL;
2342 }
2343 memset (result, 0, sizeof (fileread));
2344
2345 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2346 /* oops, something went wrong */
2347 sstate.isfolder = 0;
2348 sstate.ismime = 0;
2349 UUkillfread (result);
2350 UUkillheaders (&localenv);
2351 return NULL;
2352 }
2353 if (res == 1) {
2354 /*
2355 * new headers found
2356 */
2357 sstate.isfolder = 1;
2358 sstate.ismime = 0;
2359 sstate.mimestate = MS_HEADERS;
2360 }
2361 else {
2362 sstate.isfolder = 0;
2363 sstate.ismime = 0;
2364 }
2365 }
2366 /* produce result if uu_handletext is set */
2367 /* or if the file is explicitely named */
2368 if (result->uudet == B64ENCODED || lcount) {
2369 if (localenv.fname) {
2370 _FP_free (result->filename);
2371 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2372 *errcode = UURET_NOMEM;
2373 }
2374 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
2375 result->filename == NULL && uu_handletext) {
2376 sprintf (line, "%04d.txt", ++mimseqno);
2377 if ((result->filename = _FP_strdup (line)) == NULL)
2378 *errcode = UURET_NOMEM;
2379 }
2380 result->subject = _FP_strdup (localenv.subject);
2381 result->origin = _FP_strdup (localenv.from);
2382 result->mimeid = _FP_strdup (localenv.mimeid);
2383 result->mimetype = _FP_strdup (localenv.ctype);
2384 result->mode = 0644;
2385 result->sfname = _FP_strdup (fname);
2386 result->flags = FL_SINGLE | FL_PROPER;
2387 result->partno = 1;
2388 /* result->uudet determined above */
2389 /* result->startpos set from above */
2390 result->length = prevpos - result->startpos;
2391
2392 if ((localenv.subject != NULL && result->subject == NULL) ||
2393 result->filename == NULL || result->sfname == NULL) {
2394 *errcode = UURET_NOMEM;
2395 }
2396 }
2397 else {
2398 /* don't produce a result */
2399 _FP_free (result);
2400 result = NULL;
2401 }
2402 if (*errcode == UURET_OK)
2403 *errcode = UURET_CONT;
2404 /*
2405 * destroy local envelope
2406 */
2407 UUkillheaders (&localenv);
2408 return result;
2409 }
2410
2411 /*
2412 * we're in a subpart, but the local headers don't give us any
2413 * clue about what's to find here. So look for encoded data by
2414 * ourselves.
2415 */
2416
2417 if ((res = ScanData (datei, fname, errcode,
2418 sstate.envelope.boundary,
2419 1, 0, result)) == -1) {
2420 /* oops, something went wrong */
2421 sstate.isfolder = 0;
2422 sstate.ismime = 0;
2423 UUkillfread (result);
2424 UUkillheaders (&localenv);
2425 return NULL;
2426 }
2427 /*
2428 * we should really be at a boundary here, but check again
2429 */
2430 blen = strlen (sstate.envelope.boundary);
2431 prevpos = ftell (datei);
2432
2433 while (!feof (datei)) {
2434 if (_FP_fgets (line, 255, datei) == NULL) {
2435 line[0] = '\0';
2436 break;
2437 }
2438 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2439 line[255] = '\0';
2440 if (line[0] == '-' && line[1] == '-' &&
2441 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2442 break;
2443 if (line[0] == 'C' && line[1] == 'o' &&
2444 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2445 ptr1 = ScanHeaderLine (datei, line);
2446 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2447 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2448 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2449 break;
2450 }
2451 prevpos = ftell (datei);
2452 }
2453 /*
2454 * check if this was the last subpart
2455 */
2456 if (line[0] == '-' && line[1] == '-' &&
2457 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2458 ptr1 = line + 2 + blen;
2459 if (*ptr1 == '-' && *(ptr1+1) == '-')
2460 sstate.mimestate = MS_EPILOGUE;
2461 else
2462 sstate.mimestate = MS_SUBPART;
2463 }
2464 else {
2465 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2466 uustring (S_MIME_B_NOT_FOUND));
2467
2468 while (mssdepth) {
2469 mssdepth--;
2470 UUkillheaders (&(multistack[mssdepth].envelope));
2471 _FP_free (multistack[mssdepth].source);
2472 }
2473
2474 if (uu_fast_scanning) {
2475 UUkillheaders (&localenv);
2476 sstate.isfolder = 0;
2477 sstate.ismime = 0;
2478 sstate.mimestate = MS_BODY;
2479 _FP_free (result);
2480 return NULL;
2481 }
2482
2483 /*
2484 * Retry, listening to headers this time
2485 */
2486 fseek (datei, result->startpos, SEEK_SET);
2487
2488 UUkillfread (result);
2489 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2490 *errcode = UURET_NOMEM;
2491 sstate.isfolder = 0;
2492 sstate.ismime = 0;
2493 UUkillheaders (&localenv);
2494 return NULL;
2495 }
2496 memset (result, 0, sizeof (fileread));
2497
2498 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2499 /* oops, something went wrong */
2500 sstate.isfolder = 0;
2501 sstate.ismime = 0;
2502 UUkillfread (result);
2503 UUkillheaders (&localenv);
2504 return NULL;
2505 }
2506 if (res == 1) {
2507 /*
2508 * new headers found
2509 */
2510 sstate.isfolder = 1;
2511 sstate.ismime = 0;
2512 sstate.mimestate = MS_HEADERS;
2513 }
2514 else {
2515 sstate.isfolder = 0;
2516 sstate.ismime = 0;
2517 }
2518 }
2519
2520 /*
2521 * If this file has been nicely MIME so far, then be very suspicious
2522 * if ScanData reports anything else. So do a double check, and if
2523 * it doesn't hold up, handle as plain text instead.
2524 */
2525
2526 if (sstate.ismime && sstate.mimestate == MS_SUBPART &&
2527 strcmp (localenv.mimevers, "1.0") == 0 &&
2528 _FP_stristr (localenv.ctype, "text") != NULL &&
2529 !uu_desperate) {
2530 if (result->uudet == UU_ENCODED && !(result->begin || result->end)) {
2531 result->uudet = 0;
2532 }
2533 }
2534
2535 /*
2536 * produce result
2537 */
2538
2539 if (result->uudet == 0) {
2540 result->uudet = PT_ENCODED; /* plain text */
2541 }
2542
2543 if (localenv.fname) {
2544 _FP_free (result->filename);
2545 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2546 *errcode = UURET_NOMEM;
2547 }
2548 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2549 result->filename==NULL && uu_handletext) {
2550 sprintf (line, "%04d.txt", ++mimseqno);
2551 if ((result->filename = _FP_strdup (line)) == NULL)
2552 *errcode = UURET_NOMEM;
2553 }
2554 else {
2555 /* assign a filename lateron */
2556 }
2557 if (result->mimetype) _FP_free (result->mimetype);
2558 if (result->uudet) {
2559 if (_FP_stristr (localenv.ctype, "text") != NULL &&
2560 result->uudet != QP_ENCODED && result->uudet != PT_ENCODED)
2561 result->mimetype = NULL; /* better don't set it */
2562 else
2563 result->mimetype = _FP_strdup (localenv.ctype);
2564 }
2565 if (result->origin) _FP_free (result->origin);
2566 result->origin = _FP_strdup (localenv.from);
2567
2568 if (result->subject) _FP_free (result->subject);
2569 result->subject = _FP_strdup (localenv.subject);
2570
2571 if (result->sfname == NULL)
2572 if ((result->sfname = _FP_strdup (fname)) == NULL)
2573 *errcode = UURET_NOMEM;
2574
2575 result->length = prevpos - result->startpos;
2576 result->flags = FL_SINGLE | FL_PROPER;
2577 result->partno = 1;
2578
2579 if (result->mode == 0)
2580 result->mode = 0644;
2581
2582 /*
2583 * the other fields should already be set appropriately
2584 */
2585
2586 if (*errcode == UURET_OK)
2587 *errcode = UURET_CONT;
2588
2589 /*
2590 * kill local envelope
2591 */
2592 UUkillheaders (&localenv);
2593
2594 return result;
2595 }
2596
2597 /*
2598 * All right, so we're not in a Multipart message. Phew, took quite
2599 * long to figure this out. But this might still be a MIME message
2600 * body. And if it's a message/partial, we need more special handling
2601 */
2602
2603 if (sstate.isfolder && sstate.ismime && sstate.mimestate == MS_BODY &&
2604 _FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2605 _FP_stristr (sstate.envelope.ctype, "partial") != NULL) {
2606
2607 result->startpos = ftell (datei);
2608
2609 if (sstate.envelope.partno == 1) {
2610 /* read local envelope */
2611 UUkillheaders (&localenv);
2612 memset (&localenv, 0, sizeof (headers));
2613
2614 /* skip over blank lines first */
2615 prevpos = ftell (datei);
2616 while (!feof (datei)) {
2617 if (_FP_fgets (line, 255, datei) == NULL)
2618 break;
2619 line[255] = '\0';
2620 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2621 if (!IsLineEmpty (line))
2622 break;
2623 prevpos = ftell (datei);
2624 }
2625 /* Next, read header. But what if there is no subheader? */
2626 hcount = 0;
2627 lcount = 0;
2628 preheaders = prevpos;
2629
2630 while (!feof (datei) && !IsLineEmpty (line)) {
2631 if (IsKnownHeader (line))
2632 hcount++;
2633 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2634 if (lcount > WAITHEADER && hcount == 0) {
2635 fseek (datei, preheaders, SEEK_SET);
2636 break;
2637 }
2638 ptr1 = ScanHeaderLine (datei, line);
2639 if (ParseHeader (&localenv, ptr1) == NULL)
2640 *errcode = UURET_NOMEM;
2641
2642 if (_FP_fgets (line, 255, datei) == NULL)
2643 break;
2644 line[255] = '\0';
2645 lcount++;
2646 }
2647 prevpos = ftell (datei);
2648 /*
2649 * Examine local header. We're mostly interested in the Content-Type
2650 * and the Content-Transfer-Encoding.
2651 */
2652 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2653 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2654 uustring (S_MIME_PART_MULTI));
2655 }
2656 if (localenv.subject)
2657 result->subject = _FP_strdup (localenv.subject);
2658 else
2659 result->subject = _FP_strdup (sstate.envelope.subject);
2660
2661 if (localenv.from)
2662 result->origin = _FP_strdup (localenv.from);
2663 else
2664 result->origin = _FP_strdup (sstate.envelope.from);
2665
2666 if (localenv.ctype)
2667 result->mimetype = _FP_strdup (localenv.ctype);
2668 else
2669 result->mimetype = _FP_strdup ("text/plain");
2670
2671 if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2672 result->uudet = QP_ENCODED;
2673 else if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2674 result->uudet = B64ENCODED;
2675 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2676 result->uudet = UU_ENCODED;
2677 result->begin = result->end = 1;
2678 }
2679 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2680 result->uudet = YENC_ENCODED;
2681 result->begin = result->end = 1;
2682 }
2683 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2684 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2685 result->uudet = PT_ENCODED;
2686 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2687 _FP_stristr (localenv.ctype, "message") != NULL)
2688 result->uudet = PT_ENCODED;
2689
2690 /*
2691 * If we're switched to MIME-only mode, handle as text
2692 */
2693
2694 if (uu_more_mime >= 2 && !result->uudet) {
2695 result->uudet = PT_ENCODED;
2696 }
2697 }
2698 else {
2699 memset (&localenv, 0, sizeof (headers));
2700 }
2701
2702 /*
2703 * If this is Quoted-Printable or Plain Text, just try looking
2704 * for the next message header. If uu_fast_scanning, and the
2705 * encoding is known, there's no need to look below. Otherwise,
2706 * we check the type of encoding first.
2707 * The encoding type is determined on the first part; in all
2708 * others, we also don't read on.
2709 * If we have a partial multipart message, scan for headers, but
2710 * do not react on standard MIME headers, as they are probably
2711 * from the subparts. However, we're stuck if there's an embedded
2712 * message/rfc822 :-(
2713 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2714 * the message header and then start looking for the next header.
2715 */
2716 if (uu_fast_scanning && (result->uudet!=0||sstate.envelope.partno!=1)) {
2717 /* do nothing */
2718 res = 0;
2719 }
2720 else if (result->uudet != 0) {
2721 hcount = lcount = 0;
2722 prevpos = ftell (datei);
2723
2724 if (_FP_stristr (localenv.ctype, "message") != NULL &&
2725 _FP_stristr (localenv.ctype, "rfc822") != NULL) {
2726 /*
2727 * skip over empty lines and local header
2728 */
2729 preheaders = ftell (datei);
2730 while (!feof (datei)) {
2731 if (_FP_fgets (line, 255, datei) == NULL)
2732 break;
2733 line[255] = '\0';
2734 if (!IsLineEmpty (line)) {
2735 break;
2736 }
2737 }
2738
2739 while (!feof (datei) && !IsLineEmpty (line)) {
2740 if (IsKnownHeader (line))
2741 hcount++;
2742 lcount++;
2743 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2744 break;
2745
2746 if (_FP_fgets (line, 255, datei) == NULL)
2747 break;
2748 line[255] = '\0';
2749 }
2750 if (hcount < hlcount.afternl)
2751 fseek (datei, preheaders, SEEK_SET);
2752 hcount = lcount = 0;
2753 }
2754
2755 /*
2756 * look for next header
2757 */
2758
2759 while (!feof (datei)) {
2760 if (_FP_fgets (line, 255, datei) == NULL)
2761 break;
2762 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2763 if (ferror (datei))
2764 break;
2765 line[255] = '\0';
2766
2767 if ((vflag = IsKnownHeader (line))) {
2768 (void) ScanHeaderLine (datei, line);
2769
2770 if (result->uudet != PT_ENCODED || vflag == 1) {
2771 if (hcount == 0)
2772 preheaders = prevpos;
2773 hcount++;
2774 lcount++;
2775 if (hcount >= hlcount.restart) {
2776 /*
2777 * Hey, a new header starts here
2778 */
2779 fseek (datei, preheaders, SEEK_SET);
2780 prevpos = preheaders;
2781 break;
2782 }
2783 }
2784 }
2785 else if (lcount > WAITHEADER) {
2786 hcount = 0;
2787 lcount = 0;
2788 }
2789 else if (hcount) {
2790 lcount++;
2791 }
2792 prevpos = ftell (datei);
2793 }
2794 res = 1;
2795 }
2796 else {
2797 /*
2798 * Otherwise, let's see what we can find ourself. No
2799 * boundary (NULL) but MIME, and respect new headers.
2800 */
2801 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
2802 /* oops, something went wrong */
2803 sstate.isfolder = 0;
2804 sstate.ismime = 0;
2805 UUkillfread (result);
2806 UUkillheaders (&localenv);
2807 return NULL;
2808 }
2809 if (result->uudet == 0 && uu_handletext)
2810 result->uudet = PT_ENCODED;
2811
2812 prevpos = ftell (datei);
2813 }
2814 /*
2815 * produce result
2816 */
2817 if (localenv.fname) {
2818 _FP_free (result->filename);
2819 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2820 *errcode = UURET_NOMEM;
2821 }
2822 else if (sstate.envelope.fname) {
2823 _FP_free (result->filename);
2824 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
2825 *errcode = UURET_NOMEM;
2826 }
2827 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2828 result->filename == NULL) {
2829 sprintf (line, "%04d.txt", ++mimseqno);
2830 if ((result->filename = _FP_strdup (line)) == NULL)
2831 *errcode = UURET_NOMEM;
2832 }
2833 else {
2834 /* assign a filename lateron */
2835 }
2836 if (result->subject == NULL) {
2837 if (sstate.envelope.subject)
2838 result->subject = _FP_strdup (sstate.envelope.subject);
2839 }
2840 result->partno = sstate.envelope.partno;
2841 result->maxpno = sstate.envelope.numparts;
2842 result->flags = FL_PARTIAL |
2843 ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) |
2844 ((uu_fast_scanning) ? FL_TOEND : 0);
2845 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2846 if (result->partno == 1)
2847 result->begin = 1;
2848
2849 if (uu_fast_scanning)
2850 result->length = progress.fsize - result->startpos;
2851 else
2852 result->length = prevpos - result->startpos;
2853
2854 if (result->sfname == NULL)
2855 result->sfname = _FP_strdup (fname);
2856
2857 if (result->mode == 0)
2858 result->mode = 0644;
2859
2860 /*
2861 * the other fields should already be set appropriately
2862 */
2863
2864 if (res == 1) {
2865 /*
2866 * new headers found
2867 */
2868 sstate.isfolder = 1;
2869 sstate.ismime = 0;
2870 sstate.mimestate = MS_HEADERS;
2871
2872 UUkillheaders (&sstate.envelope);
2873 memset (&sstate.envelope, 0, sizeof (headers));
2874 }
2875 else {
2876 /*
2877 * otherwise, this can't be a mail folder
2878 */
2879 sstate.isfolder = 0;
2880 sstate.ismime = 0;
2881 }
2882 /*
2883 * kill local envelope
2884 */
2885 UUkillheaders (&localenv);
2886 return result;
2887 }
2888
2889 /*
2890 * If this is a MIME body, honor a Content-Type different than
2891 * text/plain or a proper Content-Transfer-Encoding.
2892 * We also go in here if we have an assigned filename - this means
2893 * that we've had a Content-Disposition field, and we should probably
2894 * decode a plain-text segment with a filename.
2895 */
2896
2897 if (sstate.isfolder && sstate.ismime &&
2898 sstate.mimestate == MS_BODY &&
2899 (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL ||
2900 _FP_stristr (sstate.envelope.ctenc, "base64") != NULL ||
2901 _FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL ||
2902 _FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL ||
2903 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2904 sstate.envelope.fname != NULL)) {
2905
2906 if (sstate.envelope.subject)
2907 result->subject = _FP_strdup (sstate.envelope.subject);
2908 if (sstate.envelope.from)
2909 result->origin = _FP_strdup (sstate.envelope.from);
2910
2911 if (sstate.envelope.ctype)
2912 result->mimetype = _FP_strdup (sstate.envelope.ctype);
2913 else
2914 result->mimetype = _FP_strdup ("text/plain");
2915
2916 if (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL)
2917 result->uudet = QP_ENCODED;
2918 else if (_FP_stristr (sstate.envelope.ctenc, "base64") != NULL)
2919 result->uudet = B64ENCODED;
2920 else if (_FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL) {
2921 result->uudet = UU_ENCODED;
2922 result->begin = result->end = 1;
2923 }
2924 else if (_FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL) {
2925 result->uudet = YENC_ENCODED;
2926 }
2927 else if (_FP_stristr (sstate.envelope.ctenc, "7bit") != NULL ||
2928 _FP_stristr (sstate.envelope.ctenc, "8bit") != NULL)
2929 result->uudet = PT_ENCODED;
2930 else if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL ||
2931 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2932 sstate.envelope.fname != NULL)
2933 result->uudet = PT_ENCODED;
2934
2935 /*
2936 * If we're switched to MIME-only mode, handle as text
2937 */
2938
2939 if (uu_more_mime >= 2 && !result->uudet) {
2940 result->uudet = PT_ENCODED;
2941 }
2942
2943 result->startpos = prevpos = ftell (datei);
2944
2945 /*
2946 * If this is Quoted-Printable or Plain Text, just try looking
2947 * for the next message header. If uu_fast_scanning, we know
2948 * there won't be more headers.
2949 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2950 * the message header and then start looking for the next header.
2951 */
2952 if (result->uudet != 0 && uu_fast_scanning) {
2953 /* do nothing */
2954 res = 0;
2955 }
2956 else if (result->uudet != 0) {
2957 hcount = lcount = 0;
2958 prevpos = ftell (datei);
2959
2960 if (_FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2961 _FP_stristr (sstate.envelope.ctype, "rfc822") != NULL) {
2962 /*
2963 * skip over empty lines and local header
2964 */
2965 preheaders = ftell (datei);
2966 while (!feof (datei)) {
2967 if (_FP_fgets (line, 255, datei) == NULL)
2968 break;
2969 line[255] = '\0';
2970 if (!IsLineEmpty (line)) {
2971 break;
2972 }
2973 }
2974
2975 while (!feof (datei) && !IsLineEmpty (line)) {
2976 if (IsKnownHeader (line))
2977 hcount++;
2978 lcount++;
2979 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2980 break;
2981
2982 if (_FP_fgets (line, 255, datei) == NULL)
2983 break;
2984 line[255] = '\0';
2985 }
2986 if (hcount < hlcount.afternl)
2987 fseek (datei, preheaders, SEEK_SET);
2988 hcount = lcount = 0;
2989 }
2990
2991 /*
2992 * look for next header
2993 */
2994
2995 while (!feof (datei)) {
2996 if (_FP_fgets (line, 255, datei) == NULL)
2997 break;
2998 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2999 if (ferror (datei))
3000 break;
3001 line[255] = '\0';
3002
3003 if (IsKnownHeader (line)) {
3004 (void) ScanHeaderLine (datei, line);
3005 if (hcount == 0)
3006 preheaders = prevpos;
3007 hcount++;
3008 lcount++;
3009 if (hcount >= hlcount.restart) {
3010 /*
3011 * Hey, a new header starts here
3012 */
3013 fseek (datei, preheaders, SEEK_SET);
3014 prevpos = preheaders;
3015 break;
3016 }
3017 }
3018 else if (lcount > WAITHEADER) {
3019 hcount = 0;
3020 lcount = 0;
3021 }
3022 else if (hcount) {
3023 lcount++;
3024 }
3025 prevpos = ftell (datei);
3026 }
3027 res = 1;
3028 }
3029 else {
3030 /*
3031 * Otherwise, let's see what we can find ourself. No
3032 * boundary (NULL) but MIME, and respect new headers.
3033 */
3034 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
3035 /* oops, something went wrong */
3036 sstate.isfolder = 0;
3037 sstate.ismime = 0;
3038 UUkillfread (result);
3039 return NULL;
3040 }
3041 if (result->uudet == 0 && uu_handletext) {
3042 result->startpos = before; /* display headers */
3043 result->uudet = PT_ENCODED;
3044 }
3045
3046 prevpos = ftell (datei);
3047 }
3048 /*
3049 * produce result
3050 */
3051 if (sstate.envelope.fname) {
3052 _FP_free (result->filename);
3053 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3054 *errcode = UURET_NOMEM;
3055 }
3056 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3057 result->filename == NULL) {
3058 sprintf (line, "%04d.txt", ++mimseqno);
3059 if ((result->filename = _FP_strdup (line)) == NULL)
3060 *errcode = UURET_NOMEM;
3061 }
3062 else {
3063 /* assign a filename lateron */
3064 }
3065 if (result->subject == NULL) {
3066 if (sstate.envelope.subject)
3067 result->subject = _FP_strdup (sstate.envelope.subject);
3068 }
3069 result->flags = ((res==1||uu_fast_scanning)?FL_PROPER:0) |
3070 ((uu_fast_scanning) ? FL_TOEND : 0);
3071 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3072
3073 if (uu_fast_scanning)
3074 result->length = progress.fsize - result->startpos;
3075 else
3076 result->length = prevpos - result->startpos;
3077
3078 if (result->sfname == NULL)
3079 result->sfname = _FP_strdup (fname);
3080
3081 if (result->mode == 0)
3082 result->mode = 0644;
3083
3084 /*
3085 * the other fields should already be set appropriately
3086 */
3087
3088 if (res == 1) {
3089 /*
3090 * new headers found
3091 */
3092 sstate.isfolder = 1;
3093 sstate.ismime = 0;
3094 sstate.mimestate = MS_HEADERS;
3095
3096 UUkillheaders (&sstate.envelope);
3097 memset (&sstate.envelope, 0, sizeof (headers));
3098 }
3099 else {
3100 /*
3101 * otherwise, this can't be a mail folder
3102 */
3103 sstate.isfolder = 0;
3104 sstate.ismime = 0;
3105 }
3106
3107 return result;
3108 }
3109
3110 /*
3111 * Some files have reduced headers, and what should be a multipart
3112 * message is missing the proper Content-Type. If the first thing
3113 * we find after a couple of empty lines is a boundary, try it!
3114 * But make sure that this is indeed intended as being a boundary.
3115 *
3116 * Only accept it if there was indeed no Content-Type header line
3117 * and if the following line is a proper Content-Type header. BTW,
3118 * we know that sstate.envelope.boundary is NULL, or we wouldn't
3119 * be here!
3120 */
3121
3122 if ((sstate.envelope.ctype == NULL ||
3123 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL) &&
3124 !uu_more_mime) {
3125 prevpos = ftell (datei);
3126 while (!feof (datei)) {
3127 if (_FP_fgets (line, 255, datei) == NULL) {
3128 line[0] = '\0';
3129 break;
3130 }
3131 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
3132 if (!IsLineEmpty (line))
3133 break;
3134 }
3135 if (line[0] == '-' && line[1] == '-' &&
3136 !IsLineEmpty (line+2) && !feof (datei)) {
3137 ptr1 = _FP_strrstr (line+2, "--");
3138 ptr2 = ScanHeaderLine (datei, NULL);
3139 if ((ptr1 == NULL || (*(ptr1+2) != '\012' && *(ptr1+2) != '\015')) &&
3140 ptr2 && _FP_strnicmp (ptr2, "Content-", 8) == 0) {
3141 /*
3142 * hmm, okay, let's do it!
3143 */
3144 sstate.isfolder = 1;
3145 sstate.ismime = 1;
3146 sstate.mimestate = MS_PREAMBLE;
3147 /*
3148 * get boundary
3149 */
3150 ptr1 = line+2;
3151 while (*ptr1 && !isspace(*ptr1))
3152 ptr1++;
3153 *ptr1 = '\0';
3154
3155 sstate.envelope.mimevers = _FP_strdup ("1.0");
3156 sstate.envelope.boundary = _FP_strdup (line+2);
3157
3158 /*
3159 * need restart
3160 */
3161
3162 fseek (datei, prevpos, SEEK_SET);
3163
3164 _FP_free (result);
3165 return NULL;
3166 }
3167 }
3168 fseek (datei, prevpos, SEEK_SET);
3169 }
3170
3171 /*
3172 * Hmm, we're not in a ''special'' state, so it's more or less
3173 * Freestyle time. Anyway, if this seems to be a Mime message,
3174 * don't allow the minimal Base64 handling.
3175 */
3176
3177 if (sstate.envelope.subject)
3178 result->subject = _FP_strdup (sstate.envelope.subject);
3179 if (sstate.envelope.from)
3180 result->origin = _FP_strdup (sstate.envelope.from);
3181
3182 if (sstate.envelope.ctype)
3183 result->mimetype = _FP_strdup (sstate.envelope.ctype);
3184
3185 if ((res=ScanData (datei, fname, errcode, NULL,
3186 sstate.ismime, 1, result))==-1) {
3187 /* oops, something went wrong */
3188 sstate.isfolder = 0;
3189 sstate.ismime = 0;
3190 UUkillfread (result);
3191 return NULL;
3192 }
3193
3194 /*
3195 * produce result
3196 */
3197
3198 if (result->uudet == 0 && uu_handletext) {
3199 result->startpos = before; /* display headers */
3200 result->uudet = PT_ENCODED;
3201 result->partno = 1;
3202 }
3203
3204 if (result->uudet == YENC_ENCODED && result->filename != NULL) {
3205 /*
3206 * prevent replacing the filename found on the =ybegin line
3207 */
3208 }
3209 else if (sstate.envelope.fname) {
3210 _FP_free (result->filename);
3211 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3212 *errcode = UURET_NOMEM;
3213 }
3214 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3215 result->filename == NULL) {
3216 sprintf (line, "%04d.txt", ++mimseqno);
3217 if ((result->filename = _FP_strdup (line)) == NULL)
3218 *errcode = UURET_NOMEM;
3219 }
3220 else {
3221 /* assign a filename lateron */
3222 }
3223
3224 if (result->subject == NULL) {
3225 if (sstate.envelope.subject)
3226 result->subject = _FP_strdup (sstate.envelope.subject);
3227 }
3228
3229 result->flags = (result->uudet==PT_ENCODED)?FL_SINGLE:0;
3230 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3231 result->length = ftell (datei) - result->startpos;
3232
3233 if (result->mode == 0)
3234 result->mode = 0644;
3235
3236 if (result->sfname == NULL)
3237 result->sfname = _FP_strdup (fname);
3238
3239 if (res == 1) {
3240 /*
3241 * new headers found
3242 */
3243 sstate.isfolder = 1;
3244 sstate.ismime = 0;
3245 sstate.mimestate = MS_HEADERS;
3246
3247 UUkillheaders (&sstate.envelope);
3248 memset (&sstate.envelope, 0, sizeof (headers));
3249 }
3250 else {
3251 /*
3252 * otherwise, this can't be a mail folder
3253 */
3254 sstate.isfolder = 0;
3255 sstate.ismime = 0;
3256 }
3257
3258 return result;
3259
3260 /*
3261 * Emergency handling. Set errcode before jumping here.
3262 */
3263 ScanPartEmergency:
3264 UUkillfread (result);
3265 UUkillheaders (&localenv);
3266
3267 while (mssdepth) {
3268 mssdepth--;
3269 UUkillheaders (&(multistack[mssdepth].envelope));
3270 _FP_free (multistack[mssdepth].source);
3271 }
3272
3273 return NULL;
3274 }
3275