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 the functions that are responsible for decoding. The 00019 * original idea is from a freeware utility called "uunconc", and 00020 * few lines of this code may still bear a remote resemblance to 00021 * its code. If you are the author or know him, contact me. 00022 * This program could only decode one multi-part, uuencoded file 00023 * where the parts were in order. Base64, XX and BinHex decoding, 00024 * support for multi-files and part-ordering covered by myself. 00025 **/ 00026 00027 #ifdef HAVE_CONFIG_H 00028 #ifdef _MSC_VER 00029 #include "config.h.win32" 00030 #else 00031 #include "config.h" 00032 #endif 00033 #endif 00034 00035 #include00036 00037 #ifdef SYSTEM_WINDLL 00038 #include 00039 #endif 00040 #ifdef SYSTEM_OS2 00041 #include 00042 #endif 00043 00044 #include 00045 #include 00046 00047 #ifdef STDC_HEADERS 00048 #include 00049 #include 00050 #endif 00051 #ifdef HAVE_UNISTD_H 00052 #include 00053 #endif 00054 #ifdef HAVE_ERRNO_H 00055 #include 00056 #endif 00057 00058 #include <crc32.h> 00059 #include <uudeview.h> 00060 #include <uuint.h> 00061 #include <fptools.h> 00062 #include <uustring.h> 00063 00064 /**** 00065 Some stuff coming from GLib.. Added here because of strange behaviour when using a mixed compiler environment 00066 ****/ 00067 #ifdef _MSC_VER 00068 #include 00069 #include 00070 #include 00071 00072 /* 00073 * create_temp_file based on the mkstemp implementation from the GNU C library. 00074 * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc. 00075 */ 00076 static gint 00077 create_temp_file (gchar *tmpl, 00078 int permissions) 00079 { 00080 char *XXXXXX; 00081 int count, fd; 00082 static const char letters[] = 00083 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 00084 static const int NLETTERS = sizeof (letters) - 1; 00085 glong value; 00086 GTimeVal tv; 00087 static int counter = 0; 00088 00089 /* find the last occurrence of "XXXXXX" */ 00090 XXXXXX = g_strrstr (tmpl, "XXXXXX"); 00091 00092 if (!XXXXXX || strncmp (XXXXXX, "XXXXXX", 6)) 00093 { 00094 errno = EINVAL; 00095 return -1; 00096 } 00097 00098 /* Get some more or less random data. */ 00099 g_get_current_time (&tv); 00100 value = (tv.tv_usec ^ tv.tv_sec) + counter++; 00101 00102 for (count = 0; count < 100; value += 7777, ++count) 00103 { 00104 glong v = value; 00105 00106 /* Fill in the random bits. */ 00107 XXXXXX[0] = letters[v % NLETTERS]; 00108 v /= NLETTERS; 00109 XXXXXX[1] = letters[v % NLETTERS]; 00110 v /= NLETTERS; 00111 XXXXXX[2] = letters[v % NLETTERS]; 00112 v /= NLETTERS; 00113 XXXXXX[3] = letters[v % NLETTERS]; 00114 v /= NLETTERS; 00115 XXXXXX[4] = letters[v % NLETTERS]; 00116 v /= NLETTERS; 00117 XXXXXX[5] = letters[v % NLETTERS]; 00118 00119 /* tmpl is in UTF-8 on Windows, thus use g_open() */ 00120 fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, permissions); 00121 00122 if (fd >= 0) 00123 return fd; 00124 else if (errno != EEXIST) 00125 /* Any other error will apply also to other names we might 00126 * try, and there are 2^32 or so of them, so give up now. 00127 */ 00128 return -1; 00129 } 00130 00131 /* We got out of the loop because we ran out of combinations to try. */ 00132 errno = EEXIST; 00133 return -1; 00134 } 00135 #endif 00136 /**** 00137 End of GLib code 00138 ****/ 00139 00140 char * uunconc_id = "$Id: uunconc.c 260 2007-05-04 23:32:54Z csk $"; 00141 00142 /* for braindead systems */ 00143 #ifndef SEEK_SET 00144 #ifdef L_BEGIN 00145 #define SEEK_SET L_BEGIN 00146 #else 00147 #define SEEK_SET 0 00148 #endif 00149 #endif 00150 00151 /* 00152 * decoder states 00153 */ 00154 00155 #define BEGIN (1) 00156 #define DATA (2) 00157 #define END (3) 00158 #define DONE (4) 00159 00160 /* 00161 * mallocable areas 00162 */ 00163 00164 char *uunconc_UUxlat; 00165 char *uunconc_UUxlen; 00166 char *uunconc_B64xlat; 00167 char *uunconc_XXxlat; 00168 char *uunconc_BHxlat; 00169 char *uunconc_save; 00170 00171 /* 00172 * decoding translation tables and line length table 00173 */ 00174 00175 static int * UUxlen; /* initialized in UUInitConc() */ 00176 static int * UUxlat; /* from the malloc'ed areas above */ 00177 static int * B64xlat; 00178 static int * XXxlat; 00179 static int * BHxlat; 00180 00181 /* 00182 * buffer for decoding 00183 */ 00184 00185 static char *save[3]; 00186 00187 /* 00188 * mallocable areas 00189 */ 00190 00191 char *uuncdl_fulline; 00192 char *uuncdp_oline; 00193 00194 /* 00195 * Return information for QuickDecode 00196 */ 00197 00198 static int uulboundary; 00199 00200 /* 00201 * To prevent warnings when using a char as index into an array 00202 */ 00203 00204 #define ACAST(s) ((int)(unsigned char)(s)) 00205 00206 /* 00207 * Initialize decoding tables 00208 */ 00209 00210 void 00211 UUInitConc (void) 00212 { 00213 int i, j; 00214 00215 /* 00216 * Update pointers 00217 */ 00218 UUxlen = (int *) uunconc_UUxlen; 00219 UUxlat = (int *) uunconc_UUxlat; 00220 B64xlat = (int *) uunconc_B64xlat; 00221 XXxlat = (int *) uunconc_XXxlat; 00222 BHxlat = (int *) uunconc_BHxlat; 00223 00224 save[0] = uunconc_save; 00225 save[1] = uunconc_save + 256; 00226 save[2] = uunconc_save + 512; 00227 00228 /* prepare decoding translation table */ 00229 for(i = 0; i < 256; i++) 00230 UUxlat[i] = B64xlat[i] = XXxlat[i] = BHxlat[i] = -1; 00231 00232 /* 00233 * At some time I received a file which used lowercase characters for 00234 * uuencoding. This shouldn't be, but let's accept it. Must take special 00235 * care that this doesn't break xxdecoding. This is giving me quite a 00236 * headache. If this one file hadn't been a Pocahontas picture, I might 00237 * have ignored it for good. 00238 */ 00239 00240 for (i = ' ', j = 0; i < ' ' + 64; i++, j++) 00241 UUxlat[i] /* = UUxlat[i+64] */ = j; 00242 for (i = '`', j = 0; i < '`' + 32; i++, j++) 00243 UUxlat[i] = j; 00244 00245 /* add special cases */ 00246 UUxlat['`'] = UUxlat[' ']; 00247 UUxlat['~'] = UUxlat['^']; 00248 00249 /* prepare line length table */ 00250 UUxlen[0] = 1; 00251 for(i = 1, j = 5; i <= 61; i += 3, j += 4) 00252 UUxlen[i] = UUxlen[i+1] = UUxlen[i+2] = j; 00253 00254 /* prepare other tables */ 00255 for (i=0; i<64; i++) { 00256 B64xlat[ACAST(B64EncodeTable[i])] = i; 00257 XXxlat [ACAST(XXEncodeTable [i])] = i; 00258 BHxlat [ACAST(BHEncodeTable [i])] = i; 00259 } 00260 } 00261 00262 /* 00263 * Workaround for Netscape 00264 */ 00265 00266 /* 00267 * Determines whether Netscape may have broken up a data line (by 00268 * inserting a newline). This only seems to happen after 00269 * href statement 00270 */ 00271 00272 static int 00273 UUBrokenByNetscape (char *string) 00274 { 00275 char *ptr; 00276 int len; 00277 00278 if (string==NULL || (len=strlen(string))<3) 00279 return 0; 00280 00281 if ((ptr = _FP_stristr (string, "00282 if (_FP_stristr (string, "") > ptr) 00283 return 2; 00284 } 00285 00286 ptr = string + len; 00287 00288 while (len && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) { 00289 ptr--; len--; 00290 } 00291 if (len<3) return 0; 00292 if (*--ptr == ' ') ptr--; 00293 ptr--; 00294 00295 if (_FP_strnicmp (ptr, ", 2) == 0) 00296 return 1; 00297 00298 return 0; 00299 } 00300 00301 /* 00302 * Try to repair a Netscape-corrupted line of data. 00303 * This must only be called on corrupted lines, since non-Netscape 00304 * data may even _get_ corrupted by this procedure. 00305 * 00306 * Some checks are included multiply to speed up the procedure. For 00307 * example: (*p1!='<' || strnicmp(p1,"",4)). If the first expression 00308 * becomes true, the costly function isn't called :-) 00309 * 00310 * Since '<', '>', '&' might even be replaced by their html equivalents 00311 * in href strings, I'm now using two passes, the first one for & + co, 00312 * the second one for hrefs. 00313 */ 00314 00315 static int 00316 UUNetscapeCollapse (char *string) 00317 { 00318 char *p1=string, *p2=string; 00319 int res = 0; 00320 00321 if (string==NULL) 00322 return 0; 00323 00324 /* 00325 * First pass 00326 */ 00327 while (*p1) { 00328 if (*p1 == '&') { 00329 if (_FP_strnicmp (p1, "&", 5) == 0) { p1+=5; *p2++='&'; res=1; } 00330 else if (_FP_strnicmp (p1, "<", 4) == 0) { p1+=4; *p2++='<'; res=1; } 00331 else if (_FP_strnicmp (p1, ">", 4) == 0) { p1+=4; *p2++='>'; res=1; } 00332 else *p2++ = *p1++; 00333 } 00334 else *p2++ = *p1++; 00335 } 00336 *p2 = '\0'; 00337 /* 00338 * Second pass 00339 */ 00340 p1 = p2 = string; 00341 00342 while (*p1) { 00343 if (*p1 == '<') { 00344 if ((_FP_strnicmp (p1, " , 7) == 0 || 00345 _FP_strnicmp (p1, "00346 (_FP_strstr (p1, "") != 0 || _FP_strstr (p1, "") != 0)) { 00347 while (*p1 && *p1!='>') p1++; 00348 if (*p1=='\0' || *(p1+1)!='<') return 0; 00349 p1++; 00350 while (*p1 && (*p1!='<' || _FP_strnicmp(p1,"",4)!=0)) { 00351 *p2++ = *p1++; 00352 } 00353 if (_FP_strnicmp(p1,"",4) != 0) 00354 return 0; 00355 p1+=4; 00356 res=1; 00357 } 00358 else 00359 *p2++ = *p1++; 00360 } 00361 else 00362 *p2++ = *p1++; 00363 } 00364 *p2 = '\0'; 00365 00366 return res; 00367 } 00368 00369 /* 00370 * The second parameter is 0 if we are still searching for encoded data, 00371 * otherwise it indicates the encoding we're using right now. If we're 00372 * still in the searching stage, we must be a little more strict in 00373 * deciding for or against encoding; there's too much plain text looking 00374 * like encoded data :-( 00375 */ 00376 00377 int 00378 UUValidData (char *ptr, int encoding, int *bhflag) 00379 { 00380 int i=0, j, len=0, suspicious=0, flag=0; 00381 char *s = ptr; 00382 00383 if ((s == NULL) || (*s == '\0')) { 00384 return 0; /* bad string */ 00385 } 00386 00387 while (*s && *s!='\012' && *s!='\015') { 00388 s++; 00389 len++; 00390 i++; 00391 } 00392 00393 if (i == 0) 00394 return 0; 00395 00396 switch (encoding) { 00397 case UU_ENCODED: 00398 goto _t_UU; 00399 case XX_ENCODED: 00400 goto _t_XX; 00401 case B64ENCODED: 00402 goto _t_B64; 00403 case BH_ENCODED: 00404 goto _t_Binhex; 00405 case YENC_ENCODED: 00406 return YENC_ENCODED; 00407 } 00408 00409 _t_Binhex: /* Binhex Test */ 00410 len = i; s = ptr; 00411 00412 /* 00413 * bhflag notes the state we're in. Within the data, it's 1. If we're 00414 * still looking for the initial :, it's 0 00415 */ 00416 if (*bhflag == 0 && *s != ':') { 00417 if (encoding==BH_ENCODED) return 0; 00418 goto _t_B64; 00419 } 00420 else if (*bhflag == 0 /* *s == ':' */) { 00421 s++; len--; 00422 } 00423 00424 while (len && BHxlat[ACAST(*s)] != -1) { 00425 len--; s++; 00426 } 00427 00428 /* allow space characters at the end of the line if we are sure */ 00429 /* that this is Binhex encoded data or the line was long enough */ 00430 00431 flag = (*s == ':') ? 0 : 1; 00432 00433 if (*s == ':' && len>0) { 00434 s++; len--; 00435 } 00436 if (((i>=60 && len<=10) || encoding) && *s==' ') { 00437 while (len && *s==' ') { 00438 s++; len--; 00439 } 00440 } 00441 00442 /* 00443 * BinHex data shall have exactly 64 characters (except the last 00444 * line). We ignore everything with less than 40 characters to 00445 * be flexible 00446 */ 00447 00448 if (len != 0 || (flag && i < 40)) { 00449 if (encoding==BH_ENCODED) return 0; 00450 goto _t_B64; 00451 } 00452 00453 *bhflag = flag; 00454 00455 return BH_ENCODED; 00456 00457 _t_B64: /* Base64 Test */ 00458 len = i; s = ptr; 00459 00460 /* 00461 * Face it: there _are_ Base64 lines that are not a multiple of four 00462 * in length :-( 00463 * 00464 * if (len%4) 00465 * goto _t_UU; 00466 */ 00467 00468 while (len--) { 00469 if (*s < 0 || (B64xlat[ACAST(*s)] == -1 && *s != '=')) { 00470 /* allow space characters at the end of the line if we are sure */ 00471 /* that this is Base64 encoded data or the line was long enough */ 00472 if (((i>=60 && len<=10) || encoding) && *s++==' ') { 00473 while (*s==' ' && len) s++; 00474 if (len==0) return B64ENCODED; 00475 } 00476 if (encoding==B64ENCODED) return 0; 00477 goto _t_UU; 00478 } 00479 else if (*s == '=') { /* special case at end */ 00480 /* if we know this is B64encoded, allow spaces at end of line */ 00481 s++; 00482 if (*s=='=' && len>=1) { 00483 len--; s++; 00484 } 00485 if (encoding && len && *s==' ') { 00486 while (len && *s==' ') { 00487 s++; len--; 00488 } 00489 } 00490 if (len != 0) { 00491 if (encoding==B64ENCODED) return 0; 00492 goto _t_UU; 00493 } 00494 return B64ENCODED; 00495 } 00496 s++; 00497 } 00498 return B64ENCODED; 00499 00500 _t_UU: 00501 len = i; s = ptr; 00502 00503 if (UUxlat[ACAST(*s)] == -1) { /* uutest */ 00504 if (encoding==UU_ENCODED) return 0; 00505 goto _t_XX; 00506 } 00507 00508 j = UUxlen[UUxlat[ACAST(*s)]]; 00509 00510 if (len-1 == j) /* remove trailing character */ 00511 len--; 00512 if (len != j) { 00513 switch (UUxlat[ACAST(*s)]%3) { 00514 case 1: 00515 if (j-2 == len) j-=2; 00516 break; 00517 case 2: 00518 if (j-1 == len) j-=1; 00519 break; 00520 } 00521 } 00522 00523 /* 00524 * some encoders are broken with respect to encoding the last line of 00525 * a file and produce extraoneous characters beyond the expected EOL 00526 * So were not too picky here about the last line, as long as it's longer 00527 * than necessary and shorter than the maximum 00528 * this tolerance broke the xxdecoding, because xxencoded data was 00529 * detected as being uuencoded :( so don't accept 'h' as first character 00530 * also, if the first character is lowercase, don't accept the line to 00531 * have space characters. the only encoder I've heard of which uses 00532 * lowercase characters at least accepts the special case of encoding 00533 * 0 as `. The strchr() shouldn't be too expensive here as it's only 00534 * evaluated if the first character is lowercase, which really shouldn't 00535 * be in uuencoded text. 00536 */ 00537 if (len != j && 00538 ((ptr[0] == '-' && ptr[1] == '-' && strstr(ptr,"part")!=NULL) || 00539 !(*ptr != 'M' && *ptr != 'h' && 00540 len > j && len <= UUxlen[UUxlat['M']]))) { 00541 if (encoding==UU_ENCODED) return 0; 00542 goto _t_XX; /* bad length */ 00543 } 00544 00545 if (len != j || islower ((unsigned char)*ptr)) { 00546 /* 00547 * if we are not in a 'uuencoded' state, don't allow the line to have 00548 * space characters at all. if we know we _are_ decoding uuencoded 00549 * data, the rest of the line, beyond the length of encoded data, may 00550 * have spaces. 00551 */ 00552 if (encoding != UU_ENCODED) 00553 if (strchr (ptr, ' ') != NULL) 00554 goto _t_XX; 00555 00556 /* suspicious = 1; we're careful here REMOVED 0.4.15 __FP__ */ 00557 len = j; 00558 } 00559 00560 while (len--) { 00561 if (*s < 0 || UUxlat[ACAST(*s++)] < 0) { 00562 if (encoding==UU_ENCODED) return 0; 00563 goto _t_XX; /* bad code character */ 00564 } 00565 if (*s == ' ' && suspicious) { 00566 if (encoding==UU_ENCODED) return 0; 00567 goto _t_XX; /* this line looks _too_ suspicious */ 00568 } 00569 } 00570 return UU_ENCODED; /* data is valid */ 00571 00572 _t_XX: /* XX Test */ 00573 len = i; s = ptr; 00574 00575 if (XXxlat[ACAST(*s)] == -1) 00576 return 0; 00577 00578 j = UUxlen[XXxlat[ACAST(*s)]]; /* Same line length table as UUencoding */ 00579 00580 if (len-1 == j) /* remove trailing character */ 00581 len--; 00582 if (len != j) 00583 switch (UUxlat[ACAST(*s)]%3) { 00584 case 1: 00585 if (j-2 == len) j-=2; 00586 break; 00587 case 2: 00588 if (j-1 == len) j-=1; 00589 break; 00590 } 00591 /* 00592 * some encoders are broken with respect to encoding the last line of 00593 * a file and produce extraoneous characters beyond the expected EOL 00594 * So were not too picky here about the last line, as long as it's longer 00595 * than necessary and shorter than the maximum 00596 */ 00597 if (len != j && !(*ptr != 'h' && len > j && len <= UUxlen[UUxlat['h']])) 00598 return 0; /* bad length */ 00599 00600 while(len--) { 00601 if(*s < 0 || XXxlat[ACAST(*s++)] < 0) { 00602 return 0; /* bad code character */ 00603 } 00604 } 00605 return XX_ENCODED; /* data is valid */ 00606 } 00607 00608 /* 00609 * This function may be called upon a line that does not look like 00610 * valid encoding on first sight, but might be erroneously encoded 00611 * data from Netscape, Lynx or MS Exchange. We might need to read 00612 * a new line from the stream, which is why we need the FILE. 00613 * Returns the type of encoded data if successful or 0 otherwise. 00614 */ 00615 00616 int 00617 UURepairData (FILE *datei, char *line, int encoding, int *bhflag) 00618 { 00619 int nflag, vflag=0, safety=42; 00620 char *ptr; 00621 00622 nflag = UUBrokenByNetscape (line); 00623 00624 while (vflag == 0 && nflag && safety--) { 00625 if (nflag == 1) { /* need next line to repair */ 00626 if (strlen (line) > 250) 00627 break; 00628 ptr = line + strlen (line); 00629 while (ptr>line && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) 00630 ptr--; 00631 if (_FP_fgets (ptr, 255-(ptr-line), datei) == NULL) 00632 break; 00633 } 00634 else { /* don't need next line to repair */ 00635 } 00636 if (UUNetscapeCollapse (line)) { 00637 if ((vflag = UUValidData (line, encoding, bhflag)) == 0) 00638 nflag = UUBrokenByNetscape (line); 00639 } 00640 else 00641 nflag = 0; 00642 } 00643 /* 00644 * Sometimes, a line is garbled even without it being split into 00645 * the next line. Then we try this in our despair 00646 */ 00647 if (vflag == 0) { 00648 if (UUNetscapeCollapse (line)) 00649 vflag = UUValidData (line, encoding, bhflag); 00650 } 00651 00652 /* 00653 * If this line looks uuencoded, but the line is one character short 00654 * of a valid line, it was probably broken by MS Exchange. According 00655 * to my test cases, there is at most one space character missing; 00656 * there are never two spaces together. 00657 * If adding a space character helps making this line uuencoded, do 00658 * it! 00659 */ 00660 00661 if (vflag == 0) { 00662 ptr = line + strlen(line); 00663 while (ptr>line && (*(ptr-1)=='\012' || *(ptr-1)=='\015')) { 00664 ptr--; 00665 } 00666 *ptr++ = ' '; 00667 *ptr-- = '\0'; 00668 if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) { 00669 *ptr = '\0'; 00670 vflag = 0; 00671 } 00672 } 00673 return vflag; 00674 } 00675 00676 /* 00677 * Decode a single encoded line using method 00678 */ 00679 00680 size_t 00681 UUDecodeLine (char *s, char *d, int method) 00682 { 00683 int i, j, c, cc, count=0, z1, z2, z3, z4; 00684 static int leftover=0; 00685 int *table; 00686 00687 /* 00688 * for re-initialization 00689 */ 00690 00691 if (s == NULL || d == NULL) { 00692 leftover = 0; 00693 return 0; 00694 } 00695 00696 /* 00697 * To shut up gcc -Wall 00698 */ 00699 z1 = z2 = z3 = z4 = 0; 00700 00701 if (method == UU_ENCODED || method == XX_ENCODED) { 00702 if (method == UU_ENCODED) 00703 table = UUxlat; 00704 else 00705 table = XXxlat; 00706 00707 i = table [ACAST(*s++)]; 00708 j = UUxlen[i] - 1; 00709 00710 while(j > 0) { 00711 c = table[ACAST(*s++)] << 2; 00712 cc = table[ACAST(*s++)]; 00713 c |= (cc >> 4); 00714 00715 if(i-- > 0) 00716 d[count++] = c; 00717 00718 cc <<= 4; 00719 c = table[ACAST(*s++)]; 00720 cc |= (c >> 2); 00721 00722 if(i-- > 0) 00723 d[count++] = cc; 00724 00725 c <<= 6; 00726 c |= table[ACAST(*s++)]; 00727 00728 if(i-- > 0) 00729 d[count++] = c; 00730 00731 j -= 4; 00732 } 00733 } 00734 else if (method == B64ENCODED) { 00735 if (leftover) { 00736 strcpy (uuncdl_fulline+leftover, s); 00737 leftover = 0; 00738 s = uuncdl_fulline; 00739 } 00740 00741 while ((z1 = B64xlat[ACAST(*s)]) != -1) { 00742 if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break; 00743 if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break; 00744 if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break; 00745 00746 d[count++] = (z1 << 2) | (z2 >> 4); 00747 d[count++] = (z2 << 4) | (z3 >> 2); 00748 d[count++] = (z3 << 6) | (z4); 00749 00750 s += 4; 00751 } 00752 if (z1 != -1 && z2 != -1 && *(s+2) == '=') { 00753 d[count++] = (z1 << 2) | (z2 >> 4); 00754 s+=2; 00755 } 00756 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') { 00757 d[count++] = (z1 << 2) | (z2 >> 4); 00758 d[count++] = (z2 << 4) | (z3 >> 2); 00759 s+=3; 00760 } 00761 while (B64xlat[ACAST(*s)] != -1) 00762 uuncdl_fulline[leftover++] = *s++; 00763 } 00764 else if (method == BH_ENCODED) { 00765 if (leftover) { 00766 strcpy (uuncdl_fulline+leftover, s); 00767 leftover = 0; 00768 s = uuncdl_fulline; 00769 } 00770 else if (*s == ':') 00771 s++; 00772 00773 while ((z1 = BHxlat[ACAST(*s)]) != -1) { 00774 if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break; 00775 if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break; 00776 if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break; 00777 00778 d[count++] = (z1 << 2) | (z2 >> 4); 00779 d[count++] = (z2 << 4) | (z3 >> 2); 00780 d[count++] = (z3 << 6) | (z4); 00781 00782 s += 4; 00783 } 00784 if (z1 != -1 && z2 != -1 && *(s+2) == ':') { 00785 d[count++] = (z1 << 2) | (z2 >> 4); 00786 s+=2; 00787 } 00788 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') { 00789 d[count++] = (z1 << 2) | (z2 >> 4); 00790 d[count++] = (z2 << 4) | (z3 >> 2); 00791 s+=3; 00792 } 00793 while (BHxlat[ACAST(*s)] != -1) 00794 uuncdl_fulline[leftover++] = *s++; 00795 } 00796 else if (method == YENC_ENCODED) { 00797 while (*s) { 00798 if (*s == '=') { 00799 if (*++s != '\0') { 00800 d[count++] = (char) ((int) *s - 64 - 42); 00801 s++; 00802 } 00803 } 00804 else if (*s == '\n' || *s == '\r') { 00805 s++; /* ignore */ 00806 } 00807 else { 00808 d[count++] = (char) ((int) *s++ - 42); 00809 } 00810 } 00811 } 00812 00813 return count; 00814 } 00815 00816 /* 00817 * ``Decode'' Quoted-Printable text 00818 */ 00819 00820 static int 00821 UUDecodeQP (FILE *datain, FILE *dataout, int *state, 00822 long maxpos, int method, int flags, 00823 char *boundary) 00824 { 00825 char *line=uugen_inbuffer, *p1, *p2; 00826 int val; 00827 00828 uulboundary = -1; 00829 00830 while (!feof (datain) && 00831 (ftell(datain) FL_TOEND || 00832 (!(flags&FL_PROPER) && uu_fast_scanning))) { 00833 if (_FP_fgets (line, 255, datain) == NULL) 00834 break; 00835 if (ferror (datain)) { 00836 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 00837 uustring (S_SOURCE_READ_ERR), 00838 strerror (uu_errno = errno)); 00839 return UURET_IOERR; 00840 } 00841 line[255] = '\0'; 00842 00843 if (boundary && line[0]=='-' && line[1]=='-' && 00844 strncmp (line+2, boundary, strlen (boundary)) == 0) { 00845 if (line[strlen(boundary)+2]=='-') 00846 uulboundary = 1; 00847 else 00848 uulboundary = 0; 00849 return UURET_OK; 00850 } 00851 00852 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) { 00853 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE, 00854 uustring (S_DECODE_CANCEL)); 00855 return UURET_CANCEL; 00856 } 00857 00858 p1 = p2 = line; 00859 00860 while (*p2) { 00861 while (*p2 && *p2 != '=') 00862 p2++; 00863 if (*p2 == '\0') 00864 break; 00865 *p2 = '\0'; 00866 fprintf (dataout, "%s", p1); 00867 p1 = ++p2; 00868 00869 if (isxdigit ((unsigned char)*p2) && isxdigit ((unsigned char)*(p2+1))) { 00870 val = ((isdigit((unsigned char)*p2)) ? (*p2-'0') : (tolower(*p2)-'a'+10)) << 4; 00871 val |= ((isdigit((unsigned char)*(p2+1)))?(*(p2+1)-'0') : (tolower(*(p2+1))-'a'+10)); 00872 00873 fputc (val, dataout); 00874 p2 += 2; 00875 p1 = p2; 00876 } 00877 else if (*p2 == '\012' || *(p2+1) == '\015') { 00878 /* soft line break */ 00879 *p2 = '\0'; 00880 break; 00881 } 00882 else { 00883 /* huh? */ 00884 fputc ('=', dataout); 00885 } 00886 } 00887 /* 00888 * p2 points to a nullbyte right after the CR/LF/CRLF 00889 */ 00890 val = 0; 00891 while (p2>p1 && isspace ((unsigned char)*(p2-1))) { 00892 if (*(p2-1) == '\012' || *(p2-1) == '\015') 00893 val = 1; 00894 p2--; 00895 } 00896 *p2 = '\0'; 00897 00898 /* 00899 * If the part ends directly after this line, the data does not end 00900 * with a linebreak. Or, as the docs put it, "the CRLF preceding the 00901 * encapsulation line is conceptually attached to the boundary. 00902 * So if the part ends here, don't print a line break" 00903 */ 00904 if (val && (!feof (datain) && 00905 (ftell(datain) FL_TOEND || 00906 (!(flags&FL_PROPER) && uu_fast_scanning)))) 00907 fprintf (dataout, "%s\n", p1); 00908 else 00909 fprintf (dataout, "%s", p1); 00910 } 00911 return UURET_OK; 00912 } 00913 00914 /* 00915 * ``Decode'' plain text. Our job is to properly handle the EOL sequence 00916 */ 00917 00918 static int 00919 UUDecodePT (FILE *datain, FILE *dataout, int *state, 00920 long maxpos, int method, int flags, 00921 char *boundary) 00922 { 00923 char *line=uugen_inbuffer, *ptr; 00924 00925 uulboundary = -1; 00926 00927 while (!feof (datain) && 00928 (ftell(datain) FL_TOEND || 00929 (!(flags&FL_PROPER) && uu_fast_scanning))) { 00930 if (_FP_fgets (line, 255, datain) == NULL) 00931 break; 00932 if (ferror (datain)) { 00933 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 00934 uustring (S_SOURCE_READ_ERR), 00935 strerror (uu_errno = errno)); 00936 return UURET_IOERR; 00937 } 00938 line[255] = '\0'; 00939 00940 if (boundary && line[0]=='-' && line[1]=='-' && 00941 strncmp (line+2, boundary, strlen (boundary)) == 0) { 00942 if (line[strlen(boundary)+2]=='-') 00943 uulboundary = 1; 00944 else 00945 uulboundary = 0; 00946 return UURET_OK; 00947 } 00948 00949 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) { 00950 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE, 00951 uustring (S_DECODE_CANCEL)); 00952 return UURET_CANCEL; 00953 } 00954 00955 ptr = line + strlen (line); 00956 00957 while (ptr>line && (*(ptr-1) == '\012' || *(ptr-1) == '\015')) 00958 ptr--; 00959 00960 00961 /* 00962 * If the part ends directly after this line, the data does not end 00963 * with a linebreak. Or, as the docs put it, "the CRLF preceding the 00964 * encapsulation line is conceptually attached to the boundary. 00965 * So if the part ends here, don't print a line break" 00966 */ 00967 if ((*ptr == '\012' || *ptr == '\015') && 00968 (ftell(datain) FL_TOEND || flags&FL_PARTIAL || 00969 !boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) { 00970 *ptr = '\0'; 00971 fprintf (dataout, "%s\n", line); 00972 } 00973 else { 00974 *ptr = '\0'; 00975 fprintf (dataout, "%s", line); 00976 } 00977 } 00978 return UURET_OK; 00979 } 00980 00981 /* 00982 * Decode a single field using method. For the moment, this supports 00983 * Base64 and Quoted Printable only, to support RFC 1522 header decoding. 00984 * Quit when seeing the RFC 1522 ?= end marker. 00985 */ 00986 00987 int 00988 UUDecodeField (char *s, char *d, int method) 00989 { 00990 int z1, z2, z3, z4; 00991 int count=0; 00992 00993 if (method == B64ENCODED) { 00994 while ((z1 = B64xlat[ACAST(*s)]) != -1) { 00995 if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break; 00996 if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break; 00997 if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break; 00998 00999 d[count++] = (z1 << 2) | (z2 >> 4); 01000 d[count++] = (z2 << 4) | (z3 >> 2); 01001 d[count++] = (z3 << 6) | (z4); 01002 01003 s+=4; 01004 } 01005 if (z1 != -1 && z2 != -1 && *(s+2) == '=') { 01006 d[count++] = (z1 << 2) | (z2 >> 4); 01007 s+=2; 01008 } 01009 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') { 01010 d[count++] = (z1 << 2) | (z2 >> 4); 01011 d[count++] = (z2 << 4) | (z3 >> 2); 01012 s+=3; 01013 } 01014 } 01015 else if (method == QP_ENCODED) { 01016 while (*s && (*s != '?' || *(s+1) != '=')) { 01017 while (*s && *s != '=' && (*s != '?' || *(s+1) != '=')) { 01018 d[count++] = *s++; 01019 } 01020 if (*s == '=') { 01021 if (isxdigit ((unsigned char)*(s+1)) && isxdigit ((unsigned char)*(s+2))) { 01022 d[count] = (isdigit ((unsigned char)*(s+1)) ? (*(s+1)-'0') : (tolower (*(s+1))-'a'+10)) << 4; 01023 d[count] |= (isdigit ((unsigned char)*(s+2)) ? (*(s+2)-'0') : (tolower (*(s+2))-'a'+10)); 01024 count++; 01025 s+=3; 01026 } 01027 else if (*(s+1) == '\012' || *(s+1) == '\015') { 01028 s+=2; 01029 } 01030 else { 01031 d[count++] = *s++; 01032 } 01033 } 01034 } 01035 } 01036 else { 01037 return -1; 01038 } 01039 01040 d[count] = '\0'; 01041 return count; 01042 } 01043 01044 int 01045 UUDecodePart (FILE *datain, FILE *dataout, int *state, 01046 long maxpos, int method, int flags, 01047 char *boundary) 01048 { 01049 char *line = uugen_fnbuffer; 01050 int line_len = UUGEN_FNBUFFER_LEN; 01051 char *oline=uuncdp_oline; 01052 int warning=0, vlc=0, lc[2], hadct=0; 01053 int tc=0, tf=0, vflag, haddata=0, haddh=0; 01054 long yefilesize=0, yepartends=0; 01055 crc32_t yepartcrc=crc32(0L, Z_NULL, 0); 01056 static crc32_t yefilecrc=0; 01057 static int bhflag=0; 01058 size_t count=0; 01059 size_t yepartsize=0; 01060 char *ptr; 01061 01062 if (datain == NULL || dataout == NULL) { 01063 yefilecrc = crc32(0L, Z_NULL, 0); 01064 bhflag = 0; 01065 return UURET_OK; 01066 } 01067 01068 /* 01069 * Use specialized functions for QP_ENCODED and PT_ENCODED plaintext 01070 */ 01071 01072 if (method == QP_ENCODED) 01073 return UUDecodeQP (datain, dataout, state, maxpos, 01074 method, flags, boundary); 01075 else if (method == PT_ENCODED) 01076 return UUDecodePT (datain, dataout, state, maxpos, 01077 method, flags, boundary); 01078 01079 lc[0] = lc[1] = 0; 01080 vflag = 0; 01081 01082 uulboundary = -1; 01083 01084 if (method == YENC_ENCODED) { 01085 *state = BEGIN; 01086 } 01087 01088 while (!feof (datain) && *state != DONE && 01089 (ftell(datain) FL_TOEND || maxpos==-1 || 01090 (!(flags&FL_PROPER) && uu_fast_scanning))) { 01091 if (_FP_fgets (line, line_len, datain) == NULL) 01092 break; 01093 01094 if (ferror (datain)) { 01095 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01096 uustring (S_SOURCE_READ_ERR), 01097 strerror (uu_errno = errno)); 01098 return UURET_IOERR; 01099 } 01100 01101 if (line[0]=='\015' || line[0]=='\012') { /* Empty line? */ 01102 if (*state == DATA && 01103 (method == UU_ENCODED || method == XX_ENCODED)) 01104 *state = END; 01105 01106 /* 01107 * if we had a whole block of valid lines before, we reset our 01108 * 'valid data' flag, tf. Without this 'if', we'd break decoding 01109 * files with interleaved blank lines. The value of 5 is chosen 01110 * quite arbitrarly. 01111 */ 01112 01113 if (vlc > 5) 01114 tf = tc = 0; 01115 vlc = 0; 01116 continue; 01117 } 01118 01119 /* 01120 * Busy Polls 01121 */ 01122 01123 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) { 01124 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE, 01125 uustring (S_DECODE_CANCEL)); 01126 return UURET_CANCEL; 01127 } 01128 01129 /* 01130 * try to make sense of data 01131 */ 01132 01133 line[255] = '\0'; /* For Safety of string functions */ 01134 count = 0; 01135 01136 if (boundary && line[0]=='-' && line[1]=='-' && 01137 strncmp (line+2, boundary, strlen (boundary)) == 0) { 01138 if (line[strlen(boundary)+2]=='-') 01139 uulboundary = 1; 01140 else 01141 uulboundary = 0; 01142 return UURET_OK; 01143 } 01144 01145 /* 01146 * Use this pseudo-handling only if !FL_PROPER 01147 */ 01148 01149 if ((flags&FL_PROPER) == 0) { 01150 if (strncmp (line, "BEGIN", 5) == 0 && 01151 _FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */ 01152 tc = tf = vlc = 0; 01153 continue; 01154 } 01155 /* MIME body boundary */ 01156 if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) { 01157 if ((haddata || tc) && (haddh || hadct)) { 01158 *state = DONE; 01159 vlc = 0; 01160 lc[0] = lc[1] = 0; 01161 continue; 01162 } 01163 hadct = 0; 01164 haddh = 1; 01165 continue; 01166 } 01167 if (_FP_strnicmp (line, "Content-Type", 12) == 0) 01168 hadct = 1; 01169 } 01170 01171 if (*state == BEGIN) { 01172 if ((method == UU_ENCODED || method == XX_ENCODED) && 01173 (strncmp (line, "begin ", 6) == 0 || 01174 _FP_strnicmp (line, " begin ", 11) == 0)) { /* for LYNX */ 01175 *state = DATA; 01176 continue; 01177 } 01178 else if (method == BH_ENCODED && line[0] == ':') { 01179 if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) { 01180 bhflag = 0; 01181 *state = DATA; 01182 } 01183 else 01184 continue; 01185 } 01186 else if (method == YENC_ENCODED && 01187 strncmp (line, "=ybegin ", 8) == 0 && 01188 _FP_strstr (line, " name=") != NULL) { 01189 *state = DATA; 01190 01191 if ((ptr = _FP_strstr (line, " size=")) != NULL) { 01192 ptr += 6; 01193 yefilesize = atoi (ptr); 01194 } 01195 else { 01196 yefilesize = -1; 01197 } 01198 01199 if (_FP_strstr (line, " part=") != NULL) { 01200 if (_FP_fgets (line, line_len, datain) == NULL) { 01201 break; 01202 } 01203 01204 if ((ptr = _FP_strstr (line, " end=")) == NULL) { 01205 break; 01206 } 01207 01208 yepartends = atoi (ptr + 5); 01209 } 01210 tf = 1; 01211 continue; 01212 } 01213 else { 01214 continue; 01215 } 01216 01217 tc = tf = vlc = 0; 01218 lc[0] = lc[1] = 0; 01219 } 01220 else if ((*state == END) && 01221 (method == UU_ENCODED || method == XX_ENCODED)) { 01222 if (strncmp (line, "end", 3) == 0) { 01223 *state = DONE; 01224 break; 01225 } 01226 } 01227 01228 if (*state == DATA && method == YENC_ENCODED && 01229 strncmp (line, "=yend ", 6) == 0) { 01230 if ((ptr = _FP_strstr (line, " pcrc32=")) != NULL) { 01231 crc32_t pcrc32 = strtoul (ptr + 8, NULL, 16); 01232 if (pcrc32 != yepartcrc) { 01233 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01234 uustring (S_PCRC_MISMATCH), progress.curfile, progress.partno); 01235 } 01236 } 01237 if ((ptr = _FP_strstr (line, " crc32=")) != NULL) 01238 { 01239 crc32_t fcrc32 = strtoul (ptr + 7, NULL, 16); 01240 if (fcrc32 != yefilecrc) { 01241 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01242 uustring (S_CRC_MISMATCH), progress.curfile); 01243 } 01244 } 01245 if ((ptr = _FP_strstr (line, " size=")) != NULL) 01246 { 01247 size_t size = atol(ptr + 6); 01248 if (size != yepartsize && yefilesize != -1) { 01249 if (size != yefilesize) 01250 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01251 uustring (S_PSIZE_MISMATCH), progress.curfile, 01252 progress.partno, yepartsize, size); 01253 else 01254 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01255 uustring (S_SIZE_MISMATCH), progress.curfile, 01256 yepartsize, size); 01257 } 01258 } 01259 if (yepartends == 0 || yepartends >= yefilesize) { 01260 *state = DONE; 01261 } 01262 break; 01263 } 01264 01265 if (*state == DATA || *state == END) { 01266 if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) { 01267 break; 01268 } 01269 01270 if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0) 01271 vflag = UURepairData (datain, line, (tf)?method:0, &bhflag); 01272 01273 /* 01274 * correct XX/UUencoded lines that were declared Base64 01275 */ 01276 01277 if ((method == XX_ENCODED || method == UU_ENCODED) && 01278 vflag == B64ENCODED) { 01279 if (UUValidData (line, method, &bhflag) == method) 01280 vflag = method; 01281 } 01282 01283 if (vflag == method) { 01284 if (tf) { 01285 count = UUDecodeLine (line, oline, method); 01286 if (method == YENC_ENCODED) { 01287 if (yepartends) 01288 yepartcrc = crc32(yepartcrc, (unsigned char*)oline, count); 01289 yefilecrc = crc32(yefilecrc, (unsigned char*)oline, count); 01290 yepartsize += count; 01291 } 01292 vlc++; lc[1]++; 01293 } 01294 else if (tc == 3) { 01295 count = UUDecodeLine (save[0], oline, method); 01296 count += UUDecodeLine (save[1], oline + count, method); 01297 count += UUDecodeLine (save[2], oline + count, method); 01298 count += UUDecodeLine (line, oline + count, method); 01299 tf = 1; 01300 tc = 0; 01301 01302 /* 01303 * complain if we had one or two invalid lines amidst of 01304 * correctly encoded data. This usually means that the 01305 * file is in error 01306 */ 01307 01308 if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) { 01309 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01310 uustring (S_DATA_SUSPICIOUS)); 01311 warning=1; 01312 } 01313 lc[0] = 0; 01314 lc[1] = 3; 01315 } 01316 else { 01317 _FP_strncpy (save[tc++], line, 256); 01318 } 01319 01320 if (method == UU_ENCODED) 01321 *state = (line[0] == 'M') ? DATA : END; 01322 else if (method == XX_ENCODED) 01323 *state = (line[0] == 'h') ? DATA : END; 01324 else if (method == B64ENCODED) 01325 *state = (strchr (line, '=') == NULL) ? DATA : DONE; 01326 else if (method == BH_ENCODED) 01327 *state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE; 01328 } 01329 else { 01330 vlc = tf = tc = 0; 01331 haddh = 0; 01332 lc[0]++; 01333 } 01334 } 01335 else if (*state != DONE) { 01336 return UURET_NOEND; 01337 } 01338 01339 if (count) { 01340 if (method == BH_ENCODED) { 01341 if (UUbhwrite (oline, 1, count, dataout) != count) { 01342 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01343 uustring (S_WR_ERR_TEMP), 01344 strerror (uu_errno = errno)); 01345 return UURET_IOERR; 01346 } 01347 } 01348 else if (fwrite (oline, 1, count, dataout) != count) { 01349 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01350 uustring (S_WR_ERR_TEMP), 01351 strerror (uu_errno = errno)); 01352 return UURET_IOERR; 01353 } 01354 haddata++; 01355 count = 0; 01356 } 01357 } 01358 01359 if (*state == DONE || 01360 (*state == DATA && method == B64ENCODED && 01361 vflag == B64ENCODED && (flags&FL_PROPER || haddh))) { 01362 for (tf=0; tf01363 count += UUDecodeLine (save[tf], oline + count, method); 01364 if (count) { 01365 if (method == BH_ENCODED) { 01366 if (UUbhwrite (oline, 1, count, dataout) != count) { 01367 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01368 uustring (S_WR_ERR_TEMP), 01369 strerror (uu_errno = errno)); 01370 return UURET_IOERR; 01371 } 01372 } 01373 else if (fwrite (oline, 1, count, dataout) != count) { 01374 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01375 uustring (S_WR_ERR_TEMP), 01376 strerror (uu_errno = errno)); 01377 return UURET_IOERR; 01378 } 01379 } 01380 } 01381 return UURET_OK; 01382 } 01383 01384 /* 01385 * this function decodes the file into a temporary file 01386 */ 01387 01388 int 01389 UUDecode (uulist *data) 01390 { 01391 int state=BEGIN, part=-1, res=0, hb; 01392 long rsize, dsize, numbytes; 01393 FILE *datain, *dataout; 01394 unsigned char r[8]; 01395 char *mode, *ntmp, *template; 01396 uufile *iter; 01397 size_t bytes; 01398 int fd; 01399 01400 if (data == NULL || data->thisfile == NULL) 01401 return UURET_ILLVAL; 01402 01403 if (data->state & UUFILE_TMPFILE) 01404 return UURET_OK; 01405 01406 if (data->state & UUFILE_NODATA) 01407 return UURET_NODATA; 01408 01409 if (data->state & UUFILE_NOBEGIN) { 01410 if (!uu_desperate) 01411 return UURET_NODATA; 01412 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01413 uustring(S_DATA_SUSPICIOUS)); 01414 } 01415 01416 if (data->uudet == PT_ENCODED) 01417 mode = "wt"; /* open text files in text mode */ 01418 else 01419 mode = "wb"; /* otherwise in binary */ 01420 01421 01422 template = g_build_filename (g_get_tmp_dir(), "uuXXXXXX", NULL); 01423 data->binfile = strdup (template); 01424 #ifdef _MSC_VER 01425 fd = create_temp_file (data->binfile, 0600); 01426 #else 01427 fd = g_mkstemp (data->binfile); 01428 #endif 01429 g_free (template); 01430 01431 if (fd == -1) { 01432 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01433 uustring (S_NO_TEMP_NAME)); 01434 _FP_free (data->binfile); 01435 data->binfile = NULL; 01436 uu_errno = errno; 01437 return UURET_NOMEM; 01438 } 01439 01440 if ((dataout = fdopen (fd, mode)) == NULL) { 01441 /* 01442 * we couldn't create a temporary file. Usually this means that TMP 01443 * and TEMP aren't set 01444 */ 01445 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01446 uustring (S_WR_ERR_TARGET), 01447 data->binfile, strerror (uu_errno = errno)); 01448 _FP_free (data->binfile); 01449 data->binfile = NULL; 01450 uu_errno = errno; 01451 return UURET_IOERR; 01452 } 01453 /* 01454 * we don't have begin lines in Base64 or plain text files. 01455 */ 01456 if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED || 01457 data->uudet == PT_ENCODED) 01458 state = DATA; 01459 01460 /* 01461 * If we know that the file does not have a begin, we simulate 01462 * it in desperate mode 01463 */ 01464 01465 if ((data->state & UUFILE_NOBEGIN) && uu_desperate) { 01466 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, uustring(S_DATA_SUSPICIOUS)); 01467 state = DATA; 01468 } 01469 01470 (void) UUDecodeLine (NULL, NULL, 0); /* init */ 01471 (void) UUbhwrite (NULL, 0, 0, NULL); /* dito */ 01472 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* yep */ 01473 01474 /* 01475 * initialize progress information 01476 */ 01477 progress.action = 0; 01478 if (data->filename != NULL) { 01479 _FP_strncpy (progress.curfile, 01480 (strlen(data->filename)>255)? 01481 (data->filename+strlen(data->filename)-255):data->filename, 01482 256); 01483 } 01484 else { 01485 _FP_strncpy (progress.curfile, 01486 (strlen(data->binfile)>255)? 01487 (data->binfile+strlen(data->binfile)-255):data->binfile, 01488 256); 01489 } 01490 progress.partno = 0; 01491 progress.numparts = 0; 01492 progress.fsize = -1; 01493 progress.percent = 0; 01494 progress.action = UUACT_DECODING; 01495 01496 iter = data->thisfile; 01497 while (iter) { 01498 progress.numparts = (iter->partno)?iter->partno:1; 01499 iter = iter->NEXT; 01500 } 01501 01502 /* 01503 * let's rock! 01504 */ 01505 01506 iter = data->thisfile; 01507 while (iter) { 01508 01509 if (part==-1 && iter->partno!=1) 01510 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, "Missing everything before part #%d", iter->partno); 01511 if (part!=-1 && iter->partno!=part+1) { 01512 if (!uu_desperate) 01513 break; 01514 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01515 uustring(S_PART_MISSING), part); 01516 } 01517 part = iter->partno; 01518 01519 if (iter->data->sfname == NULL) { 01520 iter = iter->NEXT; 01521 continue; 01522 } 01523 01524 /* 01525 * call our FileCallback to retrieve the file 01526 */ 01527 01528 if (uu_FileCallback) { 01529 if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, 01530 uugen_fnbuffer, 1)) != UURET_OK) 01531 break; 01532 if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) { 01533 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, 01534 uugen_fnbuffer, 0); 01535 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01536 uustring (S_NOT_OPEN_FILE), 01537 uugen_fnbuffer, strerror (uu_errno = errno)); 01538 res = UURET_IOERR; 01539 break; 01540 } 01541 } 01542 else { 01543 if ((datain = fopen (iter->data->sfname, "rb")) == NULL) { 01544 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01545 uustring (S_NOT_OPEN_FILE), 01546 iter->data->sfname, strerror (uu_errno = errno)); 01547 res = UURET_IOERR; 01548 break; 01549 } 01550 UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE, 01551 uustring (S_OPEN_FILE), 01552 iter->data->sfname); 01553 _FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024); 01554 } 01555 01556 progress.partno = part; 01557 progress.fsize = (iter->data->length)?iter->data->length:-1; 01558 progress.percent = 0; 01559 progress.foffset = iter->data->startpos; 01560 01561 fseek (datain, iter->data->startpos, SEEK_SET); 01562 res = UUDecodePart (datain, dataout, &state, 01563 iter->data->startpos+iter->data->length, 01564 data->uudet, iter->data->flags, NULL); 01565 fclose (datain); 01566 01567 if (uu_FileCallback) 01568 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0); 01569 01570 if (state == DONE || res != UURET_OK) 01571 break; 01572 01573 iter = iter->NEXT; 01574 } 01575 01576 if (state == DATA && 01577 (data->uudet == B64ENCODED || data->uudet == QP_ENCODED || 01578 data->uudet == PT_ENCODED)) 01579 state = DONE; /* assume we're done */ 01580 01581 if (fclose (dataout)) { 01582 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01583 uustring (S_WR_ERR_TEMP), 01584 strerror (uu_errno = errno)); 01585 res = UURET_IOERR; 01586 } 01587 01588 if (res != UURET_OK || (state != DONE && !uu_desperate)) { 01589 unlink (data->binfile); 01590 _FP_free (data->binfile); 01591 data->binfile = NULL; 01592 data->state &= ~UUFILE_TMPFILE; 01593 data->state |= UUFILE_ERROR; 01594 01595 if (res == UURET_OK && state != DONE) 01596 res = UURET_NOEND; 01597 } 01598 else if (res != UURET_OK) { 01599 data->state &= ~UUFILE_DECODED; 01600 data->state |= UUFILE_ERROR | UUFILE_TMPFILE; 01601 } 01602 else { 01603 data->state &= ~UUFILE_ERROR; 01604 data->state |= UUFILE_TMPFILE; 01605 } 01606 01607 /* 01608 * If this was a BinHex file, we must extract its data or resource fork 01609 */ 01610 01611 if (data->uudet == BH_ENCODED && data->binfile) 01612 { 01613 char * template = g_build_filename (g_get_tmp_dir(), "uuXXXXXX", NULL); 01614 ntmp = strdup (template); 01615 fd = g_mkstemp (ntmp); 01616 g_free (template); 01617 01618 if (fd == -1) { 01619 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01620 uustring (S_NO_TEMP_NAME)); 01621 progress.action = 0; 01622 free (ntmp); 01623 return UURET_NOMEM; 01624 } 01625 if ((datain = fdopen (fd, "rb")) == NULL) { 01626 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01627 uustring (S_NOT_OPEN_FILE), 01628 data->binfile, strerror (uu_errno = errno)); 01629 progress.action = 0; 01630 free (ntmp); 01631 return UURET_IOERR; 01632 } 01633 if ((dataout = fopen (ntmp, "wb")) == NULL) { 01634 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01635 uustring (S_NOT_OPEN_TARGET), 01636 ntmp, strerror (uu_errno = errno)); 01637 progress.action = 0; 01638 fclose (datain); 01639 free (ntmp); 01640 return UURET_IOERR; 01641 } 01642 /* 01643 * read fork lengths. remember they're in Motorola format 01644 */ 01645 r[0] = fgetc (datain); 01646 hb = (int) r[0] + 22; 01647 fseek (datain, (int) r[0] + 12, SEEK_SET); 01648 fread (r, 1, 8, datain); 01649 01650 dsize = (((long) 1 << 24) * (long) r[0]) + 01651 (((long) 1 << 16) * (long) r[1]) + 01652 (((long) 1 << 8) * (long) r[2]) + 01653 ( (long) r[3]); 01654 rsize = (((long) 1 << 24) * (long) r[4]) + 01655 (((long) 1 << 16) * (long) r[5]) + 01656 (((long) 1 << 8) * (long) r[6]) + 01657 ( (long) r[7]); 01658 01659 UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE, 01660 uustring (S_BINHEX_SIZES), 01661 dsize, rsize); 01662 01663 if (dsize == 0) { 01664 fseek (datain, dsize + hb + 2, SEEK_SET); 01665 numbytes = rsize; 01666 } 01667 else if (rsize == 0) { 01668 fseek (datain, hb, SEEK_SET); 01669 numbytes = dsize; 01670 } 01671 else { 01672 /* we should let the user have the choice here */ 01673 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE, 01674 uustring (S_BINHEX_BOTH)); 01675 fseek (datain, hb, SEEK_SET); 01676 numbytes = dsize; 01677 } 01678 01679 progress.action = 0; 01680 progress.partno = 0; 01681 progress.numparts = 1; 01682 progress.fsize = (numbytes)?numbytes:-1; 01683 progress.foffset = hb; 01684 progress.percent = 0; 01685 progress.action = UUACT_COPYING; 01686 01687 /* 01688 * copy the chosen fork 01689 */ 01690 01691 while (!feof (datain) && numbytes) { 01692 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) { 01693 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE, 01694 uustring (S_DECODE_CANCEL)); 01695 fclose (datain); 01696 fclose (dataout); 01697 unlink (ntmp); 01698 free (ntmp); 01699 return UURET_CANCEL; 01700 } 01701 01702 bytes = fread (uugen_inbuffer, 1, 01703 (size_t) ((numbytes>1024)?1024:numbytes), datain); 01704 01705 if (ferror (datain) || (bytes == 0 && !feof (datain))) { 01706 progress.action = 0; 01707 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01708 uustring (S_SOURCE_READ_ERR), 01709 data->binfile, strerror (uu_errno = errno)); 01710 fclose (datain); 01711 fclose (dataout); 01712 unlink (ntmp); 01713 free (ntmp); 01714 return UURET_IOERR; 01715 } 01716 if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) { 01717 progress.action = 0; 01718 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01719 uustring (S_WR_ERR_TARGET), 01720 ntmp, strerror (uu_errno = errno)); 01721 fclose (datain); 01722 fclose (dataout); 01723 unlink (ntmp); 01724 free (ntmp); 01725 return UURET_IOERR; 01726 } 01727 numbytes -= bytes; 01728 } 01729 01730 if (numbytes) { 01731 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01732 uustring (S_SHORT_BINHEX), 01733 (data->filename)?data->filename: 01734 (data->subfname)?data->subfname:"???", 01735 numbytes); 01736 } 01737 01738 /* 01739 * replace temp file 01740 */ 01741 01742 fclose (datain); 01743 if (fclose (dataout)) { 01744 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, 01745 uustring (S_WR_ERR_TARGET), 01746 ntmp, strerror (uu_errno = errno)); 01747 unlink (ntmp); 01748 free (ntmp); 01749 return UURET_IOERR; 01750 } 01751 01752 if (unlink (data->binfile)) { 01753 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING, 01754 uustring (S_TMP_NOT_REMOVED), 01755 data->binfile, strerror (uu_errno = errno)); 01756 } 01757 01758 free (data->binfile); 01759 data->binfile = ntmp; 01760 } 01761 01762 progress.action = 0; 01763 return res; 01764 } 01765 01766 /* 01767 * QuickDecode for proper MIME attachments. We expect the pointer to 01768 * be on the first header line. 01769 */ 01770 01771 int 01772 UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos) 01773 { 01774 int state=BEGIN, encoding=-1; 01775 headers myenv; 01776 01777 /* 01778 * Read header and find out about encoding. 01779 */ 01780 01781 memset (&myenv, 0, sizeof (headers)); 01782 UUScanHeader (datain, &myenv); 01783 01784 if (_FP_stristr (myenv.ctenc, "uu") != NULL) 01785 encoding = UU_ENCODED; 01786 else if (_FP_stristr (myenv.ctenc, "xx") != NULL) 01787 encoding = XX_ENCODED; 01788 else if (_FP_stricmp (myenv.ctenc, "base64") == 0) 01789 encoding = B64ENCODED; 01790 else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0) 01791 encoding = QP_ENCODED; 01792 else 01793 encoding = PT_ENCODED; 01794 01795 UUkillheaders (&myenv); 01796 01797 /* 01798 * okay, so decode this one 01799 */ 01800 01801 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* init */ 01802 return UUDecodePart (datain, dataout, &state, maxpos, 01803 encoding, FL_PROPER|FL_TOEND, 01804 boundary); 01805 }