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¬es */
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