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