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"
54 #include <libgnomevfs/gnome-vfs-mime-utils.h>
56 #ifdef MODEST_HAVE_ABOOK
57 #include <libosso-abook/osso-abook.h>
58 #endif /*MODEST_HAVE_ABOOK*/
60 #ifdef MODEST_HAVE_LIBALARM
61 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
62 #endif /*MODEST_HAVE_LIBALARM*/
65 #define HILDON_OSSO_URI_ACTION "uri-action"
66 #define URI_ACTION_COPY "copy:"
69 on_modest_conf_update_interval_changed (ModestConf* self,
71 ModestConfEvent event,
72 ModestConfNotificationId id,
75 g_return_if_fail (key);
77 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
78 const guint update_interval_minutes =
79 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
80 modest_platform_set_update_interval (update_interval_minutes);
87 check_required_files (void)
89 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
91 g_printerr ("modest: check for mcc file failed\n");
96 if (access (MODEST_PROVIDERS_DATA_PATH, R_OK) != 0) {
97 g_printerr ("modest: cannot find providers data\n");
105 /* the gpointer here is the osso_context. */
107 modest_platform_init (int argc, char *argv[])
109 osso_context_t *osso_context;
111 osso_hw_state_t hw_state = { 0 };
115 if (!check_required_files ()) {
116 g_printerr ("modest: missing required files\n");
120 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
123 g_printerr ("modest: failed to acquire osso context\n");
126 modest_maemo_utils_set_osso_context (osso_context);
128 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
129 g_printerr ("modest: could not get dbus connection\n");
133 /* Add a D-Bus handler to be used when the main osso-rpc
134 * D-Bus handler has not handled something.
135 * We use this for D-Bus methods that need to use more complex types
136 * than osso-rpc supports.
138 if (!dbus_connection_add_filter (con,
139 modest_dbus_req_filter,
143 g_printerr ("modest: Could not add D-Bus filter\n");
147 /* Register our simple D-Bus callbacks, via the osso API: */
148 osso_return_t result = osso_rpc_set_cb_f(osso_context,
152 modest_dbus_req_handler, NULL /* user_data */);
153 if (result != OSSO_OK) {
154 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
158 /* Register hardware event dbus callback: */
159 hw_state.shutdown_ind = TRUE;
160 osso_hw_set_event_cb(osso_context, NULL,/*&hw_state*/ modest_osso_cb_hw_state_handler, NULL);
162 /* Register osso auto-save callbacks: */
163 result = osso_application_set_autosave_cb (osso_context,
164 modest_on_osso_application_autosave, NULL /* user_data */);
165 if (result != OSSO_OK) {
166 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
171 /* Make sure that the update interval is changed whenever its gconf key
173 /* CAUTION: we're not using here the
174 modest_conf_listen_to_namespace because we know that there
175 are other parts of Modest listening for this namespace, so
176 we'll receive the notifications anyway. We basically do not
177 use it because there is no easy way to do the
178 modest_conf_forget_namespace */
179 ModestConf *conf = modest_runtime_get_conf ();
180 g_signal_connect (G_OBJECT(conf),
182 G_CALLBACK (on_modest_conf_update_interval_changed),
185 /* only force the setting of the default interval, if there are actually
187 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
189 /* Get the initial update interval from gconf: */
190 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
191 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
192 modest_account_mgr_free_account_names (acc_names);
196 #ifdef MODEST_HAVE_ABOOK
197 /* initialize the addressbook */
198 if (!osso_abook_init (&argc, &argv, osso_context)) {
199 g_printerr ("modest: failed to initialized addressbook\n");
202 #endif /*MODEST_HAVE_ABOOK*/
208 modest_platform_uninit (void)
210 osso_context_t *osso_context =
211 modest_maemo_utils_get_osso_context ();
213 osso_deinitialize (osso_context);
222 modest_platform_get_new_device (void)
224 return TNY_DEVICE (tny_maemo_conic_device_new ());
228 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
229 gchar **effective_mime_type)
231 GString *mime_str = NULL;
232 gchar *icon_name = NULL;
233 gchar **icons, **cursor;
235 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
236 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
238 mime_str = g_string_new (mime_type);
239 g_string_ascii_down (mime_str);
242 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
243 for (cursor = icons; cursor; ++cursor) {
244 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
245 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
246 icon_name = g_strdup ("qgn_list_messagin");
248 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
249 icon_name = g_strdup (*cursor);
255 if (effective_mime_type)
256 *effective_mime_type = g_string_free (mime_str, FALSE);
258 g_string_free (mime_str, TRUE);
265 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
270 g_return_val_if_fail (uri, FALSE);
272 result = hildon_uri_open (uri, action, &err);
274 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
275 uri, action, err && err->message ? err->message : "unknown error");
285 modest_platform_activate_uri (const gchar *uri)
287 HildonURIAction *action;
288 gboolean result = FALSE;
289 GSList *actions, *iter = NULL;
291 g_return_val_if_fail (uri, FALSE);
295 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
297 for (iter = actions; iter; iter = g_slist_next (iter)) {
298 action = (HildonURIAction*) iter->data;
299 if (action && strcmp (hildon_uri_action_get_service (action),
300 "com.nokia.modest") == 0) {
301 result = checked_hildon_uri_open (uri, action);
306 /* if we could not open it with email, try something else */
308 result = checked_hildon_uri_open (uri, NULL);
311 ModestWindow *parent =
312 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
313 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
314 _("mcen_ib_unsupported_link"));
321 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
325 gchar *uri_path = NULL;
327 uri_path = g_strconcat ("file://", path, NULL);
328 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
331 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
333 result = hildon_mime_open_file (con, uri_path);
335 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
343 } ModestPlatformPopupInfo;
346 delete_uri_popup (GtkWidget *menu,
350 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
352 g_free (popup_info->uri);
353 hildon_uri_free_actions (popup_info->actions);
359 activate_uri_popup_item (GtkMenuItem *menu_item,
363 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
364 const gchar* action_name;
366 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
368 g_printerr ("modest: no action name defined\n");
372 /* special handling for the copy menu item -- copy the uri to the clipboard */
373 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
374 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
375 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
376 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
378 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
379 action_name += strlen ("mailto:");
381 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
382 return; /* we're done */
385 /* now, the real uri-actions... */
386 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
387 HildonURIAction *action = (HildonURIAction *) node->data;
388 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
389 if (!checked_hildon_uri_open (popup_info->uri, action)) {
390 ModestWindow *parent =
391 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
392 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
393 _("mcen_ib_unsupported_link"));
401 modest_platform_show_uri_popup (const gchar *uri)
403 GSList *actions_list;
408 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
409 if (actions_list != NULL) {
411 GtkWidget *menu = gtk_menu_new ();
412 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
414 popup_info->actions = actions_list;
415 popup_info->uri = g_strdup (uri);
417 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
418 GtkWidget *menu_item;
419 const gchar *action_name;
420 const gchar *translation_domain;
421 HildonURIAction *action = (HildonURIAction *) node->data;
422 action_name = hildon_uri_action_get_name (action);
423 translation_domain = hildon_uri_action_get_translation_domain (action);
424 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
425 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
426 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
429 if (hildon_uri_is_default_action (action, NULL)) {
430 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
432 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
434 gtk_widget_show (menu_item);
437 /* always add the copy item */
438 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
439 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
440 g_strconcat (URI_ACTION_COPY, uri, NULL),
442 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
443 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
444 gtk_widget_show (menu_item);
447 /* and what to do when the link is deleted */
448 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
449 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
452 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
460 modest_platform_get_icon (const gchar *name)
463 GdkPixbuf* pixbuf = NULL;
464 GtkIconTheme *current_theme = NULL;
466 g_return_val_if_fail (name, NULL);
468 /* strlen == 0 is not really an error; it just
469 * means the icon is not available
471 if (!name || strlen(name) == 0)
474 #if 0 /* do we still need this? */
475 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
476 pixbuf = gdk_pixbuf_new_from_file (name, &err);
478 g_printerr ("modest: error loading icon '%s': %s\n",
486 current_theme = gtk_icon_theme_get_default ();
487 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
488 GTK_ICON_LOOKUP_NO_SVG,
491 g_printerr ("modest: error loading theme icon '%s': %s\n",
499 modest_platform_get_app_name (void)
501 return _("mcen_ap_name");
505 entry_insert_text (GtkEditable *editable,
514 chars = gtk_editable_get_chars (editable, 0, -1);
515 chars_length = g_utf8_strlen (chars, -1);
517 /* Show WID-INF036 */
518 if (chars_length >= 20) {
519 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
520 _CS("ckdg_ib_maximum_characters_reached"));
522 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
526 tmp = g_strndup (folder_name_forbidden_chars,
527 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
528 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
529 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
534 /* Write the text in the entry if it's valid */
535 g_signal_handlers_block_by_func (editable,
536 (gpointer) entry_insert_text, data);
537 gtk_editable_insert_text (editable, text, length, position);
538 g_signal_handlers_unblock_by_func (editable,
539 (gpointer) entry_insert_text, data);
542 /* Do not allow further processing */
543 g_signal_stop_emission_by_name (editable, "insert_text");
547 entry_changed (GtkEditable *editable,
551 GtkWidget *ok_button;
554 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
555 ok_button = GTK_WIDGET (buttons->next->data);
557 chars = gtk_editable_get_chars (editable, 0, -1);
558 g_return_if_fail (chars != NULL);
561 if (g_utf8_strlen (chars,-1) >= 21)
562 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
563 _CS("ckdg_ib_maximum_characters_reached"));
565 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
568 g_list_free (buttons);
573 launch_sort_headers_dialog (GtkWindow *parent_window,
574 HildonSortDialog *dialog)
576 ModestHeaderView *header_view = NULL;
578 GtkSortType sort_type;
580 gint default_key = 0;
582 gboolean outgoing = FALSE;
583 gint current_sort_colid = -1;
584 GtkSortType current_sort_type;
585 gint attachments_sort_id;
586 gint priority_sort_id;
587 GtkTreeSortable *sortable;
589 /* Get header window */
590 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
591 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
592 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
597 /* Add sorting keys */
598 cols = modest_header_view_get_columns (header_view);
601 #define SORT_ID_NUM 6
602 int sort_model_ids[SORT_ID_NUM];
603 int sort_ids[SORT_ID_NUM];
605 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
606 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
608 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
610 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
611 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
613 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
614 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
617 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
619 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
620 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
622 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
623 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
625 default_key = sort_key;
627 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
628 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
630 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
632 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
634 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
635 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
636 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
637 attachments_sort_id = sort_key;
639 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
640 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
641 sort_ids[sort_key] = 0;
643 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
644 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
645 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY_MASK;
646 priority_sort_id = sort_key;
648 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model
649 (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
651 if (!gtk_tree_sortable_get_sort_column_id (sortable,
652 ¤t_sort_colid, ¤t_sort_type)) {
653 hildon_sort_dialog_set_sort_key (dialog, default_key);
654 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
656 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
657 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
658 gpointer flags_sort_type_pointer;
659 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
660 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY_MASK)
661 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
663 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
665 gint current_sort_keyid = 0;
666 while (current_sort_keyid < 6) {
667 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
670 current_sort_keyid++;
672 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
676 result = gtk_dialog_run (GTK_DIALOG (dialog));
677 if (result == GTK_RESPONSE_OK) {
678 sort_key = hildon_sort_dialog_get_sort_key (dialog);
679 sort_type = hildon_sort_dialog_get_sort_order (dialog);
680 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
681 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
682 GINT_TO_POINTER (sort_ids[sort_key]));
683 /* This is a hack to make it resort rows always when flag fields are
684 * selected. If we do not do this, changing sort field from priority to
685 * attachments does not work */
686 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
688 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
689 sort_model_ids[sort_key]);
692 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
693 gtk_tree_sortable_sort_column_changed (sortable);
696 modest_widget_memory_save (modest_runtime_get_conf (),
697 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
699 /* while (gtk_events_pending ()) */
700 /* gtk_main_iteration (); */
709 on_response (GtkDialog *dialog,
713 GList *child_vbox, *child_hbox;
714 GtkWidget *hbox, *entry;
715 TnyFolderStore *parent;
717 if (response != GTK_RESPONSE_ACCEPT)
721 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
722 hbox = child_vbox->data;
723 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
724 entry = child_hbox->next->data;
726 parent = TNY_FOLDER_STORE (user_data);
728 /* Look for another folder with the same name */
729 if (modest_tny_folder_has_subfolder_with_name (parent,
730 gtk_entry_get_text (GTK_ENTRY (entry)),
734 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
735 NULL, _CS("ckdg_ib_folder_already_exists"));
736 /* Select the text */
737 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
738 gtk_widget_grab_focus (entry);
739 /* Do not close the dialog */
740 g_signal_stop_emission_by_name (dialog, "response");
747 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
748 TnyFolderStore *parent,
749 const gchar *dialog_title,
750 const gchar *label_text,
751 const gchar *suggested_name,
754 GtkWidget *accept_btn = NULL;
755 GtkWidget *dialog, *entry, *label, *hbox;
756 GList *buttons = NULL;
759 /* Ask the user for the folder name */
760 dialog = gtk_dialog_new_with_buttons (dialog_title,
762 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
763 _("mcen_bd_dialog_ok"),
765 _("mcen_bd_dialog_cancel"),
769 /* Add accept button (with unsensitive handler) */
770 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
771 accept_btn = GTK_WIDGET (buttons->next->data);
772 /* Create label and entry */
773 label = gtk_label_new (label_text);
774 /* TODO: check that the suggested name does not exist */
775 /* We set 21 as maximum because we want to show WID-INF036
776 when the user inputs more that 20 */
777 entry = gtk_entry_new_with_max_length (21);
779 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
781 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
782 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
784 /* Connect to the response method to avoid closing the dialog
785 when an invalid name is selected*/
786 g_signal_connect (dialog,
788 G_CALLBACK (on_response),
791 /* Track entry changes */
792 g_signal_connect (entry,
794 G_CALLBACK (entry_insert_text),
796 g_signal_connect (entry,
798 G_CALLBACK (entry_changed),
801 /* Create the hbox */
802 hbox = gtk_hbox_new (FALSE, 12);
803 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
804 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
806 /* Add hbox to dialog */
807 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
808 hbox, FALSE, FALSE, 0);
810 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
811 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
813 result = gtk_dialog_run (GTK_DIALOG(dialog));
814 if (result == GTK_RESPONSE_ACCEPT)
815 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
817 gtk_widget_destroy (dialog);
819 while (gtk_events_pending ())
820 gtk_main_iteration ();
826 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
827 TnyFolderStore *parent_folder,
828 gchar *suggested_name,
831 gchar *real_suggested_name = NULL;
834 if(suggested_name == NULL)
836 const gchar *default_name = _("mcen_ia_default_folder_name");
840 for(i = 0; i < 100; ++ i) {
841 gboolean exists = FALSE;
843 sprintf(num_str, "%.2u", i);
846 real_suggested_name = g_strdup (default_name);
848 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
850 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
857 g_free (real_suggested_name);
860 /* Didn't find a free number */
862 real_suggested_name = g_strdup (default_name);
864 real_suggested_name = suggested_name;
867 result = modest_platform_run_folder_name_dialog (parent_window,
869 _("mcen_ti_new_folder"),
870 _("mcen_fi_new_folder_name"),
873 if (suggested_name == NULL)
874 g_free(real_suggested_name);
880 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
881 TnyFolderStore *parent_folder,
882 const gchar *suggested_name,
885 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
887 return modest_platform_run_folder_name_dialog (parent_window,
889 _HL("ckdg_ti_rename_folder"),
890 _HL("ckdg_fi_rename_name"),
898 on_destroy_dialog (GtkDialog *dialog)
900 gtk_widget_destroy (GTK_WIDGET(dialog));
901 if (gtk_events_pending ())
902 gtk_main_iteration ();
906 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
907 const gchar *message)
912 dialog = hildon_note_new_confirmation (parent_window, message);
913 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
914 GTK_WINDOW (dialog));
916 response = gtk_dialog_run (GTK_DIALOG (dialog));
918 on_destroy_dialog (GTK_DIALOG(dialog));
920 while (gtk_events_pending ())
921 gtk_main_iteration ();
927 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
928 const gchar *message)
933 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
934 _("mcen_bd_yes"), GTK_RESPONSE_YES,
935 _("mcen_bd_no"), GTK_RESPONSE_NO,
937 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
938 response = gtk_dialog_run (GTK_DIALOG (dialog));
940 on_destroy_dialog (GTK_DIALOG(dialog));
942 while (gtk_events_pending ())
943 gtk_main_iteration ();
951 modest_platform_run_information_dialog (GtkWindow *parent_window,
952 const gchar *message)
956 note = hildon_note_new_information (parent_window, message);
957 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
960 g_signal_connect_swapped (note,
962 G_CALLBACK (on_destroy_dialog),
965 gtk_widget_show_all (note);
970 typedef struct _ConnectAndWaitData {
972 GMainLoop *wait_loop;
973 gboolean has_callback;
975 } ConnectAndWaitData;
979 quit_wait_loop (TnyAccount *account,
980 ConnectAndWaitData *data)
982 /* Set the has_callback to TRUE (means that the callback was
983 executed and wake up every code waiting for cond to be
985 g_mutex_lock (data->mutex);
986 data->has_callback = TRUE;
988 g_main_loop_quit (data->wait_loop);
989 g_mutex_unlock (data->mutex);
993 on_connection_status_changed (TnyAccount *account,
994 TnyConnectionStatus status,
997 TnyConnectionStatus conn_status;
998 ConnectAndWaitData *data;
1000 /* Ignore if reconnecting or disconnected */
1001 conn_status = tny_account_get_connection_status (account);
1002 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1003 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1006 /* Remove the handler */
1007 data = (ConnectAndWaitData *) user_data;
1008 g_signal_handler_disconnect (account, data->handler);
1010 /* Quit from wait loop */
1011 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1015 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1020 /* Quit from wait loop */
1021 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1025 modest_platform_connect_and_wait (GtkWindow *parent_window,
1026 TnyAccount *account)
1028 ConnectAndWaitData *data = NULL;
1029 gboolean device_online;
1031 TnyConnectionStatus conn_status;
1033 device = modest_runtime_get_device();
1034 device_online = tny_device_is_online (device);
1036 /* If there is no account check only the device status */
1041 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
1044 /* Return if the account is already connected */
1045 conn_status = tny_account_get_connection_status (account);
1046 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1049 /* Create the helper */
1050 data = g_slice_new0 (ConnectAndWaitData);
1051 data->mutex = g_mutex_new ();
1052 data->has_callback = FALSE;
1054 /* Connect the device */
1055 if (!device_online) {
1056 /* Track account connection status changes */
1057 data->handler = g_signal_connect (account, "connection-status-changed",
1058 G_CALLBACK (on_connection_status_changed),
1060 /* Try to connect the device */
1061 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
1063 /* If the device connection failed then exit */
1064 if (!device_online && data->handler)
1067 /* Force a reconnection of the account */
1068 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1069 on_tny_camel_account_set_online_cb, data);
1072 /* Wait until the callback is executed */
1073 g_mutex_lock (data->mutex);
1074 if (!data->has_callback) {
1075 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1076 gdk_threads_leave ();
1077 g_mutex_unlock (data->mutex);
1078 g_main_loop_run (data->wait_loop);
1079 g_mutex_lock (data->mutex);
1080 gdk_threads_enter ();
1082 g_mutex_unlock (data->mutex);
1086 if (g_signal_handler_is_connected (account, data->handler))
1087 g_signal_handler_disconnect (account, data->handler);
1088 g_mutex_free (data->mutex);
1089 g_main_loop_unref (data->wait_loop);
1090 g_slice_free (ConnectAndWaitData, data);
1093 conn_status = tny_account_get_connection_status (account);
1094 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1098 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1100 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1101 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1102 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1103 /* This must be a maildir account, which does not require a connection: */
1108 return modest_platform_connect_and_wait (parent_window, account);
1112 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1115 return TRUE; /* Maybe it is something local. */
1117 gboolean result = TRUE;
1118 if (TNY_IS_FOLDER (folder_store)) {
1119 /* Get the folder's parent account: */
1120 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1121 if (account != NULL) {
1122 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1123 g_object_unref (account);
1125 } else if (TNY_IS_ACCOUNT (folder_store)) {
1126 /* Use the folder store as an account: */
1127 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1134 modest_platform_is_network_folderstore (TnyFolderStore *folder_store)
1136 TnyAccount *account = NULL;
1137 gboolean result = TRUE;
1139 g_return_val_if_fail(TNY_IS_FOLDER_STORE(folder_store), FALSE);
1141 if (TNY_IS_FOLDER (folder_store)) {
1142 /* Get the folder's parent account: */
1143 account = tny_folder_get_account(TNY_FOLDER(folder_store));
1144 } else if (TNY_IS_ACCOUNT (folder_store)) {
1145 account = TNY_ACCOUNT(folder_store);
1146 g_object_ref(account);
1149 if (account != NULL) {
1150 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1151 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1152 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1153 /* This must be a maildir account, which does
1154 * not require a connection: */
1158 g_object_unref (account);
1167 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1168 ModestSortDialogType type)
1170 GtkWidget *dialog = NULL;
1173 dialog = hildon_sort_dialog_new (parent_window);
1174 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1175 GTK_WINDOW (dialog));
1177 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1178 "applications_email_sort",
1179 modest_maemo_utils_get_osso_context());
1181 /* Fill sort keys */
1183 case MODEST_SORT_HEADERS:
1184 launch_sort_headers_dialog (parent_window,
1185 HILDON_SORT_DIALOG(dialog));
1190 on_destroy_dialog (GTK_DIALOG(dialog));
1195 modest_platform_set_update_interval (guint minutes)
1197 #ifdef MODEST_HAVE_LIBALARM
1199 ModestConf *conf = modest_runtime_get_conf ();
1203 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1205 /* Delete any existing alarm,
1206 * because we will replace it: */
1208 if (alarm_event_del(alarm_cookie) != 1)
1209 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1211 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1214 /* 0 means no updates: */
1219 /* Register alarm: */
1221 /* Set the interval in alarm_event_t structure: */
1222 alarm_event_t *event = g_new0(alarm_event_t, 1);
1223 event->alarm_time = minutes * 60; /* seconds */
1225 /* Set recurrence every few minutes: */
1226 event->recurrence = minutes;
1227 event->recurrence_count = -1; /* Means infinite */
1229 /* Specify what should happen when the alarm happens:
1230 * It should call this D-Bus method: */
1232 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1233 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1234 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1235 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1237 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1238 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1239 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1240 * This is why we want to use the Alarm API instead of just g_timeout_add().
1241 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1243 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1245 alarm_cookie = alarm_event_add (event);
1248 alarm_event_free (event);
1250 /* Store the alarm ID in GConf, so we can remove it later:
1251 * This is apparently valid between application instances. */
1252 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1254 if (!alarm_cookie) {
1256 const alarm_error_t alarm_error = alarmd_get_error ();
1257 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1259 /* Give people some clue: */
1260 /* The alarm API should have a function for this: */
1261 if (alarm_error == ALARMD_ERROR_DBUS) {
1262 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1263 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1264 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1265 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1266 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1267 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1268 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1269 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1270 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1271 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1272 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1277 #endif /* MODEST_HAVE_LIBALARM */
1282 modest_platform_on_new_headers_received (TnyList *header_list)
1284 #ifdef MODEST_HAVE_HILDON_NOTIFY
1285 HildonNotification *notification;
1287 GSList *notifications_list = NULL;
1289 /* Get previous notifications ids */
1290 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1291 MODEST_CONF_NOTIFICATION_IDS,
1292 MODEST_CONF_VALUE_INT, NULL);
1294 iter = tny_list_create_iterator (header_list);
1295 while (!tny_iterator_is_done (iter)) {
1296 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1297 const gchar *display_date;
1298 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1299 TnyFolder *folder = tny_header_get_folder (header);
1300 gboolean first_notification = TRUE;
1303 /* constant string, don't free */
1304 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1306 display_address = g_strdup(tny_header_get_from (header));
1307 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1309 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1310 notification = hildon_notification_new (summary,
1311 tny_header_get_subject (header),
1312 "qgn_list_messagin",
1314 /* Create the message URL */
1315 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1316 tny_header_get_uid (header));
1318 hildon_notification_add_dbus_action(notification,
1321 MODEST_DBUS_SERVICE,
1324 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1328 /* Play sound if the user wants. Show the LED
1329 pattern. Show and play just one */
1330 if (G_UNLIKELY (first_notification)) {
1331 first_notification = FALSE;
1332 if (modest_conf_get_bool (modest_runtime_get_conf (),
1333 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1335 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1336 "sound-file", "/usr/share/sounds/ui-new_email.wav");
1339 /* Set the led pattern */
1340 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1342 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1344 "PatternCommunicationEmail");
1347 /* Notify. We need to do this in an idle because this function
1348 could be called from a thread */
1349 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1351 /* Save id in the list */
1352 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1353 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1354 /* We don't listen for the "closed" signal, because we
1355 don't care about if the notification was removed or
1356 not to store the list in gconf */
1358 /* Free & carry on */
1359 g_free (display_address);
1362 g_object_unref (folder);
1363 g_object_unref (header);
1364 tny_iterator_next (iter);
1366 g_object_unref (iter);
1369 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1370 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1372 g_slist_free (notifications_list);
1374 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1378 modest_platform_remove_new_mail_notifications (void)
1380 #ifdef MODEST_HAVE_HILDON_NOTIFY
1381 GSList *notif_list = NULL;
1383 /* Get previous notifications ids */
1384 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1385 MODEST_CONF_NOTIFICATION_IDS,
1386 MODEST_CONF_VALUE_INT, NULL);
1388 while (notif_list) {
1390 NotifyNotification *notif;
1392 /* Nasty HACK to remove the notifications, set the id
1393 of the existing ones and then close them */
1394 notif_id = GPOINTER_TO_INT(notif_list->data);
1395 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1396 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1398 /* Close the notification, note that some ids could be
1399 already invalid, but we don't care because it does
1401 notify_notification_close(notif, NULL);
1402 g_object_unref(notif);
1404 /* Delete the link, it's like going to the next */
1405 notif_list = g_slist_delete_link (notif_list, notif_list);
1409 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1410 notif_list, MODEST_CONF_VALUE_INT, NULL);
1412 g_slist_free (notif_list);
1414 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1420 modest_platform_get_global_settings_dialog ()
1422 return modest_maemo_global_settings_dialog_new ();
1426 modest_platform_show_help (GtkWindow *parent_window,
1427 const gchar *help_id)
1429 osso_return_t result;
1430 g_return_if_fail (help_id);
1432 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1433 help_id, HILDON_HELP_SHOW_DIALOG);
1435 if (result != OSSO_OK) {
1437 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1438 hildon_banner_show_information (GTK_WIDGET (parent_window),
1446 modest_platform_show_search_messages (GtkWindow *parent_window)
1448 osso_return_t result = OSSO_ERROR;
1450 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1451 "osso_global_search",
1452 "search_email", NULL, DBUS_TYPE_INVALID);
1454 if (result != OSSO_OK) {
1455 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1460 modest_platform_show_addressbook (GtkWindow *parent_window)
1462 osso_return_t result = OSSO_ERROR;
1464 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1466 "top_application", NULL, DBUS_TYPE_INVALID);
1468 if (result != OSSO_OK) {
1469 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1474 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1476 GtkWidget *widget = modest_folder_view_new (query);
1478 /* Show one account by default */
1479 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1480 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1483 /* Restore settings */
1484 modest_widget_memory_restore (modest_runtime_get_conf(),
1486 MODEST_CONF_FOLDER_VIEW_KEY);
1492 modest_platform_information_banner (GtkWidget *parent,
1493 const gchar *icon_name,
1496 hildon_banner_show_information (parent, icon_name, text);
1500 modest_platform_animation_banner (GtkWidget *parent,
1501 const gchar *animation_name,
1504 GtkWidget *inf_note = NULL;
1506 g_return_val_if_fail (text != NULL, NULL);
1508 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1516 TnyAccount *account;
1519 } CheckAccountIdleData;
1521 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1524 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1526 gboolean stop_trying = FALSE;
1527 g_return_val_if_fail (data && data->account, FALSE);
1529 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1530 tny_account_get_connection_status (data->account));
1532 if (data && data->account &&
1533 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1534 * after which the account is likely to be usable, or never likely to be usable soon: */
1535 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1537 data->is_online = TRUE;
1541 /* Give up if we have tried too many times: */
1542 if (data->count_tries >= NUMBER_OF_TRIES) {
1545 /* Wait for another timeout: */
1546 ++(data->count_tries);
1551 /* Allow the function that requested this idle callback to continue: */
1553 g_main_loop_quit (data->loop);
1556 g_object_unref (data->account);
1558 return FALSE; /* Don't call this again. */
1560 return TRUE; /* Call this timeout callback again. */
1564 /* Return TRUE immediately if the account is already online,
1565 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1566 * soon as the account is online, or FALSE if the account does
1567 * not become online in the NUMBER_OF_TRIES seconds.
1568 * This is useful when the D-Bus method was run immediately after
1569 * the application was started (when using D-Bus activation),
1570 * because the account usually takes a short time to go online.
1571 * The return value is maybe not very useful.
1574 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1576 g_return_val_if_fail (account, FALSE);
1578 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1580 if (!tny_device_is_online (modest_runtime_get_device())) {
1581 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1585 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1586 * so we avoid wait unnecessarily: */
1587 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1588 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1592 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1593 __FUNCTION__, tny_account_get_connection_status (account));
1595 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1596 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1597 * we want to avoid. */
1598 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1601 /* This blocks on the result: */
1602 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1603 data->is_online = FALSE;
1604 data->account = account;
1605 g_object_ref (data->account);
1606 data->count_tries = 0;
1608 GMainContext *context = NULL; /* g_main_context_new (); */
1609 data->loop = g_main_loop_new (context, FALSE /* not running */);
1611 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1613 /* This main loop will run until the idle handler has stopped it: */
1614 g_main_loop_run (data->loop);
1616 g_main_loop_unref (data->loop);
1617 /* g_main_context_unref (context); */
1619 g_slice_free (CheckAccountIdleData, data);
1621 return data->is_online;
1627 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1629 /* GTK_RESPONSE_HELP means we need to show the certificate */
1630 if (response_id == GTK_RESPONSE_HELP) {
1634 /* Do not close the dialog */
1635 g_signal_stop_emission_by_name (dialog, "response");
1637 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1638 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1639 gtk_dialog_run (GTK_DIALOG(note));
1640 gtk_widget_destroy (note);
1646 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1647 const gchar *certificate)
1651 ModestWindow *main_win;
1653 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1654 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1659 /* don't create it */
1660 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1661 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1664 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1667 note = hildon_note_new_confirmation_add_buttons (
1668 GTK_WINDOW(main_win),
1670 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1671 _("mcen_bd_view"), GTK_RESPONSE_HELP, /* abusing this... */
1672 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1675 g_signal_connect (G_OBJECT(note), "response",
1676 G_CALLBACK(on_cert_dialog_response),
1677 (gpointer) certificate);
1679 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1681 response = gtk_dialog_run(GTK_DIALOG(note));
1683 on_destroy_dialog (GTK_DIALOG(note));
1686 return response == GTK_RESPONSE_OK;
1690 modest_platform_run_alert_dialog (const gchar* prompt,
1691 gboolean is_question)
1693 ModestWindow *main_win;
1695 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1696 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1697 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1698 return is_question ? FALSE : TRUE;
1701 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1702 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1704 gboolean retval = TRUE;
1706 /* The Tinymail documentation says that we should show Yes and No buttons,
1707 * when it is a question.
1708 * Obviously, we need tinymail to use more specific error codes instead,
1709 * so we know what buttons to show. */
1710 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1712 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1713 GTK_WINDOW (dialog));
1715 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1716 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1718 on_destroy_dialog (GTK_DIALOG(dialog));
1720 /* Just show the error text and use the default response: */
1721 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1729 GtkWindow *parent_window;
1730 ModestConnectedPerformer callback;
1731 TnyAccount *account;
1738 on_went_online_info_free (OnWentOnlineInfo *info)
1740 /* And if we cleanup, we DO cleanup :-) */
1743 g_object_unref (info->device);
1746 if (info->parent_window)
1747 g_object_unref (info->parent_window);
1749 g_object_unref (info->account);
1751 g_slice_free (OnWentOnlineInfo, info);
1753 /* We're done ... */
1759 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1761 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1763 /* Now it's really time to callback to the caller. If going online didn't succeed,
1764 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1765 * canceled will be set. Etcetera etcetera. */
1767 if (info->callback) {
1768 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1771 /* This is our last call, we must cleanup here if we didn't yet do that */
1772 on_went_online_info_free (info);
1779 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1781 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1782 info->iap = g_strdup (iap_id);
1784 if (canceled || err || !info->account) {
1786 /* If there's a problem or if there's no account (then that's it for us, we callback
1787 * the caller's callback now. He'll have to handle err or canceled, of course.
1788 * We are not really online, as the account is not really online here ... */
1790 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1791 * this info. We don't cleanup err, Tinymail does that! */
1793 if (info->callback) {
1795 /* info->account can be NULL here, this means that the user did not
1796 * provide a nice account instance. We'll assume that the user knows
1797 * what he's doing and is happy with just the device going online.
1799 * We can't do magic, we don't know what account the user wants to
1800 * see going online. So just the device goes online, end of story */
1802 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1805 } else if (info->account) {
1807 /* If there's no problem and if we have an account, we'll put the account
1808 * online too. When done, the callback of bringing the account online
1809 * will callback the caller's callback. This is the most normal case. */
1811 info->device = TNY_DEVICE (g_object_ref (device));
1813 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1814 on_account_went_online, info);
1816 /* The on_account_went_online cb frees up the info, go look if you
1817 * don't believe me! (so we return here) */
1822 /* We cleanup if we are not bringing the account online too */
1823 on_went_online_info_free (info);
1829 modest_platform_connect_and_perform (GtkWindow *parent_window,
1830 TnyAccount *account, ModestConnectedPerformer callback, gpointer user_data)
1832 gboolean device_online;
1834 TnyConnectionStatus conn_status;
1835 OnWentOnlineInfo *info;
1837 device = modest_runtime_get_device();
1838 device_online = tny_device_is_online (device);
1840 /* If there is no account check only the device status */
1843 if (device_online) {
1845 /* We promise to instantly perform the callback, so ... */
1847 callback (FALSE, NULL, parent_window, account, user_data);
1852 info = g_slice_new0 (OnWentOnlineInfo);
1855 info->device = NULL;
1856 info->account = NULL;
1859 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1861 info->parent_window = NULL;
1862 info->user_data = user_data;
1863 info->callback = callback;
1865 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1866 on_conic_device_went_online, info);
1868 /* We'll cleanup in on_conic_device_went_online */
1871 /* The other code has no more reason to run. This is all that we can do for the
1872 * caller (he should have given us a nice and clean account instance!). We
1873 * can't do magic, we don't know what account he intends to bring online. So
1874 * we'll just bring the device online (and await his false bug report). */
1880 /* Return if the account is already connected */
1882 conn_status = tny_account_get_connection_status (account);
1883 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1885 /* We promise to instantly perform the callback, so ... */
1887 callback (FALSE, NULL, parent_window, account, user_data);
1893 /* Else, we are in a state that requires that we go online before we
1894 * call the caller's callback. */
1896 info = g_slice_new0 (OnWentOnlineInfo);
1898 info->device = NULL;
1900 info->account = TNY_ACCOUNT (g_object_ref (account));
1903 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1905 info->parent_window = NULL;
1907 /* So we'll put the callback away for later ... */
1909 info->user_data = user_data;
1910 info->callback = callback;
1912 if (!device_online) {
1914 /* If also the device is offline, then we connect both the device
1915 * and the account */
1917 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1918 on_conic_device_went_online, info);
1922 /* If the device is online, we'll just connect the account */
1924 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1925 on_account_went_online, info);
1928 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1929 * in both situations, go look if you don't believe me! */
1935 modest_platform_connect_and_perform_if_network_account (GtkWindow *parent_window,
1936 TnyAccount *account,
1937 ModestConnectedPerformer callback,
1940 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1941 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1942 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1944 /* This IS a local account like a maildir account, which does not require
1945 * a connection. (original comment had a vague assumption in its language
1946 * usage. There's no assuming needed, this IS what it IS: a local account), */
1948 /* We promise to instantly perform the callback, so ... */
1950 callback (FALSE, NULL, parent_window, account, user_data);
1957 modest_platform_connect_and_perform (parent_window, account, callback, user_data);
1963 modest_platform_connect_and_perform_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store,
1964 ModestConnectedPerformer callback, gpointer user_data)
1966 if (!folder_store) {
1968 /* We promise to instantly perform the callback, so ... */
1970 callback (FALSE, NULL, parent_window, NULL, user_data);
1974 /* Original comment: Maybe it is something local. */
1975 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
1979 if (TNY_IS_FOLDER (folder_store)) {
1980 /* Get the folder's parent account: */
1981 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1982 if (account != NULL) {
1983 modest_platform_connect_and_perform_if_network_account (NULL, account, callback, user_data);
1984 g_object_unref (account);
1986 } else if (TNY_IS_ACCOUNT (folder_store)) {
1987 /* Use the folder store as an account: */
1988 modest_platform_connect_and_perform_if_network_account (NULL, TNY_ACCOUNT (folder_store), callback, user_data);