ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Convert-UUlib/uulib/uunconc.c
Revision: 1.3.2.1
Committed: Sun Mar 31 19:51:29 2002 UTC (24 years, 6 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-15
Changes since 1.3: +37 -93 lines
Log Message:
*** empty log message ***

File Contents

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