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

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.
                      6: **
                      7: **     This version of the stream object just writes to a C file.
                      8: **     The file is assumed open and left open.
                      9: **
                     10: **     Bugs:
                     11: **             strings written must be less than buffer size.
                     12: **
                     13: **      History:
                     14: **         HFN: wrote it
                     15: **         HWL: converted the caching scheme to be hierachical by taking
                     16: **              AL code from Deamon
2.10      frystyk    17: **        HFN: moved cache code to HTCache module
2.1       frystyk    18: **
                     19: */
                     20: 
                     21: /* Library include files */
                     22: #include "tcp.h"
                     23: #include "HTUtils.h"
                     24: #include "HTString.h"
                     25: #include "HTFormat.h"
                     26: #include "HTAlert.h"
2.4       frystyk    27: #include "HTBind.h"
2.1       frystyk    28: #include "HTList.h"
2.3       frystyk    29: #include "HTParse.h"
2.15      frystyk    30: #include "HTReq.h"
2.3       frystyk    31: #include "HTFWrite.h"                                   /* Implemented here */
2.1       frystyk    32: 
2.4       frystyk    33: #define HASH_SIZE 1001         /* Tunable */
                     34: 
2.13      frystyk    35: /* The default directory for "save locally" and "save and execute" files: */
                     36: #ifndef HT_TMP_ROOT
                     37: #define HT_TMP_ROOT            "/tmp"
                     38: #endif
                     39: 
2.3       frystyk    40: struct _HTStream {
                     41:        CONST HTStreamClass *   isa;
                     42:        
                     43:        FILE *                  fp;
                     44:        BOOL                    leave_open;     /* Close file? HFN 08/02-94 */
                     45:        char *                  end_command;
                     46:        BOOL                    remove_on_close;
                     47:        BOOL                    announce;
                     48:        char *                  filename;
                     49:        HTRequest *             request;        /* saved for callback */
2.15      frystyk    50:        HTRequestCallback       *callback;
2.3       frystyk    51: };
2.1       frystyk    52: 
2.3       frystyk    53: PRIVATE HTStream       HTBlackHoleInstance;                  /* Made static */
                     54: PRIVATE char *         HTTmpRoot = NULL;              /* Dest for tmp files */
2.1       frystyk    55: 
2.3       frystyk    56: /* ------------------------------------------------------------------------- */
                     57: /*                          BASIC STREAM CLASSES                            */
                     58: /* ------------------------------------------------------------------------- */
2.1       frystyk    59: 
2.3       frystyk    60: /*
2.1       frystyk    61: **
2.3       frystyk    62: **             B L A C K    H O L E    C L A S S
2.1       frystyk    63: **
2.3       frystyk    64: **     There is only one black hole instance shared by anyone
                     65: **     who wants a black hole.  These black holes don't radiate,
                     66: **     they just absorb data.
                     67: */
2.16    ! frystyk    68: PRIVATE int HTBlackHole_put_character (HTStream * me, char c)
2.3       frystyk    69: {
                     70:     return HT_OK;
                     71: }
                     72: 
2.16    ! frystyk    73: PRIVATE int HTBlackHole_put_string (HTStream * me, CONST char * s)
2.3       frystyk    74: {
                     75:     return HT_OK;
                     76: }
                     77: 
2.16    ! frystyk    78: PRIVATE int HTBlackHole_write (HTStream * me, CONST char * s, int l)
2.3       frystyk    79: {
                     80:     return HT_OK;
                     81: }
                     82: 
2.16    ! frystyk    83: PRIVATE int HTBlackHole_flush (HTStream * me)
2.3       frystyk    84: {
                     85:     return HT_OK;
                     86: }
                     87: 
2.16    ! frystyk    88: PRIVATE int HTBlackHole_free (HTStream * me)
2.3       frystyk    89: {
                     90:     return HT_OK;
                     91: }
                     92: 
