Skip to content

Commit

Permalink
imapc: Add imapc_features=fetch-bodystructure
Browse files Browse the repository at this point in the history
This allows using the remote IMAP server's BODY and BODYSTRUCTURE replies.
  • Loading branch information
sirainen committed Apr 24, 2017
1 parent 36a0235 commit 4cce569
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/lib-storage/index/imapc/imapc-mail-fetch.c
Expand Up @@ -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"
Expand Down Expand Up @@ -259,6 +260,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))
Expand Down Expand Up @@ -343,6 +348,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;
Expand Down Expand Up @@ -398,6 +411,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)
Expand Down Expand Up @@ -724,6 +747,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)
Expand Down Expand Up @@ -759,6 +811,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 &&
Expand Down
33 changes: 33 additions & 0 deletions src/lib-storage/index/imapc/imapc-mail.c
Expand Up @@ -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;

Expand All @@ -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)) {
Expand Down Expand Up @@ -569,6 +574,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;
}
Expand Down
1 change: 1 addition & 0 deletions src/lib-storage/index/imapc/imapc-settings.c
Expand Up @@ -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 }
};

Expand Down
1 change: 1 addition & 0 deletions src/lib-storage/index/imapc/imapc-settings.h
Expand Up @@ -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> */

Expand Down
4 changes: 4 additions & 0 deletions src/lib-storage/index/imapc/imapc-storage.c
Expand Up @@ -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);
Expand Down

0 comments on commit 4cce569

Please sign in to comment.