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

# 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.2 char * uunconc_id = "$Id: uunconc.c,v 1.29 2002/03/06 13:52:48 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.2 if ((s == NULL) || (*s == '\0')) {
301     return 0; /* bad string */
302 root 1.1 }
303 root 1.3.2.2
304 root 1.1 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 root 1.3.2.2 case YENC_ENCODED:
323     return YENC_ENCODED;
324 root 1.1 }
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 root 1.2 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 root 1.1 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 root 1.3.2.1 /* suspicious = 1; we're careful here REMOVED 0.4.15 __FP__ */
474 root 1.1 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 root 1.3.2.1 if (_FP_fgets (ptr, 255-(ptr-line), datei) == NULL)
547 root 1.1 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 root 1.3.2.2 i = table [ACAST(*s++)];
623 root 1.1 j = UUxlen[i] - 1;
624    
625     while(j > 0) {
626 root 1.3.2.2 c = table[ACAST(*s++)] << 2;
627     cc = table[ACAST(*s++)];
628 root 1.1 c |= (cc >> 4);
629    
630     if(i-- > 0)
631     d[count++] = c;
632    
633     cc <<= 4;
634 root 1.3.2.2 c = table[ACAST(*s++)];
635 root 1.1 cc |= (c >> 2);
636    
637     if(i-- > 0)
638     d[count++] = cc;
639    
640     c <<= 6;
641 root 1.3.2.2 c |= table[ACAST(*s++)];
642 root 1.1
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 root 1.3.2.2 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 root 1.1
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 root 1.3.2.1 if (_FP_fgets (line, 255, datain) == NULL)
749 root 1.1 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 root 1.3.2.1 if (_FP_fgets (line, 255, datain) == NULL)
846 root 1.1 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 root 1.2 (ftell(datain)<maxpos || flags&FL_TOEND || flags&FL_PARTIAL ||
884     !boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) {
885 root 1.1 *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 root 1.3.2.2 long yefilesize=0, yepartends=0;
905 root 1.1 static int bhflag=0;
906     size_t count=0;
907 root 1.3.2.2 char *ptr;
908 root 1.1
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 root 1.3.2.2 if (method == YENC_ENCODED) {
931     *state = BEGIN;
932     }
933    
934 root 1.1 while (!feof (datain) && *state != DONE &&
935     (ftell(datain)<maxpos || flags&FL_TOEND || maxpos==-1 ||
936     (!(flags&FL_PROPER) && uu_fast_scanning))) {
937 root 1.3.2.2 if (_FP_fgets (line, 299, datain) == NULL)
938 root 1.1 break;
939 root 1.3.2.2
940 root 1.1 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 root 1.3.2.2
947 root 1.1 if (line[0]=='\015' || line[0]=='\012') { /* Empty line? */
948     if (*state == DATA &&
949     (method == UU_ENCODED || method == XX_ENCODED))
950     *state = END;
951 root 1.3.2.2
952 root 1.1 /*
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 root 1.3.2.2
959 root 1.1 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 root 1.3.2.2 line[299] = '\0'; /* For Safety of string functions */
980 root 1.1 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 root 1.3.2.1 _FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */
998 root 1.1 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 root 1.3.2.1 if (_FP_strnicmp (line, "Content-Type", 12) == 0)
1014 root 1.1 hadct = 1;
1015     }
1016    
1017     if (*state == BEGIN) {
1018 root 1.3.2.2 if ((method == UU_ENCODED || method == XX_ENCODED) &&
1019     (strncmp (line, "begin ", 6) == 0 ||
1020     _FP_strnicmp (line, "<pre>begin ", 11) == 0)) { /* for LYNX */
1021 root 1.1 *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 root 1.3.2.2 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 root 1.1 continue;
1057 root 1.3.2.2 }
1058 root 1.1
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 root 1.3.2.2
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 root 1.1 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 root 1.3.2.1 _FP_strncpy (save[tc++], line, 256);
1125 root 1.1 }
1126 root 1.3.2.2
1127 root 1.1 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 root 1.3.2.2
1146 root 1.1 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 root 1.2 if (data->uudet == PT_ENCODED)
1219 root 1.1 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 root 1.3.2.1 _FP_free (data->binfile);
1238 root 1.1 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 root 1.3.2.1 _FP_strncpy (progress.curfile,
1267 root 1.1 (strlen(data->filename)>255)?
1268     (data->filename+strlen(data->filename)-255):data->filename,
1269     256);
1270     }
1271     else {
1272 root 1.3.2.1 _FP_strncpy (progress.curfile,
1273 root 1.1 (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 root 1.3.2.1 _FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
1332 root 1.1 }
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 root 1.3.2.1 _FP_free (data->binfile);
1364 root 1.1 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 root 1.3.2.1 if (_FP_stristr (myenv.ctenc, "uu") != NULL)
1544 root 1.1 encoding = UU_ENCODED;
1545 root 1.3.2.1 else if (_FP_stristr (myenv.ctenc, "xx") != NULL)
1546 root 1.1 encoding = XX_ENCODED;
1547 root 1.3.2.1 else if (_FP_stricmp (myenv.ctenc, "base64") == 0)
1548 root 1.1 encoding = B64ENCODED;
1549 root 1.3.2.1 else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
1550 root 1.1 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     }