2.16    ! frystyk    93: PRIVATE int HTBlackHole_abort (HTStream * me, HTError e)
2.3       frystyk    94: {
                     95:     return HT_ERROR;
                     96: }
                     97: 
                     98: 
                     99: /*     Black Hole stream
                    100: **     -----------------
                    101: */
                    102: PRIVATE CONST HTStreamClass HTBlackHoleClass =
                    103: {              
                    104:     "BlackHole",
                    105:     HTBlackHole_flush,
                    106:     HTBlackHole_free,
                    107:     HTBlackHole_abort,
                    108:     HTBlackHole_put_character,
                    109:     HTBlackHole_put_string,
                    110:     HTBlackHole_write
                    111: }; 
                    112: 
2.16    ! frystyk   113: PUBLIC HTStream * HTBlackHole (void)
2.3       frystyk   114: {
2.14      frystyk   115:     if (STREAM_TRACE)
2.3       frystyk   116:        fprintf(TDEST, "BlackHole... Created\n");
                    117:     HTBlackHoleInstance.isa = &HTBlackHoleClass;       /* The rest is random */
                    118:     return &HTBlackHoleInstance;
                    119: }
                    120: 
                    121: 
                    122: /*     HTThroughLine
                    123: **     -------------
2.1       frystyk   124: **
2.3       frystyk   125: ** This function is a dummy function that returns the same output stream
                    126: ** as given as a parameter. Henrik 01/03-94
2.1       frystyk   127: */
2.16    ! frystyk   128: PUBLIC HTStream* HTThroughLine (HTRequest *    request,
        !           129:                                void *          param,
        !           130:                                HTFormat        input_format,
        !           131:                                HTFormat        output_format,
        !           132:                                HTStream *      output_stream)
2.3       frystyk   133: {
                    134:     return output_stream;
                    135: }
2.1       frystyk   136: 
2.3       frystyk   137: /* ------------------------------------------------------------------------- */
                    138: /*                          SOCKET WRITER STREAM                            */
                    139: /* ------------------------------------------------------------------------- */
                    140: 
2.16    ! frystyk   141: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3       frystyk   142: {
                    143:     return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
                    144: }
                    145: 
2.16    ! frystyk   146: PRIVATE int HTFWriter_put_string (HTStream * me, CONST char* s)
2.3       frystyk   147: {
                    148:     if (*s)                                         /* For vms :-( 10/04-94 */
                    149:        return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
                    150:     return HT_OK;
                    151: }
                    152: 
2.16    ! frystyk   153: PRIVATE int HTFWriter_flush (HTStream * me)
2.3       frystyk   154: {
2.7       frystyk   155:     return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3       frystyk   156: }
                    157: 
2.7       frystyk   158: 
2.16    ! frystyk   159: PRIVATE int HTFWriter_write (HTStream * me, CONST char* s, int l)
2.3       frystyk   160: {
2.7       frystyk   161:     int status ;
                    162:     status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
                    163:     if (l > 1 && status == HT_OK)
                    164:        (void)HTFWriter_flush( me) ;
                    165:     return status ;
                    166: 
                    167: /*    return (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK; */
                    168:     
2.3       frystyk   169: }
2.7       frystyk   170: 
2.3       frystyk   171: 
2.16    ! frystyk   172: PRIVATE int HTFWriter_free (HTStream * me)
2.3       frystyk   173: {
                    174:     if (me->leave_open != YES) fclose(me->fp);
                    175: 
                    176:     if (me->end_command) {             /* Temp file */
                    177:        system(me->end_command);        /* @@ Beware of security hole */
                    178:        free (me->end_command);
                    179:        if (me->remove_on_close) {
2.9       frystyk   180:            REMOVE(me->filename);
2.3       frystyk   181:        }
                    182:     }
                    183:     if (me->callback) {
                    184:         (*me->callback)(me->request, me->filename);
                    185:     }
                    186:     if (me->filename) free(me->filename);
                    187:     free(me);
                    188:     return HT_OK;
                    189: }
                    190: 
