int mail_set_attachment_keywords(struct mail *mail) { int ret; const struct mail_storage_settings *mail_set = mail_storage_get_settings(mailbox_get_storage(mail->box)); const char *const keyword_has_attachment[] = { MAIL_KEYWORD_HAS_ATTACHMENT, NULL, }; const char *const keyword_has_no_attachment[] = { MAIL_KEYWORD_HAS_NO_ATTACHMENT, NULL }; struct message_part_attachment_settings set = { .content_type_filter = mail_set->parsed_mail_attachment_content_type_filter, .exclude_inlined = mail_set->parsed_mail_attachment_exclude_inlined, }; struct mail_keywords *kw_has = NULL, *kw_has_not = NULL; /* walk all parts and see if there is an attachment */ struct message_part *parts; if (mail_get_parts(mail, &parts) < 0) { mail_set_critical(mail, "Failed to add attachment keywords: " "mail_get_parts() failed: %s", mail_storage_get_last_internal_error(mail->box->storage, NULL)); ret = -1; } else if (parts->data == NULL && mail_parse_parts(mail, &parts) < 0) { ret = -1; } else if (mailbox_keywords_create(mail->box, keyword_has_attachment, &kw_has) < 0 || mailbox_keywords_create(mail->box, keyword_has_no_attachment, &kw_has_not) < 0) { mail_set_critical(mail, "Failed to add attachment keywords: " "mailbox_keywords_create(%s) failed: %s", mailbox_get_vname(mail->box), mail_storage_get_last_internal_error(mail->box->storage, NULL)); ret = -1; } else { bool has_attachment = mail_message_has_attachment(parts, &set); /* make sure only one of the keywords gets set */ mail_update_keywords(mail, MODIFY_REMOVE, has_attachment ? kw_has_not : kw_has); mail_update_keywords(mail, MODIFY_ADD, has_attachment ? kw_has : kw_has_not); ret = has_attachment ? 1 : 0; } if (kw_has != NULL) mailbox_keywords_unref(&kw_has); if (kw_has_not != NULL) mailbox_keywords_unref(&kw_has_not); return ret; }
static int cmd_flags_run_box(struct flags_cmd_context *ctx, const struct mailbox_info *info) { struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; struct mail_keywords *kw = NULL; if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, 0, NULL, &iter) < 0) return -1; box = doveadm_mail_iter_get_mailbox(iter); if (ctx->keywords != NULL) { if (mailbox_keywords_create(box, ctx->keywords, &kw) < 0) { i_error("Invalid keywords: %s", mailbox_get_last_error(box, NULL)); (void)doveadm_mail_iter_deinit(&iter); ctx->ctx.exit_code = DOVEADM_EX_NOTPOSSIBLE; return -1; } } while (doveadm_mail_iter_next(iter, &mail)) { mail_update_flags(mail, ctx->modify_type, ctx->flags); if (kw != NULL) mail_update_keywords(mail, ctx->modify_type, kw); } if (kw != NULL) mailbox_keywords_unref(&kw); return doveadm_mail_iter_deinit(&iter); }
static bool store_parse_args(struct imap_store_context *ctx, const struct imap_arg *args) { struct client_command_context *cmd = ctx->cmd; const struct imap_arg *list_args; const char *type; const char *const *keywords_list = NULL; ctx->max_modseq = (uint64_t)-1; if (imap_arg_get_list(args, &list_args)) { if (!store_parse_modifiers(ctx, list_args)) return FALSE; args++; } if (!imap_arg_get_astring(args, &type) || !get_modify_type(ctx, type)) { client_send_command_error(cmd, "Invalid arguments."); return FALSE; } args++; if (imap_arg_get_list(args, &list_args)) { if (!client_parse_mail_flags(cmd, list_args, &ctx->flags, &keywords_list)) return FALSE; } else { if (!client_parse_mail_flags(cmd, args, &ctx->flags, &keywords_list)) return FALSE; } if (keywords_list != NULL || ctx->modify_type == MODIFY_REPLACE) { if (mailbox_keywords_create(cmd->client->mailbox, keywords_list, &ctx->keywords) < 0) { /* invalid keywords */ client_send_box_error(cmd, cmd->client->mailbox); return FALSE; } } return TRUE; }
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; } }