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

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

Webmaster