1
/* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */
1
/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
7
#include "write-full.h"
4
8
#include "mail-namespace.h"
5
9
#include "mail-storage.h"
6
10
#include "mail-search-build.h"
11
#include "doveadm-settings.h"
7
12
#include "doveadm-mail.h"
16
#define INDEXER_SOCKET_NAME "indexer"
17
#define INDEXER_HANDSHAKE "VERSION\tindexer\t1\t0\n"
19
struct index_cmd_context {
20
struct doveadm_mail_cmd_context ctx;
23
unsigned int max_recent_msgs;
25
unsigned int have_wildcards:1;
28
static int cmd_index_box_precache(struct mailbox *box)
30
struct mailbox_status status;
31
struct mailbox_transaction_context *trans;
32
struct mail_search_args *search_args;
33
struct mail_search_context *ctx;
35
struct mailbox_metadata metadata;
37
unsigned int counter = 0, max;
40
if (mailbox_get_metadata(box, MAILBOX_METADATA_PRECACHE_FIELDS,
43
mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_LAST_CACHED_SEQ,
46
seq = status.last_cached_seq + 1;
47
if (seq > status.messages) {
48
if (doveadm_verbose) {
49
i_info("%s: Cache is already up to date",
50
mailbox_get_vname(box));
54
if (doveadm_verbose) {
55
i_info("%s: Caching mails seq=%u..%u",
56
mailbox_get_vname(box), seq, status.messages);
59
trans = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_NO_CACHE_DEC);
60
search_args = mail_search_build_init();
61
mail_search_build_add_seqset(search_args, seq, status.messages);
62
ctx = mailbox_search_init(trans, search_args, NULL,
63
metadata.precache_fields, NULL);
64
mail_search_args_unref(&search_args);
66
max = status.messages - seq + 1;
67
while (mailbox_search_next(ctx, &mail)) {
69
if (doveadm_verbose && ++counter % 100 == 0) {
70
printf("\r%u/%u", counter, max);
75
printf("\r%u/%u\n", counter, max);
76
if (mailbox_search_deinit(&ctx) < 0)
78
if (mailbox_transaction_commit(&trans) < 0)
10
cmd_index_box(const struct mailbox_info *info)
84
cmd_index_box(struct index_cmd_context *ctx, const struct mailbox_info *info)
12
86
struct mailbox *box;
13
const char *storage_name;
87
struct mailbox_status status;
16
storage_name = mail_namespace_get_storage_name(info->ns, info->name);
17
box = mailbox_alloc(info->ns->list, storage_name,
18
MAILBOX_FLAG_KEEP_RECENT |
90
box = mailbox_alloc(info->ns->list, info->name,
19
91
MAILBOX_FLAG_IGNORE_ACLS);
21
if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ |
22
MAILBOX_SYNC_FLAG_PRECACHE) < 0) {
92
if (ctx->max_recent_msgs != 0) {
93
/* index only if there aren't too many recent messages.
94
don't bother syncing the mailbox, that alone can take a
95
while with large maildirs. */
96
if (mailbox_open(box) < 0) {
97
i_error("Opening mailbox %s failed: %s", info->name,
98
mail_storage_get_last_error(mailbox_get_storage(box), NULL));
99
doveadm_mail_failed_mailbox(&ctx->ctx, box);
104
mailbox_get_open_status(box, STATUS_RECENT, &status);
105
if (status.recent > ctx->max_recent_msgs) {
111
if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
23
112
i_error("Syncing mailbox %s failed: %s", info->name,
24
113
mail_storage_get_last_error(mailbox_get_storage(box), NULL));
114
doveadm_mail_failed_mailbox(&ctx->ctx, box);
117
if (cmd_index_box_precache(box) < 0) {
118
doveadm_mail_failed_mailbox(&ctx->ctx, box);
28
122
mailbox_free(&box);
33
cmd_index_run(struct doveadm_mail_cmd_context *ctx, struct mail_user *user)
126
static void index_queue_connect(struct index_cmd_context *ctx)
130
path = t_strconcat(doveadm_settings->base_dir,
131
"/"INDEXER_SOCKET_NAME, NULL);
132
ctx->queue_fd = net_connect_unix(path);
133
if (ctx->queue_fd == -1)
134
i_fatal("net_connect_unix(%s) failed: %m", path);
135
if (write_full(ctx->queue_fd, INDEXER_HANDSHAKE,
136
strlen(INDEXER_HANDSHAKE)) < 0)
137
i_fatal("write(indexer) failed: %m");
140
static void cmd_index_queue(struct index_cmd_context *ctx,
141
struct mail_user *user, const char *mailbox)
143
if (ctx->queue_fd == -1)
144
index_queue_connect(ctx);
147
string_t *str = t_str_new(256);
149
str_append(str, "APPEND\t0\t");
150
str_tabescape_write(str, user->username);
151
str_append_c(str, '\t');
152
str_tabescape_write(str, mailbox);
153
str_printfa(str, "\t%u\n", ctx->max_recent_msgs);
154
if (write_full(ctx->queue_fd, str_data(str), str_len(str)) < 0)
155
i_fatal("write(indexer) failed: %m");
160
cmd_index_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
162
struct index_cmd_context *ctx = (struct index_cmd_context *)_ctx;
35
163
const enum mailbox_list_iter_flags iter_flags =
36
164
MAILBOX_LIST_ITER_RAW_LIST |
37
MAILBOX_LIST_ITER_NO_AUTO_INBOX |
165
MAILBOX_LIST_ITER_NO_AUTO_BOXES |
38
166
MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
39
167
MAILBOX_LIST_ITER_STAR_WITHIN_NS;
40
168
const enum namespace_type ns_mask =
41
169
NAMESPACE_PRIVATE | NAMESPACE_SHARED | NAMESPACE_PUBLIC;
42
170
struct mailbox_list_iterate_context *iter;
43
171
const struct mailbox_info *info;
45
iter = mailbox_list_iter_init_namespaces(user->namespaces, ctx->args,
175
if (ctx->queue && !ctx->have_wildcards) {
176
/* we can do this quickly without going through the mailboxes */
177
for (i = 0; _ctx->args[i] != NULL; i++)
178
cmd_index_queue(ctx, user, _ctx->args[i]);
182
iter = mailbox_list_iter_init_namespaces(user->namespaces, _ctx->args,
46
183
ns_mask, iter_flags);
47
184
while ((info = mailbox_list_iter_next(iter)) != NULL) {
48
185
if ((info->flags & (MAILBOX_NOSELECT |
49
186
MAILBOX_NONEXISTENT)) == 0) T_BEGIN {
50
(void)cmd_index_box(info);
188
cmd_index_queue(ctx, user, info->name);
190
if (cmd_index_box(ctx, info) < 0)
53
if (mailbox_list_iter_deinit(&iter) < 0)
195
if (mailbox_list_iter_deinit(&iter) < 0) {
54
196
i_error("Listing mailboxes failed");
197
doveadm_mail_failed_error(_ctx, MAIL_ERROR_TEMP);
57
static void cmd_index_init(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED,
203
static void cmd_index_init(struct doveadm_mail_cmd_context *_ctx,
58
204
const char *const args[])
206
struct index_cmd_context *ctx = (struct index_cmd_context *)_ctx;
60
209
if (args[0] == NULL)
61
210
doveadm_mail_help_name("index");
211
for (i = 0; args[i] != NULL; i++) {
212
if (strchr(args[i], '*') != NULL ||
213
strchr(args[i], '%') != NULL) {
214
ctx->have_wildcards = TRUE;
220
static void cmd_index_deinit(struct doveadm_mail_cmd_context *_ctx)
222
struct index_cmd_context *ctx = (struct index_cmd_context *)_ctx;
224
if (ctx->queue_fd != -1) {
225
net_disconnect(ctx->queue_fd);
231
cmd_index_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c)
233
struct index_cmd_context *ctx = (struct index_cmd_context *)_ctx;
240
if (str_to_uint(optarg, &ctx->max_recent_msgs) < 0) {
241
i_fatal_status(EX_USAGE,
242
"Invalid -n parameter number: %s", optarg);
64
251
static struct doveadm_mail_cmd_context *cmd_index_alloc(void)
66
struct doveadm_mail_cmd_context *ctx;
253
struct index_cmd_context *ctx;
68
ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context);
69
ctx->v.init = cmd_index_init;
70
ctx->v.run = cmd_index_run;
255
ctx = doveadm_mail_cmd_alloc(struct index_cmd_context);
257
ctx->ctx.getopt_args = "qn:";
258
ctx->ctx.v.parse_arg = cmd_index_parse_arg;
259
ctx->ctx.v.init = cmd_index_init;
260
ctx->ctx.v.deinit = cmd_index_deinit;
261
ctx->ctx.v.run = cmd_index_run;
74
265
struct doveadm_mail_cmd cmd_index = {
75
cmd_index_alloc, "index", "<mailbox mask>"
266
cmd_index_alloc, "index", "[-q] [-n <max recent>] <mailbox mask>"