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