static int cmd_import_box_contents(struct doveadm_mail_iter *iter, struct mail *src_mail, struct mailbox *dest_box) { struct mail_save_context *save_ctx; struct mailbox_transaction_context *dest_trans; const char *mailbox = mailbox_get_vname(dest_box); int ret = 0; dest_trans = mailbox_transaction_begin(dest_box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); do { if (doveadm_debug) { i_debug("import: box=%s uid=%u", mailbox, src_mail->uid); } save_ctx = mailbox_save_alloc(dest_trans); mailbox_save_copy_flags(save_ctx, src_mail); if (mailbox_copy(&save_ctx, src_mail) < 0) { i_error("Copying box=%s uid=%u failed: %s", mailbox, src_mail->uid, mailbox_get_last_error(dest_box, NULL)); ret = -1; } } while (doveadm_mail_iter_next(iter, &src_mail)); if (mailbox_transaction_commit(&dest_trans) < 0) { i_error("Committing copied mails to %s failed: %s", mailbox, mailbox_get_last_error(dest_box, NULL)); ret = -1; } return ret; }
static int cmd_deduplicate_box(struct doveadm_mail_cmd_context *_ctx, const struct mailbox_info *info, struct mail_search_args *search_args) { struct deduplicate_cmd_context *ctx = (struct deduplicate_cmd_context *)_ctx; struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; enum mail_error error; pool_t pool; HASH_TABLE(const char *, struct uidlist *) hash; const char *key, *errstr; struct uidlist *value; int ret = 0; if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL, &iter) < 0) return -1; pool = pool_alloconly_create("deduplicate", 10240); hash_table_create(&hash, pool, 0, str_hash, strcmp); while (doveadm_mail_iter_next(iter, &mail)) { if (ctx->by_msgid) { if (mail_get_first_header(mail, "Message-ID", &key) < 0) { errstr = mailbox_get_last_error(mail->box, &error); if (error == MAIL_ERROR_NOTFOUND) continue; i_error("Couldn't lookup Message-ID: for UID=%u: %s", mail->uid, errstr); doveadm_mail_failed_error(_ctx, error); ret = -1; break; } } else { if (mail_get_special(mail, MAIL_FETCH_GUID, &key) < 0) { errstr = mailbox_get_last_error(mail->box, &error); if (error == MAIL_ERROR_NOTFOUND) continue; i_error("Couldn't lookup GUID: for UID=%u: %s", mail->uid, errstr); doveadm_mail_failed_error(_ctx, error); ret = -1; break; } } if (key != NULL && *key != '\0') { value = p_new(pool, struct uidlist, 1); value->uid = mail->uid; value->next = hash_table_lookup(hash, key); if (value->next == NULL) { key = p_strdup(pool, key); hash_table_insert(hash, key, value); } else { hash_table_update(hash, key, value); } } }
static int cmd_save_to_mailbox(struct save_cmd_context *ctx, struct mailbox *box, struct istream *input) { struct mail_storage *storage = mailbox_get_storage(box); struct mailbox_transaction_context *trans; struct mail_save_context *save_ctx; ssize_t ret; bool save_failed = FALSE; if (mailbox_open(box) < 0) { i_error("Failed to open mailbox %s: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_storage(&ctx->ctx, storage); return -1; } trans = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); save_ctx = mailbox_save_alloc(trans); if (mailbox_save_begin(&save_ctx, input) < 0) { i_error("Saving failed: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_storage(&ctx->ctx, storage); mailbox_transaction_rollback(&trans); return -1; } while ((ret = i_stream_read(input)) > 0 || ret == -2) { if (mailbox_save_continue(save_ctx) < 0) { save_failed = TRUE; ret = -1; break; } } i_assert(ret == -1); if (input->stream_errno != 0) { i_error("read(msg input) failed: %s", i_stream_get_error(input)); doveadm_mail_failed_error(&ctx->ctx, MAIL_ERROR_TEMP); } else if (save_failed) { i_error("Saving failed: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_storage(&ctx->ctx, storage); } else if (mailbox_save_finish(&save_ctx) < 0) { i_error("Saving failed: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_storage(&ctx->ctx, storage); } else if (mailbox_transaction_commit(&trans) < 0) { i_error("Save transaction commit failed: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_storage(&ctx->ctx, storage); } else { ret = 0; } if (save_ctx != NULL) mailbox_save_cancel(&save_ctx); if (trans != NULL) mailbox_transaction_rollback(&trans); i_assert(input->eof); return ret < 0 ? -1 : 0; }
static int cmd_expunge_box(struct doveadm_mail_cmd_context *_ctx, const struct mailbox_info *info, struct mail_search_args *search_args) { struct expunge_cmd_context *ctx = (struct expunge_cmd_context *)_ctx; struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; enum mail_error error; int ret = 0; if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL, &iter) < 0) return -1; while (doveadm_mail_iter_next(iter, &mail)) { if (doveadm_debug) { i_debug("expunge: box=%s uid=%u", info->vname, mail->uid); } mail_expunge(mail); } if (doveadm_mail_iter_deinit_keep_box(&iter, &box) < 0) ret = -1; else if (mailbox_sync(box, 0) < 0) { i_error("Syncing mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } if (ctx->delete_empty_mailbox && ret == 0) { if (mailbox_delete_empty(box) < 0) { error = mailbox_get_last_mail_error(box); if (error != MAIL_ERROR_EXISTS) { i_error("Deleting mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } } else { if (mailbox_set_subscribed(box, FALSE) < 0) { i_error("Unsubscribing mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } } } mailbox_free(&box); return ret; }
static int dest_mailbox_open_or_create(struct import_cmd_context *ctx, struct mail_user *user, const struct mailbox_info *info, struct mailbox **box_r) { struct mail_namespace *ns; struct mailbox *box; enum mail_error error; const char *name, *errstr; if (*ctx->dest_parent != '\0') { /* prefix destination mailbox name with given parent mailbox */ ns = mail_namespace_find(user->namespaces, ctx->dest_parent); } else { ns = mail_namespace_find(user->namespaces, info->vname); } name = convert_vname_separators(info->vname, mail_namespace_get_sep(info->ns), mail_namespace_get_sep(ns)); if (*ctx->dest_parent != '\0') { name = t_strdup_printf("%s%c%s", ctx->dest_parent, mail_namespace_get_sep(ns), name); } box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY); if (mailbox_create(box, NULL, FALSE) < 0) { errstr = mailbox_get_last_error(box, &error); if (error != MAIL_ERROR_EXISTS) { i_error("Couldn't create mailbox %s: %s", name, errstr); doveadm_mail_failed_mailbox(&ctx->ctx, box); mailbox_free(&box); return -1; } } if (ctx->subscribe) { if (mailbox_set_subscribed(box, TRUE) < 0) { i_error("Couldn't subscribe to mailbox %s: %s", name, mailbox_get_last_error(box, NULL)); } } if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Syncing mailbox %s failed: %s", name, mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, box); mailbox_free(&box); return -1; } *box_r = box; return 0; }
static int cmd_copy_box(struct copy_cmd_context *ctx, struct mailbox *destbox, const struct mailbox_info *info) { struct doveadm_mail_iter *iter; struct mailbox_transaction_context *desttrans; struct mail_save_context *save_ctx; struct mail *mail; int ret = 0; if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, 0, NULL, &iter) < 0) return -1; /* use a separately committed transaction for each mailbox. this guarantees that mails aren't expunged without actually having been copied. */ desttrans = mailbox_transaction_begin(destbox, MAILBOX_TRANSACTION_FLAG_EXTERNAL); while (doveadm_mail_iter_next(iter, &mail)) { save_ctx = mailbox_save_alloc(desttrans); mailbox_save_copy_flags(save_ctx, mail); if (mailbox_copy(&save_ctx, mail) == 0) { if (ctx->move) mail_expunge(mail); } else { i_error("Copying message UID %u from '%s' failed: %s", mail->uid, info->vname, mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); ret = -1; } } if (mailbox_transaction_commit(&desttrans) < 0) { i_error("Committing %s mails failed: %s", ctx->move ? "moved" : "copied", mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); /* rollback expunges */ doveadm_mail_iter_deinit_rollback(&iter); ret = -1; } else { if (doveadm_mail_iter_deinit_sync(&iter) < 0) ret = -1; } return ret; }
static int cmd_mailbox_metadata_get_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; struct mail_namespace *ns; struct mailbox *box; struct mail_attribute_value value; int ret; ret = cmd_mailbox_metadata_open_mailbox(ctx, user, "get attribute", &ns, &box); if (ret != 0) return ret; ret = mailbox_attribute_get_stream(box, ctx->key_type, ctx->key, &value); if (ret < 0) { i_error("Failed to get attribute: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); } else if (ret == 0) { /* not found, print as empty */ doveadm_print(""); } else if (value.value_stream != NULL) { doveadm_print_istream(value.value_stream); } else { doveadm_print(value.value); } mailbox_free(&box); return ret; }
static int cmd_acl_mailbox_open(struct doveadm_mail_cmd_context *ctx, struct mail_user *user, const char *mailbox, struct mailbox **box_r) { struct acl_user *auser = ACL_USER_CONTEXT(user); struct mail_namespace *ns; struct mailbox *box; if (auser == NULL) { i_error("ACL not enabled for %s", user->username); doveadm_mail_failed_error(ctx, MAIL_ERROR_NOTFOUND); return -1; } ns = mail_namespace_find(user->namespaces, mailbox); box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY | MAILBOX_FLAG_IGNORE_ACLS); if (mailbox_open(box) < 0) { i_error("Can't open mailbox %s: %s", mailbox, mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(ctx, box); mailbox_free(&box); return -1; } *box_r = box; return 0; }
static int ns_mailbox_try_alloc(struct dsync_brain *brain, struct mail_namespace *ns, const guid_128_t guid, struct mailbox **box_r, const char **errstr_r, enum mail_error *error_r) { enum mailbox_flags flags = 0; struct mailbox *box; enum mailbox_existence existence; int ret; if (brain->backup_send) { /* make sure mailbox isn't modified */ flags |= MAILBOX_FLAG_READONLY; } box = mailbox_alloc_guid(ns->list, guid, flags); ret = mailbox_exists(box, FALSE, &existence); if (ret < 0) { *errstr_r = mailbox_get_last_error(box, error_r); mailbox_free(&box); return -1; } if (existence != MAILBOX_EXISTENCE_SELECT) { mailbox_free(&box); *errstr_r = existence == MAILBOX_EXISTENCE_NONE ? "Mailbox was already deleted" : "Mailbox is no longer selectable"; return 0; } *box_r = box; return 1; }
static int lmtp_rcpt_to_is_over_quota(struct client *client, const struct mail_recipient *rcpt) { struct mail_user *user; struct mail_namespace *ns; struct mailbox *box; struct mailbox_status status; const char *errstr; enum mail_error error; int ret; if (!client->lmtp_set->lmtp_rcpt_check_quota) return 0; ret = mail_storage_service_next(storage_service, rcpt->service_user, &user); if (ret < 0) return -1; ns = mail_namespace_find_inbox(user->namespaces); box = mailbox_alloc(ns->list, "INBOX", 0); ret = mailbox_get_status(box, STATUS_CHECK_OVER_QUOTA, &status); if (ret < 0) { errstr = mailbox_get_last_error(box, &error); if (error == MAIL_ERROR_NOSPACE) { client_send_line(client, "552 5.2.2 <%s> %s", rcpt->address, errstr); ret = 1; } } mailbox_free(&box); mail_user_unref(&user); return ret; }
static int ns_mailbox_try_alloc(struct mail_namespace *ns, const guid_128_t guid, struct mailbox **box_r, const char **error_r) { struct mailbox *box; enum mailbox_existence existence; enum mail_error err; int ret; box = mailbox_alloc_guid(ns->list, guid, 0); ret = mailbox_exists(box, FALSE, &existence); if (ret < 0) { *error_r = mailbox_get_last_error(box, &err); mailbox_free(&box); return -1; } if (existence != MAILBOX_EXISTENCE_SELECT) { mailbox_free(&box); *error_r = existence == MAILBOX_EXISTENCE_NONE ? "Mailbox was already deleted" : "Mailbox is no longer selectable"; return 0; } *box_r = box; return 1; }
static int cmd_flags_run_box(struct flags_cmd_context *ctx, const struct mailbox_info *info) { struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; struct mail_keywords *kw = NULL; if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, 0, NULL, &iter) < 0) return -1; box = doveadm_mail_iter_get_mailbox(iter); if (ctx->keywords != NULL) { if (mailbox_keywords_create(box, ctx->keywords, &kw) < 0) { i_error("Invalid keywords: %s", mailbox_get_last_error(box, NULL)); (void)doveadm_mail_iter_deinit(&iter); ctx->ctx.exit_code = DOVEADM_EX_NOTPOSSIBLE; return -1; } } while (doveadm_mail_iter_next(iter, &mail)) { mail_update_flags(mail, ctx->modify_type, ctx->flags); if (kw != NULL) mail_update_keywords(mail, ctx->modify_type, kw); } if (kw != NULL) mailbox_keywords_unref(&kw); return doveadm_mail_iter_deinit(&iter); }
cmd_expunge_finish(struct client_command_context *cmd, struct mail_search_args *search_args) { struct client *client = cmd->client; const char *errstr; enum mail_error error = MAIL_ERROR_NONE; int ret; ret = imap_expunge(client->mailbox, search_args == NULL ? NULL : search_args->args); if (search_args != NULL) mail_search_args_unref(&search_args); if (ret < 0) { errstr = mailbox_get_last_error(client->mailbox, &error); if (error != MAIL_ERROR_PERM) { client_send_box_error(cmd, client->mailbox); return TRUE; } else { return cmd_sync(cmd, 0, IMAP_SYNC_FLAG_SAFE, t_strdup_printf("OK Expunge ignored: %s.", errstr)); } } client->sync_seen_deletes = FALSE; if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) { return cmd_sync(cmd, MAILBOX_SYNC_FLAG_EXPUNGE, IMAP_SYNC_FLAG_SAFE, "OK Expunge completed."); } else { return cmd_sync_callback(cmd, MAILBOX_SYNC_FLAG_EXPUNGE, IMAP_SYNC_FLAG_SAFE, cmd_expunge_callback); } }
int imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl, struct imap_msgpart_open_result *result_r, const char **error_r) { struct mail *mail; int ret; if (mpurl->result.input != NULL) { i_stream_seek(mpurl->result.input, 0); *result_r = mpurl->result; return 1; } /* open mail if it is not yet open */ ret = imap_msgpart_url_open_mail(mpurl, &mail, error_r); if (ret <= 0) return ret; /* open the referenced part as a stream */ ret = imap_msgpart_open(mail, mpurl->part, result_r); if (ret < 0) { *error_r = mailbox_get_last_error(mpurl->box, NULL); return ret; } mpurl->result = *result_r; return 1; }
static int cmd_deduplicate_uidlist(struct doveadm_mail_cmd_context *_ctx, struct mailbox *box, struct uidlist *uidlist) { struct mailbox_transaction_context *trans; struct mail_search_context *search_ctx; struct mail_search_args *search_args; struct mail_search_arg *arg; struct mail *mail; ARRAY_TYPE(seq_range) uids; int ret = 0; /* the uidlist is reversed with oldest mails at the end. we'll delete everything but the oldest mail. */ if (uidlist->next == NULL) return 0; t_array_init(&uids, 8); for (; uidlist->next != NULL; uidlist = uidlist->next) seq_range_array_add(&uids, uidlist->uid); search_args = mail_search_build_init(); arg = mail_search_build_add(search_args, SEARCH_UIDSET); arg->value.seqset = uids; trans = mailbox_transaction_begin(box, 0); search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL); mail_search_args_unref(&search_args); while (mailbox_search_next(search_ctx, &mail)) mail_expunge(mail); if (mailbox_search_deinit(&search_ctx) < 0) { i_error("Searching mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } if (mailbox_transaction_commit(&trans) < 0) { i_error("Committing mailbox '%s' transaction failed: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } return ret; }
static int cmd_copy_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct copy_cmd_context *ctx = (struct copy_cmd_context *)_ctx; const enum mailbox_list_iter_flags iter_flags = MAILBOX_LIST_ITER_NO_AUTO_BOXES | MAILBOX_LIST_ITER_RETURN_NO_FLAGS; struct doveadm_mailbox_list_iter *iter; struct mail_user *src_user; struct mail_namespace *ns; struct mailbox *destbox; const struct mailbox_info *info; int ret = 0; if (ctx->source_username != NULL && ctx->source_user == NULL) cmd_copy_alloc_source_user(ctx); ns = mail_namespace_find(user->namespaces, ctx->destname); destbox = mailbox_alloc(ns->list, ctx->destname, MAILBOX_FLAG_SAVEONLY); if (mailbox_open(destbox) < 0) { i_error("Can't open mailbox '%s': %s", ctx->destname, mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); mailbox_free(&destbox); return -1; } src_user = ctx->source_user != NULL ? ctx->source_user : user; iter = doveadm_mailbox_list_iter_init(_ctx, src_user, _ctx->search_args, iter_flags); while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN { if (cmd_copy_box(ctx, destbox, info) < 0) ret = -1; } T_END; if (doveadm_mailbox_list_iter_deinit(&iter) < 0) ret = -1; if (mailbox_sync(destbox, 0) < 0) { i_error("Syncing mailbox '%s' failed: %s", ctx->destname, mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); ret = -1; } mailbox_free(&destbox); return ret; }
static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree, const struct mailbox_info *info, const guid_128_t box_guid, enum mail_error *error_r) { struct dsync_mailbox_node *node; struct mailbox *box; struct mailbox_metadata metadata; struct mailbox_status status; const char *errstr; enum mail_error error; int ret = 0; if ((info->flags & MAILBOX_NONEXISTENT) != 0) return 0; if ((info->flags & MAILBOX_NOSELECT) != 0) { return !guid_128_is_empty(box_guid) ? 0 : dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r); } /* get GUID and UIDVALIDITY for selectable mailbox */ box = mailbox_alloc(info->ns->list, info->vname, MAILBOX_FLAG_READONLY); if (dsync_mailbox_tree_get_selectable(box, &metadata, &status) < 0) { errstr = mailbox_get_last_error(box, &error); switch (error) { case MAIL_ERROR_NOTFOUND: /* mailbox was just deleted? */ break; case MAIL_ERROR_NOTPOSSIBLE: /* invalid mbox files? ignore */ break; default: i_error("Failed to access mailbox %s: %s", info->vname, errstr); *error_r = error; ret = -1; } mailbox_free(&box); return ret; } mailbox_free(&box); if (!guid_128_is_empty(box_guid) && !guid_128_equals(box_guid, metadata.guid)) { /* unwanted mailbox */ return 0; } if (dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r) < 0) return -1; memcpy(node->mailbox_guid, metadata.guid, sizeof(node->mailbox_guid)); node->uid_validity = status.uidvalidity; node->uid_next = status.uidnext; return 0; }
void virtual_box_copy_error(struct mailbox *dest, struct mailbox *src) { const char *name, *str; enum mail_error error; name = get_user_visible_mailbox_name(src); str = mailbox_get_last_error(src, &error); str = t_strdup_printf("%s (for backend mailbox %s)", str, name); mail_storage_set_error(dest->storage, error, str); }
static struct mail_raw *mail_raw_create (struct mail_user *ruser, struct istream *input, const char *mailfile, const char *sender, time_t mtime) { struct mail_raw *mailr; struct mailbox_header_lookup_ctx *headers_ctx; const char *envelope_sender; int ret; if ( mailfile != NULL && *mailfile != '/' ) mailfile = t_abspath(mailfile); mailr = i_new(struct mail_raw, 1); envelope_sender = sender != NULL ? sender : DEFAULT_ENVELOPE_SENDER; if ( mailfile == NULL ) { ret = raw_mailbox_alloc_stream(ruser, input, mtime, envelope_sender, &mailr->box); } else { ret = raw_mailbox_alloc_path(ruser, mailfile, (time_t)-1, envelope_sender, &mailr->box); } if ( ret < 0 ) { if ( mailfile == NULL ) { i_fatal("Can't open delivery mail as raw: %s", mailbox_get_last_error(mailr->box, NULL)); } else { i_fatal("Can't open delivery mail as raw (file=%s): %s", mailfile, mailbox_get_last_error(mailr->box, NULL)); } } mailr->trans = mailbox_transaction_begin(mailr->box, 0); headers_ctx = mailbox_header_lookup_init(mailr->box, wanted_headers); mailr->mail = mail_alloc(mailr->trans, 0, headers_ctx); mailbox_header_lookup_unref(&headers_ctx); mail_set_seq(mailr->mail, 1); return mailr; }
static int cmd_mailbox_metadata_set_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; struct mail_namespace *ns; struct mailbox *box; struct mailbox_transaction_context *trans; int ret; ret = cmd_mailbox_metadata_open_mailbox(ctx, user, "set attribute", &ns, &box); if (ret != 0) return ret; trans = mailbox_transaction_begin(box, ctx->empty_mailbox_name ? MAILBOX_TRANSACTION_FLAG_EXTERNAL : 0); ret = ctx->value.value == NULL ? mailbox_attribute_unset(trans, ctx->key_type, ctx->key) : mailbox_attribute_set(trans, ctx->key_type, ctx->key, &ctx->value); if (ret < 0) { i_error("Failed to set attribute: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); mailbox_transaction_rollback(&trans); } else if (mailbox_transaction_commit(&trans) < 0) { i_error("Failed to commit transaction: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } mailbox_free(&box); return ret; }
static int dsync_mail_error(struct dsync_mailbox_exporter *exporter, struct mail *mail, const char *field) { const char *errstr; enum mail_error error; errstr = mailbox_get_last_error(exporter->box, &error); if (error == MAIL_ERROR_EXPUNGED) return 0; exporter->error = p_strdup_printf(exporter->pool, "Can't lookup %s for UID=%u: %s", field, mail->uid, errstr); return -1; }
static int dsync_box_get(struct mailbox *box, struct dsync_mailbox *dsync_box_r) { const enum mailbox_status_items status_items = STATUS_UIDVALIDITY | STATUS_UIDNEXT | STATUS_MESSAGES | STATUS_FIRST_RECENT_UID | STATUS_HIGHESTMODSEQ | STATUS_HIGHESTPVTMODSEQ; const enum mailbox_metadata_items metadata_items = MAILBOX_METADATA_CACHE_FIELDS | MAILBOX_METADATA_GUID; struct mailbox_status status; struct mailbox_metadata metadata; const char *errstr; enum mail_error error; /* get metadata first, since it may autocreate the mailbox */ if (mailbox_get_metadata(box, metadata_items, &metadata) < 0 || mailbox_get_status(box, status_items, &status) < 0) { errstr = mailbox_get_last_error(box, &error); if (error == MAIL_ERROR_NOTFOUND || error == MAIL_ERROR_NOTPOSSIBLE) { /* Mailbox isn't selectable, try the next one. We should have already caught \Noselect mailboxes, but check them anyway here. The NOTPOSSIBLE check is mainly for invalid mbox files. */ return 0; } i_error("Failed to access mailbox %s: %s", mailbox_get_vname(box), errstr); return -1; } i_assert(status.uidvalidity != 0 || status.messages == 0); memset(dsync_box_r, 0, sizeof(*dsync_box_r)); memcpy(dsync_box_r->mailbox_guid, metadata.guid, sizeof(dsync_box_r->mailbox_guid)); dsync_box_r->uid_validity = status.uidvalidity; dsync_box_r->uid_next = status.uidnext; dsync_box_r->messages_count = status.messages; dsync_box_r->first_recent_uid = status.first_recent_uid; dsync_box_r->highest_modseq = status.highest_modseq; dsync_box_r->highest_pvt_modseq = status.highest_pvt_modseq; dsync_box_r->cache_fields = *metadata.cache_fields; dsync_box_r->have_guids = status.have_guids; dsync_box_r->have_save_guids = status.have_save_guids; dsync_box_r->have_only_guid128 = status.have_only_guid128; return 1; }
static int quota_count_mailbox(struct quota_root *root, struct mail_namespace *ns, const char *vname, uint64_t *bytes, uint64_t *count) { struct quota_rule *rule; struct mailbox *box; struct mailbox_metadata metadata; struct mailbox_status status; enum mail_error error; const char *errstr; int ret; rule = quota_root_rule_find(root->set, vname); if (rule != NULL && rule->ignore) { /* mailbox not included in quota */ return 0; } box = mailbox_alloc(ns->list, vname, MAILBOX_FLAG_READONLY); if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NOQUOTA) != 0) { /* quota doesn't exist for this mailbox/storage */ ret = 0; } else if (mailbox_get_metadata(box, root->quota->set->vsizes ? MAILBOX_METADATA_VIRTUAL_SIZE : MAILBOX_METADATA_PHYSICAL_SIZE, &metadata) < 0 || mailbox_get_status(box, STATUS_MESSAGES, &status) < 0) { errstr = mailbox_get_last_error(box, &error); if (error == MAIL_ERROR_TEMP) { i_error("quota: Couldn't get size of mailbox %s: %s", vname, errstr); ret = -1; } else { /* non-temporary error, e.g. ACLs denied access. */ ret = 0; } } else { ret = 1; *bytes += root->quota->set->vsizes ? metadata.virtual_size : metadata.physical_size; *count += status.messages; } mailbox_free(&box); return ret; }
static bool cmd_fetch_finish(struct imap_fetch_context *ctx, struct client_command_context *cmd) { static const char *ok_message = "OK Fetch completed."; const char *tagged_reply = ok_message; enum mail_error error; bool failed, seen_flags_changed = ctx->state.seen_flags_changed; if (ctx->state.skipped_expunged_msgs) { tagged_reply = "OK ["IMAP_RESP_CODE_EXPUNGEISSUED"] " "Some messages were already expunged."; } failed = imap_fetch_end(ctx) < 0; imap_fetch_free(&ctx); if (failed) { const char *errstr; if (cmd->client->output->closed) { client_disconnect(cmd->client, "Disconnected"); return TRUE; } errstr = mailbox_get_last_error(cmd->client->mailbox, &error); if (error == MAIL_ERROR_CONVERSION || error == MAIL_ERROR_INVALIDDATA) { /* a) BINARY found unsupported Content-Transfer-Encoding b) Content was invalid */ tagged_reply = t_strdup_printf( "NO ["IMAP_RESP_CODE_UNKNOWN_CTE"] %s", errstr); } else { /* We never want to reply NO to FETCH requests, BYE is preferrable (see imap-ml for reasons). */ client_disconnect_with_error(cmd->client, errstr); return TRUE; } } return cmd_sync(cmd, (seen_flags_changed ? 0 : MAILBOX_SYNC_FLAG_FAST) | (cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES), 0, tagged_reply); }
static int imap_map_read(struct mailbox *box) { struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box); struct mailbox_status status; struct mailbox_transaction_context *t; struct mail_search_args *search_args; struct mail_search_context *ctx; struct mail *mail; struct imap_msg_map *map; uoff_t psize; int ret = 0; mailbox_get_open_status(box, STATUS_MESSAGES, &status); i_assert(!array_is_created(&mbox->imap_msg_map)); p_array_init(&mbox->imap_msg_map, box->pool, status.messages); t = mailbox_transaction_begin(box, 0); search_args = mail_search_build_init(); mail_search_build_add_all(search_args); ctx = mailbox_search_init(t, search_args, NULL, MAIL_FETCH_PHYSICAL_SIZE, NULL); mail_search_args_unref(&search_args); while (mailbox_search_next(ctx, &mail)) { if (mail_get_physical_size(mail, &psize) < 0) { i_error("pop3_migration: Failed to get psize for imap uid %u: %s", mail->uid, mailbox_get_last_error(box, NULL)); ret = -1; break; } map = array_append_space(&mbox->imap_msg_map); map->uid = mail->uid; map->psize = psize; } if (mailbox_search_deinit(&ctx) < 0) ret = -1; (void)mailbox_transaction_commit(&t); return ret; }
int imap_msgpart_url_get_bodypartstructure(struct imap_msgpart_url *mpurl, const char **bpstruct_r, const char **error_r) { struct mail *mail; int ret; /* open mail if it is not yet open */ ret = imap_msgpart_url_open_mail(mpurl, &mail, error_r); if (ret <= 0) return ret; ret = imap_msgpart_bodypartstructure(mail, mpurl->part, bpstruct_r); if (ret < 0) *error_r = mailbox_get_last_error(mpurl->box, NULL); else if (ret == 0) *error_r = "Message part not found"; return ret; }
static int cmd_mailbox_metadata_list_run_iter(struct metadata_cmd_context *ctx, struct mailbox *box, enum mail_attribute_type type) { struct mailbox_attribute_iter *iter; const char *key; iter = mailbox_attribute_iter_init(box, type, ctx->key); while ((key = mailbox_attribute_iter_next(iter)) != NULL) doveadm_print(key); if (mailbox_attribute_iter_deinit(&iter) < 0) { i_error("Mailbox %s: Failed to iterate mailbox attributes: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); return -1; } return 0; }
void dsync_brain_mailbox_update_pre(struct dsync_brain *brain, struct mailbox *box, const struct dsync_mailbox *local_box, const struct dsync_mailbox *remote_box) { struct mailbox_update update; const struct dsync_mailbox_state *state; memset(&update, 0, sizeof(update)); if (local_box->uid_validity != remote_box->uid_validity) { /* Keep the UIDVALIDITY for the mailbox that has more messages. If they equal, use the higher UIDVALIDITY. */ if (remote_box->messages_count > local_box->messages_count || (remote_box->messages_count == local_box->messages_count && remote_box->uid_validity > local_box->uid_validity)) update.uid_validity = remote_box->uid_validity; state = dsync_mailbox_state_find(brain, local_box->mailbox_guid); if (state != NULL && state->last_common_uid > 0) { /* we can't continue syncing this mailbox in this session, because the other side already started sending mailbox changes, but not for all mails. */ dsync_mailbox_state_remove(brain, local_box->mailbox_guid); // FIXME: handle this properly } } dsync_cache_fields_update(local_box, remote_box, &update); if (update.uid_validity == 0 && update.cache_updates == NULL) { /* no changes */ return; } if (mailbox_update(box, &update) < 0) { i_error("Couldn't update mailbox %s metadata: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); brain->failed = TRUE; } }
static int dsync_mailbox_tree_fix_guid_duplicate(struct dsync_mailbox_tree *tree, struct dsync_mailbox_node *node1, struct dsync_mailbox_node *node2) { struct mailbox *box; struct mailbox_update update; struct dsync_mailbox_node *change_node; const char *change_vname; int ret = 0; memset(&update, 0, sizeof(update)); guid_128_generate(update.mailbox_guid); /* just in case the duplication exists in both sides, make them choose the same node */ if (strcmp(dsync_mailbox_node_get_full_name(tree, node1), dsync_mailbox_node_get_full_name(tree, node2)) <= 0) change_node = node1; else change_node = node2; change_vname = dsync_mailbox_node_get_full_name(tree, change_node); i_error("Duplicate mailbox GUID %s for mailboxes %s and %s - " "giving a new GUID %s to %s", guid_128_to_string(node1->mailbox_guid), dsync_mailbox_node_get_full_name(tree, node1), dsync_mailbox_node_get_full_name(tree, node2), guid_128_to_string(update.mailbox_guid), change_vname); i_assert(node1->ns != NULL && node2->ns != NULL); box = mailbox_alloc(change_node->ns->list, change_vname, 0); if (mailbox_update(box, &update) < 0) { i_error("Couldn't update mailbox %s GUID: %s", change_vname, mailbox_get_last_error(box, NULL)); ret = -1; } else { memcpy(change_node->mailbox_guid, update.mailbox_guid, sizeof(change_node->mailbox_guid)); } mailbox_free(&box); return ret; }
int imap_status_get(struct client_command_context *cmd, struct mail_namespace *ns, const char *mailbox, const struct imap_status_items *items, struct imap_status_result *result_r) { struct client *client = cmd->client; struct mailbox *box; const char *errstr; int ret = 0; if (client->mailbox != NULL && mailbox_equals(client->mailbox, ns, mailbox)) { /* this mailbox is selected */ box = client->mailbox; } else { /* open the mailbox */ box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY); mailbox_set_reason(box, "STATUS"); if (client->enabled_features != 0) (void)mailbox_enable(box, client->enabled_features); } if ((items->status & STATUS_HIGHESTMODSEQ) != 0) (void)client_enable(client, MAILBOX_FEATURE_CONDSTORE); ret = mailbox_get_status(box, items->status, &result_r->status); if (items->metadata != 0 && ret == 0) { ret = mailbox_get_metadata(box, items->metadata, &result_r->metadata); } if (ret < 0) { errstr = mailbox_get_last_error(box, &result_r->error); result_r->errstr = imap_get_error_string(cmd, errstr, result_r->error); } if (box != client->mailbox) mailbox_free(&box); return ret; }