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

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.1       luotonen  143:        if ((int)(dirbuf->d_namlen) >= baselen) {
                    144:            n = HTSplitFilename(dirbuf->d_name, actual);
                    145:            if (multi_match(required, m, actual, n)) {
                    146:                HTContentDescription * cd;
                    147:                cd = HTGetContentDescription(actual, n);
                    148:                if (cd) {
                    149:                    if (cd->content_type) {
                    150:                        cd->filename = (char*)malloc(strlen(dirname) + 2 +
                    151:                                                     strlen(dirbuf->d_name));
                    152:                        if (!cd->filename) outofmem(__FILE__, "dir_matches");
                    153:                        sprintf(cd->filename, "%s/%s",
                    154:                                dirname, dirbuf->d_name);
                    155:                        HTList_addObject(matches, (void*)cd);
                    156:                    }
                    157:                    else free(cd);
                    158:                }
                    159:            }
                    160:        }
                    161:     }
                    162:     closedir(dp);
                    163: 
                    164:   dir_match_failed:
                    165:     free(dirname);
                    166:     return matches;
                    167: }
                    168: 
                    169: 
                    170: /*
                    171: **     Get the best match for a given file
                    172: **     -----------------------------------
                    173: ** On entry:
                    174: **     req->conversions  accepted content-types
                    175: **     req->encodings    accepted content-transfer-encodings
                    176: **     req->languages    accepted content-languages
                    177: **     path              absolute pathname of the filename for
                    178: **                       which the match is desired.
                    179: ** On exit:
                    180: **     returns a newly allocated absolute filepath.
                    181: */
                    182: PRIVATE char * HTGetBest ARGS2(HTRequest *,    req,
                    183:                               char *,          path)
                    184: {
                    185:     HTList * matches;
                    186:     HTList * cur;
                    187:     HTContentDescription * cd;
                    188:     HTContentDescription * best = NULL;
                    189:     char * best_path = NULL;
                    190: 
                    191:     
                    192:     if (!path || !*path) return NO;
                    193: 
                    194:     matches = dir_matches(path);
                    195:     if (!matches) {
                    196:        CTRACE(stderr, "No matches.. for \"%s\"\n", path);
                    197:        return NO;
                    198:     }
                    199: 
                    200:     /* BEGIN DEBUG */
                    201:     cur = matches;
                    202:     CTRACE(stderr, "Multi....... Possibilities for \"%s\"\n", path);
                    203:     CTRACE(stderr, "\nCONTENT-TYPE  LANGUAGE  ENCODING  QUALITY  FILE\n");
                    204:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
                    205:        CTRACE(stderr, "%s\t%s\t%s\t  %.5f  %s\n",
                    206:               cd->content_type    ?HTAtom_name(cd->content_type)  :"-\t",
                    207:               cd->content_language?HTAtom_name(cd->content_language):"-",
                    208:               cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
                    209:               cd->quality,
                    210:               cd->filename        ?cd->filename                     :"-");
                    211:     }
                    212:     CTRACE(stderr, "\n");
                    213:     /* END DEBUG */
                    214: 
                    215:     /*
                    216:     ** Finally get best that is readable
                    217:     */
                    218:     if (HTRank(matches, req->conversions, req->languages, req->encodings)) {
                    219:        cur = matches;
                    220:        while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
                    221:            if (best && best->filename) {
                    222:                if (access(best->filename, R_OK) != -1) {
                    223:                    StrAllocCopy(best_path, best->filename);
                    224:                    break;
                    225:                }
                    226:                else CTRACE(stderr, "Bad News.... \"%s\" is not readable\n",
                    227:                            best->filename);
                    228:            }
                    229:        }
                    230:     } /* Select best */
                    231: 
                    232:     cur = matches;
                    233:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
                    234:        if (cd->filename) free(cd->filename);
                    235:        free(cd);
                    236:     }
                    237:     HTList_delete(matches);
                    238: 
                    239:     return best_path;
                    240: }
                    241: 
