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

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

Webmaster