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

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.42    ! frystyk     6: **     @(#) $Id: HTFWrite.c,v 2.41 1997/12/16 21:09:09 frystyk 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.42    ! frystyk    23: #include "wwwsys.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) {
2.41      frystyk    78:        if (me->leave_open != YES)
                     79:            fclose(me->fp);
                     80:        else
                     81:            HTFWriter_flush(me);
2.28      frystyk    82: #ifdef HAVE_SYSTEM
2.24      frystyk    83:        if (me->end_command) system(me->end_command);    /* SECURITY HOLE!!! */
2.17      frystyk    84: #endif
2.37      frystyk    85:        if (me->callback) (*me->callback)(me->request, me->filename);
2.24      frystyk    86:        if (me->remove_on_close) REMOVE(me->filename);
2.26      frystyk    87:        HT_FREE(me->end_command);
                     88:        HT_FREE(me->filename);
                     89:        HT_FREE(me);
2.3       frystyk    90:     }
                     91:     return HT_OK;
                     92: }
                     93: 
2.18      frystyk    94: PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
2.3       frystyk    95: {
2.27      eric       96:     if (STREAM_TRACE) HTTrace("FileWriter.. ABORTING...\n");
2.24      frystyk    97:     if (me) {
                     98:        if (me->leave_open != YES) fclose(me->fp);
                     99:        if (me->remove_on_close) REMOVE(me->filename);
2.26      frystyk   100:        HT_FREE(me->end_command);
                    101:        HT_FREE(me->filename);
                    102:        HT_FREE(me);
2.3       frystyk   103:     }
                    104:     return HT_ERROR;
                    105: }
                    106: 
2.28      frystyk   107: PRIVATE const HTStreamClass HTFWriter = /* As opposed to print etc */
2.3       frystyk   108: {              
                    109:     "FileWriter",
                    110:     HTFWriter_flush,
2.30      frystyk   111:     HTFWriter_free,
2.3       frystyk   112:     HTFWriter_abort,
                    113:     HTFWriter_put_character,
                    114:     HTFWriter_put_string,
                    115:     HTFWriter_write
                    116: };
                    117: 
2.24      frystyk   118: PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
                    119:                                 BOOL leave_open)
2.3       frystyk   120: {
2.24      frystyk   121:     HTStream * me = NULL;
2.3       frystyk   122:     if (!fp) {
2.27      eric      123:        if (STREAM_TRACE)HTTrace("FileWriter.. Bad file descriptor\n");
2.24      frystyk   124:        return HTErrorStream();
2.3       frystyk   125:     }
2.26      frystyk   126:     if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    127:         HT_OUTOFMEM("HTFWriter_new");
2.3       frystyk   128:     me->isa = &HTFWriter;       
                    129:     me->fp = fp;
2.24      frystyk   130:     me->leave_open = leave_open;
                    131:     me->request = request;
2.3       frystyk   132:     return me;
                    133: }
                    134: 
                    135: /* ------------------------------------------------------------------------- */
                    136: /*                          FILE WRITER ROUTINES                            */
                    137: /* ------------------------------------------------------------------------- */
                    138: 
2.4       frystyk   139: /*
                    140: **   This function tries really hard to find a non-existent filename relative
2.31      frystyk   141: **   to the path given. Returns a string that must be freed by the caller or
2.4       frystyk   142: **   NULL on error. The base must be '/' terminated which!
                    143: */
2.28      frystyk   144: PRIVATE char *get_filename (char * base, const char * url, const char * suffix)
2.4       frystyk   145: {
                    146:     char *path=NULL;
                    147:     char filename[40];
                    148:     int hash=0;
                    149: 
                    150:     /* Do this until we find a name that doesn't exist */
                    151:     while (1)
                    152:     {
2.28      frystyk   153:        const char *ptr=url;
2.4       frystyk   154:        for( ; *ptr; ptr++)
                    155:            hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
                    156: 
2.28      frystyk   157: #ifdef HAVE_GETPID
2.4       frystyk   158:        sprintf(filename, "%d-%d", hash, (int) getpid());
                    159: #else
                    160:        sprintf(filename, "%d-%d", hash, time(NULL));
                    161: #endif
                    162:        StrAllocCopy(path, base);
                    163:        StrAllocCat(path, filename);
                    164:        if (suffix) StrAllocCat(path, suffix);
                    165: 
                    166:        {
                    167:            FILE *fp = fopen(path, "r");
                    168:            if (fp)                          /* This file does already exist */
                    169:                fclose(fp);
                    170:            else
                    171:                break;                                  /* Got the file name */
                    172:        }
                    173:     }
2.34      frystyk   174:     if (STREAM_TRACE) HTTrace("Save file... Temporaray file `%s\'\n", path);
2.4       frystyk   175:     return path;
                    176: }
                    177: 
