ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.3.2.4
Committed: Thu Nov 6 13:08:24 2003 UTC (20 years, 7 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-19
Changes since 1.3.2.3: +149 -37 lines
Log Message:
*** empty log message ***

File Contents

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