static struct acl_object * acl_backend_vfile_object_init(struct acl_backend *_backend, const char *name) { struct acl_backend_vfile *backend = (struct acl_backend_vfile *)_backend; struct acl_object_vfile *aclobj; const char *dir, *vname, *error; aclobj = i_new(struct acl_object_vfile, 1); aclobj->aclobj.backend = _backend; aclobj->aclobj.name = i_strdup(name); T_BEGIN { if (*name == '\0' || mailbox_list_is_valid_name(_backend->list, name, &error)) { vname = *name == '\0' ? "" : mailbox_list_get_vname(_backend->list, name); dir = acl_backend_vfile_get_local_dir(_backend, name, vname); aclobj->local_path = dir == NULL ? NULL : i_strconcat(dir, "/"ACL_FILENAME, NULL); if (backend->global_path != NULL && _backend->global_file == NULL) { aclobj->global_path = i_strconcat(backend->global_path, "/", vname, NULL); } } else { /* Invalid mailbox name, just use the default global ACL files */ } } T_END; return &aclobj->aclobj; }
static bool acl_backend_vfile_has_acl(struct acl_backend *_backend, const char *name) { struct acl_backend_vfile *backend = (struct acl_backend_vfile *)_backend; struct acl_backend_vfile_validity *old_validity, new_validity; const char *path, *local_path, *global_path, *dir, *vname = ""; const char *error; int ret; old_validity = acl_cache_get_validity(_backend->cache, name); if (old_validity != NULL) new_validity = *old_validity; else memset(&new_validity, 0, sizeof(new_validity)); /* See if the mailbox exists. If we wanted recursive lookups we could skip this, but at least for now we assume that if an existing mailbox has no ACL it's equivalent to default ACLs. */ if (mailbox_list_get_path(_backend->list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) <= 0) ret = -1; else { ret = acl_backend_vfile_exists(backend, path, &new_validity.mailbox_validity); } if (ret == 0 && (*name == '\0' || mailbox_list_is_valid_name(_backend->list, name, &error))) { vname = *name == '\0' ? "" : mailbox_list_get_vname(_backend->list, name); dir = acl_backend_vfile_get_local_dir(_backend, name, vname); if (dir != NULL) { local_path = t_strconcat(dir, "/", name, NULL); ret = acl_backend_vfile_exists(backend, local_path, &new_validity.local_validity); } } if (ret == 0 && backend->global_path != NULL) { if (_backend->global_file != NULL) { ret = acl_global_file_refresh(_backend->global_file); if (ret == 0 && acl_global_file_have_any(_backend->global_file, vname)) ret = 1; } else { global_path = t_strconcat(backend->global_path, "/", name, NULL); ret = acl_backend_vfile_exists(backend, global_path, &new_validity.global_validity); } } acl_cache_set_validity(_backend->cache, name, &new_validity); return ret > 0; }
const struct mailbox_info * mailbox_list_subscriptions_iter_next(struct mailbox_list_iterate_context *_ctx) { struct subscriptions_mailbox_list_iterate_context *ctx = (struct subscriptions_mailbox_list_iterate_context *)_ctx; struct mailbox_list *list = _ctx->list; struct mailbox_node *node; enum mailbox_info_flags subs_flags; const char *vname, *storage_name, *error; int ret; node = mailbox_tree_iterate_next(ctx->iter, &vname); if (node == NULL) return NULL; ctx->info.vname = vname; subs_flags = node->flags & (MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED); if ((_ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) != 0 && (_ctx->flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) == 0) { /* don't care about flags, just return it */ ctx->info.flags = subs_flags; return &ctx->info; } storage_name = mailbox_list_get_storage_name(list, vname); if (!mailbox_list_is_valid_name(list, storage_name, &error)) { /* broken entry in subscriptions file */ ctx->info.flags = MAILBOX_NONEXISTENT; } else if (mailbox_list_mailbox(list, storage_name, &ctx->info.flags) < 0) { ctx->info.flags = 0; _ctx->failed = TRUE; } else if ((_ctx->flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) != 0 && (ctx->info.flags & (MAILBOX_CHILDREN | MAILBOX_NOCHILDREN)) == 0) { ret = mailbox_has_children(list, storage_name); if (ret < 0) _ctx->failed = TRUE; else if (ret == 0) ctx->info.flags |= MAILBOX_NOCHILDREN; else ctx->info.flags |= MAILBOX_CHILDREN; } ctx->info.flags &= ~(MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED); ctx->info.flags |= node->flags & (MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED); return &ctx->info; }
static int mailbox_list_subscription_fill_one(struct mailbox_list *list, struct mailbox_list *src_list, const char *name) { struct mail_namespace *ns, *default_ns = list->ns; struct mail_namespace *namespaces = default_ns->user->namespaces; struct mailbox_node *node; const char *vname, *ns_name, *error; unsigned int len; bool created; /* default_ns is whatever namespace we're currently listing. if we have e.g. prefix="" and prefix=pub/ namespaces with pub/ namespace having subscriptions=no, we want to: 1) when listing "" namespace we want to skip over any names that begin with pub/. */ if (src_list->ns->prefix_len == 0) ns_name = name; else { /* we could have two-level namespace: ns/ns2/ */ ns_name = t_strconcat(src_list->ns->prefix, name, NULL); } ns = mail_namespace_find_unsubscribable(namespaces, ns_name); if (ns != NULL && ns != default_ns) { if (ns->prefix_len > 0) return 0; /* prefix="" namespace=no : catching this is basically the same as not finding any namespace. */ ns = NULL; } /* 2) when listing pub/ namespace, skip over entries that don't begin with pub/. */ if (ns == NULL && (default_ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) return 0; /* When listing shared namespace's subscriptions, we need to autocreate all the visible child namespaces. their subscriptions are listed later. */ if (ns != NULL && mail_namespace_is_shared_user_root(ns)) { /* we'll need to get the namespace autocreated. one easy way is to just ask to join a reference and pattern */ (void)mailbox_list_join_refpattern(ns->list, ns_name, ""); } /* When listing pub/ namespace, skip over the namespace prefix in the name. the rest of the name is storage_name. */ if (ns == NULL) ns = default_ns; else if (strncmp(ns_name, ns->prefix, ns->prefix_len) == 0) { ns_name += ns->prefix_len; name = ns_name; } else { /* "pub" entry - this shouldn't be possible normally, because it should be saved as "pub/", but handle it anyway */ i_assert(strncmp(ns_name, ns->prefix, ns->prefix_len-1) == 0 && ns_name[ns->prefix_len-1] == '\0'); name = ns_name = ""; } len = strlen(name); if (len > 0 && name[len-1] == mail_namespace_get_sep(ns)) { /* entry ends with hierarchy separator, remove it. this exists mainly for backwards compatibility with old Dovecot versions and non-Dovecot software that added them */ name = t_strndup(name, len-1); } if (!mailbox_list_is_valid_name(list, name, &error)) { /* we'll only get into trouble if we show this */ return -1; } else { vname = mailbox_list_get_vname(list, name); if (!uni_utf8_str_is_valid(vname)) return -1; node = mailbox_tree_get(list->subscriptions, vname, &created); node->flags = MAILBOX_SUBSCRIBED; } return 0; }