ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.3.2.2
Committed: Sun Mar 31 19:52:08 2002 UTC (22 years, 2 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-17
Changes since 1.3.2.1: +135 -18 lines
Log Message:
*** empty log message ***

File Contents

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