* Fixes NB#85964, do not crash when opening Drafts in memory full condition
[modest] / src / modest-runtime.c
index be73102..8eda572 100644 (file)
 #include <glib-object.h>
 #include <glib/gstdio.h>
 #include <modest-runtime.h>
+#include <modest-runtime-priv.h>
 #include <modest-defs.h>
 #include <modest-singletons.h>
 #include <widgets/modest-header-view.h>
 #include <widgets/modest-folder-view.h>
 #include <modest-tny-platform-factory.h>
+#include <modest-platform.h>
 #include <modest-widget-memory.h>
 #include <modest-widget-memory-priv.h>
 #include <modest-local-folder-info.h>
 #include <modest-account-mgr.h>
 #include <modest-account-mgr-helpers.h>
+#include <modest-icon-names.h>
+#include <modest-ui-actions.h>
+#include <modest-debug.h>
 
-#if MODEST_PLATFORM_ID==2 /* maemo/hildon */
-#include <libosso.h>
-static gboolean hildon_init (void);
-#endif /* MODEST_PLATFORM_ID==2 */
+static ModestSingletons       *_singletons    = NULL;
 
-static gboolean init_header_columns (ModestConf *conf, gboolean overwrite);
-static gboolean init_local_folders  (void);
-static gboolean init_default_account_maybe  (ModestAccountMgr *acc_mgr);
-static void     init_i18n (void);
-static void     debug_g_type_init (void);
-static void     debug_logging_init (void);
+// we get the account store here instead of in Singletons
+// as it leads to various chicken & problems with initialization
+static ModestTnyAccountStore  *_account_store  = NULL;
 
-static ModestSingletons *_singletons = NULL;
+/* Signal handlers for the send queues */
+static GSList *_sig_handlers = NULL;
 
 /*
- * defaults for the column headers
+ * private functions declared in modest-runtime-priv.h -
+ * only to be called from modest-init.c 
  */
