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

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.17    ! frystyk   116:        TTYPrint(TDEST, "BlackHole... Created\n");
2.3       frystyk   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 */
2.17    ! frystyk   177: #ifdef GOT_SYSTEM
2.3       frystyk   178:        system(me->end_command);        /* @@ Beware of security hole */
2.17    ! frystyk   179: #endif
2.3       frystyk   180:        free (me->end_command);
                    181:        if (me->remove_on_close) {
2.9       frystyk   182:            REMOVE(me->filename);
2.3       frystyk   183:        }
                    184:     }
                    185:     if (me->callback) {
                    186:         (*me->callback)(me->request, me->filename);
                    187:     }
                    188:     if (me->filename) free(me->filename);
                    189:     free(me);
                    190:     return HT_OK;
                    191: }
                    192: 
2.16      frystyk   193: PRIVATE int HTFWriter_abort (HTStream * me, HTError e)
2.3       frystyk   194: {
                    195:     if (me->leave_open != YES) fclose(me->fp);
                    196:     if (me->end_command) {             /* Temp file */
2.14      frystyk   197:        if (STREAM_TRACE)
2.17    ! frystyk   198:            TTYPrint(TDEST,"FileWriter.. Aborting: file %s not executed.\n",
2.3       frystyk   199:                    me->filename ? me->filename : "???" );
                    200:        free (me->end_command);
                    201:        if (me->remove_on_close) {
2.9       frystyk   202:            REMOVE(me->filename);
2.3       frystyk   203:        }
                    204:     }
                    205: 
                    206:     if (me->filename) free(me->filename);
                    207:     free(me);
                    208:     return HT_ERROR;
                    209: }
                    210: 
                    211: PRIVATE CONST HTStreamClass HTFWriter = /* As opposed to print etc */
                    212: {              
                    213:     "FileWriter",
                    214:     HTFWriter_flush,
                    215:     HTFWriter_free,
                    216:     HTFWriter_abort,
                    217:     HTFWriter_put_character,
                    218:     HTFWriter_put_string,
                    219:     HTFWriter_write
                    220: };
                    221: 
2.16      frystyk   222: PUBLIC HTStream* HTFWriter_new (FILE * fp, BOOL leave_open)
2.3       frystyk   223: {
                    224:     HTStream* me;
                    225:     
                    226:     if (!fp) {
2.14      frystyk   227:        if (STREAM_TRACE)
2.17    ! frystyk   228:            TTYPrint(TDEST, "FileWriter.. Bad file descriptor\n");
2.3       frystyk   229:        return NULL;
                    230:     }
                    231:     me = (HTStream*)calloc(sizeof(*me),1);
                    232:     if (me == NULL) outofmem(__FILE__, "HTFWriter_new");
                    233:     me->isa = &HTFWriter;       
                    234: 
                    235:     me->fp = fp;
                    236:     me->leave_open = leave_open;               /* HENRIK 08/02-94 */
                    237:     me->end_command = NULL;
                    238:     me->remove_on_close = NO;
                    239:     me->announce = NO;
                    240:     me->callback = NULL;
                    241:     return me;
                    242: }
                    243: 
                    244: /* ------------------------------------------------------------------------- */
                    245: /*                          FILE WRITER ROUTINES                            */
                    246: /* ------------------------------------------------------------------------- */
                    247: 
                    248: /*     Set TMP Root
                    249: **     --------------
                    250: **     If `tmp_root' is NULL use the current value (might be a define)
                    251: */
2.16      frystyk   252: PUBLIC BOOL HTTmp_setRoot (CONST char * tmp_root)
2.3       frystyk   253: {
                    254:     StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
                    255:     if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
                    256:        StrAllocCat(HTTmpRoot, "/");
2.14      frystyk   257:     if (STREAM_TRACE)
2.17    ! frystyk   258:        TTYPrint(TDEST, "Tmp Root.... Root set to `%s\'\n", HTTmpRoot);
2.3       frystyk   259:     return YES;
                    260: }
                    261: 
                    262: 
                    263: /*     Get Tmp Root
                    264: **     --------------
2.1       frystyk   265: */
2.16      frystyk   266: PUBLIC CONST char * HTTmp_getRoot (void)
2.3       frystyk   267: {
                    268:     return HTTmpRoot;
                    269: }
2.1       frystyk   270: 
                    271: 
2.3       frystyk   272: /*     Free Tmp Root
                    273: **     --------------
                    274: **     For clean up memory
                    275: */
2.16      frystyk   276: PUBLIC void HTTmp_freeRoot (void)
2.3       frystyk   277: {
                    278:     FREE(HTTmpRoot);
                    279: }
