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