static int cmd_import_box(struct import_cmd_context *ctx, struct mail_user *dest_user, const struct mailbox_info *info, struct mail_search_args *search_args) { struct doveadm_mail_iter *iter; struct mailbox_transaction_context *trans; struct mailbox *box; struct mail *mail; int ret = 0; if (doveadm_mail_iter_init(info, search_args, &trans, &iter) < 0) return -1; mail = mail_alloc(trans, 0, NULL); if (doveadm_mail_iter_next(iter, mail)) { /* at least one mail matches in this mailbox */ if (dest_mailbox_open_or_create(ctx, dest_user, info->name, &box) == 0) { if (cmd_import_box_contents(iter, mail, box) < 0) ret = -1; mailbox_free(&box); } } mail_free(&mail); if (doveadm_mail_iter_deinit_sync(&iter) < 0) ret = -1; return ret; }
void mail_raw_close(struct mail_raw **mailr) { mail_free(&(*mailr)->mail); mailbox_transaction_rollback(&(*mailr)->trans); mailbox_free(&(*mailr)->box); i_free(*mailr); *mailr = NULL; }
void mail_destroy(struct mail *m) { mail_free(m); if (m->base != NULL) { SHM_DEREGISTER(&m->shm); shm_destroy(&m->shm); } }
void mail_close(struct mail *m) { mail_free(m); if (m->base != NULL) { SHM_DEREGISTER(&m->shm); shm_close(&m->shm); } }
/****************************************************************** Read window dispose *******************************************************************/ void read_window_dispose(GtkObject *object, gpointer user_data) { struct Read_Data *data = (struct Read_Data*)user_data; if (data->folder_path) free(data->folder_path); mail_free(data->mail); if (data->num < MAX_READ_OPEN) read_open[data->num] = NULL; free(data); gtk_widget_hide_all(GTK_WIDGET(object)); }
static void zlib_mailbox_transaction_rollback(struct mailbox_transaction_context *t) { union mailbox_module_context *zbox = ZLIB_CONTEXT(t->box); struct zlib_transaction_context *zt = ZLIB_CONTEXT(t); if (zt->tmp_mail != NULL) mail_free(&zt->tmp_mail); zbox->super.transaction_rollback(t); i_free(zt); }
static int fetch_and_copy(struct client *client, struct mailbox_transaction_context *t, struct mail_search_args *search_args, const char **src_uidset_r, unsigned int *copy_count_r) { struct mail_search_context *search_ctx; struct mailbox_transaction_context *src_trans; struct mail_save_context *save_ctx; 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, search_args, NULL); mail = mail_alloc(src_trans, 0, NULL); ret = 1; while (mailbox_search_next(search_ctx, mail) && ret > 0) { if (mail->expunged) { ret = 0; break; } if ((++copy_count % COPY_CHECK_INTERVAL) == 0) client_send_sendalive_if_needed(client); save_ctx = mailbox_save_alloc(t); mailbox_save_copy_flags(save_ctx, mail); if (mailbox_copy(&save_ctx, mail) < 0) ret = mail->expunged ? 0 : -1; msgset_generator_next(&srcset_ctx, mail->uid); } mail_free(&mail); msgset_generator_finish(&srcset_ctx); if (mailbox_search_deinit(&search_ctx) < 0) ret = -1; if (mailbox_transaction_commit(&src_trans) < 0) ret = -1; *src_uidset_r = str_c(src_uidset); *copy_count_r = copy_count; return ret; }
void index_sort_program_deinit(struct mail_search_sort_program **_program) { struct mail_search_sort_program *program = *_program; *_program = NULL; if (program->context != NULL) index_sort_list_finish(program); mail_free(&program->temp_mail); array_free(&program->seqs); i_free(program); }
static void antispam_mailbox_transaction_rollback(struct mailbox_transaction_context *ctx) { struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(ctx->box); struct antispam_internal_context *ast = ANTISPAM_CONTEXT(ctx); if (ast->mail) mail_free(&ast->mail); asbox->module_ctx.super.transaction_rollback(ctx); antispam_transaction_rollback(&ast->backendctx); }
static int antispam_mailbox_transaction_commit(struct mailbox_transaction_context *ctx, uint32_t *uid_validity_r, uint32_t *first_saved_uid_r, uint32_t *last_saved_uid_r) { struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(ctx->box); struct antispam_internal_context *ast = ANTISPAM_CONTEXT(ctx); if (antispam_transaction_commit(ctx, &ast->backendctx) < 0) { if (ast->mail) mail_free(&ast->mail); asbox->module_ctx.super.transaction_rollback(ctx); return -1; } if (ast->mail) mail_free(&ast->mail); return asbox->module_ctx.super.transaction_commit(ctx, uid_validity_r, first_saved_uid_r, last_saved_uid_r); }
/****************************************************************** This close and disposed the window (note: this must not be called within a normal callback hook (because the object is disposed in this function)! *******************************************************************/ static void read_window_close(struct Read_Data **pdata) { struct Read_Data *data = *pdata; set(data->wnd,MUIA_Window_Open,FALSE); DoMethod(App,OM_REMMEMBER,data->wnd); MUI_DisposeObject(data->wnd); if (data->attachment_html_menu) MUI_DisposeObject(data->attachment_html_menu); if (data->attachment_standard_menu) MUI_DisposeObject(data->attachment_standard_menu); if (data->file_req) MUI_FreeAslRequest(data->file_req); mail_free(data->mail); if (data->num < MAX_READ_OPEN) read_open[data->num] = 0; free(data); }
static int zlib_mailbox_transaction_commit(struct mailbox_transaction_context *t, struct mail_transaction_commit_changes *changes_r) { union mailbox_module_context *zbox = ZLIB_CONTEXT(t->box); struct zlib_transaction_context *zt = ZLIB_CONTEXT(t); int ret; if (zt->tmp_mail != NULL) mail_free(&zt->tmp_mail); ret = zbox->super.transaction_commit(t, changes_r); i_free(zt); return ret; }
int index_sort_program_deinit(struct mail_search_sort_program **_program) { struct mail_search_sort_program *program = *_program; *_program = NULL; if (program->context != NULL) index_sort_list_finish(program); mail_free(&program->temp_mail); array_free(&program->seqs); int ret = program->failed ? -1 : 0; i_free(program); return ret; }
static void virtual_mail_free(struct mail *mail) { struct virtual_mail *vmail = (struct virtual_mail *)mail; struct mail **mails; unsigned int i, count; mails = array_get_modifiable(&vmail->backend_mails, &count); for (i = 0; i < count; i++) mail_free(&mails[i]); array_free(&vmail->backend_mails); if (vmail->wanted_headers != NULL) mailbox_header_lookup_unref(&vmail->wanted_headers); pool_unref(&vmail->imail.data_pool); pool_unref(&vmail->imail.mail.pool); }
void imap_msgpart_url_free(struct imap_msgpart_url **_mpurl) { struct imap_msgpart_url *mpurl = *_mpurl; *_mpurl = NULL; if (mpurl->result.input != NULL) i_stream_unref(&mpurl->result.input); if (mpurl->part != NULL) imap_msgpart_free(&mpurl->part); if (mpurl->mail != NULL) mail_free(&mpurl->mail); if (mpurl->trans != NULL) mailbox_transaction_rollback(&mpurl->trans); if (mpurl->box != NULL && mpurl->box != mpurl->selected_box) mailbox_free(&mpurl->box); if (mpurl->section != NULL) i_free(mpurl->section); i_free(mpurl->mailbox); i_free(mpurl); }
static int index_mailbox_get_first_save_date(struct mailbox *box, struct mailbox_metadata *metadata_r) { const struct mail_index_header *hdr; struct mailbox_transaction_context *t; struct mail *mail; uint32_t seq; int ret = -1; hdr = mail_index_get_header(box->view); if (hdr->messages_count == 0) { metadata_r->first_save_date = (time_t)-1; return 0; } t = mailbox_transaction_begin(box, 0, __func__); mail = mail_alloc(t, 0, NULL); for (seq = 1; seq <= hdr->messages_count; seq++) { mail_set_seq(mail, seq); if (mail_get_save_date(mail, &metadata_r->first_save_date) == 0) { ret = 0; break; } if (mailbox_get_last_mail_error(box) != MAIL_ERROR_EXPUNGED) { /* failed */ break; } } mail_free(&mail); (void)mailbox_transaction_commit(&t); if (seq > hdr->messages_count) { /* all messages were expunged after all */ metadata_r->first_save_date = (time_t)-1; return 0; } return ret; }
int imap_msgpart_url_open_mail(struct imap_msgpart_url *mpurl, struct mail **mail_r, const char **error_r) { struct mailbox_transaction_context *t; struct mailbox *box; enum mail_error error_code; struct mail *mail; int ret; if (mpurl->mail != NULL) { *mail_r = mpurl->mail; return 1; } /* open mailbox if it is not yet open */ if ((ret = imap_msgpart_url_open_mailbox(mpurl, &box, &error_code, error_r)) <= 0) return ret; /* start transaction */ t = mailbox_transaction_begin(box, 0); mail = mail_alloc(t, MAIL_FETCH_MESSAGE_PARTS | MAIL_FETCH_IMAP_BODYSTRUCTURE, NULL); /* find the message */ if (!mail_set_uid(mail, mpurl->uid)) { *error_r = "Message not found"; mail_free(&mail); mailbox_transaction_rollback(&t); return 0; } mpurl->trans = t; mpurl->mail = mail; *mail_r = mail; return 1; }
static int antispam_copy(struct mailbox_transaction_context *t, struct mail *mail, enum mail_flags flags, struct mail_keywords *keywords, struct mail *dest_mail) { struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(t->box); struct antispam_transaction_context *ast = ANTISPAM_CONTEXT(t); struct mail *copy_dest_mail; int ret; bool src_trash, dst_trash; if (dest_mail != NULL) copy_dest_mail = dest_mail; else copy_dest_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE, NULL); i_assert(mail->box); asbox->save_hack = FALSE; asbox->movetype = MMT_UNINTERESTING; if (mailbox_is_unsure(t->box)) { mail_storage_set_error(t->box->storage, "Cannot copy to unsure folder"); return -1; } src_trash = mailbox_is_trash(mail->box); dst_trash = mailbox_is_trash(t->box); debug_verbose("mail copy: from trash: %d, to trash: %d\n", src_trash, dst_trash); if (!src_trash && !dst_trash) { bool src_spam = mailbox_is_spam(mail->box); bool dst_spam = mailbox_is_spam(t->box); bool src_unsu = mailbox_is_unsure(mail->box); debug_verbose("mail copy: src spam: %d, dst spam: %d," " src unsure: %d\n", src_spam, dst_spam, src_unsu); if ((src_spam || src_unsu) && !dst_spam) asbox->movetype = MMT_TO_CLEAN; else if ((!src_spam || src_unsu) && dst_spam) asbox->movetype = MMT_TO_SPAM; } if (asbox->super.copy(t, mail, flags, keywords, copy_dest_mail) < 0) return -1; /* * If copying used saving internally, we already have treated the mail */ if (asbox->save_hack || asbox->movetype == MMT_UNINTERESTING) ret = 0; else ret = backend->handle_mail(t, ast, copy_dest_mail, move_to_class(asbox->movetype)); /* * Both save_hack and movetype are only valid within a copy operation, * i.e. they are now invalid. Because, in theory, another operation * could be done after mailbox_open(), we need to reset the movetype * variable here. save_hack doesn't need to be reset because it is * only ever set within the save function and tested within this copy * function after being reset at the beginning of the copy, movetype * however is tested within the save_finish() function and a subsequent * save to the mailbox should not invoke the backend. */ asbox->movetype = MMT_APPEND; if (copy_dest_mail != dest_mail) mail_free(©_dest_mail); return ret; }
static int antispam_save_finish(struct mail_save_context *ctx, struct mail *dest_mail) { struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(ctx->transaction->box); struct antispam_transaction_context *ast = ANTISPAM_CONTEXT(ctx->transaction); struct mail *save_dest_mail; int ret; if (dest_mail != NULL) save_dest_mail = dest_mail; else save_dest_mail = mail_alloc(ctx->transaction, MAIL_FETCH_PHYSICAL_SIZE, NULL); if (asbox->super.save_finish(ctx, save_dest_mail) < 0) return -1; asbox->save_hack = TRUE; ret = 0; switch (asbox->movetype) { case MMT_UNINTERESTING: break; case MMT_APPEND: /* Disallow APPENDs to UNSURE folders. */ if (mailbox_is_unsure(save_dest_mail->box)) { ret = -1; mail_storage_set_error(save_dest_mail->box->storage, "Cannot APPEND to an UNSURE folder."); break; } else if (mailbox_is_spam(save_dest_mail->box)) { /* * The client is APPENDing a message to a SPAM folder * so we try to train the backend on it. For most of * the backends, that can only succeed if the message * contains appropriate information. * * This happens especially when offlineimap is used and * the user moved a message to the SPAM folder while * offline---offlineimap cannot reproduce the COPY but * rather APPENDs the moved message on the next sync. * * This could be a bad if the spam headers were not * generated on our server, but since the user can * always APPEND to another folder and then COPY to a * SPAM folder backends need to be prepared for cases * like this anyway. With dspam, for example, the worst * that can happen is that the APPEND fails with a * training error from dspam. * * Unfortunately, we cannot handle the cases where * (1) the user moved a message from one folder that * contains SPAM to another folder containing SPAM * (2) the user moved a message out of the SPAM folder * (3) the user recovered a message from trash * * Because of these limitations, this behaviour needs * to be enabled with an option. */ if (!antispam_can_append_to_spam) { ret = -1; mail_storage_set_error( save_dest_mail->box->storage, "Cannot APPEND to a SPAM folder."); break; } asbox->movetype = MMT_TO_SPAM; /* fall through to default case to invoke backend */ } else { /* neither UNSURE nor SPAM, regular folder */ break; } /* fall through */ default: ret = backend->handle_mail(ctx->transaction, ast, save_dest_mail, move_to_class(asbox->movetype)); } if (save_dest_mail != dest_mail) mail_free(&save_dest_mail); return ret; }
static void index_storage_virtual_size_add_new(struct mailbox *box, struct index_vsize_header *vsize_hdr) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); const struct mail_index_header *hdr; struct mailbox_transaction_context *trans; struct mail_search_context *search_ctx; struct mail_search_args *search_args; struct mail *mail; uint32_t seq1, seq2; uoff_t vsize; int ret = 0; hdr = mail_index_get_header(box->view); if (vsize_hdr->highest_uid == 0) seq2 = 0; else if (!mail_index_lookup_seq_range(box->view, 1, vsize_hdr->highest_uid, &seq1, &seq2)) seq2 = 0; if (vsize_hdr->message_count != seq2) { if (vsize_hdr->message_count < seq2) { mail_storage_set_critical(box->storage, "vsize-hdr has invalid message-count (%u < %u)", vsize_hdr->message_count, seq2); } else { /* some messages have been expunged, rescan */ } memset(vsize_hdr, 0, sizeof(*vsize_hdr)); seq2 = 0; } search_args = mail_search_build_init(); mail_search_build_add_seqset(search_args, seq2 + 1, hdr->messages_count); trans = mailbox_transaction_begin(box, 0); search_ctx = mailbox_search_init(trans, search_args, NULL); mail = mail_alloc(trans, MAIL_FETCH_VIRTUAL_SIZE, NULL); while (mailbox_search_next(search_ctx, mail)) { if (mail_get_virtual_size(mail, &vsize) < 0) { if (mail->expunged) continue; ret = -1; break; } vsize_hdr->vsize += vsize; vsize_hdr->highest_uid = mail->uid; vsize_hdr->message_count++; } mail_free(&mail); if (mailbox_search_deinit(&search_ctx) < 0) ret = -1; if (ret == 0) { /* success, cache all */ vsize_hdr->highest_uid = hdr->next_uid - 1; } else { /* search failed, cache only up to highest seen uid */ } mail_index_update_header_ext(trans->itrans, ibox->vsize_hdr_ext_id, 0, vsize_hdr, sizeof(*vsize_hdr)); (void)mailbox_transaction_commit(&trans); }
static int snarf(struct mailbox *srcbox, struct mailbox *destbox) { struct mail_search_args *search_args; struct mail_search_context *search_ctx; struct mailbox_transaction_context *src_trans, *dest_trans; struct mail_save_context *save_ctx; struct mail *mail; enum mail_error error; int ret; /* make sure the destination mailbox has been opened */ if (mailbox_open(destbox) < 0) return -1; if (mailbox_sync(srcbox, MAILBOX_SYNC_FLAG_FULL_READ) < 0) return -1; src_trans = mailbox_transaction_begin(srcbox, 0); dest_trans = mailbox_transaction_begin(destbox, MAILBOX_TRANSACTION_FLAG_EXTERNAL); search_args = mail_search_build_init(); mail_search_build_add_all(search_args); search_ctx = mailbox_search_init(src_trans, search_args, NULL); mail_search_args_unref(&search_args); ret = 0; mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY, NULL); while (mailbox_search_next(search_ctx, mail)) { if (mail->expunged) continue; save_ctx = mailbox_save_alloc(dest_trans); if (mailbox_copy(&save_ctx, mail) < 0 && !mail->expunged) { (void)mail_storage_get_last_error(destbox->storage, &error); /* if we failed because of out of disk space, just move those messages we managed to move so far. */ if (error != MAIL_ERROR_NOSPACE) ret = -1; break; } mail_expunge(mail); } mail_free(&mail); if (mailbox_search_deinit(&search_ctx) < 0) ret = -1; /* commit the copied messages to the destination mailbox. if we crash between that and between expunging the messages from the source mailbox, we're left with duplicates. */ if (ret < 0) mailbox_transaction_rollback(&dest_trans); else if (mailbox_transaction_commit(&dest_trans) < 0) ret = -1; if (ret < 0) mailbox_transaction_rollback(&src_trans); else { if (mailbox_transaction_commit(&src_trans) < 0) ret = -1; } if (ret == 0) { if (mailbox_sync(srcbox, 0) < 0) ret = -1; } return ret; }