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