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