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