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

2.11      frystyk     1: /*                                                                   HTMulti.c
                      2: **     MULTIFORMAT HANDLING
                      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.28    ! frystyk     6: **     @(#) $Id: HTMulti.c,v 2.27 1996/04/12 17:48:00 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.3       luotonen   20: PRIVATE HTList * welcome_names = NULL; /* Welcome.html, index.html etc. */
                     21: 
                     22: 
2.14      frystyk    23: /* PUBLIC                                              HTSplitFilename()
                     24: **
                     25: **     Split the filename to an array of suffixes.
                     26: **     Return the number of parts placed to the array.
                     27: **     Array should have MAX_SUFF+1 items.
                     28: */
2.23      frystyk    29: PRIVATE int HTSplitFilename (char * s_str, char ** s_arr)
2.14      frystyk    30: {
2.26      frystyk    31:     const char *delimiters = HTBind_delimiters();
2.14      frystyk    32:     char * start = s_str;
                     33:     char * end;
                     34:     char save;
                     35:     int i;
                     36: 
                     37:     if (!s_str || !s_arr) return 0;
                     38: 
                     39:     for (i=0; i < MAX_SUFF && *start; i++) {
                     40:        for(end=start+1; *end && !strchr(delimiters, *end); end++);
                     41:        save = *end;
                     42:        *end = 0;
                     43:        StrAllocCopy(s_arr[i], start);  /* Frees the previous value */
                     44:        *end = save;
                     45:        start = end;
                     46:     }
2.24      frystyk    47:     HT_FREE(s_arr[i]);       /* Terminating NULL */
2.14      frystyk    48:     return i;
                     49: }
                     50: 
                     51: 
2.3       luotonen   52: /*
                     53: **     Set default file name for welcome page on each directory.
                     54: */
2.23      frystyk    55: PUBLIC void HTAddWelcome (char * name)
2.3       luotonen   56: {
                     57:     if (name) {
                     58:        char * mycopy = NULL;
                     59:        StrAllocCopy(mycopy,name);
                     60: 
                     61:        if (!welcome_names)
                     62:            welcome_names = HTList_new();
                     63:        HTList_addObject(welcome_names, (void*)mycopy);
                     64:     }
                     65: }
                     66: 
                     67: 
2.26      frystyk    68: #ifdef HAVE_READDIR
2.1       luotonen   69: 
                     70: /* PRIVATE                                             multi_match()
                     71: **
                     72: **     Check if actual filename (split in parts) fulfills
                     73: **     the requirements.
                     74: */
