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

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.13    ! frystyk    34: /* The default directory for "save locally" and "save and execute" files: */
        !            35: #ifndef HT_TMP_ROOT
        !            36: #define HT_TMP_ROOT            "/tmp"
        !            37: #endif
        !            38: 
2.3       frystyk    39: struct _HTStream {
                     40:        CONST HTStreamClass *   isa;
                     41:        
                     42:        FILE *                  fp;
                     43:        BOOL                    leave_open;     /* Close file? HFN 08/02-94 */
                     44:        char *                  end_command;
                     45:        BOOL                    remove_on_close;
                     46:        BOOL                    announce;
                     47:        char *                  filename;
                     48:        HTRequest *             request;        /* saved for callback */
                     49:        BOOL (*callback) PARAMS((struct _HTRequest * req, void * filename));
                     50: };
2.1       frystyk    51: 
2.3       frystyk    52: PRIVATE HTStream       HTBlackHoleInstance;                  /* Made static */
                     53: PRIVATE char *         HTTmpRoot = NULL;              /* Dest for tmp files */
2.1       frystyk    54: 
2.3       frystyk    55: /* ------------------------------------------------------------------------- */
                     56: /*                          BASIC STREAM CLASSES                            */
                     57: /* ------------------------------------------------------------------------- */
2.1       frystyk    58: 
2.3       frystyk    59: /*
2.1       frystyk    60: **
2.3       frystyk    61: **             B L A C K    H O L E    C L A S S
2.1       frystyk    62: **
2.3       frystyk    63: **     There is only one black hole instance shared by anyone
                     64: **     who wants a black hole.  These black holes don't radiate,
                     65: **     they just absorb data.
                     66: */
                     67: PRIVATE int HTBlackHole_put_character ARGS2(HTStream *, me, char, c)
                     68: {
                     69:     return HT_OK;
                     70: }
                     71: 
                     72: PRIVATE int HTBlackHole_put_string ARGS2(HTStream *, me, CONST char*, s)
                     73: {
                     74:     return HT_OK;
                     75: }
                     76: 
                     77: PRIVATE int HTBlackHole_write ARGS3(HTStream *, me, CONST char*, s, int, l)
                     78: {
                     79:     return HT_OK;
                     80: }
                     81: 
                     82: PRIVATE int HTBlackHole_flush ARGS1(HTStream *, me)
                     83: {
                     84:     return HT_OK;
                     85: }
                     86: 
                     87: PRIVATE int HTBlackHole_free ARGS1(HTStream *, me)
                     88: {
                     89:     return HT_OK;
                     90: }
                     91: 
                     92: PRIVATE int HTBlackHole_abort ARGS2(HTStream *, me, HTError, e)
                     93: {
                     94:     return HT_ERROR;
                     95: }
                     96: 
                     97: 
                     98: /*     Black Hole stream
                     99: **     -----------------
                    100: */
                    101: PRIVATE CONST HTStreamClass HTBlackHoleClass =
                    102: {              
                    103:     "BlackHole",
                    104:     HTBlackHole_flush,
                    105:     HTBlackHole_free,
                    106:     HTBlackHole_abort,
                    107:     HTBlackHole_put_character,
                    108:     HTBlackHole_put_string,
                    109:     HTBlackHole_write
                    110: }; 
                    111: 
                    112: PUBLIC HTStream * HTBlackHole NOARGS
                    113: {
                    114:     if (TRACE)
                    115:        fprintf(TDEST, "BlackHole... Created\n");
                    116:     HTBlackHoleInstance.isa = &HTBlackHoleClass;       /* The rest is random */
                    117:     return &HTBlackHoleInstance;
                    118: }
                    119: 
                    120: 
                    121: /*     HTThroughLine
                    122: **     -------------
2.1       frystyk   123: **
2.3       frystyk   124: ** This function is a dummy function that returns the same output stream
                    125: ** as given as a parameter. Henrik 01/03-94
2.1       frystyk   126: */
2.3       frystyk   127: PUBLIC HTStream* HTThroughLine ARGS5(
                    128:        HTRequest *,            request,
                    129:        void *,                 param,
                    130:        HTFormat,               input_format,
                    131:        HTFormat,               output_format,
                    132:        HTStream *,             output_stream)              /* Only one used */
                    133: {
                    134:     return output_stream;
                    135: }
