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); }
bool cmd_fetch(struct client_command_context *cmd) { struct client *client = cmd->client; struct imap_fetch_context *ctx; const struct imap_arg *args, *next_arg, *list_arg; struct mail_search_args *search_args; struct imap_fetch_qresync_args qresync_args; const char *messageset; bool send_vanished = FALSE; int ret; if (!client_read_args(cmd, 0, 0, &args)) return FALSE; if (!client_verify_open_mailbox(cmd)) return TRUE; /* <messageset> <field(s)> [(modifiers)] */ if (!imap_arg_get_atom(&args[0], &messageset) || (args[1].type != IMAP_ARG_LIST && args[1].type != IMAP_ARG_ATOM) || (!IMAP_ARG_IS_EOL(&args[2]) && args[2].type != IMAP_ARG_LIST)) { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } /* UID FETCH VANISHED needs the uidset, so convert it to sequence set later */ ret = imap_search_get_anyset(cmd, messageset, cmd->uid, &search_args); if (ret <= 0) return ret < 0; ctx = imap_fetch_alloc(client, cmd->pool); if (!fetch_parse_args(ctx, cmd, &args[1], &next_arg) || (imap_arg_get_list(next_arg, &list_arg) && !fetch_parse_modifiers(ctx, cmd, search_args, list_arg, &send_vanished))) { imap_fetch_free(&ctx); mail_search_args_unref(&search_args); return TRUE; } if (send_vanished) { memset(&qresync_args, 0, sizeof(qresync_args)); if (imap_fetch_send_vanished(client, client->mailbox, search_args, &qresync_args) < 0) { mail_search_args_unref(&search_args); return cmd_fetch_finish(ctx, cmd); } } imap_fetch_begin(ctx, client->mailbox, search_args); mail_search_args_unref(&search_args); if (imap_fetch_more(ctx, cmd) == 0) { /* unfinished */ cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT; cmd->func = cmd_fetch_continue; cmd->context = ctx; return FALSE; } return cmd_fetch_finish(ctx, cmd); }