2.23      frystyk    75: PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n)
2.1       luotonen   76: {
                     77:     int c;
                     78:     int i,j;
                     79: 
2.2       duns       80: #ifdef VMS
                     81:     for(c=0;  c<m && c<n && !strcasecomp(required[c], actual[c]);  c++);
                     82: #else /* not VMS */
2.1       luotonen   83:     for(c=0;  c<m && c<n && !strcmp(required[c], actual[c]);  c++);
2.2       duns       84: #endif /* not VMS */
2.1       luotonen   85: 
                     86:     if (!c) return NO;         /* Names differ rigth from start */
                     87: 
                     88:     for(i=c; i<m; i++) {
                     89:        BOOL found = NO;
                     90:        for(j=c; j<n; j++) {
2.2       duns       91: #ifdef VMS
                     92:            if (!strcasecomp(required[i], actual[j])) {
                     93: #else /* not VMS */
2.1       luotonen   94:            if (!strcmp(required[i], actual[j])) {
2.2       duns       95: #endif /* not VMS */
2.1       luotonen   96:                found = YES;
                     97:                break;
                     98:            }
                     99:        }
                    100:        if (!found) return NO;
                    101:     }
                    102:     return YES;
                    103: }
                    104: 
                    105: 
                    106: /*
                    107: **     Get multi-match possibilities for a given file
                    108: **     ----------------------------------------------
                    109: ** On entry:
                    110: **     path    absolute path to one file in a directory,
                    111: **             may end in .multi.
                    112: ** On exit:
                    113: **     returns a list of ContentDesription structures
                    114: **             describing the mathing files.
                    115: **
                    116: */
2.23      frystyk   117: PRIVATE HTList * dir_matches (char * path)
2.1       luotonen  118: {
                    119:     static char * required[MAX_SUFF+1];
                    120:     static char * actual[MAX_SUFF+1];
                    121:     int m,n;
                    122:     char * dirname = NULL;
                    123:     char * basename = NULL;
                    124:     int baselen;
                    125:     char * multi = NULL;
                    126:     DIR * dp;
2.26      frystyk   127:     struct dirent * dirbuf;
2.1       luotonen  128:     HTList * matches = NULL;
2.16      frystyk   129: #ifdef HT_REENTRANT
2.26      frystyk   130:     DIR result;                                    /* For readdir_r */
2.16      frystyk   131: #endif
2.1       luotonen  132: 
                    133:     if (!path) return NULL;
                    134: 
                    135:     StrAllocCopy(dirname, path);
                    136:     basename = (strrchr(dirname, '/'));
                    137:     if (!basename)
                    138:        goto dir_match_failed;
                    139:     *basename++ = 0;
                    140: 
                    141:     multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2       duns      142:     if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1       luotonen  143:        *multi = 0;
                    144:     baselen = strlen(basename);
                    145: 
                    146:     m = HTSplitFilename(basename, required);
                    147: 
                    148:     dp = opendir(dirname);
                    149:     if (!dp) {
2.13      frystyk   150:        if (PROT_TRACE)
2.25      eric      151:            HTTrace("Warning..... Can't open directory %s\n", dirname);
2.1       luotonen  152:        goto dir_match_failed;
                    153:     }
                    154: 
                    155:     matches = HTList_new();
2.16      frystyk   156: #ifdef HT_REENTRANT
2.26      frystyk   157:        while ((dirbuf = (DIR *) readdir_r(dp, &result))) {
2.16      frystyk   158: #else
                    159:        while ((dirbuf = readdir(dp))) {
                    160: #endif /* HT_REENTRANT */
2.1       luotonen  161:        if (!dirbuf->d_ino) continue;   /* Not in use */
2.3       luotonen  162:        if (!strcmp(dirbuf->d_name,".") ||
                    163:            !strcmp(dirbuf->d_name,"..") ||
2.20      frystyk   164:            !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3       luotonen  165:            continue;
2.7       frystyk   166: 
2.13      frystyk   167:        /* Use of direct->namlen is only valid in BSD'ish system */
                    168:        /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
                    169:        /* if ((int)(dirbuf->d_namlen) >= baselen) { */
                    170:        if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1       luotonen  171:            n = HTSplitFilename(dirbuf->d_name, actual);
                    172:            if (multi_match(required, m, actual, n)) {
                    173:                HTContentDescription * cd;
2.14      frystyk   174:                cd = HTBind_getDescription(dirbuf->d_name);
2.1       luotonen  175:                if (cd) {
                    176:                    if (cd->content_type) {
2.24      frystyk   177:                        if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
                    178:                            HT_OUTOFMEM("dir_matches");
2.1       luotonen  179:                        sprintf(cd->filename, "%s/%s",
                    180:                                dirname, dirbuf->d_name);
                    181:                        HTList_addObject(matches, (void*)cd);
                    182:                    }
2.24      frystyk   183:                    else HT_FREE(cd);
2.1       luotonen  184:                }
                    185:            }
                    186:        }
                    187:     }
                    188:     closedir(dp);
                    189: 
                    190:   dir_match_failed:
2.24      frystyk   191:     HT_FREE(dirname);
2.1       luotonen  192:     return matches;
                    193: }
                    194: 
                    195: 
                    196: /*
                    197: **     Get the best match for a given file
                    198: **     -----------------------------------
                    199: ** On entry:
                    200: **     req->conversions  accepted content-types
                    201: **     req->encodings    accepted content-transfer-encodings
                    202: **     req->languages    accepted content-languages
                    203: **     path              absolute pathname of the filename for
                    204: **                       which the match is desired.
                    205: ** On exit:
                    206: **     returns a newly allocated absolute filepath.
                    207: */
2.23      frystyk   208: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1       luotonen  209: {
                    210:     HTList * matches;
                    211:     HTList * cur;
                    212:     HTContentDescription * cd;
                    213:     HTContentDescription * best = NULL;
                    214:     char * best_path = NULL;
                    215: 
2.13      frystyk   216:     if (!path || !*path) return NULL;
2.1       luotonen  217: 
                    218:     matches = dir_matches(path);
                    219:     if (!matches) {
2.13      frystyk   220:        if (PROT_TRACE)
2.25      eric      221:            HTTrace("No matches.. for \"%s\"\n", path);
2.13      frystyk   222:        return NULL;
2.1       luotonen  223:     }
                    224: 
                    225:     /* BEGIN DEBUG */
                    226:     cur = matches;
2.13      frystyk   227:     if (PROT_TRACE)
2.25      eric      228:        HTTrace("Multi....... Possibilities for \"%s\"\n", path);
2.13      frystyk   229:     if (PROT_TRACE)
2.25      eric      230:        HTTrace("\nCONTENT-TYPE  LANGUAGE  ENCODING  QUALITY  FILE\n");
2.1       luotonen  231:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.13      frystyk   232:        if (PROT_TRACE)
2.25      eric      233:           HTTrace("%s\t%s\t%s\t  %.5f  %s\n",
2.13      frystyk   234:                   cd->content_type    ?HTAtom_name(cd->content_type)  :"-\t",
                    235:                   cd->content_language?HTAtom_name(cd->content_language):"-",
                    236:                   cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
                    237:                   cd->quality,
                    238:                   cd->filename        ?cd->filename                     :"-");
2.1       luotonen  239:     }
2.25      eric      240:     if (PROT_TRACE) HTTrace("\n");
2.1       luotonen  241:     /* END DEBUG */
                    242: 
                    243:     /*
                    244:     ** Finally get best that is readable
                    245:     */
2.28    ! frystyk   246:     if (HTRank(matches,
        !           247:               HTRequest_conversion(req),
        !           248:               HTRequest_language(req),
        !           249:               HTRequest_encoding(req))) {
2.1       luotonen  250:        cur = matches;
                    251:        while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
                    252:            if (best && best->filename) {
                    253:                if (access(best->filename, R_OK) != -1) {
                    254:                    StrAllocCopy(best_path, best->filename);
                    255:                    break;
2.13      frystyk   256:                } else if (PROT_TRACE)
2.25      eric      257:                    HTTrace("Bad News.... \"%s\" is not readable\n",
2.1       luotonen  258:                            best->filename);
                    259:            }
                    260:        }
                    261:     } /* Select best */
                    262: 
                    263:     cur = matches;
                    264:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.24      frystyk   265:        if (cd->filename) HT_FREE(cd->filename);
                    266:        HT_FREE(cd);
2.1       luotonen  267:     }
                    268:     HTList_delete(matches);
                    269: 
                    270:     return best_path;
                    271: }
                    272: 
