Annotation of libwww/Library/src/HTMulti.c, revision 2.29

2.29    ! frystyk     1: /*
        !             2: **     CONTENT NEGOTIATION
2.11      frystyk     3: **
2.15      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.11      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.29    ! frystyk     6: **     @(#) $Id: HTMulti.c,v 2.28 1996/06/02 00:34:55 frystyk Exp $
2.1       luotonen    7: **
                      8: ** History:
                      9: **     March 94  AL    Separated from HTFile.c because
                     10: **                     multiformat handling would be a mess in VMS.
                     11: */
                     12: 
2.13      frystyk    13: /* Library include files */
2.26      frystyk    14: #include "sysdep.h"
2.28      frystyk    15: #include "WWWUtil.h"
                     16: #include "WWWCore.h"
2.2       duns       17: #include "HTMulti.h"
2.20      frystyk    18: #include "HTFile.h"
2.1       luotonen   19: 
2.29    ! frystyk    20: #define MULTI_SUFFIX   ".multi"/* Extension for scanning formats */
        !            21: #define MAX_SUFF       15      /* Maximum number of suffixes for a file */
        !            22: #define VARIANTS       4       /* We start with this array size */
        !            23: 
        !            24: typedef struct _HTContentDescription {
        !            25:     char *     filename;
        !            26:     HTFormat   content_type;
        !            27:     HTLanguage content_language;
        !            28:     HTEncoding content_encoding;
        !            29:     HTEncoding content_transfer;
        !            30:     int                content_length;
        !            31:     double     quality;
        !            32: } HTContentDescription;
        !            33: 
2.3       luotonen   34: PRIVATE HTList * welcome_names = NULL; /* Welcome.html, index.html etc. */
                     35: 
