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