ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uuscan.c
Revision: 1.3.2.3
Committed: Sun Oct 13 13:03:09 2002 UTC (21 years, 7 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-18
Changes since 1.3.2.2: +8 -4 lines
Log Message:
*** empty log message ***

File Contents

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