2.24      frystyk   178: /*     Save Locally
                    179: **     ------------
                    180: **     Saves a file to local disk. This can for example be used to dump
                    181: **     date objects of unknown media types to local disk. The stream prompts
                    182: **     for a file name for the temporary file.
2.1       frystyk   183: */
2.24      frystyk   184: PUBLIC HTStream* HTSaveLocally (HTRequest *    request,
                    185:                                void *          param,
                    186:                                HTFormat        input_format,
                    187:                                HTFormat        output_format,
                    188:                                HTStream *      output_stream)
2.1       frystyk   189: {
2.24      frystyk   190:     FILE * fp = NULL;
                    191:     char * filename = NULL;
2.33      frystyk   192:     HTUserProfile * up = HTRequest_userProfile(request);
                    193:     char * tmproot = HTUserProfile_tmp(up);
2.19      frystyk   194:     if (HTLib_secure()) {
2.21      frystyk   195:        HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
2.24      frystyk   196:                           NULL, 0, "HTSaveLocally");
                    197:        return HTErrorStream();
2.1       frystyk   198:     }
2.33      frystyk   199:     if (!tmproot) {
2.27      eric      200:        if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24      frystyk   201:        return HTErrorStream();
2.1       frystyk   202:     }
                    203:        
2.24      frystyk   204:     /* Let's prompt the user for a file name for this file */
2.4       frystyk   205:     {
2.24      frystyk   206:        HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
2.13      frystyk   207:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
2.39      frystyk   208: 
                    209:        /*
                    210:        **  If we found an alert handler for prompting the user then call it.
                    211:        **  If not then either we are in non-interactive mode or no handler
                    212:        **  has been registered. For now we then return a blackhole which may
                    213:        **  not be the best thing to do.
                    214:        */
2.24      frystyk   215:        if (cbf) {
                    216:            HTAlertPar * reply = HTAlert_newReply();
2.40      frystyk   217:            char * suffix = HTBind_getSuffix(anchor);
                    218:            char * deflt = get_filename(tmproot, HTAnchor_physical(anchor), suffix);
2.24      frystyk   219:            if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
                    220:                filename = HTAlert_replyMessage(reply);
                    221:            HTAlert_deleteReply(reply);
2.40      frystyk   222:            HT_FREE(suffix);
                    223:            HT_FREE(deflt);
2.24      frystyk   224:        }
                    225:        if (filename) {
                    226:            if ((fp = fopen(filename, "wb")) == NULL) {
                    227:                HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
                    228:                                   filename, strlen(filename),"HTSaveLocally");
2.26      frystyk   229:                HT_FREE(filename);
2.24      frystyk   230:                return HTErrorStream();
                    231:            }
2.39      frystyk   232:        } else if (cbf) {
                    233:            if (STREAM_TRACE) HTTrace("Save File... No file name - error stream\n");
                    234:            return HTErrorStream();
2.24      frystyk   235:        } else {
2.39      frystyk   236:            if (STREAM_TRACE) HTTrace("Save File... No file name - black hole\n");
                    237:            return HTBlackHole();
2.4       frystyk   238:        }
                    239:     }
2.24      frystyk   240:     
                    241:     /* Now we are ready for creating the file writer stream */
                    242:     if (fp) {
                    243:        HTStream * me = HTFWriter_new(request, fp, NO);
                    244:        me->filename = filename;
                    245:        return me;
2.1       frystyk   246:     }
2.26      frystyk   247:     HT_FREE(filename);
2.24      frystyk   248:     return HTErrorStream();
2.1       frystyk   249: }
                    250: 
                    251: 
