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