Annotation of libwww/Library/src/HTFWrite.c, revision 2.39

2.1       frystyk     1: /*                                                                 HTFWrite.c
                      2: **     FILE WRITER
                      3: **
2.6       frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.1       frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.39    ! frystyk     6: **     @(#) $Id: HTFWrite.c,v 2.38 1996/12/13 22:06:11 eric Exp $
2.1       frystyk     7: **
                      8: **     This version of the stream object just writes to a C file.
                      9: **     The file is assumed open and left open.
                     10: **
                     11: **     Bugs:
                     12: **             strings written must be less than buffer size.
                     13: **
                     14: **      History:
                     15: **         HFN: wrote it
                     16: **         HWL: converted the caching scheme to be hierachical by taking
                     17: **              AL code from Deamon
2.10      frystyk    18: **        HFN: moved cache code to HTCache module
2.1       frystyk    19: **
                     20: */
                     21: 
                     22: /* Library include files */
2.28      frystyk    23: #include "sysdep.h"
2.35      frystyk    24: #include "WWWUtil.h"
2.1       frystyk    25: #include "HTFormat.h"
2.21      frystyk    26: #include "HTError.h"
2.1       frystyk    27: #include "HTAlert.h"
2.35      frystyk    28: #include "HTLib.h"
2.4       frystyk    29: #include "HTBind.h"
2.3       frystyk    30: #include "HTParse.h"
2.15      frystyk    31: #include "HTReq.h"
2.3       frystyk    32: #include "HTFWrite.h"                                   /* Implemented here */
2.1       frystyk    33: 
2.4       frystyk    34: #define HASH_SIZE 1001         /* Tunable */
                     35: 
2.3       frystyk    36: struct _HTStream {
2.28      frystyk    37:     const HTStreamClass *isa;
2.24      frystyk    38:     
                     39:     FILE *             fp;
2.31      frystyk    40:     BOOL               leave_open;                 /* Close file when free? */
2.24      frystyk    41:     char *             end_command;                   /* Command to execute */
                     42:     BOOL               remove_on_close;                     /* Remove file? */
                     43:     char *             filename;                            /* Name of file */
                     44:     HTRequest *                request;                       /* saved for callback */
                     45:     HTRequestCallback *        callback;
2.3       frystyk    46: };
2.1       frystyk    47: 
2.3       frystyk    48: /* ------------------------------------------------------------------------- */
2.1       frystyk    49: 
2.16      frystyk    50: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3       frystyk    51: {
                     52:     return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
                     53: }
                     54: 
2.28      frystyk    55: PRIVATE int HTFWriter_put_string (HTStream * me, const char* s)
2.3       frystyk    56: {
                     57:     if (*s)                                         /* For vms :-( 10/04-94 */
                     58:        return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
                     59:     return HT_OK;
                     60: }
                     61: 
2.16      frystyk    62: PRIVATE int HTFWriter_flush (HTStream * me)
2.3       frystyk    63: {
2.7       frystyk    64:     return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3       frystyk    65: }
                     66: 
2.28      frystyk    67: PRIVATE int HTFWriter_write (HTStream * me, const char* s, int l)
2.3       frystyk    68: {
2.7       frystyk    69:     int status ;
                     70:     status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
2.24      frystyk    71:     if (l > 1 && status == HT_OK) (void) HTFWriter_flush(me);
2.7       frystyk    72:     return status ;
2.3       frystyk    73: }
2.7       frystyk    74: 
2.30      frystyk    75: PRIVATE int HTFWriter_free (HTStream * me)
2.3       frystyk    76: {
2.24      frystyk    77:     if (me) {
                     78:        if (me->leave_open != YES) fclose(me->fp);
2.28      frystyk    79: #ifdef HAVE_SYSTEM
2.24      frystyk    80:        if (me->end_command) system(me->end_command);    /* SECURITY HOLE!!! */
2.17      frystyk    81: #endif
2.37      frystyk    82:        if (me->callback) (*me->callback)(me->request, me->filename);
2.24      frystyk    83:        if (me->remove_on_close) REMOVE(me->filename);
2.26      frystyk    84:        HT_FREE(me->end_command);
                     85:        HT_FREE(me->filename);
                     86:        HT_FREE(me);
2.3       frystyk    87:     }
                     88:     return HT_OK;
                     89: }
                     90: 
