2007-05-23 Murray Cumming <murrayc@murrayc.com>
authorMurray Cumming <murrayc@murrayc.com>
Wed, 23 May 2007 14:05:45 +0000 (14:05 +0000)
committerMurray Cumming <murrayc@murrayc.com>
Wed, 23 May 2007 14:05:45 +0000 (14:05 +0000)
Modest on-disk outbox directories are now here, for instance:
        /home/murrayc/.modest/outboxes/<account-id-1>/outbox
        /home/murrayc/.modest/outboxes/<account-id-2>/outbox
        instead of here:
        /home/murrayc/.modest/local-folders/outbox
        so we can have a separate outbox for each account.
        But they are shown as one outbox in the GtkTreeView, by using a
        TnyMergeFolder in a ModestTnySimpleFolderStore.

        * src/Makefile.am:
        * src/modest-tny-simple-folder-store.c:
        * src/modest-tny-simple-folder-store.h:
        Added ModestTnySimpleFolderStore, used to contain folders from
        other folder stores, such as other accounts.

        * src/modest-tny-outbox-account.h:
        * src/modest-tny-outbox-account.c:
        Added ModestTnyOutboxAccount, derived from TnyCamelStoreAccount,
        used for the per-account local outbox folders.

        * src/modest-defs.h: Rename MODEST_LOCAL_FOLDERS_ACCOUNT_ID to
        MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID, to make it clearer that we
        only use this (internally) now for the non-outbox local folders.

        * src/modest-init.h:
        * src/modest-init.c: Added modest_init_one_local_folder(), for
        setting up the directory structure for each local folder.

        * src/modest-local-folder-info.c:
        (modest_per_account_local_outbox_folder_info_get_maildir_path),
        (modest_per_account_local_outbox_folder_info_get_maildir_path_to_ou
        tbox_folder):
        * src/modest-local-folder-info.h:
        * src/modest-tny-account-store.c: (on_account_removed),
        (on_account_changed), (create_per_account_local_outbox_folders),
        (get_server_accounts), (modest_tny_account_store_get_accounts),
        (modest_tny_account_store_get_tny_account_by_account),
        (modest_tny_folder_store_is_virtual_local_folders):

        * src/modest-tny-account.h:
        * src/modest-tny-account.c:
        Added modest_tny_account_new_for_per_account_local_outbox_folder(),
        to create an on-disk per-account local outbox folder for each
        transport account.
        (create_per_account_local_outbox_folders): Create a local outbox folder
        for each transport account.
        (modest_tny_account_new_for_local_folders): Do not create an outbox folder
        for all local folders.

        Added modest_tny_account_get/set_parent_modest_account_name_for_server_account()
        instead of using g_object_get/set() directly. It is clearer.

        (modest_tny_folder_store_get_message_count),
        (modest_tny_folder_store_get_local_size
        (modest_tny_folder_store_get_folder_count): Renamed from modest_tny_account*,
        because we now use these with non-acount folder stores.

        (modest_tny_account_get_special_folder),
        (modest_tny_account_new_from_server_account),
        (modest_tny_account_new_from_account):
        (recurse_folders): Adjust to the new outbox system.

        * src/modest-tny-folder.h:
        * src/modest-tny-folder.c:
        (modest_tny_folder_is_local_folder),
        (modest_tny_folder_get_local_folder_type),
        (modest_tny_folder_is_outbox_for_account): Adjust for the new outbox system.

        * src/widgets/modest-main-window.h:
        * src/maemo/modest-main-window.c: (create_details_widget),
        (modest_main_window_set_contents_style): Show details for any folder store,
        not just accounts.

        (modest_tny_folder_get_rules):
        Remove the const. C does not support constness enough for this.

        * src/modest-ui-actions.c:
        update_model(): Use a ModestTnySimpleListStore and a TnyMergeFolder to
        make all outboxes appear as one, in the usual local-folders tree node.

        (set_active_account_from_tny_account),
        (modest_ui_actions_on_folder_selection_changed):
        * src/widgets/modest-folder-view.c: (text_cell_data),
        (icon_cell_data), (filter_row),
        (add_account_folders_to_merged_folder),
        (add_account_folders_to_simple_folder_store), (),
        (get_cmp_rows_type_pos), (cmp_rows),
        (modest_folder_view_set_account_id_of_visible_server_account):
        Adjust to the new outbox system, using generic folder stores and folder
        in the GtkTreeModel.

pmo-trunk-r1963

21 files changed:
ChangeLog2
src/Makefile.am
src/maemo/modest-main-window.c
src/modest-defs.h
src/modest-init.c
src/modest-init.h
src/modest-local-folder-info.c
src/modest-local-folder-info.h
src/modest-tny-account-store.c
src/modest-tny-account-store.h
src/modest-tny-account.c
src/modest-tny-account.h
src/modest-tny-folder.c
src/modest-tny-folder.h
src/modest-tny-outbox-account.c [new file with mode: 0644]
src/modest-tny-outbox-account.h [new file with mode: 0644]
src/modest-tny-simple-folder-store.c [new file with mode: 0644]
src/modest-tny-simple-folder-store.h [new file with mode: 0644]
src/modest-ui-actions.c
src/widgets/modest-folder-view.c
src/widgets/modest-main-window.h

index 22ab4f1..6e70845 100644 (file)
@@ -1,3 +1,96 @@
+2007-05-23  Murray Cumming  <murrayc@murrayc.com>
+
+       Modest on-disk outbox directories are now here, for instance:
+       $HOME/.modest/outboxes/<account-id-1>/outbox
+       $HOME/.modest/outboxes/<account-id-2>/outbox
+       instead of here:
+       $HOME/.modest/local-folders/outbox
+       so we can have a separate outbox for each account.
+       But they are shown as one outbox in the GtkTreeView, by using a 
+       TnyMergeFolder in a ModestTnySimpleFolderStore.
+       
+       * src/Makefile.am:
+       * src/modest-tny-simple-folder-store.c:
+       * src/modest-tny-simple-folder-store.h:
+       Added ModestTnySimpleFolderStore, used to contain folders from 
+       other folder stores, such as other accounts.
+       
+       * src/modest-tny-outbox-account.h:
+       * src/modest-tny-outbox-account.c:
+       Added ModestTnyOutboxAccount, derived from TnyCamelStoreAccount, 
+       used for the per-account local outbox folders.
+       
+       * src/modest-defs.h: Rename MODEST_LOCAL_FOLDERS_ACCOUNT_ID to 
+       MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID, to make it clearer that we 
+       only use this (internally) now for the non-outbox local folders.
+
+       * src/modest-init.h:
+       * src/modest-init.c: Added modest_init_one_local_folder(), for 
+       setting up the directory structure for each local folder.
+
+       * src/modest-local-folder-info.c:
+       (modest_per_account_local_outbox_folder_info_get_maildir_path),
+       (modest_per_account_local_outbox_folder_info_get_maildir_path_to_ou
+       tbox_folder):
+       * src/modest-local-folder-info.h:
+       * src/modest-tny-account-store.c: (on_account_removed),
+       (on_account_changed), (create_per_account_local_outbox_folders),
+       (get_server_accounts), (modest_tny_account_store_get_accounts),
+       (modest_tny_account_store_get_tny_account_by_account),
+       (modest_tny_folder_store_is_virtual_local_folders):
+
+       * src/modest-tny-account.h:
+       * src/modest-tny-account.c:
+       Added modest_tny_account_new_for_per_account_local_outbox_folder(), 
+       to create an on-disk per-account local outbox folder for each 
+       transport account.
+       (create_per_account_local_outbox_folders): Create a local outbox folder 
+       for each transport account.
+       (modest_tny_account_new_for_local_folders): Do not create an outbox folder 
+       for all local folders.
+       
+       Added modest_tny_account_get/set_parent_modest_account_name_for_server_account() 
+       instead of using g_object_get/set() directly. It is clearer.
+       
+       (modest_tny_folder_store_get_message_count),
+       (modest_tny_folder_store_get_local_size
+       (modest_tny_folder_store_get_folder_count): Renamed from modest_tny_account*, 
+       because we now use these with non-acount folder stores.
+       
+       (modest_tny_account_get_special_folder),
+       (modest_tny_account_new_from_server_account),
+       (modest_tny_account_new_from_account):
+       (recurse_folders): Adjust to the new outbox system.
+       
+       * src/modest-tny-folder.h:
+       * src/modest-tny-folder.c: 
+       (modest_tny_folder_is_local_folder),
+       (modest_tny_folder_get_local_folder_type),
+       (modest_tny_folder_is_outbox_for_account): Adjust for the new outbox system.
+       
+       * src/widgets/modest-main-window.h:
+       * src/maemo/modest-main-window.c: (create_details_widget),
+       (modest_main_window_set_contents_style): Show details for any folder store, 
+       not just accounts.
+       
+       (modest_tny_folder_get_rules): 
+       Remove the const. C does not support constness enough for this.
+       
+       * src/modest-ui-actions.c:
+       update_model(): Use a ModestTnySimpleListStore and a TnyMergeFolder to 
+       make all outboxes appear as one, in the usual local-folders tree node.
+       
+       (set_active_account_from_tny_account),
+       (modest_ui_actions_on_folder_selection_changed):
+       * src/widgets/modest-folder-view.c: (text_cell_data),
+       (icon_cell_data), (filter_row),
+       (add_account_folders_to_merged_folder),
+       (add_account_folders_to_simple_folder_store), (),
+       (get_cmp_rows_type_pos), (cmp_rows),
+       (modest_folder_view_set_account_id_of_visible_server_account):
+       Adjust to the new outbox system, using generic folder stores and folders 
+       in the GtkTreeModel.
+
 2007-05-23  Christian Kellner  <ckellner@openismus.com>
 
        * src/modest-mail-operation.c:
 
        * src/modest-tny-account.c:
        (modest_tny_account_new_from_server_account):
-       Excplicitly use ANONYMOUS secure authentication, instead of "PLAIN" for 
+       Explicitly use ANONYMOUS secure authentication, instead of "PLAIN" for 
        SMTP when "None" was chosen by the user. However, with my SMTP server that 
        does not support ANONYMOUS, the emails do not leave the Outbox and I see 
        no error dialog.
index e29b93f..7cd6ea6 100644 (file)
@@ -74,6 +74,8 @@ modest_SOURCES=\
        modest-tny-account-store.h\
        modest-tny-account.c\
        modest-tny-account.h\
+       modest-tny-outbox-account.c\
+       modest-tny-outbox-account.h\
        modest-tny-folder.c \
        modest-tny-folder.h \
        modest-tny-msg.c\
@@ -81,6 +83,8 @@ modest_SOURCES=\
        modest-platform.h\
        modest-tny-platform-factory.c \
        modest-tny-platform-factory.h \
+       modest-tny-simple-folder-store.c \
+       modest-tny-simple-folder-store.h \
        modest-tny-send-queue.c\
        modest-tny-send-queue.h\
        modest-ui-actions.c\
index adb5f15..f1e93f4 100644 (file)
@@ -1122,19 +1122,20 @@ set_alignment (GtkWidget *widget,
 }
 
 static GtkWidget *
-create_details_widget (TnyAccount *account)
+create_details_widget (TnyFolderStore *folder_store)
 {
        GtkWidget *vbox;
        gchar *label;
 
        vbox = gtk_vbox_new (FALSE, 0);
 
-       /* Account description */
-       if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
-               gchar *device_name;
-
+       /* Account description: */
+       
+       if (modest_tny_folder_store_is_virtual_local_folders (folder_store)) {
+               /* Local folders: */
+       
                /* Get device name */
-               device_name = modest_conf_get_string (modest_runtime_get_conf(),
+               gchar *device_name = modest_conf_get_string (modest_runtime_get_conf(),
                                                      MODEST_CONF_DEVICE_NAME, NULL);
    
                label = g_strdup_printf ("%s: %s",
@@ -1143,63 +1144,74 @@ create_details_widget (TnyAccount *account)
                gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
                g_free (device_name);
                g_free (label);
-       } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
-               /* TODO: MMC ? */
-               gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
-       } else {
-               GString *proto;
-
-               /* Put proto in uppercase */
-               proto = g_string_new (tny_account_get_proto (account));
-               proto = g_string_ascii_up (proto);
-
-               label = g_strdup_printf ("%s %s: %s", 
-                                        proto->str,
-                                        _("mcen_fi_remoteroot_account"),
-                                        tny_account_get_name (account));
-               gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
-               g_string_free (proto, TRUE);
-               g_free (label);
+       } else if (TNY_IS_ACCOUNT (folder_store)) {
+               TnyAccount *account = TNY_ACCOUNT(folder_store);
+               
+               if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
+                       /* TODO: MMC ? */
+                       gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
+               } else {
+                       /* Other accounts, such as IMAP and POP: */
+                       
+                       GString *proto;
+       
+                       /* Put proto in uppercase */
+                       proto = g_string_new (tny_account_get_proto (account));
+                       proto = g_string_ascii_up (proto);
+       
+                       label = g_strdup_printf ("%s %s: %s", 
+                                                proto->str,
+                                                _("mcen_fi_remoteroot_account"),
+                                                tny_account_get_name (account));
+                       gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
+                       g_string_free (proto, TRUE);
+                       g_free (label);
+               }
        }
 
        /* Message count */
+       
        label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
-                                modest_tny_account_get_message_count (account));
+                                modest_tny_folder_store_get_message_count (folder_store));
        gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
        g_free (label);
 
        /* Folder count */
        label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
-                                modest_tny_account_get_folder_count (account));
+                                modest_tny_folder_store_get_folder_count (folder_store));
        gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
        g_free (label);
 
        /* Size / Date */
