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

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

Webmaster