-
-typedef struct {
-       ModestHeaderViewColumn col;
-       guint                  width;
-} FolderCols;
-
-static const FolderCols INBOX_COLUMNS_DETAILS[] = {
-       {MODEST_HEADER_VIEW_COLUMN_MSGTYPE, 40},
-       {MODEST_HEADER_VIEW_COLUMN_ATTACH,  40},
-       {MODEST_HEADER_VIEW_COLUMN_FROM,    80},
-       {MODEST_HEADER_VIEW_COLUMN_SUBJECT, 80},
-       {MODEST_HEADER_VIEW_COLUMN_RECEIVED_DATE, 60},
-       {MODEST_HEADER_VIEW_COLUMN_SIZE, 50}
-};
-static const FolderCols INBOX_COLUMNS_TWOLINES[] = {
-       {MODEST_HEADER_VIEW_COLUMN_MSGTYPE, 40},
-       {MODEST_HEADER_VIEW_COLUMN_ATTACH,  40},
-       {MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN, 200}
-};
-
-static const FolderCols OUTBOX_COLUMNS_DETAILS[] = {
-        {MODEST_HEADER_VIEW_COLUMN_MSGTYPE, 40},
-        {MODEST_HEADER_VIEW_COLUMN_ATTACH,  40},
-        {MODEST_HEADER_VIEW_COLUMN_TO,    80},
-        {MODEST_HEADER_VIEW_COLUMN_SUBJECT, 80},
-        {MODEST_HEADER_VIEW_COLUMN_SENT_DATE, 80},
-        {MODEST_HEADER_VIEW_COLUMN_SIZE, 50}
-};
-static const FolderCols OUTBOX_COLUMNS_TWOLINES[] = {
-        {MODEST_HEADER_VIEW_COLUMN_MSGTYPE, 40},
-        {MODEST_HEADER_VIEW_COLUMN_ATTACH,  40},
-        {MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT,200},
-};
-        
-static const TnyFolderType LOCAL_FOLDERS[] = {
-       TNY_FOLDER_TYPE_OUTBOX,
-       TNY_FOLDER_TYPE_DRAFTS,
-       TNY_FOLDER_TYPE_SENT,
-       TNY_FOLDER_TYPE_TRASH,
-       TNY_FOLDER_TYPE_ARCHIVE 
-};
-
-
+/*-----------------------------------------------------------------------------*/
 gboolean
 modest_runtime_init (void)
 {
-       ModestSingletons *my_singletons;
-       gboolean reset;
-       
        if (_singletons) {
-               g_printerr ("modest: modest_runtime_init can only be called once\n");
-               return FALSE;
-       }
-       
-       init_i18n();
-       debug_g_type_init();
-       debug_logging_init();
-
-       g_thread_init(NULL);
-       gdk_threads_init ();
-
-       my_singletons = modest_singletons_new ();
-       if (!my_singletons) {
-               g_printerr ("modest: failed to initialize singletons\n");
-               return FALSE;
-       }
-
-#if MODEST_PLATFORM_ID==2 
-       if (!hildon_init ()) {
-               modest_runtime_uninit ();
-               g_printerr ("modest: failed to initialize hildon\n");
-               return FALSE;
-       }
-#endif /* MODEST_PLATFORM_ID==2 */
-
-       /* based on the debug settings, we decide whether to overwrite old settings */
-       reset = modest_runtime_get_debug_flags () & MODEST_RUNTIME_DEBUG_FACTORY_SETTINGS;
-       if (!init_header_columns(modest_singletons_get_conf (my_singletons), reset)) {
-               modest_runtime_uninit ();
-               g_printerr ("modest: failed to init header columns\n");
-               return FALSE;
-       }
-
-       if (!init_local_folders()) {
-               modest_runtime_uninit ();
-               g_printerr ("modest: failed to init local folders\n");
+               g_printerr ("modest: modest_runtime_init can only be run once\n");
                return FALSE;
        }
        
-       if (!init_default_account_maybe(modest_singletons_get_account_mgr (my_singletons))) {
-               modest_runtime_uninit ();
-               g_printerr ("modest: failed to init default account\n");
+       _singletons = modest_singletons_new ();
+       if (!_singletons) {
+               g_printerr ("modest: failed to create singletons\n");
                return FALSE;
        }
-
-       /* don't initialize _singletons before all the other init stuff
-        * is done; thus, using any of the singleton stuff before
-        * runtime is fully init'ed  is avoided
-        */
-       _singletons = my_singletons;
        
        return TRUE;
 }
 
-
 gboolean
-modest_runtime_init_ui (gint argc, gchar** argv)
+modest_runtime_uninit (void)
 {
-       if (!gtk_init_check(&argc, &argv)) {
-               g_printerr ("modest: failed to initialize graphical ui\n");
-               return FALSE;
-       }
-       return TRUE;
-}
+       if (!_singletons)
+               return TRUE;    /* uninit maybe called if runtime_init failed */
+       
+       g_return_val_if_fail (MODEST_IS_SINGLETONS(_singletons), FALSE);
+       
+       g_debug ("%s: cleaning up", __FUNCTION__);
 
+       MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(_singletons,"");
+       g_object_unref(_singletons);
+       _singletons = NULL;
 
-gboolean
-modest_runtime_uninit (void)
-{
-       if (!_singletons) {
-               g_printerr ("modest: modest_runtime is not initialized\n");
-               return FALSE;
+       g_debug ("%s: cleaned up singletons", __FUNCTION__);
+
+       if (_account_store) {
+               MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(_account_store,"");
+               g_object_unref(_account_store);
+               _account_store = NULL;
        }
+
+       g_debug ("%s: cleaned up the account store", __FUNCTION__);
+
        
-       g_object_unref (G_OBJECT(_singletons));
-       _singletons = NULL;
+       if (_sig_handlers) {
+               modest_signal_mgr_disconnect_all_and_destroy (_sig_handlers);
+               _sig_handlers = NULL;
+       }
 
+       g_debug ("%s: all cleaned up", __FUNCTION__);
+
+       
        return TRUE;
 }
-
+/*-----------------------------------------------------------------------------*/
+       
 
 ModestAccountMgr*
 modest_runtime_get_account_mgr   (void)
@@ -198,12 +124,28 @@ modest_runtime_get_account_mgr   (void)
        return modest_singletons_get_account_mgr (_singletons);
 }
 
-ModestTnyAccountStore*
-modest_runtime_get_account_store   (void)
+ModestEmailClipboard*
+modest_runtime_get_email_clipboard   (void)
 {
        g_return_val_if_fail (_singletons, NULL);
-       return modest_singletons_get_account_store (_singletons);
+       return modest_singletons_get_email_clipboard (_singletons);
+}
 
+ModestTnyAccountStore*
+modest_runtime_get_account_store   (void)
+{
+       // we get the account store here instead of in Singletons
+        // as it leads to various chicken & problems with initialization
+       g_return_val_if_fail (_singletons, NULL);       
+       if (!_account_store) {
+               _account_store  = modest_tny_account_store_new (modest_runtime_get_account_mgr(),
+                                                               modest_runtime_get_device());
+               if (!_account_store) {
+                       g_printerr ("modest: cannot create modest tny account store instance\n");
+                       return NULL;
+               }
+       }
+       return _account_store;
 }
 
 ModestConf*
@@ -230,276 +172,131 @@ modest_runtime_get_mail_operation_queue (void)
 }
 
 
