static bool catenate_args_can_stop(struct cmd_append_context *ctx, const struct imap_arg *args) { /* eat away literal_sizes from URLs */ while (args->type != IMAP_ARG_EOL) { if (imap_arg_atom_equals(args, "TEXT")) return TRUE; if (!imap_arg_atom_equals(args, "URL")) { /* error - handle it later */ return TRUE; } args++; if (args->type == IMAP_ARG_LITERAL_SIZE || args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC) { if (args->type == IMAP_ARG_LITERAL_SIZE) { if (!cmd_append_send_literal_continue(ctx)) return TRUE; } imap_parser_read_last_literal(ctx->save_parser); return FALSE; } args++; } return TRUE; }
static bool cmd_append_args_can_stop(struct cmd_append_context *ctx, const struct imap_arg *args, bool *last_literal_r) { const struct imap_arg *cat_list; *last_literal_r = FALSE; if (args->type == IMAP_ARG_EOL) return TRUE; /* [(flags)] ["internal date"] <message literal> | CATENATE (..) */ if (args->type == IMAP_ARG_LIST) args++; if (args->type == IMAP_ARG_STRING) args++; if (args->type == IMAP_ARG_LITERAL_SIZE || args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC) return TRUE; if (imap_arg_atom_equals(args, "CATENATE") && imap_arg_get_list(&args[1], &cat_list)) { if (catenate_args_can_stop(ctx, cat_list)) return TRUE; *last_literal_r = TRUE; } return FALSE; }
bool cmd_search(struct client_command_context *cmd) { struct imap_search_context *ctx; struct mail_search_args *sargs; const struct imap_arg *args; const char *charset; int ret; if (!client_read_args(cmd, 0, 0, &args)) return FALSE; if (!client_verify_open_mailbox(cmd)) return TRUE; ctx = p_new(cmd->pool, struct imap_search_context, 1); ctx->cmd = cmd; if ((ret = cmd_search_parse_return_if_found(ctx, &args)) <= 0) { /* error / waiting for unambiguity */ return ret < 0; } if (imap_arg_atom_equals(args, "CHARSET")) { /* CHARSET specified */ if (!imap_arg_get_astring(&args[1], &charset)) { client_send_command_error(cmd, "Invalid charset argument."); imap_search_context_free(ctx); return TRUE; } args += 2; } else { charset = "UTF-8"; } ret = imap_search_args_build(cmd, args, charset, &sargs); if (ret <= 0) { imap_search_context_free(ctx); return ret < 0; } return imap_search_start(ctx, sargs, NULL); }
static int cmd_append_handle_args(struct client_command_context *cmd, const struct imap_arg *args, bool *nonsync_r) { struct client *client = cmd->client; struct cmd_append_context *ctx = cmd->context; const struct imap_arg *flags_list; const struct imap_arg *cat_list = NULL; enum mail_flags flags; const char *const *keywords_list; struct mail_keywords *keywords; struct istream *input; const char *internal_date_str; time_t internal_date; int ret, timezone_offset; bool valid; /* [<flags>] */ if (!imap_arg_get_list(args, &flags_list)) flags_list = NULL; else args++; /* [<internal date>] */ if (args->type != IMAP_ARG_STRING) internal_date_str = NULL; else { internal_date_str = imap_arg_as_astring(args); args++; } /* <message literal> | CATENATE (..) */ valid = FALSE; *nonsync_r = FALSE; ctx->catenate = FALSE; if (imap_arg_get_literal_size(args, &ctx->literal_size)) { *nonsync_r = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC; ctx->binary_input = args->literal8; valid = TRUE; } else if (!imap_arg_atom_equals(args, "CATENATE")) { /* invalid */ } else if (!imap_arg_get_list(++args, &cat_list)) { /* invalid */ } else { valid = TRUE; ctx->catenate = TRUE; /* We'll do BINARY conversion only if the CATENATE's first part is a literal8. If it doesn't and a literal8 is seen later we'll abort the append with UNKNOWN-CTE. */ ctx->binary_input = imap_arg_atom_equals(&cat_list[0], "TEXT") && cat_list[1].literal8; } if (!IMAP_ARG_IS_EOL(&args[1])) valid = FALSE; if (!valid) { client->input_skip_line = TRUE; if (!ctx->failed) client_send_command_error(cmd, "Invalid arguments."); return -1; } if (flags_list == NULL || ctx->failed) { flags = 0; keywords = NULL; } else { if (!client_parse_mail_flags(cmd, flags_list, &flags, &keywords_list)) return -1; if (keywords_list == NULL) keywords = NULL; else if (mailbox_keywords_create(ctx->box, keywords_list, &keywords) < 0) { /* invalid keywords - delay failure */ client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; keywords = NULL; } } if (internal_date_str == NULL || ctx->failed) { /* no time given, default to now. */ internal_date = (time_t)-1; timezone_offset = 0; } else if (!imap_parse_datetime(internal_date_str, &internal_date, &timezone_offset)) { client_send_command_error(cmd, "Invalid internal date."); if (keywords != NULL) mailbox_keywords_unref(&keywords); return -1; } if (internal_date != (time_t)-1 && internal_date > ioloop_time + INTERNALDATE_MAX_FUTURE_SECS) { /* the client specified a time in the future, set it to now. */ internal_date = (time_t)-1; timezone_offset = 0; } if (cat_list != NULL) { ctx->cat_msg_size = 0; ctx->input = i_stream_create_chain(&ctx->catchain); } else { if (ctx->literal_size == 0) { /* no message data, abort */ if (!ctx->failed) { client_send_tagline(cmd, "NO Can't save a zero byte message."); ctx->failed = TRUE; } if (!*nonsync_r) { if (keywords != NULL) mailbox_keywords_unref(&keywords); return -1; } /* {0+} used. although there isn't any point in using MULTIAPPEND here and adding more messages, it is technically valid so we'll continue parsing.. */ } ctx->litinput = i_stream_create_limit(client->input, ctx->literal_size); ctx->input = ctx->litinput; i_stream_ref(ctx->input); } if (ctx->binary_input) { input = i_stream_create_binary_converter(ctx->input); i_stream_unref(&ctx->input); ctx->input = input; } if (!ctx->failed) { /* save the mail */ ctx->save_ctx = mailbox_save_alloc(ctx->t); mailbox_save_set_flags(ctx->save_ctx, flags, keywords); mailbox_save_set_received_date(ctx->save_ctx, internal_date, timezone_offset); if (mailbox_save_begin(&ctx->save_ctx, ctx->input) < 0) { /* save initialization failed */ client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } } if (keywords != NULL) mailbox_keywords_unref(&keywords); ctx->count++; if (cat_list == NULL) { /* normal APPEND */ return 1; } else if (cat_list->type == IMAP_ARG_EOL) { /* zero parts */ if (!ctx->failed) client_send_command_error(cmd, "Empty CATENATE list."); client->input_skip_line = TRUE; return -1; } else if ((ret = cmd_append_catenate(cmd, cat_list, nonsync_r)) < 0) { /* invalid parameters, abort immediately */ return -1; } else if (ret == 0) { /* CATENATE consisted only of URLs */ return 0; } else { /* TEXT part found from CATENATE */ return 1; } }