2.18      frystyk    91: PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
2.3       frystyk    92: {
2.27      eric       93:     if (STREAM_TRACE) HTTrace("FileWriter.. ABORTING...\n");
2.24      frystyk    94:     if (me) {
                     95:        if (me->leave_open != YES) fclose(me->fp);
                     96:        if (me->remove_on_close) REMOVE(me->filename);
2.26      frystyk    97:        HT_FREE(me->end_command);
                     98:        HT_FREE(me->filename);
                     99:        HT_FREE(me);
2.3       frystyk   100:     }
                    101:     return HT_ERROR;
                    102: }
                    103: 
2.28      frystyk   104: PRIVATE const HTStreamClass HTFWriter = /* As opposed to print etc */
2.3       frystyk   105: {              
                    106:     "FileWriter",
                    107:     HTFWriter_flush,
2.30      frystyk   108:     HTFWriter_free,
2.3       frystyk   109:     HTFWriter_abort,
                    110:     HTFWriter_put_character,
                    111:     HTFWriter_put_string,
                    112:     HTFWriter_write
                    113: };
                    114: 
2.24      frystyk   115: PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
                    116:                                 BOOL leave_open)
2.3       frystyk   117: {
2.24      frystyk   118:     HTStream * me = NULL;
2.3       frystyk   119:     if (!fp) {
2.27      eric      120:        if (STREAM_TRACE)HTTrace("FileWriter.. Bad file descriptor\n");
2.24      frystyk   121:        return HTErrorStream();
2.3       frystyk   122:     }
2.26      frystyk   123:     if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    124:         HT_OUTOFMEM("HTFWriter_new");
2.3       frystyk   125:     me->isa = &HTFWriter;       
                    126:     me->fp = fp;
2.24      frystyk   127:     me->leave_open = leave_open;
                    128:     me->request = request;
2.3       frystyk   129:     return me;
                    130: }
                    131: 
                    132: /* ------------------------------------------------------------------------- */
                    133: /*                          FILE WRITER ROUTINES                            */
                    134: /* ------------------------------------------------------------------------- */
                    135: 
2.4       frystyk   136: /*
                    137: **   This function tries really hard to find a non-existent filename relative
2.31      frystyk   138: **   to the path given. Returns a string that must be freed by the caller or
2.4       frystyk   139: **   NULL on error. The base must be '/' terminated which!
                    140: */
2.28      frystyk   141: PRIVATE char *get_filename (char * base, const char * url, const char * suffix)
2.4       frystyk   142: {
                    143:     char *path=NULL;
                    144:     char filename[40];
                    145:     int hash=0;
                    146: 
                    147:     /* Do this until we find a name that doesn't exist */
                    148:     while (1)
                    149:     {
2.28      frystyk   150:        const char *ptr=url;
2.4       frystyk   151:        for( ; *ptr; ptr++)
                    152:            hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
                    153: 
2.28      frystyk   154: #ifdef HAVE_GETPID
2.4       frystyk   155:        sprintf(filename, "%d-%d", hash, (int) getpid());
                    156: #else
                    157:        sprintf(filename, "%d-%d", hash, time(NULL));
                    158: #endif
                    159:        StrAllocCopy(path, base);
                    160:        StrAllocCat(path, filename);
                    161:        if (suffix) StrAllocCat(path, suffix);
                    162: 
                    163:        {
                    164:            FILE *fp = fopen(path, "r");
                    165:            if (fp)                          /* This file does already exist */
                    166:                fclose(fp);
                    167:            else
                    168:                break;                                  /* Got the file name */
                    169:        }
                    170:     }
2.34      frystyk   171:     if (STREAM_TRACE) HTTrace("Save file... Temporaray file `%s\'\n", path);
2.4       frystyk   172:     return path;
                    173: }
                    174: 
