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