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