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