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