ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uunconc.c
Revision: 1.14
Committed: Sat Mar 26 14:20:49 2005 UTC (19 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +1 -1 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$";
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)(uchar)(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 + 1200;
144 save[2] = uunconc_save + 2400;
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 res = 1;
252 }
253 else *p2++ = *p1++;
254 }
255 *p2 = '\0';
256 /*
257 * Second pass
258 */
259 p1 = p2 = string;
260
261 while (*p1) {
262 if (*p1 == '<') {
263 if ((_FP_strnicmp (p1, "<ahref=", 7) == 0 ||
264 _FP_strnicmp (p1, "<a href=",8) == 0) &&
265 (_FP_strstr (p1, "</a>") != 0 || _FP_strstr (p1, "</A>") != 0)) {
266 while (*p1 && *p1!='>') p1++;
267 if (*p1=='\0' || *(p1+1)!='<') return 0;
268 p1++;
269 while (*p1 && (*p1!='<' || _FP_strnicmp(p1,"</a>",4)!=0)) {
270 *p2++ = *p1++;
271 }
272 if (_FP_strnicmp(p1,"</a>",4) != 0)
273 return 0;
274 p1+=4;
275 res=1;
276 }
277 else
278 *p2++ = *p1++;
279 }
280 else
281 *p2++ = *p1++;
282 }
283 *p2 = '\0';
284
285 return res;
286 }
287
288 /*
289 * The second parameter is 0 if we are still searching for encoded data,
290 * otherwise it indicates the encoding we're using right now. If we're
291 * still in the searching stage, we must be a little more strict in
292 * deciding for or against encoding; there's too much plain text looking
293 * like encoded data :-(
294 */
295
296 int
297 UUValidData (char *ptr, int encoding, int *bhflag)
298 {
299 int i=0, j, len=0, suspicious=0, flag=0;
300 signed char *s = ptr;
301
302 if ((s == NULL) || (*s == '\0')) {
303 return 0; /* bad string */
304 }
305
306 while (*s && *s!='\012' && *s!='\015') {
307 s++;
308 len++;
309 i++;
310 }
311
312 if (i == 0)
313 return 0;
314
315 switch (encoding) {
316 case UU_ENCODED:
317 goto _t_UU;
318 case XX_ENCODED:
319 goto _t_XX;
320 case B64ENCODED:
321 goto _t_B64;
322 case BH_ENCODED:
323 goto _t_Binhex;
324 case YENC_ENCODED:
325 return YENC_ENCODED;
326 }
327
328 _t_Binhex: /* Binhex Test */
329 len = i; s = ptr;
330
331 /*
332 * bhflag notes the state we're in. Within the data, it's 1. If we're
333 * still looking for the initial :, it's 0
334 */
335 if (*bhflag == 0 && *s != ':') {
336 if (encoding==BH_ENCODED) return 0;
337 goto _t_B64;
338 }
339 else if (*bhflag == 0 /* *s == ':' */) {
340 s++; len--;
341 }
342
343 while (len && BHxlat[ACAST(*s)] != -1) {
344 len--; s++;
345 }
346
347 /* allow space characters at the end of the line if we are sure */
348 /* that this is Binhex encoded data or the line was long enough */
349
350 flag = (*s == ':') ? 0 : 1;
351
352 if (*s == ':' && len>0) {
353 s++; len--;
354 }
355 if (((i>=60 && len<=10) || encoding) && *s==' ') {
356 while (len && *s==' ') {
357 s++; len--;
358 }
359 }
360
361 /*
362 * BinHex data shall have exactly 64 characters (except the last
363 * line). We ignore everything with less than 40 characters to
364 * be flexible
365 */
366
367 if (len != 0 || (flag && i < 40)) {
368 if (encoding==BH_ENCODED) return 0;
369 goto _t_B64;
370 }
371
372 *bhflag = flag;
373
374 return BH_ENCODED;
375
376 _t_B64: /* Base64 Test */
377 len = i; s = ptr;
378
379 /*
380 * Face it: there _are_ Base64 lines that are not a multiple of four
381 * in length :-(
382 *
383 * if (len%4)
384 * goto _t_UU;
385 */
386
387 while (len--) {
388 if (*s < 0 || (B64xlat[ACAST(*s)] == -1 && *s != '=')) {
389 /* allow space characters at the end of the line if we are sure */
390 /* that this is Base64 encoded data or the line was long enough */
391 if (((i>=60 && len<=10) || encoding) && *s++==' ') {
392 while (*s==' ' && len) s++;
393 if (len==0) return B64ENCODED;
394 }
395 if (encoding==B64ENCODED) return 0;
396 goto _t_UU;
397 }
398 else if (*s == '=') { /* special case at end */
399 /* if we know this is B64encoded, allow spaces at end of line */
400 s++;
401 if (*s=='=' && len>=1) {
402 len--; s++;
403 }
404 if (encoding && len && *s==' ') {
405 while (len && *s==' ') {
406 s++; len--;
407 }
408 }
409 if (len != 0) {
410 if (encoding==B64ENCODED) return 0;
411 goto _t_UU;
412 }
413 return B64ENCODED;
414 }
415 s++;
416 }
417 return B64ENCODED;
418
419 _t_UU:
420 len = i; s = ptr;
421
422 if (UUxlat[ACAST(*s)] == -1) { /* uutest */
423 if (encoding==UU_ENCODED) return 0;
424 goto _t_XX;
425 }
426
427 j = UUxlen[UUxlat[ACAST(*s)]];
428
429 if (len-1 == j) /* remove trailing character */
430 len--;
431 if (len != j) {
432 switch (UUxlat[ACAST(*s)]%3) {
433 case 1:
434 if (j-2 == len) j-=2;
435 break;
436 case 2:
437 if (j-1 == len) j-=1;
438 break;
439 }
440 }
441
442 /*
443 * some encoders are broken with respect to encoding the last line of
444 * a file and produce extraoneous characters beyond the expected EOL
445 * So were not too picky here about the last line, as long as it's longer
446 * than necessary and shorter than the maximum
447 * this tolerance broke the xxdecoding, because xxencoded data was
448 * detected as being uuencoded :( so don't accept 'h' as first character
449 * also, if the first character is lowercase, don't accept the line to
450 * have space characters. the only encoder I've heard of which uses
451 * lowercase characters at least accepts the special case of encoding
452 * 0 as `. The strchr() shouldn't be too expensive here as it's only
453 * evaluated if the first character is lowercase, which really shouldn't
454 * be in uuencoded text.
455 */
456 if (len != j &&
457 ((ptr[0] == '-' && ptr[1] == '-' && strstr(ptr,"part")!=NULL) ||
458 !(*ptr != 'M' && *ptr != 'h' &&
459 len > j && len <= UUxlen[UUxlat['M']]))) {
460 if (encoding==UU_ENCODED) return 0;
461 goto _t_XX; /* bad length */
462 }
463
464 if (len != j || islower (*ptr)) {
465 /*
466 * if we are not in a 'uuencoded' state, don't allow the line to have
467 * space characters at all. if we know we _are_ decoding uuencoded
468 * data, the rest of the line, beyond the length of encoded data, may
469 * have spaces.
470 */
471 if (encoding != UU_ENCODED)
472 if (strchr (ptr, ' ') != NULL)
473 goto _t_XX;
474
475 /* suspicious = 1; we're careful here REMOVED 0.4.15 __FP__ */
476 len = j;
477 }
478
479 while (len--) {
480 if (*s < 0 || UUxlat[ACAST(*s++)] < 0) {
481 if (encoding==UU_ENCODED) return 0;
482 goto _t_XX; /* bad code character */
483 }
484 if (*s == ' ' && suspicious) {
485 if (encoding==UU_ENCODED) return 0;
486 goto _t_XX; /* this line looks _too_ suspicious */
487 }
488 }
489 return UU_ENCODED; /* data is valid */
490
491 _t_XX: /* XX Test */
492 len = i; s = ptr;
493
494 if (XXxlat[ACAST(*s)] == -1)
495 return 0;
496
497 j = UUxlen[XXxlat[ACAST(*s)]]; /* Same line length table as UUencoding */
498
499 if (len-1 == j) /* remove trailing character */
500 len--;
501 if (len != j)
502 switch (UUxlat[ACAST(*s)]%3) {
503 case 1:
504 if (j-2 == len) j-=2;
505 break;
506 case 2:
507 if (j-1 == len) j-=1;
508 break;
509 }
510 /*
511 * some encoders are broken with respect to encoding the last line of
512 * a file and produce extraoneous characters beyond the expected EOL
513 * So were not too picky here about the last line, as long as it's longer
514 * than necessary and shorter than the maximum
515 */
516 if (len != j && !(*ptr != 'h' && len > j && len <= UUxlen[UUxlat['h']]))
517 return 0; /* bad length */
518
519 while(len--) {
520 if(*s < 0 || XXxlat[ACAST(*s++)] < 0) {
521 return 0; /* bad code character */
522 }
523 }
524 return XX_ENCODED; /* data is valid */
525 }
526
527 /*
528 * This function may be called upon a line that does not look like
529 * valid encoding on first sight, but might be erroneously encoded
530 * data from Netscape, Lynx or MS Exchange. We might need to read
531 * a new line from the stream, which is why we need the FILE.
532 * Returns the type of encoded data if successful or 0 otherwise.
533 */
534
535 int
536 UURepairData (FILE *datei, char *line, int encoding, int *bhflag)
537 {
538 int nflag, vflag=0, safety=42;
539 char *ptr;
540
541 nflag = UUBrokenByNetscape (line);
542
543 while (vflag == 0 && nflag && safety--) {
544 if (nflag == 1) { /* need next line to repair */
545 if (strlen (line) > 250)
546 break;
547 ptr = line + strlen (line);
548 while (ptr>line && (*(ptr-1)=='\015' || *(ptr-1)=='\012'))
549 ptr--;
550 if (_FP_fgets (ptr, 299-(ptr-line), datei) == NULL)
551 break;
552 }
553 else { /* don't need next line to repair */
554 }
555 if (UUNetscapeCollapse (line)) {
556 if ((vflag = UUValidData (line, encoding, bhflag)) == 0)
557 nflag = UUBrokenByNetscape (line);
558 }
559 else
560 nflag = 0;
561 }
562 /*
563 * Sometimes, a line is garbled even without it being split into
564 * the next line. Then we try this in our despair
565 */
566 if (vflag == 0) {
567 if (UUNetscapeCollapse (line))
568 vflag = UUValidData (line, encoding, bhflag);
569 }
570
571 /*
572 * If this line looks uuencoded, but the line is one character short
573 * of a valid line, it was probably broken by MS Exchange. According
574 * to my test cases, there is at most one space character missing;
575 * there are never two spaces together.
576 * If adding a space character helps making this line uuencoded, do
577 * it!
578 */
579
580 if (vflag == 0) {
581 ptr = line + strlen(line);
582 while (ptr>line && (*(ptr-1)=='\012' || *(ptr-1)=='\015')) {
583 ptr--;
584 }
585 *ptr++ = ' ';
586 *ptr-- = '\0';
587 if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) {
588 *ptr = '\0';
589 vflag = 0;
590 }
591 }
592 return vflag;
593 }
594
595 /*
596 * Decode a single encoded line using method
597 */
598
599 size_t
600 UUDecodeLine (char *s, char *d, int method)
601 {
602 int i, j, c, cc, count=0, z1, z2, z3, z4;
603 static int leftover=0;
604 int *table;
605
606 /*
607 * for re-initialization
608 */
609
610 if (s == NULL || d == NULL) {
611 leftover = 0;
612 return 0;
613 }
614
615 /*
616 * To shut up gcc -Wall
617 */
618 z1 = z2 = z3 = z4 = 0;
619
620 if (method == UU_ENCODED || method == XX_ENCODED) {
621 if (method == UU_ENCODED)
622 table = UUxlat;
623 else
624 table = XXxlat;
625
626 i = table [ACAST(*s++)];
627 j = UUxlen[i] - 1;
628
629 while(j > 0) {
630 c = table[ACAST(*s++)] << 2;
631 cc = table[ACAST(*s++)];
632 c |= (cc >> 4);
633
634 if(i-- > 0)
635 d[count++] = c;
636
637 cc <<= 4;
638 c = table[ACAST(*s++)];
639 cc |= (c >> 2);
640
641 if(i-- > 0)
642 d[count++] = cc;
643
644 c <<= 6;
645 c |= table[ACAST(*s++)];
646
647 if(i-- > 0)
648 d[count++] = c;
649
650 j -= 4;
651 }
652 }
653 else if (method == B64ENCODED) {
654 if (leftover) {
655 strcpy (uuncdl_fulline + leftover, s);
656
657 leftover = 0;
658 s = uuncdl_fulline;
659 }
660
661 while ((z1 = B64xlat[ACAST(*s)]) != -1) {
662 if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
663 if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
664 if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
665
666 d[count++] = (z1 << 2) | (z2 >> 4);
667 d[count++] = (z2 << 4) | (z3 >> 2);
668 d[count++] = (z3 << 6) | (z4);
669
670 s += 4;
671 }
672 if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
673 d[count++] = (z1 << 2) | (z2 >> 4);
674 s+=2;
675 }
676 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
677 d[count++] = (z1 << 2) | (z2 >> 4);
678 d[count++] = (z2 << 4) | (z3 >> 2);
679 s+=3;
680 }
681 while (B64xlat[ACAST(*s)] != -1)
682 uuncdl_fulline[leftover++] = *s++;
683 }
684 else if (method == BH_ENCODED) {
685 if (leftover) {
686 strcpy (uuncdl_fulline + leftover, s);
687
688 leftover = 0;
689 s = uuncdl_fulline;
690 }
691 else if (*s == ':')
692 s++;
693
694 while ((z1 = BHxlat[ACAST(*s)]) != -1) {
695 if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break;
696 if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break;
697 if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break;
698
699 d[count++] = (z1 << 2) | (z2 >> 4);
700 d[count++] = (z2 << 4) | (z3 >> 2);
701 d[count++] = (z3 << 6) | (z4);
702
703 s += 4;
704 }
705 if (z1 != -1 && z2 != -1 && *(s+2) == ':') {
706 d[count++] = (z1 << 2) | (z2 >> 4);
707 s+=2;
708 }
709 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') {
710 d[count++] = (z1 << 2) | (z2 >> 4);
711 d[count++] = (z2 << 4) | (z3 >> 2);
712 s+=3;
713 }
714 while (BHxlat[ACAST(*s)] != -1)
715 uuncdl_fulline[leftover++] = *s++;
716 }
717 else if (method == YENC_ENCODED) {
718 while (*s) {
719 if (*s == '=') {
720 if (*++s != '\0') {
721 d[count++] = (char) ((int) *s - 64 - 42);
722 s++;
723 }
724 }
725 else if (*s == '\n' || *s == '\r') {
726 s++; /* ignore */
727 }
728 else {
729 d[count++] = (char) ((int) *s++ - 42);
730 }
731 }
732 }
733
734 return count;
735 }
736
737 /*
738 * ``Decode'' Quoted-Printable text
739 */
740
741 int
742 UUDecodeQP (FILE *datain, FILE *dataout, int *state,
743 long maxpos, int method, int flags,
744 char *boundary)
745 {
746 char *line=uugen_inbuffer, *p1, *p2;
747 int val;
748
749 uulboundary = -1;
750
751 while (!feof (datain) &&
752 (ftell(datain)<maxpos || flags&FL_TOEND ||
753 (!(flags&FL_PROPER) && uu_fast_scanning))) {
754 if (_FP_fgets (line, 1023, datain) == NULL)
755 break;
756 if (ferror (datain)) {
757 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
758 uustring (S_SOURCE_READ_ERR),
759 strerror (uu_errno = errno));
760 return UURET_IOERR;
761 }
762 line[255] = '\0';
763
764 if (boundary && line[0]=='-' && line[1]=='-' &&
765 strncmp (line+2, boundary, strlen (boundary)) == 0) {
766 if (line[strlen(boundary)+2]=='-')
767 uulboundary = 1;
768 else
769 uulboundary = 0;
770 return UURET_OK;
771 }
772
773 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
774 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
775 uustring (S_DECODE_CANCEL));
776 return UURET_CANCEL;
777 }
778
779 p1 = p2 = line;
780
781 while (*p2) {
782 while (*p2 && *p2 != '=')
783 p2++;
784 if (*p2 == '\0')
785 break;
786 *p2 = '\0';
787 fprintf (dataout, "%s", p1);
788 p1 = ++p2;
789
790 if (isxdigit (*p2) && isxdigit (*(p2+1))) {
791 val = ((isdigit(*p2)) ? (*p2-'0') : (tolower(*p2)-'a'+10)) << 4;
792 val |= ((isdigit(*(p2+1)))?(*(p2+1)-'0') : (tolower(*(p2+1))-'a'+10));
793
794 fputc (val, dataout);
795 p2 += 2;
796 p1 = p2;
797 }
798 else if (*p2 == '\012' || *(p2+1) == '\015') {
799 /* soft line break */
800 *p2 = '\0';
801 break;
802 }
803 else {
804 /* huh? */
805 fputc ('=', dataout);
806 }
807 }
808 /*
809 * p2 points to a nullbyte right after the CR/LF/CRLF
810 */
811 val = 0;
812 while (p2>p1 && isspace (*(p2-1))) {
813 if (*(p2-1) == '\012' || *(p2-1) == '\015')
814 val = 1;
815 p2--;
816 }
817 *p2 = '\0';
818
819 /*
820 * If the part ends directly after this line, the data does not end
821 * with a linebreak. Or, as the docs put it, "the CRLF preceding the
822 * encapsulation line is conceptually attached to the boundary.
823 * So if the part ends here, don't print a line break"
824 */
825 if (val && (!feof (datain) &&
826 (ftell(datain)<maxpos || flags&FL_TOEND ||
827 (!(flags&FL_PROPER) && uu_fast_scanning))))
828 fprintf (dataout, "%s\n", p1);
829 else
830 fprintf (dataout, "%s", p1);
831 }
832 return UURET_OK;
833 }
834
835 /*
836 * ``Decode'' plain text. Our job is to properly handle the EOL sequence
837 */
838
839 int
840 UUDecodePT (FILE *datain, FILE *dataout, int *state,
841 long maxpos, int method, int flags,
842 char *boundary)
843 {
844 char *line=uugen_inbuffer, *ptr;
845
846 uulboundary = -1;
847
848 while (!feof (datain) &&
849 (ftell(datain)<maxpos || flags&FL_TOEND ||
850 (!(flags&FL_PROPER) && uu_fast_scanning))) {
851 if (_FP_fgets (line, 1023, datain) == NULL)
852 break;
853 if (ferror (datain)) {
854 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
855 uustring (S_SOURCE_READ_ERR),
856 strerror (uu_errno = errno));
857 return UURET_IOERR;
858 }
859 line[255] = '\0';
860
861 if (boundary && line[0]=='-' && line[1]=='-' &&
862 strncmp (line+2, boundary, strlen (boundary)) == 0) {
863 if (line[strlen(boundary)+2]=='-')
864 uulboundary = 1;
865 else
866 uulboundary = 0;
867 return UURET_OK;
868 }
869
870 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
871 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
872 uustring (S_DECODE_CANCEL));
873 return UURET_CANCEL;
874 }
875
876 ptr = line + strlen (line);
877
878 while (ptr>line && (*(ptr-1) == '\012' || *(ptr-1) == '\015'))
879 ptr--;
880
881
882 /*
883 * If the part ends directly after this line, the data does not end
884 * with a linebreak. Or, as the docs put it, "the CRLF preceding the
885 * encapsulation line is conceptually attached to the boundary.
886 * So if the part ends here, don't print a line break"
887 */
888 if ((*ptr == '\012' || *ptr == '\015') &&
889 (ftell(datain)<maxpos || flags&FL_TOEND || flags&FL_PARTIAL ||
890 !boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) {
891 *ptr = '\0';
892 fprintf (dataout, "%s\n", line);
893 }
894 else {
895 *ptr = '\0';
896 fprintf (dataout, "%s", line);
897 }
898 }
899 return UURET_OK;
900 }
901
902 /*
903 * Decode a single field using method. For the moment, this supports
904 * Base64 and Quoted Printable only, to support RFC 1522 header decoding.
905 * Quit when seeing the RFC 1522 ?= end marker.
906 */
907
908 int
909 UUDecodeField (char *s, char *d, int method)
910 {
911 int z1, z2, z3, z4;
912 int count=0;
913
914 if (method == B64ENCODED) {
915 while ((z1 = B64xlat[ACAST(*s)]) != -1) {
916 if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
917 if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
918 if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
919
920 d[count++] = (z1 << 2) | (z2 >> 4);
921 d[count++] = (z2 << 4) | (z3 >> 2);
922 d[count++] = (z3 << 6) | (z4);
923
924 s+=4;
925 }
926 if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
927 d[count++] = (z1 << 2) | (z2 >> 4);
928 s+=2;
929 }
930 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
931 d[count++] = (z1 << 2) | (z2 >> 4);
932 d[count++] = (z2 << 4) | (z3 >> 2);
933 s+=3;
934 }
935 }
936 else if (method == QP_ENCODED) {
937 while (*s && (*s != '?' || *(s+1) != '=')) {
938 while (*s && *s != '=' && (*s != '?' || *(s+1) != '=')) {
939 d[count++] = *s++;
940 }
941 if (*s == '=') {
942 if (isxdigit (*(s+1)) && isxdigit (*(s+2))) {
943 d[count] = (isdigit (*(s+1)) ? (*(s+1)-'0') : (tolower (*(s+1))-'a'+10)) << 4;
944 d[count] |= (isdigit (*(s+2)) ? (*(s+2)-'0') : (tolower (*(s+2))-'a'+10));
945 count++;
946 s+=3;
947 }
948 else if (*(s+1) == '\012' || *(s+1) == '\015') {
949 s+=2;
950 }
951 else {
952 d[count++] = *s++;
953 }
954 }
955 }
956 }
957 else {
958 return -1;
959 }
960
961 d[count] = '\0';
962 return count;
963 }
964
965 int
966 UUDecodePart (FILE *datain, FILE *dataout, int *state,
967 long maxpos, int method, int flags,
968 char *boundary)
969 {
970 char *line, *oline=uuncdp_oline;
971 int warning=0, vlc=0, lc[2], hadct=0;
972 int tc=0, tf=0, vflag, haddata=0, haddh=0;
973 long yefilesize=0, yepartends=0;
974 crc32_t yepartcrc=crc32(0L, Z_NULL, 0);
975 static crc32_t yefilecrc=0;
976 static int bhflag=0;
977 size_t count=0;
978 size_t yepartsize=0;
979 char *ptr;
980
981 if (datain == NULL || dataout == NULL) {
982 yefilecrc = crc32(0L, Z_NULL, 0);
983 bhflag = 0;
984 return UURET_OK;
985 }
986
987 /*
988 * Use specialized functions for QP_ENCODED and PT_ENCODED plaintext
989 */
990
991 if (method == QP_ENCODED)
992 return UUDecodeQP (datain, dataout, state, maxpos,
993 method, flags, boundary);
994 else if (method == PT_ENCODED)
995 return UUDecodePT (datain, dataout, state, maxpos,
996 method, flags, boundary);
997
998 lc[0] = lc[1] = 0;
999 vflag = 0;
1000
1001 uulboundary = -1;
1002
1003 if (method == YENC_ENCODED) {
1004 *state = BEGIN;
1005 }
1006
1007 while (!feof (datain) && *state != DONE &&
1008 (ftell(datain)<maxpos || flags&FL_TOEND || maxpos==-1 ||
1009 (!(flags&FL_PROPER) && uu_fast_scanning))) {
1010 if (_FP_fgets ((line = uugen_fnbuffer), 1200 - 5, datain) == NULL)
1011 break;
1012
1013 /* optionally skip .. */
1014 if (*line == '.' && uu_dotdot)
1015 line++;
1016
1017 if (ferror (datain)) {
1018 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1019 uustring (S_SOURCE_READ_ERR),
1020 strerror (uu_errno = errno));
1021 return UURET_IOERR;
1022 }
1023
1024 if (line[0]=='\015' || line[0]=='\012') { /* Empty line? */
1025 if (*state == DATA &&
1026 (method == UU_ENCODED || method == XX_ENCODED))
1027 *state = END;
1028
1029 /*
1030 * if we had a whole block of valid lines before, we reset our
1031 * 'valid data' flag, tf. Without this 'if', we'd break decoding
1032 * files with interleaved blank lines. The value of 5 is chosen
1033 * quite arbitrarly.
1034 */
1035
1036 if (vlc > 5)
1037 tf = tc = 0;
1038 vlc = 0;
1039 continue;
1040 }
1041
1042 /*
1043 * Busy Polls
1044 */
1045
1046 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
1047 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1048 uustring (S_DECODE_CANCEL));
1049 return UURET_CANCEL;
1050 }
1051
1052 /*
1053 * try to make sense of data
1054 */
1055
1056 line[1200 - 1] = '\0'; /* For Safety of string functions */
1057 count = 0;
1058
1059 if (boundary && line[0]=='-' && line[1]=='-' &&
1060 strncmp (line+2, boundary, strlen (boundary)) == 0) {
1061 if (line[strlen(boundary)+2]=='-')
1062 uulboundary = 1;
1063 else
1064 uulboundary = 0;
1065 return UURET_OK;
1066 }
1067
1068 /*
1069 * Use this pseudo-handling only if !FL_PROPER
1070 */
1071
1072 if ((flags&FL_PROPER) == 0) {
1073 if (strncmp (line, "BEGIN", 5) == 0 &&
1074 _FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */
1075 tc = tf = vlc = 0;
1076 continue;
1077 }
1078 /* MIME body boundary */
1079 if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) {
1080 if ((haddata || tc) && (haddh || hadct)) {
1081 *state = DONE;
1082 vlc = 0;
1083 lc[0] = lc[1] = 0;
1084 continue;
1085 }
1086 hadct = 0;
1087 haddh = 1;
1088 continue;
1089 }
1090 if (_FP_strnicmp (line, "Content-Type", 12) == 0)
1091 hadct = 1;
1092 }
1093
1094 if (*state == BEGIN) {
1095 if ((method == UU_ENCODED || method == XX_ENCODED) &&
1096 (strncmp (line, "begin ", 6) == 0 ||
1097 _FP_strnicmp (line, "<pre>begin ", 11) == 0)) { /* for LYNX */
1098 *state = DATA;
1099 continue;
1100 }
1101 else if (method == BH_ENCODED && line[0] == ':') {
1102 if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) {
1103 bhflag = 0;
1104 *state = DATA;
1105 }
1106 else
1107 continue;
1108 }
1109 else if (method == YENC_ENCODED &&
1110 strncmp (line, "=ybegin ", 8) == 0 &&
1111 _FP_strstr (line, " name=") != NULL) {
1112 *state = DATA;
1113
1114 if ((ptr = _FP_strstr (line, " size=")) != NULL) {
1115 ptr += 6;
1116 yefilesize = atoi (ptr);
1117 }
1118 else {
1119 yefilesize = -1;
1120 }
1121
1122 if (_FP_strstr (line, " part=") != NULL) {
1123 if (_FP_fgets (line, 1200 - 5, datain) == NULL) {
1124 break;
1125 }
1126
1127 if ((ptr = _FP_strstr (line, " end=")) == NULL) {
1128 break;
1129 }
1130
1131 yepartends = atoi (ptr + 5);
1132 }
1133 tf = 1;
1134 continue;
1135 }
1136 else {
1137 continue;
1138 }
1139
1140 tc = tf = vlc = 0;
1141 lc[0] = lc[1] = 0;
1142 }
1143 else if ((*state == END) &&
1144 (method == UU_ENCODED || method == XX_ENCODED)) {
1145 if (strncmp (line, "end", 3) == 0) {
1146 *state = DONE;
1147 break;
1148 }
1149 }
1150
1151 if (*state == DATA && method == YENC_ENCODED &&
1152 strncmp (line, "=yend ", 6) == 0) {
1153 if ((ptr = _FP_strstr (line, " pcrc32=")) != NULL) {
1154 crc32_t pcrc32 = strtoul (ptr + 8, NULL, 16);
1155 if (pcrc32 != yepartcrc) {
1156 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1157 uustring (S_PCRC_MISMATCH), progress.curfile, progress.partno);
1158 }
1159 }
1160 if ((ptr = _FP_strstr (line, " crc32=")) != NULL)
1161 {
1162 crc32_t fcrc32 = strtoul (ptr + 7, NULL, 16);
1163 if (fcrc32 != yefilecrc) {
1164 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1165 uustring (S_CRC_MISMATCH), progress.curfile);
1166 }
1167 }
1168 if ((ptr = _FP_strstr (line, " size=")) != NULL)
1169 {
1170 size_t size = atol(ptr + 6);
1171 if (size != yepartsize && yefilesize != -1) {
1172 if (size != yefilesize)
1173 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1174 uustring (S_PSIZE_MISMATCH), progress.curfile,
1175 progress.partno, yepartsize, size);
1176 else
1177 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1178 uustring (S_SIZE_MISMATCH), progress.curfile,
1179 yepartsize, size);
1180 }
1181 }
1182 if (yepartends == 0 || yepartends >= yefilesize) {
1183 *state = DONE;
1184 }
1185 break;
1186 }
1187
1188 if (*state == DATA || *state == END) {
1189 if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) {
1190 break;
1191 }
1192
1193 if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0)
1194 vflag = UURepairData (datain, line, (tf)?method:0, &bhflag);
1195
1196 /*
1197 * correct XX/UUencoded lines that were declared Base64
1198 */
1199
1200 if ((method == XX_ENCODED || method == UU_ENCODED) &&
1201 vflag == B64ENCODED) {
1202 if (UUValidData (line, method, &bhflag) == method)
1203 vflag = method;
1204 }
1205
1206 if (vflag == method) {
1207 if (tf) {
1208 count = UUDecodeLine (line, oline, method);
1209 if (method == YENC_ENCODED) {
1210 if (yepartends)
1211 yepartcrc = crc32(yepartcrc, oline, count);
1212 yefilecrc = crc32(yefilecrc, oline, count);
1213 yepartsize += count;
1214 }
1215 vlc++; lc[1]++;
1216 }
1217 else if (tc == 3) {
1218 count = UUDecodeLine (save[0], oline, method);
1219 count += UUDecodeLine (save[1], oline + count, method);
1220 count += UUDecodeLine (save[2], oline + count, method);
1221 count += UUDecodeLine (line, oline + count, method);
1222 tf = 1;
1223 tc = 0;
1224
1225 /*
1226 * complain if we had one or two invalid lines amidst of
1227 * correctly encoded data. This usually means that the
1228 * file is in error
1229 */
1230
1231 if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) {
1232 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1233 uustring (S_DATA_SUSPICIOUS));
1234 warning=1;
1235 }
1236 lc[0] = 0;
1237 lc[1] = 3;
1238 }
1239 else {
1240 _FP_strncpy (save[tc++], line, 1200);
1241 }
1242
1243 if (method == UU_ENCODED)
1244 *state = (line[0] == 'M') ? DATA : END;
1245 else if (method == XX_ENCODED)
1246 *state = (line[0] == 'h') ? DATA : END;
1247 else if (method == B64ENCODED)
1248 *state = (strchr (line, '=') == NULL) ? DATA : DONE;
1249 else if (method == BH_ENCODED)
1250 *state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE;
1251 }
1252 else {
1253 vlc = tf = tc = 0;
1254 haddh = 0;
1255 lc[0]++;
1256 }
1257 }
1258 else if (*state != DONE) {
1259 return UURET_NOEND;
1260 }
1261
1262 if (count) {
1263 if (method == BH_ENCODED) {
1264 if (UUbhwrite (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 }
1271 else if (fwrite (oline, 1, count, dataout) != count) {
1272 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1273 uustring (S_WR_ERR_TEMP),
1274 strerror (uu_errno = errno));
1275 return UURET_IOERR;
1276 }
1277 haddata++;
1278 count = 0;
1279 }
1280 }
1281
1282 if (*state == DONE ||
1283 (*state == DATA && method == B64ENCODED &&
1284 vflag == B64ENCODED && (flags&FL_PROPER || haddh))) {
1285 for (tf=0; tf<tc; tf++)
1286 count += UUDecodeLine (save[tf], oline + count, method);
1287 if (count) {
1288 if (method == BH_ENCODED) {
1289 if (UUbhwrite (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 else if (fwrite (oline, 1, count, dataout) != count) {
1297 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1298 uustring (S_WR_ERR_TEMP),
1299 strerror (uu_errno = errno));
1300 return UURET_IOERR;
1301 }
1302 }
1303 }
1304 return UURET_OK;
1305 }
1306
1307 /*
1308 * this function decodes the file into a temporary file
1309 */
1310
1311 int
1312 UUDecode (uulist *data)
1313 {
1314 int state=BEGIN, part=-1, res=0, hb;
1315 unsigned long rsize, dsize, numbytes;
1316 FILE *datain, *dataout;
1317 unsigned char r[8];
1318 char *mode, *ntmp;
1319 uufile *iter;
1320 size_t bytes;
1321 #ifdef HAVE_MKSTEMP
1322 int tmpfd;
1323 const char *tmpprefix = "uuXXXXXX";
1324 char *tmpdir = NULL;
1325 #endif /* HAVE_MKSTEMP */
1326
1327 if (data == NULL || data->thisfile == NULL)
1328 return UURET_ILLVAL;
1329
1330 if (data->state & UUFILE_TMPFILE)
1331 return UURET_OK;
1332
1333 if (data->state & UUFILE_NODATA)
1334 return UURET_NODATA;
1335
1336 if (data->state & UUFILE_NOBEGIN && !uu_desperate)
1337 return UURET_NODATA;
1338
1339 if (data->uudet == PT_ENCODED)
1340 mode = "wt"; /* open text files in text mode */
1341 else
1342 mode = "wb"; /* otherwise in binary */
1343
1344 #ifdef HAVE_MKSTEMP
1345 if ((getuid()==geteuid()) && (getgid()==getegid())) {
1346 tmpdir=getenv("TMPDIR");
1347 }
1348
1349 if (!tmpdir) {
1350 tmpdir = "/tmp";
1351 }
1352 data->binfile = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
1353
1354 if (!data->binfile) {
1355 #else
1356 if ((data->binfile = tempnam (NULL, "uu")) == NULL) {
1357 #endif /* HAVE_MKSTEMP */
1358 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1359 uustring (S_NO_TEMP_NAME));
1360 return UURET_NOMEM;
1361 }
1362
1363 #ifdef HAVE_MKSTEMP
1364 strcpy(data->binfile, tmpdir);
1365 strcat(data->binfile, "/");
1366 strcat(data->binfile, tmpprefix);
1367
1368 if ((tmpfd = mkstemp(data->binfile)) == -1 ||
1369 (dataout = fdopen(tmpfd, mode)) == NULL) {
1370 #else
1371 if ((dataout = fopen (data->binfile, mode)) == NULL) {
1372 #endif /* HAVE_MKSTEMP */
1373 /*
1374 * we couldn't create a temporary file. Usually this means that TMP
1375 * and TEMP aren't set
1376 */
1377 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1378 uustring (S_WR_ERR_TARGET),
1379 data->binfile, strerror (uu_errno = errno));
1380 #ifdef HAVE_MKSTEMP
1381 if (tmpfd != -1) {
1382 unlink(data->binfile);
1383 close(tmpfd);
1384 }
1385 #endif /* HAVE_MKSTEMP */
1386 _FP_free (data->binfile);
1387 data->binfile = NULL;
1388 uu_errno = errno;
1389 return UURET_IOERR;
1390 }
1391
1392 /*
1393 * we don't have begin lines in Base64 or plain text files.
1394 */
1395 if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1396 data->uudet == PT_ENCODED)
1397 state = DATA;
1398
1399 /*
1400 * If we know that the file does not have a begin, we simulate
1401 * it in desperate mode
1402 */
1403
1404 if ((data->state & UUFILE_NOBEGIN) && uu_desperate)
1405 state = DATA;
1406
1407 (void) UUDecodeLine (NULL, NULL, 0); /* init */
1408 (void) UUbhwrite (NULL, 0, 0, NULL); /* dito */
1409 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* yep */
1410
1411 /*
1412 * initialize progress information
1413 */
1414 progress.action = 0;
1415 if (data->filename != NULL) {
1416 _FP_strncpy (progress.curfile,
1417 (strlen(data->filename)>255)?
1418 (data->filename+strlen(data->filename)-255):data->filename,
1419 256);
1420 }
1421 else {
1422 _FP_strncpy (progress.curfile,
1423 (strlen(data->binfile)>255)?
1424 (data->binfile+strlen(data->binfile)-255):data->binfile,
1425 256);
1426 }
1427 progress.partno = 0;
1428 progress.numparts = 0;
1429 progress.fsize = -1;
1430 progress.percent = 0;
1431 progress.action = UUACT_DECODING;
1432
1433 iter = data->thisfile;
1434 while (iter) {
1435 progress.numparts = (iter->partno)?iter->partno:1;
1436 iter = iter->NEXT;
1437 }
1438
1439 /*
1440 * let's rock!
1441 */
1442
1443 iter = data->thisfile;
1444 while (iter) {
1445 if (part != -1 && iter->partno != part+1 && !uu_desperate)
1446 break;
1447 else
1448 part = iter->partno;
1449
1450 if (iter->data->sfname == NULL) {
1451 iter = iter->NEXT;
1452 continue;
1453 }
1454
1455 /*
1456 * call our FileCallback to retrieve the file
1457 */
1458
1459 if (uu_FileCallback) {
1460 if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1461 uugen_fnbuffer, 1)) != UURET_OK)
1462 break;
1463 if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) {
1464 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1465 uugen_fnbuffer, 0);
1466 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1467 uustring (S_NOT_OPEN_FILE),
1468 uugen_fnbuffer, strerror (uu_errno = errno));
1469 res = UURET_IOERR;
1470 break;
1471 }
1472 }
1473 else {
1474 if ((datain = fopen (iter->data->sfname, "rb")) == NULL) {
1475 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1476 uustring (S_NOT_OPEN_FILE),
1477 iter->data->sfname, strerror (uu_errno = errno));
1478 res = UURET_IOERR;
1479 break;
1480 }
1481 _FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
1482 }
1483
1484 progress.partno = part;
1485 progress.fsize = (iter->data->length)?iter->data->length:-1;
1486 progress.percent = 0;
1487 progress.foffset = iter->data->startpos;
1488
1489 fseek (datain, iter->data->startpos, SEEK_SET);
1490 res = UUDecodePart (datain, dataout, &state,
1491 iter->data->startpos+iter->data->length,
1492 data->uudet, iter->data->flags, NULL);
1493 fclose (datain);
1494
1495 if (uu_FileCallback)
1496 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0);
1497
1498 if (state == DONE || res != UURET_OK)
1499 break;
1500
1501 iter = iter->NEXT;
1502 }
1503
1504 if (state == DATA &&
1505 (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1506 data->uudet == PT_ENCODED))
1507 state = DONE; /* assume we're done */
1508
1509 if (fclose (dataout)) {
1510 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1511 uustring (S_WR_ERR_TEMP),
1512 strerror (uu_errno = errno));
1513 res = UURET_IOERR;
1514 }
1515
1516 if (res != UURET_OK || (state != DONE && !uu_desperate)) {
1517 unlink (data->binfile);
1518 _FP_free (data->binfile);
1519 data->binfile = NULL;
1520 data->state &= ~UUFILE_TMPFILE;
1521 data->state |= UUFILE_ERROR;
1522
1523 if (res == UURET_OK && state != DONE)
1524 res = UURET_NOEND;
1525 }
1526 else if (res != UURET_OK) {
1527 data->state &= ~UUFILE_DECODED;
1528 data->state |= UUFILE_ERROR | UUFILE_TMPFILE;
1529 }
1530 else {
1531 data->state &= ~UUFILE_ERROR;
1532 data->state |= UUFILE_TMPFILE;
1533 }
1534
1535 /*
1536 * If this was a BinHex file, we must extract its data or resource fork
1537 */
1538
1539 if (data->uudet == BH_ENCODED && data->binfile) {
1540 #ifdef HAVE_MKSTEMP
1541 ntmp = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
1542
1543 if (ntmp == NULL) {
1544 #else
1545 if ((ntmp = tempnam (NULL, "uu")) == NULL) {
1546 #endif /* HAVE_MKSTEMP */
1547 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1548 uustring (S_NO_TEMP_NAME));
1549 progress.action = 0;
1550 return UURET_NOMEM;
1551 }
1552 if ((datain = fopen (data->binfile, "rb")) == NULL) {
1553 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1554 uustring (S_NOT_OPEN_FILE),
1555 data->binfile, strerror (uu_errno = errno));
1556 progress.action = 0;
1557 free (ntmp);
1558 return UURET_IOERR;
1559 }
1560 #ifdef HAVE_MKSTEMP
1561 strcpy(ntmp, tmpdir);
1562 strcat(ntmp, "/");
1563 strcat(ntmp, tmpprefix);
1564 if ((tmpfd = mkstemp(ntmp)) == -1 ||
1565 (dataout = fdopen(tmpfd, "wb")) == NULL) {
1566 #else
1567 if ((dataout = fopen (ntmp, "wb")) == NULL) {
1568 #endif /* HAVE_MKSTEMP */
1569 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1570 uustring (S_NOT_OPEN_TARGET),
1571 ntmp, strerror (uu_errno = errno));
1572 progress.action = 0;
1573 fclose (datain);
1574 #ifdef HAVE_MKSTEMP
1575 if (tmpfd != -1) {
1576 unlink(ntmp);
1577 close(tmpfd);
1578 }
1579 #endif /* HAVE_MKSTEMP */
1580 free (ntmp);
1581 return UURET_IOERR;
1582 }
1583
1584 /*
1585 * read fork lengths. remember they're in Motorola format
1586 */
1587 r[0] = fgetc (datain);
1588 hb = (int) r[0] + 22;
1589 fseek (datain, (int) r[0] + 12, SEEK_SET);
1590 fread (r, 1, 8, datain);
1591
1592 dsize = (((long) 1 << 24) * (long) r[0]) +
1593 (((long) 1 << 16) * (long) r[1]) +
1594 (((long) 1 << 8) * (long) r[2]) +
1595 ( (long) r[3]);
1596 rsize = (((long) 1 << 24) * (long) r[4]) +
1597 (((long) 1 << 16) * (long) r[5]) +
1598 (((long) 1 << 8) * (long) r[6]) +
1599 ( (long) r[7]);
1600
1601 UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE,
1602 uustring (S_BINHEX_SIZES),
1603 dsize, rsize);
1604
1605 if (dsize == 0) {
1606 fseek (datain, dsize + hb + 2, SEEK_SET);
1607 numbytes = rsize;
1608 }
1609 else if (rsize == 0) {
1610 fseek (datain, hb, SEEK_SET);
1611 numbytes = dsize;
1612 }
1613 else {
1614 /* we should let the user have the choice here */
1615 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1616 uustring (S_BINHEX_BOTH));
1617 fseek (datain, hb, SEEK_SET);
1618 numbytes = dsize;
1619 }
1620
1621 progress.action = 0;
1622 progress.partno = 0;
1623 progress.numparts = 1;
1624 progress.fsize = (numbytes)?numbytes:-1;
1625 progress.foffset = hb;
1626 progress.percent = 0;
1627 progress.action = UUACT_COPYING;
1628
1629 /*
1630 * copy the chosen fork
1631 */
1632
1633 while (!feof (datain) && numbytes) {
1634 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
1635 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1636 uustring (S_DECODE_CANCEL));
1637 fclose (datain);
1638 fclose (dataout);
1639 unlink (ntmp);
1640 free (ntmp);
1641 return UURET_CANCEL;
1642 }
1643
1644 bytes = fread (uugen_inbuffer, 1,
1645 (size_t) ((numbytes>1024)?1024:numbytes), datain);
1646
1647 if (ferror (datain) || (bytes == 0 && !feof (datain))) {
1648 progress.action = 0;
1649 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1650 uustring (S_SOURCE_READ_ERR),
1651 data->binfile, strerror (uu_errno = errno));
1652 fclose (datain);
1653 fclose (dataout);
1654 unlink (ntmp);
1655 free (ntmp);
1656 return UURET_IOERR;
1657 }
1658 if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) {
1659 progress.action = 0;
1660 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1661 uustring (S_WR_ERR_TARGET),
1662 ntmp, strerror (uu_errno = errno));
1663 fclose (datain);
1664 fclose (dataout);
1665 unlink (ntmp);
1666 free (ntmp);
1667 return UURET_IOERR;
1668 }
1669 numbytes -= bytes;
1670 }
1671
1672 if (numbytes) {
1673 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1674 uustring (S_SHORT_BINHEX),
1675 (data->filename)?data->filename:
1676 (data->subfname)?data->subfname:"???",
1677 numbytes);
1678 }
1679
1680 /*
1681 * replace temp file
1682 */
1683
1684 fclose (datain);
1685 if (fclose (dataout)) {
1686 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1687 uustring (S_WR_ERR_TARGET),
1688 ntmp, strerror (uu_errno = errno));
1689 unlink (ntmp);
1690 free (ntmp);
1691 return UURET_IOERR;
1692 }
1693
1694 if (unlink (data->binfile)) {
1695 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1696 uustring (S_TMP_NOT_REMOVED),
1697 data->binfile, strerror (uu_errno = errno));
1698 }
1699
1700 free (data->binfile);
1701 data->binfile = ntmp;
1702 }
1703
1704 progress.action = 0;
1705 return res;
1706 }
1707
1708 /*
1709 * QuickDecode for proper MIME attachments. We expect the pointer to
1710 * be on the first header line.
1711 */
1712
1713 int
1714 UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos)
1715 {
1716 int state=BEGIN, encoding=-1;
1717 headers myenv;
1718
1719 /*
1720 * Read header and find out about encoding.
1721 */
1722
1723 memset (&myenv, 0, sizeof (headers));
1724 UUScanHeader (datain, &myenv);
1725
1726 if (_FP_stristr (myenv.ctenc, "uu") != NULL)
1727 encoding = UU_ENCODED;
1728 else if (_FP_stristr (myenv.ctenc, "xx") != NULL)
1729 encoding = XX_ENCODED;
1730 else if (_FP_stricmp (myenv.ctenc, "base64") == 0)
1731 encoding = B64ENCODED;
1732 else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
1733 encoding = QP_ENCODED;
1734 else
1735 encoding = PT_ENCODED;
1736
1737 UUkillheaders (&myenv);
1738
1739 /*
1740 * okay, so decode this one
1741 */
1742
1743 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* init */
1744 return UUDecodePart (datain, dataout, &state, maxpos,
1745 encoding, FL_PROPER|FL_TOEND,
1746 boundary);
1747 }