dovecot-2.2-pigeonhole: lib-sieve: Created message body part ite...
pigeonhole at rename-it.nl
pigeonhole at rename-it.nl
Sun Nov 29 10:53:29 UTC 2015
details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/be0971931cfe
changeset: 2138:be0971931cfe
user: Stephan Bosch <stephan at rename-it.nl>
date: Sun Nov 29 11:49:47 2015 +0100
description:
lib-sieve: Created message body part iterator and mime header list.
diffstat:
src/lib-sieve/sieve-message.c | 441 ++++++++++++++++++++++++++++++++++++++---
src/lib-sieve/sieve-message.h | 30 ++
2 files changed, 438 insertions(+), 33 deletions(-)
diffs (truncated from 661 to 300 lines):
diff -r c107764e6008 -r be0971931cfe src/lib-sieve/sieve-message.c
--- a/src/lib-sieve/sieve-message.c Sun Nov 29 11:48:29 2015 +0100
+++ b/src/lib-sieve/sieve-message.c Sun Nov 29 11:49:47 2015 +0100
@@ -12,6 +12,7 @@
#include "message-date.h"
#include "message-parser.h"
#include "message-decoder.h"
+#include "message-header-decode.h"
#include "mail-html2text.h"
#include "mail-storage.h"
#include "mail-user.h"
@@ -52,16 +53,18 @@
* Message context
*/
-struct sieve_message_version {
- struct mail *mail;
- struct mailbox *box;
- struct mailbox_transaction_context *trans;
- struct edit_mail *edit_mail;
+struct sieve_message_header {
+ const char *name;
+
+ const unsigned char *value, *utf8_value;
+ size_t value_len, utf8_value_len;
};
struct sieve_message_part {
struct sieve_message_part *parent, *next, *children;
+ ARRAY(struct sieve_message_header) headers;
+
const char *content_type;
const char *content_disposition;
@@ -74,6 +77,13 @@
unsigned int epilogue:1; /* this is a multipart epilogue */
};
+struct sieve_message_version {
+ struct mail *mail;
+ struct mailbox *box;
+ struct mailbox_transaction_context *trans;
+ struct edit_mail *edit_mail;
+};
+
struct sieve_message_context {
pool_t pool;
pool_t context_pool;
@@ -841,12 +851,28 @@
* Message body
*/
+static void str_replace_nuls(string_t *str)
+{
+ char *data = str_c_modifiable(str);
+ unsigned int i, len = str_len(str);
+
+ for (i = 0; i < len; i++) {
+ if (data[i] == '\0')
+ data[i] = ' ';
+ }
+}
+
static bool _is_wanted_content_type
(const char * const *wanted_types, const char *content_type)
+ATTR_NULL(1)
{
- const char *subtype = strchr(content_type, '/');
+ const char *subtype;
size_t type_len;
+ if ( wanted_types == NULL )
+ return TRUE;
+
+ subtype = strchr(content_type, '/');
type_len = ( subtype == NULL ? strlen(content_type) :
(size_t)(subtype - content_type) );
@@ -1039,13 +1065,15 @@
static int sieve_message_parts_add_missing
(const struct sieve_runtime_env *renv,
const char *const *content_types,
- bool extract_text)
+ bool extract_text, bool iter_all)
+ ATTR_NULL(2)
{
struct sieve_message_context *msgctx = renv->msgctx;
pool_t pool = msgctx->context_pool;
struct mail *mail = sieve_message_get_mail(renv->msgctx);
enum message_parser_flags mparser_flags =
MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS;
+ ARRAY(struct sieve_message_header) headers;
struct sieve_message_part *body_part, *header_part, *last_part;
struct message_parser_ctx *parser;
struct message_decoder_context *decoder;
@@ -1055,11 +1083,12 @@
struct istream *input;
unsigned int idx = 0;
bool save_body = FALSE, have_all;
+ string_t *hdr_content = NULL;
int ret;
/* First check whether any are missing */
- if (sieve_message_body_get_return_parts
- (renv, content_types, extract_text)) {
+ if ( !iter_all && sieve_message_body_get_return_parts
+ (renv, content_types, extract_text) ) {
/* Cache hit; all are present */
return SIEVE_EXEC_OK;
}
@@ -1077,6 +1106,13 @@
buf = buffer_create_dynamic(default_pool, 4096);
body_part = header_part = last_part = NULL;
+ if (iter_all) {
+ t_array_init(&headers, 64);
+ hdr_content = t_str_new(512);
+ } else {
+ memset(&headers, 0, sizeof(headers));
+ }
+
/* Initialize body decoder */
decoder = message_decoder_init(NULL, 0);
@@ -1088,6 +1124,9 @@
while ( (ret=message_parser_parse_next_block
(parser, &block)) > 0 ) {
struct sieve_message_part **body_part_idx;
+ struct message_header_line *hdr = block.hdr;
+ struct sieve_message_header *header;
+ unsigned char *data;
if ( block.part != prev_mpart ) {
bool message_rfc822 = FALSE;
@@ -1104,15 +1143,23 @@
(renv, buf, body_part, extract_text);
}
}
+ if ( iter_all && !array_is_created(&body_part->headers) &&
+ array_count(&headers) > 0 ) {
+ p_array_init(&body_part->headers, pool, array_count(&headers));
+ array_copy(&body_part->headers.arr, 0,
+ &headers.arr, 0, array_count(&headers));
+ }
}
/* Start processing next part */
body_part_idx = array_idx_modifiable
(&msgctx->cached_body_parts, idx);
- if (*body_part_idx == NULL)
+ if ( *body_part_idx == NULL )
*body_part_idx = p_new(pool, struct sieve_message_part, 1);
body_part = *body_part_idx;
body_part->content_type = "text/plain";
+ if ( iter_all )
+ array_clear(&headers);
/* Copy tree structure */
if ( block.part->context != NULL ) {
@@ -1124,7 +1171,7 @@
body_part->content_type = epipart->content_type;
body_part->have_body = TRUE;
body_part->epilogue = TRUE;
- save_body = _is_wanted_content_type
+ save_body = iter_all || _is_wanted_content_type
(content_types, body_part->content_type);
} else {
@@ -1171,8 +1218,12 @@
idx++;
}
- if ( block.hdr != NULL || block.size == 0 ) {
- bool is_ctype = FALSE;
+ if ( hdr != NULL || block.size == 0 ) {
+ enum {
+ _HDR_CONTENT_TYPE,
+ _HDR_CONTENT_DISPOSITION,
+ _HDR_OTHER
+ } hdr_field;
/* Reading headers */
@@ -1181,7 +1232,7 @@
(decoder, &block, &decoded);
/* Check for end of headers */
- if ( block.hdr == NULL ) {
+ if ( hdr == NULL ) {
/* Save headers for message/rfc822 part */
if ( header_part != NULL ) {
sieve_message_part_save
@@ -1191,7 +1242,7 @@
/* Save bodies only if we have a wanted content-type */
i_assert( body_part != NULL );
- save_body = _is_wanted_content_type
+ save_body = iter_all || _is_wanted_content_type
(content_types, body_part->content_type);
continue;
}
@@ -1199,47 +1250,101 @@
/* Encountered the empty line that indicates the end of the headers and
* the start of the body
*/
- if ( block.hdr->eoh ) {
+ if ( hdr->eoh ) {
i_assert( body_part != NULL );
body_part->have_body = TRUE;
+ continue;
} else if ( header_part != NULL ) {
/* Save message/rfc822 header as part content */
- if ( block.hdr->continued ) {
- buffer_append(buf, block.hdr->value, block.hdr->value_len);
+ if ( hdr->continued ) {
+ buffer_append(buf, hdr->value, hdr->value_len);
} else {
- buffer_append(buf, block.hdr->name, block.hdr->name_len);
- buffer_append(buf, block.hdr->middle, block.hdr->middle_len);
- buffer_append(buf, block.hdr->value, block.hdr->value_len);
+ buffer_append(buf, hdr->name, hdr->name_len);
+ buffer_append(buf, hdr->middle, hdr->middle_len);
+ buffer_append(buf, hdr->value, hdr->value_len);
}
- if ( !block.hdr->no_newline ) {
+ if ( !hdr->no_newline ) {
buffer_append(buf, "\r\n", 2);
}
}
- /* We're interested in only the Content-Type: header */
- if ( strcasecmp(block.hdr->name, "Content-Type" ) == 0 )
- is_ctype = TRUE;
- else if ( strcasecmp(block.hdr->name, "Content-Disposition" ) != 0 )
+ if ( strcasecmp(hdr->name, "Content-Type" ) == 0 )
+ hdr_field = _HDR_CONTENT_TYPE;
+ else if ( strcasecmp(hdr->name, "Content-Disposition" ) != 0 )
+ hdr_field = _HDR_CONTENT_DISPOSITION;
+ else if ( iter_all && !array_is_created(&body_part->headers) )
+ hdr_field = _HDR_OTHER;
+ else {
+ /* Not interested in this header */
continue;
+ }
/* Header can have folding whitespace. Acquire the full value before
* continuing
*/
- if ( block.hdr->continues ) {
- block.hdr->use_full_value = TRUE;
+ if ( hdr->continues ) {
+ hdr->use_full_value = TRUE;
continue;
}
+ if ( iter_all && !array_is_created(&body_part->headers) ) {
+ /* Add header */
+ header = array_append_space(&headers);
+ header->name = p_strdup(pool, hdr->name);
+
+ // FIXME: trim header values
+
+ /* Decode MIME encoded-words. */
+ str_truncate(hdr_content, 0);
+ message_header_decode_utf8
+ (hdr->full_value, hdr->full_value_len, hdr_content, NULL);
+ if ( hdr->full_value_len != str_len(hdr_content) ||
+ strncmp(str_c(hdr_content), (const char *)hdr->full_value,
+ hdr->full_value_len) != 0 ) {
+ if ( strlen(str_c(hdr_content)) != str_len(hdr_content) ) {
+ /* replace NULs with spaces */
+ str_replace_nuls(hdr_content);
+ }
+ /* store raw */
+ data = p_malloc(pool, hdr->full_value_len + 1);
+ data[hdr->full_value_len] = '\0';
+ header->value = memcpy(data,
+ hdr->full_value, hdr->full_value_len);
+ header->value_len = hdr->full_value_len;
+ /* store decoded */
+ data = p_malloc(pool, str_len(hdr_content) + 1);
+ data[str_len(hdr_content)] = '\0';
+ header->utf8_value = memcpy(data,
+ str_data(hdr_content), str_len(hdr_content));
+ header->utf8_value_len = str_len(hdr_content);
+ } else {
+ /* raw == decoded */
+ data = p_malloc(pool, hdr->full_value_len + 1);
+ data[hdr->full_value_len] = '\0';
+ header->value = header->utf8_value =
+ memcpy(data, hdr->full_value, hdr->full_value_len);
+ header->value_len = header->utf8_value_len =
+ hdr->full_value_len;
+ }
+
+ if ( hdr_field == _HDR_OTHER )
+ continue;
+ }
+
More information about the dovecot-cvs
mailing list