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