ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.27
Committed: Sat Sep 24 06:02:04 2022 UTC (20 months, 1 week ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +0 -2 lines
Log Message:
*** empty log message ***

File Contents

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