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