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