#include <sys/wait.h>
#define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30
-/* The default vname_escape_char to use unless overridden by BROKENCHAR
- setting. Note that it's only used for internal dsync names, so it won't end
- up in permanent storage names. The only requirement for it is that it's not
- the same as the hierarchy separator. */
+/* The default vname_escape_char to use unless overridden by
+ mailbox_list_visible_escape_char setting. Note that it's only used for
+ internal dsync names, so it won't end up in permanent storage names. The
+ only requirement for it is that it's not the same as the hierarchy
+ separator. */
#define DSYNC_LIST_VNAME_ESCAPE_CHAR '%'
/* In case DSYNC_LIST_VNAME_ESCAPE_CHAR is the hierarchy separator,
use this instead. */
return TRUE;
}
+static void
+doveadm_update_escape_char(struct mail_namespace *ns, char ns_sep)
+{
+ const struct mail_storage_settings *old_set = ns->list->mail_set;
+ struct mail_storage_settings *new_set =
+ p_memdup(old_set->pool, old_set, sizeof(*old_set));
+ new_set->mailbox_list_visible_escape_char =
+ p_strdup_printf(old_set->pool, "%c", ns_sep);
+ ns->list->mail_set = new_set;
+}
+
static void doveadm_user_init_dsync(struct mail_user *user)
{
struct mail_namespace *ns;
p_new(ns->list->pool, struct dsync_mailbox_list, 1);
MODULE_CONTEXT_SET(ns->list, dsync_mailbox_list_module, dlist);
- if (ns->list->set.vname_escape_char == '\0') {
- ns->list->set.vname_escape_char =
+ if (ns->list->mail_set->mailbox_list_visible_escape_char[0] == '\0') {
+ doveadm_update_escape_char(ns,
ns_sep != DSYNC_LIST_VNAME_ESCAPE_CHAR ?
DSYNC_LIST_VNAME_ESCAPE_CHAR :
- DSYNC_LIST_VNAME_ALT_ESCAPE_CHAR;
+ DSYNC_LIST_VNAME_ALT_ESCAPE_CHAR);
} else {
dlist->have_orig_escape_char = TRUE;
}
if (mail_namespace_get_sep(ns) != mail_namespace_get_sep(ns2)) {
e_error(ctx->ctx.cctx->event,
"Mail locations must use the same hierarchy separator "
- "(specify namespace %s { separator } explicitly)",
- ns->set->name);
+ "(specify namespace %s { separator=%c } != "
+ "namespace %s { separator=%c })",
+ ns->set->name, mail_namespace_get_sep(ns),
+ ns2->set->name, mail_namespace_get_sep(ns2));
ctx->ctx.exit_code = EX_CONFIG;
mail_user_deinit(&user2);
return -1;
continue;
sep = mail_namespace_get_sep(ns);
- escape_char = mailbox_list_get_settings(ns->list)->vname_escape_char;
+ escape_char = ns->list->mail_set->mailbox_list_visible_escape_char[0];
if (first_ns == NULL) {
brain->hierarchy_sep = sep;
brain->escape_char = escape_char;
{
const char ns_sep = mail_namespace_get_sep(ns);
const char escape_char =
- mailbox_list_get_settings(ns->list)->vname_escape_char;
+ ns->list->mail_set->mailbox_list_visible_escape_char[0];
const char *const *old_vname_parts =
dsync_mailbox_name_to_parts(old_vname, ns_sep, escape_char);
- namespace separator = ':'
- fs_list separator = '.'
- mailbox_list storage_name_escape_char = '+'
- - mailbox_list vname_escape_char = '~'
+ - mailbox_list mailbox_list_visible_escape_char = '~'
- fs_list storage_name_escape_char = '%'
remote_name = "prefix/~foo/bar^baz+_%_."
- storage_name_escape character + is escaped as +2b
vname = "~7efoo:bar.baz+_%_."
- imapc_list_prefix is dropped
- - vname_escape_character ~ is escaped into ~7e
+ - mailbox_list_visible_escape_char ~ is escaped into ~7e
- separator is changed from ^ to :
- storage_name_escape_characters are unescaped
fs_name = "prefix.~foo.bar^baz+_%25_%2e"
static const struct setting_define imapc_setting_defines[] = {
{ .type = SET_FILTER_NAME, .key = "imapc" },
+ { .type = SET_FILTER_NAME, .key = "layout_imapc" },
DEF(STR, imapc_host),
DEF(IN_PORT, imapc_port),
static const struct setting_keyvalue imapc_default_filter_settings_keyvalue[] = {
{ "imapc/mailbox_list_layout", "imapc" },
+ /* We want to have all imapc mailboxes accessible, so escape them if
+ necessary. */
+ { "layout_imapc/mailbox_list_visible_escape_char", "~" },
{ NULL, NULL }
};
const struct mail_storage_settings *mail_set ATTR_UNUSED)
{
set->storage_name_escape_char = IMAPC_LIST_STORAGE_NAME_ESCAPE_CHAR;
- /* We want to have all imapc mailboxes accessible, so escape them if
- necessary. */
- if (set->vname_escape_char == '\0')
- set->vname_escape_char = IMAPC_LIST_VNAME_ESCAPE_CHAR;
}
static struct mailbox *
#define IMAPC_LIST_STORAGE_NAME_ESCAPE_CHAR '%'
/* fs_name separator */
#define IMAPC_LIST_FS_NAME_ESCAPE_CHAR '%'
-/* vname separator */
-#define IMAPC_LIST_VNAME_ESCAPE_CHAR '~'
struct imap_arg;
struct imapc_untagged_reply;
DEF(BOOL_HIDDEN, mailbox_list_iter_from_index_dir),
DEF(BOOL_HIDDEN, mailbox_list_drop_noselect),
DEF(BOOL_HIDDEN, mailbox_list_validate_fs_names),
+ DEF(STR, mailbox_list_visible_escape_char),
DEF(STR_HIDDEN, mailbox_root_directory_name),
DEF(STR_HIDDEN, mailbox_subscriptions_filename),
DEF(STR, mail_index_path),
.mailbox_list_iter_from_index_dir = FALSE,
.mailbox_list_drop_noselect = TRUE,
.mailbox_list_validate_fs_names = TRUE,
+ .mailbox_list_visible_escape_char = "",
.mailbox_root_directory_name = "",
.mailbox_subscriptions_filename = "subscriptions",
.mail_index_path = "",
set->mailbox_root_directory_name, "/", NULL);
}
+ if (set->mailbox_list_visible_escape_char != set_value_unknown &&
+ strlen(set->mailbox_list_visible_escape_char) > 1) {
+ *error_r = "mailbox_list_visible_escape_char value must be a single character";
+ return FALSE;
+ }
+
if (!mail_storage_settings_check_namespaces(event, set, error_r))
return FALSE;
return TRUE;
OFFSET(mailbox_list_layout),
OFFSET(mailbox_list_index_prefix),
OFFSET(mailbox_list_iter_from_index_dir),
+ OFFSET(mailbox_list_visible_escape_char),
OFFSET(mailbox_root_directory_name),
OFFSET(mailbox_subscriptions_filename),
OFFSET(mail_index_path),
bool mailbox_list_iter_from_index_dir;
bool mailbox_list_drop_noselect;
bool mailbox_list_validate_fs_names;
+ const char *mailbox_list_visible_escape_char;
const char *mailbox_root_directory_name;
const char *mailbox_subscriptions_filename;
const char *mail_index_path;
if (set->storage_name_escape_char != '\0')
list->set.storage_name_escape_char = set->storage_name_escape_char;
- list->set.vname_escape_char = set->vname_escape_char;
list->set.utf8 = set->utf8;
if (list->v.init != NULL) {
else if (strcmp(key, "FULLDIRNAME") == 0) {
set_r->index_control_use_maildir_name = TRUE;
dest = &set_r->maildir_name;
- } else if (strcmp(key, "BROKENCHAR") == 0) {
- if (strlen(value) != 1) {
- *error_r = "BROKENCHAR value must be a single character";
- return -1;
- }
- set_r->vname_escape_char = value[0];
- continue;
} else {
*error_r = t_strdup_printf("Unknown setting: %s", key);
return -1;
/* UTF-8 -> mUTF-7 conversion */
str = t_str_new(strlen(storage_name)*2);
if (imap_escaped_utf8_to_utf7(storage_name,
- list->set.vname_escape_char,
- str) < 0)
+ list->mail_set->mailbox_list_visible_escape_char[0],
+ str) < 0)
i_panic("Mailbox name not UTF-8: %s", vname_part);
storage_name = str_c(str);
- } else if (list->set.vname_escape_char != '\0') {
+ } else if (list->mail_set->mailbox_list_visible_escape_char[0] != '\0') {
mailbox_list_name_unescape(&storage_name,
- list->set.vname_escape_char);
+ list->mail_set->mailbox_list_visible_escape_char[0]);
}
if (list->set.storage_name_escape_char != '\0') {
storage_name = mailbox_list_escape_name_params(storage_name,
{
const char *vname = storage_name_part;
char escape_chars[] = {
- list->set.vname_escape_char,
+ list->mail_set->mailbox_list_visible_escape_char[0],
mail_namespace_get_sep(list->ns),
'\0'
};
can't be accessible, so just return it as the
original mUTF7 name. */
}
- } else if (list->set.vname_escape_char != '\0') {
+ } else if (list->mail_set->mailbox_list_visible_escape_char[0] != '\0') {
string_t *str = t_str_new(strlen(vname));
mailbox_list_name_escape(vname, escape_chars, str);
vname = str_c(str);
{ vname="A/B.C%D", storage_name_escape_char='%', namespace_sep='/',
storage_sep='.' } -> storage_name="A.B%2eC%25D". */
char storage_name_escape_char;
- /* Used for escaping the user/client-visible UTF-8 vname. If the
- storage_name can't be converted reversibly to the vname and back,
- encode the problematic parts using <vname_escape_char><hex>. The
- vname_escape_char itself also has to be encoded the same way. For
- example { storage_name="A/B.C%D", vname_escape_char='%',
- namespace_sep='/', storage_sep='.' } -> vname="A%2fB/C%25D".
-
- Note that it's possible for escape_char and broken_char to be the
- same character. They're just used for different directions in
- conversion. */
- char vname_escape_char;
/* Use UTF-8 mailbox names on filesystem instead of mUTF-7 */
bool utf8:1;
/* Use maildir_name also for index/control directories. This should
const struct test_mailbox_list_name *test,
bool mutf7)
{
+ static char vname_escape_char[2];
+ static struct mail_storage_settings mail_set = {
+ .mailbox_list_visible_escape_char = vname_escape_char,
+ };
+
+ list->mail_set = &mail_set;
list->ns->prefix = test->ns_prefix == NULL ? "" :
test->ns_prefix;
list->ns->prefix_len = strlen(list->ns->prefix);
ns_sep[0] = test->ns_sep;
list_hierarchy_sep = test->list_sep;
list->set.utf8 = !mutf7;
- list->set.vname_escape_char = test->vname_escape_char;
+ vname_escape_char[0] = test->vname_escape_char;
list->set.storage_name_escape_char =
test->storage_name_escape_char;
list->set.maildir_name = test->maildir_name == NULL ? "" :