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