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

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.
2.31    ! frystyk     6: **     @(#) $Id: Date Author State $
2.1       frystyk     7: **
                      8: **     This version of the stream object just writes to a C file.
                      9: **     The file is assumed open and left open.
                     10: **
                     11: **     Bugs:
                     12: **             strings written must be less than buffer size.
                     13: **
                     14: **      History:
                     15: **         HFN: wrote it
                     16: **         HWL: converted the caching scheme to be hierachical by taking
                     17: **              AL code from Deamon
2.10      frystyk    18: **        HFN: moved cache code to HTCache module
2.1       frystyk    19: **
                     20: */
                     21: 
                     22: /* Library include files */
2.28      frystyk    23: #include "sysdep.h"
2.1       frystyk    24: #include "HTUtils.h"
                     25: #include "HTString.h"
                     26: #include "HTFormat.h"
2.21      frystyk    27: #include "HTError.h"
2.1       frystyk    28: #include "HTAlert.h"
2.19      frystyk    29: #include "HTAccess.h"
2.4       frystyk    30: #include "HTBind.h"
2.1       frystyk    31: #include "HTList.h"
2.3       frystyk    32: #include "HTParse.h"
2.15      frystyk    33: #include "HTReq.h"
2.3       frystyk    34: #include "HTFWrite.h"                                   /* Implemented here */
2.1       frystyk    35: 
2.4       frystyk    36: #define HASH_SIZE 1001         /* Tunable */
                     37: 
2.13      frystyk    38: /* The default directory for "save locally" and "save and execute" files: */
                     39: #ifndef HT_TMP_ROOT
                     40: #define HT_TMP_ROOT            "/tmp"
                     41: #endif
                     42: 
2.3       frystyk    43: struct _HTStream {
2.28      frystyk    44:     const HTStreamClass *isa;
2.24      frystyk    45:     
                     46:     FILE *             fp;
2.31    ! frystyk    47:     BOOL               leave_open;                 /* Close file when free? */
2.24      frystyk    48:     char *             end_command;                   /* Command to execute */
                     49:     BOOL               remove_on_close;                     /* Remove file? */
                     50:     char *             filename;                            /* Name of file */
                     51:     HTRequest *                request;                       /* saved for callback */
                     52:     HTRequestCallback *        callback;
2.3       frystyk    53: };
2.1       frystyk    54: 
2.3       frystyk    55: PRIVATE char *         HTTmpRoot = NULL;              /* Dest for tmp files */
2.1       frystyk    56: 
2.3       frystyk    57: /* ------------------------------------------------------------------------- */
2.1       frystyk    58: 
2.16      frystyk    59: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3       frystyk    60: {
                     61:     return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
                     62: }
                     63: 
2.28      frystyk    64: PRIVATE int HTFWriter_put_string (HTStream * me, const char* s)
2.3       frystyk    65: {
                     66:     if (*s)                                         /* For vms :-( 10/04-94 */
                     67:        return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
                     68:     return HT_OK;
                     69: }
                     70: 
2.16      frystyk    71: PRIVATE int HTFWriter_flush (HTStream * me)
2.3       frystyk    72: {
2.7       frystyk    73:     return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3       frystyk    74: }
                     75: 
2.28      frystyk    76: PRIVATE int HTFWriter_write (HTStream * me, const char* s, int l)
2.3       frystyk    77: {
2.7       frystyk    78:     int status ;
                     79:     status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
2.24      frystyk    80:     if (l > 1 && status == HT_OK) (void) HTFWriter_flush(me);
2.7       frystyk    81:     return status ;
2.3       frystyk    82: }
2.7       frystyk    83: 
2.30      frystyk    84: PRIVATE int HTFWriter_free (HTStream * me)
2.3       frystyk    85: {
2.24      frystyk    86:     if (me) {
                     87:        if (me->leave_open != YES) fclose(me->fp);
2.28      frystyk    88: #ifdef HAVE_SYSTEM
2.24      frystyk    89:        if (me->end_command) system(me->end_command);    /* SECURITY HOLE!!! */
2.17      frystyk    90: #endif
2.24      frystyk    91:        if (me->remove_on_close) REMOVE(me->filename);
                     92:        if (me->callback) (*me->callback)(me->request, me->filename);
2.26      frystyk    93:        HT_FREE(me->end_command);
                     94:        HT_FREE(me->filename);
                     95:        HT_FREE(me);
2.3       frystyk    96:     }
                     97:     return HT_OK;
                     98: }
                     99: 
2.18      frystyk   100: PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
2.3       frystyk   101: {
2.27      eric      102:     if (STREAM_TRACE) HTTrace("FileWriter.. ABORTING...\n");
2.24      frystyk   103:     if (me) {
                    104:        if (me->leave_open != YES) fclose(me->fp);
                    105:        if (me->remove_on_close) REMOVE(me->filename);
2.26      frystyk   106:        HT_FREE(me->end_command);
                    107:        HT_FREE(me->filename);
                    108:        HT_FREE(me);
2.3       frystyk   109:     }
                    110:     return HT_ERROR;
                    111: }
                    112: 
2.28      frystyk   113: PRIVATE const HTStreamClass HTFWriter = /* As opposed to print etc */
2.3       frystyk   114: {              
                    115:     "FileWriter",
                    116:     HTFWriter_flush,
2.30      frystyk   117:     HTFWriter_free,
2.3       frystyk   118:     HTFWriter_abort,
                    119:     HTFWriter_put_character,
                    120:     HTFWriter_put_string,
                    121:     HTFWriter_write
                    122: };
                    123: 
2.24      frystyk   124: PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
                    125:                                 BOOL leave_open)
