static int virtual_config_parse_line(struct virtual_parse_context *ctx, const char *line, const char **error_r) { struct mail_user *user = ctx->mbox->storage->storage.user; struct virtual_backend_box *bbox; const char *p; bool no_wildcards = FALSE; if (*line == ' ' || *line == '\t') { /* continues the previous search rule */ if (ctx->rule_idx == array_count(&ctx->mbox->backend_boxes)) { *error_r = "Search rule without a mailbox"; return -1; } while (*line == ' ' || *line == '\t') line++; str_append_c(ctx->rule, ' '); str_append(ctx->rule, line); return 0; } /* if there is no rule yet, it means we want the previous mailboxes to use the rule that comes later */ if (str_len(ctx->rule) > 0) { if (virtual_config_add_rule(ctx, error_r) < 0) return -1; } if (!uni_utf8_str_is_valid(line)) { *error_r = t_strdup_printf("Mailbox name not UTF-8: %s", line); return -1; } /* new mailbox. the search args are added to it later. */ bbox = p_new(ctx->pool, struct virtual_backend_box, 1); bbox->virtual_mbox = ctx->mbox; if (strcasecmp(line, "INBOX") == 0) line = "INBOX"; bbox->name = p_strdup(ctx->pool, line); switch (bbox->name[0]) { case '+': bbox->name++; bbox->clear_recent = TRUE; break; case '-': bbox->name++; bbox->negative_match = TRUE; break; case '!': /* save messages here */ if (ctx->mbox->save_bbox != NULL) { *error_r = "Multiple save mailboxes defined"; return -1; } bbox->name++; ctx->mbox->save_bbox = bbox; no_wildcards = TRUE; break; } if (bbox->name[0] == '/') { /* [+-!]/metadata entry:value */ if ((p = strchr(bbox->name, ':')) == NULL) { *error_r = "':' separator missing between metadata entry name and value"; return -1; } bbox->metadata_entry = p_strdup_until(ctx->pool, bbox->name, p++); bbox->metadata_value = p; if (!imap_metadata_verify_entry_name(bbox->metadata_entry, error_r)) return -1; no_wildcards = TRUE; } if (!no_wildcards && (strchr(bbox->name, '*') != NULL || strchr(bbox->name, '%') != NULL)) { bbox->glob = imap_match_init(ctx->pool, bbox->name, TRUE, ctx->sep); ctx->have_wildcards = TRUE; } if (bbox->metadata_entry == NULL) { /* now that the prefix characters have been processed, find the namespace */ bbox->ns = strcasecmp(bbox->name, "INBOX") == 0 ? mail_namespace_find_inbox(user->namespaces) : mail_namespace_find(user->namespaces, bbox->name); if (bbox->ns == NULL) { *error_r = t_strdup_printf("Namespace not found for %s", bbox->name); return -1; } if (strcmp(bbox->name, ctx->mbox->box.vname) == 0) { *error_r = "Virtual mailbox can't point to itself"; return -1; } ctx->have_mailbox_defines = TRUE; } array_append(&ctx->mbox->backend_boxes, &bbox, 1); return 0; }
static int cmd_setmetadata_parse_entryvalue(struct imap_setmetadata_context *ctx, const char **entry_r, const struct imap_arg **value_r) { const struct imap_arg *args; const char *name, *error; int ret; bool fatal; /* parse the entry name */ ret = imap_parser_read_args(ctx->parser, 1, IMAP_PARSE_FLAG_INSIDE_LIST, &args); if (ret >= 0) { if (ret == 0) { /* ')' found */ *entry_r = NULL; return 1; } if (!imap_arg_get_astring(args, &name)) { client_send_command_error(ctx->cmd, "Entry name isn't astring"); return -1; } ret = imap_parser_read_args(ctx->parser, 2, IMAP_PARSE_FLAG_INSIDE_LIST | IMAP_PARSE_FLAG_LITERAL_SIZE | IMAP_PARSE_FLAG_LITERAL8, &args); } if (ret < 0) { if (ret == -2) return 0; error = imap_parser_get_error(ctx->parser, &fatal); if (fatal) { client_disconnect_with_error(ctx->cmd->client, error); return -1; } client_send_command_error(ctx->cmd, error); return -1; } if (args[1].type == IMAP_ARG_EOL) { client_send_command_error(ctx->cmd, "Entry value missing"); return -1; } if (args[1].type == IMAP_ARG_LIST) { client_send_command_error(ctx->cmd, "Entry value can't be a list"); return -1; } if (!ctx->cmd_error_sent && !imap_metadata_verify_entry_name(name, &error)) { client_send_command_error(ctx->cmd, error); ctx->cmd_error_sent = TRUE; } if (ctx->cmd_error_sent) { ctx->cmd->param_error = FALSE; ctx->cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT; ctx->failed = TRUE; if (args[1].type == IMAP_ARG_LITERAL_SIZE) { /* client won't see "+ OK", so we can abort immediately */ ctx->cmd->client->input_skip_line = FALSE; return -1; } } /* entry names are case-insensitive. handle this by using only lowercase names. */ *entry_r = t_str_lcase(name); *value_r = &args[1]; return 1; }