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