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