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