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