-ModestWidgetFactory*
-modest_runtime_get_widget_factory     (void)
+
+TnyDevice*
+modest_runtime_get_device (void)
 {
        g_return_val_if_fail (_singletons, NULL);
-       return modest_singletons_get_widget_factory (_singletons);
+       return modest_singletons_get_device (_singletons);
 }
 
 
-
-/* http://primates.ximian.com/~federico/news-2006-04.html#memory-debugging-infrastructure*/
-ModestRuntimeDebugFlags
-modest_runtime_get_debug_flags ()
+TnyPlatformFactory*
+modest_runtime_get_platform_factory  (void)
 {
-       static const GDebugKey debug_keys[] = {
-               { "abort-on-warning", MODEST_RUNTIME_DEBUG_ABORT_ON_WARNING },
-               { "log-actions",      MODEST_RUNTIME_DEBUG_LOG_ACTIONS },
-               { "debug-objects",    MODEST_RUNTIME_DEBUG_DEBUG_OBJECTS },
-               { "debug-signals",    MODEST_RUNTIME_DEBUG_DEBUG_SIGNALS },
-               { "factory-settings", MODEST_RUNTIME_DEBUG_FACTORY_SETTINGS }
-       };
-       const gchar *str;
-       static ModestRuntimeDebugFlags debug_flags = -1;
-
-       if (debug_flags != -1)
-               return debug_flags;
-       
-       str = g_getenv (MODEST_DEBUG);
-       
-       if (str != NULL)
-               debug_flags = g_parse_debug_string (str, debug_keys, G_N_ELEMENTS (debug_keys));
-       else
-               debug_flags = 0;
-       
-       return debug_flags;
+       g_return_val_if_fail (_singletons, NULL);
+       return modest_singletons_get_platform_factory (_singletons);
 }
 
-
-
-
-
-/* NOTE: the exact details of this format are important, as they
- * are also used in modest-widget-memory. FIXME: make a shared function
- * for this with widget-memory
- */
-static gboolean
-save_header_settings (ModestConf *conf, TnyFolderType type,
-                     ModestHeaderViewStyle style,  const FolderCols* cols,
-                     guint col_num, gboolean overwrite)
+ModestTnySendQueue*
+modest_runtime_get_send_queue  (TnyTransportAccount *account,
+                               gboolean create)
 {
-       int i;
-       gchar *key;
-       GString *str;
-
-       g_return_val_if_fail (cols, FALSE);
-
-       key = _modest_widget_memory_get_keyname_with_double_type ("header-view",
-                                                                 type, style,
-                                                                 MODEST_WIDGET_MEMORY_PARAM_COLUMN_WIDTH);
-       /* if we're not in overwrite mode, only write stuff it
-        * there was nothing before */
-       if (!overwrite &&  modest_conf_key_exists(conf, key, NULL)) {
-               g_free (key);
-               return TRUE;
-       }
-
-       /* the format is necessarily the same as the one in modest-widget-memory */
-       str = g_string_new (NULL);
-       for (i = 0; i != col_num; ++i) 
-               g_string_append_printf (str, "%d:%d ",
-                                       cols[i].col, cols[i].width); 
-
-       modest_conf_set_string (conf, key, str->str, NULL);
-       g_free (key);
-       g_string_free (str, TRUE);
+       ModestCacheMgr *cache_mgr;
+       GHashTable     *send_queue_cache;
+       gpointer       orig_key = NULL, send_queue = NULL;
        
-       return TRUE;
-}
+       g_return_val_if_fail (_singletons, NULL);
+       g_return_val_if_fail (TNY_IS_TRANSPORT_ACCOUNT(account), NULL);
 
