httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From max...@apache.org
Subject svn commit: r230522 [1/2] - in /httpd/mod_mbox/branches/httpd-mbox-if: ./ data/ module-2.0/
Date Sat, 06 Aug 2005 02:51:56 GMT
Author: maxime
Date: Fri Aug  5 19:51:40 2005
New Revision: 230522

URL: http://svn.apache.org/viewcvs?rev=230522&view=rev
Log:
This is the first code commit for mod_mbox interface improvements
development branch : httpd-mbox-if. It includes a major module's code
rewrite and the AJAX browser stub.

In order to clean up and simplify the code, output filters are no
longer used. The code has been split into backend and output
functions.

New configuration directives are available :

 * MboxStyle css-location : specify the stylesheet file location in
   the DocumentRoot ;
 * MboxScript js-location : specify the javascrip file location in
   the DocumentRoot ;
 * MboxHideEmpty (On|Off) : whether to hide or not empty mailboxes in
   boxes list ;
 * MboxAntispam (On|Off) : whether to activate or not the antispam
   protection (email@domain.com -> em...@domain.com)

MIME structure parsing and MIME header decoding have also been
implemented.

 * STATUS:
    Updated STATUS file. Reading recommended.

 * module-2.0/Makefile.am:
    Added needed files for compilation.

 * module-2.0/mod_mbox_cte.c:
    Content-Encoding decoding functions. Quoted-Printable, Base64 and
HTML escaping functions were converted from the corresponding output
filters.

    (mbox_cte_decode_header): new function, implementing RFC 2047 MIME
header decoding.

 * module-2.0/mbox_parse.c:
    (mbox_generate_index): Switched from apr_date_parse_rfc() to our