-       if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
+       if (modest_tny_folder_store_is_virtual_local_folders (folder_store)) {
                /* FIXME: format size */
                label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
-                                        modest_tny_account_get_local_size (account));
+                                        modest_tny_folder_store_get_local_size (folder_store));
                gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
                g_free (label);
-       } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
-               gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
-       } else {
-               time_t last_updated;
-               gchar *last_updated_string;
-               /* Get last updated from configuration */
-               last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
-                                                         tny_account_get_id (account), 
-                                                         MODEST_ACCOUNT_LAST_UPDATED, 
-                                                         TRUE);
-               if (last_updated > 0) 
-                       last_updated_string = modest_text_utils_get_display_date(last_updated);
-               else
-                       last_updated_string = g_strdup (_("FIXME: Never"));
-
-               label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
-               gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
-               g_free (last_updated_string);
-               g_free (label);
+       } else if (TNY_IS_ACCOUNT(folder_store)) {
+               TnyAccount *account = TNY_ACCOUNT(folder_store);
+               
+               if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
+                       gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
+               } else {
+                       time_t last_updated;
+                       gchar *last_updated_string;
+                       /* Get last updated from configuration */
+                       last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
+                                                                 tny_account_get_id (account), 
+                                                                 MODEST_ACCOUNT_LAST_UPDATED, 
+                                                                 TRUE);
+                       if (last_updated > 0) 
+                               last_updated_string = modest_text_utils_get_display_date(last_updated);
+                       else
+                               last_updated_string = g_strdup (_("FIXME: Never"));
+       
+                       label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
+                       gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
+                       g_free (last_updated_string);
+                       g_free (label);
+               }
        }
 
        /* Set alignment */