2.3       frystyk   126: {
2.24      frystyk   127:     HTStream * me = NULL;
2.3       frystyk   128:     if (!fp) {
2.27      eric      129:        if (STREAM_TRACE)HTTrace("FileWriter.. Bad file descriptor\n");
2.24      frystyk   130:        return HTErrorStream();
2.3       frystyk   131:     }
2.26      frystyk   132:     if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    133:         HT_OUTOFMEM("HTFWriter_new");
2.3       frystyk   134:     me->isa = &HTFWriter;       
                    135:     me->fp = fp;
2.24      frystyk   136:     me->leave_open = leave_open;
                    137:     me->request = request;
2.3       frystyk   138:     return me;
                    139: }
                    140: 
                    141: /* ------------------------------------------------------------------------- */
                    142: /*                          FILE WRITER ROUTINES                            */
                    143: /* ------------------------------------------------------------------------- */
                    144: 
                    145: /*     Set TMP Root
                    146: **     --------------
                    147: **     If `tmp_root' is NULL use the current value (might be a define)
                    148: */
2.28      frystyk   149: PUBLIC BOOL HTTmp_setRoot (const char * tmp_root)
2.3       frystyk   150: {
                    151:     StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
                    152:     if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
                    153:        StrAllocCat(HTTmpRoot, "/");
2.14      frystyk   154:     if (STREAM_TRACE)
2.27      eric      155:        HTTrace("Tmp Root.... Root set to `%s\'\n", HTTmpRoot);
2.3       frystyk   156:     return YES;
                    157: }
                    158: 
                    159: 
                    160: /*     Get Tmp Root
                    161: **     --------------
2.1       frystyk   162: */
2.28      frystyk   163: PUBLIC const char * HTTmp_getRoot (void)
2.3       frystyk   164: {
                    165:     return HTTmpRoot;
                    166: }
2.1       frystyk   167: 
                    168: 
2.3       frystyk   169: /*     Free Tmp Root
                    170: **     --------------
                    171: **     For clean up memory
                    172: */
2.29      eric      173: PUBLIC void HTTmp_freeRoot (void)
2.3       frystyk   174: {
2.26      frystyk   175:     HT_FREE(HTTmpRoot);
2.3       frystyk   176: }
2.1       frystyk   177: 
2.4       frystyk   178: /*
                    179: **   This function tries really hard to find a non-existent filename relative
2.31    ! frystyk   180: **   to the path given. Returns a string that must be freed by the caller or
2.4       frystyk   181: **   NULL on error. The base must be '/' terminated which!
                    182: */
