changeset 1654:31c4bb26a1e9 HEAD

Getting ready for namespaces. LIST is still broken with them.
author Timo Sirainen <tss@iki.fi>
date Sun, 27 Jul 2003 07:48:32 +0300
parents 949ecc6c272b
children 26e150912cc6
files src/imap/Makefile.am src/imap/client.c src/imap/client.h src/imap/cmd-append.c src/imap/cmd-close.c src/imap/cmd-copy.c src/imap/cmd-create.c src/imap/cmd-delete.c src/imap/cmd-expunge.c src/imap/cmd-fetch.c src/imap/cmd-idle.c src/imap/cmd-list.c src/imap/cmd-namespace.c src/imap/cmd-rename.c src/imap/cmd-search.c src/imap/cmd-select.c src/imap/cmd-sort.c src/imap/cmd-status.c src/imap/cmd-store.c src/imap/cmd-subscribe.c src/imap/cmd-thread.c src/imap/cmd-unselect.c src/imap/commands-util.c src/imap/commands-util.h src/imap/commands.c src/imap/commands.h src/imap/main.c src/imap/namespace.c src/imap/namespace.h
diffstat 29 files changed, 422 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/Makefile.am	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/Makefile.am	Sun Jul 27 07:48:32 2003 +0300
@@ -43,6 +43,7 @@
 	cmd-login.c \
 	cmd-logout.c \
 	cmd-lsub.c \
+	cmd-namespace.c \
 	cmd-noop.c \
 	cmd-rename.c \
 	cmd-search.c \
@@ -69,6 +70,7 @@
 	imap-thread.c \
 	mail-storage-callbacks.c \
 	main.c \
+	namespace.c \
 	rawlog.c
 
 
@@ -82,4 +84,5 @@
 	imap-search.h \
 	imap-sort.h \
 	imap-thread.h \
+	namespace.h \
 	rawlog.h
--- a/src/imap/client.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/client.c	Sun Jul 27 07:48:32 2003 +0300
@@ -6,6 +6,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "commands.h"
+#include "namespace.h"
 
 #include <stdlib.h>
 
@@ -40,7 +41,7 @@
 		"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;
 
@@ -65,8 +66,14 @@
 
 	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;
@@ -82,7 +89,7 @@
 
 	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);
--- a/src/imap/client.h	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/client.h	Sun Jul 27 07:48:32 2003 +0300
@@ -21,7 +21,7 @@
 	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 */
@@ -46,7 +46,7 @@
 
 /* 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 */
--- a/src/imap/cmd-append.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-append.c	Sun Jul 27 07:48:32 2003 +0300
@@ -45,6 +45,7 @@
 
 int cmd_append(struct client *client)
 {
+	struct mail_storage *storage;
 	struct mailbox *box;
 	struct mailbox_status status;
 	struct mail_save_context *ctx;
@@ -66,16 +67,19 @@
 	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;
 	}
@@ -86,7 +90,7 @@
 
 	ctx = box->save_init(box, TRUE);
 	if (ctx == NULL) {
-		client_send_storage_error(client);
+		client_send_storage_error(client, storage);
 		return TRUE;
 	}
 
@@ -188,7 +192,7 @@
 					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);
@@ -202,7 +206,7 @@
 
 	if (!box->save_deinit(ctx, failed)) {
 		failed = TRUE;
-		client_send_storage_error(client);
+		client_send_storage_error(client, storage);
 	}
 
 	box->close(box);
--- a/src/imap/cmd-close.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-close.c	Sun Jul 27 07:48:32 2003 +0300
@@ -14,12 +14,14 @@
 	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;
--- a/src/imap/cmd-copy.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-copy.c	Sun Jul 27 07:48:32 2003 +0300
@@ -31,6 +31,7 @@
 
 int cmd_copy(struct client *client)
 {
+	struct mail_storage *storage;
 	struct mailbox *destbox;
         struct mail_copy_context *copy_ctx;
 	const char *messageset, *mailbox;
@@ -47,11 +48,14 @@
 	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;
 	}
 
@@ -78,7 +82,7 @@
 	(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);
--- a/src/imap/cmd-create.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-create.c	Sun Jul 27 07:48:32 2003 +0300
@@ -5,6 +5,7 @@
 
 int cmd_create(struct client *client)
 {
+	struct mail_storage *storage;
 	const char *mailbox;
 	int only_hiearchy;
 	size_t len;
@@ -13,8 +14,12 @@
 	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
@@ -27,9 +32,8 @@
 	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;
 	}
 
--- a/src/imap/cmd-delete.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-delete.c	Sun Jul 27 07:48:32 2003 +0300
@@ -5,6 +5,7 @@
 
 int cmd_delete(struct client *client)
 {
+	struct mail_storage *storage;
 	struct mailbox *mailbox;
 	const char *name;
 
@@ -21,15 +22,20 @@
 	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;
 }
--- a/src/imap/cmd-expunge.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-expunge.c	Sun Jul 27 07:48:32 2003 +0300
@@ -12,7 +12,7 @@
 	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;
 }
--- a/src/imap/cmd-fetch.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-fetch.c	Sun Jul 27 07:48:32 2003 +0300
@@ -362,7 +362,7 @@
 		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;
--- a/src/imap/cmd-idle.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-idle.c	Sun Jul 27 07:48:32 2003 +0300
@@ -86,7 +86,8 @@
 
 	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;
