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