# HG changeset patch # User Timo Sirainen # Date 1493029753 -10800 # Node ID 33dbc4cdd0c56f28cef6c23536fd8e7ab10eaba6 # Parent 9282e5b090f17637145d305572ebcb879f186534 imapc: Add imapc_features=fetch-bodystructure This allows using the remote IMAP server's BODY and BODYSTRUCTURE replies. diff -r 9282e5b090f1 -r 33dbc4cdd0c5 src/lib-storage/index/imapc/imapc-mail-fetch.c --- a/src/lib-storage/index/imapc/imapc-mail-fetch.c Mon Apr 24 13:27:43 2017 +0300 +++ b/src/lib-storage/index/imapc/imapc-mail-fetch.c Mon Apr 24 13:29:13 2017 +0300 @@ -10,6 +10,7 @@ #include "imap-arg.h" #include "imap-date.h" #include "imap-quote.h" +#include "imap-bodystructure.h" #include "imap-resp-code.h" #include "imapc-client.h" #include "imapc-mail.h" @@ -259,6 +260,10 @@ str_append(str, mbox->guid_fetch_field_name); str_append_c(str, ' '); } + if ((fields & MAIL_FETCH_IMAP_BODY) != 0) + str_append(str, "BODY "); + if ((fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) + str_append(str, "BODYSTRUCTURE "); if ((fields & MAIL_FETCH_STREAM_BODY) != 0) { if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_ZIMBRA_WORKAROUNDS)) @@ -343,6 +348,14 @@ data->physical_size == (uoff_t)-1 && IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE)) fields |= MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE; + if ((data->wanted_fields & MAIL_FETCH_IMAP_BODY) != 0 && + data->body == NULL && + IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) + fields |= MAIL_FETCH_IMAP_BODY; + if ((data->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0 && + data->bodystructure == NULL && + IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) + fields |= MAIL_FETCH_IMAP_BODYSTRUCTURE; if ((data->wanted_fields & MAIL_FETCH_GUID) != 0 && data->guid == NULL && mbox->guid_fetch_field_name != NULL) fields |= MAIL_FETCH_GUID; @@ -398,6 +411,16 @@ return FALSE; fields &= ~MAIL_FETCH_GUID; } + if ((fields & MAIL_FETCH_IMAP_BODY) != 0) { + if (imail->imail.data.body == NULL) + return FALSE; + fields &= ~MAIL_FETCH_IMAP_BODY; + } + if ((fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) { + if (imail->imail.data.bodystructure == NULL) + return FALSE; + fields &= ~MAIL_FETCH_IMAP_BODYSTRUCTURE; + } if ((fields & (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0) { if (imail->imail.data.stream == NULL) @@ -724,6 +747,35 @@ i_stream_destroy(&input); } +static const char * +imapc_args_to_bodystructure(struct imapc_mail *mail, + const struct imap_arg *list_arg, bool extended) +{ + const struct imap_arg *args; + struct message_part *parts = NULL; + const char *ret, *error; + pool_t pool; + + if (!imap_arg_get_list(list_arg, &args)) { + mail_storage_set_critical(mail->imail.mail.mail.box->storage, + "imapc: Server sent invalid BODYSTRUCTURE parameters"); + return NULL; + } + + pool = pool_alloconly_create("imap bodystructure", 1024); + if (imap_bodystructure_parse_args(args, pool, &parts, &error) < 0) { + mail_storage_set_critical(mail->imail.mail.mail.box->storage, + "imapc: Server sent invalid BODYSTRUCTURE: %s", error); + ret = NULL; + } else { + string_t *str = t_str_new(128); + imap_bodystructure_write(parts, str, extended); + ret = p_strdup(mail->imail.mail.data_pool, str_c(str)); + } + pool_unref(&pool); + return ret; +} + void imapc_mail_fetch_update(struct imapc_mail *mail, const struct imapc_untagged_reply *reply, const struct imap_arg *args) @@ -759,6 +811,18 @@ imap_parse_datetime(value, &t, &tz)) mail->imail.data.received_date = t; match = TRUE; + } else if (strcasecmp(key, "BODY") == 0) { + if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) { + mail->imail.data.body = + imapc_args_to_bodystructure(mail, &args[i+1], FALSE); + } + match = TRUE; + } else if (strcasecmp(key, "BODYSTRUCTURE") == 0) { + if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) { + mail->imail.data.bodystructure = + imapc_args_to_bodystructure(mail, &args[i+1], TRUE); + } + match = TRUE; } else if (strcasecmp(key, "RFC822.SIZE") == 0) { if (imap_arg_get_atom(&args[i+1], &value) && str_to_uoff(value, &size) == 0 && diff -r 9282e5b090f1 -r 33dbc4cdd0c5 src/lib-storage/index/imapc/imapc-mail.c --- a/src/lib-storage/index/imapc/imapc-mail.c Mon Apr 24 13:27:43 2017 +0300 +++ b/src/lib-storage/index/imapc/imapc-mail.c Mon Apr 24 13:29:13 2017 +0300 @@ -351,6 +351,7 @@ struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box; struct index_mail_data *data = &mail->data; struct mailbox_header_lookup_ctx *header_ctx; + const char *str; time_t date; uoff_t size; @@ -370,6 +371,10 @@ } if ((data->wanted_fields & MAIL_FETCH_GUID) != 0) (void)imapc_mail_get_cached_guid(_mail); + if ((data->wanted_fields & MAIL_FETCH_IMAP_BODY) != 0) + (void)index_mail_get_cached_body(mail, &str); + if ((data->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) + (void)index_mail_get_cached_bodystructure(mail, &str); if (data->access_part == 0 && data->wanted_headers != NULL && !IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_HEADERS)) { @@ -569,6 +574,34 @@ *value_r = p_strdup_printf(imail->mail.data_pool, "GmailId%llx", (unsigned long long)num); return 0; + case MAIL_FETCH_IMAP_BODY: + if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) + break; + + if (index_mail_get_cached_body(imail, value_r)) + return 0; + if (imapc_mail_fetch(_mail, field, NULL) < 0) + return -1; + if (imail->data.body == NULL) { + (void)imapc_mail_failed(_mail, "BODY"); + return -1; + } + *value_r = imail->data.body; + return 0; + case MAIL_FETCH_IMAP_BODYSTRUCTURE: + if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) + break; + + if (index_mail_get_cached_bodystructure(imail, value_r)) + return 0; + if (imapc_mail_fetch(_mail, field, NULL) < 0) + return -1; + if (imail->data.bodystructure == NULL) { + (void)imapc_mail_failed(_mail, "BODYSTRUCTURE"); + return -1; + } + *value_r = imail->data.bodystructure; + return 0; default: break; } diff -r 9282e5b090f1 -r 33dbc4cdd0c5 src/lib-storage/index/imapc/imapc-settings.c --- a/src/lib-storage/index/imapc/imapc-settings.c Mon Apr 24 13:27:43 2017 +0300 +++ b/src/lib-storage/index/imapc/imapc-settings.c Mon Apr 24 13:29:13 2017 +0300 @@ -101,6 +101,7 @@ { "fetch-fix-broken-mails", IMAPC_FEATURE_FETCH_FIX_BROKEN_MAILS }, { "modseq", IMAPC_FEATURE_MODSEQ }, { "delay-login", IMAPC_FEATURE_DELAY_LOGIN }, + { "fetch-bodystructure", IMAPC_FEATURE_FETCH_BODYSTRUCTURE }, { NULL, 0 } }; diff -r 9282e5b090f1 -r 33dbc4cdd0c5 src/lib-storage/index/imapc/imapc-settings.h --- a/src/lib-storage/index/imapc/imapc-settings.h Mon Apr 24 13:27:43 2017 +0300 +++ b/src/lib-storage/index/imapc/imapc-settings.h Mon Apr 24 13:29:13 2017 +0300 @@ -17,6 +17,7 @@ IMAPC_FEATURE_FETCH_FIX_BROKEN_MAILS = 0x200, IMAPC_FEATURE_MODSEQ = 0x400, IMAPC_FEATURE_DELAY_LOGIN = 0x800, + IMAPC_FEATURE_FETCH_BODYSTRUCTURE = 0x1000, }; /* */ diff -r 9282e5b090f1 -r 33dbc4cdd0c5 src/lib-storage/index/imapc/imapc-storage.c --- a/src/lib-storage/index/imapc/imapc-storage.c Mon Apr 24 13:27:43 2017 +0300 +++ b/src/lib-storage/index/imapc/imapc-storage.c Mon Apr 24 13:29:13 2017 +0300 @@ -411,6 +411,10 @@ } storage->client->_storage = storage; p_array_init(&storage->remote_namespaces, _storage->pool, 4); + if (IMAPC_HAS_FEATURE(storage, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) { + _storage->nonbody_access_fields |= + MAIL_FETCH_IMAP_BODY | MAIL_FETCH_IMAP_BODYSTRUCTURE; + } imapc_storage_client_register_untagged(storage->client, "STATUS", imapc_untagged_status);