@@ -1213,8 +1225,6 @@ modest_main_window_set_contents_style (ModestMainWindow *self,
                                       ModestMainWindowContentsStyle style)
 {
        ModestMainWindowPrivate *priv;
-       GtkWidget *content;
-       TnyAccount *account;
 
        g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
 
@@ -1229,10 +1239,12 @@ modest_main_window_set_contents_style (ModestMainWindow *self,
 
        /* Remove previous child. Delete it if it was an account
           details widget */
-       content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
-       if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
-               g_object_ref (content);
-       gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
+       GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
+       if (content) {
+               if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
+                       g_object_ref (content);
+               gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
+       }
 
        priv->contents_style = style;
 
@@ -1241,13 +1253,17 @@ modest_main_window_set_contents_style (ModestMainWindow *self,
                wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
                break;
        case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
+       {
                /* TODO: show here account details */
-               account = TNY_ACCOUNT (modest_folder_view_get_selected (priv->folder_view));
-               priv->details_widget = create_details_widget (account);
+               TnyFolderStore *selected_folderstore = 
+                       modest_folder_view_get_selected (priv->folder_view);
+                       
+               priv->details_widget = create_details_widget (selected_folderstore);
 
                wrap_in_scrolled_window (priv->contents_widget, 
-                                        priv->details_widget);
+                                priv->details_widget);
                break;
+       }
        default:
                g_return_if_reached ();
        }
@@ -1275,7 +1291,7 @@ on_configuration_key_changed (ModestConf* conf,
 
        account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
        if (TNY_IS_ACCOUNT (account) &&
-           !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
+           !strcmp (tny_account_get_id (account), MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID)) {
                GList *children;
                GtkLabel *label;
                const gchar *device_name;
index ee32ebb..c12252f 100644 (file)
 #define MODEST_DIR                       ".modest"
 #define MODEST_CACHE_DIR                  "cache"
 
-#define MODEST_LOCAL_FOLDERS_ACCOUNT_ID   "local_folders"
-#define MODEST_LOCAL_FOLDERS_ACCOUNT_NAME MODEST_LOCAL_FOLDERS_ACCOUNT_ID
-#define MODEST_LOCAL_FOLDERS_MAILDIR      MODEST_LOCAL_FOLDERS_ACCOUNT_ID
+/** Sent, Drafts, etc, 
+ * but not outbox, because outbox is a virtual folder merged from the 
+ * various outboxes/<account-name>/outbox folders.
+ */
+#define MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID   "local_folders"
+#define MODEST_LOCAL_FOLDERS_ACCOUNT_NAME MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID
+#define MODEST_LOCAL_FOLDERS_MAILDIR      MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID
+
+/** There is an outboxes/<account-name>/outbox/ folder for each account,
+ * though we merge them so that the user sees only one outbox.
+ */
+#define MODEST_PER_ACCOUNT_LOCAL_OUTBOX_FOLDER_ACCOUNT_ID_PREFIX "outboxes"
+#define MODEST_PER_ACCOUNT_LOCAL_OUTBOX_FOLDERS_MAILDIR MODEST_PER_ACCOUNT_LOCAL_OUTBOX_FOLDER_ACCOUNT_ID_PREFIX
 
 #define MODEST_MMC_ACCOUNT_ID             "mcc"
 #define MODEST_MCC_ACCOUNT_MAILDIR       "/media/mmc1/.Maildir"
index 03de5b7..37016d4 100644 (file)
@@ -106,13 +106,13 @@ static const FolderCols SENT_COLUMNS_TWOLINES[] = {
 
 #ifdef MODEST_PLATFORM_MAEMO
 static const TnyFolderType LOCAL_FOLDERS[] = {
-       TNY_FOLDER_TYPE_OUTBOX,
+/*     TNY_FOLDER_TYPE_OUTBOX, */
        TNY_FOLDER_TYPE_DRAFTS,
        TNY_FOLDER_TYPE_SENT
 };
 #else
 static const TnyFolderType LOCAL_FOLDERS[] = {
-       TNY_FOLDER_TYPE_OUTBOX,
+/*     TNY_FOLDER_TYPE_OUTBOX, */
        TNY_FOLDER_TYPE_DRAFTS,
        TNY_FOLDER_TYPE_SENT,
        TNY_FOLDER_TYPE_TRASH,
@@ -307,6 +307,29 @@ init_header_columns (ModestConf *conf, gboolean overwrite)
        return TRUE;
 }
 
+gboolean modest_init_one_local_folder (gchar *maildir_path)
+{
+       static const gchar* maildirs[] = {
+               "cur", "new", "tmp"
+       };
+       
+       int j;
+       for (j = 0; j != G_N_ELEMENTS(maildirs); ++j) {
+               gchar *dir = g_build_filename (maildir_path,
+                                       maildirs[j],
+                                       NULL);
+               if (g_mkdir_with_parents (dir, 0755) < 0) {
+                       g_printerr ("modest: failed to create %s\n", dir);
+                       g_free (dir);
+                       return FALSE;
+               }
+               
+               g_free (dir);
+       }
+
+       return TRUE;
+}
+
 /**
  * init_local_folders:
  * 
@@ -318,30 +341,22 @@ init_header_columns (ModestConf *conf, gboolean overwrite)
  */
 static gboolean
 init_local_folders  (void)
-{
-       int i;
-       gchar *maildir_path;
-       static const gchar* maildirs[] = {
-               "cur", "new", "tmp"
-       };
-       
-       maildir_path = modest_local_folder_info_get_maildir_path ();
+{      
+       gchar *maildir_path = modest_local_folder_info_get_maildir_path ();
 
+       /* Create each of the standard on-disk folders.
+        * Per-account outbox folders will be created when first needed. */
+       int i;
        for (i = 0; i != G_N_ELEMENTS(LOCAL_FOLDERS); ++i) {
-               int j;
-               for (j = 0; j != G_N_ELEMENTS(maildirs); ++j) {
-                       gchar *dir;
-                       dir = g_build_filename (maildir_path,
+               gchar *dir = g_build_filename (maildir_path,
                                                modest_local_folder_info_get_type_name(LOCAL_FOLDERS[i]),
-                                               maildirs[j],
-                                               NULL);
-                       if (g_mkdir_with_parents (dir, 0755) < 0) {
-                               g_printerr ("modest: failed to create %s\n", dir);
-                               g_free (dir);
-                               g_free (maildir_path);
-                               return FALSE;
-                       }
-                       g_free(dir);
+                                               NULL);                  
+               const gboolean created = modest_init_one_local_folder (dir);
+               g_free(dir);
+               
+               if (!created) {
+                       g_free (maildir_path);
+                       return FALSE;
                }
        }
        
index acb2627..f5c9d43 100644 (file)
@@ -71,6 +71,15 @@ gboolean modest_init_init_ui (gint argc, gchar** argv);
  */
 gboolean modest_init_uninit (void);
 
+/**
+ * modest_init_one_local_folder:
+ *
+ * Create the directory structure for a maildir folder,
+ * so that camel can use it as a maildir folder in a 
+ * local maildir store account.
+ */
+gboolean modest_init_one_local_folder (gchar *maildir_path);
+
 G_END_DECLS
 
 #endif /*__MODEST_INIT_H__*/
index c1956b4..f066809 100644 (file)
@@ -30,6 +30,7 @@
 #include <glib/gi18n.h>
 #include <string.h> /* strcmp */
 #include <modest-local-folder-info.h>
+#include <stdio.h>
 
 typedef struct {
        TnyFolderType   type;
@@ -48,8 +49,10 @@ const ModestLocalFolder ModestLocalFolderMap[] = {
        { TNY_FOLDER_TYPE_ROOT,     "<root>",     N_("<root>")},
        { TNY_FOLDER_TYPE_NOTES,    "notes",      N_("Notes")},
        { TNY_FOLDER_TYPE_DRAFTS,   "drafts",     N_("mcen_me_folder_drafts")},
-       { TNY_FOLDER_TYPE_OUTBOX,   "contacts",   N_("Contacts")},
+/* TODO: Do we want these? If so, they need a type ID: 
+ *     { TNY_FOLDER_TYPE_OUTBOX,   "contacts",   N_("Contacts")},
        { TNY_FOLDER_TYPE_OUTBOX,   "calendar",   N_("Calendar")},
+*/
        { TNY_FOLDER_TYPE_ARCHIVE,  "archive",    N_("Archive")}
 };
 
@@ -110,3 +113,29 @@ modest_local_folder_info_get_maildir_path (void)
                                 NULL);
 }
 
+gchar *modest_per_account_local_outbox_folder_info_get_maildir_path (TnyAccount *account)
+{
+       /* This directory should contain an "outbox" child directory: */
+       return g_build_filename (g_get_home_dir(),
+                                MODEST_DIR,
+                                MODEST_PER_ACCOUNT_LOCAL_OUTBOX_FOLDERS_MAILDIR, 
+                                tny_account_get_id (account),
+                                NULL);
+}
+
+gchar *modest_per_account_local_outbox_folder_info_get_maildir_path_to_outbox_folder (TnyAccount *account)
+{
+       gchar *path_to_account_folder = 
+               modest_per_account_local_outbox_folder_info_get_maildir_path(account);
+       if (!path_to_account_folder)
+               return NULL;
+
+       gchar *path = g_build_filename (path_to_account_folder, "outbox", NULL);
+
+       g_free (path_to_account_folder);
+
+       return path;
+}
+
+
+
index 13b3a33..de83755 100644 (file)
@@ -76,9 +76,8 @@ const gchar* modest_local_folder_info_get_type_display_name (TnyFolderType type)
 
 /**
  * modest_local_folder_info_get_maildir_path
- * @type: the type of the local folder
  * 
- * get the path to the Maildir where the local folders are stored
+ * Get the path to the Maildir where the local folders are stored.
  *  
  * Returns: the local_folders Maildir path as a newly allocated
  * string, which must be freed by the caller.
@@ -86,6 +85,27 @@ const gchar* modest_local_folder_info_get_type_display_name (TnyFolderType type)
  */
 gchar *modest_local_folder_info_get_maildir_path (void);
 
+/**
+ * modest_per_account_local_outbox_folder_info_get_maildir_path
+ * 
+ * Get the path to the Maildir where the per-account local outbox folder is stored.
+ *  
+ * Returns: the local outbox account Maildir path as a newly allocated
+ * string, which must be freed by the caller.
+ *
+ */
+gchar *modest_per_account_local_outbox_folder_info_get_maildir_path (TnyAccount *account);
+
+/**
+ * modest_per_account_local_outbox_folder_info_get_maildir_path_to_outbox_folder
+ * 
+ * Get the path to the "outbox" folder directory under the local outbox account MailDir directory.
+ *  
+ * Returns: the local outbox folder Maildir path as a newly allocated
+ * string, which must be freed by the caller.
+ *
+ */
+gchar *modest_per_account_local_outbox_folder_info_get_maildir_path_to_outbox_folder (TnyAccount *account);
 
 G_END_DECLS
 #endif /* __MODEST_LOCAL_FOLDER_INFO_H__ */
index 824a67d..5c3385f 100644 (file)
@@ -73,7 +73,7 @@ static void    modest_tny_account_store_instance_init (ModestTnyAccountStore *ob
 static void    modest_tny_account_store_init          (gpointer g, gpointer iface_data);
 
 
-static GSList*
+static void
 get_server_accounts  (TnyAccountStore *self, TnyList *list, TnyAccountType type);
 
 
@@ -92,9 +92,17 @@ struct _ModestTnyAccountStorePrivate {
        TnySessionCamel    *session;
        TnyDevice          *device;
        
-       /* we cache them here */
+       /* We cache the lists of accounts here.
+        * They are created in our get_accounts_func() implementation. */
        GSList             *store_accounts;
        GSList             *transport_accounts;
+       
+       /* This is also contained in store_accounts,
+        * but we cached it temporarily separately, 
+        * because we create this while creating the transport accounts, 
+        * but return it when requesting the store accounts: 
+        */
+       GSList             *store_accounts_outboxes;
 };
 
 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
@@ -223,12 +231,16 @@ on_account_removed (ModestAccountMgr *acc_mgr, const gchar *account, gboolean se
         */
        
        account_list_free (priv->store_accounts);
-       priv->store_accounts = get_server_accounts (TNY_ACCOUNT_STORE(self), NULL, TNY_ACCOUNT_TYPE_STORE);
+       get_server_accounts (TNY_ACCOUNT_STORE(self), NULL, TNY_ACCOUNT_TYPE_STORE);
        
        account_list_free (priv->transport_accounts);
-       priv->transport_accounts = get_server_accounts (TNY_ACCOUNT_STORE(self), NULL,
+       get_server_accounts (TNY_ACCOUNT_STORE(self), NULL,
                                                        TNY_ACCOUNT_TYPE_TRANSPORT);
                
+       /* TODO: Ref these when we add them? */
+       g_slist_free (priv->store_accounts_outboxes);
+       priv->store_accounts_outboxes = NULL;
+       
        g_signal_emit (G_OBJECT(self), signals[ACCOUNT_UPDATE_SIGNAL], 0,
                       account);
 }
@@ -248,15 +260,15 @@ on_account_changed (ModestAccountMgr *acc_mgr, const gchar *account,
        if (server_account) {
                if (priv->store_accounts) {
                        account_list_free (priv->store_accounts);
-                       priv->store_accounts =
-                               get_server_accounts (TNY_ACCOUNT_STORE(self),
+                       priv->store_accounts = NULL;
+                       get_server_accounts (TNY_ACCOUNT_STORE(self),
                                                     NULL, TNY_ACCOUNT_TYPE_STORE);
                }
                
                if (priv->transport_accounts) {
                        account_list_free (priv->transport_accounts);
-                       priv->transport_accounts =
-                               get_server_accounts (TNY_ACCOUNT_STORE(self), NULL,
+                       priv->transport_accounts = NULL;
+                       get_server_accounts (TNY_ACCOUNT_STORE(self), NULL,
                                                     TNY_ACCOUNT_TYPE_TRANSPORT);
                }
        }
@@ -465,7 +477,7 @@ modest_tny_account_store_new (ModestAccountMgr *account_mgr, TnyDevice *device)
        return MODEST_TNY_ACCOUNT_STORE(obj);
 }
 
-
+/** Fill the TnyList from the appropriate cached GSList of accounts. */
 static void
 get_cached_accounts (TnyAccountStore *self, TnyList *list, TnyAccountType type)
 {
@@ -482,19 +494,73 @@ get_cached_accounts (TnyAccountStore *self, TnyList *list, TnyAccountType type)
        }
 }
 
+static void
+create_per_account_local_outbox_folders (TnyAccountStore *self)
+{
+       g_return_if_fail (self);
+       
+       ModestTnyAccountStorePrivate *priv = 
+               MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
+       
+       /* printf("DEBUG: %s: priv->store_accounts_outboxes = %p\n", __FUNCTION__, priv->store_accounts_outboxes); */
+               
+       if (priv->store_accounts_outboxes) {
+                       return;
+       }
+       
+       /* Create the transport accounts, if necessary: */
+       if (!(priv->transport_accounts)) {
+               get_server_accounts (self, NULL /* TnyList */, 
+                       TNY_ACCOUNT_TYPE_TRANSPORT);
+       }
+       
+       GSList *accounts = NULL;
+       
+       GSList *account_names  = modest_account_mgr_account_names (priv->account_mgr, 
+               TRUE /* including disabled accounts */);
+       
+       GSList *iter = account_names;
+       for (iter = priv->transport_accounts; iter; iter = g_slist_next (iter)) {
+               
+               TnyAccount *transport_account = (TnyAccount*)iter->data;
+               
+               /* Create a per-account local outbox folder (a _store_ account) 
+                * for each _transport_ account: */
+               TnyAccount *tny_account_outbox =
+                       modest_tny_account_new_for_per_account_local_outbox_folder (
+                               priv->account_mgr, transport_account, priv->session);
+                               
+               accounts = g_slist_append (accounts, tny_account_outbox); /* cache it */
+       };
+       
+       priv->store_accounts_outboxes = accounts;
+}
 
-
-/* this function fills the TnyList, and also returns a GSList of the accounts,
- * for caching purposes
+/* This function fills the TnyList, and also stores a GSList of the accounts,
+ * for caching purposes. It creates the TnyAccount objects if necessary.
+ * The @list parameter may be NULL, if you just want to fill the cache.
  */
-static GSList*
+static void
 get_server_accounts  (TnyAccountStore *self, TnyList *list, TnyAccountType type)
 {
-       ModestTnyAccountStorePrivate *priv = NULL;
+       g_return_if_fail (self);
+       
+       /* printf ("DEBUG: %s: list=%p, type=%d\n", __FUNCTION__, list, type); */
+               
+       ModestTnyAccountStorePrivate *priv = 
+               MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
+               
+       /* Do nothing if the accounts are already cached: */
+       if (type == TNY_ACCOUNT_TYPE_STORE) {
+                       if (priv->store_accounts)
+                               return;
+       } else if (type == TNY_ACCOUNT_TYPE_TRANSPORT) {
+                       if (priv->transport_accounts)
+                               return;
+       }
+       
        GSList                       *account_names = NULL, *cursor = NULL;
        GSList                       *accounts = NULL;
-       
-       priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
 
        /* these account names, not server_account names */
        account_names = modest_account_mgr_account_names (priv->account_mgr,FALSE);
@@ -505,6 +571,8 @@ get_server_accounts  (TnyAccountStore *self, TnyList *list, TnyAccountType type)
                
                /* we get the server_accounts for enabled accounts */
                if (modest_account_mgr_get_enabled(priv->account_mgr, account_name)) {
+                               
+                       /* Add the account: */
                        TnyAccount *tny_account = 
                                modest_tny_account_new_from_account (priv->account_mgr,
                                                                     account_name,
@@ -517,24 +585,67 @@ get_server_accounts  (TnyAccountStore *self, TnyList *list, TnyAccountType type)
                                if (list)
                                        tny_list_prepend (list, G_OBJECT(tny_account));
                                
-                               accounts = g_slist_append (accounts, tny_account); /* cache it */
+                               accounts = g_slist_append (accounts, tny_account); /* cache it */               
                        } else
                                g_printerr ("modest: failed to create account for %s\n",
                                            account_name);
-               }
+                       }
                g_free (account_name);
        }
        g_slist_free (account_names);
-
-       /* also, add the local folder pseudo-account */
+       
        if (type == TNY_ACCOUNT_TYPE_STORE) {
+               /* Also add the local folder pseudo-account: */
                TnyAccount *tny_account =
                        modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session);
                if (list)
                        tny_list_prepend (list, G_OBJECT(tny_account));
                accounts = g_slist_append (accounts, tny_account); /* cache it */
-       }       
-       return accounts;
+       }
+       
+       /* Do this here, in case create_per_account_local_outbox_folders() needs it. */
+       if (type == TNY_ACCOUNT_TYPE_TRANSPORT) {
+                       /* Store the cache: */
+                       priv->transport_accounts = accounts;
+       }
+       
+       /* We also create a per-account local outbox folder (a _store_ account) 
+        * for each _transport_ account. */
+       if (type == TNY_ACCOUNT_TYPE_TRANSPORT) {
+               /* Now would be a good time to create the per-account local outbox folder 
+                * _store_ accounts corresponding to each transport account: */
+               if (!priv->store_accounts_outboxes) {
+                       create_per_account_local_outbox_folders (self);
+               }
+       }
+       
+       /* But we only return the per-account local outbox folder when 
+        * _store_ accounts are requested. */
+       if (type == TNY_ACCOUNT_TYPE_STORE) {
+               /* Create them if necessary, 
+                * (which also requires creating the transport accounts, 
+                * if necessary.) */
+               if (!priv->store_accounts_outboxes) {
+                       create_per_account_local_outbox_folders (self);
+               }
+       
+               /* Add them to the TnyList: */
+               if (priv->store_accounts_outboxes) {
+                       GSList *iter = NULL;
+                       for (iter = priv->store_accounts_outboxes; iter; iter = g_slist_next (iter)) {
+                               TnyAccount *outbox_account = (TnyAccount*)iter->data;
+                               if (list && outbox_account)
+                                       tny_list_prepend (list,  G_OBJECT(outbox_account));
+                                       
+                               accounts = g_slist_append (accounts, outbox_account);
+                       }
+               }
+       }
+               
+       if (type == TNY_ACCOUNT_TYPE_STORE) {
+                       /* Store the cache: */
+                       priv->store_accounts = accounts;
+       }
 }      
 
 
@@ -559,15 +670,13 @@ modest_tny_account_store_get_accounts  (TnyAccountStore *self, TnyList *list,
        
        if (request_type == TNY_ACCOUNT_STORE_STORE_ACCOUNTS)  {
                if (!priv->store_accounts)
-                       priv->store_accounts =
-                               get_server_accounts (self, list, TNY_ACCOUNT_TYPE_STORE);
+                       get_server_accounts (self, list, TNY_ACCOUNT_TYPE_STORE);
                else
                        get_cached_accounts (self, list, TNY_ACCOUNT_TYPE_STORE);
                
        } else if (request_type == TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS) {
                if (!priv->transport_accounts)
-                       priv->transport_accounts =
-                               get_server_accounts (self, list, TNY_ACCOUNT_TYPE_TRANSPORT);
+                       get_server_accounts (self, list, TNY_ACCOUNT_TYPE_TRANSPORT);
                else
                        get_cached_accounts (self, list, TNY_ACCOUNT_TYPE_TRANSPORT);
        } else
@@ -829,8 +938,8 @@ modest_tny_account_store_get_tny_account_by_account (ModestTnyAccountStore *self
        priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
 
        /* Special case for the local account */
-       if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
-               id = g_strdup (MODEST_LOCAL_FOLDERS_ACCOUNT_ID);
+       if (!strcmp (account_name, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID)) {
+               id = g_strdup (MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID);
        } else {
                ModestAccountData *account_data;
 
@@ -924,3 +1033,10 @@ modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAcc
                             
        return account;
 }
+
+gboolean modest_tny_folder_store_is_virtual_local_folders (TnyFolderStore *self)
+{
+       /* We should make this more sophisticated if we ever use ModestTnySimpleFolderStore 
+        * for anything else. */
+       return MODEST_IS_TNY_SIMPLE_FOLDER_STORE (self);
+}
index 2e4feeb..0386769 100644 (file)
@@ -39,6 +39,7 @@
 #include <tny-session-camel.h>
 #include <tny-shared.h>
 #include <tny-folder.h>
+#include <modest-tny-simple-folder-store.h>
 #include <modest-account-mgr.h>
 
 /* other include files */
@@ -150,6 +151,15 @@ TnyAccount* modest_tny_account_store_get_transport_account_for_open_connection (
 TnySessionCamel*    modest_tny_account_store_get_session    (TnyAccountStore *self);
 
 
+/** modest_tny_folder_store_is_virtual_local_folders:
+ * @self A TnyFolderStore.
+ * 
+ * A convenience function to identify whether TnyAccount or other TnyFolderStore 
+ * is the virtual local folders store, containing the folders from local_folders/
+ * and the outboxes from outboxes/<account-name>/.
+ **/
+gboolean modest_tny_folder_store_is_virtual_local_folders (TnyFolderStore *self);
+
 G_END_DECLS
 
 #endif /* __MODEST_TNY_ACCOUNT_STORE_H__ */
index 68481d1..c6617fb 100644 (file)
 #include <modest-runtime.h>
 #include <tny-simple-list.h>
 #include <modest-tny-folder.h>
+#include <modest-tny-outbox-account.h>
 #include <modest-account-mgr-helpers.h>
+#include <modest-init.h>
 #include <tny-camel-transport-account.h>
 #include <tny-camel-imap-store-account.h>
 #include <tny-camel-pop-store-account.h>
 #include <tny-folder-stats.h>
 
-/* for now, ignore the account ===> the special folders are the same,
- * local folders for all accounts
- * this might change, ie, IMAP might have server-side sent-items
- */
+
 TnyFolder *
 modest_tny_account_get_special_folder (TnyAccount *account,
                                       TnyFolderType special_type)
@@ -50,14 +49,35 @@ modest_tny_account_get_special_folder (TnyAccount *account,
        TnyList *folders;
        TnyIterator *iter;
        TnyFolder *special_folder = NULL;
-       TnyAccount *local_account;
+
        
        g_return_val_if_fail (account, NULL);
        g_return_val_if_fail (0 <= special_type && special_type < TNY_FOLDER_TYPE_NUM,
                              NULL);
        
-       local_account = modest_tny_account_store_get_tny_account_by_id (modest_runtime_get_account_store(),
-                                                                       MODEST_LOCAL_FOLDERS_ACCOUNT_ID);
+       TnyAccount *local_account  = NULL;
+               
+       /* The accounts have already been instantiated by 
+        * modest_tny_account_store_get_accounts(), which is the 
+        * TnyAccountStore::get_accounts_func() implementation,
+        * so we just get them here.
+        */
+        
+       /* Per-account outbox folders are each in their own on-disk directory: */
+       if (special_type == TNY_FOLDER_TYPE_OUTBOX) {
+               gchar *account_id = g_strdup_printf (
+                       MODEST_PER_ACCOUNT_LOCAL_OUTBOX_FOLDER_ACCOUNT_ID_PREFIX "%s", 
+                       tny_account_get_id (account));
+               
+                       local_account = modest_tny_account_store_get_tny_account_by_id (modest_runtime_get_account_store(),
+                                                                       account_id);
+                       g_free (account_id);
+       } else {
+               /* Other local folders are all in one on-disk directory: */
+               local_account = modest_tny_account_store_get_tny_account_by_id (modest_runtime_get_account_store(),
+                                                                               MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID);
+       }
+       
        if (!local_account) {
                g_printerr ("modest: cannot get local account\n");
                return NULL;
@@ -77,9 +97,11 @@ modest_tny_account_get_special_folder (TnyAccount *account,
                        special_folder = folder;
                        break;
                }
+               
                g_object_unref (G_OBJECT(folder));
                tny_iterator_next (iter);
        }
+       
        g_object_unref (G_OBJECT (folders));
        g_object_unref (G_OBJECT (iter));
        g_object_unref (G_OBJECT (local_account));
@@ -135,7 +157,7 @@ static TnyAccount*
 modest_tny_account_new_from_server_account (ModestAccountMgr *account_mgr,
                                            ModestServerAccountData *account_data)
 {      
-       gchar *url;
+       gchar *url = NULL;
 
        g_return_val_if_fail (account_mgr, NULL);
        g_return_val_if_fail (account_data, NULL);
@@ -159,6 +181,9 @@ modest_tny_account_new_from_server_account (ModestAccountMgr *account_mgr,
                tny_account = TNY_ACCOUNT(tny_camel_imap_store_account_new ()); break;
        case MODEST_PROTOCOL_STORE_MAILDIR:
        case MODEST_PROTOCOL_STORE_MBOX:
+               /* Note that this is not where we create the special local folders account.
+                * That happens in modest_tny_account_new_for_local_folders() instead.
+                */
                tny_account = TNY_ACCOUNT(tny_camel_store_account_new()); break;
        default:
                g_return_val_if_reached (NULL);
@@ -176,10 +201,13 @@ modest_tny_account_new_from_server_account (ModestAccountMgr *account_mgr,
        tny_account_set_proto (tny_account, proto_name);
 
               
-       /* mbox and maildir accounts use a URI instead of the rest: */
+       /* mbox and maildir accounts use a URI instead of the rest:
+        * Note that this is not where we create the special local folders account.
+        * We do that in modest_tny_account_new_for_local_folders() instead. */
        if (account_data->uri)  {
                /* printf("DEBUG: %s: Using URI=%s\n", __FUNCTION__, account_data->uri); */
                tny_account_set_url_string (TNY_ACCOUNT(tny_account), account_data->uri);
+               g_message ("%s: local account-url: %s", __FUNCTION__, account_data->uri);
        }
        else {
                /* Set camel-specific options: */
@@ -335,14 +363,13 @@ modest_tny_account_new_from_account (ModestAccountMgr *account_mgr, const gchar
                                          forget_pass_func ? forget_pass_func : forget_pass_dummy);
        tny_account_set_pass_func (tny_account,
                                   get_pass_func ? get_pass_func: get_pass_dummy);
-
+       
        /* This name is what shows up in the folder view -- so for some POP/IMAP/... server
         * account, we set its name to the account of which it is part. */
        if (account_data->display_name)
                tny_account_set_name (tny_account, account_data->display_name); 
 
-       g_object_set_data_full (G_OBJECT(tny_account), "modest_account",
-                               (gpointer*) g_strdup (account_name), g_free);
+       modest_tny_account_set_parent_modest_account_name_for_server_account (tny_account, account_name);
        
        modest_account_mgr_free_account_data (account_mgr, account_data);
 
@@ -366,6 +393,9 @@ modest_tny_account_new_for_local_folders (ModestAccountMgr *account_mgr, TnySess
        }
        tny_camel_account_set_session (TNY_CAMEL_ACCOUNT(tny_account), session);
        
+       /* This path contains directories for each local folder.
+        * We have created them so that TnyCamelStoreAccount can find them 
+        * and report a folder for each directory: */
        maildir = modest_local_folder_info_get_maildir_path ();
        url = camel_url_new ("maildir:", NULL);
        camel_url_set_path (url, maildir);
@@ -374,14 +404,15 @@ modest_tny_account_new_for_local_folders (ModestAccountMgr *account_mgr, TnySess
        url_string = camel_url_to_string (url, 0);
        
        tny_account_set_url_string (TNY_ACCOUNT(tny_account), url_string);
+       printf("DEBUG: %s: local folders url=%s\n", __FUNCTION__, url_string);
 
        tny_account_set_name (TNY_ACCOUNT(tny_account), MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME); 
-       tny_account_set_id (TNY_ACCOUNT(tny_account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID); 
+       tny_account_set_id (TNY_ACCOUNT(tny_account), MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID); 
         tny_account_set_forget_pass_func (TNY_ACCOUNT(tny_account), forget_pass_dummy);
        tny_account_set_pass_func (TNY_ACCOUNT(tny_account), get_pass_dummy);
        
-       g_object_set_data (G_OBJECT(tny_account), "modest_account",
-                          (gpointer*)MODEST_LOCAL_FOLDERS_ACCOUNT_ID);
+       modest_tny_account_set_parent_modest_account_name_for_server_account (
+               TNY_ACCOUNT (tny_account), MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID);
        
        camel_url_free (url);
        g_free (maildir);
@@ -390,6 +421,73 @@ modest_tny_account_new_for_local_folders (ModestAccountMgr *account_mgr, TnySess
        return TNY_ACCOUNT(tny_account);
 }
 
+
+TnyAccount*
+modest_tny_account_new_for_per_account_local_outbox_folder (ModestAccountMgr *account_mgr, TnyAccount *account, TnySessionCamel *session)
+{
+       g_return_val_if_fail (account_mgr, NULL);
+       g_return_val_if_fail (account, NULL);
+       g_return_val_if_fail (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_TRANSPORT, NULL);
+       
+       /* Notice that we create a ModestTnyOutboxAccount here, 
+        * instead of just a TnyCamelStoreAccount,
+        * so that we can later identify this as a special account for internal use only.
+        */
+       TnyStoreAccount *tny_account = TNY_STORE_ACCOUNT (modest_tny_outbox_account_new ());
+       if (!tny_account) {
+               g_printerr ("modest: cannot create account for per-account local outbox folder.");
+               return NULL;
+       }
+       
+       tny_camel_account_set_session (TNY_CAMEL_ACCOUNT(tny_account), session);
+       
+       /* Make sure that the paths exists on-disk so that TnyCamelStoreAccount can 
+        * find it to create a TnyFolder for it: */
+       gchar *folder_dir = modest_per_account_local_outbox_folder_info_get_maildir_path_to_outbox_folder (account); 
+       modest_init_one_local_folder(folder_dir);
+       g_free (folder_dir);
+       folder_dir = NULL;
+
+       /* This path should contain just one directory - "outbox": */
+       gchar *maildir = 
+               modest_per_account_local_outbox_folder_info_get_maildir_path (account);
+                       
+       CamelURL *url = camel_url_new ("maildir:", NULL);
+       camel_url_set_path (url, maildir);
+       g_free (maildir);
+       
+       /* Needed by tinymail's DBC assertions */
+       camel_url_set_host (url, "localhost");
+       gchar *url_string = camel_url_to_string (url, 0);
+       camel_url_free (url);
+       
+       tny_account_set_url_string (TNY_ACCOUNT(tny_account), url_string);
+       printf("DEBUG: %s: local outbox folder account url=%s\n", __FUNCTION__, url_string);
+       g_free (url_string);
+
+       /* This text should never been seen,
+        * because the per-account outbox accounts are not seen directly by the user.
+        * Their folders are merged and shown as one folder. */ 
+       tny_account_set_name (TNY_ACCOUNT(tny_account), "Per-Account Outbox"); 
+       
+       gchar *account_id = g_strdup_printf (
+               MODEST_PER_ACCOUNT_LOCAL_OUTBOX_FOLDER_ACCOUNT_ID_PREFIX "%s", 
+               tny_account_get_id (account));
+       tny_account_set_id (TNY_ACCOUNT(tny_account), account_id);
+       g_free (account_id);
+       
+       tny_account_set_forget_pass_func (TNY_ACCOUNT(tny_account), forget_pass_dummy);
+       tny_account_set_pass_func (TNY_ACCOUNT(tny_account), get_pass_dummy);
+       
+       /* Make this think that it belongs to the modest local-folders parent account: */
+       modest_tny_account_set_parent_modest_account_name_for_server_account (
+               TNY_ACCOUNT (tny_account), MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID);
+
+       return TNY_ACCOUNT(tny_account);
+}
+
+
+
 typedef gint (*TnyStatsFunc) (TnyFolderStats *stats);
 
 typedef struct _RecurseFoldersHelper {
@@ -422,7 +520,9 @@ recurse_folders (TnyFolderStore *store,
                if (helper->function && helper->function (stats) > 0)
                        helper->sum += helper->function (stats);
 
-               recurse_folders (TNY_FOLDER_STORE (folder), query, helper);
+               if (TNY_IS_FOLDER_STORE (folder)) {
+                       recurse_folders (TNY_FOLDER_STORE (folder), query, helper);
+               }
            
                g_object_unref (folder);
                g_object_unref (stats);
@@ -433,12 +533,12 @@ recurse_folders (TnyFolderStore *store,
 }
 
 gint 
-modest_tny_account_get_folder_count (TnyAccount *self)
+modest_tny_folder_store_get_folder_count (TnyFolderStore *self)
 {
        RecurseFoldersHelper *helper;
        gint retval;
 
-       g_return_val_if_fail (TNY_IS_ACCOUNT (self), -1);
+       g_return_val_if_fail (TNY_IS_FOLDER_STORE (self), -1);
 
        /* Create helper */
        helper = g_malloc0 (sizeof (RecurseFoldersHelper));
@@ -446,7 +546,7 @@ modest_tny_account_get_folder_count (TnyAccount *self)
        helper->sum = 0;
        helper->folders = 0;
 
-       recurse_folders (TNY_FOLDER_STORE (self), NULL, helper);
+       recurse_folders (self, NULL, helper);
 
        retval = helper->folders;
 
@@ -456,19 +556,19 @@ modest_tny_account_get_folder_count (TnyAccount *self)
 }
 
 gint
-modest_tny_account_get_message_count (TnyAccount *self)
+modest_tny_folder_store_get_message_count (TnyFolderStore *self)
 {
        RecurseFoldersHelper *helper;
        gint retval;
 
-       g_return_val_if_fail (TNY_IS_ACCOUNT (self), -1);
+       g_return_val_if_fail (TNY_IS_FOLDER_STORE (self), -1);
        
        /* Create helper */
        helper = g_malloc0 (sizeof (RecurseFoldersHelper));
        helper->function = (TnyStatsFunc) tny_folder_stats_get_all_count;
        helper->sum = 0;
 
-       recurse_folders (TNY_FOLDER_STORE (self), NULL, helper);
+       recurse_folders (self, NULL, helper);
 
        retval = helper->sum;
 
@@ -478,7 +578,7 @@ modest_tny_account_get_message_count (TnyAccount *self)
 }
 
 gint 
-modest_tny_account_get_local_size (TnyAccount *self)
+modest_tny_folder_store_get_local_size (TnyFolderStore *self)
 {
        RecurseFoldersHelper *helper;
        gint retval;
@@ -490,7 +590,7 @@ modest_tny_account_get_local_size (TnyAccount *self)
        helper->function = (TnyStatsFunc) tny_folder_stats_get_local_size;
        helper->sum = 0;
 
-       recurse_folders (TNY_FOLDER_STORE (self), NULL, helper);
+       recurse_folders (self, NULL, helper);
 
        retval = helper->sum;
 
@@ -498,3 +598,16 @@ modest_tny_account_get_local_size (TnyAccount *self)
 
        return retval;
 }
+
+const gchar* modest_tny_account_get_parent_modest_account_name_for_server_account (TnyAccount *self)
+{
+       return (const gchar *)g_object_get_data (G_OBJECT (self), "modest_account");
+}
+
+void modest_tny_account_set_parent_modest_account_name_for_server_account (TnyAccount *self, const gchar* parent_modest_acount_name)
+{
+       g_object_set_data_full (G_OBJECT(self), "modest_account",
+                               (gpointer*) g_strdup (parent_modest_acount_name), g_free);
+}
+
+
index e81e652..02d6611 100644 (file)
@@ -77,6 +77,20 @@ TnyAccount* modest_tny_account_new_for_local_folders (ModestAccountMgr *account_
                                                      TnySessionCamel *session);
 
 /**
+ * modest_tny_account_new_for_per_account_local_outbox_folder:
+ * @account_mgr: a valid account mgr instance
+ * @account: a valid account instance
+ * @session: a tny camel session
+ * 
+ * get the per-account local outbox folder (pseudo) account.
+ * 
+ * Returns: a new per-account local outbox folder TnyAccount or NULL in case of error.
+ */
+TnyAccount* modest_tny_account_new_for_per_account_local_outbox_folder (
+       ModestAccountMgr *account_mgr, TnyAccount *account,
+       TnySessionCamel *session);
+       
+/**
  * modest_tny_account_get_special_folder:
  * @self: a TnyAccount
  * @special_type: the special folder to get
@@ -94,27 +108,27 @@ TnyFolder*    modest_tny_account_get_special_folder   (TnyAccount *self,
 
 
 /**
- * modest_tny_account_get_folder_count:
- * @self: a #TnyAccount
+ * modest_tny_folder_store_get_folder_count:
+ * @self: a #TnyFolderStore
  * 
  * gets the number of folders of the account
  * 
  * Returns: the number of folder, or -1 in case of error
  **/
-gint          modest_tny_account_get_folder_count  (TnyAccount *self);
+gint          modest_tny_folder_store_get_folder_count  (TnyFolderStore *self);
 
 /**
- * modest_tny_account_get_message_count:
+ * modest_tny_folder_store_get_message_count:
  * @self: 
  * 
  * gets the number of messages in the account
  * 
  * Returns: the number of messages, or -1 in case of error
  **/
-gint          modest_tny_account_get_message_count (TnyAccount *self);
+gint          modest_tny_folder_store_get_message_count (TnyFolderStore *self);
 
 /**
- * modest_tny_account_get_local_size:
+ * modest_tny_folder_store_get_local_size:
  * @self: 
  * 
  * gets the total size occupied by the account in the local storage
@@ -122,7 +136,19 @@ gint          modest_tny_account_get_message_count (TnyAccount *self);
  * 
  * Returns: the total size in bytes, or -1 in case of error
  **/
-gint          modest_tny_account_get_local_size    (TnyAccount *self);
+gint          modest_tny_folder_store_get_local_size    (TnyFolderStore *self);
+
+/** modest_tny_account_get_parent_modest_account_name_for_server_account:
+ * Get the name of the parent modest account of which the server account is a part.
+ */
+const gchar* modest_tny_account_get_parent_modest_account_name_for_server_account (TnyAccount *self);
+
+/** modest_tny_account_set_parent_modest_account_name_for_server_account:
+ * Set the name of the parent modest account of which the server account is a part,
+ * so it can be retrieved later with 
+ * modest_tny_account_get_parent_modest_account_name_for_server_account().
+ */
+void modest_tny_account_set_parent_modest_account_name_for_server_account (TnyAccount *self, const gchar* parent_modest_acount_name);
 
 G_END_DECLS
 
index b691bae..ca6d3d1 100644 (file)
@@ -31,7 +31,9 @@
 #include <glib/gi18n.h>
 #include <string.h>
 #include <modest-tny-folder.h>
+#include <modest-tny-outbox-account.h>
 #include <tny-camel-folder.h>
+#include <tny-merge-folder.h>
 #include <camel/camel-folder.h>
 #include <modest-protocol-info.h>
 
@@ -106,7 +108,7 @@ modest_tny_folder_guess_folder_type (const TnyFolder *folder)
 
 /* FIXME: encode all folder rules here */
 ModestTnyFolderRules
-modest_tny_folder_get_rules   (const TnyFolder *folder)
+modest_tny_folder_get_rules   (TnyFolder *folder)
 {
        ModestTnyFolderRules rules = 0;
        TnyFolderType type;
@@ -165,46 +167,79 @@ modest_tny_folder_get_rules   (const TnyFolder *folder)
 
 
 gboolean
-modest_tny_folder_is_local_folder   (const TnyFolder *folder)
+modest_tny_folder_is_local_folder   (TnyFolder *folder)
 {
-       TnyAccount*  account;
-       const gchar* account_id;
-       
        g_return_val_if_fail (folder, FALSE);
        
-       account = tny_folder_get_account ((TnyFolder*)folder);
+       /* The merge folder is a special case, 
+        * used to merge the per-account local outbox folders. 
+        * and can have no get_account() implementation.
+        * We should do something more sophisticated if we 
+        * ever use TnyMergeFolder for anything else.
+        */
+       if (TNY_IS_MERGE_FOLDER (folder))
+               return TRUE;
+
+       TnyAccount* account = tny_folder_get_account ((TnyFolder*)folder);
        if (!account)
                return FALSE;
 
-       account_id = tny_account_get_id (account);
+       /* Outbox is a special case, using a derived TnyAccount: */
+       if (MODEST_IS_TNY_OUTBOX_ACCOUNT (account)) {
+               g_object_unref (account);
+               return TRUE;  
+       }
+
+       const gchar* account_id = tny_account_get_id (account);
        if (!account_id)
                return FALSE;
 
        g_object_unref (G_OBJECT(account));
        
-       return (strcmp (account_id, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0);
+       return (strcmp (account_id, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID) == 0);
 }      
 
 
 TnyFolderType
-modest_tny_folder_get_local_folder_type  (const TnyFolder *folder)
+modest_tny_folder_get_local_folder_type  (TnyFolder *folder)
 {
-       CamelFolder *camel_folder;
-       const gchar *full_name;
-       
        g_return_val_if_fail (folder, TNY_FOLDER_TYPE_UNKNOWN);
+
+       /* The merge folder is a special case, 
+        * used to merge the per-account local outbox folders. 
+        * and can have no get_account() implementation.
+        * We should do something more sophisticated if we 
+        * ever use TnyMergeFolder for anything else.
+        */
+       if (TNY_IS_MERGE_FOLDER (folder))
+               return TNY_FOLDER_TYPE_OUTBOX;
+               
+       /* Outbox is a special case, using a derived TnyAccount: */
+       TnyAccount* parent_account = tny_folder_get_account (folder);
+       if (parent_account && MODEST_IS_TNY_OUTBOX_ACCOUNT (parent_account)) {
+               g_object_unref (parent_account);
+               return TNY_FOLDER_TYPE_OUTBOX;  
+       }
+
+       if (parent_account) {
+               g_object_unref (parent_account);
+               parent_account = NULL;
+       }
+
+
        g_return_val_if_fail (modest_tny_folder_is_local_folder(folder),
                              TNY_FOLDER_TYPE_UNKNOWN);
 
        /* we need to use the camel functions, because we want the
         * _full name_, that is, the full path name of the folder,
-        * to distinguis between 'Outbox' and 'myfunkyfolder/Outbox'
+        * to distinguish between 'Outbox' and 'myfunkyfolder/Outbox'
         */
-       camel_folder = tny_camel_folder_get_folder (TNY_CAMEL_FOLDER(folder));
+       CamelFolder *camel_folder = tny_camel_folder_get_folder (TNY_CAMEL_FOLDER(folder));
        if (!camel_folder)
                return TNY_FOLDER_TYPE_UNKNOWN;
 
-       full_name = camel_folder_get_full_name (camel_folder);
+       const gchar *full_name = camel_folder_get_full_name (camel_folder);
+       /* printf ("DEBUG: %s: full_name=%s\n", __FUNCTION__, full_name); */
        camel_object_unref (CAMEL_OBJECT(camel_folder));
        
        if (!full_name) 
@@ -212,3 +247,35 @@ modest_tny_folder_get_local_folder_type  (const TnyFolder *folder)
        else 
                return modest_local_folder_info_get_type (full_name);
 }
+
+gboolean
+modest_tny_folder_is_outbox_for_account (TnyFolder *folder, TnyAccount *account)
+{
+       g_return_val_if_fail(folder, FALSE);
+       g_return_val_if_fail(account, FALSE);
+       
+       if (modest_tny_folder_get_local_folder_type (folder) != TNY_FOLDER_TYPE_OUTBOX)
+               return FALSE;
+               
+       return TRUE;
+#if 0  
+       /* we need to use the camel functions, because we want the
+        * _full name_, that is, the full path name of the folder,
+        * to distinguis between 'Outbox' and 'myfunkyfolder/Outbox'
+        */
+       CamelFolder *camel_folder = tny_camel_folder_get_folder (TNY_CAMEL_FOLDER(folder));
+       if (!camel_folder)
+               return FALSE;
+
+       const gchar *full_name = camel_folder_get_full_name (camel_folder);
+       camel_object_unref (CAMEL_OBJECT(camel_folder));
+       
+       if (!full_name) 
+               return TNY_FOLDER_TYPE_UNKNOWN;
+       else 
+               return modest_local_folder_info_get_type (full_name);
+               
+       return FALSE;
+#endif
+}
+
index f682205..9096911 100644 (file)
@@ -46,6 +46,17 @@ typedef enum {
        MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE = 1 << 4,
 } ModestTnyFolderRules;
 
+/** Note: This is not a derived TnyFolder type. These are just convenience 
+ * functions for working with a TnyFolder. tinymail does not seem to offer any 
+ * easy way to cause derived TnyFolders to be instantiated.
+ */
+/* TODO: These "const TnyFolder*" arguments will eventually need to 
+ * be "TnyFolder*". C cannot support constness for complex objects like C++ 
+ * can, because it lacks the mutable keyword and doesn't allow both const 
+ * and non-const get function overloads.
+ */
 /**
  * modest_tny_folder_guess_type:
  * @folder: a valid tnymail folder
@@ -82,7 +93,7 @@ TnyFolderType  modest_tny_folder_guess_folder_type_from_name   (const gchar *fol
  *  
  * Returns: TRUE if it's a local folder, FALSE otherwise
  */
-gboolean modest_tny_folder_is_local_folder   (const TnyFolder *folder);
+gboolean modest_tny_folder_is_local_folder   (TnyFolder *folder);
 
 
 /**
@@ -93,7 +104,7 @@ gboolean modest_tny_folder_is_local_folder   (const TnyFolder *folder);
  *  
  * Returns: TRUE if it's a local folder, FALSE otherwise
  */
-TnyFolderType modest_tny_folder_get_local_folder_type  (const TnyFolder *folder);
+TnyFolderType modest_tny_folder_get_local_folder_type  (TnyFolder *folder);
 
 
 /**
@@ -106,7 +117,19 @@ TnyFolderType modest_tny_folder_get_local_folder_type  (const TnyFolder *folder)
  * Returns: the ModestTnyFolderRules rules (bitwise-OR) for this
  * folder
  */
-ModestTnyFolderRules  modest_tny_folder_get_rules   (const TnyFolder *folder);
+ModestTnyFolderRules  modest_tny_folder_get_rules   (TnyFolder *folder);
+
+/**
+ * modest_tny_folder_is_outbox_for_account:
+ * @folder: a valid tnymail folder
+ * 
+ * Discover whether this folder is the per-account outbox for the specified 
+ * account.
+ *  
+ * Returns: TRUE if this folder is the per-account outbox for the account.
+ */
+gboolean modest_tny_folder_is_outbox_for_account (TnyFolder *folder, 
+       TnyAccount *account);
 
 G_END_DECLS
 
diff --git a/src/modest-tny-outbox-account.c b/src/modest-tny-outbox-account.c
new file mode 100644 (file)
index 0000000..0f0fe36
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Nokia Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <modest-tny-outbox-account.h>
+
+G_DEFINE_TYPE (ModestTnyOutboxAccount, modest_tny_outbox_account, TNY_TYPE_CAMEL_STORE_ACCOUNT);
+
+#define TNY_OUTBOX_ACCOUNT_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_TNY_OUTBOX_ACCOUNT, ModestTnyOutboxAccountPrivate))
+
+typedef struct _ModestTnyOutboxAccountPrivate ModestTnyOutboxAccountPrivate;
+
+struct _ModestTnyOutboxAccountPrivate
+{
+       /* This it the outbox account for this store account: */
+       gchar *parent_account_id;
+};
+
+static void
+modest_tny_outbox_account_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (modest_tny_outbox_account_parent_class)->dispose)
+    G_OBJECT_CLASS (modest_tny_outbox_account_parent_class)->dispose (object);
+}
+
+static void
+modest_tny_outbox_account_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (modest_tny_outbox_account_parent_class)->finalize (object);
+}
+
+static void
+modest_tny_outbox_account_class_init (ModestTnyOutboxAccountClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ModestTnyOutboxAccountPrivate));
+
+  object_class->dispose = modest_tny_outbox_account_dispose;
+  object_class->finalize = modest_tny_outbox_account_finalize;
+}
+
+static void
+modest_tny_outbox_account_init (ModestTnyOutboxAccount *self)
+{
+}
+
+ModestTnyOutboxAccount*
+modest_tny_outbox_account_new (void)
+{
+  return g_object_new (MODEST_TYPE_TNY_OUTBOX_ACCOUNT, NULL);
+}
diff --git a/src/modest-tny-outbox-account.h b/src/modest-tny-outbox-account.h
new file mode 100644 (file)
index 0000000..600c8c7
--- /dev/null
@@ -0,0 +1,82 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Nokia Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MODEST_TNY_OUTBOX_ACCOUNT_H__
+#define __MODEST_TNY_OUTBOX_ACCOUNT_H__
+
+#include <tny-camel-store-account.h>
+
+G_BEGIN_DECLS
+
+#define MODEST_TYPE_TNY_OUTBOX_ACCOUNT modest_tny_outbox_account_get_type()
+
+#define MODEST_TNY_OUTBOX_ACCOUNT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  MODEST_TYPE_TNY_OUTBOX_ACCOUNT, ModestTnyOutboxAccount))
+
+#define MODEST_TNY_OUTBOX_ACCOUNT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  MODEST_TYPE_TNY_OUTBOX_ACCOUNT, ModestTnyOutboxAccountClass))
+
+#define MODEST_IS_TNY_OUTBOX_ACCOUNT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  MODEST_TYPE_TNY_OUTBOX_ACCOUNT))
+
+#define MODEST_IS_TNY_OUTBOX_ACCOUNT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  MODEST_TYPE_TNY_OUTBOX_ACCOUNT))
+
+#define MODEST_TNY_OUTBOX_ACCOUNT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  MODEST_TYPE_TNY_OUTBOX_ACCOUNT, ModestTnyOutboxAccountClass))
+
+/** ModestTnyOutboxAccount is a non-user-visible account
+ * that provides maildir-based access to the on-disk 
+ * per-account outbox directory.
+ * The actual user-visible outbox folder is actually a TnyMergeFolder that 
+ * merges the outbox folder from several ModestTnyOutboxAccount instances.
+ * 
+ * This is a simple alternative to reimplementing get_folders_func() for 
+ * every tinymail camel account type.
+ */
+typedef struct {
+  TnyCamelStoreAccount parent;
+} ModestTnyOutboxAccount;
+
+typedef struct {
+  TnyCamelStoreAccountClass parent_class;
+} ModestTnyOutboxAccountClass;
+
+GType modest_tny_outbox_account_get_type (void);
+
+ModestTnyOutboxAccount* modest_tny_outbox_account_new (void);
+
+G_END_DECLS
+
+#endif /* __MODEST_TNY_OUTBOX_ACCOUNT_H__ */
diff --git a/src/modest-tny-simple-folder-store.c b/src/modest-tny-simple-folder-store.c
new file mode 100644 (file)
index 0000000..99210ad
--- /dev/null
@@ -0,0 +1,187 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Nokia Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <modest-tny-simple-folder-store.h>
+
+static void
+tny_folder_store_init (TnyFolderStoreIface *klass);
+
+G_DEFINE_TYPE_EXTENDED (ModestTnySimpleFolderStore, 
+       modest_tny_simple_folder_store, 
+       G_TYPE_OBJECT,
+       0,
+       G_IMPLEMENT_INTERFACE (TNY_TYPE_FOLDER_STORE, tny_folder_store_init));
+
+#define TNY_SIMPLE_FOLDER_STORE_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE, ModestTnySimpleFolderStorePrivate))
+
+typedef struct _ModestTnySimpleFolderStorePrivate ModestTnySimpleFolderStorePrivate;
+
+struct _ModestTnySimpleFolderStorePrivate
+{
+       GSList *list_folders;
+};
+
+static void
+modest_tny_simple_folder_store_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (modest_tny_simple_folder_store_parent_class)->dispose)
+    G_OBJECT_CLASS (modest_tny_simple_folder_store_parent_class)->dispose (object);
+}
+
+static void
+modest_tny_simple_folder_store_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (modest_tny_simple_folder_store_parent_class)->finalize (object);
+  
+  ModestTnySimpleFolderStorePrivate *priv = 
+               TNY_SIMPLE_FOLDER_STORE_GET_PRIVATE (object);
+               
+  GSList *iter = priv->list_folders;
+  while (iter)
+  {
+       TnyFolder *folder = (TnyFolder*)iter->data;
+       if (folder) {
+               g_object_unref (folder);
+               iter->data = NULL;
+       }
+               
+       iter = g_slist_next (iter);
+  }
+
+  g_slist_free (priv->list_folders);
+  priv->list_folders = NULL;
+}
+
+static void
+modest_tny_simple_folder_store_class_init (ModestTnySimpleFolderStoreClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ModestTnySimpleFolderStorePrivate));
+
+  object_class->dispose = modest_tny_simple_folder_store_dispose;
+  object_class->finalize = modest_tny_simple_folder_store_finalize;
+}
+
+static void
+modest_tny_simple_folder_store_init (ModestTnySimpleFolderStore *self)
+{
+}
+
+ModestTnySimpleFolderStore*
+modest_tny_simple_folder_store_new (void)
+{
+  return g_object_new (MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE, NULL);
+}
+
+
+static void
+modest_tny_simple_folder_store_remove_folder (TnyFolderStore *self, TnyFolder *folder, GError **err)
+{
+}
+
+static TnyFolder*
+modest_tny_simple_folder_store_create_folder (TnyFolderStore *self, const gchar *name, GError **err)
+{
+       return NULL;
+}
+
+static void
+modest_tny_simple_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+{
+  ModestTnySimpleFolderStorePrivate *priv = 
+               TNY_SIMPLE_FOLDER_STORE_GET_PRIVATE (self);
+               
+  if (!list)
+    return;
+    
+  GSList *iter = priv->list_folders;
+  while (iter)
+  {
+       TnyFolder *folder = (TnyFolder*)iter->data;
+       if (folder) {
+               tny_list_append (list, G_OBJECT (folder));
+       }
+               
+       iter = g_slist_next (iter);
+  }
+  
+}
+
+static void
+modest_tny_simple_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyGetFoldersCallback callback, TnyFolderStoreQuery *query, TnyStatusCallback status_callback, gpointer user_data)
+{
+}
+
+static void
+modest_tny_simple_folder_store_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+}
+
+static void
+modest_tny_simple_folder_store_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+}
+
+static void
+tny_folder_store_init (TnyFolderStoreIface *klass)
+{
+       klass->remove_folder_func = modest_tny_simple_folder_store_remove_folder;
+       klass->create_folder_func = modest_tny_simple_folder_store_create_folder;
+       klass->get_folders_func = modest_tny_simple_folder_store_get_folders;
+       klass->get_folders_async_func = modest_tny_simple_folder_store_get_folders_async;
+       klass->add_observer_func = modest_tny_simple_folder_store_add_observer;
+       klass->remove_observer_func = modest_tny_simple_folder_store_remove_observer;
+}
+
+
+void
+modest_tny_simple_folder_store_add_folder (ModestTnySimpleFolderStore *store, 
+       TnyFolder *folder)
+{
+       ModestTnySimpleFolderStorePrivate *priv = 
+               TNY_SIMPLE_FOLDER_STORE_GET_PRIVATE (store);
+               
+       /* Check that it isn't already in the list: */
+       GSList *exists = g_slist_find (priv->list_folders, folder);
+       if (exists)
+               return;
+               
+       /* Add it: */
+       /* The reference is released in finalize: */
+       priv->list_folders = g_slist_append (priv->list_folders, folder);
+       g_object_ref (folder);
+}
+
diff --git a/src/modest-tny-simple-folder-store.h b/src/modest-tny-simple-folder-store.h
new file mode 100644 (file)
index 0000000..4f0805e
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Nokia Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MODEST_TNY_SIMPLE_FOLDER_STORE
+#define _MODEST_TNY_SIMPLE_FOLDER_STORE
+
+#include <tny-folder-store.h>
+
+G_BEGIN_DECLS
+
+#define MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE modest_tny_simple_folder_store_get_type()
+
+#define MODEST_TNY_SIMPLE_FOLDER_STORE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE, ModestTnySimpleFolderStore))
+
+#define MODEST_TNY_SIMPLE_FOLDER_STORE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE, ModestTnySimpleFolderStoreClass))
+
+#define MODEST_IS_TNY_SIMPLE_FOLDER_STORE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE))
+
+#define MODEST_IS_TNY_SIMPLE_FOLDER_STORE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE))
+
+#define MODEST_TNY_SIMPLE_FOLDER_STORE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  MODEST_TYPE_TNY_SIMPLE_FOLDER_STORE, ModestTnySimpleFolderStoreClass))
+
+/** ModestTnySimpleFolderStore contains references to folders that exist 
+ * in other folder stores or accounts. It does not instantiate any folders 
+ * of its own.
+ */
+typedef struct {
+  GObject parent;
+} ModestTnySimpleFolderStore;
+
+typedef struct {
+  GObjectClass parent_class;
+} ModestTnySimpleFolderStoreClass;
+
+GType modest_tny_simple_folder_store_get_type (void);
+
+ModestTnySimpleFolderStore* modest_tny_simple_folder_store_new (void);
+
+void modest_tny_simple_folder_store_add_folder (ModestTnySimpleFolderStore *store, 
+       TnyFolder *folder);
+
+G_END_DECLS
+
+#endif /* _MODEST_TNY_SIMPLE_FOLDER_STORE */
index 52a3121..b2c6eb2 100644 (file)
@@ -26,7 +26,7 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif /*HAVE_CONFIG_H*/
@@ -69,6 +69,7 @@
 #include <tny-simple-list.h>
 #include <tny-msg-view.h>
 #include <tny-device.h>
+#include <tny-merge-folder.h>
 
 typedef struct _GetMsgAsyncHelper {    
        ModestWindow *window;
@@ -471,6 +472,7 @@ modest_ui_actions_on_new_msg (GtkAction *action, ModestWindow *win)
 /*     } */
 
        /* Create and register edit window */
+       /* This is destroyed by TOOD. */
        msg_win = modest_msg_edit_window_new (msg, account_name);
        mgr = modest_runtime_get_window_mgr ();
        modest_window_mgr_register_window (mgr, msg_win);
@@ -520,7 +522,7 @@ open_msg_cb (ModestMailOperation *mail_op,
        if (!account)
                account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
        
-       /* Get folder type */
+       /* Gets folder type (OUTBOX headers will be opened in edit window */
        if (modest_tny_folder_is_local_folder (folder))
                folder_type = modest_tny_folder_get_local_folder_type (folder);
 
@@ -1101,18 +1103,20 @@ static void
 set_active_account_from_tny_account (TnyAccount *account,
                                     ModestWindow *window)
 {
-       TnyAccount *modest_server_account;
-       const gchar *server_acc_name;
-       gchar *modest_acc_name;
-
-       server_acc_name = tny_account_get_id (account);
+       const gchar *server_acc_name = tny_account_get_id (account);
+       
+       printf("%s: server_acc_name=%s\n", __FUNCTION__, server_acc_name);
        /* We need the TnyAccount provided by the
           account store because that is the one that
           knows the name of the Modest account */
-       modest_server_account = 
+       TnyAccount *modest_server_account = modest_server_account = 
                modest_tny_account_store_get_tny_account_by_id  (modest_runtime_get_account_store (), 
                                                                 server_acc_name);
-       modest_acc_name = (gchar *) g_object_get_data (G_OBJECT (modest_server_account), "modest_account");
+       printf("%s: modest_server_account name=%s\n", __FUNCTION__, tny_account_get_id (modest_server_account));
+
+       const gchar *modest_acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (modest_server_account);
+       printf("%s: modest_acc_name=%s\n", __FUNCTION__, modest_acc_name);
+
        modest_window_set_active_account (window, modest_acc_name);
        g_object_unref (modest_server_account);
 }
@@ -1125,7 +1129,6 @@ modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
 {
        ModestConf *conf;
        GtkWidget *header_view;
-       TnyAccount *account;
        
        g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
 
@@ -1141,12 +1144,19 @@ modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
                set_active_account_from_tny_account (TNY_ACCOUNT (folder_store), MODEST_WINDOW (main_window));
                /* Show account details */
                modest_main_window_set_contents_style (main_window, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
+       } else if (modest_tny_folder_store_is_virtual_local_folders  (folder_store )) {
+               printf ("DEBUG: %s: folder store.\n", __FUNCTION__);
+               //TODO: Set the virtual folder store as the "active account" somehow:
+               modest_main_window_set_contents_style (main_window, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
        } else {
                if (TNY_IS_FOLDER (folder_store) && selected) {
-                       /* Update the active account */
-                       account = tny_folder_get_account (TNY_FOLDER (folder_store));
-                       set_active_account_from_tny_account (account, MODEST_WINDOW (main_window));
-                       g_object_unref (account);
+                       
+                       if (!TNY_IS_MERGE_FOLDER (folder_store)) { /* TnyMergeFolder can have no get_account() implementation. */
+                               /* Update the active account */
+                               TnyAccount *account = tny_folder_get_account (TNY_FOLDER (folder_store));
+                               set_active_account_from_tny_account (account, MODEST_WINDOW (main_window));
+                               g_object_unref (account);
+                       }
                        
                        /* Set folder on header view */
                        modest_main_window_set_contents_style (main_window, 
@@ -1312,6 +1322,8 @@ modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edi
        /* Save settings and close the window */
        gtk_widget_destroy (GTK_WIDGET (edit_window));
 }
+
+/* For instance, when clicking the Send toolbar button when editing a message: */
 void
 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
 {
index 58b98bd..7e1cff1 100644 (file)
 #include <tny-folder.h>
 #include <tny-camel-folder.h>
 #include <tny-simple-list.h>
+#include <tny-merge-folder.h>
 #include <modest-tny-folder.h>
+#include <modest-tny-simple-folder-store.h>
 #include <modest-marshal.h>
 #include <modest-icon-names.h>
 #include <modest-tny-account-store.h>
+#include <modest-tny-outbox-account.h>
 #include <modest-text-utils.h>
 #include <modest-runtime.h>
 #include "modest-folder-view.h"
@@ -52,6 +55,7 @@
 #include <modest-account-mgr-helpers.h>
 #include <modest-widget-memory.h>
 
+
 /* 'private'/'protected' functions */
 static void modest_folder_view_class_init  (ModestFolderViewClass *klass);
 static void modest_folder_view_init        (ModestFolderView *obj);
@@ -229,8 +233,6 @@ modest_folder_view_class_init (ModestFolderViewClass *klass)
                              G_TYPE_NONE, 1, G_TYPE_STRING);
 }
 
-
-
 static void
 text_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
                 GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer data)
@@ -265,9 +267,12 @@ text_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
        
        priv =  MODEST_FOLDER_VIEW_GET_PRIVATE (data);
        
+       gchar *item_name = NULL;
+       gint item_weight = 400;
+       
        if (type != TNY_FOLDER_TYPE_ROOT) {
-               gint number;
-
+               gint number = 0;
+               
                if (modest_tny_folder_is_local_folder (TNY_FOLDER (instance))) {
                        TnyFolderType type;
                        type = modest_tny_folder_get_local_folder_type (TNY_FOLDER (instance));
@@ -285,45 +290,53 @@ text_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
 
                /* Use bold font style if there are unread messages */
                if (unread > 0) {
-                       gchar *folder_title = g_strdup_printf ("%s (%d)", fname, unread);
-                       g_object_set (rendobj,"text", folder_title,  "weight", 800, NULL);
-                       if (G_OBJECT (priv->cur_folder_store) == instance)
-                               g_signal_emit (G_OBJECT(data),
-                                              signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
-                                              folder_title);
-                       g_free (folder_title);
+                       item_name = g_strdup_printf ("%s (%d)", fname, unread);
+                       item_weight = 800;
                } else {
-                       g_object_set (rendobj,"text", fname, "weight", 400, NULL);
-                       if (G_OBJECT (priv->cur_folder_store) == instance)
-                               g_signal_emit (G_OBJECT(data),
-                                              signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
-                                              fname);
+                       item_name = g_strdup (fname);
+                       item_weight = 400;
                }
 
-       } else {
-               const gchar *account_name = NULL;
-               const gchar *account_id = NULL;
-
+       } else if (TNY_IS_ACCOUNT (instance)) {
                /* If it's a server account */
-               account_id = tny_account_get_id (TNY_ACCOUNT (instance));
-               if (!strcmp (account_id, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
-                       account_name = priv->local_account_name;
+               const gchar * account_id = tny_account_get_id (TNY_ACCOUNT (instance));
+               if (!strcmp (account_id, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID)) {
+                       item_name = g_strdup (priv->local_account_name);
                } else {
                        if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
                                /* TODO: get MMC card name */
+                               item_name = g_strdup (_("MMC"));
                        } else {
-                               account_name = fname;
+                               item_name = g_strdup (fname);
                        }
                }
 
+               item_weight = 800;
+       } else if (modest_tny_folder_store_is_virtual_local_folders (
+               TNY_FOLDER_STORE(instance)))
+       {
+               /* We use ModestTnySimpleFolder store to group the outboxes and 
+                * the other local folders together: */
+               item_name = g_strdup (_("Local Folders"));
+               item_weight = 400;
+       }
+       
+       if (!item_name)
+               item_name = g_strdup ("unknown");
+                       
+       if (item_name && item_weight) {
+               /* Set the name in the treeview cell: */
+               g_object_set (rendobj,"text", item_name, "weight", item_weight, NULL);
+               
                /* Notify display name observers */
-               if (G_OBJECT (priv->cur_folder_store) == instance)
+               if (G_OBJECT (priv->cur_folder_store) == instance) {
                        g_signal_emit (G_OBJECT(data),
-                                      signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
-                                      account_name);
-
-               /* Use bold font style */
-               g_object_set (rendobj,"text", account_name, "weight", 800, NULL);
+                                              signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
+                                              item_name);
+               }
+               
+               g_free (item_name);
+               
        }
        
        g_object_unref (G_OBJECT (instance));
@@ -365,39 +378,50 @@ icon_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
 
        switch (type) {
        case TNY_FOLDER_TYPE_ROOT:
-               account_id = tny_account_get_id (TNY_ACCOUNT (instance));
-               if (!strcmp (account_id, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
+               if (TNY_IS_ACCOUNT (instance)) {
+                       account_id = tny_account_get_id (TNY_ACCOUNT (instance));
+                       /*
+                       if (!strcmp (account_id, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID)) {
+                               pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_LOCAL_FOLDERS);
+                       } else {
+                       */
+                               if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
+                                       pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_MMC);
+                               else
+                                       pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
+                       /*
+                       }
+                       */
+               }
+               else if (modest_tny_folder_store_is_virtual_local_folders (
+                       TNY_FOLDER_STORE (instance))) {
                        pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_LOCAL_FOLDERS);
-               } else {
-                       if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
-                               pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_MMC);
-                       else
-                               pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
                }
-                break;
+               break;
        case TNY_FOLDER_TYPE_INBOX:
-                pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX);
-                break;
-        case TNY_FOLDER_TYPE_OUTBOX:
-                pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX);
-                break;
-        case TNY_FOLDER_TYPE_JUNK:
-                pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK);
-                break;
-        case TNY_FOLDER_TYPE_SENT:
-                pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_SENT);
-                break;
+           pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX);
+           break;
+       case TNY_FOLDER_TYPE_OUTBOX:
+               pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX);
+               break;
+       case TNY_FOLDER_TYPE_JUNK:
+               pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK);
+               break;
+       case TNY_FOLDER_TYPE_SENT:
+               pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_SENT);
+               break;
        case TNY_FOLDER_TYPE_TRASH:
                pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_TRASH);
-                break;
+               break;
        case TNY_FOLDER_TYPE_DRAFTS:
                pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_DRAFTS);
-                break;
+               break;
        case TNY_FOLDER_TYPE_NORMAL:
-        default:
-                pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL);
+       default:
+               pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL);
                break;
