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

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

Webmaster