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