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