ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.19
Committed: Fri Jul 10 01:17:08 2015 UTC (8 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_5
Changes since 1.18: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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