Annotation of libwww/Library/src/HTMulti.c, revision 2.28
2.11 frystyk 1: /* HTMulti.c
2: ** MULTIFORMAT HANDLING
3: **
2.15 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.11 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.28 ! frystyk 6: ** @(#) $Id: HTMulti.c,v 2.27 1996/04/12 17:48:00 frystyk Exp $
2.1 luotonen 7: **
8: ** History:
9: ** March 94 AL Separated from HTFile.c because
10: ** multiformat handling would be a mess in VMS.
11: */
12:
2.13 frystyk 13: /* Library include files */
2.26 frystyk 14: #include "sysdep.h"
2.28 ! frystyk 15: #include "WWWUtil.h"
! 16: #include "WWWCore.h"
2.2 duns 17: #include "HTMulti.h"
2.20 frystyk 18: #include "HTFile.h"
2.1 luotonen 19:
2.3 luotonen 20: PRIVATE HTList * welcome_names = NULL; /* Welcome.html, index.html etc. */
21:
22:
2.14 frystyk 23: /* PUBLIC HTSplitFilename()
24: **
25: ** Split the filename to an array of suffixes.
26: ** Return the number of parts placed to the array.
27: ** Array should have MAX_SUFF+1 items.
28: */
2.23 frystyk 29: PRIVATE int HTSplitFilename (char * s_str, char ** s_arr)
2.14 frystyk 30: {
2.26 frystyk 31: const char *delimiters = HTBind_delimiters();
2.14 frystyk 32: char * start = s_str;
33: char * end;
34: char save;
35: int i;
36:
37: if (!s_str || !s_arr) return 0;
38:
39: for (i=0; i < MAX_SUFF && *start; i++) {
40: for(end=start+1; *end && !strchr(delimiters, *end); end++);
41: save = *end;
42: *end = 0;
43: StrAllocCopy(s_arr[i], start); /* Frees the previous value */
44: *end = save;
45: start = end;
46: }
2.24 frystyk 47: HT_FREE(s_arr[i]); /* Terminating NULL */
2.14 frystyk 48: return i;
49: }
50:
51:
2.3 luotonen 52: /*
53: ** Set default file name for welcome page on each directory.
54: */
2.23 frystyk 55: PUBLIC void HTAddWelcome (char * name)
2.3 luotonen 56: {
57: if (name) {
58: char * mycopy = NULL;
59: StrAllocCopy(mycopy,name);
60:
61: if (!welcome_names)
62: welcome_names = HTList_new();
63: HTList_addObject(welcome_names, (void*)mycopy);
64: }
65: }
66:
67:
2.26 frystyk 68: #ifdef HAVE_READDIR
2.1 luotonen 69:
70: /* PRIVATE multi_match()
71: **
72: ** Check if actual filename (split in parts) fulfills
73: ** the requirements.
74: */
2.23 frystyk 75: PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n)
2.1 luotonen 76: {
77: int c;
78: int i,j;
79:
2.2 duns 80: #ifdef VMS
81: for(c=0; c<m && c<n && !strcasecomp(required[c], actual[c]); c++);
82: #else /* not VMS */
2.1 luotonen 83: for(c=0; c<m && c<n && !strcmp(required[c], actual[c]); c++);
2.2 duns 84: #endif /* not VMS */
2.1 luotonen 85:
86: if (!c) return NO; /* Names differ rigth from start */
87:
88: for(i=c; i<m; i++) {
89: BOOL found = NO;
90: for(j=c; j<n; j++) {
2.2 duns 91: #ifdef VMS
92: if (!strcasecomp(required[i], actual[j])) {
93: #else /* not VMS */
2.1 luotonen 94: if (!strcmp(required[i], actual[j])) {
2.2 duns 95: #endif /* not VMS */
2.1 luotonen 96: found = YES;
97: break;
98: }
99: }
100: if (!found) return NO;
101: }
102: return YES;
103: }
104:
105:
106: /*
107: ** Get multi-match possibilities for a given file
108: ** ----------------------------------------------
109: ** On entry:
110: ** path absolute path to one file in a directory,
111: ** may end in .multi.
112: ** On exit:
113: ** returns a list of ContentDesription structures
114: ** describing the mathing files.
115: **
116: */
2.23 frystyk 117: PRIVATE HTList * dir_matches (char * path)
2.1 luotonen 118: {
119: static char * required[MAX_SUFF+1];
120: static char * actual[MAX_SUFF+1];
121: int m,n;
122: char * dirname = NULL;
123: char * basename = NULL;
124: int baselen;
125: char * multi = NULL;
126: DIR * dp;
2.26 frystyk 127: struct dirent * dirbuf;
2.1 luotonen 128: HTList * matches = NULL;
2.16 frystyk 129: #ifdef HT_REENTRANT
2.26 frystyk 130: DIR result; /* For readdir_r */
2.16 frystyk 131: #endif
2.1 luotonen 132:
133: if (!path) return NULL;
134:
135: StrAllocCopy(dirname, path);
136: basename = (strrchr(dirname, '/'));
137: if (!basename)
138: goto dir_match_failed;
139: *basename++ = 0;
140:
141: multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2 duns 142: if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1 luotonen 143: *multi = 0;
144: baselen = strlen(basename);
145:
146: m = HTSplitFilename(basename, required);
147:
148: dp = opendir(dirname);
149: if (!dp) {
2.13 frystyk 150: if (PROT_TRACE)
2.25 eric 151: HTTrace("Warning..... Can't open directory %s\n", dirname);
2.1 luotonen 152: goto dir_match_failed;
153: }
154:
155: matches = HTList_new();
2.16 frystyk 156: #ifdef HT_REENTRANT
2.26 frystyk 157: while ((dirbuf = (DIR *) readdir_r(dp, &result))) {
2.16 frystyk 158: #else
159: while ((dirbuf = readdir(dp))) {
160: #endif /* HT_REENTRANT */
2.1 luotonen 161: if (!dirbuf->d_ino) continue; /* Not in use */
2.3 luotonen 162: if (!strcmp(dirbuf->d_name,".") ||
163: !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 164: !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 165: continue;
2.7 frystyk 166:
2.13 frystyk 167: /* Use of direct->namlen is only valid in BSD'ish system */
168: /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
169: /* if ((int)(dirbuf->d_namlen) >= baselen) { */
170: if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1 luotonen 171: n = HTSplitFilename(dirbuf->d_name, actual);
172: if (multi_match(required, m, actual, n)) {
173: HTContentDescription * cd;
2.14 frystyk 174: cd = HTBind_getDescription(dirbuf->d_name);
2.1 luotonen 175: if (cd) {
176: if (cd->content_type) {
2.24 frystyk 177: if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
178: HT_OUTOFMEM("dir_matches");
2.1 luotonen 179: sprintf(cd->filename, "%s/%s",
180: dirname, dirbuf->d_name);
181: HTList_addObject(matches, (void*)cd);
182: }
2.24 frystyk 183: else HT_FREE(cd);
2.1 luotonen 184: }
185: }
186: }
187: }
188: closedir(dp);
189:
190: dir_match_failed:
2.24 frystyk 191: HT_FREE(dirname);
2.1 luotonen 192: return matches;
193: }
194:
195:
196: /*
197: ** Get the best match for a given file
198: ** -----------------------------------
199: ** On entry:
200: ** req->conversions accepted content-types
201: ** req->encodings accepted content-transfer-encodings
202: ** req->languages accepted content-languages
203: ** path absolute pathname of the filename for
204: ** which the match is desired.
205: ** On exit:
206: ** returns a newly allocated absolute filepath.
207: */
2.23 frystyk 208: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1 luotonen 209: {
210: HTList * matches;
211: HTList * cur;
212: HTContentDescription * cd;
213: HTContentDescription * best = NULL;
214: char * best_path = NULL;
215:
2.13 frystyk 216: if (!path || !*path) return NULL;
2.1 luotonen 217:
218: matches = dir_matches(path);
219: if (!matches) {
2.13 frystyk 220: if (PROT_TRACE)
2.25 eric 221: HTTrace("No matches.. for \"%s\"\n", path);
2.13 frystyk 222: return NULL;
2.1 luotonen 223: }
224:
225: /* BEGIN DEBUG */
226: cur = matches;
2.13 frystyk 227: if (PROT_TRACE)
2.25 eric 228: HTTrace("Multi....... Possibilities for \"%s\"\n", path);
2.13 frystyk 229: if (PROT_TRACE)
2.25 eric 230: HTTrace("\nCONTENT-TYPE LANGUAGE ENCODING QUALITY FILE\n");
2.1 luotonen 231: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.13 frystyk 232: if (PROT_TRACE)
2.25 eric 233: HTTrace("%s\t%s\t%s\t %.5f %s\n",
2.13 frystyk 234: cd->content_type ?HTAtom_name(cd->content_type) :"-\t",
235: cd->content_language?HTAtom_name(cd->content_language):"-",
236: cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
237: cd->quality,
238: cd->filename ?cd->filename :"-");
2.1 luotonen 239: }
2.25 eric 240: if (PROT_TRACE) HTTrace("\n");
2.1 luotonen 241: /* END DEBUG */
242:
243: /*
244: ** Finally get best that is readable
245: */
2.28 ! frystyk 246: if (HTRank(matches,
! 247: HTRequest_conversion(req),
! 248: HTRequest_language(req),
! 249: HTRequest_encoding(req))) {
2.1 luotonen 250: cur = matches;
251: while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
252: if (best && best->filename) {
253: if (access(best->filename, R_OK) != -1) {
254: StrAllocCopy(best_path, best->filename);
255: break;
2.13 frystyk 256: } else if (PROT_TRACE)
2.25 eric 257: HTTrace("Bad News.... \"%s\" is not readable\n",
2.1 luotonen 258: best->filename);
259: }
260: }
261: } /* Select best */
262:
263: cur = matches;
264: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.24 frystyk 265: if (cd->filename) HT_FREE(cd->filename);
266: HT_FREE(cd);
2.1 luotonen 267: }
268: HTList_delete(matches);
269:
270: return best_path;
271: }
272:
2.3 luotonen 273:
274:
2.23 frystyk 275: PRIVATE int welcome_value (char * name)
2.3 luotonen 276: {
277: HTList * cur = welcome_names;
278: char * welcome;
279: int v = 0;
280:
281: while ((welcome = (char*)HTList_nextObject(cur))) {
282: v++;
283: if (!strcmp(welcome,name)) return v;
284: }
285: return 0;
286: }
287:
288:
289:
2.23 frystyk 290: PRIVATE char * get_best_welcome (char * path)
2.3 luotonen 291: {
292: char * best_welcome = NULL;
293: int best_value = 0;
294: DIR * dp;
2.26 frystyk 295: struct dirent * dirbuf;
2.3 luotonen 296: char * last = strrchr(path, '/');
297:
298: if (!welcome_names) {
299: HTAddWelcome("Welcome.html");
300: HTAddWelcome("welcome.html");
2.5 luotonen 301: #if 0
2.3 luotonen 302: HTAddWelcome("Index.html");
2.5 luotonen 303: #endif
2.3 luotonen 304: HTAddWelcome("index.html");
305: }
306:
2.5 luotonen 307: if (last && last!=path) *last = 0;
2.3 luotonen 308: dp = opendir(path);
2.5 luotonen 309: if (last && last!=path) *last='/';
2.3 luotonen 310: if (!dp) {
2.13 frystyk 311: if (PROT_TRACE)
2.25 eric 312: HTTrace("Warning..... Can't open directory %s\n",path);
2.3 luotonen 313: return NULL;
314: }
315: while ((dirbuf = readdir(dp))) {
2.13 frystyk 316: if (!dirbuf->d_ino ||
2.3 luotonen 317: !strcmp(dirbuf->d_name,".") ||
318: !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 319: !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 320: continue;
321: else {
322: int v = welcome_value(dirbuf->d_name);
323: if (v > best_value) {
324: best_value = v;
325: StrAllocCopy(best_welcome, dirbuf->d_name);
326: }
327: }
328: }
329: closedir(dp);
330:
331: if (best_welcome) {
2.24 frystyk 332: char * welcome;
333: if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
334: HT_OUTOFMEM("get_best_welcome");
2.4 luotonen 335: sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.24 frystyk 336: HT_FREE(best_welcome);
2.13 frystyk 337: if (PROT_TRACE)
2.25 eric 338: HTTrace("Welcome..... \"%s\"\n",welcome);
2.3 luotonen 339: return welcome;
340: }
341: return NULL;
342: }
343:
2.26 frystyk 344: #endif /* HAVE_READDIR */
2.1 luotonen 345:
346:
347: /*
348: ** Do multiformat handling
349: ** -----------------------
350: ** On entry:
351: ** req->conversions accepted content-types
352: ** req->encodings accepted content-transfer-encodings
353: ** req->languages accepted content-languages
354: ** path absolute pathname of the filename for
355: ** which the match is desired.
356: ** stat_info pointer to result space.
357: **
358: ** On exit:
359: ** returns a newly allocated absolute filepath of the best
360: ** match, or NULL if no match.
361: ** stat_info will contain inode information as
362: ** returned by stat().
363: */
2.23 frystyk 364: PUBLIC char * HTMulti (HTRequest * req,
365: char * path,
366: struct stat * stat_info)
2.1 luotonen 367: {
368: char * new_path = NULL;
369: int stat_status = -1;
370:
2.3 luotonen 371: if (!req || !path || !*path || !stat_info)
2.1 luotonen 372: return NULL;
373:
2.26 frystyk 374: #ifdef HAVE_READDIR
2.19 frystyk 375: if (*(path+strlen(path)-1) == '/') { /* Find welcome page */
2.3 luotonen 376: new_path = get_best_welcome(path);
377: if (new_path) path = new_path;
2.1 luotonen 378: }
2.3 luotonen 379: else{
380: char * multi = strrchr(path, MULTI_SUFFIX[0]);
381: if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.13 frystyk 382: if (PROT_TRACE)
2.25 eric 383: HTTrace("Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1 luotonen 384: if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 385: if (PROT_TRACE)
2.25 eric 386: HTTrace("Multi....... failed -- giving up\n");
2.1 luotonen 387: return NULL;
388: }
389: path = new_path;
2.3 luotonen 390: }
391: else {
2.18 frystyk 392: stat_status = HT_STAT(path, stat_info);
2.3 luotonen 393: if (stat_status == -1) {
2.13 frystyk 394: if (PROT_TRACE)
2.25 eric 395: HTTrace(
2.13 frystyk 396: "AutoMulti... can't stat \"%s\"(errno %d)\n",
397: path, errno);
2.3 luotonen 398: if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 399: if (PROT_TRACE)
2.25 eric 400: HTTrace("AutoMulti... failed -- giving up\n");
2.3 luotonen 401: return NULL;
402: }
403: path = new_path;
404: }
2.1 luotonen 405: }
406: }
2.26 frystyk 407: #endif /* HAVE_READDIR */
2.1 luotonen 408:
409: if (stat_status == -1)
2.18 frystyk 410: stat_status = HT_STAT(path, stat_info);
2.1 luotonen 411: if (stat_status == -1) {
2.13 frystyk 412: if (PROT_TRACE)
2.25 eric 413: HTTrace("Stat fails.. on \"%s\" -- giving up (errno %d)\n",
2.13 frystyk 414: path, errno);
2.1 luotonen 415: return NULL;
416: }
417: else {
418: if (!new_path) {
419: StrAllocCopy(new_path, path);
420: return new_path;
421: }
422: else return path;
423: }
424: }
425:
426:
Webmaster