static void search_update_flag_changes(struct dsync_mailbox_exporter *exporter, struct mail *mail, struct dsync_mail_change *change) { const char *const *keywords; unsigned int i; char type; i_assert((change->add_flags & change->remove_flags) == 0); change->modseq = mail_get_modseq(mail); change->pvt_modseq = mail_get_pvt_modseq(mail); change->final_flags = mail_get_flags(mail); keywords = mail_get_keywords(mail); if (!array_is_created(&change->keyword_changes) && keywords[0] != NULL) { p_array_init(&change->keyword_changes, exporter->pool, str_array_length(keywords)); } for (i = 0; keywords[i] != NULL; i++) { /* add the final keyword if it's not already there as +keyword */ if (!final_keyword_check(change, keywords[i], &type)) { const char *keyword_change = p_strdup_printf(exporter->pool, "%c%s", type, keywords[i]); array_append(&change->keyword_changes, &keyword_change, 1); } } }
static void _get_initial_flags (struct sieve_result *result, string_t *flags) { const struct sieve_message_data *msgdata = sieve_result_get_message_data(result); enum mail_flags mail_flags; const char *const *mail_keywords; mail_flags = mail_get_flags(msgdata->mail); mail_keywords = mail_get_keywords(msgdata->mail); if ( (mail_flags & MAIL_FLAGGED) > 0 ) str_printfa(flags, " \\flagged"); if ( (mail_flags & MAIL_ANSWERED) > 0 ) str_printfa(flags, " \\answered"); if ( (mail_flags & MAIL_DELETED) > 0 ) str_printfa(flags, " \\deleted"); if ( (mail_flags & MAIL_SEEN) > 0 ) str_printfa(flags, " \\seen"); if ( (mail_flags & MAIL_DRAFT) > 0 ) str_printfa(flags, " \\draft"); while ( *mail_keywords != NULL ) { str_printfa(flags, " %s", *mail_keywords); mail_keywords++; } }
bool cmd_store(struct client_command_context *cmd) { struct client *client = cmd->client; const struct imap_arg *args; struct mail_search_args *search_args; struct mail_search_context *search_ctx; struct mailbox_transaction_context *t; struct mail *mail; struct imap_store_context ctx; ARRAY_TYPE(seq_range) modified_set, uids; enum mailbox_transaction_flags flags = 0; enum imap_sync_flags imap_sync_flags = 0; const char *set, *reply, *tagged_reply; string_t *str; int ret; bool update_deletes; unsigned int deleted_count; if (!client_read_args(cmd, 0, 0, &args)) return FALSE; if (!client_verify_open_mailbox(cmd)) return TRUE; if (!imap_arg_get_atom(args, &set)) { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } ret = imap_search_get_seqset(cmd, set, cmd->uid, &search_args); if (ret <= 0) return ret < 0; memset(&ctx, 0, sizeof(ctx)); ctx.cmd = cmd; if (!store_parse_args(&ctx, ++args)) { mail_search_args_unref(&search_args); return TRUE; } if (client->mailbox_examined) { mail_search_args_unref(&search_args); if (ctx.max_modseq < (uint64_t)-1) reply = "NO CONDSTORE failed: Mailbox is read-only."; else reply = "OK Store ignored with read-only mailbox."; return cmd_sync(cmd, MAILBOX_SYNC_FLAG_FAST | (cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES), 0, reply); } if (ctx.silent) flags |= MAILBOX_TRANSACTION_FLAG_HIDE; if (ctx.max_modseq < (uint64_t)-1) { /* update modseqs so we can check them early */ flags |= MAILBOX_TRANSACTION_FLAG_REFRESH; } t = mailbox_transaction_begin(client->mailbox, flags); search_ctx = mailbox_search_init(t, search_args, NULL, MAIL_FETCH_FLAGS, NULL); mail_search_args_unref(&search_args); i_array_init(&modified_set, 64); if (ctx.max_modseq < (uint32_t)-1) { /* STORE UNCHANGEDSINCE is being used */ mailbox_transaction_set_max_modseq(t, ctx.max_modseq, &modified_set); } update_deletes = (ctx.flags & MAIL_DELETED) != 0 && ctx.modify_type != MODIFY_REMOVE; deleted_count = 0; while (mailbox_search_next(search_ctx, &mail)) { if (ctx.max_modseq < (uint64_t)-1) { /* check early so there's less work for transaction commit if something has to be cancelled */ if (mail_get_modseq(mail) > ctx.max_modseq) { seq_range_array_add(&modified_set, mail->seq); continue; } } if (update_deletes) { if ((mail_get_flags(mail) & MAIL_DELETED) == 0) deleted_count++; } if (ctx.modify_type == MODIFY_REPLACE || ctx.flags != 0) mail_update_flags(mail, ctx.modify_type, ctx.flags); if (ctx.modify_type == MODIFY_REPLACE || ctx.keywords != NULL) { mail_update_keywords(mail, ctx.modify_type, ctx.keywords); } } if (ctx.keywords != NULL) mailbox_keywords_unref(&ctx.keywords); ret = mailbox_search_deinit(&search_ctx); if (ret < 0) mailbox_transaction_rollback(&t); else ret = mailbox_transaction_commit(&t); if (ret < 0) { array_free(&modified_set); client_send_box_error(cmd, client->mailbox); return TRUE; } client->deleted_count += deleted_count; if (array_count(&modified_set) == 0) tagged_reply = "OK Store completed."; else { if (cmd->uid) { i_array_init(&uids, array_count(&modified_set)*2); mailbox_get_uid_range(client->mailbox, &modified_set, &uids); array_free(&modified_set); modified_set = uids; } str = str_new(cmd->pool, 256); str_append(str, "OK [MODIFIED "); imap_write_seq_range(str, &modified_set); str_append(str, "] Conditional store failed."); tagged_reply = str_c(str); } array_free(&modified_set); /* With UID STORE we have to return UID for the flags as well. Unfortunately we don't have the ability to separate those flag changes that were caused by UID STORE and those that came externally, so we'll just send the UID for all flag changes that we see. */ if (cmd->uid && (!ctx.silent || (client->enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0)) imap_sync_flags |= IMAP_SYNC_FLAG_SEND_UID; return cmd_sync(cmd, (cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES), imap_sync_flags, tagged_reply); }
static void mail_log_append_mail_message_real(struct mail_log_mail_txn_context *ctx, struct mail *mail, enum mail_log_event event, const char *desc) { struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(mail->box->storage->user); struct mail_log_message *msg; string_t *text; uoff_t size; msg = p_new(ctx->pool, struct mail_log_message, 1); text = t_str_new(128); str_append(text, desc); str_append(text, ": "); if ((muser->fields & MAIL_LOG_FIELD_BOX) != 0) { mail_log_append_mailbox_name(text, mail); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_UID) != 0) { if (event != MAIL_LOG_EVENT_SAVE && event != MAIL_LOG_EVENT_COPY) mail_log_append_uid(ctx, msg, text, mail->uid); else { /* with mbox mail->uid contains the uid, but handle this consistently with all mailbox formats */ mail_log_append_uid(ctx, msg, text, 0); } str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_MSGID) != 0) { mail_log_append_mail_header(text, mail, "msgid", "Message-ID"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_PSIZE) != 0) { if (mail_get_physical_size(mail, &size) == 0) str_printfa(text, "size=%"PRIuUOFF_T, size); else str_printfa(text, "size=error"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_VSIZE) != 0) { if (mail_get_virtual_size(mail, &size) == 0) str_printfa(text, "vsize=%"PRIuUOFF_T, size); else str_printfa(text, "vsize=error"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_FROM) != 0) { mail_log_append_mail_header(text, mail, "from", "From"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_SUBJECT) != 0) { mail_log_append_mail_header(text, mail, "subject", "Subject"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_FLAGS) != 0) { str_printfa(text, "flags=("); imap_write_flags(text, mail_get_flags(mail), mail_get_keywords(mail)); str_append(text, "), "); } str_truncate(text, str_len(text)-2); msg->event = event; msg->text = p_strdup(ctx->pool, str_c(text)); DLLIST2_APPEND(&ctx->messages, &ctx->messages_tail, msg); }