ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uulib.c
Revision: 1.8
Committed: Fri Apr 5 21:56:57 2002 UTC (22 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +4 -4 lines
Log Message:
*** empty log message ***

File Contents

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