ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uulib.c
Revision: 1.4.2.4
Committed: Thu Nov 6 13:08:24 2003 UTC (20 years, 6 months ago) by root
Content type: text/plain
Branch: UUDEVIEW
CVS Tags: UUDEVIEW-0-5-19
Changes since 1.4.2.3: +27 -2 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.28 2003/09/29 23:27:47 fp 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) _ANSI_ARGS_((void *, char *, int)) = NULL;
118 int (*uu_BusyCallback) _ANSI_ARGS_((void *, uuprogress *)) = NULL;
119 int (*uu_FileCallback) _ANSI_ARGS_((void *, char *, char *, int)) = NULL;
120 char * (*uu_FNameFilter) _ANSI_ARGS_((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_shlline2, 1024 }, /* from uuscan.c:ScanHeaderLine() */
246 { &uuscan_pvvalue, 300 }, /* from uuscan.c:ParseValue() */
247 { &uuscan_phtext, 300 }, /* from uuscan.c:ParseHeader() */
248 { &uuscan_sdline, 300 }, /* from uuscan.c:ScanData() */
249 { &uuscan_sdbhds1, 300 },
250 { &uuscan_sdbhds2, 300 },
251 { &uuscan_spline, 300 }, /* from uuscan.c:ScanPart() */
252 { &uuutil_bhwtmp, 300 }, /* from uuutil.c:UUbhwrite() */
253 { NULL, 0 }
254 };
255
256 /*
257 * Handle the printing of messages. Works like printf.
258 */
259
260 #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H)
261 int
262 UUMessage (char *file, int line, int level, char *format, ...)
263 #else
264 int
265 UUMessage (va_alist)
266 va_dcl
267 #endif
268 {
269 char *msgptr;
270 #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H)
271 va_list ap;
272
273 va_start (ap, format);
274 #else
275 char *file, *format;
276 int line, level;
277 va_list ap;
278
279 va_start (ap);
280 file = va_arg (ap, char *);
281 line = va_arg (ap, int);
282 level = va_arg (ap, int);
283 format = va_arg (ap, char *);
284 #endif
285
286 if (uu_debug) {
287 sprintf (uulib_msgstring, "%s(%d): %s", file, line, msgnames[level]);
288 msgptr = uulib_msgstring + strlen (uulib_msgstring);
289 }
290 else {
291 sprintf (uulib_msgstring, "%s", msgnames[level]);
292 msgptr = uulib_msgstring + strlen (uulib_msgstring);
293 }
294
295 if (uu_MsgCallback && (level>UUMSG_NOTE || uu_verbose)) {
296 vsprintf (msgptr, format, ap);
297
298 (*uu_MsgCallback) (uu_MsgCBArg, uulib_msgstring, level);
299 }
300
301 va_end (ap);
302
303 return UURET_OK;
304 }
305
306 /*
307 * Call the Busy Callback from time to time. This function must be
308 * polled from the Busy loops.
309 */
310
311 int
312 UUBusyPoll (void)
313 {
314 #ifdef HAVE_GETTIMEOFDAY
315 struct timeval tv;
316 long msecs;
317
318 if (uu_BusyCallback) {
319 (void) gettimeofday (&tv, NULL);
320
321 msecs = 1000*(tv.tv_sec-uu_last_secs)+(tv.tv_usec-uu_last_usecs)/1000;
322
323 if (uu_last_secs==0 || msecs > uu_busy_msecs) {
324 uu_last_secs = tv.tv_sec;
325 uu_last_usecs = tv.tv_usec;
326
327 return (*uu_BusyCallback) (uu_BusyCBArg, &progress);
328 }
329 }
330 #else
331 time_t now;
332 long msecs;
333
334 if (uu_BusyCallback) {
335 if (uu_busy_msecs <= 0) {
336 msecs = 1;
337 }
338 else {
339 now = time(NULL);
340 msecs = 1000 * (now - uu_last_secs);
341 }
342
343 if (uu_last_secs==0 || msecs > uu_busy_msecs) {
344 uu_last_secs = now;
345 uu_last_usecs = 0;
346
347 return (*uu_BusyCallback) (uu_BusyCBArg, &progress);
348 }
349 }
350 #endif
351
352 return 0;
353 }
354
355 /*
356 * Initialization function
357 */
358
359 int UUEXPORT
360 UUInitialize (void)
361 {
362 allomap *aiter;
363
364 progress.action = 0;
365 progress.curfile[0] = '\0';
366
367 ftodel = NULL;
368
369 uusavepath = NULL;
370 uuencodeext = NULL;
371
372 mssdepth = 0;
373 memset (&localenv, 0, sizeof (headers));
374 memset (&sstate, 0, sizeof (scanstate));
375
376 nofnum = 0;
377 mimseqno = 0;
378 lastvalid = 0;
379 lastenc = 0;
380 uuyctr = 0;
381
382 /*
383 * Allocate areas
384 */
385
386 for (aiter=toallocate; aiter->ptr; aiter++)
387 *(aiter->ptr) = NULL;
388
389 for (aiter=toallocate; aiter->ptr; aiter++) {
390 if ((*(aiter->ptr) = (char *) malloc (aiter->size)) == NULL) {
391 /*
392 * oops. we may not print a message here, because we need these
393 * areas (uulib_msgstring) in UUMessage()
394 */
395 for (aiter=toallocate; aiter->ptr; aiter++) {
396 _FP_free (*(aiter->ptr));
397 }
398 return UURET_NOMEM;
399 }
400 }
401
402 /*
403 * Must be called after areas have been malloced
404 */
405
406 UUInitConc ();
407
408 return UURET_OK;
409 }
410
411 /*
412 * Set and get Options
413 */
414
415 int UUEXPORT
416 UUGetOption (int option, int *ivalue, char *cvalue, int clength)
417 {
418 int result;
419
420 switch (option) {
421 case UUOPT_VERSION:
422 _FP_strncpy (cvalue, uulibversion, clength);
423 result = 0;
424 break;
425 case UUOPT_FAST:
426 if (ivalue) *ivalue = uu_fast_scanning;
427 result = uu_fast_scanning;
428 break;
429 case UUOPT_DUMBNESS:
430 if (ivalue) *ivalue = uu_dumbness;
431 result = uu_dumbness;
432 break;
433 case UUOPT_BRACKPOL:
434 if (ivalue) *ivalue = uu_bracket_policy;
435 result = uu_bracket_policy;
436 break;
437 case UUOPT_VERBOSE:
438 if (ivalue) *ivalue = uu_verbose;
439 result = uu_verbose;
440 break;
441 case UUOPT_DESPERATE:
442 if (ivalue) *ivalue = uu_desperate;
443 result = uu_desperate;
444 break;
445 case UUOPT_IGNREPLY:
446 if (ivalue) *ivalue = uu_ignreply;
447 result = uu_ignreply;
448 break;
449 case UUOPT_DEBUG:
450 if (ivalue) *ivalue = uu_debug;
451 result = uu_debug;
452 break;
453 case UUOPT_ERRNO:
454 if (ivalue) *ivalue = uu_errno;
455 result = uu_errno;
456 break;
457 case UUOPT_OVERWRITE:
458 if (ivalue) *ivalue = uu_overwrite;
459 result = uu_overwrite;
460 break;
461 case UUOPT_SAVEPATH:
462 _FP_strncpy (cvalue, uusavepath, clength);
463 result = 0;
464 break;
465 case UUOPT_PROGRESS:
466 if (clength==sizeof(uuprogress)) {
467 memcpy (cvalue, &progress, sizeof (uuprogress));
468 result = 0;
469 }
470 else
471 result = -1;
472 break;
473 case UUOPT_IGNMODE:
474 if (ivalue) *ivalue = uu_ignmode;
475 result = uu_ignmode;
476 break;
477 case UUOPT_USETEXT:
478 if (ivalue) *ivalue = uu_handletext;
479 result = uu_handletext;
480 break;
481 case UUOPT_PREAMB:
482 if (ivalue) *ivalue = uu_usepreamble;
483 result = uu_usepreamble;
484 break;
485 case UUOPT_TINYB64:
486 if (ivalue) *ivalue = uu_tinyb64;
487 result = uu_tinyb64;
488 break;
489 case UUOPT_ENCEXT:
490 _FP_strncpy (cvalue, uuencodeext, clength);
491 result = 0;
492 break;
493 case UUOPT_REMOVE:
494 if (ivalue) *ivalue = uu_remove_input;
495 result = uu_remove_input;
496 break;
497 case UUOPT_MOREMIME:
498 if (ivalue) *ivalue = uu_more_mime;
499 result = uu_more_mime;
500 break;
501 default:
502 return -1;
503 }
504 return result;
505 }
506
507 int UUEXPORT
508 UUSetOption (int option, int ivalue, char *cvalue)
509 {
510 switch (option) {
511 case UUOPT_FAST:
512 uu_fast_scanning = ivalue;
513 break;
514 case UUOPT_DUMBNESS:
515 uu_dumbness = ivalue;
516 break;
517 case UUOPT_BRACKPOL:
518 uu_bracket_policy = ivalue;
519 break;
520 case UUOPT_VERBOSE:
521 uu_verbose = ivalue;
522 break;
523 case UUOPT_DESPERATE:
524 uu_desperate = ivalue;
525 break;
526 case UUOPT_IGNREPLY:
527 uu_ignreply = ivalue;
528 break;
529 case UUOPT_DEBUG:
530 uu_debug = ivalue;
531 break;
532 case UUOPT_OVERWRITE:
533 uu_overwrite = ivalue;
534 break;
535 case UUOPT_SAVEPATH:
536 _FP_free (uusavepath);
537 uusavepath = _FP_strdup (cvalue);
538 break;
539 case UUOPT_IGNMODE:
540 uu_ignmode = ivalue;
541 break;
542 case UUOPT_USETEXT:
543 uu_handletext = ivalue;
544 break;
545 case UUOPT_PREAMB:
546 uu_usepreamble = ivalue;
547 break;
548 case UUOPT_TINYB64:
549 uu_tinyb64 = ivalue;
550 break;
551 case UUOPT_ENCEXT:
552 _FP_free (uuencodeext);
553 uuencodeext = _FP_strdup (cvalue);
554 break;
555 case UUOPT_REMOVE:
556 uu_remove_input = ivalue;
557 break;
558 case UUOPT_MOREMIME:
559 uu_more_mime = ivalue;
560 break;
561 default:
562 return UURET_ILLVAL;
563 }
564 return UURET_OK;
565 }
566
567 char * UUEXPORT
568 UUstrerror (int code)
569 {
570 return uuretcodes[code];
571 }
572
573 /*
574 * Set the various Callback functions
575 */
576
577 int UUEXPORT
578 UUSetMsgCallback (void *opaque,
579 void (*func) _ANSI_ARGS_((void *, char *, int)))
580 {
581 uu_MsgCallback = func;
582 uu_MsgCBArg = opaque;
583
584 return UURET_OK;
585 }
586
587 int UUEXPORT
588 UUSetBusyCallback (void *opaque,
589 int (*func) _ANSI_ARGS_((void *, uuprogress *)),
590 long msecs)
591 {
592 uu_BusyCallback = func;
593 uu_BusyCBArg = opaque;
594 uu_busy_msecs = msecs;
595
596 return UURET_OK;
597 }
598
599 int UUEXPORT
600 UUSetFileCallback (void *opaque,
601 int (*func) _ANSI_ARGS_((void *, char *, char *, int)))
602 {
603 uu_FileCallback = func;
604 uu_FileCBArg = opaque;
605
606 return UURET_OK;
607 }
608
609 int UUEXPORT
610 UUSetFNameFilter (void *opaque,
611 char * (*func) _ANSI_ARGS_((void *, char *)))
612 {
613 uu_FNameFilter = func;
614 uu_FFCBArg = opaque;
615
616 return UURET_OK;
617 }
618
619 /*
620 * Return a pointer to the nth element of the GlobalFileList
621 * zero-based, returns NULL if item is too large.
622 */
623
624 uulist * UUEXPORT
625 UUGetFileListItem (int item)
626 {
627 uulist *iter=UUGlobalFileList;
628
629 if (item < 0)
630 return NULL;
631 while (item && iter) {
632 iter = iter->NEXT;
633 item--;
634 }
635 return iter;
636 }
637
638 /*
639 * call the current filter
640 */
641
642 char * UUEXPORT
643 UUFNameFilter (char *fname)
644 {
645 if (uu_FNameFilter)
646 return (*uu_FNameFilter) (uu_FFCBArg, fname);
647
648 return fname;
649 }
650
651 /*
652 * Load a File. We call ScanPart repeatedly until at EOF and
653 * add the parts to UUGlobalFileList
654 */
655
656 int UUEXPORT
657 UULoadFile (char *filename, char *fileid, int delflag)
658 {
659 return UULoadFileWithPartNo(filename, fileid, delflag, -1);
660 }
661
662 int UUEXPORT
663 UULoadFileWithPartNo (char *filename, char *fileid, int delflag, int partno)
664 {
665 int res, sr, count=0;
666 struct stat finfo;
667 fileread *loaded;
668 uufile *fload;
669 itbd *killem;
670 FILE *datei;
671
672 if ((datei = fopen (filename, "rb")) == NULL) {
673 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
674 uustring (S_NOT_OPEN_SOURCE),
675 filename, strerror (uu_errno = errno));
676 return UURET_IOERR;
677 }
678
679 if (fstat (fileno(datei), &finfo) == -1) {
680 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
681 uustring (S_NOT_STAT_FILE),
682 filename, strerror (uu_errno = errno));
683 fclose (datei);
684 return UURET_IOERR;
685 }
686
687 /*
688 * schedule for destruction
689 */
690
691 if (delflag && fileid==NULL) {
692 if ((killem = (itbd *) malloc (sizeof (itbd))) == NULL) {
693 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
694 uustring (S_OUT_OF_MEMORY), sizeof (itbd));
695 }
696 else if ((killem->fname = _FP_strdup (filename)) == NULL) {
697 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
698 uustring (S_OUT_OF_MEMORY), strlen(filename)+1);
699 _FP_free (killem);
700 }
701 else {
702 killem->NEXT = ftodel;
703 ftodel = killem;
704 }
705 }
706
707 progress.action = 0;
708 progress.partno = 0;
709 progress.numparts = 1;
710 progress.fsize = (long) ((finfo.st_size>0)?finfo.st_size:-1);
711 progress.percent = 0;
712 progress.foffset = 0;
713 _FP_strncpy (progress.curfile,
714 (strlen(filename)>255)?
715 (filename+strlen(filename)-255):filename,
716 256);
717 progress.action = UUACT_SCANNING;
718
719 if (fileid == NULL)
720 fileid = filename;
721
722 while (!feof (datei) && !ferror (datei)) {
723 /*
724 * Peek file, or some systems won't detect EOF
725 */
726 res = fgetc (datei);
727 if (feof (datei) || ferror (datei))
728 break;
729 else
730 ungetc (res, datei);
731
732 if ((loaded = ScanPart (datei, fileid, &sr)) == NULL) {
733 if (sr != UURET_NODATA && sr != UURET_OK && sr != UURET_CONT) {
734 UUkillfread (loaded);
735 if (sr != UURET_CANCEL) {
736 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
737 uustring (S_READ_ERROR), filename,
738 strerror (uu_errno));
739 }
740 UUCheckGlobalList ();
741 progress.action = 0;
742 fclose (datei);
743 return sr;
744 }
745 continue;
746 }
747
748 if (ferror (datei)) {
749 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
750 uustring (S_READ_ERROR), filename,
751 strerror (uu_errno = errno));
752 UUCheckGlobalList ();
753 progress.action = 0;
754 fclose (datei);
755 return UURET_IOERR;
756 }
757
758 if (partno != -1)
759 loaded->partno = partno;
760
761 if ((loaded->uudet == QP_ENCODED || loaded->uudet == PT_ENCODED) &&
762 (loaded->filename == NULL || *(loaded->filename) == '\0') &&
763 !uu_handletext && (loaded->flags&FL_PARTIAL)==0) {
764 /*
765 * Don't want text
766 */
767 UUkillfread (loaded);
768 continue;
769 }
770
771 if ((loaded->subject == NULL || *(loaded->subject) == '\0') &&
772 (loaded->mimeid == NULL || *(loaded->mimeid) == '\0') &&
773 (loaded->filename== NULL || *(loaded->filename)== '\0') &&
774 (loaded->uudet == 0)) {
775 /*
776 * no useful data here
777 */
778 UUkillfread (loaded);
779 if (uu_fast_scanning && sr != UURET_CONT) break;
780 continue;
781 }
782
783 if ((fload = UUPreProcessPart (loaded, &res)) == NULL) {
784 /*
785 * no useful data found
786 */
787 if (res != UURET_NODATA) {
788 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
789 uustring (S_READ_ERROR), filename,
790 (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
791 }
792 UUkillfread (loaded);
793 if (uu_fast_scanning && sr != UURET_CONT) break;
794 continue;
795 }
796
797 if ((loaded->subject && *(loaded->subject)) ||
798 (loaded->mimeid && *(loaded->mimeid)) ||
799 (loaded->filename&& *(loaded->filename))||
800 (loaded->uudet)) {
801 UUMessage (uulib_id, __LINE__, UUMSG_MESSAGE,
802 uustring (S_LOADED_PART),
803 filename,
804 (loaded->subject) ? loaded->subject : "",
805 (fload->subfname) ? fload->subfname : "",
806 (loaded->filename) ? loaded->filename : "",
807 fload->partno,
808 (loaded->begin) ? "begin" : "",
809 (loaded->end) ? "end" : "",
810 codenames[loaded->uudet]);
811 }
812
813 if ((res = UUInsertPartToList (fload))) {
814 /*
815 * couldn't use the data
816 */
817 UUkillfile (fload);
818
819 if (res != UURET_NODATA) {
820 UUCheckGlobalList ();
821 progress.action = 0;
822 fclose (datei);
823 return res;
824 }
825 if (uu_fast_scanning && sr != UURET_CONT)
826 break;
827
828 continue;
829 }
830
831 /*
832 * if in fast mode, we don't look any further, because we're told
833 * that each source file holds at most one encoded part
834 */
835
836 if (uu_fast_scanning && sr != UURET_CONT)
837 break;
838
839 if (loaded->uudet)
840 count++;
841 }
842 if (ferror (datei)) {
843 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
844 uustring (S_READ_ERROR), filename,
845 strerror (uu_errno = errno));
846 UUCheckGlobalList ();
847 progress.action = 0;
848 fclose (datei);
849 return UURET_IOERR;
850 }
851 fclose (datei);
852
853 if (!uu_fast_scanning && count==0) {
854 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
855 uustring (S_NO_DATA_FOUND), filename);
856 }
857
858 progress.action = 0;
859 UUCheckGlobalList ();
860
861 return UURET_OK;
862 }
863
864 /*
865 * decode to a temporary file. this is well handled by uudecode()
866 */
867
868 int UUEXPORT
869 UUDecodeToTemp (uulist *thefile)
870 {
871 return UUDecode (thefile);
872 }
873
874 /*
875 * decode file first to temp file, then copy it to a final location
876 */
877
878 int UUEXPORT
879 UUDecodeFile (uulist *thefile, char *destname)
880 {
881 FILE *target, *source;
882 struct stat finfo;
883 int fildes, res;
884 size_t bytes;
885
886 if (thefile == NULL)
887 return UURET_ILLVAL;
888
889 if ((res = UUDecode (thefile)) != UURET_OK)
890 if (res != UURET_NOEND || !uu_desperate)
891 return res;
892
893 if (thefile->binfile == NULL) {
894 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
895 uustring (S_NO_BIN_FILE));
896 return UURET_IOERR;
897 }
898
899 if ((source = fopen (thefile->binfile, "rb")) == NULL) {
900 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
901 uustring (S_NOT_OPEN_FILE),
902 thefile->binfile, strerror (uu_errno = errno));
903 return UURET_IOERR;
904 }
905
906 /*
907 * for system security, strip setuid/setgid bits from mode
908 */
909
910 if ((thefile->mode & 0777) != thefile->mode) {
911 UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
912 uustring (S_STRIPPED_SETUID),
913 destname, (int)thefile->mode);
914 thefile->mode &= 0777;
915 }
916
917 /*
918 * Determine the name of the target file according to the rules:
919 *
920 * IF (destname!=NULL) THEN filename=destname;
921 * ELSE
922 * filename = thefile->filename
923 * IF (FilenameFilter!=NULL) THEN filename=FilenameFilter(filename);
924 * filename = SaveFilePath + filename
925 * END
926 */
927
928 if (destname)
929 strcpy (uugen_fnbuffer, destname);
930 else {
931 sprintf (uugen_fnbuffer, "%s%s",
932 (uusavepath)?uusavepath:"",
933 UUFNameFilter ((thefile->filename)?
934 thefile->filename:"unknown.xxx"));
935 }
936
937 /*
938 * if we don't want to overwrite existing files, check if it's there
939 */
940
941 if (!uu_overwrite) {
942 if (stat (uugen_fnbuffer, &finfo) == 0) {
943 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
944 uustring (S_TARGET_EXISTS), uugen_fnbuffer);
945 fclose (source);
946 return UURET_EXISTS;
947 }
948 }
949
950 if (fstat (fileno(source), &finfo) == -1) {
951 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
952 uustring (S_NOT_STAT_FILE),
953 thefile->binfile, strerror (uu_errno = errno));
954 fclose (source);
955 return UURET_IOERR;
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 (source);
1027 if (fclose (target)) {
1028 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1029 uustring (S_WR_ERR_TARGET),
1030 uugen_fnbuffer, strerror (uu_errno = errno));
1031 unlink (uugen_fnbuffer);
1032 return UURET_IOERR;
1033 }
1034
1035 /*
1036 * after a successful decoding run, we delete the temporary file
1037 */
1038
1039 if (unlink (thefile->binfile)) {
1040 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1041 uustring (S_TMP_NOT_REMOVED),
1042 thefile->binfile,
1043 strerror (uu_errno = errno));
1044 }
1045 _FP_free (thefile->binfile);
1046 thefile->binfile = NULL;
1047 thefile->state &= ~UUFILE_TMPFILE;
1048 thefile->state |= UUFILE_DECODED;
1049 progress.action = 0;
1050
1051 return UURET_OK;
1052 }
1053
1054 /*
1055 * Calls a function repeatedly with all the info we have for a file
1056 * If the function returns non-zero, we break and don't send any more
1057 */
1058
1059 int UUEXPORT
1060 UUInfoFile (uulist *thefile, void *opaque,
1061 int (*func) _ANSI_ARGS_((void *, char *)))
1062 {
1063 int errflag=0, res, bhflag=0, dd;
1064 long maxpos;
1065 FILE *inpfile;
1066
1067 /*
1068 * We might need to ask our callback function to download the file
1069 */
1070
1071 if (uu_FileCallback) {
1072 if ((res = (*uu_FileCallback) (uu_FileCBArg,
1073 thefile->thisfile->data->sfname,
1074 uugen_fnbuffer,
1075 1)) != UURET_OK)
1076 return res;
1077 if ((inpfile = fopen (uugen_fnbuffer, "rb")) == NULL) {
1078 (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname,
1079 uugen_fnbuffer, 0);
1080 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1081 uustring (S_NOT_OPEN_FILE), uugen_fnbuffer,
1082 strerror (uu_errno = errno));
1083 return UURET_IOERR;
1084 }
1085 }
1086 else {
1087 if ((inpfile = fopen (thefile->thisfile->data->sfname, "rb")) == NULL) {
1088 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1089 uustring (S_NOT_OPEN_FILE),
1090 thefile->thisfile->data->sfname,
1091 strerror (uu_errno=errno));
1092 return UURET_IOERR;
1093 }
1094 _FP_strncpy (uugen_fnbuffer, thefile->thisfile->data->sfname, 1024);
1095 }
1096
1097 /*
1098 * seek to beginning of info
1099 */
1100
1101 fseek (inpfile, thefile->thisfile->data->startpos, SEEK_SET);
1102 maxpos = thefile->thisfile->data->startpos + thefile->thisfile->data->length;
1103
1104 while (!feof (inpfile) &&
1105 (uu_fast_scanning || ftell(inpfile) < maxpos)) {
1106 if (_FP_fgets (uugen_inbuffer, 511, inpfile) == NULL)
1107 break;
1108 uugen_inbuffer[511] = '\0';
1109
1110 if (ferror (inpfile))
1111 break;
1112
1113 dd = UUValidData (uugen_inbuffer, 0, &bhflag);
1114
1115 if (thefile->uudet == B64ENCODED && dd == B64ENCODED)
1116 break;
1117 else if (thefile->uudet == BH_ENCODED && bhflag)
1118 break;
1119 else if ((thefile->uudet == UU_ENCODED || thefile->uudet == XX_ENCODED) &&
1120 strncmp (uugen_inbuffer, "begin ", 6) == 0)
1121 break;
1122 else if (thefile->uudet == YENC_ENCODED &&
1123 strncmp (uugen_inbuffer, "=ybegin ", 8) == 0)
1124 break;
1125
1126 if ((*func) (opaque, uugen_inbuffer))
1127 break;
1128 }
1129
1130 if (ferror (inpfile)) {
1131 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1132 uustring (S_READ_ERROR),
1133 uugen_fnbuffer, strerror (uu_errno = errno));
1134 errflag = 1;
1135 }
1136
1137 fclose (inpfile);
1138
1139 if (uu_FileCallback)
1140 (*uu_FileCallback) (uu_FileCBArg,
1141 thefile->thisfile->data->sfname,
1142 uugen_fnbuffer, 0);
1143
1144 if (errflag)
1145 return UURET_IOERR;
1146
1147 return UURET_OK;
1148 }
1149
1150 int UUEXPORT
1151 UURenameFile (uulist *thefile, char *newname)
1152 {
1153 char *oldname;
1154
1155 if (thefile == NULL)
1156 return UURET_ILLVAL;
1157
1158 oldname = thefile->filename;
1159
1160 if ((thefile->filename = _FP_strdup (newname)) == NULL) {
1161 UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
1162 uustring (S_NOT_RENAME),
1163 oldname, newname);
1164 thefile->filename = oldname;
1165 return UURET_NOMEM;
1166 }
1167 _FP_free (oldname);
1168 return UURET_OK;
1169 }
1170
1171 int UUEXPORT
1172 UURemoveTemp (uulist *thefile)
1173 {
1174 if (thefile == NULL)
1175 return UURET_ILLVAL;
1176
1177 if (thefile->binfile) {
1178 if (unlink (thefile->binfile)) {
1179 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1180 uustring (S_TMP_NOT_REMOVED),
1181 thefile->binfile,
1182 strerror (uu_errno = errno));
1183 }
1184 _FP_free (thefile->binfile);
1185 thefile->binfile = NULL;
1186 thefile->state &= ~UUFILE_TMPFILE;
1187 }
1188 return UURET_OK;
1189 }
1190
1191 int UUEXPORT
1192 UUCleanUp (void)
1193 {
1194 itbd *iter=ftodel, *ptr;
1195 uulist *liter;
1196 uufile *fiter;
1197 allomap *aiter;
1198
1199 /*
1200 * delete temporary input files (such as the copy of stdin)
1201 */
1202
1203 while (iter) {
1204 if (unlink (iter->fname)) {
1205 UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
1206 uustring (S_TMP_NOT_REMOVED),
1207 iter->fname, strerror (uu_errno = errno));
1208 }
1209 _FP_free (iter->fname);
1210 ptr = iter;
1211 iter = iter->NEXT;
1212 _FP_free (ptr);
1213 }
1214
1215 ftodel = NULL;
1216
1217 /*
1218 * Delete input files after successful decoding
1219 */
1220
1221 if (uu_remove_input) {
1222 liter = UUGlobalFileList;
1223 while (liter) {
1224 if (liter->state & UUFILE_DECODED) {
1225 fiter = liter->thisfile;
1226 while (fiter) {
1227 if (fiter->data && fiter->data->sfname) {
1228 /*
1229 * Error code ignored. We might want to delete a file multiple
1230 * times
1231 */
1232 unlink (fiter->data->sfname);
1233 }
1234 fiter = fiter->NEXT;
1235 }
1236 }
1237 liter = liter->NEXT;
1238 }
1239 }
1240
1241 UUkilllist (UUGlobalFileList);
1242 UUGlobalFileList = NULL;
1243
1244 _FP_free (uusavepath);
1245 _FP_free (uuencodeext);
1246 _FP_free (sstate.source);
1247
1248 uusavepath = NULL;
1249 uuencodeext = NULL;
1250
1251 UUkillheaders (&localenv);
1252 UUkillheaders (&sstate.envelope);
1253 memset (&localenv, 0, sizeof (headers));
1254 memset (&sstate, 0, sizeof (scanstate));
1255
1256 while (mssdepth) {
1257 mssdepth--;
1258 UUkillheaders (&(multistack[mssdepth].envelope));
1259 _FP_free (multistack[mssdepth].source);
1260 }
1261
1262 /*
1263 * clean up the malloc'ed stuff
1264 */
1265
1266 for (aiter=toallocate; aiter->ptr; aiter++) {
1267 _FP_free (*(aiter->ptr));
1268 *(aiter->ptr) = NULL;
1269 }
1270
1271 return UURET_OK;
1272 }
1273