ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.13
Committed: Fri Jun 13 13:33:08 2008 UTC (15 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_11
Changes since 1.12: +0 -1 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
937 long oldposition = ftell (datei); /* refresh oldpositition so the comment below becomes true */
938
939 if (_FP_fgets (line, 255, datei) == NULL) {
940 break;
941 }
942 if (_FP_strnicmp (line, "Content-", 8) == 0) {
943 /*
944 * Okay, let's do it. This breaks out of ScanData. ScanPart will
945 * recognize the boundary on the next call and use it.
946 */
947 fseek (datei, oldposition, SEEK_SET);
948 break;
949 }
950 }
951
952 /*
953 * Detection for yEnc encoding
954 */
955
956 if (strncmp (line, "=ybegin ", 8) == 0 &&
957 _FP_strstr (line, " name=") != NULL) {
958 if ((result->begin || result->end || result->uudet) && !uu_more_mime) {
959 fseek (datei, oldposition, SEEK_SET);
960 break;
961 }
962
963 /*
964 * name continues to the end of the line
965 */
966
967 ptr = _FP_strstr (line, " name=") + 6;
968
969 /* newsbin pro 5.0 (at least) is braindamaged enough to put (null) here */
970 /* create something sensible, trust a windows program to fuck it up */
971 if (strncmp (ptr, "(null)", 6))
972 {
973 _FP_free (result->filename);
974 result->filename = _FP_strdup (ptr);
975
976 while (isspace (result->filename[strlen(result->filename)-1]))
977 result->filename[strlen(result->filename)-1] = '\0';
978 }
979
980 /*
981 * Determine size
982 */
983
984 if ((ptr = _FP_strstr (line, " size=")) != NULL) {
985 ptr += 6;
986 yefilesize = atoi (ptr);
987 }
988 else {
989 yefilesize = -1;
990 }
991
992 /*
993 * check for multipart file and read =ypart line
994 */
995
996 if ((ptr = _FP_strstr (line, " part=")) != NULL) {
997 result->partno = atoi (ptr + 6);
998
999 if (result->partno == 1) {
1000 result->begin = 1;
1001 }
1002
1003 if (_FP_fgets (line, 255, datei) == NULL) {
1004 break;
1005 }
1006
1007 line[255] = '\0';
1008
1009 if (strncmp (line, "=ypart ", 7) != 0) {
1010 break;
1011 }
1012
1013 if ((ptr = _FP_strstr (line, " end=")) == NULL) {
1014 break;
1015 }
1016
1017 yepartends = atoi (ptr + 5);
1018 }
1019 else {
1020 result->partno = 1;
1021 result->begin = 1;
1022 }
1023
1024 /*
1025 * Don't want auto-detection
1026 */
1027
1028 result->uudet = YENC_ENCODED;
1029 continue;
1030 }
1031
1032 if (strncmp (line, "=yend ", 6) == 0 &&
1033 result->uudet == YENC_ENCODED) {
1034 if (yepartends == 0 || yepartends >= yefilesize) {
1035 result->end = 1;
1036 }
1037 #if 0
1038 if (!uu_more_mime)
1039 break;
1040 #endif
1041 continue;
1042 }
1043
1044 /*
1045 * if we haven't yet found anything encoded, try to find something
1046 */
1047
1048 if (!(result->uudet)) {
1049 /*
1050 * Netscape-Repair code is the same as in uunconc.c
1051 */
1052
1053 if ((vflag = UUValidData (line, 0, &bhflag)) == 0 && !ismime)
1054 vflag = UURepairData (datei, line, 0, &bhflag);
1055
1056 /*
1057 * Check data against all possible encodings
1058 */
1059
1060 islen[iscnt%10] = strlen(line);
1061 isb64[iscnt%10] = (UUValidData (line, B64ENCODED, &bhflag)==B64ENCODED);
1062 isuue[iscnt%10] = (UUValidData (line, UU_ENCODED, &bhflag)==UU_ENCODED);
1063 isxxe[iscnt%10] = (UUValidData (line, XX_ENCODED, &bhflag)==XX_ENCODED);
1064 isbhx[iscnt%10] = (UUValidData (line, BH_ENCODED, &bhflag)==BH_ENCODED);
1065
1066 /*
1067 * If we've got a first valid encoded line, we get suspicious if
1068 * it's shorter than, say, 40 characters.
1069 */
1070
1071 if (vflag == B64ENCODED &&
1072 (dflag == 0 || encoding != B64ENCODED) &&
1073 strlen (line) < 40 && !result->begin && !uu_tinyb64) {
1074 isb64[iscnt%10] = 0;
1075 vflag = 0;
1076 }
1077
1078 if ((vflag == UU_ENCODED || vflag == XX_ENCODED) &&
1079 (dflag == 0 || encoding != vflag) &&
1080 strlen (line) < 40 && !result->begin) {
1081 isuue[iscnt%10] = isxxe[iscnt%10] = 0;
1082 vflag = 0;
1083 }
1084
1085 iscnt++;
1086
1087 /*
1088 * Ah, so we got an encoded line? How interesting!
1089 */
1090
1091 if (vflag) {
1092 /*
1093 * For BinHex data, we can use the initial colon ':' as begin
1094 * and the terminating colon as ':'.
1095 * If (vflag && !bhflag), this is the last line,
1096 */
1097 if (vflag == BH_ENCODED) {
1098 if (line[0] == ':' && result->end) {
1099 fseek (datei, oldposition, SEEK_SET);
1100 break;
1101 }
1102 if (line[0] == ':')
1103 result->begin = 1;
1104 if (bhflag == 0) {
1105 result->uudet = BH_ENCODED;
1106 result->end = 1;
1107 }
1108 }
1109 /*
1110 * For BinHex files, the file name is encoded in the first encoded
1111 * data bytes. We try to extract it here
1112 */
1113 if (vflag == BH_ENCODED && bhnf == 0 && result->filename == NULL) {
1114 if (bhdsp == bhds2 ||
1115 ((bhdsp-bhds2) <= (int) bhds2[0] &&
1116 (bhdsp-bhds2) < 256)) {
1117 dcc = UUDecodeLine (line, bhds1, BH_ENCODED);
1118 UUbhdecomp (bhds1, bhdsp, &bhl, &bhrpc,
1119 dcc, 256-(bhdsp-bhds2), &bhopc);
1120 bhdsp += bhopc;
1121 }
1122 if ((bhdsp-bhds2) > (int) bhds2[0] && bhds2[0]>0 &&
1123 result->filename==NULL) {
1124 memcpy (bhds1, bhds2+1, (int) bhds2[0]);
1125 bhds1[(int)bhds2[0]]='\0';
1126 result->filename = _FP_strdup (bhds1);
1127 bhnf = 1;
1128 }
1129 else if (bhdsp-bhds2 >= 256 && bhds2[0]>0) {
1130 memcpy (bhds1, bhds2+1, 255);
1131 bhds1[255] = '\0';
1132 result->filename = _FP_strdup (bhds1);
1133 bhnf = 1;
1134 }
1135 else if (bhds2[0] <= 0)
1136 bhnf = 1;
1137 }
1138
1139 /*
1140 * We accept an encoding if it has been true for four consecutive
1141 * lines. Check the is<enc> arrays to avoid mistaking one encoding
1142 * for the other. Uuencoded data is rather easily mistaken for
1143 * Base 64. If the data matches more than one encoding, we need to
1144 * scan further.
1145 *
1146 * Since text can also rather easily be mistaken for UUencoded
1147 * data if it just happens to have 4 lines in a row that have the
1148 * correct first character for the length of the line, we also add
1149 * a check that the first 3 lines must be the same length, and the
1150 * 4th line must be less than or equal to that length. (since
1151 * uuencoders use the same length for all lines except the last,
1152 * this shouldn't increase the minimum size of UUdata we can
1153 * detect, as it would if we tested all 4 lines for being the same
1154 * length.) - Matthew Mueller, 20030109
1155 */
1156
1157 if (iscnt > 3) {
1158 cbb64 = (isb64[(iscnt-1)%10] && isb64[(iscnt-2)%10] &&
1159 isb64[(iscnt-3)%10] && isb64[(iscnt-4)%10]);
1160 cbuue = (isuue[(iscnt-1)%10] && isuue[(iscnt-2)%10] &&
1161 isuue[(iscnt-3)%10] && isuue[(iscnt-4)%10] &&
1162 islen[(iscnt-1)%10] <= islen[(iscnt-2)%10] &&
1163 islen[(iscnt-2)%10] == islen[(iscnt-3)%10] &&
1164 islen[(iscnt-3)%10] == islen[(iscnt-4)%10]);
1165 cbxxe = (isxxe[(iscnt-1)%10] && isxxe[(iscnt-2)%10] &&
1166 isxxe[(iscnt-3)%10] && isxxe[(iscnt-4)%10] &&
1167 islen[(iscnt-1)%10] <= islen[(iscnt-2)%10] &&
1168 islen[(iscnt-2)%10] == islen[(iscnt-3)%10] &&
1169 islen[(iscnt-3)%10] == islen[(iscnt-4)%10]);
1170 cbbhx = (isbhx[(iscnt-1)%10] && isbhx[(iscnt-2)%10] &&
1171 isbhx[(iscnt-3)%10] && isbhx[(iscnt-4)%10]);
1172 }
1173 else {
1174 cbb64 = cbuue = cbxxe = cbbhx = 0;
1175 }
1176
1177 if (cbb64 && !cbuue && !cbxxe && !cbbhx) {
1178 result->uudet = B64ENCODED;
1179 }
1180 else if (!cbb64 && cbuue && !cbxxe && !cbbhx) {
1181 result->uudet = UU_ENCODED;
1182 }
1183 else if (!cbb64 && !cbuue && cbxxe && !cbbhx) {
1184 result->uudet = XX_ENCODED;
1185 }
1186 else if (!cbb64 && !cbuue && !cbxxe && cbbhx) {
1187 result->uudet = BH_ENCODED;
1188 }
1189
1190 if (result->uudet) {
1191 encoding = dflag = 0;
1192
1193 /*
1194 * If we're in fast mode, we're told we don't have to look
1195 * for anything below, so we can as well break out of every-
1196 * thing
1197 * We cannot fast-scan if we have a boundary to look after.
1198 */
1199
1200 if (uu_fast_scanning && boundary == NULL)
1201 break;
1202
1203 /*
1204 * Skip the encoded data. We simply wait for a boundary, for
1205 * a header or for an empty line. But we also try to pick up
1206 * an "end"
1207 */
1208
1209 hcount = lcount = 0;
1210
1211 while (!feof (datei)) {
1212 /*
1213 * Make Busy Polls
1214 */
1215 if (UUBUSYPOLL(ftell(datei),progress.fsize)) {
1216 UUMessage (uuscan_id, __LINE__, UUMSG_NOTE,
1217 uustring (S_SCAN_CANCEL));
1218 *errcode = UURET_CANCEL;
1219 break;
1220 }
1221
1222 oldposition = ftell (datei);
1223 if (_FP_fgets (line, 255, datei) == NULL)
1224 break;
1225 if (ferror (datei))
1226 break;
1227
1228 line[255] = '\0';
1229
1230 /*
1231 * Stop scanning at an empty line or a MIME-boundary.
1232 */
1233 if (IsLineEmpty (line))
1234 break;
1235 if (boundary && line[0] == '-' && line[1] == '-' &&
1236 strncmp (line+2, boundary, blen) == 0) {
1237 fseek (datei, oldposition, SEEK_SET);
1238 break;
1239 }
1240 else if (line[0] == 'e' && (result->uudet == UU_ENCODED ||
1241 result->uudet == XX_ENCODED)) {
1242 if (strncmp (line, "end", 3) == 0) {
1243 result->end = 1;
1244 break;
1245 }
1246 }
1247 else if (line[0] == 'b') {
1248 if (strncmp (line, "begin ", 6) == 0) {
1249 fseek (datei, oldposition, SEEK_SET);
1250 break;
1251 }
1252 }
1253
1254 if (checkheaders) {
1255 if (IsKnownHeader (line)) {
1256 (void) ScanHeaderLine (datei, line);
1257 if (hcount == 0)
1258 preheaders = oldposition;
1259 hcount++;
1260 lcount++;
1261 if ((hcount >= hlcount.restart) ||
1262 (hcount >= hlcount.afterdata && result->uudet)) {
1263 /*
1264 * Hey, a new header starts here
1265 */
1266 fseek (datei, preheaders, SEEK_SET);
1267 break;
1268 }
1269 }
1270 else if (lcount > WAITHEADER) {
1271 hcount = 0;
1272 lcount = 0;
1273 }
1274 else if (hcount) {
1275 lcount++;
1276 }
1277 }
1278 if (result->uudet == BH_ENCODED) {
1279 /* pick up ``EOF'' for BinHex files. Slow :-< */
1280 if (line[0] && strchr (line+1, ':') != NULL) {
1281 result->end = 1;
1282 bhflag = 0;
1283 break;
1284 }
1285 }
1286 }
1287
1288 if (ferror (datei) || *errcode == UURET_CANCEL)
1289 break;
1290
1291 if (line[0] == '-' && line[1] == '-')
1292 haddh = 1;
1293
1294 /*
1295 * Okay, got everything we need. If we had headers or a
1296 * boundary, we break out of the outer loop immediately.
1297 */
1298
1299 if (IsKnownHeader (line) ||
1300 (boundary && line[0] == '-' && line[1] == '-' &&
1301 strncmp (line+2, boundary, blen) == 0)) {
1302 break;
1303 }
1304
1305 /*
1306 * Otherwise, we wait until finding something more interesting
1307 * in the outer loop
1308 */
1309
1310 continue;
1311 }
1312
1313 /*
1314 * Select the encoding with the best "history"
1315 */
1316
1317 cbb64 = isb64[(iscnt-1)%10];
1318 cbuue = isuue[(iscnt-1)%10];
1319 cbxxe = isxxe[(iscnt-1)%10];
1320 cbbhx = isbhx[(iscnt-1)%10];
1321 dflag = 0;
1322
1323 if (cbb64 || cbuue || cbxxe || cbbhx) {
1324 for (dflag=2; dflag<iscnt && dflag<4; dflag++) {
1325 if ((!cbb64 || !isb64[(iscnt-dflag)%10]) &&
1326 (!cbuue || !isuue[(iscnt-dflag)%10]) &&
1327 (!cbxxe || !isxxe[(iscnt-dflag)%10]) &&
1328 (!cbbhx || !isbhx[(iscnt-dflag)%10])) {
1329 dflag--;
1330 break;
1331 }
1332 cbb64 &= isb64[(iscnt-dflag)%10];
1333 cbuue &= isuue[(iscnt-dflag)%10];
1334 cbxxe &= isxxe[(iscnt-dflag)%10];
1335 cbbhx &= isbhx[(iscnt-dflag)%10];
1336 }
1337 }
1338
1339 /*
1340 * clear-cut cases
1341 */
1342
1343 if (cbb64 && !cbuue && !cbxxe && !cbbhx) {
1344 encoding = B64ENCODED;
1345 }
1346 else if (!cbb64 && cbuue && !cbxxe && !cbbhx) {
1347 encoding = UU_ENCODED;
1348 }
1349 else if (!cbb64 && !cbuue && cbxxe && !cbbhx) {
1350 encoding = XX_ENCODED;
1351 }
1352 else if (!cbb64 && !cbuue && !cbxxe && cbbhx) {
1353 encoding = BH_ENCODED;
1354 }
1355 else {
1356 encoding = 0;
1357 }
1358
1359 /*
1360 * Check a few common non-clear-cut cases
1361 */
1362
1363 if (!encoding && cbuue && result->begin) {
1364 encoding = UU_ENCODED;
1365 }
1366 else if (!encoding && cbxxe && result->begin) {
1367 encoding = XX_ENCODED;
1368 }
1369 else if (!encoding && cbb64) {
1370 encoding = B64ENCODED;
1371 }
1372 else if (!encoding && cbuue) {
1373 encoding = UU_ENCODED;
1374 }
1375 else if (!encoding && cbxxe) {
1376 encoding = XX_ENCODED;
1377 }
1378 else if (!encoding && cbbhx) {
1379 encoding = BH_ENCODED;
1380 }
1381 }
1382 else if (!dontcare) {
1383 encoding = 0;
1384 dflag = 0;
1385 haddh = 0;
1386 }
1387 } /* if (!uudet) */
1388 /*
1389 * End of scanning loop
1390 */
1391 } /* while (!feof (datei)) */
1392
1393 if (feof (datei))
1394 oldposition = ftell (datei);
1395
1396 if (dflag && encoding == B64ENCODED && haddh)
1397 result->uudet = B64ENCODED;
1398 else if (dflag && encoding == BH_ENCODED)
1399 result->uudet = BH_ENCODED;
1400
1401 /* Base64 doesn't have begin or end, so it was probably XX */
1402 if (result->uudet == B64ENCODED && result->begin && result->end)
1403 result->uudet = XX_ENCODED;
1404
1405 /* Base64 doesn't have begin or end */
1406 if (result->uudet == B64ENCODED)
1407 result->begin = result->end = 0;
1408
1409 /* Base64 and BinHex don't have a file mode */
1410 if (result->uudet == B64ENCODED || result->uudet == BH_ENCODED ||
1411 result->uudet == YENC_ENCODED)
1412 result->mode = 6*64+4*8+4;
1413
1414 /*
1415 * When strict MIME adherance is set, throw out suspicious attachments
1416 */
1417
1418 if (uu_more_mime) {
1419 /*
1420 * In a MIME message, Base64 should be appropriately tagged
1421 */
1422
1423 if (result->uudet == B64ENCODED) {
1424 result->uudet = 0;
1425 }
1426
1427 /*
1428 * Do not accept incomplete UU or XX encoded messages
1429 */
1430
1431 if ((result->uudet != 0 && result->uudet != B64ENCODED) &&
1432 (!result->begin || !result->end)) {
1433 result->uudet = 0;
1434 }
1435 }
1436
1437 /*
1438 * In fast mode, this length will yield a false value. We don't care.
1439 * This must be checked for in uunconc(), where we usually stop decoding
1440 * after reaching startpos+length
1441 */
1442
1443 if (uu_fast_scanning)
1444 result->length = progress.fsize-result->startpos;
1445 else
1446 result->length = ftell(datei)-result->startpos;
1447
1448 if (ferror (datei)) {
1449 *errcode = UURET_IOERR;
1450 uu_errno = errno;
1451 return -1;
1452 }
1453 if (*errcode != UURET_OK) {
1454 return -1;
1455 }
1456
1457 if (boundary && line[0] == '-' && line[1] == '-' &&
1458 strncmp (line+2, boundary, blen) == 0)
1459 return 2;
1460 else if (boundary && p3 &&
1461 line[0] == 'C' && line[1] == 'o' &&
1462 _FP_strnicmp (line, "Content-Type:", 13) == 0 &&
1463 strcmp (p3, boundary) == 0)
1464 return 2;
1465 else if (IsKnownHeader (line))
1466 return 1;
1467
1468 return 0;
1469 }
1470
1471 /*
1472 * This is the main scanning function.
1473 */
1474
1475 fileread *
1476 ScanPart (FILE *datei, char *fname, int *errcode)
1477 {
1478 int ecount, hcount, lcount;
1479 int bhflag, begflag, vflag, blen=0, res;
1480 long preheaders, prevpos=0, preenc, before;
1481 char *line=uuscan_spline;
1482 fileread *result;
1483 char *ptr1, *ptr2;
1484
1485 (void) UUDecodeLine (NULL, NULL, 0); /* init */
1486 if (datei == NULL || feof (datei)) {
1487 *errcode = UURET_OK;
1488 return NULL;
1489 }
1490
1491 *errcode = UURET_OK;
1492
1493 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
1494 *errcode = UURET_NOMEM;
1495 return NULL;
1496 }
1497 memset (result, 0, sizeof (fileread));
1498 result->startpos = ftell (datei);
1499 preheaders = result->startpos;
1500 before = result->startpos;
1501
1502 /* if this is a new file, reset our scanning state */
1503 if (sstate.source == NULL || strcmp (fname, sstate.source) != 0) {
1504 sstate.isfolder = 1; /* assume yes */
1505 sstate.ismime = 0; /* wait for MIME-Version */
1506 sstate.mimestate = MS_HEADERS; /* assume headers follow */
1507 /* mimseqno = 1; */
1508
1509 while (mssdepth) {
1510 mssdepth--;
1511 UUkillheaders (&(multistack[mssdepth].envelope));
1512 _FP_free (multistack[mssdepth].source);
1513 }
1514
1515 UUkillheaders (&sstate.envelope);
1516 memset (&sstate.envelope, 0, sizeof (headers));
1517
1518 _FP_free (sstate.source);
1519 if ((sstate.source = _FP_strdup (fname)) == NULL) {
1520 *errcode = UURET_NOMEM;
1521 _FP_free (result);
1522 return NULL;
1523 }
1524
1525 /* ignore empty lines at the beginning of a file */
1526 preheaders = ftell (datei);
1527 while (!feof (datei)) {
1528 if (UUBUSYPOLL(preheaders,progress.fsize)) SPCANCEL();
1529 if (_FP_fgets (line, 255, datei) == NULL)
1530 break;
1531 line[255] = '\0';
1532 if (!IsLineEmpty (line)) {
1533 fseek (datei, preheaders, SEEK_SET);
1534 break;
1535 }
1536 preheaders = ftell (datei);
1537 }
1538 }
1539
1540 if (ferror(datei) || feof(datei)) {
1541 _FP_free (result);
1542 return NULL;
1543 }
1544
1545 /*
1546 * If we are confident that this is a mail folder and are at the
1547 * beginning of the file, expecting to read some headers, scan
1548 * the envelope.
1549 */
1550
1551 if (sstate.isfolder && sstate.mimestate == MS_HEADERS) {
1552 hcount = 0;
1553 lcount = 0;
1554 UUkillheaders (&sstate.envelope);
1555
1556 /*
1557 * clean up leftovers from invalid messages
1558 */
1559
1560 while (mssdepth) {
1561 mssdepth--;
1562 UUkillheaders (&(multistack[mssdepth].envelope));
1563 _FP_free (multistack[mssdepth].source);
1564 }
1565
1566 prevpos = ftell (datei);
1567 if (_FP_fgets (line, 255, datei) == NULL) {
1568 _FP_free (result);
1569 return NULL;
1570 }
1571 line[255] = '\0';
1572
1573 /*
1574 * Special handling for AOL folder files, which start off with a boundary.
1575 * We recognize them by a valid boundary line as the first line of a file.
1576 * Note that the rest of the scanning code becomes suspicious if a boun-
1577 * dary does never appear in a file -- this should save us from grave
1578 * false detection errors
1579 */
1580
1581 if (!feof (datei) && line[0] == '-' && line[1] == '-' && line[2]) {
1582 while (line[strlen(line)-1] == '\012' ||
1583 line[strlen(line)-1] == '\015') {
1584 line[strlen(line)-1] = '\0';
1585 }
1586
1587 sstate.ismime = 1;
1588 sstate.envelope.mimevers = _FP_strdup ("1.0");
1589 sstate.envelope.boundary = _FP_strdup (line+2);
1590 sstate.envelope.ctype = _FP_strdup ("multipart/mixed");
1591 sstate.mimestate = MS_SUBPART;
1592
1593 *errcode = UURET_CONT;
1594 _FP_free (result);
1595 return NULL;
1596 }
1597
1598 /*
1599 * Normal behavior: look for a RFC 822 header
1600 */
1601
1602 while (!feof (datei) && !IsLineEmpty (line)) {
1603 if (IsKnownHeader (line))
1604 hcount++;
1605 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1606 if (IsHeaderLine (line)) {
1607 ptr1 = ScanHeaderLine (datei, line);
1608 if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
1609 *errcode = UURET_NOMEM;
1610 _FP_free (result);
1611 return NULL;
1612 }
1613 }
1614 /*
1615 * if we've read too many lines without finding headers, then
1616 * this probably isn't a mail folder after all
1617 */
1618 lcount++;
1619 if (lcount > WAITHEADER && hcount < hlcount.afternl) {
1620 fseek (datei, prevpos, SEEK_SET);
1621 line[0] = '\0';
1622 break;
1623 }
1624
1625 if (_FP_fgets (line, 255, datei) == NULL) {
1626 /* If we are at eof without finding headers, there probably isn't */
1627 if (hcount < hlcount.afternl) {
1628 fseek (datei, prevpos, SEEK_SET);
1629 line[0] = '\0';
1630 }
1631 break;
1632 }
1633 line[255] = '\0';
1634 }
1635
1636 /* skip empty lines */
1637 prevpos = ftell (datei);
1638 if (IsLineEmpty (line)) {
1639 while (!feof (datei)) {
1640 if (_FP_fgets (line, 255, datei) == NULL)
1641 break;
1642 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1643 if (!IsLineEmpty (line)) {
1644 fseek (datei, prevpos, SEEK_SET);
1645 line[255] = '\0';
1646 break;
1647 }
1648 prevpos = ftell (datei);
1649 }
1650 }
1651
1652 /*
1653 * If we don't have all valid MIME headers yet, but the following
1654 * line is a MIME header, accept it anyway.
1655 */
1656
1657 if (!uu_more_mime &&
1658 sstate.envelope.mimevers == NULL &&
1659 sstate.envelope.ctype == NULL &&
1660 sstate.envelope.ctenc == NULL &&
1661 IsKnownHeader (line)) {
1662 /*
1663 * see above
1664 */
1665 if (_FP_fgets (line, 255, datei) == NULL) {
1666 line[0] = '\012';
1667 line[1] = '\0';
1668 }
1669 line[255] = '\0';
1670
1671 while (!feof (datei) && !IsLineEmpty (line)) {
1672 if (IsKnownHeader (line))
1673 hcount++;
1674 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1675 ptr1 = ScanHeaderLine (datei, line);
1676 if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
1677 *errcode = UURET_NOMEM;
1678 _FP_free (result);
1679 return NULL;
1680 }
1681
1682 if (_FP_fgets (line, 255, datei) == NULL)
1683 break;
1684 line[255] = '\0';
1685 }
1686 /* skip empty lines */
1687 prevpos = ftell (datei);
1688 while (!feof (datei)) {
1689 if (_FP_fgets (line, 255, datei) == NULL)
1690 break;
1691 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1692 if (!IsLineEmpty (line)) {
1693 fseek (datei, prevpos, SEEK_SET);
1694 line[255] = '\0';
1695 break;
1696 }
1697 prevpos = ftell (datei);
1698 }
1699 }
1700
1701 /*
1702 * A partial multipart message probably has only a Content-Type
1703 * header but nothing else. In this case, at least simulate a
1704 * MIME message
1705 * if mimevers is not set but there are other well-known MIME
1706 * headers, don't be too picky about it.
1707 */
1708 if (sstate.envelope.ctype && sstate.envelope.mimevers==NULL &&
1709 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL &&
1710 sstate.envelope.boundary != NULL) {
1711 sstate.envelope.mimevers = _FP_strdup ("1.0");
1712 hcount = hlcount.afternl;
1713 }
1714 else if (sstate.envelope.mimevers==NULL && sstate.envelope.ctype &&
1715 sstate.envelope.fname && sstate.envelope.ctenc) {
1716 sstate.envelope.mimevers = _FP_strdup ("1.0");
1717 hcount = hlcount.afternl;
1718 }
1719
1720 if (sstate.envelope.mimevers != NULL) {
1721 /* this is a MIME file. check the Content-Type */
1722 sstate.ismime = 1;
1723 if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL) {
1724 if (sstate.envelope.boundary == NULL) {
1725 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1726 uustring (S_MIME_NO_BOUNDARY));
1727 sstate.mimestate = MS_BODY;
1728 _FP_free (sstate.envelope.ctype);
1729 sstate.envelope.ctype = _FP_strdup ("text/plain");
1730 }
1731 else {
1732 sstate.mimestate = MS_PREAMBLE;
1733 }
1734 }
1735 else {
1736 sstate.mimestate = MS_BODY; /* just a `simple' message */
1737 }
1738 }
1739 else {
1740 /* not a folder after all */
1741 fseek (datei, prevpos, SEEK_SET);
1742 sstate.isfolder = 0;
1743 sstate.ismime = 0;
1744 }
1745 }
1746
1747 if (feof (datei) || ferror (datei)) { /* oops */
1748 _FP_free (result);
1749 return NULL;
1750 }
1751
1752 /*
1753 * Handle MIME stuff
1754 */
1755
1756 /*
1757 * Read Preamble. This must be ended by a sstate.envelope.boundary line.
1758 * If uu_usepreamble is set, we produce a result from this one
1759 */
1760
1761 if (sstate.ismime && sstate.mimestate == MS_PREAMBLE) {
1762 result->startpos = ftell (datei); /* remember start of preamble */
1763 prevpos = ftell (datei);
1764 preheaders = ftell (datei);
1765
1766 blen = strlen (sstate.envelope.boundary);
1767 lcount = 0;
1768
1769 while (!feof (datei)) {
1770 if (_FP_fgets (line, 255, datei) == NULL) {
1771 line[0] = '\0';
1772 break;
1773 }
1774 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1775 if (line[0] == '-' && line[1] == '-' &&
1776 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
1777 break;
1778 if (!IsLineEmpty (line))
1779 lcount++;
1780
1781 prevpos = ftell (datei);
1782 }
1783 if (feof (datei) || ferror (datei)) {
1784 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1785 uustring (S_MIME_B_NOT_FOUND));
1786 /*
1787 * restart and try again; don't restart if uu_fast_scanning
1788 */
1789 sstate.isfolder = 0;
1790 sstate.ismime = 0;
1791 sstate.mimestate = MS_BODY;
1792
1793 if (!uu_fast_scanning) {
1794 *errcode = UURET_CONT;
1795 fseek (datei, preheaders, SEEK_SET);
1796 }
1797 _FP_free (result);
1798 return NULL;
1799 }
1800 if (line[0] == '-' && line[1] == '-' &&
1801 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
1802 ptr1 = line + 2 + blen;
1803 if (*ptr1 == '-' && *(ptr1+1) == '-') {
1804 /* Empty Multipart Message. Duh. */
1805 sstate.mimestate = MS_EPILOGUE;
1806 }
1807 else {
1808 sstate.mimestate = MS_SUBPART;
1809 }
1810 }
1811 else { /* shouldn't happen */
1812 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
1813 uustring (S_MIME_B_NOT_FOUND));
1814 /*
1815 * restart and try again; don't restart if uu_fast_scanning
1816 */
1817 sstate.isfolder = 0;
1818 sstate.ismime = 0;
1819 sstate.mimestate = MS_BODY;
1820
1821 if (!uu_fast_scanning) {
1822 *errcode = UURET_CONT;
1823 fseek (datei, preheaders, SEEK_SET);
1824 }
1825 _FP_free (result);
1826 return NULL;
1827 }
1828 /* produce result if uu_usepreamble is set */
1829 if (uu_usepreamble && lcount) {
1830 sprintf (line, "%04d.txt", ++mimseqno);
1831 result->subject = _FP_strdup (sstate.envelope.subject);
1832 result->filename = _FP_strdup (line);
1833 result->origin = _FP_strdup (sstate.envelope.from);
1834 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
1835 result->mimetype = _FP_strdup ("text/plain");
1836 result->mode = 0644;
1837 result->uudet = PT_ENCODED; /* plain text */
1838 result->sfname = _FP_strdup (fname);
1839 result->flags = FL_SINGLE | FL_PROPER;
1840 /* result->startpos set from above */
1841 result->length = prevpos - result->startpos;
1842 result->partno = 1;
1843
1844 /* MIME message, let's continue */
1845 *errcode = UURET_CONT;
1846
1847 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
1848 result->filename == NULL || result->sfname == NULL) {
1849 *errcode = UURET_NOMEM;
1850 }
1851
1852 return result;
1853 }
1854 /* MIME message, let's continue */
1855 if (*errcode == UURET_OK)
1856 *errcode = UURET_CONT;
1857
1858 /* otherwise, just return NULL */
1859 _FP_free (result);
1860 return NULL;
1861 }
1862
1863 /*
1864 * Read Epilogue, the plain text after the last boundary.
1865 * This can either end with new headers from the next message of a
1866 * mail folder or with a `parent' boundary if we are inside an
1867 * encapsulated Multipart message. Oh yes, and of course the file
1868 * may also simply end :-)
1869 * Another possibility is that we might find plain encoded data
1870 * without encapsulating message. We're not _too_ flexible here,
1871 * we won't detect Base64, and require a proper `begin' line for
1872 * uuencoding and xxencoding
1873 * If uu_usepreamble is set, we produce a result from this one
1874 */
1875
1876 if (sstate.ismime && sstate.mimestate == MS_EPILOGUE) {
1877 result->startpos = ftell (datei); /* remember start of epilogue */
1878 prevpos = ftell (datei);
1879 preheaders = ftell (datei);
1880 preenc = ftell (datei);
1881 hcount = lcount = 0;
1882 ecount = bhflag = 0;
1883 begflag = vflag = 0;
1884 res = 0;
1885
1886 /*
1887 * If we are in the outermost message and uu_fast_scanning, we
1888 * know (or assume) that no more messages will follow, so there's
1889 * no need to scan the rest.
1890 */
1891 if (uu_fast_scanning && mssdepth == 0) {
1892 /*
1893 * check if the epilogue is empty
1894 */
1895 while (!feof (datei) && !ferror (datei) && lcount<10 && res==0) {
1896 if (_FP_fgets (line, 255, datei) == NULL)
1897 break;
1898 if (!IsLineEmpty (line))
1899 res++;
1900 lcount++;
1901 }
1902 if (uu_usepreamble && res) {
1903 sprintf (line, "%04d.txt", ++mimseqno);
1904 result->subject = _FP_strdup (sstate.envelope.subject);
1905 result->filename = _FP_strdup (line);
1906 result->origin = _FP_strdup (sstate.envelope.from);
1907 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
1908 result->mimetype = _FP_strdup ("text/plain");
1909 result->mode = 0644;
1910 result->uudet = PT_ENCODED; /* plain text */
1911 result->sfname = _FP_strdup (fname);
1912 result->flags = FL_SINGLE | FL_PROPER | FL_TOEND;
1913 result->partno = 1;
1914 /* result->startpos set from above */
1915 result->length = progress.fsize - result->startpos;
1916
1917 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
1918 result->filename == NULL || result->sfname == NULL) {
1919 *errcode = UURET_NOMEM;
1920 }
1921
1922 return result;
1923 }
1924 _FP_free (result);
1925 return NULL;
1926 }
1927
1928 if (mssdepth > 0)
1929 blen = strlen (multistack[mssdepth-1].envelope.boundary);
1930
1931 while (!feof (datei)) {
1932 if (_FP_fgets (line, 255, datei) == NULL) {
1933 line[0] = '\0';
1934 break;
1935 }
1936 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
1937 line[255] = '\0';
1938 /* check for parent boundary */
1939 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
1940 strncmp (line+2,
1941 multistack[mssdepth-1].envelope.boundary, blen) == 0)
1942 break;
1943
1944 /* check for next headers only at outermost level */
1945 if (mssdepth == 0 && IsKnownHeader (line)) {
1946 (void) ScanHeaderLine (datei, line);
1947 if (hcount == 0) {
1948 preheaders = prevpos;
1949 lcount = 0;
1950 }
1951 hcount++;
1952 lcount++;
1953
1954 if (hcount >= hlcount.restart) {
1955 /* okay, new headers */
1956 break;
1957 }
1958 }
1959 else if (lcount > WAITHEADER) {
1960 hcount = 0;
1961 lcount = 0;
1962 }
1963 else if (hcount) {
1964 lcount++;
1965 }
1966 else {
1967 hcount = lcount = 0;
1968 }
1969
1970 /* check for begin and encoded data only at outermost level */
1971 if (mssdepth == 0 && !uu_more_mime) {
1972 if (strncmp (line, "begin ", 6) == 0 ||
1973 _FP_strnicmp (line, "<pre>begin ", 11) == 0) {
1974 preenc = prevpos;
1975 begflag = 1;
1976 }
1977 else if (strncmp (line, "end", 3) == 0 && begflag) {
1978 ecount = ELC_COUNT;
1979 break;
1980 }
1981 else if ((vflag = UUValidData (line, 0, &bhflag)) != 0) {
1982 if (vflag == BH_ENCODED && bhflag == 0) {
1983 /* very short BinHex file follows */
1984 preenc = prevpos;
1985 break;
1986 }
1987 /* remember that XX can easily be mistaken as Base64 */
1988 if ((vflag == UU_ENCODED || vflag == XX_ENCODED || vflag == B64ENCODED) && begflag) {
1989 if (++ecount >= ELC_COUNT)
1990 break;
1991 }
1992 else {
1993 begflag = 0;
1994 ecount = 0;
1995 }
1996 }
1997 else {
1998 begflag = 0;
1999 ecount = 0;
2000 }
2001 }
2002
2003 if (!IsLineEmpty (line))
2004 res++;
2005
2006 prevpos = ftell (datei);
2007 }
2008
2009 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
2010 strncmp (line+2,
2011 multistack[mssdepth-1].envelope.boundary, blen) == 0) {
2012 /* restore previous state */
2013 mssdepth--;
2014 UUkillheaders (&sstate.envelope);
2015 _FP_free (sstate.source);
2016 memcpy (&sstate, &(multistack[mssdepth]), sizeof (scanstate));
2017
2018 ptr1 = line + 2 + strlen (sstate.envelope.boundary);
2019
2020 if (*ptr1 == '-' && *(ptr1+1) == '-') {
2021 sstate.mimestate = MS_EPILOGUE;
2022 }
2023 else {
2024 sstate.mimestate = MS_SUBPART;
2025 }
2026 result->length = prevpos - result->startpos;
2027 *errcode = UURET_CONT;
2028 }
2029 else if (mssdepth > 0) {
2030 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2031 uustring (S_MIME_B_NOT_FOUND));
2032 /*
2033 * restart and try again; don't restart if uu_fast_scanning
2034 */
2035 sstate.isfolder = 0;
2036 sstate.ismime = 0;
2037 sstate.mimestate = MS_BODY;
2038
2039 while (mssdepth) {
2040 mssdepth--;
2041 UUkillheaders (&(multistack[mssdepth].envelope));
2042 _FP_free (multistack[mssdepth].source);
2043 }
2044
2045 if (!uu_fast_scanning) {
2046 *errcode = UURET_CONT;
2047 fseek (datei, preheaders, SEEK_SET);
2048 }
2049 _FP_free (result);
2050 return NULL;
2051 }
2052 else if (IsKnownHeader (line)) {
2053 /* new message follows */
2054 sstate.isfolder = 1;
2055 sstate.ismime = 0;
2056 sstate.mimestate = MS_HEADERS;
2057 result->length = preheaders - result->startpos;
2058 fseek (datei, preheaders, SEEK_SET);
2059 }
2060 else if (ecount >= ELC_COUNT) {
2061 /* new plain encoding */
2062 sstate.isfolder = 0;
2063 sstate.ismime = 0;
2064 sstate.mimestate = MS_BODY;
2065 result->length = preenc - result->startpos;
2066 fseek (datei, preenc, SEEK_SET);
2067 }
2068
2069 /* produce result if uu_usepreamble is set */
2070 if (uu_usepreamble && res) {
2071 sprintf (line, "%04d.txt", ++mimseqno);
2072 result->subject = _FP_strdup (sstate.envelope.subject);
2073 result->filename = _FP_strdup (line);
2074 result->origin = _FP_strdup (sstate.envelope.from);
2075 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2076 result->mimetype = _FP_strdup ("text/plain");
2077 result->mode = 0644;
2078 result->uudet = PT_ENCODED; /* plain text */
2079 result->sfname = _FP_strdup (fname);
2080 result->flags = FL_SINGLE | FL_PROPER;
2081 result->partno = 1;
2082 /* result->startpos set from above */
2083 /* result->length set from above */
2084
2085 if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
2086 result->filename == NULL || result->sfname == NULL) {
2087 *errcode = UURET_NOMEM;
2088 }
2089
2090 return result;
2091 }
2092 /* otherwise, just return NULL */
2093 _FP_free (result);
2094 return NULL;
2095 }
2096
2097 /*
2098 * Scan a new part from a Multipart message. Check for a new local
2099 * envelope (which defaults to `Content-Type: text/plain') and
2100 * evaluate its Content-Type and Content-Transfer-Encoding. If this
2101 * is another Multipart/something, push the current state onto our
2102 * stack and dive into the new environment, starting with another
2103 * preamble.
2104 */
2105
2106 if (sstate.ismime && sstate.mimestate == MS_SUBPART) {
2107 memset (&localenv, 0, sizeof (headers));
2108 result->startpos = ftell (datei);
2109 prevpos = ftell (datei);
2110 hcount = 0;
2111 lcount = 0;
2112
2113 /*
2114 * Duplicate some data from outer envelope
2115 */
2116
2117 localenv.mimevers = _FP_strdup (sstate.envelope.mimevers);
2118 localenv.from = _FP_strdup (sstate.envelope.from);
2119 localenv.subject = _FP_strdup (sstate.envelope.subject);
2120 localenv.rcpt = _FP_strdup (sstate.envelope.rcpt);
2121 localenv.date = _FP_strdup (sstate.envelope.date);
2122
2123 if ((sstate.envelope.mimevers != NULL && localenv.mimevers == NULL) ||
2124 (sstate.envelope.from != NULL && localenv.from == NULL) ||
2125 (sstate.envelope.subject != NULL && localenv.subject == NULL) ||
2126 (sstate.envelope.rcpt != NULL && localenv.rcpt == NULL) ||
2127 (sstate.envelope.date != NULL && localenv.date == NULL)) {
2128
2129 while (mssdepth) {
2130 mssdepth--;
2131 UUkillheaders (&(multistack[mssdepth].envelope));
2132 _FP_free (multistack[mssdepth].source);
2133 }
2134 sstate.isfolder = 0;
2135 sstate.ismime = 0;
2136
2137 UUkillheaders (&localenv);
2138 *errcode = UURET_NOMEM;
2139 _FP_free (result);
2140 return NULL;
2141 }
2142
2143 /* Scan subheader. But what if there is no subheader? */
2144 hcount = 0;
2145 lcount = 0;
2146 preheaders = prevpos;
2147
2148 if (_FP_fgets (line, 255, datei) == NULL) {
2149 sstate.isfolder = 0;
2150 sstate.ismime = 0;
2151 while (mssdepth) {
2152 mssdepth--;
2153 UUkillheaders (&(multistack[mssdepth].envelope));
2154 _FP_free (multistack[mssdepth].source);
2155 }
2156 UUkillheaders (&localenv);
2157 _FP_free (result);
2158 return NULL;
2159 }
2160 line[255] = '\0';
2161
2162 while (!feof (datei) && !IsLineEmpty (line)) {
2163 if (IsKnownHeader (line))
2164 hcount++;
2165 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2166 if (lcount > WAITHEADER && hcount == 0) {
2167 fseek (datei, preheaders, SEEK_SET);
2168 prevpos = preheaders;
2169 break;
2170 }
2171 ptr1 = ScanHeaderLine (datei, line);
2172 if (ParseHeader (&localenv, ptr1) == NULL)
2173 *errcode = UURET_NOMEM;
2174
2175 if (line[0] == '-' && line[1] == '-')
2176 break;
2177
2178 prevpos = ftell (datei);
2179
2180 if (_FP_fgets (line, 255, datei) == NULL)
2181 break;
2182 line[255] = '\0';
2183 lcount++;
2184 }
2185 if (line[0] == '-' && line[1] == '-') {
2186 /*
2187 * this shouldn't happen, there must always be an empty line,
2188 * but let's accept it anyway. Just skip back to before the
2189 * boundary, so that it gets handled below
2190 */
2191 fseek (datei, prevpos, SEEK_SET);
2192 }
2193
2194 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2195 /* oh no, not again */
2196 if (mssdepth >= MSMAXDEPTH) {
2197 /* Argh, what an isane message. Treat as plain text */
2198 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2199 uustring (S_MIME_MULTI_DEPTH));
2200 }
2201 else if (localenv.boundary == NULL) {
2202 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2203 uustring (S_MIME_NO_BOUNDARY));
2204 }
2205 else {
2206 memcpy (&multistack[mssdepth], &sstate, sizeof (scanstate));
2207 memcpy (&sstate.envelope, &localenv, sizeof (headers));
2208 memset (&localenv, 0, sizeof (headers));
2209 sstate.mimestate = MS_PREAMBLE;
2210 if ((sstate.source = _FP_strdup (sstate.source)) == NULL)
2211 *errcode = UURET_NOMEM;
2212
2213 if (*errcode == UURET_OK)
2214 *errcode = UURET_CONT;
2215
2216 mssdepth++;
2217 /* need a restart */
2218 _FP_free (result);
2219 return NULL;
2220 }
2221 }
2222
2223 /*
2224 * So this subpart is either plain text or something else. Check
2225 * the Content-Type and Content-Transfer-Encoding. If the latter
2226 * is a defined value, we know what to do and just copy everything
2227 * up to the boundary.
2228 * If Content-Transfer-Encoding is unknown or missing, look at the
2229 * Content-Type. If it's "text/plain" or undefined, we subject the
2230 * message to our encoding detection. Otherwise, treat as plain
2231 * text.
2232 * This is done because users might `attach' a uuencoded file, which
2233 * would then be correctly typed as `text/plain'.
2234 */
2235
2236 if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2237 result->uudet = B64ENCODED;
2238 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2239 result->uudet = UU_ENCODED;
2240 result->begin = result->end = 1;
2241 }
2242 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2243 result->uudet = YENC_ENCODED;
2244 result->begin = result->end = 1;
2245 }
2246 else if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2247 result->uudet = QP_ENCODED;
2248 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2249 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2250 result->uudet = PT_ENCODED;
2251 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2252 _FP_stristr (localenv.ctype, "message") != NULL)
2253 result->uudet = PT_ENCODED;
2254
2255 /*
2256 * If we're switched to MIME-only mode, handle as text
2257 */
2258
2259 if (uu_more_mime >= 2 && !result->uudet) {
2260 result->uudet = PT_ENCODED;
2261 }
2262
2263 if (result->uudet) {
2264 /*
2265 * Oh-kay, go ahead. Just read and wait for the boundary
2266 */
2267 result->startpos = ftell (datei);
2268 prevpos = ftell (datei);
2269 blen = strlen (sstate.envelope.boundary);
2270 lcount = 0;
2271
2272 while (!feof (datei)) {
2273 if (_FP_fgets (line, 255, datei) == NULL) {
2274 line[0] = '\0';
2275 break;
2276 }
2277 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2278 line[255] = '\0';
2279 if (line[0] == '-' && line[1] == '-' &&
2280 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2281 break;
2282 /*
2283 * I've had a report of someone who tried to decode a huge file
2284 * that had an early truncated multipart message and later another
2285 * multipart message with the *same* boundary. Consequently, all
2286 * some hundred messages inbetween were ignored ...
2287 * This check here doesn't cover folded header lines, but we don't
2288 * want to slow down scanning too much. We just check for
2289 * Content-Type: multipart/... boundary="same-boundary"
2290 */
2291 if (line[0] == 'C' && line[1] == 'o' &&
2292 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2293 ptr1 = ScanHeaderLine (datei, line);
2294 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2295 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2296 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2297 break;
2298 for (res=0; ptr1 && res<mssdepth; res++)
2299 if (strcmp (ptr1, multistack[res].envelope.boundary) == 0)
2300 break;
2301 if (res<mssdepth)
2302 break;
2303 }
2304 if (!IsLineEmpty (line))
2305 lcount++;
2306 prevpos = ftell (datei);
2307 }
2308 if (line[0] == '-' && line[1] == '-' &&
2309 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2310 ptr1 = line + 2 + blen;
2311 if (*ptr1 == '-' && *(ptr1+1) == '-')
2312 sstate.mimestate = MS_EPILOGUE;
2313 else
2314 sstate.mimestate = MS_SUBPART;
2315 }
2316 else {
2317 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2318 uustring (S_MIME_B_NOT_FOUND));
2319
2320 while (mssdepth) {
2321 mssdepth--;
2322 UUkillheaders (&(multistack[mssdepth].envelope));
2323 _FP_free (multistack[mssdepth].source);
2324 }
2325 /*
2326 * Don't retry if uu_fast_scanning
2327 */
2328
2329 if (uu_fast_scanning) {
2330 UUkillheaders (&localenv);
2331 sstate.isfolder = 0;
2332 sstate.ismime = 0;
2333 sstate.mimestate = MS_BODY;
2334 _FP_free (result);
2335 return NULL;
2336 }
2337
2338 /*
2339 * Retry, but listening to headers this time
2340 */
2341 fseek (datei, result->startpos, SEEK_SET);
2342
2343 UUkillfread (result);
2344 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2345 *errcode = UURET_NOMEM;
2346 sstate.isfolder = 0;
2347 sstate.ismime = 0;
2348 UUkillheaders (&localenv);
2349 return NULL;
2350 }
2351 memset (result, 0, sizeof (fileread));
2352
2353 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2354 /* oops, something went wrong */
2355 sstate.isfolder = 0;
2356 sstate.ismime = 0;
2357 UUkillfread (result);
2358 UUkillheaders (&localenv);
2359 return NULL;
2360 }
2361 if (res == 1) {
2362 /*
2363 * new headers found
2364 */
2365 sstate.isfolder = 1;
2366 sstate.ismime = 0;
2367 sstate.mimestate = MS_HEADERS;
2368 }
2369 else {
2370 sstate.isfolder = 0;
2371 sstate.ismime = 0;
2372 }
2373 }
2374 /* produce result if uu_handletext is set */
2375 /* or if the file is explicitely named */
2376 if (result->uudet == B64ENCODED || lcount) {
2377 if (localenv.fname) {
2378 _FP_free (result->filename);
2379 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2380 *errcode = UURET_NOMEM;
2381 }
2382 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
2383 result->filename == NULL && uu_handletext) {
2384 sprintf (line, "%04d.txt", ++mimseqno);
2385 if ((result->filename = _FP_strdup (line)) == NULL)
2386 *errcode = UURET_NOMEM;
2387 }
2388 result->subject = _FP_strdup (localenv.subject);
2389 result->origin = _FP_strdup (localenv.from);
2390 result->mimeid = _FP_strdup (localenv.mimeid);
2391 result->mimetype = _FP_strdup (localenv.ctype);
2392 result->mode = 0644;
2393 result->sfname = _FP_strdup (fname);
2394 result->flags = FL_SINGLE | FL_PROPER;
2395 result->partno = 1;
2396 /* result->uudet determined above */
2397 /* result->startpos set from above */
2398 result->length = prevpos - result->startpos;
2399
2400 if ((localenv.subject != NULL && result->subject == NULL) ||
2401 result->filename == NULL || result->sfname == NULL) {
2402 *errcode = UURET_NOMEM;
2403 }
2404 }
2405 else {
2406 /* don't produce a result */
2407 _FP_free (result);
2408 result = NULL;
2409 }
2410 if (*errcode == UURET_OK)
2411 *errcode = UURET_CONT;
2412 /*
2413 * destroy local envelope
2414 */
2415 UUkillheaders (&localenv);
2416 return result;
2417 }
2418
2419 /*
2420 * we're in a subpart, but the local headers don't give us any
2421 * clue about what's to find here. So look for encoded data by
2422 * ourselves.
2423 */
2424
2425 if ((res = ScanData (datei, fname, errcode,
2426 sstate.envelope.boundary,
2427 1, 0, result)) == -1) {
2428 /* oops, something went wrong */
2429 sstate.isfolder = 0;
2430 sstate.ismime = 0;
2431 UUkillfread (result);
2432 UUkillheaders (&localenv);
2433 return NULL;
2434 }
2435 /*
2436 * we should really be at a boundary here, but check again
2437 */
2438 blen = strlen (sstate.envelope.boundary);
2439 prevpos = ftell (datei);
2440
2441 while (!feof (datei)) {
2442 if (_FP_fgets (line, 255, datei) == NULL) {
2443 line[0] = '\0';
2444 break;
2445 }
2446 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2447 line[255] = '\0';
2448 if (line[0] == '-' && line[1] == '-' &&
2449 strncmp (line+2, sstate.envelope.boundary, blen) == 0)
2450 break;
2451 if (line[0] == 'C' && line[1] == 'o' &&
2452 _FP_strnicmp (line, "Content-Type:", 13) == 0) {
2453 ptr1 = ScanHeaderLine (datei, line);
2454 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
2455 ptr1 = (ptr2)?ParseValue(ptr2):NULL;
2456 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
2457 break;
2458 }
2459 prevpos = ftell (datei);
2460 }
2461 /*
2462 * check if this was the last subpart
2463 */
2464 if (line[0] == '-' && line[1] == '-' &&
2465 strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
2466 ptr1 = line + 2 + blen;
2467 if (*ptr1 == '-' && *(ptr1+1) == '-')
2468 sstate.mimestate = MS_EPILOGUE;
2469 else
2470 sstate.mimestate = MS_SUBPART;
2471 }
2472 else {
2473 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2474 uustring (S_MIME_B_NOT_FOUND));
2475
2476 while (mssdepth) {
2477 mssdepth--;
2478 UUkillheaders (&(multistack[mssdepth].envelope));
2479 _FP_free (multistack[mssdepth].source);
2480 }
2481
2482 if (uu_fast_scanning) {
2483 UUkillheaders (&localenv);
2484 sstate.isfolder = 0;
2485 sstate.ismime = 0;
2486 sstate.mimestate = MS_BODY;
2487 _FP_free (result);
2488 return NULL;
2489 }
2490
2491 /*
2492 * Retry, listening to headers this time
2493 */
2494 fseek (datei, result->startpos, SEEK_SET);
2495
2496 UUkillfread (result);
2497 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
2498 *errcode = UURET_NOMEM;
2499 sstate.isfolder = 0;
2500 sstate.ismime = 0;
2501 UUkillheaders (&localenv);
2502 return NULL;
2503 }
2504 memset (result, 0, sizeof (fileread));
2505
2506 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
2507 /* oops, something went wrong */
2508 sstate.isfolder = 0;
2509 sstate.ismime = 0;
2510 UUkillfread (result);
2511 UUkillheaders (&localenv);
2512 return NULL;
2513 }
2514 if (res == 1) {
2515 /*
2516 * new headers found
2517 */
2518 sstate.isfolder = 1;
2519 sstate.ismime = 0;
2520 sstate.mimestate = MS_HEADERS;
2521 }
2522 else {
2523 sstate.isfolder = 0;
2524 sstate.ismime = 0;
2525 }
2526 }
2527
2528 /*
2529 * If this file has been nicely MIME so far, then be very suspicious
2530 * if ScanData reports anything else. So do a double check, and if
2531 * it doesn't hold up, handle as plain text instead.
2532 */
2533
2534 if (sstate.ismime && sstate.mimestate == MS_SUBPART &&
2535 strcmp (localenv.mimevers, "1.0") == 0 &&
2536 _FP_stristr (localenv.ctype, "text") != NULL &&
2537 !uu_desperate) {
2538 if (result->uudet == UU_ENCODED && !(result->begin || result->end)) {
2539 result->uudet = 0;
2540 }
2541 }
2542
2543 /*
2544 * produce result
2545 */
2546
2547 if (result->uudet == 0) {
2548 result->uudet = PT_ENCODED; /* plain text */
2549 }
2550
2551 if (localenv.fname) {
2552 _FP_free (result->filename);
2553 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2554 *errcode = UURET_NOMEM;
2555 }
2556 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2557 result->filename==NULL && uu_handletext) {
2558 sprintf (line, "%04d.txt", ++mimseqno);
2559 if ((result->filename = _FP_strdup (line)) == NULL)
2560 *errcode = UURET_NOMEM;
2561 }
2562 else {
2563 /* assign a filename lateron */
2564 }
2565 if (result->mimetype) _FP_free (result->mimetype);
2566 if (result->uudet) {
2567 if (_FP_stristr (localenv.ctype, "text") != NULL &&
2568 result->uudet != QP_ENCODED && result->uudet != PT_ENCODED)
2569 result->mimetype = NULL; /* better don't set it */
2570 else
2571 result->mimetype = _FP_strdup (localenv.ctype);
2572 }
2573 if (result->origin) _FP_free (result->origin);
2574 result->origin = _FP_strdup (localenv.from);
2575
2576 if (result->subject) _FP_free (result->subject);
2577 result->subject = _FP_strdup (localenv.subject);
2578
2579 if (result->sfname == NULL)
2580 if ((result->sfname = _FP_strdup (fname)) == NULL)
2581 *errcode = UURET_NOMEM;
2582
2583 result->length = prevpos - result->startpos;
2584 result->flags = FL_SINGLE | FL_PROPER;
2585 result->partno = 1;
2586
2587 if (result->mode == 0)
2588 result->mode = 0644;
2589
2590 /*
2591 * the other fields should already be set appropriately
2592 */
2593
2594 if (*errcode == UURET_OK)
2595 *errcode = UURET_CONT;
2596
2597 /*
2598 * kill local envelope
2599 */
2600 UUkillheaders (&localenv);
2601
2602 return result;
2603 }
2604
2605 /*
2606 * All right, so we're not in a Multipart message. Phew, took quite
2607 * long to figure this out. But this might still be a MIME message
2608 * body. And if it's a message/partial, we need more special handling
2609 */
2610
2611 if (sstate.isfolder && sstate.ismime && sstate.mimestate == MS_BODY &&
2612 _FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2613 _FP_stristr (sstate.envelope.ctype, "partial") != NULL) {
2614
2615 result->startpos = ftell (datei);
2616
2617 if (sstate.envelope.partno == 1) {
2618 /* read local envelope */
2619 UUkillheaders (&localenv);
2620 memset (&localenv, 0, sizeof (headers));
2621
2622 /* skip over blank lines first */
2623 prevpos = ftell (datei);
2624 while (!feof (datei)) {
2625 if (_FP_fgets (line, 255, datei) == NULL)
2626 break;
2627 line[255] = '\0';
2628 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2629 if (!IsLineEmpty (line))
2630 break;
2631 prevpos = ftell (datei);
2632 }
2633 /* Next, read header. But what if there is no subheader? */
2634 hcount = 0;
2635 lcount = 0;
2636 preheaders = prevpos;
2637
2638 while (!feof (datei) && !IsLineEmpty (line)) {
2639 if (IsKnownHeader (line))
2640 hcount++;
2641 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2642 if (lcount > WAITHEADER && hcount == 0) {
2643 fseek (datei, preheaders, SEEK_SET);
2644 break;
2645 }
2646 ptr1 = ScanHeaderLine (datei, line);
2647 if (ParseHeader (&localenv, ptr1) == NULL)
2648 *errcode = UURET_NOMEM;
2649
2650 if (_FP_fgets (line, 255, datei) == NULL)
2651 break;
2652 line[255] = '\0';
2653 lcount++;
2654 }
2655 prevpos = ftell (datei);
2656 /*
2657 * Examine local header. We're mostly interested in the Content-Type
2658 * and the Content-Transfer-Encoding.
2659 */
2660 if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
2661 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
2662 uustring (S_MIME_PART_MULTI));
2663 }
2664 if (localenv.subject)
2665 result->subject = _FP_strdup (localenv.subject);
2666 else
2667 result->subject = _FP_strdup (sstate.envelope.subject);
2668
2669 if (localenv.from)
2670 result->origin = _FP_strdup (localenv.from);
2671 else
2672 result->origin = _FP_strdup (sstate.envelope.from);
2673
2674 if (localenv.ctype)
2675 result->mimetype = _FP_strdup (localenv.ctype);
2676 else
2677 result->mimetype = _FP_strdup ("text/plain");
2678
2679 if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
2680 result->uudet = QP_ENCODED;
2681 else if (_FP_stristr (localenv.ctenc, "base64") != NULL)
2682 result->uudet = B64ENCODED;
2683 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) {
2684 result->uudet = UU_ENCODED;
2685 result->begin = result->end = 1;
2686 }
2687 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) {
2688 result->uudet = YENC_ENCODED;
2689 result->begin = result->end = 1;
2690 }
2691 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
2692 _FP_stristr (localenv.ctenc, "8bit") != NULL)
2693 result->uudet = PT_ENCODED;
2694 else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
2695 _FP_stristr (localenv.ctype, "message") != NULL)
2696 result->uudet = PT_ENCODED;
2697
2698 /*
2699 * If we're switched to MIME-only mode, handle as text
2700 */
2701
2702 if (uu_more_mime >= 2 && !result->uudet) {
2703 result->uudet = PT_ENCODED;
2704 }
2705 }
2706 else {
2707 memset (&localenv, 0, sizeof (headers));
2708 }
2709
2710 /*
2711 * If this is Quoted-Printable or Plain Text, just try looking
2712 * for the next message header. If uu_fast_scanning, and the
2713 * encoding is known, there's no need to look below. Otherwise,
2714 * we check the type of encoding first.
2715 * The encoding type is determined on the first part; in all
2716 * others, we also don't read on.
2717 * If we have a partial multipart message, scan for headers, but
2718 * do not react on standard MIME headers, as they are probably
2719 * from the subparts. However, we're stuck if there's an embedded
2720 * message/rfc822 :-(
2721 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2722 * the message header and then start looking for the next header.
2723 */
2724 if (uu_fast_scanning && (result->uudet!=0||sstate.envelope.partno!=1)) {
2725 /* do nothing */
2726 res = 0;
2727 }
2728 else if (result->uudet != 0) {
2729 hcount = lcount = 0;
2730 prevpos = ftell (datei);
2731
2732 if (_FP_stristr (localenv.ctype, "message") != NULL &&
2733 _FP_stristr (localenv.ctype, "rfc822") != NULL) {
2734 /*
2735 * skip over empty lines and local header
2736 */
2737 preheaders = ftell (datei);
2738 while (!feof (datei)) {
2739 if (_FP_fgets (line, 255, datei) == NULL)
2740 break;
2741 line[255] = '\0';
2742 if (!IsLineEmpty (line)) {
2743 break;
2744 }
2745 }
2746
2747 while (!feof (datei) && !IsLineEmpty (line)) {
2748 if (IsKnownHeader (line))
2749 hcount++;
2750 lcount++;
2751 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2752 break;
2753
2754 if (_FP_fgets (line, 255, datei) == NULL)
2755 break;
2756 line[255] = '\0';
2757 }
2758 if (hcount < hlcount.afternl)
2759 fseek (datei, preheaders, SEEK_SET);
2760 hcount = lcount = 0;
2761 }
2762
2763 /*
2764 * look for next header
2765 */
2766
2767 while (!feof (datei)) {
2768 if (_FP_fgets (line, 255, datei) == NULL)
2769 break;
2770 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
2771 if (ferror (datei))
2772 break;
2773 line[255] = '\0';
2774
2775 if ((vflag = IsKnownHeader (line))) {
2776 (void) ScanHeaderLine (datei, line);
2777
2778 if (result->uudet != PT_ENCODED || vflag == 1) {
2779 if (hcount == 0)
2780 preheaders = prevpos;
2781 hcount++;
2782 lcount++;
2783 if (hcount >= hlcount.restart) {
2784 /*
2785 * Hey, a new header starts here
2786 */
2787 fseek (datei, preheaders, SEEK_SET);
2788 prevpos = preheaders;
2789 break;
2790 }
2791 }
2792 }
2793 else if (lcount > WAITHEADER) {
2794 hcount = 0;
2795 lcount = 0;
2796 }
2797 else if (hcount) {
2798 lcount++;
2799 }
2800 prevpos = ftell (datei);
2801 }
2802 res = 1;
2803 }
2804 else {
2805 /*
2806 * Otherwise, let's see what we can find ourself. No
2807 * boundary (NULL) but MIME, and respect new headers.
2808 */
2809 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
2810 /* oops, something went wrong */
2811 sstate.isfolder = 0;
2812 sstate.ismime = 0;
2813 UUkillfread (result);
2814 UUkillheaders (&localenv);
2815 return NULL;
2816 }
2817 if (result->uudet == 0 && uu_handletext)
2818 result->uudet = PT_ENCODED;
2819
2820 prevpos = ftell (datei);
2821 }
2822 /*
2823 * produce result
2824 */
2825 if (localenv.fname) {
2826 _FP_free (result->filename);
2827 if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
2828 *errcode = UURET_NOMEM;
2829 }
2830 else if (sstate.envelope.fname) {
2831 _FP_free (result->filename);
2832 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
2833 *errcode = UURET_NOMEM;
2834 }
2835 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
2836 result->filename == NULL) {
2837 sprintf (line, "%04d.txt", ++mimseqno);
2838 if ((result->filename = _FP_strdup (line)) == NULL)
2839 *errcode = UURET_NOMEM;
2840 }
2841 else {
2842 /* assign a filename lateron */
2843 }
2844 if (result->subject == NULL) {
2845 if (sstate.envelope.subject)
2846 result->subject = _FP_strdup (sstate.envelope.subject);
2847 }
2848 result->partno = sstate.envelope.partno;
2849 result->maxpno = sstate.envelope.numparts;
2850 result->flags = FL_PARTIAL |
2851 ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) |
2852 ((uu_fast_scanning) ? FL_TOEND : 0);
2853 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
2854 if (result->partno == 1)
2855 result->begin = 1;
2856
2857 if (uu_fast_scanning)
2858 result->length = progress.fsize - result->startpos;
2859 else
2860 result->length = prevpos - result->startpos;
2861
2862 if (result->sfname == NULL)
2863 result->sfname = _FP_strdup (fname);
2864
2865 if (result->mode == 0)
2866 result->mode = 0644;
2867
2868 /*
2869 * the other fields should already be set appropriately
2870 */
2871
2872 if (res == 1) {
2873 /*
2874 * new headers found
2875 */
2876 sstate.isfolder = 1;
2877 sstate.ismime = 0;
2878 sstate.mimestate = MS_HEADERS;
2879
2880 UUkillheaders (&sstate.envelope);
2881 memset (&sstate.envelope, 0, sizeof (headers));
2882 }
2883 else {
2884 /*
2885 * otherwise, this can't be a mail folder
2886 */
2887 sstate.isfolder = 0;
2888 sstate.ismime = 0;
2889 }
2890 /*
2891 * kill local envelope
2892 */
2893 UUkillheaders (&localenv);
2894 return result;
2895 }
2896
2897 /*
2898 * If this is a MIME body, honor a Content-Type different than
2899 * text/plain or a proper Content-Transfer-Encoding.
2900 * We also go in here if we have an assigned filename - this means
2901 * that we've had a Content-Disposition field, and we should probably
2902 * decode a plain-text segment with a filename.
2903 */
2904
2905 if (sstate.isfolder && sstate.ismime &&
2906 sstate.mimestate == MS_BODY &&
2907 (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL ||
2908 _FP_stristr (sstate.envelope.ctenc, "base64") != NULL ||
2909 _FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL ||
2910 _FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL ||
2911 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2912 sstate.envelope.fname != NULL)) {
2913
2914 if (sstate.envelope.subject)
2915 result->subject = _FP_strdup (sstate.envelope.subject);
2916 if (sstate.envelope.from)
2917 result->origin = _FP_strdup (sstate.envelope.from);
2918
2919 if (sstate.envelope.ctype)
2920 result->mimetype = _FP_strdup (sstate.envelope.ctype);
2921 else
2922 result->mimetype = _FP_strdup ("text/plain");
2923
2924 if (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL)
2925 result->uudet = QP_ENCODED;
2926 else if (_FP_stristr (sstate.envelope.ctenc, "base64") != NULL)
2927 result->uudet = B64ENCODED;
2928 else if (_FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL) {
2929 result->uudet = UU_ENCODED;
2930 result->begin = result->end = 1;
2931 }
2932 else if (_FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL) {
2933 result->uudet = YENC_ENCODED;
2934 }
2935 else if (_FP_stristr (sstate.envelope.ctenc, "7bit") != NULL ||
2936 _FP_stristr (sstate.envelope.ctenc, "8bit") != NULL)
2937 result->uudet = PT_ENCODED;
2938 else if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL ||
2939 _FP_stristr (sstate.envelope.ctype, "message") != NULL ||
2940 sstate.envelope.fname != NULL)
2941 result->uudet = PT_ENCODED;
2942
2943 /*
2944 * If we're switched to MIME-only mode, handle as text
2945 */
2946
2947 if (uu_more_mime >= 2 && !result->uudet) {
2948 result->uudet = PT_ENCODED;
2949 }
2950
2951 result->startpos = prevpos = ftell (datei);
2952
2953 /*
2954 * If this is Quoted-Printable or Plain Text, just try looking
2955 * for the next message header. If uu_fast_scanning, we know
2956 * there won't be more headers.
2957 * If it is a "trivial" (non-embedded) message/rfc822, skip over
2958 * the message header and then start looking for the next header.
2959 */
2960 if (result->uudet != 0 && uu_fast_scanning) {
2961 /* do nothing */
2962 res = 0;
2963 }
2964 else if (result->uudet != 0) {
2965 hcount = lcount = 0;
2966 prevpos = ftell (datei);
2967
2968 if (_FP_stristr (sstate.envelope.ctype, "message") != NULL &&
2969 _FP_stristr (sstate.envelope.ctype, "rfc822") != NULL) {
2970 /*
2971 * skip over empty lines and local header
2972 */
2973 preheaders = ftell (datei);
2974 while (!feof (datei)) {
2975 if (_FP_fgets (line, 255, datei) == NULL)
2976 break;
2977 line[255] = '\0';
2978 if (!IsLineEmpty (line)) {
2979 break;
2980 }
2981 }
2982
2983 while (!feof (datei) && !IsLineEmpty (line)) {
2984 if (IsKnownHeader (line))
2985 hcount++;
2986 lcount++;
2987 if (lcount > WAITHEADER && hcount < hlcount.afternl)
2988 break;
2989
2990 if (_FP_fgets (line, 255, datei) == NULL)
2991 break;
2992 line[255] = '\0';
2993 }
2994 if (hcount < hlcount.afternl)
2995 fseek (datei, preheaders, SEEK_SET);
2996 hcount = lcount = 0;
2997 }
2998
2999 /*
3000 * look for next header
3001 */
3002
3003 while (!feof (datei)) {
3004 if (_FP_fgets (line, 255, datei) == NULL)
3005 break;
3006 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
3007 if (ferror (datei))
3008 break;
3009 line[255] = '\0';
3010
3011 if (IsKnownHeader (line)) {
3012 (void) ScanHeaderLine (datei, line);
3013 if (hcount == 0)
3014 preheaders = prevpos;
3015 hcount++;
3016 lcount++;
3017 if (hcount >= hlcount.restart) {
3018 /*
3019 * Hey, a new header starts here
3020 */
3021 fseek (datei, preheaders, SEEK_SET);
3022 prevpos = preheaders;
3023 break;
3024 }
3025 }
3026 else if (lcount > WAITHEADER) {
3027 hcount = 0;
3028 lcount = 0;
3029 }
3030 else if (hcount) {
3031 lcount++;
3032 }
3033 prevpos = ftell (datei);
3034 }
3035 res = 1;
3036 }
3037 else {
3038 /*
3039 * Otherwise, let's see what we can find ourself. No
3040 * boundary (NULL) but MIME, and respect new headers.
3041 */
3042 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
3043 /* oops, something went wrong */
3044 sstate.isfolder = 0;
3045 sstate.ismime = 0;
3046 UUkillfread (result);
3047 return NULL;
3048 }
3049 if (result->uudet == 0 && uu_handletext) {
3050 result->startpos = before; /* display headers */
3051 result->uudet = PT_ENCODED;
3052 }
3053
3054 prevpos = ftell (datei);
3055 }
3056 /*
3057 * produce result
3058 */
3059 if (sstate.envelope.fname) {
3060 _FP_free (result->filename);
3061 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3062 *errcode = UURET_NOMEM;
3063 }
3064 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3065 result->filename == NULL) {
3066 sprintf (line, "%04d.txt", ++mimseqno);
3067 if ((result->filename = _FP_strdup (line)) == NULL)
3068 *errcode = UURET_NOMEM;
3069 }
3070 else {
3071 /* assign a filename lateron */
3072 }
3073 if (result->subject == NULL) {
3074 if (sstate.envelope.subject)
3075 result->subject = _FP_strdup (sstate.envelope.subject);
3076 }
3077 result->flags = ((res==1||uu_fast_scanning)?FL_PROPER:0) |
3078 ((uu_fast_scanning) ? FL_TOEND : 0);
3079 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3080
3081 if (uu_fast_scanning)
3082 result->length = progress.fsize - result->startpos;
3083 else
3084 result->length = prevpos - result->startpos;
3085
3086 if (result->sfname == NULL)
3087 result->sfname = _FP_strdup (fname);
3088
3089 if (result->mode == 0)
3090 result->mode = 0644;
3091
3092 /*
3093 * the other fields should already be set appropriately
3094 */
3095
3096 if (res == 1) {
3097 /*
3098 * new headers found
3099 */
3100 sstate.isfolder = 1;
3101 sstate.ismime = 0;
3102 sstate.mimestate = MS_HEADERS;
3103
3104 UUkillheaders (&sstate.envelope);
3105 memset (&sstate.envelope, 0, sizeof (headers));
3106 }
3107 else {
3108 /*
3109 * otherwise, this can't be a mail folder
3110 */
3111 sstate.isfolder = 0;
3112 sstate.ismime = 0;
3113 }
3114
3115 return result;
3116 }
3117
3118 /*
3119 * Some files have reduced headers, and what should be a multipart
3120 * message is missing the proper Content-Type. If the first thing
3121 * we find after a couple of empty lines is a boundary, try it!
3122 * But make sure that this is indeed intended as being a boundary.
3123 *
3124 * Only accept it if there was indeed no Content-Type header line
3125 * and if the following line is a proper Content-Type header. BTW,
3126 * we know that sstate.envelope.boundary is NULL, or we wouldn't
3127 * be here!
3128 */
3129
3130 if ((!sstate.envelope.ctype || _FP_stristr (sstate.envelope.ctype, "multipart"))
3131 && !uu_more_mime) {
3132 prevpos = ftell (datei);
3133 while (!feof (datei)) {
3134 if (_FP_fgets (line, 255, datei) == NULL) {
3135 line[0] = '\0';
3136 break;
3137 }
3138 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
3139 if (!IsLineEmpty (line))
3140 break;
3141 }
3142 if (line[0] == '-' && line[1] == '-' &&
3143 !IsLineEmpty (line+2) && !feof (datei)) {
3144 ptr1 = _FP_strrstr (line+2, "--");
3145 ptr2 = ScanHeaderLine (datei, NULL);
3146 if ((ptr1 == NULL || (*(ptr1+2) != '\012' && *(ptr1+2) != '\015')) &&
3147 ptr2 && _FP_strnicmp (ptr2, "Content-", 8) == 0) {
3148 /*
3149 * hmm, okay, let's do it!
3150 */
3151 sstate.isfolder = 1;
3152 sstate.ismime = 1;
3153 sstate.mimestate = MS_PREAMBLE;
3154 /*
3155 * get boundary
3156 */
3157 ptr1 = line+2;
3158 while (*ptr1 && !isspace(*ptr1))
3159 ptr1++;
3160 *ptr1 = '\0';
3161
3162 sstate.envelope.mimevers = _FP_strdup ("1.0");
3163 sstate.envelope.boundary = _FP_strdup (line+2);
3164
3165 /*
3166 * need restart
3167 */
3168
3169 fseek (datei, prevpos, SEEK_SET);
3170
3171 _FP_free (result);
3172 return NULL;
3173 }
3174 }
3175 fseek (datei, prevpos, SEEK_SET);
3176 }
3177
3178 /*
3179 * Hmm, we're not in a ''special'' state, so it's more or less
3180 * Freestyle time. Anyway, if this seems to be a Mime message,
3181 * don't allow the minimal Base64 handling.
3182 */
3183
3184 if (sstate.envelope.subject)
3185 result->subject = _FP_strdup (sstate.envelope.subject);
3186
3187 if (sstate.envelope.from)
3188 result->origin = _FP_strdup (sstate.envelope.from);
3189
3190 if (sstate.envelope.ctype)
3191 result->mimetype = _FP_strdup (sstate.envelope.ctype);
3192
3193 if ((res=ScanData (datei, fname, errcode, NULL,
3194 sstate.ismime, 1, result))==-1) {
3195 /* oops, something went wrong */
3196 sstate.isfolder = 0;
3197 sstate.ismime = 0;
3198 UUkillfread (result);
3199 return NULL;
3200 }
3201
3202 /*
3203 * produce result
3204 */
3205
3206 if (result->uudet == 0 && uu_handletext) {
3207 result->startpos = before; /* display headers */
3208 result->uudet = PT_ENCODED;
3209 result->partno = 1;
3210 }
3211
3212 if (result->uudet == YENC_ENCODED && result->filename != NULL) {
3213 /*
3214 * prevent replacing the filename found on the =ybegin line
3215 */
3216 }
3217 else if (sstate.envelope.fname) {
3218 _FP_free (result->filename);
3219 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
3220 *errcode = UURET_NOMEM;
3221 }
3222 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
3223 result->filename == NULL) {
3224 sprintf (line, "%04d.txt", ++mimseqno);
3225 if ((result->filename = _FP_strdup (line)) == NULL)
3226 *errcode = UURET_NOMEM;
3227 }
3228 else {
3229 /* assign a filename lateron */
3230 }
3231
3232 if (result->subject == NULL) {
3233 if (sstate.envelope.subject)
3234 result->subject = _FP_strdup (sstate.envelope.subject);
3235 }
3236
3237 result->flags = (result->uudet==PT_ENCODED)?FL_SINGLE:0;
3238 result->mimeid = _FP_strdup (sstate.envelope.mimeid);
3239 result->length = ftell (datei) - result->startpos;
3240
3241 if (result->mode == 0)
3242 result->mode = 0644;
3243
3244 if (result->sfname == NULL)
3245 result->sfname = _FP_strdup (fname);
3246
3247 if (res == 1) {
3248 /*
3249 * new headers found
3250 */
3251 sstate.isfolder = 1;
3252 sstate.ismime = 0;
3253 sstate.mimestate = MS_HEADERS;
3254
3255 UUkillheaders (&sstate.envelope);
3256 memset (&sstate.envelope, 0, sizeof (headers));
3257 }
3258 else {
3259 /*
3260 * otherwise, this can't be a mail folder
3261 */
3262 sstate.isfolder = 0;
3263 sstate.ismime = 0;
3264 }
3265
3266 return result;
3267
3268 /*
3269 * Emergency handling. Set errcode before jumping here.
3270 */
3271 ScanPartEmergency:
3272 UUkillfread (result);
3273 UUkillheaders (&localenv);
3274
3275 while (mssdepth) {
3276 mssdepth--;
3277 UUkillheaders (&(multistack[mssdepth].envelope));
3278 _FP_free (multistack[mssdepth].source);
3279 }
3280
3281 return NULL;
3282 }
3283