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