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