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