ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uunconc.c
Revision: 1.3.2.4
Committed: Thu Nov 6 13:08:24 2003 UTC (20 years, 7 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-19
Changes since 1.3.2.3: +81 -4 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of uudeview, the simple and friendly multi-part multi-
3 * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
4 * be contacted at fp@fpx.de
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17 /*
18 * These are the functions that are responsible for decoding. The
19 * original idea is from a freeware utility called "uunconc", and
20 * few lines of this code may still bear a remote resemblance to
21 * its code. If you are the author or know him, contact me.
22 * This program could only decode one multi-part, uuencoded file
23 * where the parts were in order. Base64, XX and BinHex decoding,
24 * support for multi-files and part-ordering covered by myself.
25 **/
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #ifdef SYSTEM_WINDLL
32 #include <windows.h>
33 #endif
34 #ifdef SYSTEM_OS2
35 #include <os2.h>
36 #endif
37
38 #include <stdio.h>
39 #include <ctype.h>
40
41 #ifdef STDC_HEADERS
42 #include <stdlib.h>
43 #include <string.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #ifdef HAVE_ERRNO_H
49 #include <errno.h>
50 #endif
51
52 #include <crc32.h>
53 #include <uudeview.h>
54 #include <uuint.h>
55 #include <fptools.h>
56 #include <uustring.h>
57
58 char * uunconc_id = "$Id: uunconc.c,v 1.36 2003/09/29 23:17:35 fp Exp $";
59
60 /* for braindead systems */
61 #ifndef SEEK_SET
62 #ifdef L_BEGIN
63 #define SEEK_SET L_BEGIN
64 #else
65 #define SEEK_SET 0
66 #endif
67 #endif
68
69 /*
70 * decoder states
71 */
72
73 #define BEGIN (1)
74 #define DATA (2)
75 #define END (3)
76 #define DONE (4)
77
78 /*
79 * mallocable areas
80 */
81
82 char *uunconc_UUxlat;
83 char *uunconc_UUxlen;
84 char *uunconc_B64xlat;
85 char *uunconc_XXxlat;
86 char *uunconc_BHxlat;
87 char *uunconc_save;
88
89 /*
90 * decoding translation tables and line length table
91 */
92
93 static int * UUxlen; /* initialized in UUInitConc() */
94 static int * UUxlat; /* from the malloc'ed areas above */
95 static int * B64xlat;
96 static int * XXxlat;
97 static int * BHxlat;
98
99 /*
100 * buffer for decoding
101 */
102
103 static char *save[3];
104
105 /*
106 * mallocable areas
107 */
108
109 char *uuncdl_fulline;
110 char *uuncdp_oline;
111
112 /*
113 * Return information for QuickDecode
114 */
115
116 static int uulboundary;
117
118 /*
119 * To prevent warnings when using a char as index into an array
120 */
121
122 #define ACAST(s) ((int)(unsigned char)(s))
123
124 /*
125 * Initialize decoding tables
126 */
127
128 void
129 UUInitConc (void)
130 {
131 int i, j;
132
133 /*
134 * Update pointers
135 */
136 UUxlen = (int *) uunconc_UUxlen;
137 UUxlat = (int *) uunconc_UUxlat;
138 B64xlat = (int *) uunconc_B64xlat;
139 XXxlat = (int *) uunconc_XXxlat;
140 BHxlat = (int *) uunconc_BHxlat;
141
142 save[0] = uunconc_save;
143 save[1] = uunconc_save + 256;
144 save[2] = uunconc_save + 512;
145
146 /* prepare decoding translation table */
147 for(i = 0; i < 256; i++)
148 UUxlat[i] = B64xlat[i] = XXxlat[i] = BHxlat[i] = -1;
149
150 /*
151 * At some time I received a file which used lowercase characters for
152 * uuencoding. This shouldn't be, but let's accept it. Must take special
153 * care that this doesn't break xxdecoding. This is giving me quite a
154 * headache. If this one file hadn't been a Pocahontas picture, I might
155 * have ignored it for good.
156 */
157
158 for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
159 UUxlat[i] /* = UUxlat[i+64] */ = j;
160 for (i = '`', j = 0; i < '`' + 32; i++, j++)
161 UUxlat[i] = j;
162
163 /* add special cases */
164 UUxlat['`'] = UUxlat[' '];
165 UUxlat['~'] = UUxlat['^'];
166
167 /* prepare line length table */
168 UUxlen[0] = 1;
169 for(i = 1, j = 5; i <= 61; i += 3, j += 4)
170 UUxlen[i] = UUxlen[i+1] = UUxlen[i+2] = j;
171
172 /* prepare other tables */
173 for (i=0; i<64; i++) {
174 B64xlat[ACAST(B64EncodeTable[i])] = i;
175 XXxlat [ACAST(XXEncodeTable [i])] = i;
176 BHxlat [ACAST(BHEncodeTable [i])] = i;
177 }
178 }
179
180 /*
181 * Workaround for Netscape
182 */
183
184 /*
185 * Determines whether Netscape may have broken up a data line (by
186 * inserting a newline). This only seems to happen after <a in a
187 * href statement
188 */
189
190 int
191 UUBrokenByNetscape (char *string)
192 {
193 char *ptr;
194 int len;
195
196 if (string==NULL || (len=strlen(string))<3)
197 return 0;
198
199 if ((ptr = _FP_stristr (string, "<a href=")) != NULL) {
200 if (_FP_stristr (string, "</a>") > ptr)
201 return 2;
202 }
203
204 ptr = string + len;
205
206 while (len && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) {
207 ptr--; len--;
208 }
209 if (len<3) return 0;
210 if (*--ptr == ' ') ptr--;
211 ptr--;
212
213 if (_FP_strnicmp (ptr, "<a", 2) == 0)
214 return 1;
215
216 return 0;
217 }
218
219 /*
220 * Try to repair a Netscape-corrupted line of data.
221 * This must only be called on corrupted lines, since non-Netscape
222 * data may even _get_ corrupted by this procedure.
223 *
224 * Some checks are included multiply to speed up the procedure. For
225 * example: (*p1!='<' || strnicmp(p1,"</a>",4)). If the first expression
226 * becomes true, the costly function isn't called :-)
227 *
228 * Since '<', '>', '&' might even be replaced by their html equivalents
229 * in href strings, I'm now using two passes, the first one for &amp; + co,
230 * the second one for hrefs.
231 */
232
233 int
234 UUNetscapeCollapse (char *string)
235 {
236 char *p1=string, *p2=string;
237 int res = 0;
238
239 if (string==NULL)
240 return 0;
241
242 /*
243 * First pass
244 */
245 while (*p1) {
246 if (*p1 == '&') {
247 if (_FP_strnicmp (p1, "&amp;", 5) == 0) { p1+=5; *p2++='&'; res=1; }
248 else if (_FP_strnicmp (p1, "&lt;", 4) == 0) { p1+=4; *p2++='<'; res=1; }
249 else if (_FP_strnicmp (p1, "&gt;", 4) == 0) { p1+=4; *p2++='>'; res=1; }
250 else *p2++ = *p1++;
251 }
252 else *p2++ = *p1++;
253 }
254 *p2 = '\0';
255 /*
256 * Second pass
257 */
258 p1 = p2 = string;
259
260 while (*p1) {
261 if (*p1 == '<') {
262 if ((_FP_strnicmp (p1, "<ahref=", 7) == 0 ||
263 _FP_strnicmp (p1, "<a href=",8) == 0) &&
264 (_FP_strstr (p1, "</a>") != 0 || _FP_strstr (p1, "</A>") != 0)) {
265 while (*p1 && *p1!='>') p1++;
266 if (*p1=='\0' || *(p1+1)!='<') return 0;
267 p1++;
268 while (*p1 && (*p1!='<' || _FP_strnicmp(p1,"</a>",4)!=0)) {
269 *p2++ = *p1++;
270 }
271 if (_FP_strnicmp(p1,"</a>",4) != 0)
272 return 0;
273 p1+=4;
274 res=1;
275 }
276 else
277 *p2++ = *p1++;
278 }
279 else
280 *p2++ = *p1++;
281 }
282 *p2 = '\0';
283
284 return res;
285 }
286
287 /*
288 * The second parameter is 0 if we are still searching for encoded data,
289 * otherwise it indicates the encoding we're using right now. If we're
290 * still in the searching stage, we must be a little more strict in
291 * deciding for or against encoding; there's too much plain text looking
292 * like encoded data :-(
293 */
294
295 int
296 UUValidData (char *ptr, int encoding, int *bhflag)
297 {
298 int i=0, j, len=0, suspicious=0, flag=0;
299 char *s = ptr;
300
301 if ((s == NULL) || (*s == '\0')) {
302 return 0; /* bad string */
303 }
304
305 while (*s && *s!='\012' && *s!='\015') {
306 s++;
307 len++;
308 i++;
309 }
310
311 if (i == 0)
312 return 0;
313
314 switch (encoding) {
315 case UU_ENCODED:
316 goto _t_UU;
317 case XX_ENCODED:
318 goto _t_XX;
319 case B64ENCODED:
320 goto _t_B64;
321 case BH_ENCODED:
322 goto _t_Binhex;
323 case YENC_ENCODED:
324 return YENC_ENCODED;
325 }
326
327 _t_Binhex: /* Binhex Test */
328 len = i; s = ptr;
329
330 /*
331 * bhflag notes the state we're in. Within the data, it's 1. If we're
332 * still looking for the initial :, it's 0
333 */
334 if (*bhflag == 0 && *s != ':') {
335 if (encoding==BH_ENCODED) return 0;
336 goto _t_B64;
337 }
338 else if (*bhflag == 0 /* *s == ':' */) {
339 s++; len--;
340 }
341
342 while (len && BHxlat[ACAST(*s)] != -1) {
343 len--; s++;
344 }
345
346 /* allow space characters at the end of the line if we are sure */
347 /* that this is Binhex encoded data or the line was long enough */
348
349 flag = (*s == ':') ? 0 : 1;
350
351 if (*s == ':' && len>0) {
352 s++; len--;
353 }
354 if (((i>=60 && len<=10) || encoding) && *s==' ') {
355 while (len && *s==' ') {
356 s++; len--;
357 }
358 }
359
360 /*
361 * BinHex data shall have exactly 64 characters (except the last
362 * line). We ignore everything with less than 40 characters to
363 * be flexible
364 */
365
366 if (len != 0 || (flag && i < 40)) {
367 if (encoding==BH_ENCODED) return 0;
368 goto _t_B64;
369 }
370
371 *bhflag = flag;
372
373 return BH_ENCODED;
374
375 _t_B64: /* Base64 Test */
376 len = i; s = ptr;
377
378 /*
379 * Face it: there _are_ Base64 lines that are not a multiple of four
380 * in length :-(
381 *
382 * if (len%4)
383 * goto _t_UU;
384 */
385
386 while (len--) {
387 if (*s < 0 || (B64xlat[ACAST(*s)] == -1 && *s != '=')) {
388 /* allow space characters at the end of the line if we are sure */
389 /* that this is Base64 encoded data or the line was long enough */
390 if (((i>=60 && len<=10) || encoding) && *s++==' ') {
391 while (*s==' ' && len) s++;
392 if (len==0) return B64ENCODED;
393 }
394 if (encoding==B64ENCODED) return 0;
395 goto _t_UU;
396 }
397 else if (*s == '=') { /* special case at end */
398 /* if we know this is B64encoded, allow spaces at end of line */
399 s++;
400 if (*s=='=' && len>=1) {
401 len--; s++;
402 }
403 if (encoding && len && *s==' ') {
404 while (len && *s==' ') {
405 s++; len--;
406 }
407 }
408 if (len != 0) {
409 if (encoding==B64ENCODED) return 0;
410 goto _t_UU;
411 }
412 return B64ENCODED;
413 }
414 s++;
415 }
416 return B64ENCODED;
417
418 _t_UU:
419 len = i; s = ptr;
420
421 if (UUxlat[ACAST(*s)] == -1) { /* uutest */
422 if (encoding==UU_ENCODED) return 0;
423 goto _t_XX;
424 }
425
426 j = UUxlen[UUxlat[ACAST(*s)]];
427
428 if (len-1 == j) /* remove trailing character */
429 len--;
430 if (len != j) {
431 switch (UUxlat[ACAST(*s)]%3) {
432 case 1:
433 if (j-2 == len) j-=2;
434 break;
435 case 2:
436 if (j-1 == len) j-=1;
437 break;
438 }
439 }
440
441 /*
442 * some encoders are broken with respect to encoding the last line of
443 * a file and produce extraoneous characters beyond the expected EOL
444 * So were not too picky here about the last line, as long as it's longer
445 * than necessary and shorter than the maximum
446 * this tolerance broke the xxdecoding, because xxencoded data was
447 * detected as being uuencoded :( so don't accept 'h' as first character
448 * also, if the first character is lowercase, don't accept the line to
449 * have space characters. the only encoder I've heard of which uses
450 * lowercase characters at least accepts the special case of encoding
451 * 0 as `. The strchr() shouldn't be too expensive here as it's only
452 * evaluated if the first character is lowercase, which really shouldn't
453 * be in uuencoded text.
454 */
455 if (len != j &&
456 ((ptr[0] == '-' && ptr[1] == '-' && strstr(ptr,"part")!=NULL) ||
457 !(*ptr != 'M' && *ptr != 'h' &&
458 len > j && len <= UUxlen[UUxlat['M']]))) {
459 if (encoding==UU_ENCODED) return 0;
460 goto _t_XX; /* bad length */
461 }
462
463 if (len != j || islower (*ptr)) {
464 /*
465 * if we are not in a 'uuencoded' state, don't allow the line to have
466 * space characters at all. if we know we _are_ decoding uuencoded
467 * data, the rest of the line, beyond the length of encoded data, may
468 * have spaces.
469 */
470 if (encoding != UU_ENCODED)
471 if (strchr (ptr, ' ') != NULL)
472 goto _t_XX;
473
474 /* suspicious = 1; we're careful here REMOVED 0.4.15 __FP__ */
475 len = j;
476 }
477
478 while (len--) {
479 if (*s < 0 || UUxlat[ACAST(*s++)] < 0) {
480 if (encoding==UU_ENCODED) return 0;
481 goto _t_XX; /* bad code character */
482 }
483 if (*s == ' ' && suspicious) {
484 if (encoding==UU_ENCODED) return 0;
485 goto _t_XX; /* this line looks _too_ suspicious */
486 }
487 }
488 return UU_ENCODED; /* data is valid */
489
490 _t_XX: /* XX Test */
491 len = i; s = ptr;
492
493 if (XXxlat[ACAST(*s)] == -1)
494 return 0;
495
496 j = UUxlen[XXxlat[ACAST(*s)]]; /* Same line length table as UUencoding */
497
498 if (len-1 == j) /* remove trailing character */
499 len--;
500 if (len != j)
501 switch (UUxlat[ACAST(*s)]%3) {
502 case 1:
503 if (j-2 == len) j-=2;
504 break;
505 case 2:
506 if (j-1 == len) j-=1;
507 break;
508 }
509 /*
510 * some encoders are broken with respect to encoding the last line of
511 * a file and produce extraoneous characters beyond the expected EOL
512 * So were not too picky here about the last line, as long as it's longer
513 * than necessary and shorter than the maximum
514 */
515 if (len != j && !(*ptr != 'h' && len > j && len <= UUxlen[UUxlat['h']]))
516 return 0; /* bad length */
517
518 while(len--) {
519 if(*s < 0 || XXxlat[ACAST(*s++)] < 0) {
520 return 0; /* bad code character */
521 }
522 }
523 return XX_ENCODED; /* data is valid */
524 }
525
526 /*
527 * This function may be called upon a line that does not look like
528 * valid encoding on first sight, but might be erroneously encoded
529 * data from Netscape, Lynx or MS Exchange. We might need to read
530 * a new line from the stream, which is why we need the FILE.
531 * Returns the type of encoded data if successful or 0 otherwise.
532 */
533
534 int
535 UURepairData (FILE *datei, char *line, int encoding, int *bhflag)
536 {
537 int nflag, vflag=0, safety=42;
538 char *ptr;
539
540 nflag = UUBrokenByNetscape (line);
541
542 while (vflag == 0 && nflag && safety--) {
543 if (nflag == 1) { /* need next line to repair */
544 if (strlen (line) > 250)
545 break;
546 ptr = line + strlen (line);
547 while (ptr>line && (*(ptr-1)=='\015' || *(ptr-1)=='\012'))
548 ptr--;
549 if (_FP_fgets (ptr, 255-(ptr-line), datei) == NULL)
550 break;
551 }
552 else { /* don't need next line to repair */
553 }
554 if (UUNetscapeCollapse (line)) {
555 if ((vflag = UUValidData (line, encoding, bhflag)) == 0)
556 nflag = UUBrokenByNetscape (line);
557 }
558 else
559 nflag = 0;
560 }
561 /*
562 * Sometimes, a line is garbled even without it being split into
563 * the next line. Then we try this in our despair
564 */
565 if (vflag == 0) {
566 if (UUNetscapeCollapse (line))
567 vflag = UUValidData (line, encoding, bhflag);
568 }
569
570 /*
571 * If this line looks uuencoded, but the line is one character short
572 * of a valid line, it was probably broken by MS Exchange. According
573 * to my test cases, there is at most one space character missing;
574 * there are never two spaces together.
575 * If adding a space character helps making this line uuencoded, do
576 * it!
577 */
578
579 if (vflag == 0) {
580 ptr = line + strlen(line);
581 while (ptr>line && (*(ptr-1)=='\012' || *(ptr-1)=='\015')) {
582 ptr--;
583 }
584 *ptr++ = ' ';
585 *ptr-- = '\0';
586 if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) {
587 *ptr = '\0';
588 vflag = 0;
589 }
590 }
591 return vflag;
592 }
593
594 /*
595 * Decode a single encoded line using method
596 */
597
598 size_t
599 UUDecodeLine (char *s, char *d, int method)
600 {
601 int i, j, c, cc, count=0, z1, z2, z3, z4;
602 static int leftover=0;
603 int *table;
604
605 /*
606 * for re-initialization
607 */
608
609 if (s == NULL || d == NULL) {
610 leftover = 0;
611 return 0;
612 }
613
614 /*
615 * To shut up gcc -Wall
616 */
617 z1 = z2 = z3 = z4 = 0;
618
619 if (method == UU_ENCODED || method == XX_ENCODED) {
620 if (method == UU_ENCODED)
621 table = UUxlat;
622 else
623 table = XXxlat;
624
625 i = table [ACAST(*s++)];
626 j = UUxlen[i] - 1;
627
628 while(j > 0) {
629 c = table[ACAST(*s++)] << 2;
630 cc = table[ACAST(*s++)];
631 c |= (cc >> 4);
632
633 if(i-- > 0)
634 d[count++] = c;
635
636 cc <<= 4;
637 c = table[ACAST(*s++)];
638 cc |= (c >> 2);
639
640 if(i-- > 0)
641 d[count++] = cc;
642
643 c <<= 6;
644 c |= table[ACAST(*s++)];
645
646 if(i-- > 0)
647 d[count++] = c;
648
649 j -= 4;
650 }
651 }
652 else if (method == B64ENCODED) {
653 if (leftover) {
654 strcpy (uuncdl_fulline+leftover, s);
655 leftover = 0;
656 s = uuncdl_fulline;
657 }
658
659 while ((z1 = B64xlat[ACAST(*s)]) != -1) {
660 if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
661 if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
662 if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
663
664 d[count++] = (z1 << 2) | (z2 >> 4);
665 d[count++] = (z2 << 4) | (z3 >> 2);
666 d[count++] = (z3 << 6) | (z4);
667
668 s += 4;
669 }
670 if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
671 d[count++] = (z1 << 2) | (z2 >> 4);
672 s+=2;
673 }
674 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
675 d[count++] = (z1 << 2) | (z2 >> 4);
676 d[count++] = (z2 << 4) | (z3 >> 2);
677 s+=3;
678 }
679 while (B64xlat[ACAST(*s)] != -1)
680 uuncdl_fulline[leftover++] = *s++;
681 }
682 else if (method == BH_ENCODED) {
683 if (leftover) {
684 strcpy (uuncdl_fulline+leftover, s);
685 leftover = 0;
686 s = uuncdl_fulline;
687 }
688 else if (*s == ':')
689 s++;
690
691 while ((z1 = BHxlat[ACAST(*s)]) != -1) {
692 if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break;
693 if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break;
694 if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break;
695
696 d[count++] = (z1 << 2) | (z2 >> 4);
697 d[count++] = (z2 << 4) | (z3 >> 2);
698 d[count++] = (z3 << 6) | (z4);
699
700 s += 4;
701 }
702 if (z1 != -1 && z2 != -1 && *(s+2) == ':') {
703 d[count++] = (z1 << 2) | (z2 >> 4);
704 s+=2;
705 }
706 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') {
707 d[count++] = (z1 << 2) | (z2 >> 4);
708 d[count++] = (z2 << 4) | (z3 >> 2);
709 s+=3;
710 }
711 while (BHxlat[ACAST(*s)] != -1)
712 uuncdl_fulline[leftover++] = *s++;
713 }
714 else if (method == YENC_ENCODED) {
715 while (*s) {
716 if (*s == '=') {
717 if (*++s != '\0') {
718 d[count++] = (char) ((int) *s - 64 - 42);
719 s++;
720 }
721 }
722 else if (*s == '\n' || *s == '\r') {
723 s++; /* ignore */
724 }
725 else {
726 d[count++] = (char) ((int) *s++ - 42);
727 }
728 }
729 }
730
731 return count;
732 }
733
734 /*
735 * ``Decode'' Quoted-Printable text
736 */
737
738 int
739 UUDecodeQP (FILE *datain, FILE *dataout, int *state,
740 long maxpos, int method, int flags,
741 char *boundary)
742 {
743 char *line=uugen_inbuffer, *p1, *p2;
744 int val;
745
746 uulboundary = -1;
747
748 while (!feof (datain) &&
749 (ftell(datain)<maxpos || flags&FL_TOEND ||
750 (!(flags&FL_PROPER) && uu_fast_scanning))) {
751 if (_FP_fgets (line, 255, datain) == NULL)
752 break;
753 if (ferror (datain)) {
754 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
755 uustring (S_SOURCE_READ_ERR),
756 strerror (uu_errno = errno));
757 return UURET_IOERR;
758 }
759 line[255] = '\0';
760
761 if (boundary && line[0]=='-' && line[1]=='-' &&
762 strncmp (line+2, boundary, strlen (boundary)) == 0) {
763 if (line[strlen(boundary)+2]=='-')
764 uulboundary = 1;
765 else
766 uulboundary = 0;
767 return UURET_OK;
768 }
769
770 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
771 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
772 uustring (S_DECODE_CANCEL));
773 return UURET_CANCEL;
774 }
775
776 p1 = p2 = line;
777
778 while (*p2) {
779 while (*p2 && *p2 != '=')
780 p2++;
781 if (*p2 == '\0')
782 break;
783 *p2 = '\0';
784 fprintf (dataout, "%s", p1);
785 p1 = ++p2;
786
787 if (isxdigit (*p2) && isxdigit (*(p2+1))) {
788 val = ((isdigit(*p2)) ? (*p2-'0') : (tolower(*p2)-'a'+10)) << 4;
789 val |= ((isdigit(*(p2+1)))?(*(p2+1)-'0') : (tolower(*(p2+1))-'a'+10));
790
791 fputc (val, dataout);
792 p2 += 2;
793 p1 = p2;
794 }
795 else if (*p2 == '\012' || *(p2+1) == '\015') {
796 /* soft line break */
797 *p2 = '\0';
798 break;
799 }
800 else {
801 /* huh? */
802 fputc ('=', dataout);
803 }
804 }
805 /*
806 * p2 points to a nullbyte right after the CR/LF/CRLF
807 */
808 val = 0;
809 while (p2>p1 && isspace (*(p2-1))) {
810 if (*(p2-1) == '\012' || *(p2-1) == '\015')
811 val = 1;
812 p2--;
813 }
814 *p2 = '\0';
815
816 /*
817 * If the part ends directly after this line, the data does not end
818 * with a linebreak. Or, as the docs put it, "the CRLF preceding the
819 * encapsulation line is conceptually attached to the boundary.
820 * So if the part ends here, don't print a line break"
821 */
822 if (val && (!feof (datain) &&
823 (ftell(datain)<maxpos || flags&FL_TOEND ||
824 (!(flags&FL_PROPER) && uu_fast_scanning))))
825 fprintf (dataout, "%s\n", p1);
826 else
827 fprintf (dataout, "%s", p1);
828 }
829 return UURET_OK;
830 }
831
832 /*
833 * ``Decode'' plain text. Our job is to properly handle the EOL sequence
834 */
835
836 int
837 UUDecodePT (FILE *datain, FILE *dataout, int *state,
838 long maxpos, int method, int flags,
839 char *boundary)
840 {
841 char *line=uugen_inbuffer, *ptr;
842
843 uulboundary = -1;
844
845 while (!feof (datain) &&
846 (ftell(datain)<maxpos || flags&FL_TOEND ||
847 (!(flags&FL_PROPER) && uu_fast_scanning))) {
848 if (_FP_fgets (line, 255, datain) == NULL)
849 break;
850 if (ferror (datain)) {
851 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
852 uustring (S_SOURCE_READ_ERR),
853 strerror (uu_errno = errno));
854 return UURET_IOERR;
855 }
856 line[255] = '\0';
857
858 if (boundary && line[0]=='-' && line[1]=='-' &&
859 strncmp (line+2, boundary, strlen (boundary)) == 0) {
860 if (line[strlen(boundary)+2]=='-')
861 uulboundary = 1;
862 else
863 uulboundary = 0;
864 return UURET_OK;
865 }
866
867 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
868 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
869 uustring (S_DECODE_CANCEL));
870 return UURET_CANCEL;
871 }
872
873 ptr = line + strlen (line);
874
875 while (ptr>line && (*(ptr-1) == '\012' || *(ptr-1) == '\015'))
876 ptr--;
877
878
879 /*
880 * If the part ends directly after this line, the data does not end
881 * with a linebreak. Or, as the docs put it, "the CRLF preceding the
882 * encapsulation line is conceptually attached to the boundary.
883 * So if the part ends here, don't print a line break"
884 */
885 if ((*ptr == '\012' || *ptr == '\015') &&
886 (ftell(datain)<maxpos || flags&FL_TOEND || flags&FL_PARTIAL ||
887 !boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) {
888 *ptr = '\0';
889 fprintf (dataout, "%s\n", line);
890 }
891 else {
892 *ptr = '\0';
893 fprintf (dataout, "%s", line);
894 }
895 }
896 return UURET_OK;
897 }
898
899 /*
900 * Decode a single field using method. For the moment, this supports
901 * Base64 and Quoted Printable only, to support RFC 1522 header decoding.
902 * Quit when seeing the RFC 1522 ?= end marker.
903 */
904
905 int
906 UUDecodeField (char *s, char *d, int method)
907 {
908 int z1, z2, z3, z4;
909 int count=0;
910
911 if (method == B64ENCODED) {
912 while ((z1 = B64xlat[ACAST(*s)]) != -1) {
913 if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
914 if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
915 if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
916
917 d[count++] = (z1 << 2) | (z2 >> 4);
918 d[count++] = (z2 << 4) | (z3 >> 2);
919 d[count++] = (z3 << 6) | (z4);
920
921 s+=4;
922 }
923 if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
924 d[count++] = (z1 << 2) | (z2 >> 4);
925 s+=2;
926 }
927 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
928 d[count++] = (z1 << 2) | (z2 >> 4);
929 d[count++] = (z2 << 4) | (z3 >> 2);
930 s+=3;
931 }
932 }
933 else if (method == QP_ENCODED) {
934 while (*s && (*s != '?' || *(s+1) != '=')) {
935 while (*s && *s != '=' && (*s != '?' || *(s+1) != '=')) {
936 d[count++] = *s++;
937 }
938 if (*s == '=') {
939 if (isxdigit (*(s+1)) && isxdigit (*(s+2))) {
940 d[count] = (isdigit (*(s+1)) ? (*(s+1)-'0') : (tolower (*(s+1))-'a'+10)) << 4;
941 d[count] |= (isdigit (*(s+2)) ? (*(s+2)-'0') : (tolower (*(s+2))-'a'+10));
942 count++;
943 s+=3;
944 }
945 else if (*(s+1) == '\012' || *(s+1) == '\015') {
946 s+=2;
947 }
948 else {
949 d[count++] = *s++;
950 }
951 }
952 }
953 }
954 else {
955 return -1;
956 }
957
958 d[count] = '\0';
959 return count;
960 }
961
962 int
963 UUDecodePart (FILE *datain, FILE *dataout, int *state,
964 long maxpos, int method, int flags,
965 char *boundary)
966 {
967 char *line=uugen_fnbuffer, *oline=uuncdp_oline;
968 int warning=0, vlc=0, lc[2], hadct=0;
969 int tc=0, tf=0, vflag, haddata=0, haddh=0;
970 long yefilesize=0, yepartends=0;
971 crc32_t yepartcrc=crc32(0L, Z_NULL, 0);
972 static crc32_t yefilecrc=0;
973 static int bhflag=0;
974 size_t count=0;
975 size_t yepartsize=0;
976 char *ptr;
977
978 if (datain == NULL || dataout == NULL) {
979 yefilecrc = crc32(0L, Z_NULL, 0);
980 bhflag = 0;
981 return UURET_OK;
982 }
983
984 /*
985 * Use specialized functions for QP_ENCODED and PT_ENCODED plaintext
986 */
987
988 if (method == QP_ENCODED)
989 return UUDecodeQP (datain, dataout, state, maxpos,
990 method, flags, boundary);
991 else if (method == PT_ENCODED)
992 return UUDecodePT (datain, dataout, state, maxpos,
993 method, flags, boundary);
994
995 lc[0] = lc[1] = 0;
996 vflag = 0;
997
998 uulboundary = -1;
999
1000 if (method == YENC_ENCODED) {
1001 *state = BEGIN;
1002 }
1003
1004 while (!feof (datain) && *state != DONE &&
1005 (ftell(datain)<maxpos || flags&FL_TOEND || maxpos==-1 ||
1006 (!(flags&FL_PROPER) && uu_fast_scanning))) {
1007 if (_FP_fgets (line, 299, datain) == NULL)
1008 break;
1009
1010 if (ferror (datain)) {
1011 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1012 uustring (S_SOURCE_READ_ERR),
1013 strerror (uu_errno = errno));
1014 return UURET_IOERR;
1015 }
1016
1017 if (line[0]=='\015' || line[0]=='\012') { /* Empty line? */
1018 if (*state == DATA &&
1019 (method == UU_ENCODED || method == XX_ENCODED))
1020 *state = END;
1021
1022 /*
1023 * if we had a whole block of valid lines before, we reset our
1024 * 'valid data' flag, tf. Without this 'if', we'd break decoding
1025 * files with interleaved blank lines. The value of 5 is chosen
1026 * quite arbitrarly.
1027 */
1028
1029 if (vlc > 5)
1030 tf = tc = 0;
1031 vlc = 0;
1032 continue;
1033 }
1034
1035 /*
1036 * Busy Polls
1037 */
1038
1039 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
1040 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1041 uustring (S_DECODE_CANCEL));
1042 return UURET_CANCEL;
1043 }
1044
1045 /*
1046 * try to make sense of data
1047 */
1048
1049 line[299] = '\0'; /* For Safety of string functions */
1050 count = 0;
1051
1052 if (boundary && line[0]=='-' && line[1]=='-' &&
1053 strncmp (line+2, boundary, strlen (boundary)) == 0) {
1054 if (line[strlen(boundary)+2]=='-')
1055 uulboundary = 1;
1056 else
1057 uulboundary = 0;
1058 return UURET_OK;
1059 }
1060
1061 /*
1062 * Use this pseudo-handling only if !FL_PROPER
1063 */
1064
1065 if ((flags&FL_PROPER) == 0) {
1066 if (strncmp (line, "BEGIN", 5) == 0 &&
1067 _FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */
1068 tc = tf = vlc = 0;
1069 continue;
1070 }
1071 /* MIME body boundary */
1072 if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) {
1073 if ((haddata || tc) && (haddh || hadct)) {
1074 *state = DONE;
1075 vlc = 0;
1076 lc[0] = lc[1] = 0;
1077 continue;
1078 }
1079 hadct = 0;
1080 haddh = 1;
1081 continue;
1082 }
1083 if (_FP_strnicmp (line, "Content-Type", 12) == 0)
1084 hadct = 1;
1085 }
1086
1087 if (*state == BEGIN) {
1088 if ((method == UU_ENCODED || method == XX_ENCODED) &&
1089 (strncmp (line, "begin ", 6) == 0 ||
1090 _FP_strnicmp (line, "<pre>begin ", 11) == 0)) { /* for LYNX */
1091 *state = DATA;
1092 continue;
1093 }
1094 else if (method == BH_ENCODED && line[0] == ':') {
1095 if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) {
1096 bhflag = 0;
1097 *state = DATA;
1098 }
1099 else
1100 continue;
1101 }
1102 else if (method == YENC_ENCODED &&
1103 strncmp (line, "=ybegin ", 8) == 0 &&
1104 _FP_strstr (line, " name=") != NULL) {
1105 *state = DATA;
1106
1107 if ((ptr = _FP_strstr (line, " size=")) != NULL) {
1108 ptr += 6;
1109 yefilesize = atoi (ptr);
1110 }
1111 else {
1112 yefilesize = -1;
1113 }
1114
1115 if (_FP_strstr (line, " part=") != NULL) {
1116 if (_FP_fgets (line, 299, datain) == NULL) {
1117 break;
1118 }
1119
1120 if ((ptr = _FP_strstr (line, " end=")) == NULL) {
1121 break;
1122 }
1123
1124 yepartends = atoi (ptr + 5);
1125 }
1126 tf = 1;
1127 continue;
1128 }
1129 else {
1130 continue;
1131 }
1132
1133 tc = tf = vlc = 0;
1134 lc[0] = lc[1] = 0;
1135 }
1136 else if ((*state == END) &&
1137 (method == UU_ENCODED || method == XX_ENCODED)) {
1138 if (strncmp (line, "end", 3) == 0) {
1139 *state = DONE;
1140 break;
1141 }
1142 }
1143
1144 if (*state == DATA && method == YENC_ENCODED &&
1145 strncmp (line, "=yend ", 6) == 0) {
1146 if ((ptr = _FP_strstr (line, " pcrc32=")) != NULL) {
1147 crc32_t pcrc32 = strtoul (ptr + 8, NULL, 16);
1148 if (pcrc32 != yepartcrc) {
1149 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1150 uustring (S_PCRC_MISMATCH), progress.curfile, progress.partno);
1151 }
1152 }
1153 if ((ptr = _FP_strstr (line, " crc32=")) != NULL)
1154 {
1155 crc32_t fcrc32 = strtoul (ptr + 7, NULL, 16);
1156 if (fcrc32 != yefilecrc) {
1157 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1158 uustring (S_CRC_MISMATCH), progress.curfile);
1159 }
1160 }
1161 if ((ptr = _FP_strstr (line, " size=")) != NULL)
1162 {
1163 size_t size = atol(ptr + 6);
1164 if (size != yepartsize && yefilesize != -1) {
1165 if (size != yefilesize)
1166 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1167 uustring (S_PSIZE_MISMATCH), progress.curfile,
1168 progress.partno, yepartsize, size);
1169 else
1170 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1171 uustring (S_SIZE_MISMATCH), progress.curfile,
1172 yepartsize, size);
1173 }
1174 }
1175 if (yepartends == 0 || yepartends >= yefilesize) {
1176 *state = DONE;
1177 }
1178 break;
1179 }
1180
1181 if (*state == DATA || *state == END) {
1182 if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) {
1183 break;
1184 }
1185
1186 if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0)
1187 vflag = UURepairData (datain, line, (tf)?method:0, &bhflag);
1188
1189 /*
1190 * correct XX/UUencoded lines that were declared Base64
1191 */
1192
1193 if ((method == XX_ENCODED || method == UU_ENCODED) &&
1194 vflag == B64ENCODED) {
1195 if (UUValidData (line, method, &bhflag) == method)
1196 vflag = method;
1197 }
1198
1199 if (vflag == method) {
1200 if (tf) {
1201 count = UUDecodeLine (line, oline, method);
1202 if (method == YENC_ENCODED) {
1203 if (yepartends)
1204 yepartcrc = crc32(yepartcrc, oline, count);
1205 yefilecrc = crc32(yefilecrc, oline, count);
1206 yepartsize += count;
1207 }
1208 vlc++; lc[1]++;
1209 }
1210 else if (tc == 3) {
1211 count = UUDecodeLine (save[0], oline, method);
1212 count += UUDecodeLine (save[1], oline + count, method);
1213 count += UUDecodeLine (save[2], oline + count, method);
1214 count += UUDecodeLine (line, oline + count, method);
1215 tf = 1;
1216 tc = 0;
1217
1218 /*
1219 * complain if we had one or two invalid lines amidst of
1220 * correctly encoded data. This usually means that the
1221 * file is in error
1222 */
1223
1224 if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) {
1225 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1226 uustring (S_DATA_SUSPICIOUS));
1227 warning=1;
1228 }
1229 lc[0] = 0;
1230 lc[1] = 3;
1231 }
1232 else {
1233 _FP_strncpy (save[tc++], line, 256);
1234 }
1235
1236 if (method == UU_ENCODED)
1237 *state = (line[0] == 'M') ? DATA : END;
1238 else if (method == XX_ENCODED)
1239 *state = (line[0] == 'h') ? DATA : END;
1240 else if (method == B64ENCODED)
1241 *state = (strchr (line, '=') == NULL) ? DATA : DONE;
1242 else if (method == BH_ENCODED)
1243 *state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE;
1244 }
1245 else {
1246 vlc = tf = tc = 0;
1247 haddh = 0;
1248 lc[0]++;
1249 }
1250 }
1251 else if (*state != DONE) {
1252 return UURET_NOEND;
1253 }
1254
1255 if (count) {
1256 if (method == BH_ENCODED) {
1257 if (UUbhwrite (oline, 1, count, dataout) != count) {
1258 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1259 uustring (S_WR_ERR_TEMP),
1260 strerror (uu_errno = errno));
1261 return UURET_IOERR;
1262 }
1263 }
1264 else if (fwrite (oline, 1, count, dataout) != count) {
1265 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1266 uustring (S_WR_ERR_TEMP),
1267 strerror (uu_errno = errno));
1268 return UURET_IOERR;
1269 }
1270 haddata++;
1271 count = 0;
1272 }
1273 }
1274
1275 if (*state == DONE ||
1276 (*state == DATA && method == B64ENCODED &&
1277 vflag == B64ENCODED && (flags&FL_PROPER || haddh))) {
1278 for (tf=0; tf<tc; tf++)
1279 count += UUDecodeLine (save[tf], oline + count, method);
1280 if (count) {
1281 if (method == BH_ENCODED) {
1282 if (UUbhwrite (oline, 1, count, dataout) != count) {
1283 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1284 uustring (S_WR_ERR_TEMP),
1285 strerror (uu_errno = errno));
1286 return UURET_IOERR;
1287 }
1288 }
1289 else if (fwrite (oline, 1, count, dataout) != count) {
1290 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1291 uustring (S_WR_ERR_TEMP),
1292 strerror (uu_errno = errno));
1293 return UURET_IOERR;
1294 }
1295 }
1296 }
1297 return UURET_OK;
1298 }
1299
1300 /*
1301 * this function decodes the file into a temporary file
1302 */
1303
1304 int
1305 UUDecode (uulist *data)
1306 {
1307 int state=BEGIN, part=-1, res=0, hb;
1308 long rsize, dsize, numbytes;
1309 FILE *datain, *dataout;
1310 unsigned char r[8];
1311 char *mode, *ntmp;
1312 uufile *iter;
1313 size_t bytes;
1314
1315 if (data == NULL || data->thisfile == NULL)
1316 return UURET_ILLVAL;
1317
1318 if (data->state & UUFILE_TMPFILE)
1319 return UURET_OK;
1320
1321 if (data->state & UUFILE_NODATA)
1322 return UURET_NODATA;
1323
1324 if (data->state & UUFILE_NOBEGIN && !uu_desperate)
1325 return UURET_NODATA;
1326
1327 if (data->uudet == PT_ENCODED)
1328 mode = "wt"; /* open text files in text mode */
1329 else
1330 mode = "wb"; /* otherwise in binary */
1331
1332 if ((data->binfile = tempnam (NULL, "uu")) == NULL) {
1333 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1334 uustring (S_NO_TEMP_NAME));
1335 return UURET_NOMEM;
1336 }
1337
1338 if ((dataout = fopen (data->binfile, mode)) == NULL) {
1339 /*
1340 * we couldn't create a temporary file. Usually this means that TMP
1341 * and TEMP aren't set
1342 */
1343 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1344 uustring (S_WR_ERR_TARGET),
1345 data->binfile, strerror (uu_errno = errno));
1346 _FP_free (data->binfile);
1347 data->binfile = NULL;
1348 uu_errno = errno;
1349 return UURET_IOERR;
1350 }
1351 /*
1352 * we don't have begin lines in Base64 or plain text files.
1353 */
1354 if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1355 data->uudet == PT_ENCODED)
1356 state = DATA;
1357
1358 /*
1359 * If we know that the file does not have a begin, we simulate
1360 * it in desperate mode
1361 */
1362
1363 if ((data->state & UUFILE_NOBEGIN) && uu_desperate)
1364 state = DATA;
1365
1366 (void) UUDecodeLine (NULL, NULL, 0); /* init */
1367 (void) UUbhwrite (NULL, 0, 0, NULL); /* dito */
1368 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* yep */
1369
1370 /*
1371 * initialize progress information
1372 */
1373 progress.action = 0;
1374 if (data->filename != NULL) {
1375 _FP_strncpy (progress.curfile,
1376 (strlen(data->filename)>255)?
1377 (data->filename+strlen(data->filename)-255):data->filename,
1378 256);
1379 }
1380 else {
1381 _FP_strncpy (progress.curfile,
1382 (strlen(data->binfile)>255)?
1383 (data->binfile+strlen(data->binfile)-255):data->binfile,
1384 256);
1385 }
1386 progress.partno = 0;
1387 progress.numparts = 0;
1388 progress.fsize = -1;
1389 progress.percent = 0;
1390 progress.action = UUACT_DECODING;
1391
1392 iter = data->thisfile;
1393 while (iter) {
1394 progress.numparts = (iter->partno)?iter->partno:1;
1395 iter = iter->NEXT;
1396 }
1397
1398 /*
1399 * let's rock!
1400 */
1401
1402 iter = data->thisfile;
1403 while (iter) {
1404 if (part != -1 && iter->partno != part+1 && !uu_desperate)
1405 break;
1406 else
1407 part = iter->partno;
1408
1409 if (iter->data->sfname == NULL) {
1410 iter = iter->NEXT;
1411 continue;
1412 }
1413
1414 /*
1415 * call our FileCallback to retrieve the file
1416 */
1417
1418 if (uu_FileCallback) {
1419 if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1420 uugen_fnbuffer, 1)) != UURET_OK)
1421 break;
1422 if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) {
1423 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1424 uugen_fnbuffer, 0);
1425 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1426 uustring (S_NOT_OPEN_FILE),
1427 uugen_fnbuffer, strerror (uu_errno = errno));
1428 res = UURET_IOERR;
1429 break;
1430 }
1431 }
1432 else {
1433 if ((datain = fopen (iter->data->sfname, "rb")) == NULL) {
1434 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1435 uustring (S_NOT_OPEN_FILE),
1436 iter->data->sfname, strerror (uu_errno = errno));
1437 res = UURET_IOERR;
1438 break;
1439 }
1440 _FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
1441 }
1442
1443 progress.partno = part;
1444 progress.fsize = (iter->data->length)?iter->data->length:-1;
1445 progress.percent = 0;
1446 progress.foffset = iter->data->startpos;
1447
1448 fseek (datain, iter->data->startpos, SEEK_SET);
1449 res = UUDecodePart (datain, dataout, &state,
1450 iter->data->startpos+iter->data->length,
1451 data->uudet, iter->data->flags, NULL);
1452 fclose (datain);
1453
1454 if (uu_FileCallback)
1455 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0);
1456
1457 if (state == DONE || res != UURET_OK)
1458 break;
1459
1460 iter = iter->NEXT;
1461 }
1462
1463 if (state == DATA &&
1464 (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1465 data->uudet == PT_ENCODED))
1466 state = DONE; /* assume we're done */
1467
1468 if (fclose (dataout)) {
1469 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1470 uustring (S_WR_ERR_TEMP),
1471 strerror (uu_errno = errno));
1472 res = UURET_IOERR;
1473 }
1474
1475 if (res != UURET_OK || (state != DONE && !uu_desperate)) {
1476 unlink (data->binfile);
1477 _FP_free (data->binfile);
1478 data->binfile = NULL;
1479 data->state &= ~UUFILE_TMPFILE;
1480 data->state |= UUFILE_ERROR;
1481
1482 if (res == UURET_OK && state != DONE)
1483 res = UURET_NOEND;
1484 }
1485 else if (res != UURET_OK) {
1486 data->state &= ~UUFILE_DECODED;
1487 data->state |= UUFILE_ERROR | UUFILE_TMPFILE;
1488 }
1489 else {
1490 data->state &= ~UUFILE_ERROR;
1491 data->state |= UUFILE_TMPFILE;
1492 }
1493
1494 /*
1495 * If this was a BinHex file, we must extract its data or resource fork
1496 */
1497
1498 if (data->uudet == BH_ENCODED && data->binfile) {
1499 if ((ntmp = tempnam (NULL, "uu")) == NULL) {
1500 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1501 uustring (S_NO_TEMP_NAME));
1502 progress.action = 0;
1503 return UURET_NOMEM;
1504 }
1505 if ((datain = fopen (data->binfile, "rb")) == NULL) {
1506 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1507 uustring (S_NOT_OPEN_FILE),
1508 data->binfile, strerror (uu_errno = errno));
1509 progress.action = 0;
1510 free (ntmp);
1511 return UURET_IOERR;
1512 }
1513 if ((dataout = fopen (ntmp, "wb")) == NULL) {
1514 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1515 uustring (S_NOT_OPEN_TARGET),
1516 ntmp, strerror (uu_errno = errno));
1517 progress.action = 0;
1518 fclose (datain);
1519 free (ntmp);
1520 return UURET_IOERR;
1521 }
1522 /*
1523 * read fork lengths. remember they're in Motorola format
1524 */
1525 r[0] = fgetc (datain);
1526 hb = (int) r[0] + 22;
1527 fseek (datain, (int) r[0] + 12, SEEK_SET);
1528 fread (r, 1, 8, datain);
1529
1530 dsize = (((long) 1 << 24) * (long) r[0]) +
1531 (((long) 1 << 16) * (long) r[1]) +
1532 (((long) 1 << 8) * (long) r[2]) +
1533 ( (long) r[3]);
1534 rsize = (((long) 1 << 24) * (long) r[4]) +
1535 (((long) 1 << 16) * (long) r[5]) +
1536 (((long) 1 << 8) * (long) r[6]) +
1537 ( (long) r[7]);
1538
1539 UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE,
1540 uustring (S_BINHEX_SIZES),
1541 dsize, rsize);
1542
1543 if (dsize == 0) {
1544 fseek (datain, dsize + hb + 2, SEEK_SET);
1545 numbytes = rsize;
1546 }
1547 else if (rsize == 0) {
1548 fseek (datain, hb, SEEK_SET);
1549 numbytes = dsize;
1550 }
1551 else {
1552 /* we should let the user have the choice here */
1553 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1554 uustring (S_BINHEX_BOTH));
1555 fseek (datain, hb, SEEK_SET);
1556 numbytes = dsize;
1557 }
1558
1559 progress.action = 0;
1560 progress.partno = 0;
1561 progress.numparts = 1;
1562 progress.fsize = (numbytes)?numbytes:-1;
1563 progress.foffset = hb;
1564 progress.percent = 0;
1565 progress.action = UUACT_COPYING;
1566
1567 /*
1568 * copy the chosen fork
1569 */
1570
1571 while (!feof (datain) && numbytes) {
1572 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
1573 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1574 uustring (S_DECODE_CANCEL));
1575 fclose (datain);
1576 fclose (dataout);
1577 unlink (ntmp);
1578 free (ntmp);
1579 return UURET_CANCEL;
1580 }
1581
1582 bytes = fread (uugen_inbuffer, 1,
1583 (size_t) ((numbytes>1024)?1024:numbytes), datain);
1584
1585 if (ferror (datain) || (bytes == 0 && !feof (datain))) {
1586 progress.action = 0;
1587 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1588 uustring (S_SOURCE_READ_ERR),
1589 data->binfile, strerror (uu_errno = errno));
1590 fclose (datain);
1591 fclose (dataout);
1592 unlink (ntmp);
1593 free (ntmp);
1594 return UURET_IOERR;
1595 }
1596 if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) {
1597 progress.action = 0;
1598 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1599 uustring (S_WR_ERR_TARGET),
1600 ntmp, strerror (uu_errno = errno));
1601 fclose (datain);
1602 fclose (dataout);
1603 unlink (ntmp);
1604 free (ntmp);
1605 return UURET_IOERR;
1606 }
1607 numbytes -= bytes;
1608 }
1609
1610 if (numbytes) {
1611 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1612 uustring (S_SHORT_BINHEX),
1613 (data->filename)?data->filename:
1614 (data->subfname)?data->subfname:"???",
1615 numbytes);
1616 }
1617
1618 /*
1619 * replace temp file
1620 */
1621
1622 fclose (datain);
1623 if (fclose (dataout)) {
1624 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1625 uustring (S_WR_ERR_TARGET),
1626 ntmp, strerror (uu_errno = errno));
1627 unlink (ntmp);
1628 free (ntmp);
1629 return UURET_IOERR;
1630 }
1631
1632 if (unlink (data->binfile)) {
1633 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1634 uustring (S_TMP_NOT_REMOVED),
1635 data->binfile, strerror (uu_errno = errno));
1636 }
1637
1638 free (data->binfile);
1639 data->binfile = ntmp;
1640 }
1641
1642 progress.action = 0;
1643 return res;
1644 }
1645
1646 /*
1647 * QuickDecode for proper MIME attachments. We expect the pointer to
1648 * be on the first header line.
1649 */
1650
1651 int
1652 UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos)
1653 {
1654 int state=BEGIN, encoding=-1;
1655 headers myenv;
1656
1657 /*
1658 * Read header and find out about encoding.
1659 */
1660
1661 memset (&myenv, 0, sizeof (headers));
1662 UUScanHeader (datain, &myenv);
1663
1664 if (_FP_stristr (myenv.ctenc, "uu") != NULL)
1665 encoding = UU_ENCODED;
1666 else if (_FP_stristr (myenv.ctenc, "xx") != NULL)
1667 encoding = XX_ENCODED;
1668 else if (_FP_stricmp (myenv.ctenc, "base64") == 0)
1669 encoding = B64ENCODED;
1670 else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
1671 encoding = QP_ENCODED;
1672 else
1673 encoding = PT_ENCODED;
1674
1675 UUkillheaders (&myenv);
1676
1677 /*
1678 * okay, so decode this one
1679 */
1680
1681 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* init */
1682 return UUDecodePart (datain, dataout, &state, maxpos,
1683 encoding, FL_PROPER|FL_TOEND,
1684 boundary);
1685 }