--- a/src/imap/cmd-list.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-list.c	Sun Jul 27 07:48:32 2003 +0300
@@ -34,21 +34,20 @@
 	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),
@@ -60,7 +59,7 @@
 		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,
@@ -93,14 +92,19 @@
 
 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';
@@ -158,13 +162,13 @@
 			}
 		}
 
-		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	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imap/cmd-namespace.c	Sun Jul 27 07:48:32 2003 +0300
@@ -0,0 +1,55 @@
+/* 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;
+}
--- a/src/imap/cmd-rename.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-rename.c	Sun Jul 27 07:48:32 2003 +0300
@@ -5,6 +5,7 @@
 
 int cmd_rename(struct client *client)
 {
+	struct mail_storage *old_storage, *new_storage;
 	const char *oldname, *newname;
 
 	/* <old name> <new name> */
@@ -14,11 +15,24 @@
 	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;
 }
--- a/src/imap/cmd-search.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-search.c	Sun Jul 27 07:48:32 2003 +0300
@@ -97,7 +97,7 @@
 			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);
--- a/src/imap/cmd-select.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-select.c	Sun Jul 27 07:48:32 2003 +0300
@@ -5,6 +5,7 @@
 
 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;
@@ -17,23 +18,29 @@
 	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;
 	}
--- a/src/imap/cmd-sort.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-sort.c	Sun Jul 27 07:48:32 2003 +0300
@@ -128,7 +128,7 @@
 			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);
--- a/src/imap/cmd-status.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-status.c	Sun Jul 27 07:48:32 2003 +0300
@@ -51,7 +51,8 @@
 	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)
 {
@@ -64,11 +65,10 @@
 		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;
 	}
@@ -86,6 +86,7 @@
 	struct imap_arg *args;
 	struct mailbox_status status;
 	enum mailbox_status_items items;
+	struct mail_storage *storage;
 	const char *mailbox;
 	string_t *str;
 
@@ -106,9 +107,13 @@
 		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;
 	}
 
--- a/src/imap/cmd-store.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-store.c	Sun Jul 27 07:48:32 2003 +0300
@@ -132,7 +132,7 @@
 		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;
--- a/src/imap/cmd-subscribe.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-subscribe.c	Sun Jul 27 07:48:32 2003 +0300
@@ -5,6 +5,7 @@
 
 int _cmd_subscribe_full(struct client *client, int subscribe)
 {
+        struct mail_storage *storage;
 	const char *mailbox;
 
 	/* <mailbox> */
@@ -14,13 +15,16 @@
 	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;
--- a/src/imap/cmd-thread.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-thread.c	Sun Jul 27 07:48:32 2003 +0300
@@ -70,7 +70,7 @@
 			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);
--- a/src/imap/cmd-unselect.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/cmd-unselect.c	Sun Jul 27 07:48:32 2003 +0300
@@ -13,7 +13,7 @@
 	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;
--- a/src/imap/commands-util.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/commands-util.c	Sun Jul 27 07:48:32 2003 +0300
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "common.h"
 #include "str.h"
@@ -6,6 +6,7 @@
 #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
@@ -13,15 +14,33 @@
    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;
@@ -41,9 +60,9 @@
 	}
 
 	/* 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;
 	}
 
@@ -93,32 +112,40 @@
 
 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;
@@ -131,12 +158,13 @@
 		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;
@@ -149,7 +177,7 @@
 		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));
 }
--- a/src/imap/commands-util.h	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/commands-util.h	Sun Jul 27 07:48:32 2003 +0300
@@ -3,6 +3,11 @@
 
 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].
@@ -27,10 +32,12 @@
 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. */
--- a/src/imap/commands.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/commands.c	Sun Jul 27 07:48:32 2003 +0300
@@ -43,6 +43,7 @@
 
 const struct command imap_ext_commands[] = {
 	{ "IDLE",		cmd_idle },
+	{ "NAMESPACE",		cmd_namespace },
 	{ "SORT",		cmd_sort },
 	{ "THREAD",		cmd_thread },
 	{ "UID SORT",		cmd_sort },
--- a/src/imap/commands.h	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/commands.h	Sun Jul 27 07:48:32 2003 +0300
@@ -62,10 +62,11 @@
 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);
--- a/src/imap/main.c	Sun Jul 27 07:35:44 2003 +0300
+++ b/src/imap/main.c	Sun Jul 27 07:48:32 2003 +0300
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "common.h"
 #include "ioloop.h"
@@ -13,6 +13,7 @@
 #include "module-dir.h"
 #include "mail-storage.h"
 #include "commands.h"
+#include "namespace.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -28,6 +29,7 @@
 
 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;
@@ -85,8 +87,7 @@
 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);
@@ -113,33 +114,6 @@
 	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) :
@@ -157,7 +131,8 @@
 	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()) {
@@ -185,6 +160,7 @@
 	clients_deinit();
         mail_storage_deinit();
 	random_deinit();
+	pool_unref(namespace_pool);
 
 	closelog();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imap/namespace.c	Sun Jul 27 07:48:32 2003 +0300
@@ -0,0 +1,143 @@
+/* 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	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imap/namespace.h	Sun Jul 27 07:48:32 2003 +0300
@@ -0,0 +1,25 @@
+#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