From: Timo Sirainen Date: Mon, 12 Dec 2011 06:45:32 +0000 (+0200) Subject: imapc: Added support for fetching GUID from remote server, if supported. X-Git-Tag: 2.1.rc2~45 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=df452e9628fe8d3356c42dd644b020ea9733c0c1;p=thirdparty%2Fdovecot%2Fcore.git imapc: Added support for fetching GUID from remote server, if supported. Currently this is only done for GMail. --- diff --git a/src/lib-storage/index/imapc/imapc-mail-fetch.c b/src/lib-storage/index/imapc/imapc-mail-fetch.c index 6852c28bc1..1d2ff1c1cd 100644 --- a/src/lib-storage/index/imapc/imapc-mail-fetch.c +++ b/src/lib-storage/index/imapc/imapc-mail-fetch.c @@ -95,6 +95,11 @@ imapc_mail_send_fetch(struct mail *_mail, enum mail_fetch_field fields) str_printfa(str, "UID FETCH %u (", _mail->uid); if ((fields & MAIL_FETCH_RECEIVED_DATE) != 0) str_append(str, "INTERNALDATE "); + if ((fields & MAIL_FETCH_GUID) != 0) { + str_append(str, mbox->guid_fetch_field_name); + str_append_c(str, ' '); + } + if ((fields & MAIL_FETCH_STREAM_BODY) != 0) str_append(str, "BODY.PEEK[] "); else if ((fields & MAIL_FETCH_STREAM_HEADER) != 0) @@ -152,6 +157,9 @@ bool imapc_mail_prefetch(struct mail *_mail) if ((data->wanted_fields & MAIL_FETCH_RECEIVED_DATE) != 0 && data->received_date == (time_t)-1) fields |= MAIL_FETCH_RECEIVED_DATE; + if ((data->wanted_fields & MAIL_FETCH_GUID) != 0 && + data->guid == NULL && mbox->guid_fetch_field_name != NULL) + fields |= MAIL_FETCH_GUID; if (data->stream == NULL && data->access_part != 0) { if ((data->access_part & (READ_BODY | PARSE_BODY)) != 0) @@ -173,6 +181,11 @@ imapc_mail_have_fields(struct imapc_mail *imail, enum mail_fetch_field fields) return FALSE; fields &= ~MAIL_FETCH_RECEIVED_DATE; } + if ((fields & MAIL_FETCH_GUID) != 0) { + if (imail->imail.data.guid == NULL) + return FALSE; + fields &= ~MAIL_FETCH_GUID; + } if ((fields & (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0) { if (imail->imail.data.stream == NULL) @@ -186,10 +199,18 @@ imapc_mail_have_fields(struct imapc_mail *imail, enum mail_fetch_field fields) int imapc_mail_fetch(struct mail *_mail, enum mail_fetch_field fields) { struct imapc_mail *imail = (struct imapc_mail *)_mail; - struct imapc_storage *storage = - (struct imapc_storage *)_mail->box->storage; + struct imapc_mailbox *mbox = + (struct imapc_mailbox *)_mail->box; int ret; + if ((fields & MAIL_FETCH_GUID) != 0 && + mbox->guid_fetch_field_name == NULL) { + mail_storage_set_error(_mail->box->storage, + MAIL_ERROR_NOTPOSSIBLE, + "Message GUID not available in this server"); + return -1; + } + T_BEGIN { ret = imapc_mail_send_fetch(_mail, fields); } T_END; @@ -200,7 +221,7 @@ int imapc_mail_fetch(struct mail *_mail, enum mail_fetch_field fields) or until all FETCH replies have been received (i.e. some FETCHes failed) */ while (!imapc_mail_have_fields(imail, fields) && imail->fetch_count > 0) - imapc_storage_run(storage); + imapc_storage_run(mbox->storage); return 0; } @@ -356,6 +377,13 @@ 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, "X-GM-MSGID") == 0 || + strcasecmp(key, "X-GUID") == 0) { + if (imap_arg_get_astring(&args[i+1], &value)) { + mail->imail.data.guid = + p_strdup(mail->imail.mail.pool, value); + } + match = TRUE; } } if (!match) { diff --git a/src/lib-storage/index/imapc/imapc-mail.c b/src/lib-storage/index/imapc/imapc-mail.c index d4be94dc11..771faaa6d7 100644 --- a/src/lib-storage/index/imapc/imapc-mail.c +++ b/src/lib-storage/index/imapc/imapc-mail.c @@ -267,6 +267,55 @@ static void imapc_mail_close(struct mail *_mail) buffer_free(&mail->body); } +static int imapc_mail_get_guid(struct mail *_mail, const char **value_r) +{ + struct index_mail *imail = (struct index_mail *)_mail; + struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box; + const enum index_cache_field cache_idx = + imail->ibox->cache_fields[MAIL_CACHE_GUID].idx; + string_t *str; + + if (imail->data.guid != NULL) { + *value_r = imail->data.guid; + return 0; + } + + str = str_new(imail->data_pool, 64); + if (mail_cache_lookup_field(_mail->transaction->cache_view, + str, imail->mail.mail.seq, cache_idx) > 0) { + *value_r = str_c(str); + return 0; + } + + /* GUID not in cache, fetch it */ + if (imapc_mail_fetch(_mail, MAIL_FETCH_GUID) < 0) + return -1; + if (imail->data.guid == NULL) { + imapc_mail_failed(_mail, mbox->guid_fetch_field_name); + return -1; + } + + index_mail_cache_add_idx(imail, cache_idx, + imail->data.guid, strlen(imail->data.guid)+1); + *value_r = imail->data.guid; + return 0; +} + +static int +imapc_mail_get_special(struct mail *_mail, enum mail_fetch_field field, + const char **value_r) +{ + switch (field) { + case MAIL_FETCH_GUID: + *value_r = ""; + return imapc_mail_get_guid(_mail, value_r); + default: + break; + } + + return index_mail_get_special(_mail, field, value_r); +} + struct mail_vfuncs imapc_mail_vfuncs = { imapc_mail_close, index_mail_free, @@ -291,7 +340,7 @@ struct mail_vfuncs imapc_mail_vfuncs = { index_mail_get_headers, index_mail_get_header_stream, imapc_mail_get_stream, - index_mail_get_special, + imapc_mail_get_special, index_mail_get_real_mail, index_mail_update_flags, index_mail_update_keywords, diff --git a/src/lib-storage/index/imapc/imapc-storage.c b/src/lib-storage/index/imapc/imapc-storage.c index c5f457f48b..ce78348731 100644 --- a/src/lib-storage/index/imapc/imapc-storage.c +++ b/src/lib-storage/index/imapc/imapc-storage.c @@ -410,6 +410,20 @@ imapc_mailbox_open_callback(const struct imapc_command_reply *reply, imapc_client_stop(ctx->mbox->storage->client); } +static void imapc_mailbox_get_extensions(struct imapc_mailbox *mbox) +{ + enum imapc_capability capa = + imapc_client_get_capabilities(mbox->storage->client); + + if (mbox->guid_fetch_field_name == NULL) { + /* see if we can get message GUIDs somehow */ + if ((capa & IMAPC_CAPABILITY_X_GM_EXT_1) != 0) { + /* GMail */ + mbox->guid_fetch_field_name = "X-GM-MSGID"; + } + } +} + int imapc_mailbox_select(struct imapc_mailbox *mbox) { struct imapc_command *cmd; @@ -422,6 +436,8 @@ int imapc_mailbox_select(struct imapc_mailbox *mbox) imapc_client_mailbox_set_reopen_cb(mbox->client_box, imapc_mailbox_reopen, mbox); + imapc_mailbox_get_extensions(mbox); + mbox->selecting = TRUE; ctx.mbox = mbox; ctx.ret = -2; diff --git a/src/lib-storage/index/imapc/imapc-storage.h b/src/lib-storage/index/imapc/imapc-storage.h index 5f3dea7fec..fb0bb7db4c 100644 --- a/src/lib-storage/index/imapc/imapc-storage.h +++ b/src/lib-storage/index/imapc/imapc-storage.h @@ -83,6 +83,8 @@ struct imapc_mailbox { uint32_t prev_skipped_rseq, prev_skipped_uid; struct imapc_sync_context *sync_ctx; + const char *guid_fetch_field_name; + unsigned int selecting:1; unsigned int syncing:1; unsigned int initial_sync_done:1;