The leading '~' check used to fire whenever the input started with '~'.
That assumed callers always passed the full vname. Since
mailbox_list_default_get_storage_name() and
mailbox_name_hdr_decode_storage_name() now split into hierarchy parts
before escaping, the '~' check would wrongly match the start of any
part - e.g. "foo/~bar" would have its second component escaped as
"+7ebar" even though '~' in the middle of a path has no special
meaning.
Add a first_part parameter. Only when first_part=TRUE do we apply the
leading-'~' escape. Callers operating on parts pass first_part=FALSE
for non-leading parts.
For mailbox_list_default_get_storage_name() also require prefix[0] ==
'\\0' so that when the INBOX/INBOX prefix has been prepended to
storage_name, the first split-part is no longer the very start of the
escaped output.
return mailbox_list_escape_name_params(remote_name,
list->root_sep,
mailbox_list_get_hierarchy_sep(&list->list),
- list->list.mail_set->mailbox_list_storage_escape_char[0], "");
+ list->list.mail_set->mailbox_list_storage_escape_char[0], "",
+ TRUE);
}
static const char *
remote_name = imapc_list_storage_to_remote_name(list, storage_name);
return mailbox_list_escape_name_params(remote_name,
list->root_sep, mailbox_list_get_hierarchy_sep(fs_list),
- fs_list->mail_set->mailbox_list_storage_escape_char[0], "");
+ fs_list->mail_set->mailbox_list_storage_escape_char[0], "",
+ TRUE);
}
static const char *
const char list_sep = mailbox_list_get_hierarchy_sep(list);
const char escape_char = list->mail_set->mailbox_list_storage_escape_char[0];
+ bool first_part = TRUE;
array_foreach_elem(&raw_parts, raw_part) {
if (str_len(storage_name) > 0)
str_append_c(storage_name, list_sep);
str_append(storage_name,
mailbox_list_escape_name_params(raw_part,
'\0', list_sep, escape_char,
- list->mail_set->mailbox_directory_name));
+ list->mail_set->mailbox_directory_name,
+ first_part));
}
+ first_part = FALSE;
}
return str_c(storage_name);
}
const char *
mailbox_list_escape_name_params(const char *vname, char ns_sep, char list_sep,
- char escape_char, const char *maildir_name);
+ char escape_char, const char *maildir_name,
+ bool first_part);
const char *
mailbox_list_unescape_name_params(const char *src, char ns_sep, char list_sep,
char escape_char);
const char *
mailbox_list_escape_name_params(const char *vname, char ns_sep, char list_sep,
- char escape_char, const char *maildir_name)
+ char escape_char, const char *maildir_name,
+ bool first_part)
{
string_t *escaped_name = t_str_new(64);
bool dirstart = TRUE;
i_assert(escape_char != '\0');
- /* escape the mailbox name */
- if (*vname == '~') {
+ /* escape the mailbox name. The leading '~' is escaped only at the very
+ beginning of the full name, since '~' is otherwise a perfectly valid
+ character in a hierarchy component. Callers operating on a single
+ hierarchy part (already split from the full vname) pass first_part=FALSE
+ for non-leading parts to skip this check. */
+ if (first_part && *vname == '~') {
str_printfa(escaped_name, "%c%02x", escape_char, *vname);
vname++;
dirstart = FALSE;
'\0', /* no separator conversion */
mailbox_list_get_hierarchy_sep(list),
list->mail_set->mailbox_list_storage_escape_char[0],
- list->mail_set->mailbox_directory_name));
+ list->mail_set->mailbox_directory_name,
+ i == 0 && prefix[0] == '\0'));
}
}
return str_c(storage_name);