ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uunconc.c
Revision: 1.1
Committed: Mon Jun 11 19:49:00 2001 UTC (23 years ago) by root
Content type: text/plain
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

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