You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ma...@apache.org on 2005/10/01 18:48:55 UTC
svn commit: r292999 [1/2] - in /httpd/mod_mbox/trunk: ./ data/ module-2.0/
Author: maxime
Date: Sat Oct 1 09:48:34 2005
New Revision: 292999
URL: http://svn.apache.org/viewcvs?rev=292999&view=rev
Log:
Merging changes from the httpd-mbox-if development branch to module's
trunk. For a list of changes, roll back the branch revision history.
The 0.2 mod_mbox release might come soon.
Added:
httpd/mod_mbox/trunk/data/
- copied from r292998, httpd/mod_mbox/branches/httpd-mbox-if/data/
httpd/mod_mbox/trunk/data/archives.js
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/data/archives.js
httpd/mod_mbox/trunk/data/asf_logo_simple.png
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_simple.png
httpd/mod_mbox/trunk/data/asf_logo_wide.gif
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_wide.gif
httpd/mod_mbox/trunk/data/style.css
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/data/style.css
httpd/mod_mbox/trunk/module-2.0/mbox_date.c
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.c
httpd/mod_mbox/trunk/module-2.0/mbox_date.h
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.h
httpd/mod_mbox/trunk/module-2.0/mod_mbox_cte.c
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_cte.c
httpd/mod_mbox/trunk/module-2.0/mod_mbox_out.c
- copied unchanged from r292998, httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_out.c
Modified:
httpd/mod_mbox/trunk/STATUS
httpd/mod_mbox/trunk/module-2.0/Makefile.am
httpd/mod_mbox/trunk/module-2.0/mbox_parse.c
httpd/mod_mbox/trunk/module-2.0/mbox_parse.h
httpd/mod_mbox/trunk/module-2.0/mod-mbox-util.c
httpd/mod_mbox/trunk/module-2.0/mod_mbox.c
httpd/mod_mbox/trunk/module-2.0/mod_mbox.h
httpd/mod_mbox/trunk/module-2.0/mod_mbox_file.c
httpd/mod_mbox/trunk/module-2.0/mod_mbox_index.c
httpd/mod_mbox/trunk/module-2.0/mod_mbox_mime.c
httpd/mod_mbox/trunk/module-2.0/mod_mbox_search.c
Modified: httpd/mod_mbox/trunk/STATUS
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/STATUS?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/STATUS (original)
+++ httpd/mod_mbox/trunk/STATUS Sat Oct 1 09:48:34 2005
@@ -1,23 +1,77 @@
Apache httpd-mbox STATUS: -*-text-*-
Last modified at [$Date$]
-Release:
+Release history:
+ 0.2 : currently under development [SoC]
0.1 : released July 17, 2001
-RELEASE SHOWSTOPPERS:
+Release showstoppers:
-Other bugs that need fixing:
+ * Awaiting release instructions.
+
+ToDo:
+
+ * Documentation
+ - For developpers : internals
+ - For admins : setup and update
+ - For users : usage, interface description, ...
+
+ * Charset conversions (to UTF-8). APR-Xlate features are nice, but
+ the conversion is easy only from APR v1.1.0. Multibyte
+ characters conversion with APR v0.x is a pain.
+
+ * Better page selector (useful for 10+ pages archives)
+
+ * Restore browser compatibility
+
+ * Remove built-in apr_date_rfc() replacement when the fixed version
+ will be packaged and distributed in common distros.
+
+Wish list:
-Other features that need writing:
-
* Better integration with httpd-2.0 build system.
+ * Interface internationalization
+ * Better XML semantics ?
+ * Use Javascript object-oriented features
+ * When viewing a message, come back to the page we came instead of
+ the first page of the choosen listing (without cookie, if
+ possible)
+
+Compatibility problems:
+
+ The AJAX browsing interface is only known to work with Gecko based
+ browsers. It has been successfully tested with :
+
+ * Firefox 1.0.4, 1.0.5 and 1.0.6
+ * Firefox Deep Park Alpha 2
+ * Epiphany-browser 1.6.4
+ * Galeon 1.3.21
+
+ Internet Explorer:
+
+ * _msglist is not considered as defined in the
+ drawFullMsgList() function. Still, it should have been set by
+ getMsgList() just before the call to drawFullMsgList().
+ * local variable scope is not supported. the
+ parseMimeStructure() function will *not* work.
+
+ Safari:
+
+ * Browser crashes when calling toggleMessage(). Some debugging
+ did not help locating the bug (sometimes in the
+ toggleMessage() function, sometimes in the
+ buildMessageListEntry() function ...)
-Documentation that needs writing:
+ Konqueror:
- * Documentation? What documentation?
+ * KHTML does not support AJAX. Some strange errors related to
+ .innerHTML, but I was not able to reproduce them outside
+ mod_mbox (http://skikda.bulix.org/~sam/ajax/compat.html).
-Available Patches:
+ Opera:
-Open issues:
+ * The AJAX browsing interface does not work. All the data is
+ here and loaded, but it's displayed as if the browser did not
+ even care of the generated XHTML content.
Modified: httpd/mod_mbox/trunk/module-2.0/Makefile.am
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/Makefile.am?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/Makefile.am (original)
+++ httpd/mod_mbox/trunk/module-2.0/Makefile.am Sat Oct 1 09:48:34 2005
@@ -1,24 +1,24 @@
libmboxutil_la_SOURCES = mbox_search.c mbox_cache.c mbox_parse.c \
- mbox_sort.c mbox_thread.c
+ mbox_sort.c mbox_thread.c mbox_date.c
libmboxutil_la_CFLAGS = -Wall ${MODULE_CFLAGS}
libmboxutil_la_LDFLAGS = -avoid-version ${MODULE_LDFLAGS}
-mod_mbox_la_SOURCES = mod_mbox.c mod_mbox_file.c mod_mbox_search.c \
- mod_mbox_index.c mod_mbox_mime.c libmboxutil.la
+mod_mbox_la_SOURCES = mod_mbox.c mod_mbox_file.c mod_mbox_out.c mod_mbox_search.c \
+ mod_mbox_index.c mod_mbox_cte.c mod_mbox_mime.c libmboxutil.la
mod_mbox_la_LIBADD = libmboxutil.la
mod_mbox_la_CFLAGS = -Wall ${MODULE_CFLAGS}
mod_mbox_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LDFLAGS}
-mod_mbox_util_SOURCES = mod-mbox-util.c
-mod_mbox_util_LDADD = libmboxutil.la
+mod_mbox_util_SOURCES = mod-mbox-util.c
+mod_mbox_util_LDADD = libmboxutil.la
mod_mbox_util_CFLAGS = -Wall ${MODULE_CFLAGS}
mod_mbox_util_LDFLAGS = -avoid-version ${BIN_LDFLAGS}
noinst_LTLIBRARIES = libmboxutil.la
-bin_PROGRAMS = mod-mbox-util
+bin_PROGRAMS = mod-mbox-util
mod_LTLIBRARIES = mod_mbox.la
moddir=${AP_LIBEXECDIR}
-install: install-am
+install: install-am
rm -f $(DESTDIR)${AP_LIBEXECDIR}/mod_mbox.a
rm -f $(DESTDIR)${AP_LIBEXECDIR}/mod_mbox.la
Modified: httpd/mod_mbox/trunk/module-2.0/mbox_parse.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mbox_parse.c?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mbox_parse.c (original)
+++ httpd/mod_mbox/trunk/module-2.0/mbox_parse.c Sat Oct 1 09:48:34 2005
@@ -35,6 +35,9 @@
#include "mbox_sort.h"
#include "mbox_search.h"
+/* FIXME: Remove this when apr_date_parse_rfc() is fixed ! */
+#include "mbox_date.h"
+
#include "apr_dbm.h"
#include "apr_hash.h"
#include "apr_date.h"
@@ -494,6 +497,9 @@
*/
static void normalize_message(request_rec *r, Message *m)
{
+ apr_time_exp_t time_exp;
+ apr_size_t len = 0;
+
/* Clean up the from to hide email addresses if possible. */
parse_from(r, m);
@@ -504,8 +510,14 @@
if (!m->content_type || !*m->content_type)
m->content_type = "text/plain";
+ apr_time_exp_gmt(&time_exp, m->date);
+
m->str_date = (char*)apr_pcalloc(r->pool, APR_RFC822_DATE_LEN);
- apr_rfc822_date(m->str_date, m->date);
+ m->rfc822_date = (char*)apr_pcalloc(r->pool, APR_RFC822_DATE_LEN);
+
+ apr_strftime(m->str_date, &len, APR_RFC822_DATE_LEN,
+ "%a, %d %b, %H:%M", &time_exp);
+ apr_rfc822_date(m->rfc822_date, m->date);
/* Parse the references into a table. */
parse_references(r, m);
@@ -738,13 +750,13 @@
{
#ifdef APR_HAS_MMAP
msgc.body_end = b.b - b.sb;
- /* With mmap, we can hit a file that brings the From check to the very
- * end of the mmap region - hence a dangling pointer (likely SEGV).
- * Therefore, break out of the loop first.
- */
- if (msgc.body_end == b.maxlen) {
- break;
- }
+ /* With mmap, we can hit a file that brings the From check to the very
+ * end of the mmap region - hence a dangling pointer (likely SEGV).
+ * Therefore, break out of the loop first.
+ */
+ if (msgc.body_end == b.maxlen) {
+ break;
+ }
#else
msgc.body_end = b.totalread - b.len + b.b - b.rb;
#endif
@@ -790,7 +802,9 @@
msgc.subject = apr_table_get(table, "Subject");
temp = apr_table_get(table, "Date");
if (temp) {
- msgc.date = apr_date_parse_rfc(temp);
+ /* FIXME: Change this back to apr_date_parse_rfc()
+ as soon as it is fixed ! */
+ msgc.date = mbox_date_parse_rfc(temp);
}
else {
msgc.date = 0;
@@ -872,7 +886,7 @@
/* This function returns a list of all messages contained within the mbox.
* This information is stored within the DBMs, so this is fairly fast.
*/
-MBOX_LIST * mbox_load_index(request_rec *r, apr_file_t * f)
+MBOX_LIST *mbox_load_index(request_rec *r, apr_file_t *f, int *count)
{
apr_status_t status;
MBOX_LIST *head, *keys;
@@ -885,8 +899,13 @@
OPEN_DBM(r, msgDB, APR_DBM_READONLY, MSGID_DBM_SUFFIX, temp, status);
- if (status != APR_SUCCESS)
+ if (status != APR_SUCCESS) {
return NULL;
+ }
+
+ if (count) {
+ *count = 0;
+ }
/* APR SDBM iteration is badly broken. You can't skip around during
* an iteration. Fixing this would be nice.
@@ -927,6 +946,10 @@
put_entry(r, &head, curMsg->date, curMsg);
status = apr_dbm_nextkey(msgDB, &msgKey);
+
+ if (count) {
+ (*count)++;
+ }
}
apr_pool_destroy(tpool);
Modified: httpd/mod_mbox/trunk/module-2.0/mbox_parse.h
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mbox_parse.h?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mbox_parse.h (original)
+++ httpd/mod_mbox/trunk/module-2.0/mbox_parse.h Sat Oct 1 09:48:34 2005
@@ -38,8 +38,9 @@
#include "mbox_search.h"
#include <stdio.h>
-#define MBOX_SORT_DATE 0
+#define MBOX_SORT_DATE 0
#define MBOX_SORT_AUTHOR 1
+#define MBOX_SORT_THREAD 2
/*
* MBOX_BUFF emulates the Apache BUFF structure, however it only
@@ -107,23 +108,51 @@
typedef struct Message_Struct Message;
typedef struct Container_Struct Container;
+typedef struct mbox_mime_message
+{
+ char *body;
+ apr_size_t body_len;
+ char *boundary;
+
+ char *content_type;
+ char *content_encoding;
+ char *content_disposition;
+ char *content_name;
+ mbox_cte_e cte;
+
+ struct mbox_mime_message **sub;
+ unsigned int sub_count;
+} mbox_mime_message_t;
+
/* The basic information about a message. */
struct Message_Struct
{
ID msgID;
- char * from;
- char * str_from;
- char * subject;
- char * content_type;
- char * boundary;
+
+ char *from;
+ char *str_from;
+
+ char *subject;
+
apr_time_t date;
- char * str_date;
+ char *str_date;
+ char *rfc822_date;
+
+ char *content_type;
+ char *boundary;
+ mbox_cte_e cte;
+
apr_table_t *references;
- char * raw_ref;
+ char *raw_ref;
+
apr_off_t msg_start;
apr_off_t body_start;
apr_off_t body_end;
- mbox_cte_e cte;
+
+ char *raw_msg;
+ char *raw_body;
+
+ mbox_mime_message_t *mime_msg;
};
/* The threading information about a message. */
@@ -160,7 +189,7 @@
/*
* Returns a list of Messages
*/
-MBOX_LIST* mbox_load_index(request_rec *r, apr_file_t * f);
+MBOX_LIST* mbox_load_index(request_rec *r, apr_file_t *f, int *count);
/*
* Returns a single message based on message ID
Modified: httpd/mod_mbox/trunk/module-2.0/mod-mbox-util.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mod-mbox-util.c?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mod-mbox-util.c (original)
+++ httpd/mod_mbox/trunk/module-2.0/mod-mbox-util.c Sat Oct 1 09:48:34 2005
@@ -165,10 +165,8 @@
apr_dir_close(dir);
if (files->nelts == 0) {
- if (verbose) {
- apr_file_printf(errfile, "Error: No mbox Files found in '%s'" NL,
- r->filename);
- }
+ apr_file_printf(errfile, "Error: No mbox Files found in '%s'" NL,
+ r->filename);
return EXIT_FAILURE;
}
@@ -189,56 +187,42 @@
}
}
- /* This only happens if we have empty archives. */
- if (i == files->nelts) {
- if (verbose) {
- apr_file_printf(errfile, "Archive %s empty" NL,
- r->filename);
- }
- return EXIT_FAILURE;
- }
-
if (verbose) {
- apr_file_printf(errfile, "Scanning %s for Mailing List info" NL,
+ apr_file_printf(errfile, "Scaning %s for Mailing List info" NL,
file);
}
ml = mbox_get_list_post(r, file);
if (!ml) {
- if (verbose) {
- apr_file_printf(errfile, "Warning: Reading List-Post header "
- "from '%s' failed" NL, file);
- }
- domain = "";
- list = "";
- }
- else {
- domain = strchr(ml, '@');
- if (!domain) {
- apr_file_printf(errfile, "Error: Failed to parse domain name "
- "from '%s'" NL, ml);
- return EXIT_FAILURE;
- }
-
- *domain = '\0';
- *domain++;
-
- list = strchr(ml, ':');
- if (!list) {
- apr_file_printf(errfile, "Error: Failed to parse list name "
- "from '%s'" NL, ml);
- return EXIT_FAILURE;
- }
-
- *list = '\0';
- *list++;
-
- ml = strrchr(domain, '>');
-
- if (ml) {
- *ml = '\0';
- }
+ apr_file_printf(errfile, "Error: Reading List-Post header "
+ "from '%s' failed" NL, file);
+ return EXIT_FAILURE;
+ }
+
+ domain = strchr(ml, '@');
+ if (!domain) {
+ apr_file_printf(errfile, "Error: Failed to parse domain name "
+ "from '%s'" NL, ml);
+ return EXIT_FAILURE;
+ }
+
+ *domain = '\0';
+ *domain++;
+
+ list = strchr(ml, ':');
+ if (!list) {
+ apr_file_printf(errfile, "Error: Failed to parse list name "
+ "from '%s'" NL, ml);
+ return EXIT_FAILURE;
+ }
+ *list = '\0';
+ *list++;
+
+ ml = strrchr(domain, '>');
+
+ if (ml) {
+ *ml = '\0';
}
if (verbose) {
Modified: httpd/mod_mbox/trunk/module-2.0/mod_mbox.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mod_mbox.c?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mod_mbox.c (original)
+++ httpd/mod_mbox/trunk/module-2.0/mod_mbox.c Sat Oct 1 09:48:34 2005
@@ -27,23 +27,10 @@
* By placing the appropriate AddHandler configuration in httpd.conf
* (mbox-handler), you can then access the list of messages of any mbox
* file by accessing it like the following:
+ * http://www.example.com/foo/bar.mbox/
*
- * http://www.example.com/foo/bar.mbox/index.html
- *
- * This will return a nicely formatted index sorted by date.
- *
- * If you go to the following fictional URL:
- *
- * http://www.example.com/foo/bar.mbox/threads.html
- *
- * This will return a nicely formatted index complete with threading.
- *
- * By clicking on a message that has a message-id of <12...@example.com>,
- * which could have the following URI:
- *
- * http://www.example.com/foo/bar.mbox/%3c12345@example.com%3e
- *
- * mod_mbox will return the body of the message.
+ * Direct link to raw messages are also available:
+ * http://www.example.com/foo/bar.mbox/raw?%3c12345@example.com%3e
*
* Please note that the actual indexing of the messages does not occur
* here in the module, but in the "generate_index" standalone program.
@@ -51,49 +38,42 @@
#include "mod_mbox.h"
+/* Register module hooks.
+ */
static void mbox_register_hooks(apr_pool_t *p)
{
ap_hook_handler(mbox_file_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(mbox_index_handler, NULL, NULL, APR_HOOK_FIRST);
ap_hook_handler(mbox_search_handler, NULL, NULL, APR_HOOK_MIDDLE);
-
- ap_register_output_filter(MBOX_OUT_INDEX_FILTER, mbox_out_index_filter,
- NULL,
- AP_FTYPE_RESOURCE);
- ap_register_output_filter(MBOX_OUT_MSG_FILTER, mbox_out_message_filter,
- NULL,
- AP_FTYPE_RESOURCE);
- ap_register_output_filter(MBOX_MPART_FILTER, mbox_mpart_filter,
- NULL,
- AP_FTYPE_RESOURCE);
- ap_register_output_filter(MBOX_BASE64_FILTER, mbox_base64_filter,
- NULL,
- AP_FTYPE_RESOURCE);
- ap_register_output_filter(MBOX_QP_FILTER, mbox_qp_filter,
- NULL,
- AP_FTYPE_RESOURCE);
- ap_register_output_filter(MBOX_HTML_FILTER, mbox_html_filter,
- NULL,
- AP_FTYPE_RESOURCE);
}
-static void *mbox_create_dir_config(apr_pool_t * p, char *x)
+/* Module configuration management.
+ */
+static void *mbox_create_dir_config(apr_pool_t *p, char *x)
{
- dir_cfg *conf = apr_pcalloc(p, sizeof(dir_cfg));
+ mbox_dir_cfg_t *conf;
+
+ conf = apr_pcalloc(p, sizeof(mbox_dir_cfg_t));
conf->enabled = 0;
- conf->root_url = NULL;
+ conf->hide_empty = 0;
+ conf->root_path = NULL;
conf->search_path = NULL;
+ conf->style_path = NULL;
+ conf->script_path = NULL;
return conf;
}
static void *mbox_merge_dir_config(apr_pool_t *p, void *basev, void *addv)
{
- dir_cfg *from = basev;
- dir_cfg *merge = addv;
- dir_cfg *to = apr_palloc(p, sizeof(dir_cfg));
+ mbox_dir_cfg_t *from = (mbox_dir_cfg_t *)basev;
+ mbox_dir_cfg_t *merge = (mbox_dir_cfg_t *)addv;
+ mbox_dir_cfg_t *to;
+
+ to = apr_palloc(p, sizeof(mbox_dir_cfg_t));
+ /* Update 'enabled' */
if (merge->enabled == 1) {
to->enabled = 1;
}
@@ -101,16 +81,34 @@
to->enabled = from->enabled;
}
- if (merge->root_url != NULL) {
- to->root_url = apr_pstrdup(p, merge->root_url);
+ /* Update 'hide_empty' */
+ if (merge->hide_empty == 1) {
+ to->hide_empty = 1;
}
- else if (from->root_url != NULL) {
- to->root_url = apr_pstrdup(p, from->root_url);
+ else {
+ to->hide_empty = from->hide_empty;
+ }
+
+ /* Update 'antispam' */
+ if (merge->antispam == 1) {
+ to->antispam = 1;
+ }
+ else {
+ to->antispam = from->antispam;
+ }
+
+ /* Update 'root_path' */
+ if (merge->root_path != NULL) {
+ to->root_path = apr_pstrdup(p, merge->root_path);
+ }
+ else if (from->root_path != NULL) {
+ to->root_path = apr_pstrdup(p, from->root_path);
}
else {
- to->root_url = NULL;
+ to->root_path = NULL;
}
+ /* Update 'search_path' */
if (merge->search_path != NULL) {
to->search_path = apr_pstrdup(p, merge->search_path);
}
@@ -121,19 +119,108 @@
to->search_path = NULL;
}
+ /* Update 'style_path' */
+ if (merge->style_path != NULL) {
+ to->style_path = apr_pstrdup(p, merge->style_path);
+ }
+ else if (from->style_path != NULL) {
+ to->style_path = apr_pstrdup(p, from->style_path);
+ }
+ else {
+ to->style_path = NULL;
+ }
+
+ /* Update 'style_path' */
+ if (merge->script_path != NULL) {
+ to->script_path = apr_pstrdup(p, merge->script_path);
+ }
+ else if (from->script_path != NULL) {
+ to->script_path = apr_pstrdup(p, from->script_path);
+ }
+ else {
+ to->script_path = NULL;
+ }
+
return to;
}
+/* Wrap text to MBOX_WRAP_TO. Changes passed string. */
+char *mbox_wrap_text(char *str)
+{
+ int i, pos;
+
+ if (!str || (strlen(str) < MBOX_WRAP_TO))
+ return str;
+
+ for (i=0, pos=0; i<strlen(str); i++, pos++) {
+ /* Reset the position counter if we pass a newline character */
+ if (str[i] == '\n') {
+ pos = 0;
+ }
+
+ /* If the position counter is after the wrap limit, wrap text at
+ first space available */
+ if ((pos >= MBOX_WRAP_TO) &&
+ ((str[i] == ' ') || (str[i] == '\t'))) {
+ str[i] = '\n';
+ pos = 0;
+ }
+ }
+
+ return str;
+}
+
+/* Returns the archives base path */
+char *get_base_path(request_rec *r)
+{
+ char *baseURI, *temp;
+
+ baseURI = get_base_uri(r);
+ temp = strstr(baseURI, ".mbox");
+ if (!temp) {
+ return NULL;
+ }
+
+ temp = temp-7;
+ *temp = 0;
+
+ return baseURI;
+}
+
+/* Returns the base URI, stripping the path_info */
+char *get_base_uri(request_rec *r)
+{
+ char *baseURI, *temp;
+
+ baseURI = apr_pstrdup(r->pool, r->uri);
+ temp = strstr(baseURI, r->path_info);
+ *temp = '\0';
+
+ return baseURI;
+}
+
static const command_rec mbox_cmds[] ={
AP_INIT_FLAG("mboxindex", ap_set_flag_slot,
- (void *)APR_OFFSETOF(dir_cfg, enabled), OR_INDEXES,
- "Enable mod_mbox directory listings of .mbox files."),
- AP_INIT_TAKE1("mboxindexroot", ap_set_string_slot,
- (void *)APR_OFFSETOF(dir_cfg, root_url), OR_INDEXES,
- "URL for site index (optional)"),
+ (void *)APR_OFFSETOF(mbox_dir_cfg_t, enabled), OR_INDEXES,
+ "Enable mod_mbox to create directory listings of .mbox files."),
+ AP_INIT_FLAG("mboxantispam", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(mbox_dir_cfg_t, antispam), OR_INDEXES,
+ "Enable mod_mbox email obfuscation."),
AP_INIT_TAKE1("mboxsearch", ap_set_string_slot,
- (void *)APR_OFFSETOF(dir_cfg, search_path), OR_INDEXES,
+ (void *)APR_OFFSETOF(mbox_dir_cfg_t, search_path), OR_INDEXES,
"Set the Directory that contains Search Data"),
+ AP_INIT_TAKE1("mboxrootpath", ap_set_string_slot,
+ (void *)APR_OFFSETOF(mbox_dir_cfg_t, root_path), OR_INDEXES,
+ "Set the path to the site index."),
+ AP_INIT_TAKE1("mboxstyle", ap_set_string_slot,
+ (void *)APR_OFFSETOF(mbox_dir_cfg_t, style_path), OR_INDEXES,
+ "Set the path to Css stylesheet file."),
+ AP_INIT_TAKE1("mboxscript", ap_set_string_slot,
+ (void *)APR_OFFSETOF(mbox_dir_cfg_t, script_path), OR_INDEXES,
+ "Set the path to the Javascript file."),
+ AP_INIT_FLAG("mboxhideempty", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(mbox_dir_cfg_t, hide_empty), OR_INDEXES,
+ "Whether to display empty mboxes in index listing."),
{NULL}
};
Modified: httpd/mod_mbox/trunk/module-2.0/mod_mbox.h
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mod_mbox.h?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mod_mbox.h (original)
+++ httpd/mod_mbox/trunk/module-2.0/mod_mbox.h Sat Oct 1 09:48:34 2005
@@ -24,12 +24,13 @@
#include "http_protocol.h"
#include "http_request.h"
#include "util_script.h"
-#include "apr_date.h"
+#include "apr_date.h"
#include "apr_strings.h"
#include "apr_dbm.h"
#include "apr_hash.h"
#include "apr_fnmatch.h"
+#include "apr_xlate.h"
#include <stdio.h>
#include <ctype.h>
@@ -48,60 +49,102 @@
#define MBOX_HANDLER "mbox-handler"
#define MBOX_MAGIC_TYPE "mbox-file"
-#define MBOX_OUT_MSG_FILTER "mbox-out-message-filter"
-#define MBOX_OUT_INDEX_FILTER "mbox-out-index-filter"
-#define MBOX_BASE64_FILTER "mbox-out-base64-filter"
-#define MBOX_QP_FILTER "mbox-out-quoted-printable-filter"
-#define MBOX_MPART_FILTER "mbox-out-multipart-filter"
-#define MBOX_HTML_FILTER "mbox-out-html-filter"
+#define DEFAULT_MSGS_PER_PAGE 100
+#define DEFAULT_THREADS_PER_PAGE 40
#define MBOX_PREV 0
#define MBOX_NEXT 1
#define MBOX_PREV_THREAD 2
#define MBOX_NEXT_THREAD 3
-typedef struct mbox_filter_ctx {
- Message *m;
- char *baseURI;
- int sent;
- apr_bucket_brigade *tbb;
-} mbox_filter_ctx;
+/* FIXME: MAX_MBOX_FILES is set to 240 (20 years of 12 months), but
+ this is not a really clean mechanism. I've used that because there
+ is not easy way of sorting a chained list, and because there is no
+ realloc function in the APR, so I use a static array */
+#define MAX_MBOX_FILES 240
-typedef struct dir_cfg {
- int enabled;
- const char* root_url;
- const char* search_path;
-} dir_cfg;
+#define MBOX_OUTPUT_STATIC 0
+#define MBOX_OUTPUT_AJAX 1
+#define MBOX_WRAP_TO 90
+
+typedef struct mbox_dir_cfg {
+ int enabled;
+ int antispam;
+ int hide_empty;
+ const char *root_path;
+ const char *search_path;
+ const char *style_path;
+ const char *script_path;
+} mbox_dir_cfg_t;
+
+typedef struct mbox_file {
+ char *filename;
+ int count;
+} mbox_file_t;
/* Declare ourselves so the configuration routines can find and know us.
* We'll fill it in at the end of the module.
*/
extern module mbox_module;
+extern char *mbox_months[12][2];
+
#define ESCAPE_OR_BLANK(pool, s) \
(s ? ap_escape_html(pool, s) : "")
#define URI_ESCAPE_OR_BLANK(pool, s) \
(s ? ap_escape_uri(pool, s) : "")
+/* Handlers */
int mbox_file_handler(request_rec *r);
int mbox_index_handler(request_rec *r);
int mbox_search_handler(request_rec *r);
-apr_status_t mbox_out_message_filter(ap_filter_t *f, apr_bucket_brigade *bb);
-apr_status_t mbox_out_index_filter(ap_filter_t *f, apr_bucket_brigade *bb);
-apr_status_t mbox_html_filter(ap_filter_t *f, apr_bucket_brigade *bb);
-apr_status_t mbox_mpart_filter(ap_filter_t *f, apr_bucket_brigade *bb);
-apr_status_t mbox_qp_filter(ap_filter_t *f, apr_bucket_brigade *bb);
-apr_status_t mbox_base64_filter(ap_filter_t *f, apr_bucket_brigade *bb);
-apr_status_t mbox_cte_filter(ap_filter_t *f, apr_bucket_brigade *bb,
- mbox_cte_e cte, int noescape);
-apr_size_t mbox_mime_decode_qp(char* p);
-apr_size_t mbox_mime_decode_b64(char *src);
-
-AP_DECLARE(apr_bucket*) mbox_bucket_escape_html(ap_filter_t* f, apr_pool_t* p,
- const char* s, apr_size_t len);
+/* Output functions */
+apr_status_t mbox_xml_msglist(request_rec *r, apr_file_t *f, int sortFlags);
+apr_status_t mbox_static_msglist(request_rec *r, apr_file_t *f, int sortFlags);
+
+apr_status_t mbox_xml_boxlist(request_rec *r);
+apr_status_t mbox_static_boxlist(request_rec *r);
+apr_status_t mbox_static_index_boxlist(request_rec *r, mbox_dir_cfg_t *conf,
+ mbox_cache_info *mli);
+
+apr_status_t mbox_ajax_browser(request_rec *r);
+
+apr_status_t mbox_raw_message(request_rec *r, apr_file_t *f);
+apr_status_t mbox_static_message(request_rec *r, apr_file_t *f);
+apr_status_t mbox_xml_message(request_rec *r, apr_file_t *f);
+
+/* CTE decoding functions */
+const char *mbox_cte_to_char(mbox_cte_e cte);
+apr_size_t mbox_cte_decode_qp(char* p);
+apr_size_t mbox_cte_decode_b64(char *src);
+apr_size_t mbox_cte_escape_html(apr_pool_t *p, const char *s,
+ apr_size_t len, char **body);
+char *mbox_cte_decode_header(apr_pool_t *p, char *src);
+
+/* MIME decoding functions */
+mbox_mime_message_t *mbox_mime_decode_multipart(apr_pool_t *p, char *body,
+ char *ct, mbox_cte_e cte,
+ char *boundary);
+char *mbox_mime_decode_body(apr_pool_t *p, mbox_cte_e cte, char *body, apr_size_t len);
+char *mbox_mime_get_body(apr_pool_t *p, mbox_mime_message_t *m);
+void mbox_mime_display_static_structure(request_rec *r, mbox_mime_message_t *m,
+ char *link);
+void mbox_mime_display_xml_structure(request_rec *r, mbox_mime_message_t *m,
+ char *link);
+
+/* Utility functions */
+char *mbox_wrap_text(char *str);
+char *get_base_path(request_rec *r);
+char *get_base_uri(request_rec *r);
+
+/* Backend functions */
+mbox_file_t *mbox_fetch_boxes_list(request_rec *r, mbox_cache_info *mli,
+ char *path, int *count);
+Message *fetch_message(request_rec *r, apr_file_t *f, char *msgID);
+char **fetch_context_msgids(request_rec *r, apr_file_t *f, char*msgID);
#ifdef __cplusplus
}
Modified: httpd/mod_mbox/trunk/module-2.0/mod_mbox_file.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mod_mbox_file.c?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mod_mbox_file.c (original)
+++ httpd/mod_mbox/trunk/module-2.0/mod_mbox_file.c Sat Oct 1 09:48:34 2005
@@ -14,144 +14,43 @@
* limitations under the License.
*/
-/**
- * This file contains all routines for displaying part of an mbox file to the
- * client. This includes seeking in the mbox file, and assigning the correct
- * output filters. It also generates the Threaded, Author and Date indexes,
- * from the information in the DBM cache.
- */
-
#include "mod_mbox.h"
-/*
- * This function prints one message
- */
-static void print_message(request_rec *r, char* baseURI, Message *m)
-{
- /* FIXME: HTML or TEXT formats? */
- ap_rprintf(r, "<A HREF=\"%s/%s\">%s</A> %s (%s)",
- baseURI,
- URI_ESCAPE_OR_BLANK(r->pool, m->msgID),
- ESCAPE_OR_BLANK(r->pool, m->subject),
- ESCAPE_OR_BLANK(r->pool, m->str_from),
- ESCAPE_OR_BLANK(r->pool, m->str_date));
-}
-
-/* This function displays the index about the specified mbox file.
- *
- * The presentation is meant to emulate the old hypermail archives.
- */
-static apr_status_t display_index(request_rec *r, apr_file_t * f,
- int sortFlags)
+/* Fetch a message from mailbox */
+Message *fetch_message(request_rec *r, apr_file_t *f, char *msgID)
{
- MBOX_LIST *head;
- char *temp, *baseURI;
+ apr_size_t len = 0;
Message *m;
- mbox_filter_ctx *ctx;
- apr_finfo_t fi;
-
- /* Generate the base URI based on the URI they sent in */
- baseURI = apr_pstrdup(r->pool, r->unparsed_uri);
- temp = strstr(baseURI, r->path_info);
- *temp = '\0';
-
- /* Load the index of messages from the DB into the MBOX_LIST */
- head = mbox_load_index(r, f);
-
- /* This index only changes when the .mbox file changes. */
- apr_file_info_get(&fi, APR_FINFO_MTIME, f);
- r->mtime = fi.mtime;
- ap_set_last_modified(r);
-
- /* Sort the list */
- head = mbox_sort_list(head, sortFlags);
-
- ctx = (mbox_filter_ctx*) apr_pcalloc(r->pool, sizeof(mbox_filter_ctx));
- ap_add_output_filter(MBOX_OUT_INDEX_FILTER, ctx, r, r->connection);
-
- while (head)
- {
- m = (Message*)head->value;
-
- ap_rputs("<LI>", r);
- print_message(r, baseURI, m);
- ap_rputs("</LI>\n", r);
-
- head = head->next;
- }
-
- return OK;
-}
-
-static void print_container(request_rec *r, char *baseURI, Container *c, int depth)
-{
- ap_rputs("<LI>", r);
-
- /* Under the rules of our threading tree, if we do not have a
- * message, we MUST have at least one child. Therefore, print
- * that child's subject when we don't have a message.
- */
- if (c->message)
- print_message(r, baseURI, c->message);
- else
- ap_rprintf(r, "%s", c->child->message->subject);
- if (c->child)
- {
- ap_rputs("<UL>", r);
- print_container(r, baseURI, c->child, depth+1);
- ap_rputs("</UL>", r);
+ /* Fetch message from mbox backend */
+ m = mbox_fetch_index(r, f, msgID);
+ if (!m) {
+ return NULL;
}
- ap_rputs("</LI>\n", r);
-
- if (depth && c->next)
- print_container(r, baseURI, c->next, depth);
-}
-
-/* This function displays the index with threading.
- *
- * The presentation is meant to emulate the old hypermail archives.
- */
-static apr_status_t display_thread_index(request_rec *r, apr_file_t * f)
-{
- MBOX_LIST *head;
- char *temp, *baseURI;
- Container *c;
- mbox_filter_ctx *ctx;
- apr_finfo_t fi;
-
- /* Generate the base URI based on the URI they sent in */
- baseURI = apr_pstrdup(r->pool, r->unparsed_uri);
- temp = strstr(baseURI, r->path_info);
- *temp = '\0';
-
- /* Load the index of messages from the DB into the MBOX_LIST */
- head = mbox_load_index(r, f);
-
- /* This index only changes when the .mbox file changes. */
- apr_file_info_get(&fi, APR_FINFO_MTIME, f);
- r->mtime = fi.mtime;
+ r->mtime = m->date;
ap_set_last_modified(r);
- /* Calculate the threading tree for this list */
- /* Note that the threading does an implicit sort for us.
- * FIXME: Change that later. */
- c = calculate_threads(r->pool, head);
+ /* Fetch message (from msg_start to body_end) */
+ if (apr_file_seek(f, APR_SET, &m->msg_start) != APR_SUCCESS) {
+ return NULL;
+ }
- ctx = (mbox_filter_ctx*) apr_pcalloc(r->pool, sizeof(mbox_filter_ctx));
- ap_add_output_filter(MBOX_OUT_INDEX_FILTER, ctx, r, r->connection);
+ len = m->body_end - m->msg_start;
+ m->raw_msg = apr_palloc(r->pool, len+1);
- while (c)
- {
- print_container(r, baseURI, c, 0);
- c = c->next;
+ if (apr_file_read(f, m->raw_msg, &len) != APR_SUCCESS) {
+ return NULL;
}
- return OK;
+ m->raw_msg[len] = '\0';
+ m->raw_body = m->raw_msg + (m->body_start - m->msg_start);
+
+ return m;
}
-static Container* find_thread(request_rec* r, char* msgID, Container* c)
+/* Find thread starting with message 'msgID' in container 'c' */
+static Container *find_thread(request_rec *r, char *msgID, Container *c)
{
Container *next = NULL;
@@ -167,7 +66,7 @@
return next;
}
-static Container* find_prev_thread(request_rec *r, char* msgID, Container* c)
+static Container *find_prev_thread(request_rec *r, char *msgID, Container *c)
{
Container *next = NULL;
@@ -211,7 +110,7 @@
return next;
}
-static Container* find_next_thread(request_rec *r, char* msgID, Container *c)
+static Container *find_next_thread(request_rec *r, char *msgID, Container *c)
{
c = find_thread(r, msgID, c);
@@ -226,8 +125,7 @@
return c->next;
/* We are at the end of this level, so let's go up levels until we
- * find a next message.
- */
+ find a next message. */
while (c->parent) {
c = c->parent;
@@ -238,10 +136,9 @@
return c->next;
}
- /* Allow skipping to non-related root nodes. This makes for a better
- * browsing experience. However, if a root node doesn't have a
- * message, we need to return its first child.
- */
+ /* Allow skipping to non-related root nodes. This makes for a
+ better browsing experience. However, if a root node doesn't
+ have a message, we need to return its first child. */
if (c->next) {
if (c->next->message)
return c->next;
@@ -252,696 +149,58 @@
return NULL;
}
-static apr_status_t fetch_relative_message(request_rec *r, apr_file_t* f,
- int flags)
-{
- MBOX_LIST *head, *prev = NULL;
- Container *c;
- char *msgID, *newMsgID = NULL;
-
- head = mbox_load_index(r, f);
-
- if (!r->args)
- return HTTP_NOT_FOUND;
-
- msgID = r->args;
- ap_unescape_url(msgID);
-
- switch (flags) {
- case MBOX_PREV:
- head = mbox_sort_list(head, MBOX_SORT_DATE);
- /* FIXME: hash would help... */
- while (head && strcmp(msgID, ((Message*)(head->value))->msgID) != 0)
- {
- prev = head;
- head = head->next;
- }
- if (prev)
- newMsgID = ((Message*)(prev->value))->msgID;
- break;
- case MBOX_NEXT:
- head = mbox_sort_list(head, MBOX_SORT_DATE);
- /* FIXME: hash would help... */
- while (head && strcmp(msgID, ((Message*)(head->value))->msgID) != 0)
- head = head->next;
- if (head && head->next)
- newMsgID = ((Message*)(head->next->value))->msgID;
- break;
- case MBOX_PREV_THREAD:
- c = calculate_threads(r->pool, head);
- if (!c) {
- break;
- }
- c = find_prev_thread(r, msgID, c);
- if (c && c->message)
- newMsgID = c->message->msgID;
- break;
- case MBOX_NEXT_THREAD:
- c = calculate_threads(r->pool, head);
- if (!c) {
- break;
- }
- c = find_next_thread(r, msgID, c);
- if (c && c->message)
- newMsgID = c->message->msgID;
- break;
- default:
- break;
- }
-
- if (newMsgID)
- {
- char *baseURI = apr_pstrdup(r->pool, r->unparsed_uri), *temp;
- ap_unescape_url(baseURI);
- temp = strstr(baseURI, r->path_info);
- *temp = '\0';
- temp = apr_pstrcat(r->pool, baseURI, "/", newMsgID, NULL);
- temp = ap_escape_uri(r->pool, temp);
- apr_table_set(r->err_headers_out, "Location", temp);
- /*ap_internal_redirect(temp, r);*/
- /* HTTP_SEE_OTHER is proper here, but Netscape doesn't
- * properly recognize that status code. */
- return HTTP_MOVED_TEMPORARILY;
- }
-
- return HTTP_NOT_FOUND;
-}
-
-static const char* cte_e_to_char(mbox_cte_e cte)
-{
- switch(cte) {
- case CTE_NONE:
- return "None";
- case CTE_7BIT:
- return "7-Bit";
- case CTE_8BIT:
- return "8-Bit";
- case CTE_UUENCODE:
- return "uuencode";
- case CTE_BINARY:
- return "Binary";
- case CTE_QP:
- return "Quoted Printable";
- case CTE_BASE64:
- return "Base64";
- default:
- return "Unknown CTE";
- }
-}
-
-typedef struct
-{
- int get_part;
- int mp_count;
- int status;
- Message *m;
- char* bound;
- apr_bucket_brigade *bb;
- apr_bucket_brigade *tbb;
- char buf[HUGE_STRING_LEN+1];
-} mbox_mpartf_ctx;
-
-/**
- * Output filter for decoding Multipart/MIME Messages into human readable form.
- * This also includes Content-Encoding Decoding and download links to
- * Binary files.
- */
-apr_status_t mbox_mpart_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- mbox_mpartf_ctx* ctx = f->ctx;
- int seen_eos = 0;
- apr_bucket* e;
- apr_bucket* eos;
- apr_size_t len;
- char* d;
- const char* ct;
- mbox_cte_e ccte = CTE_NONE;
- apr_status_t rv = APR_SUCCESS;
- /* A default that should never happen in the wild. */
- ct = "multipart/broken";
-
- /**
- * FIXME: Is the EOS always the last bucket in a brigade?
- * What about other meta-data buckets?
- * This becomes complicated, because in effect apr_brigade_split_line
- * will eat these meta-buckets.
- */
- eos = APR_BRIGADE_LAST(bb);
-
- if (APR_BUCKET_IS_EOS(eos)) {
- seen_eos = 1;
- }
-
- do {
- apr_brigade_cleanup(ctx->bb);
-
- /**
- * FIXME: The Brigade could end in the middle of a line.
- * Solution 1: Save it all into one brigade, until we get EOF.
- * Solution 2: Change how we search for the separators.
- */
- apr_brigade_split_line(ctx->bb, bb, APR_BLOCK_READ, HUGE_STRING_LEN);
-
- if (APR_BRIGADE_EMPTY(ctx->bb)) {
- /* End of the Source Brigade.. */
- if (seen_eos) {
- eos = apr_bucket_eos_create(f->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(ctx->bb, eos);
- rv = ap_pass_brigade(f->next, ctx->bb);
- }
-
- break;
- }
-
- len = HUGE_STRING_LEN;
-
- apr_brigade_flatten(ctx->bb, ctx->buf, &len);
-
- ctx->buf[len+1] = '\0';
-
- /* FIXME: We Don't care about meta buckets? */
- apr_brigade_cleanup(ctx->bb);
-
- if (ctx->status == 1) {
- d = strstr(ctx->buf, ctx->bound);
- if (d) {
- char* tmp = d + strlen(ctx->bound);
- /* Check for the end of the entire multipart email. */
- if (strlen(tmp) >= 2 && tmp[0] == '-' && tmp[1] == '-') {
- ctx->status = 0;
- }
- else {
- /* Goto the next line, and look for a content type */
- ctx->status = 2;
- ct = "multipart/broken";
- }
-
- if (ctx->get_part != 0 && ctx->mp_count == ctx->get_part) {
- /* Attempt to handle downloading of a single part */
- ap_set_content_type(f->r, apr_pstrdup(f->r->pool, ct));
- rv = mbox_cte_filter(f, ctx->tbb, ccte, 1);
- }
- else if (ctx->get_part == 0){
- /* Fetching the main message */
- rv = mbox_cte_filter(f, ctx->tbb, ccte, 0);
- }
- apr_brigade_cleanup(ctx->tbb);
- /* Reset C-T-E */
- ccte = CTE_NONE;
- continue;
- }
- else {
- if (ctx->get_part != 0 && ctx->mp_count != ctx->get_part) {
- continue;
- }
- else if (ctx->get_part != 0 && ctx->get_part == ctx->mp_count) {
- /* this is the correct section! */
- }
- else if (strcmp(ct, "text/plain") != 0 &&
- strcmp(ct, "text/x-patch") != 0) {
- continue;
- }
-
- e = apr_bucket_heap_create(ctx->buf, len,
- NULL, f->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(ctx->tbb, e);
- continue;
- }
- }
- else if (ctx->status == 2) {
- if (len <= 2 && (strcmp(ctx->buf, "\r\n") || strcmp(ctx->buf, "\n"))) {
- if (!strcmp(ct, "multipart/broken")) {
- /* Unable to find a Content Type header. */
- ctx->status = 1;
- ctx->mp_count++;
- continue;
- }
- else if (!strcmp(ct, "text/plain")) {
- ctx->status = 1;
- ctx->mp_count++;
- continue;
- }
- else {
- if (ctx->get_part) {
- ctx->status = 1;
- ctx->mp_count++;
- continue;
- }
-
- apr_brigade_printf(ctx->bb, NULL, NULL,
- "<hr/>Attachment "
- "<a href='%s/%d'>#%d</a> (%s) (%s)<hr/>",
- f->r->uri, ctx->mp_count+1, ctx->mp_count,
- ct, cte_e_to_char(ccte));
-
- ctx->status = 1;
- ctx->mp_count++;
- rv = ap_pass_brigade(f->next, ctx->bb);
- continue;
- }
- }
- else {
- /* FIXME: Handle Content-Disposition */
- /* FIXME: This does not properly handle line wrapped headers. */
- if (!strncasecmp(ctx->buf, "Content-Type: ",
- strlen("Content-Type: "))) {
- char* tmp = ctx->buf + strlen("Content-Type: ");
- char* p = strstr(tmp, ";");
- if (p) {
- *p = '\0';
- /* FIXME: Handle the name= param. */
- }
- else {
- p = tmp;
- while(*p != '\0') {
- if (isspace(*p)) {
- *p = '\0';
- break;
- }
- *p++;
- }
- }
- ct = apr_pstrdup(f->r->pool, tmp);
- continue;
- }
-
- if (!strncasecmp(ctx->buf, "Content-Transfer-Encoding:",
- strlen("Content-Transfer-Encoding:"))) {
-
- ccte = mbox_parse_cte_header(ctx->buf);
- continue;
- }
- }
- }
- } while(rv == APR_SUCCESS);
-
- return rv;
-}
-
-/* Unlike the original ap_escape_html, this one is also binary safe. */
-apr_bucket* mbox_bucket_escape_html(ap_filter_t* f, apr_pool_t* p,
- const char* s, apr_size_t len)
-{
- apr_bucket* e;
- int i, j;
- char *x;
-
- /* first, count the number of extra characters */
- for (i = 0, j = 0; i < len; i++) {
- if (s[i] == '<' || s[i] == '>') {
- j += 3;
- }
- else if (s[i] == '&') {
- j += 4;
- }
- }
-
- if (j == 0) {
- j = len;
- x = apr_pstrmemdup(p, s, len);
- }
- else {
- x = apr_palloc(p, i + j);
- for (i = 0, j = 0; i < len; i++, j++) {
- if (s[i] == '<') {
- memcpy(&x[j], "<", 4);
- j += 3;
- }
- else if (s[i] == '>') {
- memcpy(&x[j], ">", 4);
- j += 3;
- }
- else if (s[i] == '&') {
- memcpy(&x[j], "&", 5);
- j += 4;
- }
- else {
- x[j] = s[i];
- }
- }
- }
-
- e = apr_bucket_pool_create(x, j, p, f->c->bucket_alloc);
-
- return e;
-}
-
-/**
- * Escapes '<', '>' and '&' as HTML Entities. This is based on
- * ap_escape_html(), but operates on brigades and buckets, instead
- * of a block of char*.
- */
-apr_status_t mbox_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- const char *buf = 0;
- apr_size_t bytes = 0;
- apr_bucket *b;
- apr_bucket *e;
- apr_bucket_brigade *nbb = f->ctx;
-
- if (!f->ctx) {
- nbb = f->ctx = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
- }
- else {
- apr_brigade_cleanup(nbb);
- }
-
- for (b = APR_BRIGADE_FIRST(bb);
- b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
- if (APR_BUCKET_IS_METADATA(b)) {
- apr_bucket_copy(b, &e);
- APR_BRIGADE_INSERT_TAIL(nbb, e);
- }
- else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
- == APR_SUCCESS) {
- e = mbox_bucket_escape_html(f, f->r->pool, buf, bytes);
- APR_BRIGADE_INSERT_TAIL(nbb, e);
- }
- }
-
- apr_brigade_cleanup(bb);
-
- return ap_pass_brigade(f->next, nbb);
-}
-
-/**
- * Using the cached information, this will seek to the correct
- * position in the file, and then put that range into a bucket.
- * This includes the Headers and Body of the Message. No decoding is done.
- */
-static apr_status_t fetch_raw_message(request_rec *r, apr_file_t* f)
-{
- apr_bucket_brigade *bb;
- apr_bucket* e;
- Message *m;
- char *msgID = NULL;
-
- if (!r->args)
- return HTTP_NOT_FOUND;
-
- msgID = r->args;
- ap_unescape_url(msgID);
-
- m = mbox_fetch_index(r, f, msgID);
-
- if (!m) {
- return HTTP_NOT_FOUND;
- }
-
- ap_set_content_type(r, "text/plain");
-
- e = apr_bucket_file_create(f, m->msg_start, m->body_end - m->msg_start,
- r->pool, r->connection->bucket_alloc);
-
- bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
-
- APR_BRIGADE_INSERT_TAIL(bb, e);
-
- return ap_pass_brigade(r->output_filters, bb);
-}
-
-/* This function will take the message id from the virtual namespace, and
- * print out the cached headers of the message and the complete body
- * of the message.
+/* Return an array of 4 strings : the prev, next, prev by thread an
+ * next by thread msgIDs relative to the given msgID.
+ *
+ * FIXME: not working very well, must investigate!
*/
-static apr_status_t fetch_message(request_rec *r, apr_file_t* f)
+char **fetch_context_msgids(request_rec *r, apr_file_t *f, char *msgID)
{
- char *msgID;
- char *bound;
- int len = 0;
- int multipart = 0;
- apr_status_t status;
- mbox_filter_ctx *ctx;
- mbox_mpartf_ctx* mctx = NULL;
- Message *m;
- apr_bucket_brigade *bb;
- apr_bucket* e;
-
- /* msgID should be the part of the URI that Apache could not resolve
- * on its own. Grab it and skip over the expected /.
- */
- msgID = r->path_info;
- msgID++;
-
- bound = strrchr(msgID, '/');
- if (bound) {
- *bound = '\0';
- *bound++;
- len = atoi(bound);
- /* We don't support mime messages with more than 32 parts */
- if (len < 1 || len > 32) {
- len = 0;
- }
- }
- else {
- len = 0;
- }
-
- m = mbox_fetch_index(r, f, msgID);
-
- if (!m) {
- return HTTP_NOT_FOUND;
- }
-
- r->mtime = m->date;
- ap_set_last_modified(r);
-
- status = apr_file_seek(f, APR_SET, &m->body_start);
-
- if (!strncmp(m->content_type,"multipart/", strlen("multipart/"))) {
- multipart = 2;
- if (m->boundary) {
- bound = apr_pstrcat(r->pool, "--", m->boundary, NULL);
- }
- else {
- bound = NULL;
- }
- }
-
- /* If the entire message is Base64 or Q-P, it cannot be a multipart. */
- if (m->cte == CTE_BASE64) {
- ap_add_output_filter(MBOX_BASE64_FILTER, NULL, r, r->connection);
- }
- else if (m->cte == CTE_QP) {
- ap_add_output_filter(MBOX_QP_FILTER, NULL, r, r->connection);
- }
- else if (multipart) {
-
- mctx = apr_palloc(r->pool, sizeof(mbox_mpartf_ctx));
- mctx->m = m;
- mctx->get_part = len;
- mctx->tbb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
- mctx->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
- mctx->status = multipart;
- mctx->bound = bound;
- mctx->buf[HUGE_STRING_LEN] = '\0';
- mctx->mp_count = 0;
- ap_add_output_filter(MBOX_MPART_FILTER, mctx, r, r->connection);
- }
- else {
- /* Just Escape the HTML */
- ap_add_output_filter(MBOX_HTML_FILTER, NULL, r, r->connection);
- }
-
- if (!(multipart && mctx->get_part != 0)) {
- ctx = (mbox_filter_ctx*) apr_pcalloc(r->pool, sizeof(mbox_filter_ctx));
- ctx->m = m;
- ap_add_output_filter(MBOX_OUT_MSG_FILTER, ctx, r, r->connection);
- }
- /*
- if ((r->proto_num >= 1001) && !r->main && !r->prev)
- r->chunked = 1;
- */
-
- e = apr_bucket_file_create(f, m->body_start, m->body_end - m->body_start,
- r->pool, r->connection->bucket_alloc);
+ MBOX_LIST *head, *prev = NULL;
+ Container *threads, *c;
- bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ char **context = apr_palloc(r->pool, 4*sizeof(char *));
- APR_BRIGADE_INSERT_TAIL(bb, e);
+ memset(context, 0, 4*sizeof(char *));
- return ap_pass_brigade(r->output_filters, bb);
-}
+ head = mbox_load_index(r, f, NULL);
-#define MBOX_INDEX_TYPE_FMT "[<A HREF=\"%s/index.html\">Date</A>] " \
- "[<A HREF=\"%s/authors.html\">Author</A>] " \
- "[<A HREF=\"%s/threads.html\">Thread</A>]"
+ /* Compute threads before touching 'head' */
+ threads = calculate_threads(r->pool, head);
-apr_status_t mbox_out_index_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- apr_bucket *b, *bucket;
- mbox_filter_ctx *ctx;
- char *baseURI, *temp, *header, *footer;
-
- ctx = (mbox_filter_ctx*) f->ctx;
-
- /* We want to be nice and display a link back to the index from whence
- * they came. We want the NON r->path_info part, but that isn't a
- * part of the request_rec (no reason why not - could be added?) - so
- * we have to do some trickery to get at it.
- *
- * The unparsed_uri is exactly that, but the path_info has been
- * escaped, so we need to play with the escaping here.
- */
- if (!ctx->baseURI)
- {
- baseURI = apr_pstrdup(f->r->pool, f->r->unparsed_uri);
- ap_unescape_url(baseURI);
- temp = strstr(baseURI, f->r->path_info);
- *temp = '\0';
- ctx->baseURI = ap_escape_uri(f->r->pool, baseURI);
+ /* First, set the MBOX_PREV and MBOX_NEXT IDs */
+ head = mbox_sort_list(head, MBOX_SORT_DATE);
+ while (head && strcmp(msgID, ((Message*)(head->value))->msgID) != 0) {
+ prev = head;
+ head = head->next;
}
- if (!ctx->sent)
- {
- apr_table_unset(f->r->headers_out, "Content-Length");
-
- header = apr_psprintf(f->r->pool,
- DOCTYPE_HTML_4_0T
- "<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n</HEAD>\n<BODY>"
- "Message Index: "
- MBOX_INDEX_TYPE_FMT
- "\n<HR>\n<UL>\n",
- f->r->uri,
- ctx->baseURI, ctx->baseURI, ctx->baseURI);
-
- b = apr_bucket_pool_create(header, strlen(header), f->r->pool,
- f->c->bucket_alloc);
- APR_BRIGADE_INSERT_HEAD(bb, b);
-
- /* mark as having sent the header */
- ctx->sent = 1;
- }
-
- b = APR_BRIGADE_FIRST(bb);
-
- while (b != APR_BRIGADE_SENTINEL(bb)) {
- if (APR_BUCKET_IS_EOS(b))
- {
- footer = apr_psprintf(f->r->pool,
- "</UL>\n<HR>\nMessage Index: "
- MBOX_INDEX_TYPE_FMT
- "\n</BODY>\n</HTML>",
- ctx->baseURI, ctx->baseURI, ctx->baseURI);
-
- bucket = apr_bucket_pool_create(footer, strlen(footer),
- f->r->pool, f->c->bucket_alloc);
-
- /* EOS is a special bucket not containing anything.
- * Insert us before EOS. */
- APR_BUCKET_INSERT_BEFORE(b, bucket);
- }
- b = APR_BUCKET_NEXT(b);
+ if (prev) {
+ context[0] = ((Message*)(prev->value))->msgID;
}
- return ap_pass_brigade(f->next, bb);
-}
-
-apr_status_t mbox_out_message_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- apr_bucket *b;
- mbox_filter_ctx *ctx = f->ctx;
- Message *m = ctx->m;
- char *baseURI, *temp;
-
-
- /* We want to be nice and display a link back to the index from whence
- * they came. We want the NON r->path_info part, but that isn't a
- * part of the request_rec (no reason why not - could be added?) - so
- * we have to do some trickery to get at it.
- *
- * The unparsed_uri is exactly that, but the path_info has been
- * escaped, so we need to play with the escaping here.
- */
- if (!ctx->baseURI)
- {
- baseURI = apr_pstrdup(f->r->pool, f->r->unparsed_uri);
- ap_unescape_url(baseURI);
- temp = strstr(baseURI, f->r->path_info);
- /* Consider the case of a message-ID containing http:// in it.
- * That's kind of bogus, but r->path_info is stored after the
- * double-escapes. This is just all-around bad. Refuse. */
- if (!temp) {
- return APR_EGENERAL;
- }
- *temp = '\0';
- ctx->baseURI = ap_escape_uri(f->r->pool, baseURI);
+ if (head && head->next) {
+ context[1] = ((Message*)(head->next->value))->msgID;
}
- if (!ctx->sent)
- {
- apr_table_unset(f->r->headers_out, "Content-Length");
-
- ctx->tbb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
+ /* And the MBOX_PREV_THREAD and MBOX_NEXT_THREAD ones */
+ if (threads) {
+ c = find_prev_thread(r, msgID, threads);
- temp = URI_ESCAPE_OR_BLANK(f->r->pool, m->msgID);
+ if (c && c->message) {
+ context[2] = c->message->msgID;
+ }
- apr_brigade_printf(ctx->tbb, NULL, NULL,
- DOCTYPE_HTML_4_0T
- "<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n</HEAD>\n<BODY>"
- "Message Index: "
- MBOX_INDEX_TYPE_FMT
- "\n<HR>\n"
- "<STRONG>From:</STRONG> %s<BR>\n"
- "<STRONG>Subject:</STRONG> %s<BR>\n"
- "<STRONG>Date:</STRONG> %s<BR>\n"
- "<A HREF=\"%s/raw?%s\">Raw Message</A> "
- "<A HREF=\"%s/prev?%s\">Prev</A> "
- "<A HREF=\"%s/next?%s\">Next</A> "
- "<A HREF=\"%s/prev-thread?%s\">Prev by Thread</A> "
- "<A HREF=\"%s/next-thread?%s\">Next by Thread</A><BR>\n"
- "<HR>\n<PRE>\n",
- ap_escape_html(f->r->pool, m->subject),
- ctx->baseURI, ctx->baseURI, ctx->baseURI,
- ESCAPE_OR_BLANK(f->r->pool, m->from),
- ESCAPE_OR_BLANK(f->r->pool, m->subject),
- ESCAPE_OR_BLANK(f->r->pool, m->str_date),
- ctx->baseURI, temp,
- ctx->baseURI, temp,
- ctx->baseURI, temp,
- ctx->baseURI, temp,
- ctx->baseURI, temp);
-
- APR_BRIGADE_PREPEND(bb, ctx->tbb);
- /* mark as having sent the header */
- ctx->sent = 1;
- }
-
- b = APR_BRIGADE_FIRST(bb);
-
- while (b != APR_BRIGADE_SENTINEL(bb)) {
- if (APR_BUCKET_IS_EOS(b))
- {
- temp = URI_ESCAPE_OR_BLANK(f->r->pool, m->msgID);
- apr_brigade_printf(ctx->tbb, NULL, NULL,
- "</PRE>\n<HR>\nMessage Index: "
- MBOX_INDEX_TYPE_FMT
- "<BR>\n"
- "<A HREF=\"%s/prev?%s\">Prev</A> "
- "<A HREF=\"%s/next?%s\">Next</A> "
- "<A HREF=\"%s/prev-thread?%s\">Prev by Thread</A> "
- "<A HREF=\"%s/next-thread?%s\">Next by Thread</A>\n"
- "</BODY>\n</HTML>",
- ctx->baseURI, ctx->baseURI, ctx->baseURI,
- ctx->baseURI, temp,
- ctx->baseURI, temp,
- ctx->baseURI, temp,
- ctx->baseURI, temp);
-
- /* EOS is a special bucket not containing anything.
- * Insert us before EOS. */
- APR_BUCKET_REMOVE(b);
- APR_BRIGADE_INSERT_TAIL(ctx->tbb, b);
- APR_BRIGADE_CONCAT(bb, ctx->tbb);
- }
- b = APR_BUCKET_NEXT(b);
+ c = find_next_thread(r, msgID, threads);
+ if (c && c->message) {
+ context[3] = c->message->msgID;
+ }
}
- return ap_pass_brigade(f->next, bb);
+ return context;
}
-/*
- * The return value instructs the caller concerning what happened and what to
+/* The return value instructs the caller concerning what happened and what to
* do next:
* OK ("we did our thing")
* DECLINED ("this isn't something with which we want to get involved")
@@ -953,71 +212,89 @@
apr_finfo_t fi;
apr_status_t status;
- /* Only get involved in our requests */
- /* r->handler == null or
- * r->handler != MBOX_MAGIC_TYPE or
- * r->handler != MBOX_HANDLER
- */
+ /* Only get involved in our requests:
+ r->handler == null or
+ r->handler != MBOX_MAGIC_TYPE or
+ r->handler != MBOX_HANDLER */
if (!r->handler ||
(strcmp(r->handler,MBOX_MAGIC_TYPE) &&
- strcmp(r->handler,MBOX_HANDLER)))
+ strcmp(r->handler,MBOX_HANDLER))) {
return DECLINED;
+ }
/* Only allow GETs */
r->allowed |= (AP_METHOD_BIT << M_GET);
- if (r->method_number != M_GET)
+ if (r->method_number != M_GET) {
return HTTP_METHOD_NOT_ALLOWED;
+ }
/* Make sure file exists - Allows us to give NOT_FOUND */
- if ((apr_stat(&fi, r->filename, APR_FINFO_TYPE, r->pool)) != APR_SUCCESS)
+ if ((apr_stat(&fi, r->filename, APR_FINFO_TYPE, r->pool)) != APR_SUCCESS) {
return HTTP_NOT_FOUND;
+ }
/* Allow the core to handle this... */
- if (!r->path_info || r->path_info[0] == '\0')
- {
+ if (!r->path_info || r->path_info[0] == '\0') {
r->handler = "default-handler";
return DECLINED;
}
/* Required? */
/* Ideally, we'd like to make sure this is a valid subpath */
- if (r->path_info[0] != '/')
+ if (r->path_info[0] != '/') {
return HTTP_BAD_REQUEST;
+ }
/* Open the file */
if ((status = apr_file_open(&f, r->filename, APR_READ,
- APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) {
+ APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
"file permissions deny server access: %s", r->filename);
return HTTP_FORBIDDEN;
}
- /* Set content type */
- r->content_type = "text/html";
+ /* AJAX requests return XML */
+ if (strncmp(r->path_info, "/ajax", 5) == 0) {
+ /* Set content type */
+ r->content_type = "text/xml";
+
+ if (r->header_only)
+ status = OK;
+
+ if (strcmp(r->path_info, "/ajax/boxlist") == 0)
+ status = mbox_xml_boxlist(r);
+
+ else if (strcmp(r->path_info, "/ajax/thread") == 0)
+ status = mbox_xml_msglist(r, f, MBOX_SORT_THREAD);
+ else if (strcmp(r->path_info, "/ajax/author") == 0)
+ status = mbox_xml_msglist(r, f, MBOX_SORT_AUTHOR);
+ else if (strcmp(r->path_info, "/ajax/date") == 0)
+ status = mbox_xml_msglist(r, f, MBOX_SORT_DATE);
+ else
+ status = mbox_xml_message(r, f);
+ }
+ else if (strncmp(r->path_info, "/raw", 4) == 0) {
+ status = mbox_raw_message(r, f);
+ }
+ else {
+ /* Set content type */
+ r->content_type = "text/html";
+
+ if (r->header_only)
+ status = OK;
+
+ if (strcmp(r->path_info, "/browser") == 0)
+ status = mbox_ajax_browser(r);
+
+ else if (strcmp(r->path_info, "/thread") == 0)
+ status = mbox_static_msglist(r, f, MBOX_SORT_THREAD);
+ else if (strcmp(r->path_info, "/author") == 0)
+ status = mbox_static_msglist(r, f, MBOX_SORT_AUTHOR);
+ else if (strcmp(r->path_info, "/date") == 0)
+ status = mbox_static_msglist(r, f, MBOX_SORT_DATE);
- if (r->header_only)
- status = OK;
- else
- {
- /* Send index now or the actual body of the message */
- if (strcmp(r->path_info,"/index.html") == 0)
- status = display_index(r, f, MBOX_SORT_DATE);
- else if (strcmp(r->path_info,"/authors.html") == 0)
- status = display_index(r, f, MBOX_SORT_AUTHOR);
- else if (strcmp(r->path_info,"/threads.html") == 0)
- status = display_thread_index(r, f);
- else if (strcmp(r->path_info,"/prev") == 0)
- status = fetch_relative_message(r, f, MBOX_PREV);
- else if (strcmp(r->path_info,"/next") == 0)
- status = fetch_relative_message(r, f, MBOX_NEXT);
- else if (strcmp(r->path_info,"/prev-thread") == 0)
- status = fetch_relative_message(r, f, MBOX_PREV_THREAD);
- else if (strcmp(r->path_info,"/next-thread") == 0)
- status = fetch_relative_message(r, f, MBOX_NEXT_THREAD);
- else if (strcmp(r->path_info,"/raw") == 0)
- status = fetch_raw_message(r, f);
else
- status = fetch_message(r, f);
+ status = mbox_static_message(r, f);
}
/* Close the file - don't let its status interfere with our request */
@@ -1025,4 +302,3 @@
return status;
}
-
Modified: httpd/mod_mbox/trunk/module-2.0/mod_mbox_index.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mod_mbox_index.c?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mod_mbox_index.c (original)
+++ httpd/mod_mbox/trunk/module-2.0/mod_mbox_index.c Sat Oct 1 09:48:34 2005
@@ -14,101 +14,99 @@
* limitations under the License.
*/
-/* The file contains an alternative Directory Index Handler that displays
- * information about the mailing list.
+/* The file contains an alternative Directory Index Handler that
+ * displays information about the mailing list.
*/
#include "mod_mbox.h"
-static int show_list_info_row(request_rec* r,
- const char* title, const char* sub,
- const char* list, const char* domain) {
- return ap_rprintf(r,
- "<tr>\n"
- "<th>%s:</th>\n"
- "<td><a href=\"mailto:%s-%s@%s\">"
- "%s-%s@%s</a></td>\n</tr>\n",
- title, list, sub, domain,
- list, sub, domain);
+/* Compare two file entries (in reverse order).
+ *
+ * This function is only Used when sorting file list to :
+ * 200501
+ * 200412
+ * 200411
+ */
+static int filename_rsort(const void *fn1, const void *fn2)
+{
+ mbox_file_t *f1 = (mbox_file_t *)fn1;
+ mbox_file_t *f2 = (mbox_file_t *)fn2;
+
+ return strcmp(f2->filename, f1->filename);
}
-static int show_list_info(request_rec *r, mbox_cache_info* mli, dir_cfg *conf)
+/* Fetches the .mbox files from the directory and return a chained
+ * list of mbox_files_t containing all the information we need to
+ * output a complete box listing.
+ */
+mbox_file_t *mbox_fetch_boxes_list(request_rec *r, mbox_cache_info *mli,
+ char *path, int *count)
{
- char dstr[APR_RFC822_DATE_LEN];
- char* list;
- char* domain;
+ apr_status_t rv = APR_SUCCESS;
+ apr_finfo_t finfo;
+ apr_dir_t *dir;
- list = ESCAPE_OR_BLANK(r->pool, mli->list);
- domain = ESCAPE_OR_BLANK(r->pool, mli->domain);
+ mbox_file_t *files;
- ap_rprintf(r,
- "%s@%s Archives",
- list, domain);
- ap_rputs("</title>\n</head>\n"
- "<body\n bgcolor=\"#FFFFFF\" text=\"#000000\" "
- "link=\"#0000FF\" vlink=\"#000080\" alink=\"#FF0000\">\n",
- r);
-
- if (conf->root_url) {
- ap_rprintf(r,
- "<h2>%s@%s (<a href=\"%s\">Site Index</a>)</h2>\n"
- "<table style='text-align: left;'>\n",
- list, domain, conf->root_url);
- }
- else {
- ap_rprintf(r,
- "<h2>%s@%s</h2>\n"
- "<table style='text-align: left;'>\n",
- list, domain);
- }
-
- show_list_info_row(r, "Subscription address", "subscribe",
- list, domain);
- show_list_info_row(r, "Digest subscription address", "digest-subscribe",
- list, domain);
- show_list_info_row(r, "Unsubscription addresses", "unsubscribe",
- list, domain);
- show_list_info_row(r, "Getting help with the list", "help",
- list, domain);
+ rv = apr_dir_open(&dir, path, r->pool);
- apr_rfc822_date(dstr, mli->mtime);
- ap_rprintf(r, "</table><hr/><I>Last Updated: %s</I><hr/>\n", dstr);
+ /* If we couldn't open the directory, something like file
+ permissions are stopping us. */
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "mod_mbox(fetch_boxes_list): Failed to open directory '%s' for index",
+ path);
+ return NULL;
+ }
- return OK;
-}
+ if (!mli) {
+ return NULL;
+ }
-static int show_index_file_info(request_rec *r,
- mbox_cache_info* mli, char* path)
-{
- int count = 0;
- mbox_cache_get_count(mli, &count, path);
- ap_rprintf(r, "<tr><td>%.2s/%.4s</td><td>"
- "<a href=\"%s/threads.html\">Threads</a> "
- "<a href=\"%s/index.html\">Date</a> "
- "<a href=\"%s/authors.html\">Authors</a></td>"
- "<td>%d</td></tr>\n",
- path+4, path, path, path, path, count);
- return OK;
-}
+ *count = 0;
+ files = apr_pcalloc(r->pool, MAX_MBOX_FILES * sizeof(mbox_file_t));
-static int file_alphasort(const void *fn1, const void *fn2)
-{
- /* reverse order */
- return strcmp(*(char**)fn2, *(char**)fn1);
+ /* Foreach file in the directory, add its name and the message
+ count to our array */
+ while ((apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS) &&
+ (*count < MAX_MBOX_FILES)) {
+ if ((apr_fnmatch("*.mbox", finfo.name, 0) == APR_SUCCESS) &&
+ (strstr(finfo.name, "incomplete") == NULL)) {
+ files[*count].filename = apr_pstrdup(r->pool, finfo.name);
+ mbox_cache_get_count(mli, &(files[*count].count), (char *)finfo.name);
+
+ (*count)++;
+ }
+ }
+
+ apr_dir_close(dir);
+
+ /* Sort by reverse filename order */
+ qsort((void *) files, *count, sizeof(mbox_file_t), filename_rsort);
+
+ return files;
}
-static int generate_mbox_index(request_rec *r)
+/* The default index handler, using mbox_display_static_index() */
+int mbox_index_handler(request_rec *r)
{
apr_status_t rv = APR_SUCCESS;
- char* file;
- char* etag;
- apr_dir_t *dir;
- apr_finfo_t finfo;
- apr_array_header_t* files;
- mbox_cache_info* mli;
- dir_cfg *conf;
- int i;
+ mbox_dir_cfg_t *conf;
+ mbox_cache_info *mli;
+
+ char dstr[APR_RFC822_DATE_LEN];
+ char *etag;
+
+ conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+
+ /* Don't serve index if it's not a directory or if it's not
+ enabled */
+ if (strcmp(r->handler, DIR_MAGIC_TYPE) || !conf->enabled) {
+ return DECLINED;
+ }
+
+ /* Open mbox cache */
rv = mbox_cache_get(&mli, r->filename, r->pool);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
@@ -119,104 +117,88 @@
ap_set_content_type(r, "text/html; charset=utf-8");
- rv = apr_dir_open(&dir, r->filename, r->pool);
- if (rv != APR_SUCCESS) {
- /* If we couldn't open the directory, something like file permissions
- * are stopping us.
- */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "mod_mbox: Failed to open directory '%s' for index",
- r->filename);
- return HTTP_FORBIDDEN;
- }
-
- conf = ap_get_module_config(r->per_dir_config, &mbox_module);
-
/* Try to make the index page more cache friendly */
ap_update_mtime(r, mli->mtime);
ap_set_last_modified(r);
etag = ap_make_etag(r, 1);
apr_table_setn(r->headers_out, "ETag", etag);
- files = apr_array_make(r->pool, 0, sizeof(char *));
+ ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", r);
+ ap_rputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n", r);
+ ap_rputs("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n", r);
+
+ ap_rputs("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n", r);
+ ap_rputs(" <head>\n", r);
+ ap_rputs(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n", r);
+ ap_rputs(" <title>Mailing list archives</title>\n", r);
- while (apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS) {
- if (apr_fnmatch("*.mbox", finfo.name, 0) == APR_SUCCESS &&
- strstr(finfo.name, "incomplete") == NULL) {
- *(const char **)apr_array_push(files) = \
- apr_pstrdup(r->pool, finfo.name);
- }
+ if (conf->style_path) {
+ ap_rprintf(r, " <link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n",
+ conf->style_path);
}
- apr_dir_close(dir);
+ if (conf->script_path) {
+ ap_rprintf(r, " <script type=\"text/javascript\" src=\"%s\"></script>\n",
+ conf->script_path);
+ }
+
+ ap_rputs(" </head>\n\n", r);
+
+ ap_rputs(" <body id=\"archives\" onload=\"indexLinks ();\">\n", r);
+ ap_rprintf(r, " <h1>Mailing list archives: %s@%s</h1>\n",
+ ESCAPE_OR_BLANK(r->pool, mli->list),
+ ESCAPE_OR_BLANK(r->pool, mli->domain));
- if (files->nelts != 0) {
- qsort((void *) files->elts, files->nelts,
- sizeof(char *), file_alphasort);
- }
-
- /* FIXME: Alternative Languages. Always forcing to english isn't truthful. */
- ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- DOCTYPE_XHTML_1_0T
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
- "<head>\n<title>", r);
-
-
- if (files->nelts != 0 && mli->list && mli->list[0]) {
- show_list_info(r, mli, conf);
- }
- else {
- ap_rputs("No List Information", r);
- ap_rputs("</title>\n</head>\n"
- "<body\n bgcolor=\"#FFFFFF\" text=\"#000000\" "
- "link=\"#0000FF\" vlink=\"#000080\" alink=\"#FF0000\">\n",
- r);
- if (conf->root_url) {
- ap_rprintf(r, "<h2><a href=\"%s\">Site Index</a></h2>\n",
- conf->root_url);
- }
- }
- ap_rputs("<table width=\"100%\">\n", r);
- ap_rputs("<tr><th align=\"left\" width=\"15%\">Date</th>"
- "<th align=\"left\" width=\"85%\">Sorted by</th><th>Messages</th></tr>", r);
-
- if (files->nelts != 0) {
-
- for (i = 0; i < files->nelts; i++) {
- file = ((char**)files->elts)[i];
- show_index_file_info(r, mli, file);
- if (i+1 < files->nelts) {
- if(((char**)files->elts)[i][3] != ((char**)files->elts)[i+1][3]) {
- ap_rputs("<tr><td colspan='3'><hr/></td></tr>", r);
- }
- }
- }
- }
- else {
- ap_rputs("<tr><td colspan=\"2\">"
- "No messages have been archived for this list."
- "</td></tr>", r);
+ if (conf->root_path) {
+ ap_rprintf(r, " <h5><a href=\"%s\" title=\"Back to the archives depot\">"
+ "Site index</a></h5>\n\n",
+ conf->root_path);
}
- ap_rputs("</table>\n</body>\n</html>", r);
+ /* Output header and list information */
+ ap_rputs(" <table id=\"listinfo\">\n", r);
+ ap_rputs(" <thead><tr><th colspan=\"2\">List information</th></tr></thead>\n", r);
+ ap_rputs(" <tbody>\n", r);
- return OK;
-}
+ ap_rprintf(r, " <tr><td class=\"left\">Writing to the list</td>"
+ "<td class=\"right\">%s@%s</td></tr>\n",
+ ESCAPE_OR_BLANK(r->pool, mli->list),
+ ESCAPE_OR_BLANK(r->pool, mli->domain));
-int mbox_index_handler(request_rec *r)
-{
- dir_cfg *conf;
+ ap_rprintf(r, " <tr><td class=\"left\">Subscription address</td>"
+ "<td class=\"right\">%s-subscribe@%s</td></tr>\n",
+ ESCAPE_OR_BLANK(r->pool, mli->list),
+ ESCAPE_OR_BLANK(r->pool, mli->domain));
- if (strcmp(r->handler, DIR_MAGIC_TYPE)) {
- return DECLINED;
- }
+ ap_rprintf(r, " <tr><td class=\"left\">Digest subscription address</td>"
+ "<td class=\"right\">%s-digest-subscribe@%s</td></tr>\n",
+ ESCAPE_OR_BLANK(r->pool, mli->list),
+ ESCAPE_OR_BLANK(r->pool, mli->domain));
- conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+ ap_rprintf(r, " <tr><td class=\"left\">Unsubscription addresses</td>"
+ "<td class=\"right\">%s-unsubscribe@%s</td></tr>\n",
+ ESCAPE_OR_BLANK(r->pool, mli->list),
+ ESCAPE_OR_BLANK(r->pool, mli->domain));
- if (!conf->enabled) {
- return DECLINED;
+ ap_rprintf(r, " <tr><td class=\"left\">Getting help with the list</td>"
+ "<td class=\"right\">%s-help@%s</td></tr>\n",
+ ESCAPE_OR_BLANK(r->pool, mli->list),
+ ESCAPE_OR_BLANK(r->pool, mli->domain));
+
+ ap_rputs(" </tbody>\n", r);
+ ap_rputs(" </table>\n", r);
+
+ /* Display the box list */
+ rv = mbox_static_index_boxlist(r, conf, mli);
+ if (rv != APR_SUCCESS) {
+ return rv;
}
- return generate_mbox_index(r);
-}
+ apr_rfc822_date(dstr, mli->mtime);
+ ap_rprintf(r, "<p id=\"lastupdated\">Last updated on: %s</p>\n", dstr);
+
+ ap_rputs(" </body>\n", r);
+ ap_rputs("</html>", r);
+ return OK;
+}