ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uunconc.c
Revision: 1.30
Committed: Sat Sep 24 06:02:04 2022 UTC (20 months, 1 week ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.29: +0 -2 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.11 #include <crc32.h>
53 root 1.2 #include <uudeview.h>
54 root 1.1 #include <uuint.h>
55     #include <fptools.h>
56     #include <uustring.h>
57    
58     /* for braindead systems */
59     #ifndef SEEK_SET
60     #ifdef L_BEGIN
61     #define SEEK_SET L_BEGIN
62     #else
63     #define SEEK_SET 0
64     #endif
65     #endif
66    
67     /*
68     * decoder states
69     */
70    
71     #define BEGIN (1)
72     #define DATA (2)
73     #define END (3)
74     #define DONE (4)
75    
76     /*
77     * mallocable areas
78     */
79    
80     char *uunconc_UUxlat;
81     char *uunconc_UUxlen;
82     char *uunconc_B64xlat;
83     char *uunconc_XXxlat;
84     char *uunconc_BHxlat;
85     char *uunconc_save;
86    
87     /*
88     * decoding translation tables and line length table
89     */
90    
91     static int * UUxlen; /* initialized in UUInitConc() */
92     static int * UUxlat; /* from the malloc'ed areas above */
93     static int * B64xlat;
94     static int * XXxlat;
95     static int * BHxlat;
96    
97     /*
98     * buffer for decoding
99     */
100    
101     static char *save[3];
102    
103     /*
104     * mallocable areas
105     */
106    
107     char *uuncdl_fulline;
108     char *uuncdp_oline;
109    
110     /*
111     * Return information for QuickDecode
112     */
113    
114     static int uulboundary;
115    
116     /*
117     * To prevent warnings when using a char as index into an array
118     */
119    
120     #define ACAST(s) ((int)(uchar)(s))
121    
122     /*
123     * Initialize decoding tables
124     */
125    
126     void
127     UUInitConc (void)
128     {
129     int i, j;
130    
131     /*
132     * Update pointers
133     */
134     UUxlen = (int *) uunconc_UUxlen;
135     UUxlat = (int *) uunconc_UUxlat;
136     B64xlat = (int *) uunconc_B64xlat;
137     XXxlat = (int *) uunconc_XXxlat;
138     BHxlat = (int *) uunconc_BHxlat;
139    
140     save[0] = uunconc_save;
141 root 1.9 save[1] = uunconc_save + 1200;
142     save[2] = uunconc_save + 2400;
143 root 1.1
144     /* prepare decoding translation table */
145     for(i = 0; i < 256; i++)
146     UUxlat[i] = B64xlat[i] = XXxlat[i] = BHxlat[i] = -1;
147    
148     /*
149     * At some time I received a file which used lowercase characters for
150     * uuencoding. This shouldn't be, but let's accept it. Must take special
151     * care that this doesn't break xxdecoding. This is giving me quite a
152     * headache. If this one file hadn't been a Pocahontas picture, I might
153     * have ignored it for good.
154     */
155    
156     for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
157     UUxlat[i] /* = UUxlat[i+64] */ = j;
158     for (i = '`', j = 0; i < '`' + 32; i++, j++)
159     UUxlat[i] = j;
160    
161     /* add special cases */
162     UUxlat['`'] = UUxlat[' '];
163     UUxlat['~'] = UUxlat['^'];
164    
165     /* prepare line length table */
166     UUxlen[0] = 1;
167 root 1.2 for(i = 1, j = 5; i <= 61; i += 3, j += 4)
168 root 1.1 UUxlen[i] = UUxlen[i+1] = UUxlen[i+2] = j;
169    
170     /* prepare other tables */
171     for (i=0; i<64; i++) {
172     B64xlat[ACAST(B64EncodeTable[i])] = i;
173     XXxlat [ACAST(XXEncodeTable [i])] = i;
174     BHxlat [ACAST(BHEncodeTable [i])] = i;
175     }
176     }
177    
178     /*
179     * Workaround for Netscape
180     */
181    
182     /*
183     * Determines whether Netscape may have broken up a data line (by
184     * inserting a newline). This only seems to happen after <a in a
185     * href statement
186     */
187    
188     int
189     UUBrokenByNetscape (char *string)
190     {
191     char *ptr;
192     int len;
193    
194     if (string==NULL || (len=strlen(string))<3)
195     return 0;
196    
197 root 1.27 if ((ptr = FP_stristr (string, "<a href=")) != NULL) {
198     if (FP_stristr (string, "</a>") > ptr)
199 root 1.1 return 2;
200     }
201    
202     ptr = string + len;
203    
204     if (len<3) return 0;
205     if (*--ptr == ' ') ptr--;
206     ptr--;
207    
208 root 1.27 if (FP_strnicmp (ptr, "<a", 2) == 0)
209 root 1.1 return 1;
210    
211     return 0;
212     }
213    
214     /*
215     * Try to repair a Netscape-corrupted line of data.
216     * This must only be called on corrupted lines, since non-Netscape
217     * data may even _get_ corrupted by this procedure.
218 root 1.26 *
219 root 1.1 * Some checks are included multiply to speed up the procedure. For
220     * example: (*p1!='<' || strnicmp(p1,"</a>",4)). If the first expression
221     * becomes true, the costly function isn't called :-)
222     *
223     * Since '<', '>', '&' might even be replaced by their html equivalents
224     * in href strings, I'm now using two passes, the first one for &amp; + co,
225     * the second one for hrefs.
226     */
227    
228     int
229     UUNetscapeCollapse (char *string)
230     {
231     char *p1=string, *p2=string;
232     int res = 0;
233    
234     if (string==NULL)
235     return 0;
236    
237     /*
238     * First pass
239     */
240     while (*p1) {
241     if (*p1 == '&') {
242 root 1.27 if (FP_strnicmp (p1, "&amp;", 5) == 0) { p1+=5; *p2++='&'; res=1; }
243     else if (FP_strnicmp (p1, "&lt;", 4) == 0) { p1+=4; *p2++='<'; res=1; }
244     else if (FP_strnicmp (p1, "&gt;", 4) == 0) { p1+=4; *p2++='>'; res=1; }
245 root 1.1 else *p2++ = *p1++;
246     res = 1;
247     }
248     else *p2++ = *p1++;
249     }
250     *p2 = '\0';
251     /*
252     * Second pass
253     */
254     p1 = p2 = string;
255    
256     while (*p1) {
257     if (*p1 == '<') {
258 root 1.27 if ((FP_strnicmp (p1, "<ahref=", 7) == 0 ||
259     FP_strnicmp (p1, "<a href=",8) == 0) &&
260     (FP_strstr (p1, "</a>") != 0 || FP_strstr (p1, "</A>") != 0)) {
261 root 1.1 while (*p1 && *p1!='>') p1++;
262     if (*p1=='\0' || *(p1+1)!='<') return 0;
263     p1++;
264 root 1.27 while (*p1 && (*p1!='<' || FP_strnicmp(p1,"</a>",4)!=0)) {
265 root 1.1 *p2++ = *p1++;
266     }
267 root 1.27 if (FP_strnicmp(p1,"</a>",4) != 0)
268 root 1.1 return 0;
269     p1+=4;
270     res=1;
271     }
272     else
273     *p2++ = *p1++;
274     }
275     else
276     *p2++ = *p1++;
277     }
278     *p2 = '\0';
279    
280     return res;
281     }
282    
283     /*
284     * The second parameter is 0 if we are still searching for encoded data,
285     * otherwise it indicates the encoding we're using right now. If we're
286     * still in the searching stage, we must be a little more strict in
287     * deciding for or against encoding; there's too much plain text looking
288     * like encoded data :-(
289     */
290    
291     int
292     UUValidData (char *ptr, int encoding, int *bhflag)
293     {
294     int i=0, j, len=0, suspicious=0, flag=0;
295 root 1.14 signed char *s = ptr;
296 root 1.1
297 root 1.4 if ((s == NULL) || (*s == '\0')) {
298     return 0; /* bad string */
299 root 1.1 }
300 root 1.4
301 root 1.22 if (encoding == YENC_ENCODED)
302     return YENC_ENCODED;
303 root 1.1
304 root 1.22 i = strlen (s);
305 root 1.1
306     switch (encoding) {
307     case UU_ENCODED:
308     goto _t_UU;
309     case XX_ENCODED:
310     goto _t_XX;
311     case B64ENCODED:
312     goto _t_B64;
313     case BH_ENCODED:
314     goto _t_Binhex;
315     }
316    
317     _t_Binhex: /* Binhex Test */
318     len = i; s = ptr;
319    
320     /*
321     * bhflag notes the state we're in. Within the data, it's 1. If we're
322     * still looking for the initial :, it's 0
323     */
324     if (*bhflag == 0 && *s != ':') {
325     if (encoding==BH_ENCODED) return 0;
326     goto _t_B64;
327     }
328     else if (*bhflag == 0 /* *s == ':' */) {
329     s++; len--;
330     }
331    
332     while (len && BHxlat[ACAST(*s)] != -1) {
333     len--; s++;
334     }
335    
336     /* allow space characters at the end of the line if we are sure */
337     /* that this is Binhex encoded data or the line was long enough */
338    
339     flag = (*s == ':') ? 0 : 1;
340    
341     if (*s == ':' && len>0) {
342     s++; len--;
343     }
344     if (((i>=60 && len<=10) || encoding) && *s==' ') {
345     while (len && *s==' ') {
346     s++; len--;
347     }
348     }
349    
350     /*
351     * BinHex data shall have exactly 64 characters (except the last
352     * line). We ignore everything with less than 40 characters to
353     * be flexible
354     */
355    
356     if (len != 0 || (flag && i < 40)) {
357     if (encoding==BH_ENCODED) return 0;
358     goto _t_B64;
359     }
360    
361     *bhflag = flag;
362    
363     return BH_ENCODED;
364    
365     _t_B64: /* Base64 Test */
366     len = i; s = ptr;
367    
368     /*
369     * Face it: there _are_ Base64 lines that are not a multiple of four
370     * in length :-(
371     *
372     * if (len%4)
373     * goto _t_UU;
374     */
375    
376     while (len--) {
377     if (*s < 0 || (B64xlat[ACAST(*s)] == -1 && *s != '=')) {
378     /* allow space characters at the end of the line if we are sure */
379     /* that this is Base64 encoded data or the line was long enough */
380     if (((i>=60 && len<=10) || encoding) && *s++==' ') {
381     while (*s==' ' && len) s++;
382     if (len==0) return B64ENCODED;
383     }
384     if (encoding==B64ENCODED) return 0;
385     goto _t_UU;
386     }
387     else if (*s == '=') { /* special case at end */
388     /* if we know this is B64encoded, allow spaces at end of line */
389     s++;
390     if (*s=='=' && len>=1) {
391     len--; s++;
392     }
393     if (encoding && len && *s==' ') {
394     while (len && *s==' ') {
395     s++; len--;
396     }
397     }
398     if (len != 0) {
399     if (encoding==B64ENCODED) return 0;
400     goto _t_UU;
401     }
402     return B64ENCODED;
403     }
404     s++;
405     }
406     return B64ENCODED;
407    
408     _t_UU:
409     len = i; s = ptr;
410    
411     if (UUxlat[ACAST(*s)] == -1) { /* uutest */
412     if (encoding==UU_ENCODED) return 0;
413     goto _t_XX;
414     }
415    
416     j = UUxlen[UUxlat[ACAST(*s)]];
417    
418     if (len-1 == j) /* remove trailing character */
419     len--;
420     if (len != j) {
421     switch (UUxlat[ACAST(*s)]%3) {
422     case 1:
423     if (j-2 == len) j-=2;
424     break;
425     case 2:
426     if (j-1 == len) j-=1;
427     break;
428     }
429     }
430    
431     /*
432     * some encoders are broken with respect to encoding the last line of
433     * a file and produce extraoneous characters beyond the expected EOL
434     * So were not too picky here about the last line, as long as it's longer
435     * than necessary and shorter than the maximum
436     * this tolerance broke the xxdecoding, because xxencoded data was
437     * detected as being uuencoded :( so don't accept 'h' as first character
438     * also, if the first character is lowercase, don't accept the line to
439     * have space characters. the only encoder I've heard of which uses
440     * lowercase characters at least accepts the special case of encoding
441     * 0 as `. The strchr() shouldn't be too expensive here as it's only
442     * evaluated if the first character is lowercase, which really shouldn't
443     * be in uuencoded text.
444     */
445 root 1.2 if (len != j &&
446     ((ptr[0] == '-' && ptr[1] == '-' && strstr(ptr,"part")!=NULL) ||
447     !(*ptr != 'M' && *ptr != 'h' &&
448     len > j && len <= UUxlen[UUxlat['M']]))) {
449 root 1.1 if (encoding==UU_ENCODED) return 0;
450     goto _t_XX; /* bad length */
451     }
452    
453     if (len != j || islower (*ptr)) {
454     /*
455     * if we are not in a 'uuencoded' state, don't allow the line to have
456     * space characters at all. if we know we _are_ decoding uuencoded
457     * data, the rest of the line, beyond the length of encoded data, may
458     * have spaces.
459     */
460     if (encoding != UU_ENCODED)
461     if (strchr (ptr, ' ') != NULL)
462     goto _t_XX;
463    
464 root 1.5 /* suspicious = 1; we're careful here REMOVED 0.4.15 __FP__ */
465 root 1.1 len = j;
466     }
467    
468     while (len--) {
469     if (*s < 0 || UUxlat[ACAST(*s++)] < 0) {
470     if (encoding==UU_ENCODED) return 0;
471     goto _t_XX; /* bad code character */
472     }
473     if (*s == ' ' && suspicious) {
474     if (encoding==UU_ENCODED) return 0;
475     goto _t_XX; /* this line looks _too_ suspicious */
476     }
477     }
478     return UU_ENCODED; /* data is valid */
479    
480     _t_XX: /* XX Test */
481     len = i; s = ptr;
482    
483     if (XXxlat[ACAST(*s)] == -1)
484     return 0;
485    
486     j = UUxlen[XXxlat[ACAST(*s)]]; /* Same line length table as UUencoding */
487    
488     if (len-1 == j) /* remove trailing character */
489     len--;
490     if (len != j)
491     switch (UUxlat[ACAST(*s)]%3) {
492     case 1:
493     if (j-2 == len) j-=2;
494     break;
495     case 2:
496     if (j-1 == len) j-=1;
497     break;
498     }
499     /*
500     * some encoders are broken with respect to encoding the last line of
501     * a file and produce extraoneous characters beyond the expected EOL
502     * So were not too picky here about the last line, as long as it's longer
503     * than necessary and shorter than the maximum
504     */
505     if (len != j && !(*ptr != 'h' && len > j && len <= UUxlen[UUxlat['h']]))
506     return 0; /* bad length */
507    
508     while(len--) {
509     if(*s < 0 || XXxlat[ACAST(*s++)] < 0) {
510     return 0; /* bad code character */
511     }
512     }
513     return XX_ENCODED; /* data is valid */
514     }
515    
516     /*
517     * This function may be called upon a line that does not look like
518     * valid encoding on first sight, but might be erroneously encoded
519     * data from Netscape, Lynx or MS Exchange. We might need to read
520     * a new line from the stream, which is why we need the FILE.
521     * Returns the type of encoded data if successful or 0 otherwise.
522     */
523    
524     int
525     UURepairData (FILE *datei, char *line, int encoding, int *bhflag)
526     {
527     int nflag, vflag=0, safety=42;
528     char *ptr;
529    
530     nflag = UUBrokenByNetscape (line);
531    
532     while (vflag == 0 && nflag && safety--) {
533     if (nflag == 1) { /* need next line to repair */
534 root 1.12 if (strlen (line) > 250)
535     break;
536 root 1.1 ptr = line + strlen (line);
537 root 1.27 if (FP_fgets (ptr, 299-(ptr-line), datei) == NULL)
538 root 1.1 break;
539     }
540     else { /* don't need next line to repair */
541     }
542     if (UUNetscapeCollapse (line)) {
543     if ((vflag = UUValidData (line, encoding, bhflag)) == 0)
544     nflag = UUBrokenByNetscape (line);
545     }
546     else
547     nflag = 0;
548     }
549     /*
550     * Sometimes, a line is garbled even without it being split into
551     * the next line. Then we try this in our despair
552     */
553     if (vflag == 0) {
554     if (UUNetscapeCollapse (line))
555     vflag = UUValidData (line, encoding, bhflag);
556     }
557    
558     /*
559     * If this line looks uuencoded, but the line is one character short
560     * of a valid line, it was probably broken by MS Exchange. According
561     * to my test cases, there is at most one space character missing;
562     * there are never two spaces together.
563     * If adding a space character helps making this line uuencoded, do
564     * it!
565     */
566    
567     if (vflag == 0) {
568     ptr = line + strlen(line);
569     *ptr++ = ' ';
570     *ptr-- = '\0';
571     if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) {
572     *ptr = '\0';
573     vflag = 0;
574     }
575     }
576     return vflag;
577     }
578    
579     /*
580     * Decode a single encoded line using method
581     */
582    
583     size_t
584     UUDecodeLine (char *s, char *d, int method)
585     {
586     int i, j, c, cc, count=0, z1, z2, z3, z4;
587     static int leftover=0;
588     int *table;
589    
590     /*
591     * for re-initialization
592     */
593    
594     if (s == NULL || d == NULL) {
595     leftover = 0;
596     return 0;
597     }
598    
599     /*
600     * To shut up gcc -Wall
601     */
602     z1 = z2 = z3 = z4 = 0;
603    
604 root 1.29 if (method == YENC_ENCODED) {
605     while (*s) {
606     if (ecb_expect_false (*s == '=')) {
607     if (*++s != '\0') {
608     d[count++] = (char) ((int) *s - 64 - 42);
609     s++;
610     }
611     }
612     #if 0 /* FP_fgets never leaves CR or LF in the buffer, so skip this */
613     else if (ecb_expect_false (*s == '\n' || *s == '\r')) {
614     s++; /* ignore */
615     }
616     #endif
617     else {
618     d[count++] = (char) ((int) *s++ - 42);
619     }
620     }
621     }
622     else if (method == UU_ENCODED || method == XX_ENCODED) {
623 root 1.1 if (method == UU_ENCODED)
624     table = UUxlat;
625     else
626     table = XXxlat;
627    
628 root 1.4 i = table [ACAST(*s++)];
629 root 1.1 j = UUxlen[i] - 1;
630    
631     while(j > 0) {
632 root 1.4 c = table[ACAST(*s++)] << 2;
633     cc = table[ACAST(*s++)];
634 root 1.1 c |= (cc >> 4);
635    
636     if(i-- > 0)
637     d[count++] = c;
638 root 1.26
639 root 1.1 cc <<= 4;
640 root 1.4 c = table[ACAST(*s++)];
641 root 1.1 cc |= (c >> 2);
642 root 1.26
643 root 1.1 if(i-- > 0)
644     d[count++] = cc;
645 root 1.26
646 root 1.1 c <<= 6;
647 root 1.4 c |= table[ACAST(*s++)];
648 root 1.26
649 root 1.1 if(i-- > 0)
650     d[count++] = c;
651 root 1.26
652 root 1.1 j -= 4;
653     }
654     }
655     else if (method == B64ENCODED) {
656     if (leftover) {
657 root 1.9 strcpy (uuncdl_fulline + leftover, s);
658 root 1.7
659 root 1.1 leftover = 0;
660     s = uuncdl_fulline;
661     }
662    
663     while ((z1 = B64xlat[ACAST(*s)]) != -1) {
664     if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
665     if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
666     if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
667    
668     d[count++] = (z1 << 2) | (z2 >> 4);
669     d[count++] = (z2 << 4) | (z3 >> 2);
670     d[count++] = (z3 << 6) | (z4);
671    
672     s += 4;
673     }
674     if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
675     d[count++] = (z1 << 2) | (z2 >> 4);
676     s+=2;
677     }
678     else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
679     d[count++] = (z1 << 2) | (z2 >> 4);
680     d[count++] = (z2 << 4) | (z3 >> 2);
681     s+=3;
682     }
683     while (B64xlat[ACAST(*s)] != -1)
684     uuncdl_fulline[leftover++] = *s++;
685     }
686     else if (method == BH_ENCODED) {
687     if (leftover) {
688 root 1.9 strcpy (uuncdl_fulline + leftover, s);
689 root 1.8
690 root 1.1 leftover = 0;
691     s = uuncdl_fulline;
692     }
693     else if (*s == ':')
694     s++;
695    
696     while ((z1 = BHxlat[ACAST(*s)]) != -1) {
697     if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break;
698     if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break;
699     if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break;
700    
701     d[count++] = (z1 << 2) | (z2 >> 4);
702     d[count++] = (z2 << 4) | (z3 >> 2);
703     d[count++] = (z3 << 6) | (z4);
704    
705     s += 4;
706     }
707     if (z1 != -1 && z2 != -1 && *(s+2) == ':') {
708     d[count++] = (z1 << 2) | (z2 >> 4);
709     s+=2;
710     }
711     else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') {
712     d[count++] = (z1 << 2) | (z2 >> 4);
713     d[count++] = (z2 << 4) | (z3 >> 2);
714     s+=3;
715     }
716     while (BHxlat[ACAST(*s)] != -1)
717     uuncdl_fulline[leftover++] = *s++;
718     }
719    
720     return count;
721     }
722    
723     /*
724     * ``Decode'' Quoted-Printable text
725     */
726    
727     int
728     UUDecodeQP (FILE *datain, FILE *dataout, int *state,
729     long maxpos, int method, int flags,
730     char *boundary)
731     {
732     char *line=uugen_inbuffer, *p1, *p2;
733     int val;
734    
735     uulboundary = -1;
736    
737 root 1.27 while (!FP_feof (datain) &&
738 root 1.1 (ftell(datain)<maxpos || flags&FL_TOEND ||
739     (!(flags&FL_PROPER) && uu_fast_scanning))) {
740 root 1.27 if (FP_fgets (line, 1023, datain) == NULL)
741 root 1.1 break;
742     if (ferror (datain)) {
743     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
744     uustring (S_SOURCE_READ_ERR),
745     strerror (uu_errno = errno));
746     return UURET_IOERR;
747     }
748     line[255] = '\0';
749    
750     if (boundary && line[0]=='-' && line[1]=='-' &&
751     strncmp (line+2, boundary, strlen (boundary)) == 0) {
752     if (line[strlen(boundary)+2]=='-')
753     uulboundary = 1;
754     else
755     uulboundary = 0;
756     return UURET_OK;
757     }
758    
759     if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
760     UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
761     uustring (S_DECODE_CANCEL));
762     return UURET_CANCEL;
763     }
764    
765     p1 = p2 = line;
766    
767     while (*p2) {
768     while (*p2 && *p2 != '=')
769     p2++;
770     if (*p2 == '\0')
771     break;
772     *p2 = '\0';
773     fprintf (dataout, "%s", p1);
774     p1 = ++p2;
775    
776     if (isxdigit (*p2) && isxdigit (*(p2+1))) {
777     val = ((isdigit(*p2)) ? (*p2-'0') : (tolower(*p2)-'a'+10)) << 4;
778     val |= ((isdigit(*(p2+1)))?(*(p2+1)-'0') : (tolower(*(p2+1))-'a'+10));
779    
780     fputc (val, dataout);
781     p2 += 2;
782     p1 = p2;
783     }
784 root 1.17 else if (!*p2) {
785 root 1.1 /* soft line break */
786 root 1.20 goto skip_lbr;
787 root 1.1 break;
788     }
789     else {
790     /* huh? */
791     fputc ('=', dataout);
792     }
793     }
794 root 1.20 /*
795     * p2 points to a nullbyte right after the CR/LF/CRLF
796     */
797     val = 0;
798     while (p2>p1 && isspace (*(p2-1))) {
799     if (*(p2-1) == '\012' || *(p2-1) == '\015')
800     val = 1;
801     p2--;
802     }
803     *p2 = '\0';
804 root 1.1
805     /*
806     * If the part ends directly after this line, the data does not end
807     * with a linebreak. Or, as the docs put it, "the CRLF preceding the
808     * encapsulation line is conceptually attached to the boundary.
809     * So if the part ends here, don't print a line break"
810     */
811 root 1.17 /* something is broken here now, but it was broken before */
812 root 1.27 if (!FP_feof (datain) &&
813 root 1.17 (ftell(datain)<maxpos || flags&FL_TOEND ||
814     (!(flags&FL_PROPER) && uu_fast_scanning)))
815 root 1.1 fprintf (dataout, "%s\n", p1);
816     else
817     fprintf (dataout, "%s", p1);
818 root 1.20
819     skip_lbr: ;
820 root 1.1 }
821     return UURET_OK;
822     }
823    
824     /*
825     * ``Decode'' plain text. Our job is to properly handle the EOL sequence
826     */
827    
828     int
829     UUDecodePT (FILE *datain, FILE *dataout, int *state,
830     long maxpos, int method, int flags,
831     char *boundary)
832     {
833     char *line=uugen_inbuffer, *ptr;
834    
835     uulboundary = -1;
836    
837 root 1.27 while (!FP_feof (datain) &&
838 root 1.1 (ftell(datain)<maxpos || flags&FL_TOEND ||
839     (!(flags&FL_PROPER) && uu_fast_scanning))) {
840 root 1.27 if (FP_fgets (line, 1023, datain) == NULL)
841 root 1.1 break;
842     if (ferror (datain)) {
843     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
844     uustring (S_SOURCE_READ_ERR),
845     strerror (uu_errno = errno));
846     return UURET_IOERR;
847     }
848     line[255] = '\0';
849    
850     if (boundary && line[0]=='-' && line[1]=='-' &&
851     strncmp (line+2, boundary, strlen (boundary)) == 0) {
852     if (line[strlen(boundary)+2]=='-')
853     uulboundary = 1;
854     else
855     uulboundary = 0;
856     return UURET_OK;
857     }
858    
859     if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
860     UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
861     uustring (S_DECODE_CANCEL));
862     return UURET_CANCEL;
863     }
864    
865     ptr = line + strlen (line);
866    
867     /*
868     * If the part ends directly after this line, the data does not end
869     * with a linebreak. Or, as the docs put it, "the CRLF preceding the
870     * encapsulation line is conceptually attached to the boundary.
871     * So if the part ends here, don't print a line break"
872     */
873 root 1.17 if ((ftell(datain)<maxpos || flags&FL_TOEND || flags&FL_PARTIAL ||
874 root 1.2 !boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) {
875 root 1.1 *ptr = '\0';
876     fprintf (dataout, "%s\n", line);
877     }
878     else {
879     *ptr = '\0';
880     fprintf (dataout, "%s", line);
881     }
882     }
883     return UURET_OK;
884     }
885    
886 root 1.12 /*
887     * Decode a single field using method. For the moment, this supports
888     * Base64 and Quoted Printable only, to support RFC 1522 header decoding.
889     * Quit when seeing the RFC 1522 ?= end marker.
890     */
891    
892     int
893     UUDecodeField (char *s, char *d, int method)
894     {
895     int z1, z2, z3, z4;
896     int count=0;
897    
898     if (method == B64ENCODED) {
899     while ((z1 = B64xlat[ACAST(*s)]) != -1) {
900     if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
901     if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
902     if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
903    
904     d[count++] = (z1 << 2) | (z2 >> 4);
905     d[count++] = (z2 << 4) | (z3 >> 2);
906     d[count++] = (z3 << 6) | (z4);
907    
908     s+=4;
909     }
910     if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
911     d[count++] = (z1 << 2) | (z2 >> 4);
912     s+=2;
913     }
914     else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
915     d[count++] = (z1 << 2) | (z2 >> 4);
916     d[count++] = (z2 << 4) | (z3 >> 2);
917     s+=3;
918     }
919     }
920     else if (method == QP_ENCODED) {
921     while (*s && (*s != '?' || *(s+1) != '=')) {
922     while (*s && *s != '=' && (*s != '?' || *(s+1) != '=')) {
923     d[count++] = *s++;
924     }
925     if (*s == '=') {
926     if (isxdigit (*(s+1)) && isxdigit (*(s+2))) {
927     d[count] = (isdigit (*(s+1)) ? (*(s+1)-'0') : (tolower (*(s+1))-'a'+10)) << 4;
928     d[count] |= (isdigit (*(s+2)) ? (*(s+2)-'0') : (tolower (*(s+2))-'a'+10));
929     count++;
930     s+=3;
931     }
932 root 1.17 else if (!s[1]) {
933     d[count++] = '\012';
934 root 1.12 }
935     else {
936     d[count++] = *s++;
937     }
938     }
939     }
940     }
941     else {
942     return -1;
943     }
944    
945     d[count] = '\0';
946     return count;
947     }
948    
949 root 1.1 int
950     UUDecodePart (FILE *datain, FILE *dataout, int *state,
951     long maxpos, int method, int flags,
952     char *boundary)
953     {
954 root 1.9 char *line, *oline=uuncdp_oline;
955 root 1.1 int warning=0, vlc=0, lc[2], hadct=0;
956     int tc=0, tf=0, vflag, haddata=0, haddh=0;
957 root 1.19 long yefilesize=0, yepartends=0, yenotlastpart=0;
958 root 1.24 crc32_t yepartcrc=CRC32_INIT;
959 root 1.25 static crc32_t yefilecrc;
960 root 1.1 static int bhflag=0;
961     size_t count=0;
962 root 1.11 size_t yepartsize=0;
963 root 1.4 char *ptr;
964 root 1.1
965     if (datain == NULL || dataout == NULL) {
966 root 1.24 yefilecrc = CRC32_INIT;
967 root 1.1 bhflag = 0;
968     return UURET_OK;
969     }
970    
971     /*
972     * Use specialized functions for QP_ENCODED and PT_ENCODED plaintext
973     */
974    
975     if (method == QP_ENCODED)
976     return UUDecodeQP (datain, dataout, state, maxpos,
977     method, flags, boundary);
978     else if (method == PT_ENCODED)
979     return UUDecodePT (datain, dataout, state, maxpos,
980     method, flags, boundary);
981    
982     lc[0] = lc[1] = 0;
983     vflag = 0;
984    
985     uulboundary = -1;
986    
987 root 1.4 if (method == YENC_ENCODED) {
988     *state = BEGIN;
989     }
990    
991 root 1.27 while (!FP_feof (datain) && *state != DONE &&
992 root 1.1 (ftell(datain)<maxpos || flags&FL_TOEND || maxpos==-1 ||
993     (!(flags&FL_PROPER) && uu_fast_scanning))) {
994 root 1.27 if (FP_fgets ((line = uugen_fnbuffer), 1200 - 5, datain) == NULL)
995 root 1.1 break;
996 root 1.4
997 root 1.9 /* optionally skip .. */
998     if (*line == '.' && uu_dotdot)
999     line++;
1000    
1001 root 1.1 if (ferror (datain)) {
1002     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1003     uustring (S_SOURCE_READ_ERR),
1004     strerror (uu_errno = errno));
1005     return UURET_IOERR;
1006     }
1007 root 1.4
1008 root 1.17 if (!*line) { /* Empty line? */
1009 root 1.1 if (*state == DATA &&
1010     (method == UU_ENCODED || method == XX_ENCODED))
1011     *state = END;
1012 root 1.4
1013 root 1.1 /*
1014     * if we had a whole block of valid lines before, we reset our
1015     * 'valid data' flag, tf. Without this 'if', we'd break decoding
1016     * files with interleaved blank lines. The value of 5 is chosen
1017     * quite arbitrarly.
1018     */
1019 root 1.4
1020 root 1.1 if (vlc > 5)
1021     tf = tc = 0;
1022     vlc = 0;
1023     continue;
1024     }
1025 root 1.26
1026 root 1.1 /*
1027     * Busy Polls
1028     */
1029    
1030     if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
1031     UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1032     uustring (S_DECODE_CANCEL));
1033     return UURET_CANCEL;
1034     }
1035    
1036     /*
1037     * try to make sense of data
1038     */
1039    
1040 root 1.9 line[1200 - 1] = '\0'; /* For Safety of string functions */
1041     count = 0;
1042 root 1.1
1043     if (boundary && line[0]=='-' && line[1]=='-' &&
1044     strncmp (line+2, boundary, strlen (boundary)) == 0) {
1045     if (line[strlen(boundary)+2]=='-')
1046     uulboundary = 1;
1047     else
1048     uulboundary = 0;
1049     return UURET_OK;
1050     }
1051    
1052     /*
1053     * Use this pseudo-handling only if !FL_PROPER
1054     */
1055    
1056     if ((flags&FL_PROPER) == 0) {
1057     if (strncmp (line, "BEGIN", 5) == 0 &&
1058 root 1.27 FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */
1059 root 1.1 tc = tf = vlc = 0;
1060     continue;
1061     }
1062     /* MIME body boundary */
1063     if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) {
1064     if ((haddata || tc) && (haddh || hadct)) {
1065     *state = DONE;
1066     vlc = 0;
1067     lc[0] = lc[1] = 0;
1068     continue;
1069     }
1070     hadct = 0;
1071     haddh = 1;
1072     continue;
1073     }
1074 root 1.27 if (FP_strnicmp (line, "Content-Type", 12) == 0)
1075 root 1.1 hadct = 1;
1076     }
1077    
1078     if (*state == BEGIN) {
1079 root 1.4 if ((method == UU_ENCODED || method == XX_ENCODED) &&
1080     (strncmp (line, "begin ", 6) == 0 ||
1081 root 1.27 FP_strnicmp (line, "<pre>begin ", 11) == 0)) { /* for LYNX */
1082 root 1.1 *state = DATA;
1083     continue;
1084     }
1085     else if (method == BH_ENCODED && line[0] == ':') {
1086     if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) {
1087     bhflag = 0;
1088     *state = DATA;
1089     }
1090     else
1091     continue;
1092     }
1093 root 1.4 else if (method == YENC_ENCODED &&
1094     strncmp (line, "=ybegin ", 8) == 0 &&
1095 root 1.27 FP_strstr (line, " name=") != NULL) {
1096 root 1.4 *state = DATA;
1097    
1098 root 1.27 if ((ptr = FP_strstr (line, " size=")) != NULL) {
1099 root 1.11 ptr += 6;
1100     yefilesize = atoi (ptr);
1101     }
1102     else {
1103     yefilesize = -1;
1104     }
1105 root 1.4
1106 root 1.27 if ((ptr =FP_strstr (line, " part="))) {
1107 root 1.19 int partno = atoi (ptr + 6);
1108 root 1.26
1109 root 1.27 if ((ptr = FP_strstr (line, " total=")))
1110 root 1.19 yenotlastpart = atoi (ptr + 7) != partno;
1111    
1112 root 1.27 if (FP_fgets (line, 1200 - 5, datain) == NULL) {
1113 root 1.4 break;
1114     }
1115    
1116 root 1.27 if ((ptr = FP_strstr (line, " end=")) == NULL) {
1117 root 1.4 break;
1118     }
1119 root 1.19
1120 root 1.4 yepartends = atoi (ptr + 5);
1121     }
1122     tf = 1;
1123     continue;
1124     }
1125     else {
1126 root 1.1 continue;
1127 root 1.4 }
1128 root 1.26
1129 root 1.1 tc = tf = vlc = 0;
1130     lc[0] = lc[1] = 0;
1131     }
1132 root 1.21 else if ((*state == END || *state == DATA) &&
1133 root 1.1 (method == UU_ENCODED || method == XX_ENCODED)) {
1134     if (strncmp (line, "end", 3) == 0) {
1135     *state = DONE;
1136     break;
1137     }
1138     }
1139 root 1.4
1140     if (*state == DATA && method == YENC_ENCODED &&
1141     strncmp (line, "=yend ", 6) == 0) {
1142 root 1.23 int lastpart = !yenotlastpart && (yepartends == 0 || yepartends >= yefilesize);
1143 root 1.25 yefilecrc = uu_crc32_combine(yefilecrc, yepartcrc, yepartsize);
1144 root 1.27 if ((ptr = FP_strstr (line, " pcrc32=")) != NULL) {
1145 root 1.11 crc32_t pcrc32 = strtoul (ptr + 8, NULL, 16);
1146     if (pcrc32 != yepartcrc) {
1147     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1148     uustring (S_PCRC_MISMATCH), progress.curfile, progress.partno);
1149     }
1150 root 1.27 } else if ((ptr = FP_strstr (line, " pcrc=")) != NULL) {
1151 root 1.23 crc32_t pcrc32 = strtoul (ptr + 6, NULL, 16);
1152     if (pcrc32 != yepartcrc) {
1153     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1154     uustring (S_PCRC_MISMATCH), progress.curfile, progress.partno);
1155     }
1156 root 1.11 }
1157 root 1.27 if (lastpart && (ptr = FP_strstr (line, " crc32=")) != NULL)
1158 root 1.11 {
1159     crc32_t fcrc32 = strtoul (ptr + 7, NULL, 16);
1160     if (fcrc32 != yefilecrc) {
1161     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1162     uustring (S_CRC_MISMATCH), progress.curfile);
1163     }
1164     }
1165 root 1.27 if ((ptr = FP_strstr (line, " size=")) != NULL)
1166 root 1.11 {
1167     size_t size = atol(ptr + 6);
1168     if (size != yepartsize && yefilesize != -1) {
1169     if (size != yefilesize)
1170     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1171     uustring (S_PSIZE_MISMATCH), progress.curfile,
1172     progress.partno, yepartsize, size);
1173     else
1174     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1175     uustring (S_SIZE_MISMATCH), progress.curfile,
1176     yepartsize, size);
1177     }
1178     }
1179 root 1.23 if (lastpart) {
1180 root 1.4 *state = DONE;
1181     }
1182     break;
1183     }
1184    
1185 root 1.1 if (*state == DATA || *state == END) {
1186     if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) {
1187     break;
1188     }
1189    
1190     if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0)
1191     vflag = UURepairData (datain, line, (tf)?method:0, &bhflag);
1192    
1193     /*
1194     * correct XX/UUencoded lines that were declared Base64
1195     */
1196    
1197     if ((method == XX_ENCODED || method == UU_ENCODED) &&
1198     vflag == B64ENCODED) {
1199     if (UUValidData (line, method, &bhflag) == method)
1200     vflag = method;
1201     }
1202    
1203     if (vflag == method) {
1204     if (tf) {
1205     count = UUDecodeLine (line, oline, method);
1206 root 1.11 if (method == YENC_ENCODED) {
1207 root 1.24 yepartcrc = uu_crc32(yepartcrc, oline, count);
1208 root 1.11 yepartsize += count;
1209     }
1210 root 1.1 vlc++; lc[1]++;
1211     }
1212     else if (tc == 3) {
1213     count = UUDecodeLine (save[0], oline, method);
1214     count += UUDecodeLine (save[1], oline + count, method);
1215     count += UUDecodeLine (save[2], oline + count, method);
1216     count += UUDecodeLine (line, oline + count, method);
1217     tf = 1;
1218     tc = 0;
1219    
1220     /*
1221     * complain if we had one or two invalid lines amidst of
1222     * correctly encoded data. This usually means that the
1223     * file is in error
1224     */
1225    
1226     if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) {
1227     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1228     uustring (S_DATA_SUSPICIOUS));
1229     warning=1;
1230     }
1231     lc[0] = 0;
1232     lc[1] = 3;
1233     }
1234     else {
1235 root 1.27 FP_strncpy (save[tc++], line, 1200);
1236 root 1.1 }
1237 root 1.4
1238 root 1.1 if (method == UU_ENCODED)
1239     *state = (line[0] == 'M') ? DATA : END;
1240     else if (method == XX_ENCODED)
1241     *state = (line[0] == 'h') ? DATA : END;
1242     else if (method == B64ENCODED)
1243     *state = (strchr (line, '=') == NULL) ? DATA : DONE;
1244     else if (method == BH_ENCODED)
1245     *state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE;
1246     }
1247     else {
1248     vlc = tf = tc = 0;
1249     haddh = 0;
1250     lc[0]++;
1251     }
1252     }
1253     else if (*state != DONE) {
1254     return UURET_NOEND;
1255     }
1256 root 1.4
1257 root 1.1 if (count) {
1258     if (method == BH_ENCODED) {
1259     if (UUbhwrite (oline, 1, count, dataout) != count) {
1260     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1261     uustring (S_WR_ERR_TEMP),
1262     strerror (uu_errno = errno));
1263     return UURET_IOERR;
1264     }
1265     }
1266     else if (fwrite (oline, 1, count, dataout) != count) {
1267     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1268     uustring (S_WR_ERR_TEMP),
1269     strerror (uu_errno = errno));
1270     return UURET_IOERR;
1271     }
1272     haddata++;
1273     count = 0;
1274     }
1275     }
1276    
1277     if (*state == DONE ||
1278     (*state == DATA && method == B64ENCODED &&
1279     vflag == B64ENCODED && (flags&FL_PROPER || haddh))) {
1280 root 1.26 for (tf=0; tf<tc; tf++)
1281 root 1.1 count += UUDecodeLine (save[tf], oline + count, method);
1282     if (count) {
1283     if (method == BH_ENCODED) {
1284     if (UUbhwrite (oline, 1, count, dataout) != count) {
1285     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1286     uustring (S_WR_ERR_TEMP),
1287     strerror (uu_errno = errno));
1288     return UURET_IOERR;
1289     }
1290     }
1291     else if (fwrite (oline, 1, count, dataout) != count) {
1292     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1293     uustring (S_WR_ERR_TEMP),
1294     strerror (uu_errno = errno));
1295     return UURET_IOERR;
1296     }
1297     }
1298     }
1299     return UURET_OK;
1300     }
1301    
1302     /*
1303     * this function decodes the file into a temporary file
1304     */
1305    
1306     int
1307     UUDecode (uulist *data)
1308     {
1309     int state=BEGIN, part=-1, res=0, hb;
1310 root 1.13 unsigned long rsize, dsize, numbytes;
1311 root 1.1 FILE *datain, *dataout;
1312 root 1.15 void *datain_buf, *dataout_buf;
1313 root 1.1 unsigned char r[8];
1314     char *mode, *ntmp;
1315     uufile *iter;
1316     size_t bytes;
1317 root 1.3 #ifdef HAVE_MKSTEMP
1318     int tmpfd;
1319     const char *tmpprefix = "uuXXXXXX";
1320     char *tmpdir = NULL;
1321     #endif /* HAVE_MKSTEMP */
1322 root 1.1
1323     if (data == NULL || data->thisfile == NULL)
1324     return UURET_ILLVAL;
1325    
1326     if (data->state & UUFILE_TMPFILE)
1327     return UURET_OK;
1328    
1329     if (data->state & UUFILE_NODATA)
1330     return UURET_NODATA;
1331    
1332     if (data->state & UUFILE_NOBEGIN && !uu_desperate)
1333     return UURET_NODATA;
1334    
1335 root 1.2 if (data->uudet == PT_ENCODED)
1336 root 1.1 mode = "wt"; /* open text files in text mode */
1337     else
1338     mode = "wb"; /* otherwise in binary */
1339    
1340 root 1.3 #ifdef HAVE_MKSTEMP
1341     if ((getuid()==geteuid()) && (getgid()==getegid())) {
1342     tmpdir=getenv("TMPDIR");
1343     }
1344    
1345     if (!tmpdir) {
1346     tmpdir = "/tmp";
1347     }
1348     data->binfile = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
1349    
1350     if (!data->binfile) {
1351     #else
1352 root 1.28 if ((data->binfile = tmpnam (NULL)) == NULL) {
1353 root 1.3 #endif /* HAVE_MKSTEMP */
1354 root 1.1 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1355     uustring (S_NO_TEMP_NAME));
1356     return UURET_NOMEM;
1357     }
1358    
1359 root 1.3 #ifdef HAVE_MKSTEMP
1360     strcpy(data->binfile, tmpdir);
1361     strcat(data->binfile, "/");
1362     strcat(data->binfile, tmpprefix);
1363    
1364 root 1.26 if ((tmpfd = mkstemp(data->binfile)) == -1 ||
1365 root 1.3 (dataout = fdopen(tmpfd, mode)) == NULL) {
1366     #else
1367 root 1.1 if ((dataout = fopen (data->binfile, mode)) == NULL) {
1368 root 1.3 #endif /* HAVE_MKSTEMP */
1369 root 1.1 /*
1370     * we couldn't create a temporary file. Usually this means that TMP
1371     * and TEMP aren't set
1372     */
1373     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1374     uustring (S_WR_ERR_TARGET),
1375     data->binfile, strerror (uu_errno = errno));
1376 root 1.3 #ifdef HAVE_MKSTEMP
1377     if (tmpfd != -1) {
1378     unlink(data->binfile);
1379     close(tmpfd);
1380     }
1381     #endif /* HAVE_MKSTEMP */
1382 root 1.27 FP_free (data->binfile);
1383 root 1.1 data->binfile = NULL;
1384     uu_errno = errno;
1385     return UURET_IOERR;
1386     }
1387 root 1.15 UUSETBUF (dataout, dataout_buf, uu_wbuf);
1388 root 1.28 FP_flockfile (dataout);
1389 root 1.3
1390 root 1.1 /*
1391     * we don't have begin lines in Base64 or plain text files.
1392     */
1393     if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1394     data->uudet == PT_ENCODED)
1395     state = DATA;
1396    
1397     /*
1398     * If we know that the file does not have a begin, we simulate
1399     * it in desperate mode
1400     */
1401    
1402     if ((data->state & UUFILE_NOBEGIN) && uu_desperate)
1403     state = DATA;
1404    
1405     (void) UUDecodeLine (NULL, NULL, 0); /* init */
1406     (void) UUbhwrite (NULL, 0, 0, NULL); /* dito */
1407     (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* yep */
1408    
1409     /*
1410     * initialize progress information
1411     */
1412     progress.action = 0;
1413     if (data->filename != NULL) {
1414 root 1.27 FP_strncpy (progress.curfile,
1415 root 1.1 (strlen(data->filename)>255)?
1416     (data->filename+strlen(data->filename)-255):data->filename,
1417     256);
1418     }
1419     else {
1420 root 1.27 FP_strncpy (progress.curfile,
1421 root 1.1 (strlen(data->binfile)>255)?
1422     (data->binfile+strlen(data->binfile)-255):data->binfile,
1423     256);
1424     }
1425     progress.partno = 0;
1426     progress.numparts = 0;
1427     progress.fsize = -1;
1428     progress.percent = 0;
1429     progress.action = UUACT_DECODING;
1430    
1431     iter = data->thisfile;
1432     while (iter) {
1433     progress.numparts = (iter->partno)?iter->partno:1;
1434     iter = iter->NEXT;
1435     }
1436 root 1.26
1437 root 1.1 /*
1438     * let's rock!
1439     */
1440    
1441     iter = data->thisfile;
1442     while (iter) {
1443 root 1.12 if (part != -1 && iter->partno != part+1 && !uu_desperate)
1444 root 1.1 break;
1445     else
1446     part = iter->partno;
1447    
1448     if (iter->data->sfname == NULL) {
1449     iter = iter->NEXT;
1450     continue;
1451     }
1452    
1453     /*
1454     * call our FileCallback to retrieve the file
1455     */
1456    
1457     if (uu_FileCallback) {
1458     if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1459     uugen_fnbuffer, 1)) != UURET_OK)
1460     break;
1461     if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) {
1462     (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
1463     uugen_fnbuffer, 0);
1464     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1465     uustring (S_NOT_OPEN_FILE),
1466     uugen_fnbuffer, strerror (uu_errno = errno));
1467     res = UURET_IOERR;
1468     break;
1469     }
1470     }
1471     else {
1472     if ((datain = fopen (iter->data->sfname, "rb")) == NULL) {
1473     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1474     uustring (S_NOT_OPEN_FILE),
1475     iter->data->sfname, strerror (uu_errno = errno));
1476     res = UURET_IOERR;
1477     break;
1478     }
1479 root 1.27 FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
1480 root 1.1 }
1481 root 1.15 UUSETBUF (datain, datain_buf, uu_rbuf);
1482 root 1.28 FP_flockfile (datain);
1483 root 1.1
1484     progress.partno = part;
1485     progress.fsize = (iter->data->length)?iter->data->length:-1;
1486     progress.percent = 0;
1487     progress.foffset = iter->data->startpos;
1488    
1489     fseek (datain, iter->data->startpos, SEEK_SET);
1490     res = UUDecodePart (datain, dataout, &state,
1491     iter->data->startpos+iter->data->length,
1492     data->uudet, iter->data->flags, NULL);
1493     fclose (datain);
1494 root 1.15 UUCLRBUF (uu_rbuf, datain_buf);
1495 root 1.1
1496     if (uu_FileCallback)
1497     (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0);
1498    
1499     if (state == DONE || res != UURET_OK)
1500     break;
1501    
1502     iter = iter->NEXT;
1503     }
1504    
1505 root 1.26 if (state == DATA &&
1506 root 1.1 (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
1507     data->uudet == PT_ENCODED))
1508     state = DONE; /* assume we're done */
1509    
1510 root 1.12 if (fclose (dataout)) {
1511     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1512     uustring (S_WR_ERR_TEMP),
1513     strerror (uu_errno = errno));
1514     res = UURET_IOERR;
1515     }
1516 root 1.15 UUCLRBUF (uu_wbuf, dataout_buf);
1517 root 1.1
1518     if (res != UURET_OK || (state != DONE && !uu_desperate)) {
1519     unlink (data->binfile);
1520 root 1.27 FP_free (data->binfile);
1521 root 1.1 data->binfile = NULL;
1522     data->state &= ~UUFILE_TMPFILE;
1523     data->state |= UUFILE_ERROR;
1524    
1525     if (res == UURET_OK && state != DONE)
1526     res = UURET_NOEND;
1527     }
1528     else if (res != UURET_OK) {
1529     data->state &= ~UUFILE_DECODED;
1530     data->state |= UUFILE_ERROR | UUFILE_TMPFILE;
1531     }
1532     else {
1533     data->state &= ~UUFILE_ERROR;
1534     data->state |= UUFILE_TMPFILE;
1535     }
1536    
1537     /*
1538     * If this was a BinHex file, we must extract its data or resource fork
1539     */
1540    
1541     if (data->uudet == BH_ENCODED && data->binfile) {
1542 root 1.3 #ifdef HAVE_MKSTEMP
1543 root 1.28 ntmp = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
1544 root 1.3 #else
1545 root 1.28 ntmp = tempnam (NULL);
1546 root 1.3 #endif /* HAVE_MKSTEMP */
1547 root 1.28 if (ntmp == NULL) {
1548 root 1.1 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1549     uustring (S_NO_TEMP_NAME));
1550     progress.action = 0;
1551     return UURET_NOMEM;
1552     }
1553     if ((datain = fopen (data->binfile, "rb")) == NULL) {
1554     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1555     uustring (S_NOT_OPEN_FILE),
1556     data->binfile, strerror (uu_errno = errno));
1557     progress.action = 0;
1558     free (ntmp);
1559     return UURET_IOERR;
1560     }
1561 root 1.15 UUSETBUF (datain, datain_buf, uu_rbuf);
1562 root 1.28 FP_flockfile (datain);
1563 root 1.15
1564 root 1.3 #ifdef HAVE_MKSTEMP
1565 root 1.15 strcpy(ntmp, tmpdir);
1566     strcat(ntmp, "/");
1567 root 1.26 strcat(ntmp, tmpprefix);
1568 root 1.3 if ((tmpfd = mkstemp(ntmp)) == -1 ||
1569     (dataout = fdopen(tmpfd, "wb")) == NULL) {
1570     #else
1571 root 1.1 if ((dataout = fopen (ntmp, "wb")) == NULL) {
1572 root 1.3 #endif /* HAVE_MKSTEMP */
1573 root 1.1 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1574     uustring (S_NOT_OPEN_TARGET),
1575     ntmp, strerror (uu_errno = errno));
1576     progress.action = 0;
1577     fclose (datain);
1578 root 1.15 UUCLRBUF (uu_rbuf, datain_buf);
1579 root 1.3 #ifdef HAVE_MKSTEMP
1580     if (tmpfd != -1) {
1581     unlink(ntmp);
1582     close(tmpfd);
1583     }
1584     #endif /* HAVE_MKSTEMP */
1585 root 1.1 free (ntmp);
1586     return UURET_IOERR;
1587     }
1588 root 1.15 UUSETBUF (dataout, dataout_buf, uu_wbuf);
1589 root 1.28 FP_flockfile (dataout);
1590 root 1.3
1591 root 1.1 /*
1592     * read fork lengths. remember they're in Motorola format
1593     */
1594 root 1.27 r[0] = FP_getc (datain);
1595 root 1.1 hb = (int) r[0] + 22;
1596     fseek (datain, (int) r[0] + 12, SEEK_SET);
1597     fread (r, 1, 8, datain);
1598    
1599     dsize = (((long) 1 << 24) * (long) r[0]) +
1600     (((long) 1 << 16) * (long) r[1]) +
1601     (((long) 1 << 8) * (long) r[2]) +
1602     ( (long) r[3]);
1603     rsize = (((long) 1 << 24) * (long) r[4]) +
1604     (((long) 1 << 16) * (long) r[5]) +
1605     (((long) 1 << 8) * (long) r[6]) +
1606     ( (long) r[7]);
1607    
1608     UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE,
1609     uustring (S_BINHEX_SIZES),
1610     dsize, rsize);
1611    
1612     if (dsize == 0) {
1613     fseek (datain, dsize + hb + 2, SEEK_SET);
1614     numbytes = rsize;
1615     }
1616     else if (rsize == 0) {
1617     fseek (datain, hb, SEEK_SET);
1618     numbytes = dsize;
1619     }
1620     else {
1621     /* we should let the user have the choice here */
1622     UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1623     uustring (S_BINHEX_BOTH));
1624     fseek (datain, hb, SEEK_SET);
1625     numbytes = dsize;
1626     }
1627    
1628     progress.action = 0;
1629     progress.partno = 0;
1630     progress.numparts = 1;
1631 root 1.16 progress.fsize = numbytes ? numbytes : -1;
1632 root 1.1 progress.foffset = hb;
1633     progress.percent = 0;
1634     progress.action = UUACT_COPYING;
1635    
1636     /*
1637     * copy the chosen fork
1638     */
1639    
1640 root 1.27 while (!FP_feof (datain) && numbytes) {
1641 root 1.1 if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
1642     UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
1643     uustring (S_DECODE_CANCEL));
1644     fclose (datain);
1645 root 1.15 UUCLRBUF (uu_rbuf, datain_buf);
1646 root 1.1 fclose (dataout);
1647 root 1.15 UUCLRBUF (uu_wbuf, dataout_buf);
1648 root 1.1 unlink (ntmp);
1649     free (ntmp);
1650     return UURET_CANCEL;
1651     }
1652    
1653     bytes = fread (uugen_inbuffer, 1,
1654     (size_t) ((numbytes>1024)?1024:numbytes), datain);
1655    
1656 root 1.27 if (ferror (datain) || (bytes == 0 && !FP_feof (datain))) {
1657 root 1.1 progress.action = 0;
1658     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1659     uustring (S_SOURCE_READ_ERR),
1660     data->binfile, strerror (uu_errno = errno));
1661     fclose (datain);
1662 root 1.15 UUCLRBUF (uu_rbuf, datain_buf);
1663 root 1.1 fclose (dataout);
1664 root 1.15 UUCLRBUF (uu_wbuf, dataout_buf);
1665 root 1.1 unlink (ntmp);
1666     free (ntmp);
1667     return UURET_IOERR;
1668     }
1669     if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) {
1670     progress.action = 0;
1671     UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1672     uustring (S_WR_ERR_TARGET),
1673     ntmp, strerror (uu_errno = errno));
1674     fclose (datain);
1675 root 1.15 UUCLRBUF (uu_rbuf, datain_buf);
1676 root 1.1 fclose (dataout);
1677 root 1.15 UUCLRBUF (uu_wbuf, dataout_buf);
1678 root 1.1 unlink (ntmp);
1679     free (ntmp);
1680     return UURET_IOERR;
1681     }
1682     numbytes -= bytes;
1683     }
1684    
1685     if (numbytes) {
1686     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1687     uustring (S_SHORT_BINHEX),
1688     (data->filename)?data->filename:
1689     (data->subfname)?data->subfname:"???",
1690     numbytes);
1691     }
1692    
1693     /*
1694     * replace temp file
1695     */
1696    
1697     fclose (datain);
1698 root 1.15 UUCLRBUF (uu_rbuf, datain_buf);
1699 root 1.12 if (fclose (dataout)) {
1700 root 1.15 UUCLRBUF (uu_wbuf, dataout_buf);
1701 root 1.12 UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
1702     uustring (S_WR_ERR_TARGET),
1703     ntmp, strerror (uu_errno = errno));
1704     unlink (ntmp);
1705     free (ntmp);
1706     return UURET_IOERR;
1707     }
1708 root 1.15 UUCLRBUF (uu_wbuf, dataout_buf);
1709 root 1.1
1710     if (unlink (data->binfile)) {
1711     UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
1712     uustring (S_TMP_NOT_REMOVED),
1713     data->binfile, strerror (uu_errno = errno));
1714     }
1715    
1716     free (data->binfile);
1717     data->binfile = ntmp;
1718     }
1719    
1720     progress.action = 0;
1721     return res;
1722     }
1723    
1724     /*
1725     * QuickDecode for proper MIME attachments. We expect the pointer to
1726     * be on the first header line.
1727     */
1728    
1729     int
1730     UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos)
1731     {
1732     int state=BEGIN, encoding=-1;
1733     headers myenv;
1734    
1735     /*
1736     * Read header and find out about encoding.
1737     */
1738    
1739     memset (&myenv, 0, sizeof (headers));
1740     UUScanHeader (datain, &myenv);
1741    
1742 root 1.27 if (FP_stristr (myenv.ctenc, "uu") != NULL)
1743 root 1.1 encoding = UU_ENCODED;
1744 root 1.27 else if (FP_stristr (myenv.ctenc, "xx") != NULL)
1745 root 1.1 encoding = XX_ENCODED;
1746 root 1.27 else if (FP_stricmp (myenv.ctenc, "base64") == 0)
1747 root 1.1 encoding = B64ENCODED;
1748 root 1.27 else if (FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
1749 root 1.1 encoding = QP_ENCODED;
1750     else
1751     encoding = PT_ENCODED;
1752    
1753     UUkillheaders (&myenv);
1754    
1755     /*
1756     * okay, so decode this one
1757     */
1758    
1759     (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* init */
1760     return UUDecodePart (datain, dataout, &state, maxpos,
1761     encoding, FL_PROPER|FL_TOEND,
1762     boundary);
1763     }