You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ma...@apache.org on 2005/10/01 18:48:55 UTC
svn commit: r292999 [2/2] - in /httpd/mod_mbox/trunk: ./ data/ module-2.0/
Modified: httpd/mod_mbox/trunk/module-2.0/mod_mbox_mime.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mod_mbox_mime.c?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mod_mbox_mime.c (original)
+++ httpd/mod_mbox/trunk/module-2.0/mod_mbox_mime.c Sat Oct 1 09:48:34 2005
@@ -14,228 +14,389 @@
* 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;
+ char *headers_bound = NULL;
+
+ /* Locate the end of part headers */
+ headers_bound = strstr(body, "\n\n");
+ if (!headers_bound) {
+ return 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. */
+ tmp = strstr(body, "Content-Type: ");
+ if (!ct && (!tmp || tmp > headers_bound)) {
+ 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 += strlen("Content-Type: ");
+ k = strchr(tmp, ';');
+
+ /* Isolate the Content-Type string (between 'Content-Type: '
+ and ';' or end of line */
+ if (k && k < headers_bound) {
+ *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 < headers_bound) {
+ tmp += strlen("name=");
+ k = tmp;
+
+ while (*k) {
+ if (isspace(*k) || *k == ';') {
+ *k = 0;
+ break;
+ }
+ *k++;
+ }
+
+ /* Check for double quotes */
+ if ((*tmp == '"') && (tmp[strlen(tmp)-1] == '"')) {
+ mail->content_name = apr_pstrndup(p, tmp+1, strlen(tmp) - 2);
+ }
+ else {
+ 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 if the match is within the headers */
+ tmp = strstr(body, "Content-Disposition: ");
+ if (tmp && tmp < headers_bound) {
+ 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 < headers_bound) {
+ 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;
+ }
+
+ /* 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) */
+
+ if (ct) {
+ mail->body = body;
}
+ else {
+ mail->body = strstr(body, "\n\n") + 2;
+ }
+
+ /* 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;
+
+ if (mail->sub[count-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. */
+ // *tmp = '-';
+ }
+
+ /* 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);
+ }
+
+ return mail;
}
-/* 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)
+/* Decode a MIME part body, according to its CTE. */
+char *mbox_mime_decode_body(apr_pool_t *p, mbox_cte_e cte, char *body, apr_size_t len)
{
- unsigned char *src, *dst;
- apr_size_t len = 0;
+ char *new_body = apr_pstrndup(p, body, len);
- 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 (cte == CTE_BASE64) {
+ len = mbox_cte_decode_b64(new_body);
+ }
+ else if (cte == CTE_QP) {
+ len = mbox_cte_decode_qp(new_body);
}
- return len;
+ new_body[len] = 0;
+ return new_body;
}
-/** End metamail 2.7 code **/
-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;
+
+ if (!m) {
+ return NULL;
+ }
+
+ if (strncasecmp(m->content_type, "text/", strlen("text/")) == 0) {
+ char *new_body;
+
+ new_body = mbox_mime_decode_body(p, m->cte, m->body, m->body_len);
+ m->body_len = mbox_cte_escape_html(p, new_body, m->body_len, &(m->body));
+
+ return apr_pstrndup(p, m->body, m->body_len);
+ }
- eos = APR_BRIGADE_LAST(bb);
+ if (!m->sub) {
+ return NULL;
+ }
- if (APR_BUCKET_IS_EOS(eos)) {
- seen_eos = 1;
+ for (i=0 ; i<m->sub_count ; i++) {
+ return mbox_mime_get_body(p, m->sub[i]);
}
- apr_brigade_length(bb, 1, &off);
+ 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);
+/* Display an XHTML MIME structure */
+void mbox_mime_display_static_structure(request_rec *r, mbox_mime_message_t *m,
+ char *link)
+{
+ int i;
- if (rv == APR_SUCCESS) {
+ if (!m) {
+ return;
+ }
- p[len] = '\0';
+ ap_rputs("<li>", r);
- if (cte == CTE_BASE64) {
- len = mbox_mime_decode_b64(p);
- }
- else if (cte == CTE_QP) {
- len = mbox_mime_decode_qp(p);
- }
+ if (m->body_len) {
+ ap_rprintf(r, "<a href=\"%s\">", link);
+ }
- 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);
- }
+ if (m->content_name) {
+ ap_rprintf(r, "%s", m->content_name);
+ }
+ else {
+ ap_rprintf(r, "Unnamed %s", m->content_type);
+ }
- apr_brigade_cleanup(bb);
+ if (m->body_len) {
+ ap_rputs("</a>", r);
+ }
- 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);
-apr_status_t mbox_base64_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- return mbox_cte_filter(f, bb, CTE_BASE64, 0);
+ if (link[strlen(link)-1] == '/') {
+ link[strlen(link)-1] = 0;
+ }
+
+ mbox_mime_display_static_structure(r, m->sub[i],
+ apr_psprintf(r->pool, "%s/%d", link, i+1));
+ ap_rputs("</ul>\n", r);
+ }
}
-apr_status_t mbox_qp_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,
+ char *link)
{
- return mbox_cte_filter(f, bb, CTE_QP, 0);
-}
+ int i;
+
+ if (!m) {
+ return;
+ }
+
+ if (m->content_name) {
+ ap_rprintf(r, "<part name=\"%s\" cd=\"%s\" cte=\"%s\" "
+ "length=\"%u\" link=\"%s\" />\n",
+ m->content_name, m->content_disposition,
+ mbox_cte_to_char(m->cte), m->body_len, link);
+ }
+ else {
+ ap_rprintf(r, "<part ct=\"%s\" cd=\"%s\" cte=\"%s\" "
+ "length=\"%u\" link=\"%s\" />\n",
+ m->content_type, m->content_disposition,
+ mbox_cte_to_char(m->cte), m->body_len, link);
+ }
+
+ if (!m->sub) {
+ return;
+ }
+ ap_rputs("<mime>\n", r);
+ for (i=0 ; i<m->sub_count ; i++) {
+ if (link[strlen(link)-1] == '/') {
+ link[strlen(link)-1] = 0;
+ }
+
+ mbox_mime_display_xml_structure(r, m->sub[i],
+ apr_psprintf(r->pool, "%s/%d", link, i+1));
+ }
+ ap_rputs("</mime>\n", r);
+}
Modified: httpd/mod_mbox/trunk/module-2.0/mod_mbox_search.c
URL: http://svn.apache.org/viewcvs/httpd/mod_mbox/trunk/module-2.0/mod_mbox_search.c?rev=292999&r1=292998&r2=292999&view=diff
==============================================================================
--- httpd/mod_mbox/trunk/module-2.0/mod_mbox_search.c (original)
+++ httpd/mod_mbox/trunk/module-2.0/mod_mbox_search.c Sat Oct 1 09:48:34 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;