Annotation of libwww/Library/src/HTMulti.c, revision 2.14
2.11 frystyk 1: /* HTMulti.c
2: ** MULTIFORMAT HANDLING
3: **
4: ** (c) COPYRIGHT CERN 1994.
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"
20:
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;
135:
136: if (!path) return NULL;
137:
138: StrAllocCopy(dirname, path);
139: basename = (strrchr(dirname, '/'));
140: if (!basename)
141: goto dir_match_failed;
142: *basename++ = 0;
143:
144: multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2 duns 145: if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1 luotonen 146: *multi = 0;
147: baselen = strlen(basename);
148:
149: m = HTSplitFilename(basename, required);
150:
151: dp = opendir(dirname);
152: if (!dp) {
2.13 frystyk 153: if (PROT_TRACE)
154: fprintf(TDEST,"Warning..... Can't open directory %s\n", dirname);
2.1 luotonen 155: goto dir_match_failed;
156: }
157:
158: matches = HTList_new();
159: while ((dirbuf = readdir(dp))) {
160: if (!dirbuf->d_ino) continue; /* Not in use */
2.3 luotonen 161: if (!strcmp(dirbuf->d_name,".") ||
162: !strcmp(dirbuf->d_name,"..") ||
2.10 frystyk 163: !strcmp(dirbuf->d_name, HT_DIR_ENABLE_FILE))
2.3 luotonen 164: continue;
2.7 frystyk 165:
2.13 frystyk 166: /* Use of direct->namlen is only valid in BSD'ish system */
167: /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
168: /* if ((int)(dirbuf->d_namlen) >= baselen) { */
169: if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1 luotonen 170: n = HTSplitFilename(dirbuf->d_name, actual);
171: if (multi_match(required, m, actual, n)) {
172: HTContentDescription * cd;
2.14 ! frystyk 173: cd = HTBind_getDescription(dirbuf->d_name);
2.1 luotonen 174: if (cd) {
175: if (cd->content_type) {
176: cd->filename = (char*)malloc(strlen(dirname) + 2 +
177: strlen(dirbuf->d_name));
178: if (!cd->filename) outofmem(__FILE__, "dir_matches");
179: sprintf(cd->filename, "%s/%s",
180: dirname, dirbuf->d_name);
181: HTList_addObject(matches, (void*)cd);
182: }
183: else free(cd);
184: }
185: }
186: }
187: }
188: closedir(dp);
189:
190: dir_match_failed:
191: free(dirname);
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: */
208: PRIVATE char * HTGetBest ARGS2(HTRequest *, req,
209: char *, path)
210: {
211: HTList * matches;
212: HTList * cur;
213: HTContentDescription * cd;
214: HTContentDescription * best = NULL;
215: char * best_path = NULL;
216:
2.13 frystyk 217: if (!path || !*path) return NULL;
2.1 luotonen 218:
219: matches = dir_matches(path);
220: if (!matches) {
2.13 frystyk 221: if (PROT_TRACE)
222: fprintf(TDEST, "No matches.. for \"%s\"\n", path);
223: return NULL;
2.1 luotonen 224: }
225:
226: /* BEGIN DEBUG */
227: cur = matches;
2.13 frystyk 228: if (PROT_TRACE)
229: fprintf(TDEST, "Multi....... Possibilities for \"%s\"\n", path);
230: if (PROT_TRACE)
231: fprintf(TDEST, "\nCONTENT-TYPE LANGUAGE ENCODING QUALITY FILE\n");
2.1 luotonen 232: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.13 frystyk 233: if (PROT_TRACE)
234: fprintf(TDEST, "%s\t%s\t%s\t %.5f %s\n",
235: cd->content_type ?HTAtom_name(cd->content_type) :"-\t",
236: cd->content_language?HTAtom_name(cd->content_language):"-",
237: cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
238: cd->quality,
239: cd->filename ?cd->filename :"-");
2.1 luotonen 240: }
2.13 frystyk 241: if (PROT_TRACE) fprintf(TDEST, "\n");
2.1 luotonen 242: /* END DEBUG */
243:
244: /*
245: ** Finally get best that is readable
246: */
247: if (HTRank(matches, req->conversions, req->languages, req->encodings)) {
248: cur = matches;
249: while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
250: if (best && best->filename) {
251: if (access(best->filename, R_OK) != -1) {
252: StrAllocCopy(best_path, best->filename);
253: break;
2.13 frystyk 254: } else if (PROT_TRACE)
255: fprintf(TDEST, "Bad News.... \"%s\" is not readable\n",
2.1 luotonen 256: best->filename);
257: }
258: }
259: } /* Select best */
260:
261: cur = matches;
262: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
263: if (cd->filename) free(cd->filename);
264: free(cd);
265: }
266: HTList_delete(matches);
267:
268: return best_path;
269: }
270:
2.3 luotonen 271:
272:
273: PRIVATE int welcome_value ARGS1(char *, name)
274: {
275: HTList * cur = welcome_names;
276: char * welcome;
277: int v = 0;
278:
279: while ((welcome = (char*)HTList_nextObject(cur))) {
280: v++;
281: if (!strcmp(welcome,name)) return v;
282: }
283: return 0;
284: }
285:
286:
287:
288: PRIVATE char * get_best_welcome ARGS1(char *, path)
289: {
290: char * best_welcome = NULL;
291: int best_value = 0;
292: DIR * dp;
2.13 frystyk 293: STRUCT_DIRENT * dirbuf;
2.3 luotonen 294: char * last = strrchr(path, '/');
295:
296: if (!welcome_names) {
297: HTAddWelcome("Welcome.html");
298: HTAddWelcome("welcome.html");
2.5 luotonen 299: #if 0
2.3 luotonen 300: HTAddWelcome("Index.html");
2.5 luotonen 301: #endif
2.3 luotonen 302: HTAddWelcome("index.html");
303: }
304:
2.5 luotonen 305: if (last && last!=path) *last = 0;
2.3 luotonen 306: dp = opendir(path);
2.5 luotonen 307: if (last && last!=path) *last='/';
2.3 luotonen 308: if (!dp) {
2.13 frystyk 309: if (PROT_TRACE)
310: fprintf(TDEST, "Warning..... Can't open directory %s\n",path);
2.3 luotonen 311: return NULL;
312: }
313: while ((dirbuf = readdir(dp))) {
2.13 frystyk 314: if (!dirbuf->d_ino ||
2.3 luotonen 315: !strcmp(dirbuf->d_name,".") ||
316: !strcmp(dirbuf->d_name,"..") ||
2.10 frystyk 317: !strcmp(dirbuf->d_name, HT_DIR_ENABLE_FILE))
2.3 luotonen 318: continue;
319: else {
320: int v = welcome_value(dirbuf->d_name);
321: if (v > best_value) {
322: best_value = v;
323: StrAllocCopy(best_welcome, dirbuf->d_name);
324: }
325: }
326: }
327: closedir(dp);
328:
329: if (best_welcome) {
330: char * welcome = (char*)malloc(strlen(path) + strlen(best_welcome)+2);
331: if (!welcome) outofmem(__FILE__, "get_best_welcome");
2.4 luotonen 332: sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.3 luotonen 333: free(best_welcome);
2.13 frystyk 334: if (PROT_TRACE)
335: fprintf(TDEST,"Welcome..... \"%s\"\n",welcome);
2.3 luotonen 336: return welcome;
337: }
338: return NULL;
339: }
340:
2.13 frystyk 341: #endif /* GOT_READ_DIR */
2.1 luotonen 342:
343:
344: /*
345: ** Do multiformat handling
346: ** -----------------------
347: ** On entry:
348: ** req->conversions accepted content-types
349: ** req->encodings accepted content-transfer-encodings
350: ** req->languages accepted content-languages
351: ** path absolute pathname of the filename for
352: ** which the match is desired.
353: ** stat_info pointer to result space.
354: **
355: ** On exit:
356: ** returns a newly allocated absolute filepath of the best
357: ** match, or NULL if no match.
358: ** stat_info will contain inode information as
359: ** returned by stat().
360: */
361: PUBLIC char * HTMulti ARGS3(HTRequest *, req,
362: char *, path,
363: struct stat *, stat_info)
364: {
365: char * new_path = NULL;
366: int stat_status = -1;
2.3 luotonen 367: int len;
2.1 luotonen 368:
2.3 luotonen 369: if (!req || !path || !*path || !stat_info)
2.1 luotonen 370: return NULL;
371:
2.13 frystyk 372: #ifdef GOT_READ_DIR
2.3 luotonen 373: len = strlen(path);
374: if (path[len-1] == '/') { /* Find welcome page */
375: new_path = get_best_welcome(path);
376: if (new_path) path = new_path;
2.1 luotonen 377: }
2.3 luotonen 378: else{
379: char * multi = strrchr(path, MULTI_SUFFIX[0]);
380: if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.13 frystyk 381: if (PROT_TRACE)
382: fprintf(TDEST, "Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1 luotonen 383: if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 384: if (PROT_TRACE)
385: fprintf(TDEST, "Multi....... failed -- giving up\n");
2.1 luotonen 386: return NULL;
387: }
388: path = new_path;
2.3 luotonen 389: }
390: else {
2.9 duns 391: stat_status = HTStat(path, stat_info);
2.3 luotonen 392: if (stat_status == -1) {
2.13 frystyk 393: if (PROT_TRACE)
394: fprintf(TDEST,
395: "AutoMulti... can't stat \"%s\"(errno %d)\n",
396: path, errno);
2.3 luotonen 397: if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 398: if (PROT_TRACE)
399: fprintf(TDEST, "AutoMulti... failed -- giving up\n");
2.3 luotonen 400: return NULL;
401: }
402: path = new_path;
403: }
2.1 luotonen 404: }
405: }
2.13 frystyk 406: #endif /* GOT_READ_DIR */
2.1 luotonen 407:
408: if (stat_status == -1)
2.9 duns 409: stat_status = HTStat(path, stat_info);
2.1 luotonen 410: if (stat_status == -1) {
2.13 frystyk 411: if (PROT_TRACE)
412: fprintf(TDEST, "Stat fails.. on \"%s\" -- giving up (errno %d)\n",
413: path, errno);
2.1 luotonen 414: return NULL;
415: }
416: else {
417: if (!new_path) {
418: StrAllocCopy(new_path, path);
419: return new_path;
420: }
421: else return path;
422: }
423: }
424:
425:
Webmaster