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

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

Webmaster