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