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