/* HTNewsDir_new ** ---------- ** Creates a structured stream object and sets up the initial HTML stuff ** Returns the newsdir object if OK, else NULL */ PUBLIC HTNewsDir * HTNewsDir_new (HTRequest * request, const char * title, HTNewsDirKey key, BOOL cache) { HTNewsDir *dir; if (!request) return NULL; /* Create object */ if ((dir = (HTNewsDir *) HT_CALLOC(1, sizeof (HTNewsDir))) == NULL) HT_OUTOFMEM("HTNewsDir_new"); dir->target = HTMLGenerator(request, NULL, WWW_HTML, HTRequest_outputFormat(request), HTRequest_outputStream(request)); HTAnchor_setFormat(HTRequest_anchor(request), WWW_HTML); dir->request = request; dir->key = key; dir->lastLevel = -1; /* Added by MP. */ /* Get the newsgroup(s) name; added by MP. */ { char* url = HTAnchor_physical(HTRequest_anchor(request)); char* p = url+strlen(url); while (p > url && p[-1] != ':' && p[-1] != '/' && p[-1] != '\\') p--; StrAllocCopy (dir->name, p); } if (key != HT_NDK_NONE) { /* Thread is unsorted */ int total = HTNews_maxArticles(); dir->array = HTArray_new(total > 0 ? total : 128); } /* If we are asked to prepare a cache entry then create the cache array */ if (cache) { int total = HTNews_maxArticles(); dir->cache = HTArray_new(total > 0 ? total : 128); } /* Start the HTML stuff */ { HTStructured *target = dir->target; const char *msg = title ? title : "News Listing"; START(HTML_HTML); START(HTML_HEAD); START(HTML_TITLE); PUTS(msg); END(HTML_TITLE); END(HTML_HEAD); START(HTML_BODY); START(HTML_H1); PUTS(msg); END(HTML_H1); } return dir; }
/* 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; }
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; }
/* 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; }
/* HTDir_new ** --------- ** Creates a structured stream object and sets up the initial HTML stuff ** Returns the dir object if OK, else NULL */ PUBLIC HTDir * HTDir_new (HTRequest * request, HTDirShow show, HTDirKey key) { HTDir *dir; char *title = NULL; if (!request) return NULL; /* Create object */ if ((dir = (HTDir *) HT_CALLOC(1, sizeof (HTDir))) == NULL || (dir->fnbuf = (char *) HT_MALLOC(MaxFileW+HT_DLEN_SPACE)) == NULL) HT_OUTOFMEM("HTDir_new"); dir->target = HTMLGenerator(request, NULL, WWW_HTML, HTRequest_outputFormat(request), HTRequest_outputStream(request)); HTRequest_setOutputConnected(request, YES); HTAnchor_setFormat(HTRequest_anchor(request), WWW_HTML); dir->request = request; dir->show = show; dir->key = key; if (key==HT_DK_NONE) dir->curfw = MaxFileW; else { dir->curfw = MinFileW; dir->array = HTArray_new(256); } /* We're all OK */ HTRequest_addError(request, ERR_INFO, NO, HTERR_OK, NULL, 0, "HTDir_new"); /* Find the length of the fields */ { int len = HT_DLEN_SPACE+1; if (show & HT_DS_SIZE) len += (HT_DLEN_SIZE+HT_DLEN_SPACE); if (show & HT_DS_DATE) len += (HT_DLEN_DATE+HT_DLEN_SPACE); if (show & HT_DS_DES) len += HT_DLEN_DES; if ((dir->lnbuf = (char *) HT_MALLOC(len)) == NULL) HT_OUTOFMEM("HTDir_new"); } /* Find the title and the base URL */ { char *addr = HTAnchor_address((HTAnchor *) HTRequest_anchor(request)); char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION); char *ptr; if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?'))) *ptr = '\0'; StrAllocCopy(title, path); HTUnEscape(title); /* Title */ if((ptr=strrchr(path, '/')) && (ptr<path+strlen(path)-1 || ptr==path)){ StrAllocCopy(dir->base, ++ptr); StrAllocCat(dir->base, "/"); } HTTRACE(PROT_TRACE, "HTDir_new... base is `%s\'\n" _ dir->base ? dir->base : ""); HT_FREE(addr); HT_FREE(path); } /* Start the HTML stuff */ { HTStructured *target = dir->target; START(HTML_HTML); START(HTML_HEAD); START(HTML_TITLE); PUTS("Current index is "); PUTS(title); END(HTML_TITLE); END(HTML_HEAD); START(HTML_BODY); START(HTML_H1); PUTS("Index of "); PUTS(title); END(HTML_H1); } HT_FREE(title); return dir; }