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

2.1       frystyk     1: /*                                                                 HTFWrite.c
                      2: **     FILE WRITER
                      3: **
                      4: **     (c) COPYRIGHT CERN 1994.
                      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.2.2.3 ! cbrooks    17: **         WSM: added suffix argument to hierarchical caching
2.1       frystyk    18: */
                     19: 
                     20: /* Library include files */
                     21: #include "tcp.h"
                     22: #include "HTUtils.h"
                     23: #include "HTString.h"
                     24: #include "HTFormat.h"
                     25: #include "HTAlert.h"
                     26: #include "HTFile.h"
                     27: #include "HTList.h"
                     28: #include "HTFWrite.h"
                     29: 
                     30: #define CACHE_LIMIT 100                /* files */
                     31: 
                     32: #ifdef Mips
                     33: #define L_tmpnam 64
                     34: #endif
                     35: 
                     36: 
                     37: 
                     38: 
                     39: #include "HTParse.h"
                     40: 
                     41: #define CACHE_INFO     ".cache_info"
                     42: #define INDEX_FILE     ".cache_dirindex"
                     43: #define WELCOME_FILE   ".cache_welcome"
                     44: #define TMP_SUFFIX     ".cache_tmp"
                     45: #define LOCK_SUFFIX    ".cache_lock"
                     46: #define INFO_LINE_LEN  256
                     47: 
                     48: 
                     49: /************************************************************************
                     50: **
                     51: **     FILENAME GENERATION
                     52: **
                     53: **     Mapping between URLs and cache files
                     54: **
                     55: *************************************************************************
                     56: */
                     57: 
                     58: 
                     59: /*
                     60: **     Check that the name we're about to generate doesn't
                     61: **     clash with anything used by the caching system.
                     62: */
                     63: 
                     64: PRIVATE BOOL reserved_name ARGS1(char *, url)
                     65: {
                     66:     char * name = strrchr(url, '/');
                     67:     char * suff = NULL;
                     68: 
                     69:     if (name) name++;
                     70:     else name = url;
                     71: 
                     72:     if (!strcmp(name, CACHE_INFO) ||
                     73:        !strcmp(name, INDEX_FILE) ||
                     74:        !strcmp(name, WELCOME_FILE))
                     75:        return YES;
                     76: 
                     77:     suff = strrchr(name, TMP_SUFFIX[0]);
                     78:     if (suff && !strcmp(suff, TMP_SUFFIX))
                     79:        return YES;
                     80: 
                     81:     suff = strrchr(name, LOCK_SUFFIX[0]);
                     82:     if (suff && !strcmp(suff, LOCK_SUFFIX))
                     83:        return YES;
                     84: 
                     85:     return NO;
                     86: }
                     87: 
                     88: 
                     89: /*
                     90: **     Map url to cache file name.
                     91: */
2.2.2.3 ! cbrooks    92: /*
        !            93: **     WSM: Added suffix argument and code to replace suffix analagous to 
        !            94: **     non-hierarchical caching.
        !            95: */
        !            96: PRIVATE char * cache_file_name ARGS3(char *, base, 
        !            97:                                     char *, url, 
        !            98:                                     CONST char *, suffix)