2.1       frystyk   136: 
2.3       frystyk   137: /* ------------------------------------------------------------------------- */
                    138: /*                          SOCKET WRITER STREAM                            */
                    139: /* ------------------------------------------------------------------------- */
                    140: 
                    141: PRIVATE int HTFWriter_put_character ARGS2(HTStream *, me, char, c)
                    142: {
                    143:     return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
                    144: }
                    145: 
                    146: PRIVATE int HTFWriter_put_string ARGS2(HTStream *, me, CONST char*, s)
                    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.7       frystyk   153: PRIVATE int HTFWriter_flush ARGS1(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: 
                    159: PRIVATE int HTFWriter_write ARGS3(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: 
                    172: PRIVATE int HTFWriter_free ARGS1(HTStream *, me)
                    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: 
                    191: PRIVATE int HTFWriter_abort ARGS2(HTStream *, me, HTError, e)
                    192: {
                    193:     if (me->leave_open != YES) fclose(me->fp);
                    194:     if (me->end_command) {             /* Temp file */
                    195:        if (TRACE)
                    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: 
                    220: PUBLIC HTStream* HTFWriter_new ARGS2(FILE *, fp, BOOL, leave_open)
                    221: {
                    222:     HTStream* me;
                    223:     
                    224:     if (!fp) {
                    225:        if (TRACE)
                    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: */
                    250: PUBLIC BOOL HTTmp_setRoot ARGS1(CONST char *, tmp_root)
                    251: {
                    252:     StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
                    253:     if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
                    254:        StrAllocCat(HTTmpRoot, "/");
                    255:     if (TRACE)
                    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.3       frystyk   264: PUBLIC CONST char * HTTmp_getRoot NOARGS
                    265: {
                    266:     return HTTmpRoot;
                    267: }
2.1       frystyk   268: 
                    269: 
2.3       frystyk   270: /*     Free Tmp Root
                    271: **     --------------
                    272: **     For clean up memory
                    273: */
                    274: PUBLIC void HTTmp_freeRoot NOARGS
                    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: */
                    284: PRIVATE char *get_filename ARGS3(char *, base, CONST char *, url,
                    285:                                 CONST char *, suffix)
                    286: {
                    287:     char *path=NULL;
                    288:     char filename[40];
                    289:     int hash=0;
                    290: 
                    291:     /* Do this until we find a name that doesn't exist */
                    292:     while (1)
                    293:     {
                    294:        CONST char *ptr=url;
                    295:        for( ; *ptr; ptr++)
                    296:            hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
                    297: 
                    298: #ifndef NO_GETPID
                    299:        sprintf(filename, "%d-%d", hash, (int) getpid());
                    300: #else
                    301:        sprintf(filename, "%d-%d", hash, time(NULL));
                    302: #endif
                    303:        StrAllocCopy(path, base);
                    304:        StrAllocCat(path, filename);
                    305:        if (suffix) StrAllocCat(path, suffix);
                    306: 
                    307:        {
                    308:            FILE *fp = fopen(path, "r");
                    309:            if (fp)                          /* This file does already exist */
                    310:                fclose(fp);
                    311:            else
                    312:                break;                                  /* Got the file name */
                    313:        }
                    314:     }
                    315:     return path;
                    316: }
                    317: 
                    318: 
2.1       frystyk   319: /*     Take action using a system command
                    320: **     ----------------------------------
                    321: **
                    322: **     Creates temporary file, writes to it, executes system command
                    323: **     on end-document.  The suffix of the temp file can be given
                    324: **     in case the application is fussy, or so that a generic opener can
                    325: **     be used.
                    326: */
                    327: PUBLIC HTStream* HTSaveAndExecute ARGS5(
                    328:        HTRequest *,            request,
                    329:        void *,                 param,
                    330:        HTFormat,               input_format,
                    331:        HTFormat,               output_format,
                    332:        HTStream *,             output_stream)
                    333: {
                    334:     char *fnam;
                    335:     HTStream* me;
                    336:     
                    337:     if (HTSecure) {
2.11      frystyk   338:         HTAlert(request, "Can't save data to file -- please run WWW locally");
2.1       frystyk   339:        return HTBlackHole();
                    340:     }
                    341:     
2.3       frystyk   342:     if (!HTTmpRoot) {
2.1       frystyk   343:        if (TRACE) fprintf(TDEST, "Save and execute turned off");
                    344:        return HTBlackHole();
                    345:     }
                    346:        
2.4       frystyk   347:     /* Let's find a hash name for this file */
                    348:     {
2.13    ! frystyk   349:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
        !           350:        char *suffix = HTBind_getSuffix(anchor);
        !           351:        fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.5       frystyk   352:        FREE(suffix);
2.4       frystyk   353:        if (!fnam) {
2.11      frystyk   354:            HTAlert(request, "Can't find a suitable file name");
2.4       frystyk   355:            return HTBlackHole();
                    356:        }
                    357:     }
                    358: 
2.1       frystyk   359:     me = (HTStream*)calloc(sizeof(*me), 1);
                    360:     if (me == NULL) outofmem(__FILE__, "Save and execute");
                    361:     me->isa = &HTFWriter;  
                    362:     me->request = request;     /* won't be freed */    
2.12      frystyk   363:     me->fp = fopen (fnam, "wb");
2.1       frystyk   364:     if (!me->fp) {
2.11      frystyk   365:        HTAlert(request, "Can't open temporary file!");
2.1       frystyk   366:         free(fnam);
                    367:        free(me);
2.4       frystyk   368:        return HTBlackHole();
2.1       frystyk   369:     }
                    370:     StrAllocCopy(me->filename, fnam);
                    371: 
2.4       frystyk   372:     /* Make command to process file */
2.1       frystyk   373:     me->end_command = (char *) malloc ((strlen((char *) param) + 10 +
                    374:                                        3*strlen(fnam)) * sizeof (char));
                    375:     if (me == NULL) outofmem(__FILE__, "SaveAndExecute");
                    376:     
                    377:     sprintf (me->end_command, (char *) param, fnam, fnam, fnam);
                    378:     me->remove_on_close = NO;
                    379:     me->announce = NO;
                    380:     free (fnam);
                    381:     return me;
                    382: }
                    383: 
                    384: 
                    385: /*     Save Locally
                    386: **     ------------
                    387: **
                    388: **  Bugs:
                    389: **     GUI Apps should open local Save panel here really.
                    390: **
                    391: */
                    392: PUBLIC HTStream* HTSaveLocally ARGS5(
                    393:        HTRequest *,            request,
                    394:        void *,                 param,
                    395:        HTFormat,               input_format,
                    396:        HTFormat,               output_format,
                    397:        HTStream *,             output_stream)  /* Not used */
                    398: 
                    399: {
                    400:     char *fnam = NULL;
                    401:     char *answer = NULL;
                    402:     HTStream* me;
                    403:     
2.8       frystyk   404:     if (HTSecure) {
2.11      frystyk   405:         HTAlert(request, "Can't save data to file -- please run WWW locally");
2.1       frystyk   406:        return HTBlackHole();
                    407:     }
                    408: 
2.3       frystyk   409:     if (!HTTmpRoot) {
2.1       frystyk   410:        if (TRACE) fprintf(TDEST, "Save locally turned off");
                    411:        return HTBlackHole();
                    412:     }
                    413:        
2.4       frystyk   414:     /* Let's find a file name for this file */
                    415:     {
2.13    ! frystyk   416:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
        !           417:        char *suffix = HTBind_getSuffix(anchor);
        !           418:        fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.11      frystyk   419:        answer = HTPrompt(request, "Give name of file to save in",
                    420:                          fnam ? fnam : "");
2.4       frystyk   421:        if (!answer) {
                    422:            FREE(fnam);
                    423:            return HTBlackHole();
                    424:        }
2.5       frystyk   425:        FREE(suffix);
2.4       frystyk   426:        FREE(fnam);
                    427:     }
                    428:     
2.1       frystyk   429:     me = (HTStream*)calloc(sizeof(*me),1);
                    430:     if (me == NULL) outofmem(__FILE__, "SaveLocally");
                    431:     me->isa = &HTFWriter;  
                    432:     me->announce = YES;
                    433:     
2.12      frystyk   434:     me->fp = fopen (answer, "wb");
2.1       frystyk   435:     if (!me->fp) {
2.11      frystyk   436:        HTAlert(request, "Can't open local file to write into.");
2.1       frystyk   437:         FREE(answer);
                    438:        free(me);
2.4       frystyk   439:        return HTBlackHole();
2.1       frystyk   440:     }
                    441:     me->callback = NULL;
                    442:     me->request = request;     /* won't be freed */
                    443:     me->filename = answer;     /* Will be freed */
                    444:     return me;
                    445: }
                    446: 
                    447: 
                    448: /*     Save and Call Back
                    449: **     ------------------
                    450: **
                    451: **
                    452: **     The special case is a kludge. Better is everything uses streams
                    453: **     and nothing uses files.  Then this routine will go too. :-))
                    454: */
                    455: PUBLIC HTStream* HTSaveAndCallBack ARGS5(
                    456:        HTRequest *,            request,
                    457:        void *,                 param,
                    458:        HTFormat,               input_format,
                    459:        HTFormat,               output_format,
                    460:        HTStream *,             output_stream)
                    461: {
                    462:    HTStream * me;
                    463:    
2.10      frystyk   464: #if 0
2.1       frystyk   465:    if (request->using_cache) {  /* Special case! file wanted && cache hit */
                    466:         (*request->callback)(request,
2.13    ! frystyk   467:                         ((HTCache*) request->using_cache)->filename);
2.3       frystyk   468:        return HTBlackHole();
2.1       frystyk   469:    } else {
                    470:        me = HTCacheWriter(request, param,
                    471:                            input_format, output_format, output_stream);
                    472:        if (me) {
                    473:            me->callback = request->callback;
                    474:        }
                    475:    }
2.10      frystyk   476: #endif
2.1       frystyk   477:    return me;   
                    478: }
                    479: 

Webmaster