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