# HG changeset patch # User Timo Sirainen # Date 1176830379 -10800 # Node ID 0bc6ec4cddab15052aad0e54cc47bcc232d9cdbd # Parent 9805becea644688ce876d78f8d2eeee9f7648183 Implemented UIDPLUS extension. diff -r 9805becea644 -r 0bc6ec4cddab configure.in --- a/configure.in Tue Apr 17 20:17:52 2007 +0300 +++ b/configure.in Tue Apr 17 20:19:39 2007 +0300 @@ -1890,7 +1890,7 @@ dnl ** capabilities dnl ** -capability="IMAP4rev1 SASL-IR SORT THREAD=REFERENCES THREAD=X-REFERENCES2 MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN NAMESPACE LOGIN-REFERRALS" +capability="IMAP4rev1 SASL-IR SORT THREAD=REFERENCES THREAD=X-REFERENCES2 MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN NAMESPACE LOGIN-REFERRALS UIDPLUS" AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", IMAP capabilities) CFLAGS="$CFLAGS $EXTRA_CFLAGS" diff -r 9805becea644 -r 0bc6ec4cddab src/imap/cmd-append.c --- a/src/imap/cmd-append.c Tue Apr 17 20:17:52 2007 +0300 +++ b/src/imap/cmd-append.c Tue Apr 17 20:19:39 2007 +0300 @@ -25,6 +25,7 @@ struct imap_parser *save_parser; struct mail_save_context *save_ctx; struct mailbox_keywords old_keywords; + unsigned int count; unsigned int message_input:1; unsigned int failed:1; @@ -231,6 +232,9 @@ if (args->type == IMAP_ARG_EOL) { /* last message */ enum mailbox_sync_flags sync_flags; + struct mailbox_status status; + uint32_t uid1, uid2; + const char *msg; /* eat away the trailing CRLF */ client->input_skip_line = TRUE; @@ -241,18 +245,37 @@ return TRUE; } - ret = mailbox_transaction_commit(&ctx->t, 0); + if (mailbox_get_status(ctx->box, STATUS_UIDVALIDITY, + &status) < 0) { + client_send_storage_error(cmd, ctx->storage); + cmd_append_finish(ctx); + return TRUE; + } + + ret = mailbox_transaction_commit_get_uids(&ctx->t, 0, + &uid1, &uid2); if (ret < 0) { client_send_storage_error(cmd, ctx->storage); cmd_append_finish(ctx); return TRUE; } + i_assert(ctx->count == uid2 - uid1 + 1); + + if (uid1 == uid2) { + msg = t_strdup_printf("OK [APPENDUID %u %u] " + "Append completed.", + status.uidvalidity, uid1); + } else { + msg = t_strdup_printf("OK [APPENDUID %u %u:%u] " + "Append completed.", + status.uidvalidity, uid1, uid2); + } sync_flags = ctx->box == cmd->client->mailbox ? 0 : MAILBOX_SYNC_FLAG_FAST; cmd_append_finish(ctx); - return cmd_sync(cmd, sync_flags, 0, "OK Append completed."); + return cmd_sync(cmd, sync_flags, 0, msg); } if (!validate_args(args, &flags_list, &internal_date_str, @@ -321,6 +344,7 @@ o_stream_uncork(client->output); } + ctx->count++; ctx->message_input = TRUE; cmd->func = cmd_append_continue_message; return cmd_append_continue_message(cmd); @@ -473,7 +497,8 @@ ctx->failed = TRUE; } else { ctx->t = mailbox_transaction_begin(ctx->box, - MAILBOX_TRANSACTION_FLAG_EXTERNAL); + MAILBOX_TRANSACTION_FLAG_EXTERNAL | + MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS); } } diff -r 9805becea644 -r 0bc6ec4cddab src/imap/cmd-copy.c --- a/src/imap/cmd-copy.c Tue Apr 17 20:17:52 2007 +0300 +++ b/src/imap/cmd-copy.c Tue Apr 17 20:19:39 2007 +0300 @@ -27,7 +27,9 @@ static int fetch_and_copy(struct client *client, struct mailbox_transaction_context *t, - struct mail_search_arg *search_args) + struct mail_search_arg *search_args, + const char **src_uidset_r, + unsigned int *copy_count_r) { struct mail_search_context *search_ctx; struct mailbox_transaction_context *src_trans; @@ -35,8 +37,13 @@ const char *const *keywords_list; struct mail *mail; unsigned int copy_count = 0; + struct msgset_generator_context srcset_ctx; + string_t *src_uidset; int ret; + src_uidset = t_str_new(256); + msgset_generator_init(&srcset_ctx, src_uidset); + src_trans = mailbox_transaction_begin(client->mailbox, 0); search_ctx = mailbox_search_init(src_trans, NULL, search_args, NULL); @@ -59,8 +66,11 @@ keywords, NULL) < 0) ret = mail->expunged ? 0 : -1; mailbox_keywords_free(t, &keywords); + + msgset_generator_next(&srcset_ctx, mail->uid); } mail_free(&mail); + msgset_generator_finish(&srcset_ctx); if (mailbox_search_deinit(&search_ctx) < 0) ret = -1; @@ -68,6 +78,8 @@ if (mailbox_transaction_commit(&src_trans, 0) < 0) ret = -1; + *src_uidset_r = str_c(src_uidset); + *copy_count_r = copy_count; return ret; } @@ -78,8 +90,11 @@ struct mailbox *destbox; struct mailbox_transaction_context *t; struct mail_search_arg *search_arg; - const char *messageset, *mailbox; + struct mailbox_status status; + const char *messageset, *mailbox, *src_uidset, *msg = NULL; enum mailbox_sync_flags sync_flags = 0; + unsigned int copy_count; + uint32_t uid1, uid2; int ret; /* */ @@ -115,14 +130,34 @@ } t = mailbox_transaction_begin(destbox, - MAILBOX_TRANSACTION_FLAG_EXTERNAL); - ret = fetch_and_copy(client, t, search_arg); + MAILBOX_TRANSACTION_FLAG_EXTERNAL | + MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS); + ret = fetch_and_copy(client, t, search_arg, &src_uidset, ©_count); + + if (ret > 0 && + mailbox_get_status(destbox, STATUS_UIDVALIDITY, &status) < 0) { + client_send_storage_error(cmd, storage); + ret = -1; + } if (ret <= 0) mailbox_transaction_rollback(&t); + else if (mailbox_transaction_commit_get_uids(&t, 0, &uid1, &uid2) < 0) + ret = -1; else { - if (mailbox_transaction_commit(&t, 0) < 0) - ret = -1; + i_assert(copy_count == uid2 - uid1 + 1); + + if (uid1 == uid2) { + msg = t_strdup_printf("OK [COPYUID %u %s %u] " + "Copy completed.", + status.uidvalidity, + src_uidset, uid1); + } else { + msg = t_strdup_printf("OK [COPYUID %u %s %u:%u] " + "Copy completed.", + status.uidvalidity, + src_uidset, uid1, uid2); + } } if (destbox != client->mailbox) { @@ -131,7 +166,7 @@ } if (ret > 0) - return cmd_sync(cmd, sync_flags, 0, "OK Copy completed."); + return cmd_sync(cmd, sync_flags, 0, msg); else if (ret == 0) { /* some messages were expunged, sync them */ return cmd_sync(cmd, 0, 0,