1
/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */
7
#include "var-expand.h"
8
#include "index-storage.h"
9
#include "shared-storage.h"
14
#define SHARED_LIST_CONTEXT(obj) \
15
MODULE_CONTEXT(obj, shared_mailbox_list_module)
17
extern struct mail_storage shared_storage;
18
extern struct mailbox shared_mailbox;
20
static MODULE_CONTEXT_DEFINE_INIT(shared_mailbox_list_module,
21
&mailbox_list_module_register);
23
static struct mail_storage *shared_alloc(void)
25
struct shared_storage *storage;
28
pool = pool_alloconly_create("shared storage", 1024);
29
storage = p_new(pool, struct shared_storage, 1);
30
storage->storage = shared_storage;
31
storage->storage.pool = pool;
32
storage->storage.storage_class = &shared_storage;
34
storage->base_dir = p_strdup(pool, getenv("BASE_DIR"));
35
if (storage->base_dir == NULL)
36
storage->base_dir = PKG_RUNDIR;
38
return &storage->storage;
41
static int shared_create(struct mail_storage *_storage, const char *data,
44
struct shared_storage *storage = (struct shared_storage *)_storage;
45
struct mailbox_list_settings list_set;
46
const char *driver, *p;
50
/* data must begin with the actual mailbox driver */
51
p = strchr(data, ':');
53
*error_r = "Shared mailbox location not prefixed with driver";
56
driver = t_strdup_until(data, p);
57
storage->location = p_strdup(_storage->pool, data);
58
storage->storage_class = mail_storage_find_class(driver);
59
if (storage->storage_class == NULL) {
60
*error_r = t_strconcat("Unknown shared storage driver: ",
64
_storage->mailbox_is_file = storage->storage_class->mailbox_is_file;
66
wildcardp = strchr(_storage->ns->prefix, '%');
67
if (wildcardp == NULL) {
68
*error_r = "Shared namespace prefix doesn't contain %";
71
storage->ns_prefix_pattern = p_strdup(_storage->pool, wildcardp);
73
have_username = FALSE;
74
for (p = storage->ns_prefix_pattern; *p != '\0'; p++) {
79
if (*p == 'u' || *p == 'n')
81
else if (*p != '%' && *p != 'd')
85
*error_r = "Shared namespace prefix contains unknown variables";
89
*error_r = "Shared namespace prefix doesn't contain %u or %n";
93
/* truncate prefix after the above checks are done, so they can log
94
the full prefix in error conditions */
97
if (mailbox_list_alloc("shared", &_storage->list, error_r) < 0)
99
MODULE_CONTEXT_SET_FULL(_storage->list, shared_mailbox_list_module,
100
storage, &storage->list_module_ctx);
102
memset(&list_set, 0, sizeof(list_set));
103
list_set.mail_storage_flags = &_storage->flags;
104
list_set.lock_method = &_storage->lock_method;
105
mailbox_list_init(_storage->list, _storage->ns, &list_set,
106
mail_storage_get_list_flags(_storage->flags));
111
get_nonexisting_user_location(struct shared_storage *storage,
112
const char *username, string_t *location)
114
/* user wasn't found. we'll still need to create the storage
115
to avoid exposing which users exist and which don't. */
116
str_append(location, storage->storage_class->name);
117
str_append_c(location, ':');
119
/* use a reachable but non-existing path as the mail root directory */
120
str_append(location, storage->base_dir);
121
str_append(location, "/user-not-found/");
122
str_append(location, username);
125
int shared_storage_get_namespace(struct mail_storage *_storage,
127
struct mail_namespace **ns_r)
129
struct shared_storage *storage = (struct shared_storage *)_storage;
130
struct mail_user *user = _storage->ns->user;
131
static struct var_expand_table static_tab[] = {
132
{ 'u', NULL, "user" },
133
{ 'n', NULL, "username" },
134
{ 'd', NULL, "domain" },
135
{ 'h', NULL, "home" },
138
struct var_expand_table *tab;
139
struct mail_namespace *ns;
140
struct mail_user *owner;
141
const char *domain = NULL, *username = NULL, *userdomain = NULL;
142
const char *name, *p, *next, **dest, *error;
143
string_t *prefix, *location;
148
p = storage->ns_prefix_pattern;
149
for (name = *_name; *p != '\0';) {
167
/* we checked this already above */
172
next = strchr(name, *p != '\0' ? *p : _storage->ns->sep);
178
*dest = t_strdup_until(name, next);
183
(name[1] == '\0' && *name == _storage->ns->sep)) {
184
/* trying to open <prefix>/<user> mailbox */
187
mail_storage_set_critical(_storage,
188
"Invalid namespace prefix %s vs %s",
189
storage->ns_prefix_pattern, *_name);
194
/* successfully matched the name. */
195
if (userdomain != NULL) {
196
/* user@domain given */
197
domain = strchr(userdomain, '@');
199
username = userdomain;
201
username = t_strdup_until(userdomain, domain);
204
} else if (username == NULL) {
205
/* trying to open namespace "shared/domain"
207
mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
208
T_MAIL_ERR_MAILBOX_NOT_FOUND(*_name));
211
if (domain == NULL) {
212
/* no domain given, use ours (if we have one) */
213
domain = strchr(user->username, '@');
214
if (domain != NULL) domain++;
216
userdomain = domain == NULL ? username :
217
t_strconcat(username, "@", domain, NULL);
219
if (*userdomain == '\0') {
220
mail_storage_set_error(_storage, MAIL_ERROR_PARAMS,
221
"Empty username doesn't exist");
225
/* expand the namespace prefix and see if it already exists.
226
this should normally happen only when the mailbox is being opened */
227
tab = t_malloc(sizeof(static_tab));
228
memcpy(tab, static_tab, sizeof(static_tab));
229
tab[0].value = userdomain;
230
tab[1].value = username;
231
tab[2].value = domain;
233
prefix = t_str_new(128);
234
str_append(prefix, _storage->ns->prefix);
235
var_expand(prefix, storage->ns_prefix_pattern, tab);
237
ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix));
239
*_name = mail_namespace_fix_sep(ns, name);
244
owner = mail_user_init(userdomain);
245
if (!var_has_key(storage->location, 'h', "home"))
248
/* we'll need to look up the user's home directory */
249
if ((ret = mail_user_get_home(owner, &tab[3].value)) < 0) {
250
mail_storage_set_critical(_storage, "Namespace '%s': "
251
"Could not lookup home for user %s",
252
_storage->ns->prefix, userdomain);
253
mail_user_unref(&owner);
258
/* create the new namespace */
259
ns = i_new(struct mail_namespace, 1);
260
ns->type = NAMESPACE_SHARED;
262
ns->prefix = i_strdup(str_c(prefix));
264
ns->flags = (NAMESPACE_FLAG_SUBSCRIPTIONS & _storage->ns->flags) |
265
NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
266
NAMESPACE_FLAG_AUTOCREATED | NAMESPACE_FLAG_INBOX;
267
ns->sep = _storage->ns->sep;
269
location = t_str_new(256);
271
var_expand(location, storage->location, tab);
273
get_nonexisting_user_location(storage, userdomain, location);
274
ns->flags |= NAMESPACE_FLAG_UNUSABLE;
276
if (mail_storage_create(ns, NULL, str_c(location), _storage->flags,
277
_storage->lock_method, &error) < 0) {
278
mail_storage_set_critical(_storage, "Namespace '%s': %s",
280
mail_namespace_destroy(ns);
283
_storage->ns->flags |= NAMESPACE_FLAG_USABLE;
284
*_name = mail_namespace_fix_sep(ns, name);
287
mail_user_add_namespace(user, &ns);
291
static void shared_mailbox_copy_error(struct mail_storage *shared_storage,
292
struct mail_namespace *backend_ns)
295
enum mail_error error;
297
str = mail_storage_get_last_error(backend_ns->storage, &error);
298
mail_storage_set_error(shared_storage, error, str);
301
static int shared_mailbox_create(struct mail_storage *storage,
302
const char *name, bool directory)
304
struct mail_namespace *ns;
307
if (shared_storage_get_namespace(storage, &name, &ns) < 0)
310
ret = mail_storage_mailbox_create(ns->storage, name, directory);
312
shared_mailbox_copy_error(storage, ns);
316
struct mail_storage shared_storage = {
317
MEMBER(name) SHARED_STORAGE_NAME,
318
MEMBER(mailbox_is_file) FALSE, /* unknown at this point */
325
index_storage_destroy,
328
shared_mailbox_create