]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Getting ready for namespaces. LIST is still broken with them.
authorTimo Sirainen <tss@iki.fi>
Sun, 27 Jul 2003 04:48:32 +0000 (07:48 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 27 Jul 2003 04:48:32 +0000 (07:48 +0300)
--HG--
branch : HEAD

29 files changed:
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 [new file with mode: 0644]
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 [new file with mode: 0644]
src/imap/namespace.h [new file with mode: 0644]

index a63f9eee741ab9d2d0f882f50aa5f863246645f2..892621c1ce9a922e26cfd5d0748b11fe38c5ab0d 100644 (file)
@@ -43,6 +43,7 @@ cmds = \
        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_SOURCES = \
        imap-thread.c \
        mail-storage-callbacks.c \
        main.c \
+       namespace.c \
        rawlog.c
 
 
@@ -82,4 +84,5 @@ noinst_HEADERS = \
        imap-search.h \
        imap-sort.h \
        imap-thread.h \
+       namespace.h \
        rawlog.h
index 09c53d8cbf54b4edb9e2261d186f0a85cbe47817..b5962701176d0a1958a3dc80190fa3797de2e5ac 100644 (file)
@@ -6,6 +6,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "commands.h"
+#include "namespace.h"
 
 #include <stdlib.h>
 
@@ -40,7 +41,7 @@ static void client_input_timeout(void *context)
                "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 @@ struct client *client_create(int hin, int hout, struct mail_storage *storage)
 
        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 @@ void client_destroy(struct 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);
index 49ee80cd588b0ec83ea4564d838a059883c84e38..a1b6f92ae27248ff2118fa6845dec2a7971c356b 100644 (file)
@@ -21,7 +21,7 @@ struct client {
        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 @@ struct client {
 
 /* 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 */
index 1380f21de938d36c8c60aae7cc4e9a70ecf1b654..83990b38f68e1e6d91c216093ee8c267d59136d5 100644 (file)
@@ -45,6 +45,7 @@ static int validate_args(struct imap_arg *args, struct imap_arg_list **flags,
 
 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 @@ int cmd_append(struct client *client)
        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 @@ int cmd_append(struct client *client)
 
        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 @@ int cmd_append(struct client *client)
                                        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 @@ int cmd_append(struct client *client)
 
        if (!box->save_deinit(ctx, failed)) {
                failed = TRUE;
-               client_send_storage_error(client);
+               client_send_storage_error(client, storage);
        }
 
        box->close(box);
index cbbdab859abc7b310f1cc7f153eed91679bd00b1..6f59a9502a18d6d78fdd3a32003881583c842728 100644 (file)
@@ -14,12 +14,14 @@ int cmd_close(struct client *client)
        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;
index c8bd18ba08dcdc6abddeaf51b473a7227d7e7ccc..ce4854a54aa0226040ef21316a52fa3fe5650776 100644 (file)
@@ -31,6 +31,7 @@ static int fetch_and_copy(struct mail_copy_context *copy_ctx,
 
 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 @@ int cmd_copy(struct client *client)
        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 @@ int cmd_copy(struct client *client)
        (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);
index c45714f659e21059057ddb083c9e979e39f9a514..449b98261c61cf84985d59d8414dd5e60c44bbac 100644 (file)
@@ -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 @@ int cmd_create(struct client *client)
        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 @@ int cmd_create(struct client *client)
        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;
        }
 
index 350f8a4cd3bcf9b0d1ededf01405a86b79b03418..4903e6b6679e958c39ce5b1d6fd8550ea109acf6 100644 (file)
@@ -5,6 +5,7 @@
 
 int cmd_delete(struct client *client)
 {
+       struct mail_storage *storage;
        struct mailbox *mailbox;
        const char *name;
 
@@ -21,15 +22,20 @@ int cmd_delete(struct client *client)
        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;
 }
index 719efc923f8a190f8250d1bcaa314857e4e10b20..9e25b34933c4696575ffd8e73688dc704e67386b 100644 (file)
@@ -12,7 +12,7 @@ int cmd_expunge(struct client *client)
        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;
 }
index 871f7c6416da9e27813b1e823014397ffb1c3d20..fbbb78ed6684eeab9140f1bcc6b841ba03a2f958 100644 (file)
@@ -362,7 +362,7 @@ int cmd_fetch(struct client *client)
                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;
index c8c23f2c47718a0ddf2e80607858ee3dd1880dd4..4de5f3619ac132ebe36506a0ca1fb64d60a3e478 100644 (file)
@@ -86,7 +86,8 @@ static void idle_timeout(void *context)
 
        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;
index 0a7344965713237298e60b43f392ae1a0642a96d..e08758dada76080c75eb24f9c7a9467d371a9229 100644 (file)
@@ -34,21 +34,20 @@ static const char *mailbox_flags2str(enum mailbox_flags flags, int listext)
        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 @@ static int mailbox_list(struct client *client, const char *mask,
                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 @@ 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';
@@ -158,13 +162,13 @@ int _cmd_list_full(struct client *client, int lsub)
                        }
                }
 
-               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." :
diff --git a/src/imap/cmd-namespace.c b/src/imap/cmd-namespace.c
new file mode 100644 (file)
index 0000000..6529723
--- /dev/null
@@ -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;
+}
index 91cf6fae777facd45dcafbe6c2bc06e9387f6419..af6777e90929cdf4e5795c6c87b510feea1aa549 100644 (file)
@@ -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 @@ int cmd_rename(struct client *client)
        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;
 }
