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

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

Webmaster