own mbox_date_parse_rfc(), implementing the recently submitted fix on
the dev@apr mailing list (mail from Maxime Petazzoni : '[PATCH] fixing
bogus apr_date_parse_rfc()', August 3rd 2005). This change will be
reverted as soon as the fixed APR will be released.

    (mbox_load_index): Now returns the message count in the passed
pointer parameter.

 * module-2.0/mbox_parse.h:
    Added the mbox_mime_message_t structure for MIME multipart
decoding. Style fixes and prototype update for mbox_load_index().

 * module-2.0/mbox_date.c, mbox_date.h:
    Implementing the fixed version of apr_date_parse_rfc(). These
files will be removed as soon as the fixed APR will be released.

 * module-2.0/mod_mbox_file.c:
    This file now contains mailbox-related backend functions only.

    (fetch_message): This is now a pure backend function, fetching the
message from the mailbox and calling the multipart decoding. Message
output is no longer done from here.

    (fetch_context_msgids): Created from the fetch_relative_message()
function. Returns the previous by date, next by date, previous by
thread and next by thread message IDs, used when displaying the
message instead of redirecting to the wanted message ID. This allows
"real" links to the context messages and removes a redirection.

    (mbox_file_handler): Code style fixes. Now handle both static
XHTML output and XML output requests. Please notice that the
/index.html URI is no longer handled. Thus, a temporary redirection
should be setup to avoid bookmarks and links breaking.

 * module-2.0/mod_mbox_out.c:
    XHTML and XML output functions for boxes list, message list (with
pagination) and message view. New and valid XHTML output. Code clean
up, uses module's backend functions.

    (mbox_ajax_browser): XHTML stub for AJAX browser.

 * module-2.0/mod_mbox.c:
    Removed hook registrations, added new configuration directives.

    (get_base_path): New function, returns the base path of the
current request : http://domain.com/archives/dev/200508.mbox/thread
returns /archives/dev/.

    (get_base_uri): New function, returns the base URI of the current
request, ie. including the current mailbox.

 * module-2.0/mod_mbox.h:
    Removed useless #define lines. Updated mbox_dir_cfg_t
structure. Added mbox_file_t structure for box list backend function
(see mod_mbox_index.c) and needed function prototypes.

 * module-2.0/mod_mbox_mime.c:
    MIME multipart parsing and structure display functions/

    (mbox_mime_decode_multipart): New multipart parser. Handles
Content-Type, Content-Disposition, Content-Transfer-Encoding and
attachment filenames.

 * module-2.0/mod_mbox_index.c:
    (mbox_fetch_boxes_list): New backend function. Returns an array of
mbox_file_t structures containing mailboxes information (filename,
message count).

    (mbox_index_handler): Updated XHTML output. Two columns boxes
list.

 * data/archives.js:
    Stub for Javascript file. Only implements a stub loadBrowser()
function.

 * data/style.css:
    Basic ASF stylesheet.


Added:
    httpd/mod_mbox/branches/httpd-mbox-if/data/
    httpd/mod_mbox/branches/httpd-mbox-if/data/archives.js
    httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_simple.png   (with props)
    httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_wide.gif   (with props)
    httpd/mod_mbox/branches/httpd-mbox-if/data/style.css
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.c
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.h
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_cte.c
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_out.c
Modified:
    httpd/mod_mbox/branches/httpd-mbox-if/STATUS
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/Makefile.am
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.c
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.h
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.c
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.h
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_file.c
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_index.c
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_mime.c
    httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_search.c

Modified: httpd/mod_mbox/branches/httpd-mbox-if/STATUS
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/STATUS?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/STATUS (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/STATUS Fri Aug  5 19:51:40 2005
@@ -1,23 +1,39 @@
 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:
+    * AJAX browsing interface
+    * S/MIME and MIME structure parsing [done]
+    * MIME header parsing
+    * Charset conversions (to UTF-8)
 
-Other features that need writing:
-	
-    * Better integration with httpd-2.0 build system.
+Other known issues / ToDo:
+
+    * MIME part viewing / downloading
 
-Documentation that needs writing:
+    * Documentation
+      - For developpers : internals
+      - For admins      : setup and update
+      - For users       : usage, interface description, ...
 
-    * Documentation?  What documentation?
+    * Wrap long lines in mails (to ~90 chars so we don't mess
+      with MUA different configurations)
 
-Available Patches:
+    * A QP mail with a '=_N' in it's MIME boundary fails to be parsed
+      by mbox_mime_decode_multipart[1]. Strange, because no QP
+      decoding is done before multipart parsing : only 'JIT' before
+      display.
 
-Open issues:
+      [1] dev@httpd (200302.mbox): <002601c2cd22$2d8b9620$802a24d5@fred>
 
+Wish list:
+
+    * Better integration with httpd-2.0 build system.
+    * Interface internationalization
+    * Better XML semantics ?

Added: httpd/mod_mbox/branches/httpd-mbox-if/data/archives.js
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/data/archives.js?rev=230522&view=auto
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/data/archives.js (added)
+++ httpd/mod_mbox/branches/httpd-mbox-if/data/archives.js Fri Aug  5 19:51:40 2005
@@ -0,0 +1,12 @@
+/** mod_mbox
+ */
+
+/* onLoad function for browser.
+ *
+ */
+function loadBrowser ()
+{
+  document.write('Loading ...');
+
+  return true;
+}

Added: httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_simple.png
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_simple.png?rev=230522&view=auto
==============================================================================
Binary file - no diff available.

Propchange: httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_simple.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_wide.gif
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_wide.gif?rev=230522&view=auto
==============================================================================
Binary file - no diff available.

Propchange: httpd/mod_mbox/branches/httpd-mbox-if/data/asf_logo_wide.gif
------------------------------------------------------------------------------
    svn:mime-type = image/gif

Added: httpd/mod_mbox/branches/httpd-mbox-if/data/style.css
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/data/style.css?rev=230522&view=auto
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/data/style.css (added)
+++ httpd/mod_mbox/branches/httpd-mbox-if/data/style.css Fri Aug  5 19:51:40 2005
@@ -0,0 +1,178 @@
+body
+{
+  margin: 0;
+  padding: 0;
+  font-size: small;
+  background-color: white;
+  background-image: url("/archives/asf_logo_simple.png");
+  background-repeat: no-repeat;
+  background-position: 98% 1em;
+}
+
+a:hover { text-decoration: underline; }
+
+h1
+{
+  font-size: xx-large;
+  margin: 0.6em 2%;
+  padding: 0 0 0.2em 0;
+}
+
+p#lastupdated
+{
+  border-top: 1px #ccc solid;
+  padding: 0.2em;
+  color: #ccc;
+  text-align: right;
+  margin: 1em;
+  font-style: italic;
+}
+
+table
+{
+  margin: 0;
+  border-spacing: 0;
+  border-collapse: collapse;
+
+  border: 1px #900 solid;
+  border-top: none;
+}
+
+table thead th
+{
+  font-size: 110%;
+  font-weight: bold;
+  text-align: left;
+  margin: 0;
+  padding: 0.3em;
+  background: #900;
+  color: white;
+}
+
+table thead th a { color: white; }
+table td { padding: 0.3em 0.5em; }
+
+table#grid
+{
+  margin: 1em 2%;
+  width: 96%;
+  border: none;
+}
+
+table#grid td       { vertical-align: top; }
+table#grid td.left  { width: 50%; }
+table#grid td.right { width: 50%; }
+
+/** List info
+   */
+table#listinfo
+{
+  margin: 1em 2%;
+  width: 96%;
+}
+
+table#listinfo td.left  { background: #ddd; font-weight: bold;
+                          text-align: right; padding-right: 1em;
+                          width: 15%; }
+table#listinfo td.right { background: #eee; text-align: left; }
+
+/** Year
+   */
+table.year { width: 100%; }
+
+table.year tr td.date     { background: #ddd; width: 20%;
+                            text-align: center; padding-right: 1em;
+                            font-weight: bold; }
+table.year tr td.links    { background: #eee; width: 70%; }
+table.year tr td.msgcount { background: #ddd; width: 10%; text-align: center; }
+
+table.year tr:hover td.date     { background: #eee; }
+table.year tr:hover td.links    { background: white; }
+table.year tr:hover td.msgcount { background: #eee; }
+
+
+/** Box list
+   */
+table#boxlist
+{
+  position: absolute;
+  top: 7em;
+  left: 2%;
+  right: 88%;
+  width: 10%;
+  margin-top: 2px;
+  margin-bottom: 1em;
+}
+
+table#boxlist tr       { background: #eee;  }
+table#boxlist tr:hover { background: white; }
+
+table#boxlist tr#boxactive
+{
+  background: white;
+  border-top: 1px #888 solid;
+  border-bottom: 1px #888 solid;
+}
+
+table#boxlist tr.newyear  { border-top: 1px #888 solid; border-bottom: 1px #888 solid;
+                            text-align: center; font-weight: bold; background: white; }
+
+table#boxlist td.msgcount { text-align: right; }
+table#boxlist td.box      { white-space: nowrap; }
+table#boxlist td.box a    { display: block;    }
+
+/** Message list
+   */
+table#msglist
+{
+  margin: 1em 2% 2em auto;
+  width: 80%;
+}
+
+table#msglist thead th.title { text-align: left; white-space: nowrap; }
+table#msglist thead th.pages { text-align: right; }
+table#msglist thead th.sort  { text-align: right; padding-right: 0.3em;
+                               white-space: nowrap; }
+
+table#msglist tr td.author  { background: #ddd; width: 20%; }
+table#msglist tr td.subject { background: #eee; width: 60%;
+                              white-space: pre-wrap; font-family: monospace; overflow: hidden; }
+table#msglist tr td.date    { background: #ddd; width: auto;
+                              text-align: right; font-style: italic;
+                              white-space: nowrap; }
+
+table#msglist tr#msgactive
+{
+  border-top: 1px #888 solid;
+}
+
+table#msglist tr#msgactive td.author,
+table#msglist tr#msgactive td.subject,
+table#msglist tr#msgactive td.date { background: white; }
+
+table#msglist tr:hover td.author  { background: #eee;  }
+table#msglist tr:hover td.subject { background: white; }
+table#msglist tr:hover td.date    { background: #eee;  }
+
+/** Message view
+   */
+table#msgview
+{
+  margin: 1em 2%;
+  width: 96%;
+}
+
+table#msgview thead th.title { text-align: left; white-space: nowrap; }
+table#msgview thead th.nav   { text-align: right; padding-right: 0.3em; }
+
+table#msgview tr td.left   { background: #ddd; width: 10%;
+                             text-align: right; padding-right: 1em; font-weight: bold; }
+table#msgview tr td.right  { background: #eee; width: auto; font-family: monospace; }
+
+table#msgview tr.raw td.right { font-family: sans-serif; }
+
+table#msgview tr.contents  { border-top: 1px #888 solid; }
+table#msgview tr.contents pre { white-space: pre-wrap; }
+
+table#msgview tr.mime { vertical-align: top; }
+table#msgview tr.mime ul { padding-left: 1.5em; margin: 0; }