2.16    ! frystyk   191: PRIVATE int HTFWriter_abort (HTStream * me, HTError e)
2.3       frystyk   192: {
                    193:     if (me->leave_open != YES) fclose(me->fp);
                    194:     if (me->end_command) {             /* Temp file */
2.14      frystyk   195:        if (STREAM_TRACE)
2.3       frystyk   196:            fprintf(TDEST,"FileWriter.. Aborting: file %s not executed.\n",
                    197:                    me->filename ? me->filename : "???" );
                    198:        free (me->end_command);
                    199:        if (me->remove_on_close) {
2.9       frystyk   200:            REMOVE(me->filename);
2.3       frystyk   201:        }
                    202:     }
                    203: 
                    204:     if (me->filename) free(me->filename);
                    205:     free(me);
                    206:     return HT_ERROR;
                    207: }
                    208: 
                    209: PRIVATE CONST HTStreamClass HTFWriter = /* As opposed to print etc */
                    210: {              
                    211:     "FileWriter",
                    212:     HTFWriter_flush,
                    213:     HTFWriter_free,
                    214:     HTFWriter_abort,
                    215:     HTFWriter_put_character,
                    216:     HTFWriter_put_string,
                    217:     HTFWriter_write
                    218: };
                    219: 
2.16    ! frystyk   220: PUBLIC HTStream* HTFWriter_new (FILE * fp, BOOL leave_open)
2.3       frystyk   221: {
                    222:     HTStream* me;
                    223:     
                    224:     if (!fp) {
2.14      frystyk   225:        if (STREAM_TRACE)
2.3       frystyk   226:            fprintf(TDEST, "FileWriter.. Bad file descriptor\n");
                    227:        return NULL;
                    228:     }
                    229:     me = (HTStream*)calloc(sizeof(*me),1);
                    230:     if (me == NULL) outofmem(__FILE__, "HTFWriter_new");
                    231:     me->isa = &HTFWriter;       
                    232: 
                    233:     me->fp = fp;
                    234:     me->leave_open = leave_open;               /* HENRIK 08/02-94 */
                    235:     me->end_command = NULL;
                    236:     me->remove_on_close = NO;
                    237:     me->announce = NO;
                    238:     me->callback = NULL;
                    239:     return me;
                    240: }
                    241: 
                    242: /* ------------------------------------------------------------------------- */
                    243: /*                          FILE WRITER ROUTINES                            */
                    244: /* ------------------------------------------------------------------------- */
                    245: 
                    246: /*     Set TMP Root
                    247: **     --------------
                    248: **     If `tmp_root' is NULL use the current value (might be a define)
                    249: */
2.16    ! frystyk   250: PUBLIC BOOL HTTmp_setRoot (CONST char * tmp_root)
2.3       frystyk   251: {
                    252:     StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
                    253:     if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
                    254:        StrAllocCat(HTTmpRoot, "/");
2.14      frystyk   255:     if (STREAM_TRACE)
2.3       frystyk   256:        fprintf(TDEST, "Tmp Root.... Root set to `%s\'\n", HTTmpRoot);
                    257:     return YES;
                    258: }
                    259: 
                    260: 
                    261: /*     Get Tmp Root
                    262: **     --------------
2.1       frystyk   263: */
2.16    ! frystyk   264: PUBLIC CONST char * HTTmp_getRoot (void)
2.3       frystyk   265: {
                    266:     return HTTmpRoot;
                    267: }
2.1       frystyk   268: 
                    269: 
2.3       frystyk   270: /*     Free Tmp Root
                    271: **     --------------
                    272: **     For clean up memory
                    273: */
2.16    ! frystyk   274: PUBLIC void HTTmp_freeRoot (void)
2.3       frystyk   275: {
                    276:     FREE(HTTmpRoot);
                    277: }
2.1       frystyk   278: 
2.4       frystyk   279: /*
                    280: **   This function tries really hard to find a non-existent filename relative
                    281: **   to the path given. Returns a string that must be freed by the caller or
                    282: **   NULL on error. The base must be '/' terminated which!
                    283: */
