ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Convert-UUlib/uulib/uuscan.c
Revision: 1.10
Committed: Tue Feb 22 20:11:57 2005 UTC (19 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-0_7, rel-1_06, rel-1_05, rel-1_08
Changes since 1.9: +1 -2 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 || vflag == B64ENCODED) && begflag) {
1980 if (++ecount >= ELC_COUNT)
1981 break;
1982 }
1983 else {
1984 begflag = 0;
1985 ecount = 0;
1986 }
1987 }
1988 else {
1989 begflag = 0;
1990 ecount = 0;
1991 }
1992 }
1993
1994 if (!IsLineEmpty (line))
1995 res++;
1996
1997 prevpos = ftell (datei);
1998 }
1999
2000 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
2001 strncmp (line+2,
2002 multistack[mssdepth-1].envelope.boundary, blen) == 0) {
2003 /* restore previous state */
2004 mssdepth--;
2005 UUkillheaders (&sstate.envelope);
2006 _FP_free (sstate.source);
2007 memcpy (&sstate, &(multistack[mssdepth]), sizeof (scanstate));
2008
2009 ptr1 = line + 2 + strlen (sstate.envelope.boundary);
2010
2011 if (*ptr1 == '-' && *(ptr1+1) == '-') {
2012 sstate.mimestate = MS_EPILOGUE;
2013 }
2014 else {
2015 sstate.mimestate = MS_SUBPART;
2016 }
2017 result->length = prevpos - result->startpos;
2018 *errcode = UURET_CONT;
2019 }
2020 else if (mssdepth > 0) {
2021 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2022 uustring (S_MIME_B_NOT_FOUND));
2023 /*
2024 * restart and try again; don't restart if uu_fast_scanning
2025 */
2026 sstate.isfolder = 0;
2027 sstate.ismime = 0;
2028 sstate.mimestate = MS_BODY;
2029
2030 while (mssdepth) {
2031 mssdepth--;
2032 UUkillheaders (&(multistack[mssdepth].envelope));
2033 _FP_free (multistack[mssdepth].source);
2034 }
2035
2036 if (!uu_fast_scanning) {
2037 *errcode = UURET_CONT;
2038 fseek (datei, preheaders, SEEK_SET);
2039 }
2040 _FP_free (result);
2041 return NULL;
2042 }
2043 else if (IsKnownHeader (line)) {
2044 /* new message follows */
2045 sstate.isfolder = 1;
2046 sstate.ismime = 0;
2047 sstate.mimestate = MS_HEADERS;
2048 result->length = preheaders - result->startpos;
2049 fseek (datei, preheaders, SEEK_SET);
2050 }
2051 else if (ecount >= ELC_COUNT) {
2052 /* new plain encoding */
2053 sstate.isfolder = 0;
2054 sstate.ismime = 0;
2055 sstate.mimestate = MS_BODY;
2056 result->length = preenc - result->startpos;
2057 fseek (datei, preenc, SEEK_SET);
2058 }
2059
2060 /* produce result if uu_usepreamble is set */
2061 if (uu_usepreamble && res) {
2062 sprintf (line, "%04d.txt", ++mimseqno);
2063 result->subject = _FP_strdup (sstate.envelope.subject);
2064 result->filename = _FP_strdup (line);
2065 result->origin = _FP_strdup (sstate.envelope.from);
2066 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2067 result->mimetype = _FP_strdup ("text/plain");
2068 result->mode = 0644;
2069 result->uudet = PT_ENCODED; /* plain text */
2070 result->sfname = _FP_strdup (fname);
2071 result->flags = FL_SINGLE | FL_PROPER;
2072 result->partno = 1;
2073 /* result->startpos set from above */
2074 /* result->length set from above */
2075
2076 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
2077 result->filename == NULL || result->sfname == NULL) {
2078 *errcode = UURET_NOMEM;
2079 }
2080
2081 return result;
2082 }
2083 /* otherwise, just return NULL */
2084 _FP_free (result);
2085 return NULL;
2086 }
2087
2088 /*
2089 * Scan a new part from a Multipart message. Check for a new local
2090 * envelope (which defaults to `Content-Type: text/plain') and
2091 * evaluate its Content-Type and Content-Transfer-Encoding. If this
2092 * is another Multipart/something, push the current state onto our
2093 * stack and dive into the new environment, starting with another
2094 * preamble.
2095 */
2096
2097 if (sstate.ismime && sstate.mimestate == MS_SUBPART) {
2098 memset (&localenv, 0, sizeof (headers));
2099 result->startpos = ftell (datei);
2100 prevpos = ftell (datei);
2101 hcount = 0;
2102 lcount = 0;
2103
2104 /*
2105 * Duplicate some data from outer envelope
2106 */
2107
2108 localenv.mimevers = _FP_strdup (sstate.envelope.mimevers);
2109 localenv.from = _FP_strdup (sstate.envelope.from);
2110 localenv.subject = _FP_strdup (sstate.envelope.subject);
2111 localenv.rcpt = _FP_strdup (sstate.envelope.rcpt);
2112 localenv.date = _FP_strdup (sstate.envelope.date);
2113
2114 if ((sstate.envelope.mimevers != NULL && localenv.mimevers == NULL) ||
2115 (sstate.envelope.from != NULL && localenv.from == NULL) ||
2116 (sstate.envelope.subject != NULL && localenv.subject == NULL) ||
2117 (sstate.envelope.rcpt != NULL && localenv.rcpt == NULL) ||
2118 (sstate.envelope.date != NULL && localenv.date == NULL)) {
2119
2120 while (mssdepth) {
2121 mssdepth--;
2122 UUkillheaders (&(multistack[mssdepth].envelope));
2123 _FP_free (multistack[mssdepth].source);
2124 }
2125 sstate.isfolder = 0;
2126 sstate.ismime = 0;
2127
2128 UUkillheaders (&localenv);
2129 *errcode = UURET_NOMEM;
2130 _FP_free (result);
2131 return NULL;
2132 }
2133
2134 /* Scan subheader. But what if there is no subheader? */
2135 hcount = 0;
2136 lcount = 0;
2137 preheaders = prevpos;
2138
2139 if (_FP_fgets (line, 255, datei) == NULL) {
2140 sstate.isfolder = 0;
2141 sstate.ismime = 0;
2142 while (mssdepth) {
2143 mssdepth--;
2144 UUkillheaders (&(multistack[mssdepth].envelope));
2145 _FP_free (multistack[mssdepth].source);
2146 }
2147 UUkillheaders (&localenv);
2148 _FP_free (result);
2149 return NULL;
2150 }
2151 line[255] = '\0';
2152
2153 while (!feof (datei) && !IsLineEmpty (line)) {
2154 if (IsKnownHeader (line))
2155 hcount++;
2156 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2157 if (lcount > WAITHEADER && hcount == 0) {
2158 fseek (datei, preheaders, SEEK_SET);
2159 prevpos = preheaders;
2160 break;
2161 }
2162 ptr1 = ScanHeaderLine (datei, line);
2163 if (ParseHeader (&localenv, ptr1) == NULL)
2164 *errcode = UURET_NOMEM;
2165
2166 if (line[0] == '-' && line[1] == '-')
2167 break;
2168
2169 prevpos = ftell (datei);
2170
2171 if (_FP_fgets (line, 255, datei) == NULL)
2172 break;
2173 line[255] = '\0';
2174 lcount++;
2175 }
2176 if (line[0] == '-' && line[1] == '-') {
2177 /*
2178 * this shouldn't happen, there must always be an empty line,
2179 * but let's accept it anyway. Just skip back to before the
2180 * boundary, so that it gets handled below
2181 */
2182 fseek (datei, prevpos, SEEK_SET);
2183 }
2184
2185 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2186 /* oh no, not again */
2187 if (mssdepth >= MSMAXDEPTH) {
2188 /* Argh, what an isane message. Treat as plain text */
2189 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2190 uustring (S_MIME_MULTI_DEPTH));
2191 }
2192 else if (localenv.boundary == NULL) {
2193 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2194 uustring (S_MIME_NO_BOUNDARY));
2195 }
2196 else {
2197 memcpy (&multistack[mssdepth], &sstate, sizeof (scanstate));
2198 memcpy (&sstate.envelope, &localenv, sizeof (headers));
2199 memset (&localenv, 0, sizeof (headers));
2200 sstate.mimestate = MS_PREAMBLE;
2201 if ((sstate.source = _FP_strdup (sstate.source)) == NULL)
2202 *errcode = UURET_NOMEM;
2203
2204 if (*errcode == UURET_OK)
2205 *errcode = UURET_CONT;
2206
2207 mssdepth++;
2208 /* need a restart */
2209 _FP_free (result);
2210 return NULL;
2211 }
2212 }
2213
2214 /*
2215 * So this subpart is either plain text or something else. Check
2216 * the Content-Type and Content-Transfer-Encoding. If the latter
2217 * is a defined value, we know what to do and just copy everything
2218 * up to the boundary.
2219 * If Content-Transfer-Encoding is unknown or missing, look at the
2220 * Content-Type. If it's "text/plain" or undefined, we subject the
2221 * message to our encoding detection. Otherwise, treat as plain
2222 * text.
2223 * This is done because users might `attach' a uuencoded file, which
2224 * would then be correctly typed as `text/plain'.
2225 */
2226
2227 if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2228 result->uudet = B64ENCODED;
2229 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2230 result->uudet = UU_ENCODED;
2231 result->begin = result->end = 1;
2232 }
2233 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2234 result->uudet = YENC_ENCODED;
2235 result->begin = result->end = 1;
2236 }
2237 else if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2238 result->uudet = QP_ENCODED;
2239 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2240 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2241 result->uudet = PT_ENCODED;
2242 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2243 _FP_stristr (localenv.ctype, "message") != NULL)
2244 result->uudet = PT_ENCODED;
2245
2246 /*
2247 * If we're switched to MIME-only mode, handle as text
2248 */
2249
2250 if (uu_more_mime >= 2 && !result->uudet) {
2251 result->uudet = PT_ENCODED;
2252 }
2253
2254 if (result->uudet) {
2255 /*
2256 * Oh-kay, go ahead. Just read and wait for the boundary
2257 */
2258 result->startpos = ftell (datei);
2259 prevpos = ftell (datei);
2260 blen = strlen (sstate.envelope.boundary);
2261 lcount = 0;
2262
2263 while (!feof (datei)) {
2264 if (_FP_fgets (line, 255, datei) == NULL) {
2265 line[0] = '\0';
2266 break;
2267 }
2268 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2269 line[255] = '\0';
2270 if (line[0] == '-' && line[1] == '-' &&
2271 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2272 break;
2273 /*
2274 * I've had a report of someone who tried to decode a huge file
2275 * that had an early truncated multipart message and later another
2276 * multipart message with the *same* boundary. Consequently, all
2277 * some hundred messages inbetween were ignored ...
2278 * This check here doesn't cover folded header lines, but we don't
2279 * want to slow down scanning too much. We just check for
2280 * Content-Type: multipart/... boundary="same-boundary"
2281 */
2282 if (line[0] == 'C' && line[1] == 'o' &&
2283 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2284 ptr1 = ScanHeaderLine (datei, line);
2285 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2286 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2287 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2288 break;
2289 for (res=0; ptr1 && res<mssdepth; res++)
2290 if (strcmp (ptr1, multistack[res].envelope.boundary) == 0)
2291 break;
2292 if (res<mssdepth)
2293 break;
2294 }
2295 if (!IsLineEmpty (line))
2296 lcount++;
2297 prevpos = ftell (datei);
2298 }
2299 if (line[0] == '-' && line[1] == '-' &&
2300 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2301 ptr1 = line + 2 + blen;
2302 if (*ptr1 == '-' && *(ptr1+1) == '-')
2303 sstate.mimestate = MS_EPILOGUE;
2304 else
2305 sstate.mimestate = MS_SUBPART;
2306 }
2307 else {
2308 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2309 uustring (S_MIME_B_NOT_FOUND));
2310
2311 while (mssdepth) {
2312 mssdepth--;
2313 UUkillheaders (&(multistack[mssdepth].envelope));
2314 _FP_free (multistack[mssdepth].source);
2315 }
2316 /*
2317 * Don't retry if uu_fast_scanning
2318 */
2319
2320 if (uu_fast_scanning) {
2321 UUkillheaders (&localenv);
2322 sstate.isfolder = 0;
2323 sstate.ismime = 0;
2324 sstate.mimestate = MS_BODY;
2325 _FP_free (result);
2326 return NULL;
2327 }
2328
2329 /*
2330 * Retry, but listening to headers this time
2331 */
2332 fseek (datei, result->startpos, SEEK_SET);
2333
2334 UUkillfread (result);
2335 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2336 *errcode = UURET_NOMEM;
2337 sstate.isfolder = 0;
2338 sstate.ismime = 0;
2339 UUkillheaders (&localenv);
2340 return NULL;
2341 }
2342 memset (result, 0, sizeof (fileread));
2343
2344 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2345 /* oops, something went wrong */
2346 sstate.isfolder = 0;
2347 sstate.ismime = 0;
2348 UUkillfread (result);
2349 UUkillheaders (&localenv);
2350 return NULL;
2351 }
2352 if (res == 1) {
2353 /*
2354 * new headers found
2355 */
2356 sstate.isfolder = 1;
2357 sstate.ismime = 0;
2358 sstate.mimestate = MS_HEADERS;
2359 }
2360 else {
2361 sstate.isfolder = 0;
2362 sstate.ismime = 0;
2363 }
2364 }
2365 /* produce result if uu_handletext is set */
2366 /* or if the file is explicitely named */
2367 if (result->uudet == B64ENCODED || lcount) {
2368 if (localenv.fname) {
2369 _FP_free (result->filename);
2370 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2371 *errcode = UURET_NOMEM;
2372 }
2373 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
2374 result->filename == NULL && uu_handletext) {
2375 sprintf (line, "%04d.txt", ++mimseqno);
2376 if ((result->filename = _FP_strdup (line)) == NULL)
2377 *errcode = UURET_NOMEM;
2378 }
2379 result->subject = _FP_strdup (localenv.subject);
2380 result->origin = _FP_strdup (localenv.from);
2381 result->mimeid = _FP_strdup (localenv.mimeid);
2382 result->mimetype = _FP_strdup (localenv.ctype);
2383 result->mode = 0644;
2384 result->sfname = _FP_strdup (fname);
2385 result->flags = FL_SINGLE | FL_PROPER;
2386 result->partno = 1;
2387 /* result->uudet determined above */
2388 /* result->startpos set from above */
2389 result->length = prevpos - result->startpos;
2390
2391 if ((localenv.subject != NULL && result->subject == NULL) ||
2392 result->filename == NULL || result->sfname == NULL) {
2393 *errcode = UURET_NOMEM;
2394 }
2395 }
2396 else {
2397 /* don't produce a result */
2398 _FP_free (result);
2399 result = NULL;
2400 }
2401 if (*errcode == UURET_OK)
2402 *errcode = UURET_CONT;
2403 /*
2404 * destroy local envelope
2405 */
2406 UUkillheaders (&localenv);
2407 return result;
2408 }
2409
2410 /*
2411 * we're in a subpart, but the local headers don't give us any
2412 * clue about what's to find here. So look for encoded data by
2413 * ourselves.
2414 */
2415
2416 if ((res = ScanData (datei, fname, errcode,
2417 sstate.envelope.boundary,
2418 1, 0, result)) == -1) {
2419 /* oops, something went wrong */
2420 sstate.isfolder = 0;
2421 sstate.ismime = 0;
2422 UUkillfread (result);
2423 UUkillheaders (&localenv);
2424 return NULL;
2425 }
2426 /*
2427 * we should really be at a boundary here, but check again
2428 */
2429 blen = strlen (sstate.envelope.boundary);
2430 prevpos = ftell (datei);
2431
2432 while (!feof (datei)) {
2433 if (_FP_fgets (line, 255, datei) == NULL) {
2434 line[0] = '\0';
2435 break;
2436 }
2437 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2438 line[255] = '\0';
2439 if (line[0] == '-' && line[1] == '-' &&
2440 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2441 break;
2442 if (line[0] == 'C' && line[1] == 'o' &&
2443 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2444 ptr1 = ScanHeaderLine (datei, line);
2445 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2446 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2447 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2448 break;
2449 }
2450 prevpos = ftell (datei);
2451 }
2452 /*
2453 * check if this was the last subpart
2454 */
2455 if (line[0] == '-' && line[1] == '-' &&
2456 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2457 ptr1 = line + 2 + blen;
2458 if (*ptr1 == '-' && *(ptr1+1) == '-')
2459 sstate.mimestate = MS_EPILOGUE;
2460 else
2461 sstate.mimestate = MS_SUBPART;
2462 }
2463 else {
2464 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2465 uustring (S_MIME_B_NOT_FOUND));
2466
2467 while (mssdepth) {
2468 mssdepth--;
2469 UUkillheaders (&(multistack[mssdepth].envelope));
2470 _FP_free (multistack[mssdepth].source);
2471 }
2472
2473 if (uu_fast_scanning) {
2474 UUkillheaders (&localenv);
2475 sstate.isfolder = 0;
2476 sstate.ismime = 0;
2477 sstate.mimestate = MS_BODY;
2478 _FP_free (result);
2479 return NULL;
2480 }
2481
2482 /*
2483 * Retry, listening to headers this time
2484 */
2485 fseek (datei, result->startpos, SEEK_SET);
2486
2487 UUkillfread (result);
2488 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2489 *errcode = UURET_NOMEM;
2490 sstate.isfolder = 0;
2491 sstate.ismime = 0;
2492 UUkillheaders (&localenv);
2493 return NULL;
2494 }
2495 memset (result, 0, sizeof (fileread));
2496
2497 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2498 /* oops, something went wrong */
2499 sstate.isfolder = 0;
2500 sstate.ismime = 0;
2501 UUkillfread (result);
2502 UUkillheaders (&localenv);
2503 return NULL;
2504 }
2505 if (res == 1) {
2506 /*
2507 * new headers found
2508 */
2509 sstate.isfolder = 1;
2510 sstate.ismime = 0;
2511 sstate.mimestate = MS_HEADERS;
2512 }
2513 else {
2514 sstate.isfolder = 0;
2515 sstate.ismime = 0;
2516 }
2517 }
2518
2519 /*
2520 * If this file has been nicely MIME so far, then be very suspicious
2521 * if ScanData reports anything else. So do a double check, and if
2522 * it doesn't hold up, handle as plain text instead.
2523 */
2524
2525 if (sstate.ismime && sstate.mimestate == MS_SUBPART &&
2526 strcmp (localenv.mimevers, "1.0") == 0 &&
2527 _FP_stristr (localenv.ctype, "text") != NULL &&
2528 !uu_desperate) {
2529 if (result->uudet == UU_ENCODED && !(result->begin || result->end)) {
2530 result->uudet = 0;
2531 }
2532 }
2533
2534 /*
2535 * produce result
2536 */
2537
2538 if (result->uudet == 0) {
2539 result->uudet = PT_ENCODED; /* plain text */
2540 }
2541
2542 if (localenv.fname) {
2543 _FP_free (result->filename);
2544 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2545 *errcode = UURET_NOMEM;
2546 }
2547 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2548 result->filename==NULL && uu_handletext) {
2549 sprintf (line, "%04d.txt", ++mimseqno);
2550 if ((result->filename = _FP_strdup (line)) == NULL)
2551 *errcode = UURET_NOMEM;
2552 }
2553 else {
2554 /* assign a filename lateron */
2555 }
2556 if (result->mimetype) _FP_free (result->mimetype);
2557 if (result->uudet) {
2558 if (_FP_stristr (localenv.ctype, "text") != NULL &&
2559 result->uudet != QP_ENCODED && result->uudet != PT_ENCODED)
2560 result->mimetype = NULL; /* better don't set it */
2561 else
2562 result->mimetype = _FP_strdup (localenv.ctype);
2563 }
2564 if (result->origin) _FP_free (result->origin);
2565 result->origin = _FP_strdup (localenv.from);
2566
2567 if (result->subject) _FP_free (result->subject);
2568 result->subject = _FP_strdup (localenv.subject);
2569
2570 if (result->sfname == NULL)
2571 if ((result->sfname = _FP_strdup (fname)) == NULL)
2572 *errcode = UURET_NOMEM;
2573
2574 result->length = prevpos - result->startpos;
2575 result->flags = FL_SINGLE | FL_PROPER;
2576 result->partno = 1;
2577
2578 if (result->mode == 0)
2579 result->mode = 0644;
2580
2581 /*
2582 * the other fields should already be set appropriately
2583 */
2584
2585 if (*errcode == UURET_OK)
2586 *errcode = UURET_CONT;
2587
2588 /*
2589 * kill local envelope
2590 */
2591 UUkillheaders (&localenv);
2592
2593 return result;
2594 }
2595
2596 /*
2597 * All right, so we're not in a Multipart message. Phew, took quite
2598 * long to figure this out. But this might still be a MIME message
2599 * body. And if it's a message/partial, we need more special handling
2600 */
2601
2602 if (sstate.isfolder && sstate.ismime && sstate.mimestate == MS_BODY &&
2603 _FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2604 _FP_stristr (sstate.envelope.ctype, "partial") != NULL) {
2605
2606 result->startpos = ftell (datei);
2607
2608 if (sstate.envelope.partno == 1) {
2609 /* read local envelope */
2610 UUkillheaders (&localenv);
2611 memset (&localenv, 0, sizeof (headers));
2612
2613 /* skip over blank lines first */
2614 prevpos = ftell (datei);
2615 while (!feof (datei)) {
2616 if (_FP_fgets (line, 255, datei) == NULL)
2617 break;
2618 line[255] = '\0';
2619 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2620 if (!IsLineEmpty (line))
2621 break;
2622 prevpos = ftell (datei);
2623 }
2624 /* Next, read header. But what if there is no subheader? */
2625 hcount = 0;
2626 lcount = 0;
2627 preheaders = prevpos;
2628
2629 while (!feof (datei) && !IsLineEmpty (line)) {
2630 if (IsKnownHeader (line))
2631 hcount++;
2632 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2633 if (lcount > WAITHEADER && hcount == 0) {
2634 fseek (datei, preheaders, SEEK_SET);
2635 break;
2636 }
2637 ptr1 = ScanHeaderLine (datei, line);
2638 if (ParseHeader (&localenv, ptr1) == NULL)
2639 *errcode = UURET_NOMEM;
2640
2641 if (_FP_fgets (line, 255, datei) == NULL)
2642 break;
2643 line[255] = '\0';
2644 lcount++;
2645 }
2646 prevpos = ftell (datei);
2647 /*
2648 * Examine local header. We're mostly interested in the Content-Type
2649 * and the Content-Transfer-Encoding.
2650 */
2651 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2652 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2653 uustring (S_MIME_PART_MULTI));
2654 }
2655 if (localenv.subject)
2656 result->subject = _FP_strdup (localenv.subject);
2657 else
2658 result->subject = _FP_strdup (sstate.envelope.subject);
2659
2660 if (localenv.from)
2661 result->origin = _FP_strdup (localenv.from);
2662 else
2663 result->origin = _FP_strdup (sstate.envelope.from);
2664
2665 if (localenv.ctype)
2666 result->mimetype = _FP_strdup (localenv.ctype);
2667 else
2668 result->mimetype = _FP_strdup ("text/plain");
2669
2670 if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2671 result->uudet = QP_ENCODED;
2672 else if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2673 result->uudet = B64ENCODED;
2674 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2675 result->uudet = UU_ENCODED;
2676 result->begin = result->end = 1;
2677 }
2678 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2679 result->uudet = YENC_ENCODED;
2680 result->begin = result->end = 1;
2681 }
2682 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2683 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2684 result->uudet = PT_ENCODED;
2685 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2686 _FP_stristr (localenv.ctype, "message") != NULL)
2687 result->uudet = PT_ENCODED;
2688
2689 /*
2690 * If we're switched to MIME-only mode, handle as text
2691 */
2692
2693 if (uu_more_mime >= 2 && !result->uudet) {
2694 result->uudet = PT_ENCODED;
2695 }
2696 }
2697 else {
2698 memset (&localenv, 0, sizeof (headers));
2699 }
2700
2701 /*
2702 * If this is Quoted-Printable or Plain Text, just try looking
2703 * for the next message header. If uu_fast_scanning, and the
2704 * encoding is known, there's no need to look below. Otherwise,
2705 * we check the type of encoding first.
2706 * The encoding type is determined on the first part; in all
2707 * others, we also don't read on.
2708 * If we have a partial multipart message, scan for headers, but
2709 * do not react on standard MIME headers, as they are probably
2710 * from the subparts. However, we're stuck if there's an embedded
2711 * message/rfc822 :-(
2712 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2713 * the message header and then start looking for the next header.
2714 */
2715 if (uu_fast_scanning && (result->uudet!=0||sstate.envelope.partno!=1)) {
2716 /* do nothing */
2717 res = 0;
2718 }
2719 else if (result->uudet != 0) {
2720 hcount = lcount = 0;
2721 prevpos = ftell (datei);
2722
2723 if (_FP_stristr (localenv.ctype, "message") != NULL &&
2724 _FP_stristr (localenv.ctype, "rfc822") != NULL) {
2725 /*
2726 * skip over empty lines and local header
2727 */
2728 preheaders = ftell (datei);
2729 while (!feof (datei)) {
2730 if (_FP_fgets (line, 255, datei) == NULL)
2731 break;
2732 line[255] = '\0';
2733 if (!IsLineEmpty (line)) {
2734 break;
2735 }
2736 }
2737
2738 while (!feof (datei) && !IsLineEmpty (line)) {
2739 if (IsKnownHeader (line))
2740 hcount++;
2741 lcount++;
2742 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2743 break;
2744
2745 if (_FP_fgets (line, 255, datei) == NULL)
2746 break;
2747 line[255] = '\0';
2748 }
2749 if (hcount < hlcount.afternl)
2750 fseek (datei, preheaders, SEEK_SET);
2751 hcount = lcount = 0;
2752 }
2753
2754 /*
2755 * look for next header
2756 */
2757
2758 while (!feof (datei)) {
2759 if (_FP_fgets (line, 255, datei) == NULL)
2760 break;
2761 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2762 if (ferror (datei))
2763 break;
2764 line[255] = '\0';
2765
2766 if ((vflag = IsKnownHeader (line))) {
2767 (void) ScanHeaderLine (datei, line);
2768
2769 if (result->uudet != PT_ENCODED || vflag == 1) {
2770 if (hcount == 0)
2771 preheaders = prevpos;
2772 hcount++;
2773 lcount++;
2774 if (hcount >= hlcount.restart) {
2775 /*
2776 * Hey, a new header starts here
2777 */
2778 fseek (datei, preheaders, SEEK_SET);
2779 prevpos = preheaders;
2780 break;
2781 }
2782 }
2783 }
2784 else if (lcount > WAITHEADER) {
2785 hcount = 0;
2786 lcount = 0;
2787 }
2788 else if (hcount) {
2789 lcount++;
2790 }
2791 prevpos = ftell (datei);
2792 }
2793 res = 1;
2794 }
2795 else {
2796 /*
2797 * Otherwise, let's see what we can find ourself. No
2798 * boundary (NULL) but MIME, and respect new headers.
2799 */
2800 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
2801 /* oops, something went wrong */
2802 sstate.isfolder = 0;
2803 sstate.ismime = 0;
2804 UUkillfread (result);
2805 UUkillheaders (&localenv);
2806 return NULL;
2807 }
2808 if (result->uudet == 0 && uu_handletext)
2809 result->uudet = PT_ENCODED;
2810
2811 prevpos = ftell (datei);
2812 }
2813 /*
2814 * produce result
2815 */
2816 if (localenv.fname) {
2817 _FP_free (result->filename);
2818 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2819 *errcode = UURET_NOMEM;
2820 }
2821 else if (sstate.envelope.fname) {
2822 _FP_free (result->filename);
2823 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
2824 *errcode = UURET_NOMEM;
2825 }
2826 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2827 result->filename == NULL) {
2828 sprintf (line, "%04d.txt", ++mimseqno);
2829 if ((result->filename = _FP_strdup (line)) == NULL)
2830 *errcode = UURET_NOMEM;
2831 }
2832 else {
2833 /* assign a filename lateron */
2834 }
2835 if (result->subject == NULL) {
2836 if (sstate.envelope.subject)
2837 result->subject = _FP_strdup (sstate.envelope.subject);
2838 }
2839 result->partno = sstate.envelope.partno;
2840 result->maxpno = sstate.envelope.numparts;
2841 result->flags = FL_PARTIAL |
2842 ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) |
2843 ((uu_fast_scanning) ? FL_TOEND : 0);
2844 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2845 if (result->partno == 1)
2846 result->begin = 1;
2847
2848 if (uu_fast_scanning)
2849 result->length = progress.fsize - result->startpos;
2850 else
2851 result->length = prevpos - result->startpos;
2852
2853 if (result->sfname == NULL)
2854 result->sfname = _FP_strdup (fname);
2855
2856 if (result->mode == 0)
2857 result->mode = 0644;
2858
2859 /*
2860 * the other fields should already be set appropriately
2861 */
2862
2863 if (res == 1) {
2864 /*
2865 * new headers found
2866 */
2867 sstate.isfolder = 1;
2868 sstate.ismime = 0;
2869 sstate.mimestate = MS_HEADERS;
2870
2871 UUkillheaders (&sstate.envelope);
2872 memset (&sstate.envelope, 0, sizeof (headers));
2873 }
2874 else {
2875 /*
2876 * otherwise, this can't be a mail folder
2877 */
2878 sstate.isfolder = 0;
2879 sstate.ismime = 0;
2880 }
2881 /*
2882 * kill local envelope
2883 */
2884 UUkillheaders (&localenv);
2885 return result;
2886 }
2887
2888 /*
2889 * If this is a MIME body, honor a Content-Type different than
2890 * text/plain or a proper Content-Transfer-Encoding.
2891 * We also go in here if we have an assigned filename - this means
2892 * that we've had a Content-Disposition field, and we should probably
2893 * decode a plain-text segment with a filename.
2894 */
2895
2896 if (sstate.isfolder && sstate.ismime &&
2897 sstate.mimestate == MS_BODY &&
2898 (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL ||
2899 _FP_stristr (sstate.envelope.ctenc, "base64") != NULL ||
2900 _FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL ||
2901 _FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL ||
2902 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2903 sstate.envelope.fname != NULL)) {
2904
2905 if (sstate.envelope.subject)
2906 result->subject = _FP_strdup (sstate.envelope.subject);
2907 if (sstate.envelope.from)
2908 result->origin = _FP_strdup (sstate.envelope.from);
2909
2910 if (sstate.envelope.ctype)
2911 result->mimetype = _FP_strdup (sstate.envelope.ctype);
2912 else
2913 result->mimetype = _FP_strdup ("text/plain");
2914
2915 if (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL)
2916 result->uudet = QP_ENCODED;
2917 else if (_FP_stristr (sstate.envelope.ctenc, "base64") != NULL)
2918 result->uudet = B64ENCODED;
2919 else if (_FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL) {
2920 result->uudet = UU_ENCODED;
2921 result->begin = result->end = 1;
2922 }
2923 else if (_FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL) {
2924 result->uudet = YENC_ENCODED;
2925 }
2926 else if (_FP_stristr (sstate.envelope.ctenc, "7bit") != NULL ||
2927 _FP_stristr (sstate.envelope.ctenc, "8bit") != NULL)
2928 result->uudet = PT_ENCODED;
2929 else if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL ||
2930 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2931 sstate.envelope.fname != NULL)
2932 result->uudet = PT_ENCODED;
2933
2934 /*
2935 * If we're switched to MIME-only mode, handle as text
2936 */
2937
2938 if (uu_more_mime >= 2 && !result->uudet) {
2939 result->uudet = PT_ENCODED;
2940 }
2941
2942 result->startpos = prevpos = ftell (datei);
2943
2944 /*
2945 * If this is Quoted-Printable or Plain Text, just try looking
2946 * for the next message header. If uu_fast_scanning, we know
2947 * there won't be more headers.
2948 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2949 * the message header and then start looking for the next header.
2950 */
2951 if (result->uudet != 0 && uu_fast_scanning) {
2952 /* do nothing */
2953 res = 0;
2954 }
2955 else if (result->uudet != 0) {
2956 hcount = lcount = 0;
2957 prevpos = ftell (datei);
2958
2959 if (_FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2960 _FP_stristr (sstate.envelope.ctype, "rfc822") != NULL) {
2961 /*
2962 * skip over empty lines and local header
2963 */
2964 preheaders = ftell (datei);
2965 while (!feof (datei)) {
2966 if (_FP_fgets (line, 255, datei) == NULL)
2967 break;
2968 line[255] = '\0';
2969 if (!IsLineEmpty (line)) {
2970 break;
2971 }
2972 }
2973
2974 while (!feof (datei) && !IsLineEmpty (line)) {
2975 if (IsKnownHeader (line))
2976 hcount++;
2977 lcount++;
2978 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2979 break;
2980
2981 if (_FP_fgets (line, 255, datei) == NULL)
2982 break;
2983 line[255] = '\0';
2984 }
2985 if (hcount < hlcount.afternl)
2986 fseek (datei, preheaders, SEEK_SET);
2987 hcount = lcount = 0;
2988 }
2989
2990 /*
2991 * look for next header
2992 */
2993
2994 while (!feof (datei)) {
2995 if (_FP_fgets (line, 255, datei) == NULL)
2996 break;
2997 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2998 if (ferror (datei))
2999 break;
3000 line[255] = '\0';
3001
3002 if (IsKnownHeader (line)) {
3003 (void) ScanHeaderLine (datei, line);
3004 if (hcount == 0)
3005 preheaders = prevpos;
3006 hcount++;
3007 lcount++;
3008 if (hcount >= hlcount.restart) {
3009 /*
3010 * Hey, a new header starts here
3011 */
3012 fseek (datei, preheaders, SEEK_SET);
3013 prevpos = preheaders;
3014 break;
3015 }
3016 }
3017 else if (lcount > WAITHEADER) {
3018 hcount = 0;
3019 lcount = 0;
3020 }
3021 else if (hcount) {
3022 lcount++;
3023 }
3024 prevpos = ftell (datei);
3025 }
3026 res = 1;
3027 }
3028 else {
3029 /*
3030 * Otherwise, let's see what we can find ourself. No
3031 * boundary (NULL) but MIME, and respect new headers.
3032 */
3033 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
3034 /* oops, something went wrong */
3035 sstate.isfolder = 0;
3036 sstate.ismime = 0;
3037 UUkillfread (result);
3038 return NULL;
3039 }
3040 if (result->uudet == 0 && uu_handletext) {
3041 result->startpos = before; /* display headers */
3042 result->uudet = PT_ENCODED;
3043 }
3044
3045 prevpos = ftell (datei);
3046 }
3047 /*
3048 * produce result
3049 */
3050 if (sstate.envelope.fname) {
3051 _FP_free (result->filename);
3052 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3053 *errcode = UURET_NOMEM;
3054 }
3055 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3056 result->filename == NULL) {
3057 sprintf (line, "%04d.txt", ++mimseqno);
3058 if ((result->filename = _FP_strdup (line)) == NULL)
3059 *errcode = UURET_NOMEM;
3060 }
3061 else {
3062 /* assign a filename lateron */
3063 }
3064 if (result->subject == NULL) {
3065 if (sstate.envelope.subject)
3066 result->subject = _FP_strdup (sstate.envelope.subject);
3067 }
3068 result->flags = ((res==1||uu_fast_scanning)?FL_PROPER:0) |
3069 ((uu_fast_scanning) ? FL_TOEND : 0);
3070 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3071
3072 if (uu_fast_scanning)
3073 result->length = progress.fsize - result->startpos;
3074 else
3075 result->length = prevpos - result->startpos;
3076
3077 if (result->sfname == NULL)
3078 result->sfname = _FP_strdup (fname);
3079
3080 if (result->mode == 0)
3081 result->mode = 0644;
3082
3083 /*
3084 * the other fields should already be set appropriately
3085 */
3086
3087 if (res == 1) {
3088 /*
3089 * new headers found
3090 */
3091 sstate.isfolder = 1;
3092 sstate.ismime = 0;
3093 sstate.mimestate = MS_HEADERS;
3094
3095 UUkillheaders (&sstate.envelope);
3096 memset (&sstate.envelope, 0, sizeof (headers));
3097 }
3098 else {
3099 /*
3100 * otherwise, this can't be a mail folder
3101 */
3102 sstate.isfolder = 0;
3103 sstate.ismime = 0;
3104 }
3105
3106 return result;
3107 }
3108
3109 /*
3110 * Some files have reduced headers, and what should be a multipart
3111 * message is missing the proper Content-Type. If the first thing
3112 * we find after a couple of empty lines is a boundary, try it!
3113 * But make sure that this is indeed intended as being a boundary.
3114 *
3115 * Only accept it if there was indeed no Content-Type header line
3116 * and if the following line is a proper Content-Type header. BTW,
3117 * we know that sstate.envelope.boundary is NULL, or we wouldn't
3118 * be here!
3119 */
3120
3121 if ((sstate.envelope.ctype == NULL ||
3122 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL) &&
3123 !uu_more_mime) {
3124 prevpos = ftell (datei);
3125 while (!feof (datei)) {
3126 if (_FP_fgets (line, 255, datei) == NULL) {
3127 line[0] = '\0';
3128 break;
3129 }
3130 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
3131 if (!IsLineEmpty (line))
3132 break;
3133 }
3134 if (line[0] == '-' && line[1] == '-' &&
3135 !IsLineEmpty (line+2) && !feof (datei)) {
3136 ptr1 = _FP_strrstr (line+2, "--");
3137 ptr2 = ScanHeaderLine (datei, NULL);
3138 if ((ptr1 == NULL || (*(ptr1+2) != '\012' && *(ptr1+2) != '\015')) &&
3139 ptr2 && _FP_strnicmp (ptr2, "Content-", 8) == 0) {
3140 /*
3141 * hmm, okay, let's do it!
3142 */
3143 sstate.isfolder = 1;
3144 sstate.ismime = 1;
3145 sstate.mimestate = MS_PREAMBLE;
3146 /*
3147 * get boundary
3148 */
3149 ptr1 = line+2;
3150 while (*ptr1 && !isspace(*ptr1))
3151 ptr1++;
3152 *ptr1 = '\0';
3153
3154 sstate.envelope.mimevers = _FP_strdup ("1.0");
3155 sstate.envelope.boundary = _FP_strdup (line+2);
3156
3157 /*
3158 * need restart
3159 */
3160
3161 fseek (datei, prevpos, SEEK_SET);
3162
3163 _FP_free (result);
3164 return NULL;
3165 }
3166 }
3167 fseek (datei, prevpos, SEEK_SET);
3168 }
3169
3170 /*
3171 * Hmm, we're not in a ''special'' state, so it's more or less
3172 * Freestyle time. Anyway, if this seems to be a Mime message,
3173 * don't allow the minimal Base64 handling.
3174 */
3175
3176 if (sstate.envelope.subject)
3177 result->subject = _FP_strdup (sstate.envelope.subject);
3178 if (sstate.envelope.from)
3179 result->origin = _FP_strdup (sstate.envelope.from);
3180
3181 if (sstate.envelope.ctype)
3182 result->mimetype = _FP_strdup (sstate.envelope.ctype);
3183
3184 if ((res=ScanData (datei, fname, errcode, NULL,
3185 sstate.ismime, 1, result))==-1) {
3186 /* oops, something went wrong */
3187 sstate.isfolder = 0;
3188 sstate.ismime = 0;
3189 UUkillfread (result);
3190 return NULL;
3191 }
3192
3193 /*
3194 * produce result
3195 */
3196
3197 if (result->uudet == 0 && uu_handletext) {
3198 result->startpos = before; /* display headers */
3199 result->uudet = PT_ENCODED;
3200 result->partno = 1;
3201 }
3202
3203 if (result->uudet == YENC_ENCODED && result->filename != NULL) {
3204 /*
3205 * prevent replacing the filename found on the =ybegin line
3206 */
3207 }
3208 else if (sstate.envelope.fname) {
3209 _FP_free (result->filename);
3210 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3211 *errcode = UURET_NOMEM;
3212 }
3213 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3214 result->filename == NULL) {
3215 sprintf (line, "%04d.txt", ++mimseqno);
3216 if ((result->filename = _FP_strdup (line)) == NULL)
3217 *errcode = UURET_NOMEM;
3218 }
3219 else {
3220 /* assign a filename lateron */
3221 }
3222
3223 if (result->subject == NULL) {
3224 if (sstate.envelope.subject)
3225 result->subject = _FP_strdup (sstate.envelope.subject);
3226 }
3227
3228 result->flags = (result->uudet==PT_ENCODED)?FL_SINGLE:0;
3229 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3230 result->length = ftell (datei) - result->startpos;
3231
3232 if (result->mode == 0)
3233 result->mode = 0644;
3234
3235 if (result->sfname == NULL)
3236 result->sfname = _FP_strdup (fname);
3237
3238 if (res == 1) {
3239 /*
3240 * new headers found
3241 */
3242 sstate.isfolder = 1;
3243 sstate.ismime = 0;
3244 sstate.mimestate = MS_HEADERS;
3245
3246 UUkillheaders (&sstate.envelope);
3247 memset (&sstate.envelope, 0, sizeof (headers));
3248 }
3249 else {
3250 /*
3251 * otherwise, this can't be a mail folder
3252 */
3253 sstate.isfolder = 0;
3254 sstate.ismime = 0;
3255 }
3256
3257 return result;
3258
3259 /*
3260 * Emergency handling. Set errcode before jumping here.
3261 */
3262 ScanPartEmergency:
3263 UUkillfread (result);
3264 UUkillheaders (&localenv);
3265
3266 while (mssdepth) {
3267 mssdepth--;
3268 UUkillheaders (&(multistack[mssdepth].envelope));
3269 _FP_free (multistack[mssdepth].source);
3270 }
3271
3272 return NULL;
3273 }
3274