home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / mod_dir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-21  |  24.7 KB  |  847 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /*
  56.  * http_dir.c: Handles the on-the-fly html index generation
  57.  * 
  58.  * Rob McCool
  59.  * 3/23/93
  60.  * 
  61.  * Adapted to Shambhala by rst.
  62.  */
  63.  
  64. #include "httpd.h"
  65. #include "http_config.h"
  66. #include "http_core.h"
  67. #include "http_request.h"
  68. #include "http_protocol.h"
  69. #include "http_log.h"
  70. #include "http_main.h"
  71. #include "util_script.h"
  72.  
  73. module dir_module;
  74.  
  75. /****************************************************************
  76.  *
  77.  * Handling configuration directives...
  78.  */
  79.  
  80. #define FANCY_INDEXING 1    /* Indexing options */
  81. #define ICONS_ARE_LINKS 2
  82. #define SCAN_HTML_TITLES 4
  83. #define SUPPRESS_LAST_MOD 8
  84. #define SUPPRESS_SIZE 16
  85. #define SUPPRESS_DESC 32
  86.  
  87. struct item {
  88.     char *type;
  89.     char *apply_to;
  90.     char *apply_path;
  91.     char *data;
  92. };
  93.  
  94. typedef struct dir_config_struct {
  95.  
  96.     char *default_icon;
  97.     char *index_names;
  98.   
  99.     array_header *icon_list, *alt_list, *desc_list, *ign_list;
  100.     array_header *hdr_list, *rdme_list, *opts_list;
  101.   
  102. } dir_config_rec;
  103.  
  104. char c_by_encoding, c_by_type, c_by_path;
  105.  
  106. #define BY_ENCODING &c_by_encoding
  107. #define BY_TYPE &c_by_type
  108. #define BY_PATH &c_by_path
  109.  
  110. void push_item(array_header *arr, char *type, char *to, char *path, char *data)
  111. {
  112.     struct item *p = (struct item *)push_array(arr);
  113.  
  114.     if (!to) to = "";
  115.     if (!path) path = "";
  116.     
  117.     p->type = type;
  118.     p->data = data ? pstrdup(arr->pool, data): NULL;
  119.     p->apply_path = pstrcat(arr->pool, path, "*", NULL);
  120.     
  121.     if((type == BY_PATH) && (!is_matchexp(to)))
  122.         p->apply_to = pstrcat (arr->pool, "*", to, NULL);
  123.     else if (to)
  124.         p->apply_to = pstrdup (arr->pool, to);
  125.     else
  126.         p->apply_to = NULL;
  127. }
  128.  
  129. char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to)
  130. {
  131.     if (cmd->info == BY_PATH)
  132.         if(!strcmp(to,"**DIRECTORY**"))
  133.             to = "^^DIRECTORY^^";
  134.  
  135.     push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt);
  136.     return NULL;
  137. }
  138.  
  139. char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
  140. {
  141.     char *iconbak = pstrdup (cmd->pool, icon);
  142.  
  143.     if(icon[0] == '(') {
  144.         char *alt = getword (cmd->pool, &iconbak, ',');
  145.         iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */
  146.         add_alt(cmd, d, &alt[1], to);
  147.     }
  148.     if(cmd->info == BY_PATH) 
  149.         if(!strcmp(to,"**DIRECTORY**"))
  150.             to = "^^DIRECTORY^^";
  151.  
  152.     push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path,
  153.           iconbak);
  154.     return NULL;
  155. }
  156.  
  157. char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to)
  158. {
  159.     push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc);
  160.     return NULL;
  161. }
  162.  
  163. char *add_ignore(cmd_parms *cmd, void *d, char *ext) {
  164.     push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL);
  165.     return NULL;
  166. }
  167.  
  168. char *add_header(cmd_parms *cmd, void *d, char *name) {
  169.     push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name);
  170.     return NULL;
  171. }
  172.  
  173. char *add_readme(cmd_parms *cmd, void *d, char *name) {
  174.     push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name);
  175.     return NULL;
  176. }
  177.  
  178.  
  179. char *add_opts_int(cmd_parms *cmd, void *d, int opts) {
  180.     push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL,
  181.           cmd->path, NULL);
  182.     return NULL;
  183. }
  184.  
  185. char *fancy_indexing (cmd_parms *cmd, void *d, int arg)
  186. {
  187.     return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0);
  188. }
  189.  
  190. char *add_opts(cmd_parms *cmd, void *d, char *optstr) {
  191.     char *w;
  192.     int opts = 0;
  193.  
  194.     while(optstr[0]) {
  195.         w = getword_conf(cmd->pool, &optstr);
  196.         if(!strcasecmp(w,"FancyIndexing"))
  197.             opts |= FANCY_INDEXING;
  198.         else if(!strcasecmp(w,"IconsAreLinks"))
  199.             opts |= ICONS_ARE_LINKS;
  200.         else if(!strcasecmp(w,"ScanHTMLTitles"))
  201.             opts |= SCAN_HTML_TITLES;
  202.         else if(!strcasecmp(w,"SuppressLastModified"))
  203.             opts |= SUPPRESS_LAST_MOD;
  204.         else if(!strcasecmp(w,"SuppressSize"))
  205.             opts |= SUPPRESS_SIZE;
  206.         else if(!strcasecmp(w,"SuppressDescription"))
  207.             opts |= SUPPRESS_DESC;
  208.         else if(!strcasecmp(w,"None"))
  209.             opts = 0;
  210.     else
  211.         return "Invalid directory indexing option";
  212.     }
  213.     return add_opts_int(cmd, d, opts);
  214. }
  215.  
  216. #define DIR_CMD_PERMS OR_INDEXES
  217.  
  218. command_rec dir_cmds[] = {
  219. { "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2,
  220.     "an icon URL followed by one or more filenames" },
  221. { "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
  222.     "an icon URL followed by one or more MIME types" },
  223. { "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
  224.     "an icon URL followed by one or more content encodings" },
  225. { "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2,
  226.     "alternate descriptive text followed by one or more filenames" },
  227. { "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
  228.     "alternate descriptive text followed by one or more MIME types" },
  229. { "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
  230.     "alternate descriptive text followed by one or more content encodings" },
  231. { "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS,
  232.     "one or more index options" },
  233. { "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE,
  234.     "one or more file extensions" },
  235. { "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2,
  236.     "Descriptive text followed by one or more filenames" },
  237. { "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
  238. { "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
  239. { "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL },
  240. { "DefaultIcon", set_string_slot,
  241.     (void*)XtOffsetOf(dir_config_rec, default_icon),
  242.     DIR_CMD_PERMS, TAKE1, "an icon URL"},
  243. { "DirectoryIndex", set_string_slot,
  244.     (void*)XtOffsetOf(dir_config_rec, index_names),
  245.     DIR_CMD_PERMS, RAW_ARGS, NULL },
  246. { NULL }
  247. };
  248.  
  249. void *create_dir_config (pool *p, char *dummy)
  250. {
  251.     dir_config_rec *new =
  252.         (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec));
  253.  
  254.     new->index_names = NULL;
  255.     new->icon_list = make_array (p, 4, sizeof (struct item));
  256.     new->alt_list = make_array (p, 4, sizeof (struct item));
  257.     new->desc_list = make_array (p, 4, sizeof (struct item));
  258.     new->ign_list = make_array (p, 4, sizeof (struct item));
  259.     new->hdr_list = make_array (p, 4, sizeof (struct item));
  260.     new->rdme_list = make_array (p, 4, sizeof (struct item));
  261.     new->opts_list = make_array (p, 4, sizeof (struct item));
  262.     
  263.     return (void *)new;
  264. }
  265.  
  266. void *merge_dir_configs (pool *p, void *basev, void *addv)
  267. {
  268.     dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec));
  269.     dir_config_rec *base = (dir_config_rec *)basev;
  270.     dir_config_rec *add = (dir_config_rec *)addv;
  271.  
  272.     new->default_icon = add->default_icon?add->default_icon:base->default_icon;
  273.     new->index_names = add->index_names? add->index_names: base->index_names;
  274.  
  275.     new->alt_list = append_arrays (p, add->alt_list, base->alt_list);
  276.     new->ign_list = append_arrays (p, add->ign_list, base->ign_list);
  277.     new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list);
  278.     new->desc_list = append_arrays (p, add->desc_list, base->desc_list);
  279.     new->icon_list = append_arrays (p, add->icon_list, base->icon_list);
  280.     new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list);
  281.     new->opts_list = append_arrays (p, add->opts_list, base->opts_list);
  282.     
  283.     return new;
  284. }
  285.  
  286. /****************************************************************
  287.  *
  288.  * Looking things up in config entries...
  289.  */
  290.  
  291. /* Structure used to hold entries when we're actually building an index */
  292.  
  293. struct ent {
  294.     char *name;
  295.     char *icon;
  296.     char *alt;
  297.     char *desc;
  298.     size_t size;
  299.     time_t lm;
  300.     struct ent *next;
  301. };
  302.  
  303. char *find_item(request_rec *r, array_header *list, int path_only) {
  304.     char *content_type = r->content_type;
  305.     char *content_encoding = r->content_encoding;
  306.     char *path = r->filename;
  307.  
  308.     struct item *items = (struct item *)list->elts;
  309.     int i;
  310.  
  311.     for (i = 0; i < list->nelts; ++i) {
  312.         struct item *p = &items[i];
  313.       
  314.         /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
  315.         if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
  316.             if(!*(p->apply_to))
  317.                 return p->data;
  318.             else if(p->type == BY_PATH || path[0] == '^') {
  319.                 if(!strcmp_match(path,p->apply_to))
  320.                     return p->data;
  321.             } else if(!path_only) {
  322.                 if(!content_encoding) {
  323.                     if(p->type == BY_TYPE) {
  324.                         if(content_type && !strcmp_match(content_type,p->apply_to))
  325.                             return p->data;
  326.                     }
  327.                 } else {
  328.                     if(p->type == BY_ENCODING) {
  329.                         if(!strcmp_match(content_encoding,p->apply_to))
  330.                             return p->data;
  331.                     }
  332.                 }
  333.             }
  334.         }
  335.     }
  336.     return NULL;
  337. }
  338.  
  339. #define find_icon(d,p,t) find_item(p,d->icon_list,t)
  340. #define find_alt(d,p,t) find_item(p,d->alt_list,t)
  341. #define find_desc(d,p) find_item(p,d->desc_list,0)
  342. #define find_header(d,p) find_item(p,d->hdr_list,0)
  343. #define find_readme(d,p) find_item(p,d->rdme_list,0)
  344.  
  345. char *find_default_icon (dir_config_rec *d, char *bogus_name)
  346. {
  347.     request_rec r;
  348.  
  349.     /* Bleah.  I tried to clean up find_item, and it lead to this bit
  350.      * of ugliness.   Note that the fields initialized are precisely
  351.      * those that find_item looks at...
  352.      */
  353.     
  354.     r.filename = bogus_name;
  355.     r.content_type = r.content_encoding = NULL;
  356.  
  357.     return find_item (&r, d->icon_list, 1);
  358. }
  359.  
  360. int ignore_entry(dir_config_rec *d, char *path) {
  361.     array_header *list = d->ign_list;
  362.     struct item *items = (struct item *)list->elts;
  363.     char *tt;
  364.     int i;
  365.  
  366.     if((tt=strrchr(path,'/')) == NULL)
  367.       tt=path;
  368.     else {
  369.       tt++;
  370.     }
  371.  
  372.     for (i = 0; i < list->nelts; ++i) {
  373.         struct item *p = &items[i];
  374.     char *ap;
  375.  
  376.     if((ap=strrchr(p->apply_to,'/')) == NULL)
  377.       ap=p->apply_to;
  378.     else
  379.       ap++;
  380.  
  381.         if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap))
  382.        return 1;
  383.     }
  384.     return 0;
  385. }
  386.  
  387. int find_opts(dir_config_rec *d, request_rec *r) {
  388.     char *path = r->filename;
  389.     array_header *list = d->opts_list;
  390.     struct item *items = (struct item *)list->elts;
  391.     int i;
  392.  
  393.     for (i = 0; i < list->nelts; ++i) {
  394.         struct item *p = &items[i];
  395.     
  396.         if(!strcmp_match(path,p->apply_path))
  397.             return (int)p->type;
  398.     }
  399.     return 0;
  400. }
  401.  
  402. /*****************************************************************
  403.  *
  404.  * Actually generating output
  405.  */
  406.  
  407.  
  408. int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) {
  409.     char *fn;
  410.     FILE *f;
  411.     struct stat finfo;
  412.     int plaintext=0;
  413.  
  414.     fn = make_full_path(r->pool, name, readme_fname);
  415.     fn = pstrcat(r->pool, fn, ".html", NULL);
  416.     if(stat(fn,&finfo) == -1) {
  417.         /* A brief fake multiviews search for README.html */
  418.         fn[strlen(fn)-5] = '\0';
  419.         if(stat(fn,&finfo) == -1)
  420.             return 0;
  421.         plaintext=1;
  422.         if(rule) rputs("<HR>\n", r);
  423.         rputs("<PRE>\n", r);
  424.     }
  425.     else if (rule) rputs("<HR>\n", r);
  426.     if(!(f = pfopen(r->pool,fn,"r")))
  427.         return 0;
  428.     if (!plaintext)
  429.     send_fd(f, r);
  430.     else
  431.     {
  432.     char buf[IOBUFSIZE+1];
  433.     int i, n, c, ch;
  434.     while (!feof(f))
  435.     {
  436.         do n = fread(buf, sizeof(char), IOBUFSIZE, f);
  437.         while (n == -1 && ferror(f) && errno == EINTR);
  438.         if (n == -1 || n == 0) break;
  439.         buf[n] = '\0';
  440.         c = 0;
  441.         while (c < n)
  442.         {
  443.         for (i=c; i < n; i++)
  444.             if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') break;
  445.         ch = buf[i];
  446.         buf[i] = '\0';
  447.         rputs(&buf[c], r);
  448.         if (ch == '<') rputs("<", r);
  449.         else if (ch == '>') rputs(">", r);
  450.         else if (ch == '&') rputs("&", r);
  451.         c = i + 1;
  452.         }
  453.     }
  454.     }
  455.     pfclose(r->pool, f);
  456.     if(plaintext)
  457.         rputs("</PRE>\n", r);
  458.     return 1;
  459. }
  460.  
  461.  
  462. char *find_title(request_rec *r) {
  463.     char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
  464.     FILE *thefile = NULL;
  465.     int x,y,n,p;
  466.  
  467.     if (r->content_type && !strcmp(r->content_type,"text/html") && !r->content_encoding) {
  468.         if(!(thefile = pfopen(r->pool, r->filename,"r")))
  469.             return NULL;
  470.         n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
  471.         titlebuf[n] = '\0';
  472.         for(x=0,p=0;titlebuf[x];x++) {
  473.             if(toupper(titlebuf[x]) == find[p]) {
  474.                 if(!find[++p]) {
  475.                     if((p = ind(&titlebuf[++x],'<')) != -1)
  476.                         titlebuf[x+p] = '\0';
  477.                     /* Scan for line breaks for Tanmoy's secretary */
  478.                     for(y=x;titlebuf[y];y++)
  479.                         if((titlebuf[y] == CR) || (titlebuf[y] == LF))
  480.                             titlebuf[y] = ' ';
  481.             pfclose (r->pool, thefile);
  482.                     return pstrdup(r->pool, &titlebuf[x]);
  483.                 }
  484.             } else p=0;
  485.         }
  486.     pfclose(r->pool, thefile);
  487.     }
  488.     return NULL;
  489. }
  490.  
  491. struct ent *make_dir_entry(char *name, int dir_opts,
  492.                dir_config_rec *d, request_rec *r)
  493. {
  494.     struct ent *p;
  495.  
  496.     if((name[0] == '.') && (!name[1]))
  497.         return(NULL);
  498.  
  499.     if (ignore_entry(d, make_full_path (r->pool, r->filename, name)))
  500.         return(NULL);
  501.  
  502.     p=(struct ent *)pcalloc(r->pool, sizeof(struct ent));
  503.     p->name = pstrdup (r->pool, name);
  504.     p->size = -1;
  505.     p->icon = NULL;
  506.     p->alt = NULL;
  507.     p->desc = NULL;
  508.     p->lm = -1;
  509.  
  510.     if(dir_opts & FANCY_INDEXING) {
  511.         request_rec *rr = sub_req_lookup_file (name, r);
  512.     
  513.     if (rr->finfo.st_mode != 0) {
  514.             p->lm = rr->finfo.st_mtime;
  515.             if(S_ISDIR(rr->finfo.st_mode)) {
  516.                 if(!(p->icon = find_icon(d,rr,1)))
  517.                     p->icon = find_default_icon(d,"^^DIRECTORY^^");
  518.                 if(!(p->alt = find_alt(d,rr,1)))
  519.                     p->alt = "DIR";
  520.                 p->size = -1;
  521.         p->name = pstrcat (r->pool, name, "/", NULL);
  522.             }
  523.             else {
  524.                 p->icon = find_icon(d, rr, 0);
  525.                 p->alt = find_alt(d, rr, 0);
  526.                 p->size = rr->finfo.st_size;
  527.             }
  528.         }
  529.     
  530.         p->desc = find_desc(d, rr);
  531.     
  532.         if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
  533.             p->desc = pstrdup (r->pool, find_title(rr));
  534.  
  535.     destroy_sub_req (rr);
  536.     }
  537.     return(p);
  538. }
  539.  
  540. char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) {
  541.     int maxsize = 23;
  542.     register int x;
  543.     
  544.     if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
  545.     if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
  546.  
  547.     for(x=0;desc[x] && maxsize;x++) {
  548.         if(desc[x] == '<') {
  549.             while(desc[x] != '>') {
  550.                 if(!desc[x]) {
  551.                     maxsize = 0;
  552.                     break;
  553.                 }
  554.                 ++x;
  555.             }
  556.         }
  557.         else --maxsize;
  558.     }
  559.     if(!maxsize) {
  560.         desc[x-1] = '>';    /* Grump. */
  561.     desc[x] = '\0';        /* Double Grump! */
  562.     }
  563.     return desc;
  564. }
  565.  
  566. void output_directories(struct ent **ar, int n,
  567.             dir_config_rec *d, request_rec *r, int dir_opts)
  568. {
  569.     int x, len;
  570.     char *name = r->uri;
  571.     char *tp;
  572.     pool *scratch = make_sub_pool (r->pool);
  573.     
  574.     if(name[0] == '\0') name = "/";
  575.  
  576.     if(dir_opts & FANCY_INDEXING) {
  577.         rputs("<PRE>", r);
  578.         if((tp = find_default_icon(d,"^^BLANKICON^^")))
  579.             rvputs(r, "<IMG SRC=\"", escape_html(scratch, tp),
  580.            "\" ALT=\"     \"> ", NULL);
  581.         rputs("Name                   ", r);
  582.         if(!(dir_opts & SUPPRESS_LAST_MOD))
  583.             rputs("Last modified     ", r);
  584.         if(!(dir_opts & SUPPRESS_SIZE))
  585.             rputs("Size  ", r);
  586.         if(!(dir_opts & SUPPRESS_DESC))
  587.             rputs("Description", r);
  588.         rputs("\n<HR>\n", r);
  589.     }
  590.     else {
  591.         rputs("<UL>", r);
  592.     }
  593.         
  594.     for(x=0;x<n;x++) {
  595.     char *anchor = NULL, *t = NULL, *t2 = NULL;
  596.     
  597.     clear_pool (scratch);
  598.     
  599.         if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
  600.             char *t = make_full_path (scratch, name, "../");
  601.             getparents(t);
  602.             if(t[0] == '\0') t = "/";
  603.         anchor = pstrcat (scratch, "<A HREF=\"",
  604.                   escape_html(scratch, os_escape_path(scratch, t, 0)),
  605.                   "\">", NULL);
  606.         t2 = "Parent Directory</A>       ";
  607.         }
  608.         else {
  609.         t = ar[x]->name;
  610.         len = strlen(t);
  611.             if(len > 23) {
  612.         t2 = pstrdup(scratch, t);
  613.         t2[21] = '.';
  614.         t2[22] = '.';
  615.                 t2[23] = '\0';
  616.         t2 = escape_html(scratch, t2);
  617.         t2 = pstrcat(scratch, t2, "</A>", NULL);
  618.             } else 
  619.         {
  620.         char buff[24]="                       ";
  621.         t2 = escape_html(scratch, t);
  622.         buff[23-len] = '\0';
  623.         t2 = pstrcat(scratch, t2, "</A>", buff, NULL);
  624.         }
  625.         anchor = pstrcat (scratch, "<A HREF=\"",
  626.                   escape_html(scratch, os_escape_path(scratch, t, 0)),
  627.                   "\">", NULL);
  628.         }
  629.  
  630.         if(dir_opts & FANCY_INDEXING) {
  631.             if(dir_opts & ICONS_ARE_LINKS)
  632.                 rputs(anchor, r);
  633.             if((ar[x]->icon) || d->default_icon) {
  634.                 rvputs(r, "<IMG SRC=\"", 
  635.                escape_html(scratch, ar[x]->icon ?
  636.                    ar[x]->icon : d->default_icon),
  637.                "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : "   "),
  638.                "]\">", NULL);
  639.             }
  640.             if(dir_opts & ICONS_ARE_LINKS) 
  641.                 rputs("</A>", r);
  642.  
  643.             rvputs(r," ", anchor, t2, NULL);
  644.             if(!(dir_opts & SUPPRESS_LAST_MOD)) {
  645.                 if(ar[x]->lm != -1) {
  646.             char time[MAX_STRING_LEN];
  647.                     struct tm *ts = localtime(&ar[x]->lm);
  648.                     strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M  ",ts);
  649.             rputs(time, r);
  650.                 }
  651.                 else {
  652.                     rputs("                 ", r);
  653.                 }
  654.             }
  655.             if(!(dir_opts & SUPPRESS_SIZE)) {
  656.                 send_size(ar[x]->size,r);
  657.                 rputs("  ", r);
  658.             }
  659.             if(!(dir_opts & SUPPRESS_DESC)) {
  660.                 if(ar[x]->desc) {
  661.                     rputs(terminate_description(d, ar[x]->desc, dir_opts), r);
  662.                 }
  663.             }
  664.         }
  665.         else
  666.             rvputs(r, "<LI> ", anchor," ", t2, NULL);
  667.         rputc('\n', r);
  668.     }
  669.     if(dir_opts & FANCY_INDEXING) {
  670.         rputs("</PRE>", r);
  671.     }
  672.     else {
  673.         rputs("</UL>", r);
  674.     }
  675. }
  676.  
  677.  
  678. int dsortf(struct ent **s1,struct ent **s2)
  679. {
  680.     return(strcmp((*s1)->name,(*s2)->name));
  681. }
  682.  
  683.     
  684. int index_directory(request_rec *r, dir_config_rec *dir_conf)
  685. {
  686.     char *title_name = escape_html(r->pool, r->uri);
  687.     char *title_endp;
  688.     char *name = r->filename;
  689.     
  690.     DIR *d;
  691.     struct DIR_TYPE *dstruct;
  692.     int num_ent=0,x;
  693.     struct ent *head,*p;
  694.     struct ent **ar;
  695.     char *tmp;
  696.     int dir_opts = find_opts(dir_conf, r);
  697.  
  698.     if(!(d=opendir(name))) return FORBIDDEN;
  699.  
  700.     r->content_type = "text/html";
  701.     
  702.     soft_timeout ("send directory", r);
  703.     send_http_header(r);
  704.  
  705.     if (r->header_only) {
  706.     closedir (d);
  707.     return 0;
  708.     }
  709.  
  710.     /* Spew HTML preamble */
  711.     
  712.     title_endp = title_name + strlen(title_name) - 1;
  713.  
  714.     while (title_endp > title_name && *title_endp == '/')
  715.     *title_endp-- = '\0';
  716.     
  717.     rvputs(r, "<HEAD><TITLE>Index of ", title_name, "</TITLE></HEAD><BODY>\n",
  718.        NULL);
  719.  
  720.     if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r))))
  721.         rvputs(r, "<H1>Index of ", title_name, "</H1>\n", NULL);
  722.  
  723.     /* 
  724.      * Since we don't know how many dir. entries there are, put them into a 
  725.      * linked list and then arrayificate them so qsort can use them. 
  726.      */
  727.     head=NULL;
  728.     while((dstruct=readdir(d))) {
  729.         if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) {
  730.             p->next=head;
  731.             head=p;
  732.             num_ent++;
  733.         }
  734.     }
  735.     ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *));
  736.     p=head;
  737.     x=0;
  738.     while(p) {
  739.         ar[x++]=p;
  740.         p = p->next;
  741.     }
  742.     
  743.     qsort((void *)ar,num_ent,sizeof(struct ent *),
  744. #ifdef ULTRIX_BRAIN_DEATH
  745.           (int (*))dsortf);
  746. #else
  747.           (int (*)(const void *,const void *))dsortf);
  748. #endif
  749.      output_directories(ar, num_ent, dir_conf, r, dir_opts);
  750.      closedir(d);
  751.  
  752.      if (dir_opts & FANCY_INDEXING)
  753.          if((tmp = find_readme(dir_conf, r)))
  754.              insert_readme(name,tmp,1,r);
  755.      else {
  756.          rputs("</UL>", r);
  757.      }
  758.  
  759.      rputs("</BODY>", r);
  760.      return 0;
  761. }
  762.  
  763. /* The formal handler... */
  764.  
  765. int handle_dir (request_rec *r)
  766. {
  767.     dir_config_rec *d =
  768.       (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module);
  769.     char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX;
  770.     int allow_opts = allow_options (r);
  771.  
  772.     if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') {
  773.     char* ifile;
  774.     if (r->args != NULL)
  775.             ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri),
  776.             "/", "?", r->args, NULL);
  777.     else
  778.             ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri),
  779.              "/", NULL);
  780.  
  781.     table_set (r->headers_out, "Location",
  782.            construct_url(r->pool, ifile, r->server));
  783.     return REDIRECT;
  784.     }
  785.  
  786.     /* KLUDGE --- make the sub_req lookups happen in the right directory.
  787.      * Fixing this in the sub_req_lookup functions themselves is difficult,
  788.      * and would probably break virtual includes...
  789.      */
  790.  
  791.     r->filename = pstrcat (r->pool, r->filename, "/", NULL);
  792.     
  793.     while (*names_ptr) {
  794.           
  795.     char *name_ptr = getword_conf (r->pool, &names_ptr);
  796.     request_rec *rr = sub_req_lookup_uri (name_ptr, r);
  797.            
  798.     if (rr->status == 200 && rr->finfo.st_mode != 0) {
  799.         char* new_uri = escape_uri(r->pool, rr->uri);
  800.  
  801.         if (rr->args != NULL)
  802.         new_uri = pstrcat(r->pool, new_uri, "?", rr->args, NULL);
  803.         else if (r->args != NULL)
  804.         new_uri = pstrcat(r->pool, new_uri, "?", r->args, NULL);
  805.     
  806.         destroy_sub_req (rr);
  807.         internal_redirect (new_uri, r);
  808.         return OK;
  809.     }
  810.  
  811.         destroy_sub_req (rr);
  812.     }
  813.  
  814.     if (r->method_number != M_GET) return NOT_IMPLEMENTED;
  815.     
  816.     /* OK, nothing easy.  Trot out the heavy artillery... */
  817.  
  818.     if (allow_opts & OPT_INDEXES) 
  819.         return index_directory (r, d);
  820.     else
  821.         return FORBIDDEN;
  822. }
  823.  
  824.  
  825. handler_rec dir_handlers[] = {
  826. { DIR_MAGIC_TYPE, handle_dir },
  827. { NULL }
  828. };
  829.  
  830. module dir_module = {
  831.    STANDARD_MODULE_STUFF,
  832.    NULL,            /* initializer */
  833.    create_dir_config,        /* dir config creater */
  834.    merge_dir_configs,        /* dir merger --- default is to override */
  835.    NULL,            /* server config */
  836.    NULL,            /* merge server config */
  837.    dir_cmds,            /* command table */
  838.    dir_handlers,        /* handlers */
  839.    NULL,            /* filename translation */
  840.    NULL,            /* check_user_id */
  841.    NULL,            /* check auth */
  842.    NULL,            /* check access */
  843.    NULL,            /* type_checker */
  844.    NULL,            /* fixups */
  845.    NULL                /* logger */
  846. };
  847.