]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Add imapc_features=fetch-bodystructure
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 24 Apr 2017 10:29:13 +0000 (13:29 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 24 Apr 2017 11:15:45 +0000 (14:15 +0300)
This allows using the remote IMAP server's BODY and BODYSTRUCTURE replies.

src/lib-storage/index/imapc/imapc-mail-fetch.c
src/lib-storage/index/imapc/imapc-mail.c
src/lib-storage/index/imapc/imapc-settings.c
src/lib-storage/index/imapc/imapc-settings.h
src/lib-storage/index/imapc/imapc-storage.c

index 8534981aefc6ebea6e3cb37df8df92781bb4c9c8..c63f68265420d6dbfddda63dbee9890787ca5060 100644 (file)
@@ -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"
@@ -258,6 +259,10 @@ imapc_mail_send_fetch(struct mail *_mail, enum mail_fetch_field fields,
                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))
@@ -340,6 +345,14 @@ imapc_mail_get_wanted_fetch_fields(struct imapc_mail *mail)
            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;
@@ -395,6 +408,16 @@ imapc_mail_have_fields(struct imapc_mail *imail, enum mail_fetch_field fields)
                        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)
@@ -721,6 +744,35 @@ imapc_fetch_header_stream(struct imapc_mail *mail,
        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)
@@ -756,6 +808,18 @@ void imapc_mail_fetch_update(struct imapc_mail *mail,
                            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 &&
index c22b52e5d128ff9b377ebf0735f9073b507150f2..2750754f7639db8c927e87735b3d3e62e1a9897b 100644 (file)
@@ -351,6 +351,7 @@ void imapc_mail_update_access_parts(struct index_mail *mail)
        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 @@ void imapc_mail_update_access_parts(struct index_mail *mail)
        }
        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)) {
@@ -571,6 +576,34 @@ imapc_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
                *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;
        }
index 170238d5d8def0abe7b3950df3c6599aa7c45614..6c3f84a0fbd709ce0485c3f7a49c93ff9ea2a11a 100644 (file)
@@ -101,6 +101,7 @@ static const struct imapc_feature_list imapc_feature_list[] = {
        { "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 }
 };
 
index 32be70492168fe7997a048fd03900cbeea834f28..8210bbe072dd8eb4d86cc7dcd0cbaa031da6ccb4 100644 (file)
@@ -17,6 +17,7 @@ enum imapc_features {
        IMAPC_FEATURE_FETCH_FIX_BROKEN_MAILS    = 0x200,
        IMAPC_FEATURE_MODSEQ                    = 0x400,
        IMAPC_FEATURE_DELAY_LOGIN               = 0x800,
+       IMAPC_FEATURE_FETCH_BODYSTRUCTURE       = 0x1000,
 };
 /* </settings checks> */
 
index ce0bb033eeafd9ca4639bb8e970630f18341db60..60f756a7ca6dace58fe28302fec8b39586312e52 100644 (file)
@@ -411,6 +411,10 @@ imapc_storage_create(struct mail_storage *_storage,
        }
        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);