]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Added support for fetching GUID from remote server, if supported.
authorTimo Sirainen <tss@iki.fi>
Mon, 12 Dec 2011 06:45:32 +0000 (08:45 +0200)
committerTimo Sirainen <tss@iki.fi>
Mon, 12 Dec 2011 06:45:32 +0000 (08:45 +0200)
Currently this is only done for GMail.

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

index 6852c28bc179e551efa0c32fc6f941bbe821b89d..1d2ff1c1cd338b0780851655bad01538bc8087b4 100644 (file)
@@ -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) {
index d4be94dc117361e9fe445a56ffe72a12ad43a33a..771faaa6d730f991042422f3c3152166409359e7 100644 (file)
@@ -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,
index c5f457f48b44d19a6045d67e2672111722c318bb..ce78348731256fb1c7dff9eaf3215f53b4cbe3f5 100644 (file)
@@ -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;
index 5f3dea7feca2876974e04d6ddb5ba1d089202011..fb0bb7db4c05e1a13e3a28e425261acd3857645a 100644 (file)
@@ -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;