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