-/**
- * modest_init_header_columns:
- * @overwrite: write the setting, even if it already exists
- * 
- * will set defaults for the columns to show for folder,
- * if there are no such settings yet (in ModestWidgetMemory)
- * 
- * Returns: TRUE if succeeded, FALSE in case of error
- */
-static gboolean
-init_header_columns (ModestConf *conf, gboolean overwrite)
-{
-       int folder_type;
-       
-       for (folder_type = TNY_FOLDER_TYPE_UNKNOWN;
-            folder_type <= TNY_FOLDER_TYPE_CALENDAR; ++folder_type) {          
-               
-               switch (folder_type) {
-               case TNY_FOLDER_TYPE_OUTBOX:
-               case TNY_FOLDER_TYPE_SENT:
-               case TNY_FOLDER_TYPE_DRAFTS:
-               save_header_settings (conf, folder_type,
-                                     MODEST_HEADER_VIEW_STYLE_DETAILS,
-                                     OUTBOX_COLUMNS_DETAILS,
-                                     G_N_ELEMENTS(OUTBOX_COLUMNS_DETAILS),
-                                     overwrite);
-               save_header_settings (conf, folder_type,
-                                     MODEST_HEADER_VIEW_STYLE_TWOLINES,
-                                     OUTBOX_COLUMNS_TWOLINES,
-                                     G_N_ELEMENTS(OUTBOX_COLUMNS_TWOLINES),
-                                     overwrite);
-               break;
-
-               default:
-               save_header_settings (conf, folder_type,
-                                     MODEST_HEADER_VIEW_STYLE_DETAILS,
-                                     INBOX_COLUMNS_DETAILS,
-                                     G_N_ELEMENTS(INBOX_COLUMNS_DETAILS),
-                                     overwrite);
-               save_header_settings (conf, folder_type,
-                                     MODEST_HEADER_VIEW_STYLE_TWOLINES,
-                                     INBOX_COLUMNS_TWOLINES,
-                                     G_N_ELEMENTS(INBOX_COLUMNS_TWOLINES),
-                                     overwrite);
-               };
-       }
-       return TRUE;
-}
+       cache_mgr = modest_singletons_get_cache_mgr (_singletons);
+       send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
+                                                      MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
 
-/**
- * init_local_folders:
- * 
- * create the Local Folders folder under cache, if they
- * do not exist yet.
- * 
- * Returns: TRUE if the folder were already there, or
- * they were created, FALSE otherwise
- */
-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 ();
-
-       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,
-                                               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);
+       /* Each modest account has its own send queue.
+        * Note that each modest account will have its own outbox folder, 
+        * returned by TnySendQueue::get_outbox_func().
+        */
+       if (!g_hash_table_lookup_extended (send_queue_cache, account, &orig_key, &send_queue) &&
+           create) {
+               /* Note that this send queue will start sending messages from its outbox 
+                * as soon as it is instantiated: */
+               send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(account));
+
+               if (send_queue) {
+                       _sig_handlers = 
+                               modest_signal_mgr_connect (_sig_handlers, 
+                                                          send_queue, 
+                                                          "error_happened",
+                                                          G_CALLBACK (modest_ui_actions_on_send_queue_error_happened), 
+                                                          NULL);
+
+                       _sig_handlers = 
+                               modest_signal_mgr_connect (_sig_handlers, 
+                                                          send_queue, 
+                                                          "status_changed",
+                                                          G_CALLBACK (modest_ui_actions_on_send_queue_status_changed), 
+                                                          NULL);
+
+                       g_hash_table_insert (send_queue_cache, 
+                                            g_object_ref (account), 
+                                            g_object_ref (send_queue));
                }
        }
-       
-       g_free (maildir_path);
-       return TRUE;
-}
-
 
-
-static void
-free_element (gpointer data, gpointer user_data)
-{
-       g_free (data);
+       return (send_queue) ? MODEST_TNY_SEND_QUEUE(send_queue) : NULL;
 }
 
