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

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

Webmaster