2.3       luotonen  242: 
                    243: 
                    244: PRIVATE int welcome_value ARGS1(char *, name)
                    245: {
                    246:     HTList * cur = welcome_names;
                    247:     char * welcome;
                    248:     int v = 0;
                    249: 
                    250:     while ((welcome = (char*)HTList_nextObject(cur))) {
                    251:        v++;
                    252:        if (!strcmp(welcome,name)) return v;
                    253:     }
                    254:     return 0;
                    255: }
                    256: 
                    257: 
                    258: 
                    259: PRIVATE char * get_best_welcome ARGS1(char *, path)
                    260: {
                    261:     char * best_welcome = NULL;
                    262:     int best_value = 0;
                    263:     DIR * dp;
                    264:     STRUCT_DIRENT * dirbuf;
                    265:     char * last = strrchr(path, '/');
                    266: 
                    267:     if (!welcome_names) {
                    268:        HTAddWelcome("Welcome.html");
                    269:        HTAddWelcome("welcome.html");
2.5       luotonen  270: #if 0
2.3       luotonen  271:        HTAddWelcome("Index.html");
2.5       luotonen  272: #endif
2.3       luotonen  273:        HTAddWelcome("index.html");
                    274:     }
                    275: 
2.5       luotonen  276:     if (last && last!=path) *last = 0;
2.3       luotonen  277:     dp = opendir(path);
2.5       luotonen  278:     if (last && last!=path) *last='/';
2.3       luotonen  279:     if (!dp) {
                    280:        CTRACE(stderr, "Warning..... Can't open directory %s\n",path);
                    281:        return NULL;
                    282:     }
                    283:     while ((dirbuf = readdir(dp))) {
                    284:        if (!dirbuf->d_ino ||
                    285:            !strcmp(dirbuf->d_name,".") ||
                    286:            !strcmp(dirbuf->d_name,"..") ||
                    287:            !strcmp(dirbuf->d_name,".www_browsable"))
                    288:            continue;
                    289:        else {
                    290:            int v = welcome_value(dirbuf->d_name);
                    291:            if (v > best_value) {
                    292:                best_value = v;
                    293:                StrAllocCopy(best_welcome, dirbuf->d_name);
                    294:            }
                    295:        }
                    296:     }
                    297:     closedir(dp);
                    298: 
                    299:     if (best_welcome) {
                    300:        char * welcome = (char*)malloc(strlen(path) + strlen(best_welcome)+2);
                    301:        if (!welcome) outofmem(__FILE__, "get_best_welcome");
2.4       luotonen  302:        sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.3       luotonen  303:        free(best_welcome);
                    304:        CTRACE(stderr,"Welcome..... \"%s\"\n",welcome);
                    305:        return welcome;
                    306:     }
                    307:     return NULL;
                    308: }
                    309: 
2.2       duns      310: #endif /* GOT_READ_DIR */
2.1       luotonen  311: 
                    312: 
                    313: /*
                    314: **     Do multiformat handling
                    315: **     -----------------------
                    316: ** On entry:
                    317: **     req->conversions  accepted content-types
                    318: **     req->encodings    accepted content-transfer-encodings
                    319: **     req->languages    accepted content-languages
                    320: **     path              absolute pathname of the filename for
                    321: **                       which the match is desired.
                    322: **     stat_info         pointer to result space.
                    323: **
                    324: ** On exit:
                    325: **     returns a newly allocated absolute filepath of the best
                    326: **             match, or NULL if no match.
                    327: **     stat_info         will contain inode information as
                    328: **                       returned by stat().
                    329: */
                    330: PUBLIC char * HTMulti ARGS3(HTRequest *,       req,
                    331:                            char *,             path,
                    332:                            struct stat *,      stat_info)
                    333: {
                    334:     char * new_path = NULL;
                    335:     int stat_status = -1;
2.3       luotonen  336:     int len;
2.1       luotonen  337: 
2.3       luotonen  338:     if (!req || !path || !*path || !stat_info)
2.1       luotonen  339:        return NULL;
                    340: 
2.2       duns      341: #ifdef GOT_READ_DIR
2.3       luotonen  342:     len = strlen(path);
                    343:     if (path[len-1] == '/') {  /* Find welcome page */
                    344:        new_path = get_best_welcome(path);
                    345:        if (new_path) path = new_path;
2.1       luotonen  346:     }
2.3       luotonen  347:     else{
                    348:        char * multi = strrchr(path, MULTI_SUFFIX[0]);
                    349:        if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
                    350:            CTRACE(stderr, "Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1       luotonen  351:            if (!(new_path = HTGetBest(req, path))) {
2.3       luotonen  352:                CTRACE(stderr, "Multi....... failed -- giving up\n");
2.1       luotonen  353:                return NULL;
                    354:            }
                    355:            path = new_path;
2.3       luotonen  356:        }
                    357:        else {
                    358:            stat_status = stat(path, stat_info);
                    359:            if (stat_status == -1) {
                    360:                CTRACE(stderr,
                    361:                       "AutoMulti... because can't stat \"%s\" (errno %d)\n",
                    362:                       path, errno);
                    363:                if (!(new_path = HTGetBest(req, path))) {
                    364:                    CTRACE(stderr, "AutoMulti... failed -- giving up\n");
                    365:                    return NULL;
                    366:                }
                    367:                path = new_path;
                    368:            }
2.1       luotonen  369:        }
                    370:     }
2.2       duns      371: #endif /* GOT_READ_DIR */
2.1       luotonen  372: 
                    373:     if (stat_status == -1)
                    374:        stat_status = stat(path, stat_info);
                    375:     if (stat_status == -1) {
                    376:        CTRACE(stderr, "Stat fails.. on \"%s\" -- giving up (errno %d)\n",
                    377:               path, errno);
                    378:        return NULL;
                    379:     }
                    380:     else {
                    381:        if (!new_path) {
                    382:            StrAllocCopy(new_path, path);
                    383:            return new_path;
                    384:        }
                    385:        else return path;
                    386:     }
                    387: }
                    388: 
                    389: 

Webmaster