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