ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uulib.c
Revision: 1.26
Committed: Sat Sep 24 06:02:04 2022 UTC (20 months, 1 week ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.25: +1 -22 lines
Log Message:
*** empty log message ***

File Contents

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