You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ma...@apache.org on 2005/08/06 04:51:56 UTC
svn commit: r230522 [2/2] - in /httpd/mod_mbox/branches/httpd-mbox-if: ./
data/ module-2.0/
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>"
+ " · <a href=\"%.4s%.2s.mbox/date\">Date</a>"
+ " · <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, "<");
+ if (tmp) {
+ /* After the '<' */
+ ltsign = tmp - email + strlen("<") - 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(" ", 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(" · ", 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> · "
+ "<a href=\"%s/author\">Author</a> · "
+ "<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\">«</a>",
+ baseURI, context[0]);
+ }
+ else {
+ ap_rputs("«", 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\">»</a>",
+ baseURI, context[1]);
+ }
+ else {
+ ap_rputs("»", r);
+ }
+
+ ap_rputs(" · ", r);
+
+ /* Thread navigation */
+ if (context[2]) {
+ ap_rprintf(r, "<a href=\"%s/%s\" "
+ "title=\"Previous by thread\">«</a>",
+ baseURI, context[2]);
+ }
+ else {
+ ap_rputs("«", 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\">»</a>",
+ baseURI, context[3]);
+ }
+ else {
+ ap_rputs("»", 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;