1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "maemo/modest-maemo-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <osso-helplib.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <libosso-abook/osso-abook.h>
42 #include <maemo/modest-osso-autosave-callbacks.h>
44 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
45 #include <tny-maemo-conic-device.h>
46 #include <tny-simple-list.h>
47 #include <tny-folder.h>
48 #include <tny-camel-imap-store-account.h>
49 #include <tny-camel-pop-store-account.h>
50 #include <gtk/gtkicontheme.h>
51 #include <gtk/gtkmenuitem.h>
52 #include <gtk/gtkmain.h>
53 #include <modest-text-utils.h>
54 #include "modest-tny-folder.h"
58 #define HILDON_OSSO_URI_ACTION "uri-action"
59 #define URI_ACTION_COPY "copy:"
61 static osso_context_t *osso_context = NULL;
64 on_modest_conf_update_interval_changed (ModestConf* self,
66 ModestConfEvent event,
67 ModestConfNotificationId id,
70 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
71 const guint update_interval_minutes =
72 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
73 modest_platform_set_update_interval (update_interval_minutes);
78 modest_platform_init (int argc, char *argv[])
80 osso_hw_state_t hw_state = { 0 };
84 osso_initialize(PACKAGE,PACKAGE_VERSION,
87 g_printerr ("modest: failed to acquire osso context\n");
91 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
92 g_printerr ("modest: could not get dbus connection\n");
97 /* Add a D-Bus handler to be used when the main osso-rpc
98 * D-Bus handler has not handled something.
99 * We use this for D-Bus methods that need to use more complex types
100 * than osso-rpc supports.
102 if (!dbus_connection_add_filter (con,
103 modest_dbus_req_filter,
107 g_printerr ("modest: Could not add D-Bus filter\n");
111 /* Register our simple D-Bus callbacks, via the osso API: */
112 osso_return_t result = osso_rpc_set_cb_f(osso_context,
116 modest_dbus_req_handler, NULL /* user_data */);
117 if (result != OSSO_OK) {
118 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
122 /* Add handler for Exit D-BUS messages.
123 * Not used because osso_application_set_exit_cb() is deprecated and obsolete:
124 result = osso_application_set_exit_cb(osso_context,
125 modest_dbus_exit_event_handler,
127 if (result != OSSO_OK) {
128 g_print("Error setting exit callback (%d)\n", result);
133 /* Register hardware event dbus callback: */
134 hw_state.shutdown_ind = TRUE;
135 osso_hw_set_event_cb(osso_context, NULL,/*&hw_state*/ modest_osso_cb_hw_state_handler, NULL);
137 /* Register osso auto-save callbacks: */
138 result = osso_application_set_autosave_cb (osso_context,
139 modest_on_osso_application_autosave, NULL /* user_data */);
140 if (result != OSSO_OK) {
141 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
146 /* Make sure that the update interval is changed whenever its gconf key
148 /* CAUTION: we're not using here the
149 modest_conf_listen_to_namespace because we know that there
150 are other parts of Modest listening for this namespace, so
151 we'll receive the notifications anyway. We basically do not
152 use it because there is no easy way to do the
153 modest_conf_forget_namespace */
154 ModestConf *conf = modest_runtime_get_conf ();
155 g_signal_connect (G_OBJECT(conf),
157 G_CALLBACK (on_modest_conf_update_interval_changed),
160 /* Get the initial update interval from gconf: */
161 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
162 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
164 /* initialize the addressbook */
165 if (!osso_abook_init (&argc, &argv, osso_context)) {
166 g_printerr ("modest: failed to initialized addressbook\n");
174 modest_platform_get_new_device (void)
176 return TNY_DEVICE (tny_maemo_conic_device_new ());
181 guess_mime_type_from_name (const gchar* name)
185 const static gchar* octet_stream= "application/octet-stream";
186 const static gchar* mime_map[][2] = {
187 { "pdf", "application/pdf"},
188 { "doc", "application/msword"},
189 { "xls", "application/excel"},
190 { "png", "image/png" },
191 { "gif", "image/gif" },
192 { "jpg", "image/jpeg"},
193 { "jpeg", "image/jpeg"},
194 { "mp3", "audio/mp3" }
200 ext = g_strrstr (name, ".");
204 for (i = 0; i != G_N_ELEMENTS(mime_map); ++i) {
205 if (!g_ascii_strcasecmp (mime_map[i][0], ext + 1)) /* +1: ignore '.'*/
206 return mime_map[i][1];
213 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
214 gchar **effective_mime_type)
216 GString *mime_str = NULL;
217 gchar *icon_name = NULL;
218 gchar **icons, **cursor;
220 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
221 mime_str = g_string_new (guess_mime_type_from_name(name));
223 mime_str = g_string_new (mime_type);
224 g_string_ascii_down (mime_str);
227 #ifdef MODEST_HAVE_OSSO_MIME
228 icons = osso_mime_get_icon_names (mime_str->str, NULL);
230 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
231 #endif /*MODEST_HAVE_OSSO_MIME*/
232 for (cursor = icons; cursor; ++cursor) {
233 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
234 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
235 icon_name = g_strdup ("qgn_list_messagin");
237 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
238 icon_name = g_strdup (*cursor);
244 if (effective_mime_type)
245 *effective_mime_type = g_string_free (mime_str, FALSE);
247 g_string_free (mime_str, TRUE);
255 #ifdef MODEST_HAVE_OSSO_MIME
257 modest_platform_activate_uri (const gchar *uri)
259 OssoURIAction *action;
260 gboolean result = FALSE;
261 GSList *actions, *iter = NULL;
264 g_return_val_if_fail (uri, FALSE);
268 /* the default action should be email */
269 scheme = osso_uri_get_scheme_from_uri (uri, NULL);
270 actions = osso_uri_get_actions (scheme, NULL);
272 for (iter = actions; iter; iter = g_slist_next (iter)) {
273 action = (OssoURIAction*) iter->data;
274 if (action && strcmp (osso_uri_action_get_name (action), "uri_link_compose_email") == 0) {
276 result = osso_uri_open (uri, action, &err);
277 if (!result && err) {
278 g_printerr ("modest: modest_platform_activate_uri : %s",
279 err->message ? err->message : "unknown error");
286 /* if we could open it with email, try something else */
288 result = osso_uri_open (uri, NULL, NULL);
292 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
296 #else /* !MODEST_HAVE_OSSO_MIME*/
299 modest_platform_activate_uri (const gchar *uri)
301 HildonURIAction *action;
302 gboolean result = FALSE;
303 GSList *actions, *iter = NULL;
306 g_return_val_if_fail (uri, FALSE);
310 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
311 actions = hildon_uri_get_actions (scheme, NULL);
313 for (iter = actions; iter; iter = g_slist_next (iter)) {
314 action = (HildonURIAction*) iter->data;
315 if (action && strcmp (hildon_uri_action_get_service (action), "com.nokia.modest") == 0) {
317 result = hildon_uri_open (uri, action, &err);
318 if (!result && err) {
319 g_printerr ("modest: modest_platform_activate_uri : %s",
320 err->message ? err->message : "unknown error");
327 /* if we could open it with email, try something else */
329 result = hildon_uri_open (uri, NULL, NULL);
332 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
338 #endif /* MODEST_HAVE_OSSO_MIME*/
341 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
345 gchar *uri_path = NULL;
346 GString *mime_str = NULL;
348 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
349 mime_str = g_string_new (guess_mime_type_from_name(path));
351 mime_str = g_string_new (mime_type);
352 g_string_ascii_down (mime_str);
355 uri_path = g_strconcat ("file://", path, NULL);
357 con = osso_get_dbus_connection (osso_context);
358 #ifdef MODEST_HAVE_OSSO_MIME
359 result = osso_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
361 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
362 #endif /*MODEST_HAVE_OSSO_MIME*/
363 g_string_free (mime_str, TRUE);
366 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
373 } ModestPlatformPopupInfo;
376 delete_uri_popup (GtkWidget *menu,
380 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
382 g_free (popup_info->uri);
383 #ifdef MODEST_HAVE_OSSO_MIME
384 osso_uri_free_actions (popup_info->actions);
386 hildon_uri_free_actions (popup_info->actions);
387 #endif /*MODEST_HAVE_OSSO_MIME*/
392 activate_uri_popup_item (GtkMenuItem *menu_item,
396 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
397 const gchar* action_name;
399 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
401 g_printerr ("modest: no action name defined\n");
405 /* special handling for the copy menu item -- copy the uri to the clipboard */
406 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
407 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
408 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
409 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
411 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
412 action_name += strlen ("mailto:");
414 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
415 return; /* we're done */
418 /* now, the real uri-actions... */
419 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
420 #ifdef MODEST_HAVE_OSSO_MIME
421 OssoURIAction *action = (OssoURIAction *) node->data;
422 if (strcmp (action_name, osso_uri_action_get_name (action))==0) {
423 osso_uri_open (popup_info->uri, action, NULL);
427 HildonURIAction *action = (HildonURIAction *) node->data;
428 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
429 hildon_uri_open (popup_info->uri, action, NULL);
432 #endif /*MODEST_HAVE_OSSO_MIME*/
437 modest_platform_show_uri_popup (const gchar *uri)
440 GSList *actions_list;
445 #ifdef MODEST_HAVE_OSSO_MIME
446 scheme = osso_uri_get_scheme_from_uri (uri, NULL);
447 actions_list = osso_uri_get_actions (scheme, NULL);
449 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
450 actions_list = hildon_uri_get_actions (scheme, NULL);
451 #endif /* MODEST_HAVE_OSSO_MIME */
452 if (actions_list != NULL) {
454 GtkWidget *menu = gtk_menu_new ();
455 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
457 popup_info->actions = actions_list;
458 popup_info->uri = g_strdup (uri);
460 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
461 GtkWidget *menu_item;
462 const gchar *action_name;
463 const gchar *translation_domain;
464 #ifdef MODEST_HAVE_OSSO_MIME
465 OssoURIAction *action = (OssoURIAction *) node->data;
466 action_name = osso_uri_action_get_name (action);
467 translation_domain = osso_uri_action_get_translation_domain (action);
468 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain,action_name));
469 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);
470 /* hack, we add it as a gobject property*/
471 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
474 if (osso_uri_is_default_action (action, NULL)) {
475 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
477 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
480 HildonURIAction *action = (HildonURIAction *) node->data;
481 action_name = hildon_uri_action_get_name (action);
482 translation_domain = hildon_uri_action_get_translation_domain (action);
483 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
484 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
485 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
488 if (hildon_uri_is_default_action (action, NULL)) {
489 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
491 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
493 #endif /*MODEST_HAVE_OSSO_MIME*/
494 gtk_widget_show (menu_item);
497 /* always add the copy item */
498 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
499 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
500 g_strconcat (URI_ACTION_COPY, uri, NULL),
502 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
503 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
504 gtk_widget_show (menu_item);
507 /* and what to do when the link is deleted */
508 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
509 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
512 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
521 modest_platform_get_icon (const gchar *name)
524 GdkPixbuf* pixbuf = NULL;
525 GtkIconTheme *current_theme = NULL;
527 g_return_val_if_fail (name, NULL);
529 /* strlen == 0 is not really an error; it just
530 * means the icon is not available
532 if (!name || strlen(name) == 0)
535 #if 0 /* do we still need this? */
536 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
537 pixbuf = gdk_pixbuf_new_from_file (name, &err);
539 g_printerr ("modest: error loading icon '%s': %s\n",
547 current_theme = gtk_icon_theme_get_default ();
548 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
549 GTK_ICON_LOOKUP_NO_SVG,
552 g_printerr ("modest: error loading theme icon '%s': %s\n",
560 modest_platform_get_app_name (void)
562 return _("mcen_ap_name");
566 entry_insert_text (GtkEditable *editable,
575 chars = gtk_editable_get_chars (editable, 0, -1);
576 chars_length = g_utf8_strlen (chars, -1);
578 /* Show WID-INF036 */
579 if (chars_length >= 20) {
580 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
581 _CS("ckdg_ib_maximum_characters_reached"));
583 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
587 tmp = g_strndup (folder_name_forbidden_chars,
588 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
589 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
590 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
595 /* Write the text in the entry if it's valid */
596 g_signal_handlers_block_by_func (editable,
597 (gpointer) entry_insert_text, data);
598 gtk_editable_insert_text (editable, text, length, position);
599 g_signal_handlers_unblock_by_func (editable,
600 (gpointer) entry_insert_text, data);
603 /* Do not allow further processing */
604 g_signal_stop_emission_by_name (editable, "insert_text");
608 entry_changed (GtkEditable *editable,
612 GtkWidget *ok_button;
615 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
616 ok_button = GTK_WIDGET (buttons->next->data);
618 chars = gtk_editable_get_chars (editable, 0, -1);
619 g_return_if_fail (chars != NULL);
622 if (g_utf8_strlen (chars,-1) >= 21)
623 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
624 _CS("ckdg_ib_maximum_characters_reached"));
626 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
629 g_list_free (buttons);
634 launch_sort_headers_dialog (GtkWindow *parent_window,
635 HildonSortDialog *dialog)
637 ModestHeaderView *header_view = NULL;
639 GtkSortType sort_type;
641 gint default_key = 0;
643 gboolean outgoing = FALSE;
644 gint current_sort_colid = -1;
645 GtkSortType current_sort_type;
646 gint attachments_sort_id;
647 gint priority_sort_id;
648 GtkTreeSortable *sortable;
650 /* Get header window */
651 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
652 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
653 MODEST_WIDGET_TYPE_HEADER_VIEW));
655 if (!header_view) return;
657 /* Add sorting keys */
658 cols = modest_header_view_get_columns (header_view);
659 if (cols == NULL) return;
660 int sort_model_ids[6];
664 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
665 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
667 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
669 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
670 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
672 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
673 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
676 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
678 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
679 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
681 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
682 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
684 default_key = sort_key;
686 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
687 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
689 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
691 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
693 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
694 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
695 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
696 attachments_sort_id = sort_key;
698 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
699 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
700 sort_ids[sort_key] = 0;
702 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
703 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
704 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY;
705 priority_sort_id = sort_key;
707 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
709 if (!gtk_tree_sortable_get_sort_column_id (sortable,
710 ¤t_sort_colid, ¤t_sort_type)) {
711 hildon_sort_dialog_set_sort_key (dialog, default_key);
712 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
714 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
715 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
716 gpointer flags_sort_type_pointer;
717 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
718 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY)
719 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
721 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
723 gint current_sort_keyid = 0;
724 while (current_sort_keyid < 6) {
725 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
728 current_sort_keyid++;
730 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
734 result = gtk_dialog_run (GTK_DIALOG (dialog));
735 if (result == GTK_RESPONSE_OK) {
736 sort_key = hildon_sort_dialog_get_sort_key (dialog);
737 sort_type = hildon_sort_dialog_get_sort_order (dialog);
738 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
739 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
740 GINT_TO_POINTER (sort_ids[sort_key]));
741 /* This is a hack to make it resort rows always when flag fields are
742 * selected. If we do not do this, changing sort field from priority to
743 * attachments does not work */
744 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
746 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
747 sort_model_ids[sort_key]);
750 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
751 gtk_tree_sortable_sort_column_changed (sortable);
754 modest_widget_memory_save (modest_runtime_get_conf (),
755 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
757 /* while (gtk_events_pending ()) */
758 /* gtk_main_iteration (); */
767 on_response (GtkDialog *dialog,
771 GList *child_vbox, *child_hbox;
772 GtkWidget *hbox, *entry;
773 TnyFolderStore *parent;
775 if (response != GTK_RESPONSE_ACCEPT)
779 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
780 hbox = child_vbox->data;
781 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
782 entry = child_hbox->next->data;
784 parent = TNY_FOLDER_STORE (user_data);
786 /* Look for another folder with the same name */
787 if (modest_tny_folder_has_subfolder_with_name (parent,
788 gtk_entry_get_text (GTK_ENTRY (entry)))) {
790 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
791 NULL, _CS("ckdg_ib_folder_already_exists"));
792 /* Select the text */
793 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
794 gtk_widget_grab_focus (entry);
795 /* Do not close the dialog */
796 g_signal_stop_emission_by_name (dialog, "response");
802 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
803 TnyFolderStore *parent,
804 const gchar *dialog_title,
805 const gchar *label_text,
806 const gchar *suggested_name,
809 GtkWidget *accept_btn = NULL;
810 GtkWidget *dialog, *entry, *label, *hbox;
811 GList *buttons = NULL;
814 /* Ask the user for the folder name */
815 dialog = gtk_dialog_new_with_buttons (dialog_title,
817 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
818 _("mcen_bd_dialog_ok"),
820 _("mcen_bd_dialog_cancel"),
824 /* Add accept button (with unsensitive handler) */
825 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
826 accept_btn = GTK_WIDGET (buttons->next->data);
827 /* Create label and entry */
828 label = gtk_label_new (label_text);
829 /* TODO: check that the suggested name does not exist */
830 /* We set 21 as maximum because we want to show WID-INF036
831 when the user inputs more that 20 */
832 entry = gtk_entry_new_with_max_length (21);
834 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
836 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
837 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
839 /* Connect to the response method to avoid closing the dialog
840 when an invalid name is selected*/
841 g_signal_connect (dialog,
843 G_CALLBACK (on_response),
846 /* Track entry changes */
847 g_signal_connect (entry,
849 G_CALLBACK (entry_insert_text),
851 g_signal_connect (entry,
853 G_CALLBACK (entry_changed),
856 /* Create the hbox */
857 hbox = gtk_hbox_new (FALSE, 12);
858 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
859 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
861 /* Add hbox to dialog */
862 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
863 hbox, FALSE, FALSE, 0);
865 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
867 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
871 result = gtk_dialog_run (GTK_DIALOG(dialog));
872 if (result == GTK_RESPONSE_ACCEPT)
873 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
875 gtk_widget_destroy (dialog);
877 while (gtk_events_pending ())
878 gtk_main_iteration ();
884 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
885 TnyFolderStore *parent_folder,
886 gchar *suggested_name,
889 gchar *real_suggested_name = NULL;
892 if(suggested_name == NULL)
894 const gchar *default_name = _("mcen_ia_default_folder_name");
898 for(i = 0; i < 100; ++ i) {
899 gboolean exists = FALSE;
901 sprintf(num_str, "%.2u", i);
904 real_suggested_name = g_strdup (default_name);
906 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
909 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
910 real_suggested_name);
915 g_free (real_suggested_name);
918 /* Didn't find a free number */
920 real_suggested_name = g_strdup (default_name);
922 real_suggested_name = suggested_name;
925 result = modest_platform_run_folder_name_dialog (parent_window,
927 _("mcen_ti_new_folder"),
928 _("mcen_fi_new_folder_name"),
931 if (suggested_name == NULL)
932 g_free(real_suggested_name);
938 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
939 TnyFolderStore *parent_folder,
940 const gchar *suggested_name,
943 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
945 return modest_platform_run_folder_name_dialog (parent_window,
947 _HL("ckdg_ti_rename_folder"),
948 _HL("ckdg_fi_rename_name"),
954 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
955 const gchar *message)
960 dialog = hildon_note_new_confirmation (parent_window, message);
961 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
963 response = gtk_dialog_run (GTK_DIALOG (dialog));
965 gtk_widget_destroy (GTK_WIDGET (dialog));
967 while (gtk_events_pending ())
968 gtk_main_iteration ();
974 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
975 const gchar *message)
980 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
981 _("mcen_bd_yes"), GTK_RESPONSE_YES,
982 _("mcen_bd_no"), GTK_RESPONSE_NO,
984 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
986 response = gtk_dialog_run (GTK_DIALOG (dialog));
988 gtk_widget_destroy (GTK_WIDGET (dialog));
990 while (gtk_events_pending ())
991 gtk_main_iteration ();
997 modest_platform_run_information_dialog (GtkWindow *parent_window,
998 const gchar *message)
1002 dialog = hildon_note_new_information (parent_window, message);
1004 g_signal_connect_swapped (dialog,
1006 G_CALLBACK (gtk_widget_destroy),
1009 gtk_widget_show_all (dialog);
1020 on_idle_connect_and_wait(gpointer user_data)
1022 printf ("DEBUG: %s:\n", __FUNCTION__);
1023 TnyDevice *device = modest_runtime_get_device();
1024 if (!tny_device_is_online (device)) {
1026 /* This is a GDK lock because we are an idle callback and
1027 * tny_maemo_conic_device_connect can contain Gtk+ code */
1029 gdk_threads_enter(); /* CHECKED */
1030 tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
1031 gdk_threads_leave(); /* CHECKED */
1034 /* Allow the function that requested this idle callback to continue: */
1035 UtilIdleData *data = (UtilIdleData*)user_data;
1037 g_main_loop_quit (data->loop);
1039 return FALSE; /* Don't call this again. */
1042 static gboolean connect_request_in_progress = FALSE;
1044 /* This callback is used when connect_and_wait() is already queued as an idle callback.
1045 * This can happen because the gtk_dialog_run() for the connection dialog
1046 * (at least in the fake scratchbox version) allows idle handlers to keep running.
1049 on_idle_wait_for_previous_connect_to_finish(gpointer user_data)
1051 gboolean result = FALSE;
1052 TnyDevice *device = modest_runtime_get_device();
1053 if (tny_device_is_online (device))
1054 result = FALSE; /* Stop trying. */
1056 /* Keep trying until connect_request_in_progress is FALSE. */
1057 if (connect_request_in_progress)
1058 result = TRUE; /* Keep trying */
1060 printf ("DEBUG: %s: other idle has finished.\n", __FUNCTION__);
1062 result = FALSE; /* Stop trying, now that a result should be available. */
1066 if (result == FALSE) {
1067 /* Allow the function that requested this idle callback to continue: */
1068 UtilIdleData *data = (UtilIdleData*)user_data;
1070 g_main_loop_quit (data->loop);
1077 set_account_to_online (TnyAccount *account)
1079 /* TODO: This is necessary to prevent a cancel of the password dialog
1080 * from making a restart necessary to be asked the password again,
1081 * but it causes a hang:
1084 if (account && TNY_IS_CAMEL_STORE_ACCOUNT (account)) {
1085 /* Make sure that store accounts are online too,
1086 * because tinymail sets accounts to offline if
1087 * a password dialog is ever cancelled.
1088 * We don't do this for transport accounts because
1089 * a) They fundamentally need network access, so they can't really be offline.
1090 * b) That might cause a transport connection to happen too early.
1092 GError *error = NULL;
1093 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, &error);
1095 g_warning ("%s: tny_camel_account_set_online() returned a GError:\n %s\n",
1096 __FUNCTION__, error->message);
1097 g_error_free (error);
1103 gboolean modest_platform_connect_and_wait (GtkWindow *parent_window, TnyAccount *account)
1105 if (connect_request_in_progress)
1108 printf ("DEBUG: %s:\n", __FUNCTION__);
1109 TnyDevice *device = modest_runtime_get_device();
1111 if (tny_device_is_online (device)) {
1112 printf ("DEBUG: %s: Already online.\n", __FUNCTION__);
1113 set_account_to_online (account);
1117 printf ("DEBUG: %s: tny_device_is_online() returned FALSE\n", __FUNCTION__);
1120 /* This blocks on the result: */
1121 UtilIdleData *data = g_slice_new0 (UtilIdleData);
1123 GMainContext *context = NULL; /* g_main_context_new (); */
1124 data->loop = g_main_loop_new (context, FALSE /* not running */);
1126 /* Cause the function to be run in an idle-handler, which is always
1127 * in the main thread:
1129 if (!connect_request_in_progress) {
1130 printf ("DEBUG: %s: First request\n", __FUNCTION__);
1131 connect_request_in_progress = TRUE;
1132 g_idle_add (&on_idle_connect_and_wait, data);
1135 printf ("DEBUG: %s: nth request\n", __FUNCTION__);
1136 g_idle_add_full (G_PRIORITY_LOW, &on_idle_wait_for_previous_connect_to_finish, data, NULL);
1139 /* This main loop will run until the idle handler has stopped it: */
1140 printf ("DEBUG: %s: before g_main_loop_run()\n", __FUNCTION__);
1141 GDK_THREADS_LEAVE();
1142 g_main_loop_run (data->loop);
1143 GDK_THREADS_ENTER();
1144 printf ("DEBUG: %s: after g_main_loop_run()\n", __FUNCTION__);
1145 connect_request_in_progress = FALSE;
1146 printf ("DEBUG: %s: Finished\n", __FUNCTION__);
1147 g_main_loop_unref (data->loop);
1148 /* g_main_context_unref (context); */
1150 g_slice_free (UtilIdleData, data);
1152 const gboolean result = tny_device_is_online (device);
1155 set_account_to_online (account);
1161 gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1163 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1164 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1165 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1166 /* This must be a maildir account, which does not require a connection: */
1171 return modest_platform_connect_and_wait (parent_window, account);
1174 gboolean modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1177 return TRUE; /* Maybe it is something local. */
1179 gboolean result = TRUE;
1180 if (TNY_IS_FOLDER (folder_store)) {
1181 /* Get the folder's parent account: */
1182 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1183 if (account != NULL) {
1184 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1185 g_object_unref (account);
1187 } else if (TNY_IS_ACCOUNT (folder_store)) {
1188 /* Use the folder store as an account: */
1189 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1195 gboolean modest_platform_is_network_folderstore (TnyFolderStore *folder_store)
1197 TnyAccount *account = NULL;
1198 gboolean result = TRUE;
1200 g_return_val_if_fail(TNY_IS_FOLDER_STORE(folder_store), FALSE);
1202 if (TNY_IS_FOLDER (folder_store)) {
1203 /* Get the folder's parent account: */
1204 account = tny_folder_get_account(TNY_FOLDER(folder_store));
1205 } else if (TNY_IS_ACCOUNT (folder_store)) {
1206 account = TNY_ACCOUNT(folder_store);
1207 g_object_ref(account);
1210 if (account != NULL) {
1211 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1212 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1213 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1214 /* This must be a maildir account, which does
1215 * not require a connection: */
1219 g_object_unref (account);
1228 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1229 ModestSortDialogType type)
1231 GtkWidget *dialog = NULL;
1234 dialog = hildon_sort_dialog_new (parent_window);
1235 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
1237 /* Fill sort keys */
1239 case MODEST_SORT_HEADERS:
1240 launch_sort_headers_dialog (parent_window,
1241 HILDON_SORT_DIALOG(dialog));
1246 gtk_widget_destroy (GTK_WIDGET (dialog));
1250 gboolean modest_platform_set_update_interval (guint minutes)
1252 ModestConf *conf = modest_runtime_get_conf ();
1256 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1258 /* Delete any existing alarm,
1259 * because we will replace it: */
1261 /* TODO: What does the alarm_event_del() return value mean? */
1262 alarm_event_del(alarm_cookie);
1264 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1267 /* 0 means no updates: */
1272 /* Register alarm: */
1274 /* Set the interval in alarm_event_t structure: */
1275 alarm_event_t *event = g_new0(alarm_event_t, 1);
1276 event->alarm_time = minutes * 60; /* seconds */
1278 /* Set recurrence every few minutes: */
1279 event->recurrence = minutes;
1280 event->recurrence_count = -1; /* Means infinite */
1282 /* Specify what should happen when the alarm happens:
1283 * It should call this D-Bus method: */
1285 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1286 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1287 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1288 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1290 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1291 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1292 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1293 * This is why we want to use the Alarm API instead of just g_timeout_add().
1294 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1296 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1298 alarm_cookie = alarm_event_add (event);
1301 alarm_event_free (event);
1303 /* Store the alarm ID in GConf, so we can remove it later:
1304 * This is apparently valid between application instances. */
1305 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1307 if (!alarm_cookie) {
1309 const alarm_error_t alarm_error = alarmd_get_error ();
1310 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1312 /* Give people some clue: */
1313 /* The alarm API should have a function for this: */
1314 if (alarm_error == ALARMD_ERROR_DBUS) {
1315 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1316 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1317 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1318 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1319 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1320 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1321 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1322 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1323 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1324 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1325 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1335 modest_platform_get_global_settings_dialog ()
1337 return modest_maemo_global_settings_dialog_new ();
1341 modest_platform_on_new_msg (void)
1343 #ifdef MODEST_HAVE_HILDON_NOTIFY
1344 HildonNotification *not;
1346 /* Create a new notification. TODO: per-mail data needed */
1347 not = hildon_notification_new ("TODO: (new email) Summary",
1348 "TODO: (new email) Description",
1349 "qgn_list_messagin_mail_unread",
1352 hildon_notification_add_dbus_action(not,
1355 MODEST_DBUS_SERVICE,
1358 MODEST_DBUS_METHOD_OPEN_DEFAULT_INBOX,
1361 /* Play sound SR-SND-18 */
1362 hildon_notification_set_sound (not, "/usr/share/sounds/ui-new_email.wav");
1363 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (not), "dialog-type", 4);
1365 /* Set the led pattern */
1366 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (not),
1368 "PatternCommunicationEmail");
1370 /* Notify. We need to do this in an idle because this function
1371 could be called from a thread */
1372 if (!notify_notification_show (NOTIFY_NOTIFICATION (not), NULL))
1373 g_error ("Failed to send notification");
1375 g_object_unref (not);
1376 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1381 modest_platform_show_help (GtkWindow *parent_window,
1382 const gchar *help_id)
1384 osso_return_t result;
1386 g_return_if_fail (help_id);
1387 g_return_if_fail (osso_context);
1390 #ifdef MODEST_HAVE_OSSO_HELP
1391 result = ossohelp_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1393 result = hildon_help_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1396 if (result != OSSO_OK) {
1398 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1399 hildon_banner_show_information (GTK_WIDGET (parent_window),
1407 modest_platform_show_search_messages (GtkWindow *parent_window)
1409 osso_return_t result = OSSO_ERROR;
1411 result = osso_rpc_run_with_defaults (osso_context, "osso_global_search", "search_email", NULL, DBUS_TYPE_INVALID);
1413 if (result != OSSO_OK) {
1414 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1419 modest_platform_show_addressbook (GtkWindow *parent_window)
1421 osso_return_t result = OSSO_ERROR;
1423 result = osso_rpc_run_with_defaults (osso_context, "osso_addressbook", "top_application", NULL, DBUS_TYPE_INVALID);
1425 if (result != OSSO_OK) {
1426 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1431 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1433 GtkWidget *widget = modest_folder_view_new (query);
1435 /* Show one account by default */
1436 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1437 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1440 /* Restore settings */
1441 modest_widget_memory_restore (modest_runtime_get_conf(),
1443 MODEST_CONF_FOLDER_VIEW_KEY);
1449 modest_platform_information_banner (GtkWidget *parent,
1450 const gchar *icon_name,
1453 hildon_banner_show_information (parent, icon_name, text);
1457 modest_platform_animation_banner (GtkWidget *parent,
1458 const gchar *animation_name,
1461 GtkWidget *inf_note = NULL;
1463 g_return_val_if_fail (text != NULL, NULL);
1465 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1473 TnyAccount *account;
1476 } CheckAccountIdleData;
1478 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1481 on_timeout_check_account_is_online(gpointer user_data)
1483 printf ("DEBUG: %s:\n", __FUNCTION__);
1484 CheckAccountIdleData *data = (CheckAccountIdleData*)user_data;
1487 g_warning ("%s: data is NULL.\n", __FUNCTION__);
1490 if (!(data->account)) {
1491 g_warning ("%s: data->account is NULL.\n", __FUNCTION__);
1494 if (data && data->account) {
1495 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__, tny_account_get_connection_status (data->account));
1498 gboolean stop_trying = FALSE;
1499 if (data && data->account &&
1500 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1501 * after which the account is likely to be usable, or never likely to be usable soon: */
1502 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1504 data->is_online = TRUE;
1509 /* Give up if we have tried too many times: */
1510 if (data->count_tries >= NUMBER_OF_TRIES)
1515 /* Wait for another timeout: */
1516 ++(data->count_tries);
1521 /* Allow the function that requested this idle callback to continue: */
1523 g_main_loop_quit (data->loop);
1526 g_object_unref (data->account);
1528 return FALSE; /* Don't call this again. */
1530 return TRUE; /* Call this timeout callback again. */
1534 /* Return TRUE immediately if the account is already online,
1535 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1536 * soon as the account is online, or FALSE if the account does
1537 * not become online in the NUMBER_OF_TRIES seconds.
1538 * This is useful when the D-Bus method was run immediately after
1539 * the application was started (when using D-Bus activation),
1540 * because the account usually takes a short time to go online.
1541 * The return value is maybe not very useful.
1544 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1546 g_return_val_if_fail (account, FALSE);
1548 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1550 if (!tny_device_is_online (modest_runtime_get_device())) {
1551 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1555 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1556 * so we avoid wait unnecessarily: */
1557 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1558 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1562 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__, tny_account_get_connection_status (account));
1564 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1565 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1566 * we want to avoid. */
1567 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1570 /* This blocks on the result: */
1571 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1572 data->is_online = FALSE;
1573 data->account = account;
1574 g_object_ref (data->account);
1575 data->count_tries = 0;
1577 GMainContext *context = NULL; /* g_main_context_new (); */
1578 data->loop = g_main_loop_new (context, FALSE /* not running */);
1580 g_timeout_add (1000, &on_timeout_check_account_is_online, data);
1582 /* This main loop will run until the idle handler has stopped it: */
1583 g_main_loop_run (data->loop);
1585 g_main_loop_unref (data->loop);
1586 /* g_main_context_unref (context); */
1588 g_slice_free (CheckAccountIdleData, data);
1590 return data->is_online;