ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uulib.c
Revision: 1.15
Committed: Sat May 26 15:14:10 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_09
Changes since 1.14: +3 -3 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of uudeview, the simple and friendly multi-part multi-
3 * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
4 * be contacted at fp@fpx.de
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17 /*
18 * This file implements the externally visible functions, as declared
19 * in uudeview.h, and some internal interfacing functions
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #ifdef SYSTEM_WINDLL
27 #include <windows.h>
28 #endif
29 #ifdef SYSTEM_OS2
30 #include <os2.h>
31 #endif
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <stdio.h>
36
37 #ifdef HAVE_FCNTL_H
38 #include <fcntl.h>
39 #endif
40
41 #ifdef STDC_HEADERS
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #else
46 #ifdef HAVE_STDARG_H
47 #include <stdarg.h>
48 #else
49 #ifdef HAVE_VARARGS_H
50 #include <varargs.h>
51 #endif
52 #endif
53 #endif
54
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58
59 #ifdef TIME_WITH_SYS_TIME
60 # include <sys/time.h>
61 # include <time.h>
62 #else
63 # ifdef HAVE_SYS_TIME_H
64 # include <sys/time.h>
65 # else
66 # include <time.h>
67 # endif
68 #endif
69
70 #ifdef HAVE_ERRNO_H
71 #include <errno.h>
72 #endif
73
74 /* to get open() in Windows */
75 #ifdef HAVE_IO_H
76 #include <io.h>
77 #endif
78
79 #include <uudeview.h>
80 #include <uuint.h>
81 #include <fptools.h>
82 #include <uustring.h>
83
84 char * uulib_id = "$Id$";
85
86 #ifdef SYSTEM_WINDLL
87 BOOL _export WINAPI
88 DllEntryPoint (HINSTANCE hInstance, DWORD seginfo,
89 LPVOID lpCmdLine)
90 {
91 /* Don't do anything, so just return true */
92 return TRUE;
93 }
94 #endif
95
96 /*
97 * In DOS, we must open the file binary, O_BINARY is defined there
98 */
99
100 #ifndef O_BINARY
101 #define O_BINARY 0
102 #endif
103
104 /* for braindead systems */
105 #ifndef SEEK_SET
106 #ifdef L_BEGIN
107 #define SEEK_SET L_BEGIN
108 #else
109 #define SEEK_SET 0
110 #endif
111 #endif
112
113 /*
114 * Callback functions and their opaque arguments
115 */
116
117 void (*uu_MsgCallback) (void *, char *, int) = NULL;
118 int (*uu_BusyCallback) (void *, uuprogress *) = NULL;
119 int (*uu_FileCallback) (void *, char *, char *, int) = NULL;
120 char * (*uu_FNameFilter) (void *, char *) = NULL;
121 char * (*uu_FileNameCallback)(void *, char *, char *);
122 ;
123 void *uu_MsgCBArg = NULL;
124 void *uu_BusyCBArg = NULL;
125 void *uu_FileCBArg = NULL;
126 void *uu_FFCBArg = NULL;
127 void *uu_FNCBArg;
128
129 /* I/O buffer sizes */
130 int uu_rbuf = 0;
131 int uu_wbuf = 0;
132
133 /*
134 * Global variables
135 */
136
137 int uu_fast_scanning = 0; /* assumes at most 1 part per file */
138 int uu_bracket_policy = 0; /* gives part numbers in [] higher priority */
139 int uu_verbose = 1; /* enables/disables messages&notes */
140 int uu_desperate = 0; /* desperate mode */
141 int uu_ignreply = 0; /* ignore replies */
142 int uu_debug = 0; /* debugging mode (print __FILE__/__LINE__) */
143 int uu_errno = 0; /* the errno that caused this UURET_IOERR */
144 int uu_dumbness = 0; /* switch off the program's intelligence */
145 int uu_overwrite = 1; /* whether it's ok to overwrite ex. files */
146 int uu_ignmode = 0; /* ignore the original file mode */
147 int uu_handletext = 0; /* do we want text/plain messages */
148 int uu_usepreamble = 0; /* do we want Mime preambles/epilogues */
149 int uu_tinyb64 = 0; /* detect short B64 outside of MIME */
150 int uu_remove_input = 0; /* remove input files after decoding */
151 int uu_more_mime = 0; /* strictly adhere to MIME headers */
152 int uu_dotdot = 0; /* dot-unescaping has not yet been done */
153
154 headercount hlcount = {
155 3, /* restarting after a MIME body */
156 2, /* after useful data in freestyle mode */
157 1 /* after useful data and an empty line */
158 };
159
160 /*
161 * version string
162 */
163
164 char uulibversion[256] = VERSION "pl" PATCH;
165
166 /*
167 * prefix to the files on disk, usually a path name to save files to
168 */
169
170 char *uusavepath;
171
172 /*
173 * extension to use when encoding single-part files
174 */
175
176 char *uuencodeext;
177
178 /*
179 * areas to malloc
180 */
181
182 char *uulib_msgstring;
183 char *uugen_inbuffer;
184 char *uugen_fnbuffer;
185
186 /*
187 * The Global List of Files
188 */
189
190 uulist *UUGlobalFileList = NULL;
191
192 /*
193 * time values for BusyCallback. msecs is MILLIsecs here
194 */
195
196 static long uu_busy_msecs = 0; /* call callback function each msecs */
197 static long uu_last_secs = 0; /* secs of last call to callback */
198 static long uu_last_usecs = 0; /* usecs of last call to callback */
199
200 /*
201 * progress information
202 */
203
204 uuprogress progress;
205
206 /*
207 * Linked list of files we want to delete after decoding
208 */
209
210 typedef struct _itbd {
211 char *fname;
212 struct _itbd *NEXT;
213 } itbd;
214 static itbd * ftodel = NULL;
215
216 /*
217 * for the busy poll
218 */
219
220 unsigned long uuyctr;
221
222 /*
223 * Areas to allocate. Instead of using static memory areas, we malloc()
224 * the memory in UUInitialize() and release them in UUCleanUp to prevent
225 * blowing up of the binary size
226 * This is a table with the pointers to allocate and required sizes.
227 * They are guaranteed to be never NULL.
228 */
229
230 typedef struct {
231 char **ptr;
232 size_t size;
233 } allomap;
234
235 static allomap toallocate[] = {
236 { &uugen_fnbuffer, 4096 }, /* generic filename buffer */
237 { &uugen_inbuffer, 1024 }, /* generic input data buffer */
238 { &uucheck_lastname, 256 }, /* from uucheck.c */
239 { &uucheck_tempname, 256 },
240 { &uuestr_itemp, 256 }, /* from uuencode.c:UUEncodeStream() */
241 { &uuestr_otemp, 1024 },
242 { &uulib_msgstring, 1024 }, /* from uulib.c:UUMessage() */
243 { &uuncdl_fulline, 1200 }, /* from uunconc.c:UUDecodeLine() */
244 { &uuncdp_oline, 3600 }, /* from uunconc.c:UUDecodePart() */
245 { &uunconc_UUxlat, 256 * sizeof (int) }, /* from uunconc.c:toplevel */
246 { &uunconc_UUxlen, 64 * sizeof (int) },
247 { &uunconc_B64xlat, 256 * sizeof (int) },
248 { &uunconc_XXxlat, 256 * sizeof (int) },
249 { &uunconc_BHxlat, 256 * sizeof (int) },
250 { &uunconc_save, 3*1200 }, /* from uunconc.c:decoding buffer */
251 { &uuscan_shlline, 1024 }, /* from uuscan.c:ScanHeaderLine() */
252 { &uuscan_shlline2, 1024 }, /* from uuscan.c:ScanHeaderLine() */
253 { &uuscan_pvvalue, 300 }, /* from uuscan.c:ParseValue() */
254 { &uuscan_phtext, 300 }, /* from uuscan.c:ParseHeader() */
255 { &uuscan_sdline, 300 }, /* from uuscan.c:ScanData() */
256 { &uuscan_sdbhds1, 300 },
257 { &uuscan_sdbhds2, 300 },
258 { &uuscan_spline, 300 }, /* from uuscan.c:ScanPart() */
259 { &uuutil_bhwtmp, 300 }, /* from uuutil.c:UUbhwrite() */
260 { NULL, 0 }
261 };
262
263 /*
264 * Handle the printing of messages. Works like printf.
265 */
266
267 #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H)
268 int
269 UUMessage (char *file, int line, int level, char *format, ...)
270 #else
271 int
272 UUMessage (va_alist)
273 va_dcl
274 #endif
275 {
276 char *msgptr;
277 #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H)
278 va_list ap;
279
280 va_start (ap, format);
281 #else
282 char *file, *format;
283 int line, level;
284 va_list ap;
285
286 va_start (ap);
287 file = va_arg (ap, char *);
288 line = va_arg (ap, int);
289 level = va_arg (ap, int);
290 format = va_arg (ap, char *);
291 #endif
292
293 if (uu_debug) {
294 sprintf (uulib_msgstring, "%s(%d): %s", file, line, msgnames[level]);
295 msgptr = uulib_msgstring + strlen (uulib_msgstring);
296 }
297 else {
298 sprintf (uulib_msgstring, "%s", msgnames[level]);
299 msgptr = uulib_msgstring + strlen (uulib_msgstring);
300 }
301
302 if (uu_MsgCallback && (level>UUMSG_NOTE || uu_verbose)) {
303 vsprintf (msgptr, format, ap);
304
305 (*uu_MsgCallback) (uu_MsgCBArg, uulib_msgstring, level);
306 }
307
308 va_end (ap);
309
310 return UURET_OK;
311 }
312
313 /*
314 * Call the Busy Callback from time to time. This function must be
315 * polled from the Busy loops.
316 */
317
318 int
319 UUBusyPoll (void)
320 {
321 #ifdef HAVE_GETTIMEOFDAY
322 struct timeval tv;
323 long msecs;
324
325 if (uu_BusyCallback) {
326 (void) gettimeofday (&tv, NULL);
327
328 msecs = 1000*(tv.tv_sec-uu_last_secs)+(tv.tv_usec-uu_last_usecs)/1000;
329
330 if (uu_last_secs==0 || msecs > uu_busy_msecs) {
331 uu_last_secs = tv.tv_sec;
332 uu_last_usecs = tv.tv_usec;
333
334 return (*uu_BusyCallback) (uu_BusyCBArg, &progress);
335 }
336 }
337 #else
338 time_t now;
339 long msecs;
340
341 if (uu_BusyCallback) {
342 if (uu_busy_msecs <= 0) {
343 msecs = 1;
344 }
345 else {
346 now = time(NULL);
347 msecs = 1000 * (now - uu_last_secs);
348 }
349
350 if (uu_last_secs==0 || msecs > uu_busy_msecs) {
351 uu_last_secs = now;
352 uu_last_usecs = 0;
353
354 return (*uu_BusyCallback) (uu_BusyCBArg, &progress);
355 }
356 }
357 #endif
358
359 return 0;
360 }
361
362 /*
363 * Initialization function
364 */
365
366 int UUEXPORT
367 UUInitialize (void)
368 {
369 allomap *aiter;
370
371 progress.action = 0;
372 progress.curfile[0] = '\0';
373
374 ftodel = NULL;
375
376 uusavepath = NULL;
377 uuencodeext = NULL;
378
379 mssdepth = 0;
380 memset (&localenv, 0, sizeof (headers));
381 memset (&sstate, 0, sizeof (scanstate));
382
383 nofnum = 0;
384 mimseqno = 0;
385 lastvalid = 0;
386 lastenc = 0;
387 uuyctr = 0;
388
389 /*
390 * Allocate areas
391 */
392
393 for (aiter=toallocate; aiter->ptr; aiter++)
394 *(aiter->ptr) = NULL;
395
396 for (aiter=toallocate; aiter->ptr; aiter++) {
397 if ((*(aiter->ptr) = (char *) malloc (aiter->size)) == NULL) {
398 /*
399 * oops. we may not print a message here, because we need these
400 * areas (uulib_msgstring) in UUMessage()
401 */
402 for (aiter=toallocate; aiter->ptr; aiter++) {
403 _FP_free (*(aiter->ptr));
404 }
405 return UURET_NOMEM;
406 }
407 }
408
409 /*
410 * Must be called after areas have been malloced
411 */
412
413 UUInitConc ();
414
415 return UURET_OK;
416 }
417
418 /*
419 * Set and get Options
420 */
421
422 int UUEXPORT
423 UUGetOption (int option, int *ivalue, char *cvalue, int clength)
424 {
425 int result;
426
427 switch (option) {
428 case UUOPT_RBUF:
429 *ivalue = uu_rbuf;
430 result = 0;
431 break;
432 case UUOPT_WBUF:
433 *ivalue = uu_wbuf;
434 result = 0;
435 break;
436 case UUOPT_VERSION:
437 _FP_strncpy (cvalue, uulibversion, clength);
438 result = 0;
439 break;
440 case UUOPT_FAST:
441 if (ivalue) *ivalue = uu_fast_scanning;
442 result = uu_fast_scanning;
443 break;
444 case UUOPT_DUMBNESS:
445 if (ivalue) *ivalue = uu_dumbness;
446 result = uu_dumbness;
447 break;
448 case UUOPT_BRACKPOL:
449 if (ivalue) *ivalue = uu_bracket_policy;
450 result = uu_bracket_policy;
451 break;
452 case UUOPT_VERBOSE:
453 if (ivalue) *ivalue = uu_verbose;
454 result = uu_verbose;
455 break;
456 case UUOPT_DESPERATE:
457 if (ivalue) *ivalue = uu_desperate;
458 result = uu_desperate;
459 break;
460 case UUOPT_IGNREPLY:
461 if (ivalue) *ivalue = uu_ignreply;
462 result = uu_ignreply;
463 break;
464 case UUOPT_DEBUG:
465 if (ivalue) *ivalue = uu_debug;
466 result = uu_debug;
467 break;
468 case UUOPT_ERRNO:
469 if (ivalue) *ivalue = uu_errno;
470 result = uu_errno;
471 break;
472 case UUOPT_OVERWRITE:
473 if (ivalue) *ivalue = uu_overwrite;
474 result = uu_overwrite;
475 break;
476 case UUOPT_SAVEPATH:
477 _FP_strncpy (cvalue, uusavepath, clength);
478 result = 0;
479 break;
480 case UUOPT_PROGRESS:
481 if (clength==sizeof(uuprogress)) {
482 memcpy (cvalue, &progress, sizeof (uuprogress));
483 result = 0;
484 }
485 else
486 result = -1;
487 break;
488 case UUOPT_IGNMODE:
489 if (ivalue) *ivalue = uu_ignmode;
490 result = uu_ignmode;
491 break;
492 case UUOPT_USETEXT:
493 if (ivalue) *ivalue = uu_handletext;
494 result = uu_handletext;
495 break;
496 case UUOPT_PREAMB:
497 if (ivalue) *ivalue = uu_usepreamble;
498 result = uu_usepreamble;
499 break;
500 case UUOPT_TINYB64:
501 if (ivalue) *ivalue = uu_tinyb64;
502 result = uu_tinyb64;
503 break;
504 case UUOPT_ENCEXT:
505 _FP_strncpy (cvalue, uuencodeext, clength);
506 result = 0;
507 break;
508 case UUOPT_REMOVE:
509 if (ivalue) *ivalue = uu_remove_input;
510 result = uu_remove_input;
511 break;
512 case UUOPT_MOREMIME:
513 if (ivalue) *ivalue = uu_more_mime;
514 result = uu_more_mime;
515 break;
516 case UUOPT_DOTDOT:
517 if (ivalue) *ivalue = uu_dotdot;
518 result = uu_dotdot;
519 break;
520 default:
521 return -1;
522 }
523 return result;
524 }
525
526 int UUEXPORT
527 UUSetOption (int option, int ivalue, char *cvalue)
528 {
529 switch (option) {
530 case UUOPT_RBUF:
531 uu_rbuf = ivalue;
532 break;
533 case UUOPT_WBUF:
534 uu_wbuf = ivalue;
535 break;
536 case UUOPT_FAST:
537 uu_fast_scanning = ivalue;
538 break;
539 case UUOPT_DUMBNESS:
540 uu_dumbness = ivalue;
541 break;
542 case UUOPT_BRACKPOL:
543 uu_bracket_policy = ivalue;
544 break;
545 case UUOPT_VERBOSE:
546 uu_verbose = ivalue;
547 break;
548 case UUOPT_DESPERATE:
549 uu_desperate = ivalue;
550 break;
551 case UUOPT_IGNREPLY:
552 uu_ignreply = ivalue;
553 break;
554 case UUOPT_DEBUG:
555 uu_debug = ivalue;
556 break;
557 case UUOPT_OVERWRITE:
558 uu_overwrite = ivalue;
559 break;
560 case UUOPT_SAVEPATH:
561 _FP_free (uusavepath);
562 uusavepath = _FP_strdup (cvalue);
563 break;
564 case UUOPT_IGNMODE:
565 uu_ignmode = ivalue;
566 break;
567 case UUOPT_USETEXT:
568 uu_handletext = ivalue;
569 break;
570 case UUOPT_PREAMB:
571 uu_usepreamble = ivalue;
572 break;
573 case UUOPT_TINYB64:
574 uu_tinyb64 = ivalue;
575 break;
576 case UUOPT_ENCEXT:
577 _FP_free (uuencodeext);
578 uuencodeext = _FP_strdup (cvalue);
579 break;
580 case UUOPT_REMOVE:
581 uu_remove_input = ivalue;
582 break;
583 case UUOPT_MOREMIME:
584 uu_more_mime = ivalue;
585 break;
586 case UUOPT_DOTDOT:
587 uu_dotdot = ivalue;
588 break;
589 default:
590 return UURET_ILLVAL;
591 }
592 return UURET_OK;
593 }
594
595 char * UUEXPORT
596 UUstrerror (int code)
597 {
598 return uuretcodes[code];
599 }
600
601 /*
602 * Set the various Callback functions
603 */
604
605 int UUEXPORT
606 UUSetMsgCallback (void *opaque,
607 void (*func) (void *, char *, int))
608 {
609 uu_MsgCallback = func;
610 uu_MsgCBArg = opaque;
611
612 return UURET_OK;
613 }
614
615 int UUEXPORT
616 UUSetBusyCallback (void *opaque,
617 int (*func) (void *, uuprogress *),
618 long msecs)
619 {
620 uu_BusyCallback = func;
621 uu_BusyCBArg = opaque;
622 uu_busy_msecs = msecs;
623
624 return UURET_OK;
625 }
626
627 int UUEXPORT
628 UUSetFileCallback (void *opaque,
629 int (*func) (void *, char *, char *, int))
630 {
631 uu_FileCallback = func;
632 uu_FileCBArg = opaque;
633
634 return UURET_OK;
635 }
636
637 int UUEXPORT
638 UUSetFNameFilter (void *opaque,
639 char * (*func) (void *, char *))
640 {
641 uu_FNameFilter = func;
642 uu_FFCBArg = opaque;
643
644 return UURET_OK;
645 }
646
647 int UUEXPORT
648 UUSetFileNameCallback (void *opaque,
649 char * (*func) (void *, char *, char *))
650 {
651 uu_FileNameCallback = func;
652 uu_FNCBArg = opaque;
653
654 return UURET_OK;
655 }
656
657 /*
658 * Return a pointer to the nth element of the GlobalFileList
659 * zero-based, returns NULL if item is too large.
660 */
661
662 uulist * UUEXPORT
663 UUGetFileListItem (int item)
664 {
665 uulist *iter=UUGlobalFileList;
666
667 if (item < 0)
668 return NULL;
669 while (item && iter) {
670 iter = iter->NEXT;
671 item--;
672 }
673 return iter;
674 }
675
676 /*
677 * call the current filter
678 */
679
680 char * UUEXPORT
681 UUFNameFilter (char *fname)
682 {
683 if (uu_FNameFilter)
684 return (*uu_FNameFilter) (uu_FFCBArg, fname);
685
686 return fname;
687 }
688
689 /*
690 * Load a File. We call ScanPart repeatedly until at EOF and
691 * add the parts to UUGlobalFileList
692 */
693
694 int UUEXPORT
695 UULoadFile (char *filename, char *fileid, int delflag, int *partcount)
696 {
697 return UULoadFileWithPartNo(filename, fileid, delflag, -1, partcount);
698 }
699
700 int UUEXPORT
701 UULoadFileWithPartNo (char *filename, char *fileid, int delflag, int partno, int *partcount)
702 {
703 int res, sr;
704 struct stat finfo;
705 fileread *loaded;
706 uufile *fload;
707 itbd *killem;
708 FILE *datei;
709 void *datei_buf;
710
711 int _count;
712 if (!partcount)
713 partcount = &_count;
714
715 *partcount = 0;
716
717 if ((datei = fopen (filename, "rb")) == NULL) {
718 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
719 uustring (S_NOT_OPEN_SOURCE),
720 filename, strerror (uu_errno = errno));
721 return UURET_IOERR;
722 }
723 UUSETBUF (datei, datei_buf, uu_rbuf);
724
725 if (fstat (fileno(datei), &finfo) == -1) {
726 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
727 uustring (S_NOT_STAT_FILE),
728 filename, strerror (uu_errno = errno));
729 fclose (datei);
730 UUCLRBUF (uu_rbuf, datei_buf);
731 return UURET_IOERR;
732 }
733
734 /*
735 * schedule for destruction
736 */
737
738 if (delflag && fileid==NULL) {
739 if ((killem = (itbd *) malloc (sizeof (itbd))) == NULL) {
740 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
741 uustring (S_OUT_OF_MEMORY), sizeof (itbd));
742 }
743 else if ((killem->fname = _FP_strdup (filename)) == NULL) {
744 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
745 uustring (S_OUT_OF_MEMORY), strlen(filename)+1);
746 _FP_free (killem);
747 }
748 else {
749 killem->NEXT = ftodel;
750 ftodel = killem;
751 }
752 }
753
754 progress.action = 0;
755 progress.partno = 0;
756 progress.numparts = 1;
757 progress.fsize = (long) ((finfo.st_size>0)?finfo.st_size:-1);
758 progress.percent = 0;
759 progress.foffset = 0;
760 _FP_strncpy (progress.curfile,
761 (strlen(filename)>255)?
762 (filename+strlen(filename)-255):filename,
763 256);
764 progress.action = UUACT_SCANNING;
765
766 if (fileid == NULL)
767 fileid = filename;
768
769 while (!feof (datei) && !ferror (datei)) {
770 /*
771 * Peek file, or some systems won't detect EOF
772 */
773 res = fgetc (datei);
774 if (feof (datei) || ferror (datei))
775 break;
776 else
777 ungetc (res, datei);
778
779 if ((loaded = ScanPart (datei, fileid, &sr)) == NULL) {
780 if (sr != UURET_NODATA && sr != UURET_OK && sr != UURET_CONT) {
781 UUkillfread (loaded);
782 if (sr != UURET_CANCEL)
783 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
784 uustring (S_READ_ERROR), filename,
785 strerror (uu_errno));
786
787 UUCheckGlobalList ();
788 progress.action = 0;
789 fclose (datei);
790 UUCLRBUF (uu_rbuf, datei_buf);
791 return sr;
792 }
793 continue;
794 }
795
796 if (ferror (datei)) {
797 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
798 uustring (S_READ_ERROR), filename,
799 strerror (uu_errno = errno));
800 UUCheckGlobalList ();
801 progress.action = 0;
802 fclose (datei);
803 UUCLRBUF (uu_rbuf, datei_buf);
804 return UURET_IOERR;
805 }
806
807 if (partno != -1)
808 loaded->partno = partno;
809
810 if ((loaded->uudet == QP_ENCODED || loaded->uudet == PT_ENCODED) &&
811 (loaded->filename == NULL || *(loaded->filename) == '\0') &&
812 !uu_handletext && (loaded->flags&FL_PARTIAL)==0) {
813 /*
814 * Don't want text
815 */
816 UUkillfread (loaded);
817 continue;
818 }
819
820 if ((loaded->subject == NULL || *(loaded->subject) == '\0') &&
821 (loaded->mimeid == NULL || *(loaded->mimeid) == '\0') &&
822 (loaded->filename== NULL || *(loaded->filename)== '\0') &&
823 (loaded->uudet == 0)) {
824 /*
825 * no useful data here
826 */
827 UUkillfread (loaded);
828 if (uu_fast_scanning && sr != UURET_CONT) break;
829 continue;
830 }
831
832 if ((fload = UUPreProcessPart (loaded, &res)) == NULL) {
833 /*
834 * no useful data found
835 */
836 if (res != UURET_NODATA) {
837 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
838 uustring (S_READ_ERROR), filename,
839 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
840 }
841 UUkillfread (loaded);
842 if (uu_fast_scanning && sr != UURET_CONT) break;
843 continue;
844 }
845
846 if ((loaded->subject && *(loaded->subject)) ||
847 (loaded->mimeid && *(loaded->mimeid)) ||
848 (loaded->filename&& *(loaded->filename))||
849 (loaded->uudet)) {
850 UUMessage (uulib_id, __LINE__, UUMSG_MESSAGE,
851 uustring (S_LOADED_PART),
852 filename,
853 (loaded->subject) ? loaded->subject : "",
854 (fload->subfname) ? fload->subfname : "",
855 (loaded->filename) ? loaded->filename : "",
856 fload->partno,
857 (loaded->begin) ? "begin" : "",
858 (loaded->end) ? "end" : "",
859 codenames[loaded->uudet]);
860 }
861
862 if ((res = UUInsertPartToList (fload))) {
863 /*
864 * couldn't use the data
865 */
866 UUkillfile (fload);
867
868 if (res != UURET_NODATA) {
869 UUCheckGlobalList ();
870 progress.action = 0;
871 fclose (datei);
872 UUCLRBUF (uu_rbuf, datei_buf);
873 return res;
874 }
875 if (uu_fast_scanning && sr != UURET_CONT)
876 break;
877
878 continue;
879 }
880
881 /*
882 * if in fast mode, we don't look any further, because we're told
883 * that each source file holds at most one encoded part
884 */
885
886 if (loaded->uudet)
887 (*partcount)++;
888
889 if (uu_fast_scanning && sr != UURET_CONT)
890 break;
891 }
892 if (ferror (datei)) {
893 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
894 uustring (S_READ_ERROR), filename,
895 strerror (uu_errno = errno));
896 UUCheckGlobalList ();
897 progress.action = 0;
898 fclose (datei);
899 UUCLRBUF (uu_rbuf, datei_buf);
900 return UURET_IOERR;
901 }
902 fclose (datei);
903 UUCLRBUF (uu_rbuf, datei_buf);
904
905 if (!uu_fast_scanning && *partcount == 0)
906 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
907 uustring (S_NO_DATA_FOUND), filename);
908
909 progress.action = 0;
910 UUCheckGlobalList ();
911
912 return UURET_OK;
913 }
914
915 /*
916 * decode to a temporary file. this is well handled by uudecode()
917 */
918
919 int UUEXPORT
920 UUDecodeToTemp (uulist *thefile)
921 {
922 return UUDecode (thefile);
923 }
924
925 /*
926 * decode file first to temp file, then copy it to a final location
927 */
928
929 int UUEXPORT
930 UUDecodeFile (uulist *thefile, char *destname)
931 {
932 FILE *target, *source;
933 void *target_buf, *source_buf;
934 struct stat finfo;
935 int fildes, res;
936 size_t bytes;
937
938 if (thefile == NULL)
939 return UURET_ILLVAL;
940
941 if ((res = UUDecode (thefile)) != UURET_OK)
942 if (res != UURET_NOEND || !uu_desperate)
943 return res;
944
945 if (thefile->binfile == NULL) {
946 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
947 uustring (S_NO_BIN_FILE));
948 return UURET_IOERR;
949 }
950
951 if ((source = fopen (thefile->binfile, "rb")) == NULL) {
952 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
953 uustring (S_NOT_OPEN_FILE),
954 thefile->binfile, strerror (uu_errno = errno));
955 return UURET_IOERR;
956 }
957 UUSETBUF (source, source_buf, uu_rbuf);
958
959 /*
960 * for system security, strip setuid/setgid bits from mode
961 */
962
963 if ((thefile->mode & 0777) != thefile->mode) {
964 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
965 uustring (S_STRIPPED_SETUID),
966 destname, (int)thefile->mode);
967 thefile->mode &= 0777;
968 }
969
970 /*
971 * Determine the name of the target file according to the rules:
972 *
973 * IF (destname!=NULL) THEN filename=destname;
974 * ELSE
975 * filename = thefile->filename
976 * IF (FilenameFilter!=NULL) THEN filename=FilenameFilter(filename);
977 * filename = SaveFilePath + filename
978 * END
979 */
980
981 if (destname)
982 strcpy (uugen_fnbuffer, destname);
983 else {
984 char *fname = UUFNameFilter (thefile->filename ? thefile->filename : "unknown.xxx");
985 sprintf (uugen_fnbuffer, "%.1024s%.3071s",
986 uusavepath ? uusavepath : "",
987 fname ? fname : "unknown.xxx");
988 }
989
990 /*
991 * if we don't want to overwrite existing files, check if it's there
992 */
993
994 if (!uu_overwrite) {
995 if (stat (uugen_fnbuffer, &finfo) == 0) {
996 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
997 uustring (S_TARGET_EXISTS), uugen_fnbuffer);
998 fclose (source);
999 UUCLRBUF (uu_rbuf, source_buf);
1000 return UURET_EXISTS;
1001 }
1002 }
1003
1004 if (fstat (fileno(source), &finfo) == -1) {
1005 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1006 uustring (S_NOT_STAT_FILE),
1007 thefile->binfile, strerror (uu_errno = errno));
1008 fclose (source);
1009 UUCLRBUF (uu_rbuf, source_buf);
1010 return UURET_IOERR;
1011 }
1012
1013 /* try rename() shortcut first */
1014 if (!rename (thefile->binfile, uugen_fnbuffer))
1015 {
1016 mode_t mask = 0000; /* there is a slight window here anyway */
1017 #if HAVE_UMASK
1018 mask = umask (0022); umask (mask);
1019 #endif
1020 fclose (source);
1021 UUCLRBUF (uu_rbuf, source_buf);
1022 #if HAVE_CHMOD
1023 chmod (uugen_fnbuffer, thefile->mode & ~mask);
1024 #endif
1025 goto skip_copy;
1026 }
1027
1028 progress.action = 0;
1029 _FP_strncpy (progress.curfile,
1030 (strlen(uugen_fnbuffer)>255)?
1031 (uugen_fnbuffer+strlen(uugen_fnbuffer)-255):uugen_fnbuffer,
1032 256);
1033 progress.partno = 0;
1034 progress.numparts = 1;
1035 progress.fsize = (long) ((finfo.st_size)?finfo.st_size:-1);
1036 progress.foffset = 0;
1037 progress.percent = 0;
1038 progress.action = UUACT_COPYING;
1039
1040 if ((fildes = open (uugen_fnbuffer,
1041 O_WRONLY | O_CREAT | O_BINARY | O_TRUNC,
1042 (uu_ignmode)?0666:thefile->mode)) == -1) {
1043 progress.action = 0;
1044 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1045 uustring (S_NOT_OPEN_TARGET),
1046 uugen_fnbuffer, strerror (uu_errno = errno));
1047 fclose (source);
1048 UUCLRBUF (uu_rbuf, source_buf);
1049 return UURET_IOERR;
1050 }
1051
1052 if ((target = fdopen (fildes, "wb")) == NULL) {
1053 progress.action = 0;
1054 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1055 uustring (S_IO_ERR_TARGET),
1056 uugen_fnbuffer, strerror (uu_errno = errno));
1057 fclose (source);
1058 UUCLRBUF (uu_rbuf, source_buf);
1059 close (fildes);
1060 return UURET_IOERR;
1061 }
1062 UUSETBUF (target, target_buf, uu_wbuf);
1063
1064 while (!feof (source)) {
1065
1066 if (UUBUSYPOLL(ftell(source),progress.fsize)) {
1067 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
1068 uustring (S_DECODE_CANCEL));
1069 fclose (source);
1070 UUCLRBUF (uu_rbuf, source_buf);
1071 fclose (target);
1072 UUCLRBUF (uu_wbuf, target_buf);
1073 unlink (uugen_fnbuffer);
1074 return UURET_CANCEL;
1075 }
1076
1077 bytes = fread (uugen_inbuffer, 1, 1024, source);
1078
1079 if (ferror (source) || (bytes == 0 && !feof (source))) {
1080 progress.action = 0;
1081 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1082 uustring (S_READ_ERROR),
1083 thefile->binfile, strerror (uu_errno = errno));
1084 fclose (source);
1085 UUCLRBUF (uu_rbuf, source_buf);
1086 fclose (target);
1087 UUCLRBUF (uu_wbuf, target_buf);
1088 unlink (uugen_fnbuffer);
1089 return UURET_IOERR;
1090 }
1091 if (fwrite (uugen_inbuffer, 1, bytes, target) != bytes) {
1092 progress.action = 0;
1093 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1094 uustring (S_WR_ERR_TARGET),
1095 uugen_fnbuffer, strerror (uu_errno = errno));
1096 fclose (source);
1097 UUCLRBUF (uu_rbuf, source_buf);
1098 fclose (target);
1099 UUCLRBUF (uu_wbuf, target_buf);
1100 unlink (uugen_fnbuffer);
1101 return UURET_IOERR;
1102 }
1103 }
1104
1105 fclose (source);
1106 UUCLRBUF (uu_rbuf, source_buf);
1107 if (fclose (target)) {
1108 UUCLRBUF (uu_wbuf, target_buf);
1109 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1110 uustring (S_WR_ERR_TARGET),
1111 uugen_fnbuffer, strerror (uu_errno = errno));
1112 unlink (uugen_fnbuffer);
1113 return UURET_IOERR;
1114 }
1115 UUCLRBUF (uu_wbuf, target_buf);
1116
1117 /*
1118 * after a successful decoding run, we delete the temporary file
1119 */
1120
1121 if (unlink (thefile->binfile)) {
1122 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1123 uustring (S_TMP_NOT_REMOVED),
1124 thefile->binfile,
1125 strerror (uu_errno = errno));
1126 }
1127
1128 skip_copy:
1129 _FP_free (thefile->binfile);
1130 thefile->binfile = NULL;
1131 thefile->state &= ~UUFILE_TMPFILE;
1132 thefile->state |= UUFILE_DECODED;
1133 progress.action = 0;
1134
1135 return UURET_OK;
1136 }
1137
1138 /*
1139 * Calls a function repeatedly with all the info we have for a file
1140 * If the function returns non-zero, we break and don't send any more
1141 */
1142
1143 int UUEXPORT
1144 UUInfoFile (uulist *thefile, void *opaque,
1145 int (*func) (void *, char *))
1146 {
1147 int errflag=0, res, bhflag=0, dd;
1148 long maxpos;
1149 FILE *inpfile;
1150
1151 /*
1152 * We might need to ask our callback function to download the file
1153 */
1154
1155 if (uu_FileCallback) {
1156 if ((res = (*uu_FileCallback) (uu_FileCBArg,
1157 thefile->thisfile->data->sfname,
1158 uugen_fnbuffer,
1159 1)) != UURET_OK)
1160 return res;
1161 if ((inpfile = fopen (uugen_fnbuffer, "rb")) == NULL) {
1162 (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname,
1163 uugen_fnbuffer, 0);
1164 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1165 uustring (S_NOT_OPEN_FILE), uugen_fnbuffer,
1166 strerror (uu_errno = errno));
1167 return UURET_IOERR;
1168 }
1169 }
1170 else {
1171 if ((inpfile = fopen (thefile->thisfile->data->sfname, "rb")) == NULL) {
1172 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1173 uustring (S_NOT_OPEN_FILE),
1174 thefile->thisfile->data->sfname,
1175 strerror (uu_errno=errno));
1176 return UURET_IOERR;
1177 }
1178 _FP_strncpy (uugen_fnbuffer, thefile->thisfile->data->sfname, 1024);
1179 }
1180
1181 /*
1182 * seek to beginning of info
1183 */
1184
1185 fseek (inpfile, thefile->thisfile->data->startpos, SEEK_SET);
1186 maxpos = thefile->thisfile->data->startpos + thefile->thisfile->data->length;
1187
1188 while (!feof (inpfile) &&
1189 (uu_fast_scanning || ftell(inpfile) < maxpos)) {
1190 if (_FP_fgets (uugen_inbuffer, 511, inpfile) == NULL)
1191 break;
1192 uugen_inbuffer[511] = '\0';
1193
1194 if (ferror (inpfile))
1195 break;
1196
1197 dd = UUValidData (uugen_inbuffer, 0, &bhflag);
1198
1199 if (thefile->uudet == B64ENCODED && dd == B64ENCODED)
1200 break;
1201 else if (thefile->uudet == BH_ENCODED && bhflag)
1202 break;
1203 else if ((thefile->uudet == UU_ENCODED || thefile->uudet == XX_ENCODED) &&
1204 strncmp (uugen_inbuffer, "begin ", 6) == 0)
1205 break;
1206 else if (thefile->uudet == YENC_ENCODED &&
1207 strncmp (uugen_inbuffer, "=ybegin ", 8) == 0)
1208 break;
1209
1210 if ((*func) (opaque, uugen_inbuffer))
1211 break;
1212 }
1213
1214 if (ferror (inpfile)) {
1215 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1216 uustring (S_READ_ERROR),
1217 uugen_fnbuffer, strerror (uu_errno = errno));
1218 errflag = 1;
1219 }
1220
1221 fclose (inpfile);
1222
1223 if (uu_FileCallback)
1224 (*uu_FileCallback) (uu_FileCBArg,
1225 thefile->thisfile->data->sfname,
1226 uugen_fnbuffer, 0);
1227
1228 if (errflag)
1229 return UURET_IOERR;
1230
1231 return UURET_OK;
1232 }
1233
1234 int UUEXPORT
1235 UURenameFile (uulist *thefile, char *newname)
1236 {
1237 char *oldname;
1238
1239 if (thefile == NULL)
1240 return UURET_ILLVAL;
1241
1242 oldname = thefile->filename;
1243
1244 if ((thefile->filename = _FP_strdup (newname)) == NULL) {
1245 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1246 uustring (S_NOT_RENAME),
1247 oldname, newname);
1248 thefile->filename = oldname;
1249 return UURET_NOMEM;
1250 }
1251 _FP_free (oldname);
1252 return UURET_OK;
1253 }
1254
1255 int UUEXPORT
1256 UURemoveTemp (uulist *thefile)
1257 {
1258 if (thefile == NULL)
1259 return UURET_ILLVAL;
1260
1261 if (thefile->binfile) {
1262 if (unlink (thefile->binfile)) {
1263 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1264 uustring (S_TMP_NOT_REMOVED),
1265 thefile->binfile,
1266 strerror (uu_errno = errno));
1267 }
1268 _FP_free (thefile->binfile);
1269 thefile->binfile = NULL;
1270 thefile->state &= ~UUFILE_TMPFILE;
1271 }
1272 return UURET_OK;
1273 }
1274
1275 int UUEXPORT
1276 UUCleanUp (void)
1277 {
1278 itbd *iter=ftodel, *ptr;
1279 uulist *liter;
1280 uufile *fiter;
1281 allomap *aiter;
1282
1283 /*
1284 * delete temporary input files (such as the copy of stdin)
1285 */
1286
1287 while (iter) {
1288 if (unlink (iter->fname)) {
1289 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1290 uustring (S_TMP_NOT_REMOVED),
1291 iter->fname, strerror (uu_errno = errno));
1292 }
1293 _FP_free (iter->fname);
1294 ptr = iter;
1295 iter = iter->NEXT;
1296 _FP_free (ptr);
1297 }
1298
1299 ftodel = NULL;
1300
1301 /*
1302 * Delete input files after successful decoding
1303 */
1304
1305 if (uu_remove_input) {
1306 liter = UUGlobalFileList;
1307 while (liter) {
1308 if (liter->state & UUFILE_DECODED) {
1309 fiter = liter->thisfile;
1310 while (fiter) {
1311 if (fiter->data && fiter->data->sfname) {
1312 /*
1313 * Error code ignored. We might want to delete a file multiple
1314 * times
1315 */
1316 unlink (fiter->data->sfname);
1317 }
1318 fiter = fiter->NEXT;
1319 }
1320 }
1321 liter = liter->NEXT;
1322 }
1323 }
1324
1325 UUkilllist (UUGlobalFileList);
1326 UUGlobalFileList = NULL;
1327
1328 _FP_free (uusavepath);
1329 _FP_free (uuencodeext);
1330 _FP_free (sstate.source);
1331
1332 uusavepath = NULL;
1333 uuencodeext = NULL;
1334
1335 UUkillheaders (&localenv);
1336 UUkillheaders (&sstate.envelope);
1337 memset (&localenv, 0, sizeof (headers));
1338 memset (&sstate, 0, sizeof (scanstate));
1339
1340 while (mssdepth) {
1341 mssdepth--;
1342 UUkillheaders (&(multistack[mssdepth].envelope));
1343 _FP_free (multistack[mssdepth].source);
1344 }
1345
1346 /*
1347 * clean up the malloc'ed stuff
1348 */
1349
1350 for (aiter=toallocate; aiter->ptr; aiter++) {
1351 _FP_free (*(aiter->ptr));
1352 *(aiter->ptr) = NULL;
1353 }
1354
1355 return UURET_OK;
1356 }
1357