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