/* FLATTEN ALL ANCHORS ** ------------------- ** Flattens the anchor web structure into an array. ** This is useful for calculating statistics, sorting ** the parent anchors etc. ** ** The caller can indicate the size of the array (total ** number of anchors if known - otherwise 0). ** ** Return an array that must be freed by the caller or ** NULL if no anchors. */ PUBLIC HTArray * HTAnchor_getArray (int growby) { int cnt; HTArray * array = NULL; HTList * cur = NULL; if (!adult_table) return NULL; /* Allocate an array for the anchors */ if (growby <= 0) growby = PARENT_HASH_SIZE; array = HTArray_new(growby); /* Traverse anchor structure */ for (cnt=0; cnt<PARENT_HASH_SIZE; cnt++) { if ((cur = adult_table[cnt])) { HTParentAnchor * pres = NULL; while ((pres = (HTParentAnchor *) HTList_nextObject(cur)) != NULL) { if (HTArray_addObject(array, pres) == NO) { HTTRACE(ANCH_TRACE, "Anchor...... Can't add object %p to array %p\n" _ pres _ array); break; } } } } return array; }
/* HTDir_addElement ** --------------- ** This function accepts a directory line. "data" and "size", and ** "description" can all be NULL ** Returns YES if OK, else NO */ PUBLIC BOOL HTDir_addElement (HTDir *dir, char *name, char *date, char *size, HTFileMode mode) { HTDirNode *node = HTDirNode_new(); if (!dir || !name) return NO; if ((node->fname = (char *) HT_MALLOC(strlen(name) + 2)) == NULL) HT_OUTOFMEM("HTDir_addElement"); strcpy(node->fname, name); /* Mandatory */ if (dir->show & HT_DS_DATE && date) StrAllocCopy(node->date, date); if (dir->show & HT_DS_SIZE && size) StrAllocCopy(node->size, size); if (dir->show & HT_DS_DES) { #if 0 /* FIND DESCRIPTION */ #endif } /* Set the mode of the file */ node->mode = mode; /* Should we display now or later? */ if (dir->key == HT_DK_NONE) { if (!dir->size++) HTDir_headLine(dir); HTDirNode_print(dir, node); HTDirNode_free(node); } else { int slen = strlen(name); if (slen > dir->curfw) dir->curfw = slen < MaxFileW ? slen : MaxFileW; HTArray_addObject(dir->array, (void *) node); } return YES; }
/* Helper function - added by MP. */ PUBLIC HTNewsNode * HTNewsDir_addGroupElement (HTNewsDir * dir, char * group, BOOL tmplate) { HTNewsNode * node = NULL; if (dir && group) { if (HTNewsDir_belongsToSet(dir, group)) node=HTNewsDir_addElement (dir, 0, group, NULL, 0, group, 0, NULL); /* If we are building a cache object then add the entry */ if (dir->cache && !tmplate) { char * name = node ? node->name : NULL; if (!name) StrAllocCopy(name, group); HTArray_addObject(dir->cache, name); } } return node; }
/* HTNewsDir_addElement ** -------------------- ** This function accepts a news line. Everything except dir and name can ** can be 0 or NULL. ** Returns new node pointer if OK, else NULL ** Changed by MP: reference list added. ** Note: Unlike other parameters, refNames is not copied, but assigned, so ** it has to contain copies of message names, not the originals. */ PUBLIC HTNewsNode* HTNewsDir_addElement (HTNewsDir * dir, int index, char * subject, char * from, time_t date, char * name, int refs, HTList * refNames) { if (dir && name) { HTNewsNode * node = HTNewsNode_new(index, subject, from, date, name, refs, refNames); if (dir->key == HT_NDK_NONE) { HTNewsNode_print(dir, node); HTNewsNode_delete(node, (dir->cache!=NULL)); } else HTArray_addObject(dir->array, (void *) node); return node; } return NULL; }
PUBLIC HTArray * HTHashtable_keys (HTHashtable *me) { if(me) { HTArray *keys = HTArray_new(me->count); int i; for(i = 0; i< me->size; i++) { HTList * l = (HTList *)me->table[i]; if (l) { HTList *cur = l; keynode *kn; while ((kn = (keynode *) HTList_nextObject(cur))) { char * nkey = NULL; StrAllocCopy(nkey,kn->key); HTArray_addObject(keys,nkey); } } } return keys; } return NULL; }
/* 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; }