-
-
-/**
- * init_default_account_maybe:
- *
- * if there are accounts defined, but there is no default account,
- * it will be defined.
- * 
- * Returns: TRUE if there was a default account already,
- *  or one has been created or there are no accounts yet,
- *  returns FALSE in case of error
- */
-static gboolean
-init_default_account_maybe  (ModestAccountMgr *acc_mgr)
+void modest_runtime_remove_all_send_queues ()
 {
-       GSList *all_accounts = NULL;
-       gchar *default_account;
-       gboolean retval = TRUE;
+       ModestCacheMgr *cache_mgr = modest_singletons_get_cache_mgr (_singletons);
        
-       all_accounts = modest_account_mgr_account_names (acc_mgr, NULL);
-       if (all_accounts) { /* if there are any accounts, there should be a default one */
-               default_account = 
-                       modest_account_mgr_get_default_account (acc_mgr);
-               if (!default_account) {
-                       gchar *first_account;
-                       g_printerr ("modest: no default account defined\n");
-                       first_account = (gchar*)all_accounts->data;
-                       if ((retval = modest_account_mgr_set_default_account (acc_mgr, first_account)))
-                               g_printerr ("modest: set '%s' as the default account\n",
-                                           first_account);
-                       else
-                               g_printerr ("modest: failed to set '%s' as the default account\n",
-                                           first_account);
-                       g_free (default_account);
-               }
-               g_slist_foreach (all_accounts, free_element, NULL);
-               g_slist_free    (all_accounts);
-       }
-       return retval;
+       modest_cache_mgr_flush (cache_mgr, MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
 }
 
+void 
+modest_runtime_remove_send_queue (TnyTransportAccount *account)
+{
 
+       ModestCacheMgr *cache_mgr;
+       GHashTable     *send_queue_cache;
 
-static void
-debug_g_type_init (void)
-{
-       GTypeDebugFlags gflags;
-       ModestRuntimeDebugFlags mflags;
-       
-       gflags = 0;
-       mflags = modest_runtime_get_debug_flags ();
+       g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (account));  
+       g_return_if_fail (_singletons);
 
-       if (mflags & MODEST_RUNTIME_DEBUG_DEBUG_OBJECTS)
-               gflags |= G_TYPE_DEBUG_OBJECTS;
-       if (mflags & MODEST_RUNTIME_DEBUG_DEBUG_SIGNALS)
-               gflags |= G_TYPE_DEBUG_SIGNALS;
+       cache_mgr = modest_singletons_get_cache_mgr (_singletons);
+       send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
+                                                      MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE); 
 
-       g_type_init_with_debug_flags (gflags);
+       if (g_hash_table_lookup (send_queue_cache, account))
+               g_hash_table_remove (send_queue_cache, account);
 }
 
-static void
-debug_logging_init (void)
+ModestWindowMgr *
+modest_runtime_get_window_mgr (void)
 {
-       ModestRuntimeDebugFlags mflags;
-       mflags = modest_runtime_get_debug_flags ();
-       
-       if (mflags & MODEST_RUNTIME_DEBUG_ABORT_ON_WARNING)
-               g_log_set_always_fatal (G_LOG_LEVEL_ERROR |
-                                       G_LOG_LEVEL_CRITICAL |
-                                       G_LOG_LEVEL_WARNING);
+       g_return_val_if_fail (_singletons, NULL);
+       return modest_singletons_get_window_mgr (_singletons);
 }
 
-
-static void
-init_i18n (void)
+/* http://primates.ximian.com/~federico/news-2006-04.html#memory-debugging-infrastructure*/
+ModestRuntimeDebugFlags
+modest_runtime_get_debug_flags ()
 {
-       bindtextdomain (GETTEXT_PACKAGE, MODEST_LOCALEDIR);
-       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-       textdomain (GETTEXT_PACKAGE);
+       static const GDebugKey debug_keys[] = {
+               { "abort-on-warning",   MODEST_RUNTIME_DEBUG_ABORT_ON_WARNING },
+               { "log-actions",        MODEST_RUNTIME_DEBUG_LOG_ACTIONS },
+               { "debug-objects",      MODEST_RUNTIME_DEBUG_OBJECTS },
+               { "debug-signals",      MODEST_RUNTIME_DEBUG_SIGNALS },
+               { "factory-settings",   MODEST_RUNTIME_DEBUG_FACTORY_SETTINGS},
+               { "debug-code",         MODEST_RUNTIME_DEBUG_CODE}
+       };
+       const gchar *str;
+       static ModestRuntimeDebugFlags debug_flags = -1;
 
+       if (debug_flags != -1)
+               return debug_flags;
+       
+       str = g_getenv (MODEST_DEBUG);
+       
+       if (str != NULL)
+               debug_flags = g_parse_debug_string (str, debug_keys, G_N_ELEMENTS (debug_keys));
+       else
+               debug_flags = 0;
+       
+       return debug_flags;
 }
 
 
-#if MODEST_PLATFORM_ID==2 
-static gboolean
-hildon_init (void)
-{
-       osso_context_t *osso_context =
-               osso_initialize(PACKAGE, PACKAGE_VERSION,
-                               TRUE, NULL);    
-       if (!osso_context) {
-               g_printerr ("modest: failed to acquire osso context\n");
-               return FALSE;
-       }
-}
-#endif /* MODEST_PLATFORM_ID==2 */
+
+