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

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

Webmaster