24
fetch_parse_args(struct imap_fetch_context *ctx, const struct imap_arg *arg,
25
const struct imap_arg **next_arg_r)
24
imap_fetch_cmd_init_handler(struct imap_fetch_context *ctx,
25
struct client_command_context *cmd,
26
const char *name, const struct imap_arg **args)
28
struct imap_fetch_init_context init_ctx;
30
memset(&init_ctx, 0, sizeof(init_ctx));
31
init_ctx.fetch_ctx = ctx;
32
init_ctx.pool = ctx->ctx_pool;
34
init_ctx.args = *args;
36
if (!imap_fetch_init_handler(&init_ctx)) {
37
i_assert(init_ctx.error != NULL);
38
client_send_command_error(cmd, init_ctx.error);
41
*args = init_ctx.args;
46
fetch_parse_args(struct imap_fetch_context *ctx,
47
struct client_command_context *cmd,
48
const struct imap_arg *arg, const struct imap_arg **next_arg_r)
27
50
const char *str, *const *macro;
30
if (!imap_fetch_init_handler(ctx, "UID", &arg))
53
if (!imap_fetch_cmd_init_handler(ctx, cmd, "UID", &arg))
33
56
if (imap_arg_get_atom(arg, &str)) {
58
81
*next_arg_r = arg + 1;
59
82
arg = imap_arg_as_list(arg);
60
83
if (IMAP_ARG_IS_EOL(arg)) {
61
client_send_command_error(ctx->cmd,
84
client_send_command_error(cmd,
62
85
"FETCH list is empty.");
65
88
while (imap_arg_get_atom(arg, &str)) {
66
89
str = t_str_ucase(str);
68
if (!imap_fetch_init_handler(ctx, str, &arg))
91
if (!imap_fetch_cmd_init_handler(ctx, cmd, str, &arg))
71
94
if (!IMAP_ARG_IS_EOL(arg)) {
72
client_send_command_error(ctx->cmd,
95
client_send_command_error(cmd,
73
96
"FETCH list contains non-atoms.");
87
113
if (strcmp(name, "CHANGEDSINCE") == 0) {
88
114
if (!imap_arg_get_atom(*args, &str) ||
89
115
str_to_uint64(str, &modseq) < 0) {
90
client_send_command_error(ctx->cmd,
116
client_send_command_error(cmd,
91
117
"Invalid CHANGEDSINCE modseq.");
95
return imap_fetch_add_changed_since(ctx, modseq);
121
imap_search_add_changed_since(search_args, modseq);
122
imap_fetch_init_nofail_handler(ctx, imap_fetch_modseq_init);
97
if (strcmp(name, "VANISHED") == 0 && ctx->cmd->uid) {
125
if (strcmp(name, "VANISHED") == 0 && cmd->uid) {
98
126
if ((ctx->client->enabled_features &
99
127
MAILBOX_FEATURE_QRESYNC) == 0) {
100
client_send_command_error(ctx->cmd,
101
"QRESYNC not enabled");
128
client_send_command_error(cmd, "QRESYNC not enabled");
104
ctx->send_vanished = TRUE;
131
*send_vanished = TRUE;
108
client_send_command_error(ctx->cmd, "Unknown FETCH modifier");
135
client_send_command_error(cmd, "Unknown FETCH modifier");
113
140
fetch_parse_modifiers(struct imap_fetch_context *ctx,
114
const struct imap_arg *args)
141
struct client_command_context *cmd,
142
struct mail_search_args *search_args,
143
const struct imap_arg *args, bool *send_vanished_r)
116
145
const char *name;
147
*send_vanished_r = FALSE;
118
149
while (!IMAP_ARG_IS_EOL(args)) {
119
150
if (!imap_arg_get_atom(args, &name)) {
120
client_send_command_error(ctx->cmd,
151
client_send_command_error(cmd,
121
152
"FETCH modifiers contain non-atoms.");
125
if (!fetch_parse_modifier(ctx, t_str_ucase(name), &args))
156
if (!fetch_parse_modifier(ctx, cmd, search_args,
158
&args, send_vanished_r))
128
if (ctx->send_vanished &&
129
(ctx->search_args->args->next == NULL ||
130
ctx->search_args->args->next->type != SEARCH_MODSEQ)) {
131
client_send_command_error(ctx->cmd,
161
if (*send_vanished_r &&
162
(search_args->args->next == NULL ||
163
search_args->args->next->type != SEARCH_MODSEQ)) {
164
client_send_command_error(cmd,
132
165
"VANISHED used without CHANGEDSINCE");
138
static bool cmd_fetch_finish(struct imap_fetch_context *ctx)
171
static bool cmd_fetch_finish(struct imap_fetch_context *ctx,
172
struct client_command_context *cmd)
140
174
static const char *ok_message = "OK Fetch completed.";
141
struct client_command_context *cmd = ctx->cmd;
142
175
const char *tagged_reply = ok_message;
176
enum mail_error error;
177
bool failed, seen_flags_changed = ctx->state.seen_flags_changed;
144
if (ctx->partial_fetch) {
179
if (ctx->state.skipped_expunged_msgs) {
145
180
tagged_reply = "OK ["IMAP_RESP_CODE_EXPUNGEISSUED"] "
146
181
"Some messages were already expunged.";
149
if (imap_fetch_deinit(ctx) < 0)
184
failed = imap_fetch_end(ctx) < 0;
185
imap_fetch_free(&ctx);
153
188
const char *errstr;
155
if (ctx->client->output->closed) {
190
if (cmd->client->output->closed) {
156
191
client_disconnect(cmd->client, "Disconnected");
160
errstr = mailbox_get_last_error(cmd->client->mailbox, NULL);
162
/* We never want to reply NO to FETCH requests,
163
BYE is preferrable (see imap-ml for reasons). */
164
client_disconnect_with_error(cmd->client, errstr);
195
errstr = mailbox_get_last_error(cmd->client->mailbox, &error);
196
if (error == MAIL_ERROR_CONVERSION) {
197
/* BINARY found unsupported Content-Transfer-Encoding */
198
tagged_reply = t_strdup_printf(
199
"NO ["IMAP_RESP_CODE_UNKNOWN_CTE"] %s", errstr);
201
/* We never want to reply NO to FETCH requests,
202
BYE is preferrable (see imap-ml for reasons). */
203
client_disconnect_with_error(cmd->client, errstr);
168
208
return cmd_sync(cmd,
169
(ctx->seen_flags_changed ? 0 : MAILBOX_SYNC_FLAG_FAST) |
209
(seen_flags_changed ? 0 : MAILBOX_SYNC_FLAG_FAST) |
170
210
(cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES), 0,
214
ctx = imap_fetch_init(cmd, client->mailbox);
256
ctx = imap_fetch_alloc(client, cmd->pool);
258
if (!fetch_parse_args(ctx, cmd, &args[1], &next_arg) ||
259
(imap_arg_get_list(next_arg, &list_arg) &&
260
!fetch_parse_modifiers(ctx, cmd, search_args, list_arg,
262
imap_fetch_free(&ctx);
216
263
mail_search_args_unref(&search_args);
219
ctx->search_args = search_args;
221
if (!fetch_parse_args(ctx, &args[1], &next_arg) ||
222
(imap_arg_get_list(next_arg, &list_arg) &&
223
!fetch_parse_modifiers(ctx, list_arg))) {
224
imap_fetch_deinit(ctx);
228
if (imap_fetch_begin(ctx) == 0) {
229
if (imap_fetch_more(ctx) == 0) {
231
cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
233
cmd->func = cmd_fetch_continue;
268
memset(&qresync_args, 0, sizeof(qresync_args));
269
if (imap_fetch_send_vanished(client, client->mailbox,
270
search_args, &qresync_args) < 0) {
271
mail_search_args_unref(&search_args);
272
return cmd_fetch_finish(ctx, cmd);
238
return cmd_fetch_finish(ctx);
276
imap_fetch_begin(ctx, client->mailbox, search_args);
277
mail_search_args_unref(&search_args);
279
if (imap_fetch_more(ctx, cmd) == 0) {
281
cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
283
cmd->func = cmd_fetch_continue;
287
return cmd_fetch_finish(ctx, cmd);