ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.8
Committed: Sun Feb 1 18:50:00 2004 UTC (20 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +8 -6 lines
Log Message:
*** empty log message ***

File Contents

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