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