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 <modest-maemo-utils.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <maemo/modest-osso-autosave-callbacks.h>
43 #include <tny-maemo-conic-device.h>
44 #include <tny-simple-list.h>
45 #include <tny-folder.h>
46 #include <tny-camel-imap-store-account.h>
47 #include <tny-camel-pop-store-account.h>
48 #include <gtk/gtkicontheme.h>
49 #include <gtk/gtkmenuitem.h>
50 #include <gtk/gtkmain.h>
51 #include <modest-text-utils.h>
52 #include "modest-tny-folder.h"
53 #include "modest-tny-account.h"
55 #include <libgnomevfs/gnome-vfs-mime-utils.h>
57 #ifdef MODEST_HAVE_ABOOK
58 #include <libosso-abook/osso-abook.h>
59 #endif /*MODEST_HAVE_ABOOK*/
61 #ifdef MODEST_HAVE_LIBALARM
62 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
63 #endif /*MODEST_HAVE_LIBALARM*/
66 #define HILDON_OSSO_URI_ACTION "uri-action"
67 #define URI_ACTION_COPY "copy:"
70 on_modest_conf_update_interval_changed (ModestConf* self,
72 ModestConfEvent event,
73 ModestConfNotificationId id,
76 g_return_if_fail (key);
78 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
79 const guint update_interval_minutes =
80 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
81 modest_platform_set_update_interval (update_interval_minutes);
88 check_required_files (void)
90 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
92 g_printerr ("modest: check for mcc file failed\n");
97 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
98 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
99 g_printerr ("modest: cannot find providers data\n");
107 /* the gpointer here is the osso_context. */
109 modest_platform_init (int argc, char *argv[])
111 osso_context_t *osso_context;
113 osso_hw_state_t hw_state = { 0 };
117 if (!check_required_files ()) {
118 g_printerr ("modest: missing required files\n");
122 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
125 g_printerr ("modest: failed to acquire osso context\n");
128 modest_maemo_utils_set_osso_context (osso_context);
130 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
131 g_printerr ("modest: could not get dbus connection\n");
135 /* Add a D-Bus handler to be used when the main osso-rpc
136 * D-Bus handler has not handled something.
137 * We use this for D-Bus methods that need to use more complex types
138 * than osso-rpc supports.
140 if (!dbus_connection_add_filter (con,
141 modest_dbus_req_filter,
145 g_printerr ("modest: Could not add D-Bus filter\n");
149 /* Register our simple D-Bus callbacks, via the osso API: */
150 osso_return_t result = osso_rpc_set_cb_f(osso_context,
154 modest_dbus_req_handler, NULL /* user_data */);
155 if (result != OSSO_OK) {
156 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
160 /* Register hardware event dbus callback: */
161 hw_state.shutdown_ind = TRUE;
162 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
164 /* Register osso auto-save callbacks: */
165 result = osso_application_set_autosave_cb (osso_context,
166 modest_on_osso_application_autosave, NULL /* user_data */);
167 if (result != OSSO_OK) {
168 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
173 /* Make sure that the update interval is changed whenever its gconf key
175 /* CAUTION: we're not using here the
176 modest_conf_listen_to_namespace because we know that there
177 are other parts of Modest listening for this namespace, so
178 we'll receive the notifications anyway. We basically do not
179 use it because there is no easy way to do the
180 modest_conf_forget_namespace */
181 ModestConf *conf = modest_runtime_get_conf ();
182 g_signal_connect (G_OBJECT(conf),
184 G_CALLBACK (on_modest_conf_update_interval_changed),
187 /* only force the setting of the default interval, if there are actually
189 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
191 /* Get the initial update interval from gconf: */
192 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
193 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
194 modest_account_mgr_free_account_names (acc_names);
198 #ifdef MODEST_HAVE_ABOOK
199 /* initialize the addressbook */
200 if (!osso_abook_init (&argc, &argv, osso_context)) {
201 g_printerr ("modest: failed to initialized addressbook\n");
204 #endif /*MODEST_HAVE_ABOOK*/
210 modest_platform_uninit (void)
212 osso_context_t *osso_context =
213 modest_maemo_utils_get_osso_context ();
215 osso_deinitialize (osso_context);
224 modest_platform_get_new_device (void)
226 return TNY_DEVICE (tny_maemo_conic_device_new ());
230 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
231 gchar **effective_mime_type)
233 GString *mime_str = NULL;
234 gchar *icon_name = NULL;
235 gchar **icons, **cursor;
237 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
238 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
240 mime_str = g_string_new (mime_type);
241 g_string_ascii_down (mime_str);
244 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
245 for (cursor = icons; cursor; ++cursor) {
246 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
247 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
248 icon_name = g_strdup ("qgn_list_messagin");
250 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
251 icon_name = g_strdup (*cursor);
257 if (effective_mime_type)
258 *effective_mime_type = g_string_free (mime_str, FALSE);
260 g_string_free (mime_str, TRUE);
267 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
272 g_return_val_if_fail (uri, FALSE);
274 result = hildon_uri_open (uri, action, &err);
276 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
277 uri, action, err && err->message ? err->message : "unknown error");
287 modest_platform_activate_uri (const gchar *uri)
289 HildonURIAction *action;
290 gboolean result = FALSE;
291 GSList *actions, *iter = NULL;
293 g_return_val_if_fail (uri, FALSE);
297 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
299 for (iter = actions; iter; iter = g_slist_next (iter)) {
300 action = (HildonURIAction*) iter->data;
301 if (action && strcmp (hildon_uri_action_get_service (action),
302 "com.nokia.modest") == 0) {
303 result = checked_hildon_uri_open (uri, action);
308 /* if we could not open it with email, try something else */
310 result = checked_hildon_uri_open (uri, NULL);
313 ModestWindow *parent =
314 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
315 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
316 _("mcen_ib_unsupported_link"));
323 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
327 gchar *uri_path = NULL;
329 uri_path = g_strconcat ("file://", path, NULL);
330 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
333 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
335 result = hildon_mime_open_file (con, uri_path);
337 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
345 } ModestPlatformPopupInfo;
348 delete_uri_popup (GtkWidget *menu,
352 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
354 g_free (popup_info->uri);
355 hildon_uri_free_actions (popup_info->actions);
361 activate_uri_popup_item (GtkMenuItem *menu_item,
365 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
366 const gchar* action_name;
368 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
370 g_printerr ("modest: no action name defined\n");
374 /* special handling for the copy menu item -- copy the uri to the clipboard */
375 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
376 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
377 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
378 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
380 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
381 action_name += strlen ("mailto:");
383 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
384 return; /* we're done */
387 /* now, the real uri-actions... */
388 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
389 HildonURIAction *action = (HildonURIAction *) node->data;
390 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
391 if (!checked_hildon_uri_open (popup_info->uri, action)) {
392 ModestWindow *parent =
393 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
394 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
395 _("mcen_ib_unsupported_link"));
403 modest_platform_show_uri_popup (const gchar *uri)
405 GSList *actions_list;
410 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
411 if (actions_list != NULL) {
413 GtkWidget *menu = gtk_menu_new ();
414 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
416 popup_info->actions = actions_list;
417 popup_info->uri = g_strdup (uri);
419 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
420 GtkWidget *menu_item;
421 const gchar *action_name;
422 const gchar *translation_domain;
423 HildonURIAction *action = (HildonURIAction *) node->data;
424 action_name = hildon_uri_action_get_name (action);
425 translation_domain = hildon_uri_action_get_translation_domain (action);
426 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
427 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
428 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
431 if (hildon_uri_is_default_action (action, NULL)) {
432 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
434 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
436 gtk_widget_show (menu_item);
439 /* always add the copy item */
440 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
441 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
442 g_strconcat (URI_ACTION_COPY, uri, NULL),
444 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
445 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
446 gtk_widget_show (menu_item);
449 /* and what to do when the link is deleted */
450 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
451 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
454 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
462 modest_platform_get_icon (const gchar *name)
465 GdkPixbuf* pixbuf = NULL;
466 GtkIconTheme *current_theme = NULL;
468 g_return_val_if_fail (name, NULL);
470 /* strlen == 0 is not really an error; it just
471 * means the icon is not available
473 if (!name || strlen(name) == 0)
476 #if 0 /* do we still need this? */
477 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
478 pixbuf = gdk_pixbuf_new_from_file (name, &err);
480 g_printerr ("modest: error loading icon '%s': %s\n",
488 current_theme = gtk_icon_theme_get_default ();
489 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
490 GTK_ICON_LOOKUP_NO_SVG,
493 g_printerr ("modest: error loading theme icon '%s': %s\n",
501 modest_platform_get_app_name (void)
503 return _("mcen_ap_name");
507 entry_insert_text (GtkEditable *editable,
516 chars = gtk_editable_get_chars (editable, 0, -1);
517 chars_length = g_utf8_strlen (chars, -1);
519 /* Show WID-INF036 */
520 if (chars_length >= 20) {
521 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
522 _CS("ckdg_ib_maximum_characters_reached"));
524 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
528 tmp = g_strndup (folder_name_forbidden_chars,
529 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
530 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
531 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
536 /* Write the text in the entry if it's valid */
537 g_signal_handlers_block_by_func (editable,
538 (gpointer) entry_insert_text, data);
539 gtk_editable_insert_text (editable, text, length, position);
540 g_signal_handlers_unblock_by_func (editable,
541 (gpointer) entry_insert_text, data);
544 /* Do not allow further processing */
545 g_signal_stop_emission_by_name (editable, "insert_text");
549 entry_changed (GtkEditable *editable,
553 GtkWidget *ok_button;
556 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
557 ok_button = GTK_WIDGET (buttons->next->data);
559 chars = gtk_editable_get_chars (editable, 0, -1);
560 g_return_if_fail (chars != NULL);
563 if (g_utf8_strlen (chars,-1) >= 21)
564 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
565 _CS("ckdg_ib_maximum_characters_reached"));
567 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
570 g_list_free (buttons);
575 launch_sort_headers_dialog (GtkWindow *parent_window,
576 HildonSortDialog *dialog)
578 ModestHeaderView *header_view = NULL;
580 GtkSortType sort_type;
582 gint default_key = 0;
584 gboolean outgoing = FALSE;
585 gint current_sort_colid = -1;
586 GtkSortType current_sort_type;
587 gint attachments_sort_id;
588 gint priority_sort_id;
589 GtkTreeSortable *sortable;
591 /* Get header window */
592 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
593 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
594 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
599 /* Add sorting keys */
600 cols = modest_header_view_get_columns (header_view);
603 #define SORT_ID_NUM 6
604 int sort_model_ids[SORT_ID_NUM];
605 int sort_ids[SORT_ID_NUM];
607 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
608 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
610 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
612 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
613 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
615 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
616 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
619 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
621 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
622 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
624 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
625 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
627 default_key = sort_key;
629 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
630 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
632 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
634 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
636 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
637 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
638 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
639 attachments_sort_id = sort_key;
641 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
642 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
643 sort_ids[sort_key] = 0;
645 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
646 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
647 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY_MASK;
648 priority_sort_id = sort_key;
650 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model
651 (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
653 if (!gtk_tree_sortable_get_sort_column_id (sortable,
654 ¤t_sort_colid, ¤t_sort_type)) {
655 hildon_sort_dialog_set_sort_key (dialog, default_key);
656 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
658 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
659 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
660 gpointer flags_sort_type_pointer;
661 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
662 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY_MASK)
663 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
665 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
667 gint current_sort_keyid = 0;
668 while (current_sort_keyid < 6) {
669 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
672 current_sort_keyid++;
674 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
678 result = gtk_dialog_run (GTK_DIALOG (dialog));
679 if (result == GTK_RESPONSE_OK) {
680 sort_key = hildon_sort_dialog_get_sort_key (dialog);
681 sort_type = hildon_sort_dialog_get_sort_order (dialog);
682 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
683 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
684 GINT_TO_POINTER (sort_ids[sort_key]));
685 /* This is a hack to make it resort rows always when flag fields are
686 * selected. If we do not do this, changing sort field from priority to
687 * attachments does not work */
688 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
690 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
691 sort_model_ids[sort_key]);
694 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
695 gtk_tree_sortable_sort_column_changed (sortable);
698 modest_widget_memory_save (modest_runtime_get_conf (),
699 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
701 /* while (gtk_events_pending ()) */
702 /* gtk_main_iteration (); */
711 on_response (GtkDialog *dialog,
715 GList *child_vbox, *child_hbox;
716 GtkWidget *hbox, *entry;
717 TnyFolderStore *parent;
718 const gchar *new_name;
721 if (response != GTK_RESPONSE_ACCEPT)
725 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
726 hbox = child_vbox->data;
727 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
728 entry = child_hbox->next->data;
730 parent = TNY_FOLDER_STORE (user_data);
731 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
734 /* Look for another folder with the same name */
735 if (modest_tny_folder_has_subfolder_with_name (parent,
742 if (TNY_IS_ACCOUNT (parent) &&
743 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
744 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
753 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
754 NULL, _CS("ckdg_ib_folder_already_exists"));
755 /* Select the text */
756 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
757 gtk_widget_grab_focus (entry);
758 /* Do not close the dialog */
759 g_signal_stop_emission_by_name (dialog, "response");
766 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
767 TnyFolderStore *parent,
768 const gchar *dialog_title,
769 const gchar *label_text,
770 const gchar *suggested_name,
773 GtkWidget *accept_btn = NULL;
774 GtkWidget *dialog, *entry, *label, *hbox;
775 GList *buttons = NULL;
778 /* Ask the user for the folder name */
779 dialog = gtk_dialog_new_with_buttons (dialog_title,
781 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
782 _("mcen_bd_dialog_ok"),
784 _("mcen_bd_dialog_cancel"),
788 /* Add accept button (with unsensitive handler) */
789 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
790 accept_btn = GTK_WIDGET (buttons->next->data);
791 /* Create label and entry */
792 label = gtk_label_new (label_text);
793 /* TODO: check that the suggested name does not exist */
794 /* We set 21 as maximum because we want to show WID-INF036
795 when the user inputs more that 20 */
796 entry = gtk_entry_new_with_max_length (21);
798 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
800 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
801 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
803 /* Connect to the response method to avoid closing the dialog
804 when an invalid name is selected*/
805 g_signal_connect (dialog,
807 G_CALLBACK (on_response),
810 /* Track entry changes */
811 g_signal_connect (entry,
813 G_CALLBACK (entry_insert_text),
815 g_signal_connect (entry,
817 G_CALLBACK (entry_changed),
820 /* Create the hbox */
821 hbox = gtk_hbox_new (FALSE, 12);
822 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
823 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
825 /* Add hbox to dialog */
826 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
827 hbox, FALSE, FALSE, 0);
829 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
830 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
832 result = gtk_dialog_run (GTK_DIALOG(dialog));
833 if (result == GTK_RESPONSE_ACCEPT)
834 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
836 gtk_widget_destroy (dialog);
838 while (gtk_events_pending ())
839 gtk_main_iteration ();
845 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
846 TnyFolderStore *parent_folder,
847 gchar *suggested_name,
850 gchar *real_suggested_name = NULL;
853 if(suggested_name == NULL)
855 const gchar *default_name = _("mcen_ia_default_folder_name");
859 for(i = 0; i < 100; ++ i) {
860 gboolean exists = FALSE;
862 sprintf(num_str, "%.2u", i);
865 real_suggested_name = g_strdup (default_name);
867 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
869 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
876 g_free (real_suggested_name);
879 /* Didn't find a free number */
881 real_suggested_name = g_strdup (default_name);
883 real_suggested_name = suggested_name;
886 result = modest_platform_run_folder_name_dialog (parent_window,
888 _("mcen_ti_new_folder"),
889 _("mcen_fi_new_folder_name"),
892 if (suggested_name == NULL)
893 g_free(real_suggested_name);
899 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
900 TnyFolderStore *parent_folder,
901 const gchar *suggested_name,
904 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
906 return modest_platform_run_folder_name_dialog (parent_window,
908 _HL("ckdg_ti_rename_folder"),
909 _HL("ckdg_fi_rename_name"),
917 on_destroy_dialog (GtkDialog *dialog)
919 gtk_widget_destroy (GTK_WIDGET(dialog));
920 if (gtk_events_pending ())
921 gtk_main_iteration ();
925 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
926 const gchar *message)
931 dialog = hildon_note_new_confirmation (parent_window, message);
932 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
933 GTK_WINDOW (dialog));
935 response = gtk_dialog_run (GTK_DIALOG (dialog));
937 on_destroy_dialog (GTK_DIALOG(dialog));
939 while (gtk_events_pending ())
940 gtk_main_iteration ();
946 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
947 const gchar *message)
952 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
953 _("mcen_bd_yes"), GTK_RESPONSE_YES,
954 _("mcen_bd_no"), GTK_RESPONSE_NO,
956 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
957 response = gtk_dialog_run (GTK_DIALOG (dialog));
959 on_destroy_dialog (GTK_DIALOG(dialog));
961 while (gtk_events_pending ())
962 gtk_main_iteration ();
970 modest_platform_run_information_dialog (GtkWindow *parent_window,
971 const gchar *message)
975 note = hildon_note_new_information (parent_window, message);
976 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
979 g_signal_connect_swapped (note,
981 G_CALLBACK (on_destroy_dialog),
984 gtk_widget_show_all (note);
989 typedef struct _ConnectAndWaitData {
991 GMainLoop *wait_loop;
992 gboolean has_callback;
994 } ConnectAndWaitData;
998 quit_wait_loop (TnyAccount *account,
999 ConnectAndWaitData *data)
1001 /* Set the has_callback to TRUE (means that the callback was
1002 executed and wake up every code waiting for cond to be
1004 g_mutex_lock (data->mutex);
1005 data->has_callback = TRUE;
1006 if (data->wait_loop)
1007 g_main_loop_quit (data->wait_loop);
1008 g_mutex_unlock (data->mutex);
1012 on_connection_status_changed (TnyAccount *account,
1013 TnyConnectionStatus status,
1016 TnyConnectionStatus conn_status;
1017 ConnectAndWaitData *data;
1019 /* Ignore if reconnecting or disconnected */
1020 conn_status = tny_account_get_connection_status (account);
1021 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1022 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1025 /* Remove the handler */
1026 data = (ConnectAndWaitData *) user_data;
1027 g_signal_handler_disconnect (account, data->handler);
1029 /* Quit from wait loop */
1030 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1034 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1039 /* Quit from wait loop */
1040 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1044 modest_platform_connect_and_wait (GtkWindow *parent_window,
1045 TnyAccount *account)
1047 ConnectAndWaitData *data = NULL;
1048 gboolean device_online;
1050 TnyConnectionStatus conn_status;
1051 gboolean user_requested;
1053 device = modest_runtime_get_device();
1054 device_online = tny_device_is_online (device);
1056 /* Whether the connection is user requested or automatically
1057 requested, for example via D-Bus */
1058 user_requested = (parent_window) ? TRUE : FALSE;
1060 /* If there is no account check only the device status */
1065 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1066 NULL, user_requested);
1069 /* Return if the account is already connected */
1070 conn_status = tny_account_get_connection_status (account);
1071 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1074 /* Create the helper */
1075 data = g_slice_new0 (ConnectAndWaitData);
1076 data->mutex = g_mutex_new ();
1077 data->has_callback = FALSE;
1079 /* Connect the device */
1080 if (!device_online) {
1081 /* Track account connection status changes */
1082 data->handler = g_signal_connect (account, "connection-status-changed",
1083 G_CALLBACK (on_connection_status_changed),
1085 /* Try to connect the device */
1086 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1087 NULL, user_requested);
1089 /* If the device connection failed then exit */
1090 if (!device_online && data->handler)
1093 /* Force a reconnection of the account */
1094 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1095 on_tny_camel_account_set_online_cb, data);
1098 /* Wait until the callback is executed */
1099 g_mutex_lock (data->mutex);
1100 if (!data->has_callback) {
1101 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1102 gdk_threads_leave ();
1103 g_mutex_unlock (data->mutex);
1104 g_main_loop_run (data->wait_loop);
1105 g_mutex_lock (data->mutex);
1106 gdk_threads_enter ();
1108 g_mutex_unlock (data->mutex);
1112 if (g_signal_handler_is_connected (account, data->handler))
1113 g_signal_handler_disconnect (account, data->handler);
1114 g_mutex_free (data->mutex);
1115 g_main_loop_unref (data->wait_loop);
1116 g_slice_free (ConnectAndWaitData, data);
1119 conn_status = tny_account_get_connection_status (account);
1120 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1124 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1126 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1127 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1128 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1129 /* This must be a maildir account, which does not require a connection: */
1134 return modest_platform_connect_and_wait (parent_window, account);
1138 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1141 return TRUE; /* Maybe it is something local. */
1143 gboolean result = TRUE;
1144 if (TNY_IS_FOLDER (folder_store)) {
1145 /* Get the folder's parent account: */
1146 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1147 if (account != NULL) {
1148 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1149 g_object_unref (account);
1151 } else if (TNY_IS_ACCOUNT (folder_store)) {
1152 /* Use the folder store as an account: */
1153 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1160 modest_platform_is_network_folderstore (TnyFolderStore *folder_store)
1162 TnyAccount *account = NULL;
1163 gboolean result = TRUE;
1165 g_return_val_if_fail(TNY_IS_FOLDER_STORE(folder_store), FALSE);
1167 if (TNY_IS_FOLDER (folder_store)) {
1168 /* Get the folder's parent account: */
1169 account = tny_folder_get_account(TNY_FOLDER(folder_store));
1170 } else if (TNY_IS_ACCOUNT (folder_store)) {
1171 account = TNY_ACCOUNT(folder_store);
1172 g_object_ref(account);
1175 if (account != NULL) {
1176 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1177 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1178 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1179 /* This must be a maildir account, which does
1180 * not require a connection: */
1184 g_object_unref (account);
1193 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1194 ModestSortDialogType type)
1196 GtkWidget *dialog = NULL;
1199 dialog = hildon_sort_dialog_new (parent_window);
1200 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1201 GTK_WINDOW (dialog));
1203 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1204 "applications_email_sort",
1205 modest_maemo_utils_get_osso_context());
1207 /* Fill sort keys */
1209 case MODEST_SORT_HEADERS:
1210 launch_sort_headers_dialog (parent_window,
1211 HILDON_SORT_DIALOG(dialog));
1216 on_destroy_dialog (GTK_DIALOG(dialog));
1221 modest_platform_set_update_interval (guint minutes)
1223 #ifdef MODEST_HAVE_LIBALARM
1225 ModestConf *conf = modest_runtime_get_conf ();
1229 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1231 /* Delete any existing alarm,
1232 * because we will replace it: */
1234 if (alarm_event_del(alarm_cookie) != 1)
1235 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1237 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1240 /* 0 means no updates: */
1245 /* Register alarm: */
1247 /* Set the interval in alarm_event_t structure: */
1248 alarm_event_t *event = g_new0(alarm_event_t, 1);
1249 event->alarm_time = minutes * 60; /* seconds */
1251 /* Set recurrence every few minutes: */
1252 event->recurrence = minutes;
1253 event->recurrence_count = -1; /* Means infinite */
1255 /* Specify what should happen when the alarm happens:
1256 * It should call this D-Bus method: */
1258 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1259 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1260 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1261 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1263 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1264 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1265 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1266 * This is why we want to use the Alarm API instead of just g_timeout_add().
1267 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1269 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1271 alarm_cookie = alarm_event_add (event);
1274 alarm_event_free (event);
1276 /* Store the alarm ID in GConf, so we can remove it later:
1277 * This is apparently valid between application instances. */
1278 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1280 if (!alarm_cookie) {
1282 const alarm_error_t alarm_error = alarmd_get_error ();
1283 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1285 /* Give people some clue: */
1286 /* The alarm API should have a function for this: */
1287 if (alarm_error == ALARMD_ERROR_DBUS) {
1288 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1289 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1290 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1291 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1292 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1293 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1294 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1295 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1296 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1297 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1298 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1303 #endif /* MODEST_HAVE_LIBALARM */
1308 modest_platform_on_new_headers_received (TnyList *header_list)
1310 #ifdef MODEST_HAVE_HILDON_NOTIFY
1311 HildonNotification *notification;
1313 GSList *notifications_list = NULL;
1315 /* Get previous notifications ids */
1316 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1317 MODEST_CONF_NOTIFICATION_IDS,
1318 MODEST_CONF_VALUE_INT, NULL);
1320 iter = tny_list_create_iterator (header_list);
1321 while (!tny_iterator_is_done (iter)) {
1322 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1323 const gchar *display_date;
1324 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1325 TnyFolder *folder = tny_header_get_folder (header);
1326 gboolean first_notification = TRUE;
1329 /* constant string, don't free */
1330 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1332 display_address = g_strdup(tny_header_get_from (header));
1333 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1335 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1336 notification = hildon_notification_new (summary,
1337 tny_header_get_subject (header),
1338 "qgn_list_messagin",
1340 /* Create the message URL */
1341 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1342 tny_header_get_uid (header));
1344 hildon_notification_add_dbus_action(notification,
1347 MODEST_DBUS_SERVICE,
1350 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1354 /* Play sound if the user wants. Show the LED
1355 pattern. Show and play just one */
1356 if (G_UNLIKELY (first_notification)) {
1357 first_notification = FALSE;
1358 if (modest_conf_get_bool (modest_runtime_get_conf (),
1359 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1361 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1362 "sound-file", "/usr/share/sounds/ui-new_email.wav");
1365 /* Set the led pattern */
1366 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1368 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1370 "PatternCommunicationEmail");
1373 /* Notify. We need to do this in an idle because this function
1374 could be called from a thread */
1375 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1377 /* Save id in the list */
1378 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1379 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1380 /* We don't listen for the "closed" signal, because we
1381 don't care about if the notification was removed or
1382 not to store the list in gconf */
1384 /* Free & carry on */
1385 g_free (display_address);
1388 g_object_unref (folder);
1389 g_object_unref (header);
1390 tny_iterator_next (iter);
1392 g_object_unref (iter);
1395 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1396 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1398 g_slist_free (notifications_list);
1400 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1404 modest_platform_remove_new_mail_notifications (void)
1406 #ifdef MODEST_HAVE_HILDON_NOTIFY
1407 GSList *notif_list = NULL;
1409 /* Get previous notifications ids */
1410 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1411 MODEST_CONF_NOTIFICATION_IDS,
1412 MODEST_CONF_VALUE_INT, NULL);
1414 while (notif_list) {
1416 NotifyNotification *notif;
1418 /* Nasty HACK to remove the notifications, set the id
1419 of the existing ones and then close them */
1420 notif_id = GPOINTER_TO_INT(notif_list->data);
1421 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1422 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1424 /* Close the notification, note that some ids could be
1425 already invalid, but we don't care because it does
1427 notify_notification_close(notif, NULL);
1428 g_object_unref(notif);
1430 /* Delete the link, it's like going to the next */
1431 notif_list = g_slist_delete_link (notif_list, notif_list);
1435 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1436 notif_list, MODEST_CONF_VALUE_INT, NULL);
1438 g_slist_free (notif_list);
1440 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1446 modest_platform_get_global_settings_dialog ()
1448 return modest_maemo_global_settings_dialog_new ();
1452 modest_platform_show_help (GtkWindow *parent_window,
1453 const gchar *help_id)
1455 osso_return_t result;
1456 g_return_if_fail (help_id);
1458 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1459 help_id, HILDON_HELP_SHOW_DIALOG);
1461 if (result != OSSO_OK) {
1463 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1464 hildon_banner_show_information (GTK_WIDGET (parent_window),
1472 modest_platform_show_search_messages (GtkWindow *parent_window)
1474 osso_return_t result = OSSO_ERROR;
1476 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1477 "osso_global_search",
1478 "search_email", NULL, DBUS_TYPE_INVALID);
1480 if (result != OSSO_OK) {
1481 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1486 modest_platform_show_addressbook (GtkWindow *parent_window)
1488 osso_return_t result = OSSO_ERROR;
1490 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1492 "top_application", NULL, DBUS_TYPE_INVALID);
1494 if (result != OSSO_OK) {
1495 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1500 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1502 GtkWidget *widget = modest_folder_view_new (query);
1504 /* Show one account by default */
1505 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1506 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1509 /* Restore settings */
1510 modest_widget_memory_restore (modest_runtime_get_conf(),
1512 MODEST_CONF_FOLDER_VIEW_KEY);
1518 modest_platform_information_banner (GtkWidget *parent,
1519 const gchar *icon_name,
1522 hildon_banner_show_information (parent, icon_name, text);
1526 modest_platform_animation_banner (GtkWidget *parent,
1527 const gchar *animation_name,
1530 GtkWidget *inf_note = NULL;
1532 g_return_val_if_fail (text != NULL, NULL);
1534 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1542 TnyAccount *account;
1545 } CheckAccountIdleData;
1547 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1550 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1552 gboolean stop_trying = FALSE;
1553 g_return_val_if_fail (data && data->account, FALSE);
1555 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1556 tny_account_get_connection_status (data->account));
1558 if (data && data->account &&
1559 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1560 * after which the account is likely to be usable, or never likely to be usable soon: */
1561 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1563 data->is_online = TRUE;
1567 /* Give up if we have tried too many times: */
1568 if (data->count_tries >= NUMBER_OF_TRIES) {
1571 /* Wait for another timeout: */
1572 ++(data->count_tries);
1577 /* Allow the function that requested this idle callback to continue: */
1579 g_main_loop_quit (data->loop);
1582 g_object_unref (data->account);
1584 return FALSE; /* Don't call this again. */
1586 return TRUE; /* Call this timeout callback again. */
1590 /* Return TRUE immediately if the account is already online,
1591 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1592 * soon as the account is online, or FALSE if the account does
1593 * not become online in the NUMBER_OF_TRIES seconds.
1594 * This is useful when the D-Bus method was run immediately after
1595 * the application was started (when using D-Bus activation),
1596 * because the account usually takes a short time to go online.
1597 * The return value is maybe not very useful.
1600 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1602 g_return_val_if_fail (account, FALSE);
1604 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1606 if (!tny_device_is_online (modest_runtime_get_device())) {
1607 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1611 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1612 * so we avoid wait unnecessarily: */
1613 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1614 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1618 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1619 __FUNCTION__, tny_account_get_connection_status (account));
1621 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1622 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1623 * we want to avoid. */
1624 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1627 /* This blocks on the result: */
1628 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1629 data->is_online = FALSE;
1630 data->account = account;
1631 g_object_ref (data->account);
1632 data->count_tries = 0;
1634 GMainContext *context = NULL; /* g_main_context_new (); */
1635 data->loop = g_main_loop_new (context, FALSE /* not running */);
1637 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1639 /* This main loop will run until the idle handler has stopped it: */
1640 g_main_loop_run (data->loop);
1642 g_main_loop_unref (data->loop);
1643 /* g_main_context_unref (context); */
1645 g_slice_free (CheckAccountIdleData, data);
1647 return data->is_online;
1653 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1655 /* GTK_RESPONSE_HELP means we need to show the certificate */
1656 if (response_id == GTK_RESPONSE_HELP) {
1660 /* Do not close the dialog */
1661 g_signal_stop_emission_by_name (dialog, "response");
1663 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1664 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1665 gtk_dialog_run (GTK_DIALOG(note));
1666 gtk_widget_destroy (note);
1672 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1673 const gchar *certificate)
1677 ModestWindow *main_win;
1679 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1680 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1685 /* don't create it */
1686 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1687 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1690 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1693 note = hildon_note_new_confirmation_add_buttons (
1694 GTK_WINDOW(main_win),
1696 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1697 _("mcen_bd_view"), GTK_RESPONSE_HELP, /* abusing this... */
1698 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1701 g_signal_connect (G_OBJECT(note), "response",
1702 G_CALLBACK(on_cert_dialog_response),
1703 (gpointer) certificate);
1705 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1707 response = gtk_dialog_run(GTK_DIALOG(note));
1709 on_destroy_dialog (GTK_DIALOG(note));
1712 return response == GTK_RESPONSE_OK;
1716 modest_platform_run_alert_dialog (const gchar* prompt,
1717 gboolean is_question)
1719 ModestWindow *main_win;
1721 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1722 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1723 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1724 return is_question ? FALSE : TRUE;
1727 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1728 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1730 gboolean retval = TRUE;
1732 /* The Tinymail documentation says that we should show Yes and No buttons,
1733 * when it is a question.
1734 * Obviously, we need tinymail to use more specific error codes instead,
1735 * so we know what buttons to show. */
1736 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1738 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1739 GTK_WINDOW (dialog));
1741 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1742 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1744 on_destroy_dialog (GTK_DIALOG(dialog));
1746 /* Just show the error text and use the default response: */
1747 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1755 GtkWindow *parent_window;
1756 ModestConnectedPerformer callback;
1757 TnyAccount *account;
1764 on_went_online_info_free (OnWentOnlineInfo *info)
1766 /* And if we cleanup, we DO cleanup :-) */
1769 g_object_unref (info->device);
1772 if (info->parent_window)
1773 g_object_unref (info->parent_window);
1775 g_object_unref (info->account);
1777 g_slice_free (OnWentOnlineInfo, info);
1779 /* We're done ... */
1785 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1787 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1789 /* Now it's really time to callback to the caller. If going online didn't succeed,
1790 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1791 * canceled will be set. Etcetera etcetera. */
1793 if (info->callback) {
1794 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1797 /* This is our last call, we must cleanup here if we didn't yet do that */
1798 on_went_online_info_free (info);
1805 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1807 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1808 info->iap = g_strdup (iap_id);
1810 if (canceled || err || !info->account) {
1812 /* If there's a problem or if there's no account (then that's it for us, we callback
1813 * the caller's callback now. He'll have to handle err or canceled, of course.
1814 * We are not really online, as the account is not really online here ... */
1816 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1817 * this info. We don't cleanup err, Tinymail does that! */
1819 if (info->callback) {
1821 /* info->account can be NULL here, this means that the user did not
1822 * provide a nice account instance. We'll assume that the user knows
1823 * what he's doing and is happy with just the device going online.
1825 * We can't do magic, we don't know what account the user wants to
1826 * see going online. So just the device goes online, end of story */
1828 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1831 } else if (info->account) {
1833 /* If there's no problem and if we have an account, we'll put the account
1834 * online too. When done, the callback of bringing the account online
1835 * will callback the caller's callback. This is the most normal case. */
1837 info->device = TNY_DEVICE (g_object_ref (device));
1839 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1840 on_account_went_online, info);
1842 /* The on_account_went_online cb frees up the info, go look if you
1843 * don't believe me! (so we return here) */
1848 /* We cleanup if we are not bringing the account online too */
1849 on_went_online_info_free (info);
1855 modest_platform_connect_and_perform (GtkWindow *parent_window,
1856 TnyAccount *account,
1857 ModestConnectedPerformer callback,
1860 gboolean device_online;
1862 TnyConnectionStatus conn_status;
1863 OnWentOnlineInfo *info;
1864 gboolean user_requested;
1866 device = modest_runtime_get_device();
1867 device_online = tny_device_is_online (device);
1869 /* Whether the connection is user requested or automatically
1870 requested, for example via D-Bus */
1871 user_requested = (parent_window) ? TRUE : FALSE;
1873 /* If there is no account check only the device status */
1876 if (device_online) {
1878 /* We promise to instantly perform the callback, so ... */
1880 callback (FALSE, NULL, parent_window, account, user_data);
1885 info = g_slice_new0 (OnWentOnlineInfo);
1888 info->device = NULL;
1889 info->account = NULL;
1892 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1894 info->parent_window = NULL;
1895 info->user_data = user_data;
1896 info->callback = callback;
1898 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1899 user_requested, on_conic_device_went_online,
1902 /* We'll cleanup in on_conic_device_went_online */
1905 /* The other code has no more reason to run. This is all that we can do for the
1906 * caller (he should have given us a nice and clean account instance!). We
1907 * can't do magic, we don't know what account he intends to bring online. So
1908 * we'll just bring the device online (and await his false bug report). */
1914 /* Return if the account is already connected */
1916 conn_status = tny_account_get_connection_status (account);
1917 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1919 /* We promise to instantly perform the callback, so ... */
1921 callback (FALSE, NULL, parent_window, account, user_data);
1927 /* Else, we are in a state that requires that we go online before we
1928 * call the caller's callback. */
1930 info = g_slice_new0 (OnWentOnlineInfo);
1932 info->device = NULL;
1934 info->account = TNY_ACCOUNT (g_object_ref (account));
1937 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1939 info->parent_window = NULL;
1941 /* So we'll put the callback away for later ... */
1943 info->user_data = user_data;
1944 info->callback = callback;
1946 if (!device_online) {
1948 /* If also the device is offline, then we connect both the device
1949 * and the account */
1951 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1952 user_requested, on_conic_device_went_online,
1957 /* If the device is online, we'll just connect the account */
1959 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1960 on_account_went_online, info);
1963 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1964 * in both situations, go look if you don't believe me! */
1970 modest_platform_connect_and_perform_if_network_account (GtkWindow *parent_window,
1971 TnyAccount *account,
1972 ModestConnectedPerformer callback,
1975 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1976 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1977 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1979 /* This IS a local account like a maildir account, which does not require
1980 * a connection. (original comment had a vague assumption in its language
1981 * usage. There's no assuming needed, this IS what it IS: a local account), */
1983 /* We promise to instantly perform the callback, so ... */
1985 callback (FALSE, NULL, parent_window, account, user_data);
1992 modest_platform_connect_and_perform (parent_window, account, callback, user_data);
1998 modest_platform_connect_and_perform_if_network_folderstore (GtkWindow *parent_window,
1999 TnyFolderStore *folder_store,
2000 ModestConnectedPerformer callback,
2003 if (!folder_store) {
2005 /* We promise to instantly perform the callback, so ... */
2007 callback (FALSE, NULL, parent_window, NULL, user_data);
2011 /* Original comment: Maybe it is something local. */
2012 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
2016 if (TNY_IS_FOLDER (folder_store)) {
2017 /* Get the folder's parent account: */
2018 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
2019 if (account != NULL) {
2020 modest_platform_connect_and_perform_if_network_account (NULL, account, callback, user_data);
2021 g_object_unref (account);
2023 } else if (TNY_IS_ACCOUNT (folder_store)) {
2024 /* Use the folder store as an account: */
2025 modest_platform_connect_and_perform_if_network_account (NULL, TNY_ACCOUNT (folder_store), callback, user_data);