2.16    ! frystyk   284: PRIVATE char *get_filename (char * base, CONST char * url, CONST char * suffix)
2.4       frystyk   285: {
                    286:     char *path=NULL;
                    287:     char filename[40];
                    288:     int hash=0;
                    289: 
                    290:     /* Do this until we find a name that doesn't exist */
                    291:     while (1)
                    292:     {
                    293:        CONST char *ptr=url;
                    294:        for( ; *ptr; ptr++)
                    295:            hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
                    296: 
                    297: #ifndef NO_GETPID
                    298:        sprintf(filename, "%d-%d", hash, (int) getpid());
                    299: #else
                    300:        sprintf(filename, "%d-%d", hash, time(NULL));
                    301: #endif
                    302:        StrAllocCopy(path, base);
                    303:        StrAllocCat(path, filename);
                    304:        if (suffix) StrAllocCat(path, suffix);
                    305: 
                    306:        {
                    307:            FILE *fp = fopen(path, "r");
                    308:            if (fp)                          /* This file does already exist */
                    309:                fclose(fp);
                    310:            else
                    311:                break;                                  /* Got the file name */
                    312:        }
                    313:     }
                    314:     return path;
                    315: }
                    316: 
                    317: 
2.1       frystyk   318: /*     Take action using a system command
                    319: **     ----------------------------------
                    320: **
                    321: **     Creates temporary file, writes to it, executes system command
                    322: **     on end-document.  The suffix of the temp file can be given
                    323: **     in case the application is fussy, or so that a generic opener can
                    324: **     be used.
                    325: */
2.16    ! frystyk   326: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
        !           327:                                   void *       param,
        !           328:                                   HTFormat     input_format,
        !           329:                                   HTFormat     output_format,
        !           330:                                   HTStream *   output_stream)
2.1       frystyk   331: {
                    332:     char *fnam;
                    333:     HTStream* me;
                    334:     
                    335:     if (HTSecure) {
2.11      frystyk   336:         HTAlert(request, "Can't save data to file -- please run WWW locally");
2.1       frystyk   337:        return HTBlackHole();
                    338:     }
                    339:     
2.3       frystyk   340:     if (!HTTmpRoot) {
2.14      frystyk   341:        if (STREAM_TRACE) fprintf(TDEST, "Save and execute turned off");
2.1       frystyk   342:        return HTBlackHole();
                    343:     }
                    344:        
2.4       frystyk   345:     /* Let's find a hash name for this file */
                    346:     {
2.13      frystyk   347:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    348:        char *suffix = HTBind_getSuffix(anchor);
                    349:        fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.5       frystyk   350:        FREE(suffix);
2.4       frystyk   351:        if (!fnam) {
2.11      frystyk   352:            HTAlert(request, "Can't find a suitable file name");
2.4       frystyk   353:            return HTBlackHole();
                    354:        }
                    355:     }
                    356: 
2.1       frystyk   357:     me = (HTStream*)calloc(sizeof(*me), 1);
                    358:     if (me == NULL) outofmem(__FILE__, "Save and execute");
                    359:     me->isa = &HTFWriter;  
                    360:     me->request = request;     /* won't be freed */    
2.12      frystyk   361:     me->fp = fopen (fnam, "wb");
2.1       frystyk   362:     if (!me->fp) {
2.11      frystyk   363:        HTAlert(request, "Can't open temporary file!");
2.1       frystyk   364:         free(fnam);
                    365:        free(me);
2.4       frystyk   366:        return HTBlackHole();
2.1       frystyk   367:     }
                    368:     StrAllocCopy(me->filename, fnam);
                    369: 
2.4       frystyk   370:     /* Make command to process file */
2.1       frystyk   371:     me->end_command = (char *) malloc ((strlen((char *) param) + 10 +
                    372:                                        3*strlen(fnam)) * sizeof (char));
                    373:     if (me == NULL) outofmem(__FILE__, "SaveAndExecute");
                    374:     
                    375:     sprintf (me->end_command, (char *) param, fnam, fnam, fnam);
                    376:     me->remove_on_close = NO;
                    377:     me->announce = NO;
                    378:     free (fnam);
                    379:     return me;
                    380: }
                    381: 
                    382: 
                    383: /*     Save Locally
                    384: **     ------------
                    385: **
                    386: **  Bugs:
                    387: **     GUI Apps should open local Save panel here really.
                    388: **
                    389: */
