PRIVATE BOOL HTRank (HTRequest * request, HTArray * variants) { HTContentDescription * cd; void ** data; if (!variants) { HTTRACE(PROT_TRACE, "Ranking..... No variants\n"); return NO; } /* ** Walk through the list of local and global preferences and find the ** overall q factor for each variant */ cd = (HTContentDescription *) HTArray_firstObject(variants, data); while (cd) { double ctq_local = type_value(cd->content_type, HTRequest_conversion(request)); double ctq_global = type_value(cd->content_type, HTFormat_conversion()); double clq_local = lang_value(cd->content_language, HTRequest_language(request)); double clq_global = lang_value(cd->content_language, HTFormat_language()); double ceq_local = encoding_value(cd->content_encoding, HTRequest_encoding(request)); double ceq_global = encoding_value(cd->content_encoding, HTFormat_contentCoding()); HTTRACE(PROT_TRACE, "Qualities... Content type: %.3f, Content language: %.3f, Content encoding: %.3f\n" _ HTMAX(ctq_local, ctq_global) _ HTMAX(clq_local, clq_global) _ HTMAX(ceq_local, ceq_global)); cd->quality *= (HTMAX(ctq_local, ctq_global) * HTMAX(clq_local, clq_global) * HTMAX(ceq_local, ceq_global)); cd = (HTContentDescription *) HTArray_nextObject(variants, data); } /* Sort the array of all our accepted preferences */ HTArray_sort(variants, VariantSort); /* Write out the result */ #ifdef HTDEBUG if (PROT_TRACE) { int cnt = 1; cd = (HTContentDescription *) HTArray_firstObject(variants, data); HTTRACE(PROT_TRACE, "Ranking.....\n"); HTTRACE(PROT_TRACE, "RANK QUALITY CONTENT-TYPE LANGUAGE ENCODING FILE\n"); while (cd) { HTTRACE(PROT_TRACE, "%d. %.4f %-20.20s %-8.8s %-10.10s %s\n" _ cnt++ _ cd->quality _ cd->content_type ? HTAtom_name(cd->content_type) : "-" _ cd->content_language?HTAtom_name(cd->content_language):"-" _ cd->content_encoding?HTAtom_name(cd->content_encoding):"-" _ cd->filename ? cd->filename :"-"); cd = (HTContentDescription *) HTArray_nextObject(variants, data); } } #endif /* HTDEBUG */ return YES; }
/* ** Before filter: Check whether we have a cache entry for this host */ PUBLIC int HTNewsCache_before (HTRequest * request, void * context, int mode) { char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request)); HTNewsCache * element = HTNewsCache_find(request, url); HT_FREE(url); /* ** If we have found a cache object then create a new dir obejct and fill ** it with data from the cache */ if (element) { char * title = GetNewsGroupTitle(request); HTNewsDir * dir = HTNewsDir_new(request, title, list_key, NO); void ** data = NULL; char * line = (char *) HTArray_firstObject(element->cache, data); while (line) { HTNewsDir_addGroupElement(dir, line, NO); line = (char *) HTArray_nextObject(element->cache, data); } /* ** After filling the new dir object we write it out and free it again */ HTNewsDir_free(dir); HT_FREE(title); return HT_LOADED; } return HT_OK; }
/* HTDir_free ** ---------- ** If we are sorting then do the sorting and put out the list, ** else just append the end of the list. */ PUBLIC BOOL HTDir_free (HTDir * dir) { if (!dir) return NO; if (dir->key != HT_DK_NONE) { HTArray *array = dir->array; void **data = NULL; HTDirNode *node; HTDir_headLine(dir); HTArray_sort(array, (dir->key==HT_DK_CINS ? DirCaseSort : DirSort)); node = (HTDirNode *) HTArray_firstObject(array, data); while (node) { HTDirNode_print(dir, node); HTDirNode_free(node); node = (HTDirNode *) HTArray_nextObject(array, data); } dir->size = HTArray_size(array); HTArray_delete(array); } /* Put out the end of the HTML stuff */ { HTStructured *target = dir->target; END(HTML_PRE); START(HTML_HR); START(HTML_PRE); if (!dir->size) PUTS("Empty directory"); else if (dir->size == 1) PUTS("1 File"); else { char buffer[20]; sprintf(buffer, "%u files", dir->size); PUTS(buffer); } END(HTML_PRE); END(HTML_BODY); END(HTML_HTML); FREE_TARGET; } HT_FREE(dir->fnbuf); HT_FREE(dir->lnbuf); HT_FREE(dir->base); HT_FREE(dir); return YES; }
/* ** Instead of just deleting we could save it to file. */ PRIVATE int HTNewsCache_delete (void * context) { HTNewsCache * me = (HTNewsCache *) context; if (me) { if (me->cache) { void ** data; char * line = (char *) HTArray_firstObject(me->cache, data); while (line) { HT_FREE(line); line = (char *) HTArray_nextObject(me->cache, data); } HTArray_delete(me->cache); } HT_FREE(me->host); HTTRACE(PROT_TRACE, "News Cache.. Deleted cache %p\n" _ me); HT_FREE(me); return YES; } return NO; }
/* HTNewsDir_free ** -------------- ** If we are sorting then do the sorting and put out the list, ** else just append the end of the list. */ PUBLIC BOOL HTNewsDir_free (HTNewsDir * dir) { if (!dir) return NO; if (dir->key != HT_NDK_NONE) { HTArray * array = dir->array; HTArray * cache = NULL; HTComparer * comp = NULL; /* ** Find a suitable sort key for this listing. The sort function ** depends on the type of new listing we have received. */ if (dir->key == HT_NDK_INDEX) /* Sort by Message Number */ comp = NDirIndexSort; else if (dir->key == HT_NDK_DATE) /* Sort by Date */ comp = NDirDateSort; else if (dir->key == HT_NDK_SUBJECT) /* Sort after Subject */ comp = NDirSubjectSort; else if (dir->key == HT_NDK_FROM) /* Sort after From */ comp = NDirFromSort; else if (dir->key == HT_NDK_GROUP) { /* Sort as group hierarchi */ comp = NDirGroupSort; } else if (dir->key == HT_NDK_REFTHREAD) { /* Added by MP. */ HTNewsDir_setRefInfo (dir); comp = NDirRefThreadSort; } else { HTTRACE(STREAM_TRACE, "NewsListing. Invalid sortkey\n"); return NO; } /* ** Now sort the array of news items that we have read with the sort ** function defined by the sort key above. */ HTArray_sort(array, comp); /* ** If we are showing a group listing then run through the list and ** identify group hierarchy. We have to sort the thing again in order ** to get the new template groups included */ if (dir->key == HT_NDK_GROUP) { HTNewsDir_setGroupInfo(dir); HTArray_sort(array, comp); } /* ** After we have sorted the listing, we can write out the result and ** free the array. */ { void ** data; HTNewsNode *node = (HTNewsNode *) HTArray_firstObject(array, data); while (node) { HTNewsNode_print(dir, node); /* ** Create a special array for the cache containing the group ** names only and no templates */ if (dir->key == HT_NDK_GROUP && !node->is_tmplate) HTArray_addObject(cache, node->name); HTNewsNode_delete(node, (dir->cache!=NULL)); node = (HTNewsNode *) HTArray_nextObject(array, data); } HTArray_delete(array); } /* Update the cache */ if (dir->cache) HTNewsCache_after(dir->request, NULL, dir->cache, 0); } /* Put out the end of the HTML stuff */ { HTStructured *target = dir->target; /* END(HTML_UL); */ HTNewsDir_addLevelTags (dir, -1); START(HTML_HR); END(HTML_BODY); END(HTML_HTML); FREE_TARGET; } /* Clean up the dir object */ HT_FREE(dir->name); HT_FREE(dir->tmplate); HT_FREE(dir); return YES; }
/* PRIVATE multi_match() ** ** Check if actual filename (split in parts) fulfills ** the requirements. */ PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n) { int c; int i,j; #ifdef VMS for(c=0; c<m && c<n && !strcasecomp(required[c], actual[c]); c++); #else /* not VMS */ for(c=0; c<m && c<n && !strcmp(required[c], actual[c]); c++); #endif /* not VMS */ if (!c) return NO; /* Names differ rigth from start */ for(i=c; i<m; i++) { BOOL found = NO; for(j=c; j<n; j++) { #ifdef VMS if (!strcasecomp(required[i], actual[j])) { #else /* not VMS */ if (!strcmp(required[i], actual[j])) { #endif /* not VMS */ found = YES; break; } } if (!found) return NO; } return YES; } /* ** Get multi-match possibilities for a given file ** ---------------------------------------------- ** On entry: ** path absolute path to one file in a directory, ** may end in .multi. ** On exit: ** returns a list of ContentDesription structures ** describing the mathing files. ** */ PRIVATE HTArray * dir_matches (char * path) { static char * required[MAX_SUFF+1]; static char * actual[MAX_SUFF+1]; int m,n; char * dirname = NULL; char * basename = NULL; int baselen; char * multi = NULL; DIR * dp; struct dirent * dirbuf; HTArray * matches = NULL; #ifdef HT_REENTRANT struct dirent result; /* For readdir_r */ #endif if (!path) return NULL; StrAllocCopy(dirname, path); basename = (strrchr(dirname, '/')); if (!basename) goto dir_match_failed; *basename++ = 0; multi = strrchr(basename, MULTI_SUFFIX[0]); if (multi && !strcasecomp(multi, MULTI_SUFFIX)) *multi = 0; baselen = strlen(basename); m = HTSplitFilename(basename, required); dp = opendir(dirname); if (!dp) { HTTRACE(PROT_TRACE, "Warning..... Can't open directory %s\n" _ dirname); goto dir_match_failed; } matches = HTArray_new(VARIANTS); #ifdef HAVE_READDIR_R_2 while ((dirbuf = (struct dirent *) readdir_r(dp, &result))) { #elif defined(HAVE_READDIR_R_3) while (readdir_r(dp, &result, &dirbuf) == 0) { #else while ((dirbuf = readdir(dp))) { #endif /* HAVE_READDIR_R_2 */ if (!dirbuf->d_ino) continue; /* Not in use */ if (!strcmp(dirbuf->d_name,".") || !strcmp(dirbuf->d_name,"..") || !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE)) continue; /* Use of direct->namlen is only valid in BSD'ish system */ /* Thanks to [email protected] (Chip Rosenthal) */ /* if ((int)(dirbuf->d_namlen) >= baselen) { */ if ((int) strlen(dirbuf->d_name) >= baselen) { n = HTSplitFilename(dirbuf->d_name, actual); if (multi_match(required, m, actual, n)) { HTContentDescription * cd; if ((cd = (HTContentDescription *) HT_CALLOC(1, sizeof(HTContentDescription))) == NULL) HT_OUTOFMEM("dir_matches"); if (HTBind_getFormat(dirbuf->d_name, &cd->content_type, &cd->content_encoding, &cd->content_transfer, &cd->content_language, &cd->quality)) { if (cd->content_type) { if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL) HT_OUTOFMEM("dir_matches"); sprintf(cd->filename, "%s/%s", dirname, dirbuf->d_name); HTArray_addObject(matches, (void *) cd); } else { HT_FREE(cd); } } else { HT_FREE(cd); } } } } closedir(dp); dir_match_failed: HT_FREE(dirname); return matches; } /* ** Get the best match for a given file ** ----------------------------------- ** On entry: ** req->conversions accepted content-types ** req->encodings accepted content-transfer-encodings ** req->languages accepted content-languages ** path absolute pathname of the filename for ** which the match is desired. ** On exit: ** returns a newly allocated absolute filepath. */ PRIVATE char * HTGetBest (HTRequest * req, char * path) { HTArray * variants = NULL; char * representation = NULL; if (!path || !*path) return NULL; if ((variants = dir_matches(path)) == NULL) { HTTRACE(PROT_TRACE, "No matches.. for \"%s\"\n" _ path); return NULL; } #ifdef HTDEBUG if (PROT_TRACE) { void ** data; HTContentDescription * cd = HTArray_firstObject(variants, data); HTTRACE(PROT_TRACE, "Multi....... Possibilities for \"%s\"\n" _ path); HTTRACE(PROT_TRACE, " QUALITY CONTENT-TYPE LANGUAGE ENCODING FILE\n"); while (cd) { HTTRACE(PROT_TRACE, " %.4f %-20.20s %-8.8s %-10.10s %s\n" _ cd->quality _ cd->content_type ?HTAtom_name(cd->content_type) :"-\t" _ cd->content_language?HTAtom_name(cd->content_language):"-" _ cd->content_encoding?HTAtom_name(cd->content_encoding):"-" _ cd->filename ?cd->filename :"-"); cd = (HTContentDescription *) HTArray_nextObject(variants, data); } } #endif /* HTDEBUG */ /* ** Finally get the best variant which is readable */ if (HTRank(req, variants)) { void ** data; HTContentDescription * cd = HTArray_firstObject(variants, data); while (cd) { if (cd->filename) { if (access(cd->filename, R_OK) != -1) StrAllocCopy(representation, cd->filename); else HTTRACE(PROT_TRACE, "Multi....... `%s\' is not readable\n" _ cd->filename); } HT_FREE(cd->filename); HT_FREE(cd); cd = (HTContentDescription *) HTArray_nextObject(variants, data); } } HTArray_delete(variants); return representation; } PRIVATE int welcome_value (char * name) { HTList * cur = welcome_names; char * welcome; int v = 0; while ((welcome = (char*)HTList_nextObject(cur))) { v++; if (!strcmp(welcome,name)) return v; } return 0; } PRIVATE char * get_best_welcome (char * path) { char * best_welcome = NULL; int best_value = 0; DIR * dp; struct dirent * dirbuf; char * last = strrchr(path, '/'); if (!welcome_names) { HTAddWelcome("Welcome.html"); HTAddWelcome("welcome.html"); #if 0 HTAddWelcome("Index.html"); #endif HTAddWelcome("index.html"); } if (last && last!=path) *last = 0; dp = opendir(path); if (last && last!=path) *last='/'; if (!dp) { HTTRACE(PROT_TRACE, "Warning..... Can't open directory %s\n" _ path); return NULL; } while ((dirbuf = readdir(dp))) { if (!dirbuf->d_ino || !strcmp(dirbuf->d_name,".") || !strcmp(dirbuf->d_name,"..") || !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE)) continue; else { int v = welcome_value(dirbuf->d_name); if (v > best_value) { best_value = v; StrAllocCopy(best_welcome, dirbuf->d_name); } } } closedir(dp); if (best_welcome) { char * welcome; if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL) HT_OUTOFMEM("get_best_welcome"); sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome); HT_FREE(best_welcome); HTTRACE(PROT_TRACE, "Welcome..... \"%s\"\n" _ welcome); return welcome; } return NULL; }