2.3       luotonen  273: 
                    274: 
2.23      frystyk   275: PRIVATE int welcome_value (char * name)
2.3       luotonen  276: {
                    277:     HTList * cur = welcome_names;
                    278:     char * welcome;
                    279:     int v = 0;
                    280: 
                    281:     while ((welcome = (char*)HTList_nextObject(cur))) {
                    282:        v++;
                    283:        if (!strcmp(welcome,name)) return v;
                    284:     }
                    285:     return 0;
                    286: }
                    287: 
                    288: 
                    289: 
2.23      frystyk   290: PRIVATE char * get_best_welcome (char * path)
2.3       luotonen  291: {
                    292:     char * best_welcome = NULL;
                    293:     int best_value = 0;
                    294:     DIR * dp;
2.26      frystyk   295:     struct dirent * dirbuf;
2.3       luotonen  296:     char * last = strrchr(path, '/');
                    297: 
                    298:     if (!welcome_names) {
                    299:        HTAddWelcome("Welcome.html");
                    300:        HTAddWelcome("welcome.html");
2.5       luotonen  301: #if 0
2.3       luotonen  302:        HTAddWelcome("Index.html");
2.5       luotonen  303: #endif
2.3       luotonen  304:        HTAddWelcome("index.html");
                    305:     }
                    306: 
2.5       luotonen  307:     if (last && last!=path) *last = 0;
2.3       luotonen  308:     dp = opendir(path);
2.5       luotonen  309:     if (last && last!=path) *last='/';
2.3       luotonen  310:     if (!dp) {
2.13      frystyk   311:        if (PROT_TRACE)
2.25      eric      312:            HTTrace("Warning..... Can't open directory %s\n",path);
2.3       luotonen  313:        return NULL;
                    314:     }
                    315:     while ((dirbuf = readdir(dp))) {
2.13      frystyk   316:        if (!dirbuf->d_ino ||
2.3       luotonen  317:            !strcmp(dirbuf->d_name,".") ||
                    318:            !strcmp(dirbuf->d_name,"..") ||
2.20      frystyk   319:            !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3       luotonen  320:            continue;
                    321:        else {
                    322:            int v = welcome_value(dirbuf->d_name);
                    323:            if (v > best_value) {
                    324:                best_value = v;
                    325:                StrAllocCopy(best_welcome, dirbuf->d_name);
                    326:            }
                    327:        }
                    328:     }
                    329:     closedir(dp);
                    330: 
                    331:     if (best_welcome) {
2.24      frystyk   332:        char * welcome;
                    333:        if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
                    334:            HT_OUTOFMEM("get_best_welcome");
2.4       luotonen  335:        sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.24      frystyk   336:        HT_FREE(best_welcome);
2.13      frystyk   337:        if (PROT_TRACE)
2.25      eric      338:            HTTrace("Welcome..... \"%s\"\n",welcome);
2.3       luotonen  339:        return welcome;
                    340:     }
                    341:     return NULL;
                    342: }
                    343: 
2.26      frystyk   344: #endif /* HAVE_READDIR */
2.1       luotonen  345: 
                    346: 
                    347: /*
                    348: **     Do multiformat handling
                    349: **     -----------------------
                    350: ** On entry:
                    351: **     req->conversions  accepted content-types
                    352: **     req->encodings    accepted content-transfer-encodings
                    353: **     req->languages    accepted content-languages
                    354: **     path              absolute pathname of the filename for
                    355: **                       which the match is desired.
                    356: **     stat_info         pointer to result space.
                    357: **
                    358: ** On exit:
                    359: **     returns a newly allocated absolute filepath of the best
                    360: **             match, or NULL if no match.
                    361: **     stat_info         will contain inode information as
                    362: **                       returned by stat().
                    363: */
2.23      frystyk   364: PUBLIC char * HTMulti (HTRequest *     req,
                    365:                       char *           path,
                    366:                       struct stat *    stat_info)
2.1       luotonen  367: {
                    368:     char * new_path = NULL;
                    369:     int stat_status = -1;
                    370: 
2.3       luotonen  371:     if (!req || !path || !*path || !stat_info)
2.1       luotonen  372:        return NULL;
                    373: 
2.26      frystyk   374: #ifdef HAVE_READDIR
2.19      frystyk   375:     if (*(path+strlen(path)-1) == '/') {       /* Find welcome page */
2.3       luotonen  376:        new_path = get_best_welcome(path);
                    377:        if (new_path) path = new_path;
2.1       luotonen  378:     }
2.3       luotonen  379:     else{
                    380:        char * multi = strrchr(path, MULTI_SUFFIX[0]);
                    381:        if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.13      frystyk   382:            if (PROT_TRACE)
2.25      eric      383:                HTTrace("Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1       luotonen  384:            if (!(new_path = HTGetBest(req, path))) {
2.13      frystyk   385:                if (PROT_TRACE)
2.25      eric      386:                    HTTrace("Multi....... failed -- giving up\n");
2.1       luotonen  387:                return NULL;
                    388:            }
                    389:            path = new_path;
2.3       luotonen  390:        }
                    391:        else {
2.18      frystyk   392:            stat_status = HT_STAT(path, stat_info);
2.3       luotonen  393:            if (stat_status == -1) {
2.13      frystyk   394:                if (PROT_TRACE)
2.25      eric      395:                    HTTrace(
2.13      frystyk   396:                            "AutoMulti... can't stat \"%s\"(errno %d)\n",
                    397:                            path, errno);
2.3       luotonen  398:                if (!(new_path = HTGetBest(req, path))) {
2.13      frystyk   399:                    if (PROT_TRACE)
2.25      eric      400:                        HTTrace("AutoMulti... failed -- giving up\n");
2.3       luotonen  401:                    return NULL;
                    402:                }
                    403:                path = new_path;
                    404:            }
2.1       luotonen  405:        }
                    406:     }
2.26      frystyk   407: #endif /* HAVE_READDIR */
2.1       luotonen  408: 
                    409:     if (stat_status == -1)
2.18      frystyk   410:        stat_status = HT_STAT(path, stat_info);
2.1       luotonen  411:     if (stat_status == -1) {
2.13      frystyk   412:        if (PROT_TRACE)
2.25      eric      413:            HTTrace("Stat fails.. on \"%s\" -- giving up (errno %d)\n",
2.13      frystyk   414:                    path, errno);
2.1       luotonen  415:        return NULL;
                    416:     }
                    417:     else {
                    418:        if (!new_path) {
                    419:            StrAllocCopy(new_path, path);
                    420:            return new_path;
                    421:        }
                    422:        else return path;
                    423:     }
                    424: }
                    425: 
                    426: 

Webmaster