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