2.24      frystyk   252: /*     Take action using a system command
                    253: **     ----------------------------------
                    254: **     Creates temporary file, writes to it and then executes system
                    255: **     command (maybe an external viewer) when EOF has been reached. The
                    256: **     stream finds a suitable name of the temporary file which preserves the
                    257: **     suffix. This way, the system command can find out the file type from
                    258: **     the name of the temporary file name.
2.1       frystyk   259: */
2.24      frystyk   260: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
                    261:                                   void *       param,
                    262:                                   HTFormat     input_format,
                    263:                                   HTFormat     output_format,
                    264:                                   HTStream *   output_stream)
2.1       frystyk   265: {
2.24      frystyk   266:     FILE * fp = NULL;
                    267:     char * filename = NULL;
2.33      frystyk   268:     HTUserProfile * up = HTRequest_userProfile(request);
                    269:     char * tmproot = HTUserProfile_tmp(up);
2.19      frystyk   270:     if (HTLib_secure()) {
2.21      frystyk   271:        HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
                    272:                           NULL, 0, "HTSaveLocally");
2.24      frystyk   273:        return HTErrorStream();
2.1       frystyk   274:     }
2.33      frystyk   275:     if (!tmproot) {
2.27      eric      276:        if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24      frystyk   277:        return HTErrorStream();
2.1       frystyk   278:     }
                    279:        
2.24      frystyk   280:     /* Let's find a hash name for this file without asking user */
2.4       frystyk   281:     {
2.13      frystyk   282:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    283:        char *suffix = HTBind_getSuffix(anchor);
2.33      frystyk   284:        filename = get_filename(tmproot, HTAnchor_physical(anchor), suffix);
2.26      frystyk   285:        HT_FREE(suffix);
2.25      frystyk   286:        if (filename) {
                    287:            if ((fp = fopen(filename, "wb")) == NULL) {
                    288:                HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
                    289:                                   filename, strlen(filename),"HTSaveAndExecute");
2.26      frystyk   290:                HT_FREE(filename);
2.25      frystyk   291:                return HTErrorStream();
                    292:            }
                    293:        } else {
2.27      eric      294:            if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24      frystyk   295:            return HTErrorStream();
2.4       frystyk   296:        }
                    297:     }
                    298:     
2.24      frystyk   299:     /* Now we are ready for creating the file writer stream */
                    300:     if (fp) {
                    301:        HTStream * me = HTFWriter_new(request, fp, NO);
                    302:        me->filename = filename;
2.31      frystyk   303:        if (param) {
                    304:            if ((me->end_command = (char  *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
                    305:                HT_OUTOFMEM("SaveAndExecute");
                    306:            sprintf (me->end_command,
                    307:                     (char *)param, filename, filename, filename);
                    308:        }
2.24      frystyk   309:        return me;
2.1       frystyk   310:     }
2.26      frystyk   311:     HT_FREE(filename);
2.24      frystyk   312:     return HTErrorStream();
2.1       frystyk   313: }
                    314: 
                    315: 
                    316: /*     Save and Call Back
                    317: **     ------------------
2.32      frystyk   318: **     This stream works exactly like the HTSaveAndExecute
2.24      frystyk   319: **     stream but in addition when EOF has been reached, it checks whether a
                    320: **     callback function has been associated with the request object in which
                    321: **     case, this callback is being called. This can be use by the
                    322: **     application to do some processing after the system command
                    323: **     has terminated. The callback function is called with the file name of
                    324: **     the temporary file as parameter.
2.1       frystyk   325: */
2.16      frystyk   326: PUBLIC HTStream* HTSaveAndCallback (HTRequest *                request,
                    327:                                    void *              param,
                    328:                                    HTFormat            input_format,
                    329:                                    HTFormat            output_format,
                    330:                                    HTStream *          output_stream)
2.1       frystyk   331: {
2.24      frystyk   332:     HTStream * me = HTSaveAndExecute(request, param, input_format,
                    333:                                     output_format, output_stream);
                    334:     if (me) {
                    335:        me->callback = HTRequest_callback(request);
                    336:        return me;
                    337:     }
                    338:     return HTErrorStream();
2.1       frystyk   339: }
                    340: 

Webmaster