index b4aa7b14803a45af7b8cfdcfb634c51583a9b752..a6eeb5545ffbfd2dad64dd6569a4d75f7a9dbfd7 100644 (file)
@@ -97,7 +97,7 @@ int cmd_search(struct client *client)
                        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);
index 0134578bb56ae7c1b3e57cd5a2e18109d78c5e42..8066871dd5875e78bba080a0f914981fc1d0c872 100644 (file)
@@ -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 @@ int _cmd_select_full(struct client *client, int readonly)
        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;
        }
index 16d17e24f684a8a0f718b0b1a937d0dad9f0da26..937e6378b0a842a72d4bc2fd741b53fc0aad0990 100644 (file)
@@ -128,7 +128,7 @@ int cmd_sort(struct client *client)
                        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);
index 62c04a377d38e73d1b6e760b440d4e422700f5cf..83226083cd31aba2d1e169aedea6d49d9e4a86d5 100644 (file)
@@ -51,7 +51,8 @@ static int mailbox_name_equals(const char *box1, const char *box2)
        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 @@ static int get_mailbox_status(struct client *client, const char *mailbox,
                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 @@ int cmd_status(struct client *client)
        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 @@ int cmd_status(struct client *client)
                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;
        }
 
index 119d168c36eeafe064b0e94d2508897b41b80e68..e0fa6918c16572ff0916b4e970ecc42a780a2160 100644 (file)
@@ -132,7 +132,7 @@ int cmd_store(struct client *client)
                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;
index 654b8591e18d1e9202c4008903773d9fe52fac4d..6c3ee50d2a947a79b66f1c2cd948c6c0ef6fed41 100644 (file)
@@ -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 @@ int _cmd_subscribe_full(struct client *client, int subscribe)
        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;
index b191d79404fadec4904eb990dbcbb35e1c66d29c..3d97908a5866c086f73e1eb345adbb1149b9c8bf 100644 (file)
@@ -70,7 +70,7 @@ int cmd_thread(struct client *client)
                        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);
index a44475de84aa3d875e653dbb00428c342ae3992d..338affd84b71d2fa0218c983efd3844a9a321da4 100644 (file)
@@ -13,7 +13,7 @@ int cmd_unselect(struct client *client)
        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;
index d56ee4ecc203d90d9dff47368a3baa3942598f5b..671e91b3f5992ff91ffcd70d3c79d47b7febcde6 100644 (file)
@@ -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
    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 @@ int client_verify_mailbox_name(struct client *client, const char *mailbox,
        }
 
        /* 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 @@ int client_verify_open_mailbox(struct client *client)
 
 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 @@ void client_send_storage_error(struct client *client)
                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 @@ void client_send_untagged_storage_error(struct client *client)
                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));
 }
index cdc230c108b3bb62946ba085e005826ce59b2c23..be720b4c0bf20884223aaa271399958798d3dfd5 100644 (file)
@@ -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_full_fast(struct client *client);
 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. */
index 164e99df31bd088b63d5cf57e62ee80da3e925d4..16db0bbd8b15ec0d98da16f6e8dac4ba2634e254 100644 (file)
@@ -43,6 +43,7 @@ const struct command imap4rev1_commands[] = {
 
 const struct command imap_ext_commands[] = {
        { "IDLE",               cmd_idle },
+       { "NAMESPACE",          cmd_namespace },
        { "SORT",               cmd_sort },
        { "THREAD",             cmd_thread },
        { "UID SORT",           cmd_sort },
index 7a044852ababf59e3d94aa4f9ed7c5a1685ecf0f..951393d8a68e2b389f8bca88f06ad5216eda63d4 100644 (file)
@@ -62,10 +62,11 @@ int cmd_copy(struct client *client);
 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);
index 391ddf4b9363b1533ee65d8123123d1e9639e5b0..f2cbe0681e8b1b297abb173600ffc00150288c1c 100644 (file)
@@ -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 @@ enum mailbox_open_flags mailbox_open_flags;
 
 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 drop_privileges(void)
 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 @@ static void main_init(void)
        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 @@ static void main_init(void)
        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 @@ static void main_deinit(void)
        clients_deinit();
         mail_storage_deinit();
        random_deinit();
+       pool_unref(namespace_pool);
 
        closelog();
 }
diff --git a/src/imap/namespace.c b/src/imap/namespace.c
new file mode 100644 (file)
index 0000000..97b1ea5
--- /dev/null
@@ -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;
+}
diff --git a/src/imap/namespace.h b/src/imap/namespace.h
new file mode 100644 (file)
index 0000000..16dcf0a
--- /dev/null
@@ -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