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