2.16    ! frystyk   390: PUBLIC HTStream* HTSaveLocally (HTRequest *    request,
        !           391:                                void *          param,
        !           392:                                HTFormat        input_format,
        !           393:                                HTFormat        output_format,
        !           394:                                HTStream *      output_stream)
2.1       frystyk   395: {
                    396:     char *fnam = NULL;
                    397:     char *answer = NULL;
                    398:     HTStream* me;
                    399:     
2.8       frystyk   400:     if (HTSecure) {
2.11      frystyk   401:         HTAlert(request, "Can't save data to file -- please run WWW locally");
2.1       frystyk   402:        return HTBlackHole();
                    403:     }
                    404: 
2.3       frystyk   405:     if (!HTTmpRoot) {
2.14      frystyk   406:        if (STREAM_TRACE) fprintf(TDEST, "Save locally turned off");
2.1       frystyk   407:        return HTBlackHole();
                    408:     }
                    409:        
2.4       frystyk   410:     /* Let's find a file name for this file */
                    411:     {
2.13      frystyk   412:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    413:        char *suffix = HTBind_getSuffix(anchor);
                    414:        fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.11      frystyk   415:        answer = HTPrompt(request, "Give name of file to save in",
                    416:                          fnam ? fnam : "");
2.4       frystyk   417:        if (!answer) {
                    418:            FREE(fnam);
                    419:            return HTBlackHole();
                    420:        }
2.5       frystyk   421:        FREE(suffix);
2.4       frystyk   422:        FREE(fnam);
                    423:     }
                    424:     
2.1       frystyk   425:     me = (HTStream*)calloc(sizeof(*me),1);
                    426:     if (me == NULL) outofmem(__FILE__, "SaveLocally");
                    427:     me->isa = &HTFWriter;  
                    428:     me->announce = YES;
                    429:     
2.12      frystyk   430:     me->fp = fopen (answer, "wb");
2.1       frystyk   431:     if (!me->fp) {
2.11      frystyk   432:        HTAlert(request, "Can't open local file to write into.");
2.1       frystyk   433:         FREE(answer);
                    434:        free(me);
2.4       frystyk   435:        return HTBlackHole();
2.1       frystyk   436:     }
                    437:     me->callback = NULL;
                    438:     me->request = request;     /* won't be freed */
                    439:     me->filename = answer;     /* Will be freed */
                    440:     return me;
                    441: }
                    442: 
                    443: 
                    444: /*     Save and Call Back
                    445: **     ------------------
                    446: **
                    447: **
                    448: **     The special case is a kludge. Better is everything uses streams
                    449: **     and nothing uses files.  Then this routine will go too. :-))
                    450: */
2.16    ! frystyk   451: PUBLIC HTStream* HTSaveAndCallback (HTRequest *                request,
        !           452:                                    void *              param,
        !           453:                                    HTFormat            input_format,
        !           454:                                    HTFormat            output_format,
        !           455:                                    HTStream *          output_stream)
2.1       frystyk   456: {
                    457:    HTStream * me;
                    458:    
2.10      frystyk   459: #if 0
2.1       frystyk   460:    if (request->using_cache) {  /* Special case! file wanted && cache hit */
                    461:         (*request->callback)(request,
2.13      frystyk   462:                         ((HTCache*) request->using_cache)->filename);
2.3       frystyk   463:        return HTBlackHole();
2.1       frystyk   464:    } else {
                    465:        me = HTCacheWriter(request, param,
                    466:                            input_format, output_format, output_stream);
                    467:        if (me) {
                    468:            me->callback = request->callback;
                    469:        }
                    470:    }
2.10      frystyk   471: #endif
2.1       frystyk   472:    return me;   
                    473: }
                    474: 

Webmaster