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