ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uulib.c
Revision: 1.5
Committed: Sun Mar 31 20:04:30 2002 UTC (22 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +11 -11 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.4.2.2 2002/03/31 19:52:07 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
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
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
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 if (uu_busy_msecs <= 0) {
335 msecs = 1;
336 }
337 else {
338 now = time(NULL);
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
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
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
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
567 UUstrerror (int code)
568 {
569 return uuretcodes[code];
570 }
571
572 /*
573 * Set the various Callback functions
574 */
575
576 int UUEXPORT
577 UUSetMsgCallback (void *opaque,
578 void (*func) (void *, char *, int))
579 {
580 uu_MsgCallback = func;
581 uu_MsgCBArg = opaque;
582
583 return UURET_OK;
584 }
585
586 int UUEXPORT
587 UUSetBusyCallback (void *opaque,
588 int (*func) (void *, uuprogress *),
589 long msecs)
590 {
591 uu_BusyCallback = func;
592 uu_BusyCBArg = opaque;
593 uu_busy_msecs = msecs;
594
595 return UURET_OK;
596 }
597
598 int UUEXPORT
599 UUSetFileCallback (void *opaque,
600 int (*func) (void *, char *, char *, int))
601 {
602 uu_FileCallback = func;
603 uu_FileCBArg = opaque;
604
605 return UURET_OK;
606 }
607
608 int UUEXPORT
609 UUSetFNameFilter (void *opaque,
610 char * (*func) (void *, char *))
611 {
612 uu_FNameFilter = func;
613 uu_FFCBArg = opaque;
614
615 return UURET_OK;
616 }
617
618 /*
619 * Return a pointer to the nth element of the GlobalFileList
620 * zero-based, returns NULL if item is too large.
621 */
622
623 uulist * UUEXPORT
624 UUGetFileListItem (int item)
625 {
626 uulist *iter=UUGlobalFileList;
627
628 if (item < 0)
629 return NULL;
630 while (item && iter) {
631 iter = iter->NEXT;
632 item--;
633 }
634 return iter;
635 }
636
637 /*
638 * call the current filter
639 */
640
641 char * UUEXPORT
642 UUFNameFilter (char *fname)
643 {
644 if (uu_FNameFilter)
645 return (*uu_FNameFilter) (uu_FFCBArg, fname);
646
647 return fname;
648 }
649
650 /*
651 * Load a File. We call ScanPart repeatedly until at EOF and
652 * add the parts to UUGlobalFileList
653 */
654
655 int UUEXPORT
656 UULoadFile (char *filename, char *fileid, int delflag, int *partcount)
657 {
658 int res, sr;
659 struct stat finfo;
660 fileread *loaded;
661 uufile *fload;
662 itbd *killem;
663 FILE *datei;
664
665 int _count;
666 if (!partcount)
667 partcount = &_count;
668
669 *partcount = 0;
670
671 if ((datei = fopen (filename, "rb")) == NULL) {
672 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
673 uustring (S_NOT_OPEN_SOURCE),
674 filename, strerror (uu_errno = errno));
675 return UURET_IOERR;
676 }
677
678 if (fstat (fileno(datei), &finfo) == -1) {
679 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
680 uustring (S_NOT_STAT_FILE),
681 filename, strerror (uu_errno = errno));
682 fclose (datei);
683 return UURET_IOERR;
684 }
685
686 /*
687 * schedule for destruction
688 */
689
690 if (delflag && fileid==NULL) {
691 if ((killem = (itbd *) malloc (sizeof (itbd))) == NULL) {
692 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
693 uustring (S_OUT_OF_MEMORY), sizeof (itbd));
694 }
695 else if ((killem->fname = FP_strdup (filename)) == NULL) {
696 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
697 uustring (S_OUT_OF_MEMORY), strlen(filename)+1);
698 FP_free (killem);
699 }
700 else {
701 killem->NEXT = ftodel;
702 ftodel = killem;
703 }
704 }
705
706 progress.action = 0;
707 progress.partno = 0;
708 progress.numparts = 1;
709 progress.fsize = (long) ((finfo.st_size>0)?finfo.st_size:-1);
710 progress.percent = 0;
711 progress.foffset = 0;
712 FP_strncpy (progress.curfile,
713 (strlen(filename)>255)?
714 (filename+strlen(filename)-255):filename,
715 256);
716 progress.action = UUACT_SCANNING;
717
718 if (fileid == NULL)
719 fileid = filename;
720
721 while (!feof (datei) && !ferror (datei)) {
722 /*
723 * Peek file, or some systems won't detect EOF
724 */
725 res = fgetc (datei);
726 if (feof (datei) || ferror (datei))
727 break;
728 else
729 ungetc (res, datei);
730
731 if ((loaded = ScanPart (datei, fileid, &sr)) == NULL) {
732 if (sr != UURET_NODATA && sr != UURET_OK && sr != UURET_CONT) {
733 UUkillfread (loaded);
734 if (sr != UURET_CANCEL)
735 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
736 uustring (S_READ_ERROR), filename,
737 strerror (uu_errno));
738
739 UUCheckGlobalList ();
740 progress.action = 0;
741 fclose (datei);
742 return sr;
743 }
744 continue;
745 }
746
747 if (ferror (datei)) {
748 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
749 uustring (S_READ_ERROR), filename,
750 strerror (uu_errno = errno));
751 UUCheckGlobalList ();
752 progress.action = 0;
753 fclose (datei);
754 return UURET_IOERR;
755 }
756
757 if ((loaded->uudet == QP_ENCODED || loaded->uudet == PT_ENCODED) &&
758 (loaded->filename == NULL || *(loaded->filename) == '\0') &&
759 !uu_handletext && (loaded->flags&FL_PARTIAL)==0) {
760 /*
761 * Don't want text
762 */
763 UUkillfread (loaded);
764 continue;
765 }
766
767 if ((loaded->subject == NULL || *(loaded->subject) == '\0') &&
768 (loaded->mimeid == NULL || *(loaded->mimeid) == '\0') &&
769 (loaded->filename== NULL || *(loaded->filename)== '\0') &&
770 (loaded->uudet == 0)) {
771 /*
772 * no useful data here
773 */
774 UUkillfread (loaded);
775 if (uu_fast_scanning && sr != UURET_CONT) break;
776 continue;
777 }
778
779 if ((fload = UUPreProcessPart (loaded, &res)) == NULL) {
780 /*
781 * no useful data found
782 */
783 if (res != UURET_NODATA) {
784 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
785 uustring (S_READ_ERROR), filename,
786 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
787 }
788 UUkillfread (loaded);
789 if (uu_fast_scanning && sr != UURET_CONT) break;
790 continue;
791 }
792
793 if ((loaded->subject && *(loaded->subject)) ||
794 (loaded->mimeid && *(loaded->mimeid)) ||
795 (loaded->filename&& *(loaded->filename))||
796 (loaded->uudet)) {
797 UUMessage (uulib_id, __LINE__, UUMSG_MESSAGE,
798 uustring (S_LOADED_PART),
799 filename,
800 (loaded->subject) ? loaded->subject : "",
801 (fload->subfname) ? fload->subfname : "",
802 (loaded->filename) ? loaded->filename : "",
803 fload->partno,
804 (loaded->begin) ? "begin" : "",
805 (loaded->end) ? "end" : "",
806 codenames[loaded->uudet]);
807 }
808
809 if ((res = UUInsertPartToList (fload))) {
810 /*
811 * couldn't use the data
812 */
813 UUkillfile (fload);
814
815 if (res != UURET_NODATA) {
816 UUCheckGlobalList ();
817 progress.action = 0;
818 fclose (datei);
819 return res;
820 }
821 if (uu_fast_scanning && sr != UURET_CONT)
822 break;
823
824 continue;
825 }
826
827 /*
828 * if in fast mode, we don't look any further, because we're told
829 * that each source file holds at most one encoded part
830 */
831
832 if (loaded->uudet)
833 (*partcount)++;
834
835 if (uu_fast_scanning && sr != UURET_CONT)
836 break;
837 }
838 fclose (datei);
839
840 if (!uu_fast_scanning && *partcount == 0)
841 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
842 uustring (S_NO_DATA_FOUND), filename);
843
844 progress.action = 0;
845 UUCheckGlobalList ();
846
847 return UURET_OK;
848 }
849
850 /*
851 * decode to a temporary file. this is well handled by uudecode()
852 */
853
854 int UUEXPORT
855 UUDecodeToTemp (uulist *thefile)
856 {
857 return UUDecode (thefile);
858 }
859
860 /*
861 * decode file first to temp file, then copy it to a final location
862 */
863
864 int UUEXPORT
865 UUDecodeFile (uulist *thefile, char *destname)
866 {
867 FILE *target, *source;
868 struct stat finfo;
869 int fildes, res;
870 size_t bytes;
871
872 if (thefile == NULL)
873 return UURET_ILLVAL;
874
875 if ((res = UUDecode (thefile)) != UURET_OK)
876 if (res != UURET_NOEND || !uu_desperate)
877 return res;
878
879 if (thefile->binfile == NULL) {
880 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
881 uustring (S_NO_BIN_FILE));
882 return UURET_IOERR;
883 }
884
885 if ((source = fopen (thefile->binfile, "rb")) == NULL) {
886 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
887 uustring (S_NOT_OPEN_FILE),
888 thefile->binfile, strerror (uu_errno = errno));
889 return UURET_IOERR;
890 }
891
892 /*
893 * for system security, strip setuid/setgid bits from mode
894 */
895
896 if ((thefile->mode & 0777) != thefile->mode) {
897 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
898 uustring (S_STRIPPED_SETUID),
899 destname, (int)thefile->mode);
900 thefile->mode &= 0777;
901 }
902
903 /*
904 * Determine the name of the target file according to the rules:
905 *
906 * IF (destname!=NULL) THEN filename=destname;
907 * ELSE
908 * filename = thefile->filename
909 * IF (FilenameFilter!=NULL) THEN filename=FilenameFilter(filename);
910 * filename = SaveFilePath + filename
911 * END
912 */
913
914 if (destname)
915 strcpy (uugen_fnbuffer, destname);
916 else {
917 sprintf (uugen_fnbuffer, "%s%s",
918 (uusavepath)?uusavepath:"",
919 UUFNameFilter ((thefile->filename)?
920 thefile->filename:"unknown.xxx"));
921 }
922
923 /*
924 * if we don't want to overwrite existing files, check if it's there
925 */
926
927 if (!uu_overwrite) {
928 if (stat (uugen_fnbuffer, &finfo) == 0) {
929 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
930 uustring (S_TARGET_EXISTS), uugen_fnbuffer);
931 fclose (source);
932 return UURET_EXISTS;
933 }
934 }
935
936 if (fstat (fileno(source), &finfo) == -1) {
937 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
938 uustring (S_NOT_STAT_FILE),
939 thefile->binfile, strerror (uu_errno = errno));
940 fclose (source);
941 return UURET_IOERR;
942 }
943
944 /* try rename() shortcut first */
945 if (!rename (thefile->binfile, uugen_fnbuffer))
946 {
947 mode_t mask = 0000; /* there is a slight window here anyway */
948 #if HAVE_UMASK
949 mask = umask (0022); umask (mask);
950 #endif
951 fclose (source);
952 #if HAVE_CHMOD
953 chmod (uugen_fnbuffer, thefile->mode & ~mask);
954 #endif
955 goto skip_copy;
956 }
957
958 progress.action = 0;
959 FP_strncpy (progress.curfile,
960 (strlen(uugen_fnbuffer)>255)?
961 (uugen_fnbuffer+strlen(uugen_fnbuffer)-255):uugen_fnbuffer,
962 256);
963 progress.partno = 0;
964 progress.numparts = 1;
965 progress.fsize = (long) ((finfo.st_size)?finfo.st_size:-1);
966 progress.foffset = 0;
967 progress.percent = 0;
968 progress.action = UUACT_COPYING;
969
970 if ((fildes = open (uugen_fnbuffer,
971 O_WRONLY | O_CREAT | O_BINARY | O_TRUNC,
972 (uu_ignmode)?0666:thefile->mode)) == -1) {
973 progress.action = 0;
974 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
975 uustring (S_NOT_OPEN_TARGET),
976 uugen_fnbuffer, strerror (uu_errno = errno));
977 fclose (source);
978 return UURET_IOERR;
979 }
980
981 if ((target = fdopen (fildes, "wb")) == NULL) {
982 progress.action = 0;
983 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
984 uustring (S_IO_ERR_TARGET),
985 uugen_fnbuffer, strerror (uu_errno = errno));
986 fclose (source);
987 close (fildes);
988 return UURET_IOERR;
989 }
990
991 while (!feof (source)) {
992
993 if (UUBUSYPOLL(ftell(source),progress.fsize)) {
994 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
995 uustring (S_DECODE_CANCEL));
996 fclose (source);
997 fclose (target);
998 unlink (uugen_fnbuffer);
999 return UURET_CANCEL;
1000 }
1001
1002 bytes = fread (uugen_inbuffer, 1, 1024, source);
1003
1004 if (ferror (source) || (bytes == 0 && !feof (source))) {
1005 progress.action = 0;
1006 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1007 uustring (S_READ_ERROR),
1008 thefile->binfile, strerror (uu_errno = errno));
1009 fclose (source);
1010 fclose (target);
1011 unlink (uugen_fnbuffer);
1012 return UURET_IOERR;
1013 }
1014 if (fwrite (uugen_inbuffer, 1, bytes, target) != bytes) {
1015 progress.action = 0;
1016 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1017 uustring (S_WR_ERR_TARGET),
1018 uugen_fnbuffer, strerror (uu_errno = errno));
1019 fclose (source);
1020 fclose (target);
1021 unlink (uugen_fnbuffer);
1022 return UURET_IOERR;
1023 }
1024 }
1025
1026 fclose (target);
1027 fclose (source);
1028
1029 /*
1030 * after a successful decoding run, we delete the temporary file
1031 */
1032
1033 if (unlink (thefile->binfile)) {
1034 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1035 uustring (S_TMP_NOT_REMOVED),
1036 thefile->binfile,
1037 strerror (uu_errno = errno));
1038 }
1039
1040 skip_copy:
1041 FP_free (thefile->binfile);
1042 thefile->binfile = NULL;
1043 thefile->state &= ~UUFILE_TMPFILE;
1044 thefile->state |= UUFILE_DECODED;
1045 progress.action = 0;
1046
1047 return UURET_OK;
1048 }
1049
1050 /*
1051 * Calls a function repeatedly with all the info we have for a file
1052 * If the function returns non-zero, we break and don't send any more
1053 */
1054
1055 int UUEXPORT
1056 UUInfoFile (uulist *thefile, void *opaque,
1057 int (*func) (void *, char *))
1058 {
1059 int errflag=0, res, bhflag=0, dd;
1060 long maxpos;
1061 FILE *inpfile;
1062
1063 /*
1064 * We might need to ask our callback function to download the file
1065 */
1066
1067 if (uu_FileCallback) {
1068 if ((res = (*uu_FileCallback) (uu_FileCBArg,
1069 thefile->thisfile->data->sfname,
1070 uugen_fnbuffer,
1071 1)) != UURET_OK)
1072 return res;
1073 if ((inpfile = fopen (uugen_fnbuffer, "rb")) == NULL) {
1074 (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname,
1075 uugen_fnbuffer, 0);
1076 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1077 uustring (S_NOT_OPEN_FILE), uugen_fnbuffer,
1078 strerror (uu_errno = errno));
1079 return UURET_IOERR;
1080 }
1081 }
1082 else {
1083 if ((inpfile = fopen (thefile->thisfile->data->sfname, "rb")) == NULL) {
1084 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1085 uustring (S_NOT_OPEN_FILE),
1086 thefile->thisfile->data->sfname,
1087 strerror (uu_errno=errno));
1088 return UURET_IOERR;
1089 }
1090 FP_strncpy (uugen_fnbuffer, thefile->thisfile->data->sfname, 1024);
1091 }
1092
1093 /*
1094 * seek to beginning of info
1095 */
1096
1097 fseek (inpfile, thefile->thisfile->data->startpos, SEEK_SET);
1098 maxpos = thefile->thisfile->data->startpos + thefile->thisfile->data->length;
1099
1100 while (!feof (inpfile) &&
1101 (uu_fast_scanning || ftell(inpfile) < maxpos)) {
1102 if (FP_fgets (uugen_inbuffer, 511, inpfile) == NULL)
1103 break;
1104 uugen_inbuffer[511] = '\0';
1105
1106 if (ferror (inpfile))
1107 break;
1108
1109 dd = UUValidData (uugen_inbuffer, 0, &bhflag);
1110
1111 if (thefile->uudet == B64ENCODED && dd == B64ENCODED)
1112 break;
1113 else if (thefile->uudet == BH_ENCODED && bhflag)
1114 break;
1115 else if ((thefile->uudet == UU_ENCODED || thefile->uudet == XX_ENCODED) &&
1116 strncmp (uugen_inbuffer, "begin ", 6) == 0)
1117 break;
1118
1119 if ((*func) (opaque, uugen_inbuffer))
1120 break;
1121 }
1122
1123 if (ferror (inpfile)) {
1124 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1125 uustring (S_READ_ERROR),
1126 uugen_fnbuffer, strerror (uu_errno = errno));
1127 errflag = 1;
1128 }
1129
1130 fclose (inpfile);
1131
1132 if (uu_FileCallback)
1133 (*uu_FileCallback) (uu_FileCBArg,
1134 thefile->thisfile->data->sfname,
1135 uugen_fnbuffer, 0);
1136
1137 if (errflag)
1138 return UURET_IOERR;
1139
1140 return UURET_OK;
1141 }
1142
1143 int UUEXPORT
1144 UURenameFile (uulist *thefile, char *newname)
1145 {
1146 char *oldname;
1147
1148 if (thefile == NULL)
1149 return UURET_ILLVAL;
1150
1151 oldname = thefile->filename;
1152
1153 if ((thefile->filename = FP_strdup (newname)) == NULL) {
1154 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1155 uustring (S_NOT_RENAME),
1156 oldname, newname);
1157 thefile->filename = oldname;
1158 return UURET_NOMEM;
1159 }
1160 FP_free (oldname);
1161 return UURET_OK;
1162 }
1163
1164 int UUEXPORT
1165 UURemoveTemp (uulist *thefile)
1166 {
1167 if (thefile == NULL)
1168 return UURET_ILLVAL;
1169
1170 if (thefile->binfile) {
1171 if (unlink (thefile->binfile)) {
1172 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1173 uustring (S_TMP_NOT_REMOVED),
1174 thefile->binfile,
1175 strerror (uu_errno = errno));
1176 }
1177 FP_free (thefile->binfile);
1178 thefile->binfile = NULL;
1179 thefile->state &= ~UUFILE_TMPFILE;
1180 }
1181 return UURET_OK;
1182 }
1183
1184 int UUEXPORT
1185 UUCleanUp (void)
1186 {
1187 itbd *iter=ftodel, *ptr;
1188 uulist *liter;
1189 uufile *fiter;
1190 allomap *aiter;
1191
1192 /*
1193 * delete temporary input files (such as the copy of stdin)
1194 */
1195
1196 while (iter) {
1197 if (unlink (iter->fname)) {
1198 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1199 uustring (S_TMP_NOT_REMOVED),
1200 iter->fname, strerror (uu_errno = errno));
1201 }
1202 FP_free (iter->fname);
1203 ptr = iter;
1204 iter = iter->NEXT;
1205 FP_free (ptr);
1206 }
1207
1208 ftodel = NULL;
1209
1210 /*
1211 * Delete input files after successful decoding
1212 */
1213
1214 if (uu_remove_input) {
1215 liter = UUGlobalFileList;
1216 while (liter) {
1217 if (liter->state & UUFILE_DECODED) {
1218 fiter = liter->thisfile;
1219 while (fiter) {
1220 if (fiter->data && fiter->data->sfname) {
1221 /*
1222 * Error code ignored. We might want to delete a file multiple
1223 * times
1224 */
1225 unlink (fiter->data->sfname);
1226 }
1227 fiter = fiter->NEXT;
1228 }
1229 }
1230 liter = liter->NEXT;
1231 }
1232 }
1233
1234 UUkilllist (UUGlobalFileList);
1235 UUGlobalFileList = NULL;
1236
1237 FP_free (uusavepath);
1238 FP_free (uuencodeext);
1239 FP_free (sstate.source);
1240
1241 uusavepath = NULL;
1242 uuencodeext = NULL;
1243
1244 UUkillheaders (&localenv);
1245 UUkillheaders (&sstate.envelope);
1246 memset (&localenv, 0, sizeof (headers));
1247 memset (&sstate, 0, sizeof (scanstate));
1248
1249 while (mssdepth) {
1250 mssdepth--;
1251 UUkillheaders (&(multistack[mssdepth].envelope));
1252 FP_free (multistack[mssdepth].source);
1253 }
1254
1255 /*
1256 * clean up the malloc'ed stuff
1257 */
1258
1259 for (aiter=toallocate; aiter->ptr; aiter++) {
1260 FP_free (*(aiter->ptr));
1261 *(aiter->ptr) = NULL;
1262 }
1263
1264 return UURET_OK;
1265 }
1266