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