uulib.c

Go to the documentation of this file.
00001 /*
00002  * This file is part of uudeview, the simple and friendly multi-part multi-
00003  * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
00004  * be contacted at [email protected]
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  * GNU General Public License for more details.
00015  */
00016 
00017 /*
00018  * This file implements the externally visible functions, as declared
00019  * in uudeview.h, and some internal interfacing functions
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #ifdef _MSC_VER
00024 #include "config.h.win32"
00025 #else
00026 #include "config.h"
00027 #endif
00028 #endif
00029 
00030 #ifdef SYSTEM_WINDLL
00031 #include 
00032 #endif
00033 #ifdef SYSTEM_OS2
00034 #include 
00035 #endif
00036 
00037 #include 
00038 #include 
00039 #include 
00040 
00041 #ifdef HAVE_FCNTL_H
00042 #include 
00043 #endif
00044 
00045 #ifdef STDC_HEADERS
00046 #include 
00047 #include 
00048 #include 
00049 #else
00050 #ifdef HAVE_STDARG_H
00051 #include 
00052 #else
00053 #ifdef HAVE_VARARGS_H
00054 #include 
00055 #endif
00056 #endif
00057 #endif
00058 
00059 #ifdef HAVE_UNISTD_H
00060 #include 
00061 #endif
00062 
00063 #ifdef TIME_WITH_SYS_TIME
00064 # include 
00065 # include 
00066 #else
00067 # ifdef HAVE_SYS_TIME_H
00068 # include 
00069 # else
00070 # include 
00071 # endif
00072 #endif
00073 
00074 #ifdef HAVE_ERRNO_H
00075 #include 
00076 #endif
00077 
00078 /* to get open() in Windows */
00079 #ifdef HAVE_IO_H
00080 #include 
00081 #endif
00082 
00083 #ifdef _MSC_VER
00084 #include 
00085 #endif
00086 
00087 #include uudeview.h>
00088 #include uuint.h>
00089 #include fptools.h>
00090 #include uustring.h>
00091 
00092 char * uulib_id = "$Id: uulib.c 260 2007-05-04 23:32:54Z csk $";
00093 
00094 #ifdef SYSTEM_WINDLL
00095 BOOL _export WINAPI 
00096 DllEntryPoint (HINSTANCE hInstance, DWORD seginfo,
00097                LPVOID lpCmdLine)
00098 {
00099   /* Don't do anything, so just return true */
00100   return TRUE;
00101 }
00102 #endif
00103 
00104 /*
00105  * In DOS, we must open the file binary, O_BINARY is defined there
00106  */
00107 
00108 #ifndef O_BINARY
00109 #define O_BINARY 0
00110 #endif
00111 
00112 /* for braindead systems */
00113 #ifndef SEEK_SET
00114 #ifdef L_BEGIN
00115 #define SEEK_SET L_BEGIN
00116 #else
00117 #define SEEK_SET 0
00118 #endif
00119 #endif
00120 
00121 /*
00122  * Callback functions and their opaque arguments
00123  */
00124 
00125 void   (*uu_MsgCallback)  _ANSI_ARGS_((void *, char *, int))         = NULL;
00126 int    (*uu_BusyCallback) _ANSI_ARGS_((void *, uuprogress *))        = NULL;
00127 int    (*uu_FileCallback) _ANSI_ARGS_((void *, char *, char *, int)) = NULL;
00128 char * (*uu_FNameFilter)  _ANSI_ARGS_((void *, char *))              = NULL;
00129 
00130 void *uu_MsgCBArg  = NULL;
00131 void *uu_BusyCBArg = NULL;
00132 void *uu_FileCBArg = NULL;
00133 void *uu_FFCBArg   = NULL;
00134 
00135 /*
00136  * Global variables
00137  */
00138 
00139 int uu_fast_scanning = 0;       /* assumes at most 1 part per file */
00140 int uu_bracket_policy = 0;      /* gives part numbers in [] higher priority */
00141 int uu_verbose = 1;             /* enables/disables messages¬es */
00142 int uu_desperate = 0;           /* desperate mode */
00143 int uu_ignreply = 0;            /* ignore replies */
00144 int uu_debug = 0;               /* debugging mode (print __FILE__/__LINE__) */
00145 int uu_errno = 0;               /* the errno that caused this UURET_IOERR */
00146 int uu_dumbness = 0;            /* switch off the program's intelligence */
00147 int uu_overwrite = 1;           /* whether it's ok to overwrite ex. files */
00148 int uu_ignmode = 0;             /* ignore the original file mode */
00149 int uu_handletext = 0;          /* do we want text/plain messages */
00150 int uu_usepreamble = 0;         /* do we want Mime preambles/epilogues */
00151 int uu_tinyb64 = 0;             /* detect short B64 outside of MIME */
00152 int uu_remove_input = 0;        /* remove input files after decoding */
00153 int uu_more_mime = 0;           /* strictly adhere to MIME headers */
00154 
00155 headercount hlcount = {
00156   3,                            /* restarting after a MIME body */
00157   2,                            /* after useful data in freestyle mode */
00158   1                             /* after useful data and an empty line */
00159 };
00160 
00161 /*
00162  * version string
00163  */
00164 
00165 char uulibversion[256] = "0.5pl20";
00166 
00167 /*
00168  * prefix to the files on disk, usually a path name to save files to
00169  */
00170 
00171 char *uusavepath;
00172 
00173 /*
00174  * extension to use when encoding single-part files
00175  */
00176 
00177 char *uuencodeext;
00178 
00179 /*
00180  * areas to malloc
00181  */
00182 
00183 char *uulib_msgstring;
00184 char *uugen_inbuffer;
00185 char *uugen_fnbuffer;
00186 
00187 /*
00188  * The Global List of Files
00189  */
00190 
00191 uulist *UUGlobalFileList = NULL;
00192 
00193 /*
00194  * time values for BusyCallback. msecs is MILLIsecs here
00195  */
00196 
00197 static long uu_busy_msecs = 0;  /* call callback function each msecs */
00198 static long uu_last_secs  = 0;  /* secs of last call to callback */
00199 static long uu_last_usecs = 0;  /* usecs of last call to callback */
00200 
00201 /*
00202  * progress information
00203  */
00204 
00205 uuprogress progress;
00206 
00207 /*
00208  * Linked list of files we want to delete after decoding
00209  */
00210 
00211 typedef struct _itbd {
00212   char *fname;
00213   struct _itbd *NEXT;
00214 } itbd;
00215 static itbd * ftodel = NULL;
00216 
00217 /*
00218  * for the busy poll
00219  */
00220 
00221 unsigned long uuyctr;
00222 
00223 /*
00224  * Areas to allocate. Instead of using static memory areas, we malloc()
00225  * the memory in UUInitialize() and release them in UUCleanUp to prevent
00226  * blowing up of the binary size
00227  * This is a table with the pointers to allocate and required sizes.
00228  * They are guaranteed to be never NULL.
00229  */
00230 
00231 typedef struct {
00232   char **ptr;
00233   size_t size;
00234 } allomap;
00235 
00236 static allomap toallocate[] = {
00237   { &uugen_fnbuffer,    UUGEN_FNBUFFER_LEN },  /* generic filename buffer */
00238   { &uugen_inbuffer,    1024 },  /* generic input data buffer */
00239   { &uucheck_lastname,   256 },  /* from uucheck.c */
00240   { &uucheck_tempname,   256 },
00241   { &uuestr_itemp,       256 },  /* from uuencode.c:UUEncodeStream() */
00242   { &uuestr_otemp,      1024 },
00243   { &uulib_msgstring,   1024 },  /* from uulib.c:UUMessage() */
00244   { &uuncdl_fulline,     300 },  /* from uunconc.c:UUDecodeLine() */
00245   { &uuncdp_oline,      1200 },  /* from uunconc.c:UUDecodePart() */
00246   { &uunconc_UUxlat,     256 * sizeof (int) },  /* from uunconc.c:toplevel */
00247   { &uunconc_UUxlen,      64 * sizeof (int) },
00248   { &uunconc_B64xlat,    256 * sizeof (int) },
00249   { &uunconc_XXxlat,     256 * sizeof (int) },
00250   { &uunconc_BHxlat,     256 * sizeof (int) },
00251   { &uunconc_save,     3*300 },  /* from uunconc.c:decoding buffer */
00252   { &uuscan_shlline,    1024 },  /* from uuscan.c:ScanHeaderLine() */
00253   { &uuscan_shlline2,   1024 },  /* from uuscan.c:ScanHeaderLine() */
00254   { &uuscan_pvvalue,    4096 },  /* from uuscan.c:ParseValue() */
00255   { &uuscan_phtext,     4096 },  /* from uuscan.c:ParseHeader() */
00256   { &uuscan_sdline,    UUSCAN_SDLINE_LEN },  /* from uuscan.c:ScanData() */
00257   { &uuscan_sdbhds1,     300 },
00258   { &uuscan_sdbhds2,     300 },
00259   { &uuscan_spline,    UUSCAN_SPLINE_LEN },  /* from uuscan.c:ScanPart() */
00260   { &uuutil_bhwtmp,      300 },  /* from uuutil.c:UUbhwrite() */
00261   { NULL, 0 }
00262 };
00263 
00264 /*
00265  * Handle the printing of messages. Works like printf.
00266  */
00267 
00268 #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H)
00269 int
00270 UUMessage (char *file, int line, int level, char *format, ...)
00271 #else
00272 int
00273 UUMessage (va_alist)
00274   va_dcl
00275 #endif
00276 {
00277   char *msgptr;
00278 #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H)
00279   va_list ap;
00280 
00281   va_start (ap, format);
00282 #else
00283   char *file, *format;
00284   int   line, level;
00285   va_list ap;
00286 
00287   va_start (ap);
00288   file   = va_arg (ap, char *);
00289   line   = va_arg (ap, int);
00290   level  = va_arg (ap, int);
00291   format = va_arg (ap, char *);
00292 #endif
00293 
00294   if (uu_debug) {
00295     sprintf (uulib_msgstring, "%s(%d): %s", file, line, msgnames[level]);
00296     msgptr = uulib_msgstring + strlen (uulib_msgstring);
00297   }
00298   else {
00299     sprintf (uulib_msgstring, "%s", msgnames[level]);
00300     msgptr = uulib_msgstring + strlen (uulib_msgstring);
00301   }
00302 
00303   if (uu_MsgCallback && (level>UUMSG_NOTE || uu_verbose)) {
00304     vsprintf (msgptr, format, ap);
00305 
00306     (*uu_MsgCallback) (uu_MsgCBArg, uulib_msgstring, level);
00307   }
00308 
00309   va_end (ap);
00310 
00311   return UURET_OK;
00312 }
00313 
00314 /*
00315  * Call the Busy Callback from time to time. This function must be
00316  * polled from the Busy loops.
00317  */
00318 
00319 int
00320 UUBusyPoll (void)
00321 {
00322 #ifdef HAVE_GETTIMEOFDAY
00323   struct timeval tv;
00324   long msecs;
00325 
00326   if (uu_BusyCallback) {
00327     (void) gettimeofday (&tv, NULL);
00328 
00329     msecs = 1000*(tv.tv_sec-uu_last_secs)+(tv.tv_usec-uu_last_usecs)/1000;
00330 
00331     if (uu_last_secs==0 || msecs > uu_busy_msecs) {
00332       uu_last_secs  = tv.tv_sec;
00333       uu_last_usecs = tv.tv_usec;
00334 
00335       return (*uu_BusyCallback) (uu_BusyCBArg, &progress);
00336     }
00337   }
00338 #else
00339   time_t now = time (NULL);
00340   long msecs;
00341 
00342   if (uu_BusyCallback) {
00343     if (uu_busy_msecs 00344       msecs = 1;
00345     }
00346     else {
00347       msecs = 1000 * (now - uu_last_secs);
00348     }
00349 
00350     if (uu_last_secs==0 || msecs > uu_busy_msecs) {
00351       uu_last_secs  = now;
00352       uu_last_usecs = 0;
00353 
00354       return (*uu_BusyCallback) (uu_BusyCBArg, &progress);
00355     }
00356   }
00357 #endif
00358 
00359   return 0;
00360 }
00361 
00362 /*
00363  * Initialization function
00364  */
00365 
00366 int UUEXPORT
00367 UUInitialize (void)
00368 {
00369   allomap *aiter;
00370 
00371   progress.action     = 0;
00372   progress.curfile[0] = '\0';
00373 
00374   ftodel = NULL;
00375 
00376   uusavepath  = NULL;
00377   uuencodeext = NULL;
00378 
00379   mssdepth = 0;
00380   memset (&localenv, 0, sizeof (headers));
00381   memset (&sstate,   0, sizeof (scanstate));
00382 
00383   nofnum    = 0;
00384   mimseqno  = 0;
00385   lastvalid = 0;
00386   lastenc   = 0;
00387   uuyctr    = 0;
00388 
00389   /*
00390  * Allocate areas
00391  */
00392 
00393   for (aiter=toallocate; aiter->ptr; aiter++)
00394     *(aiter->ptr) = NULL;
00395 
00396   for (aiter=toallocate; aiter->ptr; aiter++) {
00397     if ((*(aiter->ptr) = (char *) malloc (aiter->size)) == NULL) {
00398       /*
00399  * oops. we may not print a message here, because we need these
00400  * areas (uulib_msgstring) in UUMessage()
00401  */
00402       for (aiter=toallocate; aiter->ptr; aiter++) {
00403         _FP_free (*(aiter->ptr));
00404       }
00405       return UURET_NOMEM;
00406     }
00407   }
00408 
00409   /*
00410  * Must be called after areas have been malloced
00411  */
00412 
00413   UUInitConc ();
00414 
00415   return UURET_OK;
00416 }
00417 
00418 /*
00419  * Set and get Options
00420  */
00421 
00422 int UUEXPORT
00423 UUGetOption (int option, int *ivalue, char *cvalue, int clength)
00424 {
00425   int result;
00426 
00427   switch (option) {
00428   case UUOPT_VERSION:
00429     _FP_strncpy (cvalue, uulibversion, clength);
00430     result = 0;
00431     break;
00432   case UUOPT_FAST:
00433     if (ivalue) *ivalue = uu_fast_scanning;
00434     result = uu_fast_scanning;
00435     break;
00436   case UUOPT_DUMBNESS:
00437     if (ivalue) *ivalue = uu_dumbness;
00438     result = uu_dumbness;
00439     break;
00440   case UUOPT_BRACKPOL:
00441     if (ivalue) *ivalue = uu_bracket_policy;
00442     result = uu_bracket_policy;
00443     break;
00444   case UUOPT_VERBOSE:
00445     if (ivalue) *ivalue = uu_verbose;
00446     result = uu_verbose;
00447     break;
00448   case UUOPT_DESPERATE:
00449     if (ivalue) *ivalue = uu_desperate;
00450     result = uu_desperate;
00451     break;
00452   case UUOPT_IGNREPLY:
00453     if (ivalue) *ivalue = uu_ignreply;
00454     result = uu_ignreply;
00455     break;
00456   case UUOPT_DEBUG:
00457     if (ivalue) *ivalue = uu_debug;
00458     result = uu_debug;
00459     break;
00460   case UUOPT_ERRNO:
00461     if (ivalue) *ivalue = uu_errno;
00462     result = uu_errno;
00463     break;
00464   case UUOPT_OVERWRITE:
00465     if (ivalue) *ivalue = uu_overwrite;
00466     result = uu_overwrite;
00467     break;
00468   case UUOPT_SAVEPATH:
00469     _FP_strncpy (cvalue, uusavepath, clength);
00470     result = 0;
00471     break;
00472   case UUOPT_PROGRESS:
00473     if (clength==sizeof(uuprogress)) {
00474       memcpy (cvalue, &progress, sizeof (uuprogress));
00475       result = 0;
00476     }
00477     else
00478       result = -1;
00479     break;
00480   case UUOPT_IGNMODE:
00481     if (ivalue) *ivalue = uu_ignmode;
00482     result = uu_ignmode;
00483     break;
00484   case UUOPT_USETEXT:
00485     if (ivalue) *ivalue = uu_handletext;
00486     result = uu_handletext;
00487     break;
00488   case UUOPT_PREAMB:
00489     if (ivalue) *ivalue = uu_usepreamble;
00490     result = uu_usepreamble;
00491     break;
00492   case UUOPT_TINYB64:
00493     if (ivalue) *ivalue = uu_tinyb64;
00494     result = uu_tinyb64;
00495     break;
00496   case UUOPT_ENCEXT:
00497     _FP_strncpy (cvalue, uuencodeext, clength);
00498     result = 0;
00499     break;
00500   case UUOPT_REMOVE:
00501     if (ivalue) *ivalue = uu_remove_input;
00502     result = uu_remove_input;
00503     break;
00504   case UUOPT_MOREMIME:
00505     if (ivalue) *ivalue = uu_more_mime;
00506     result = uu_more_mime;
00507     break;
00508   default:
00509     return -1;
00510   }
00511   return result;
00512 }
00513 
00514 int UUEXPORT
00515 UUSetOption (int option, int ivalue, char *cvalue)
00516 {
00517   switch (option) {
00518   case UUOPT_FAST:
00519     uu_fast_scanning  = ivalue;
00520     break;
00521   case UUOPT_DUMBNESS:
00522     uu_dumbness       = ivalue;
00523     break;
00524   case UUOPT_BRACKPOL:
00525     uu_bracket_policy = ivalue;
00526     break;
00527   case UUOPT_VERBOSE:
00528     uu_verbose        = ivalue;
00529     break;
00530   case UUOPT_DESPERATE:
00531     uu_desperate      = ivalue;
00532     break;
00533   case UUOPT_IGNREPLY:
00534     uu_ignreply       = ivalue;
00535     break;
00536   case UUOPT_DEBUG:
00537     uu_debug          = ivalue;
00538     break;
00539   case UUOPT_OVERWRITE:
00540     uu_overwrite      = ivalue;
00541     break;
00542   case UUOPT_SAVEPATH:
00543     _FP_free (uusavepath);
00544     uusavepath = _FP_strdup (cvalue);
00545     break;
00546   case UUOPT_IGNMODE:
00547     uu_ignmode = ivalue;
00548     break;
00549   case UUOPT_USETEXT:
00550     uu_handletext = ivalue;
00551     break;
00552   case UUOPT_PREAMB:
00553     uu_usepreamble = ivalue;
00554     break;
00555   case UUOPT_TINYB64:
00556     uu_tinyb64 = ivalue;
00557     break;
00558   case UUOPT_ENCEXT:
00559     _FP_free (uuencodeext);
00560     uuencodeext = _FP_strdup (cvalue);
00561     break;
00562   case UUOPT_REMOVE:
00563     uu_remove_input = ivalue;
00564     break;
00565   case UUOPT_MOREMIME:
00566     uu_more_mime = ivalue;
00567     break;
00568   default:
00569     return UURET_ILLVAL;
00570   }
00571   return UURET_OK;
00572 }
00573 
00574 char * UUEXPORT
00575 UUstrerror (int code)
00576 {
00577   return uuretcodes[code];
00578 }
00579 
00580 /*
00581  * Set the various Callback functions
00582  */
00583 
00584 int UUEXPORT
00585 UUSetMsgCallback (void *opaque, 
00586                   void (*func) _ANSI_ARGS_((void *, char *, int)))
00587 {
00588   uu_MsgCallback = func;
00589   uu_MsgCBArg    = opaque;
00590 
00591   return UURET_OK;
00592 }
00593 
00594 int UUEXPORT
00595 UUSetBusyCallback (void *opaque,
00596                    int (*func) _ANSI_ARGS_((void *, uuprogress *)),
00597                    long msecs)
00598 {
00599   uu_BusyCallback = func;
00600   uu_BusyCBArg    = opaque;
00601   uu_busy_msecs   = msecs;
00602 
00603   return UURET_OK;
00604 }
00605 
00606 int UUEXPORT
00607 UUSetFileCallback (void *opaque,
00608                    int (*func) _ANSI_ARGS_((void *, char *, char *, int)))
00609 {
00610   uu_FileCallback = func;
00611   uu_FileCBArg    = opaque;
00612 
00613   return UURET_OK;
00614 }
00615 
00616 int UUEXPORT
00617 UUSetFNameFilter (void *opaque,
00618                   char * (*func) _ANSI_ARGS_((void *, char *)))
00619 {
00620   uu_FNameFilter = func;
00621   uu_FFCBArg     = opaque;
00622 
00623   return UURET_OK;
00624 }
00625 
00626 /*
00627  * Return a pointer to the nth element of the GlobalFileList
00628  * zero-based, returns NULL if item is too large.
00629  */
00630 
00631 uulist * UUEXPORT
00632 UUGetFileListItem (int item)
00633 {
00634   uulist *iter=UUGlobalFileList;
00635 
00636   if (item 00637     return NULL;
00638   while (item && iter) {
00639     iter = iter->NEXT;
00640     item--;
00641   }
00642   return iter;
00643 }
00644 
00645 /*
00646  * call the current filter
00647  */
00648 
00649 char * UUEXPORT
00650 UUFNameFilter (char *fname)
00651 {
00652   if (uu_FNameFilter)
00653     return (*uu_FNameFilter) (uu_FFCBArg, fname);
00654 
00655   return fname;
00656 }
00657 
00658 /*
00659  * Load a File. We call ScanPart repeatedly until at EOF and
00660  * add the parts to UUGlobalFileList
00661  */
00662 
00663 int UUEXPORT
00664 UULoadFile (char *filename, char *fileid, int delflag)
00665 {
00666   return UULoadFileWithPartNo(filename, fileid, delflag, -1);
00667 }
00668 
00669 int UUEXPORT
00670 UULoadFileWithPartNo (char *filename, char *fileid, int delflag, int partno)
00671 {
00672   int res, sr, count=0;
00673   struct stat finfo;
00674   fileread *loaded;
00675   uufile *fload;
00676   itbd *killem;
00677   FILE *datei;
00678 
00679   if ((datei = fopen (filename, "rb")) == NULL) {
00680     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00681                uustring (S_NOT_OPEN_SOURCE),
00682                filename, strerror (uu_errno = errno));
00683     return UURET_IOERR;
00684   }
00685 
00686   if (fstat (fileno(datei), &finfo) == -1) {
00687     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00688                uustring (S_NOT_STAT_FILE),
00689                filename, strerror (uu_errno = errno));
00690     fclose (datei);
00691     return UURET_IOERR;
00692   }
00693 
00694   /*
00695  * schedule for destruction
00696  */
00697 
00698   if (delflag && fileid==NULL) {
00699     if ((killem = (itbd *) malloc (sizeof (itbd))) == NULL) {
00700       UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
00701                  uustring (S_OUT_OF_MEMORY), sizeof (itbd));
00702     }
00703     else if ((killem->fname = _FP_strdup (filename)) == NULL) {
00704       UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
00705                  uustring (S_OUT_OF_MEMORY), strlen(filename)+1);
00706       _FP_free (killem);
00707     }
00708     else {
00709       killem->NEXT = ftodel;
00710       ftodel = killem;
00711     }
00712   }
00713 
00714   progress.action   = 0;
00715   progress.partno   = 0;
00716   progress.numparts = 1;
00717   progress.fsize    = (long) ((finfo.st_size>0)?finfo.st_size:-1);
00718   progress.percent  = 0;
00719   progress.foffset  = 0;
00720   _FP_strncpy (progress.curfile,
00721                (strlen(filename)>255)?
00722                (filename+strlen(filename)-255):filename,
00723                256);
00724   progress.action   = UUACT_SCANNING;
00725 
00726   if (fileid == NULL)
00727     fileid = filename;
00728 
00729   while (!feof (datei) && !ferror (datei)) {
00730     /* 
00731  * Peek file, or some systems won't detect EOF
00732  */
00733     res = fgetc (datei);
00734     if (feof (datei) || ferror (datei))
00735       break;
00736     else
00737       ungetc (res, datei);
00738     
00739     if ((loaded = ScanPart (datei, fileid, &sr)) == NULL) {
00740       if (sr != UURET_NODATA && sr != UURET_OK && sr != UURET_CONT) {
00741         UUkillfread (loaded);
00742         if (sr != UURET_CANCEL) {
00743           UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00744                      uustring (S_READ_ERROR), filename,
00745                      strerror (uu_errno));
00746         }
00747         UUCheckGlobalList ();
00748         progress.action = 0;
00749         fclose (datei);
00750         return sr;
00751       }
00752       continue;
00753     }
00754 
00755     if (ferror (datei)) {
00756       UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00757                  uustring (S_READ_ERROR), filename,
00758                  strerror (uu_errno = errno));
00759       UUCheckGlobalList ();
00760       progress.action = 0;
00761       fclose (datei);
00762       return UURET_IOERR;
00763     }
00764 
00765     if (partno != -1)
00766       loaded->partno = partno;
00767 
00768     if ((loaded->uudet == QP_ENCODED || loaded->uudet == PT_ENCODED) &&
00769         (loaded->filename == NULL || *(loaded->filename) == '\0') &&
00770         !uu_handletext && (loaded->flags&FL_PARTIAL)==0) {
00771       /*
00772  * Don't want text
00773  */
00774       UUkillfread (loaded);
00775       continue;
00776     }
00777 
00778     if ((loaded->subject == NULL || *(loaded->subject) == '\0') &&
00779         (loaded->mimeid  == NULL || *(loaded->mimeid)  == '\0') &&
00780         (loaded->filename== NULL || *(loaded->filename)== '\0') &&
00781         (loaded->uudet   == 0)) {
00782       /*
00783  * no useful data here
00784  */
00785       UUkillfread (loaded);
00786       if (uu_fast_scanning && sr != UURET_CONT) break;
00787       continue;
00788     }
00789     
00790     if ((fload = UUPreProcessPart (loaded, &res)) == NULL) {
00791       /*
00792  * no useful data found
00793  */
00794       if (res != UURET_NODATA) {
00795         UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00796                    uustring (S_READ_ERROR), filename,
00797                    (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res));
00798       }
00799       UUkillfread (loaded);
00800       if (uu_fast_scanning && sr != UURET_CONT) break;
00801       continue;
00802     }
00803 
00804     if ((loaded->subject && *(loaded->subject)) ||
00805         (loaded->mimeid  && *(loaded->mimeid))  ||
00806         (loaded->filename&& *(loaded->filename))||
00807         (loaded->uudet)) {
00808       UUMessage (uulib_id, __LINE__, UUMSG_MESSAGE,
00809                  uustring (S_LOADED_PART),
00810                  filename,
00811                  (loaded->subject)  ? loaded->subject  : "",
00812                  (fload->subfname)  ? fload->subfname  : "",
00813                  (loaded->filename) ? loaded->filename : "",
00814                  fload->partno,
00815                  (loaded->begin)    ? "begin" : "",
00816                  (loaded->end)      ? "end"   : "",
00817                  codenames[loaded->uudet]);
00818     }
00819     
00820     if ((res = UUInsertPartToList (fload))) {
00821       /*
00822  * couldn't use the data
00823  */
00824       UUkillfile (fload);
00825 
00826       if (res != UURET_NODATA) {
00827         UUCheckGlobalList ();
00828         progress.action = 0;
00829         fclose (datei);
00830         return res;
00831       }
00832       if (uu_fast_scanning && sr != UURET_CONT)
00833         break;
00834 
00835       continue;
00836     }
00837 
00838     /*
00839  * if in fast mode, we don't look any further, because we're told
00840  * that each source file holds at most one encoded part
00841  */
00842 
00843     if (uu_fast_scanning && sr != UURET_CONT)
00844       break;
00845 
00846     if (loaded->uudet)
00847       count++;
00848   }
00849   if (ferror (datei)) {
00850     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00851                uustring (S_READ_ERROR), filename,
00852                strerror (uu_errno = errno));
00853     UUCheckGlobalList ();
00854     progress.action = 0;
00855     fclose (datei);
00856     return UURET_IOERR;
00857   }
00858   fclose (datei);
00859 
00860   if (!uu_fast_scanning && count==0) {
00861     UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
00862                uustring (S_NO_DATA_FOUND), filename);
00863   }
00864 
00865   progress.action = 0;
00866   UUCheckGlobalList ();
00867 
00868   return UURET_OK;
00869 }
00870 
00871 /*
00872  * decode to a temporary file. this is well handled by uudecode()
00873  */
00874 
00875 int UUEXPORT
00876 UUDecodeToTemp (uulist *thefile)
00877 {
00878   return UUDecode (thefile);
00879 }
00880 
00881 /*
00882  * Decode file first to temp file, then copy it to a final location.
00883  * A move is preferable to a copy. If the file is on the same
00884  * partition, no copy is performed. This is important for large
00885  * files.
00886  */
00887 
00888 int UUEXPORT
00889 UUDecodeFile (uulist *thefile, char *destname)
00890 {
00891   FILE *target, *source;
00892   struct stat finfo;
00893   int fildes, res;
00894   size_t bytes;
00895 
00896   if (thefile == NULL)
00897     return UURET_ILLVAL;
00898 
00899   if ((res = UUDecode (thefile)) != UURET_OK)
00900     if (res != UURET_NOEND || !uu_desperate)
00901       return res;
00902 
00903   if (thefile->binfile == NULL) {
00904     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00905                uustring (S_NO_BIN_FILE));
00906     return UURET_IOERR;
00907   }
00908 
00909   if ((source = fopen (thefile->binfile, "rb")) == NULL) {
00910     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00911                uustring (S_NOT_OPEN_FILE),
00912                thefile->binfile, strerror (uu_errno = errno));
00913     return UURET_IOERR;
00914   }
00915 
00916   /*
00917  * for system security, strip setuid/setgid bits from mode
00918  */
00919 
00920   if ((thefile->mode & 0777) != thefile->mode) {
00921     UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
00922                uustring (S_STRIPPED_SETUID),
00923                destname, (int)thefile->mode);
00924     thefile->mode &= 0777;
00925   }
00926 
00927   /*
00928  * Determine the name of the target file according to the rules:
00929  * 
00930  * IF (destname!=NULL) THEN filename=destname;
00931  * ELSE
00932  * filename = thefile->filename
00933  * IF (FilenameFilter!=NULL) THEN filename=FilenameFilter(filename);
00934  * filename = SaveFilePath + filename
00935  * END
00936  */
00937 
00938   if (destname)
00939     strcpy (uugen_fnbuffer, destname);
00940   else {
00941     sprintf (uugen_fnbuffer, "%s%s",
00942              (uusavepath)?uusavepath:"",
00943              UUFNameFilter ((thefile->filename)?
00944                             thefile->filename:"unknown.xxx"));
00945   }
00946 
00947   /*
00948  * if we don't want to overwrite existing files, check if it's there
00949  */
00950 
00951   if (!uu_overwrite) {
00952     if (stat (uugen_fnbuffer, &finfo) == 0) {
00953       UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00954                  uustring (S_TARGET_EXISTS), uugen_fnbuffer);
00955       fclose (source);
00956       return UURET_EXISTS;
00957     }
00958   }
00959 
00960   if (fstat (fileno(source), &finfo) == -1) {
00961     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00962                uustring (S_NOT_STAT_FILE),
00963                thefile->binfile, strerror (uu_errno = errno));
00964     fclose (source);
00965     return UURET_IOERR;
00966   }
00967 
00968   progress.action   = 0;
00969   _FP_strncpy (progress.curfile,
00970                (strlen(uugen_fnbuffer)>255)?
00971                (uugen_fnbuffer+strlen(uugen_fnbuffer)-255):uugen_fnbuffer,
00972                256);
00973   progress.partno   = 0;
00974   progress.numparts = 1;
00975   progress.fsize    = (long) ((finfo.st_size)?finfo.st_size:-1);
00976   progress.foffset  = 0;
00977   progress.percent  = 0;
00978   progress.action   = UUACT_COPYING;
00979 
00980   if ((fildes = open (uugen_fnbuffer,
00981                       O_WRONLY | O_CREAT | O_BINARY | O_TRUNC,
00982                       (uu_ignmode)?0666:thefile->mode)) == -1) {
00983     progress.action = 0;
00984     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
00985                uustring (S_NOT_OPEN_TARGET),
00986                uugen_fnbuffer, strerror (uu_errno = errno));
00987     fclose (source);
00988     return UURET_IOERR;
00989   }
00990 
00991   if (rename(thefile->binfile, uugen_fnbuffer) == 0) {
00992     fclose(source);
00993     close(fildes);
00994     goto finish_ok;
00995   }
00996 
00997   if ((target = fdopen (fildes, "wb")) == NULL) {
00998     progress.action = 0;
00999     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01000                uustring (S_IO_ERR_TARGET),
01001                uugen_fnbuffer, strerror (uu_errno = errno));
01002     fclose (source);
01003     close  (fildes);
01004     return UURET_IOERR;
01005   }
01006 
01007   while (!feof (source)) {
01008 
01009     if (UUBUSYPOLL(ftell(source),progress.fsize)) {
01010       UUMessage (uulib_id, __LINE__, UUMSG_NOTE,
01011                  uustring (S_DECODE_CANCEL));
01012       fclose (source);
01013       fclose (target);
01014       unlink (uugen_fnbuffer);
01015       return UURET_CANCEL;
01016     }
01017 
01018     bytes = fread (uugen_inbuffer, 1, 1024, source);
01019 
01020     if (ferror (source) || (bytes == 0 && !feof (source))) {
01021       progress.action = 0;
01022       UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01023                  uustring (S_READ_ERROR),
01024                  thefile->binfile, strerror (uu_errno = errno));
01025       fclose (source);
01026       fclose (target);
01027       unlink (uugen_fnbuffer);
01028       return UURET_IOERR;
01029     }
01030     if (fwrite (uugen_inbuffer, 1, bytes, target) != bytes) {
01031       progress.action = 0;
01032       UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01033                  uustring (S_WR_ERR_TARGET),
01034                  uugen_fnbuffer, strerror (uu_errno = errno));
01035       fclose (source);
01036       fclose (target);
01037       unlink (uugen_fnbuffer);
01038       return UURET_IOERR;
01039     }
01040   }
01041 
01042   fclose (source);
01043   if (fclose (target)) {
01044     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01045                uustring (S_WR_ERR_TARGET),
01046                uugen_fnbuffer, strerror (uu_errno = errno));
01047     unlink (uugen_fnbuffer);
01048     return UURET_IOERR;
01049   }
01050 
01051   /*
01052  * after a successful decoding run, we delete the temporary file
01053  */
01054 
01055   if (unlink (thefile->binfile)) {
01056     UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
01057                uustring (S_TMP_NOT_REMOVED),
01058                thefile->binfile,
01059                strerror (uu_errno = errno));
01060   }
01061 
01062  finish_ok:
01063   _FP_free (thefile->binfile);
01064   thefile->binfile = NULL;
01065   thefile->state  &= ~UUFILE_TMPFILE;
01066   thefile->state  |=  UUFILE_DECODED;
01067   progress.action  = 0;
01068 
01069   return UURET_OK;
01070 }
01071 
01072 /*
01073  * Calls a function repeatedly with all the info we have for a file
01074  * If the function returns non-zero, we break and don't send any more
01075  */
01076 
01077 int UUEXPORT
01078 UUInfoFile (uulist *thefile, void *opaque,
01079             int (*func) _ANSI_ARGS_((void *, char *)))
01080 {
01081   int errflag=0, res, bhflag=0, dd;
01082   long maxpos;
01083   FILE *inpfile;
01084 
01085   /*
01086  * We might need to ask our callback function to download the file
01087  */
01088 
01089   if (uu_FileCallback) {
01090     if ((res = (*uu_FileCallback) (uu_FileCBArg, 
01091                                    thefile->thisfile->data->sfname,
01092                                    uugen_fnbuffer,
01093                                    1)) != UURET_OK)
01094       return res;
01095     if ((inpfile = fopen (uugen_fnbuffer, "rb")) == NULL) {
01096       (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname,
01097                           uugen_fnbuffer, 0);
01098       UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01099                  uustring (S_NOT_OPEN_FILE), uugen_fnbuffer,
01100                  strerror (uu_errno = errno));
01101       return UURET_IOERR;
01102     }
01103   }
01104   else {
01105     if ((inpfile = fopen (thefile->thisfile->data->sfname, "rb")) == NULL) {
01106       UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01107                  uustring (S_NOT_OPEN_FILE), 
01108                  thefile->thisfile->data->sfname,
01109                  strerror (uu_errno=errno));
01110       return UURET_IOERR;
01111     }
01112     _FP_strncpy (uugen_fnbuffer, thefile->thisfile->data->sfname, 1024);
01113   }
01114 
01115   /*
01116  * seek to beginning of info
01117  */
01118 
01119   fseek (inpfile, thefile->thisfile->data->startpos, SEEK_SET);
01120   maxpos = thefile->thisfile->data->startpos + thefile->thisfile->data->length;
01121 
01122   while (!feof (inpfile) && 
01123          (uu_fast_scanning || ftell(inpfile) 01124     if (_FP_fgets (uugen_inbuffer, 511, inpfile) == NULL)
01125       break;
01126     uugen_inbuffer[511] = '\0';
01127 
01128     if (ferror (inpfile))
01129       break;
01130 
01131     dd = UUValidData (uugen_inbuffer, 0, &bhflag);
01132 
01133     if (thefile->uudet == B64ENCODED && dd == B64ENCODED)
01134       break;
01135     else if (thefile->uudet == BH_ENCODED && bhflag)
01136       break;
01137     else if ((thefile->uudet == UU_ENCODED || thefile->uudet == XX_ENCODED) &&
01138              strncmp (uugen_inbuffer, "begin ", 6) == 0)
01139       break;
01140     else if (thefile->uudet == YENC_ENCODED &&
01141              strncmp (uugen_inbuffer, "=ybegin ", 8) == 0)
01142       break;
01143 
01144     if ((*func) (opaque, uugen_inbuffer))
01145       break;
01146   }
01147 
01148   if (ferror (inpfile)) {
01149     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01150                uustring (S_READ_ERROR),
01151                uugen_fnbuffer, strerror (uu_errno = errno));
01152     errflag = 1;
01153   }
01154 
01155   fclose (inpfile);
01156 
01157   if (uu_FileCallback)
01158     (*uu_FileCallback) (uu_FileCBArg, 
01159                         thefile->thisfile->data->sfname,
01160                         uugen_fnbuffer, 0);
01161 
01162   if (errflag)
01163     return UURET_IOERR;
01164 
01165   return UURET_OK;
01166 }
01167             
01168 int UUEXPORT
01169 UURenameFile (uulist *thefile, char *newname)
01170 {
01171   char *oldname;
01172 
01173   if (thefile == NULL)
01174     return UURET_ILLVAL;
01175 
01176   oldname = thefile->filename;
01177 
01178   if ((thefile->filename = _FP_strdup (newname)) == NULL) {
01179     UUMessage (uulib_id, __LINE__, UUMSG_ERROR,
01180                uustring (S_NOT_RENAME),
01181                oldname, newname);
01182     thefile->filename = oldname;
01183     return UURET_NOMEM;
01184   }
01185   _FP_free (oldname);
01186   return UURET_OK;
01187 }
01188 
01189 int UUEXPORT
01190 UURemoveTemp (uulist *thefile)
01191 {
01192   if (thefile == NULL)
01193     return UURET_ILLVAL;
01194 
01195   if (thefile->binfile) {
01196     if (unlink (thefile->binfile)) {
01197       UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
01198                  uustring (S_TMP_NOT_REMOVED),
01199                  thefile->binfile,
01200                  strerror (uu_errno = errno));
01201     }
01202     _FP_free (thefile->binfile);
01203     thefile->binfile = NULL;
01204     thefile->state  &= ~UUFILE_TMPFILE;
01205   }
01206   return UURET_OK;
01207 }
01208 
01209 int UUEXPORT
01210 UUCleanUp (void)
01211 {
01212   itbd *iter=ftodel, *ptr;
01213   uulist *liter;
01214   uufile *fiter;
01215   allomap *aiter;
01216 
01217   /*
01218  * delete temporary input files (such as the copy of stdin)
01219  */
01220 
01221   while (iter) {
01222     if (unlink (iter->fname)) {
01223       UUMessage (uulib_id, __LINE__, UUMSG_WARNING,
01224                  uustring (S_TMP_NOT_REMOVED),
01225                  iter->fname, strerror (uu_errno = errno));
01226     }
01227     _FP_free (iter->fname);
01228     ptr  = iter;
01229     iter = iter->NEXT;
01230     _FP_free (ptr);
01231   }
01232 
01233   ftodel = NULL;
01234 
01235   /*
01236  * Delete input files after successful decoding
01237  */
01238 
01239   if (uu_remove_input) {
01240     liter = UUGlobalFileList;
01241     while (liter) {
01242       if (liter->state & UUFILE_DECODED) {
01243         fiter = liter->thisfile;
01244         while (fiter) {
01245           if (fiter->data && fiter->data->sfname) {
01246             /*
01247  * Error code ignored. We might want to delete a file multiple
01248  * times
01249  */
01250             unlink (fiter->data->sfname);
01251           }
01252           fiter = fiter->NEXT;
01253         }
01254       }
01255       liter = liter->NEXT;
01256     }
01257   }
01258 
01259   UUkilllist (UUGlobalFileList);
01260   UUGlobalFileList = NULL;
01261 
01262   _FP_free (uusavepath);
01263   _FP_free (uuencodeext);
01264   _FP_free (sstate.source);
01265 
01266   uusavepath  = NULL;
01267   uuencodeext = NULL;
01268 
01269   UUkillheaders (&localenv);
01270   UUkillheaders (&sstate.envelope);
01271   memset (&localenv, 0, sizeof (headers));
01272   memset (&sstate,   0, sizeof (scanstate));
01273 
01274   while (mssdepth) {
01275     mssdepth--;
01276     UUkillheaders (&(multistack[mssdepth].envelope));
01277     _FP_free (multistack[mssdepth].source);
01278   }
01279 
01280   /*
01281  * clean up the malloc'ed stuff
01282  */
01283 
01284   for (aiter=toallocate; aiter->ptr; aiter++) {
01285     _FP_free (*(aiter->ptr));
01286     *(aiter->ptr) = NULL;
01287   }
01288 
01289   return UURET_OK;
01290 }
01291 

Generated on Sun Oct 12 01:45:30 2008 for NNTPGrab by  1.5.4