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

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

Webmaster