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