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_PROVIDER_DATA_FILE, R_OK) != 0 &&
97 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
98 g_printerr ("modest: cannot find providers data\n");
106 /* the gpointer here is the osso_context. */
108 modest_platform_init (int argc, char *argv[])
110 osso_context_t *osso_context;
112 osso_hw_state_t hw_state = { 0 };
116 if (!check_required_files ()) {
117 g_printerr ("modest: missing required files\n");
121 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
124 g_printerr ("modest: failed to acquire osso context\n");
127 modest_maemo_utils_set_osso_context (osso_context);
129 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
130 g_printerr ("modest: could not get dbus connection\n");
134 /* Add a D-Bus handler to be used when the main osso-rpc
135 * D-Bus handler has not handled something.
136 * We use this for D-Bus methods that need to use more complex types
137 * than osso-rpc supports.
139 if (!dbus_connection_add_filter (con,
140 modest_dbus_req_filter,
144 g_printerr ("modest: Could not add D-Bus filter\n");
148 /* Register our simple D-Bus callbacks, via the osso API: */
149 osso_return_t result = osso_rpc_set_cb_f(osso_context,
153 modest_dbus_req_handler, NULL /* user_data */);
154 if (result != OSSO_OK) {
155 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
159 /* Register hardware event dbus callback: */
160 hw_state.shutdown_ind = TRUE;
161 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
163 /* Register osso auto-save callbacks: */
164 result = osso_application_set_autosave_cb (osso_context,
165 modest_on_osso_application_autosave, NULL /* user_data */);
166 if (result != OSSO_OK) {
167 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
172 /* Make sure that the update interval is changed whenever its gconf key
174 /* CAUTION: we're not using here the
175 modest_conf_listen_to_namespace because we know that there
176 are other parts of Modest listening for this namespace, so
177 we'll receive the notifications anyway. We basically do not
178 use it because there is no easy way to do the
179 modest_conf_forget_namespace */
180 ModestConf *conf = modest_runtime_get_conf ();
181 g_signal_connect (G_OBJECT(conf),
183 G_CALLBACK (on_modest_conf_update_interval_changed),
186 /* only force the setting of the default interval, if there are actually
188 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
190 /* Get the initial update interval from gconf: */
191 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
192 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
193 modest_account_mgr_free_account_names (acc_names);
197 #ifdef MODEST_HAVE_ABOOK
198 /* initialize the addressbook */
199 if (!osso_abook_init (&argc, &argv, osso_context)) {
200 g_printerr ("modest: failed to initialized addressbook\n");
203 #endif /*MODEST_HAVE_ABOOK*/
209 modest_platform_uninit (void)
211 osso_context_t *osso_context =
212 modest_maemo_utils_get_osso_context ();
214 osso_deinitialize (osso_context);
223 modest_platform_get_new_device (void)
225 return TNY_DEVICE (tny_maemo_conic_device_new ());
229 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
230 gchar **effective_mime_type)
232 GString *mime_str = NULL;
233 gchar *icon_name = NULL;
234 gchar **icons, **cursor;
236 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
237 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
239 mime_str = g_string_new (mime_type);
240 g_string_ascii_down (mime_str);
243 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
244 for (cursor = icons; cursor; ++cursor) {
245 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
246 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
247 icon_name = g_strdup ("qgn_list_messagin");
249 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
250 icon_name = g_strdup (*cursor);
256 if (effective_mime_type)
257 *effective_mime_type = g_string_free (mime_str, FALSE);
259 g_string_free (mime_str, TRUE);
266 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
271 g_return_val_if_fail (uri, FALSE);
273 result = hildon_uri_open (uri, action, &err);
275 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
276 uri, action, err && err->message ? err->message : "unknown error");
286 modest_platform_activate_uri (const gchar *uri)
288 HildonURIAction *action;
289 gboolean result = FALSE;
290 GSList *actions, *iter = NULL;
292 g_return_val_if_fail (uri, FALSE);
296 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
298 for (iter = actions; iter; iter = g_slist_next (iter)) {
299 action = (HildonURIAction*) iter->data;
300 if (action && strcmp (hildon_uri_action_get_service (action),
301 "com.nokia.modest") == 0) {
302 result = checked_hildon_uri_open (uri, action);
307 /* if we could not open it with email, try something else */
309 result = checked_hildon_uri_open (uri, NULL);
312 ModestWindow *parent =
313 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
314 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
315 _("mcen_ib_unsupported_link"));
322 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
326 gchar *uri_path = NULL;
328 uri_path = g_strconcat ("file://", path, NULL);
329 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
332 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
334 result = hildon_mime_open_file (con, uri_path);
336 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
344 } ModestPlatformPopupInfo;
347 delete_uri_popup (GtkWidget *menu,
351 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
353 g_free (popup_info->uri);
354 hildon_uri_free_actions (popup_info->actions);
360 activate_uri_popup_item (GtkMenuItem *menu_item,
364 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
365 const gchar* action_name;
367 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
369 g_printerr ("modest: no action name defined\n");
373 /* special handling for the copy menu item -- copy the uri to the clipboard */
374 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
375 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
376 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
377 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
379 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
380 action_name += strlen ("mailto:");
382 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
383 return; /* we're done */
386 /* now, the real uri-actions... */
387 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
388 HildonURIAction *action = (HildonURIAction *) node->data;
389 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
390 if (!checked_hildon_uri_open (popup_info->uri, action)) {
391 ModestWindow *parent =
392 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
393 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
394 _("mcen_ib_unsupported_link"));
402 modest_platform_show_uri_popup (const gchar *uri)
404 GSList *actions_list;
409 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
410 if (actions_list != NULL) {
412 GtkWidget *menu = gtk_menu_new ();
413 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
415 popup_info->actions = actions_list;
416 popup_info->uri = g_strdup (uri);
418 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
419 GtkWidget *menu_item;
420 const gchar *action_name;
421 const gchar *translation_domain;
422 HildonURIAction *action = (HildonURIAction *) node->data;
423 action_name = hildon_uri_action_get_name (action);
424 translation_domain = hildon_uri_action_get_translation_domain (action);
425 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
426 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
427 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
430 if (hildon_uri_is_default_action (action, NULL)) {
431 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
433 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
435 gtk_widget_show (menu_item);
438 /* always add the copy item */
439 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
440 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
441 g_strconcat (URI_ACTION_COPY, uri, NULL),
443 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
444 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
445 gtk_widget_show (menu_item);
448 /* and what to do when the link is deleted */
449 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
450 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
453 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
461 modest_platform_get_icon (const gchar *name)
464 GdkPixbuf* pixbuf = NULL;
465 GtkIconTheme *current_theme = NULL;
467 g_return_val_if_fail (name, NULL);
469 /* strlen == 0 is not really an error; it just
470 * means the icon is not available
472 if (!name || strlen(name) == 0)
475 #if 0 /* do we still need this? */
476 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
477 pixbuf = gdk_pixbuf_new_from_file (name, &err);
479 g_printerr ("modest: error loading icon '%s': %s\n",
487 current_theme = gtk_icon_theme_get_default ();
488 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
489 GTK_ICON_LOOKUP_NO_SVG,
492 g_printerr ("modest: error loading theme icon '%s': %s\n",
500 modest_platform_get_app_name (void)
502 return _("mcen_ap_name");
506 entry_insert_text (GtkEditable *editable,
515 chars = gtk_editable_get_chars (editable, 0, -1);
516 chars_length = g_utf8_strlen (chars, -1);
518 /* Show WID-INF036 */
519 if (chars_length >= 20) {
520 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
521 _CS("ckdg_ib_maximum_characters_reached"));
523 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
527 tmp = g_strndup (folder_name_forbidden_chars,
528 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
529 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
530 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
535 /* Write the text in the entry if it's valid */
536 g_signal_handlers_block_by_func (editable,
537 (gpointer) entry_insert_text, data);
538 gtk_editable_insert_text (editable, text, length, position);
539 g_signal_handlers_unblock_by_func (editable,
540 (gpointer) entry_insert_text, data);
543 /* Do not allow further processing */
544 g_signal_stop_emission_by_name (editable, "insert_text");
548 entry_changed (GtkEditable *editable,
552 GtkWidget *ok_button;
555 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
556 ok_button = GTK_WIDGET (buttons->next->data);
558 chars = gtk_editable_get_chars (editable, 0, -1);
559 g_return_if_fail (chars != NULL);
562 if (g_utf8_strlen (chars,-1) >= 21)
563 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
564 _CS("ckdg_ib_maximum_characters_reached"));
566 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
569 g_list_free (buttons);
574 launch_sort_headers_dialog (GtkWindow *parent_window,
575 HildonSortDialog *dialog)
577 ModestHeaderView *header_view = NULL;
579 GtkSortType sort_type;
581 gint default_key = 0;
583 gboolean outgoing = FALSE;
584 gint current_sort_colid = -1;
585 GtkSortType current_sort_type;
586 gint attachments_sort_id;
587 gint priority_sort_id;
588 GtkTreeSortable *sortable;
590 /* Get header window */
591 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
592 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
593 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
598 /* Add sorting keys */
599 cols = modest_header_view_get_columns (header_view);
602 #define SORT_ID_NUM 6
603 int sort_model_ids[SORT_ID_NUM];
604 int sort_ids[SORT_ID_NUM];
606 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
607 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
609 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
611 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
612 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
614 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
615 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
618 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
620 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
621 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
623 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
624 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
626 default_key = sort_key;
628 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
629 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
631 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
633 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
635 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
636 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
637 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
638 attachments_sort_id = sort_key;
640 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
641 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
642 sort_ids[sort_key] = 0;
644 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
645 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
646 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY_MASK;
647 priority_sort_id = sort_key;
649 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model
650 (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
652 if (!gtk_tree_sortable_get_sort_column_id (sortable,
653 ¤t_sort_colid, ¤t_sort_type)) {
654 hildon_sort_dialog_set_sort_key (dialog, default_key);
655 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
657 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
658 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
659 gpointer flags_sort_type_pointer;
660 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
661 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY_MASK)
662 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
664 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
666 gint current_sort_keyid = 0;
667 while (current_sort_keyid < 6) {
668 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
671 current_sort_keyid++;
673 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
677 result = gtk_dialog_run (GTK_DIALOG (dialog));
678 if (result == GTK_RESPONSE_OK) {
679 sort_key = hildon_sort_dialog_get_sort_key (dialog);
680 sort_type = hildon_sort_dialog_get_sort_order (dialog);
681 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
682 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
683 GINT_TO_POINTER (sort_ids[sort_key]));
684 /* This is a hack to make it resort rows always when flag fields are
685 * selected. If we do not do this, changing sort field from priority to
686 * attachments does not work */
687 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
689 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
690 sort_model_ids[sort_key]);
693 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
694 gtk_tree_sortable_sort_column_changed (sortable);
697 modest_widget_memory_save (modest_runtime_get_conf (),
698 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
700 /* while (gtk_events_pending ()) */
701 /* gtk_main_iteration (); */
710 on_response (GtkDialog *dialog,
714 GList *child_vbox, *child_hbox;
715 GtkWidget *hbox, *entry;
716 TnyFolderStore *parent;
718 if (response != GTK_RESPONSE_ACCEPT)
722 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
723 hbox = child_vbox->data;
724 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
725 entry = child_hbox->next->data;
727 parent = TNY_FOLDER_STORE (user_data);
729 /* Look for another folder with the same name */
730 if (modest_tny_folder_has_subfolder_with_name (parent,
731 gtk_entry_get_text (GTK_ENTRY (entry)),
735 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
736 NULL, _CS("ckdg_ib_folder_already_exists"));
737 /* Select the text */
738 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
739 gtk_widget_grab_focus (entry);
740 /* Do not close the dialog */
741 g_signal_stop_emission_by_name (dialog, "response");
748 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
749 TnyFolderStore *parent,
750 const gchar *dialog_title,
751 const gchar *label_text,
752 const gchar *suggested_name,
755 GtkWidget *accept_btn = NULL;
756 GtkWidget *dialog, *entry, *label, *hbox;
757 GList *buttons = NULL;
760 /* Ask the user for the folder name */
761 dialog = gtk_dialog_new_with_buttons (dialog_title,
763 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
764 _("mcen_bd_dialog_ok"),
766 _("mcen_bd_dialog_cancel"),
770 /* Add accept button (with unsensitive handler) */
771 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
772 accept_btn = GTK_WIDGET (buttons->next->data);
773 /* Create label and entry */
774 label = gtk_label_new (label_text);
775 /* TODO: check that the suggested name does not exist */
776 /* We set 21 as maximum because we want to show WID-INF036
777 when the user inputs more that 20 */
778 entry = gtk_entry_new_with_max_length (21);
780 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
782 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
783 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
785 /* Connect to the response method to avoid closing the dialog
786 when an invalid name is selected*/
787 g_signal_connect (dialog,
789 G_CALLBACK (on_response),
792 /* Track entry changes */
793 g_signal_connect (entry,
795 G_CALLBACK (entry_insert_text),
797 g_signal_connect (entry,
799 G_CALLBACK (entry_changed),
802 /* Create the hbox */
803 hbox = gtk_hbox_new (FALSE, 12);
804 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
805 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
807 /* Add hbox to dialog */
808 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
809 hbox, FALSE, FALSE, 0);
811 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
812 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
814 result = gtk_dialog_run (GTK_DIALOG(dialog));
815 if (result == GTK_RESPONSE_ACCEPT)
816 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
818 gtk_widget_destroy (dialog);
820 while (gtk_events_pending ())
821 gtk_main_iteration ();
827 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
828 TnyFolderStore *parent_folder,
829 gchar *suggested_name,
832 gchar *real_suggested_name = NULL;
835 if(suggested_name == NULL)
837 const gchar *default_name = _("mcen_ia_default_folder_name");
841 for(i = 0; i < 100; ++ i) {
842 gboolean exists = FALSE;
844 sprintf(num_str, "%.2u", i);
847 real_suggested_name = g_strdup (default_name);
849 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
851 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
858 g_free (real_suggested_name);
861 /* Didn't find a free number */
863 real_suggested_name = g_strdup (default_name);
865 real_suggested_name = suggested_name;
868 result = modest_platform_run_folder_name_dialog (parent_window,
870 _("mcen_ti_new_folder"),
871 _("mcen_fi_new_folder_name"),
874 if (suggested_name == NULL)
875 g_free(real_suggested_name);
881 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
882 TnyFolderStore *parent_folder,
883 const gchar *suggested_name,
886 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
888 return modest_platform_run_folder_name_dialog (parent_window,
890 _HL("ckdg_ti_rename_folder"),
891 _HL("ckdg_fi_rename_name"),
899 on_destroy_dialog (GtkDialog *dialog)
901 gtk_widget_destroy (GTK_WIDGET(dialog));
902 if (gtk_events_pending ())
903 gtk_main_iteration ();
907 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
908 const gchar *message)
913 dialog = hildon_note_new_confirmation (parent_window, message);
914 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
915 GTK_WINDOW (dialog));
917 response = gtk_dialog_run (GTK_DIALOG (dialog));
919 on_destroy_dialog (GTK_DIALOG(dialog));
921 while (gtk_events_pending ())
922 gtk_main_iteration ();
928 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
929 const gchar *message)
934 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
935 _("mcen_bd_yes"), GTK_RESPONSE_YES,
936 _("mcen_bd_no"), GTK_RESPONSE_NO,
938 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
939 response = gtk_dialog_run (GTK_DIALOG (dialog));
941 on_destroy_dialog (GTK_DIALOG(dialog));
943 while (gtk_events_pending ())
944 gtk_main_iteration ();
952 modest_platform_run_information_dialog (GtkWindow *parent_window,
953 const gchar *message)
957 note = hildon_note_new_information (parent_window, message);
958 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
961 g_signal_connect_swapped (note,
963 G_CALLBACK (on_destroy_dialog),
966 gtk_widget_show_all (note);
971 typedef struct _ConnectAndWaitData {
973 GMainLoop *wait_loop;
974 gboolean has_callback;
976 } ConnectAndWaitData;
980 quit_wait_loop (TnyAccount *account,
981 ConnectAndWaitData *data)
983 /* Set the has_callback to TRUE (means that the callback was
984 executed and wake up every code waiting for cond to be
986 g_mutex_lock (data->mutex);
987 data->has_callback = TRUE;
989 g_main_loop_quit (data->wait_loop);
990 g_mutex_unlock (data->mutex);
994 on_connection_status_changed (TnyAccount *account,
995 TnyConnectionStatus status,
998 TnyConnectionStatus conn_status;
999 ConnectAndWaitData *data;
1001 /* Ignore if reconnecting or disconnected */
1002 conn_status = tny_account_get_connection_status (account);
1003 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1004 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1007 /* Remove the handler */
1008 data = (ConnectAndWaitData *) user_data;
1009 g_signal_handler_disconnect (account, data->handler);
1011 /* Quit from wait loop */
1012 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1016 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1021 /* Quit from wait loop */
1022 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1026 modest_platform_connect_and_wait (GtkWindow *parent_window,
1027 TnyAccount *account)
1029 ConnectAndWaitData *data = NULL;
1030 gboolean device_online;
1032 TnyConnectionStatus conn_status;
1033 gboolean user_requested;
1035 device = modest_runtime_get_device();
1036 device_online = tny_device_is_online (device);
1038 /* Whether the connection is user requested or automatically
1039 requested, for example via D-Bus */
1040 user_requested = (parent_window) ? TRUE : FALSE;
1042 /* If there is no account check only the device status */
1047 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1048 NULL, user_requested);
1051 /* Return if the account is already connected */
1052 conn_status = tny_account_get_connection_status (account);
1053 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1056 /* Create the helper */
1057 data = g_slice_new0 (ConnectAndWaitData);
1058 data->mutex = g_mutex_new ();
1059 data->has_callback = FALSE;
1061 /* Connect the device */
1062 if (!device_online) {
1063 /* Track account connection status changes */
1064 data->handler = g_signal_connect (account, "connection-status-changed",
1065 G_CALLBACK (on_connection_status_changed),
1067 /* Try to connect the device */
1068 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1069 NULL, user_requested);
1071 /* If the device connection failed then exit */
1072 if (!device_online && data->handler)
1075 /* Force a reconnection of the account */
1076 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1077 on_tny_camel_account_set_online_cb, data);
1080 /* Wait until the callback is executed */
1081 g_mutex_lock (data->mutex);
1082 if (!data->has_callback) {
1083 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1084 gdk_threads_leave ();
1085 g_mutex_unlock (data->mutex);
1086 g_main_loop_run (data->wait_loop);
1087 g_mutex_lock (data->mutex);
1088 gdk_threads_enter ();
1090 g_mutex_unlock (data->mutex);
1094 if (g_signal_handler_is_connected (account, data->handler))
1095 g_signal_handler_disconnect (account, data->handler);
1096 g_mutex_free (data->mutex);
1097 g_main_loop_unref (data->wait_loop);
1098 g_slice_free (ConnectAndWaitData, data);
1101 conn_status = tny_account_get_connection_status (account);
1102 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1106 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1108 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1109 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1110 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1111 /* This must be a maildir account, which does not require a connection: */
1116 return modest_platform_connect_and_wait (parent_window, account);
1120 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1123 return TRUE; /* Maybe it is something local. */
1125 gboolean result = TRUE;
1126 if (TNY_IS_FOLDER (folder_store)) {
1127 /* Get the folder's parent account: */
1128 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1129 if (account != NULL) {
1130 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1131 g_object_unref (account);
1133 } else if (TNY_IS_ACCOUNT (folder_store)) {
1134 /* Use the folder store as an account: */
1135 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1142 modest_platform_is_network_folderstore (TnyFolderStore *folder_store)
1144 TnyAccount *account = NULL;
1145 gboolean result = TRUE;
1147 g_return_val_if_fail(TNY_IS_FOLDER_STORE(folder_store), FALSE);
1149 if (TNY_IS_FOLDER (folder_store)) {
1150 /* Get the folder's parent account: */
1151 account = tny_folder_get_account(TNY_FOLDER(folder_store));
1152 } else if (TNY_IS_ACCOUNT (folder_store)) {
1153 account = TNY_ACCOUNT(folder_store);
1154 g_object_ref(account);
1157 if (account != NULL) {
1158 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1159 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1160 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1161 /* This must be a maildir account, which does
1162 * not require a connection: */
1166 g_object_unref (account);
1175 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1176 ModestSortDialogType type)
1178 GtkWidget *dialog = NULL;
1181 dialog = hildon_sort_dialog_new (parent_window);
1182 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1183 GTK_WINDOW (dialog));
1185 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1186 "applications_email_sort",
1187 modest_maemo_utils_get_osso_context());
1189 /* Fill sort keys */
1191 case MODEST_SORT_HEADERS:
1192 launch_sort_headers_dialog (parent_window,
1193 HILDON_SORT_DIALOG(dialog));
1198 on_destroy_dialog (GTK_DIALOG(dialog));
1203 modest_platform_set_update_interval (guint minutes)
1205 #ifdef MODEST_HAVE_LIBALARM
1207 ModestConf *conf = modest_runtime_get_conf ();
1211 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1213 /* Delete any existing alarm,
1214 * because we will replace it: */
1216 if (alarm_event_del(alarm_cookie) != 1)
1217 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1219 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1222 /* 0 means no updates: */
1227 /* Register alarm: */
1229 /* Set the interval in alarm_event_t structure: */
1230 alarm_event_t *event = g_new0(alarm_event_t, 1);
1231 event->alarm_time = minutes * 60; /* seconds */
1233 /* Set recurrence every few minutes: */
1234 event->recurrence = minutes;
1235 event->recurrence_count = -1; /* Means infinite */
1237 /* Specify what should happen when the alarm happens:
1238 * It should call this D-Bus method: */
1240 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1241 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1242 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1243 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1245 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1246 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1247 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1248 * This is why we want to use the Alarm API instead of just g_timeout_add().
1249 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1251 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1253 alarm_cookie = alarm_event_add (event);
1256 alarm_event_free (event);
1258 /* Store the alarm ID in GConf, so we can remove it later:
1259 * This is apparently valid between application instances. */
1260 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1262 if (!alarm_cookie) {
1264 const alarm_error_t alarm_error = alarmd_get_error ();
1265 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1267 /* Give people some clue: */
1268 /* The alarm API should have a function for this: */
1269 if (alarm_error == ALARMD_ERROR_DBUS) {
1270 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1271 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1272 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1273 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1274 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1275 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1276 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1277 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1278 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1279 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1280 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1285 #endif /* MODEST_HAVE_LIBALARM */
1290 modest_platform_on_new_headers_received (TnyList *header_list)
1292 #ifdef MODEST_HAVE_HILDON_NOTIFY
1293 HildonNotification *notification;
1295 GSList *notifications_list = NULL;
1297 /* Get previous notifications ids */
1298 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1299 MODEST_CONF_NOTIFICATION_IDS,
1300 MODEST_CONF_VALUE_INT, NULL);
1302 iter = tny_list_create_iterator (header_list);
1303 while (!tny_iterator_is_done (iter)) {
1304 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1305 const gchar *display_date;
1306 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1307 TnyFolder *folder = tny_header_get_folder (header);
1308 gboolean first_notification = TRUE;
1311 /* constant string, don't free */
1312 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1314 display_address = g_strdup(tny_header_get_from (header));
1315 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1317 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1318 notification = hildon_notification_new (summary,
1319 tny_header_get_subject (header),
1320 "qgn_list_messagin",
1322 /* Create the message URL */
1323 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1324 tny_header_get_uid (header));
1326 hildon_notification_add_dbus_action(notification,
1329 MODEST_DBUS_SERVICE,
1332 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1336 /* Play sound if the user wants. Show the LED
1337 pattern. Show and play just one */
1338 if (G_UNLIKELY (first_notification)) {
1339 first_notification = FALSE;
1340 if (modest_conf_get_bool (modest_runtime_get_conf (),
1341 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1343 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1344 "sound-file", "/usr/share/sounds/ui-new_email.wav");
1347 /* Set the led pattern */
1348 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1350 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1352 "PatternCommunicationEmail");
1355 /* Notify. We need to do this in an idle because this function
1356 could be called from a thread */
1357 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1359 /* Save id in the list */
1360 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1361 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1362 /* We don't listen for the "closed" signal, because we
1363 don't care about if the notification was removed or
1364 not to store the list in gconf */
1366 /* Free & carry on */
1367 g_free (display_address);
1370 g_object_unref (folder);
1371 g_object_unref (header);
1372 tny_iterator_next (iter);
1374 g_object_unref (iter);
1377 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1378 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1380 g_slist_free (notifications_list);
1382 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1386 modest_platform_remove_new_mail_notifications (void)
1388 #ifdef MODEST_HAVE_HILDON_NOTIFY
1389 GSList *notif_list = NULL;
1391 /* Get previous notifications ids */
1392 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1393 MODEST_CONF_NOTIFICATION_IDS,
1394 MODEST_CONF_VALUE_INT, NULL);
1396 while (notif_list) {
1398 NotifyNotification *notif;
1400 /* Nasty HACK to remove the notifications, set the id
1401 of the existing ones and then close them */
1402 notif_id = GPOINTER_TO_INT(notif_list->data);
1403 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1404 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1406 /* Close the notification, note that some ids could be
1407 already invalid, but we don't care because it does
1409 notify_notification_close(notif, NULL);
1410 g_object_unref(notif);
1412 /* Delete the link, it's like going to the next */
1413 notif_list = g_slist_delete_link (notif_list, notif_list);
1417 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1418 notif_list, MODEST_CONF_VALUE_INT, NULL);
1420 g_slist_free (notif_list);
1422 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1428 modest_platform_get_global_settings_dialog ()
1430 return modest_maemo_global_settings_dialog_new ();
1434 modest_platform_show_help (GtkWindow *parent_window,
1435 const gchar *help_id)
1437 osso_return_t result;
1438 g_return_if_fail (help_id);
1440 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1441 help_id, HILDON_HELP_SHOW_DIALOG);
1443 if (result != OSSO_OK) {
1445 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1446 hildon_banner_show_information (GTK_WIDGET (parent_window),
1454 modest_platform_show_search_messages (GtkWindow *parent_window)
1456 osso_return_t result = OSSO_ERROR;
1458 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1459 "osso_global_search",
1460 "search_email", NULL, DBUS_TYPE_INVALID);
1462 if (result != OSSO_OK) {
1463 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1468 modest_platform_show_addressbook (GtkWindow *parent_window)
1470 osso_return_t result = OSSO_ERROR;
1472 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1474 "top_application", NULL, DBUS_TYPE_INVALID);
1476 if (result != OSSO_OK) {
1477 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1482 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1484 GtkWidget *widget = modest_folder_view_new (query);
1486 /* Show one account by default */
1487 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1488 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1491 /* Restore settings */
1492 modest_widget_memory_restore (modest_runtime_get_conf(),
1494 MODEST_CONF_FOLDER_VIEW_KEY);
1500 modest_platform_information_banner (GtkWidget *parent,
1501 const gchar *icon_name,
1504 hildon_banner_show_information (parent, icon_name, text);
1508 modest_platform_animation_banner (GtkWidget *parent,
1509 const gchar *animation_name,
1512 GtkWidget *inf_note = NULL;
1514 g_return_val_if_fail (text != NULL, NULL);
1516 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1524 TnyAccount *account;
1527 } CheckAccountIdleData;
1529 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1532 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1534 gboolean stop_trying = FALSE;
1535 g_return_val_if_fail (data && data->account, FALSE);
1537 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1538 tny_account_get_connection_status (data->account));
1540 if (data && data->account &&
1541 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1542 * after which the account is likely to be usable, or never likely to be usable soon: */
1543 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1545 data->is_online = TRUE;
1549 /* Give up if we have tried too many times: */
1550 if (data->count_tries >= NUMBER_OF_TRIES) {
1553 /* Wait for another timeout: */
1554 ++(data->count_tries);
1559 /* Allow the function that requested this idle callback to continue: */
1561 g_main_loop_quit (data->loop);
1564 g_object_unref (data->account);
1566 return FALSE; /* Don't call this again. */
1568 return TRUE; /* Call this timeout callback again. */
1572 /* Return TRUE immediately if the account is already online,
1573 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1574 * soon as the account is online, or FALSE if the account does
1575 * not become online in the NUMBER_OF_TRIES seconds.
1576 * This is useful when the D-Bus method was run immediately after
1577 * the application was started (when using D-Bus activation),
1578 * because the account usually takes a short time to go online.
1579 * The return value is maybe not very useful.
1582 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1584 g_return_val_if_fail (account, FALSE);
1586 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1588 if (!tny_device_is_online (modest_runtime_get_device())) {
1589 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1593 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1594 * so we avoid wait unnecessarily: */
1595 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1596 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1600 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1601 __FUNCTION__, tny_account_get_connection_status (account));
1603 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1604 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1605 * we want to avoid. */
1606 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1609 /* This blocks on the result: */
1610 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1611 data->is_online = FALSE;
1612 data->account = account;
1613 g_object_ref (data->account);
1614 data->count_tries = 0;
1616 GMainContext *context = NULL; /* g_main_context_new (); */
1617 data->loop = g_main_loop_new (context, FALSE /* not running */);
1619 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1621 /* This main loop will run until the idle handler has stopped it: */
1622 g_main_loop_run (data->loop);
1624 g_main_loop_unref (data->loop);
1625 /* g_main_context_unref (context); */
1627 g_slice_free (CheckAccountIdleData, data);
1629 return data->is_online;
1635 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1637 /* GTK_RESPONSE_HELP means we need to show the certificate */
1638 if (response_id == GTK_RESPONSE_HELP) {
1642 /* Do not close the dialog */
1643 g_signal_stop_emission_by_name (dialog, "response");
1645 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1646 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1647 gtk_dialog_run (GTK_DIALOG(note));
1648 gtk_widget_destroy (note);
1654 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1655 const gchar *certificate)
1659 ModestWindow *main_win;
1661 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1662 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1667 /* don't create it */
1668 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1669 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1672 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1675 note = hildon_note_new_confirmation_add_buttons (
1676 GTK_WINDOW(main_win),
1678 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1679 _("mcen_bd_view"), GTK_RESPONSE_HELP, /* abusing this... */
1680 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1683 g_signal_connect (G_OBJECT(note), "response",
1684 G_CALLBACK(on_cert_dialog_response),
1685 (gpointer) certificate);
1687 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1689 response = gtk_dialog_run(GTK_DIALOG(note));
1691 on_destroy_dialog (GTK_DIALOG(note));
1694 return response == GTK_RESPONSE_OK;
1698 modest_platform_run_alert_dialog (const gchar* prompt,
1699 gboolean is_question)
1701 ModestWindow *main_win;
1703 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1704 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1705 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1706 return is_question ? FALSE : TRUE;
1709 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1710 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1712 gboolean retval = TRUE;
1714 /* The Tinymail documentation says that we should show Yes and No buttons,
1715 * when it is a question.
1716 * Obviously, we need tinymail to use more specific error codes instead,
1717 * so we know what buttons to show. */
1718 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1720 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1721 GTK_WINDOW (dialog));
1723 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1724 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1726 on_destroy_dialog (GTK_DIALOG(dialog));
1728 /* Just show the error text and use the default response: */
1729 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1737 GtkWindow *parent_window;
1738 ModestConnectedPerformer callback;
1739 TnyAccount *account;
1746 on_went_online_info_free (OnWentOnlineInfo *info)
1748 /* And if we cleanup, we DO cleanup :-) */
1751 g_object_unref (info->device);
1754 if (info->parent_window)
1755 g_object_unref (info->parent_window);
1757 g_object_unref (info->account);
1759 g_slice_free (OnWentOnlineInfo, info);
1761 /* We're done ... */
1767 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1769 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1771 /* Now it's really time to callback to the caller. If going online didn't succeed,
1772 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1773 * canceled will be set. Etcetera etcetera. */
1775 if (info->callback) {
1776 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1779 /* This is our last call, we must cleanup here if we didn't yet do that */
1780 on_went_online_info_free (info);
1787 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1789 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1790 info->iap = g_strdup (iap_id);
1792 if (canceled || err || !info->account) {
1794 /* If there's a problem or if there's no account (then that's it for us, we callback
1795 * the caller's callback now. He'll have to handle err or canceled, of course.
1796 * We are not really online, as the account is not really online here ... */
1798 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1799 * this info. We don't cleanup err, Tinymail does that! */
1801 if (info->callback) {
1803 /* info->account can be NULL here, this means that the user did not
1804 * provide a nice account instance. We'll assume that the user knows
1805 * what he's doing and is happy with just the device going online.
1807 * We can't do magic, we don't know what account the user wants to
1808 * see going online. So just the device goes online, end of story */
1810 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1813 } else if (info->account) {
1815 /* If there's no problem and if we have an account, we'll put the account
1816 * online too. When done, the callback of bringing the account online
1817 * will callback the caller's callback. This is the most normal case. */
1819 info->device = TNY_DEVICE (g_object_ref (device));
1821 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1822 on_account_went_online, info);
1824 /* The on_account_went_online cb frees up the info, go look if you
1825 * don't believe me! (so we return here) */
1830 /* We cleanup if we are not bringing the account online too */
1831 on_went_online_info_free (info);
1837 modest_platform_connect_and_perform (GtkWindow *parent_window,
1838 TnyAccount *account,
1839 ModestConnectedPerformer callback,
1842 gboolean device_online;
1844 TnyConnectionStatus conn_status;
1845 OnWentOnlineInfo *info;
1846 gboolean user_requested;
1848 device = modest_runtime_get_device();
1849 device_online = tny_device_is_online (device);
1851 /* Whether the connection is user requested or automatically
1852 requested, for example via D-Bus */
1853 user_requested = (parent_window) ? TRUE : FALSE;
1855 /* If there is no account check only the device status */
1858 if (device_online) {
1860 /* We promise to instantly perform the callback, so ... */
1862 callback (FALSE, NULL, parent_window, account, user_data);
1867 info = g_slice_new0 (OnWentOnlineInfo);
1870 info->device = NULL;
1871 info->account = NULL;
1874 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1876 info->parent_window = NULL;
1877 info->user_data = user_data;
1878 info->callback = callback;
1880 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1881 user_requested, on_conic_device_went_online,
1884 /* We'll cleanup in on_conic_device_went_online */
1887 /* The other code has no more reason to run. This is all that we can do for the
1888 * caller (he should have given us a nice and clean account instance!). We
1889 * can't do magic, we don't know what account he intends to bring online. So
1890 * we'll just bring the device online (and await his false bug report). */
1896 /* Return if the account is already connected */
1898 conn_status = tny_account_get_connection_status (account);
1899 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1901 /* We promise to instantly perform the callback, so ... */
1903 callback (FALSE, NULL, parent_window, account, user_data);
1909 /* Else, we are in a state that requires that we go online before we
1910 * call the caller's callback. */
1912 info = g_slice_new0 (OnWentOnlineInfo);
1914 info->device = NULL;
1916 info->account = TNY_ACCOUNT (g_object_ref (account));
1919 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1921 info->parent_window = NULL;
1923 /* So we'll put the callback away for later ... */
1925 info->user_data = user_data;
1926 info->callback = callback;
1928 if (!device_online) {
1930 /* If also the device is offline, then we connect both the device
1931 * and the account */
1933 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1934 user_requested, on_conic_device_went_online,
1939 /* If the device is online, we'll just connect the account */
1941 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1942 on_account_went_online, info);
1945 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1946 * in both situations, go look if you don't believe me! */
1952 modest_platform_connect_and_perform_if_network_account (GtkWindow *parent_window,
1953 TnyAccount *account,
1954 ModestConnectedPerformer callback,
1957 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1958 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1959 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1961 /* This IS a local account like a maildir account, which does not require
1962 * a connection. (original comment had a vague assumption in its language
1963 * usage. There's no assuming needed, this IS what it IS: a local account), */
1965 /* We promise to instantly perform the callback, so ... */
1967 callback (FALSE, NULL, parent_window, account, user_data);
1974 modest_platform_connect_and_perform (parent_window, account, callback, user_data);
1980 modest_platform_connect_and_perform_if_network_folderstore (GtkWindow *parent_window,
1981 TnyFolderStore *folder_store,
1982 ModestConnectedPerformer callback,
1985 if (!folder_store) {
1987 /* We promise to instantly perform the callback, so ... */
1989 callback (FALSE, NULL, parent_window, NULL, user_data);
1993 /* Original comment: Maybe it is something local. */
1994 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
1998 if (TNY_IS_FOLDER (folder_store)) {
1999 /* Get the folder's parent account: */
2000 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
2001 if (account != NULL) {
2002 modest_platform_connect_and_perform_if_network_account (NULL, account, callback, user_data);
2003 g_object_unref (account);
2005 } else if (TNY_IS_ACCOUNT (folder_store)) {
2006 /* Use the folder store as an account: */
2007 modest_platform_connect_and_perform_if_network_account (NULL, TNY_ACCOUNT (folder_store), callback, user_data);