-        }
+       }
+       
        g_object_unref (G_OBJECT (instance));
        g_free (fname);
 
@@ -653,7 +677,7 @@ expand_root_items (ModestFolderView *self)
 /*
  * We use this function to implement the
  * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
- * account in this case
+ * account in this case, and the local folders.
  */
 static gboolean 
 filter_row (GtkTreeModel *model,
@@ -661,7 +685,7 @@ filter_row (GtkTreeModel *model,
            gpointer data)
 {
        gboolean retval = TRUE;
-       gint type;
+       gint type = 0;
        GObject *instance = NULL;
 
        gtk_tree_model_get (model, iter,
@@ -670,20 +694,26 @@ filter_row (GtkTreeModel *model,
                            -1);
 
        if (type == TNY_FOLDER_TYPE_ROOT) {
-               TnyAccount *acc;
-               const gchar *account_id;
-
-               acc = TNY_ACCOUNT (instance);
-               account_id = tny_account_get_id (acc);
-
-               if (strcmp (account_id, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) &&
-                   strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) { 
-                       ModestFolderViewPrivate *priv;
+               /* TNY_FOLDER_TYPE_ROOT means that the instance is an account instead of a folder. */
+               if (TNY_IS_ACCOUNT (instance)) {
+                       TnyAccount *acc = TNY_ACCOUNT (instance);
+                       const gchar *account_id = tny_account_get_id (acc);
                        
-                       /* Show only the visible account id */
-                       priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data);
-                       if (priv->visible_account_id && strcmp (account_id, priv->visible_account_id))
-                               retval = FALSE;
+                       /* If it isn't a special folder, 
+                        * don't show it unless it is the visible account: */
+                       if (strcmp (account_id, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID) &&
+                           strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) { 
+                               
+                               /* TODO: Merge the folders before we get to this point? */
+                               
+                               /* Show only the visible account id */
+                               /*
+                               ModestFolderViewPrivate *priv = 
+                                       MODEST_FOLDER_VIEW_GET_PRIVATE (data);
+                               if (priv->visible_account_id && strcmp (account_id, priv->visible_account_id))
+                                       retval = FALSE;
+                               */
+                       }
                }
        }
 
@@ -692,11 +722,109 @@ filter_row (GtkTreeModel *model,
        return retval;
 }
 
+/*
+static void on_tnylist_accounts_debug_print(gpointer data,  gpointer user_data)
+{
+       TnyAccount* account = TNY_ACCOUNT(data);
+       const gchar *prefix = (const gchar*)(user_data);
+       
+       printf("%s account id=%s\n", prefix, tny_account_get_id (account));
+}
+*/
+
+static void
+add_account_folders_to_merged_folder (TnyAccount *account, TnyMergeFolder* merge_folder)
+{
+       const gchar* account_id = tny_account_get_id (account);
+       const gboolean is_actual_local_folders_account = account_id && 
+               (strcmp (account_id, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID) == 0);
+               
+       TnyList *list_outbox_folders = tny_simple_list_new ();
+       tny_folder_store_get_folders (TNY_FOLDER_STORE (account), 
+               list_outbox_folders, NULL, NULL);
+               
+       TnyIterator*  iter =  tny_list_create_iterator (list_outbox_folders);
+       while (!tny_iterator_is_done (iter))
+       {
+               TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (iter));
+               
+               if (folder) {
+                       gboolean add = TRUE;
+                       /* TODO: Do not add outboxes that are inside local-folders/, 
+                        * because these are just left-over from earlier Modest versions 
+                        * that put the outbox there: */
+                       if (is_actual_local_folders_account) {
+                               const TnyFolderType type = modest_tny_folder_get_local_folder_type (folder);
+                               if (type == TNY_FOLDER_TYPE_OUTBOX) {
+                                       add = FALSE;
+                               }
+                       }
+                       
+                       if (add)
+                               tny_merge_folder_add_folder (merge_folder, folder);
+                               
+                       g_object_unref (folder);        
+               }
+               
+               tny_iterator_next (iter);
+       }
+       
+       g_object_unref (list_outbox_folders);
+}
+
+
+static void
+add_account_folders_to_simple_folder_store (TnyAccount *account, ModestTnySimpleFolderStore* store)
+{
+       g_return_if_fail (account);
+       g_return_if_fail (store);
+               
+       TnyList *list_outbox_folders = tny_simple_list_new ();
+       tny_folder_store_get_folders (TNY_FOLDER_STORE (account), 
+               list_outbox_folders, NULL, NULL);
+       
+       /* Special handling for the .modest/local-folders account,
+        * to avoid adding unwanted folders.
+        * We cannot prevent them from being in the TnyAccount without 
+        * changing the libtinymail-camel. */
+       const gchar* account_id = tny_account_get_id (account);
+       const gboolean is_actual_local_folders_account = account_id && 
+               (strcmp (account_id, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID) == 0);
+       
+       TnyIterator*  iter =  tny_list_create_iterator (list_outbox_folders);
+       while (!tny_iterator_is_done (iter))
+       {
+               TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (iter));
+               
+               if (folder) {
+                       gboolean add = TRUE;
+                       /* TODO: Do not add outboxes that are inside local-folders/, 
+                        * because these are just left-over from earlier Modest versions 
+                        * that put the outbox there: */
+                       if (is_actual_local_folders_account) {
+                               const TnyFolderType type = modest_tny_folder_get_local_folder_type (folder);
+                               if (type == TNY_FOLDER_TYPE_OUTBOX) {
+                                       add = FALSE;
+                               }
+                       }
+                       
+                       if (add)
+                               modest_tny_simple_folder_store_add_folder (store, folder);
+                               
+                       g_object_unref (folder);        
+               }
+               
+               tny_iterator_next (iter);
+       }
+       
+       g_object_unref (list_outbox_folders);
+}
+
 static gboolean
 update_model (ModestFolderView *self, ModestTnyAccountStore *account_store)
 {
        ModestFolderViewPrivate *priv;
-       TnyList          *account_list;
+
        GtkTreeModel     *model;
 
        g_return_val_if_fail (account_store, FALSE);
@@ -712,37 +840,97 @@ update_model (ModestFolderView *self, ModestTnyAccountStore *account_store)
           selects only the subscribed folders. */
 /*     model        = tny_gtk_folder_store_tree_model_new (TRUE, priv->query); */
        model        = tny_gtk_folder_store_tree_model_new (TRUE, NULL);
-       account_list = TNY_LIST(model);
+       
+       /* Deal with the model via its TnyList Interface,
+        * filling the TnyList via a get_accounts() call: */
+       TnyList *model_as_list = TNY_LIST(model);
 
+       /* Create a virtual local-folders folder store, 
+        * containing the real local folders and the (merged) various per-account 
+        * outbox folders:
+        */
+       ModestTnySimpleFolderStore *store = modest_tny_simple_folder_store_new ();
+
+       /* Get the accounts: */
+       TnyList *account_list = tny_simple_list_new ();
        tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
                                        account_list,
-                                       TNY_ACCOUNT_STORE_STORE_ACCOUNTS);      
-       if (account_list) {
-               GtkTreeModel *filter_model = NULL, *sortable = NULL;
-
-               sortable = gtk_tree_model_sort_new_with_model (model);
-               gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
-                                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, 
-                                                     GTK_SORT_ASCENDING);
-               gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
-                                                TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
-                                                cmp_rows, NULL, NULL);
-
-               /* Create filter model */
-               if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE) {
-                       filter_model = gtk_tree_model_filter_new (sortable, NULL);
-                       gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
-                                                               filter_row,
-                                                               self,
-                                                               NULL);
+                                       TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
+       TnyIterator* iter =  tny_list_create_iterator (account_list);
+       
+       /* All per-account outbox folders are merged into one folders
+        * so that they appear as one outbox to the user: */
+       TnyMergeFolder *merged_outbox = TNY_MERGE_FOLDER (tny_merge_folder_new());
+       
+       while (!tny_iterator_is_done (iter))
+       {
+               GObject *cur = tny_iterator_get_current (iter);
+               TnyAccount *account = TNY_ACCOUNT (cur);
+               if (account) {
+                       /* Add both outbox account and local-folders account folders
+                        * to our one combined account:
+                        */
+                       if (MODEST_IS_TNY_OUTBOX_ACCOUNT (account)) {
+                               /* Add the folder to the merged folder.
+                                * We will add it later to the virtual local-folders store: */
+                               add_account_folders_to_merged_folder (account, merged_outbox);
+                       } else {
+                               const gchar *account_id = tny_account_get_id (account);
+                               if (account_id && !strcmp (account_id, MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID)) {
+                                       /* Add the folders to the virtual local-folders store: */
+                                       add_account_folders_to_simple_folder_store (account, store);
+                               }
+                               else {
+                                       /* Just add the account: */
+                                       tny_list_append (model_as_list, G_OBJECT (account));
+                               }
+                       }
                }
-
-               /* Set new model */
-               gtk_tree_view_set_model (GTK_TREE_VIEW(self), 
-                                        (filter_model) ? filter_model : sortable);
-               expand_root_items (self); /* expand all account folders */
-               g_object_unref (account_list);
+          
+               g_object_unref (cur);
+               tny_iterator_next (iter);
+       }
+       
+       /* Add the merged outbox folder to the virtual local-folders store: */
+       modest_tny_simple_folder_store_add_folder (store, TNY_FOLDER(merged_outbox));
+       g_object_unref (merged_outbox);
+       merged_outbox = NULL;
+       
+       /* Add the virtual local-folders store to the model: */
+       tny_list_append (model_as_list, G_OBJECT (store));
+       
+       
+       g_object_unref (account_list);
+       account_list = NULL;
+       
+       g_object_unref (model_as_list);
+       model_as_list = NULL;   
+               
+       /* tny_list_foreach (account_list, on_tnylist_accounts_debug_print, "update_model: "); */
+                                                     
+       GtkTreeModel *filter_model = NULL, *sortable = NULL;
+
+       sortable = gtk_tree_model_sort_new_with_model (model);
+       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
+                                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, 
+                                             GTK_SORT_ASCENDING);
+       gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
+                                        TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
+                                        cmp_rows, NULL, NULL);
+
+       /* Create filter model */
+       if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE) {
+               filter_model = gtk_tree_model_filter_new (sortable, NULL);
+               gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
+                                                       filter_row,
+                                                       self,
+                                                       NULL);
        }
