struct mail_search_sort_program * index_sort_program_init(struct mailbox_transaction_context *t, const enum mail_sort_type *sort_program) { struct mail_search_sort_program *program; unsigned int i; if (sort_program == NULL || sort_program[0] == MAIL_SORT_END) return NULL; /* we support internal sorting by the primary condition */ program = i_new(struct mail_search_sort_program, 1); program->t = t; program->temp_mail = mail_alloc(t, 0, NULL); for (i = 0; i < MAX_SORT_PROGRAM_SIZE; i++) { program->sort_program[i] = sort_program[i]; if (sort_program[i] == MAIL_SORT_END) break; } if (i == MAX_SORT_PROGRAM_SIZE) i_panic("index_sort_program_init(): Invalid sort program"); switch (program->sort_program[0] & MAIL_SORT_MASK) { case MAIL_SORT_ARRIVAL: case MAIL_SORT_DATE: { ARRAY_TYPE(mail_sort_node_date) *nodes; nodes = i_malloc(sizeof(*nodes)); i_array_init(nodes, 128); if ((program->sort_program[0] & MAIL_SORT_MASK) == MAIL_SORT_ARRIVAL) program->sort_list_add = index_sort_list_add_arrival; else program->sort_list_add = index_sort_list_add_date; program->sort_list_finish = index_sort_list_finish_date; program->context = nodes; break; } case MAIL_SORT_SIZE: { ARRAY_TYPE(mail_sort_node_size) *nodes; nodes = i_malloc(sizeof(*nodes)); i_array_init(nodes, 128); program->sort_list_add = index_sort_list_add_size; program->sort_list_finish = index_sort_list_finish_size; program->context = nodes; break; } case MAIL_SORT_CC: case MAIL_SORT_FROM: case MAIL_SORT_SUBJECT: case MAIL_SORT_TO: case MAIL_SORT_DISPLAYFROM: case MAIL_SORT_DISPLAYTO: program->sort_list_add = index_sort_list_add_string; program->sort_list_finish = index_sort_list_finish_string; index_sort_list_init_string(program); break; case MAIL_SORT_RELEVANCY: { ARRAY_TYPE(mail_sort_node_float) *nodes; nodes = i_malloc(sizeof(*nodes)); i_array_init(nodes, 128); program->sort_list_add = index_sort_list_add_relevancy; program->sort_list_finish = index_sort_list_finish_float; program->context = nodes; break; } case MAIL_SORT_POP3_ORDER: { ARRAY_TYPE(mail_sort_node_size) *nodes; nodes = i_malloc(sizeof(*nodes)); i_array_init(nodes, 128); program->sort_list_add = index_sort_list_add_pop3_order; program->sort_list_finish = index_sort_list_finish_size; program->context = nodes; break; } default: i_unreached(); } return program; }
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; }
struct maildir_filename * maildir_save_add(struct mail_save_context *_ctx, const char *tmp_fname, struct mail *src_mail) { struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx; struct mail_save_data *mdata = &_ctx->data; struct maildir_filename *mf; struct istream *input; unsigned int keyword_count; i_assert(*tmp_fname != '\0'); /* allow caller to specify recent flag only when uid is specified (we're replicating, converting, etc.). */ if (mdata->uid == 0) mdata->flags |= MAIL_RECENT; else if ((mdata->flags & MAIL_RECENT) == 0 && ctx->last_nonrecent_uid < mdata->uid) ctx->last_nonrecent_uid = mdata->uid; /* now, we want to be able to rollback the whole append session, so we'll just store the name of this temp file and move it later into new/ or cur/. */ /* @UNSAFE */ keyword_count = mdata->keywords == NULL ? 0 : mdata->keywords->count; mf = p_malloc(ctx->pool, sizeof(*mf) + sizeof(unsigned int) * keyword_count); mf->tmp_name = mf->dest_basename = p_strdup(ctx->pool, tmp_fname); mf->flags = mdata->flags; mf->size = (uoff_t)-1; mf->vsize = (uoff_t)-1; ctx->file_last = mf; i_assert(*ctx->files_tail == NULL); *ctx->files_tail = mf; ctx->files_tail = &mf->next; ctx->files_count++; if (mdata->keywords != NULL) { /* @UNSAFE */ mf->keywords_count = keyword_count; memcpy(mf + 1, mdata->keywords->idx, sizeof(unsigned int) * keyword_count); ctx->have_keywords = TRUE; } if (mdata->pop3_uidl != NULL) mf->pop3_uidl = p_strdup(ctx->pool, mdata->pop3_uidl); mf->pop3_order = mdata->pop3_order; /* insert into index */ mail_index_append(ctx->trans, mdata->uid, &ctx->seq); mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, mdata->flags & ~MAIL_RECENT); if (mdata->keywords != NULL) { mail_index_update_keywords(ctx->trans, ctx->seq, MODIFY_REPLACE, mdata->keywords); } if (mdata->min_modseq != 0) { mail_index_update_modseq(ctx->trans, ctx->seq, mdata->min_modseq); } if (ctx->first_seq == 0) { ctx->first_seq = ctx->seq; i_assert(ctx->files->next == NULL); } if (_ctx->dest_mail == NULL) { if (ctx->mail == NULL) ctx->mail = mail_alloc(_ctx->transaction, 0, NULL); _ctx->dest_mail = ctx->mail; } mail_set_seq_saving(_ctx->dest_mail, ctx->seq); if (ctx->input == NULL) { /* copying with hardlinking. */ i_assert(src_mail != NULL); index_copy_cache_fields(_ctx, src_mail, ctx->seq); ctx->cur_dest_mail = NULL; } else { input = index_mail_cache_parse_init(_ctx->dest_mail, ctx->input); i_stream_unref(&ctx->input); ctx->input = input; ctx->cur_dest_mail = _ctx->dest_mail; } return mf; }