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