]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: index: imapc: Implement support for SAVEDATE attribute.
authorStephan Bosch <stephan.bosch@open-xchange.com>
Thu, 19 Mar 2020 16:14:34 +0000 (17:14 +0100)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Sun, 5 Apr 2020 21:31:34 +0000 (21:31 +0000)
src/lib-storage/index/imapc/imapc-mail-fetch.c
src/lib-storage/index/imapc/imapc-mail.c
src/lib-storage/index/imapc/imapc-search.c

index 9e8bd41fcad65a59b15e33fc3a42a5282b854b59..1f93d4b5d1dbdb9b0482b8cdd7aad96d6655a8bf 100644 (file)
@@ -253,6 +253,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_SAVE_DATE) != 0) {
+               i_assert(HAS_ALL_BITS(mbox->capabilities,
+                                     IMAPC_CAPABILITY_SAVEDATE));
+               str_append(str, "SAVEDATE ");
+       }
        if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE)) != 0)
                str_append(str, "RFC822.SIZE ");
        if ((fields & MAIL_FETCH_GUID) != 0) {
@@ -338,8 +343,12 @@ imapc_mail_get_wanted_fetch_fields(struct imapc_mail *mail)
            data->received_date == (time_t)-1)
                fields |= MAIL_FETCH_RECEIVED_DATE;
        if ((data->wanted_fields & MAIL_FETCH_SAVE_DATE) != 0 &&
-           data->save_date == (time_t)-1 && data->received_date == (time_t)-1)
-               fields |= MAIL_FETCH_RECEIVED_DATE;
+           data->save_date == (time_t)-1) {
+               if (HAS_ALL_BITS(mbox->capabilities, IMAPC_CAPABILITY_SAVEDATE))
+                       fields |= MAIL_FETCH_SAVE_DATE;
+               else
+                       fields |= MAIL_FETCH_RECEIVED_DATE;
+       }
        if ((data->wanted_fields & (MAIL_FETCH_PHYSICAL_SIZE |
                                    MAIL_FETCH_VIRTUAL_SIZE)) != 0 &&
            data->physical_size == (uoff_t)-1 &&
@@ -410,11 +419,20 @@ bool imapc_mail_prefetch(struct mail *_mail)
 static bool
 imapc_mail_have_fields(struct imapc_mail *imail, enum mail_fetch_field fields)
 {
+       struct imapc_mailbox *mbox = IMAPC_MAILBOX(imail->imail.mail.mail.box);
+
        if ((fields & MAIL_FETCH_RECEIVED_DATE) != 0) {
                if (imail->imail.data.received_date == (time_t)-1)
                        return FALSE;
                fields &= ~MAIL_FETCH_RECEIVED_DATE;
        }
+       if ((fields & MAIL_FETCH_SAVE_DATE) != 0) {
+               i_assert(HAS_ALL_BITS(mbox->capabilities,
+                                     IMAPC_CAPABILITY_SAVEDATE));
+               if (imail->imail.data.save_date == (time_t)-1)
+                       return FALSE;
+               fields &= ~MAIL_FETCH_SAVE_DATE;
+       }
        if ((fields & (MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE)) != 0) {
                if (imail->imail.data.physical_size == (uoff_t)-1)
                        return FALSE;
@@ -826,8 +844,20 @@ void imapc_mail_fetch_update(struct imapc_mail *mail,
                        match = TRUE;
                } else if (strcasecmp(key, "INTERNALDATE") == 0) {
                        if (imap_arg_get_astring(&args[i+1], &value) &&
-                           imap_parse_datetime(value, &t, &tz))
+                           imap_parse_datetime(value, &t, &tz)) {
                                mail->imail.data.received_date = t;
+                               if (HAS_NO_BITS(mbox->capabilities,
+                                                IMAPC_CAPABILITY_SAVEDATE))
+                                       mail->imail.data.save_date = t;
+                       }
+                       match = TRUE;
+               } else if (strcasecmp(key, "SAVEDATE") == 0) {
+                       if (imap_arg_get_astring(&args[i+1], &value)) {
+                               if (strcasecmp(value, "NIL") == 0)
+                                       mail->imail.data.save_date = 0;
+                               else if (imap_parse_datetime(value, &t, &tz))
+                                       mail->imail.data.save_date = t;
+                       }
                        match = TRUE;
                } else if (strcasecmp(key, "BODY") == 0) {
                        if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_BODYSTRUCTURE)) {
index 414327f264077c1e5b8a2515058643990d8426cc..3ea21eb7b348dc582cccfe1fdef4887612ab6c68 100644 (file)
@@ -140,17 +140,29 @@ static int imapc_mail_get_received_date(struct mail *_mail, time_t *date_r)
 
 static int imapc_mail_get_save_date(struct mail *_mail, time_t *date_r)
 {
+       struct imapc_mailbox *mbox = IMAPC_MAILBOX(_mail->box);
        struct index_mail *mail = INDEX_MAIL(_mail);
        struct index_mail_data *data = &mail->data;
 
-       if (data->save_date == (time_t)-1) {
-               /* FIXME: we could use a value stored in cache */
+       if (data->save_date != 0 && index_mail_get_save_date(_mail, date_r) > 0)
+               return 1;
+
+       if (HAS_NO_BITS(mbox->capabilities, IMAPC_CAPABILITY_SAVEDATE)) {
+               data->save_date = 0;
+       } else if (data->save_date == (time_t)-1) {
+               if (imapc_mail_fetch(_mail, MAIL_FETCH_SAVE_DATE, NULL) < 0)
+                       return -1;
+               if (data->save_date == (time_t)-1 &&
+                   imapc_mail_failed(_mail, "SAVEDATE") < 0)
+                       return -1;
+       }
+       if (data->save_date == (time_t)-1 || data->save_date == 0) {
                if (imapc_mail_get_received_date(_mail, date_r) < 0)
                        return -1;
                return 0;
        }
        *date_r = data->save_date;
-       return 0;
+       return 1;
 }
 
 static int imapc_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
@@ -369,7 +381,9 @@ void imapc_mail_update_access_parts(struct index_mail *mail)
        if ((data->wanted_fields & MAIL_FETCH_RECEIVED_DATE) != 0)
                (void)index_mail_get_received_date(_mail, &date);
        if ((data->wanted_fields & MAIL_FETCH_SAVE_DATE) != 0) {
-               if (index_mail_get_save_date(_mail, &date) < 0) {
+               if (index_mail_get_save_date(_mail, &date) < 0 &&
+                   HAS_NO_BITS(mbox->capabilities,
+                               IMAPC_CAPABILITY_SAVEDATE)) {
                        (void)index_mail_get_received_date(_mail, &date);
                        data->save_date = data->received_date;
                }
index b776ae4212955a3ebad998c06d04daec3d8ae918..e395919f3429d70accc65eacca55ac3aa6f167c9 100644 (file)
@@ -96,7 +96,9 @@ imapc_build_search_query_arg(struct imapc_mailbox *mbox,
                return TRUE;
        case SEARCH_BEFORE:
        case SEARCH_SINCE:
-               if ((mbox->capabilities & IMAPC_CAPABILITY_WITHIN) == 0) {
+       case SEARCH_ON:
+               if (arg->type != SEARCH_ON &&
+                   (mbox->capabilities & IMAPC_CAPABILITY_WITHIN) == 0) {
                        /* a bit kludgy way to check this.. */
                        size_t pos = str_len(str);
                        if (!mail_search_arg_to_imap(str, arg, &error))
@@ -106,12 +108,17 @@ imapc_build_search_query_arg(struct imapc_mailbox *mbox,
                                return FALSE;
                        return TRUE;
                }
+               if (arg->value.date_type == MAIL_SEARCH_DATE_TYPE_SAVED &&
+                   (mbox->capabilities & IMAPC_CAPABILITY_SAVEDATE) == 0) {
+                       /* Fall back to internal date if save date is not
+                          supported. */
+                       arg2.value.date_type = MAIL_SEARCH_DATE_TYPE_RECEIVED;
+               }
                /* fall through */
        case SEARCH_ALL:
        case SEARCH_UIDSET:
        case SEARCH_FLAGS:
        case SEARCH_KEYWORDS:
-       case SEARCH_ON:
        case SEARCH_SMALLER:
        case SEARCH_LARGER:
        case SEARCH_HEADER:
@@ -126,6 +133,9 @@ imapc_build_search_query_arg(struct imapc_mailbox *mbox,
                        return FALSE;
                return mail_search_arg_to_imap(str, arg, &error);
        case SEARCH_SAVEDATESUPPORTED:
+               if ((mbox->capabilities & IMAPC_CAPABILITY_SAVEDATE) == 0)
+                       return FALSE;
+               return mail_search_arg_to_imap(str, arg, &error);
        case SEARCH_INTHREAD:
        case SEARCH_GUID:
        case SEARCH_MAILBOX: