return ret < 0;
ctx = imap_fetch_alloc(client, cmd->pool,
- imap_client_command_get_reason(cmd));
+ imap_client_command_get_reason(cmd), cmd->utf8);
if (!fetch_parse_args(ctx, cmd, &args[1], &next_arg) ||
(imap_arg_get_list(next_arg, &list_arg) &&
if (ctx->box == NULL) {
/* server metadata reply */
str_append(str, "\"\"");
+ } else if (ctx->cmd->utf8) {
+ imap_append_astring(str, mailbox_get_vname(ctx->box), FALSE);
} else {
if (imap_utf8_to_utf7(mailbox_get_vname(ctx->box), mailbox_mutf7) < 0)
i_unreached();
continue;
}
- str_truncate(mutf7_name, 0);
- if (imap_utf8_to_utf7(name, mutf7_name) < 0)
- i_panic("LIST: Mailbox name not UTF-8: %s", name);
+ if (!cmd->utf8) {
+ str_truncate(mutf7_name, 0);
+ if (imap_utf8_to_utf7(name, mutf7_name) < 0)
+ i_panic("LIST: Mailbox name not UTF-8: %s", name);
+ name = str_c(mutf7_name);
+ }
str_truncate(str, 0);
str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
list_reply_append_ns_sep_param(str,
mail_namespace_get_sep(info->ns));
str_append_c(str, ' ');
- imap_append_astring(str, str_c(mutf7_name), 0);
+ imap_append_astring(str, name, 0);
mailbox_childinfo2str(ctx, str, flags);
/* send LIST/LSUB response */
/* send optional responses (if any) */
if (list_has_options(ctx)) {
struct imap_list_return_flag_params params = {
- .name = name,
- .mutf7_name = str_c(mutf7_name),
+ .name = info->vname,
+ .mutf7_name = name,
.mbox_flags = flags,
.list_flags = ctx->list_flags,
};
ctx->list_flags);
}
-static void cmd_list_ref_root(struct client *client, const char *ref)
+static void cmd_list_ref_root(struct client *client, const char *ref, bool utf8)
{
struct mail_namespace *ns;
const char *ns_prefix;
Otherwise we'll emulate UW-IMAP behavior. */
ns = mail_namespace_find_visible(client->user->namespaces, ref);
if (ns != NULL) {
- ns_prefix = ns_prefix_mutf7(ns);
+ if (utf8)
+ ns_prefix = ns->prefix;
+ else
+ ns_prefix = ns_prefix_mutf7(ns);
ns_sep = mail_namespace_get_sep(ns);
} else {
ns_prefix = "";
return TRUE;
}
str = t_str_new(64);
- if (imap_utf7_to_utf8(ref, str) == 0)
+ if (cmd->utf8) {
+ if (!uni_utf8_str_is_valid(ref))
+ invalid_ref = TRUE;
+ } else if (imap_utf7_to_utf8(ref, str) == 0) {
ref = p_strdup(cmd->pool, str_c(str));
- else
+ } else {
invalid_ref = TRUE;
+ }
str_truncate(str, 0);
if (imap_arg_get_list_full(&args[1], &list_args, &arg_count)) {
"Invalid pattern list.");
return TRUE;
}
- if (imap_utf7_to_utf8(pattern, str) == 0) {
+ if (cmd->utf8) {
+ if (uni_utf8_str_is_valid(pattern))
+ array_push_back(&patterns, &pattern);
+ } else if (imap_utf7_to_utf8(pattern, str) == 0) {
pattern = p_strdup(cmd->pool, str_c(str));
array_push_back(&patterns, &pattern);
}
return TRUE;
}
p_array_init(&patterns, cmd->pool, 1);
- if (imap_utf7_to_utf8(pattern, str) == 0) {
+ if (cmd->utf8) {
+ if (uni_utf8_str_is_valid(pattern))
+ array_push_back(&patterns, &pattern);
+ } else if (imap_utf7_to_utf8(pattern, str) == 0) {
pattern = p_strdup(cmd->pool, str_c(str));
array_push_back(&patterns, &pattern);
}
array_append_zero(&patterns); /* NULL-terminate */
patterns_strarr = array_front(&patterns);
- if (invalid_ref || patterns_strarr[0] == NULL ||
- (!ctx->used_listext && !lsub && *patterns_strarr[0] == '\0')) {
- /* Only LIST ref "" gets us here, or invalid ref/pattern */
- cmd_list_ref_root(client, ref);
+ if (invalid_ref || patterns_strarr[0] == NULL) {
+ /* invalid ref/pattern */
+ client_send_tagline(cmd, "OK List completed.");
+ } else if (!ctx->used_listext && !lsub &&
+ *patterns_strarr[0] == '\0') {
+ /* Only LIST ref "" gets us here */
+ cmd_list_ref_root(client, ref, cmd->utf8);
client_send_tagline(cmd, "OK List completed.");
} else {
patterns_strarr =
return 0;
}
-static void list_namespaces(struct mail_namespace *ns,
- enum mail_namespace_type type, string_t *str)
+static void
+list_namespaces(struct mail_namespace *ns, enum mail_namespace_type type,
+ string_t *str, bool utf8)
{
ARRAY(struct namespace_order) ns_order;
struct namespace_order *no;
}
array_sort(&ns_order, namespace_order_cmp);
- mutf7_prefix = t_str_new(64);
+ mutf7_prefix = (utf8 ? NULL : t_str_new(64));
str_append_c(str, '(');
array_foreach_modifiable(&ns_order, no) {
+ const char *prefix = no->ns->prefix;
+
ns_sep = mail_namespace_get_sep(no->ns);
str_append_c(str, '(');
- str_truncate(mutf7_prefix, 0);
- if (imap_utf8_to_utf7(no->ns->prefix, mutf7_prefix) < 0) {
- i_panic("LIST: Namespace prefix not UTF-8: %s",
- no->ns->prefix);
+ if (!utf8) {
+ str_truncate(mutf7_prefix, 0);
+ if (imap_utf8_to_utf7(prefix, mutf7_prefix) < 0) {
+ i_panic("LIST: Namespace prefix not UTF-8: %s",
+ prefix);
+ }
+ prefix = str_c(mutf7_prefix);
}
- imap_append_string(str, str_c(mutf7_prefix), 0);
+ imap_append_string(str, prefix, 0);
str_append(str, " \"");
if (ns_sep == '\\')
str_append_c(str, '\\');
str_append(str, "* NAMESPACE ");
list_namespaces(client->user->namespaces,
- MAIL_NAMESPACE_TYPE_PRIVATE, str);
+ MAIL_NAMESPACE_TYPE_PRIVATE, str, cmd->utf8);
str_append_c(str, ' ');
list_namespaces(client->user->namespaces,
- MAIL_NAMESPACE_TYPE_SHARED, str);
+ MAIL_NAMESPACE_TYPE_SHARED, str, cmd->utf8);
str_append_c(str, ' ');
list_namespaces(client->user->namespaces,
- MAIL_NAMESPACE_TYPE_PUBLIC, str);
+ MAIL_NAMESPACE_TYPE_PUBLIC, str, cmd->utf8);
client_send_line(client, str_c(str));
client_send_tagline(cmd, "OK Namespace completed.");
if (list->type == IMAP_ARG_EOL)
return -1; /* at least one attribute must be set */
return imap_fetch_att_list_parse(ctx->client, ctx->pool, list,
- &ctx->fetch_ctx, &ctx->error);
+ ctx->utf8, &ctx->fetch_ctx,
+ &ctx->error);
}
static bool
} else {
const char *vname = info->vname;
- string_t *mutf7_vname = t_str_new(128);
- if (imap_utf8_to_utf7(vname, mutf7_vname) < 0)
- i_panic("Mailbox name not UTF-8: %s", vname);
- vname = str_c(mutf7_vname);
+ if (!cmd->utf8) {
+ string_t *mutf7_vname = t_str_new(128);
+ if (imap_utf8_to_utf7(vname, mutf7_vname) < 0)
+ i_panic("Mailbox name not UTF-8: %s", vname);
+ vname = str_c(mutf7_vname);
+ }
imap_status_send(client, vname, &items, &result);
}
mailbox_free(&box);
ctx = p_new(pool, struct imap_notify_context, 1);
ctx->pool = pool;
ctx->client = cmd->client;
+ ctx->utf8 = cmd->utf8;
p_array_init(&ctx->namespaces, pool, 4);
if (!imap_arg_get_atom(&args[0], &str))
if (imap_arg_atom_equals(args, "CHARSET")) {
/* CHARSET specified */
- if ((client_enabled_mailbox_features(cmd->client) & MAILBOX_FEATURE_UTF8ACCEPT) != 0) {
+ if (cmd->utf8) {
/* RFC 6855 Section 3 bans CHARSET after UTF8=ACCEPT */
client_send_command_error(cmd,
"Cannot set search charset when using UTF8=ACCEPT");
}
fetch_ctx = imap_fetch_alloc(ctx->cmd->client, ctx->cmd->pool,
- t_strdup_printf("%s %s", ctx->cmd->name, ctx->cmd->args));
+ t_strdup_printf("%s %s", ctx->cmd->name, ctx->cmd->args),
+ ctx->cmd->utf8);
imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_uid_init);
imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_flags_init);
cmd->stats.last_run_timeval = ioloop_timeval;
cmd->stats.start_ioloop_wait_usecs =
io_loop_get_wait_usecs(current_ioloop);
+ cmd->utf8 = client_has_enabled(client, imap_feature_utf8accept);
p_array_init(&cmd->module_contexts, cmd->pool, 5);
DLLIST_PREPEND(&client->command_queue, cmd);
bool tagline_sent:1;
bool executing:1;
bool internal:1;
+ bool utf8:1; /* status of UTF8=ACCEPT feature at command alloc */
};
struct imap_client_vfuncs {
string_t *utf8_name;
utf8_name = t_str_new(64);
- if (imap_utf7_to_utf8(*mailbox, utf8_name) < 0) {
+ if (cmd->utf8) {
+ if (!uni_utf8_str_is_valid(*mailbox)) {
+ *client_error_r = "NO Mailbox name is not valid UTF-8";
+ return NULL;
+ }
+ str_append(utf8_name, *mailbox);
+ } else if (imap_utf7_to_utf8(*mailbox, utf8_name) < 0) {
*client_error_r = "NO Mailbox name is not valid mUTF-7";
return NULL;
}
}
int imap_fetch_att_list_parse(struct client *client, pool_t pool,
- const struct imap_arg *list,
+ const struct imap_arg *list, bool utf8,
struct imap_fetch_context **fetch_ctx_r,
const char **client_error_r)
{
const char *str;
i_zero(&init_ctx);
- init_ctx.fetch_ctx = imap_fetch_alloc(client, pool, "NOTIFY");
+ init_ctx.fetch_ctx = imap_fetch_alloc(client, pool, "NOTIFY", utf8);
init_ctx.pool = pool;
init_ctx.args = list;
}
struct imap_fetch_context *
-imap_fetch_alloc(struct client *client, pool_t pool, const char *reason)
+imap_fetch_alloc(struct client *client, pool_t pool, const char *reason,
+ bool utf8)
{
struct imap_fetch_context *ctx;
ctx->client = client;
ctx->ctx_pool = pool;
ctx->reason = p_strdup(pool, reason);
+ ctx->utf8 = utf8;
pool_ref(pool);
p_array_init(&ctx->all_headers, pool, 64);
void *context ATTR_UNUSED)
{
const char *name;
- string_t *mutf7_name;
if (mail_get_special(mail, MAIL_FETCH_MAILBOX_NAME, &name) < 0) {
/* This can happen with virtual mailbox if the backend mail
return -1;
}
- mutf7_name = t_str_new(strlen(name)*2);
- if (imap_utf8_to_utf7(name, mutf7_name) < 0)
- i_panic("FETCH: Mailbox name not UTF-8: %s", name);
+ if (!ctx->utf8) {
+ string_t *mutf7_name = t_str_new(strlen(name)*2);
+ if (imap_utf8_to_utf7(name, mutf7_name) < 0)
+ i_panic("FETCH: Mailbox name not UTF-8: %s", name);
+ name = str_c(mutf7_name);
+ }
str_append(ctx->state.cur_str, "X-MAILBOX ");
- imap_append_astring(ctx->state.cur_str, str_c(mutf7_name), 0);
+ imap_append_astring(ctx->state.cur_str, name, 0);
str_append_c(ctx->state.cur_str, ' ');
return 1;
}
bool flags_show_only_seen_changes:1;
/* HEADER.FIELDS or HEADER.FIELDS.NOT is fetched */
bool fetch_header_fields:1;
+ bool utf8:1;
};
void imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
(imap_fetch_handler_t *)handler, context)
int imap_fetch_att_list_parse(struct client *client, pool_t pool,
- const struct imap_arg *list,
+ const struct imap_arg *list, bool utf8,
struct imap_fetch_context **fetch_ctx_r,
const char **client_error_r);
struct imap_fetch_context *
-imap_fetch_alloc(struct client *client, pool_t pool, const char *reason);
+imap_fetch_alloc(struct client *client, pool_t pool, const char *reason,
+ bool utf8);
void imap_fetch_free(struct imap_fetch_context **ctx);
bool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx);
void imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx,
if (error != MAIL_ERROR_PERM)
ret = -1;
} else {
+ bool utf8 = client_has_enabled(client, imap_feature_utf8accept);
const char *vname = rec->vname;
- string_t *mutf7_vname = t_str_new(128);
- if (imap_utf8_to_utf7(vname, mutf7_vname) < 0)
- i_panic("Mailbox name not UTF-8: %s", vname);
- vname = str_c(mutf7_vname);
+ if (!utf8) {
+ string_t *mutf7_vname = t_str_new(128);
+ if (imap_utf8_to_utf7(vname, mutf7_vname) < 0)
+ i_panic("Mailbox name not UTF-8: %s", vname);
+ vname = str_c(mutf7_vname);
+ }
ret = imap_status_send(client, vname, &items, &result);
}
mailbox_free(&box);
bool send_immediate_status:1;
bool watching_mailbox:1;
bool notifying:1;
+ bool utf8:1;
};
bool imap_notify_match_mailbox(struct imap_notify_namespace *notify_ns,
ctx->fetch_pool = pool_alloconly_create("search update fetch", 512);
if (imap_fetch_att_list_parse(ctx->cmd->client, ctx->fetch_pool,
- update_args, &ctx->fetch_ctx,
- &client_error) < 0) {
+ update_args, ctx->cmd->utf8,
+ &ctx->fetch_ctx, &client_error) < 0) {
client_send_command_error(ctx->cmd, t_strconcat(
"SEARCH UPDATE fetch-att: ", client_error, NULL));
pool_unref(&ctx->fetch_pool);
const struct mailbox_import_state *state,
unsigned int *flag_change_count_r)
{
+ bool utf8 = client_has_enabled(client, imap_feature_utf8accept);
struct imap_fetch_context *fetch_ctx;
struct mail_search_args *search_args;
ARRAY_TYPE(seq_range) old_uids;
imap_search_add_changed_since(search_args, state->highest_modseq);
pool = pool_alloconly_create("imap state flag changes", 1024);
- fetch_ctx = imap_fetch_alloc(client, pool, "unhibernate");
+ fetch_ctx = imap_fetch_alloc(client, pool, "unhibernate", utf8);
pool_unref(&pool);
imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_flags_init);