+
+       /* Set new model */
+       gtk_tree_view_set_model (GTK_TREE_VIEW(self), 
+                                (filter_model) ? filter_model : sortable);
+       expand_root_items (self); /* expand all account folders */
        
        return TRUE;
 }
@@ -820,8 +1008,32 @@ modest_folder_view_get_selected (ModestFolderView *self)
        return priv->cur_folder_store;
 }
 
+static gint
+get_cmp_rows_type_pos (GObject *folder)
+{
+       /* Remote accounts -> Local account -> MMC account .*/
+       /* 0, 1, 2 */
+       
+       if (TNY_IS_FOLDER_STORE (folder) && 
+               modest_tny_folder_store_is_virtual_local_folders (
+                       TNY_FOLDER_STORE (folder))) {
+               return 1;
+       } else if (TNY_IS_ACCOUNT (folder)) {
+               TnyAccount *account = TNY_ACCOUNT (folder);
+               const gchar *account_id = tny_account_get_id (account);
+               if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
+                       return 2;
+               else
+                       return 0;
+       }
+       else {
+               printf ("DEBUG: %s: unexpected type.\n", __FUNCTION__);
+               return -1; /* Should never happen */
+       }
+}
+
 /*
- * This function orders the mail accounts following the next rules
+ * This function orders the mail accounts according to these rules:
  * 1st - remote accounts
  * 2nd - local account
  * 3rd - MMC account
@@ -833,7 +1045,8 @@ cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
        gint cmp;
        gchar         *name1, *name2;
        TnyFolderType type;
-       TnyFolder     *folder1, *folder2;
+       GObject *folder1 = NULL;
+       GObject *folder2 = NULL;
 
        gtk_tree_model_get (tree_model, iter1,
                            TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name1,
@@ -845,29 +1058,45 @@ cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
                            TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder2,
                            -1);
 
-       /* Order must be: Remote accounts -> Local account -> MMC account */
        if (type == TNY_FOLDER_TYPE_ROOT) {
-               const gchar *account_id = tny_account_get_id (TNY_ACCOUNT (folder1));
-               const gchar *account_id2 = tny_account_get_id (TNY_ACCOUNT (folder2));
-
-               if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
-                       cmp = +1;
+               /* Compare the types, so that 
+                * Remote accounts -> Local account -> MMC account .*/
+               const gint pos1 = get_cmp_rows_type_pos (folder1);
+               const gint pos2 = get_cmp_rows_type_pos (folder2);
+               /* printf ("DEBUG: %s:\n  type1=%s, pos1=%d\n  type2=%s, pos2=%d\n", 
+                       __FUNCTION__, G_OBJECT_TYPE_NAME(folder1), pos1, G_OBJECT_TYPE_NAME(folder2), pos2); */
+               if (pos1 <  pos2)
+                       cmp = -1;
+               else if (pos1 > pos2)
+                       cmp = 1;
                else {
-                       if (!strcmp (account_id, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
-                               if (!strcmp (account_id2, MODEST_MMC_ACCOUNT_ID))
-                                       cmp = -1;
-                               else
-                                       cmp = +1;
-                       } else {
-                               if (!strcmp (account_id2, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) ||
-                                   !strcmp (account_id2, MODEST_MMC_ACCOUNT_ID))
-                                       cmp = -1;
-                               else
-                                       cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
-                       }
+                       /* Compare items of the same type: */
+                       
+                       TnyAccount *account1 = NULL;
+                       if (TNY_IS_ACCOUNT (folder1))
+                               account1 = TNY_ACCOUNT (folder1);
+                               
+                       TnyAccount *account2 = NULL;
+                       if (TNY_IS_ACCOUNT (folder2))
+                               account2 = TNY_ACCOUNT (folder2);
+                               
+                       const gchar *account_id = account1 ? tny_account_get_id (account1) : NULL;
+                       const gchar *account_id2 = account2 ? tny_account_get_id (account2) : NULL;
+       
+                       if (!account_id && !account_id2)
+                               return 0;
+                       else if (!account_id)
+                               return -1;
+                       else if (!account_id2)
+                               return +1;
+                       else if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
+                               cmp = +1;
+                       else
+                               cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
                }
-       } else 
+       } else {
                cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
+       }
        
        if (folder1)
                g_object_unref(G_OBJECT(folder1));
@@ -1453,6 +1682,8 @@ modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *s
        
        priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
 
+       /* This will be used by the filter_row callback,
+        * to decided which rows to show: */
        if (priv->visible_account_id)
                g_free (priv->visible_account_id);
        priv->visible_account_id = g_strdup (account_id);
index 6565e82..6a4b130 100644 (file)
@@ -165,10 +165,10 @@ ModestMainWindowStyle       modest_main_window_get_style        (ModestMainWindo
 /**
  * modest_main_window_set_contents_style:
  * @self: the #ModestMainWindow
- * @style: a #ModestMainWindowContentsStyle that will be set
+ * @style: a #ModestMainWindowContentsStyle that will be set. Either headers or details.
  * 
  * Shows either the folder details, or the header list of the current
- * selected folder
+ * selected folder.
  **/
 void       modest_main_window_set_contents_style       (ModestMainWindow *self, 
                                                        ModestMainWindowContentsStyle style);