2.28      frystyk   183: PRIVATE char *get_filename (char * base, const char * url, const char * suffix)
2.4       frystyk   184: {
                    185:     char *path=NULL;
                    186:     char filename[40];
                    187:     int hash=0;
                    188: 
                    189:     /* Do this until we find a name that doesn't exist */
                    190:     while (1)
                    191:     {
2.28      frystyk   192:        const char *ptr=url;
2.4       frystyk   193:        for( ; *ptr; ptr++)
                    194:            hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
                    195: 
2.28      frystyk   196: #ifdef HAVE_GETPID
2.4       frystyk   197:        sprintf(filename, "%d-%d", hash, (int) getpid());
                    198: #else
                    199:        sprintf(filename, "%d-%d", hash, time(NULL));
                    200: #endif
                    201:        StrAllocCopy(path, base);
                    202:        StrAllocCat(path, filename);
                    203:        if (suffix) StrAllocCat(path, suffix);
                    204: 
                    205:        {
                    206:            FILE *fp = fopen(path, "r");
                    207:            if (fp)                          /* This file does already exist */
                    208:                fclose(fp);
                    209:            else
                    210:                break;                                  /* Got the file name */
                    211:        }
                    212:     }
                    213:     return path;
                    214: }
                    215: 
                    216: 
2.24      frystyk   217: /*     Save Locally
                    218: **     ------------
                    219: **     Saves a file to local disk. This can for example be used to dump
                    220: **     date objects of unknown media types to local disk. The stream prompts
                    221: **     for a file name for the temporary file.
2.1       frystyk   222: */
2.24      frystyk   223: PUBLIC HTStream* HTSaveLocally (HTRequest *    request,
                    224:                                void *          param,
                    225:                                HTFormat        input_format,
                    226:                                HTFormat        output_format,
                    227:                                HTStream *      output_stream)
2.1       frystyk   228: {
2.24      frystyk   229:     FILE * fp = NULL;
                    230:     char * filename = NULL;
2.19      frystyk   231:     if (HTLib_secure()) {
2.21      frystyk   232:        HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
2.24      frystyk   233:                           NULL, 0, "HTSaveLocally");
                    234:        return HTErrorStream();
2.1       frystyk   235:     }
2.3       frystyk   236:     if (!HTTmpRoot) {
2.27      eric      237:        if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24      frystyk   238:        return HTErrorStream();
2.1       frystyk   239:     }
                    240:        
2.24      frystyk   241:     /* Let's prompt the user for a file name for this file */
2.4       frystyk   242:     {
2.24      frystyk   243:        HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
2.13      frystyk   244:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    245:        char *suffix = HTBind_getSuffix(anchor);
2.24      frystyk   246:        char *deflt = get_filename(HTTmpRoot,HTAnchor_physical(anchor),suffix);
                    247:        if (cbf) {
                    248:            HTAlertPar * reply = HTAlert_newReply();
                    249:            if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
                    250:                filename = HTAlert_replyMessage(reply);
                    251:            HTAlert_deleteReply(reply);
                    252:        }
2.26      frystyk   253:        HT_FREE(suffix);
                    254:        HT_FREE(deflt);
2.24      frystyk   255:        if (filename) {
                    256:            if ((fp = fopen(filename, "wb")) == NULL) {
                    257:                HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
                    258:                                   filename, strlen(filename),"HTSaveLocally");
2.26      frystyk   259:                HT_FREE(filename);
2.24      frystyk   260:                return HTErrorStream();
                    261:            }
                    262:        } else {
2.27      eric      263:            if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24      frystyk   264:            return HTErrorStream();
2.4       frystyk   265:        }
                    266:     }
2.24      frystyk   267:     
                    268:     /* Now we are ready for creating the file writer stream */
                    269:     if (fp) {
                    270:        HTStream * me = HTFWriter_new(request, fp, NO);
                    271:        me->filename = filename;
                    272:        return me;
2.1       frystyk   273:     }
2.26      frystyk   274:     HT_FREE(filename);
2.24      frystyk   275:     return HTErrorStream();
2.1       frystyk   276: }
                    277: 
                    278: 