Modified: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/Makefile.am
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/Makefile.am?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/Makefile.am (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/Makefile.am Fri Aug  5 19:51:40 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

Added: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.c?rev=230522&view=auto
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.c (added)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.c Fri Aug  5 19:51:40 2005
@@ -0,0 +1,378 @@
+/** THIS FILE MUST BE REMOVED WHEN THE APR-UTIL LIBRARY WILL BE FIXED
+ * AND PACKAGED. */
+
+/* Since the apr_date_parse_rfc() function is buggy in current
+ * versions of the Apache Portable Runtime Library, we use a fixed *
+ * version copied here while the fixed version will be uploaded and *
+ * available.
+ */
+
+#include "mbox_date.h"
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if APR_HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+/* Compare a string to a mask. See apr-util/misc/apr_date.c for more
+ * information.
+ */
+static int mbox_date_checkmask(const char *data, const char *mask)
+{
+    int i;
+    char d;
+
+    for (i = 0; i < 256; i++) {
+        d = data[i];
+        switch (mask[i]) {
+        case '\0':
+            return (d == '\0');
+
+        case '*':
+            return 1;
+
+        case '@':
+            if (!apr_isupper(d))
+                return 0;
+            break;
+        case '$':
+            if (!apr_islower(d))
+                return 0;
+            break;
+        case '#':
+            if (!apr_isdigit(d))
+                return 0;
+            break;
+        case '&':
+            if (!apr_isxdigit(d))
+                return 0;
+            break;
+        case '~':
+            if ((d != ' ') && !apr_isdigit(d))
+                return 0;
+            break;
+        default:
+            if (mask[i] != d)
+                return 0;
+            break;
+        }
+    }
+
+    return 0;          /* We only get here if mask is corrupted (exceeds 256) */
+}
+
+/* Parses RFC 822 or RFC 2822 dates. */
+
+#define TIMEPARSE(ds,hr10,hr1,min10,min1,sec10,sec1)        \
+    {                                                       \
+        ds.tm_hour = ((hr10 - '0') * 10) + (hr1 - '0');     \
+        ds.tm_min = ((min10 - '0') * 10) + (min1 - '0');    \
+        ds.tm_sec = ((sec10 - '0') * 10) + (sec1 - '0');    \
+    }
+#define TIMEPARSE_STD(ds,timstr)                            \
+    {                                                       \
+        TIMEPARSE(ds, timstr[0],timstr[1],                  \
+                      timstr[3],timstr[4],                  \
+                      timstr[6],timstr[7]);                 \
+    }
+
+apr_time_t mbox_date_parse_rfc(const char *date)
+{
+    apr_time_exp_t ds;
+    apr_time_t result;
+    int mint, mon;
+    const char *monstr, *timstr, *gmtstr;
+    static const int months[12] =
+    {
+    ('J' << 16) | ('a' << 8) | 'n', ('F' << 16) | ('e' << 8) | 'b',
+    ('M' << 16) | ('a' << 8) | 'r', ('A' << 16) | ('p' << 8) | 'r',
+    ('M' << 16) | ('a' << 8) | 'y', ('J' << 16) | ('u' << 8) | 'n',
+    ('J' << 16) | ('u' << 8) | 'l', ('A' << 16) | ('u' << 8) | 'g',
+    ('S' << 16) | ('e' << 8) | 'p', ('O' << 16) | ('c' << 8) | 't',
+    ('N' << 16) | ('o' << 8) | 'v', ('D' << 16) | ('e' << 8) | 'c' };
+
+    if (!date)
+        return APR_DATE_BAD;
+
+    /* Not all dates have text months at the beginning. */
+    if (!apr_isdigit(date[0]))
+    {
+        while (*date && apr_isspace(*date)) /* Find first non-whitespace char */
+            ++date;
+
+        if (*date == '\0')
+            return APR_DATE_BAD;
+
+        if ((date = strchr(date, ' ')) == NULL)   /* Find space after weekday */
+            return APR_DATE_BAD;
+
+        ++date;    /* Now pointing to first char after space, which should be */    }
+
+    /* start of the actual date information for all 11 formats. */
+    if (mbox_date_checkmask(date, "## @$$ #### ##:##:## *")) {   /* RFC 1123 format */
+        ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
+
+        if (ds.tm_year < 0)
+            return APR_DATE_BAD;
+
+        ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0');
+
+        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 12;
+        gmtstr = date + 21;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else if (mbox_date_checkmask(date, "##-@$$-## ##:##:## *")) {/* RFC 850 format  */
+        ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
+
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 10;
+        gmtstr = date + 19;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else if (mbox_date_checkmask(date, "@$$ ~# ##:##:## ####*")) {
+        /* asctime format */
+        ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100;
+        if (ds.tm_year < 0)
+            return APR_DATE_BAD;
+
+        ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0');
+
+        if (date[4] == ' ')
+            ds.tm_mday = 0;
+        else
+            ds.tm_mday = (date[4] - '0') * 10;
+
+        ds.tm_mday += (date[5] - '0');
+
+        monstr = date;
+        timstr = date + 7;
+        gmtstr = NULL;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else if (mbox_date_checkmask(date, "# @$$ #### ##:##:## *")) {
+        /* RFC 1123 format*/
+        ds.tm_year = ((date[6] - '0') * 10 + (date[7] - '0') - 19) * 100;
+
+        if (ds.tm_year < 0)
+            return APR_DATE_BAD;
+
+        ds.tm_year += ((date[8] - '0') * 10) + (date[9] - '0');
+        ds.tm_mday = (date[0] - '0');
+
+        monstr = date + 2;
+        timstr = date + 11;
+        gmtstr = date + 20;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else if (mbox_date_checkmask(date, "## @$$ ## ##:##:## *")) {
+        /* This is the old RFC 1123 date format - many many years ago, people
+         * used two-digit years.  Oh, how foolish.  */
+        ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
+
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 10;
+        gmtstr = date + 19;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else if (mbox_date_checkmask(date, "# @$$ ## ##:##:## *")) {
+        /* This is the old RFC 1123 date format - many many years ago, people
+         * used two-digit years.  Oh, how foolish.  */
+        ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0');
+
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = (date[0] - '0');
+
+        monstr = date + 2;
+        timstr = date + 9;
+        gmtstr = date + 18;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else if (mbox_date_checkmask(date, "## @$$ ## ##:## *")) {
+        /* Loser format.  This is quite bogus.  */
+        ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
+
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 10;
+        gmtstr = NULL;
+
+        TIMEPARSE(ds, timstr[0],timstr[1], timstr[3],timstr[4], '0','0');
+    }
+    else if (mbox_date_checkmask(date, "# @$$ ## ##:## *")) {
+        /* Loser format.  This is quite bogus.  */
+        ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0');
+
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = (date[0] - '0');
+
+        monstr = date + 2;
+        timstr = date + 9;
+        gmtstr = NULL;
+
+        TIMEPARSE(ds, timstr[0],timstr[1], timstr[3],timstr[4], '0','0');
+    }
+    else if (mbox_date_checkmask(date, "## @$$ ## #:##:## *")) {
+        /* Loser format.  This is quite bogus.  */
+        ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
+
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 9;
+        gmtstr = date + 18;
+
+        TIMEPARSE(ds, '0',timstr[1], timstr[3],timstr[4], timstr[6],timstr[7]);
+    }
+    else if (mbox_date_checkmask(date, "# @$$ ## #:##:## *")) {
+         /* Loser format.  This is quite bogus.  */
+        ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0');
+
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = (date[0] - '0');
+
+        monstr = date + 2;
+        timstr = date + 8;
+        gmtstr = date + 17;
+
+        TIMEPARSE(ds, '0',timstr[1], timstr[3],timstr[4], timstr[6],timstr[7]);
+    }
+    else if (mbox_date_checkmask(date, " # @$$ #### ##:##:## *")) {
+        /* RFC 1123 format with a space instead of a leading zero. */
+        ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
+
+        if (ds.tm_year < 0)
+            return APR_DATE_BAD;
+
+        ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0');
+
+        ds.tm_mday = (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 12;
+        gmtstr = date + 21;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else if (mbox_date_checkmask(date, "##-@$$-#### ##:##:## *")) {
+       /* RFC 1123 with dashes instead of spaces between date/month/year
+        * This also looks like RFC 850 with four digit years.
+        */
+        ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
+        if (ds.tm_year < 0)
+            return APR_DATE_BAD;
+
+        ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0');
+
+        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 12;
+        gmtstr = date + 21;
+
+        TIMEPARSE_STD(ds, timstr);
+    }
+    else
+        return APR_DATE_BAD;
+
+    if (ds.tm_mday <= 0 || ds.tm_mday > 31)
+        return APR_DATE_BAD;
+
+    if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
+        return APR_DATE_BAD;
+
+    mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2];
+    for (mon = 0; mon < 12; mon++)
+        if (mint == months[mon])
+            break;
+
+    if (mon == 12)
+        return APR_DATE_BAD;
+
+    if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10))
+        return APR_DATE_BAD;
+
+    /* February gets special check for leapyear */
+
+    if ((mon == 1) &&
+        ((ds.tm_mday > 29)
+        || ((ds.tm_mday == 29)
+        && ((ds.tm_year & 3)
+        || (((ds.tm_year % 100) == 0)
+        && (((ds.tm_year % 400) != 100)))))))
+        return APR_DATE_BAD;
+
+    ds.tm_mon = mon;
+
+    /* tm_gmtoff is the number of seconds off of GMT the time is.
+     *
+     * We only currently support: [+-]ZZZZ where Z is the offset in
+     * hours from GMT.
+     *
+     * If there is any confusion, tm_gmtoff will remain 0.
+     */
+    ds.tm_gmtoff = 0;
+
+    /* Do we have a timezone ? */
+    if (gmtstr) {
+        int offset;
+	switch (*gmtstr) {
+	case '-':
+  	    offset = atoi(gmtstr+1);
+	    ds.tm_gmtoff -= (offset / 100) * 60 * 60;
+	    ds.tm_gmtoff -= (offset % 100) * 60;
+	    break;
+	case '+':
+	    offset = atoi(gmtstr+1);
+	    ds.tm_gmtoff += (offset / 100) * 60 * 60;
+	    ds.tm_gmtoff += (offset % 100) * 60;
+	    break;
+        }
+    }
+
+    /* apr_time_exp_get uses tm_usec field, but it hasn't been set yet.
+     * It should be safe to just zero out this value.
+     * tm_usec is the number of microseconds into the second.  HTTP only
+     * cares about second granularity.
+     */
+    ds.tm_usec = 0;
+
+    if (apr_time_exp_gmt_get(&result, &ds) != APR_SUCCESS)
+        return APR_DATE_BAD;
+
+    return result;
+}

Added: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.h
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.h?rev=230522&view=auto
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.h (added)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_date.h Fri Aug  5 19:51:40 2005
@@ -0,0 +1,25 @@
+/** THIS FILE MUST BE REMOVED WHEN THE APR-UTIL LIBRARY WILL BE FIXED
+ * AND PACKAGED. */
+
+#ifndef MBOX_DATE_H
+#define MBOX_DATE_H
+
+#define CORE_PRIVATE
+#include "apr.h"
+#include "apr_lib.h"
+#include "apu.h"
+#include "apr_time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define APR_DATE_BAD ((apr_time_t)0)
+
+apr_time_t mbox_date_parse_rfc(const char *date);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBOX_DATE_H */

Modified: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.c?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.c (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.c Fri Aug  5 19:51:40 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"
@@ -783,7 +786,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;
@@ -865,7 +870,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;
@@ -878,8 +883,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.
@@ -920,6 +930,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/branches/httpd-mbox-if/module-2.0/mbox_parse.h
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.h?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.h (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mbox_parse.h Fri Aug  5 19:51:40 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,43 @@
 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;
+    char *content_type;
+    char *boundary;
+    mbox_cte_e cte;
     apr_time_t date;
-    char * str_date;
+    char *str_date;
+
     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;
+
+    mbox_mime_message_t *mime_msg;
 };
 
 /* The threading information about a message. */
@@ -160,7 +181,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/branches/httpd-mbox-if/module-2.0/mod_mbox.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.c?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.c (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.c Fri Aug  5 19:51:40 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 <12345@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,48 +38,41 @@
 
 #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->hide_empty = 0;
     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;
     }
@@ -100,6 +80,23 @@
         to->enabled = from->enabled;
     }
 
+    /* Update 'hide_empty' */
+    if (merge->hide_empty == 1) {
+        to->hide_empty = 1;
+    }
+    else {
+        to->hide_empty = from->hide_empty;
+    }
+
+    /* Update 'antispam' */
+    if (merge->antispam == 1) {
+        to->antispam = 1;
+    }
+    else {
+        to->antispam = from->antispam;
+    }
+
+    /* Update 'search_path' */
     if (merge->search_path != NULL) {
         to->search_path = apr_pstrdup(p, merge->search_path);
     }
@@ -110,16 +107,78 @@
         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;
 }
 
+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,
+                 (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("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/branches/httpd-mbox-if/module-2.0/mod_mbox.h
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.h?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.h (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox.h Fri Aug  5 19:51:40 2005
@@ -48,59 +48,96 @@
 #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* search_path;
-} dir_cfg;
+#define MBOX_OUTPUT_STATIC 0
+#define MBOX_OUTPUT_AJAX   1
 
+typedef struct mbox_dir_cfg {
+    int enabled;
+    int antispam;
+    int hide_empty;
+    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_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);
+
+/* Utility functions */
+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
 }

Added: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_cte.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_cte.c?rev=230522&view=auto
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_cte.c (added)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_cte.c Fri Aug  5 19:51:40 2005
@@ -0,0 +1,317 @@
+/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
+* applicable.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+/* Decoding common Content-Encodings of E-Mail functions.
+ */
+
+#include "mod_mbox.h"
+
+/*
+ * The char64 macro and `mime_decode_b64' routine are taken from
+ * metamail 2.7, which is copyright (c) 1991 Bell Communications
+ * Research, Inc. (Bellcore).  The following license applies to all
+ * code below this point:
+ *
+ * Permission to use, copy, modify, and distribute this material
+ * for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice
+ * appear in all copies, and that the name of Bellcore not be
+ * used in advertising or publicity pertaining to this
+ * material without the specific, prior written permission
+ * of an authorized representative of Bellcore.  BELLCORE
+ * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
+ * OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
+ */
+
+static char index_64[128] = {
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+#define char64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+
+const char *mbox_cte_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";
+    }
+}
+
+/* Unlike the original ap_escape_html, this one is also binary
+ * safe.
+ */
+apr_size_t mbox_cte_escape_html(apr_pool_t *p, const char *s,
+				apr_size_t len, char **body)
+{
+    char *x;
+    int i, j;
+
+    /* 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 there is nothing to escape, just copy the body to the new
+       string */
+    if (j == 0) {
+        j = len;
+        x = apr_pstrmemdup(p, s, len);
+    }
+
+    /* Otherwise, we have some extra characters to insert : allocate
+       enough space for them, and process the data. */
+    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];
+            }
+        }
+    }
+
+    *body = x;
+    return j;
+}
+
+/* Decode BASE64 encoded data */
+apr_size_t mbox_cte_decode_b64(char *src)
+{
+    apr_size_t len = 0;
+
+    int newline = 1, data_done = 0;
+    int c1, c2, c3, c4;
+    char *dst;
+
+    dst = src;
+
+    while ((c1 = *src++) != '\0') {
+        if (isspace(c1)) {
+            if (c1 == '\n') {
+                newline = 1;
+            } else {
+                newline = 0;
+            }
+            continue;
+        }
+
+        if (data_done) {
+            continue;
+        }
+
+        newline = 0;
+
+        do {
+            c2 = *src++;
+        } while (c2 != '\0' && isspace(c2));
+
+        do {
+            c3 = *src++;
+        } while (c3 != '\0' && isspace(c3));
+
+        do {
+            c4 = *src++;
+        } while (c4 != '\0' && isspace(c4));
+
+        /* Premature EOF. Should return an Error? */
+        if ((c2 == '\0') || (c3 == '\0') || (c4 == '\0')) {
+            return len;
+        }
+
+        if (c1 == '=' || c2 == '=') {
+            data_done = 1;
+            continue;
+        }
+
+        c1 = char64(c1);
+        c2 = char64(c2);
+        *dst++ = (c1 << 2) | ((c2 & 0x30) >> 4);
+        len++;
+
+        if (c3 == '=') {
+            data_done = 1;
+        }
+        else {
+            c3 = char64(c3);
+            *dst++ = ((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2);
+            len++;
+
+            if (c4 == '=') {
+                data_done = 1;
+            }
+            else {
+                c4 = char64(c4);
+                *dst++ = ((c3 & 0x03) << 6) | c4;
+                len++;
+            }
+        }
+    }
+
+    *dst = '\0';
+    return len;
+}
+
+static int hex2dec_char(char ch)
+{
+    if (isdigit(ch)) {
+        return ch - '0';
+    }
+    else if (isupper(ch)) {
+        return ch - 'A' + 10;
+    }
+    else {
+        return ch - 'a' + 10;
+    }
+}
+
+/* Decode quoted-printable to raw text. */
+apr_size_t mbox_cte_decode_qp(char* p)
+{
+    apr_size_t len = 0;
+    char *src, *dst;
+
+    dst = src = p;
+    while (*src != '\0') {
+        if (*src == '=') {
+            if (*++src == '\n') {
+                ++src;
+                continue;
+            }
+            else {
+                int hi, lo;
+                hi = hex2dec_char(*src++);
+                lo = hex2dec_char(*src);
+                *dst = (hi * 16) + lo;
+            }
+        }
+        else {
+            *dst = *src;
+        }
+
+        ++dst, ++src;
+        len++;
+    }
+
+    return len;
+}
+
+/* MIME header decoding (see RFC 2047).
+ *
+ * This function performs the decoding of headers like :
+ * =?UTF-8?B?QnJhbmtvIMSMaWJlag==?=
+ *
+ * These headers complies to the following syntax :
+ * =?charset?mode?data?= rest
+ */
+char *mbox_cte_decode_header(apr_pool_t *p, char *src)
+{
+    apr_size_t len;
+    char *charset, *mode, *data, *rest;
+
+    /* Look for the end bound */
+    rest = strstr(src, "?=");
+    if (!rest) {
+        return src;
+    }
+    *rest = 0;
+    rest += strlen("?=");
+
+    /* Look for charset */
+    charset = strstr(src, "=?");
+    if (!charset) {
+        return src;
+    }
+    charset += strlen("=?");
+
+    /* Encoding mode (first '?' after charset) */
+    mode = strstr(charset, "?");
+    if (!mode) {
+        return src;
+    }
+    *mode = 0;
+    mode++;
+
+    /* Fetch data */
+    data = strstr(mode, "?");
+    if (!data) {
+        return src;
+    }
+    *data = 0;
+    data++;
+
+    /* Quoted-Printable decoding : mode 'q' */
+    if ((*mode == 'q') || (*mode == 'Q')) {
+        int i;
+
+	/* In QP header encoding, spaces are encoded either in =20 (as
+	   in all QP encoding) or in underscores '_' (for header
+	   encoding). The first case will be handle by the QP
+	   decoding, so we must handle the other one */
+	for (i = 0; i < strlen(data); i++) {
+	    if (data[i] == '_') {
+	      data[i] = ' ';
+	    }
+	}
+
+	len = mbox_cte_decode_qp(data);
+	data[len] = 0;
+    }
+    else if ((*mode == 'b') || (*mode == 'B')) {
+        len = mbox_cte_decode_b64(data);
+	data[len] = 0;
+    }
+
+    return apr_psprintf(p, "%s%s", data, rest);
+}

Modified: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_file.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_file.c?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_file.c (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_file.c Fri Aug  5 19:51:40 2005
@@ -14,144 +14,46 @@
 * 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);
+    char *body;
 
-    /* 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;
+    /* Fetch message from mbox backend */
+    m = mbox_fetch_index(r, f, msgID);
+    if (!m) {
+        return NULL;
     }
 
-    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);
+    r->mtime = m->date;
+    ap_set_last_modified(r);
 
-    if (c->child)
-    {
-        ap_rputs("<UL>", r);
-        print_container(r, baseURI, c->child, depth+1);
-        ap_rputs("</UL>", r);
+    /* Fetch message body (from body_start to body_end) */
+    if (apr_file_seek(f, APR_SET, &m->body_start) != APR_SUCCESS) {
+        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;
-    ap_set_last_modified(r);
+    len = m->body_end - m->body_start;
+    body = apr_palloc(r->pool, len+1);
 
-    /* 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);
+    if (apr_file_read(f, body, &len) != 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);
+    body[len] = '\0';
 
-    while (c)
-    {
-        print_container(r, baseURI, c, 0);
-        c = c->next;
-    }
+    m->mime_msg = mbox_mime_decode_multipart(r->pool, body, m->content_type,
+					     m->cte, m->boundary);
 
-    return OK;
+    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 +69,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 +113,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 +128,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 +139,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,690 +152,51 @@
     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);
-        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);
-        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;
-    }
+    MBOX_LIST *head, *prev = NULL;
+    Container *threads, *c;
 
-    r->mtime = m->date;
-    ap_set_last_modified(r);
+    char **context = apr_palloc(r->pool, 4*sizeof(char *));
 
-    status = apr_file_seek(f, APR_SET, &m->body_start);
+    /* First, set the MBOX_PREV and MBOX_NEXT IDs */
+    head = mbox_load_index(r, f, NULL);
+    head = mbox_sort_list(head, MBOX_SORT_DATE);
 
-    if (!strncmp(m->content_type,"multipart/", strlen("multipart/"))) {
-        multipart = 2;
-        if (m->boundary) {
-            bound = apr_pstrcat(r->pool, "--", m->boundary, NULL);
-        }
-        else {
-            bound = NULL;
-        }
+    while (head && strcmp(msgID, ((Message*)(head->value))->msgID) != 0) {
+      prev = head;
+      head = head->next;
     }
 
-    /* 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 (prev) {
+        context[0] = ((Message*)(prev->value))->msgID;
     }
 
-    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 (head && head->next) {
+        context[1] = ((Message*)(head->next->value))->msgID;
     }
-    /*
-     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);
-
-    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
-
-    APR_BRIGADE_INSERT_TAIL(bb, e);
-
-    return ap_pass_brigade(r->output_filters, bb);
-}
-
-#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>]"
-
-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);
+    /* And the MBOX_PREV_THREAD and MBOX_NEXT_THREAD ones */
+    threads = calculate_threads(r->pool, head);
+    c = find_prev_thread(r, msgID, threads);
+    if (c && c->message) {
+        context[2] = c->message->msgID;
     }
 
-    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);
+    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;
 }
 
-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 (!ctx->sent)
-    {
-        apr_table_unset(f->r->headers_out, "Content-Length");
-
-        ctx->tbb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
-
-        temp = URI_ESCAPE_OR_BLANK(f->r->pool, m->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);
-    }
-
-    return ap_pass_brigade(f->next, bb);
-}
-
-/*
- * 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")
@@ -947,71 +208,88 @@
     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 {
+	/* Set content type */
+	r->content_type = "text/html";
 
-    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);
+	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);
+
+        else if (strcmp(r->path_info, "/raw") == 0)
+            status = mbox_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 */
@@ -1019,4 +297,3 @@
 
     return status;
 }
-



Mime
View raw message