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