2.24      frystyk   279: /*     Take action using a system command
                    280: **     ----------------------------------
                    281: **     Creates temporary file, writes to it and then executes system
                    282: **     command (maybe an external viewer) when EOF has been reached. The
                    283: **     stream finds a suitable name of the temporary file which preserves the
                    284: **     suffix. This way, the system command can find out the file type from
                    285: **     the name of the temporary file name.
2.1       frystyk   286: */
2.24      frystyk   287: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
                    288:                                   void *       param,
                    289:                                   HTFormat     input_format,
                    290:                                   HTFormat     output_format,
                    291:                                   HTStream *   output_stream)
2.1       frystyk   292: {
2.24      frystyk   293:     FILE * fp = NULL;
                    294:     char * filename = NULL;
2.19      frystyk   295:     if (HTLib_secure()) {
2.21      frystyk   296:        HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
                    297:                           NULL, 0, "HTSaveLocally");
2.24      frystyk   298:        return HTErrorStream();
2.1       frystyk   299:     }
2.3       frystyk   300:     if (!HTTmpRoot) {
2.27      eric      301:        if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24      frystyk   302:        return HTErrorStream();
2.1       frystyk   303:     }
                    304:        
2.24      frystyk   305:     /* Let's find a hash name for this file without asking user */
2.4       frystyk   306:     {
2.13      frystyk   307:        HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
                    308:        char *suffix = HTBind_getSuffix(anchor);
2.24      frystyk   309:        filename = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.26      frystyk   310:        HT_FREE(suffix);
2.25      frystyk   311:        if (filename) {
                    312:            if ((fp = fopen(filename, "wb")) == NULL) {
                    313:                HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
                    314:                                   filename, strlen(filename),"HTSaveAndExecute");
2.26      frystyk   315:                HT_FREE(filename);
2.25      frystyk   316:                return HTErrorStream();
                    317:            }
                    318:        } else {
2.27      eric      319:            if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24      frystyk   320:            return HTErrorStream();
2.4       frystyk   321:        }
                    322:     }
                    323:     
2.24      frystyk   324:     /* Now we are ready for creating the file writer stream */
                    325:     if (fp) {
                    326:        HTStream * me = HTFWriter_new(request, fp, NO);
                    327:        me->filename = filename;
2.31    ! frystyk   328:        if (param) {
        !           329:            if ((me->end_command = (char  *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
        !           330:                HT_OUTOFMEM("SaveAndExecute");
        !           331:            sprintf (me->end_command,
        !           332:                     (char *)param, filename, filename, filename);
        !           333:        }
2.24      frystyk   334:        return me;
2.1       frystyk   335:     }
2.26      frystyk   336:     HT_FREE(filename);
2.24      frystyk   337:     return HTErrorStream();
2.1       frystyk   338: }
                    339: 
                    340: 
                    341: /*     Save and Call Back
                    342: **     ------------------
2.24      frystyk   343: **     This stream works exactly like the TSaveAndExecute
                    344: **     stream but in addition when EOF has been reached, it checks whether a
                    345: **     callback function has been associated with the request object in which
                    346: **     case, this callback is being called. This can be use by the
                    347: **     application to do some processing after the system command
                    348: **     has terminated. The callback function is called with the file name of
                    349: **     the temporary file as parameter.
2.1       frystyk   350: */
2.16      frystyk   351: PUBLIC HTStream* HTSaveAndCallback (HTRequest *                request,
                    352:                                    void *              param,
                    353:                                    HTFormat            input_format,
                    354:                                    HTFormat            output_format,
                    355:                                    HTStream *          output_stream)
2.1       frystyk   356: {
2.24      frystyk   357:     HTStream * me = HTSaveAndExecute(request, param, input_format,
                    358:                                     output_format, output_stream);
                    359:     if (me) {
                    360:        me->callback = HTRequest_callback(request);
                    361:        return me;
                    362:     }
                    363:     return HTErrorStream();
2.1       frystyk   364: }
                    365: 

Webmaster