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