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