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