2.1       frystyk    99: {
                    100:     char * access = NULL;
                    101:     char * host = NULL;
                    102:     char * path = NULL;
                    103:     char * cfn = NULL;
                    104:     BOOL welcome = NO;
                    105:     BOOL res = NO;
                    106: 
                    107:     if (!url ||  strchr(url, '?')  ||  (res = reserved_name(url))  ||
                    108:        !(access = HTParse(url, "", PARSE_ACCESS)) ||
                    109:        (0 != strcmp(access, "http") &&
                    110:         0 != strcmp(access, "ftp")  &&
                    111:         0 != strcmp(access, "gopher"))) {
                    112: 
                    113:        if (access) free(access);
                    114: 
                    115:        if (res && TRACE)
                    116:            fprintf(TDEST,
                    117:                    "Cache....... Clash with reserved name (\"%s\")\n",url);
                    118: 
                    119:        return NULL;
                    120:     }
                    121: 
                    122:     host = HTParse(url, "", PARSE_HOST);
                    123:     path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
                    124:     if (path && path[strlen(path)-1] == '/')
                    125:        welcome = YES;
                    126: 
2.2.2.3 ! cbrooks   127:     if ((suffix != NULL) && (!welcome)) { /* Strip old suffix if necessary */
        !           128:            char *ptr = strrchr(path, '.');
        !           129:            if (ptr != NULL) *ptr = '\0';
        !           130:        }
        !           131:        
        !           132:            
2.1       frystyk   133:     if (host) {                /* Canonilize host name */
                    134:        char * cur = host;
                    135:        while (*cur) {
                    136:            *cur = TOLOWER(*cur);
                    137:            cur++;
                    138:        }
                    139:     }
                    140: 
                    141:     cfn = (char*)malloc(strlen(base) +
                    142:                        strlen(access) +
                    143:                        (host ? strlen(host) : 0) +
                    144:                        (path ? strlen(path) : 0) +
2.2.2.3 ! cbrooks   145:                        (suffix ? strlen(suffix) : 0) +
2.1       frystyk   146:                        (welcome ? strlen(WELCOME_FILE) : 0) + 3);
                    147:     if (!cfn) outofmem(__FILE__, "cache_file_name");
2.2.2.3 ! cbrooks   148:    sprintf(cfn, "%s/%s/%s%s%s%s%s", base, access, host, path,
        !           149:           (welcome ? WELCOME_FILE : ""),
        !           150:           ((suffix && (*suffix != '.') ? "." : "")),
        !           151:           (suffix ? suffix : ""));
2.1       frystyk   152: 
                    153:     FREE(access); FREE(host); FREE(path);
                    154: 
                    155:     /*
                    156:     ** This checks that the last component is not too long.
                    157:     ** It could check all the components, but the last one
                    158:     ** is most important because it could later blow up the
                    159:     ** whole gc when reading cache info files.
                    160:     ** Operating system handles other cases.
                    161:     ** 64 = 42 + 22  and  22 = 42 - 20  :-)
                    162:     ** In other words I just picked some number, it doesn't
                    163:     ** really matter that much.
                    164:     */
                    165:     {
                    166:        char * last = strrchr(cfn, '/');
                    167:        if (!last) last = cfn;
                    168:        if ((int)strlen(last) > 64) {
                    169:            if (PROT_TRACE)
                    170:                fprintf(TDEST, "Too long.... cache file name \"%s\"\n", cfn);
                    171:            free(cfn);
                    172:            cfn = NULL;
                    173:        }
                    174:     }
                    175:     return cfn;
                    176: }
                    177: 
                    178: 
                    179: /*
                    180: **     Create directory path for cache file
                    181: **
                    182: ** On exit:
                    183: **     return YES
                    184: **             if directories created -- after that caller
                    185: **             can rely on fopen(cfn,"w") succeeding.
                    186: **
                    187: */
                    188: PRIVATE BOOL create_cache_place ARGS2(char *, base, char *, cfn)
                    189: {
                    190:     struct stat stat_info;
                    191:     char * cur = NULL;
                    192:     BOOL create = NO;
                    193: 
                    194:     if (!cfn  ||  (int)strlen(cfn) <= (int)strlen(base) + 1)
                    195:        return NO;
                    196: 
                    197:     cur = cfn + strlen(base) + 1;
                    198: 
                    199:     while ((cur = strchr(cur, '/'))) {
                    200:        *cur = 0;
                    201:        if (create || HTStat(cfn, &stat_info) == -1) {
                    202:            create = YES;       /* To avoid doing stat()s in vain */
                    203:            if (PROT_TRACE)
                    204:                fprintf(TDEST,"Cache....... creating cache dir \"%s\"\n",cfn);
2.2.2.3 ! cbrooks   205:                if (-1 == MKDIR(cfn, 0777)) {
2.1       frystyk   206:                if (PROT_TRACE)
2.2.2.3 ! cbrooks   207:                    fprintf(TDEST, "Cache....... can't create dir \"%s\"\n", cfn);
2.1       frystyk   208:                return NO;
                    209:            }
2.2.2.3 ! cbrooks   210:        }
        !           211:        else {
2.1       frystyk   212:            if (S_ISREG(stat_info.st_mode)) {
                    213:                int len = strlen(cfn);
                    214:                char * tmp1 = (char*)malloc(len + strlen(TMP_SUFFIX) + 1);
                    215:                char * tmp2 = (char*)malloc(len + strlen(INDEX_FILE) + 2);
                    216:                /* time_t t1,t2,t3,t4,t5; */
                    217: 
                    218: 
                    219:                sprintf(tmp1, "%s%s", cfn, TMP_SUFFIX);
                    220:                sprintf(tmp2, "%s/%s", cfn, INDEX_FILE);
                    221: 
                    222:                if (TRACE) {
                    223:                    fprintf(TDEST,"Cache....... moving \"%s\" to \"%s\"\n",
                    224:                            cfn,tmp1);
                    225:                    fprintf(TDEST,"and......... creating dir \"%s\"\n",
                    226:                            cfn);
                    227:                    fprintf(TDEST,"and......... moving \"%s\" to \"%s\"\n",
                    228:                            tmp1,tmp2);
                    229:                }
                    230:                rename(cfn,tmp1);
2.2.2.3 ! cbrooks   231:                (void)MKDIR(cfn, 0777) ;
2.1       frystyk   232:                rename(tmp1,tmp2);
                    233: 
                    234: /*             if (HTCacheInfo_for(cfn,&t1,&t2,&t3,&t4,&t5)) {
                    235:                    if (PROT_TRACE)
                    236:                       fprintf(TDEST,"Adding...... info entry for %s\n",tmp2);
                    237:                    if (!HTCacheInfo_writeEntryFor(tmp2,t1,t2,t3,t4,t5))
                    238:                        HTLog_error2("Can't write cache info entry for",tmp2);
                    239:                }
                    240: */
                    241:                free(tmp1);
                    242:                free(tmp2);
                    243:            }
                    244:            else {
                    245:                if (PROT_TRACE)
                    246:                    fprintf(TDEST,"Cache....... dir \"%s\" already exists\n",
                    247:                            cfn);
                    248:            }
                    249:        }
                    250:        *cur = '/';
                    251:        cur++;
                    252:     }
                    253:     return YES;
                    254: }
                    255: 
                    256: 
                    257: 
                    258: 
                    259: 
                    260: 
                    261: 
                    262: 
                    263: 
                    264: 
                    265: 
                    266: 
                    267: 
                    268: 
                    269: 
                    270: /*             Stream Object
                    271: **             ------------
                    272: */
                    273: 
                    274: struct _HTStream {
                    275:        CONST HTStreamClass *   isa;
                    276:        
                    277:        FILE *                  fp;
                    278:        BOOL                    leave_open;     /* Close file? HFN 08/02-94 */
                    279:        char *                  end_command;
                    280:        BOOL                    remove_on_close;
                    281:        BOOL                    announce;
                    282:        char *                  filename;
                    283:        HTRequest *             request;        /* saved for callback */
                    284:        BOOL (*callback) PARAMS((struct _HTRequest * req, void * filename));
                    285:        HTCacheItem *           cache;
                    286: };
                    287: 
                    288: 
                    289: /* ------------------------------------------------------------------------- */
                    290: /*                          BASIC STREAM CLASSES                            */
                    291: /* ------------------------------------------------------------------------- */
                    292: 
                    293: /*
                    294: **
                    295: **             B L A C K    H O L E    C L A S S
                    296: **
                    297: **     There is only one black hole instance shared by anyone
                    298: **     who wants a black hole.  These black holes don't radiate,
                    299: **     they just absorb data.
                    300: */
                    301: PRIVATE void HTBlackHole_put_character ARGS2(HTStream *, me, char, c)
                    302: {
                    303:     return;
                    304: }
                    305: 
                    306: PRIVATE void HTBlackHole_put_string ARGS2(HTStream *, me, CONST char*, s)
                    307: {
                    308:     return;
                    309: }
                    310: 
                    311: PRIVATE void HTBlackHole_write ARGS3(HTStream *, me, CONST char*, s, int, l)
                    312: {
                    313:     return;
                    314: }
                    315: 
                    316: PRIVATE int HTBlackHole_free ARGS1(HTStream *, me)
                    317: {
                    318:     return 0;
                    319: }
                    320: 
                    321: PRIVATE int HTBlackHole_abort ARGS2(HTStream *, me, HTError, e)
                    322: {
                    323:     return EOF;
                    324: }
                    325: 
                    326: 
                    327: /*     Black Hole stream
                    328: **     -----------------
                    329: */
                    330: PRIVATE CONST HTStreamClass HTBlackHoleClass =
                    331: {              
                    332:        "BlackHole",
                    333:        HTBlackHole_free,
                    334:        HTBlackHole_abort,
                    335:        HTBlackHole_put_character,      HTBlackHole_put_string,
                    336:        HTBlackHole_write
                    337: }; 
                    338: 
                    339: PRIVATE HTStream HTBlackHoleInstance =
                    340: {
                    341:        &HTBlackHoleClass,
                    342: 
                    343:        NULL,
                    344:        NO,                             /* HENRIK 08/02-94 */
                    345:        NULL,
                    346:        NO,
                    347:        NO,
                    348:        NULL,
                    349:        NULL,
                    350:        NULL,
                    351:        NULL,
                    352: };
                    353: 
                    354: /* Black hole creation */
                    355: PUBLIC HTStream * HTBlackHole NOARGS
                    356: {
                    357:     if (TRACE)
                    358:        fprintf(TDEST, "BlackHole... Created\n");
                    359:     return &HTBlackHoleInstance;
                    360: }
                    361: 
                    362: 
                    363: /*     HTThroughLine
                    364: **     -------------
                    365: **
                    366: ** This function is a dummy function that returns the same output stream
                    367: ** as given as a parameter. Henrik 01/03-94
                    368: */
                    369: PUBLIC HTStream* HTThroughLine ARGS5(
                    370:        HTRequest *,            request,
                    371:        void *,                 param,
                    372:        HTFormat,               input_format,
                    373:        HTFormat,               output_format,
                    374:        HTStream *,             output_stream)              /* Only one used */
                    375: {
                    376:     return output_stream;
                    377: }
                    378: 
                    379: 
                    380: 
                    381: /*_________________________________________________________________________
                    382: **
                    383: **             F I L E     A C T I O N         R O U T I N E S
                    384: **  Bug:
                    385: **     All errors are ignored.
                    386: */
                    387: 
                    388: 
                    389: 
                    390: 
                    391: /* -------------------------------------------------------------------------
                    392:    This function tries really hard to find a non-existent filename relative
                    393:    to the path given.
                    394:        path:   path of directory in which to put temp file
                    395:        url:    used for a similar name or generating a hash within 'limit'
                    396:        suffix: if != 0, this suffix is used, else no suffix
                    397:        limit:  if 0 => use last part of url
                    398:                        if >0 generate hash. Max value
                    399:                       of limit is max(unsigned int).
                    400:    Returns NULL if no filename could be found.
                    401:    Henrik 10/03-94
                    402:    ------------------------------------------------------------------------- */
                    403: PUBLIC char *HTFWriter_filename ARGS5(char *, path, char *, url,
                    404:                                      CONST char *, suffix,
                    405:                                      unsigned int, limit,
                    406:                                      BOOL, flat)
                    407: {
                    408: #define HASHTRY 5                         /* Keep this less than 10, please */
                    409:     static int primes[HASHTRY] = {31, 37, 41, 43, 47};       /* Some primes */
                    410:     char *urlfile = strrchr(url, '/');
                    411:     char *filename = NULL;
                    412: 
                    413:     /* HWL 22/9/94 */
                    414:     /* HWL added support for hierachical structure */
2.2.2.3 ! cbrooks   415:     /* WSM 14/4/94 */
        !           416:     /* WSM added suffix argument to cache_file_name */
2.1       frystyk   417:     if (!flat) {
2.2.2.3 ! cbrooks   418:        filename = cache_file_name(path, url, suffix);
2.1       frystyk   419:        if (!filename)
                    420:             return NULL;
                    421:        if (create_cache_place(path, filename))
                    422:             return(filename);
                    423:        else
                    424:             return NULL;
                    425:     }
                    426: 
                    427:     StrAllocCopy(filename, path);
                    428:     if (filename && urlfile++) {                  /* We don't want two '/'s */
                    429:        int digits = 1;
                    430:        unsigned hash;
                    431:        char *hashstr = NULL;
                    432:        char *replace = 0;
                    433:        char *ptr;                              /* Dummy used several places */
                    434:        char format[10];
                    435:        if (*(filename+strlen(filename)-1) != '/')  /* But one is OK, though */
                    436:            StrAllocCat(filename, "/");
                    437:        if (limit) {                                      /* Use hash method */
                    438:            unsigned int residue = limit;
                    439:            while ((residue /= 10))                 /* Find number of digits */
                    440:                digits++;
                    441:            if ((hashstr = (char *) malloc(digits+1)) == NULL)
                    442:                outofmem(__FILE__, "HTFWriter_filename");
                    443:            for(ptr=urlfile, hash=0; *ptr; ptr++)          /* Calculate hash */
                    444:                hash = *ptr + *primes * hash;
                    445:            hash %= limit;
                    446:            sprintf(format, "%%0%du", digits);     /* Convert hash to string */
                    447:            sprintf(hashstr, format, hash);
                    448:            *(hashstr+digits) = '\0';
                    449:            StrAllocCat(filename, hashstr);
                    450: #ifndef NO_GETPID
                    451: /* RISK: Race conditions may occur if this is not added to the filename */
                    452:            {
                    453:                char pidstr[10];
                    454:                sprintf(pidstr, "-%d", getpid());
                    455:                StrAllocCat(filename, pidstr);
                    456:            }
                    457: #endif
                    458:            if (suffix) {                                      /* Add suffix */
                    459:                if (*suffix != '.')
                    460:                    StrAllocCat(filename, ".");
                    461:                StrAllocCat(filename, suffix);
                    462:            }
                    463:            replace = strrchr(filename, '/')+1;    /* Remember place */
                    464:        } else {                                             /* Use url name */
                    465:            char *urlptr = 0;                        /* Strip off any suffix */
                    466:            StrAllocCopy(urlptr, urlfile);
                    467:            ptr = strrchr(urlptr, '.');
                    468:            if (ptr)
                    469:                *ptr = '\0';
                    470:            StrAllocCat(filename, urlptr);
                    471:            free(urlptr);
                    472:            if (suffix) {                           /* Add new suffix if any */
                    473:                if (*suffix != '.')
                    474:                    StrAllocCat(filename, ".");
                    475:                StrAllocCat(filename, suffix);
                    476:            }
                    477:        }
                    478:        {                                              /* Try if file exists */
                    479:            int cnt;
                    480:            FILE *fp;
                    481:            for (cnt=1; cnt<HASHTRY; cnt++) {
                    482:                if ((fp = fopen(filename, "r")) != NULL) {
                    483:                    fclose(fp);
                    484:                    if (limit) {          /* recalculate hash with new prime */
                    485:                        for(ptr=urlfile, hash=0; *ptr; ptr++)
                    486:                            hash = *ptr + *(primes+cnt) * hash;
                    487:                        hash %= limit;
                    488:                        sprintf(hashstr, format, hash);
                    489:                        *(hashstr+digits) = '\0';
                    490:                        memcpy(replace, hashstr, digits);
                    491:                    } else {            /* Add .n to the urlfile. n is a int */
                    492:                        if (cnt == 1) {
                    493:                            StrAllocCat(filename, ".1");
                    494:                            replace = filename+strlen(filename)-1;
                    495:                        } else
                    496:                            *replace = (char) cnt+0x30;   /* Works if cnt<10 */
                    497:                    }
                    498:                } else
                    499:                    break;                     /* File does not exist, so OK */
                    500:            }
                    501:            if (cnt >= HASHTRY) {          /* If no file name could be found */
                    502:                free(filename);
                    503:                filename = NULL;
                    504:            }
                    505:        }
                    506:        FREE(hashstr);
                    507:     }
                    508:     return filename;
                    509: }
                    510: 
                    511: 
                    512: 
                    513: /*     Character handling
                    514: **     ------------------
                    515: */
                    516: 
                    517: PRIVATE void HTFWriter_put_character ARGS2(HTStream *, me, char, c)
                    518: {
                    519:     fputc(c, me->fp);
                    520: }
                    521: 
                    522: 
                    523: 
                    524: /*     String handling
                    525: **     ---------------
                    526: **
                    527: **     Strings must be smaller than this buffer size.
                    528: */
                    529: PRIVATE void HTFWriter_put_string ARGS2(HTStream *, me, CONST char*, s)
                    530: {
                    531:     if (*s)                                         /* For vms :-( 10/04-94 */
                    532:        fputs(s, me->fp);
                    533: }
                    534: 
                    535: 
                    536: /*     Buffer write.  Buffers can (and should!) be big.
                    537: **     ------------
                    538: */
                    539: PRIVATE void HTFWriter_write ARGS3(HTStream *, me, CONST char*, s, int, l)
                    540: {
                    541:     fwrite(s, 1, l, me->fp);
                    542: }
                    543: 
                    544: 
                    545: 
                    546: 
                    547: /*     Free an HTML object
                    548: **     -------------------
                    549: **
                    550: **     Note that the SGML parsing context is freed, but the created
                    551: **     object is not,
                    552: **     as it takes on an existence of its own unless explicitly freed.
                    553: */
                    554: PRIVATE int HTFWriter_free ARGS1(HTStream *, me)
                    555: {
                    556:     if (me->cache) {
                    557:         time_t finish_time;
                    558:        time(&finish_time);
                    559:        me->cache->load_delay = finish_time - me->cache->load_time;
                    560:        /* Actually, ought to use draft ANSI-C difftime() */
                    561:        /* But that I bet is more portable in real life  (@@?) */
                    562:     }
                    563: 
                    564:     if (me->leave_open != YES) fclose(me->fp);
                    565: 
                    566:     if (me->end_command) {             /* Temp file */
                    567:         HTProgress(me->end_command);   /* Tell user what's happening */
                    568:        system(me->end_command);        /* @@ Beware of security hole */
                    569:        free (me->end_command);
                    570:        if (me->remove_on_close) {
                    571:            unlink(me->filename);
                    572:        }
                    573:     }
                    574:     if (me->callback) {
                    575:         (*me->callback)(me->request, me->filename);
                    576:     }
                    577:     if (me->filename) free(me->filename);
                    578:     free(me);
                    579:     return 0;
                    580: }
                    581: 
                    582: /*     End writing
                    583: */
                    584: 
                    585: PRIVATE int HTFWriter_abort ARGS2(HTStream *, me, HTError, e)
                    586: {
                    587:     if (me->leave_open != YES) fclose(me->fp);
                    588:     if (me->end_command) {             /* Temp file */
                    589:        if (TRACE) fprintf(TDEST,
                    590:                "HTFWriter: Aborting: file %s not executed.\n",
                    591:                me->filename ? me->filename : "???" );
                    592:        free (me->end_command);
                    593:        if (me->remove_on_close) {
                    594:            unlink(me->filename);
                    595:        }
                    596:     }
                    597: 
                    598:     if (me->filename) free(me->filename);
                    599:     free(me);
                    600:     return EOF;
                    601: }
                    602: 
                    603: 
                    604: 
                    605: /*     Structured Object Class
                    606: **     -----------------------
                    607: */
                    608: PRIVATE CONST HTStreamClass HTFWriter = /* As opposed to print etc */
                    609: {              
                    610:        "FileWriter",
                    611:        HTFWriter_free,
                    612:        HTFWriter_abort,
                    613:        HTFWriter_put_character,        HTFWriter_put_string,
                    614:        HTFWriter_write
                    615: }; 
                    616: 
                    617: 
                    618: /*     Subclass-specific Methods
                    619: **     -------------------------
                    620: */
                    621: PUBLIC HTStream* HTFWriter_new ARGS2(FILE *, fp, BOOL, leave_open)
                    622: {
                    623:     HTStream* me;
                    624:     
                    625:     if (!fp) return NULL;
                    626: 
                    627:     me = (HTStream*)calloc(sizeof(*me),1);
                    628:     if (me == NULL) outofmem(__FILE__, "HTFWriter_new");
                    629:     me->isa = &HTFWriter;       
                    630: 
                    631:     me->fp = fp;
                    632:     me->leave_open = leave_open;               /* HENRIK 08/02-94 */
                    633:     me->end_command = NULL;
                    634:     me->remove_on_close = NO;
                    635:     me->announce = NO;
                    636:     me->callback = NULL;
                    637:     return me;
                    638: }
                    639: 
                    640: /*     Make system command from template
                    641: **     ---------------------------------
                    642: **
                    643: **     See mailcap spec for description of template.
                    644: */
                    645: /* @@ to be written.  sprintfs will do for now.  */
                    646: 
                    647: 
                    648: 
                    649: /*     Take action using a system command
                    650: **     ----------------------------------
                    651: **
                    652: **     Creates temporary file, writes to it, executes system command
                    653: **     on end-document.  The suffix of the temp file can be given
                    654: **     in case the application is fussy, or so that a generic opener can
                    655: **     be used.
                    656: */
                    657: PUBLIC HTStream* HTSaveAndExecute ARGS5(
                    658:        HTRequest *,            request,
                    659:        void *,                 param,
                    660:        HTFormat,               input_format,
                    661:        HTFormat,               output_format,
                    662:        HTStream *,             output_stream)
