uuscan.c

Go to the documentation of this file.
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 #include 
00034 #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 is arrays 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

Generated on Sun Oct 12 01:45:30 2008 for NNTPGrab by  1.5.4