2.24      frystyk   175: /*     Save Locally
                    176: **     ------------
                    177: **     Saves a file to local disk. This can for example be used to dump
                    178: **     date objects of unknown media types to local disk. The stream prompts
                    179: **     for a file name for the temporary file.
2.1       frystyk   180: */
2.24      frystyk   181: PUBLIC HTStream* HTSaveLocally (HTRequest *    request,
                    182:                                void *          param,
                    183:                                HTFormat        input_format,
                    184:                                HTFormat        output_format,
                    185:                                HTStream *      output_stream)
2.1       frystyk   186: {
2.24      frystyk   187:     FILE * fp = NULL;
                    188:     char * filename = NULL;
2.33      frystyk   189:     HTUserProfile * up = HTRequest_userProfile(request);
                    190:     char * tmproot = HTUserProfile_tmp(up);
2.19      frystyk   191:     if (HTLib_secure()) {
2.21      frystyk   192:        HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
2.24      frystyk   193:                           NULL, 0, "HTSaveLocally");
                    194:        return HTErrorStream();
2.1       frystyk   195:     }
2.33      frystyk   196:     if (!tmproot) {
2.27      eric      197:        if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24      frystyk   198:        return HTErrorStream();
2.1       frystyk   199:     }
                    200:        
2.24      frystyk   201:     /* Let's prompt the user for a file name for this file */
2.4       frystyk   202:     {
2.24      frystyk   203:        HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
2.13      frystyk   204:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    205:        char *suffix = HTBind_getSuffix(anchor);
2.33      frystyk   206:        char *deflt = get_filename(tmproot,HTAnchor_physical(anchor),suffix);
2.39    ! frystyk   207: 
        !           208:        /*
        !           209:        **  If we found an alert handler for prompting the user then call it.
        !           210:        **  If not then either we are in non-interactive mode or no handler
        !           211:        **  has been registered. For now we then return a blackhole which may
        !           212:        **  not be the best thing to do.
        !           213:        */
2.24      frystyk   214:        if (cbf) {
                    215:            HTAlertPar * reply = HTAlert_newReply();
                    216:            if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
                    217:                filename = HTAlert_replyMessage(reply);
                    218:            HTAlert_deleteReply(reply);
                    219:        }
2.26      frystyk   220:        HT_FREE(suffix);
                    221:        HT_FREE(deflt);
2.24      frystyk   222:        if (filename) {
                    223:            if ((fp = fopen(filename, "wb")) == NULL) {
                    224:                HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
                    225:                                   filename, strlen(filename),"HTSaveLocally");
2.26      frystyk   226:                HT_FREE(filename);
2.24      frystyk   227:                return HTErrorStream();
                    228:            }
2.39    ! frystyk   229:        } else if (cbf) {
        !           230:            if (STREAM_TRACE) HTTrace("Save File... No file name - error stream\n");
        !           231:            return HTErrorStream();
2.24      frystyk   232:        } else {
2.39    ! frystyk   233:            if (STREAM_TRACE) HTTrace("Save File... No file name - black hole\n");
        !           234:            return HTBlackHole();
2.4       frystyk   235:        }
                    236:     }
2.24      frystyk   237:     
                    238:     /* Now we are ready for creating the file writer stream */
                    239:     if (fp) {
                    240:        HTStream * me = HTFWriter_new(request, fp, NO);
                    241:        me->filename = filename;
                    242:        return me;
2.1       frystyk   243:     }
2.26      frystyk   244:     HT_FREE(filename);
2.24      frystyk   245:     return HTErrorStream();
2.1       frystyk   246: }
                    247: 
                    248: 
