00001 /* 00002 * This file is part of uudeview, the simple and friendly multi-part multi- 00003 * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may 00004 * be contacted at [email protected] 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 */ 00016 00017 /* 00018 * These are very central functions of UUDeview. Here, we scan a file 00019 * and decide whether it contains encoded data or not. ScanPart() must 00020 * be called repeatedly on the same file until feof(file). Each time, 00021 * it returns information about the next part found within. 00022 */ 00023 00024 #ifdef HAVE_CONFIG_H 00025 #ifdef _MSC_VER 00026 #include "config.h.win32" 00027 #else 00028 #include "config.h" 00029 #endif 00030 #endif 00031 00032 #ifdef SYSTEM_WINDLL 00033 #include00034 #endif 00035 #ifdef SYSTEM_OS2 00036 #include 00037 #endif 00038 00039 #include 00040 #include 00041 00042 #ifdef STDC_HEADERS 00043 #include 00044 #include 00045 #endif 00046 #ifdef HAVE_MALLOC_H 00047 #include 00048 #endif 00049 #ifdef HAVE_UNISTD_H 00050 #include 00051 #endif 00052 #ifdef HAVE_MEMORY_H 00053 #include 00054 #endif 00055 #ifdef HAVE_ERRNO_H 00056 #include 00057 #endif 00058 00059 #include uudeview.h> 00060 #include uuint.h> 00061 #include fptools.h> 00062 #include uustring.h> 00063 00064 char * uuscan_id = "$Id: uuscan.c 316 2007-08-01 17:26:35Z csk $"; 00065 00066 /* 00067 * Header fields we recognize as such. See RFC822. We add "From ", 00068 * the usual marker for a beginning of a new message, and a couple 00069 * of usual MDA, News and MIME headers. 00070 * We make a distinction of MIME headers as we need the difference 00071 * to scan the bodies from partial multipart messages. 00072 * 00073 * Change for Pan: sysprof says this is another uulib hotspot. 00074 * I've converted these to lowercase and sorted them so that 00075 * IsKnownHeader can pass a lowercase buf to bsearch rather than 00076 * having to do a stricmp against each header. 00077 */ 00078 static char *knownmsgheaders[] = { 00079 "bcc:", "cc:", "comments:", "date:", "delivery-date:", 00080 "from ", "from:", "in-reply-to:", "keywords:", "lines:", 00081 "message-id:", "newsgroups:", "nntp-posting-host:", 00082 "organization:", "path:", "posted-date:", "precedence:", 00083 "received-date:", "received:", "references:", "reply-to:", 00084 "resent-bcc:", "resent-date:", "resent-from:", "resent-message-id:", 00085 "resent-reply-to:", "resent-sender:", "resent-to:", "return-path:", 00086 "sender:", "subject:", "to:" 00087 }; 00088 00089 static char *knownmimeheaders[] = { 00090 "content-description:", "content-disposition:", "content-length:", 00091 "content-transfer-encoding:", "content-type:", "mime-version:" 00092 }; 00093 00094 /* 00095 * for MIME (plaintext) parts without filename 00096 */ 00097 int mimseqno; 00098 00099 /* 00100 * how many lines do we read when checking for headers 00101 */ 00102 #define WAITHEADER 10 00103 00104 /* 00105 * The stack for encapsulated Multipart messages 00106 */ 00107 #define MSMAXDEPTH 3 00108 00109 int mssdepth = 0; 00110 scanstate multistack[MSMAXDEPTH+1]; 00111 00112 /* 00113 * The state and the local envelope 00114 */ 00115 headers localenv; 00116 scanstate sstate; 00117 00118 /* 00119 * mallocable areas 00120 */ 00121 00122 char *uuscan_shlline; 00123 char *uuscan_shlline2; 00124 char *uuscan_pvvalue; 00125 char *uuscan_phtext; 00126 char *uuscan_sdline; 00127 char *uuscan_sdbhds1; 00128 char *uuscan_sdbhds2; 00129 char *uuscan_spline; 00130 00131 /* 00132 * Macro: print cancellation message in UUScanPart 00133 */ 00134 00135 #define SPCANCEL() {UUMessage(uuscan_id,__LINE__,UUMSG_NOTE,uustring(S_SCAN_CANCEL));*errcode=UURET_CANCEL;goto ScanPartEmergency;} 00136 00137 /* 00138 * Is line empty? A line is empty if it is composed of whitespace. 00139 */ 00140 00141 static int 00142 IsLineEmpty (char *data) 00143 { 00144 if (data == NULL) return 0; 00145 while (*data && isspace ((unsigned char)*data)) data++; 00146 return ((*data)?0:1); 00147 } 00148 00149 /* 00150 * Is this a header line? A header line has alphanumeric characters 00151 * followed by a colon. 00152 */ 00153 00154 static int 00155 IsHeaderLine (char *data) 00156 { 00157 if (data == NULL) return 0; 00158 if (*data == ':') return 0; 00159 while (*data && (isalnum ((unsigned char)*data) || *data=='-')) data++; 00160 return (*data == ':') ? 1 : 0; 00161 } 00162 00163 /* 00164 * Scans a potentially folded header line from the input file. If 00165 * initial is non-NULL, it is the first line of the header, useful 00166 * if the calling function just coincidentally noticed that this is 00167 * a header. 00168 * RFC0822 does not specify a maximum length for headers, but we 00169 * truncate everything beyond an insane value of 1024 characters. 00170 */ 00171 00172 static char * 00173 ScanHeaderLine (FILE *datei, char *initial) 00174 { 00175 char *ptr=uuscan_shlline; 00176 char *ptr2, *p1, *p2, *p3; 00177 int llength; 00178 long curpos; 00179 int hadcr; 00180 size_t len; 00181 00182 if (initial) { 00183 _FP_strncpy (uuscan_shlline, initial, 1023); 00184 } 00185 else { 00186 /* read first line */ 00187 if (feof (datei) || ferror (datei)) 00188 return NULL; 00189 if (_FP_fgets (uuscan_shlline, 1023, datei) == NULL) 00190 return NULL; 00191 uuscan_shlline[1023] = '\0'; 00192 } 00193 00194 llength = strlen (uuscan_shlline); 00195 hadcr = 0; 00196 00197 /* strip whitespace at end */ 00198 ptr = uuscan_shlline + llength; 00199 while (llength && isspace((unsigned char)*(ptr-1))) { 00200 if (*(ptr-1) == '\012' || *(ptr-1) == '\015') 00201 hadcr = 1; 00202 ptr--; llength--; 00203 } 00204 if (llength == 0) { 00205 uuscan_shlline[0] = '\0'; 00206 return uuscan_shlline; 00207 } 00208 00209 while (!feof (datei)) { 00210 char c = fgetc (datei); 00211 if (feof (datei)) 00212 break; 00213 00214 /* 00215 * If the line didn't have a CR, it was longer than 256 characters 00216 * and is continued anyway. 00217 */ 00218 00219 if (hadcr==1 && c != ' ' && c != '\t') { 00220 /* no LWSP-char, header line does not continue */ 00221 ungetc (c, datei); 00222 break; 00223 } 00224 while (!feof (datei) && (c == ' ' || c == '\t')) 00225 c = fgetc (datei); 00226 00227 if (!feof (datei)) 00228 ungetc (c, datei); /* push back for fgets() */ 00229 00230 /* insert a single LWSP */ 00231 if (hadcr==1 && llength 00232 *ptr++ = ' '; 00233 llength++; 00234 } 00235 *ptr = '\0'; /* make lint happier */ 00236 00237 if (feof (datei)) 00238 break; 00239 00240 /* read next line */ 00241 curpos = ftell (datei); 00242 if (_FP_fgets (uugen_inbuffer, 255, datei) == NULL) 00243 break; 00244 uugen_inbuffer[255] = '\0'; 00245 00246 if (IsLineEmpty (uugen_inbuffer)) { /* oops */ 00247 fseek (datei, curpos, SEEK_SET); 00248 break; 00249 } 00250 00251 if (llength 00252 break; 00253 } 00254 00255 _FP_strncpy (ptr, uugen_inbuffer, 1024-llength); 00256 00257 /* 00258 * see if line was terminated with CR. Otherwise, it continues ... 00259 */ 00260 len = strlen (uugen_inbuffer); 00261 if (len > 0 && 00262 (uugen_inbuffer[len - 1] == '\012' || uugen_inbuffer[len - 1] == '\015')) 00263 hadcr = 1; 00264 else 00265 hadcr = 0; 00266 00267 /* 00268 * strip whitespace 00269 */ 00270 00271 len = strlen (ptr); 00272 ptr += len; 00273 llength += len; 00274 while (llength > 0 && isspace((unsigned char)*(ptr-1))) { 00275 ptr--; llength--; 00276 } 00277 } 00278 00279 *ptr = '\0'; 00280 00281 if (llength == 0) 00282 return NULL; 00283 00284 /* 00285 * Now that we've read the header line, we can RFC 1522-decode it 00286 */ 00287 00288 ptr = uuscan_shlline; 00289 ptr2 = uuscan_shlline2; 00290 00291 while (*ptr) { 00292 /* 00293 * Look for =? magic 00294 */ 00295 00296 if (*ptr == '=' && *(ptr+1) == '?') { 00297 /* 00298 * Let p1 point to the charset, look for next question mark 00299 */ 00300 00301 p1 = p2 = ptr+2; 00302 00303 while (*p2 && *p2 != '?') { 00304 p2++; 00305 } 00306 00307 if (*p2 == '?' && 00308 (*(p2+1) == 'q' || *(p2+1) == 'Q' || 00309 *(p2+1) == 'b' || *(p2+1) == 'B') && 00310 *(p2+2) == '?') { 00311 /* 00312 * Let p2 point to the encoding, look for ?= magic 00313 */ 00314 00315 p2++; 00316 p3=p2+2; 00317 00318 while (*p3 && (*p3 != '?' || *(p3+1) != '=')) { 00319 p3++; 00320 } 00321 00322 if (*p3 == '?' && *(p3+1) == '=') { 00323 char c = -1; 00324 /* 00325 * Alright, we've found an RFC 1522 header field 00326 */ 00327 c = -1; 00328 if (*p2 == 'q' || *p2 == 'Q') { 00329 c = UUDecodeField (p2+2, ptr2, QP_ENCODED); 00330 } 00331 else if (*p2 == 'b' || *p2 == 'B') { 00332 c = UUDecodeField (p2+2, ptr2, B64ENCODED); 00333 } 00334 if (c >= 0) { 00335 ptr2 += c; 00336 ptr = p3+2; 00337 continue; 00338 } 00339 } 00340 } 00341 } 00342 00343 *ptr2++ = *ptr++; 00344 } 00345 00346 *ptr2 = 0; 00347 00348 return uuscan_shlline2; 00349 } 00350 00351 /* 00352 * Extract the value from a MIME attribute=value pair. This function 00353 * receives a pointer to the attribute. 00354 */ 00355 static char * 00356 ParseValue (char *attribute) 00357 { 00358 char *ptr=uuscan_pvvalue; 00359 int length=0; 00360 00361 if (attribute == NULL) 00362 return NULL; 00363 00364 while ((isalnum((unsigned char)*attribute) || *attribute=='_') && *attribute != '=') 00365 attribute++; 00366 00367 while (isspace((unsigned char)*attribute)) 00368 attribute++; 00369 00370 if (*attribute == '=') { 00371 attribute++; 00372 while (isspace ((unsigned char)*attribute)) 00373 attribute++; 00374 } 00375 else 00376 return NULL; 00377 00378 if (*attribute == '"') { 00379 /* quoted-string */ 00380 attribute++; 00381 while (*attribute && *attribute != '"' && length 00382 *ptr++ = *attribute++; 00383 length++; 00384 } 00385 *ptr = '\0'; 00386 } 00387 else { 00388 /* tspecials from RFC1521 */ 00389 /* 00390 * Note - exclude '[', ']' and ';' on popular request; these are 00391 * used in some Content-Type fields by the Klez virus, and people 00392 * who feed their virus scanners with the output of UUDeview would 00393 * like to catch it! 00394 */ 00395 00396 while (*attribute && !isspace ((unsigned char)*attribute) && 00397 *attribute != '(' && *attribute != ')' && 00398 *attribute != ' && *attribute != '>' && 00399 *attribute != '@' && *attribute != ',' && 00400 *attribute != ';' && *attribute != ':' && 00401 *attribute != '\\' && *attribute != '"' && 00402 *attribute != '/' && *attribute != '[' && 00403 *attribute != ']' && *attribute != '?' && 00404 *attribute != '=' && length 00405 *ptr++ = *attribute++; 00406 length++; 00407 } 00408 00409 *ptr = '\0'; 00410 } 00411 return uuscan_pvvalue; 00412 } 00413 00414 /* 00415 * Extract the information we need from header fields 00416 */ 00417 00418 static headers * 00419 ParseHeader (headers *theheaders, char *line) 00420 { 00421 char **variable=NULL; 00422 char *value, *ptr, *thenew; 00423 int delimit, length; 00424 00425 if (line == NULL) 00426 return theheaders; 00427 00428 if (_FP_strnicmp (line, "From:", 5) == 0) { 00429 if (theheaders->from) return theheaders; 00430 variable = &theheaders->from; 00431 value = line+5; 00432 delimit = 0; 00433 } 00434 else if (_FP_strnicmp (line, "Subject:", 8) == 0) { 00435 if (theheaders->subject) return theheaders; 00436 variable = &theheaders->subject; 00437 value = line+8; 00438 delimit = 0; 00439 } 00440 else if (_FP_strnicmp (line, "To:", 3) == 0) { 00441 if (theheaders->rcpt) return theheaders; 00442 variable = &theheaders->rcpt; 00443 value = line+3; 00444 delimit = 0; 00445 } 00446 else if (_FP_strnicmp (line, "Date:", 5) == 0) { 00447 if (theheaders->date) return theheaders; 00448 variable = &theheaders->date; 00449 value = line+5; 00450 delimit = 0; 00451 } 00452 else if (_FP_strnicmp (line, "Mime-Version:", 13) == 0) { 00453 if (theheaders->mimevers) return theheaders; 00454 variable = &theheaders->mimevers; 00455 value = line+13; 00456 delimit = 0; 00457 } 00458 else if (_FP_strnicmp (line, "Content-Type:", 13) == 0) { 00459 if (theheaders->ctype) return theheaders; 00460 variable = &theheaders->ctype; 00461 value = line+13; 00462 delimit = ';'; 00463 00464 /* we can probably extract more information */ 00465 if ((ptr = _FP_stristr (line, "boundary")) != NULL) { 00466 if ((thenew = ParseValue (ptr))) { 00467 if (theheaders->boundary) free (theheaders->boundary); 00468 theheaders->boundary = _FP_strdup (thenew); 00469 } 00470 } 00471 if ((ptr = _FP_stristr (line, "name")) != NULL) { 00472 if ((thenew = ParseValue (ptr))) { 00473 if (theheaders->fname) free (theheaders->fname); 00474 theheaders->fname = _FP_strdup (thenew); 00475 } 00476 } 00477 if ((ptr = _FP_stristr (line, "id")) != NULL) { 00478 if ((thenew = ParseValue (ptr))) { 00479 if (theheaders->mimeid) free (theheaders->mimeid); 00480 theheaders->mimeid = _FP_strdup (thenew); 00481 } 00482 } 00483 if ((ptr = _FP_stristr (line, "number")) != NULL) { 00484 if ((thenew = ParseValue (ptr))) { 00485 theheaders->partno = atoi (thenew); 00486 } 00487 } 00488 if ((ptr = _FP_stristr (line, "total")) != NULL) { 00489 if ((thenew = ParseValue (ptr))) { 00490 theheaders->numparts = atoi (thenew); 00491 } 00492 } 00493 } 00494 else if (_FP_strnicmp (line, "Content-Transfer-Encoding:", 26) == 0) { 00495 if (theheaders->ctenc) return theheaders; 00496 variable = &theheaders->ctenc; 00497 value = line+26; 00498 delimit = ';'; 00499 } 00500 else if (_FP_strnicmp (line, "Content-Disposition:", 20) == 0) { 00501 /* 00502 * Some encoders mention the original filename as parameter to 00503 * Content-Type, others as parameter to Content-Disposition. We 00504 * do prefer the first solution, but accept this situation, too. 00505 * TODO: Read RFC1806 00506 */ 00507 if ((ptr = _FP_stristr (line, "name")) != NULL) { 00508 if (theheaders->fname == NULL && (thenew=ParseValue(ptr)) != NULL) { 00509 theheaders->fname = _FP_strdup (thenew); 00510 } 00511 } 00512 variable = NULL; 00513 } 00514 else { 00515 /* 00516 * nothing interesting 00517 */ 00518 return theheaders; 00519 } 00520 00521 /* 00522 * okay, so extract the actual data 00523 */ 00524 if (variable) { 00525 length = 0; 00526 ptr = uuscan_phtext; 00527 00528 while (isspace ((unsigned char)*value)) 00529 value++; 00530 while (*value && (delimit==0 || *value!=delimit) && 00531 *value != '\012' && *value != '\015' && length 00532 *ptr++ = *value++; 00533 length++; 00534 } 00535 while (length && isspace((unsigned char)*(ptr-1))) { 00536 ptr--; length--; 00537 } 00538 *ptr = '\0'; 00539 00540 if ((*variable = _FP_strdup (uuscan_phtext)) == NULL) 00541 return NULL; 00542 } 00543 00544 return theheaders; 00545 } 00546 00547 static int bsearch_strcmp (const void * v1, const void * v2) 00548 { 00549 const char * s1 = *(const char**) v1; 00550 const char * s2 = *(const char**) v2; 00551 return strcmp (s1, s2); 00552 } 00553 00554 /* 00555 * is this a header line we know about? 00556 */ 00557 00558 static int 00559 IsKnownHeader (char *line) 00560 { 00561 static const int n_msg = sizeof(knownmsgheaders) / sizeof(knownmsgheaders[0]); 00562 static const int n_mime = sizeof(knownmimeheaders) / sizeof(knownmimeheaders[0]); 00563 static const int max_width = 25; // content-transfer-encoding 00564 00565 int retval = 0; 00566 if (line && *line) 00567 { 00568 const char * pch = strchr (line, ' '); 00569 const int len = pch ? pch-line : strlen(line); 00570 if (len 00571 { 00572 // buf holds a lowercase version of `line' 00573 char buf[32], *pch, *end; 00574 for (pch=buf, end=line+len; line!=end; ) 00575 *pch++ = tolower (*line++); 00576 *pch = '\0'; 00577 pch = buf; 00578 00579 // search for that in knownmsgheaders 00580 if (bsearch (&pch, knownmsgheaders, n_msg, sizeof(char*), bsearch_strcmp) != NULL) 00581 retval = 1; 00582 00583 // search for that in knownmimeheaders 00584 else if (bsearch (&pch, knownmimeheaders, n_mime, sizeof(char*), bsearch_strcmp) != NULL) 00585 retval = 2; 00586 } 00587 } 00588 00589 return retval; 00590 } 00591 00592 /* 00593 * Scan a header 00594 */ 00595 00596 int 00597 UUScanHeader (FILE *datei, headers *envelope) 00598 { 00599 char *ptr; 00600 00601 while (!feof (datei)) { 00602 if ((ptr = ScanHeaderLine (datei, NULL)) == NULL) 00603 break; 00604 if (*ptr == '\0' || *ptr == '\012' || *ptr == '\015') 00605 break; 00606 ParseHeader (envelope, ptr); 00607 } 00608 return 0; 00609 } 00610 00611 /* 00612 * Scan something for encoded data and fill the fileread* structure. 00613 * If boundary is non-NULL, we stop after having read it. If Check- 00614 * Headers != 0, we also stop after we've found uu_headercount recog- 00615 * nized header lines. 00616 * If we have a boundary, then we also don't accept Base64; MIME mails 00617 * really should handle this properly. 00618 * We return -1 if something went wrong, 0 if everything is normal, 00619 * 1 if we found a new header and 2 if we found a boundary. 00620 * In MIME message bodies (not multiparts), we also disable our reduced 00621 * MIME handling. 00622 */ 00623 00624 static int 00625 ScanData (FILE *datei, char *fname, int *errcode, 00626 char *boundary, int ismime, int checkheaders, 00627 fileread *result) 00628 { 00629 char *line=uuscan_sdline; 00630 int line_len = UUSCAN_SDLINE_LEN; 00631 char *bhds1=uuscan_sdbhds1, *bhds2=uuscan_sdbhds2; 00632 static char *ptr, *p2, *p3=NULL, *bhdsp, bhl; 00633 int islen[10], isb64[10], isuue[10], isxxe[10], isbhx[10], iscnt; 00634 int cbb64, cbuue, cbxxe, cbbhx; 00635 int bhflag=0, vflag, haddh=0, hadct=0; 00636 int bhrpc=0, bhnf=0, c, hcount, lcount, blen=0; 00637 int encoding=0, dflag=0, ctline=42; 00638 int dontcare=0, hadnl=0; 00639 long preheaders=0, oldposition; 00640 long yefilesize=0, yepartends=0; 00641 size_t dcc, bhopc; 00642 int oldcheckheaders = 0; 00643 00644 *errcode = UURET_OK; 00645 (void) UUDecodeLine (NULL, NULL, 0); /* init */ 00646 bhdsp = bhds2; 00647 00648 if (datei == NULL || feof (datei)) 00649 return -1; 00650 00651 result->startpos = ftell (datei); 00652 hcount = lcount = 0; 00653 00654 for (iscnt=0; iscnt00655 isb64[iscnt] = isuue[iscnt] = isxxe[iscnt] = isbhx[iscnt] = 0; 00656 islen[iscnt] = -1; 00657 } 00658 00659 iscnt = 0; 00660 00661 if (boundary) 00662 blen = strlen (boundary); 00663 00664 while (!feof (datei)) { 00665 oldposition = ftell (datei); 00666 if (_FP_fgets (line, line_len, datei) == NULL) 00667 break; 00668 if (ferror (datei)) 00669 break; 00670 00671 /* 00672 * Make Busy Polls 00673 */ 00674 00675 if (UUBUSYPOLL(ftell(datei),progress.fsize)) { 00676 UUMessage (uuscan_id, __LINE__, UUMSG_NOTE, 00677 uustring (S_SCAN_CANCEL)); 00678 *errcode = UURET_CANCEL; 00679 break; 00680 } 00681 00682 if (IsLineEmpty (line)) { /* line empty? */ 00683 hcount = 0; 00684 hadnl = 1; 00685 continue; /* then ignore */ 00686 } 00687 00688 if (checkheaders) { 00689 if (IsKnownHeader (line)) { 00690 (void) ScanHeaderLine (datei, line); 00691 00692 if (hcount == 0) { 00693 preheaders = oldposition; 00694 lcount = 0; 00695 } 00696 hcount++; 00697 lcount++; 00698 00699 /* 00700 * check for the various restart counters 00701 */ 00702 00703 if ((hcount >= hlcount.restart) || 00704 (hcount >= hlcount.afterdata && ismime == 0) || 00705 (hcount >= hlcount.afterdata && result->uudet) || 00706 (hcount >= hlcount.afternl && result->uudet && hadnl)) { 00707 /* 00708 * Hey, a new header starts here 00709 */ 00710 fseek (datei, preheaders, SEEK_SET); 00711 break; 00712 } 00713 /* continue; */ 00714 } 00715 else if (lcount > WAITHEADER) { 00716 hcount = 0; 00717 lcount = 0; 00718 dontcare=0; 00719 } 00720 else if (hcount) { 00721 lcount++; 00722 dontcare=1; 00723 } 00724 else { 00725 dontcare=0; 00726 } 00727 } 00728 else { 00729 dontcare=0; 00730 } 00731 00732 if (boundary != NULL && 00733 line[0] == '-' && line[1] == '-' && 00734 strncmp (line+2, boundary, blen) == 0) { 00735 fseek (datei, oldposition, SEEK_SET); 00736 break; 00737 } 00738 if (boundary != NULL && line[0] == 'C' && line[1] == 'o' && 00739 _FP_strnicmp (line, "Content-Type:", 13) == 0) { 00740 ptr = ScanHeaderLine (datei, line); 00741 p2 = (ptr)?_FP_stristr(ptr,"boundary"):NULL; 00742 p3 = (p2)?ParseValue(p2):NULL; 00743 00744 if (p3 && strcmp (p3, boundary) == 0) { 00745 fseek (datei, oldposition, SEEK_SET); 00746 break; 00747 } 00748 else { 00749 p3 = NULL; 00750 } 00751 } 00752 00753 if (strncmp (line, "begin ", 6) == 0 || 00754 _FP_strnicmp (line, " begin ", 11) == 0) { 00755 if ((result->begin || result->end || 00756 result->uudet == B64ENCODED || 00757 result->uudet == BH_ENCODED) && !uu_more_mime) { 00758 fseek (datei, oldposition, SEEK_SET); 00759 break; 00760 } 00761 00762 if (*line == ') 00763 ptr = line + 10; 00764 else 00765 ptr = line + 5; 00766 00767 while (*ptr == ' ') ptr++; 00768 while (isdigit ((unsigned char)*ptr)) 00769 result->mode = result->mode * 8 + *ptr++ - '0'; 00770 while (*ptr == ' ') ptr++; 00771 00772 /* 00773 * We may have picked up a filename from a uuenview-style header 00774 */ 00775 _FP_free (result->filename); 00776 result->filename = _FP_strdup (ptr); 00777 result->begin = 1; 00778 00779 while (isspace ((unsigned char)result->filename[strlen(result->filename)-1])) 00780 result->filename[strlen(result->filename)-1] = '\0'; 00781 00782 continue; 00783 } 00784 00785 if ((strncmp (line, "end", 3) == 0) && 00786 result->uudet != BH_ENCODED && 00787 result->uudet != YENC_ENCODED) { 00788 if (result->uudet == B64ENCODED && result->begin) 00789 result->uudet = XX_ENCODED; 00790 00791 if (result->uudet != B64ENCODED) { 00792 result->end = 1; 00793 if (dflag && encoding) 00794 result->uudet = encoding; 00795 continue; 00796 } 00797 } 00798 00799 hadnl = 0; 00800 00801 /* 00802 * Detect a UUDeview-Style header 00803 */ 00804 00805 if (_FP_strnicmp (line, "_=_ Part ", 9) == 0 && 00806 result->uudet != YENC_ENCODED) { 00807 if (result->uudet) { 00808 fseek (datei, oldposition, SEEK_SET); 00809 break; 00810 } 00811 result->partno = atoi (line + 8); 00812 if ((ptr = _FP_stristr (line, "of file ")) != NULL) { 00813 ptr += 8; 00814 while (isspace ((unsigned char)*ptr)) ptr++; 00815 p2 = ptr; 00816 while (isalnum((unsigned char)*p2) || 00817 *p2 == '.' || *p2=='_' || *p2 == '-' || 00818 *p2 == '!' || *p2=='@' || *p2 == '$') 00819 p2++; 00820 c = *p2; *p2 = '\0'; 00821 if (p2 != ptr && result->filename == NULL) 00822 result->filename = _FP_strdup (ptr); 00823 else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL) { 00824 /* 00825 * This file name looks good, too. Let's use it 00826 */ 00827 _FP_free (result->filename); 00828 result->filename = _FP_strdup (ptr); 00829 } 00830 *p2 = c; 00831 } 00832 } 00833 00834 /* 00835 * Some reduced MIME handling. Only use if boundary == NULL. Also 00836 * accept the "X-Orcl-Content-Type" used by some braindead program. 00837 */ 00838 if (boundary == NULL && !ismime && !uu_more_mime && 00839 result->uudet != YENC_ENCODED) { 00840 if (_FP_strnicmp (line, "Content-Type", 12) == 0 || 00841 _FP_strnicmp (line, "X-Orcl-Content-Type", 19) == 0) { 00842 /* 00843 * We use Content-Type to mark a new attachment and split the file. 00844 * However, we do not split if we haven't found anything encoded yet. 00845 */ 00846 if (result->uudet) { 00847 fseek (datei, oldposition, SEEK_SET); 00848 break; 00849 } 00850 if ((ptr = strchr (line, ':')) != NULL) { 00851 ptr++; 00852 while (isspace ((unsigned char)*ptr)) ptr++; p2 = ptr; 00853 while (!isspace ((unsigned char)*p2) && *p2 != ';') p2++; 00854 c = *p2; *p2 = '\0'; 00855 if (p2 != ptr) { 00856 _FP_free (result->mimetype); 00857 result->mimetype = _FP_strdup (ptr); 00858 } 00859 *p2 = c; 00860 } 00861 ctline=0; 00862 hadct=1; 00863 } 00864 if ((ptr = _FP_stristr (line, "number=")) && ctline00865 ptr += 7; if (*ptr == '"') ptr++; 00866 result->partno = atoi (ptr); 00867 } 00868 if ((ptr = _FP_stristr (line, "total=")) && ctline00869 ptr += 6; if (*ptr == '"') ptr++; 00870 result->maxpno = atoi (ptr); 00871 } 00872 if ((ptr = _FP_stristr (line, "name=")) && ctline00873 ptr += 5; 00874 while (isspace ((unsigned char)*ptr)) ptr++; 00875 if (*ptr == '"' && *(ptr+1) && (p2 = strchr (ptr+2, '"')) != NULL) { 00876 c = *p2; *p2 = '\0'; 00877 _FP_free (result->filename); 00878 result->filename = _FP_strdup (ptr+1); 00879 *p2 = c; 00880 } 00881 else if (*ptr=='\''&&*(ptr+1)&&(p2 = strchr(ptr+2, '\'')) != NULL) { 00882 c = *p2; *p2 = '\0'; 00883 _FP_free (result->filename); 00884 result->filename = _FP_strdup (ptr+1); 00885 *p2 = c; 00886 } 00887 else { 00888 p2 = ptr; 00889 while (isalnum((unsigned char)*p2) || 00890 *p2 == '.' || *p2=='_' || *p2 == '-' || 00891 *p2 == '!' || *p2=='@' || *p2 == '$') 00892 p2++; 00893 c = *p2; *p2 = '\0'; 00894 if (p2 != ptr && result->filename == NULL) 00895 result->filename = _FP_strdup (ptr); 00896 else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL) { 00897 /* 00898 * This file name looks good, too. Let's use it 00899 */ 00900 _FP_free (result->filename); 00901 result->filename = _FP_strdup (ptr); 00902 } 00903 *p2 = c; 00904 } 00905 } 00906 if ((ptr = _FP_stristr (line, "id=")) && ctline00907 p2 = ptr += 3; 00908 if (*p2 == '"') { 00909 p2 = strchr (++ptr, '"'); 00910 } 00911 else { 00912 while (*p2 && isprint((unsigned char)*p2) && !isspace((unsigned char)*p2) && *p2 != ';') 00913 p2++; 00914 } 00915 if (p2 && *p2 && p2!=ptr) { 00916 c = *p2; *p2 = '\0'; 00917 if (result->mimeid) 00918 _FP_free (result->mimeid); 00919 result->mimeid = _FP_strdup (ptr); 00920 *p2 = c; 00921 } 00922 } 00923 00924 /* 00925 * Handling for very short Base64 files. 00926 */ 00927 if (uu_tinyb64 && !ismime && !uu_more_mime) { 00928 if (line[0] == '-' && line[1] == '-') { 00929 if (dflag && (encoding==B64ENCODED || result->uudet==B64ENCODED)) { 00930 if (encoding==B64ENCODED && result->uudet==0 && (haddh||hadct)) { 00931 result->uudet = encoding; 00932 encoding = dflag = 0; 00933 } 00934 haddh = 1; 00935 continue; 00936 } 00937 hadct = 0; 00938 } 00939 } 00940 } /* end of reduced MIME handling */ 00941 00942 /* 00943 * If we're in "freestyle" mode, have not encountered anything 00944 * interesting yet, and stumble upon something that looks like 00945 * a boundary, followed by a Content-* line, try to use it. 00946 */ 00947 00948 if (boundary == NULL && !ismime && !uu_more_mime && dflag 00949 line[0] == '-' && line[1] == '-' && strlen(line+2)>10 && 00950 (((ptr = _FP_strrstr (line+2, "--")) == NULL) || 00951 (*(ptr+2) != '\012' && *(ptr+2) != '\015')) && 00952 _FP_strstr (line+2, "_=_") != NULL) { 00953 if (_FP_fgets (line, line_len, datei) == NULL) { 00954 break; 00955 } 00956 if (_FP_strnicmp (line, "Content-", 8) == 0) { 00957 /* 00958 * Okay, let's do it. This breaks out of ScanData. ScanPart will 00959 * recognize the boundary on the next call and use it. 00960 */ 00961 fseek (datei, oldposition, SEEK_SET); 00962 break; 00963 } 00964 } 00965 00966 /* 00967 * Detection for yEnc encoding 00968 */ 00969 00970 if (strncmp (line, "=ybegin ", 8) == 0 && 00971 _FP_strstr (line, " name=") != NULL) { 00972 if ((result->begin || result->end || result->uudet) && !uu_more_mime) { 00973 fseek (datei, oldposition, SEEK_SET); 00974 break; 00975 } 00976 00977 /* 00978 * name continues to the end of the line 00979 */ 00980 00981 _FP_free (result->filename); 00982 ptr = _FP_strstr (line, " name=") + 6; 00983 result->filename = _FP_strdup (ptr); 00984 00985 while (isspace ((unsigned char)result->filename[strlen(result->filename)-1])) 00986 result->filename[strlen(result->filename)-1] = '\0'; 00987 00988 /* 00989 * Determine size 00990 */ 00991 00992 if ((ptr = _FP_strstr (line, " size=")) != NULL) { 00993 ptr += 6; 00994 yefilesize = atoi (ptr); 00995 } 00996 else { 00997 yefilesize = -1; 00998 } 00999 01000 /* 01001 * check for multipart file and read =ypart line 01002 */ 01003 01004 if ((ptr = _FP_strstr (line, " part=")) != NULL) { 01005 result->partno = atoi (ptr + 6); 01006 01007 if (result->partno == 1) { 01008 result->begin = 1; 01009 } 01010 01011 if (_FP_fgets (line, line_len, datei) == NULL) { 01012 break; 01013 } 01014 01015 if (strncmp (line, "=ypart ", 7) != 0) { 01016 break; 01017 } 01018 01019 if ((ptr = _FP_strstr (line, " end=")) == NULL) { 01020 break; 01021 } 01022 01023 yepartends = atoi (ptr + 5); 01024 } 01025 else { 01026 result->partno = 1; 01027 result->begin = 1; 01028 } 01029 01030 /* don't scan for headers inside a yenc block */ 01031 oldcheckheaders = checkheaders; 01032 checkheaders = 0; 01033 01034 /* 01035 * Don't want auto-detection 01036 */ 01037 result->uudet = YENC_ENCODED; 01038 continue; 01039 } 01040 01041 if (strncmp (line, "=yend ", 6) == 0 && 01042 result->uudet == YENC_ENCODED) { 01043 if (yepartends == 0 || yepartends >= yefilesize) { 01044 result->end = 1; 01045 } 01046 #if 0 01047 if (!uu_more_mime) 01048 break; 01049 #endif 01050 01051 /* restore the checkheaders state we had before =ybegin */ 01052 checkheaders = oldcheckheaders; 01053 continue; 01054 } 01055 01056 /* 01057 * if we haven't yet found anything encoded, try to find something 01058 */ 01059 01060 if (!(result->uudet)) { 01061 /* 01062 * Netscape-Repair code is the same as in uunconc.c 01063 */ 01064 01065 if ((vflag = UUValidData (line, 0, &bhflag)) == 0 && !ismime) 01066 vflag = UURepairData (datei, line, 0, &bhflag); 01067 01068 /* 01069 * Check data against all possible encodings 01070 */ 01071 01072 islen[iscnt%10] = strlen(line); 01073 isb64[iscnt%10] = (UUValidData (line, B64ENCODED, &bhflag)==B64ENCODED); 01074 isuue[iscnt%10] = (UUValidData (line, UU_ENCODED, &bhflag)==UU_ENCODED); 01075 isxxe[iscnt%10] = (UUValidData (line, XX_ENCODED, &bhflag)==XX_ENCODED); 01076 isbhx[iscnt%10] = (UUValidData (line, BH_ENCODED, &bhflag)==BH_ENCODED); 01077 01078 /* 01079 * If we've got a first valid encoded line, we get suspicious if 01080 * it's shorter than, say, 40 characters. 01081 */ 01082 01083 if (vflag == B64ENCODED && 01084 (dflag == 0 || encoding != B64ENCODED) && 01085 strlen (line) begin && !uu_tinyb64) { 01086 isb64[iscnt%10] = 0; 01087 vflag = 0; 01088 } 01089 01090 if ((vflag == UU_ENCODED || vflag == XX_ENCODED) && 01091 (dflag == 0 || encoding != vflag) && 01092 strlen (line) begin) { 01093 isuue[iscnt%10] = isxxe[iscnt%10] = 0; 01094 vflag = 0; 01095 } 01096 01097 iscnt++; 01098 01099 /* 01100 * Ah, so we got an encoded line? How interesting! 01101 */ 01102 01103 if (vflag) { 01104 /* 01105 * For BinHex data, we can use the initial colon ':' as begin 01106 * and the terminating colon as ':'. 01107 * If (vflag && !bhflag), this is the last line, 01108 */ 01109 if (vflag == BH_ENCODED) { 01110 if (line[0] == ':' && result->end) { 01111 fseek (datei, oldposition, SEEK_SET); 01112 break; 01113 } 01114 if (line[0] == ':') 01115 result->begin = 1; 01116 if (bhflag == 0) { 01117 result->uudet = BH_ENCODED; 01118 result->end = 1; 01119 } 01120 } 01121 /* 01122 * For BinHex files, the file name is encoded in the first encoded 01123 * data bytes. We try to extract it here 01124 */ 01125 if (vflag == BH_ENCODED && bhnf == 0 && result->filename == NULL) { 01126 if (bhdsp == bhds2 || 01127 ((bhdsp-bhds2) int) bhds2[0] && 01128 (bhdsp-bhds2) 01129 dcc = UUDecodeLine (line, bhds1, BH_ENCODED); 01130 UUbhdecomp (bhds1, bhdsp, &bhl, &bhrpc, 01131 dcc, 256-(bhdsp-bhds2), &bhopc); 01132 bhdsp += bhopc; 01133 } 01134 if ((bhdsp-bhds2) > (int) bhds2[0] && bhds2[0]>0 && 01135 result->filename==NULL) { 01136 memcpy (bhds1, bhds2+1, (int) bhds2[0]); 01137 bhds1[(int)bhds2[0]]='\0'; 01138 result->filename = _FP_strdup (bhds1); 01139 bhnf = 1; 01140 } 01141 else if (bhdsp-bhds2 >= 256 && bhds2[0]>0) { 01142 memcpy (bhds1, bhds2+1, 255); 01143 bhds1[255] = '\0'; 01144 result->filename = _FP_strdup (bhds1); 01145 bhnf = 1; 01146 } 01147 else if (bhds2[0] 01148 bhnf = 1; 01149 } 01150 01151 /* 01152 * We accept an encoding if it has been true for four consecutive 01153 * lines. Check the isarrays to avoid mistaking one encoding 01154 * for the other. Uuencoded data is rather easily mistaken for 01155 * Base 64. If the data matches more than one encoding, we need to 01156 * scan further. 01157 * 01158 * Since text can also rather easily be mistaken for UUencoded 01159 * data if it just happens to have 4 lines in a row that have the 01160 * correct first character for the length of the line, we also add 01161 * a check that the first 3 lines must be the same length, and the 01162 * 4th line must be less than or equal to that length. (since 01163 * uuencoders use the same length for all lines except the last, 01164 * this shouldn't increase the minimum size of UUdata we can 01165 * detect, as it would if we tested all 4 lines for being the same 01166 * length.) - Matthew Mueller, 20030109 01167 */ 01168 01169 if (iscnt > 3) { 01170 cbb64 = (isb64[(iscnt-1)%10] && isb64[(iscnt-2)%10] && 01171 isb64[(iscnt-3)%10] && isb64[(iscnt-4)%10]); 01172 cbuue = (isuue[(iscnt-1)%10] && isuue[(iscnt-2)%10] && 01173 isuue[(iscnt-3)%10] && isuue[(iscnt-4)%10] && 01174 islen[(iscnt-1)%10] 01175 islen[(iscnt-2)%10] == islen[(iscnt-3)%10] && 01176 islen[(iscnt-3)%10] == islen[(iscnt-4)%10]); 01177 cbxxe = (isxxe[(iscnt-1)%10] && isxxe[(iscnt-2)%10] && 01178 isxxe[(iscnt-3)%10] && isxxe[(iscnt-4)%10] && 01179 islen[(iscnt-1)%10] 01180 islen[(iscnt-2)%10] == islen[(iscnt-3)%10] && 01181 islen[(iscnt-3)%10] == islen[(iscnt-4)%10]); 01182 cbbhx = (isbhx[(iscnt-1)%10] && isbhx[(iscnt-2)%10] && 01183 isbhx[(iscnt-3)%10] && isbhx[(iscnt-4)%10]); 01184 } 01185 else { 01186 cbb64 = cbuue = cbxxe = cbbhx = 0; 01187 } 01188 01189 if (cbb64 && !cbuue && !cbxxe && !cbbhx) { 01190 result->uudet = B64ENCODED; 01191 } 01192 else if (!cbb64 && cbuue && !cbxxe && !cbbhx) { 01193 result->uudet = UU_ENCODED; 01194 } 01195 else if (!cbb64 && !cbuue && cbxxe && !cbbhx) { 01196 result->uudet = XX_ENCODED; 01197 } 01198 else if (!cbb64 && !cbuue && !cbxxe && cbbhx) { 01199 result->uudet = BH_ENCODED; 01200 } 01201 01202 if (result->uudet) { 01203 encoding = dflag = 0; 01204 01205 /* 01206 * If we're in fast mode, we're told we don't have to look 01207 * for anything below, so we can as well break out of every- 01208 * thing 01209 * We cannot fast-scan if we have a boundary to look after. 01210 */ 01211 01212 if (uu_fast_scanning && boundary == NULL) 01213 break; 01214 01215 /* 01216 * Skip the encoded data. We simply wait for a boundary, for 01217 * a header or for an empty line. But we also try to pick up 01218 * an "end" 01219 */ 01220 01221 hcount = lcount = 0; 01222 01223 while (!feof (datei)) { 01224 /* 01225 * Make Busy Polls 01226 */ 01227 if (UUBUSYPOLL(ftell(datei),progress.fsize)) { 01228 UUMessage (uuscan_id, __LINE__, UUMSG_NOTE, 01229 uustring (S_SCAN_CANCEL)); 01230 *errcode = UURET_CANCEL; 01231 break; 01232 } 01233 01234 oldposition = ftell (datei); 01235 if (_FP_fgets (line, line_len, datei) == NULL) 01236 break; 01237 if (ferror (datei)) 01238 break; 01239 01240 /* 01241 * Stop scanning at an empty line or a MIME-boundary. 01242 */ 01243 if (IsLineEmpty (line)) 01244 break; 01245 if (boundary && line[0] == '-' && line[1] == '-' && 01246 strncmp (line+2, boundary, blen) == 0) { 01247 fseek (datei, oldposition, SEEK_SET); 01248 break; 01249 } 01250 else if (line[0] == 'e' && (result->uudet == UU_ENCODED || 01251 result->uudet == XX_ENCODED)) { 01252 if (strncmp (line, "end", 3) == 0) { 01253 result->end = 1; 01254 break; 01255 } 01256 } 01257 else if (line[0] == 'b') { 01258 if (strncmp (line, "begin ", 6) == 0) { 01259 fseek (datei, oldposition, SEEK_SET); 01260 break; 01261 } 01262 } 01263 01264 if (checkheaders) { 01265 if (IsKnownHeader (line)) { 01266 (void) ScanHeaderLine (datei, line); 01267 if (hcount == 0) 01268 preheaders = oldposition; 01269 hcount++; 01270 lcount++; 01271 if ((hcount >= hlcount.restart) || 01272 (hcount >= hlcount.afterdata && result->uudet)) { 01273 /* 01274 * Hey, a new header starts here 01275 */ 01276 fseek (datei, preheaders, SEEK_SET); 01277 break; 01278 } 01279 } 01280 else if (lcount > WAITHEADER) { 01281 hcount = 0; 01282 lcount = 0; 01283 } 01284 else if (hcount) { 01285 lcount++; 01286 } 01287 } 01288 if (result->uudet == BH_ENCODED) { 01289 /* pick up ``EOF'' for BinHex files. Slow :- 01290 if (line[0] && strchr (line+1, ':') != NULL) { 01291 result->end = 1; 01292 bhflag = 0; 01293 break; 01294 } 01295 } 01296 } 01297 01298 if (ferror (datei) || *errcode == UURET_CANCEL) 01299 break; 01300 01301 if (line[0] == '-' && line[1] == '-') 01302 haddh = 1; 01303 01304 /* 01305 * Okay, got everything we need. If we had headers or a 01306 * boundary, we break out of the outer loop immediately. 01307 */ 01308 01309 if (IsKnownHeader (line) || 01310 (boundary && line[0] == '-' && line[1] == '-' && 01311 strncmp (line+2, boundary, blen) == 0)) { 01312 break; 01313 } 01314 01315 /* 01316 * Otherwise, we wait until finding something more interesting 01317 * in the outer loop 01318 */ 01319 01320 continue; 01321 } 01322 01323 /* 01324 * Select the encoding with the best "history" 01325 */ 01326 01327 cbb64 = isb64[(iscnt-1)%10]; 01328 cbuue = isuue[(iscnt-1)%10]; 01329 cbxxe = isxxe[(iscnt-1)%10]; 01330 cbbhx = isbhx[(iscnt-1)%10]; 01331 dflag = 0; 01332 01333 if (cbb64 || cbuue || cbxxe || cbbhx) { 01334 for (dflag=2; dflag01335 if ((!cbb64 || !isb64[(iscnt-dflag)%10]) && 01336 (!cbuue || !isuue[(iscnt-dflag)%10]) && 01337 (!cbxxe || !isxxe[(iscnt-dflag)%10]) && 01338 (!cbbhx || !isbhx[(iscnt-dflag)%10])) { 01339 dflag--; 01340 break; 01341 } 01342 cbb64 &= isb64[(iscnt-dflag)%10]; 01343 cbuue &= isuue[(iscnt-dflag)%10]; 01344 cbxxe &= isxxe[(iscnt-dflag)%10]; 01345 cbbhx &= isbhx[(iscnt-dflag)%10]; 01346 } 01347 } 01348 01349 /* 01350 * clear-cut cases 01351 */ 01352 01353 if (cbb64 && !cbuue && !cbxxe && !cbbhx) { 01354 encoding = B64ENCODED; 01355 } 01356 else if (!cbb64 && cbuue && !cbxxe && !cbbhx) { 01357 encoding = UU_ENCODED; 01358 } 01359 else if (!cbb64 && !cbuue && cbxxe && !cbbhx) { 01360 encoding = XX_ENCODED; 01361 } 01362 else if (!cbb64 && !cbuue && !cbxxe && cbbhx) { 01363 encoding = BH_ENCODED; 01364 } 01365 else { 01366 encoding = 0; 01367 } 01368 01369 /* 01370 * Check a few common non-clear-cut cases 01371 */ 01372 01373 if (!encoding && cbuue && result->begin) { 01374 encoding = UU_ENCODED; 01375 } 01376 else if (!encoding && cbxxe && result->begin) { 01377 encoding = XX_ENCODED; 01378 } 01379 else if (!encoding && cbb64) { 01380 encoding = B64ENCODED; 01381 } 01382 else if (!encoding && cbuue) { 01383 encoding = UU_ENCODED; 01384 } 01385 else if (!encoding && cbxxe) { 01386 encoding = XX_ENCODED; 01387 } 01388 else if (!encoding && cbbhx) { 01389 encoding = BH_ENCODED; 01390 } 01391 } 01392 else if (!dontcare) { 01393 encoding = 0; 01394 dflag = 0; 01395 haddh = 0; 01396 } 01397 } /* if (!uudet) */ 01398 /* 01399 * End of scanning loop 01400 */ 01401 } /* while (!feof (datei)) */ 01402 01403 if (feof (datei)) 01404 oldposition = ftell (datei); 01405 01406 if (dflag && encoding == B64ENCODED && haddh) 01407 result->uudet = B64ENCODED; 01408 else if (dflag && encoding == BH_ENCODED) 01409 result->uudet = BH_ENCODED; 01410 01411 /* Base64 doesn't have begin or end, so it was probably XX */ 01412 if (result->uudet == B64ENCODED && result->begin && result->end) 01413 result->uudet = XX_ENCODED; 01414 01415 /* Base64 doesn't have begin or end */ 01416 if (result->uudet == B64ENCODED) 01417 result->begin = result->end = 0; 01418 01419 /* Base64 and BinHex don't have a file mode */ 01420 if (result->uudet == B64ENCODED || result->uudet == BH_ENCODED || 01421 result->uudet == YENC_ENCODED) 01422 result->mode = 6*64+4*8+4; 01423 01424 /* 01425 * When strict MIME adherance is set, throw out suspicious attachments 01426 */ 01427 01428 if (uu_more_mime) { 01429 /* 01430 * In a MIME message, Base64 should be appropriately tagged 01431 */ 01432 01433 if (result->uudet == B64ENCODED) { 01434 result->uudet = 0; 01435 } 01436 01437 /* 01438 * Do not accept incomplete UU or XX encoded messages 01439 */ 01440 01441 if ((result->uudet != 0 && result->uudet != B64ENCODED) && 01442 (!result->begin || !result->end)) { 01443 result->uudet = 0; 01444 } 01445 } 01446 01447 /* 01448 * In fast mode, this length will yield a false value. We don't care. 01449 * This must be checked for in uunconc(), where we usually stop decoding 01450 * after reaching startpos+length 01451 */ 01452 01453 if (uu_fast_scanning) 01454 result->length = progress.fsize-result->startpos; 01455 else 01456 result->length = ftell(datei)-result->startpos; 01457 01458 if (ferror (datei)) { 01459 *errcode = UURET_IOERR; 01460 uu_errno = errno; 01461 return -1; 01462 } 01463 if (*errcode != UURET_OK) { 01464 return -1; 01465 } 01466 01467 if (boundary && line[0] == '-' && line[1] == '-' && 01468 strncmp (line+2, boundary, blen) == 0) 01469 return 2; 01470 else if (boundary && p3 && 01471 line[0] == 'C' && line[1] == 'o' && 01472 _FP_strnicmp (line, "Content-Type:", 13) == 0 && 01473 strcmp (p3, boundary) == 0) 01474 return 2; 01475 else if (IsKnownHeader (line)) 01476 return 1; 01477 01478 return 0; 01479 } 01480 01481 /* 01482 * This is the main scanning function. 01483 */ 01484 01485 fileread * 01486 ScanPart (FILE *datei, char *fname, int *errcode) 01487 { 01488 int ecount, hcount, lcount; 01489 int bhflag, begflag, vflag, blen=0, res; 01490 long preheaders, prevpos=0, preenc, before; 01491 char *line=uuscan_spline; 01492 const int line_len = UUSCAN_SPLINE_LEN; 01493 fileread *result; 01494 char *ptr1, *ptr2; 01495 01496 (void) UUDecodeLine (NULL, NULL, 0); /* init */ 01497 if (datei == NULL || feof (datei)) { 01498 *errcode = UURET_OK; 01499 return NULL; 01500 } 01501 01502 *errcode = UURET_OK; 01503 01504 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) { 01505 *errcode = UURET_NOMEM; 01506 return NULL; 01507 } 01508 memset (result, 0, sizeof (fileread)); 01509 result->startpos = ftell (datei); 01510 preheaders = result->startpos; 01511 before = result->startpos; 01512 01513 /* if this is a new file, reset our scanning state */ 01514 if (sstate.source == NULL || strcmp (fname, sstate.source) != 0) { 01515 sstate.isfolder = 1; /* assume yes */ 01516 sstate.ismime = 0; /* wait for MIME-Version */ 01517 sstate.mimestate = MS_HEADERS; /* assume headers follow */ 01518 /* mimseqno = 1; */ 01519 01520 while (mssdepth) { 01521 mssdepth--; 01522 UUkillheaders (&(multistack[mssdepth].envelope)); 01523 _FP_free (multistack[mssdepth].source); 01524 } 01525 01526 UUkillheaders (&sstate.envelope); 01527 memset (&sstate.envelope, 0, sizeof (headers)); 01528 01529 _FP_free (sstate.source); 01530 if ((sstate.source = _FP_strdup (fname)) == NULL) { 01531 *errcode = UURET_NOMEM; 01532 _FP_free (result); 01533 return NULL; 01534 } 01535 01536 /* ignore empty lines at the beginning of a file */ 01537 preheaders = ftell (datei); 01538 while (!feof (datei)) { 01539 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 01540 if (_FP_fgets (line, line_len, datei) == NULL) 01541 break; 01542 if (!IsLineEmpty (line)) { 01543 fseek (datei, preheaders, SEEK_SET); 01544 break; 01545 } 01546 preheaders = ftell (datei); 01547 } 01548 } 01549 01550 if (ferror(datei) || feof(datei)) { 01551 _FP_free (result); 01552 return NULL; 01553 } 01554 01555 /* 01556 * If we are confident that this is a mail folder and are at the 01557 * beginning of the file, expecting to read some headers, scan 01558 * the envelope. 01559 */ 01560 01561 if (sstate.isfolder && sstate.mimestate == MS_HEADERS) { 01562 hcount = 0; 01563 lcount = 0; 01564 UUkillheaders (&sstate.envelope); 01565 01566 /* 01567 * clean up leftovers from invalid messages 01568 */ 01569 01570 while (mssdepth) { 01571 mssdepth--; 01572 UUkillheaders (&(multistack[mssdepth].envelope)); 01573 _FP_free (multistack[mssdepth].source); 01574 } 01575 01576 prevpos = ftell (datei); 01577 if (_FP_fgets (line, line_len, datei) == NULL) { 01578 _FP_free (result); 01579 return NULL; 01580 } 01581 01582 /* 01583 * Special handling for AOL folder files, which start off with a boundary. 01584 * We recognize them by a valid boundary line as the first line of a file. 01585 * Note that the rest of the scanning code becomes suspicious if a boun- 01586 * dary does never appear in a file -- this should save us from grave 01587 * false detection errors 01588 */ 01589 01590 if (!feof (datei) && line[0] == '-' && line[1] == '-' && line[2]) { 01591 while (line[strlen(line)-1] == '\012' || 01592 line[strlen(line)-1] == '\015') { 01593 line[strlen(line)-1] = '\0'; 01594 } 01595 01596 sstate.ismime = 1; 01597 sstate.envelope.mimevers = _FP_strdup ("1.0"); 01598 sstate.envelope.boundary = _FP_strdup (line+2); 01599 sstate.envelope.ctype = _FP_strdup ("multipart/mixed"); 01600 sstate.mimestate = MS_SUBPART; 01601 01602 *errcode = UURET_CONT; 01603 _FP_free (result); 01604 return NULL; 01605 } 01606 01607 /* 01608 * Normal behavior: look for a RFC 822 header 01609 */ 01610 01611 while (!feof (datei) && !IsLineEmpty (line)) { 01612 if (IsKnownHeader (line)) 01613 hcount++; 01614 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 01615 if (IsHeaderLine (line)) { 01616 ptr1 = ScanHeaderLine (datei, line); 01617 if (ParseHeader (&sstate.envelope, ptr1) == NULL) { 01618 *errcode = UURET_NOMEM; 01619 _FP_free (result); 01620 return NULL; 01621 } 01622 } 01623 /* 01624 * if we've read too many lines without finding headers, then 01625 * this probably isn't a mail folder after all 01626 */ 01627 lcount++; 01628 if (lcount > WAITHEADER && hcount hlcount.afternl) { 01629 fseek (datei, prevpos, SEEK_SET); 01630 line[0] = '\0'; 01631 break; 01632 } 01633 01634 if (_FP_fgets (line, line_len, datei) == NULL) 01635 break; 01636 } 01637 01638 /* skip empty lines */ 01639 prevpos = ftell (datei); 01640 if (IsLineEmpty (line)) { 01641 while (!feof (datei)) { 01642 if (_FP_fgets (line, line_len, datei) == NULL) 01643 break; 01644 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 01645 if (!IsLineEmpty (line)) { 01646 fseek (datei, prevpos, SEEK_SET); 01647 break; 01648 } 01649 prevpos = ftell (datei); 01650 } 01651 } 01652 01653 /* 01654 * If we don't have all valid MIME headers yet, but the following 01655 * line is a MIME header, accept it anyway. 01656 */ 01657 01658 if (!uu_more_mime && 01659 sstate.envelope.mimevers == NULL && 01660 sstate.envelope.ctype == NULL && 01661 sstate.envelope.ctenc == NULL && 01662 IsKnownHeader (line)) { 01663 /* 01664 * see above 01665 */ 01666 if (_FP_fgets (line, line_len, datei) == NULL) { 01667 line[0] = '\012'; 01668 line[1] = '\0'; 01669 } 01670 01671 while (!feof (datei) && !IsLineEmpty (line)) { 01672 if (IsKnownHeader (line)) 01673 hcount++; 01674 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 01675 ptr1 = ScanHeaderLine (datei, line); 01676 if (ParseHeader (&sstate.envelope, ptr1) == NULL) { 01677 *errcode = UURET_NOMEM; 01678 _FP_free (result); 01679 return NULL; 01680 } 01681 if (_FP_fgets (line, line_len, datei) == NULL) 01682 break; 01683 } 01684 /* skip empty lines */ 01685 prevpos = ftell (datei); 01686 while (!feof (datei)) { 01687 if (_FP_fgets (line, line_len, datei) == NULL) 01688 break; 01689 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 01690 if (!IsLineEmpty (line)) { 01691 fseek (datei, prevpos, SEEK_SET); 01692 break; 01693 } 01694 prevpos = ftell (datei); 01695 } 01696 } 01697 01698 /* 01699 * A partial multipart message probably has only a Content-Type 01700 * header but nothing else. In this case, at least simulate a 01701 * MIME message 01702 * if mimevers is not set but there are other well-known MIME 01703 * headers, don't be too picky about it. 01704 */ 01705 if (sstate.envelope.ctype && sstate.envelope.mimevers==NULL && 01706 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL && 01707 sstate.envelope.boundary != NULL) { 01708 sstate.envelope.mimevers = _FP_strdup ("1.0"); 01709 hcount = hlcount.afternl; 01710 } 01711 else if (sstate.envelope.mimevers==NULL && sstate.envelope.ctype && 01712 sstate.envelope.fname && sstate.envelope.ctenc) { 01713 sstate.envelope.mimevers = _FP_strdup ("1.0"); 01714 hcount = hlcount.afternl; 01715 } 01716 01717 if (sstate.envelope.mimevers != NULL) { 01718 /* this is a MIME file. check the Content-Type */ 01719 sstate.ismime = 1; 01720 if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL) { 01721 if (sstate.envelope.boundary == NULL) { 01722 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 01723 uustring (S_MIME_NO_BOUNDARY)); 01724 sstate.mimestate = MS_BODY; 01725 _FP_free (sstate.envelope.ctype); 01726 sstate.envelope.ctype = _FP_strdup ("text/plain"); 01727 } 01728 else { 01729 sstate.mimestate = MS_PREAMBLE; 01730 } 01731 } 01732 else { 01733 sstate.mimestate = MS_BODY; /* just a `simple' message */ 01734 } 01735 } 01736 else { 01737 /* not a folder after all */ 01738 fseek (datei, prevpos, SEEK_SET); 01739 sstate.isfolder = 0; 01740 sstate.ismime = 0; 01741 } 01742 } 01743 01744 if (feof (datei) || ferror (datei)) { /* oops */ 01745 _FP_free (result); 01746 return NULL; 01747 } 01748 01749 /* 01750 * Handle MIME stuff 01751 */ 01752 01753 /* 01754 * Read Preamble. This must be ended by a sstate.envelope.boundary line. 01755 * If uu_usepreamble is set, we produce a result from this one 01756 */ 01757 01758 if (sstate.ismime && sstate.mimestate == MS_PREAMBLE) { 01759 result->startpos = ftell (datei); /* remember start of preamble */ 01760 prevpos = ftell (datei); 01761 preheaders = ftell (datei); 01762 01763 blen = strlen (sstate.envelope.boundary); 01764 lcount = 0; 01765 01766 while (!feof (datei)) { 01767 if (_FP_fgets (line, line_len, datei) == NULL) 01768 break; 01769 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 01770 if (line[0] == '-' && line[1] == '-' && 01771 strncmp (line+2, sstate.envelope.boundary, blen) == 0) 01772 break; 01773 if (!IsLineEmpty (line)) 01774 lcount++; 01775 01776 prevpos = ftell (datei); 01777 } 01778 if (feof (datei) || ferror (datei)) { 01779 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 01780 uustring (S_MIME_B_NOT_FOUND)); 01781 /* 01782 * restart and try again; don't restart if uu_fast_scanning 01783 */ 01784 sstate.isfolder = 0; 01785 sstate.ismime = 0; 01786 sstate.mimestate = MS_BODY; 01787 01788 if (!uu_fast_scanning) { 01789 *errcode = UURET_CONT; 01790 fseek (datei, preheaders, SEEK_SET); 01791 } 01792 _FP_free (result); 01793 return NULL; 01794 } 01795 if (line[0] == '-' && line[1] == '-' && 01796 strncmp (line+2, sstate.envelope.boundary, blen) == 0) { 01797 ptr1 = line + 2 + blen; 01798 if (*ptr1 == '-' && *(ptr1+1) == '-') { 01799 /* Empty Multipart Message. Duh. */ 01800 sstate.mimestate = MS_EPILOGUE; 01801 } 01802 else { 01803 sstate.mimestate = MS_SUBPART; 01804 } 01805 } 01806 else { /* shouldn't happen */ 01807 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 01808 uustring (S_MIME_B_NOT_FOUND)); 01809 /* 01810 * restart and try again; don't restart if uu_fast_scanning 01811 */ 01812 sstate.isfolder = 0; 01813 sstate.ismime = 0; 01814 sstate.mimestate = MS_BODY; 01815 01816 if (!uu_fast_scanning) { 01817 *errcode = UURET_CONT; 01818 fseek (datei, preheaders, SEEK_SET); 01819 } 01820 _FP_free (result); 01821 return NULL; 01822 } 01823 /* produce result if uu_usepreamble is set */ 01824 if (uu_usepreamble && lcount) { 01825 sprintf (line, "%04d.txt", ++mimseqno); 01826 result->subject = _FP_strdup (sstate.envelope.subject); 01827 result->filename = _FP_strdup (line); 01828 result->origin = _FP_strdup (sstate.envelope.from); 01829 result->mimeid = _FP_strdup (sstate.envelope.mimeid); 01830 result->mimetype = _FP_strdup ("text/plain"); 01831 result->mode = 0644; 01832 result->uudet = PT_ENCODED; /* plain text */ 01833 result->sfname = _FP_strdup (fname); 01834 result->flags = FL_SINGLE | FL_PROPER; 01835 /* result->startpos set from above */ 01836 result->length = prevpos - result->startpos; 01837 result->partno = 1; 01838 01839 /* MIME message, let's continue */ 01840 *errcode = UURET_CONT; 01841 01842 if ((sstate.envelope.subject != NULL && result->subject == NULL) || 01843 result->filename == NULL || result->sfname == NULL) { 01844 *errcode = UURET_NOMEM; 01845 } 01846 01847 return result; 01848 } 01849 /* MIME message, let's continue */ 01850 if (*errcode == UURET_OK) 01851 *errcode = UURET_CONT; 01852 01853 /* otherwise, just return NULL */ 01854 _FP_free (result); 01855 return NULL; 01856 } 01857 01858 /* 01859 * Read Epilogue, the plain text after the last boundary. 01860 * This can either end with new headers from the next message of a 01861 * mail folder or with a `parent' boundary if we are inside an 01862 * encapsulated Multipart message. Oh yes, and of course the file 01863 * may also simply end :-) 01864 * Another possibility is that we might find plain encoded data 01865 * without encapsulating message. We're not _too_ flexible here, 01866 * we won't detect Base64, and require a proper `begin' line for 01867 * uuencoding and xxencoding 01868 * If uu_usepreamble is set, we produce a result from this one 01869 */ 01870 01871 if (sstate.ismime && sstate.mimestate == MS_EPILOGUE) { 01872 result->startpos = ftell (datei); /* remember start of epilogue */ 01873 prevpos = ftell (datei); 01874 preheaders = ftell (datei); 01875 preenc = ftell (datei); 01876 hcount = lcount = 0; 01877 ecount = bhflag = 0; 01878 begflag = vflag = 0; 01879 res = 0; 01880 01881 /* 01882 * If we are in the outermost message and uu_fast_scanning, we 01883 * know (or assume) that no more messages will follow, so there's 01884 * no need to scan the rest. 01885 */ 01886 if (uu_fast_scanning && mssdepth == 0) { 01887 /* 01888 * check if the epilogue is empty 01889 */ 01890 while (!feof (datei) && !ferror (datei) && lcount01891 if (_FP_fgets (line, line_len, datei) == NULL) 01892 break; 01893 if (!IsLineEmpty (line)) 01894 res++; 01895 lcount++; 01896 } 01897 if (uu_usepreamble && res) { 01898 sprintf (line, "%04d.txt", ++mimseqno); 01899 result->subject = _FP_strdup (sstate.envelope.subject); 01900 result->filename = _FP_strdup (line); 01901 result->origin = _FP_strdup (sstate.envelope.from); 01902 result->mimeid = _FP_strdup (sstate.envelope.mimeid); 01903 result->mimetype = _FP_strdup ("text/plain"); 01904 result->mode = 0644; 01905 result->uudet = PT_ENCODED; /* plain text */ 01906 result->sfname = _FP_strdup (fname); 01907 result->flags = FL_SINGLE | FL_PROPER | FL_TOEND; 01908 result->partno = 1; 01909 /* result->startpos set from above */ 01910 result->length = progress.fsize - result->startpos; 01911 01912 if ((sstate.envelope.subject != NULL && result->subject == NULL) || 01913 result->filename == NULL || result->sfname == NULL) { 01914 *errcode = UURET_NOMEM; 01915 } 01916 01917 return result; 01918 } 01919 _FP_free (result); 01920 return NULL; 01921 } 01922 01923 if (mssdepth > 0) 01924 blen = strlen (multistack[mssdepth-1].envelope.boundary); 01925 01926 while (!feof (datei)) { 01927 if (_FP_fgets (line, line_len, datei) == NULL) 01928 break; 01929 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 01930 /* check for parent boundary */ 01931 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' && 01932 strncmp (line+2, 01933 multistack[mssdepth-1].envelope.boundary, blen) == 0) 01934 break; 01935 01936 /* check for next headers only at outermost level */ 01937 if (mssdepth == 0 && IsKnownHeader (line)) { 01938 (void) ScanHeaderLine (datei, line); 01939 if (hcount == 0) { 01940 preheaders = prevpos; 01941 lcount = 0; 01942 } 01943 hcount++; 01944 lcount++; 01945 01946 if (hcount >= hlcount.restart) { 01947 /* okay, new headers */ 01948 break; 01949 } 01950 } 01951 else if (lcount > WAITHEADER) { 01952 hcount = 0; 01953 lcount = 0; 01954 } 01955 else if (hcount) { 01956 lcount++; 01957 } 01958 else { 01959 hcount = lcount = 0; 01960 } 01961 01962 /* check for begin and encoded data only at outermost level */ 01963 if (mssdepth == 0 && !uu_more_mime) { 01964 if (strncmp (line, "begin ", 6) == 0 || 01965 _FP_strnicmp (line, " begin ", 11) == 0) { 01966 preenc = prevpos; 01967 begflag = 1; 01968 } 01969 else if (strncmp (line, "end", 3) == 0 && begflag) { 01970 ecount = ELC_COUNT; 01971 break; 01972 } 01973 else if ((vflag = UUValidData (line, 0, &bhflag)) != 0) { 01974 if (vflag == BH_ENCODED && bhflag == 0) { 01975 /* very short BinHex file follows */ 01976 preenc = prevpos; 01977 break; 01978 } 01979 /* remember that XX can easily be mistaken as Base64 */ 01980 if ((vflag == UU_ENCODED || vflag == XX_ENCODED || 01981 vflag == B64ENCODED) && begflag) { 01982 if (++ecount >= ELC_COUNT) 01983 break; 01984 } 01985 else { 01986 begflag = 0; 01987 ecount = 0; 01988 } 01989 } 01990 else { 01991 begflag = 0; 01992 ecount = 0; 01993 } 01994 } 01995 01996 if (!IsLineEmpty (line)) 01997 res++; 01998 01999 prevpos = ftell (datei); 02000 } 02001 02002 if (mssdepth > 0 && line[0] == '-' && line[1] == '-' && 02003 strncmp (line+2, 02004 multistack[mssdepth-1].envelope.boundary, blen) == 0) { 02005 /* restore previous state */ 02006 mssdepth--; 02007 UUkillheaders (&sstate.envelope); 02008 _FP_free (sstate.source); 02009 memcpy (&sstate, &(multistack[mssdepth]), sizeof (scanstate)); 02010 02011 ptr1 = line + 2 + strlen (sstate.envelope.boundary); 02012 02013 if (*ptr1 == '-' && *(ptr1+1) == '-') { 02014 sstate.mimestate = MS_EPILOGUE; 02015 } 02016 else { 02017 sstate.mimestate = MS_SUBPART; 02018 } 02019 result->length = prevpos - result->startpos; 02020 *errcode = UURET_CONT; 02021 } 02022 else if (mssdepth > 0) { 02023 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 02024 uustring (S_MIME_B_NOT_FOUND)); 02025 /* 02026 * restart and try again; don't restart if uu_fast_scanning 02027 */ 02028 sstate.isfolder = 0; 02029 sstate.ismime = 0; 02030 sstate.mimestate = MS_BODY; 02031 02032 while (mssdepth) { 02033 mssdepth--; 02034 UUkillheaders (&(multistack[mssdepth].envelope)); 02035 _FP_free (multistack[mssdepth].source); 02036 } 02037 02038 if (!uu_fast_scanning) { 02039 *errcode = UURET_CONT; 02040 fseek (datei, preheaders, SEEK_SET); 02041 } 02042 _FP_free (result); 02043 return NULL; 02044 } 02045 else if (IsKnownHeader (line)) { 02046 /* new message follows */ 02047 sstate.isfolder = 1; 02048 sstate.ismime = 0; 02049 sstate.mimestate = MS_HEADERS; 02050 result->length = preheaders - result->startpos; 02051 fseek (datei, preheaders, SEEK_SET); 02052 } 02053 else if (ecount >= ELC_COUNT) { 02054 /* new plain encoding */ 02055 sstate.isfolder = 0; 02056 sstate.ismime = 0; 02057 sstate.mimestate = MS_BODY; 02058 result->length = preenc - result->startpos; 02059 fseek (datei, preenc, SEEK_SET); 02060 } 02061 02062 /* produce result if uu_usepreamble is set */ 02063 if (uu_usepreamble && res) { 02064 sprintf (line, "%04d.txt", ++mimseqno); 02065 result->subject = _FP_strdup (sstate.envelope.subject); 02066 result->filename = _FP_strdup (line); 02067 result->origin = _FP_strdup (sstate.envelope.from); 02068 result->mimeid = _FP_strdup (sstate.envelope.mimeid); 02069 result->mimetype = _FP_strdup ("text/plain"); 02070 result->mode = 0644; 02071 result->uudet = PT_ENCODED; /* plain text */ 02072 result->sfname = _FP_strdup (fname); 02073 result->flags = FL_SINGLE | FL_PROPER; 02074 result->partno = 1; 02075 /* result->startpos set from above */ 02076 /* result->length set from above */ 02077 02078 if ((sstate.envelope.subject != NULL && result->subject == NULL) || 02079 result->filename == NULL || result->sfname == NULL) { 02080 *errcode = UURET_NOMEM; 02081 } 02082 02083 return result; 02084 } 02085 /* otherwise, just return NULL */ 02086 _FP_free (result); 02087 return NULL; 02088 } 02089 02090 /* 02091 * Scan a new part from a Multipart message. Check for a new local 02092 * envelope (which defaults to `Content-Type: text/plain') and 02093 * evaluate its Content-Type and Content-Transfer-Encoding. If this 02094 * is another Multipart/something, push the current state onto our 02095 * stack and dive into the new environment, starting with another 02096 * preamble. 02097 */ 02098 02099 if (sstate.ismime && sstate.mimestate == MS_SUBPART) { 02100 memset (&localenv, 0, sizeof (headers)); 02101 result->startpos = ftell (datei); 02102 prevpos = ftell (datei); 02103 hcount = 0; 02104 lcount = 0; 02105 02106 /* 02107 * Duplicate some data from outer envelope 02108 */ 02109 02110 localenv.mimevers = _FP_strdup (sstate.envelope.mimevers); 02111 localenv.from = _FP_strdup (sstate.envelope.from); 02112 localenv.subject = _FP_strdup (sstate.envelope.subject); 02113 localenv.rcpt = _FP_strdup (sstate.envelope.rcpt); 02114 localenv.date = _FP_strdup (sstate.envelope.date); 02115 02116 if ((sstate.envelope.mimevers != NULL && localenv.mimevers == NULL) || 02117 (sstate.envelope.from != NULL && localenv.from == NULL) || 02118 (sstate.envelope.subject != NULL && localenv.subject == NULL) || 02119 (sstate.envelope.rcpt != NULL && localenv.rcpt == NULL) || 02120 (sstate.envelope.date != NULL && localenv.date == NULL)) { 02121 02122 while (mssdepth) { 02123 mssdepth--; 02124 UUkillheaders (&(multistack[mssdepth].envelope)); 02125 _FP_free (multistack[mssdepth].source); 02126 } 02127 sstate.isfolder = 0; 02128 sstate.ismime = 0; 02129 02130 UUkillheaders (&localenv); 02131 *errcode = UURET_NOMEM; 02132 _FP_free (result); 02133 return NULL; 02134 } 02135 02136 /* Scan subheader. But what if there is no subheader? */ 02137 hcount = 0; 02138 lcount = 0; 02139 preheaders = prevpos; 02140 02141 if (_FP_fgets (line, line_len, datei) == NULL) { 02142 sstate.isfolder = 0; 02143 sstate.ismime = 0; 02144 while (mssdepth) { 02145 mssdepth--; 02146 UUkillheaders (&(multistack[mssdepth].envelope)); 02147 _FP_free (multistack[mssdepth].source); 02148 } 02149 UUkillheaders (&localenv); 02150 _FP_free (result); 02151 return NULL; 02152 } 02153 02154 while (!feof (datei) && !IsLineEmpty (line)) { 02155 if (IsKnownHeader (line)) 02156 hcount++; 02157 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 02158 if (lcount > WAITHEADER && hcount == 0) { 02159 fseek (datei, preheaders, SEEK_SET); 02160 prevpos = preheaders; 02161 break; 02162 } 02163 ptr1 = ScanHeaderLine (datei, line); 02164 if (ParseHeader (&localenv, ptr1) == NULL) 02165 *errcode = UURET_NOMEM; 02166 02167 if (line[0] == '-' && line[1] == '-') 02168 break; 02169 02170 prevpos = ftell (datei); 02171 02172 if (_FP_fgets (line, line_len, datei) == NULL) 02173 break; 02174 lcount++; 02175 } 02176 if (line[0] == '-' && line[1] == '-') { 02177 /* 02178 * this shouldn't happen, there must always be an empty line, 02179 * but let's accept it anyway. Just skip back to before the 02180 * boundary, so that it gets handled below 02181 */ 02182 fseek (datei, prevpos, SEEK_SET); 02183 } 02184 02185 if (_FP_stristr (localenv.ctype, "multipart") != NULL) { 02186 /* oh no, not again */ 02187 if (mssdepth >= MSMAXDEPTH) { 02188 /* Argh, what an isane message. Treat as plain text */ 02189 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 02190 uustring (S_MIME_MULTI_DEPTH)); 02191 } 02192 else if (localenv.boundary == NULL) { 02193 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 02194 uustring (S_MIME_NO_BOUNDARY)); 02195 } 02196 else { 02197 memcpy (&multistack[mssdepth], &sstate, sizeof (scanstate)); 02198 memcpy (&sstate.envelope, &localenv, sizeof (headers)); 02199 memset (&localenv, 0, sizeof (headers)); 02200 sstate.mimestate = MS_PREAMBLE; 02201 if ((sstate.source = _FP_strdup (sstate.source)) == NULL) 02202 *errcode = UURET_NOMEM; 02203 02204 if (*errcode == UURET_OK) 02205 *errcode = UURET_CONT; 02206 02207 mssdepth++; 02208 /* need a restart */ 02209 _FP_free (result); 02210 return NULL; 02211 } 02212 } 02213 02214 /* 02215 * So this subpart is either plain text or something else. Check 02216 * the Content-Type and Content-Transfer-Encoding. If the latter 02217 * is a defined value, we know what to do and just copy everything 02218 * up to the boundary. 02219 * If Content-Transfer-Encoding is unknown or missing, look at the 02220 * Content-Type. If it's "text/plain" or undefined, we subject the 02221 * message to our encoding detection. Otherwise, treat as plain 02222 * text. 02223 * This is done because users might `attach' a uuencoded file, which 02224 * would then be correctly typed as `text/plain'. 02225 */ 02226 02227 if (_FP_stristr (localenv.ctenc, "base64") != NULL) 02228 result->uudet = B64ENCODED; 02229 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) { 02230 result->uudet = UU_ENCODED; 02231 result->begin = result->end = 1; 02232 } 02233 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) { 02234 result->uudet = YENC_ENCODED; 02235 result->begin = result->end = 1; 02236 } 02237 else if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL) 02238 result->uudet = QP_ENCODED; 02239 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL || 02240 _FP_stristr (localenv.ctenc, "8bit") != NULL) 02241 result->uudet = PT_ENCODED; 02242 else if (_FP_stristr (localenv.ctype, "multipart") != NULL || 02243 _FP_stristr (localenv.ctype, "message") != NULL) 02244 result->uudet = PT_ENCODED; 02245 02246 /* 02247 * If we're switched to MIME-only mode, handle as text 02248 */ 02249 02250 if (uu_more_mime >= 2 && !result->uudet) { 02251 result->uudet = PT_ENCODED; 02252 } 02253 02254 if (result->uudet) { 02255 /* 02256 * Oh-kay, go ahead. Just read and wait for the boundary 02257 */ 02258 result->startpos = ftell (datei); 02259 prevpos = ftell (datei); 02260 blen = strlen (sstate.envelope.boundary); 02261 lcount = 0; 02262 02263 while (!feof (datei)) { 02264 if (_FP_fgets (line, line_len, datei) == NULL) { 02265 line[0] = '\0'; 02266 break; 02267 } 02268 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 02269 if (line[0] == '-' && line[1] == '-' && 02270 strncmp (line+2, sstate.envelope.boundary, blen) == 0) 02271 break; 02272 /* 02273 * I've had a report of someone who tried to decode a huge file 02274 * that had an early truncated multipart message and later another 02275 * multipart message with the *same* boundary. Consequently, all 02276 * some hundred messages inbetween were ignored ... 02277 * This check here doesn't cover folded header lines, but we don't 02278 * want to slow down scanning too much. We just check for 02279 * Content-Type: multipart/... boundary="same-boundary" 02280 */ 02281 if (line[0] == 'C' && line[1] == 'o' && 02282 _FP_strnicmp (line, "Content-Type:", 13) == 0) { 02283 ptr1 = ScanHeaderLine (datei, line); 02284 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL; 02285 ptr1 = (ptr2)?ParseValue(ptr2):NULL; 02286 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0) 02287 break; 02288 for (res=0; ptr1 && resmssdepth; res++) 02289 if (strcmp (ptr1, multistack[res].envelope.boundary) == 0) 02290 break; 02291 if (res02292 break; 02293 } 02294 if (!IsLineEmpty (line)) 02295 lcount++; 02296 prevpos = ftell (datei); 02297 } 02298 if (line[0] == '-' && line[1] == '-' && 02299 strncmp (line+2, sstate.envelope.boundary, blen) == 0) { 02300 ptr1 = line + 2 + blen; 02301 if (*ptr1 == '-' && *(ptr1+1) == '-') 02302 sstate.mimestate = MS_EPILOGUE; 02303 else 02304 sstate.mimestate = MS_SUBPART; 02305 } 02306 else { 02307 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 02308 uustring (S_MIME_B_NOT_FOUND)); 02309 02310 while (mssdepth) { 02311 mssdepth--; 02312 UUkillheaders (&(multistack[mssdepth].envelope)); 02313 _FP_free (multistack[mssdepth].source); 02314 } 02315 /* 02316 * Don't retry if uu_fast_scanning 02317 */ 02318 02319 if (uu_fast_scanning) { 02320 UUkillheaders (&localenv); 02321 sstate.isfolder = 0; 02322 sstate.ismime = 0; 02323 sstate.mimestate = MS_BODY; 02324 _FP_free (result); 02325 return NULL; 02326 } 02327 02328 /* 02329 * Retry, but listening to headers this time 02330 */ 02331 fseek (datei, result->startpos, SEEK_SET); 02332 02333 UUkillfread (result); 02334 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) { 02335 *errcode = UURET_NOMEM; 02336 sstate.isfolder = 0; 02337 sstate.ismime = 0; 02338 UUkillheaders (&localenv); 02339 return NULL; 02340 } 02341 memset (result, 0, sizeof (fileread)); 02342 02343 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) { 02344 /* oops, something went wrong */ 02345 sstate.isfolder = 0; 02346 sstate.ismime = 0; 02347 UUkillfread (result); 02348 UUkillheaders (&localenv); 02349 return NULL; 02350 } 02351 if (res == 1) { 02352 /* 02353 * new headers found 02354 */ 02355 sstate.isfolder = 1; 02356 sstate.ismime = 0; 02357 sstate.mimestate = MS_HEADERS; 02358 } 02359 else { 02360 sstate.isfolder = 0; 02361 sstate.ismime = 0; 02362 } 02363 } 02364 /* produce result if uu_handletext is set */ 02365 /* or if the file is explicitely named */ 02366 if (result->uudet == B64ENCODED || lcount) { 02367 if (localenv.fname) { 02368 _FP_free (result->filename); 02369 if ((result->filename = _FP_strdup (localenv.fname)) == NULL) 02370 *errcode = UURET_NOMEM; 02371 } 02372 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) && 02373 result->filename == NULL && uu_handletext) { 02374 sprintf (line, "%04d.txt", ++mimseqno); 02375 if ((result->filename = _FP_strdup (line)) == NULL) 02376 *errcode = UURET_NOMEM; 02377 } 02378 result->subject = _FP_strdup (localenv.subject); 02379 result->origin = _FP_strdup (localenv.from); 02380 result->mimeid = _FP_strdup (localenv.mimeid); 02381 result->mimetype = _FP_strdup (localenv.ctype); 02382 result->mode = 0644; 02383 result->sfname = _FP_strdup (fname); 02384 result->flags = FL_SINGLE | FL_PROPER; 02385 result->partno = 1; 02386 /* result->uudet determined above */ 02387 /* result->startpos set from above */ 02388 result->length = prevpos - result->startpos; 02389 02390 if ((localenv.subject != NULL && result->subject == NULL) || 02391 result->filename == NULL || result->sfname == NULL) { 02392 *errcode = UURET_NOMEM; 02393 } 02394 } 02395 else { 02396 /* don't produce a result */ 02397 _FP_free (result); 02398 result = NULL; 02399 } 02400 if (*errcode == UURET_OK) 02401 *errcode = UURET_CONT; 02402 /* 02403 * destroy local envelope 02404 */ 02405 UUkillheaders (&localenv); 02406 return result; 02407 } 02408 02409 /* 02410 * we're in a subpart, but the local headers don't give us any 02411 * clue about what's to find here. So look for encoded data by 02412 * ourselves. 02413 */ 02414 02415 if ((res = ScanData (datei, fname, errcode, 02416 sstate.envelope.boundary, 02417 1, 0, result)) == -1) { 02418 /* oops, something went wrong */ 02419 sstate.isfolder = 0; 02420 sstate.ismime = 0; 02421 UUkillfread (result); 02422 UUkillheaders (&localenv); 02423 return NULL; 02424 } 02425 /* 02426 * we should really be at a boundary here, but check again 02427 */ 02428 blen = strlen (sstate.envelope.boundary); 02429 prevpos = ftell (datei); 02430 02431 while (!feof (datei)) { 02432 if (_FP_fgets (line, line_len, datei) == NULL) { 02433 line[0] = '\0'; 02434 break; 02435 } 02436 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 02437 if (line[0] == '-' && line[1] == '-' && 02438 strncmp (line+2, sstate.envelope.boundary, blen) == 0) 02439 break; 02440 if (line[0] == 'C' && line[1] == 'o' && 02441 _FP_strnicmp (line, "Content-Type:", 13) == 0) { 02442 ptr1 = ScanHeaderLine (datei, line); 02443 ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL; 02444 ptr1 = (ptr2)?ParseValue(ptr2):NULL; 02445 if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0) 02446 break; 02447 } 02448 prevpos = ftell (datei); 02449 } 02450 /* 02451 * check if this was the last subpart 02452 */ 02453 if (line[0] == '-' && line[1] == '-' && 02454 strncmp (line+2, sstate.envelope.boundary, blen) == 0) { 02455 ptr1 = line + 2 + blen; 02456 if (*ptr1 == '-' && *(ptr1+1) == '-') 02457 sstate.mimestate = MS_EPILOGUE; 02458 else 02459 sstate.mimestate = MS_SUBPART; 02460 } 02461 else { 02462 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 02463 uustring (S_MIME_B_NOT_FOUND)); 02464 02465 while (mssdepth) { 02466 mssdepth--; 02467 UUkillheaders (&(multistack[mssdepth].envelope)); 02468 _FP_free (multistack[mssdepth].source); 02469 } 02470 02471 if (uu_fast_scanning) { 02472 UUkillheaders (&localenv); 02473 sstate.isfolder = 0; 02474 sstate.ismime = 0; 02475 sstate.mimestate = MS_BODY; 02476 _FP_free (result); 02477 return NULL; 02478 } 02479 02480 /* 02481 * Retry, listening to headers this time 02482 */ 02483 fseek (datei, result->startpos, SEEK_SET); 02484 02485 UUkillfread (result); 02486 if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) { 02487 *errcode = UURET_NOMEM; 02488 sstate.isfolder = 0; 02489 sstate.ismime = 0; 02490 UUkillheaders (&localenv); 02491 return NULL; 02492 } 02493 memset (result, 0, sizeof (fileread)); 02494 02495 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) { 02496 /* oops, something went wrong */ 02497 sstate.isfolder = 0; 02498 sstate.ismime = 0; 02499 UUkillfread (result); 02500 UUkillheaders (&localenv); 02501 return NULL; 02502 } 02503 if (res == 1) { 02504 /* 02505 * new headers found 02506 */ 02507 sstate.isfolder = 1; 02508 sstate.ismime = 0; 02509 sstate.mimestate = MS_HEADERS; 02510 } 02511 else { 02512 sstate.isfolder = 0; 02513 sstate.ismime = 0; 02514 } 02515 } 02516 02517 /* 02518 * If this file has been nicely MIME so far, then be very suspicious 02519 * if ScanData reports anything else. So do a double check, and if 02520 * it doesn't hold up, handle as plain text instead. 02521 */ 02522 02523 if (strcmp (localenv.mimevers, "1.0") == 0 && 02524 _FP_stristr (localenv.ctype, "text") != NULL && 02525 sstate.ismime && sstate.mimestate == MS_SUBPART && 02526 !uu_desperate) { 02527 if (result->uudet == UU_ENCODED && !(result->begin || result->end)) { 02528 result->uudet = 0; 02529 } 02530 } 02531 02532 /* 02533 * produce result 02534 */ 02535 02536 if (result->uudet == 0) { 02537 result->uudet = PT_ENCODED; /* plain text */ 02538 } 02539 02540 if (localenv.fname) { 02541 _FP_free (result->filename); 02542 if ((result->filename = _FP_strdup (localenv.fname)) == NULL) 02543 *errcode = UURET_NOMEM; 02544 } 02545 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) && 02546 result->filename==NULL && uu_handletext) { 02547 sprintf (line, "%04d.txt", ++mimseqno); 02548 if ((result->filename = _FP_strdup (line)) == NULL) 02549 *errcode = UURET_NOMEM; 02550 } 02551 else { 02552 /* assign a filename lateron */ 02553 } 02554 if (result->mimetype) _FP_free (result->mimetype); 02555 if (result->uudet) { 02556 if (_FP_stristr (localenv.ctype, "text") != NULL && 02557 result->uudet != QP_ENCODED && result->uudet != PT_ENCODED) 02558 result->mimetype = NULL; /* better don't set it */ 02559 else 02560 result->mimetype = _FP_strdup (localenv.ctype); 02561 } 02562 if (result->origin) _FP_free (result->origin); 02563 result->origin = _FP_strdup (localenv.from); 02564 02565 if (result->subject) _FP_free (result->subject); 02566 result->subject = _FP_strdup (localenv.subject); 02567 02568 if (result->sfname == NULL) 02569 if ((result->sfname = _FP_strdup (fname)) == NULL) 02570 *errcode = UURET_NOMEM; 02571 02572 result->length = prevpos - result->startpos; 02573 result->flags = FL_SINGLE | FL_PROPER; 02574 result->partno = 1; 02575 02576 if (result->mode == 0) 02577 result->mode = 0644; 02578 02579 /* 02580 * the other fields should already be set appropriately 02581 */ 02582 02583 if (*errcode == UURET_OK) 02584 *errcode = UURET_CONT; 02585 02586 /* 02587 * kill local envelope 02588 */ 02589 UUkillheaders (&localenv); 02590 02591 return result; 02592 } 02593 02594 /* 02595 * All right, so we're not in a Multipart message. Phew, took quite 02596 * long to figure this out. But this might still be a MIME message 02597 * body. And if it's a message/partial, we need more special handling 02598 */ 02599 02600 if (sstate.isfolder && sstate.ismime && sstate.mimestate == MS_BODY && 02601 _FP_stristr (sstate.envelope.ctype, "message") != NULL && 02602 _FP_stristr (sstate.envelope.ctype, "partial") != NULL) { 02603 02604 result->startpos = ftell (datei); 02605 02606 if (sstate.envelope.partno == 1) { 02607 /* read local envelope */ 02608 UUkillheaders (&localenv); 02609 memset (&localenv, 0, sizeof (headers)); 02610 02611 /* skip over blank lines first */ 02612 prevpos = ftell (datei); 02613 while (!feof (datei)) { 02614 if (_FP_fgets (line, line_len, datei) == NULL) 02615 break; 02616 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 02617 if (!IsLineEmpty (line)) 02618 break; 02619 prevpos = ftell (datei); 02620 } 02621 /* Next, read header. But what if there is no subheader? */ 02622 hcount = 0; 02623 lcount = 0; 02624 preheaders = prevpos; 02625 02626 while (!feof (datei) && !IsLineEmpty (line)) { 02627 if (IsKnownHeader (line)) 02628 hcount++; 02629 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 02630 if (lcount > WAITHEADER && hcount == 0) { 02631 fseek (datei, preheaders, SEEK_SET); 02632 break; 02633 } 02634 ptr1 = ScanHeaderLine (datei, line); 02635 if (ParseHeader (&localenv, ptr1) == NULL) 02636 *errcode = UURET_NOMEM; 02637 02638 if (_FP_fgets (line, line_len, datei) == NULL) 02639 break; 02640 lcount++; 02641 } 02642 prevpos = ftell (datei); 02643 /* 02644 * Examine local header. We're mostly interested in the Content-Type 02645 * and the Content-Transfer-Encoding. 02646 */ 02647 if (_FP_stristr (localenv.ctype, "multipart") != NULL) { 02648 UUMessage (uuscan_id, __LINE__, UUMSG_WARNING, 02649 uustring (S_MIME_PART_MULTI)); 02650 } 02651 if (localenv.subject) 02652 result->subject = _FP_strdup (localenv.subject); 02653 else 02654 result->subject = _FP_strdup (sstate.envelope.subject); 02655 02656 if (localenv.from) 02657 result->origin = _FP_strdup (localenv.from); 02658 else 02659 result->origin = _FP_strdup (sstate.envelope.from); 02660 02661 if (localenv.ctype) 02662 result->mimetype = _FP_strdup (localenv.ctype); 02663 else 02664 result->mimetype = _FP_strdup ("text/plain"); 02665 02666 if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL) 02667 result->uudet = QP_ENCODED; 02668 else if (_FP_stristr (localenv.ctenc, "base64") != NULL) 02669 result->uudet = B64ENCODED; 02670 else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL) { 02671 result->uudet = UU_ENCODED; 02672 result->begin = result->end = 1; 02673 } 02674 else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL) { 02675 result->uudet = YENC_ENCODED; 02676 result->begin = result->end = 1; 02677 } 02678 else if (_FP_stristr (localenv.ctenc, "7bit") != NULL || 02679 _FP_stristr (localenv.ctenc, "8bit") != NULL) 02680 result->uudet = PT_ENCODED; 02681 else if (_FP_stristr (localenv.ctype, "multipart") != NULL || 02682 _FP_stristr (localenv.ctype, "message") != NULL) 02683 result->uudet = PT_ENCODED; 02684 02685 /* 02686 * If we're switched to MIME-only mode, handle as text 02687 */ 02688 02689 if (uu_more_mime >= 2 && !result->uudet) { 02690 result->uudet = PT_ENCODED; 02691 } 02692 } 02693 else { 02694 memset (&localenv, 0, sizeof (headers)); 02695 } 02696 02697 /* 02698 * If this is Quoted-Printable or Plain Text, just try looking 02699 * for the next message header. If uu_fast_scanning, and the 02700 * encoding is known, there's no need to look below. Otherwise, 02701 * we check the type of encoding first. 02702 * The encoding type is determined on the first part; in all 02703 * others, we also don't read on. 02704 * If we have a partial multipart message, scan for headers, but 02705 * do not react on standard MIME headers, as they are probably 02706 * from the subparts. However, we're stuck if there's an embedded 02707 * message/rfc822 :-( 02708 * If it is a "trivial" (non-embedded) message/rfc822, skip over 02709 * the message header and then start looking for the next header. 02710 */ 02711 if (uu_fast_scanning && (result->uudet!=0||sstate.envelope.partno!=1)) { 02712 /* do nothing */ 02713 res = 0; 02714 } 02715 else if (result->uudet != 0) { 02716 hcount = lcount = 0; 02717 prevpos = ftell (datei); 02718 02719 if (_FP_stristr (localenv.ctype, "message") != NULL && 02720 _FP_stristr (localenv.ctype, "rfc822") != NULL) { 02721 /* 02722 * skip over empty lines and local header 02723 */ 02724 preheaders = ftell (datei); 02725 while (!feof (datei)) { 02726 if (_FP_fgets (line, line_len, datei) == NULL) 02727 break; 02728 if (!IsLineEmpty (line)) { 02729 break; 02730 } 02731 } 02732 02733 while (!feof (datei) && !IsLineEmpty (line)) { 02734 if (IsKnownHeader (line)) 02735 hcount++; 02736 lcount++; 02737 if (lcount > WAITHEADER && hcount hlcount.afternl) 02738 break; 02739 02740 if (_FP_fgets (line, line_len, datei) == NULL) 02741 break; 02742 } 02743 if (hcount hlcount.afternl) 02744 fseek (datei, preheaders, SEEK_SET); 02745 hcount = lcount = 0; 02746 } 02747 02748 /* 02749 * look for next header 02750 */ 02751 02752 while (!feof (datei)) { 02753 if (_FP_fgets (line, line_len, datei) == NULL) 02754 break; 02755 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 02756 if (ferror (datei)) 02757 break; 02758 02759 if ((vflag = IsKnownHeader (line))) { 02760 (void) ScanHeaderLine (datei, line); 02761 02762 if (result->uudet != PT_ENCODED || vflag == 1) { 02763 if (hcount == 0) 02764 preheaders = prevpos; 02765 hcount++; 02766 lcount++; 02767 if (hcount >= hlcount.restart) { 02768 /* 02769 * Hey, a new header starts here 02770 */ 02771 fseek (datei, preheaders, SEEK_SET); 02772 prevpos = preheaders; 02773 break; 02774 } 02775 } 02776 } 02777 else if (lcount > WAITHEADER) { 02778 hcount = 0; 02779 lcount = 0; 02780 } 02781 else if (hcount) { 02782 lcount++; 02783 } 02784 prevpos = ftell (datei); 02785 } 02786 res = 1; 02787 } 02788 else { 02789 /* 02790 * Otherwise, let's see what we can find ourself. No 02791 * boundary (NULL) but MIME, and respect new headers. 02792 */ 02793 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) { 02794 /* oops, something went wrong */ 02795 sstate.isfolder = 0; 02796 sstate.ismime = 0; 02797 UUkillfread (result); 02798 UUkillheaders (&localenv); 02799 return NULL; 02800 } 02801 if (result->uudet == 0 && uu_handletext) 02802 result->uudet = PT_ENCODED; 02803 02804 prevpos = ftell (datei); 02805 } 02806 /* 02807 * produce result 02808 */ 02809 if (localenv.fname) { 02810 _FP_free (result->filename); 02811 if ((result->filename = _FP_strdup (localenv.fname)) == NULL) 02812 *errcode = UURET_NOMEM; 02813 } 02814 else if (sstate.envelope.fname) { 02815 _FP_free (result->filename); 02816 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL) 02817 *errcode = UURET_NOMEM; 02818 } 02819 else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) && 02820 result->filename == NULL) { 02821 sprintf (line, "%04d.txt", ++mimseqno); 02822 if ((result->filename = _FP_strdup (line)) == NULL) 02823 *errcode = UURET_NOMEM; 02824 } 02825 else { 02826 /* assign a filename lateron */ 02827 } 02828 if (result->subject == NULL) { 02829 if (sstate.envelope.subject) 02830 result->subject = _FP_strdup (sstate.envelope.subject); 02831 } 02832 result->partno = sstate.envelope.partno; 02833 result->maxpno = sstate.envelope.numparts; 02834 result->flags = FL_PARTIAL | 02835 ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) | 02836 ((uu_fast_scanning) ? FL_TOEND : 0); 02837 result->mimeid = _FP_strdup (sstate.envelope.mimeid); 02838 if (result->partno == 1) 02839 result->begin = 1; 02840 02841 if (uu_fast_scanning) 02842 result->length = progress.fsize - result->startpos; 02843 else 02844 result->length = prevpos - result->startpos; 02845 02846 if (result->sfname == NULL) 02847 result->sfname = _FP_strdup (fname); 02848 02849 if (result->mode == 0) 02850 result->mode = 0644; 02851 02852 /* 02853 * the other fields should already be set appropriately 02854 */ 02855 02856 if (res == 1) { 02857 /* 02858 * new headers found 02859 */ 02860 sstate.isfolder = 1; 02861 sstate.ismime = 0; 02862 sstate.mimestate = MS_HEADERS; 02863 02864 UUkillheaders (&sstate.envelope); 02865 memset (&sstate.envelope, 0, sizeof (headers)); 02866 } 02867 else { 02868 /* 02869 * otherwise, this can't be a mail folder 02870 */ 02871 sstate.isfolder = 0; 02872 sstate.ismime = 0; 02873 } 02874 /* 02875 * kill local envelope 02876 */ 02877 UUkillheaders (&localenv); 02878 return result; 02879 } 02880 02881 /* 02882 * If this is a MIME body, honor a Content-Type different than 02883 * text/plain or a proper Content-Transfer-Encoding. 02884 * We also go in here if we have an assigned filename - this means 02885 * that we've had a Content-Disposition field, and we should probably 02886 * decode a plain-text segment with a filename. 02887 */ 02888 02889 if (sstate.isfolder && sstate.ismime && 02890 sstate.mimestate == MS_BODY && 02891 (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL || 02892 _FP_stristr (sstate.envelope.ctenc, "base64") != NULL || 02893 _FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL || 02894 _FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL || 02895 _FP_stristr (sstate.envelope.ctype, "message") != NULL || 02896 sstate.envelope.fname != NULL)) { 02897 02898 if (sstate.envelope.subject) 02899 result->subject = _FP_strdup (sstate.envelope.subject); 02900 if (sstate.envelope.from) 02901 result->origin = _FP_strdup (sstate.envelope.from); 02902 02903 if (sstate.envelope.ctype) 02904 result->mimetype = _FP_strdup (sstate.envelope.ctype); 02905 else 02906 result->mimetype = _FP_strdup ("text/plain"); 02907 02908 if (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL) 02909 result->uudet = QP_ENCODED; 02910 else if (_FP_stristr (sstate.envelope.ctenc, "base64") != NULL) 02911 result->uudet = B64ENCODED; 02912 else if (_FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL) { 02913 result->uudet = UU_ENCODED; 02914 result->begin = result->end = 1; 02915 } 02916 else if (_FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL) { 02917 result->uudet = YENC_ENCODED; 02918 } 02919 else if (_FP_stristr (sstate.envelope.ctenc, "7bit") != NULL || 02920 _FP_stristr (sstate.envelope.ctenc, "8bit") != NULL) 02921 result->uudet = PT_ENCODED; 02922 else if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL || 02923 _FP_stristr (sstate.envelope.ctype, "message") != NULL || 02924 sstate.envelope.fname != NULL) 02925 result->uudet = PT_ENCODED; 02926 02927 /* 02928 * If we're switched to MIME-only mode, handle as text 02929 */ 02930 02931 if (uu_more_mime >= 2 && !result->uudet) { 02932 result->uudet = PT_ENCODED; 02933 } 02934 02935 result->startpos = prevpos = ftell (datei); 02936 02937 /* 02938 * If this is Quoted-Printable or Plain Text, just try looking 02939 * for the next message header. If uu_fast_scanning, we know 02940 * there won't be more headers. 02941 * If it is a "trivial" (non-embedded) message/rfc822, skip over 02942 * the message header and then start looking for the next header. 02943 */ 02944 if (result->uudet != 0 && uu_fast_scanning) { 02945 /* do nothing */ 02946 res = 0; 02947 } 02948 else if (result->uudet != 0) { 02949 hcount = lcount = 0; 02950 prevpos = ftell (datei); 02951 02952 if (_FP_stristr (sstate.envelope.ctype, "message") != NULL && 02953 _FP_stristr (sstate.envelope.ctype, "rfc822") != NULL) { 02954 /* 02955 * skip over empty lines and local header 02956 */ 02957 preheaders = ftell (datei); 02958 while (!feof (datei)) { 02959 if (_FP_fgets (line, line_len, datei) == NULL) 02960 break; 02961 if (!IsLineEmpty (line)) { 02962 break; 02963 } 02964 } 02965 02966 while (!feof (datei) && !IsLineEmpty (line)) { 02967 if (IsKnownHeader (line)) 02968 hcount++; 02969 lcount++; 02970 if (lcount > WAITHEADER && hcount hlcount.afternl) 02971 break; 02972 02973 if (_FP_fgets (line, line_len, datei) == NULL) 02974 break; 02975 } 02976 if (hcount hlcount.afternl) 02977 fseek (datei, preheaders, SEEK_SET); 02978 hcount = lcount = 0; 02979 } 02980 02981 /* 02982 * look for next header 02983 */ 02984 02985 while (!feof (datei)) { 02986 if (_FP_fgets (line, line_len, datei) == NULL) 02987 break; 02988 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 02989 if (ferror (datei)) 02990 break; 02991 02992 if (IsKnownHeader (line)) { 02993 (void) ScanHeaderLine (datei, line); 02994 if (hcount == 0) 02995 preheaders = prevpos; 02996 hcount++; 02997 lcount++; 02998 if (hcount >= hlcount.restart) { 02999 /* 03000 * Hey, a new header starts here 03001 */ 03002 fseek (datei, preheaders, SEEK_SET); 03003 prevpos = preheaders; 03004 break; 03005 } 03006 } 03007 else if (lcount > WAITHEADER) { 03008 hcount = 0; 03009 lcount = 0; 03010 } 03011 else if (hcount) { 03012 lcount++; 03013 } 03014 prevpos = ftell (datei); 03015 } 03016 res = 1; 03017 } 03018 else { 03019 /* 03020 * Otherwise, let's see what we can find ourself. No 03021 * boundary (NULL) but MIME, and respect new headers. 03022 */ 03023 if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) { 03024 /* oops, something went wrong */ 03025 sstate.isfolder = 0; 03026 sstate.ismime = 0; 03027 UUkillfread (result); 03028 return NULL; 03029 } 03030 if (result->uudet == 0 && uu_handletext) { 03031 result->startpos = before; /* display headers */ 03032 result->uudet = PT_ENCODED; 03033 } 03034 03035 prevpos = ftell (datei); 03036 } 03037 /* 03038 * produce result 03039 */ 03040 if (sstate.envelope.fname) { 03041 _FP_free (result->filename); 03042 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL) 03043 *errcode = UURET_NOMEM; 03044 } 03045 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) && 03046 result->filename == NULL) { 03047 sprintf (line, "%04d.txt", ++mimseqno); 03048 if ((result->filename = _FP_strdup (line)) == NULL) 03049 *errcode = UURET_NOMEM; 03050 } 03051 else { 03052 /* assign a filename lateron */ 03053 } 03054 if (result->subject == NULL) { 03055 if (sstate.envelope.subject) 03056 result->subject = _FP_strdup (sstate.envelope.subject); 03057 } 03058 result->flags = ((res==1||uu_fast_scanning)?FL_PROPER:0) | 03059 ((uu_fast_scanning) ? FL_TOEND : 0); 03060 result->mimeid = _FP_strdup (sstate.envelope.mimeid); 03061 03062 if (uu_fast_scanning) 03063 result->length = progress.fsize - result->startpos; 03064 else 03065 result->length = prevpos - result->startpos; 03066 03067 if (result->sfname == NULL) 03068 result->sfname = _FP_strdup (fname); 03069 03070 if (result->mode == 0) 03071 result->mode = 0644; 03072 03073 /* 03074 * the other fields should already be set appropriately 03075 */ 03076 03077 if (res == 1) { 03078 /* 03079 * new headers found 03080 */ 03081 sstate.isfolder = 1; 03082 sstate.ismime = 0; 03083 sstate.mimestate = MS_HEADERS; 03084 03085 UUkillheaders (&sstate.envelope); 03086 memset (&sstate.envelope, 0, sizeof (headers)); 03087 } 03088 else { 03089 /* 03090 * otherwise, this can't be a mail folder 03091 */ 03092 sstate.isfolder = 0; 03093 sstate.ismime = 0; 03094 } 03095 03096 return result; 03097 } 03098 03099 /* 03100 * Some files have reduced headers, and what should be a multipart 03101 * message is missing the proper Content-Type. If the first thing 03102 * we find after a couple of empty lines is a boundary, try it! 03103 * But make sure that this is indeed intended as being a boundary. 03104 * 03105 * Only accept it if there was indeed no Content-Type header line 03106 * and if the following line is a proper Content-Type header. BTW, 03107 * we know that sstate.envelope.boundary is NULL, or we wouldn't 03108 * be here! 03109 */ 03110 03111 if ((sstate.envelope.ctype == NULL || 03112 _FP_stristr (sstate.envelope.ctype, "multipart") != NULL) && 03113 !uu_more_mime) { 03114 prevpos = ftell (datei); 03115 while (!feof (datei)) { 03116 if (_FP_fgets (line, line_len, datei) == NULL) { 03117 line[0] = '\0'; 03118 break; 03119 } 03120 if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL(); 03121 if (!IsLineEmpty (line)) 03122 break; 03123 } 03124 if (line[0] == '-' && line[1] == '-' && 03125 !IsLineEmpty (line+2) && !feof (datei)) { 03126 ptr1 = _FP_strrstr (line+2, "--"); 03127 ptr2 = ScanHeaderLine (datei, NULL); 03128 if ((ptr1 == NULL || (*(ptr1+2) != '\012' && *(ptr1+2) != '\015')) && 03129 ptr2 && _FP_strnicmp (ptr2, "Content-", 8) == 0) { 03130 /* 03131 * hmm, okay, let's do it! 03132 */ 03133 sstate.isfolder = 1; 03134 sstate.ismime = 1; 03135 sstate.mimestate = MS_PREAMBLE; 03136 /* 03137 * get boundary 03138 */ 03139 ptr1 = line+2; 03140 while (*ptr1 && !isspace((unsigned char)*ptr1)) 03141 ptr1++; 03142 *ptr1 = '\0'; 03143 03144 sstate.envelope.mimevers = _FP_strdup ("1.0"); 03145 sstate.envelope.boundary = _FP_strdup (line+2); 03146 03147 /* 03148 * need restart 03149 */ 03150 03151 fseek (datei, prevpos, SEEK_SET); 03152 03153 _FP_free (result); 03154 return NULL; 03155 } 03156 } 03157 fseek (datei, prevpos, SEEK_SET); 03158 } 03159 03160 /* 03161 * Hmm, we're not in a ''special'' state, so it's more or less 03162 * Freestyle time. Anyway, if this seems to be a Mime message, 03163 * don't allow the minimal Base64 handling. 03164 */ 03165 03166 if (sstate.envelope.subject) 03167 result->subject = _FP_strdup (sstate.envelope.subject); 03168 if (sstate.envelope.from) 03169 result->origin = _FP_strdup (sstate.envelope.from); 03170 03171 if (sstate.envelope.ctype) 03172 result->mimetype = _FP_strdup (sstate.envelope.ctype); 03173 03174 if ((res=ScanData (datei, fname, errcode, NULL, 03175 sstate.ismime, 1, result))==-1) { 03176 /* oops, something went wrong */ 03177 sstate.isfolder = 0; 03178 sstate.ismime = 0; 03179 UUkillfread (result); 03180 return NULL; 03181 } 03182 03183 /* 03184 * produce result 03185 */ 03186 03187 if (result->uudet == 0 && uu_handletext) { 03188 result->startpos = before; /* display headers */ 03189 result->uudet = PT_ENCODED; 03190 result->partno = 1; 03191 } 03192 03193 if (result->uudet == YENC_ENCODED && result->filename != NULL) { 03194 /* 03195 * prevent replacing the filename found on the =ybegin line 03196 */ 03197 } 03198 else if (sstate.envelope.fname) { 03199 _FP_free (result->filename); 03200 if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL) 03201 *errcode = UURET_NOMEM; 03202 } 03203 else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) && 03204 result->filename == NULL) { 03205 sprintf (line, "%04d.txt", ++mimseqno); 03206 if ((result->filename = _FP_strdup (line)) == NULL) 03207 *errcode = UURET_NOMEM; 03208 } 03209 else { 03210 /* assign a filename lateron */ 03211 } 03212 03213 if (result->subject == NULL) { 03214 if (sstate.envelope.subject) 03215 result->subject = _FP_strdup (sstate.envelope.subject); 03216 } 03217 03218 result->flags = (result->uudet==PT_ENCODED)?FL_SINGLE:0; 03219 result->mimeid = _FP_strdup (sstate.envelope.mimeid); 03220 result->length = ftell (datei) - result->startpos; 03221 03222 if (result->mode == 0) 03223 result->mode = 0644; 03224 03225 if (result->sfname == NULL) 03226 result->sfname = _FP_strdup (fname); 03227 03228 if (res == 1) { 03229 /* 03230 * new headers found 03231 */ 03232 sstate.isfolder = 1; 03233 sstate.ismime = 0; 03234 sstate.mimestate = MS_HEADERS; 03235 03236 UUkillheaders (&sstate.envelope); 03237 memset (&sstate.envelope, 0, sizeof (headers)); 03238 } 03239 else { 03240 /* 03241 * otherwise, this can't be a mail folder 03242 */ 03243 sstate.isfolder = 0; 03244 sstate.ismime = 0; 03245 } 03246 03247 return result; 03248 03249 /* 03250 * Emergency handling. Set errcode before jumping here. 03251 */ 03252 ScanPartEmergency: 03253 UUkillfread (result); 03254 UUkillheaders (&localenv); 03255 03256 while (mssdepth) { 03257 mssdepth--; 03258 UUkillheaders (&(multistack[mssdepth].envelope)); 03259 _FP_free (multistack[mssdepth].source); 03260 } 03261 03262 return NULL; 03263 } 03264