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