2.24      frystyk   249: /*     Take action using a system command
                    250: **     ----------------------------------
                    251: **     Creates temporary file, writes to it and then executes system
                    252: **     command (maybe an external viewer) when EOF has been reached. The
                    253: **     stream finds a suitable name of the temporary file which preserves the
                    254: **     suffix. This way, the system command can find out the file type from
                    255: **     the name of the temporary file name.
2.1       frystyk   256: */
2.24      frystyk   257: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
                    258:                                   void *       param,
                    259:                                   HTFormat     input_format,
                    260:                                   HTFormat     output_format,
                    261:                                   HTStream *   output_stream)
2.1       frystyk   262: {
2.24      frystyk   263:     FILE * fp = NULL;
                    264:     char * filename = NULL;
2.33      frystyk   265:     HTUserProfile * up = HTRequest_userProfile(request);
                    266:     char * tmproot = HTUserProfile_tmp(up);
2.19      frystyk   267:     if (HTLib_secure()) {
2.21      frystyk   268:        HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
                    269:                           NULL, 0, "HTSaveLocally");
2.24      frystyk   270:        return HTErrorStream();
2.1       frystyk   271:     }
2.33      frystyk   272:     if (!tmproot) {
2.27      eric      273:        if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24      frystyk   274:        return HTErrorStream();
2.1       frystyk   275:     }
                    276:        
2.24      frystyk   277:     /* Let's find a hash name for this file without asking user */
2.4       frystyk   278:     {
2.13      frystyk   279:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    280:        char *suffix = HTBind_getSuffix(anchor);
2.33      frystyk   281:        filename = get_filename(tmproot, HTAnchor_physical(anchor), suffix);
2.26      frystyk   282:        HT_FREE(suffix);
2.25      frystyk   283:        if (filename) {
                    284:            if ((fp = fopen(filename, "wb")) == NULL) {
                    285:                HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
                    286:                                   filename, strlen(filename),"HTSaveAndExecute");
2.26      frystyk   287:                HT_FREE(filename);
2.25      frystyk   288:                return HTErrorStream();
                    289:            }
                    290:        } else {
2.27      eric      291:            if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24      frystyk   292:            return HTErrorStream();
2.4       frystyk   293:        }
                    294:     }
                    295:     
2.24      frystyk   296:     /* Now we are ready for creating the file writer stream */
                    297:     if (fp) {
                    298:        HTStream * me = HTFWriter_new(request, fp, NO);
                    299:        me->filename = filename;
2.31      frystyk   300:        if (param) {
                    301:            if ((me->end_command = (char  *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
                    302:                HT_OUTOFMEM("SaveAndExecute");
                    303:            sprintf (me->end_command,
                    304:                     (char *)param, filename, filename, filename);
                    305:        }
2.24      frystyk   306:        return me;
2.1       frystyk   307:     }
2.26      frystyk   308:     HT_FREE(filename);
2.24      frystyk   309:     return HTErrorStream();
2.1       frystyk   310: }
                    311: 
                    312: 
                    313: /*     Save and Call Back
                    314: **     ------------------
2.32      frystyk   315: **     This stream works exactly like the HTSaveAndExecute
2.24      frystyk   316: **     stream but in addition when EOF has been reached, it checks whether a
                    317: **     callback function has been associated with the request object in which
                    318: **     case, this callback is being called. This can be use by the
                    319: **     application to do some processing after the system command
                    320: **     has terminated. The callback function is called with the file name of
                    321: **     the temporary file as parameter.
2.1       frystyk   322: */
2.16      frystyk   323: PUBLIC HTStream* HTSaveAndCallback (HTRequest *                request,
                    324:                                    void *              param,
                    325:                                    HTFormat            input_format,
                    326:                                    HTFormat            output_format,
                    327:                                    HTStream *          output_stream)
2.1       frystyk   328: {
2.24      frystyk   329:     HTStream * me = HTSaveAndExecute(request, param, input_format,
                    330:                                     output_format, output_stream);
                    331:     if (me) {
                    332:        me->callback = HTRequest_callback(request);
                    333:        return me;
                    334:     }
                    335:     return HTErrorStream();
2.1       frystyk   336: }
                    337: 

Webmaster