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