httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From max...@apache.org
Subject svn commit: r230522 [2/2] - in /httpd/mod_mbox/branches/httpd-mbox-if: ./ data/ module-2.0/
Date Sat, 06 Aug 2005 02:51:56 GMT
Modified: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_index.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_index.c?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_index.c (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_index.c Fri Aug  5 19:51:40 2005
@@ -14,92 +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)
+/* 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);
-
-    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;
-    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_ERR, rv, r,
@@ -110,98 +117,83 @@
 
     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;
-    }
-
     /* 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);
 
-    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);
-        }
-    }
+    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);
 
-    apr_dir_close(dir);
+    if (conf->style_path) {
+        ap_rprintf(r, "   <link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n",
+		   conf->style_path);
+    }
 
-    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) {
-        show_list_info(r, mli);
-    }
-    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);
-    }
-    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->script_path) {
+        ap_rprintf(r, "   <script type=\"text/javascript\" src=\"%s\"></script>\n",
+		   conf->script_path);
     }
 
-    ap_rputs("</table>\n</body>\n</html>", r);
+    ap_rputs(" </head>\n\n", r);
 
-    return OK;
-}
+    ap_rputs(" <body onload=\"indexLinks ();\">\n", r);
+    ap_rputs("  <h1>Mailing list archives</h1>\n\n", r);
 
-int mbox_index_handler(request_rec *r)
-{
-    dir_cfg *conf;
+    /* 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);
 
-    if (strcmp(r->handler, DIR_MAGIC_TYPE)) {
-        return DECLINED;
-    }
+    ap_rprintf(r, "    <tr><td class=\"left\">List name</td>"
+	       "<td class=\"right\">%s</td></tr>\n",
+	       ESCAPE_OR_BLANK(r->pool, mli->list));
 
-    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+    ap_rprintf(r, "    <tr><td class=\"left\">Domain</td>"
+	       "<td class=\"right\">%s</td></tr>\n",
+	       ESCAPE_OR_BLANK(r->pool, mli->domain));
 
-    if (!conf->enabled) {
-        return DECLINED;
+    ap_rprintf(r, "    <tr><td class=\"left\">Subscribe</td>"
+	       "<td class=\"right\">subscribe-%s@%s</td></tr>\n",
+	       ESCAPE_OR_BLANK(r->pool, mli->list),
+	       ESCAPE_OR_BLANK(r->pool, mli->domain));
+
+    ap_rprintf(r, "    <tr><td class=\"left\">Digest</td>"
+	       "<td class=\"right\">digest-subscribe-%s@%s</td></tr>\n",
+	       ESCAPE_OR_BLANK(r->pool, mli->list),
+	       ESCAPE_OR_BLANK(r->pool, mli->domain));
+
+    ap_rprintf(r, "    <tr><td class=\"left\">Unsubscribe</td>"
+	       "<td class=\"right\">unsubscribe-%s@%s</td></tr>\n",
+	       ESCAPE_OR_BLANK(r->pool, mli->list),
+	       ESCAPE_OR_BLANK(r->pool, mli->domain));
+
+    ap_rprintf(r, "    <tr><td class=\"left\">Help</td>"
+	       "<td class=\"right\">help-%s@%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;
+}

Modified: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_mime.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_mime.c?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_mime.c (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_mime.c Fri Aug  5 19:51:40 2005
@@ -14,228 +14,342 @@
 * limitations under the License.
 */
 
-/**
- * Output filters for decoding common Content-Encodings of E-Mail.  Currently
- * only quoted-printable and base64 are supported.
+/* MIME parsing and structure management 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.
+/* Decode a multipart (or not) email. In order to support multiple
+ * levels of MIME parts, this function is recursive.
  */
+mbox_mime_message_t *mbox_mime_decode_multipart(apr_pool_t *p, char *body,
+						char *ct, mbox_cte_e cte,
+						char *boundary)
+{
+    mbox_mime_message_t *mail;
+    char *tmp = NULL, *k = NULL, *end_bound = NULL;
 
-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
-};
+    /* If no Content-Type is provided, it means that we are parsing a
+       sub-part of the multipart message. The Content-Type header
+       should then be the first line of the part. If not, just ignore
+       the sub-part. */
+    if (!ct && strncasecmp(body, "Content-Type: ", strlen("Content-Type: "))) {
+        return NULL;
+    }
 
-#define char64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+    mail = calloc(1, sizeof(mbox_mime_message_t));
 
-apr_size_t mbox_mime_decode_b64(char *src)
-{
-    char *dst;
-    int c1, c2, c3, c4;
-    int newline = 1, DataDone = 0;
-    apr_size_t len = 0;
-    dst = src;
-
-    while ((c1 = *src++) != '\0') {
-        if (isspace(c1)) {
-            if (c1 == '\n') {
-                newline = 1;
-            } else {
-                newline = 0;
-            }
-            continue;
-        }
-
-        if (DataDone) {
-            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));
-
-        if (c2 == '\0' || c3 == '\0' || c4 == '\0') {
-            /* Premature EOF. Should return an Error? */
-            return len;
-        }
-
-        if (c1 == '=' || c2 == '=') {
-            DataDone=1;
-            continue;
-        }
-
-        c1 = char64(c1);
-        c2 = char64(c2);
-        *dst++ = (c1<<2) | ((c2&0x30)>>4);
-        len++;
-
-        if (c3 == '=') {
-            DataDone = 1;
-        }
-        else {
-            c3 = char64(c3);
-            *dst++ = ((c2&0XF) << 4) | ((c3&0x3C) >> 2);
-            len++;
-
-            if (c4 == '=') {
-                DataDone = 1;
-            }
-            else {
-                c4 = char64(c4);
-                *dst++ = ((c3&0x03) <<6) | c4;
-                len++;
-            }
-        }
+    /* If no Content-Type is given, we have to look for it. */
+    if (!ct) {
+	tmp = body + strlen("Content-Type: ");
+	k = strchr(tmp, ';');
+
+	/* Isolate the Content-Type string (between 'Content-Type: '
+	   and ';' or end of line */
+	if (k) {
+	    *k = 0;
+	}
+	else {
+	    k = tmp;
+	    while (*k) {
+	        if (isspace(*k)) {
+		    *k = 0;
+		    break;
+		}
+		*k++;
+	    }
+	}
+
+	/* Copy the Content-Type and reset *k */
+	mail->content_type = apr_pstrdup(p, tmp);
+	*k = ';';
+
+	/* If available, get MIME part name */
+	tmp = strstr(body, "name=\"");
+	if (tmp) {
+	    tmp += strlen("name=\"");
+	    k = tmp;
+
+	    while (*k) {
+	        if (isspace(*k) || *k == '"') {
+		    *k = 0;
+		    break;
+		}
+		*k++;
+	    }
+
+	    mail->content_name = apr_pstrdup(p, tmp);
+	    *k = '"';
+	}
     }
+    else
+      mail->content_type = ct;
 
-    *dst = '\0';
-    return len;
-}
+    /* Now we have a Content-Type. Look for other useful header information */
 
