/[Apache-SVN]/httpd/httpd/tags/2.3.1/modules/generators/mod_autoindex.c
ViewVC logotype

Contents of /httpd/httpd/tags/2.3.1/modules/generators/mod_autoindex.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 730918 - (hide annotations)
Sat Jan 3 06:15:00 2009 UTC (10 months, 3 weeks ago) by pquerna
File MIME type: text/plain
File size: 75686 byte(s)
Tag 2.3.1 from trunk.
1 fielding 420983 /* Licensed to the Apache Software Foundation (ASF) under one or more
2     * contributor license agreements. See the NOTICE file distributed with
3     * this work for additional information regarding copyright ownership.
4     * The ASF licenses this file to You under the Apache License, Version 2.0
5     * (the "License"); you may not use this file except in compliance with
6     * the License. You may obtain a copy of the License at
7 fielding 83751 *
8 nd 102524 * http://www.apache.org/licenses/LICENSE-2.0
9 fielding 83751 *
10 nd 102524 * Unless required by applicable law or agreed to in writing, software
11     * distributed under the License is distributed on an "AS IS" BASIS,
12     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     * See the License for the specific language governing permissions and
14     * limitations under the License.
15 fielding 83751 */
16    
17     /*
18     * mod_autoindex.c: Handles the on-the-fly html index generation
19 nd 98880 *
20 fielding 83751 * Rob McCool
21     * 3/23/93
22 nd 98880 *
23 fielding 83751 * Adapted to Apache by rst.
24 dgaudet 85021 *
25 gstein 88060 * Version sort added by Martin Pool <mbp@humbug.org.au>.
26     */
27 fielding 83751
28 rbb 85867 #include "apr_strings.h"
29 gstein 88060 #include "apr_fnmatch.h"
30     #include "apr_strings.h"
31     #include "apr_lib.h"
32    
33     #define APR_WANT_STRFUNC
34     #include "apr_want.h"
35    
36 rbb 84497 #include "ap_config.h"
37 fielding 83751 #include "httpd.h"
38     #include "http_config.h"
39     #include "http_core.h"
40     #include "http_request.h"
41     #include "http_protocol.h"
42     #include "http_log.h"
43     #include "http_main.h"
44     #include "util_script.h"
45    
46 rbb 88341 #include "mod_core.h"
47 gstein 88060
48 wrowe 86609 module AP_MODULE_DECLARE_DATA autoindex_module;
49 fielding 83751
50     /****************************************************************
51     *
52     * Handling configuration directives...
53     */
54    
55 wrowe 98181 #define NO_OPTIONS (1 << 0) /* Indexing options */
56     #define ICONS_ARE_LINKS (1 << 1)
57     #define SCAN_HTML_TITLES (1 << 2)
58     #define SUPPRESS_ICON (1 << 3)
59     #define SUPPRESS_LAST_MOD (1 << 4)
60     #define SUPPRESS_SIZE (1 << 5)
61     #define SUPPRESS_DESC (1 << 6)
62     #define SUPPRESS_PREAMBLE (1 << 7)
63     #define SUPPRESS_COLSORT (1 << 8)
64     #define SUPPRESS_RULES (1 << 9)
65     #define FOLDERS_FIRST (1 << 10)
66     #define VERSION_SORT (1 << 11)
67     #define TRACK_MODIFIED (1 << 12)
68     #define FANCY_INDEXING (1 << 13)
69     #define TABLE_INDEXING (1 << 14)
70     #define IGNORE_CLIENT (1 << 15)
71     #define IGNORE_CASE (1 << 16)
72 nd 101683 #define EMIT_XHTML (1 << 17)
73 pquerna 104212 #define SHOW_FORBIDDEN (1 << 18)
74 fielding 83751
75     #define K_NOADJUST 0
76     #define K_ADJUST 1
77     #define K_UNSET 2
78    
79     /*
80     * Define keys for sorting.
81     */
82 aaron 92624 #define K_NAME 'N' /* Sort by file name (default) */
83     #define K_LAST_MOD 'M' /* Last modification date */
84     #define K_SIZE 'S' /* Size (absolute, not as displayed) */
85     #define K_DESC 'D' /* Description */
86 wrowe 89981 #define K_VALID "NMSD" /* String containing _all_ valid K_ opts */
87 fielding 83751
88     #define D_ASCENDING 'A'
89     #define D_DESCENDING 'D'
90 wrowe 89981 #define D_VALID "AD" /* String containing _all_ valid D_ opts */
91 fielding 83751
92     /*
93     * These are the dimensions of the default icons supplied with Apache.
94     */
95     #define DEFAULT_ICON_WIDTH 20
96     #define DEFAULT_ICON_HEIGHT 22
97    
98     /*
99     * Other default dimensions.
100     */
101     #define DEFAULT_NAME_WIDTH 23
102 wrowe 89979 #define DEFAULT_DESC_WIDTH 23
103 fielding 83751
104     struct item {
105     char *type;
106     char *apply_to;
107     char *apply_path;
108     char *data;
109     };
110    
111     typedef struct ai_desc_t {
112     char *pattern;
113     char *description;
114     int full_path;
115     int wildcards;
116     } ai_desc_t;
117    
118     typedef struct autoindex_config_struct {
119    
120     char *default_icon;
121 ianh 101809 char *style_sheet;
122 niq 689261 char *head_insert;
123 takashi 729314 char *header;
124     char *readme;
125 wrowe 89981 apr_int32_t opts;
126     apr_int32_t incremented_opts;
127     apr_int32_t decremented_opts;
128 fielding 83751 int name_width;
129     int name_adjust;
130 wrowe 89979 int desc_width;
131     int desc_adjust;
132 fielding 83751 int icon_width;
133     int icon_height;
134 wrowe 89979 char default_keyid;
135     char default_direction;
136 fielding 83751
137 dougm 85976 apr_array_header_t *icon_list;
138     apr_array_header_t *alt_list;
139     apr_array_header_t *desc_list;
140     apr_array_header_t *ign_list;
141 fielding 83751
142 jim 570532 char *ctype;
143     char *charset;
144 fielding 83751 } autoindex_config_rec;
145    
146     static char c_by_encoding, c_by_type, c_by_path;
147    
148     #define BY_ENCODING &c_by_encoding
149     #define BY_TYPE &c_by_type
150     #define BY_PATH &c_by_path
151    
152     /*
153     * This routine puts the standard HTML header at the top of the index page.
154     * We include the DOCTYPE because we may be using features therefrom (i.e.,
155     * HEIGHT and WIDTH attributes on the icons if we're FancyIndexing).
156     */
157 nd 101683 static void emit_preamble(request_rec *r, int xhtml, const char *title)
158 fielding 83751 {
159 ianh 101809 autoindex_config_rec *d;
160    
161     d = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config,
162     &autoindex_module);
163    
164 rpluem 593816 if (xhtml) {
165     ap_rvputs(r, DOCTYPE_XHTML_1_0T,
166 rpluem 599589 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
167     " <head>\n <title>Index of ", title,
168     "</title>\n", NULL);
169 rpluem 593816 } else {
170     ap_rvputs(r, DOCTYPE_HTML_3_2,
171 rpluem 599589 "<html>\n <head>\n"
172     " <title>Index of ", title,
173     "</title>\n", NULL);
174 rpluem 593816 }
175    
176 ianh 101809 if (d->style_sheet != NULL) {
177     ap_rvputs(r, " <link rel=\"stylesheet\" href=\"", d->style_sheet,
178 nd 101854 "\" type=\"text/css\"", xhtml ? " />\n" : ">\n", NULL);
179 ianh 101809 }
180 niq 689261 if (d->head_insert != NULL) {
181     ap_rputs(d->head_insert, r);
182     }
183 nd 101853 ap_rvputs(r, " </head>\n <body>\n", NULL);
184 fielding 83751 }
185    
186 dougm 85976 static void push_item(apr_array_header_t *arr, char *type, const char *to,
187 aaron 92624 const char *path, const char *data)
188 fielding 83751 {
189 dougm 88019 struct item *p = (struct item *) apr_array_push(arr);
190 fielding 83751
191     if (!to) {
192 aaron 92624 to = "";
193 fielding 83751 }
194     if (!path) {
195 aaron 92624 path = "";
196 fielding 83751 }
197    
198     p->type = type;
199 dreid 89511 p->data = data ? apr_pstrdup(arr->pool, data) : NULL;
200     p->apply_path = apr_pstrcat(arr->pool, path, "*", NULL);
201 fielding 83751
202     if ((type == BY_PATH) && (!ap_is_matchexp(to))) {
203 aaron 92624 p->apply_to = apr_pstrcat(arr->pool, "*", to, NULL);
204 fielding 83751 }
205     else if (to) {
206 aaron 92624 p->apply_to = apr_pstrdup(arr->pool, to);
207 fielding 83751 }
208     else {
209 aaron 92624 p->apply_to = NULL;
210 fielding 83751 }
211     }
212    
213 ben 85640 static const char *add_alt(cmd_parms *cmd, void *d, const char *alt,
214 aaron 92624 const char *to)
215 fielding 83751 {
216     if (cmd->info == BY_PATH) {
217     if (!strcmp(to, "**DIRECTORY**")) {
218 aaron 92624 to = "^^DIRECTORY^^";
219     }
220 fielding 83751 }
221     if (cmd->info == BY_ENCODING) {
222 dougm 85976 char *tmp = apr_pstrdup(cmd->pool, to);
223 aaron 92624 ap_str_tolower(tmp);
224     to = tmp;
225 fielding 83751 }
226    
227     push_item(((autoindex_config_rec *) d)->alt_list, cmd->info, to,
228 aaron 92624 cmd->path, alt);
229 fielding 83751 return NULL;
230     }
231    
232 ben 85640 static const char *add_icon(cmd_parms *cmd, void *d, const char *icon,
233 aaron 92624 const char *to)
234 fielding 83751 {
235 dougm 85976 char *iconbak = apr_pstrdup(cmd->pool, icon);
236 fielding 83751
237     if (icon[0] == '(') {
238 aaron 92624 char *alt;
239     char *cl = strchr(iconbak, ')');
240 fielding 83751
241 aaron 92624 if (cl == NULL) {
242     return "missing closing paren";
243     }
244     alt = ap_getword_nc(cmd->pool, &iconbak, ',');
245     *cl = '\0'; /* Lose closing paren */
246     add_alt(cmd, d, &alt[1], to);
247 fielding 83751 }
248     if (cmd->info == BY_PATH) {
249     if (!strcmp(to, "**DIRECTORY**")) {
250 aaron 92624 to = "^^DIRECTORY^^";
251     }
252 fielding 83751 }
253     if (cmd->info == BY_ENCODING) {
254 dougm 85976 char *tmp = apr_pstrdup(cmd->pool, to);
255 aaron 92624 ap_str_tolower(tmp);
256     to = tmp;
257 fielding 83751 }
258    
259     push_item(((autoindex_config_rec *) d)->icon_list, cmd->info, to,
260 aaron 92624 cmd->path, iconbak);
261 fielding 83751 return NULL;
262     }
263    
264     /*
265     * Add description text for a filename pattern. If the pattern has
266     * wildcards already (or we need to add them), add leading and
267     * trailing wildcards to it to ensure substring processing. If the
268     * pattern contains a '/' anywhere, force wildcard matching mode,
269     * add a slash to the prefix so that "bar/bletch" won't be matched
270     * by "foobar/bletch", and make a note that there's a delimiter;
271     * the matching routine simplifies to just the actual filename
272     * whenever it can. This allows definitions in parent directories
273     * to be made for files in subordinate ones using relative paths.
274     */
275    
276     /*
277     * Absent a strcasestr() function, we have to force wildcards on
278     * systems for which "AAA" and "aaa" mean the same file.
279     */
280     #ifdef CASE_BLIND_FILESYSTEM
281     #define WILDCARDS_REQUIRED 1
282     #else
283     #define WILDCARDS_REQUIRED 0
284     #endif
285    
286 ben 85640 static const char *add_desc(cmd_parms *cmd, void *d, const char *desc,
287 aaron 92624 const char *to)
288 fielding 83751 {
289     autoindex_config_rec *dcfg = (autoindex_config_rec *) d;
290     ai_desc_t *desc_entry;
291     char *prefix = "";
292    
293 dougm 88019 desc_entry = (ai_desc_t *) apr_array_push(dcfg->desc_list);
294 ben 85640 desc_entry->full_path = (ap_strchr_c(to, '/') == NULL) ? 0 : 1;
295 fielding 83751 desc_entry->wildcards = (WILDCARDS_REQUIRED
296 aaron 92624 || desc_entry->full_path
297 wrowe 95976 || apr_fnmatch_test(to));
298 fielding 83751 if (desc_entry->wildcards) {
299 aaron 92624 prefix = desc_entry->full_path ? "*/" : "*";
300     desc_entry->pattern = apr_pstrcat(dcfg->desc_list->pool,
301     prefix, to, "*", NULL);
302 fielding 83751 }
303     else {
304 aaron 92624 desc_entry->pattern = apr_pstrdup(dcfg->desc_list->pool, to);
305 fielding 83751 }
306 dreid 89511 desc_entry->description = apr_pstrdup(dcfg->desc_list->pool, desc);
307 fielding 83751 return NULL;
308     }
309    
310 trawick 85627 static const char *add_ignore(cmd_parms *cmd, void *d, const char *ext)
311 fielding 83751 {
312     push_item(((autoindex_config_rec *) d)->ign_list, 0, ext, cmd->path, NULL);
313     return NULL;
314     }
315    
316 pquerna 168202 static const char *add_opts(cmd_parms *cmd, void *d, int argc, char *const argv[])
317 fielding 83751 {
318 pquerna 168202 int i;
319 fielding 83751 char *w;
320 wrowe 89981 apr_int32_t opts;
321     apr_int32_t opts_add;
322     apr_int32_t opts_remove;
323 fielding 83751 char action;
324     autoindex_config_rec *d_cfg = (autoindex_config_rec *) d;
325    
326     opts = d_cfg->opts;
327     opts_add = d_cfg->incremented_opts;
328     opts_remove = d_cfg->decremented_opts;
329 pquerna 168202
330     for (i = 0; i < argc; i++) {
331 aaron 92624 int option = 0;
332 pquerna 168202 w = argv[i];
333 fielding 83751
334 aaron 92624 if ((*w == '+') || (*w == '-')) {
335     action = *(w++);
336     }
337     else {
338     action = '\0';
339     }
340     if (!strcasecmp(w, "FancyIndexing")) {
341     option = FANCY_INDEXING;
342     }
343 coar 91660 else if (!strcasecmp(w, "FoldersFirst")) {
344 nd 98880 option = FOLDERS_FIRST;
345     }
346 aaron 92624 else if (!strcasecmp(w, "HTMLTable")) {
347     option = TABLE_INDEXING;
348     }
349     else if (!strcasecmp(w, "IconsAreLinks")) {
350     option = ICONS_ARE_LINKS;
351     }
352 wrowe 98181 else if (!strcasecmp(w, "IgnoreCase")) {
353     option = IGNORE_CASE;
354     }
355 wrowe 89981 else if (!strcasecmp(w, "IgnoreClient")) {
356     option = IGNORE_CLIENT;
357 aaron 92624 }
358     else if (!strcasecmp(w, "ScanHTMLTitles")) {
359     option = SCAN_HTML_TITLES;
360     }
361 wrowe 89981 else if (!strcasecmp(w, "SuppressColumnSorting")) {
362     option = SUPPRESS_COLSORT;
363 aaron 92624 }
364     else if (!strcasecmp(w, "SuppressDescription")) {
365     option = SUPPRESS_DESC;
366     }
367     else if (!strcasecmp(w, "SuppressHTMLPreamble")) {
368     option = SUPPRESS_PREAMBLE;
369     }
370     else if (!strcasecmp(w, "SuppressIcon")) {
371     option = SUPPRESS_ICON;
372     }
373     else if (!strcasecmp(w, "SuppressLastModified")) {
374     option = SUPPRESS_LAST_MOD;
375     }
376     else if (!strcasecmp(w, "SuppressSize")) {
377     option = SUPPRESS_SIZE;
378     }
379 wrowe 89979 else if (!strcasecmp(w, "SuppressRules")) {
380     option = SUPPRESS_RULES;
381 aaron 92624 }
382 coar 91660 else if (!strcasecmp(w, "TrackModified")) {
383 nd 98880 option = TRACK_MODIFIED;
384     }
385 dgaudet 85021 else if (!strcasecmp(w, "VersionSort")) {
386     option = VERSION_SORT;
387 aaron 92624 }
388 nd 101683 else if (!strcasecmp(w, "XHTML")) {
389     option = EMIT_XHTML;
390     }
391 pquerna 104212 else if (!strcasecmp(w, "ShowForbidden")) {
392     option = SHOW_FORBIDDEN;
393     }
394 aaron 92624 else if (!strcasecmp(w, "None")) {
395     if (action != '\0') {
396     return "Cannot combine '+' or '-' with 'None' keyword";
397     }
398     opts = NO_OPTIONS;
399     opts_add = 0;
400     opts_remove = 0;
401     }
402     else if (!strcasecmp(w, "IconWidth")) {
403     if (action != '-') {
404     d_cfg->icon_width = DEFAULT_ICON_WIDTH;
405     }
406     else {
407     d_cfg->icon_width = 0;
408     }
409     }
410     else if (!strncasecmp(w, "IconWidth=", 10)) {
411     if (action == '-') {
412     return "Cannot combine '-' with IconWidth=n";
413     }
414     d_cfg->icon_width = atoi(&w[10]);
415     }
416     else if (!strcasecmp(w, "IconHeight")) {
417     if (action != '-') {
418     d_cfg->icon_height = DEFAULT_ICON_HEIGHT;
419     }
420     else {
421     d_cfg->icon_height = 0;
422     }
423     }
424     else if (!strncasecmp(w, "IconHeight=", 11)) {
425     if (action == '-') {
426     return "Cannot combine '-' with IconHeight=n";
427     }
428     d_cfg->icon_height = atoi(&w[11]);
429     }
430     else if (!strcasecmp(w, "NameWidth")) {
431     if (action != '-') {
432     return "NameWidth with no value may only appear as "
433     "'-NameWidth'";
434     }
435     d_cfg->name_width = DEFAULT_NAME_WIDTH;
436     d_cfg->name_adjust = K_NOADJUST;
437     }
438     else if (!strncasecmp(w, "NameWidth=", 10)) {
439     if (action == '-') {
440     return "Cannot combine '-' with NameWidth=n";
441     }
442     if (w[10] == '*') {
443     d_cfg->name_adjust = K_ADJUST;
444     }
445     else {
446     int width = atoi(&w[10]);
447 fielding 83751
448 aaron 92624 if (width && (width < 5)) {
449     return "NameWidth value must be greater than 5";
450     }
451     d_cfg->name_width = width;
452     d_cfg->name_adjust = K_NOADJUST;
453     }
454     }
455 coar 91660 else if (!strcasecmp(w, "DescriptionWidth")) {
456 nd 98880 if (action != '-') {
457     return "DescriptionWidth with no value may only appear as "
458     "'-DescriptionWidth'";
459     }
460     d_cfg->desc_width = DEFAULT_DESC_WIDTH;
461     d_cfg->desc_adjust = K_NOADJUST;
462     }
463 coar 91660 else if (!strncasecmp(w, "DescriptionWidth=", 17)) {
464 nd 98880 if (action == '-') {
465     return "Cannot combine '-' with DescriptionWidth=n";
466     }
467     if (w[17] == '*') {
468     d_cfg->desc_adjust = K_ADJUST;
469     }
470 coar 91660 else {
471 nd 98880 int width = atoi(&w[17]);
472 wrowe 89979
473 nd 98880 if (width && (width < 12)) {
474     return "DescriptionWidth value must be greater than 12";
475     }
476     d_cfg->desc_width = width;
477     d_cfg->desc_adjust = K_NOADJUST;
478     }
479     }
480 jim 570558 else if (!strncasecmp(w, "Type=", 5)) {
481     d_cfg->ctype = apr_pstrdup(cmd->pool, &w[5]);
482 jim 570532 }
483     else if (!strncasecmp(w, "Charset=", 8)) {
484     d_cfg->charset = apr_pstrdup(cmd->pool, &w[8]);
485     }
486 aaron 92624 else {
487     return "Invalid directory indexing option";
488     }
489     if (action == '\0') {
490     opts |= option;
491     opts_add = 0;
492     opts_remove = 0;
493     }
494     else if (action == '+') {
495     opts_add |= option;
496     opts_remove &= ~option;
497     }
498     else {
499     opts_remove |= option;
500     opts_add &= ~option;
501     }
502 fielding 83751 }
503     if ((opts & NO_OPTIONS) && (opts & ~NO_OPTIONS)) {
504 aaron 92624 return "Cannot combine other IndexOptions keywords with 'None'";
505 fielding 83751 }
506     d_cfg->incremented_opts = opts_add;
507     d_cfg->decremented_opts = opts_remove;
508     d_cfg->opts = opts;
509     return NULL;
510     }
511    
512 aaron 92624 static const char *set_default_order(cmd_parms *cmd, void *m,
513     const char *direction, const char *key)
514 fielding 83751 {
515     autoindex_config_rec *d_cfg = (autoindex_config_rec *) m;
516    
517     if (!strcasecmp(direction, "Ascending")) {
518 aaron 92624 d_cfg->default_direction = D_ASCENDING;
519 fielding 83751 }
520     else if (!strcasecmp(direction, "Descending")) {
521 aaron 92624 d_cfg->default_direction = D_DESCENDING;
522 fielding 83751 }
523     else {
524 aaron 92624 return "First keyword must be 'Ascending' or 'Descending'";
525 fielding 83751 }
526    
527     if (!strcasecmp(key, "Name")) {
528 aaron 92624 d_cfg->default_keyid = K_NAME;
529 fielding 83751 }
530     else if (!strcasecmp(key, "Date")) {
531 aaron 92624 d_cfg->default_keyid = K_LAST_MOD;
532 fielding 83751 }
533     else if (!strcasecmp(key, "Size")) {
534 aaron 92624 d_cfg->default_keyid = K_SIZE;
535 fielding 83751 }
536     else if (!strcasecmp(key, "Description")) {
537 aaron 92624 d_cfg->default_keyid = K_DESC;
538 fielding 83751 }
539     else {
540 aaron 92624 return "Second keyword must be 'Name', 'Date', 'Size', or "
541     "'Description'";
542 fielding 83751 }
543    
544     return NULL;
545     }
546    
547     #define DIR_CMD_PERMS OR_INDEXES
548    
549     static const command_rec autoindex_cmds[] =
550     {
551 nd 98880 AP_INIT_ITERATE2("AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS,
552 trawick 85627 "an icon URL followed by one or more filenames"),
553     AP_INIT_ITERATE2("AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS,
554     "an icon URL followed by one or more MIME types"),
555     AP_INIT_ITERATE2("AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS,
556     "an icon URL followed by one or more content encodings"),
557     AP_INIT_ITERATE2("AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS,
558 nd 98880 "alternate descriptive text followed by one or more "
559     "filenames"),
560 trawick 85627 AP_INIT_ITERATE2("AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS,
561 nd 98880 "alternate descriptive text followed by one or more MIME "
562     "types"),
563 trawick 85627 AP_INIT_ITERATE2("AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS,
564 nd 98880 "alternate descriptive text followed by one or more "
565     "content encodings"),
566 pquerna 168202 AP_INIT_TAKE_ARGV("IndexOptions", add_opts, NULL, DIR_CMD_PERMS,
567     "one or more index options [+|-][]"),
568 trawick 85627 AP_INIT_TAKE2("IndexOrderDefault", set_default_order, NULL, DIR_CMD_PERMS,
569     "{Ascending,Descending} {Name,Size,Description,Date}"),
570     AP_INIT_ITERATE("IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS,
571     "one or more file extensions"),
572     AP_INIT_ITERATE2("AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS,
573     "Descriptive text followed by one or more filenames"),
574 takashi 729314 AP_INIT_TAKE1("HeaderName", ap_set_string_slot,
575     (void *)APR_OFFSETOF(autoindex_config_rec, header),
576     DIR_CMD_PERMS, "a filename"),
577     AP_INIT_TAKE1("ReadmeName", ap_set_string_slot,
578     (void *)APR_OFFSETOF(autoindex_config_rec, header),
579     DIR_CMD_PERMS, "a filename"),
580 wrowe 89897 AP_INIT_RAW_ARGS("FancyIndexing", ap_set_deprecated, NULL, OR_ALL,
581 nd 98880 "The FancyIndexing directive is no longer supported. "
582     "Use IndexOptions FancyIndexing."),
583 trawick 85627 AP_INIT_TAKE1("DefaultIcon", ap_set_string_slot,
584 jwoolley 95164 (void *)APR_OFFSETOF(autoindex_config_rec, default_icon),
585 trawick 85627 DIR_CMD_PERMS, "an icon URL"),
586 ianh 101809 AP_INIT_TAKE1("IndexStyleSheet", ap_set_string_slot,
587     (void *)APR_OFFSETOF(autoindex_config_rec, style_sheet),
588     DIR_CMD_PERMS, "URL to style sheet"),
589 niq 689261 AP_INIT_TAKE1("IndexHeadInsert", ap_set_string_slot,
590     (void *)APR_OFFSETOF(autoindex_config_rec, head_insert),
591     DIR_CMD_PERMS, "String to insert in HTML HEAD section"),
592 fielding 83751 {NULL}
593     };
594    
595 dougm 85976 static void *create_autoindex_config(apr_pool_t *p, char *dummy)
596 fielding 83751 {
597     autoindex_config_rec *new =
598 dougm 85976 (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec));
599 fielding 83751
600     new->icon_width = 0;
601     new->icon_height = 0;
602     new->name_width = DEFAULT_NAME_WIDTH;
603     new->name_adjust = K_UNSET;
604 nd 98880 new->desc_width = DEFAULT_DESC_WIDTH;
605     new->desc_adjust = K_UNSET;
606 dougm 88019 new->icon_list = apr_array_make(p, 4, sizeof(struct item));
607     new->alt_list = apr_array_make(p, 4, sizeof(struct item));
608     new->desc_list = apr_array_make(p, 4, sizeof(ai_desc_t));
609     new->ign_list = apr_array_make(p, 4, sizeof(struct item));
610 fielding 83751 new->opts = 0;
611     new->incremented_opts = 0;
612     new->decremented_opts = 0;
613 wrowe 89979 new->default_keyid = '\0';
614     new->default_direction = '\0';
615 fielding 83751
616     return (void *) new;
617     }
618    
619 dougm 85976 static void *merge_autoindex_configs(apr_pool_t *p, void *basev, void *addv)
620 fielding 83751 {
621     autoindex_config_rec *new;
622     autoindex_config_rec *base = (autoindex_config_rec *) basev;
623     autoindex_config_rec *add = (autoindex_config_rec *) addv;
624    
625 dougm 85976 new = (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec));
626 fielding 83751 new->default_icon = add->default_icon ? add->default_icon
627     : base->default_icon;
628 ianh 101809 new->style_sheet = add->style_sheet ? add->style_sheet
629     : base->style_sheet;
630 niq 689261 new->head_insert = add->head_insert ? add->head_insert
631     : base->head_insert;
632 takashi 729314 new->header = add->header ? add->header
633     : base->header;
634     new->readme = add->readme ? add->readme
635     : base->readme;
636 fielding 83751 new->icon_height = add->icon_height ? add->icon_height : base->icon_height;
637     new->icon_width = add->icon_width ? add->icon_width : base->icon_width;
638    
639 jim 570532 new->ctype = add->ctype ? add->ctype : base->ctype;
640     new->charset = add->charset ? add->charset : base->charset;
641    
642 dougm 88019 new->alt_list = apr_array_append(p, add->alt_list, base->alt_list);
643     new->ign_list = apr_array_append(p, add->ign_list, base->ign_list);
644     new->desc_list = apr_array_append(p, add->desc_list, base->desc_list);
645     new->icon_list = apr_array_append(p, add->icon_list, base->icon_list);
646 fielding 83751 if (add->opts & NO_OPTIONS) {
647 aaron 92624 /*
648     * If the current directory says 'no options' then we also
649     * clear any incremental mods from being inheritable further down.
650     */
651     new->opts = NO_OPTIONS;
652     new->incremented_opts = 0;
653     new->decremented_opts = 0;
654 fielding 83751 }
655     else {
656 aaron 92624 /*
657     * If there were any nonincremental options selected for
658     * this directory, they dominate and we don't inherit *anything.*
659     * Contrariwise, we *do* inherit if the only settings here are
660     * incremental ones.
661     */
662     if (add->opts == 0) {
663 nd 98880 new->incremented_opts = (base->incremented_opts
664 aaron 92624 | add->incremented_opts)
665     & ~add->decremented_opts;
666     new->decremented_opts = (base->decremented_opts
667     | add->decremented_opts);
668     /*
669     * We may have incremental settings, so make sure we don't
670     * inadvertently inherit an IndexOptions None from above.
671     */
672     new->opts = (base->opts & ~NO_OPTIONS);
673     }
674     else {
675     /*
676     * There are local nonincremental settings, which clear
677     * all inheritance from above. They *are* the new base settings.
678     */
679     new->opts = add->opts;;
680     }
681     /*
682     * We're guaranteed that there'll be no overlap between
683     * the add-options and the remove-options.
684     */
685     new->opts |= new->incremented_opts;
686     new->opts &= ~new->decremented_opts;
687 fielding 83751 }
688     /*
689     * Inherit the NameWidth settings if there aren't any specific to
690     * the new location; otherwise we'll end up using the defaults set in the
691     * config-rec creation routine.
692     */
693     if (add->name_adjust == K_UNSET) {
694 aaron 92624 new->name_width = base->name_width;
695     new->name_adjust = base->name_adjust;
696 fielding 83751 }
697     else {
698 aaron 92624 new->name_width = add->name_width;
699     new->name_adjust = add->name_adjust;
700 fielding 83751 }
701 wrowe 89981
702 nd 98880 /*
703     * Likewise for DescriptionWidth.
704     */
705     if (add->desc_adjust == K_UNSET) {
706     new->desc_width = base->desc_width;
707     new->desc_adjust = base->desc_adjust;
708     }
709 coar 91660 else {
710 nd 98880 new->desc_width = add->desc_width;
711     new->desc_adjust = add->desc_adjust;
712     }
713 fielding 83751
714 nd 98880 new->default_keyid = add->default_keyid ? add->default_keyid
715 wrowe 89979 : base->default_keyid;
716 nd 98880 new->default_direction = add->default_direction ? add->default_direction
717 wrowe 89979 : base->default_direction;
718 fielding 83751 return new;
719     }
720    
721     /****************************************************************
722     *
723     * Looking things up in config entries...
724     */
725    
726     /* Structure used to hold entries when we're actually building an index */
727    
728     struct ent {
729     char *name;
730     char *icon;
731     char *alt;
732     char *desc;
733 wrowe 89683 apr_off_t size;
734 dougm 85976 apr_time_t lm;
735 fielding 83751 struct ent *next;
736 wrowe 98181 int ascending, ignore_case, version_sort;
737 fielding 83751 char key;
738 wrowe 89979 int isdir;
739 fielding 83751 };
740    
741 takashi 729388 static char *find_item(const char *content_type, const char *content_encoding,
742     char *path, apr_array_header_t *list, int path_only)
743 fielding 83751 {
744     struct item *items = (struct item *) list->elts;
745     int i;
746    
747     for (i = 0; i < list->nelts; ++i) {
748 aaron 92624 struct item *p = &items[i];
749 fielding 83751
750 aaron 92624 /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
751     if ((path[0] == '^') || (!ap_strcmp_match(path, p->apply_path))) {
752     if (!*(p->apply_to)) {
753     return p->data;
754     }
755     else if (p->type == BY_PATH || path[0] == '^') {
756     if (!ap_strcmp_match(path, p->apply_to)) {
757     return p->data;
758     }
759     }
760     else if (!path_only) {
761     if (!content_encoding) {
762     if (p->type == BY_TYPE) {
763     if (content_type
764     && !ap_strcasecmp_match(content_type,
765     p->apply_to)) {
766     return p->data;
767     }
768     }
769     }
770     else {
771     if (p->type == BY_ENCODING) {
772     if (!ap_strcasecmp_match(content_encoding,
773     p->apply_to)) {
774     return p->data;
775     }
776     }
777     }
778     }
779     }
780 fielding 83751 }
781     return NULL;
782     }
783    
784 takashi 729388 static char *find_item_by_request(request_rec *r, apr_array_header_t *list, int path_only)
785 fielding 83751 {
786 takashi 729388 return find_item(ap_field_noparam(r->pool, r->content_type),
787     r->content_encoding, r->filename, list, path_only);
788 fielding 83751 }
789    
790 takashi 729388 #define find_icon(d,p,t) find_item_by_request(p,d->icon_list,t)
791     #define find_alt(d,p,t) find_item_by_request(p,d->alt_list,t)
792     #define find_default_icon(d,n) find_item(NULL, NULL, n, d->icon_list, 1)
793     #define find_default_alt(d,n) find_item(NULL, NULL, n, d->alt_list, 1)
794 wrowe 89909
795 fielding 83751 /*
796     * Look through the list of pattern/description pairs and return the first one
797     * if any) that matches the filename in the request. If multiple patterns
798     * match, only the first one is used; since the order in the array is the
799     * same as the order in which directives were processed, earlier matching
800     * directives will dominate.
801     */
802    
803     #ifdef CASE_BLIND_FILESYSTEM
804 trawick 101154 #define MATCH_FLAGS APR_FNM_CASE_BLIND
805 fielding 83751 #else
806     #define MATCH_FLAGS 0
807     #endif
808    
809 wrowe 89909 static char *find_desc(autoindex_config_rec *dcfg, const char *filename_full)
810 fielding 83751 {
811     int i;
812     ai_desc_t *list = (ai_desc_t *) dcfg->desc_list->elts;
813     const char *filename_only;
814     const char *filename;
815    
816     /*
817     * If the filename includes a path, extract just the name itself
818     * for the simple matches.
819     */
820 ben 85599 if ((filename_only = ap_strrchr_c(filename_full, '/')) == NULL) {
821 aaron 92624 filename_only = filename_full;
822 fielding 83751 }
823     else {
824 aaron 92624 filename_only++;
825 fielding 83751 }
826     for (i = 0; i < dcfg->desc_list->nelts; ++i) {
827 aaron 92624 ai_desc_t *tuple = &list[i];
828     int found;
829 fielding 83751
830 aaron 92624 /*
831     * Only use the full-path filename if the pattern contains '/'s.
832     */
833     filename = (tuple->full_path) ? filename_full : filename_only;
834     /*
835     * Make the comparison using the cheapest method; only do
836     * wildcard checking if we must.
837     */
838     if (tuple->wildcards) {
839     found = (apr_fnmatch(tuple->pattern, filename, MATCH_FLAGS) == 0);
840     }
841     else {
842     found = (ap_strstr_c(filename, tuple->pattern) != NULL);
843     }
844     if (found) {
845     return tuple->description;
846     }
847 fielding 83751 }
848     return NULL;
849     }
850    
851     static int ignore_entry(autoindex_config_rec *d, char *path)
852     {
853 dougm 85976 apr_array_header_t *list = d->ign_list;
854 fielding 83751 struct item *items = (struct item *) list->elts;
855     char *tt;
856     int i;
857    
858     if ((tt = strrchr(path, '/')) == NULL) {
859 aaron 92624 tt = path;
860 fielding 83751 }
861     else {
862 aaron 92624 tt++;
863 fielding 83751 }
864    
865     for (i = 0; i < list->nelts; ++i) {
866 aaron 92624 struct item *p = &items[i];
867     char *ap;
868 fielding 83751
869 aaron 92624 if ((ap = strrchr(p->apply_to, '/')) == NULL) {
870     ap = p->apply_to;
871     }
872     else {
873     ap++;
874     }
875 fielding 83751
876     #ifndef CASE_BLIND_FILESYSTEM
877 aaron 92624 if (!ap_strcmp_match(path, p->apply_path)
878     && !ap_strcmp_match(tt, ap)) {
879     return 1;
880     }
881 fielding 83751 #else /* !CASE_BLIND_FILESYSTEM */
882 aaron 92624 /*
883     * On some platforms, the match must be case-blind. This is really
884     * a factor of the filesystem involved, but we can't detect that
885     * reliably - so we have to granularise at the OS level.
886     */
887     if (!ap_strcasecmp_match(path, p->apply_path)
888     && !ap_strcasecmp_match(tt, ap)) {
889     return 1;
890     }
891 fielding 83751 #endif /* !CASE_BLIND_FILESYSTEM */
892     }
893     return 0;
894     }
895    
896     /*****************************************************************
897     *
898     * Actually generating output
899     */
900    
901     /*
902     * Elements of the emitted document:
903 aaron 92624 * Preamble
904     * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req
905     * succeeds for the (content_type == text/html) header file.
906     * Header file
907     * Emitted if found (and able).
908     * H1 tag line
909     * Emitted if a header file is NOT emitted.
910     * Directory stuff
911     * Always emitted.
912     * HR
913     * Emitted if FANCY_INDEXING is set.
914     * Readme file
915     * Emitted if found (and able).
916     * ServerSig
917     * Emitted if ServerSignature is not Off AND a readme file
918     * is NOT emitted.
919     * Postamble
920     * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req
921     * succeeds for the (content_type == text/html) readme file.
922 fielding 83751 */
923    
924    
925     /*
926     * emit a plain text file
927     */
928 dougm 85976 static void do_emit_plain(request_rec *r, apr_file_t *f)
929 fielding 83751 {
930 rbb 88282 char buf[AP_IOBUFSIZE + 1];
931 wrowe 89715 int ch;
932     apr_size_t i, c, n;
933 aaron 92625 apr_status_t rv;
934 fielding 83751
935 wrowe 89751 ap_rputs("<pre>\n", r);
936 dougm 88019 while (!apr_file_eof(f)) {
937 aaron 92624 do {
938 rbb 88282 n = sizeof(char) * AP_IOBUFSIZE;
939 aaron 92625 rv = apr_file_read(f, buf, &n);
940     } while (APR_STATUS_IS_EINTR(rv));
941     if (n == 0 || rv != APR_SUCCESS) {
942 wrowe 89715 /* ###: better error here? */
943 aaron 92624 break;
944     }
945     buf[n] = '\0';
946     c = 0;
947     while (c < n) {
948     for (i = c; i < n; i++) {
949     if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') {
950     break;
951     }
952     }
953     ch = buf[i];
954     buf[i] = '\0';
955     ap_rputs(&buf[c], r);
956     if (ch == '<') {
957     ap_rputs("&lt;", r);
958     }
959     else if (ch == '>') {
960     ap_rputs("&gt;", r);
961     }
962     else if (ch == '&') {
963     ap_rputs("&amp;", r);
964     }
965     c = i + 1;
966     }
967 fielding 83751 }
968 wrowe 89751 ap_rputs("</pre>\n", r);
969 fielding 83751 }
970    
971     /*
972     * Handle the preamble through the H1 tag line, inclusive. Locate
973     * the file with a subrequests. Process text/html documents by actually
974     * running the subrequest; text/xxx documents get copied verbatim,
975     * and any other content type is ignored. This means that a non-text
976     * document (such as HEADER.gif) might get multiviewed as the result
977     * instead of a text document, meaning nothing will be displayed, but
978     * oh well.
979     */
980     static void emit_head(request_rec *r, char *header_fname, int suppress_amble,
981 nd 101683 int emit_xhtml, char *title)
982 fielding 83751 {
983 wrowe 91609 apr_table_t *hdrs = r->headers_in;
984 dougm 85976 apr_file_t *f = NULL;
985 fielding 83751 request_rec *rr = NULL;
986     int emit_amble = 1;
987     int emit_H1 = 1;
988 wrowe 91609 const char *r_accept;
989     const char *r_accept_enc;
990 fielding 83751
991     /*
992     * If there's a header file, send a subrequest to look for it. If it's
993 wrowe 91609 * found and html do the subrequest, otherwise handle it
994 fielding 83751 */
995 wrowe 91609 r_accept = apr_table_get(hdrs, "Accept");
996     r_accept_enc = apr_table_get(hdrs, "Accept-Encoding");
997     apr_table_setn(hdrs, "Accept", "text/html, text/plain");
998     apr_table_unset(hdrs, "Accept-Encoding");
999    
1000 rbb 94457
1001 wrowe 91609 if ((header_fname != NULL) && r->args) {
1002     header_fname = apr_pstrcat(r->pool, header_fname, "?", r->args, NULL);
1003     }
1004    
1005 fielding 83751 if ((header_fname != NULL)
1006 wrowe 93663 && (rr = ap_sub_req_lookup_uri(header_fname, r, r->output_filters))
1007 aaron 92624 && (rr->status == HTTP_OK)
1008     && (rr->filename != NULL)
1009     && (rr->finfo.filetype == APR_REG)) {
1010     /*
1011     * Check for the two specific cases we allow: text/html and
1012     * text/anything-else. The former is allowed to be processed for
1013     * SSIs.
1014     */
1015     if (rr->content_type != NULL) {
1016     if (!strcasecmp(ap_field_noparam(r->pool, rr->content_type),
1017     "text/html")) {
1018 rbb 94457 ap_filter_t *f;
1019     /* Hope everything will work... */
1020 aaron 92624 emit_amble = 0;
1021     emit_H1 = 0;
1022 fielding 83751
1023 aaron 92624 if (! suppress_amble) {
1024 nd 101683 emit_preamble(r, emit_xhtml, title);
1025 aaron 92624 }
1026 rbb 94457 /* This is a hack, but I can't find any better way to do this.
1027     * The problem is that we have already created the sub-request,
1028 nd 98880 * but we just inserted the OLD_WRITE filter, and the
1029 rbb 94457 * sub-request needs to pass its data through the OLD_WRITE
1030     * filter, or things go horribly wrong (missing data, data in
1031 nd 98880 * the wrong order, etc). To fix it, if you create a
1032 rbb 94457 * sub-request and then insert the OLD_WRITE filter before you
1033     * run the request, you need to make sure that the sub-request
1034 nd 98880 * data goes through the OLD_WRITE filter. Just steal this
1035 rbb 94457 * code. The long-term solution is to remove the ap_r*
1036     * functions.
1037     */
1038 nd 98880 for (f=rr->output_filters;
1039 rbb 94457 f->frec != ap_subreq_core_filter_handle; f = f->next);
1040 nd 98880 f->next = r->output_filters;
1041 rbb 94457
1042 aaron 92624 /*
1043     * If there's a problem running the subrequest, display the
1044     * preamble if we didn't do it before -- the header file
1045     * didn't get displayed.
1046     */
1047     if (ap_run_sub_req(rr) != OK) {
1048     /* It didn't work */
1049     emit_amble = suppress_amble;
1050     emit_H1 = 1;
1051     }
1052     }
1053     else if (!strncasecmp("text/", rr->content_type, 5)) {
1054     /*
1055     * If we can open the file, prefix it with the preamble
1056     * regardless; since we'll be sending a <pre> block around
1057     * the file's contents, any HTML header it had won't end up
1058     * where it belongs.
1059     */
1060     if (apr_file_open(&f, rr->filename, APR_READ,
1061     APR_OS_DEFAULT, r->pool) == APR_SUCCESS) {
1062 nd 101683 emit_preamble(r, emit_xhtml, title);
1063 aaron 92624 emit_amble = 0;
1064     do_emit_plain(r, f);
1065     apr_file_close(f);
1066     emit_H1 = 0;
1067     }
1068     }
1069     }
1070 fielding 83751 }
1071    
1072 coar 91660 if (r_accept) {
1073 wrowe 91609 apr_table_setn(hdrs, "Accept", r_accept);
1074 coar 91660 }
1075     else {
1076 wrowe 91609 apr_table_unset(hdrs, "Accept");
1077 coar 91660 }
1078 wrowe 91609
1079 coar 91660 if (r_accept_enc) {
1080 wrowe 91609 apr_table_setn(hdrs, "Accept-Encoding", r_accept_enc);
1081 coar 91660 }
1082 wrowe 91609
1083 fielding 83751 if (emit_amble) {
1084 nd 101683 emit_preamble(r, emit_xhtml, title);
1085 fielding 83751 }
1086     if (emit_H1) {
1087 aaron 92624 ap_rvputs(r, "<h1>Index of ", title, "</h1>\n", NULL);
1088 fielding 83751 }
1089     if (rr != NULL) {
1090 aaron 92624 ap_destroy_sub_req(rr);
1091 fielding 83751 }
1092     }
1093    
1094    
1095     /*
1096     * Handle the Readme file through the postamble, inclusive. Locate
1097     * the file with a subrequests. Process text/html documents by actually
1098     * running the subrequest; text/xxx documents get copied verbatim,
1099     * and any other content type is ignored. This means that a non-text
1100     * document (such as FOOTER.gif) might get multiviewed as the result
1101     * instead of a text document, meaning nothing will be displayed, but
1102     * oh well.
1103     */
1104     static void emit_tail(request_rec *r, char *readme_fname, int suppress_amble)
1105     {
1106 dougm 85976 apr_file_t *f = NULL;
1107 fielding 83751 request_rec *rr = NULL;
1108     int suppress_post = 0;
1109     int suppress_sig = 0;
1110    
1111     /*
1112     * If there's a readme file, send a subrequest to look for it. If it's
1113     * found and a text file, handle it -- otherwise fall through and
1114     * pretend there's nothing there.
1115     */
1116     if ((readme_fname != NULL)
1117 wrowe 93663 && (rr = ap_sub_req_lookup_uri(readme_fname, r, r->output_filters))
1118 aaron 92624 && (rr->status == HTTP_OK)
1119     && (rr->filename != NULL)
1120     && rr->finfo.filetype == APR_REG) {
1121     /*
1122     * Check for the two specific cases we allow: text/html and
1123     * text/anything-else. The former is allowed to be processed for
1124     * SSIs.
1125     */
1126     if (rr->content_type != NULL) {
1127     if (!strcasecmp(ap_field_noparam(r->pool, rr->content_type),
1128     "text/html")) {
1129 rbb 94457 ap_filter_t *f;
1130 nd 98880 for (f=rr->output_filters;
1131 rbb 94457 f->frec != ap_subreq_core_filter_handle; f = f->next);
1132 nd 98880 f->next = r->output_filters;
1133 rbb 94457
1134    
1135 aaron 92624 if (ap_run_sub_req(rr) == OK) {
1136     /* worked... */
1137     suppress_sig = 1;
1138     suppress_post = suppress_amble;
1139     }
1140     }
1141     else if (!strncasecmp("text/", rr->content_type, 5)) {
1142     /*
1143     * If we can open the file, suppress the signature.
1144     */
1145     if (apr_file_open(&f, rr->filename, APR_READ,
1146     APR_OS_DEFAULT, r->pool) == APR_SUCCESS) {
1147     do_emit_plain(r, f);
1148     apr_file_close(f);
1149     suppress_sig = 1;
1150     }
1151     }
1152     }
1153 fielding 83751 }
1154 nd 98880
1155 fielding 83751 if (!suppress_sig) {
1156 aaron 92624 ap_rputs(ap_psignature("", r), r);
1157 fielding 83751 }
1158     if (!suppress_post) {
1159 aaron 92624 ap_rputs("</body></html>\n", r);
1160 fielding 83751 }
1161     if (rr != NULL) {
1162 aaron 92624 ap_destroy_sub_req(rr);
1163 fielding 83751 }
1164     }
1165    
1166    
1167     static char *find_title(request_rec *r)
1168     {
1169 wrowe 89751 char titlebuf[MAX_STRING_LEN], *find = "<title>";
1170 dougm 85976 apr_file_t *thefile = NULL;
1171 ben 84032 int x, y, p;
1172 rbb 86915 apr_size_t n;
1173 fielding 83751
1174     if (r->status != HTTP_OK) {
1175 aaron 92624 return NULL;
1176 fielding 83751 }
1177     if ((r->content_type != NULL)
1178 aaron 92624 && (!strcasecmp(ap_field_noparam(r->pool, r->content_type),
1179     "text/html")
1180     || !strcmp(r->content_type, INCLUDES_MAGIC_TYPE))
1181     && !r->content_encoding) {
1182 dougm 88019 if (apr_file_open(&thefile, r->filename, APR_READ,
1183 aaron 92624 APR_OS_DEFAULT, r->pool) != APR_SUCCESS) {
1184     return NULL;
1185     }
1186 rbb 83879 n = sizeof(char) * (MAX_STRING_LEN - 1);
1187 aaron 92624 apr_file_read(thefile, titlebuf, &n);
1188     if (n <= 0) {
1189     apr_file_close(thefile);
1190     return NULL;
1191     }
1192     titlebuf[n] = '\0';
1193     for (x = 0, p = 0; titlebuf[x]; x++) {
1194     if (apr_tolower(titlebuf[x]) == find[p]) {
1195     if (!find[++p]) {
1196     if ((p = ap_ind(&titlebuf[++x], '<')) != -1) {
1197     titlebuf[x + p] = '\0';
1198     }
1199     /* Scan for line breaks for Tanmoy's secretary */
1200     for (y = x; titlebuf[y]; y++) {
1201     if ((titlebuf[y] == CR) || (titlebuf[y] == LF)) {
1202     if (y == x) {
1203     x++;
1204     }
1205     else {
1206     titlebuf[y] = ' ';
1207     }
1208     }
1209     }
1210     apr_file_close(thefile);
1211     return apr_pstrdup(r->pool, &titlebuf[x]);
1212     }
1213     }
1214     else {
1215     p = 0;
1216     }
1217     }
1218     apr_file_close(thefile);
1219 fielding 83751 }
1220     return NULL;
1221     }
1222    
1223 wrowe 89981 static struct ent *make_parent_entry(apr_int32_t autoindex_opts,
1224 aaron 92624 autoindex_config_rec *d,
1225 nd 98880 request_rec *r, char keyid,
1226 wrowe 89909 char direction)
1227     {
1228     struct ent *p = (struct ent *) apr_pcalloc(r->pool, sizeof(struct ent));
1229     char *testpath;
1230     /*
1231     * p->name is now the true parent URI.
1232     * testpath is a crafted lie, so that the syntax '/some/..'
1233     * (or simply '..')be used to describe 'up' from '/some/'
1234     * when processeing IndexIgnore, and Icon|Alt|Desc configs.
1235     */
1236    
1237     /* The output has always been to the parent. Don't make ourself
1238     * our own parent (worthless cyclical reference).
1239     */
1240 coar 91660 if (!(p->name = ap_make_full_path(r->pool, r->uri, "../"))) {
1241 wrowe 89909 return (NULL);
1242 coar 91660 }
1243 wrowe 89909 ap_getparents(p->name);
1244 coar 91660 if (!*p->name) {
1245 wrowe 89909 return (NULL);
1246 coar 91660 }
1247 wrowe 89909
1248     /* IndexIgnore has always compared "/thispath/.." */
1249     testpath = ap_make_full_path(r->pool, r->filename, "..");
1250 coar 91660 if (ignore_entry(d, testpath)) {
1251 wrowe 89909 return (NULL);
1252 coar 91660 }
1253 wrowe 89909
1254     p->size = -1;
1255     p->lm = -1;
1256     p->key = apr_toupper(keyid);
1257     p->ascending = (apr_toupper(direction) == D_ASCENDING);
1258     p->version_sort = autoindex_opts & VERSION_SORT;
1259     if (autoindex_opts & FANCY_INDEXING) {
1260 coar 91660 if (!(p->icon = find_default_icon(d, testpath))) {
1261 aaron 92624 p->icon = find_default_icon(d, "^^DIRECTORY^^");
1262 coar 91660 }
1263     if (!(p->alt = find_default_alt(d, testpath))) {
1264     if (!(p->alt = find_default_alt(d, "^^DIRECTORY^^"))) {
1265 aaron 92624 p->alt = "DIR";
1266 coar 91660 }
1267     }
1268 wrowe 89909 p->desc = find_desc(d, testpath);
1269     }
1270     return p;
1271     }
1272    
1273 nd 98880 static struct ent *make_autoindex_entry(const apr_finfo_t *dirent,
1274 wrowe 89448 int autoindex_opts,
1275 aaron 92624 autoindex_config_rec *d,
1276     request_rec *r, char keyid,
1277     char direction,
1278 wrowe 89981 const char *pattern)
1279 fielding 83751 {
1280 wrowe 89899 request_rec *rr;
1281 fielding 83751 struct ent *p;
1282 pquerna 104212 int show_forbidden = 0;
1283 fielding 83751
1284 wrowe 89909 /* Dot is ignored, Parent is handled by make_parent_entry() */
1285     if ((dirent->name[0] == '.') && (!dirent->name[1]
1286 trawick 89911 || ((dirent->name[1] == '.') && !dirent->name[2])))
1287 aaron 92624 return (NULL);
1288 fielding 83751
1289 nd 101657 /*
1290     * On some platforms, the match must be case-blind. This is really
1291     * a factor of the filesystem involved, but we can't detect that
1292     * reliably - so we have to granularise at the OS level.
1293     */
1294 nd 98880 if (pattern && (apr_fnmatch(pattern, dirent->name,
1295 nd 101657 APR_FNM_NOESCAPE | APR_FNM_PERIOD
1296     #ifdef CASE_BLIND_FILESYSTEM
1297     | APR_FNM_CASE_BLIND
1298     #endif
1299     )
1300     != APR_SUCCESS)) {
1301 wrowe 89981 return (NULL);
1302 nd 101657 }
1303 wrowe 89981
1304 coar 91660 if (ignore_entry(d, ap_make_full_path(r->pool,
1305     r->filename, dirent->name))) {
1306 fielding 83751 return (NULL);
1307 coar 91660 }
1308 fielding 83751
1309 wrowe 93045 if (!(rr = ap_sub_req_lookup_dirent(dirent, r, AP_SUBREQ_NO_ARGS, NULL))) {
1310 wrowe 89899 return (NULL);
1311 wrowe 89981 }
1312 wrowe 89899
1313 jim 332306 if((autoindex_opts & SHOW_FORBIDDEN)
1314 pquerna 104212 && (rr->status == HTTP_UNAUTHORIZED || rr->status == HTTP_FORBIDDEN)) {
1315     show_forbidden = 1;
1316     }
1317    
1318 wrowe 89899 if ((rr->finfo.filetype != APR_DIR && rr->finfo.filetype != APR_REG)
1319 wrowe 89909 || !(rr->status == OK || ap_is_HTTP_SUCCESS(rr->status)
1320 pquerna 104212 || ap_is_HTTP_REDIRECT(rr->status)
1321     || show_forbidden == 1)) {
1322 wrowe 89899 ap_destroy_sub_req(rr);
1323     return (NULL);
1324     }
1325    
1326 dougm 85976 p = (struct ent *) apr_pcalloc(r->pool, sizeof(struct ent));
1327 jerenkrantz 93329 if (dirent->filetype == APR_DIR) {
1328 wrowe 90364 p->name = apr_pstrcat(r->pool, dirent->name, "/", NULL);
1329 coar 91660 }
1330     else {
1331 wrowe 90364 p->name = apr_pstrdup(r->pool, dirent->name);
1332 coar 91660 }
1333 fielding 83751 p->size = -1;
1334     p->icon = NULL;
1335     p->alt = NULL;
1336     p->desc = NULL;
1337     p->lm = -1;
1338 wrowe 89979 p->isdir = 0;
1339 wrowe 86008 p->key = apr_toupper(keyid);
1340     p->ascending = (apr_toupper(direction) == D_ASCENDING);
1341 wrowe 89981 p->version_sort = !!(autoindex_opts & VERSION_SORT);
1342 wrowe 98181 p->ignore_case = !!(autoindex_opts & IGNORE_CASE);
1343 wrowe 89979
1344 coar 91660 if (autoindex_opts & (FANCY_INDEXING | TABLE_INDEXING)) {
1345 aaron 92624 p->lm = rr->finfo.mtime;
1346 jerenkrantz 93329 if (dirent->filetype == APR_DIR) {
1347 coar 91660 if (autoindex_opts & FOLDERS_FIRST) {
1348 wrowe 89979 p->isdir = 1;
1349 coar 91660 }
1350 nd 100628 rr->filename = ap_make_dirstr_parent (rr->pool, rr->filename);
1351 nd 101693
1352     /* omit the trailing slash (1.3 compat) */
1353     rr->filename[strlen(rr->filename) - 1] = '\0';
1354    
1355 aaron 92624 if (!(p->icon = find_icon(d, rr, 1))) {
1356     p->icon = find_default_icon(d, "^^DIRECTORY^^");
1357     }
1358     if (!(p->alt = find_alt(d, rr, 1))) {
1359     if (!(p->alt = find_default_alt(d, "^^DIRECTORY^^"))) {
1360     p->alt = "DIR";
1361 coar 91660 }
1362 aaron 92624 }
1363     }
1364     else {
1365     p->icon = find_icon(d, rr, 0);
1366     p->alt = find_alt(d, rr, 0);
1367     p->size = rr->finfo.size;
1368     }
1369 fielding 83751
1370 aaron 92624 p->desc = find_desc(d, rr->filename);
1371 fielding 83751
1372 aaron 92624 if ((!p->desc) && (autoindex_opts & SCAN_HTML_TITLES)) {
1373     p->desc = apr_pstrdup(r->pool, find_title(rr));
1374     }
1375 fielding 83751 }
1376 wrowe 89899 ap_destroy_sub_req(rr);
1377 fielding 83751 /*
1378 wrowe 89899 * We don't need to take any special action for the file size key.
1379     * If we did, it would go here.
1380 fielding 83751 */
1381     if (keyid == K_LAST_MOD) {
1382     if (p->lm < 0) {
1383 aaron 92624 p->lm = 0;
1384     }
1385 fielding 83751 }
1386     return (p);
1387     }
1388    
1389     static char *terminate_description(autoindex_config_rec *d, char *desc,
1390 aaron 92624 apr_int32_t autoindex_opts, int desc_width)
1391 fielding 83751 {
1392 wrowe 89979 int maxsize = desc_width;
1393 fielding 83751 register int x;
1394    
1395 nd 98880 /*
1396 wrowe 89979 * If there's no DescriptionWidth in effect, default to the old
1397 nd 98880 * behaviour of adjusting the description size depending upon
1398     * what else is being displayed. Otherwise, stick with the
1399     * setting.
1400     */
1401     if (d->desc_adjust == K_UNSET) {
1402 wrowe 89979 if (autoindex_opts & SUPPRESS_ICON) {
1403 aaron 92624 maxsize += 6;
1404 wrowe 89979 }
1405     if (autoindex_opts & SUPPRESS_LAST_MOD) {
1406 aaron 92624 maxsize += 19;
1407 wrowe 89979 }
1408     if (autoindex_opts & SUPPRESS_SIZE) {
1409 aaron 92624 maxsize += 7;
1410 wrowe 89979 }
1411 fielding 83751 }
1412 wrowe 89979 for (x = 0; desc[x] && ((maxsize > 0) || (desc[x] == '<')); x++) {
1413 aaron 92624 if (desc[x] == '<') {
1414     while (desc[x] != '>') {
1415     if (!desc[x]) {
1416     maxsize = 0;
1417     break;
1418     }
1419     ++x;
1420     }
1421     }
1422     else if (desc[x] == '&') {
1423     /* entities like &auml; count as one character */
1424     --maxsize;
1425     for ( ; desc[x] != ';'; ++x) {
1426     if (desc[x] == '\0') {
1427 fielding 83751 maxsize = 0;
1428     break;
1429 aaron 92624 }
1430     }
1431 fielding 83751 }
1432 aaron 92624 else {
1433     --maxsize;
1434     }
1435 fielding 83751 }
1436     if (!maxsize && desc[x] != '\0') {
1437 aaron 92624 desc[x - 1] = '>'; /* Grump. */
1438     desc[x] = '\0'; /* Double Grump! */
1439 fielding 83751 }
1440     return desc;
1441     }
1442    
1443     /*
1444     * Emit the anchor for the specified field. If a field is the key for the
1445     * current request, the link changes its meaning to reverse the order when
1446     * selected again. Non-active fields always start in ascending order.
1447     */
1448 nd 98880 static void emit_link(request_rec *r, const char *anchor, char column,
1449     char curkey, char curdirection,
1450 wrowe 89981 const char *colargs, int nosort)
1451 fielding 83751 {
1452 nd 98883 if (!nosort) {
1453     char qvalue[9];
1454 fielding 83751
1455 aaron 92624 qvalue[0] = '?';
1456     qvalue[1] = 'C';
1457     qvalue[2] = '=';
1458     qvalue[3] = column;
1459 nd 98883 qvalue[4] = ';';
1460     qvalue[5] = 'O';
1461     qvalue[6] = '=';
1462     /* reverse? */
1463     qvalue[7] = ((curkey == column) && (curdirection == D_ASCENDING))
1464     ? D_DESCENDING : D_ASCENDING;
1465     qvalue[8] = '\0';
1466 nd 98880 ap_rvputs(r, "<a href=\"", qvalue, colargs ? colargs : "",
1467 wrowe 89981 "\">", anchor, "</a>", NULL);
1468 fielding 83751 }
1469     else {
1470     ap_rputs(anchor, r);
1471     }
1472     }
1473    
1474     static void output_directories(struct ent **ar, int n,
1475 aaron 92624 autoindex_config_rec *d, request_rec *r,
1476 nd 98880 apr_int32_t autoindex_opts, char keyid,
1477 wrowe 89981 char direction, const char *colargs)
1478 fielding 83751 {
1479 dreid 84598 int x;
1480 dougm 85976 apr_size_t rv;
1481 fielding 83751 char *name = r->uri;
1482     char *tp;
1483 wrowe 89981 int static_columns = !!(autoindex_opts & SUPPRESS_COLSORT);
1484 dougm 85976 apr_pool_t *scratch;
1485 fielding 83751 int name_width;
1486 wrowe 89979 int desc_width;
1487 fielding 83751 char *name_scratch;
1488     char *pad_scratch;
1489 wrowe 89983 char *breakrow = "";
1490 fielding 83751
1491 dougm 88019 apr_pool_create(&scratch, r->pool);
1492 fielding 83751 if (name[0] == '\0') {
1493 aaron 92624 name = "/";
1494 fielding 83751 }
1495    
1496     name_width = d->name_width;
1497 nd 98880 desc_width = d->desc_width;
1498 wrowe 89979
1499 nd 98880 if ((autoindex_opts & (FANCY_INDEXING | TABLE_INDEXING))
1500 wrowe 89979 == FANCY_INDEXING) {
1501     if (d->name_adjust == K_ADJUST) {
1502 aaron 92624 for (x = 0; x < n; x++) {
1503     int t = strlen(ar[x]->name);
1504     if (t > name_width) {
1505     name_width = t;
1506     }
1507     }
1508 wrowe 89979 }
1509    
1510 nd 98880 if (d->desc_adjust == K_ADJUST) {
1511 coar 91660 for (x = 0; x < n; x++) {
1512 nd 98880 if (ar[x]->desc != NULL) {
1513     int t = strlen(ar[x]->desc);
1514     if (t > desc_width) {
1515     desc_width = t;
1516     }
1517     }
1518     }
1519     }
1520 fielding 83751 }
1521 dougm 85976 name_scratch = apr_palloc(r->pool, name_width + 1);
1522     pad_scratch = apr_palloc(r->pool, name_width + 1);
1523 fielding 83751 memset(pad_scratch, ' ', name_width);
1524     pad_scratch[name_width] = '\0';
1525    
1526 wrowe 89979 if (autoindex_opts & TABLE_INDEXING) {
1527     int cols = 1;
1528 aaron 92624 ap_rputs("<table><tr>", r);
1529     if (!(autoindex_opts & SUPPRESS_ICON)) {
1530 striker 97158 ap_rputs("<th>", r);
1531 aaron 92624 if ((tp = find_default_icon(d, "^^BLANKICON^^"))) {
1532     ap_rvputs(r, "<img src=\"", ap_escape_html(scratch, tp),
1533     "\" alt=\"[ICO]\"", NULL);
1534     if (d->icon_width) {
1535     ap_rprintf(r, " width=\"%d\"", d->icon_width);
1536 coar 91660 }
1537     if (d->icon_height) {
1538 aaron 92624 ap_rprintf(r, " height=\"%d\"", d->icon_height);
1539 coar 91660 }
1540 nd 101683
1541     if (autoindex_opts & EMIT_XHTML) {
1542     ap_rputs(" /", r);
1543     }
1544     ap_rputs("></th>", r);
1545 wrowe 89979 }
1546 coar 91660 else {
1547 wrowe 89979 ap_rputs("&nbsp;</th>", r);
1548 coar 91660 }
1549 nd 98880
1550 wrowe 89979 ++cols;
1551     }
1552     ap_rputs("<th>", r);
1553 nd 98880 emit_link(r, "Name", K_NAME, keyid, direction,
1554 wrowe 89981 colargs, static_columns);
1555 aaron 92624 if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
1556 wrowe 89979 ap_rputs("</th><th>", r);
1557 nd 98880 emit_link(r, "Last modified", K_LAST_MOD, keyid, direction,
1558 wrowe 89981 colargs, static_columns);
1559 aaron 92624 ++cols;
1560     }
1561     if (!(autoindex_opts & SUPPRESS_SIZE)) {
1562 wrowe 89979 ap_rputs("</th><th>", r);
1563 nd 98880 emit_link(r, "Size", K_SIZE, keyid, direction,
1564 wrowe 89981 colargs, static_columns);
1565 aaron 92624 ++cols;
1566     }
1567     if (!(autoindex_opts & SUPPRESS_DESC)) {
1568 wrowe 89979 ap_rputs("</th><th>", r);
1569 nd 98880 emit_link(r, "Description", K_DESC, keyid, direction,
1570 wrowe 89981 colargs, static_columns);
1571 aaron 92624 ++cols;
1572     }
1573 coar 91660 if (!(autoindex_opts & SUPPRESS_RULES)) {
1574     breakrow = apr_psprintf(r->pool,
1575     "<tr><th colspan=\"%d\">"
1576 nd 101683 "<hr%s></th></tr>\n", cols,
1577     (autoindex_opts & EMIT_XHTML) ? " /" : "");
1578 coar 91660 }
1579 aaron 92624 ap_rvputs(r, "</th></tr>", breakrow, NULL);
1580 wrowe 89979 }
1581     else if (autoindex_opts & FANCY_INDEXING) {
1582 aaron 92624 ap_rputs("<pre>", r);
1583     if (!(autoindex_opts & SUPPRESS_ICON)) {
1584     if ((tp = find_default_icon(d, "^^BLANKICON^^"))) {
1585     ap_rvputs(r, "<img src=\"", ap_escape_html(scratch, tp),
1586     "\" alt=\"Icon \"", NULL);
1587     if (d->icon_width) {
1588     ap_rprintf(r, " width=\"%d\"", d->icon_width);
1589 coar 91660 }
1590     if (d->icon_height) {
1591 aaron 92624 ap_rprintf(r, " height=\"%d\"", d->icon_height);
1592 coar 91660 }
1593 nd 101683
1594     if (autoindex_opts & EMIT_XHTML) {
1595     ap_rputs(" /", r);
1596     }
1597     ap_rputs("> ", r);
1598 aaron 92624 }
1599 coar 91660 else {
1600 aaron 92624 ap_rputs(" ", r);
1601 coar 91660 }
1602 wrowe 89979 }
1603 nd 98880 emit_link(r, "Name", K_NAME, keyid, direction,
1604 wrowe 89981 colargs, static_columns);
1605 aaron 92624 ap_rputs(pad_scratch + 4, r);
1606     /*
1607     * Emit the guaranteed-at-least-one-space-between-columns byte.
1608     */
1609     ap_rputs(" ", r);
1610     if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
1611 fielding 83751 emit_link(r, "Last modified", K_LAST_MOD, keyid, direction,
1612 wrowe 89981 colargs, static_columns);
1613 aaron 92624 ap_rputs(" ", r);
1614     }
1615     if (!(autoindex_opts & SUPPRESS_SIZE)) {
1616 nd 98880 emit_link(r, "Size", K_SIZE, keyid, direction,
1617 wrowe 89981 colargs, static_columns);
1618 aaron 92624 ap_rputs(" ", r);
1619     }
1620     if (!(autoindex_opts & SUPPRESS_DESC)) {
1621 fielding 83751 emit_link(r, "Description", K_DESC, keyid, direction,
1622 wrowe 89981 colargs, static_columns);
1623 aaron 92624 }
1624     if (!(autoindex_opts & SUPPRESS_RULES)) {
1625 nd 101683 ap_rputs("<hr", r);
1626     if (autoindex_opts & EMIT_XHTML) {
1627     ap_rputs(" /", r);
1628     }
1629     ap_rputs(">", r);
1630 coar 91660 }
1631 jwoolley 94739 else {
1632     ap_rputc('\n', r);
1633     }
1634 fielding 83751 }
1635     else {
1636 aaron 92624 ap_rputs("<ul>", r);
1637 fielding 83751 }
1638    
1639     for (x = 0; x < n; x++) {
1640 aaron 92624 char *anchor, *t, *t2;
1641     int nwidth;
1642 fielding 83751
1643 aaron 92624 apr_pool_clear(scratch);
1644 fielding 83751
1645 wrowe 89909 t = ar[x]->name;
1646 aaron 92624 anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0));
1647 wrowe 89909
1648 coar 91660 if (!x && t[0] == '/') {
1649 aaron 92624 t2 = "Parent Directory";
1650 coar 91660 }
1651     else {
1652 aaron 92624 t2 = t;
1653 coar 91660 }
1654 fielding 83751
1655 wrowe 89979 if (autoindex_opts & TABLE_INDEXING) {
1656 nd 101661 ap_rputs("<tr>", r);
1657 aaron 92624 if (!(autoindex_opts & SUPPRESS_ICON)) {
1658 nd 101661 ap_rputs("<td valign=\"top\">", r);
1659 wrowe 89979 if (autoindex_opts & ICONS_ARE_LINKS) {
1660 aaron 92624 ap_rvputs(r, "<a href=\"", anchor, "\">", NULL);
1661     }
1662 wrowe 89979 if ((ar[x]->icon) || d->default_icon) {
1663 aaron 92624 ap_rvputs(r, "<img src=\"",
1664     ap_escape_html(scratch,
1665     ar[x]->icon ? ar[x]->icon
1666     : d->default_icon),
1667     "\" alt=\"[", (ar[x]->alt ? ar[x]->alt : " "),
1668     "]\"", NULL);
1669     if (d->icon_width) {
1670     ap_rprintf(r, " width=\"%d\"", d->icon_width);
1671 coar 91660 }
1672     if (d->icon_height) {
1673 wrowe 89979 ap_rprintf(r, " height=\"%d\"", d->icon_height);
1674 coar 91660 }
1675 nd 101683
1676     if (autoindex_opts & EMIT_XHTML) {
1677     ap_rputs(" /", r);
1678     }
1679     ap_rputs(">", r);
1680 aaron 92624 }
1681 coar 91660 else {
1682 nd 98880 ap_rputs("&nbsp;", r);
1683 coar 91660 }
1684 aaron 92624 if (autoindex_opts & ICONS_ARE_LINKS) {
1685     ap_rputs("</a></td>", r);
1686 coar 91660 }
1687 aaron 92624 else {
1688 wrowe 89979 ap_rputs("</td>", r);
1689 coar 91660 }
1690 wrowe 89979 }
1691     if (d->name_adjust == K_ADJUST) {
1692 aaron 92624 ap_rvputs(r, "<td><a href=\"", anchor, "\">",
1693 coar 91660 ap_escape_html(scratch, t2), "</a>", NULL);
1694 wrowe 89979 }
1695     else {
1696 aaron 92624 nwidth = strlen(t2);
1697     if (nwidth > name_width) {
1698     memcpy(name_scratch, t2, name_width - 3);
1699     name_scratch[name_width - 3] = '.';
1700     name_scratch[name_width - 2] = '.';
1701     name_scratch[name_width - 1] = '>';
1702     name_scratch[name_width] = 0;
1703     t2 = name_scratch;
1704     nwidth = name_width;
1705     }
1706     ap_rvputs(r, "<td><a href=\"", anchor, "\">",
1707     ap_escape_html(scratch, t2),
1708     "</a>", pad_scratch + nwidth, NULL);
1709 wrowe 89979 }
1710 aaron 92624 if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
1711     if (ar[x]->lm != -1) {
1712     char time_str[MAX_STRING_LEN];
1713 ianh 93733 apr_time_exp_t ts;
1714 striker 94631 apr_time_exp_lt(&ts, ar[x]->lm);
1715 nd 98880 apr_strftime(time_str, &rv, MAX_STRING_LEN,
1716     "</td><td align=\"right\">%d-%b-%Y %H:%M ",
1717     &ts);
1718 aaron 92624 ap_rputs(time_str, r);
1719     }
1720     else {
1721     ap_rputs("</td><td>&nbsp;", r);
1722     }
1723     }
1724     if (!(autoindex_opts & SUPPRESS_SIZE)) {
1725 wrowe 89979 char buf[5];
1726 aaron 92624 ap_rvputs(r, "</td><td align=\"right\">",
1727     apr_strfsize(ar[x]->size, buf), NULL);
1728     }
1729     if (!(autoindex_opts & SUPPRESS_DESC)) {
1730     if (ar[x]->desc) {
1731 coar 91660 if (d->desc_adjust == K_ADJUST) {
1732 aaron 92624 ap_rvputs(r, "</td><td>", ar[x]->desc, NULL);
1733 coar 91660 }
1734     else {
1735 nd 98880 ap_rvputs(r, "</td><td>",
1736 wrowe 89979 terminate_description(d, ar[x]->desc,
1737 nd 98880 autoindex_opts,
1738 wrowe 90162 desc_width), NULL);
1739 coar 91660 }
1740 aaron 92624 }
1741     }
1742     else {
1743 wrowe 89979 ap_rputs("</td><td>&nbsp;", r);
1744 aaron 92624 }
1745 wrowe 89979 ap_rputs("</td></tr>\n", r);
1746     }
1747 aaron 92624 else if (autoindex_opts & FANCY_INDEXING) {
1748     if (!(autoindex_opts & SUPPRESS_ICON)) {
1749     if (autoindex_opts & ICONS_ARE_LINKS) {
1750     ap_rvputs(r, "<a href=\"", anchor, "\">", NULL);
1751     }
1752     if ((ar[x]->icon) || d->default_icon) {
1753     ap_rvputs(r, "<img src=\"",
1754     ap_escape_html(scratch,
1755     ar[x]->icon ? ar[x]->icon
1756     : d->default_icon),
1757     "\" alt=\"[", (ar[x]->alt ? ar[x]->alt : " "),
1758     "]\"", NULL);
1759     if (d->icon_width) {
1760     ap_rprintf(r, " width=\"%d\"", d->icon_width);
1761 coar 91660 }
1762     if (d->icon_height) {
1763 wrowe 89979 ap_rprintf(r, " height=\"%d\"", d->icon_height);
1764 coar 91660 }
1765 nd 101683
1766     if (autoindex_opts & EMIT_XHTML) {
1767     ap_rputs(" /", r);
1768     }
1769     ap_rputs(">", r);
1770 aaron 92624 }
1771 coar 91660 else {
1772 aaron 92624 ap_rputs(" ", r);
1773 coar 91660 }
1774 aaron 92624 if (autoindex_opts & ICONS_ARE_LINKS) {
1775     ap_rputs("</a> ", r);
1776 coar 91660 }
1777 aaron 92624 else {
1778     ap_rputc(' ', r);
1779 coar 91660 }
1780 wrowe 89979 }
1781 aaron 92624 nwidth = strlen(t2);
1782     if (nwidth > name_width) {
1783     memcpy(name_scratch, t2, name_width - 3);
1784     name_scratch[name_width - 3] = '.';
1785     name_scratch[name_width - 2] = '.';
1786     name_scratch[name_width - 1] = '>';
1787     name_scratch[name_width] = 0;
1788     t2 = name_scratch;
1789     nwidth = name_width;
1790     }
1791     ap_rvputs(r, "<a href=\"", anchor, "\">",
1792     ap_escape_html(scratch, t2),
1793     "</a>", pad_scratch + nwidth, NULL);
1794     /*
1795     * The blank before the storm.. er, before the next field.
1796     */
1797     ap_rputs(" ", r);
1798     if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
1799     if (ar[x]->lm != -1) {
1800     char time_str[MAX_STRING_LEN];
1801 ianh 93733 apr_time_exp_t ts;
1802 striker 94631 apr_time_exp_lt(&ts, ar[x]->lm);
1803 nd 98880 apr_strftime(time_str, &rv, MAX_STRING_LEN,
1804 dgaudet 84413 "%d-%b-%Y %H:%M ", &ts);
1805 aaron 92624 ap_rputs(time_str, r);
1806     }
1807     else {
1808     /*Length="22-Feb-1998 23:42 " (see 4 lines above) */
1809     ap_rputs(" ", r);
1810     }
1811     }
1812     if (!(autoindex_opts & SUPPRESS_SIZE)) {
1813 wrowe 89713 char buf[5];
1814 aaron 92624 ap_rputs(apr_strfsize(ar[x]->size, buf), r);
1815     ap_rputs(" ", r);
1816     }
1817