ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uunconc.c
Revision: 1.8
Committed: Sat Apr 6 01:53:30 2002 UTC (22 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +21 -6 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 <uudeview.h>
53 #include <uuint.h>
54 #include <fptools.h>
55 #include <uustring.h>
56
57 char * uunconc_id = "$Id: uunconc.c,v 1.7 2002/04/05 21:56:57 root Exp $";
58
59 /* for braindead systems */
60 #ifndef SEEK_SET
61 #ifdef L_BEGIN
62 #define SEEK_SET L_BEGIN
63 #else
64 #define SEEK_SET 0
65 #endif
66 #endif
67
68 /*
69 * decoder states
70 */
71
72 #define BEGIN (1)
73 #define DATA (2)
74 #define END (3)
75 #define DONE (4)
76
77 /*
78 * mallocable areas
79 */
80
81 char *uunconc_UUxlat;
82 char *uunconc_UUxlen;
83 char *uunconc_B64xlat;
84 char *uunconc_XXxlat;
85 char *uunconc_BHxlat;
86 char *uunconc_save;
87
88 /*
89 * decoding translation tables and line length table
90 */
91
92 static int * UUxlen; /* initialized in UUInitConc() */
93 static int * UUxlat; /* from the malloc'ed areas above */
94 static int * B64xlat;
95 static int * XXxlat;
96 static int * BHxlat;
97
98 /*
99 * buffer for decoding
100 */
101
102 static char *save[3];
103
104 /*
105 * mallocable areas
106 */
107
108 char *uuncdl_fulline;
109 char *uuncdp_oline;
110
111 /*
112 * Return information for QuickDecode
113 */
114
115 static int uulboundary;
116
117 /*
118 * To prevent warnings when using a char as index into an array
119 */
120
121 #define ACAST(s) ((int)(uchar)(s))
122
123 /*
124 * Initialize decoding tables
125 */
126
127 void
128 UUInitConc (void)
129 {
130 int i, j;
131
132 /*
133 * Update pointers
134 */
135 UUxlen = (int *) uunconc_UUxlen;
136 UUxlat = (int *) uunconc_UUxlat;
137 B64xlat = (int *) uunconc_B64xlat;
138 XXxlat = (int *) uunconc_XXxlat;
139 BHxlat = (int *) uunconc_BHxlat;
140
141 save[0] = uunconc_save;
142 save[1] = uunconc_save + 256;
143 save[2] = uunconc_save + 512;
144
145 /* prepare decoding translation table */
146 for(i = 0; i < 256; i++)
147 UUxlat[i] = B64xlat[i] = XXxlat[i] = BHxlat[i] = -1;
148
149 /*
150 * At some time I received a file which used lowercase characters for
151 * uuencoding. This shouldn't be, but let's accept it. Must take special
152 * care that this doesn't break xxdecoding. This is giving me quite a
153 * headache. If this one file hadn't been a Pocahontas picture, I might
154 * have ignored it for good.
155 */
156
157 for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
158 UUxlat[i] /* = UUxlat[i+64] */ = j;
159 for (i = '`', j = 0; i < '`' + 32; i++, j++)
160 UUxlat[i] = j;
161
162 /* add special cases */
163 UUxlat['`'] = UUxlat[' '];
164 UUxlat['~'] = UUxlat['^'];
165
166 /* prepare line length table */
167 UUxlen[0] = 1;
168 for(i = 1, j = 5; i <= 61; i += 3, j += 4)
169 UUxlen[i] = UUxlen[i+1] = UUxlen[i+2] = j;
170
171 /* prepare other tables */
172 for (i=0; i<64; i++) {
173 B64xlat[ACAST(B64EncodeTable[i])] = i;
174 XXxlat [ACAST(XXEncodeTable [i])] = i;
175 BHxlat [ACAST(BHEncodeTable [i])] = i;
176 }
177 }
178
179 /*
180 * Workaround for Netscape
181 */
182
183 /*
184 * Determines whether Netscape may have broken up a data line (by
185 * inserting a newline). This only seems to happen after <a in a
186 * href statement
187 */
188
189 int
190 UUBrokenByNetscape (char *string)
191 {
192 char *ptr;
193 int len;
194
195 if (string==NULL || (len=strlen(string))<3)
196 return 0;
197
198 if ((ptr = _FP_stristr (string, "<a href=")) != NULL) {
199 if (_FP_stristr (string, "</a>") > ptr)
200 return 2;
201 }
202
203 ptr = string + len;
204
205 while (len && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) {
206 ptr--; len--;
207 }
208 if (len<3) return 0;
209 if (*--ptr == ' ') ptr--;
210 ptr--;
211
212 if (_FP_strnicmp (ptr, "<a", 2) == 0)
213 return 1;
214
215 return 0;
216 }
217
218 /*
219 * Try to repair a Netscape-corrupted line of data.
220 * This must only be called on corrupted lines, since non-Netscape
221 * data may even _get_ corrupted by this procedure.
222 *
223 * Some checks are included multiply to speed up the procedure. For
224 * example: (*p1!='<' || strnicmp(p1,"</a>",4)). If the first expression
225 * becomes true, the costly function isn't called :-)
226 *
227 * Since '<', '>', '&' might even be replaced by their html equivalents
228 * in href strings, I'm now using two passes, the first one for &amp; + co,
229 * the second one for hrefs.
230 */
231
232 int
233 UUNetscapeCollapse (char *string)
234 {
235 char *p1=string, *p2=string;
236 int res = 0;
237
238 if (string==NULL)
239 return 0;
240
241 /*
242 * First pass
243 */
244 while (*p1) {
245 if (*p1 == '&') {
246 if (_FP_strnicmp (p1, "&amp;", 5) == 0) { p1+=5; *p2++='&'; res=1; }
247 else if (_FP_strnicmp (p1, "&lt;", 4) == 0) { p1+=4; *p2++='<'; res=1; }
248 else if (_FP_strnicmp (p1, "&gt;", 4) == 0) { p1+=4; *p2++='>'; res=1; }
249 else *p2++ = *p1++;
250 res = 1;
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 ptr = line + strlen (line);
545 while (ptr>line && (*(ptr-1)=='\015' || *(ptr-1)=='\012'))
546 ptr--;
547 if (_FP_fgets (ptr, 255-(ptr-line), datei) == NULL)
548 break;
549 }
550 else { /* don't need next line to repair */
551 }
552 if (UUNetscapeCollapse (line)) {
553 if ((vflag = UUValidData (line, encoding, bhflag)) == 0)
554 nflag = UUBrokenByNetscape (line);
555 }
556 else
557 nflag = 0;
558 }
559 /*
560 * Sometimes, a line is garbled even without it being split into
561 * the next line. Then we try this in our despair
562 */
563 if (vflag == 0) {
564 if (UUNetscapeCollapse (line))
565 vflag = UUValidData (line, encoding, bhflag);
566 }
567
568 /*
569 * If this line looks uuencoded, but the line is one character short
570 * of a valid line, it was probably broken by MS Exchange. According
571 * to my test cases, there is at most one space character missing;
572 * there are never two spaces together.
573 * If adding a space character helps making this line uuencoded, do
574 * it!
575 */
576
577 if (vflag == 0) {
578 ptr = line + strlen(line);
579 while (ptr>line && (*(ptr-1)=='\012' || *(ptr-1)=='\015')) {
580 ptr--;
581 }
582 *ptr++ = ' ';
583 *ptr-- = '\0';
584 if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) {
585 *ptr = '\0';
586 vflag = 0;
587 }
588 }
589 return vflag;
590 }
591
592 /*
593 * Decode a single encoded line using method
594 */
595
596 size_t
597 UUDecodeLine (char *s, char *d, int method)
598 {
599 int i, j, c, cc, count=0, z1, z2, z3, z4;
600 static int leftover=0;
601 int *table;
602
603 /*
604 * for re-initialization
605 */
606
607 if (s == NULL || d == NULL) {
608 leftover = 0;
609 return 0;
610 }
611
612 /* optionally skip .. */
613 if (*s == '.' && uu_dotdot)
614 s++;
615
616 /*
617 * To shut up gcc -Wall
618 */
619 z1 = z2 = z3 = z4 = 0;
620
621 if (method == UU_ENCODED || method == XX_ENCODED) {
622 if (method == UU_ENCODED)
623 table = UUxlat;
624 else
625 table = XXxlat;
626
627 i = table [ACAST(*s++)];
628 j = UUxlen[i] - 1;
629
630 while(j > 0) {
631 c = table[ACAST(*s++)] << 2;
632 cc = table[ACAST(*s++)];
633 c |= (cc >> 4);
634
635 if(i-- > 0)
636 d[count++] = c;
637
638 cc <<= 4;
639 c = table[ACAST(*s++)];
640 cc |= (c >> 2);
641
642 if(i-- > 0)
643 d[count++] = cc;
644
645 c <<= 6;
646 c |= table[ACAST(*s++)];
647
648 if(i-- > 0)
649 d[count++] = c;
650
651 j -= 4;
652 }
653 }
654 else if (method == B64ENCODED) {
655 if (leftover) {
656 int len = strlen (s);
657
658 if (len > 1200 - 1 - leftover)
659 len = 1200 - 1 - leftover;
660
661 memcpy (uuncdl_fulline + leftover, s, len);
662 uuncdl_fulline[leftover + len] = 0;
663
664 leftover = 0;
665 s = uuncdl_fulline;
666 }
667
668 while ((z1 = B64xlat[ACAST(*s)]) != -1) {
669 if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
670 if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
671 if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
672
673 d[count++] = (z1 << 2) | (z2 >> 4);
674 d[count++] = (z2 << 4) | (z3 >> 2);
675 d[count++] = (z3 << 6) | (z4);
676
677 s += 4;
678 }
679 if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
680 d[count++] = (z1 << 2) | (z2 >> 4);
681 s+=2;
682 }
683 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
684 d[count++] = (z1 << 2) | (z2 >> 4);
685 d[count++] = (z2 << 4) | (z3 >> 2);
686 s+=3;
687 }
688 while (B64xlat[ACAST(*s)] != -1)
689 uuncdl_fulline[leftover++] = *s++;
690 }
691 else if (method == BH_ENCODED) {
692 if (leftover) {
693 int len = strlen (s);
694
695 if (len > 1200 - 1 - leftover)
696 len = 1200 - 1 - leftover;
697
698 memcpy (uuncdl_fulline + leftover, s, len);
699 uuncdl_fulline[leftover + len] = 0;
700
701 leftover = 0;
702 s = uuncdl_fulline;
703 }
704 else if (*s == ':')
705 s++;
706
707 while ((z1 = BHxlat[ACAST(*s)]) != -1) {
708 if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break;
709 if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break;
710 if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break;
711
712 d[count++] = (z1 << 2) | (z2 >> 4);
713 d[count++] = (z2 << 4) | (z3 >> 2);
714 d[count++] = (z3 << 6) | (z4);
715
716 s += 4;
717 }
718 if (z1 != -1 && z2 != -1 && *(s+2) == ':') {
719 d[count++] = (z1 << 2) | (z2 >> 4);
720 s+=2;
721 }
722 else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') {
723 d[count++] = (z1 << 2) | (z2 >> 4);
724 d[count++] = (z2 << 4) | (z3 >> 2);
725 s+=3;
726 }
727 while (BHxlat[ACAST(*s)] != -1)
728 uuncdl_fulline[leftover++] = *s++;
729 }
730 else if (method == YENC_ENCODED) {
731 while (*s) {
732 if (*s == '=') {
733 if (*++s != '\0') {
734 d[count++] = (char) ((int) *s - 64 - 42);
735 s++;
736 }
737 }
738 else if (*s == '\n' || *s == '\r') {
739 s++; /* ignore */
740 }
741 else {
742 d[count++] = (char) ((int) *s++ - 42);
743 }
744 }
745 }
746
747 return count;
748 }
749
750 /*
751 * ``Decode'' Quoted-Printable text
752 */
753
754 int
755 UUDecodeQP (FILE *datain, FILE *dataout, int *state,
756 long maxpos, int method, int flags,
757 char *boundary)
758 {
759 char *line=uugen_inbuffer, *p1, *p2;
760 int val;
761
762 uulboundary = -1;
763
764 while (!feof (datain) &&
765 (ftell(datain)<maxpos || flags&FL_TOEND ||
766 (!(flags&FL_PROPER) && uu_fast_scanning))) {
767 if (_FP_fgets (line, 255, datain) == NULL)
768 break;
769 if (ferror (datain)) {
770 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
771 uustring (S_SOURCE_READ_ERR),
772 strerror (uu_errno = errno));
773 return UURET_IOERR;
774 }
775 line[255] = '\0';
776
777 if (boundary && line[0]=='-' && line[1]=='-' &&
778 strncmp (line+2, boundary, strlen (boundary)) == 0) {
779 if (line[strlen(boundary)+2]=='-')
780 uulboundary = 1;
781 else
782 uulboundary = 0;
783 return UURET_OK;
784 }
785
786 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
787 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
788 uustring (S_DECODE_CANCEL));
789 return UURET_CANCEL;
790 }
791
792 p1 = p2 = line;
793
794 while (*p2) {
795 while (*p2 && *p2 != '=')
796 p2++;
797 if (*p2 == '\0')
798 break;
799 *p2 = '\0';
800 fprintf (dataout, "%s", p1);
801 p1 = ++p2;
802
803 if (isxdigit (*p2) && isxdigit (*(p2+1))) {
804 val = ((isdigit(*p2)) ? (*p2-'0') : (tolower(*p2)-'a'+10)) << 4;
805 val |= ((isdigit(*(p2+1)))?(*(p2+1)-'0') : (tolower(*(p2+1))-'a'+10));
806
807 fputc (val, dataout);
808 p2 += 2;
809 p1 = p2;
810 }
811 else if (*p2 == '\012' || *(p2+1) == '\015') {
812 /* soft line break */
813 *p2 = '\0';
814 break;
815 }
816 else {
817 /* huh? */
818 fputc ('=', dataout);
819 }
820 }
821 /*
822 * p2 points to a nullbyte right after the CR/LF/CRLF
823 */
824 val = 0;
825 while (p2>p1 && isspace (*(p2-1))) {
826 if (*(p2-1) == '\012' || *(p2-1) == '\015')
827 val = 1;
828 p2--;
829 }
830 *p2 = '\0';
831
832 /*
833 * If the part ends directly after this line, the data does not end
834 * with a linebreak. Or, as the docs put it, "the CRLF preceding the
835 * encapsulation line is conceptually attached to the boundary.
836 * So if the part ends here, don't print a line break"
837 */
838 if (val && (!feof (datain) &&
839 (ftell(datain)<maxpos || flags&FL_TOEND ||
840 (!(flags&FL_PROPER) && uu_fast_scanning))))
841 fprintf (dataout, "%s\n", p1);
842 else
843 fprintf (dataout, "%s", p1);
844 }
845 return UURET_OK;
846 }
847
848 /*
849 * ``Decode'' plain text. Our job is to properly handle the EOL sequence
850 */
851
852 int
853 UUDecodePT (FILE *datain, FILE *dataout, int *state,
854 long maxpos, int method, int flags,
855 char *boundary)
856 {
857 char *line=uugen_inbuffer, *ptr;
858
859 uulboundary = -1;
860
861 while (!feof (datain) &&
862 (ftell(datain)<maxpos || flags&FL_TOEND ||
863 (!(flags&FL_PROPER) && uu_fast_scanning))) {
864 if (_FP_fgets (line, 255, datain) == NULL)
865 break;
866 if (ferror (datain)) {
867 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
868 uustring (S_SOURCE_READ_ERR),
869 strerror (uu_errno = errno));
870 return UURET_IOERR;
871 }
872 line[255] = '\0';
873
874 if (boundary && line[0]=='-' && line[1]=='-' &&
875 strncmp (line+2, boundary, strlen (boundary)) == 0) {
876 if (line[strlen(boundary)+2]=='-')
877 uulboundary = 1;
878 else
879 uulboundary = 0;
880 return UURET_OK;
881 }
882
883 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
884 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
885 uustring (S_DECODE_CANCEL));
886 return UURET_CANCEL;
887 }
888
889 ptr = line + strlen (line);
890
891 while (ptr>line && (*(ptr-1) == '\012' || *(ptr-1) == '\015'))
892 ptr--;
893
894
895 /*
896 * If the part ends directly after this line, the data does not end
897 * with a linebreak. Or, as the docs put it, "the CRLF preceding the
898 * encapsulation line is conceptually attached to the boundary.
899 * So if the part ends here, don't print a line break"
900 */
901 if ((*ptr == '\012' || *ptr == '\015') &&
902 (ftell(datain)<maxpos || flags&FL_TOEND || flags&FL_PARTIAL ||
903 !boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) {
904 *ptr = '\0';
905 fprintf (dataout, "%s\n", line);
906 }
907 else {
908 *ptr = '\0';
909 fprintf (dataout, "%s", line);
910 }
911 }
912 return UURET_OK;
913 }
914
915 int
916 UUDecodePart (FILE *datain, FILE *dataout, int *state,
917 long maxpos, int method, int flags,
918 char *boundary)
919 {
920 char *line=uugen_fnbuffer, *oline=uuncdp_oline;
921 int warning=0, vlc=0, lc[2], hadct=0;
922 int tc=0, tf=0, vflag, haddata=0, haddh=0;
923 long yefilesize=0, yepartends=0;
924 static int bhflag=0;
925 size_t count=0;
926 char *ptr;
927
928 if (datain == NULL || dataout == NULL) {
929 bhflag = 0;
930 return UURET_OK;
931 }
932
933 /*
934 * Use specialized functions for QP_ENCODED and PT_ENCODED plaintext
935 */
936
937 if (method == QP_ENCODED)
938 return UUDecodeQP (datain, dataout, state, maxpos,
939 method, flags, boundary);
940 else if (method == PT_ENCODED)
941 return UUDecodePT (datain, dataout, state, maxpos,
942 method, flags, boundary);
943
944 lc[0] = lc[1] = 0;
945 vflag = 0;
946
947 uulboundary = -1;
948
949 if (method == YENC_ENCODED) {
950 *state = BEGIN;
951 }
952
953 while (!feof (datain) && *state != DONE &&
954 (ftell(datain)<maxpos || flags&FL_TOEND || maxpos==-1 ||
955 (!(flags&FL_PROPER) && uu_fast_scanning))) {
956 if (_FP_fgets (line, 299, datain) == NULL)
957 break;
958
959 if (ferror (datain)) {
960 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
961 uustring (S_SOURCE_READ_ERR),
962 strerror (uu_errno = errno));
963 return UURET_IOERR;
964 }
965
966 if (line[0]=='\015' || line[0]=='\012') { /* Empty line? */
967 if (*state == DATA &&
968 (method == UU_ENCODED || method == XX_ENCODED))
969 *state = END;
970
971 /*
972 * if we had a whole block of valid lines before, we reset our
973 * 'valid data' flag, tf. Without this 'if', we'd break decoding
974 * files with interleaved blank lines. The value of 5 is chosen
975 * quite arbitrarly.
976 */
977
978 if (vlc > 5)
979 tf = tc = 0;
980 vlc = 0;
981 continue;
982 }
983
984 /*
985 * Busy Polls
986 */
987
988 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
989 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
990 uustring (S_DECODE_CANCEL));
991 return UURET_CANCEL;
992 }
993
994 /*
995 * try to make sense of data
996 */
997
998 line[299] = '\0'; /* For Safety of string functions */
999 count = 0;
1000
1001 if (boundary && line[0]=='-' && line[1]=='-' &&
1002 strncmp (line+2, boundary, strlen (boundary)) == 0) {
1003 if (line[strlen(boundary)+2]=='-')
1004 uulboundary = 1;
1005 else
1006 uulboundary = 0;
1007 return UURET_OK;
1008 }
1009
1010 /*
1011 * Use this pseudo-handling only if !FL_PROPER
1012 */
1013
1014 if ((flags&FL_PROPER) == 0) {
1015 if (strncmp (line, "BEGIN", 5) == 0 &&
1016 _FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */
1017 tc = tf = vlc = 0;
1018 continue;
1019 }
1020 /* MIME body boundary */
1021 if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) {
1022 if ((haddata || tc) && (haddh || hadct)) {
1023 *state = DONE;
1024 vlc = 0;
1025 lc[0] = lc[1] = 0;
1026 continue;
1027 }
1028 hadct = 0;
1029 haddh = 1;
1030 continue;
1031 }
1032 if (_FP_strnicmp (line, "Content-Type", 12) == 0)
1033 hadct = 1;
1034 }
1035
1036 if (*state == BEGIN) {
1037 if ((method == UU_ENCODED || method == XX_ENCODED) &&
1038 (strncmp (line, "begin ", 6) == 0 ||
1039 _FP_strnicmp (line, "<pre>begin ", 11) == 0)) { /* for LYNX */
1040 *state = DATA;
1041 continue;
1042 }
1043 else if (method == BH_ENCODED && line[0] == ':') {
1044 if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) {
1045 bhflag = 0;
1046 *state = DATA;
1047 }
1048 else
1049 continue;
1050 }
1051 else if (method == YENC_ENCODED &&
1052 strncmp (line, "=ybegin ", 8) == 0 &&
1053 _FP_strstr (line, " size=") != NULL &&
1054 _FP_strstr (line, " name=") != NULL) {
1055 *state = DATA;
1056
1057 ptr = _FP_strstr (line, " size=") + 6;
1058 yefilesize = atoi (ptr);
1059
1060 if (_FP_strstr (line, " part=") != NULL) {
1061 if (_FP_fgets (line, 299, datain) == NULL) {
1062 break;
1063 }
1064
1065 if ((ptr = _FP_strstr (line, " end=")) == NULL) {
1066 break;
1067 }
1068
1069 yepartends = atoi (ptr + 5);
1070 }
1071 tf = 1;
1072 continue;
1073 }
1074 else {
1075 continue;
1076 }
1077
1078 tc = tf = vlc = 0;
1079 lc[0] = lc[1] = 0;
1080 }
1081 else if ((*state == END) &&
1082 (method == UU_ENCODED || method == XX_ENCODED)) {
1083 if (strncmp (line, "end", 3) == 0) {
1084 *state = DONE;
1085 break;
1086 }
1087 }
1088
1089 if (*state == DATA && method == YENC_ENCODED &&
1090 strncmp (line, "=yend ", 6) == 0) {
1091 if (yepartends == 0 || yepartends >= yefilesize) {
1092 *state = DONE;
1093 }
1094 break;
1095 }
1096
1097 if (*state == DATA || *state == END) {
1098 if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) {
1099 break;
1100 }
1101
1102 if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0)
1103 vflag = UURepairData (datain, line, (tf)?method:0, &bhflag);
1104
1105 /*
1106 * correct XX/UUencoded lines that were declared Base64
1107 */
1108
1109 if ((method == XX_ENCODED || method == UU_ENCODED) &&
1110 vflag == B64ENCODED) {
1111 if (UUValidData (line, method, &bhflag) == method)
1112 vflag = method;
1113 }
1114
1115 if (vflag == method) {
1116 if (tf) {
1117 count = UUDecodeLine (line, oline, method);
1118 vlc++; lc[1]++;
1119 }
1120 else if (tc == 3) {
1121 count = UUDecodeLine (save[0], oline, method);
1122 count += UUDecodeLine (save[1], oline + count, method);
1123 count += UUDecodeLine (save[2], oline + count, method);
1124 count += UUDecodeLine (line, oline + count, method);
1125 tf = 1;
1126 tc = 0;
1127
1128 /*
1129 * complain if we had one or two invalid lines amidst of
1130 * correctly encoded data. This usually means that the
1131 * file is in error
1132 */
1133
1134 if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) {
1135 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1136 uustring (S_DATA_SUSPICIOUS));
1137 warning=1;
1138 }
1139 lc[0] = 0;
1140 lc[1] = 3;
1141 }
1142 else {
1143 _FP_strncpy (save[tc++], line, 256);
1144 }
1145
1146 if (method == UU_ENCODED)
1147 *state = (line[0] == 'M') ? DATA : END;
1148 else if (method == XX_ENCODED)
1149 *state = (line[0] == 'h') ? DATA : END;
1150 else if (method == B64ENCODED)
1151 *state = (strchr (line, '=') == NULL) ? DATA : DONE;
1152 else if (method == BH_ENCODED)
1153 *state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE;
1154 }
1155 else {
1156 vlc = tf = tc = 0;
1157 haddh = 0;
1158 lc[0]++;
1159 }
1160 }
1161 else if (*state != DONE) {
1162 return UURET_NOEND;
1163 }
1164
1165 if (count) {
1166 if (method == BH_ENCODED) {
1167 if (UUbhwrite (oline, 1, count, dataout) != count) {
1168 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1169 uustring (S_WR_ERR_TEMP),
1170 strerror (uu_errno = errno));
1171 return UURET_IOERR;
1172 }
1173 }
1174 else if (fwrite (oline, 1, count, dataout) != count) {
1175 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1176 uustring (S_WR_ERR_TEMP),
1177 strerror (uu_errno = errno));
1178 return UURET_IOERR;
1179 }
1180 haddata++;
1181 count = 0;
1182 }
1183 }
1184
1185 if (*state == DONE ||
1186 (*state == DATA && method == B64ENCODED &&
1187 vflag == B64ENCODED && (flags&FL_PROPER || haddh))) {
1188 for (tf=0; tf<tc; tf++)
1189 count += UUDecodeLine (save[tf], oline + count, method);
1190 if (count) {
1191 if (method == BH_ENCODED) {
1192 if (UUbhwrite (oline, 1, count, dataout) != count) {
1193 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1194 uustring (S_WR_ERR_TEMP),
1195 strerror (uu_errno = errno));
1196 return UURET_IOERR;
1197 }
1198 }
1199 else if (fwrite (oline, 1, count, dataout) != count) {
1200 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1201 uustring (S_WR_ERR_TEMP),
1202 strerror (uu_errno = errno));
1203 return UURET_IOERR;
1204 }
1205 }
1206 }
1207 return UURET_OK;
1208 }
1209
1210 /*
1211 * this function decodes the file into a temporary file
1212 */
1213
1214 int
1215 UUDecode (uulist *data)
1216 {
1217 int state=BEGIN, part=-1, res=0, hb;
1218 long rsize, dsize, numbytes;
1219 FILE *datain, *dataout;
1220 unsigned char r[8];
1221 char *mode, *ntmp;
1222 uufile *iter;
1223 size_t bytes;
1224 #ifdef HAVE_MKSTEMP
1225 int tmpfd;
1226 const char *tmpprefix = "uuXXXXXX";
1227 char *tmpdir = NULL;
1228 #endif /* HAVE_MKSTEMP */
1229
1230 if (data == NULL || data->thisfile == NULL)
1231 return UURET_ILLVAL;
1232
1233 if (data->state & UUFILE_TMPFILE)
1234 return UURET_OK;
1235
1236 if (data->state & UUFILE_NODATA)
1237 return UURET_NODATA;
1238
1239 if (data->state & UUFILE_NOBEGIN && !uu_desperate)
1240 return UURET_NODATA;
1241
1242 if (data->uudet == PT_ENCODED)
1243 mode = "wt"; /* open text files in text mode */
1244 else
1245 mode = "wb"; /* otherwise in binary */
1246
1247 #ifdef HAVE_MKSTEMP
1248 if ((getuid()==geteuid()) && (getgid()==getegid())) {
1249 tmpdir=getenv("TMPDIR");
1250 }
1251
1252 if (!tmpdir) {
1253 tmpdir = "/tmp";
1254 }
1255 data->binfile = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
1256
1257 if (!data->binfile) {
1258 #else
1259 if ((data->binfile = tempnam (NULL, "uu")) == NULL) {
1260 #endif /* HAVE_MKSTEMP */
1261 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1262 uustring (S_NO_TEMP_NAME));
1263 return UURET_NOMEM;
1264 }
1265
1266 #ifdef HAVE_MKSTEMP
1267 strcpy(data->binfile, tmpdir);
1268 strcat(data->binfile, "/");
1269 strcat(data->binfile, tmpprefix);
1270
1271 if ((tmpfd = mkstemp(data->binfile)) == -1 ||
1272 (dataout = fdopen(tmpfd, mode)) == NULL) {
1273 #else
1274 if ((dataout = fopen (data->binfile, mode)) == NULL) {
1275 #endif /* HAVE_MKSTEMP */
1276 /*
1277 * we couldn't create a temporary file. Usually this means that TMP
1278 * and TEMP aren't set
1279 */
1280 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1281 uustring (S_WR_ERR_TARGET),
1282 data->binfile, strerror (uu_errno = errno));
1283 #ifdef HAVE_MKSTEMP
1284 if (tmpfd != -1) {
1285 unlink(data->binfile);
1286 close(tmpfd);
1287 }
1288 #endif /* HAVE_MKSTEMP */
1289 _FP_free (data->binfile);
1290 data->binfile = NULL;
1291 uu_errno = errno;
1292 return UURET_IOERR;
1293 }
1294
1295 /*
1296 * we don't have begin lines in Base64 or plain text files.
1297 */
1298 if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1299 data->uudet == PT_ENCODED)
1300 state = DATA;
1301
1302 /*
1303 * If we know that the file does not have a begin, we simulate
1304 * it in desperate mode
1305 */
1306
1307 if ((data->state & UUFILE_NOBEGIN) && uu_desperate)
1308 state = DATA;
1309
1310 (void) UUDecodeLine (NULL, NULL, 0); /* init */
1311 (void) UUbhwrite (NULL, 0, 0, NULL); /* dito */
1312 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* yep */
1313
1314 /*
1315 * initialize progress information
1316 */
1317 progress.action = 0;
1318 if (data->filename != NULL) {
1319 _FP_strncpy (progress.curfile,
1320 (strlen(data->filename)>255)?
1321 (data->filename+strlen(data->filename)-255):data->filename,
1322 256);
1323 }
1324 else {
1325 _FP_strncpy (progress.curfile,
1326 (strlen(data->binfile)>255)?
1327 (data->binfile+strlen(data->binfile)-255):data->binfile,
1328 256);
1329 }
1330 progress.partno = 0;
1331 progress.numparts = 0;
1332 progress.fsize = -1;
1333 progress.percent = 0;
1334 progress.action = UUACT_DECODING;
1335
1336 iter = data->thisfile;
1337 while (iter) {
1338 progress.numparts = (iter->partno)?iter->partno:1;
1339 iter = iter->NEXT;
1340 }
1341
1342 /*
1343 * let's rock!
1344 */
1345
1346 iter = data->thisfile;
1347 while (iter) {
1348 if (part != -1 && iter->partno != part+1)
1349 break;
1350 else
1351 part = iter->partno;
1352
1353 if (iter->data->sfname == NULL) {
1354 iter = iter->NEXT;
1355 continue;
1356 }
1357
1358 /*
1359 * call our FileCallback to retrieve the file
1360 */
1361
1362 if (uu_FileCallback) {
1363 if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1364 uugen_fnbuffer, 1)) != UURET_OK)
1365 break;
1366 if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) {
1367 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1368 uugen_fnbuffer, 0);
1369 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1370 uustring (S_NOT_OPEN_FILE),
1371 uugen_fnbuffer, strerror (uu_errno = errno));
1372 res = UURET_IOERR;
1373 break;
1374 }
1375 }
1376 else {
1377 if ((datain = fopen (iter->data->sfname, "rb")) == NULL) {
1378 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1379 uustring (S_NOT_OPEN_FILE),
1380 iter->data->sfname, strerror (uu_errno = errno));
1381 res = UURET_IOERR;
1382 break;
1383 }
1384 _FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
1385 }
1386
1387 progress.partno = part;
1388 progress.fsize = (iter->data->length)?iter->data->length:-1;
1389 progress.percent = 0;
1390 progress.foffset = iter->data->startpos;
1391
1392 fseek (datain, iter->data->startpos, SEEK_SET);
1393 res = UUDecodePart (datain, dataout, &state,
1394 iter->data->startpos+iter->data->length,
1395 data->uudet, iter->data->flags, NULL);
1396 fclose (datain);
1397
1398 if (uu_FileCallback)
1399 (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0);
1400
1401 if (state == DONE || res != UURET_OK)
1402 break;
1403
1404 iter = iter->NEXT;
1405 }
1406
1407 if (state == DATA &&
1408 (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1409 data->uudet == PT_ENCODED))
1410 state = DONE; /* assume we're done */
1411
1412 fclose (dataout);
1413
1414 if (res != UURET_OK || (state != DONE && !uu_desperate)) {
1415 unlink (data->binfile);
1416 _FP_free (data->binfile);
1417 data->binfile = NULL;
1418 data->state &= ~UUFILE_TMPFILE;
1419 data->state |= UUFILE_ERROR;
1420
1421 if (res == UURET_OK && state != DONE)
1422 res = UURET_NOEND;
1423 }
1424 else if (res != UURET_OK) {
1425 data->state &= ~UUFILE_DECODED;
1426 data->state |= UUFILE_ERROR | UUFILE_TMPFILE;
1427 }
1428 else {
1429 data->state &= ~UUFILE_ERROR;
1430 data->state |= UUFILE_TMPFILE;
1431 }
1432
1433 /*
1434 * If this was a BinHex file, we must extract its data or resource fork
1435 */
1436
1437 if (data->uudet == BH_ENCODED && data->binfile) {
1438 #ifdef HAVE_MKSTEMP
1439 ntmp = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
1440
1441 if (ntmp == NULL) {
1442 #else
1443 if ((ntmp = tempnam (NULL, "uu")) == NULL) {
1444 #endif /* HAVE_MKSTEMP */
1445 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1446 uustring (S_NO_TEMP_NAME));
1447 progress.action = 0;
1448 return UURET_NOMEM;
1449 }
1450 if ((datain = fopen (data->binfile, "rb")) == NULL) {
1451 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1452 uustring (S_NOT_OPEN_FILE),
1453 data->binfile, strerror (uu_errno = errno));
1454 progress.action = 0;
1455 free (ntmp);
1456 return UURET_IOERR;
1457 }
1458 #ifdef HAVE_MKSTEMP
1459 strcpy(ntmp, tmpdir);
1460 strcat(ntmp, "/");
1461 strcat(ntmp, tmpprefix);
1462 if ((tmpfd = mkstemp(ntmp)) == -1 ||
1463 (dataout = fdopen(tmpfd, "wb")) == NULL) {
1464 #else
1465 if ((dataout = fopen (ntmp, "wb")) == NULL) {
1466 #endif /* HAVE_MKSTEMP */
1467 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1468 uustring (S_NOT_OPEN_TARGET),
1469 ntmp, strerror (uu_errno = errno));
1470 progress.action = 0;
1471 fclose (datain);
1472 #ifdef HAVE_MKSTEMP
1473 if (tmpfd != -1) {
1474 unlink(ntmp);
1475 close(tmpfd);
1476 }
1477 #endif /* HAVE_MKSTEMP */
1478 free (ntmp);
1479 return UURET_IOERR;
1480 }
1481
1482 /*
1483 * read fork lengths. remember they're in Motorola format
1484 */
1485 r[0] = fgetc (datain);
1486 hb = (int) r[0] + 22;
1487 fseek (datain, (int) r[0] + 12, SEEK_SET);
1488 fread (r, 1, 8, datain);
1489
1490 dsize = (((long) 1 << 24) * (long) r[0]) +
1491 (((long) 1 << 16) * (long) r[1]) +
1492 (((long) 1 << 8) * (long) r[2]) +
1493 ( (long) r[3]);
1494 rsize = (((long) 1 << 24) * (long) r[4]) +
1495 (((long) 1 << 16) * (long) r[5]) +
1496 (((long) 1 << 8) * (long) r[6]) +
1497 ( (long) r[7]);
1498
1499 UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE,
1500 uustring (S_BINHEX_SIZES),
1501 dsize, rsize);
1502
1503 if (dsize == 0) {
1504 fseek (datain, dsize + hb + 2, SEEK_SET);
1505 numbytes = rsize;
1506 }
1507 else if (rsize == 0) {
1508 fseek (datain, hb, SEEK_SET);
1509 numbytes = dsize;
1510 }
1511 else {
1512 /* we should let the user have the choice here */
1513 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1514 uustring (S_BINHEX_BOTH));
1515 fseek (datain, hb, SEEK_SET);
1516 numbytes = dsize;
1517 }
1518
1519 progress.action = 0;
1520 progress.partno = 0;
1521 progress.numparts = 1;
1522 progress.fsize = (numbytes)?numbytes:-1;
1523 progress.foffset = hb;
1524 progress.percent = 0;
1525 progress.action = UUACT_COPYING;
1526
1527 /*
1528 * copy the chosen fork
1529 */
1530
1531 while (!feof (datain) && numbytes) {
1532 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
1533 UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1534 uustring (S_DECODE_CANCEL));
1535 fclose (datain);
1536 fclose (dataout);
1537 unlink (ntmp);
1538 free (ntmp);
1539 return UURET_CANCEL;
1540 }
1541
1542 bytes = fread (uugen_inbuffer, 1,
1543 (size_t) ((numbytes>1024)?1024:numbytes), datain);
1544
1545 if (ferror (datain) || (bytes == 0 && !feof (datain))) {
1546 progress.action = 0;
1547 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1548 uustring (S_SOURCE_READ_ERR),
1549 data->binfile, strerror (uu_errno = errno));
1550 fclose (datain);
1551 fclose (dataout);
1552 unlink (ntmp);
1553 free (ntmp);
1554 return UURET_IOERR;
1555 }
1556 if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) {
1557 progress.action = 0;
1558 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1559 uustring (S_WR_ERR_TARGET),
1560 ntmp, strerror (uu_errno = errno));
1561 fclose (datain);
1562 fclose (dataout);
1563 unlink (ntmp);
1564 free (ntmp);
1565 return UURET_IOERR;
1566 }
1567 numbytes -= bytes;
1568 }
1569
1570 if (numbytes) {
1571 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1572 uustring (S_SHORT_BINHEX),
1573 (data->filename)?data->filename:
1574 (data->subfname)?data->subfname:"???",
1575 numbytes);
1576 }
1577
1578 /*
1579 * replace temp file
1580 */
1581
1582 fclose (datain);
1583 fclose (dataout);
1584
1585 if (unlink (data->binfile)) {
1586 UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1587 uustring (S_TMP_NOT_REMOVED),
1588 data->binfile, strerror (uu_errno = errno));
1589 }
1590
1591 free (data->binfile);
1592 data->binfile = ntmp;
1593 }
1594
1595 progress.action = 0;
1596 return res;
1597 }
1598
1599 /*
1600 * QuickDecode for proper MIME attachments. We expect the pointer to
1601 * be on the first header line.
1602 */
1603
1604 int
1605 UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos)
1606 {
1607 int state=BEGIN, encoding=-1;
1608 headers myenv;
1609
1610 /*
1611 * Read header and find out about encoding.
1612 */
1613
1614 memset (&myenv, 0, sizeof (headers));
1615 UUScanHeader (datain, &myenv);
1616
1617 if (_FP_stristr (myenv.ctenc, "uu") != NULL)
1618 encoding = UU_ENCODED;
1619 else if (_FP_stristr (myenv.ctenc, "xx") != NULL)
1620 encoding = XX_ENCODED;
1621 else if (_FP_stricmp (myenv.ctenc, "base64") == 0)
1622 encoding = B64ENCODED;
1623 else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
1624 encoding = QP_ENCODED;
1625 else
1626 encoding = PT_ENCODED;
1627
1628 UUkillheaders (&myenv);
1629
1630 /*
1631 * okay, so decode this one
1632 */
1633
1634 (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* init */
1635 return UUDecodePart (datain, dataout, &state, maxpos,
1636 encoding, FL_PROPER|FL_TOEND,
1637 boundary);
1638 }