cmd-login.c \
cmd-logout.c \
cmd-lsub.c \
+ cmd-namespace.c \
cmd-noop.c \
cmd-rename.c \
cmd-search.c \
imap-thread.c \
mail-storage-callbacks.c \
main.c \
+ namespace.c \
rawlog.c
imap-search.h \
imap-sort.h \
imap-thread.h \
+ namespace.h \
rawlog.h
#include "istream.h"
#include "ostream.h"
#include "commands.h"
+#include "namespace.h"
#include <stdlib.h>
"Disconnected for inactivity while waiting for command data.");
}
-struct client *client_create(int hin, int hout, struct mail_storage *storage)
+struct client *client_create(int hin, int hout, struct namespace *namespaces)
{
struct client *client;
client->mailbox_flags.pool =
pool_alloconly_create("mailbox_custom_flags", 512);
- client->storage = storage;
- storage->set_callbacks(storage, &mail_storage_callbacks, client);
+ client->namespaces = namespaces;
+
+ while (namespaces != NULL) {
+ namespaces->storage->set_callbacks(namespaces->storage,
+ &mail_storage_callbacks,
+ client);
+ namespaces = namespaces->next;
+ }
i_assert(my_client == NULL);
my_client = client;
if (client->mailbox != NULL)
client->mailbox->close(client->mailbox);
- mail_storage_destroy(client->storage);
+ namespace_deinit(client->namespaces);
imap_parser_destroy(client->parser);
io_remove(client->io);
struct istream *input;
struct ostream *output;
- struct mail_storage *storage;
+ struct namespace *namespaces;
struct mailbox *mailbox;
struct mailbox_custom_flags mailbox_flags;
unsigned int select_counter; /* increased when mailbox is changed */
/* Create new client with specified input/output handles. socket specifies
if the handle is a socket. */
-struct client *client_create(int hin, int hout, struct mail_storage *storage);
+struct client *client_create(int hin, int hout, struct namespace *namespaces);
void client_destroy(struct client *client);
/* Disconnect client connection */
int cmd_append(struct client *client)
{
+ struct mail_storage *storage;
struct mailbox *box;
struct mailbox_status status;
struct mail_save_context *ctx;
if (!client_verify_mailbox_name(client, mailbox, TRUE, FALSE))
return TRUE;
- box = client->storage->open_mailbox(client->storage,
- mailbox, mailbox_open_flags |
- MAILBOX_OPEN_FAST);
+ storage = client_find_storage(client, mailbox);
+ if (storage == NULL)
+ return TRUE;
+
+ box = storage->open_mailbox(storage, mailbox,
+ mailbox_open_flags | MAILBOX_OPEN_FAST);
if (box == NULL) {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
return TRUE;
}
if (!box->get_status(box, STATUS_CUSTOM_FLAGS, &status)) {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
box->close(box);
return TRUE;
}
ctx = box->save_init(box, TRUE);
if (ctx == NULL) {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
return TRUE;
}
client->input->v_offset + msg_size);
if (!box->save_next(ctx, &flags, internal_date,
timezone_offset, client->input)) {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
break;
}
i_stream_set_read_limit(client->input, 0);
if (!box->save_deinit(ctx, failed)) {
failed = TRUE;
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
}
box->close(box);
client->mailbox = NULL;
if (!mailbox->is_readonly(mailbox)) {
- if (!imap_expunge(mailbox, FALSE))
- client_send_untagged_storage_error(client);
+ if (!imap_expunge(mailbox, FALSE)) {
+ client_send_untagged_storage_error(client,
+ mailbox->storage);
+ }
}
if (!mailbox->close(mailbox))
- client_send_untagged_storage_error(client);
+ client_send_untagged_storage_error(client, mailbox->storage);
client_send_tagline(client, "OK Close completed.");
return TRUE;
int cmd_copy(struct client *client)
{
+ struct mail_storage *storage;
struct mailbox *destbox;
struct mail_copy_context *copy_ctx;
const char *messageset, *mailbox;
if (!client_verify_mailbox_name(client, mailbox, TRUE, FALSE))
return TRUE;
- destbox = client->storage->open_mailbox(client->storage,
- mailbox, mailbox_open_flags |
- MAILBOX_OPEN_FAST);
+ storage = client_find_storage(client, mailbox);
+ if (storage == NULL)
+ return TRUE;
+
+ destbox = storage->open_mailbox(storage, mailbox,
+ mailbox_open_flags | MAILBOX_OPEN_FAST);
if (destbox == NULL) {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
return TRUE;
}
(void)destbox->lock(destbox, MAILBOX_LOCK_UNLOCK);
if (failed)
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
else if (!all_found) {
/* some messages were expunged, sync them */
client_sync_full(client);
int cmd_create(struct client *client)
{
+ struct mail_storage *storage;
const char *mailbox;
int only_hiearchy;
size_t len;
if (!client_read_string_args(client, 1, &mailbox))
return FALSE;
+ storage = client_find_storage(client, mailbox);
+ if (storage == NULL)
+ return TRUE;
+
len = strlen(mailbox);
- if (mailbox[len-1] != client->storage->hierarchy_sep)
+ if (mailbox[len-1] != storage->hierarchy_sep)
only_hiearchy = FALSE;
else {
/* name ends with hierarchy separator - client is just
if (!client_verify_mailbox_name(client, mailbox, FALSE, TRUE))
return TRUE;
- if (!client->storage->create_mailbox(client->storage, mailbox,
- only_hiearchy)) {
- client_send_storage_error(client);
+ if (!storage->create_mailbox(storage, mailbox, only_hiearchy)) {
+ client_send_storage_error(client, storage);
return TRUE;
}
int cmd_delete(struct client *client)
{
+ struct mail_storage *storage;
struct mailbox *mailbox;
const char *name;
mailbox = client->mailbox;
if (mailbox != NULL && strcmp(mailbox->name, name) == 0) {
/* deleting selected mailbox. close it first */
+ storage = mailbox->storage;
client->mailbox = NULL;
if (!mailbox->close(mailbox))
- client_send_untagged_storage_error(client);
+ client_send_untagged_storage_error(client, storage);
+ } else {
+ storage = client_find_storage(client, name);
+ if (storage == NULL)
+ return TRUE;
}
- if (client->storage->delete_mailbox(client->storage, name))
+ if (storage->delete_mailbox(storage, name))
client_send_tagline(client, "OK Delete completed.");
else
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
return TRUE;
}
if (imap_expunge(client->mailbox, TRUE))
client_send_tagline(client, "OK Expunge completed.");
else
- client_send_storage_error(client);
+ client_send_storage_error(client, client->mailbox->storage);
return TRUE;
}
client_send_tagline(client, ret > 0 ? "OK Fetch completed." :
"NO Some of the requested messages no longer exist.");
} else {
- client_send_storage_error(client);
+ client_send_storage_error(client, client->mailbox->storage);
}
return TRUE;
if (!client->mailbox->get_status(client->mailbox, STATUS_MESSAGES,
&status)) {
- client_send_untagged_storage_error(client);
+ client_send_untagged_storage_error(client,
+ client->mailbox->storage);
idle_finish(client, TRUE);
} else {
client->idle_expunge = status.messages+1;
return *str == '\0' ? "" : str+1;
}
-static int mailbox_list(struct client *client, const char *mask,
- const char *sep, const char *reply,
+static int mailbox_list(struct client *client, struct mail_storage *storage,
+ const char *mask, const char *sep, const char *reply,
enum mailbox_list_flags list_flags, int listext)
{
struct mailbox_list_context *ctx;
struct mailbox_list *list;
string_t *str;
- ctx = client->storage->list_mailbox_init(client->storage, mask,
- list_flags);
+ ctx = storage->list_mailbox_init(storage, mask, list_flags);
if (ctx == NULL)
return FALSE;
str = t_str_new(256);
- while ((list = client->storage->list_mailbox_next(ctx)) != NULL) {
+ while ((list = storage->list_mailbox_next(ctx)) != NULL) {
str_truncate(str, 0);
str_printfa(str, "* %s (%s) \"%s\" ", reply,
mailbox_flags2str(list->flags, listext),
client_send_line(client, str_c(str));
}
- return client->storage->list_mailbox_deinit(ctx);
+ return storage->list_mailbox_deinit(ctx);
}
static int parse_list_flags(struct client *client, struct imap_arg *args,
int _cmd_list_full(struct client *client, int lsub)
{
+ struct mail_storage *storage;
struct imap_arg *args;
enum mailbox_list_flags list_flags;
const char *ref, *mask;
char sep_chr, sep[3];
int failed, listext;
- sep_chr = client->storage->hierarchy_sep;
- if (IS_ESCAPED_CHAR(sep_chr)) {
+ storage = client_find_storage(client, "");
+ if (storage == NULL)
+ return TRUE;
+
+ sep_chr = storage->hierarchy_sep;
+ if (sep_chr == '"' || sep_chr == '\\') {
sep[0] = '\\';
sep[1] = sep_chr;
sep[2] = '\0';
}
}
- failed = !mailbox_list(client, mask, sep,
+ failed = !mailbox_list(client, storage, mask, sep,
lsub ? "LSUB" : "LIST",
list_flags, listext);
}
if (failed)
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
else {
client_send_tagline(client, lsub ?
"OK Lsub completed." :
--- /dev/null
+/* Copyright (C) 2003 Timo Sirainen */
+
+#include "common.h"
+#include "str.h"
+#include "imap-quote.h"
+#include "commands.h"
+#include "namespace.h"
+
+static void list_namespaces(struct namespace *ns, enum namespace_type type,
+ string_t *str)
+{
+ int found = FALSE;
+
+ while (ns != NULL) {
+ if (ns->type == type) {
+ if (!found) {
+ str_append_c(str, '(');
+ found = TRUE;
+ }
+ str_append_c(str, '(');
+ imap_quote_append_string(str, ns->prefix, FALSE);
+ str_append(str, " \"");
+ if (ns->hierarchy_sep == '"' ||
+ ns->hierarchy_sep == '\\')
+ str_append_c(str, '\\');
+ str_append_c(str, ns->hierarchy_sep);
+ str_append(str, "\")");
+ }
+
+ ns = ns->next;
+ }
+
+ if (found)
+ str_append_c(str, ')');
+ else
+ str_append(str, "NIL");
+}
+
+int cmd_namespace(struct client *client)
+{
+ string_t *str;
+
+ str = t_str_new(256);
+ str_append(str, "* NAMESPACE ");
+
+ list_namespaces(client->namespaces, NAMESPACE_PRIVATE, str);
+ str_append_c(str, ' ');
+ list_namespaces(client->namespaces, NAMESPACE_SHARED, str);
+ str_append_c(str, ' ');
+ list_namespaces(client->namespaces, NAMESPACE_PUBLIC, str);
+
+ client_send_line(client, str_c(str));
+ client_send_tagline(client, "OK Namespace completed.");
+ return TRUE;
+}
int cmd_rename(struct client *client)
{
+ struct mail_storage *old_storage, *new_storage;
const char *oldname, *newname;
/* <old name> <new name> */
if (!client_verify_mailbox_name(client, newname, FALSE, TRUE))
return TRUE;
- if (client->storage->rename_mailbox(client->storage,
- oldname, newname))
+ old_storage = client_find_storage(client, oldname);
+ if (old_storage == NULL)
+ return TRUE;
+
+ new_storage = client_find_storage(client, newname);
+ if (new_storage == NULL)
+ return TRUE;
+
+ if (old_storage != new_storage) {
+ client_send_tagline(client,
+ "NO Can't rename mailbox to another namespace.");
+ return TRUE;
+ }
+
+ if (old_storage->rename_mailbox(old_storage, oldname, newname))
client_send_tagline(client, "OK Rename completed.");
else
- client_send_storage_error(client);
+ client_send_storage_error(client, old_storage);
return TRUE;
}
client_sync_without_expunges(client);
client_send_tagline(client, "OK Search completed.");
} else {
- client_send_storage_error(client);
+ client_send_storage_error(client, client->mailbox->storage);
}
pool_unref(pool);
int _cmd_select_full(struct client *client, int readonly)
{
+ struct mail_storage *storage;
struct mailbox *box;
struct mailbox_status status;
enum mailbox_open_flags flags;
if (client->mailbox != NULL) {
box = client->mailbox;
client->mailbox = NULL;
- if (!box->close(box))
- client_send_untagged_storage_error(client);
+ if (!box->close(box)) {
+ client_send_untagged_storage_error(client,
+ box->storage);
+ }
}
+ storage = client_find_storage(client, mailbox);
+ if (storage == NULL)
+ return TRUE;
+
flags = mailbox_open_flags;
if (readonly)
flags |= MAILBOX_OPEN_READONLY;
- box = client->storage->open_mailbox(client->storage, mailbox, flags);
+ box = storage->open_mailbox(storage, mailbox, flags);
if (box == NULL) {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
return TRUE;
}
if (!box->get_status(box, STATUS_MESSAGES | STATUS_RECENT |
STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY |
STATUS_UIDNEXT | STATUS_CUSTOM_FLAGS, &status)) {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
box->close(box);
return TRUE;
}
client_sync_without_expunges(client);
client_send_tagline(client, "OK Sort completed.");
} else {
- client_send_storage_error(client);
+ client_send_storage_error(client, client->mailbox->storage);
}
pool_unref(pool);
return strcasecmp(box1, "INBOX") == 0 && strcasecmp(box2, "INBOX") == 0;
}
-static int get_mailbox_status(struct client *client, const char *mailbox,
+static int get_mailbox_status(struct client *client,
+ struct mail_storage *storage, const char *mailbox,
enum mailbox_status_items items,
struct mailbox_status *status)
{
box = client->mailbox;
} else {
/* open the mailbox */
- box = client->storage->open_mailbox(client->storage,
- mailbox,
- mailbox_open_flags |
- MAILBOX_OPEN_FAST |
- MAILBOX_OPEN_READONLY);
+ box = storage->open_mailbox(storage, mailbox,
+ mailbox_open_flags |
+ MAILBOX_OPEN_FAST |
+ MAILBOX_OPEN_READONLY);
if (box == NULL)
return FALSE;
}
struct imap_arg *args;
struct mailbox_status status;
enum mailbox_status_items items;
+ struct mail_storage *storage;
const char *mailbox;
string_t *str;
return TRUE;
}
+ storage = client_find_storage(client, mailbox);
+ if (storage == NULL)
+ return FALSE;
+
/* get status */
- if (!get_mailbox_status(client, mailbox, items, &status)) {
- client_send_storage_error(client);
+ if (!get_mailbox_status(client, storage, mailbox, items, &status)) {
+ client_send_storage_error(client, storage);
return TRUE;
}
client_send_tagline(client, all_found ? "OK Store completed." :
"NO Some of the messages no longer exist.");
} else {
- client_send_storage_error(client);
+ client_send_storage_error(client, client->mailbox->storage);
}
return TRUE;
int _cmd_subscribe_full(struct client *client, int subscribe)
{
+ struct mail_storage *storage;
const char *mailbox;
/* <mailbox> */
if (!client_verify_mailbox_name(client, mailbox, subscribe, FALSE))
return TRUE;
- if (client->storage->set_subscribed(client->storage,
- mailbox, subscribe)) {
+ storage = client_find_storage(client, mailbox);
+ if (storage == NULL)
+ return FALSE;
+
+ if (storage->set_subscribed(storage, mailbox, subscribe)) {
client_send_tagline(client, subscribe ?
"OK Subscribe completed." :
"OK Unsubscribe completed.");
} else {
- client_send_storage_error(client);
+ client_send_storage_error(client, storage);
}
return TRUE;
client_sync_without_expunges(client);
client_send_tagline(client, "OK Search completed.");
} else {
- client_send_storage_error(client);
+ client_send_storage_error(client, client->mailbox->storage);
}
pool_unref(pool);
client->mailbox = NULL;
if (!mailbox->close(mailbox))
- client_send_untagged_storage_error(client);
+ client_send_untagged_storage_error(client, mailbox->storage);
client_send_tagline(client, "OK Unselect completed.");
return TRUE;
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
#include "common.h"
#include "str.h"
#include "imap-util.h"
#include "mail-storage.h"
#include "imap-parser.h"
+#include "namespace.h"
/* Maximum length for mailbox name, including it's path. This isn't fully
exact since the user can create folder hierarchy with small names, then
to them, mbox/maildir currently allow paths only up to PATH_MAX. */
#define MAILBOX_MAX_NAME_LEN 512
+struct mail_storage *
+client_find_storage(struct client *client, const char *mailbox)
+{
+ struct namespace *ns;
+
+ ns = namespace_find(client->namespaces, mailbox);
+ if (ns != NULL)
+ return ns->storage;
+
+ client_send_tagline(client, "NO Unknown namespace.");
+ return NULL;
+}
+
int client_verify_mailbox_name(struct client *client, const char *mailbox,
int should_exist, int should_not_exist)
{
+ struct mail_storage *storage;
enum mailbox_name_status mailbox_status;
const char *p;
char sep;
+ storage = client_find_storage(client, mailbox);
+ if (storage == NULL)
+ return FALSE;
+
/* make sure it even looks valid */
- sep = client->storage->hierarchy_sep;
+ sep = storage->hierarchy_sep;
if (*mailbox == '\0' || strspn(mailbox, "\r\n*%?") != 0) {
client_send_tagline(client, "NO Invalid mailbox name.");
return FALSE;
}
/* check what our storage thinks of it */
- if (!client->storage->get_mailbox_name_status(client->storage, mailbox,
- &mailbox_status)) {
- client_send_storage_error(client);
+ if (!storage->get_mailbox_name_status(storage, mailbox,
+ &mailbox_status)) {
+ client_send_storage_error(client, storage);
return FALSE;
}
void client_sync_full(struct client *client)
{
- if (client->mailbox != NULL) {
- if (!client->mailbox->sync(client->mailbox, 0))
- client_send_untagged_storage_error(client);
+ if (client->mailbox == NULL)
+ return;
+
+ if (!client->mailbox->sync(client->mailbox, 0)) {
+ client_send_untagged_storage_error(client,
+ client->mailbox->storage);
}
}
void client_sync_full_fast(struct client *client)
{
- if (client->mailbox != NULL) {
- if (!client->mailbox->sync(client->mailbox,
- MAIL_SYNC_FLAG_FAST))
- client_send_untagged_storage_error(client);
+ if (client->mailbox == NULL)
+ return;
+
+ if (!client->mailbox->sync(client->mailbox, MAIL_SYNC_FLAG_FAST)) {
+ client_send_untagged_storage_error(client,
+ client->mailbox->storage);
}
}
void client_sync_without_expunges(struct client *client)
{
- if (client->mailbox != NULL) {
- if (!client->mailbox->sync(client->mailbox,
- MAIL_SYNC_FLAG_NO_EXPUNGES |
- MAIL_SYNC_FLAG_FAST))
- client_send_untagged_storage_error(client);
+ if (client->mailbox == NULL)
+ return;
+
+ if (!client->mailbox->sync(client->mailbox, MAIL_SYNC_FLAG_NO_EXPUNGES |
+ MAIL_SYNC_FLAG_FAST)) {
+ client_send_untagged_storage_error(client,
+ client->mailbox->storage);
}
}
-void client_send_storage_error(struct client *client)
+void client_send_storage_error(struct client *client,
+ struct mail_storage *storage)
{
const char *error;
int syntax;
return;
}
- error = client->storage->get_last_error(client->storage, &syntax);
+ error = storage->get_last_error(storage, &syntax);
client_send_tagline(client, t_strconcat(syntax ? "BAD " : "NO ",
error, NULL));
}
-void client_send_untagged_storage_error(struct client *client)
+void client_send_untagged_storage_error(struct client *client,
+ struct mail_storage *storage)
{
const char *error;
int syntax;
return;
}
- error = client->storage->get_last_error(client->storage, &syntax);
+ error = storage->get_last_error(storage, &syntax);
client_send_line(client,
t_strconcat(syntax ? "* BAD " : "* NO ", error, NULL));
}
struct mail_full_flags;
+/* Finds mail storage for given mailbox from namespaces. If not found,
+ sends "Unknown namespace" error message to client. */
+struct mail_storage *
+client_find_storage(struct client *client, const char *mailbox);
+
/* If should_exist is TRUE, this function returns TRUE if the mailbox
exists. If it doesn't exist but would be a valid mailbox name, the
error message is prefixed with [TRYCREATE].
void client_sync_without_expunges(struct client *client);
/* Send last mail storage error message to client. */
-void client_send_storage_error(struct client *client);
+void client_send_storage_error(struct client *client,
+ struct mail_storage *storage);
/* Send untagged error message to client. */
-void client_send_untagged_storage_error(struct client *client);
+void client_send_untagged_storage_error(struct client *client,
+ struct mail_storage *storage);
/* Parse flags. Returns TRUE if successful, if not sends an error message to
client. */
const struct command imap_ext_commands[] = {
{ "IDLE", cmd_idle },
+ { "NAMESPACE", cmd_namespace },
{ "SORT", cmd_sort },
{ "THREAD", cmd_thread },
{ "UID SORT", cmd_sort },
int cmd_uid(struct client *client);
/* IMAP extensions: */
+int cmd_idle(struct client *client);
+int cmd_namespace(struct client *client);
int cmd_sort(struct client *client);
int cmd_thread(struct client *client);
int cmd_unselect(struct client *client);
-int cmd_idle(struct client *client);
/* private: */
int _cmd_list_full(struct client *client, int lsub);
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
#include "common.h"
#include "ioloop.h"
#include "module-dir.h"
#include "mail-storage.h"
#include "commands.h"
+#include "namespace.h"
#include <stdlib.h>
#include <unistd.h>
static struct module *modules;
static char log_prefix[128]; /* syslog() needs this to be permanent */
+static pool_t namespace_pool;
void (*hook_mail_storage_created)(struct mail_storage **storage) = NULL;
void (*hook_client_created)(struct client **client) = NULL;
static void main_init(void)
{
struct client *client;
- struct mail_storage *storage;
- const char *user, *mail, *str;
+ const char *user, *str;
int hin, hout;
lib_init_signals(sig_quit);
modules = getenv("MODULE_DIR") == NULL ? NULL :
module_dir_load(getenv("MODULE_DIR"));
- mail = getenv("MAIL");
- if (mail == NULL) {
- /* support also maildir-specific environment */
- mail = getenv("MAILDIR");
- if (mail != NULL)
- mail = t_strconcat("maildir:", mail, NULL);
- }
-
- storage = mail_storage_create_with_data(mail, user, NULL, '\0');
- if (storage == NULL) {
- /* failed */
- if (mail != NULL && *mail != '\0')
- i_fatal("Failed to create storage with data: %s", mail);
- else {
- const char *home;
-
- home = getenv("HOME");
- if (home == NULL) home = "not set";
-
- i_fatal("MAIL environment missing and "
- "autodetection failed (home %s)", home);
- }
- }
-
- if (hook_mail_storage_created != NULL)
- hook_mail_storage_created(&storage);
-
str = getenv("IMAP_MAX_LINE_LENGTH");
imap_max_line_length = str != NULL ?
(unsigned int)strtoul(str, NULL, 10) :
mailbox_open_flags = getenv("MMAP_INVALIDATE") != NULL ?
MAILBOX_OPEN_MMAP_INVALIDATE : 0;
- client = client_create(hin, hout, storage);
+ namespace_pool = pool_alloconly_create("namespaces", 1024);
+ client = client_create(hin, hout, namespace_init(namespace_pool, user));
o_stream_cork(client->output);
if (IS_STANDALONE()) {
clients_deinit();
mail_storage_deinit();
random_deinit();
+ pool_unref(namespace_pool);
closelog();
}
--- /dev/null
+/* Copyright (C) 2003 Timo Sirainen */
+
+#include "common.h"
+#include "commands.h"
+#include "namespace.h"
+
+#include <stdlib.h>
+
+static struct namespace *
+namespace_add_env(pool_t pool, const char *data, unsigned int num,
+ const char *user)
+{
+ struct namespace *ns;
+ const char *sep, *type, *prefix;
+
+ ns = p_new(pool, struct namespace, 1);
+
+ sep = getenv(t_strdup_printf("NAMESPACE_%u_SEP", num));
+ type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num));
+ prefix = getenv(t_strdup_printf("NAMESPACE_%u_PREFIX", num));
+
+ if (type == NULL || *type == '\0' || strncmp(type, "private", 7) == 0)
+ ns->type = NAMESPACE_PRIVATE;
+ else if (strncmp(type, "shared", 6) == 0)
+ ns->type = NAMESPACE_SHARED;
+ else if (strncmp(type, "public", 6) == 0)
+ ns->type = NAMESPACE_PUBLIC;
+ else
+ i_fatal("Unknown namespace type: %s", type);
+
+ if (prefix == NULL)
+ prefix = "";
+
+ ns->prefix = p_strdup(pool, prefix);
+ ns->storage = mail_storage_create_with_data(data, user, ns->prefix,
+ sep != NULL ? *sep : '\0');
+ if (ns->storage == NULL) {
+ i_fatal("Failed to create storage for '%s' with data: %s",
+ ns->prefix, data);
+ }
+
+ if (hook_mail_storage_created != NULL)
+ hook_mail_storage_created(&ns->storage);
+
+ ns->hierarchy_sep = ns->storage->hierarchy_sep;
+ return ns;
+}
+
+struct namespace *namespace_init(pool_t pool, const char *user)
+{
+ struct namespace *namespaces, *ns, **ns_p;
+ const char *mail, *data;
+ unsigned int i;
+
+ namespaces = NULL; ns_p = &namespaces;
+
+ /* first try NAMESPACE_* environments */
+ for (i = 1; ; i++) {
+ t_push();
+ data = getenv(t_strdup_printf("NAMESPACE_%u", i));
+ t_pop();
+
+ if (data == NULL)
+ break;
+
+ t_push();
+ *ns_p = namespace_add_env(pool, data, i, user);
+ t_pop();
+
+ ns_p = &(*ns_p)->next;
+ }
+
+ if (namespaces != NULL)
+ return namespaces;
+
+ /* fallback to MAIL */
+ mail = getenv("MAIL");
+ if (mail == NULL) {
+ /* support also maildir-specific environment */
+ mail = getenv("MAILDIR");
+ if (mail != NULL)
+ mail = t_strconcat("maildir:", mail, NULL);
+ }
+
+ ns = p_new(pool, struct namespace, 1);
+ ns->storage = mail_storage_create_with_data(mail, user, NULL, '\0');
+ if (ns->storage == NULL) {
+ if (mail != NULL && *mail != '\0')
+ i_fatal("Failed to create storage with data: %s", mail);
+ else {
+ const char *home;
+
+ home = getenv("HOME");
+ if (home == NULL) home = "not set";
+
+ i_fatal("MAIL environment missing and "
+ "autodetection failed (home %s)", home);
+ }
+ }
+
+ ns->type = NAMESPACE_PRIVATE;
+ ns->prefix = p_strdup(pool, "");
+ ns->hierarchy_sep = ns->storage->hierarchy_sep;
+ if (hook_mail_storage_created != NULL)
+ hook_mail_storage_created(&ns->storage);
+
+ return ns;
+}
+
+void namespace_deinit(struct namespace *namespaces)
+{
+ while (namespaces != NULL) {
+ mail_storage_destroy(namespaces->storage);
+ namespaces = namespaces->next;
+ }
+}
+
+struct namespace *
+namespace_find(struct namespace *namespaces, const char *mailbox)
+{
+ struct namespace *best = NULL;
+ size_t len, best_len = 0;
+ int inbox;
+
+ inbox = strncasecmp(mailbox, "INBOX", 5) == 0;
+
+ while (namespaces != NULL) {
+ len = namespaces->prefix == NULL ? 0 :
+ strlen(namespaces->prefix);
+ if (len >= best_len &&
+ (strncmp(namespaces->prefix, mailbox, len) == 0 ||
+ (inbox && strncmp(namespaces->prefix, "INBOX", 5) == 0 &&
+ mailbox[5] == namespaces->hierarchy_sep &&
+ namespaces->prefix[5] == namespaces->hierarchy_sep &&
+ strncmp(namespaces->prefix+6, mailbox+6, len-6) == 0))) {
+ best = namespaces;
+ best_len = len;
+ }
+ namespaces = namespaces->next;
+ }
+
+ return best;
+}
--- /dev/null
+#ifndef __NAMESPACE_H
+#define __NAMESPACE_H
+
+enum namespace_type {
+ NAMESPACE_PRIVATE,
+ NAMESPACE_SHARED,
+ NAMESPACE_PUBLIC
+};
+
+struct namespace {
+ struct namespace *next;
+
+ enum namespace_type type;
+ char hierarchy_sep;
+ char *prefix;
+ struct mail_storage *storage;
+};
+
+struct namespace *namespace_init(pool_t pool, const char *user);
+void namespace_deinit(struct namespace *namespaces);
+
+struct namespace *
+namespace_find(struct namespace *namespaces, const char *mailbox);
+
+#endif