2.29    ! frystyk    36: /* ------------------------------------------------------------------------- */
        !            37: 
        !            38: /*
        !            39: **  Sort the q values in descending order
        !            40: */
        !            41: PRIVATE int VariantSort (const void * a, const void * b)
        !            42: {
        !            43:     HTContentDescription * aa = *(HTContentDescription **) a;
        !            44:     HTContentDescription * bb = *(HTContentDescription **) b;
        !            45:     return (aa->quality > bb->quality) ? -1 : 1;
        !            46: }
        !            47: 
        !            48: PRIVATE BOOL wild_match (HTAtom * tmplate, HTAtom * actual)
        !            49: {
        !            50:     const char *t, *a;
        !            51:     char *st, *sa;
        !            52:     BOOL match = NO;
        !            53: 
        !            54:     if (tmplate && actual && (t = HTAtom_name(tmplate))) {
        !            55:        if (!strcmp(t, "*"))
        !            56:            return YES;
        !            57: 
        !            58:        if (strchr(t, '*') &&
        !            59:            (a = HTAtom_name(actual)) &&
        !            60:            (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
        !            61: 
        !            62:            *sa = 0;
        !            63:            *st = 0;
        !            64: 
        !            65:            if ((*(st-1)=='*' &&
        !            66:                 (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
        !            67:                (*(st+1)=='*' && !strcasecomp(t,a)))
        !            68:                match = YES;
        !            69: 
        !            70:            *sa = '/';
        !            71:            *st = '/';
        !            72:        }    
        !            73:     }
        !            74:     return match;
        !            75: }
        !            76: 
        !            77: /*
        !            78:  * Added by takada@seraph.ntt.jp (94/04/08)
        !            79:  */
        !            80: PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
        !            81: {
        !            82:     const char *t, *a;
        !            83:     char *st, *sa;
        !            84:     BOOL match = NO;
        !            85: 
        !            86:     if (tmplate && actual &&
        !            87:        (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
        !            88:        st = strchr(t, '_');
        !            89:        sa = strchr(a, '_');
        !            90:        if ((st != NULL) && (sa != NULL)) {
        !            91:            if (!strcasecomp(t, a))
        !            92:              match = YES;
        !            93:            else
        !            94:              match = NO;
        !            95:        }
        !            96:        else {
        !            97:            if (st != NULL) *st = 0;
        !            98:            if (sa != NULL) *sa = 0;
        !            99:            if (!strcasecomp(t, a))
        !           100:              match = YES;
        !           101:            else
        !           102:              match = NO;
        !           103:            if (st != NULL) *st = '_';
        !           104:            if (sa != NULL) *sa = '_';
        !           105:        }
        !           106:     }
        !           107:     return match;
        !           108: }
        !           109: 
        !           110: PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
        !           111: {
        !           112:     if (!content_type) return (1.0);
        !           113:     if (accepted) {
        !           114:        HTList * cur = accepted;
        !           115:        HTPresentation * pres;
        !           116:        HTPresentation * wild = NULL;
        !           117:        while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
        !           118:            if (pres->rep == content_type)
        !           119:                return pres->quality;
        !           120:            else if (wild_match(pres->rep, content_type))
        !           121:                wild = pres;
        !           122:        }
        !           123:        if (wild) return wild->quality;
        !           124:        else return (0.0);                                /* Nothing matched */
        !           125:     }
        !           126:     return (1.0);                                    /* We accept all types */
        !           127: }
        !           128: 
        !           129: PRIVATE double lang_value (HTAtom * language, HTList * accepted)
        !           130: {
        !           131:     if (!language) return (1.0);
        !           132:     if (accepted) {
        !           133:        HTList * cur = accepted;
        !           134:        HTAcceptNode * node;
        !           135:        HTAcceptNode * wild = NULL;
        !           136:        while ((node = (HTAcceptNode *) HTList_nextObject(cur))) {
        !           137:            if (node->atom == language)
        !           138:                return node->quality;
        !           139:            /*
        !           140:             * patch by takada@seraph.ntt.jp (94/04/08)
        !           141:             * the original line was
        !           142:             * else if (wild_match(node->atom, language)) {
        !           143:             * and the new line is
        !           144:             */
        !           145:            else if (lang_match(node->atom, language))
        !           146:                wild = node;
        !           147:        }
        !           148:        if (wild) return wild->quality;
        !           149:        else return (0.0);                                /* Nothing matched */
        !           150:     }
        !           151:     return (1.0);                                /* We accept all languages */
        !           152: }
        !           153: 
        !           154: PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
        !           155: {
        !           156:     if (!encoding) return (1.0);
        !           157:     if (accepted) {
        !           158:        HTList * cur = accepted;
        !           159:        HTAcceptNode * node;
        !           160:        HTAcceptNode * wild = NULL;
        !           161:        const char * e = HTAtom_name(encoding);
        !           162:        if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
        !           163:            return (1.0);
        !           164:        while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
        !           165:            if (node->atom == encoding)
        !           166:                return node->quality;
        !           167:            else if (wild_match(node->atom, encoding))
        !           168:                wild = node;
        !           169:        }
        !           170:        if (wild) return wild->quality;
        !           171:        else return (0.0);                                /* Nothing matched */
        !           172:     }
        !           173:     return (1.0);                                /* We accept all encodings */
        !           174: }
        !           175: 
        !           176: PRIVATE BOOL HTRank (HTRequest * request, HTArray * variants)
        !           177: {
        !           178:     HTContentDescription * cd;
        !           179:     void ** data;
        !           180:     if (!variants) {
        !           181:        if (PROT_TRACE) HTTrace("Ranking..... No variants\n");
        !           182:        return NO;
        !           183:     }
        !           184:     /* 
        !           185:     **  Walk through the list of local and global preferences and find the
        !           186:     **  overall q factor for each variant
        !           187:     */
        !           188:     cd = (HTContentDescription *) HTArray_firstObject(variants, data);
        !           189:     while (cd) {
        !           190:        double ctq_local  = type_value(cd->content_type, HTRequest_conversion(request));
        !           191:        double ctq_global = type_value(cd->content_type, HTFormat_conversion());
        !           192:        double clq_local  = lang_value(cd->content_language, HTRequest_language(request));
        !           193:        double clq_global = lang_value(cd->content_language, HTFormat_language());
        !           194:        double ceq_local  = encoding_value(cd->content_encoding, HTRequest_encoding(request));
        !           195:        double ceq_global = encoding_value(cd->content_encoding, HTFormat_contentCoding());
        !           196:        if (PROT_TRACE)
        !           197:            HTTrace("Qualities... Content type: %.3f, Content language: %.3f, Content encoding: %.3f\n",
        !           198:                    HTMAX(ctq_local, ctq_global),
        !           199:                    HTMAX(clq_local, clq_global),
        !           200:                    HTMAX(ceq_local, ceq_global));
        !           201:        cd->quality *= (HTMAX(ctq_local, ctq_global) *
        !           202:                        HTMAX(clq_local, clq_global) *
        !           203:                        HTMAX(ceq_local, ceq_global));
        !           204:        cd = (HTContentDescription *) HTArray_nextObject(variants, data);
        !           205:     }
        !           206: 
        !           207:     /* Sort the array of all our accepted preferences */
        !           208:     HTArray_sort(variants, VariantSort);
        !           209: 
        !           210:     /* Write out the result */
        !           211:     if (PROT_TRACE) {
        !           212:        int cnt = 1;
        !           213:        cd = (HTContentDescription *) HTArray_firstObject(variants, data);
        !           214:        HTTrace("Ranking.....\n");
        !           215:        HTTrace("RANK QUALITY CONTENT-TYPE         LANGUAGE ENCODING  FILE\n");
        !           216:        while (cd) {
        !           217:            HTTrace("%d.   %.4f  %-20.20s %-8.8s %-10.10s %s\n",
        !           218:                    cnt++,
        !           219:                    cd->quality,
        !           220:                    cd->content_type ? HTAtom_name(cd->content_type) : "-",
        !           221:                    cd->content_language?HTAtom_name(cd->content_language):"-",
        !           222:                    cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
        !           223:                    cd->filename ? cd->filename :"-");
        !           224:            cd = (HTContentDescription *) HTArray_nextObject(variants, data);
        !           225:        }
        !           226:     }
        !           227:     return YES;
        !           228: }
2.3       luotonen  229: 
2.14      frystyk   230: /* PUBLIC                                              HTSplitFilename()
                    231: **
                    232: **     Split the filename to an array of suffixes.
                    233: **     Return the number of parts placed to the array.
                    234: **     Array should have MAX_SUFF+1 items.
                    235: */
2.23      frystyk   236: PRIVATE int HTSplitFilename (char * s_str, char ** s_arr)
2.14      frystyk   237: {
2.26      frystyk   238:     const char *delimiters = HTBind_delimiters();
2.14      frystyk   239:     char * start = s_str;
                    240:     char * end;
                    241:     char save;
                    242:     int i;
                    243: 
                    244:     if (!s_str || !s_arr) return 0;
                    245: 
                    246:     for (i=0; i < MAX_SUFF && *start; i++) {
                    247:        for(end=start+1; *end && !strchr(delimiters, *end); end++);
                    248:        save = *end;
                    249:        *end = 0;
                    250:        StrAllocCopy(s_arr[i], start);  /* Frees the previous value */
                    251:        *end = save;
                    252:        start = end;
                    253:     }
2.24      frystyk   254:     HT_FREE(s_arr[i]);       /* Terminating NULL */
2.14      frystyk   255:     return i;
                    256: }
                    257: 
                    258: 
2.3       luotonen  259: /*
                    260: **     Set default file name for welcome page on each directory.
                    261: */
2.23      frystyk   262: PUBLIC void HTAddWelcome (char * name)
2.3       luotonen  263: {
                    264:     if (name) {
                    265:        char * mycopy = NULL;
                    266:        StrAllocCopy(mycopy,name);
                    267: 
                    268:        if (!welcome_names)
                    269:            welcome_names = HTList_new();
                    270:        HTList_addObject(welcome_names, (void*)mycopy);
                    271:     }
                    272: }
                    273: 
                    274: 
2.26      frystyk   275: #ifdef HAVE_READDIR
2.1       luotonen  276: 
                    277: /* PRIVATE                                             multi_match()
                    278: **
                    279: **     Check if actual filename (split in parts) fulfills
                    280: **     the requirements.
                    281: */
2.23      frystyk   282: PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n)
2.1       luotonen  283: {
                    284:     int c;
                    285:     int i,j;
                    286: 
2.2       duns      287: #ifdef VMS
                    288:     for(c=0;  c<m && c<n && !strcasecomp(required[c], actual[c]);  c++);
                    289: #else /* not VMS */
2.1       luotonen  290:     for(c=0;  c<m && c<n && !strcmp(required[c], actual[c]);  c++);
2.2       duns      291: #endif /* not VMS */
2.1       luotonen  292: 
                    293:     if (!c) return NO;         /* Names differ rigth from start */
                    294: 
                    295:     for(i=c; i<m; i++) {
                    296:        BOOL found = NO;
                    297:        for(j=c; j<n; j++) {
2.2       duns      298: #ifdef VMS
                    299:            if (!strcasecomp(required[i], actual[j])) {
                    300: #else /* not VMS */
2.1       luotonen  301:            if (!strcmp(required[i], actual[j])) {
2.2       duns      302: #endif /* not VMS */
2.1       luotonen  303:                found = YES;
                    304:                break;
                    305:            }
                    306:        }
                    307:        if (!found) return NO;
                    308:     }
                    309:     return YES;
                    310: }
                    311: 
                    312: 
                    313: /*
                    314: **     Get multi-match possibilities for a given file
                    315: **     ----------------------------------------------
                    316: ** On entry:
                    317: **     path    absolute path to one file in a directory,
                    318: **             may end in .multi.
                    319: ** On exit:
                    320: **     returns a list of ContentDesription structures
                    321: **             describing the mathing files.
                    322: **
                    323: */
2.29    ! frystyk   324: PRIVATE HTArray * dir_matches (char * path)
2.1       luotonen  325: {
                    326:     static char * required[MAX_SUFF+1];
                    327:     static char * actual[MAX_SUFF+1];
                    328:     int m,n;
                    329:     char * dirname = NULL;
                    330:     char * basename = NULL;
                    331:     int baselen;
                    332:     char * multi = NULL;
                    333:     DIR * dp;
2.26      frystyk   334:     struct dirent * dirbuf;
2.29    ! frystyk   335:     HTArray * matches = NULL;
2.16      frystyk   336: #ifdef HT_REENTRANT
2.26      frystyk   337:     DIR result;                                    /* For readdir_r */
2.16      frystyk   338: #endif
2.1       luotonen  339: 
                    340:     if (!path) return NULL;
                    341: 
                    342:     StrAllocCopy(dirname, path);
                    343:     basename = (strrchr(dirname, '/'));
                    344:     if (!basename)
                    345:        goto dir_match_failed;
                    346:     *basename++ = 0;
                    347: 
                    348:     multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2       duns      349:     if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1       luotonen  350:        *multi = 0;
                    351:     baselen = strlen(basename);
                    352: 
                    353:     m = HTSplitFilename(basename, required);
                    354: 
                    355:     dp = opendir(dirname);
                    356:     if (!dp) {
2.13      frystyk   357:        if (PROT_TRACE)
2.25      eric      358:            HTTrace("Warning..... Can't open directory %s\n", dirname);
2.1       luotonen  359:        goto dir_match_failed;
                    360:     }
                    361: 
2.29    ! frystyk   362:     matches = HTArray_new(VARIANTS);
2.16      frystyk   363: #ifdef HT_REENTRANT
2.26      frystyk   364:        while ((dirbuf = (DIR *) readdir_r(dp, &result))) {
2.16      frystyk   365: #else
                    366:        while ((dirbuf = readdir(dp))) {
                    367: #endif /* HT_REENTRANT */
2.1       luotonen  368:        if (!dirbuf->d_ino) continue;   /* Not in use */
2.3       luotonen  369:        if (!strcmp(dirbuf->d_name,".") ||
                    370:            !strcmp(dirbuf->d_name,"..") ||
2.20      frystyk   371:            !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3       luotonen  372:            continue;
2.7       frystyk   373: 
2.13      frystyk   374:        /* Use of direct->namlen is only valid in BSD'ish system */
                    375:        /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
                    376:        /* if ((int)(dirbuf->d_namlen) >= baselen) { */
                    377:        if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1       luotonen  378:            n = HTSplitFilename(dirbuf->d_name, actual);
                    379:            if (multi_match(required, m, actual, n)) {
                    380:                HTContentDescription * cd;
2.29    ! frystyk   381:                if ((cd = (HTContentDescription  *)
        !           382:                     HT_CALLOC(1, sizeof(HTContentDescription))) == NULL)
        !           383:                    HT_OUTOFMEM("dir_matches");
        !           384:                if (HTBind_getFormat(dirbuf->d_name,
        !           385:                                     &cd->content_type,
        !           386:                                     &cd->content_encoding,
        !           387:                                     &cd->content_transfer,
        !           388:                                     &cd->content_language,
        !           389:                                     &cd->quality)) {
2.1       luotonen  390:                    if (cd->content_type) {
2.24      frystyk   391:                        if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
                    392:                            HT_OUTOFMEM("dir_matches");
2.29    ! frystyk   393:                        sprintf(cd->filename, "%s/%s", dirname, dirbuf->d_name);
        !           394:                        HTArray_addObject(matches, (void *) cd);
        !           395:                    } else {
        !           396:                        HT_FREE(cd);
2.1       luotonen  397:                    }
2.29    ! frystyk   398:                } else {
        !           399:                    HT_FREE(cd);
2.1       luotonen  400:                }
                    401:            }
                    402:        }
                    403:     }
                    404:     closedir(dp);
                    405: 
                    406:   dir_match_failed:
2.24      frystyk   407:     HT_FREE(dirname);
2.1       luotonen  408:     return matches;
                    409: }
                    410: 
                    411: 
                    412: /*
                    413: **     Get the best match for a given file
                    414: **     -----------------------------------
                    415: ** On entry:
                    416: **     req->conversions  accepted content-types
                    417: **     req->encodings    accepted content-transfer-encodings
                    418: **     req->languages    accepted content-languages
                    419: **     path              absolute pathname of the filename for
                    420: **                       which the match is desired.
                    421: ** On exit:
                    422: **     returns a newly allocated absolute filepath.
                    423: */
2.23      frystyk   424: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1       luotonen  425: {
2.29    ! frystyk   426:     HTArray * variants = NULL;
        !           427:     char * representation = NULL;
2.1       luotonen  428: 
2.13      frystyk   429:     if (!path || !*path) return NULL;
2.1       luotonen  430: 
2.29    ! frystyk   431:     if ((variants = dir_matches(path)) == NULL) {
        !           432:        if (PROT_TRACE) HTTrace("No matches.. for \"%s\"\n", path);
2.13      frystyk   433:        return NULL;
2.1       luotonen  434:     }
                    435: 
2.29    ! frystyk   436:     if (PROT_TRACE) {
        !           437:        void ** data;
        !           438:        HTContentDescription * cd = HTArray_firstObject(variants, data);
2.25      eric      439:        HTTrace("Multi....... Possibilities for \"%s\"\n", path);
2.29    ! frystyk   440:        HTTrace("     QUALITY CONTENT-TYPE         LANGUAGE ENCODING  FILE\n");
        !           441:        while (cd) {
        !           442:            HTTrace("     %.4f  %-20.20s %-8.8s %-10.10s %s\n",
        !           443:                    cd->quality,
        !           444:                    cd->content_type    ?HTAtom_name(cd->content_type)  :"-\t",
        !           445:                    cd->content_language?HTAtom_name(cd->content_language):"-",
        !           446:                    cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
        !           447:                    cd->filename        ?cd->filename                    :"-");
        !           448:            cd = (HTContentDescription *) HTArray_nextObject(variants, data);
        !           449:        }
2.1       luotonen  450:     }
                    451: 
                    452:     /*
2.29    ! frystyk   453:     ** Finally get the best variant which is readable
2.1       luotonen  454:     */
2.29    ! frystyk   455:     if (HTRank(req, variants)) {
        !           456:        void ** data;
        !           457:        HTContentDescription * cd = HTArray_firstObject(variants, data);
        !           458:        while (cd) {
        !           459:            if (cd->filename) {
        !           460:                if (access(cd->filename, R_OK) != -1)
        !           461:                    StrAllocCopy(representation, cd->filename);
        !           462:                else if (PROT_TRACE)
        !           463:                    HTTrace("Multi....... `%s\' is not readable\n",
        !           464:                            cd->filename);
2.1       luotonen  465:            }
2.29    ! frystyk   466:            HT_FREE(cd->filename);
        !           467:            HT_FREE(cd);
        !           468:            cd = (HTContentDescription *) HTArray_nextObject(variants, data);
2.1       luotonen  469:        }
                    470:     }
2.29    ! frystyk   471:     HTArray_delete(variants);
        !           472:     return representation;
2.1       luotonen  473: }
                    474: 
2.3       luotonen  475: 
                    476: 
2.23      frystyk   477: PRIVATE int welcome_value (char * name)
2.3       luotonen  478: {
                    479:     HTList * cur = welcome_names;
                    480:     char * welcome;
                    481:     int v = 0;
                    482: 
                    483:     while ((welcome = (char*)HTList_nextObject(cur))) {
                    484:        v++;
                    485:        if (!strcmp(welcome,name)) return v;
                    486:     }
                    487:     return 0;
                    488: }
                    489: 
                    490: 
                    491: 
2.23      frystyk   492: PRIVATE char * get_best_welcome (char * path)
2.3       luotonen  493: {
                    494:     char * best_welcome = NULL;
                    495:     int best_value = 0;
                    496:     DIR * dp;
2.26      frystyk   497:     struct dirent * dirbuf;
2.3       luotonen  498:     char * last = strrchr(path, '/');
                    499: 
                    500:     if (!welcome_names) {
                    501:        HTAddWelcome("Welcome.html");
                    502:        HTAddWelcome("welcome.html");
2.5       luotonen  503: #if 0
2.3       luotonen  504:        HTAddWelcome("Index.html");
2.5       luotonen  505: #endif
2.3       luotonen  506:        HTAddWelcome("index.html");
                    507:     }
                    508: 
2.5       luotonen  509:     if (last && last!=path) *last = 0;
2.3       luotonen  510:     dp = opendir(path);
2.5       luotonen  511:     if (last && last!=path) *last='/';
2.3       luotonen  512:     if (!dp) {
2.13      frystyk   513:        if (PROT_TRACE)
2.25      eric      514:            HTTrace("Warning..... Can't open directory %s\n",path);
2.3       luotonen  515:        return NULL;
                    516:     }
                    517:     while ((dirbuf = readdir(dp))) {
2.13      frystyk   518:        if (!dirbuf->d_ino ||
2.3       luotonen  519:            !strcmp(dirbuf->d_name,".") ||
                    520:            !strcmp(dirbuf->d_name,"..") ||
2.20      frystyk   521:            !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3       luotonen  522:            continue;
                    523:        else {
                    524:            int v = welcome_value(dirbuf->d_name);
                    525:            if (v > best_value) {
                    526:                best_value = v;
                    527:                StrAllocCopy(best_welcome, dirbuf->d_name);
                    528:            }
                    529:        }
                    530:     }
                    531:     closedir(dp);
                    532: 
                    533:     if (best_welcome) {
2.24      frystyk   534:        char * welcome;
                    535:        if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
                    536:            HT_OUTOFMEM("get_best_welcome");
2.4       luotonen  537:        sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.24      frystyk   538:        HT_FREE(best_welcome);
2.13      frystyk   539:        if (PROT_TRACE)
2.25      eric      540:            HTTrace("Welcome..... \"%s\"\n",welcome);
2.3       luotonen  541:        return welcome;
                    542:     }
                    543:     return NULL;
                    544: }
                    545: 
2.26      frystyk   546: #endif /* HAVE_READDIR */
2.1       luotonen  547: 
                    548: 
                    549: /*
                    550: **     Do multiformat handling
                    551: **     -----------------------
                    552: ** On entry:
                    553: **     req->conversions  accepted content-types
                    554: **     req->encodings    accepted content-transfer-encodings
                    555: **     req->languages    accepted content-languages
                    556: **     path              absolute pathname of the filename for
                    557: **                       which the match is desired.
                    558: **     stat_info         pointer to result space.
                    559: **
                    560: ** On exit:
                    561: **     returns a newly allocated absolute filepath of the best
                    562: **             match, or NULL if no match.
                    563: **     stat_info         will contain inode information as
                    564: **                       returned by stat().
                    565: */
2.23      frystyk   566: PUBLIC char * HTMulti (HTRequest *     req,
                    567:                       char *           path,
                    568:                       struct stat *    stat_info)
2.1       luotonen  569: {
                    570:     char * new_path = NULL;
                    571:     int stat_status = -1;
                    572: 
2.3       luotonen  573:     if (!req || !path || !*path || !stat_info)
2.1       luotonen  574:        return NULL;
                    575: 
2.26      frystyk   576: #ifdef HAVE_READDIR
2.19      frystyk   577:     if (*(path+strlen(path)-1) == '/') {       /* Find welcome page */
2.3       luotonen  578:        new_path = get_best_welcome(path);
                    579:        if (new_path) path = new_path;
2.29    ! frystyk   580:     } else{
2.3       luotonen  581:        char * multi = strrchr(path, MULTI_SUFFIX[0]);
                    582:        if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.13      frystyk   583:            if (PROT_TRACE)
2.25      eric      584:                HTTrace("Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1       luotonen  585:            if (!(new_path = HTGetBest(req, path))) {
2.13      frystyk   586:                if (PROT_TRACE)
2.25      eric      587:                    HTTrace("Multi....... failed -- giving up\n");
2.1       luotonen  588:                return NULL;
                    589:            }
                    590:            path = new_path;
2.29    ! frystyk   591:        } else {
2.18      frystyk   592:            stat_status = HT_STAT(path, stat_info);
2.3       luotonen  593:            if (stat_status == -1) {
2.13      frystyk   594:                if (PROT_TRACE)
2.29    ! frystyk   595:                    HTTrace("AutoMulti... can't stat \"%s\"(errno %d)\n",
2.13      frystyk   596:                            path, errno);
2.3       luotonen  597:                if (!(new_path = HTGetBest(req, path))) {
2.13      frystyk   598:                    if (PROT_TRACE)
2.25      eric      599:                        HTTrace("AutoMulti... failed -- giving up\n");
2.3       luotonen  600:                    return NULL;
                    601:                }
                    602:                path = new_path;
                    603:            }
2.1       luotonen  604:        }
                    605:     }
2.26      frystyk   606: #endif /* HAVE_READDIR */
2.1       luotonen  607: 
                    608:     if (stat_status == -1)
2.18      frystyk   609:        stat_status = HT_STAT(path, stat_info);
2.1       luotonen  610:     if (stat_status == -1) {
2.13      frystyk   611:        if (PROT_TRACE)
2.25      eric      612:            HTTrace("Stat fails.. on \"%s\" -- giving up (errno %d)\n",
2.13      frystyk   613:                    path, errno);
2.1       luotonen  614:        return NULL;
2.29    ! frystyk   615:     } else {
2.1       luotonen  616:        if (!new_path) {
                    617:            StrAllocCopy(new_path, path);
                    618:            return new_path;
                    619:        }
                    620:        else return path;
                    621:     }
                    622: }
                    623: 
                    624: 

Webmaster