home *** CD-ROM | disk | FTP | other *** search
- /*
- * http_dir.c: Handles the on-the-fly html index generation
- *
- * All code contained herein is covered by the Copyright as distributed
- * in the README file in the main directory of the distribution of
- * NCSA HTTPD.
- *
- * 03-23-93 Rob McCool
- * Wrote base code up to release 1.3
- *
- * 03-12-95 blong
- * Added patch by Roy T. Fielding <fielding@avron.ICS.UCI.EDU>
- * to fix missing trailing slash for parent directory
- */
-
-
- /* httpd.h includes proper directory file */
- #include "httpd.h"
-
- struct ent {
- char *name;
- char *icon;
- char *alt;
- char *desc;
- size_t size;
- time_t lm;
- struct ent *next;
- };
-
-
- struct item {
- int type;
- char *apply_to;
- char *apply_path;
- char *data;
- struct item *next;
- };
-
-
- static struct item *icon_list, *alt_list, *desc_list, *ign_list;
- static struct item *hdr_list, *rdme_list, *opts_list;
-
- static int dir_opts;
-
- void init_indexing() {
- icon_list = NULL;
- alt_list = NULL;
- desc_list = NULL;
- ign_list = NULL;
-
- hdr_list = NULL;
- rdme_list = NULL;
- opts_list = NULL;
- }
-
- void kill_item_list(struct item *p) {
- struct item *q;
-
- while(p) {
- if(p->apply_to) free(p->apply_to);
- if(p->apply_path) free(p->apply_path);
- if(p->data) free(p->data);
- q = p;
- p = p->next;
- free(q);
- }
- }
-
- void kill_indexing() {
- kill_item_list(icon_list);
- kill_item_list(alt_list);
- kill_item_list(desc_list);
- kill_item_list(ign_list);
-
- kill_item_list(hdr_list);
- kill_item_list(rdme_list);
- kill_item_list(opts_list);
- }
-
- struct item *new_item(int type, char *to, char *path, char *data, FILE *out)
- {
- struct item *p;
-
- if(!(p = (struct item *)malloc(sizeof(struct item))))
- die(NO_MEMORY,"new_item",out);
-
- p->type = type;
- if(data) {
- if(!(p->data = strdup(data)))
- die(NO_MEMORY,"new_item",out);
- } else
- p->data = NULL;
-
- if(to) {
- if(!(p->apply_to = (char *)malloc(strlen(to) + 2)))
- die(NO_MEMORY,"new_item",out);
- if((type == BY_PATH) && (!is_matchexp(to))) {
- p->apply_to[0] = '*';
- strcpy(&p->apply_to[1],to);
- } else
- strcpy(p->apply_to,to);
- } else
- p->apply_to = NULL;
-
- if(!(p->apply_path = (char *)malloc(strlen(path) + 2)))
- die(NO_MEMORY,"new_item",out);
- sprintf(p->apply_path,"%s*",path);
-
- return p;
- }
-
- void add_alt(int type, char *alt, char *to, char *path, FILE *out) {
- struct item *p;
-
- if(type == BY_PATH) {
- if(!strcmp(to,"**DIRECTORY**"))
- strcpy(to,"^^DIRECTORY^^");
- }
- p = new_item(type,to,path,alt,out);
- p->next = alt_list;
- alt_list = p;
- }
-
- void add_icon(int type, char *icon, char *to, char *path, FILE *out) {
- struct item *p;
- char iconbak[MAX_STRING_LEN];
-
- strcpy(iconbak,icon);
- if(icon[0] == '(') {
- char alt[MAX_STRING_LEN];
- getword(alt,iconbak,',');
- add_alt(type,&alt[1],to,path,out);
- iconbak[strlen(iconbak) - 1] = '\0';
- }
- if(type == BY_PATH) {
- if(!strcmp(to,"**DIRECTORY**"))
- strcpy(to,"^^DIRECTORY^^");
- }
- p = new_item(type,to,path,iconbak,out);
- p->next = icon_list;
- icon_list = p;
- }
-
- void add_desc(int type, char *desc, char *to, char *path, FILE *out) {
- struct item *p;
-
- p = new_item(type,to,path,desc,out);
- p->next = desc_list;
- desc_list = p;
- }
-
- void add_ignore(char *ext, char *path, FILE *out) {
- struct item *p;
-
- p = new_item(0,ext,path,NULL,out);
- p->next = ign_list;
- ign_list = p;
- }
-
- void add_header(char *name, char *path, FILE *out) {
- struct item *p;
-
- p = new_item(0,NULL,path,name,out);
- p->next = hdr_list;
- hdr_list = p;
- }
-
- void add_readme(char *name, char *path, FILE *out) {
- struct item *p;
-
- p = new_item(0,NULL,path,name,out);
- p->next = rdme_list;
- rdme_list = p;
- }
-
-
- void add_opts_int(int opts, char *path, FILE *out) {
- struct item *p;
-
- p = new_item(0,NULL,path,NULL,out);
- p->type = opts;
- p->next = opts_list;
- opts_list = p;
- }
-
- void add_opts(char *optstr, char *path, FILE *out) {
- char w[MAX_STRING_LEN];
- int opts = 0;
-
- while(optstr[0]) {
- cfg_getword(w,optstr);
- if(!strcasecmp(w,"FancyIndexing"))
- opts |= FANCY_INDEXING;
- else if(!strcasecmp(w,"IconsAreLinks"))
- opts |= ICONS_ARE_LINKS;
- else if(!strcasecmp(w,"ScanHTMLTitles"))
- opts |= SCAN_HTML_TITLES;
- else if(!strcasecmp(w,"SuppressLastModified"))
- opts |= SUPPRESS_LAST_MOD;
- else if(!strcasecmp(w,"SuppressSize"))
- opts |= SUPPRESS_SIZE;
- else if(!strcasecmp(w,"SuppressDescription"))
- opts |= SUPPRESS_DESC;
- else if(!strcasecmp(w,"None"))
- opts = 0;
- }
- add_opts_int(opts,path,out);
- }
-
-
- char *find_item(struct item *list, char *path, int path_only) {
- struct item *p = list;
-
- while(p) {
- /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
- if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
- if(!(p->apply_to))
- return p->data;
- else if(p->type == BY_PATH) {
- if(!strcmp_match(path,p->apply_to))
- return p->data;
- } else if(!path_only) {
- char pathbak[MAX_STRING_LEN];
-
- strcpy(pathbak,path);
- content_encoding[0] = '\0';
- set_content_type(pathbak);
- if(!content_encoding[0]) {
- if(p->type == BY_TYPE) {
- if(!strcmp_match(content_type,p->apply_to))
- return p->data;
- }
- } else {
- if(p->type == BY_ENCODING) {
- if(!strcmp_match(content_encoding,p->apply_to))
- return p->data;
- }
- }
- }
- }
- p = p->next;
- }
- return NULL;
- }
-
- #define find_icon(p,t) find_item(icon_list,p,t)
- #define find_alt(p,t) find_item(alt_list,p,t)
- #define find_desc(p) find_item(desc_list,p,0)
- #define find_header(p) find_item(hdr_list,p,0)
- #define find_readme(p) find_item(rdme_list,p,0)
-
-
- int ignore_entry(char *path) {
- struct item *p = ign_list;
-
- while(p) {
- if(!strcmp_match(path,p->apply_path))
- if(!strcmp_match(path,p->apply_to))
- return 1;
- p = p->next;
- }
- return 0;
- }
-
- int find_opts(char *path) {
- struct item *p = opts_list;
-
- while(p) {
- if(!strcmp_match(path,p->apply_path))
- return p->type;
- p = p->next;
- }
- return 0;
- }
-
- int insert_readme(char *name, char *readme_fname, int rule, FILE *fd) {
- char fn[MAX_STRING_LEN];
- FILE *r;
- struct stat finfo;
- int plaintext=0;
-
- make_full_path(name,readme_fname,fn);
- strcat(fn,".html");
- if(stat(fn,&finfo) == -1) {
- fn[strlen(fn)-5] = '\0';
- if(stat(fn,&finfo) == -1)
- return 0;
- plaintext=1;
- if(rule) bytes_sent += fprintf(fd,"<HR>%c",LF);
- bytes_sent += fprintf(fd,"<PRE>%c",LF);
- }
- else if(rule) bytes_sent += fprintf(fd,"<HR>%c",LF);
- if(!(r = fopen(fn,"r")))
- return 0;
- send_fd(r,fd,NULL);
- fclose(r);
- if(plaintext)
- bytes_sent += fprintf(fd,"</PRE>%c",LF);
- return 1;
- }
-
-
- char *find_title(char *filename) {
- char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
- char filebak[MAX_STRING_LEN];
- FILE *thefile;
- int x,y,n,p;
-
- content_encoding[0] = '\0';
- strcpy(filebak,filename);
- set_content_type(filebak);
- if(((!strcmp(content_type,"text/html")) ||
- (strcmp(content_type,INCLUDES_MAGIC_TYPE)==0))
- && (!content_encoding[0]))
- {
- if(!(thefile = fopen(filename,"r")))
- return NULL;
- n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
- titlebuf[n] = '\0';
- for(x=0,p=0;titlebuf[x];x++) {
- if(toupper(titlebuf[x]) == find[p]) {
- if(!find[++p]) {
- if((p = ind(&titlebuf[++x],'<')) != -1)
- titlebuf[x+p] = '\0';
- /* Scan for line breaks for Tanmoy's secretary */
- for(y=x;titlebuf[y];y++)
- if((titlebuf[y] == CR) || (titlebuf[y] == LF))
- titlebuf[y] = ' ';
- fclose(thefile);
- return strdup(&titlebuf[x]);
- }
- } else p=0;
- }
- fclose(thefile);
- return NULL;
- }
- content_encoding[0] = '\0';
- return NULL;
- }
-
-
- void escape_html(char *fn) {
- register int x,y;
- char copy[MAX_STRING_LEN];
-
- strcpy(copy,fn);
- for(x=0,y=0;copy[y];x++,y++) {
- if(copy[y] == '<') {
- strcpy(&fn[x],"<");
- x+=3;
- }
- else if(copy[y] == '>') {
- strcpy(&fn[x],">");
- x+=3;
- }
- else if(copy[y] == '&') {
- strcpy(&fn[x],"&");
- x+=4;
- }
- else
- fn[x] = copy[y];
- }
- fn[x] = '\0';
- }
-
- struct ent *make_dir_entry(char *path, char *name, FILE *out) {
- struct ent *p;
- struct stat finfo;
- char t[MAX_STRING_LEN];
- char *tmp;
-
- if((name[0] == '.') && (!name[1]))
- return(NULL);
-
- make_full_path(path,name,t);
-
- if(ignore_entry(t))
- return(NULL);
-
- if(!(p=(struct ent *)malloc(sizeof(struct ent))))
- die(NO_MEMORY,"make_dir_entry",out);
- if(!(p->name=(char *)malloc(strlen(name) + 2)))
- die(NO_MEMORY,"make_dir_entry",out);
-
- if(dir_opts & FANCY_INDEXING) {
- if((!(dir_opts & FANCY_INDEXING)) || stat(t,&finfo) == -1) {
- strcpy(p->name,name);
- p->size = -1;
- p->icon = NULL;
- p->alt = NULL;
- p->desc = NULL;
- p->lm = -1;
- }
- else {
- p->lm = finfo.st_mtime;
- p->size = -1;
- p->icon = NULL;
- p->alt = NULL;
- p->desc = NULL;
- if(S_ISDIR(finfo.st_mode)) {
- if(!(p->icon = find_icon(t,1)))
- if (p->icon != NULL) free(p->icon);
- p->icon = find_icon("^^DIRECTORY^^",1);
- if(!(tmp = find_alt(t,1))){
- p->alt = (char *) malloc(sizeof(char)*4);
- strcpy(p->alt,"DIR");
- } else {
- p->alt = strdup(tmp);
- }
- p->size = -1;
- strncpy_dir(p->name,name,MAX_STRING_LEN);
- }
- else {
- p->icon = find_icon(t,0);
- tmp = find_alt(t,0);
- if (tmp != NULL) p->alt = strdup(tmp);
- p->size = finfo.st_size;
- strcpy(p->name,name);
- }
- }
- if(p->desc = find_desc(t))
- p->desc = strdup(p->desc);
- if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
- p->desc = find_title(t);
- }
- else {
- p->icon = NULL;
- p->alt = NULL;
- p->desc = NULL;
- p->size = -1;
- p->lm = -1;
- strcpy(p->name,name);
- }
- return(p);
- }
-
-
- void send_size(size_t size, FILE *fd) {
-
- if(size == -1) {
- fputs(" -",fd);
- bytes_sent += 5;
- }
- else {
- if(!size) {
- fputs(" 0K",fd);
- bytes_sent += 5;
- }
- else if(size < 1024) {
- fputs(" 1K",fd);
- bytes_sent += 5;
- }
- else if(size < 1048576)
- bytes_sent += fprintf(fd,"%4dK",size / 1024);
- else
- bytes_sent += fprintf(fd,"%4dM",size / 1048576);
- }
- }
-
- void terminate_description(char *desc) {
- int maxsize = 23;
- register int x;
-
- if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
- if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
-
- for(x=0;desc[x] && maxsize;x++) {
- if(desc[x] == '<') {
- while(desc[x] != '>') {
- if(!desc[x]) {
- maxsize = 0;
- break;
- }
- ++x;
- }
- }
- else --maxsize;
- }
- if(!maxsize) {
- desc[x] = '>';
- desc[x+1] = '\0';
- }
-
- }
-
- void output_directories(struct ent **ar,int n,char *name,FILE *fd)
- {
- int x;
- char anchor[2 * MAX_STRING_LEN + 64],t[MAX_STRING_LEN],t2[MAX_STRING_LEN];
- char *tp;
-
- if(name[0] == '\0') {
- name[0] = '/'; name[1] = '\0';
- }
- /* aaaaargh Solaris sucks. */
- fflush(fd);
-
- if(dir_opts & FANCY_INDEXING) {
- fputs("<PRE>",fd);
- bytes_sent += 5;
- if(tp = find_icon("^^BLANKICON^^",1))
- bytes_sent += (fprintf(fd,"<IMG SRC=\"%s\" ALT=\" \"> ",tp));
- bytes_sent += fprintf(fd,"Name ");
- if(!(dir_opts & SUPPRESS_LAST_MOD))
- bytes_sent += fprintf(fd,"Last modified ");
- if(!(dir_opts & SUPPRESS_SIZE))
- bytes_sent += fprintf(fd,"Size ");
- if(!(dir_opts & SUPPRESS_DESC))
- bytes_sent += fprintf(fd,"Description");
- bytes_sent += fprintf(fd,"%c<HR>%c",LF,LF);
- }
- else {
- fputs("<UL>",fd);
- bytes_sent += 4;
- }
-
- for(x=0;x<n;x++) {
- if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
-
- /* Fixes trailing slash for fancy indexing. Thanks Roy ? */
- make_full_path(name,"../",t);
- getparents(t);
- if(t[0] == '\0') {
- t[0] = '/'; t[1] = '\0';
- }
- escape_uri(t);
- sprintf(anchor,"<A HREF=\"%s\">",t);
- strcpy(t2,"Parent Directory</A>");
- }
- else {
- lim_strcpy(t,ar[x]->name, MAX_STRING_LEN);
- strcpy(t2,t);
- if(strlen(t2) > 21) {
- t2[21] = '>';
- t2[22] = '\0';
- }
- /* screws up formatting, but some need it. should fix. */
- /* escape_html(t2); */
- strcat(t2,"</A>");
- escape_uri(t);
- sprintf(anchor,"<A NAME=\"%s\" HREF=\"%s\">",t,t);
- }
- escape_url(t);
-
- if(dir_opts & FANCY_INDEXING) {
- if(dir_opts & ICONS_ARE_LINKS)
- bytes_sent += fprintf(fd,"%s",anchor);
- if((ar[x]->icon) || default_icon[0] || local_default_icon[0]) {
- bytes_sent += fprintf(fd,"<IMG SRC=\"%s\" ALT=\"[%s]\">",
- ar[x]->icon ? ar[x]->icon :
- local_default_icon[0] ?
- local_default_icon : default_icon,
- ar[x]->alt ? ar[x]->alt : " ");
- }
- if(dir_opts & ICONS_ARE_LINKS) {
- fputs("</A>",fd);
- bytes_sent += 4;
- }
- bytes_sent += fprintf(fd," %s",anchor);
- bytes_sent += fprintf(fd,"%-27.27s",t2);
- if(!(dir_opts & SUPPRESS_LAST_MOD)) {
- if(ar[x]->lm != -1) {
- struct tm *ts = localtime(&ar[x]->lm);
- strftime(t,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts);
- fputs(t,fd);
- bytes_sent += strlen(t);
- }
- else {
- fputs(" ",fd);
- bytes_sent += 17;
- }
- }
- if(!(dir_opts & SUPPRESS_SIZE)) {
- send_size(ar[x]->size,fd);
- fputs(" ",fd);
- bytes_sent += 2;
- }
- if(!(dir_opts & SUPPRESS_DESC)) {
- if(ar[x]->desc) {
- terminate_description(ar[x]->desc);
- bytes_sent += fprintf(fd,"%s",ar[x]->desc);
- }
- }
- }
- else
- bytes_sent += fprintf(fd,"<LI> %s %s",anchor,t2);
- fputc(LF,fd);
- ++bytes_sent;
- }
- if(dir_opts & FANCY_INDEXING) {
- fputs("</PRE>",fd);
- bytes_sent += 6;
- }
- else {
- fputs("</UL>",fd);
- bytes_sent += 5;
- }
- }
-
-
- int dsortf(struct ent **s1,struct ent **s2)
- {
- return(strcmp((*s1)->name,(*s2)->name));
- }
-
-
- void index_directory(char *name, FILE *fd)
- {
- DIR *d;
- struct DIR_TYPE *dstruct;
- int num_ent=0,x;
- struct ent *head,*p,*q;
- struct ent **ar;
- char unmunged_name[HUGE_STRING_LEN];
- char *tmp;
-
- strncpy_dir(unmunged_name,name,HUGE_STRING_LEN);
- unmunge_name(unmunged_name);
-
- if(!(d=opendir(name)))
- die(FORBIDDEN,unmunged_name,fd);
-
- strcpy(content_type,"text/html");
- if(!assbackwards)
- send_http_header(fd);
-
- if(header_only) {
- closedir(d);
- return;
- }
-
- bytes_sent = 0;
-
- dir_opts = find_opts(name);
-
- /* Spew HTML preamble */
- bytes_sent += fprintf(fd,"<HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>",
- unmunged_name);
- fputc(LF,fd);
- ++bytes_sent;
-
- if((!(tmp = find_header(name))) || (!(insert_readme(name,tmp,0,fd))))
- bytes_sent += fprintf(fd,"<H1>Index of %s</H1>%c",unmunged_name,LF);
-
- /*
- * Since we don't know how many dir. entries there are, put them into a
- * linked list and then arrayificate them so qsort can use them.
- */
- head=NULL;
- while(dstruct=readdir(d)) {
- if(p = make_dir_entry(name,dstruct->d_name,fd)) {
- p->next = head;
- head = p;
- num_ent++;
- }
- }
- if(!(ar=(struct ent **) malloc(num_ent*sizeof(struct ent *)))) {
- closedir(d);
- die(NO_MEMORY,"index_directory",fd);
- }
- p=head;
- x=0;
- while(p) {
- ar[x++]=p;
- p = p->next;
- }
-
- qsort((void *)ar,num_ent,sizeof(struct ent *),
- #ifdef ULTRIX_BRAIN_DEATH
- (int (*))dsortf);
- #else
- (int (*)(const void *,const void *))dsortf);
- #endif
- output_directories(ar,num_ent,unmunged_name,fd);
- free(ar);
- q = head;
- while(q) {
- p=q->next;
- free(q->name);
- if(q->desc)
- free(q->desc);
- if(q->alt)
- free(q->alt);
- free(q);
- q=p;
- }
- closedir(d);
- if(dir_opts & FANCY_INDEXING)
- if(tmp = find_readme(name))
- insert_readme(name,tmp,1,fd);
- else {
- fputs("</UL>",fd);
- bytes_sent += 5;
- }
-
- fputs("</BODY>",fd);
- fflush(fd);
- bytes_sent += 7;
- fflush(fd);
- log_transaction();
- }
-