ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uulib.c
Revision: 1.4.2.2
Committed: Sun Mar 31 19:52:07 2002 UTC (22 years, 2 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-17
Changes since 1.4.2.1: +11 -11 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.4.2.2 char * uulib_id = "$Id: uulib.c,v 1.23 2002/03/06 13:52:48 fp 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.4.2.1 void (*uu_MsgCallback) _ANSI_ARGS_((void *, char *, int)) = NULL;
118     int (*uu_BusyCallback) _ANSI_ARGS_((void *, uuprogress *)) = NULL;
119     int (*uu_FileCallback) _ANSI_ARGS_((void *, char *, char *, int)) = NULL;
120     char * (*uu_FNameFilter) _ANSI_ARGS_((void *, char *)) = NULL;
121 root 1.1
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.4.2.2 { &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.4.2.2 { &uunconc_save, 3*300 }, /* from uunconc.c:decoding buffer */
244 root 1.1 { &uuscan_shlline, 1024 }, /* from uuscan.c:ScanHeaderLine() */
245 root 1.4.2.2 { &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.4.2.1 _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.4.2.1 _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.4.2.1 _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.4.2.1 _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.4.2.1 _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.4.2.1 _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 root 1.4.2.1 void (*func) _ANSI_ARGS_((void *, char *, int)))
579 root 1.1 {
580     uu_MsgCallback = func;
581     uu_MsgCBArg = opaque;
582    
583     return UURET_OK;
584     }
585    
586     int UUEXPORT
587     UUSetBusyCallback (void *opaque,
588 root 1.4.2.1 int (*func) _ANSI_ARGS_((void *, uuprogress *)),
589 root 1.1 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 root 1.4.2.1 int (*func) _ANSI_ARGS_((void *, char *, char *, int)))
601 root 1.1 {
602     uu_FileCallback = func;
603     uu_FileCBArg = opaque;
604    
605     return UURET_OK;
606     }
607    
608     int UUEXPORT
609     UUSetFNameFilter (void *opaque,
610 root 1.4.2.1 char * (*func) _ANSI_ARGS_((void *, char *)))
611 root 1.1 {
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 root 1.4.2.1 UULoadFile (char *filename, char *fileid, int delflag)
657 root 1.1 {
658 root 1.4.2.1 int res, sr, count=0;
659 root 1.1 struct stat finfo;
660     fileread *loaded;
661     uufile *fload;
662     itbd *killem;
663     FILE *datei;
664    
665     if ((datei = fopen (filename, "rb")) == NULL) {
666     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
667     uustring (S_NOT_OPEN_SOURCE),
668     filename, strerror (uu_errno = errno));
669     return UURET_IOERR;
670     }
671    
672     if (fstat (fileno(datei), &finfo) == -1) {
673     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
674     uustring (S_NOT_STAT_FILE),
675     filename, strerror (uu_errno = errno));
676     fclose (datei);
677     return UURET_IOERR;
678     }
679    
680     /*
681     * schedule for destruction
682     */
683    
684     if (delflag && fileid==NULL) {
685     if ((killem = (itbd *) malloc (sizeof (itbd))) == NULL) {
686     UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
687     uustring (S_OUT_OF_MEMORY), sizeof (itbd));
688     }
689 root 1.4.2.1 else if ((killem->fname = _FP_strdup (filename)) == NULL) {
690 root 1.1 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
691     uustring (S_OUT_OF_MEMORY), strlen(filename)+1);
692 root 1.4.2.1 _FP_free (killem);
693 root 1.1 }
694     else {
695     killem->NEXT = ftodel;
696     ftodel = killem;
697     }
698     }
699    
700     progress.action = 0;
701     progress.partno = 0;
702     progress.numparts = 1;
703     progress.fsize = (long) ((finfo.st_size>0)?finfo.st_size:-1);
704     progress.percent = 0;
705     progress.foffset = 0;
706 root 1.4.2.1 _FP_strncpy (progress.curfile,
707 root 1.1 (strlen(filename)>255)?
708     (filename+strlen(filename)-255):filename,
709     256);
710     progress.action = UUACT_SCANNING;
711    
712     if (fileid == NULL)
713     fileid = filename;
714    
715     while (!feof (datei) && !ferror (datei)) {
716     /*
717     * Peek file, or some systems won't detect EOF
718     */
719     res = fgetc (datei);
720     if (feof (datei) || ferror (datei))
721     break;
722     else
723     ungetc (res, datei);
724    
725     if ((loaded = ScanPart (datei, fileid, &sr)) == NULL) {
726     if (sr != UURET_NODATA && sr != UURET_OK && sr != UURET_CONT) {
727     UUkillfread (loaded);
728 root 1.4.2.1 if (sr != UURET_CANCEL) {
729 root 1.1 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
730     uustring (S_READ_ERROR), filename,
731     strerror (uu_errno));
732 root 1.4.2.1 }
733 root 1.1 UUCheckGlobalList ();
734     progress.action = 0;
735     fclose (datei);
736     return sr;
737     }
738     continue;
739     }
740    
741     if (ferror (datei)) {
742     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
743     uustring (S_READ_ERROR), filename,
744     strerror (uu_errno = errno));
745     UUCheckGlobalList ();
746     progress.action = 0;
747     fclose (datei);
748     return UURET_IOERR;
749     }
750    
751     if ((loaded->uudet == QP_ENCODED || loaded->uudet == PT_ENCODED) &&
752 root 1.2 (loaded->filename == NULL || *(loaded->filename) == '\0') &&
753 root 1.1 !uu_handletext && (loaded->flags&FL_PARTIAL)==0) {
754     /*
755     * Don't want text
756     */
757     UUkillfread (loaded);
758     continue;
759     }
760    
761     if ((loaded->subject == NULL || *(loaded->subject) == '\0') &&
762     (loaded->mimeid == NULL || *(loaded->mimeid) == '\0') &&
763     (loaded->filename== NULL || *(loaded->filename)== '\0') &&
764     (loaded->uudet == 0)) {
765     /*
766     * no useful data here
767     */
768     UUkillfread (loaded);
769     if (uu_fast_scanning && sr != UURET_CONT) break;
770     continue;
771     }
772    
773     if ((fload = UUPreProcessPart (loaded, &res)) == NULL) {
774     /*
775     * no useful data found
776     */
777     if (res != UURET_NODATA) {
778     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
779     uustring (S_READ_ERROR), filename,
780     (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
781     }
782     UUkillfread (loaded);
783     if (uu_fast_scanning && sr != UURET_CONT) break;
784     continue;
785     }
786    
787     if ((loaded->subject && *(loaded->subject)) ||
788     (loaded->mimeid && *(loaded->mimeid)) ||
789     (loaded->filename&& *(loaded->filename))||
790     (loaded->uudet)) {
791     UUMessage (uulib_id, __LINE__, UUMSG_MESSAGE,
792     uustring (S_LOADED_PART),
793     filename,
794     (loaded->subject) ? loaded->subject : "",
795     (fload->subfname) ? fload->subfname : "",
796     (loaded->filename) ? loaded->filename : "",
797     fload->partno,
798     (loaded->begin) ? "begin" : "",
799     (loaded->end) ? "end" : "",
800     codenames[loaded->uudet]);
801     }
802    
803     if ((res = UUInsertPartToList (fload))) {
804     /*
805     * couldn't use the data
806     */
807     UUkillfile (fload);
808    
809     if (res != UURET_NODATA) {
810     UUCheckGlobalList ();
811     progress.action = 0;
812     fclose (datei);
813     return res;
814     }
815     if (uu_fast_scanning && sr != UURET_CONT)
816     break;
817    
818     continue;
819     }
820    
821     /*
822     * if in fast mode, we don't look any further, because we're told
823     * that each source file holds at most one encoded part
824     */
825    
826     if (uu_fast_scanning && sr != UURET_CONT)
827     break;
828 root 1.4.2.1
829     if (loaded->uudet)
830     count++;
831 root 1.1 }
832     fclose (datei);
833    
834 root 1.4.2.1 if (!uu_fast_scanning && count==0) {
835 root 1.1 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
836     uustring (S_NO_DATA_FOUND), filename);
837 root 1.4.2.1 }
838 root 1.1
839     progress.action = 0;
840     UUCheckGlobalList ();
841    
842     return UURET_OK;
843     }
844    
845     /*
846     * decode to a temporary file. this is well handled by uudecode()
847     */
848    
849     int UUEXPORT
850     UUDecodeToTemp (uulist *thefile)
851     {
852     return UUDecode (thefile);
853     }
854    
855     /*
856     * decode file first to temp file, then copy it to a final location
857     */
858    
859     int UUEXPORT
860     UUDecodeFile (uulist *thefile, char *destname)
861     {
862     FILE *target, *source;
863     struct stat finfo;
864     int fildes, res;
865     size_t bytes;
866    
867     if (thefile == NULL)
868     return UURET_ILLVAL;
869    
870     if ((res = UUDecode (thefile)) != UURET_OK)
871     if (res != UURET_NOEND || !uu_desperate)
872     return res;
873    
874     if (thefile->binfile == NULL) {
875     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
876     uustring (S_NO_BIN_FILE));
877     return UURET_IOERR;
878     }
879    
880     if ((source = fopen (thefile->binfile, "rb")) == NULL) {
881     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
882     uustring (S_NOT_OPEN_FILE),
883     thefile->binfile, strerror (uu_errno = errno));
884     return UURET_IOERR;
885     }
886    
887     /*
888     * for system security, strip setuid/setgid bits from mode
889     */
890    
891     if ((thefile->mode & 0777) != thefile->mode) {
892     UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
893     uustring (S_STRIPPED_SETUID),
894     destname, (int)thefile->mode);
895     thefile->mode &= 0777;
896     }
897    
898     /*
899     * Determine the name of the target file according to the rules:
900     *
901     * IF (destname!=NULL) THEN filename=destname;
902     * ELSE
903     * filename = thefile->filename
904     * IF (FilenameFilter!=NULL) THEN filename=FilenameFilter(filename);
905     * filename = SaveFilePath + filename
906     * END
907     */
908    
909     if (destname)
910     strcpy (uugen_fnbuffer, destname);
911     else {
912     sprintf (uugen_fnbuffer, "%s%s",
913     (uusavepath)?uusavepath:"",
914     UUFNameFilter ((thefile->filename)?
915     thefile->filename:"unknown.xxx"));
916     }
917    
918     /*
919     * if we don't want to overwrite existing files, check if it's there
920     */
921    
922     if (!uu_overwrite) {
923     if (stat (uugen_fnbuffer, &finfo) == 0) {
924     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
925     uustring (S_TARGET_EXISTS), uugen_fnbuffer);
926     fclose (source);
927     return UURET_EXISTS;
928     }
929     }
930    
931     if (fstat (fileno(source), &finfo) == -1) {
932     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
933     uustring (S_NOT_STAT_FILE),
934     thefile->binfile, strerror (uu_errno = errno));
935     fclose (source);
936     return UURET_IOERR;
937     }
938    
939     progress.action = 0;
940 root 1.4.2.1 _FP_strncpy (progress.curfile,
941 root 1.1 (strlen(uugen_fnbuffer)>255)?
942     (uugen_fnbuffer+strlen(uugen_fnbuffer)-255):uugen_fnbuffer,
943     256);
944     progress.partno = 0;
945     progress.numparts = 1;
946     progress.fsize = (long) ((finfo.st_size)?finfo.st_size:-1);
947     progress.foffset = 0;
948     progress.percent = 0;
949     progress.action = UUACT_COPYING;
950    
951     if ((fildes = open (uugen_fnbuffer,
952     O_WRONLY | O_CREAT | O_BINARY | O_TRUNC,
953     (uu_ignmode)?0666:thefile->mode)) == -1) {
954     progress.action = 0;
955     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
956     uustring (S_NOT_OPEN_TARGET),
957     uugen_fnbuffer, strerror (uu_errno = errno));
958     fclose (source);
959     return UURET_IOERR;
960     }
961    
962     if ((target = fdopen (fildes, "wb")) == NULL) {
963     progress.action = 0;
964     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
965     uustring (S_IO_ERR_TARGET),
966     uugen_fnbuffer, strerror (uu_errno = errno));
967     fclose (source);
968     close (fildes);
969     return UURET_IOERR;
970     }
971    
972     while (!feof (source)) {
973    
974     if (UUBUSYPOLL(ftell(source),progress.fsize)) {
975     UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
976     uustring (S_DECODE_CANCEL));
977     fclose (source);
978     fclose (target);
979     unlink (uugen_fnbuffer);
980     return UURET_CANCEL;
981     }
982    
983     bytes = fread (uugen_inbuffer, 1, 1024, source);
984    
985     if (ferror (source) || (bytes == 0 && !feof (source))) {
986     progress.action = 0;
987     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
988     uustring (S_READ_ERROR),
989     thefile->binfile, strerror (uu_errno = errno));
990     fclose (source);
991     fclose (target);
992     unlink (uugen_fnbuffer);
993     return UURET_IOERR;
994     }
995     if (fwrite (uugen_inbuffer, 1, bytes, target) != bytes) {
996     progress.action = 0;
997     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
998     uustring (S_WR_ERR_TARGET),
999     uugen_fnbuffer, strerror (uu_errno = errno));
1000     fclose (source);
1001     fclose (target);
1002     unlink (uugen_fnbuffer);
1003     return UURET_IOERR;
1004     }
1005     }
1006    
1007     fclose (target);
1008     fclose (source);
1009    
1010     /*
1011     * after a successful decoding run, we delete the temporary file
1012     */
1013    
1014     if (unlink (thefile->binfile)) {
1015     UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1016     uustring (S_TMP_NOT_REMOVED),
1017     thefile->binfile,
1018     strerror (uu_errno = errno));
1019     }
1020 root 1.4.2.1 _FP_free (thefile->binfile);
1021 root 1.1 thefile->binfile = NULL;
1022     thefile->state &= ~UUFILE_TMPFILE;
1023     thefile->state |= UUFILE_DECODED;
1024     progress.action = 0;
1025    
1026     return UURET_OK;
1027     }
1028    
1029     /*
1030     * Calls a function repeatedly with all the info we have for a file
1031     * If the function returns non-zero, we break and don't send any more
1032     */
1033    
1034     int UUEXPORT
1035     UUInfoFile (uulist *thefile, void *opaque,
1036 root 1.4.2.1 int (*func) _ANSI_ARGS_((void *, char *)))
1037 root 1.1 {
1038     int errflag=0, res, bhflag=0, dd;
1039     long maxpos;
1040     FILE *inpfile;
1041    
1042     /*
1043     * We might need to ask our callback function to download the file
1044     */
1045    
1046     if (uu_FileCallback) {
1047     if ((res = (*uu_FileCallback) (uu_FileCBArg,
1048     thefile->thisfile->data->sfname,
1049     uugen_fnbuffer,
1050     1)) != UURET_OK)
1051     return res;
1052     if ((inpfile = fopen (uugen_fnbuffer, "rb")) == NULL) {
1053     (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname,
1054     uugen_fnbuffer, 0);
1055     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1056     uustring (S_NOT_OPEN_FILE), uugen_fnbuffer,
1057     strerror (uu_errno = errno));
1058     return UURET_IOERR;
1059     }
1060     }
1061     else {
1062     if ((inpfile = fopen (thefile->thisfile->data->sfname, "rb")) == NULL) {
1063     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1064     uustring (S_NOT_OPEN_FILE),
1065     thefile->thisfile->data->sfname,
1066     strerror (uu_errno=errno));
1067     return UURET_IOERR;
1068     }
1069 root 1.4.2.1 _FP_strncpy (uugen_fnbuffer, thefile->thisfile->data->sfname, 1024);
1070 root 1.1 }
1071    
1072     /*
1073     * seek to beginning of info
1074     */
1075    
1076     fseek (inpfile, thefile->thisfile->data->startpos, SEEK_SET);
1077     maxpos = thefile->thisfile->data->startpos + thefile->thisfile->data->length;
1078    
1079     while (!feof (inpfile) &&
1080     (uu_fast_scanning || ftell(inpfile) < maxpos)) {
1081 root 1.4.2.1 if (_FP_fgets (uugen_inbuffer, 511, inpfile) == NULL)
1082 root 1.1 break;
1083     uugen_inbuffer[511] = '\0';
1084    
1085     if (ferror (inpfile))
1086     break;
1087    
1088     dd = UUValidData (uugen_inbuffer, 0, &bhflag);
1089    
1090     if (thefile->uudet == B64ENCODED && dd == B64ENCODED)
1091     break;
1092     else if (thefile->uudet == BH_ENCODED && bhflag)
1093     break;
1094     else if ((thefile->uudet == UU_ENCODED || thefile->uudet == XX_ENCODED) &&
1095     strncmp (uugen_inbuffer, "begin ", 6) == 0)
1096     break;
1097    
1098     if ((*func) (opaque, uugen_inbuffer))
1099     break;
1100     }
1101    
1102     if (ferror (inpfile)) {
1103     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1104     uustring (S_READ_ERROR),
1105     uugen_fnbuffer, strerror (uu_errno = errno));
1106     errflag = 1;
1107     }
1108    
1109     fclose (inpfile);
1110    
1111     if (uu_FileCallback)
1112     (*uu_FileCallback) (uu_FileCBArg,
1113     thefile->thisfile->data->sfname,
1114     uugen_fnbuffer, 0);
1115    
1116     if (errflag)
1117     return UURET_IOERR;
1118    
1119     return UURET_OK;
1120     }
1121    
1122     int UUEXPORT
1123     UURenameFile (uulist *thefile, char *newname)
1124     {
1125     char *oldname;
1126    
1127     if (thefile == NULL)
1128     return UURET_ILLVAL;
1129    
1130     oldname = thefile->filename;
1131    
1132 root 1.4.2.1 if ((thefile->filename = _FP_strdup (newname)) == NULL) {
1133 root 1.1 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1134     uustring (S_NOT_RENAME),
1135     oldname, newname);
1136     thefile->filename = oldname;
1137     return UURET_NOMEM;
1138     }
1139 root 1.4.2.1 _FP_free (oldname);
1140 root 1.1 return UURET_OK;
1141     }
1142    
1143     int UUEXPORT
1144     UURemoveTemp (uulist *thefile)
1145     {
1146     if (thefile == NULL)
1147     return UURET_ILLVAL;
1148    
1149     if (thefile->binfile) {
1150     if (unlink (thefile->binfile)) {
1151     UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1152     uustring (S_TMP_NOT_REMOVED),
1153     thefile->binfile,
1154     strerror (uu_errno = errno));
1155     }
1156 root 1.4.2.1 _FP_free (thefile->binfile);
1157 root 1.1 thefile->binfile = NULL;
1158     thefile->state &= ~UUFILE_TMPFILE;
1159     }
1160     return UURET_OK;
1161     }
1162    
1163     int UUEXPORT
1164     UUCleanUp (void)
1165     {
1166     itbd *iter=ftodel, *ptr;
1167 root 1.2 uulist *liter;
1168     uufile *fiter;
1169 root 1.1 allomap *aiter;
1170    
1171     /*
1172 root 1.2 * delete temporary input files (such as the copy of stdin)
1173 root 1.1 */
1174 root 1.2
1175 root 1.1 while (iter) {
1176     if (unlink (iter->fname)) {
1177     UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1178     uustring (S_TMP_NOT_REMOVED),
1179     iter->fname, strerror (uu_errno = errno));
1180     }
1181 root 1.4.2.1 _FP_free (iter->fname);
1182 root 1.1 ptr = iter;
1183     iter = iter->NEXT;
1184 root 1.4.2.1 _FP_free (ptr);
1185 root 1.1 }
1186 root 1.2
1187 root 1.1 ftodel = NULL;
1188 root 1.2
1189     /*
1190     * Delete input files after successful decoding
1191     */
1192    
1193     if (uu_remove_input) {
1194     liter = UUGlobalFileList;
1195     while (liter) {
1196     if (liter->state & UUFILE_DECODED) {
1197     fiter = liter->thisfile;
1198     while (fiter) {
1199     if (fiter->data && fiter->data->sfname) {
1200     /*
1201     * Error code ignored. We might want to delete a file multiple
1202     * times
1203     */
1204     unlink (fiter->data->sfname);
1205     }
1206     fiter = fiter->NEXT;
1207     }
1208     }
1209     liter = liter->NEXT;
1210     }
1211     }
1212    
1213     UUkilllist (UUGlobalFileList);
1214     UUGlobalFileList = NULL;
1215 root 1.1
1216 root 1.4.2.1 _FP_free (uusavepath);
1217     _FP_free (uuencodeext);
1218     _FP_free (sstate.source);
1219 root 1.1
1220     uusavepath = NULL;
1221     uuencodeext = NULL;
1222    
1223     UUkillheaders (&localenv);
1224     UUkillheaders (&sstate.envelope);
1225     memset (&localenv, 0, sizeof (headers));
1226     memset (&sstate, 0, sizeof (scanstate));
1227    
1228     while (mssdepth) {
1229     mssdepth--;
1230     UUkillheaders (&(multistack[mssdepth].envelope));
1231 root 1.4.2.1 _FP_free (multistack[mssdepth].source);
1232 root 1.1 }
1233    
1234     /*
1235     * clean up the malloc'ed stuff
1236     */
1237    
1238     for (aiter=toallocate; aiter->ptr; aiter++) {
1239 root 1.4.2.1 _FP_free (*(aiter->ptr));
1240 root 1.1 *(aiter->ptr) = NULL;
1241     }
1242    
1243     return UURET_OK;
1244     }
1245