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

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

Webmaster