bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe)
{
- struct mail_namespace *ns;
- const char *mailbox, *verify_name;
+ struct mail_namespace *ns, *real_ns;
+ struct mail_storage *storage;
+ const char *mailbox, *verify_name, *real_name;
/* <mailbox> */
if (!client_read_string_args(cmd, 1, &mailbox))
return FALSE;
-
verify_name = mailbox;
+
+ real_name = mailbox;
+ storage = client_find_storage(cmd, &real_name);
+ if (storage == NULL)
+ return TRUE;
+
+ /* now find a namespace where the subscription can be added to */
ns = mail_namespace_find_subscribable(cmd->client->user->namespaces,
&mailbox);
if (ns == NULL) {
- client_send_tagline(cmd, "NO Unknown namespace.");
+ client_send_tagline(cmd, "NO Unknown subscription namespace.");
return TRUE;
}
+ real_ns = mail_storage_get_namespace(storage);
+ if (ns != real_ns) {
+ /* subscription is being written to a different namespace
+ than where the mailbox exists. */
+ mailbox = t_strconcat(real_ns->prefix, real_name, NULL);
+ /* drop the common prefix */
+ i_assert(strncmp(ns->prefix, mailbox, strlen(ns->prefix)) == 0);
+ mailbox += strlen(ns->prefix);
+ }
+
if ((client_workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
*mailbox != '\0' && mailbox[strlen(mailbox)-1] ==
mail_storage_get_hierarchy_sep(ns->storage)) {
ns->type = NAMESPACE_SHARED;
ns->user = user;
ns->prefix = p_strdup(user->pool, str_c(prefix));
- ns->flags = NAMESPACE_FLAG_LIST | NAMESPACE_FLAG_HIDDEN;
+ ns->flags = NAMESPACE_FLAG_LIST | NAMESPACE_FLAG_HIDDEN |
+ NAMESPACE_FLAG_AUTOCREATED;
ns->sep = _storage->ns->sep;
location = t_str_new(256);
struct imap_match_glob *glob,
bool update_only)
{
- struct mail_namespace *ns = ctx->list->ns;
+ struct mail_namespace *default_ns = ctx->list->ns;
+ struct mail_namespace *namespaces = default_ns->user->namespaces;
struct mailbox_list_iter_update_context update_ctx;
struct subsfile_list_context *subsfile_ctx;
- const char *path, *name;
+ struct mail_namespace *ns;
+ const char *path, *name, *name2, *full_name;
string_t *vname;
vname = t_str_new(256);
update_ctx.match_parents =
(ctx->flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0;
- while ((name = subsfile_list_next(subsfile_ctx)) != NULL) {
+ while ((name = subsfile_list_next(subsfile_ctx)) != NULL) T_BEGIN {
+ full_name = name2 =
+ t_strconcat(default_ns->prefix, name, NULL);
+ ns = mail_namespace_find_unsubscribable(namespaces, &name2);
+ if (ns == NULL)
+ ns = default_ns;
+ else if (ns->type == NAMESPACE_SHARED &&
+ (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
+ /* we'll need to get the namespace autocreated. */
+ (void)mailbox_list_is_valid_existing_name(ns->list,
+ name2);
+ name = full_name;
+ ns = mail_namespace_find_unsubscribable(namespaces,
+ &name);
+ } else {
+ name = name2;
+ }
name = mail_namespace_get_vname(ns, vname, name);
mailbox_list_iter_update(&update_ctx, name);
- }
+ } T_END;
return subsfile_list_deinit(subsfile_ctx);
}
{
return mail_namespace_find_mask(namespaces, mailbox,
NAMESPACE_FLAG_SUBSCRIPTIONS,
- NAMESPACE_FLAG_SUBSCRIPTIONS);
+ NAMESPACE_FLAG_SUBSCRIPTIONS);
+}
+
+struct mail_namespace *
+mail_namespace_find_unsubscribable(struct mail_namespace *namespaces,
+ const char **mailbox)
+{
+ return mail_namespace_find_mask(namespaces, mailbox,
+ 0, NAMESPACE_FLAG_SUBSCRIPTIONS);
}
struct mail_namespace *
NAMESPACE_FLAG_SUBSCRIPTIONS = 0x10,
/* Namespace is created for internal use only. */
- NAMESPACE_FLAG_INTERNAL = 0x1000
+ NAMESPACE_FLAG_INTERNAL = 0x1000,
+ /* Namespace was created automatically (for shared mailboxes) */
+ NAMESPACE_FLAG_AUTOCREATED = 0x2000
};
struct mail_namespace {
struct mail_namespace *
mail_namespace_find_subscribable(struct mail_namespace *namespaces,
const char **mailbox);
+/* Like above, but find only from namespaces with subscriptions flag not set. */
+struct mail_namespace *
+mail_namespace_find_unsubscribable(struct mail_namespace *namespaces,
+ const char **mailbox);
/* Returns the INBOX namespace */
struct mail_namespace *
mail_namespace_find_inbox(struct mail_namespace *namespaces);