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], "&lt;", 4);
-                j += 3;
-            }
-            else if (s[i] == '>') {
-                memcpy(&x[j], "&gt;", 4);
-                j += 3;
-            }
-            else if (s[i] == '&') {
-                memcpy(&x[j], "&amp;", 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;
+}