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

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

Webmaster