ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Convert-UUlib/uulib/uulib.c
Revision: 1.25
Committed: Sat Dec 12 03:55:00 2020 UTC (5 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_8
Changes since 1.24: +3 -0 lines
Log Message:
*** empty log message ***

File Contents

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