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