2.1       frystyk   280: 
2.4       frystyk   281: /*
                    282: **   This function tries really hard to find a non-existent filename relative
                    283: **   to the path given. Returns a string that must be freed by the caller or
                    284: **   NULL on error. The base must be '/' terminated which!
                    285: */
2.16      frystyk   286: PRIVATE char *get_filename (char * base, CONST char * url, CONST char * suffix)
2.4       frystyk   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: */
2.16      frystyk   328: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
                    329:                                   void *       param,
                    330:                                   HTFormat     input_format,
                    331:                                   HTFormat     output_format,
                    332:                                   HTStream *   output_stream)
2.1       frystyk   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.17    ! frystyk   343:        if (STREAM_TRACE) TTYPrint(TDEST, "Save and execute turned off");
2.1       frystyk   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: */
2.16      frystyk   392: PUBLIC HTStream* HTSaveLocally (HTRequest *    request,
                    393:                                void *          param,
                    394:                                HTFormat        input_format,
                    395:                                HTFormat        output_format,
                    396:                                HTStream *      output_stream)
2.1       frystyk   397: {
                    398:     char *fnam = NULL;
                    399:     char *answer = NULL;
                    400:     HTStream* me;
                    401:     
2.8       frystyk   402:     if (HTSecure) {
2.11      frystyk   403:         HTAlert(request, "Can't save data to file -- please run WWW locally");
2.1       frystyk   404:        return HTBlackHole();
                    405:     }
                    406: 
2.3       frystyk   407:     if (!HTTmpRoot) {
2.17    ! frystyk   408:        if (STREAM_TRACE) TTYPrint(TDEST, "Save locally turned off");
2.1       frystyk   409:        return HTBlackHole();
                    410:     }
                    411:        
2.4       frystyk   412:     /* Let's find a file name for this file */
                    413:     {
2.13      frystyk   414:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    415:        char *suffix = HTBind_getSuffix(anchor);
                    416:        fnam = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.11      frystyk   417:        answer = HTPrompt(request, "Give name of file to save in",
                    418:                          fnam ? fnam : "");
2.4       frystyk   419:        if (!answer) {
                    420:            FREE(fnam);
                    421:            return HTBlackHole();
                    422:        }
2.5       frystyk   423:        FREE(suffix);
2.4       frystyk   424:        FREE(fnam);
                    425:     }
                    426:     
2.1       frystyk   427:     me = (HTStream*)calloc(sizeof(*me),1);
                    428:     if (me == NULL) outofmem(__FILE__, "SaveLocally");
                    429:     me->isa = &HTFWriter;  
                    430:     me->announce = YES;
                    431:     
2.12      frystyk   432:     me->fp = fopen (answer, "wb");
2.1       frystyk   433:     if (!me->fp) {
2.11      frystyk   434:        HTAlert(request, "Can't open local file to write into.");
2.1       frystyk   435:         FREE(answer);
                    436:        free(me);
2.4       frystyk   437:        return HTBlackHole();
2.1       frystyk   438:     }
                    439:     me->callback = NULL;
                    440:     me->request = request;     /* won't be freed */
                    441:     me->filename = answer;     /* Will be freed */
                    442:     return me;
                    443: }
                    444: 
                    445: 
                    446: /*     Save and Call Back
                    447: **     ------------------
                    448: **
                    449: **
                    450: **     The special case is a kludge. Better is everything uses streams
                    451: **     and nothing uses files.  Then this routine will go too. :-))
                    452: */
2.16      frystyk   453: PUBLIC HTStream* HTSaveAndCallback (HTRequest *                request,
                    454:                                    void *              param,
                    455:                                    HTFormat            input_format,
                    456:                                    HTFormat            output_format,
                    457:                                    HTStream *          output_stream)
2.1       frystyk   458: {
                    459:    HTStream * me;
                    460:    
2.10      frystyk   461: #if 0
2.1       frystyk   462:    if (request->using_cache) {  /* Special case! file wanted && cache hit */
                    463:         (*request->callback)(request,
2.13      frystyk   464:                         ((HTCache*) request->using_cache)->filename);
2.3       frystyk   465:        return HTBlackHole();
2.1       frystyk   466:    } else {
                    467:        me = HTCacheWriter(request, param,
                    468:                            input_format, output_format, output_stream);
                    469:        if (me) {
                    470:            me->callback = request->callback;
                    471:        }
                    472:    }
2.10      frystyk   473: #endif
2.1       frystyk   474:    return me;   
                    475: }
                    476: 

Webmaster