-static int hex2dec_char(char ch)
-{
-    if (isdigit(ch)) {
-        return ch-'0';
+    /* Check Content-Disposition */
+    tmp = strstr(body, "Content-Disposition: ");
+    if (tmp) {
+	tmp += strlen("Content-Disposition: ");
+	k = tmp;
+
+	while (*k) {
+	    if (isspace(*k) || *k == ';') {
+		*k = 0;
+		break;
+	    }
+	    *k++;
+	}
+
+	/* Copy the Content-Disposition and reset *k */
+	mail->content_disposition = apr_pstrdup(p, tmp);
+	*k = '\n';
     }
-    else if (isupper(ch)) {
-        return ch-'A'+10;
+    else {
+        mail->content_disposition = apr_pstrdup(p, "inline");
     }
+
+    /* Check Content-Transfer-Encoding, if needed */
+    if (cte == CTE_NONE)
+      {
+	  tmp = strstr(body, "Content-Transfer-Encoding: ");
+	  if (tmp) {
+	      tmp += strlen("Content-Transfer-Encoding: ");
+	      k = tmp;
+
+	      while (*k) {
+		  if (isspace(*k) || *k == ';') {
+		      *k = 0;
+		      break;
+		  }
+		  *k++;
+	      }
+
+	      /* Copy the Content-Disposition and reset *k */
+	      mail->cte = mbox_parse_cte_header(tmp);
+	      *k = '\n';
+	  }
+      }
     else {
-        return ch-'a'+10;
+      mail->cte = cte;
     }
-}
 
-/* mime_decode_qp: convert the preamble of MSG from a quoted-printable
-*	encoding to raw text.
-*/
-apr_size_t mbox_mime_decode_qp(char* p)
-{
-    unsigned char *src, *dst;
-    apr_size_t len = 0;
+    /* Now we have all the headers we need. Start processing the
+       body. If the Content-Type was given at call time, the body
+       starts where it's given. Otherwise it's after the headers
+       (first new empty line) */
 
-    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++;
+    if (ct) {
+        mail->body = body;
+    }
+    else {
+        mail->body = strstr(body, "\n\n") + 2;
     }
 
-    return len;
-}
+    /* If the mail is a multipart message, search for the boundary,
+       and process its sub parts by recursive calls. */
+    if (strncmp(mail->content_type, "multipart/", strlen("multipart/")) == 0) {
+	int end = 0, count = 0;
+	char *search, *bound;
+
+	/* If the boundary was not given, we must look for it in the headers */
+	if (!boundary) {
+	    tmp = strstr(body, "boundary=\"");
+	    if (!tmp) {
+		return NULL;
+	    }
+
+	    tmp += strlen("boundary=\"");
+	    k = tmp;
+
+	    while (*k) {
+		if (*k == '"') {
+		    *k = 0;
+		    break;
+		}
+		*k++;
+	    }
+
+	    mail->boundary = apr_pstrdup(p, tmp);
+	    *k = '"';
+	}
+
+	/* Otherwise, the boundary is as given to us */
+	else {
+	    mail->boundary = boundary;
+	}
+
+	/* Now we have our boundary string. We must : look for it once
+	 (begining of MIME part) and then look for the end boundary :
+	 --boundary-- to mark the end of the MIME part */
+
+	/* The start boundary */
+	bound = strstr(mail->body, mail->boundary);
+	if (!bound) {
+	    return NULL;
+	}
+
+	/* The end boudary */
+	end_bound = calloc(strlen(mail->boundary)+5, sizeof(char));
+	sprintf(end_bound, "--%s--", mail->boundary);
+	tmp = strstr(mail->body, end_bound);
+	if (!tmp) {
+	    return NULL;
+	}
+	*tmp = 0;
+
+	/* Set the search begining to the line after the start boundary. */
+	search = bound + strlen(mail->boundary) + 1;
+
+	/* While the MIME part is not finished, go through all sub parts */
+	while (!end) {
+	    char *inbound;
+
+	    inbound = strstr(search+strlen(mail->boundary), mail->boundary);
+	    if (inbound) {
+		char *t = inbound - 2;
+		*t = 0;
+	    }
+
+	    /* Allocate a new pointer for the sub part, and parse it. */
+	    mail->sub = realloc(mail->sub, ++count * sizeof(struct mimemsg *));
+	    mail->sub[count-1] = mbox_mime_decode_multipart(p, search, NULL, CTE_NONE, NULL);
+
+	    /* If the boudary is found again, it means we have another
+	       MIME part in the same multipart message. Set the new
+	       search begining to the line after this new start
+	       boundary */
+	    if (inbound) {
+		char *t = inbound - 2;
+		*t = '-';
+
+		search = inbound + strlen(mail->boundary) + 1;
+		mail->sub[count-1]->body_len = inbound - mail->sub[count-1]->body - 2;
+	    }
+
+	    /* Otherwise, the MIME part is finished. */
+	    else {
+		mail->sub_count = count;
+		end = 1;
+	    }
+	}
+
+	/* Finally reset the end-body pointer. */
+	*k = '\n';
+      }
+
+    /* If the parsed body is not multipart or is a MIME part, the body
+       length is the length of the body string (no surprise here). If
+       it's a MIME part, its correct length will be set after the call
+       to mbox_mime_decode_multipart just a dozen lines above. */
+    else {
+        mail->body_len = strlen(mail->body);
+    }
 
-/** End metamail 2.7 code **/
+    return mail;
+}
 
-apr_status_t mbox_cte_filter(ap_filter_t *f, apr_bucket_brigade *bb,
-                             mbox_cte_e cte, int noescape)
+/* This function returns the relevant MIME part from a message. For
+ * the moment, it just returns the first text/ MIME part available.
+ */
+char *mbox_mime_get_body(apr_pool_t *p, mbox_mime_message_t *m)
 {
-    apr_status_t rv = 0;
-    apr_size_t len;
-    apr_off_t off;
-    int seen_eos = 0;
-    apr_bucket* eos;
-    apr_bucket* e;
-    char* p;
+    int i;
 
-    eos = APR_BRIGADE_LAST(bb);
+    if (!m) {
+        return NULL;
+    }
+
+    if (strncmp(m->content_type, "text/", strlen("text/")) == 0) {
+	char *new_body = NULL;
+
+        if (m->cte == CTE_BASE64) {
+            m->body_len = mbox_cte_decode_b64(m->body);
+	    m->body[m->body_len] = 0;
+	}
+	else if (m->cte == CTE_QP) {
+            m->body_len = mbox_cte_decode_qp(m->body);
+	    m->body[m->body_len] = 0;
+	}
 
-    if (APR_BUCKET_IS_EOS(eos)) {
-        seen_eos = 1;
+	m->body_len = mbox_cte_escape_html(p, m->body, m->body_len, &new_body);
+	m->body = new_body;
+
+	return apr_pstrndup(p, m->body, m->body_len);
     }
 
-    apr_brigade_length(bb, 1, &off);
+    if (!m->sub) {
+        return NULL;
+    }
 
-    /* FIXME: Make the C-T Encoding streamy/bucket based, instead of
-     *        using pflatten
-     */
-    rv = apr_brigade_pflatten(bb, &p, &len, f->r->pool);
+    for (i=0 ; i<m->sub_count ; i++) {
+        return mbox_mime_get_body(p, m->sub[i]);
+    }
 
-    if (rv == APR_SUCCESS) {
+    return NULL;
+}
 
-        p[len] = '\0';
+/* Display an XHTML MIME structure */
+void mbox_mime_display_static_structure(request_rec *r, mbox_mime_message_t *m,
+					char *link)
+{
+    int i;
 
-        if (cte == CTE_BASE64) {
-            len = mbox_mime_decode_b64(p);
-        }
-        else if (cte == CTE_QP) {
-            len = mbox_mime_decode_qp(p);
-        }
+    if (!m) {
+        return;
+    }
 
-        if (noescape) {
-            e = apr_bucket_pool_create(p, len, f->r->pool,
-                                       f->c->bucket_alloc);
-        }
-        else {
-            e = mbox_bucket_escape_html(f, f->r->pool, p, len);
-        }
+    ap_rprintf(r, "<li><a href=\"%s\">", link);
 
-        apr_brigade_cleanup(bb);
+    if (m->content_name) {
+        ap_rprintf(r, "%s</a>", m->content_name);
+    }
+    else {
+        ap_rprintf(r, "Unnamed %s</a>", m->content_type);
+    }
 
-        if (seen_eos) {
-            eos = apr_bucket_eos_create(f->c->bucket_alloc);
-            APR_BRIGADE_INSERT_HEAD(bb, eos);
-        }
+    ap_rprintf(r, " (%s, %s, %u bytes)</li>\n", m->content_disposition,
+	       mbox_cte_to_char(m->cte), m->body_len);
 
-        APR_BRIGADE_INSERT_HEAD(bb, e);
+    if (!m->sub) {
+        return;
     }
 
-    return ap_pass_brigade(f->next, bb);
+    for (i=0 ; i<m->sub_count ; i++) {
+        ap_rputs("<ul>\n", r);
+	mbox_mime_display_static_structure(r, m->sub[i],
+					   apr_psprintf(r->pool, "%s%d/", link, i));
+	ap_rputs("</ul>\n", r);
+    }
 }
 
-apr_status_t mbox_base64_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+/* Display an XML MIME structure */
+void mbox_mime_display_xml_structure(request_rec *r, mbox_mime_message_t *m)
 {
-    return mbox_cte_filter(f, bb, CTE_BASE64, 0);
-}
+    int i;
 
-apr_status_t mbox_qp_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
-    return mbox_cte_filter(f, bb, CTE_QP, 0);
-}
+    if (!m) {
+        return;
+    }
+
+    if (m->content_name) {
+        ap_rprintf(r, "<part name=\"%s\" cd=\"%s\" cte=\"%s\" length=\"%u\" />\n",
+		   m->content_name, m->content_disposition,
+		   mbox_cte_to_char(m->cte), m->body_len);
+    }
+    else {
+        ap_rprintf(r, "<part ct=\"%s\" cd=\"%s\" cte=\"%s\" length=\"%u\" />\n",
+		   m->content_type, m->content_disposition,
+		   mbox_cte_to_char(m->cte), m->body_len);
+    }
+
+    if (!m->sub) {
+        return;
+    }
 
+    for (i=0 ; i<m->sub_count ; i++) {
+        ap_rputs("<mime>\n", r);
+	mbox_mime_display_xml_structure(r, m->sub[i]);
+	ap_rputs("</mime>\n", r);
+    }
+}

Added: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_out.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_out.c?rev=230522&view=auto
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_out.c (added)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_out.c Fri Aug  5 19:51:40 2005
@@ -0,0 +1,963 @@
+/* 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.
+*/
+
+/* This file contains all output functions.
+ */
+
+#include "mod_mbox.h"
+
+char *mbox_months[12][2] = {
+    { "Jan", "January"  },
+    { "Feb", "February" },
+    { "Mar", "March"    },
+    { "Apr", "April"    },
+    { "May", "May"      },
+    { "Jun", "June"     },
+    { "Jul", "July"     },
+    { "Aug", "August"   },
+    { "Sep", "September"},
+    { "Oct", "October"  },
+    { "Nov", "November" },
+    { "Dec", "December" }
+};
+
+/* Outputs an XML list of available mailboxes */
+apr_status_t mbox_xml_boxlist(request_rec *r)
+{
+    apr_status_t rv = APR_SUCCESS;
+
+    mbox_dir_cfg_t *conf;
+    mbox_cache_info *mli;
+    mbox_file_t *files;
+
+    int i, count = 0;
+    char *path, *k;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+
+    path = apr_pstrdup(r->pool, r->filename);
+
+    k = strstr(path, ".mbox");
+    if (!k) {
+        return HTTP_NOT_FOUND;
+    }
+
+    k = k-6;
+    *k = 0;
+
+    /* Open mbox cache */
+    rv = mbox_cache_get(&mli, path, r->pool);
+    if (rv != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                       "mod_mbox(xml_boxlist): Can't open directory cache '%s' for index",
+                       r->filename);
+        return HTTP_FORBIDDEN;
+    }
+
+    files = mbox_fetch_boxes_list(r, mli, path, &count);
+    if (!files) {
+        return HTTP_FORBIDDEN;
+    }
+
+    ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", r);
+    ap_rputs("<boxlist>\n", r);
+
+    for (i=0 ; i<count ; i++) {
+        if (files[i].count || !conf->hide_empty) {
+	    ap_rprintf(r, "<mbox id=\"%s\" count=\"%d\" />\n",
+		       files[i].filename, files[i].count);
+	}
+    }
+
+    ap_rputs("</boxlist>\n", r);
+
+    return APR_SUCCESS;
+}
+
+/* Outputs an XML list of available mailboxes */
+apr_status_t mbox_static_boxlist(request_rec *r)
+{
+    apr_status_t rv = APR_SUCCESS;
+
+    mbox_dir_cfg_t *conf;
+    mbox_cache_info *mli;
+    mbox_file_t *files;
+
+    int i, count = 0;
+    char *base_path;
+    char *path, *k;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+    base_path = get_base_path(r);
+
+    path = apr_pstrdup(r->pool, r->filename);
+    k = strstr(path, ".mbox");
+    if (!k) {
+        return HTTP_NOT_FOUND;
+    }
+
+    /* Roll back before the '/YYYYMM' part of the filename */
+    k = k-7;
+    *k = 0;
+
+    /* Open mbox cache */
+    rv = mbox_cache_get(&mli, path, r->pool);
+    if (rv != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                       "mod_mbox(static_boxlist): Can't open directory cache '%s' for index",
+                       path);
+        return HTTP_FORBIDDEN;
+    }
+
+    files = mbox_fetch_boxes_list(r, mli, path, &count);
+    if (!files) {
+        return HTTP_FORBIDDEN;
+    }
+
+    ap_rputs("  <table id=\"boxlist\">\n", r);
+    ap_rputs("   <thead><tr><th colspan=\"2\">Box list</th></tr></thead>\n", r);
+    ap_rputs("   <tbody>\n", r);
+
+    for (i=0 ; i<count ; i++) {
+        if (files[i].count || !conf->hide_empty) {
+	    if (strcmp(k+1, files[i].filename) == 0) {
+	        ap_rputs("   <tr id=\"boxactive\">", r);
+	    }
+	    else {
+	        ap_rputs("   <tr>", r);
+	    }
+
+	    ap_rprintf(r, "<td class=\"box\"><a href=\"%s/%s%s\">%s %.4s</a></td>"
+		       "<td class=\"msgcount\">%d</td></tr>\n",
+		       base_path, files[i].filename, r->path_info,
+		       mbox_months[atoi(apr_pstrndup(r->pool,
+						     files[i].filename+4, 2)) - 1][0],
+		       files[i].filename, files[i].count);
+	}
+    }
+
+    ap_rputs("   </tbody>\n", r);
+    ap_rputs("  </table>\n", r);
+
+    return APR_SUCCESS;
+}
+
+/* Outputs an XHTML list of available mailboxes */
+apr_status_t mbox_static_index_boxlist(request_rec *r, mbox_dir_cfg_t *conf,
+				       mbox_cache_info *mli)
+{
+    mbox_file_t *files;
+    int side = 0, year_hdr = 0, count = 0, i;
+
+    files = mbox_fetch_boxes_list(r, mli, r->filename, &count);
+    if (!files) {
+        return HTTP_FORBIDDEN;
+    }
+
+    if (!count) {
+        return APR_SUCCESS;
+    }
+
+    ap_rputs("  <table id=\"grid\">\n", r);
+
+    for (i=0 ; i<count ; i++) {
+        /* Only display an entry if it has messages or if we don't
+	   hide empty mailboxes */
+        if (files[i].count || !conf->hide_empty) {
+	    if (!year_hdr) {
+	        if (!side) {
+		    ap_rputs("  <tr><td class=\"left\">\n", r);
+		    side = 1;
+		}
+		else {
+		    ap_rputs("  <td class=\"right\">\n", r);
+		    side = 0;
+		}
+
+		ap_rputs("   <table class=\"year\">\n", r);
+		ap_rputs("    <thead><tr>\n", r);
+		ap_rprintf(r, "     <th colspan=\"3\">Year %.4s</th>\n",
+			   files[i].filename);
+		ap_rputs("    </tr></thead>\n", r);
+		ap_rputs("    <tbody>\n", r);
+
+		year_hdr = 1;
+	    }
+
+	    ap_rprintf(r, "    <tr id=\"mbox-%.4s%.2s\">\n",
+		       files[i].filename, files[i].filename+4);
+	    ap_rprintf(r, "     <td class=\"date\">%s %.4s</td>\n",
+		       mbox_months[atoi(apr_pstrndup(r->pool,
+						     files[i].filename+4, 2)) - 1][0],
+		       files[i].filename);
+	    ap_rprintf(r, "     <td class=\"links\">"
+		       "<a href=\"%.4s%.2s.mbox/thread\">Thread</a>"
+		       " &middot; <a href=\"%.4s%.2s.mbox/date\">Date</a>"
+		       " &middot; <a href=\"%.4s%.2s.mbox/author\">Author</a></td>\n",
+		       files[i].filename, files[i].filename+4,
+		       files[i].filename, files[i].filename+4,
+		       files[i].filename, files[i].filename+4);
+	    ap_rprintf(r, "     <td class=\"msgcount\">%d</td>\n", files[i].count);
+	    ap_rputs("    </tr>\n", r);
+	}
+
+	/* Year separation */
+	if ((files[i+1].filename && year_hdr) &&
+	    (files[i].filename[3] != files[i+1].filename[3])) {
+	    ap_rputs("    </tbody>\n", r);
+	    ap_rputs("   </table>\n", r);
+	    if (side) {
+	        ap_rputs("  </td>\n", r);
+	    }
+	    else {
+	        ap_rputs("  </td></tr>\n\n", r);
+	    }
+
+	    year_hdr = 0;
+	}
+    }
+
+    ap_rputs("    </tbody>\n", r);
+    ap_rputs("   </table>\n\n", r);
+
+    if (side) {
+        ap_rputs("  </td><td class=\"right\"></td></tr>\n", r);
+    }
+
+    ap_rputs("  </table>\n\n", r);
+
+    return APR_SUCCESS;
+}
+
+/* Antispam protection */
+static char *email_antispam(char *email)
+{
+    char *tmp;
+    int i, atsign = 0, ltsign = 0;
+
+    tmp = strrchr(email, '@');
+
+    if (!tmp) {
+        return email;
+    }
+
+    /* Before the '@' sign */
+    atsign = tmp - email - 1;
+
+    tmp = strstr(email, "&lt;");
+    if (tmp) {
+        /* After the '&lt;' */
+        ltsign = tmp - email + strlen("&lt;") - 1;
+    }
+
+    /* Wipe out at most three chars preceding the '@' sign */
+    for (i=0 ; i<3 ; i++) {
+        if ((atsign - i) > ltsign) {
+	    email[atsign - i] = '.';
+	}
+    }
+
+    return email;
+}
+
+/* Display an XHTML message list entry */
+static void display_static_msglist_entry(request_rec *r, Message *m,
+					 int linked, int depth)
+{
+    mbox_dir_cfg_t *conf;
+
+    char *from;
+    int i;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+
+    from = ESCAPE_OR_BLANK(r->pool, m->str_from);
+    from = mbox_cte_decode_header(r->pool, from);
+    if (conf->antispam) {
+        from = email_antispam(from);
+    }
+
+    ap_rputs("   <tr>\n", r);
+
+    /* Message author */
+    if (linked) {
+        ap_rprintf(r, "    <td class=\"author\">%s</td>\n", from);
+    }
+    else {
+        ap_rputs("    <td class=\"author\"></td>\n", r);
+    }
+
+
+    /* Subject, linked or not */
+    ap_rputs("     <td class=\"subject\">", r);
+    for (i=0 ; i < depth ; i++) {
+        ap_rputs("&nbsp;&nbsp;", r);
+    }
+
+    if (linked) {
+        ap_rprintf(r, "<a href=\"%s\">", URI_ESCAPE_OR_BLANK(r->pool, m->msgID));
+    }
+
+    ap_rprintf(r, "%s", ESCAPE_OR_BLANK(r->pool, m->subject));
+    if (linked) {
+        ap_rputs("</a>" , r);
+    }
+    ap_rputs("     </td>\n", r);
+
+    /* Message date */
+    if (linked) {
+        ap_rprintf(r, "    <td class=\"date\">%s</td>\n",
+		   ESCAPE_OR_BLANK(r->pool, m->str_date));
+    }
+    else {
+        ap_rputs("    <td class=\"date\"></td>\n", r);
+    }
+
+    ap_rputs("   </tr>\n", r);
+}
+
+/* Display an XML message list entry */
+static void display_xml_msglist_entry(request_rec *r, Message *m,
+				      int linked, int depth)
+{
+    mbox_dir_cfg_t *conf;
+
+    char *from;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+
+    from = ESCAPE_OR_BLANK(r->pool, m->str_from);
+    from = mbox_cte_decode_header(r->pool, from);
+    if (conf->antispam) {
+        from = email_antispam(from);
+    }
+
+    ap_rprintf(r, " <message linked=\"%d\" depth=\"%d\" id=\"%s\">\n",
+	       linked, depth, URI_ESCAPE_OR_BLANK(r->pool, m->msgID));
+
+    ap_rprintf(r, "  <from><![CDATA[%s]]></from>\n", from);
+    ap_rprintf(r, "  <date>%s</date>\n", ESCAPE_OR_BLANK(r->pool, m->str_date));
+
+    ap_rprintf(r, "  <subject>%s</subject>\n", ESCAPE_OR_BLANK(r->pool, m->subject));
+    ap_rprintf(r, " </message>\n");
+}
+
+/* Display a threaded message list for Container 'c' */
+static void display_msglist_thread(request_rec *r, Container *c,
+				   int depth, int mode)
+{
+    Message *m;
+    int linked = 1;
+
+    /* 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) {
+        m = c->message;
+    }
+    else {
+        m = c->child->message;
+	linked = 0;
+    }
+
+    if (mode == MBOX_OUTPUT_STATIC) {
+        display_static_msglist_entry(r, m, linked, depth);
+    }
+    else {
+        display_xml_msglist_entry(r, m, linked, depth);
+    }
+
+    /* Display children :
+     * Subject
+     *  +-> Re: Subject */
+    if (c->child) {
+        display_msglist_thread(r, c->child, depth+1, mode);
+    }
+
+    /* Display follow-ups :
+     * Subject
+     *  +-> ...
+     *  | +-> ...
+     *  +-> Re: Subject */
+    if (depth && c->next) {
+        display_msglist_thread(r, c->next, depth, mode);
+    }
+}
+
+/* Display the XML index of the specified mbox file. */
+apr_status_t mbox_xml_msglist(request_rec *r, apr_file_t *f, int sortFlags)
+{
+    apr_finfo_t fi;
+
+    mbox_dir_cfg_t *conf;
+    MBOX_LIST *head;
+    Message *m;
+    Container *threads = NULL, *c;
+
+    int current_page = 0;  /* Current page number, starting at 0 */
+    int pages;             /* Number of pages */
+    int count = 0;         /* Message count */
+    int i = 0;
+
+    char *baseURI;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+    baseURI = get_base_uri(r);
+
+    /* Fetch page number if present. Otherwise, assume page #1 */
+    if (r->args && strcmp(r->args, ""))
+      current_page = atoi(r->args);
+
+    /* Load the index of messages from the DB into the MBOX_LIST */
+    head = mbox_load_index(r, f, &count);
+
+    /* Compute the page count, depending on the sort flags */
+    if (sortFlags != MBOX_SORT_THREAD) {
+        pages = count / DEFAULT_MSGS_PER_PAGE;
+	if (count > pages * DEFAULT_MSGS_PER_PAGE) {
+	    pages++;
+	}
+    }
+    else {
+	threads = calculate_threads(r->pool, head);
+	c = threads;
+	count = 0;
+
+	while (c) {
+	    c = c->next;
+	    count++;
+	}
+
+        pages = count / DEFAULT_THREADS_PER_PAGE;
+	if (count > pages * DEFAULT_THREADS_PER_PAGE) {
+	    pages++;
+	}
+    }
+
+    /* 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);
+
+    /* Send page header */
+    ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", r);
+    ap_rprintf(r, "<index month=\"%.2s\" year=\"%.4s\" page=\"%d\" pages=\"%d\">\n",
+	       baseURI + (strlen(baseURI) - strlen(".mbox") - 2),
+	       baseURI + (strlen(baseURI) - strlen(".mbox") - 6),
+	       current_page + 1, pages);
+
+    /* For date and author sorts */
+    if (sortFlags != MBOX_SORT_THREAD) {
+        /* Sort the list */
+        head = mbox_sort_list(head, sortFlags);
+
+	/* Pass useless messages */
+	while (head && (i < current_page * DEFAULT_MSGS_PER_PAGE)) {
+	    head = head->next;
+	    i++;
+	}
+
+	/* Display current_page's messages */
+	while (head && (i < (current_page + 1) * DEFAULT_MSGS_PER_PAGE)) {
+	    m = (Message*)head->value;
+	    display_xml_msglist_entry(r, m, 1, 0);
+
+	    head = head->next;
+	    i++;
+	}
+    }
+
+    /* For threaded view */
+    else {
+        c = threads;
+
+	/* Pass useless threads */
+	while (c && (i < current_page * DEFAULT_THREADS_PER_PAGE)) {
+	    c = c->next;
+	    i++;
+	}
+
+	/* Display current_page's threads */
+	while (c && (i < (current_page + 1) * DEFAULT_THREADS_PER_PAGE)) {
+	    display_msglist_thread(r, c, 0, MBOX_OUTPUT_AJAX);
+	    c = c->next;
+	    i++;
+	}
+    }
+
+    ap_rputs("</index>", r);
+
+    return OK;
+}
+
+/* Display the page selector.
+ *
+ * FIXME: improve the algorithm in order to handle long pages list.
+ */
+static void mbox_static_msglist_page_selector(request_rec *r, char *baseURI,
+					      int pages, int current_page)
+{
+    int i;
+
+    /* If we don't have more than one page, the page selector is
+       useless. Just return silently. */
+    if (pages <= 1) {
+        return;
+    }
+
+    for (i = 0; i < pages; i++) {
+        if (i != 0) {
+	    ap_rputs(" &middot; ", r);
+	}
+
+	if (i != current_page) {
+	    ap_rprintf(r, "<a href=\"%s%s?%d\">%d</a>",
+		       baseURI, r->path_info, i, i+1);
+	}
+	else {
+	  ap_rprintf(r, "%d", i+1);
+	}
+    }
+}
+
+/* Display the XHTML index of the specified mbox file. */
+apr_status_t mbox_static_msglist(request_rec *r, apr_file_t *f, int sortFlags)
+{
+    apr_finfo_t fi;
+
+    mbox_dir_cfg_t *conf;
+    MBOX_LIST *head;
+    Message *m;
+    Container *threads = NULL, *c;
+
+    int current_page = 0;  /* Current page number, starting at 0 */
+    int pages;             /* Ttotal number of pages */
+    int count = 0;         /* Message count */
+    int i = 0;
+
+    char *baseURI;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+    baseURI = get_base_uri(r);
+
+    /* Fetch page number if present. Otherwise, assume page #1 */
+    if (r->args && strcmp(r->args, ""))
+      current_page = atoi(r->args);
+
+    /* Load the index of messages from the DB into the MBOX_LIST */
+    head = mbox_load_index(r, f, &count);
+
+    /* Compute the page count, depending on the sort flags */
+    if (sortFlags != MBOX_SORT_THREAD) {
+        pages = count / DEFAULT_MSGS_PER_PAGE;
+	if (count > pages * DEFAULT_MSGS_PER_PAGE) {
+	    pages++;
+	}
+    }
+    else {
+	threads = calculate_threads(r->pool, head);
+	c = threads;
+	count = 0;
+
+	while (c) {
+	    c = c->next;
+	    count++;
+	}
+
+        pages = count / DEFAULT_THREADS_PER_PAGE;
+	if (count > pages * DEFAULT_THREADS_PER_PAGE) {
+	    pages++;
+	}
+    }
+
+    /* 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);
+
+    /* Send page header */
+    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);
+
+    if (conf->style_path) {
+        ap_rprintf(r, "   <link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n",
+		   conf->style_path);
+    }
+
+    ap_rputs(" </head>\n\n", r);
+    ap_rputs(" <body>\n", r);
+
+    ap_rputs("  <h1>Mailing list archives</a></h1>\n\n", r);
+
+    ap_rputs("  <table id=\"msglist\">\n", r);
+    ap_rprintf(r, "   <thead><tr><th class=\"title\">Message list : %s %.4s</th>",
+	       mbox_months[atoi(apr_pstrndup(r->pool, baseURI +
+					     (strlen(baseURI) -
+					      strlen(".mbox") - 2), 2)) - 1][1],
+	       baseURI + (strlen(baseURI) - strlen(".mbox") - 6));
+
+    ap_rputs("<th class=\"pages\">", r);
+    mbox_static_msglist_page_selector(r, baseURI, pages, current_page);
+    ap_rputs("</th>", r);
+
+    ap_rprintf(r, "<th class=\"sort\">"
+	       "<a href=\"%s/thread\">Thread</a> &middot; "
+	       "<a href=\"%s/author\">Author</a> &middot; "
+	       "<a href=\"%s/date\">Date</a></th></tr></thead>\n",
+	       baseURI, baseURI, baseURI);
+
+    ap_rputs("   <tbody>\n", r);
+
+    /* For date or author sorts */
+    if (sortFlags != MBOX_SORT_THREAD) {
+        /* Sort the list */
+        head = mbox_sort_list(head, sortFlags);
+
+	/* Pass useless messages */
+	while (head && (i < current_page * DEFAULT_MSGS_PER_PAGE)) {
+	    head = head->next;
+	    i++;
+	}
+
+	/* Display current_page's messages */
+	while (head && (i < (current_page + 1) * DEFAULT_MSGS_PER_PAGE)) {
+	    m = (Message*)head->value;
+	    display_static_msglist_entry(r, m, 1, 0);
+
+	    head = head->next;
+	    i++;
+	}
+    }
+
+    /* For threaded view */
+    else {
+        c = threads;
+
+	/* Pass useless threads */
+	while (c && (i < current_page * DEFAULT_THREADS_PER_PAGE)) {
+	    c = c->next;
+	    i++;
+	}
+
+	/* Display current_page's threads */
+	while (c && (i < (current_page + 1) * DEFAULT_THREADS_PER_PAGE)) {
+	    display_msglist_thread(r, c, 0, MBOX_OUTPUT_STATIC);
+	    c = c->next;
+	    i++;
+	}
+    }
+
+    ap_rputs("   </tbody>\n", r);
+    ap_rputs("  </table>\n", r);
+
+    /* Display box list */
+    mbox_static_boxlist(r);
+
+    ap_rputs(" </body>\n", r);
+    ap_rputs("</html>", r);
+    return OK;
+}
+
+/* Outputs the AJAX browser XHTML stub. */
+apr_status_t mbox_ajax_browser(request_rec *r)
+{
+    mbox_dir_cfg_t *conf;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+
+    ap_set_content_type(r, "text/html; charset=utf-8");
+
+    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);
+
+    if (conf->style_path) {
+        ap_rprintf(r, "   <link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n",
+		   conf->style_path);
+    }
+
+    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 onload=\"javascript:loadBrowser ();\">\n", r);
+    ap_rputs("  <h1>Mailing list archives</h1>\n\n", r);
+
+    /* Output a small notice if no MboxScriptPath configuration
+       directive was specified. */
+    if (!conf->script_path) {
+        ap_rputs("  <p>You did not specified a script path, and the dynamic "
+		 "browser won't run without it. Check your server configuration.\n", r);
+    }
+
+    ap_rputs(" </body>\n</html>\n", r);
+
+    return OK;
+}
+
+/* Display a raw mail from cache. No processing is done here. */
+apr_status_t mbox_raw_message(request_rec *r, apr_file_t *f)
+{
+    apr_size_t len = 0;
+
+    Message *m;
+
+    char *msgID, *body;
+
+    /* Fetch message ID */
+    if (!r->args)
+        return HTTP_NOT_FOUND;
+
+    msgID = r->args;
+    ap_unescape_url(msgID);
+
+    /* Fetch message */
+    m = mbox_fetch_index(r, f, msgID);
+    if (!m) {
+        return HTTP_NOT_FOUND;
+    }
+
+    /* Fetch message contents (from msg_start to body_end) */
+    if (apr_file_seek(f, APR_SET, &m->msg_start) != APR_SUCCESS)
+        return HTTP_NOT_FOUND;
+
+    len = m->body_end - m->msg_start;
+    body = apr_palloc(r->pool, len+1);
+
+    if (apr_file_read(f, body, &len) != APR_SUCCESS)
+        return HTTP_INTERNAL_SERVER_ERROR;
+
+    body[len] = '\0';
+
+    ap_set_content_type(r, "text/plain");
+    ap_rprintf(r, "%s", body);
+
+    return OK;
+}
+
+/* Display a static XHTML mail */
+apr_status_t mbox_static_message(request_rec *r, apr_file_t *f)
+{
+    mbox_dir_cfg_t *conf;
+    Message *m;
+
+    char *baseURI, *from, **context;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+    baseURI = get_base_uri(r);
+
+    /* msgID should be the part of the URI that Apache could not resolve
+     * on its own.  Grab it and skip over the expected /.
+     */
+    m = fetch_message(r, f, r->path_info+1);
+    if (!m) {
+        return HTTP_NOT_FOUND;
+    }
+
+    /* FIXME: handle attachment viewing/downloading from here ? */
+
+    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);
+
+    if (conf->style_path) {
+        ap_rprintf(r, "   <link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n",
+		   conf->style_path);
+    }
+
+    ap_rputs(" </head>\n\n", r);
+    ap_rputs(" <body>\n", r);
+    ap_rputs("  <h1>Mailing list archives</h1>\n\n", r);
+
+    /* Display context message list */
+    from = ESCAPE_OR_BLANK(r->pool, m->from);
+    from = mbox_cte_decode_header(r->pool, from);
+    if (conf->antispam) {
+        from = email_antispam(from);
+    }
+
+    ap_rputs("  <table id=\"msgview\">\n", r);
+
+    context = fetch_context_msgids(r, f, m->msgID);
+    ap_rputs("   <thead>\n"
+	     "   <tr>\n"
+	     "    <th class=\"title\">Message view</th>\n"
+	     "    <th class=\"nav\">", r);
+
+    /* Date navigation */
+    if (context[0]) {
+        ap_rprintf(r, "<a href=\"%s/%s\" "
+		   "title=\"Previous by date\">&laquo;</a>",
+		   baseURI, context[0]);
+    }
+    else {
+        ap_rputs("&laquo;", r);
+    }
+
+    ap_rprintf(r, " <a href=\"%s/date\" "
+	       "title=\"View messages sorted by date\">Date</a> ",
+	       baseURI);
+
+    if (context[1]) {
+        ap_rprintf(r, "<a href=\"%s/%s\" "
+		   "title=\"Next by date\">&raquo;</a>",
+		   baseURI, context[1]);
+    }
+    else {
+        ap_rputs("&raquo;", r);
+    }
+
+    ap_rputs(" &middot; ", r);
+
+    /* Thread navigation */
+    if (context[2]) {
+        ap_rprintf(r, "<a href=\"%s/%s\" "
+		   "title=\"Previous by thread\">&laquo;</a>",
+		   baseURI, context[2]);
+    }
+    else {
+        ap_rputs("&laquo;", r);
+    }
+
+    ap_rprintf(r, " <a href=\"%s/thread\" "
+	       "title=\"View messages sorted by thread\">Thread</a> ",
+	       baseURI);
+
+    if (context[3]) {
+        ap_rprintf(r, "<a href=\"%s/%s\" "
+		   "title=\"Next by thread\">&raquo;</a>",
+		   baseURI, context[3]);
+    }
+    else {
+        ap_rputs("&raquo;", r);
+    }
+
+    ap_rputs("</th>\n"
+	     "   </tr>\n"
+	     "   </thead>\n\n", r);
+
+    /* Headers */
+    ap_rputs("   <tbody>\n", r);
+    ap_rprintf(r, "   <tr class=\"from\">\n"
+	       "    <td class=\"left\">From</td>\n"
+	       "    <td class=\"right\">%s</td>\n"
+	       "   </tr>\n", from);
+
+    ap_rprintf(r, "   <tr class=\"subject\">\n"
+	       "    <td class=\"left\">Subject</td>\n"
+	       "    <td class=\"right\">%s</td>\n"
+	       "   </tr>\n", ESCAPE_OR_BLANK(r->pool, m->subject));
+
+    ap_rprintf(r, "   <tr class=\"date\">\n"
+	       "    <td class=\"left\">Date</td>\n"
+	       "    <td class=\"right\">%s</td>\n"
+	       "   </tr>\n", ESCAPE_OR_BLANK(r->pool, m->str_date));
+
+    ap_rprintf(r, "   <tr class=\"raw\">\n"
+	       "    <td class=\"left\"></td>\n"
+	       "    <td class=\"right\"><a href=\"%s/raw?%s\">View raw message</a></td>\n"
+	       "   </tr>\n", baseURI, URI_ESCAPE_OR_BLANK(r->pool, m->msgID));
+
+    /* Message body */
+    ap_rputs("   <tr class=\"contents\"><td colspan=\"2\"><pre>\n", r);
+    ap_rprintf(r, "%s", mbox_mime_get_body(r->pool, m->mime_msg));
+    ap_rputs("</pre></td></tr>\n", r);
+
+    /* MIME structure */
+    ap_rputs("   <tr class=\"mime\">\n"
+	     "    <td class=\"left\">Mime</td>\n"
+	     "    <td class=\"right\">\n<ul>\n", r);
+    mbox_mime_display_static_structure(r, m->mime_msg,
+				       apr_psprintf(r->pool, "%s/%s/",
+						    baseURI, m->msgID));
+    ap_rputs("</ul>\n</td>\n</tr>\n", r);
+    ap_rputs("   </tbody>\n", r);
+    ap_rputs("  </table>\n", r);
+
+    ap_rputs(" </body>\n", r);
+    ap_rputs("</html>\n", r);
+
+    return OK;
+}
+
+/* Display an XML formatted mail */
+apr_status_t mbox_xml_message(request_rec *r, apr_file_t *f)
+{
+    mbox_dir_cfg_t *conf;
+    Message *m;
+
+    char *baseURI, *from;
+
+    conf = ap_get_module_config(r->per_dir_config, &mbox_module);
+    baseURI = get_base_uri(r);
+
+    /* Here, we skip 6 chars (/ajax/). */
+    m = fetch_message(r, f, r->path_info+6);
+    if (!m) {
+        return HTTP_NOT_FOUND;
+    }
+
+    ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", r);
+
+    from = ESCAPE_OR_BLANK(r->pool, m->from);
+    from = mbox_cte_decode_header(r->pool, from);
+    if (conf->antispam) {
+      from = email_antispam(from);
+    }
+
+    ap_rprintf(r, "<mail id=\"%s\">\n"
+	       " <from><![CDATA[%s]]></from>\n"
+	       " <subject>%s</subject>\n"
+	       " <date>%s</date>\n"
+	       " <contents><![CDATA[",
+	       URI_ESCAPE_OR_BLANK(r->pool, m->msgID),
+	       from,
+	       ESCAPE_OR_BLANK(r->pool, m->subject),
+	       ESCAPE_OR_BLANK(r->pool, m->str_date));
+
+    ap_rprintf(r, "%s", mbox_mime_get_body(r->pool, m->mime_msg));
+    ap_rputs("]]></contents>\n", r);
+    ap_rputs(" <mime>\n", r);
+    mbox_mime_display_xml_structure(r, m->mime_msg);
+    ap_rputs(" </mime>\n", r);
+    ap_rputs("</mail>\n", r);
+
+    return OK;
+}

Modified: httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_search.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_search.c?rev=230522&r1=230521&r2=230522&view=diff
==============================================================================
--- httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_search.c (original)
+++ httpd/mod_mbox/branches/httpd-mbox-if/module-2.0/mod_mbox_search.c Fri Aug  5 19:51:40 2005
@@ -61,7 +61,7 @@
 
 int mbox_search_handler(request_rec *r)
 {
-    dir_cfg *conf;
+    mbox_dir_cfg_t *conf;
 
     if (strcmp(r->handler, "mbox-search")) {
         return DECLINED;



Mime
View raw message