Mercurial > dovecot > core-2.2
changeset 14591:07e6ca397a72
Created lib-imap-storage for IMAP-specific functionality that uses lib-storage.
This is done to prevent introducing dependencies on lib-storage in
lib-imap. It contains IMAP message part access functionality, including
URL-based access.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Sat, 02 Jun 2012 17:56:27 +0300 |
parents | 9eef4f7b0187 |
children | 5344ff4215b4 |
files | configure.in src/Makefile.am src/imap/Makefile.am src/imap/imap-fetch-body.c src/lib-imap-storage/Makefile.am src/lib-imap-storage/imap-msgpart-url.c src/lib-imap-storage/imap-msgpart-url.h src/lib-imap-storage/imap-msgpart.c src/lib-imap-storage/imap-msgpart.h src/lib-storage/Makefile.am |
diffstat | 10 files changed, 683 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Sat Jun 02 17:53:31 2012 +0300 +++ b/configure.in Sat Jun 02 17:56:27 2012 +0300 @@ -2512,13 +2512,13 @@ if test "$want_shared_libs" = "yes"; then LIBDOVECOT_DEPS='$(top_builddir)/src/lib-dovecot/libdovecot.la' LIBDOVECOT="$LIBDOVECOT_DEPS" - LIBDOVECOT_STORAGE_DEPS='$(top_builddir)/src/lib-storage/libdovecot-storage.la' + LIBDOVECOT_STORAGE_DEPS='$(top_builddir)/src/lib-storage/libdovecot-storage.la $(top_builddir)/src/lib-imap-storage/libimap-storage.la' LIBDOVECOT_LOGIN='$(top_builddir)/src/login-common/libdovecot-login.la' LIBDOVECOT_LDA='$(top_builddir)/src/lib-lda/libdovecot-lda.la' else LIBDOVECOT_DEPS='$(top_builddir)/src/lib-master/libmaster.la $(top_builddir)/src/lib-settings/libsettings.la $(top_builddir)/src/lib-dict/libdict.la $(top_builddir)/src/lib-dns/libdns.la $(top_builddir)/src/lib-fs/libfs.la $(top_builddir)/src/lib-imap/libimap.la $(top_builddir)/src/lib-mail/libmail.la $(top_builddir)/src/lib-auth/libauth.la $(top_builddir)/src/lib-charset/libcharset.la $(top_builddir)/src/lib/liblib.la' LIBDOVECOT="$LIBDOVECOT_DEPS \$(LIBICONV)" - LIBDOVECOT_STORAGE_LAST='$(top_builddir)/src/lib-storage/list/libstorage_list.la $(top_builddir)/src/lib-storage/index/libstorage_index.la $(top_builddir)/src/lib-storage/libstorage.la $(top_builddir)/src/lib-index/libindex.la' + LIBDOVECOT_STORAGE_LAST='$(top_builddir)/src/lib-storage/list/libstorage_list.la $(top_builddir)/src/lib-storage/index/libstorage_index.la $(top_builddir)/src/lib-storage/libstorage.la $(top_builddir)/src/lib-index/libindex.la $(top_builddir)/src/lib-imap-storage/libimap-storage.la' LIBDOVECOT_STORAGE_FIRST='$(top_builddir)/src/lib-storage/libstorage_service.la $(top_builddir)/src/lib-storage/register/libstorage_register.la' LIBDOVECOT_STORAGE_DEPS="$LIBDOVECOT_STORAGE_FIRST $LINKED_STORAGE_LIBS $LIBDOVECOT_STORAGE_LAST" LIBDOVECOT_LOGIN='$(top_builddir)/src/login-common/liblogin.la $(top_builddir)/src/lib-ssl-iostream/libssl_iostream.la' @@ -2748,6 +2748,7 @@ src/lib-dns/Makefile src/lib-fs/Makefile src/lib-imap/Makefile +src/lib-imap-storage/Makefile src/lib-imap-client/Makefile src/lib-index/Makefile src/lib-lda/Makefile
--- a/src/Makefile.am Sat Jun 02 17:53:31 2012 +0300 +++ b/src/Makefile.am Sat Jun 02 17:56:27 2012 +0300 @@ -6,6 +6,7 @@ lib-fs \ lib-mail \ lib-imap \ + lib-imap-storage \ lib-master \ lib-dict \ lib-settings
--- a/src/imap/Makefile.am Sat Jun 02 17:53:31 2012 +0300 +++ b/src/imap/Makefile.am Sat Jun 02 17:56:27 2012 +0300 @@ -9,6 +9,7 @@ -I$(top_srcdir)/src/lib-master \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-imap-storage \ -I$(top_srcdir)/src/lib-index \ -I$(top_srcdir)/src/lib-storage @@ -78,7 +79,6 @@ mail-storage-callbacks.c \ main.c - headers = \ imap-client.h \ imap-commands.h \
--- a/src/imap/imap-fetch-body.c Sat Jun 02 17:53:31 2012 +0300 +++ b/src/imap/imap-fetch-body.c Sat Jun 02 17:56:27 2012 +0300 @@ -11,6 +11,7 @@ #include "message-send.h" #include "mail-storage-private.h" #include "imap-parser.h" +#include "imap-msgpart.h" #include "imap-fetch.h" #include <stdlib.h> @@ -464,63 +465,13 @@ return fetch_data(ctx, body, &size); } -/* Find message_part for section (eg. 1.3.4) */ -static int part_find(struct mail *mail, const struct imap_fetch_body_data *body, - const struct message_part **part_r, const char **section_r) -{ - struct message_part *part; - const char *path; - unsigned int num; - - if (mail_get_parts(mail, &part) < 0) - return -1; - - path = body->section; - while (*path >= '0' && *path <= '9' && part != NULL) { - /* get part number, we have already verified its validity */ - num = 0; - while (*path != '\0' && *path != '.') { - i_assert(*path >= '0' && *path <= '9'); - - num = num*10 + (*path - '0'); - path++; - } - - if (*path == '.') - path++; - - if (part->flags & MESSAGE_PART_FLAG_MULTIPART) { - /* find the part */ - part = part->children; - for (; num > 1 && part != NULL; num--) - part = part->next; - } else { - /* only 1 allowed with non-multipart messages */ - if (num != 1) - part = NULL; - } - - if (part != NULL && - (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) && - (*path >= '0' && *path <= '9')) { - /* if we continue inside the message/rfc822, skip this - body part */ - part = part->children; - } - } - - *part_r = part; - *section_r = path; - return 0; -} - static int fetch_body_mime(struct imap_fetch_context *ctx, struct mail *mail, const struct imap_fetch_body_data *body) { const struct message_part *part; const char *section; - if (part_find(mail, body, &part, §ion) < 0) + if (imap_msgpart_find(mail, body->section, &part, §ion) < 0) return -1; if (part == NULL) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-imap-storage/Makefile.am Sat Jun 02 17:56:27 2012 +0300 @@ -0,0 +1,21 @@ +noinst_LTLIBRARIES = libimap-storage.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-test \ + -I$(top_srcdir)/src/lib-charset \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/lib-imap + +libimap_storage_la_SOURCES = \ + imap-msgpart.c \ + imap-msgpart-url.c + +headers = \ + imap-msgpart.h \ + imap-msgpart-url.h + +pkginc_libdir=$(pkgincludedir) +pkginc_lib_HEADERS = $(headers) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-imap-storage/imap-msgpart-url.c Sat Jun 02 17:56:27 2012 +0300 @@ -0,0 +1,230 @@ +#include "lib.h" +#include "network.h" +#include "istream.h" +#include "message-parser.h" +#include "mail-storage.h" +#include "mail-namespace.h" +#include "imap-url.h" +#include "imap-msgpart.h" +#include "imap-msgpart-url.h" + +struct imap_msgpart_url { + char *mailbox; + uint32_t uidvalidity; + uint32_t uid; + char *section; + uoff_t partial_offset, partial_size; + + struct mail_user *user; + struct mailbox *box; + struct mailbox_transaction_context *trans; + struct mail *mail; + + struct istream *input; + uoff_t part_size; +}; + +struct imap_msgpart_url * +imap_msgpart_url_create(struct mail_user *user, const struct imap_url *url) +{ + struct imap_msgpart_url *mpurl; + + i_assert(url->mailbox != NULL && url->uid != 0 && + url->search_program == NULL); + + mpurl = i_new(struct imap_msgpart_url, 1); + mpurl->user = user; + mpurl->mailbox = i_strdup(url->mailbox); + mpurl->uidvalidity = url->uidvalidity; + mpurl->uid = url->uid; + if (url->section != NULL) + mpurl->section = i_strdup(url->section); + mpurl->partial_offset = url->partial_offset; + mpurl->partial_size = url->partial_size; + return mpurl; +} + +struct imap_msgpart_url * +imap_msgpart_url_parse(struct mail_user *user, struct mailbox *selected_box, + const char *urlstr, const char **error_r) +{ + struct mailbox_status box_status; + struct imap_url base_url, *url; + const char *error; + + /* build base url */ + memset(&base_url, 0, sizeof(base_url)); + if (selected_box != NULL) { + mailbox_get_open_status(selected_box, STATUS_UIDVALIDITY, + &box_status); + base_url.mailbox = mailbox_get_vname(selected_box); + base_url.uidvalidity = box_status.uidvalidity; + } + + /* parse url */ + url = imap_url_parse(urlstr, NULL, &base_url, + IMAP_URL_PARSE_REQUIRE_RELATIVE, &error); + if (url == NULL) { + *error_r = t_strconcat("Invalid IMAP URL: ", error, NULL); + return NULL; + } + if (url->mailbox == NULL) { + *error_r = "Mailbox-relative IMAP URL, but no mailbox selected"; + return NULL; + } + if (url->uid == 0 || url->search_program != NULL) { + *error_r = "Invalid messagepart IMAP URL"; + return NULL; + } + return imap_msgpart_url_create(user, url); +} + +struct mailbox *imap_msgpart_url_get_mailbox(struct imap_msgpart_url *mpurl) +{ + return mpurl->box; +} + +struct mailbox * +imap_msgpart_url_open_mailbox(struct imap_msgpart_url *mpurl, + const char **error_r) +{ + struct mailbox_status box_status; + enum mail_error error_code; + enum mailbox_flags flags = MAILBOX_FLAG_READONLY; + struct mail_namespace *ns; + struct mailbox *box; + + if (mpurl->box != NULL) + return mpurl->box; + + /* find mailbox namespace */ + ns = mail_namespace_find(mpurl->user->namespaces, mpurl->mailbox); + if (ns == NULL) { + *error_r = "Nonexistent mailbox namespace"; + return NULL; + } + + /* open mailbox */ + box = mailbox_alloc(ns->list, mpurl->mailbox, flags); + if (mailbox_open(box) < 0) { + *error_r = mail_storage_get_last_error(mailbox_get_storage(box), + &error_code); + mailbox_free(&box); + return NULL; + } + + /* verify UIDVALIDITY */ + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &box_status); + if (mpurl->uidvalidity > 0 && + box_status.uidvalidity != mpurl->uidvalidity) { + *error_r = "Invalid UIDVALIDITY"; + mailbox_free(&box); + return NULL; + } + mpurl->box = box; + return box; +} + +struct mail * +imap_msgpart_url_open_mail(struct imap_msgpart_url *mpurl, const char **error_r) +{ + struct mailbox_transaction_context *t; + struct mail *mail; + + if (mpurl->mail != NULL) + return mpurl->mail; + + /* open mailbox if it is not yet open */ + if (mpurl->box == NULL) { + if (imap_msgpart_url_open_mailbox(mpurl, error_r) == NULL) + return NULL; + } + + /* start transaction */ + t = mailbox_transaction_begin(mpurl->box, 0); + mail = mail_alloc(t, 0, NULL); + + /* find the message */ + if (!mail_set_uid(mail, mpurl->uid)) { + *error_r = "Message not found"; + mail_free(&mail); + mailbox_transaction_rollback(&t); + return NULL; + } + + mpurl->trans = t; + mpurl->mail = mail; + return mail; +} + +bool imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl, + struct istream **stream_r, uoff_t *size_r, + const char **error_r) +{ + struct istream *input; + uoff_t part_size; + + if (mpurl->input != NULL) { + i_stream_seek(mpurl->input, 0); + *stream_r = mpurl->input; + *size_r = mpurl->part_size; + return TRUE; + } + + /* open mailbox if it is not yet open */ + if (mpurl->mail == NULL) { + if (imap_msgpart_url_open_mail(mpurl, error_r) == NULL) + return FALSE; + } + + /* open the referenced part as a stream */ + if (!imap_msgpart_open(mpurl->mail, mpurl->section, + mpurl->partial_offset, mpurl->partial_size, + &input, &part_size, error_r)) + return FALSE; + + mpurl->input = input; + mpurl->part_size = part_size; + + *stream_r = input; + *size_r = part_size; + return TRUE; +} + +bool imap_msgpart_url_verify(struct imap_msgpart_url *mpurl, + const char **error_r) +{ + if (mpurl->input != NULL) + return TRUE; + + /* open mailbox if it is not yet open */ + if (mpurl->mail == NULL) { + if (imap_msgpart_url_open_mail(mpurl, error_r) == NULL) + return FALSE; + } + + /* open the referenced part as a stream */ + if (!imap_msgpart_verify(mpurl->mail, mpurl->section, error_r)) + return FALSE; + return TRUE; +} + +void imap_msgpart_url_free(struct imap_msgpart_url **_mpurl) +{ + struct imap_msgpart_url *mpurl = *_mpurl; + + *_mpurl = NULL; + + if (mpurl->input != NULL) + i_stream_unref(&mpurl->input); + if (mpurl->mail != NULL) + mail_free(&mpurl->mail); + if (mpurl->trans != NULL) + mailbox_transaction_rollback(&mpurl->trans); + if (mpurl->box != NULL) + mailbox_free(&mpurl->box); + if (mpurl->section != NULL) + i_free(mpurl->section); + i_free(mpurl->mailbox); + i_free(mpurl); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-imap-storage/imap-msgpart-url.h Sat Jun 02 17:56:27 2012 +0300 @@ -0,0 +1,29 @@ +#ifndef IMAP_MSGPART_URL_H +#define IMAP_MSGPART_URL_H + +struct imap_url; +struct imap_msgpart_url; + +struct imap_msgpart_url * +imap_msgpart_url_create(struct mail_user *user, const struct imap_url *url); +struct imap_msgpart_url * +imap_msgpart_url_parse(struct mail_user *user, struct mailbox *selected_box, + const char *urlstr, const char **error_r); + +struct mailbox * +imap_msgpart_url_open_mailbox(struct imap_msgpart_url *mpurl, + const char **error_r); +struct mailbox *imap_msgpart_url_get_mailbox(struct imap_msgpart_url *mpurl); +struct mail * +imap_msgpart_url_open_mail(struct imap_msgpart_url *mpurl, const char **error_r); + +/* Returns NULL stream when part has zero length, e.g. when partial offset is + larger than the size of the referenced part */ +bool imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl, + struct istream **stream_r, uoff_t *size_r, + const char **error_r); +bool imap_msgpart_url_verify(struct imap_msgpart_url *mpurl, + const char **error_r); +void imap_msgpart_url_free(struct imap_msgpart_url **mpurl); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-imap-storage/imap-msgpart.c Sat Jun 02 17:56:27 2012 +0300 @@ -0,0 +1,371 @@ +#include "lib.h" +#include "array.h" +#include "istream.h" +#include "istream-crlf.h" +#include "istream-header-filter.h" +#include "message-parser.h" +#include "mail-storage.h" +#include "mail-namespace.h" +#include "imap-parser.h" +#include "imap-msgpart.h" + +int imap_msgpart_find(struct mail *mail, const char *section, + const struct message_part **part_r, + const char **subsection_r) +{ + struct message_part *part; + const char *path; + unsigned int num; + + if (mail_get_parts(mail, &part) < 0) + return -1; + + path = section; + while (*path >= '0' && *path <= '9' && part != NULL) { + /* get part number, we have already verified its validity */ + num = 0; + while (*path != '\0' && *path != '.') { + i_assert(*path >= '0' && *path <= '9'); + + num = num*10 + (*path - '0'); + path++; + } + + if (*path == '.') + path++; + + if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0) { + /* find the part */ + part = part->children; + for (; num > 1 && part != NULL; num--) + part = part->next; + } else { + /* only 1 allowed with non-multipart messages */ + if (num != 1) + part = NULL; + } + + if (part != NULL && + (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0 && + (*path >= '0' && *path <= '9')) { + /* if we continue inside the message/rfc822, skip this + body part */ + part = part->children; + } + } + + *part_r = part; + *subsection_r = path; + return 0; +} + +static bool +imap_msgpart_get_header_fields(const char *header_list, + const char *const **fields_r, size_t *count_r) +{ + struct istream *input; + struct imap_parser *parser; + const struct imap_arg *args, *hdr_list; + unsigned int list_count; + ARRAY_TYPE(const_string) fields = ARRAY_INIT; + unsigned int i; + bool result = TRUE; + + input = i_stream_create_from_data(header_list, strlen(header_list)); + parser = imap_parser_create(input, NULL, (size_t)-1); + + if (imap_parser_finish_line(parser, 0, 0, &args) > 0 && + imap_arg_get_list_full(args, &hdr_list, &list_count) && + list_count > 0) { + const char *value; + + if (fields_r != NULL) + t_array_init(&fields, list_count); + + for (i = 0; i < list_count; i++) { + if (!imap_arg_get_astring(&hdr_list[i], &value)) { + result = FALSE; + break; + } + + if (fields_r != NULL) { + value = t_str_ucase(value); + array_append(&fields, &value, 1); + } + } + + if (fields_r != NULL) { + *fields_r = array_get(&fields, &list_count); + *count_r = list_count; + } + } else { + result = FALSE; + } + + imap_parser_unref(&parser); + i_stream_unref(&input); + + return result; +} + +static bool +imap_msgpart_verify_header_fields(const char *header_list, const char **error_r) +{ + /* HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */ + if (!imap_msgpart_get_header_fields(header_list, NULL, NULL)) { + *error_r = "Invalid header fields"; + return FALSE; + } + return TRUE; +} + +static struct istream * +imap_msgpart_get_partial_header(struct istream *mail_input, bool exclude, + const char *header_list, + struct message_size *hdr_size_r, + const char **error_r) +{ + const char *const *hdr_fields; + size_t hdr_count; + struct istream *input; + uoff_t old_offset; + + /* HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */ + if (!imap_msgpart_get_header_fields(header_list, &hdr_fields, &hdr_count)) { + *error_r = "Invalid header fields"; + return NULL; + } + + if (!exclude) { + input = i_stream_create_header_filter(mail_input, + HEADER_FILTER_INCLUDE, + hdr_fields, hdr_count, + null_header_filter_callback, NULL); + } else { + input = i_stream_create_header_filter(mail_input, + HEADER_FILTER_EXCLUDE, + hdr_fields, hdr_count, + null_header_filter_callback, NULL); + } + + old_offset = input->v_offset; + if (message_get_header_size(input, hdr_size_r, NULL) < 0) { + *error_r = "Failed to determine header size"; + return NULL; + } + i_stream_seek(input, old_offset); + + return input; +} + +static bool +imap_msgpart_get_partial(struct istream *input, struct message_size part_size, + uoff_t partial_offset, uoff_t partial_size, + struct istream **stream_r, uoff_t *size_r) +{ + struct istream *result; + uoff_t size = part_size.virtual_size; + + if (partial_offset >= size) { + i_stream_unref(&input); + *size_r = 0; + *stream_r = NULL; + return TRUE; + } + + if (size != part_size.physical_size) { + result = i_stream_create_crlf(input); + i_stream_unref(&input); + input = result; + } + + if (partial_offset > 0) + i_stream_seek(input, input->v_offset + partial_offset); + + size = partial_size > 0 && (size - partial_offset) > partial_size ? + partial_size : (size - partial_offset); + result = i_stream_create_limit(input, size); + i_stream_unref(&input); + + *size_r = size; + *stream_r = result; + return TRUE; +} + +bool imap_msgpart_open(struct mail *mail, const char *section, + uoff_t partial_offset, uoff_t partial_size, + struct istream **stream_r, + uoff_t *size_r, const char **error_r) +{ + struct message_size hdr_size, body_size, part_size; + struct istream *input = NULL; + + /* only get stream when we intend to read actual data */ + if (stream_r != NULL) { + if (mail_get_stream(mail, &hdr_size, &body_size, &input) < 0) { + *error_r = "Failed to read message"; + return FALSE; + } + } + + if (section == NULL || *section == '\0') { + /* full message */ + if (stream_r == NULL) + return TRUE; + + part_size.physical_size = + hdr_size.physical_size + body_size.physical_size; + part_size.virtual_size = + hdr_size.virtual_size + body_size.virtual_size; + + i_stream_seek(input, 0); + i_stream_ref(input); + return imap_msgpart_get_partial(input, part_size, + partial_offset, partial_size, + stream_r, size_r); + } + + section = t_str_ucase(section); + + if (strcmp(section, "TEXT") == 0) { + /* message body */ + if (stream_r == NULL) + return TRUE; + + i_stream_seek(input, hdr_size.physical_size); + i_stream_ref(input); + return imap_msgpart_get_partial(input, body_size, + partial_offset, partial_size, + stream_r, size_r); + } + + if (strncmp(section, "HEADER", 6) == 0) { + /* header */ + if (stream_r == NULL) { + if (section[6] == '\0') { + return TRUE; + } else if (strncmp(section, "HEADER.FIELDS ", 14) == 0) { + return imap_msgpart_verify_header_fields(section+14, error_r); + } else if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0) { + return imap_msgpart_verify_header_fields(section+18, error_r); + } + } else { + i_stream_seek(input, 0); + + if (section[6] == '\0') { + i_stream_ref(input); + } else if (strncmp(section, "HEADER.FIELDS ", 14) == 0) { + input = imap_msgpart_get_partial_header(input, + FALSE, section+14, &hdr_size, error_r); + } else if (strncmp(section, "HEADER.FIELDS.NOT ", 18) == 0) { + input = imap_msgpart_get_partial_header(input, + TRUE, section+18, &hdr_size, error_r); + } else { + input = NULL; + } + + if (input != NULL) { + return imap_msgpart_get_partial(input, + hdr_size, partial_offset, partial_size, + stream_r, size_r); + } + } + + } else if (*section >= '0' && *section <= '9') { + const struct message_part *part; + const char *subsection; + + if (imap_msgpart_find(mail, section, &part, &subsection) < 0) { + *error_r = "Cannot read message part"; + return FALSE; + } + + if (part == NULL) { + *error_r = "Unknown message part"; + return FALSE; + } + + if (*subsection == '\0') { + if (stream_r == NULL) + return TRUE; + + /* fetch the whole section */ + i_stream_seek(input, part->physical_pos + + part->header_size.physical_size); + i_stream_ref(input); + return imap_msgpart_get_partial(input, part->body_size, partial_offset, + partial_size, stream_r, size_r); + } + + if (strcmp(subsection, "MIME") == 0) { + if (stream_r == NULL) + return TRUE; + + /* fetch section's MIME header */ + i_stream_seek(input, part->physical_pos); + i_stream_ref(input); + return imap_msgpart_get_partial(input, part->header_size, + partial_offset, partial_size, stream_r, size_r); + } + + /* TEXT and HEADER are only for message/rfc822 parts */ + if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) == 0) { + *error_r = "Invalid section"; + return FALSE; + } + + i_assert(part->children != NULL && part->children->next == NULL); + part = part->children; + + if (strcmp(subsection, "TEXT") == 0) { + if (stream_r == NULL) + return TRUE; + + /* sub-message body */ + i_stream_seek(input, part->physical_pos + + part->header_size.physical_size); + i_stream_ref(input); + return imap_msgpart_get_partial(input, part->body_size, + partial_offset, partial_size, stream_r, size_r); + } + + if (strncmp(subsection, "HEADER", 6) == 0) { + if (stream_r == NULL) { + if (section[6] == '\0') { + return TRUE; + } else if (strncmp(subsection, "HEADER.FIELDS ", 14) == 0) { + return imap_msgpart_verify_header_fields(subsection+14, error_r); + } else if (strncmp(subsection, "HEADER.FIELDS.NOT ", 18) == 0) { + return imap_msgpart_verify_header_fields(subsection+18, error_r); + } + } else { + i_stream_seek(input, part->physical_pos); + + if (subsection[6] == '\0') { + /* full */ + hdr_size = part->header_size; + i_stream_ref(input); + } else if (strncmp(subsection, "HEADER.FIELDS ", 14) == 0) { + input = imap_msgpart_get_partial_header( + input, FALSE, section+14, + &hdr_size, error_r); + } else if (strncmp(subsection, "HEADER.FIELDS.NOT ", 18) == 0) { + input = imap_msgpart_get_partial_header( + input, TRUE, section+18, + &hdr_size, error_r); + } else { + input = NULL; + } + + if (input != NULL) { + return imap_msgpart_get_partial(input, + hdr_size, partial_offset, + partial_size, stream_r, size_r); + } + } + } + } + + *error_r = "Invalid section"; + return FALSE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-imap-storage/imap-msgpart.h Sat Jun 02 17:56:27 2012 +0300 @@ -0,0 +1,24 @@ +#ifndef IMAP_MSGPART_H +#define IMAP_MSGPART_H + +/* Find message_part for section (eg. 1.3.4) */ +int imap_msgpart_find(struct mail *mail, const char *section, + const struct message_part **part_r, + const char **subsection_r); + +/* Open message part refenced by IMAP section as istream. Returns TRUE on + success and FALSE otherwise. Returned stream_r stream may be NULL when there + is no data to return. */ +bool imap_msgpart_open(struct mail *mail, const char *section, + uoff_t partial_offset, uoff_t partial_size, + struct istream **stream_r, + uoff_t *size_r, const char **error_r); + +static inline bool +imap_msgpart_verify(struct mail *mail, const char *section, + const char **error_r) +{ + return imap_msgpart_open(mail, section, 0, 0, NULL, NULL, error_r); +} + +#endif
--- a/src/lib-storage/Makefile.am Sat Jun 02 17:53:31 2012 +0300 +++ b/src/lib-storage/Makefile.am Sat Jun 02 17:56:27 2012 +0300 @@ -82,6 +82,7 @@ index/libstorage_index.la \ register/libstorage_register.la \ ../lib-index/libindex.la \ + ../lib-imap-storage/libimap-storage.la \ ../lib-dovecot/libdovecot.la pkglib_LTLIBRARIES = libdovecot-storage.la