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

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

Webmaster