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