2.2.2.3 ! cbrooks   663: 
        !           664: #ifdef unix
        !           665: #define REMOVE_FILE unlink
        !           666: #endif
        !           667: #ifdef VMS
        !           668: #define REMOVE_FILE unlink             /* ok? */
        !           669: #endif
        !           670: #ifdef WIN32
        !           671: #define REMOVE_FILE remove 
        !           672: #endif
2.1       frystyk   673: 
                    674: #ifdef REMOVE_FILE
                    675: {
                    676:     char *fnam;
                    677:     
                    678:     HTStream* me;
                    679:     
                    680:     if (HTSecure) {
                    681:         HTAlert("Can't save data to file -- please run WWW locally");
                    682:        return HTBlackHole();
                    683:     }
                    684:     
                    685:     if (!HTSaveLocallyDir) {
                    686:        if (TRACE) fprintf(TDEST, "Save and execute turned off");
                    687:        return HTBlackHole();
                    688:     }
                    689:        
                    690:     me = (HTStream*)calloc(sizeof(*me),1);
                    691:     me = (HTStream*)calloc(sizeof(*me), 1);
                    692:     if (me == NULL) outofmem(__FILE__, "Save and execute");
                    693:     me->isa = &HTFWriter;  
                    694:     
                    695:     /* Let's find a hash name for this file */
                    696:     if ((fnam = HTFWriter_filename(HTSaveLocallyDir,
                    697:                                   HTAnchor_physical(request->anchor),
                    698:                                   HTFileSuffix(input_format),
                    699:                                   1000, YES)) == NULL) {
                    700:        HTAlert("Can't find a suitable file name");
                    701:        return NULL;
                    702:     }
                    703: 
                    704:     me->request = request;     /* won't be freed */    
                    705:     me->fp = fopen (fnam, "w");
                    706:     if (!me->fp) {
                    707:        HTAlert("Can't open temporary file!");
                    708:         free(fnam);
                    709:        free(me);
                    710:        return NULL;
                    711:     }
                    712:     StrAllocCopy(me->filename, fnam);
                    713: 
                    714: /*     Make command to process file
                    715: */
                    716:     me->end_command = (char *) malloc ((strlen((char *) param) + 10 +
                    717:                                        3*strlen(fnam)) * sizeof (char));
                    718:     if (me == NULL) outofmem(__FILE__, "SaveAndExecute");
                    719:     
                    720:     sprintf (me->end_command, (char *) param, fnam, fnam, fnam);
                    721: 
                    722:     me->remove_on_close = NO;
                    723: 
                    724:     me->announce = NO;
                    725:     free (fnam);
                    726:     return me;
                    727: }
                    728: 
                    729: #else  /* can't do remove */
                    730: { return NULL; }
                    731: #endif
                    732: 
                    733: 
                    734: /*     Save Locally
                    735: **     ------------
                    736: **
                    737: **  Bugs:
                    738: **     GUI Apps should open local Save panel here really.
                    739: **
                    740: */
                    741: PUBLIC HTStream* HTSaveLocally ARGS5(
                    742:        HTRequest *,            request,
                    743:        void *,                 param,
                    744:        HTFormat,               input_format,
                    745:        HTFormat,               output_format,
                    746:        HTStream *,             output_stream)  /* Not used */
                    747: 
                    748: {
                    749:     char *fnam = NULL;
                    750:     char *answer = NULL;
                    751:     HTStream* me;
                    752:     
                    753:     if (HTClientHost) {
                    754:         HTAlert("Can't save data to file -- please run WWW locally");
                    755:        return HTBlackHole();
                    756:     }
                    757: 
                    758:     if (!HTSaveLocallyDir) {
                    759:        if (TRACE) fprintf(TDEST, "Save locally turned off");
                    760:        return HTBlackHole();
                    761:     }
                    762:        
                    763:     me = (HTStream*)calloc(sizeof(*me),1);
                    764:     if (me == NULL) outofmem(__FILE__, "SaveLocally");
                    765:     me->isa = &HTFWriter;  
                    766:     me->announce = YES;
                    767:     
                    768:     /* Let's find a 'human' file name for this file */
                    769:     fnam = HTFWriter_filename(HTSaveLocallyDir,
                    770:                              HTAnchor_physical(request->anchor),
                    771:                              HTFileSuffix(input_format),
                    772:                              0, YES);
                    773:     
                    774:     /* Save Panel */
                    775:     answer = HTPrompt("Give name of file to save in", fnam ? fnam : "");
                    776:     FREE(fnam);
                    777:     
                    778:     me->fp = fopen (answer, "w");
                    779:     if (!me->fp) {
                    780:        HTAlert("Can't open local file to write into.");
                    781:         FREE(answer);
                    782:        free(me);
                    783:        return NULL;
                    784:     }
                    785:     me->callback = NULL;
                    786:     me->request = request;     /* won't be freed */
                    787:     me->filename = answer;     /* Will be freed */
                    788:     return me;
                    789: }
                    790: 
                    791: 
                    792: /*     Cache handling
                    793: **     --------------
                    794: */
                    795: 
                    796: PUBLIC HTList * HTCache = NULL;
                    797: PUBLIC int     HTCacheLimit = CACHE_LIMIT;
                    798: 
                    799: PRIVATE void HTCache_remove ARGS2(HTList *, list, HTCacheItem *, item)
                    800: {
                    801:     if (TRACE) fprintf(TDEST, "Cache: Removing %s\n", item->filename);
                    802:     HTList_removeObject(list, item);
                    803:     HTList_removeObject(item->anchor->cacheItems, item);
                    804:     unlink(item->filename);
                    805: 
                    806:     /* HWL 22/9/94: since we added a hierachical file structure, we should also clean up */
                    807:     {
                    808:        char * p;
                    809: 
                    810:        while ((p = strrchr(item->filename,'/')) && (p != NULL)){
                    811:            item->filename[p - item->filename] = 0; /* this will be freed in a sec */
                    812:            if (strcmp(item->filename, HTCacheDir) != 0) {
                    813:                if (TRACE) 
                    814:                    fprintf(TDEST,"rmdir %s\n", item->filename);
                    815:                rmdir(item->filename);         /* this will luckily fail if directory is not empty */
                    816:            }
                    817:        }
                    818:     }
                    819: 
                    820:     free(item->filename);
                    821:     free(item);
                    822: }
                    823: 
                    824: /* This can be called for the main list or an anchor's list
                    825: */
                    826: 
                    827: 
                    828: 
                    829: PUBLIC void HTCacheClear ARGS1(HTList *, list)
                    830: {
                    831:     HTCacheItem * item;
                    832:     while ((item = (HTCacheItem *) HTList_objectAt(list, 0)) != NULL) {
                    833:         HTCache_remove(list, item);
                    834:     }
                    835: }
                    836: 
                    837: 
                    838: /* -------------------------------------------------------------------------
                    839:    This function removes ALL cache files known to this session. The anchors
                    840:    ARE updated, but normally this function is for exiting purposes.
                    841:    Henrik 09/03-94
                    842:    ------------------------------------------------------------------------- */
                    843: PUBLIC void HTCacheDeleteAll NOARGS
                    844: {
                    845:     HTCacheItem * item;
                    846:     while ((item = (HTCacheItem *) HTList_objectAt(HTCache, 0)) != NULL) {
                    847:         HTCache_remove(HTCache, item);
                    848:     }
                    849: }
                    850: 
                    851: /*  Remove a file from the cache to prevent too many files from being cached
                    852: */
                    853: PRIVATE void limit_cache ARGS1(HTList * , list)
                    854: {
                    855:     HTList * cur = list;
                    856:     HTCacheItem * item;
                    857:     time_t best_delay = 0;   /* time_t in principle can be any arith type */
                    858:     HTCacheItem* best_item = NULL;
                    859: 
                    860:     if (HTList_count(list) < HTCacheLimit) return;   /* Limit not reached */
                    861: 
                    862:     while (NULL != (item = (HTCacheItem*)HTList_nextObject(cur))) {
                    863:         if (best_delay == 0  ||  item->load_delay < best_delay) {
                    864:             best_delay = item->load_delay;
                    865:             best_item = item;
                    866:         }
                    867:     }
                    868: 
                    869:     if (best_item) HTCache_remove(list, best_item);
                    870: }
                    871: 
                    872: /*     Cache Writer
                    873: **     ------------------
                    874: **
                    875: */
                    876: PUBLIC HTStream* HTCacheWriter ARGS5(
                    877:        HTRequest *,            request,
                    878:        void *,                 param,
                    879:        HTFormat,               input_format,
                    880:        HTFormat,               output_format,
                    881:        HTStream *,             output_stream)
                    882: 
                    883: {
                    884:     char *fnam;
                    885:     HTStream* me;
                    886: 
                    887:     if (HTClientHost) {
                    888:        if (TRACE) fprintf(TDEST, "Only caching if WWW is run locally.\n");
                    889:        return HTBlackHole();
                    890:     }
                    891:     me = (HTStream*)calloc(sizeof(*me),1);
                    892:     if (me == NULL) outofmem(__FILE__, "CacheWriter");
                    893:     me->isa = &HTFWriter;  
                    894:     me->end_command = NULL;
                    895:     me->remove_on_close = NO;  /* If needed, put into end_command */
                    896:     me->announce = NO;
                    897:     
                    898:     /* Save the file under a suitably suffixed name */
                    899:     fnam = HTFWriter_filename(HTCacheDir,
                    900:                              HTAnchor_physical(request->anchor),
                    901:                              HTFileSuffix(input_format),
                    902:                              0, NO);
                    903:     if (!fnam) {                         /* HWL 22/9/94 */
                    904:        free(me);
                    905:        return NULL;
                    906:     }
                    907: 
                    908:     me->filename = NULL;
                    909:     limit_cache(HTCache);               /* Limit number (not size) of files */
                    910:     me->fp = fopen (fnam, "w");
                    911:     if (!me->fp) {
                    912:        HTAlert("Can't open local file for writing.");
                    913:        if (TRACE) fprintf(TDEST, "HTStream: can't open %s for writing\n",fnam);
                    914:        free(fnam);
                    915:        free(me);
                    916:        return NULL;
                    917:     }
                    918:     
                    919:     /* Set up a cache record */
                    920:     
                    921:     if (TRACE) fprintf(TDEST, "Cache....... Creating file %s\n", fnam);
                    922:     me->cache = (HTCacheItem*)calloc(sizeof(*me->cache),1);
                    923:     if (!me->cache)outofmem(__FILE__, "cache");
                    924:     time(&me->cache->load_time);
                    925:     StrAllocCopy(me->cache->filename, fnam);
                    926:     me->cache->anchor = request->anchor;
                    927:     if (!request->anchor->cacheItems)
                    928:        request->anchor->cacheItems = HTList_new();
                    929:     HTList_addObject(request->anchor->cacheItems, me->cache);
                    930:     me->cache->format = input_format;
                    931:     
                    932:     if (!HTCache) HTCache = HTList_new();
                    933:     HTList_addObject(HTCache, me->cache);
                    934:     
                    935:     me->callback = request->callback;
                    936:     me->request = request;     /* won't be freed */
                    937:     me->filename = fnam;   /* will be freed */
                    938:     return me;
                    939: }
                    940: 
                    941: 
                    942: /*     Save and Call Back
                    943: **     ------------------
                    944: **
                    945: **
                    946: **     The special case is a kludge. Better is everything uses streams
                    947: **     and nothing uses files.  Then this routine will go too. :-))
                    948: */
                    949: 
                    950: 
                    951: PUBLIC HTStream* HTSaveAndCallBack ARGS5(
                    952:        HTRequest *,            request,
                    953:        void *,                 param,
                    954:        HTFormat,               input_format,
                    955:        HTFormat,               output_format,
                    956:        HTStream *,             output_stream)
                    957: {
                    958:    HTStream * me;
                    959:    
                    960:    if (request->using_cache) {  /* Special case! file wanted && cache hit */
                    961:         (*request->callback)(request,
                    962:                         ((HTCacheItem*)request->using_cache)->filename);
                    963:        return &HTBlackHoleInstance;    /* @@@@@@@@@@@@@@ */
                    964:    } else {
                    965:        me = HTCacheWriter(request, param,
                    966:                            input_format, output_format, output_stream);
                    967:        if (me) {
                    968:            me->callback = request->callback;
                    969:        }
                    970:    }
                    971:    return me;   
                    972: }
                    973: 
                    974: 

Webmaster