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 <mce/dbus-names.h>
44 #include <tny-maemo-conic-device.h>
45 #include <tny-simple-list.h>
46 #include <tny-folder.h>
47 #include <tny-camel-imap-store-account.h>
48 #include <tny-camel-pop-store-account.h>
49 #include <gtk/gtkicontheme.h>
50 #include <gtk/gtkmenuitem.h>
51 #include <gtk/gtkmain.h>
52 #include <modest-text-utils.h>
53 #include "modest-tny-folder.h"
54 #include "modest-tny-account.h"
56 #include <libgnomevfs/gnome-vfs-mime-utils.h>
57 #include <modest-account-settings-dialog.h>
58 #include <maemo/easysetup/modest-easysetup-wizard.h>
59 #include <hildon/hildon-sound.h>
61 #ifdef MODEST_HAVE_ABOOK
62 #include <libosso-abook/osso-abook.h>
63 #endif /*MODEST_HAVE_ABOOK*/
65 #ifdef MODEST_HAVE_LIBALARM
66 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
67 #endif /*MODEST_HAVE_LIBALARM*/
70 #define HILDON_OSSO_URI_ACTION "uri-action"
71 #define URI_ACTION_COPY "copy:"
72 #define MODEST_NEW_MAIL_SOUND_FILE "/usr/share/sounds/ui-new_email.wav"
73 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
76 on_modest_conf_update_interval_changed (ModestConf* self,
78 ModestConfEvent event,
79 ModestConfNotificationId id,
82 g_return_if_fail (key);
84 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
85 const guint update_interval_minutes =
86 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
87 modest_platform_set_update_interval (update_interval_minutes);
94 check_required_files (void)
96 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
98 g_printerr ("modest: check for mcc file failed\n");
103 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
104 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
105 g_printerr ("modest: cannot find providers data\n");
113 /* the gpointer here is the osso_context. */
115 modest_platform_init (int argc, char *argv[])
117 osso_context_t *osso_context;
119 osso_hw_state_t hw_state = { 0 };
123 if (!check_required_files ()) {
124 g_printerr ("modest: missing required files\n");
128 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
131 g_printerr ("modest: failed to acquire osso context\n");
134 modest_maemo_utils_set_osso_context (osso_context);
136 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
137 g_printerr ("modest: could not get dbus connection\n");
141 /* Add a D-Bus handler to be used when the main osso-rpc
142 * D-Bus handler has not handled something.
143 * We use this for D-Bus methods that need to use more complex types
144 * than osso-rpc supports.
146 if (!dbus_connection_add_filter (con,
147 modest_dbus_req_filter,
151 g_printerr ("modest: Could not add D-Bus filter\n");
155 /* Register our simple D-Bus callbacks, via the osso API: */
156 osso_return_t result = osso_rpc_set_cb_f(osso_context,
160 modest_dbus_req_handler, NULL /* user_data */);
161 if (result != OSSO_OK) {
162 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
166 /* Register hardware event dbus callback: */
167 hw_state.shutdown_ind = TRUE;
168 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
170 /* Register osso auto-save callbacks: */
171 result = osso_application_set_autosave_cb (osso_context,
172 modest_on_osso_application_autosave, NULL /* user_data */);
173 if (result != OSSO_OK) {
174 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
179 /* Make sure that the update interval is changed whenever its gconf key
181 /* CAUTION: we're not using here the
182 modest_conf_listen_to_namespace because we know that there
183 are other parts of Modest listening for this namespace, so
184 we'll receive the notifications anyway. We basically do not
185 use it because there is no easy way to do the
186 modest_conf_forget_namespace */
187 ModestConf *conf = modest_runtime_get_conf ();
188 g_signal_connect (G_OBJECT(conf),
190 G_CALLBACK (on_modest_conf_update_interval_changed),
193 /* only force the setting of the default interval, if there are actually
195 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
197 /* Get the initial update interval from gconf: */
198 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
199 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
200 modest_account_mgr_free_account_names (acc_names);
204 #ifdef MODEST_HAVE_ABOOK
205 /* initialize the addressbook */
206 if (!osso_abook_init (&argc, &argv, osso_context)) {
207 g_printerr ("modest: failed to initialized addressbook\n");
210 #endif /*MODEST_HAVE_ABOOK*/
216 modest_platform_uninit (void)
218 osso_context_t *osso_context =
219 modest_maemo_utils_get_osso_context ();
221 osso_deinitialize (osso_context);
230 modest_platform_get_new_device (void)
232 return TNY_DEVICE (tny_maemo_conic_device_new ());
236 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
237 gchar **effective_mime_type)
239 GString *mime_str = NULL;
240 gchar *icon_name = NULL;
241 gchar **icons, **cursor;
243 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
244 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
246 mime_str = g_string_new (mime_type);
247 g_string_ascii_down (mime_str);
250 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
252 for (cursor = icons; cursor; ++cursor) {
253 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
254 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
255 icon_name = g_strdup ("qgn_list_messagin");
257 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
258 icon_name = g_strdup (*cursor);
264 if (effective_mime_type)
265 *effective_mime_type = g_string_free (mime_str, FALSE);
267 g_string_free (mime_str, TRUE);
274 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
279 g_return_val_if_fail (uri, FALSE);
281 result = hildon_uri_open (uri, action, &err);
283 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
284 uri, action, err && err->message ? err->message : "unknown error");
294 modest_platform_activate_uri (const gchar *uri)
296 HildonURIAction *action;
297 gboolean result = FALSE;
298 GSList *actions, *iter = NULL;
300 g_return_val_if_fail (uri, FALSE);
304 /* don't try to activate file: uri's -- they might confuse the user,
305 * and/or might have security implications */
306 if (!g_str_has_prefix (uri, "file:")) {
308 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
310 for (iter = actions; iter; iter = g_slist_next (iter)) {
311 action = (HildonURIAction*) iter->data;
312 if (action && strcmp (hildon_uri_action_get_service (action),
313 "com.nokia.modest") == 0) {
314 result = checked_hildon_uri_open (uri, action);
319 /* if we could not open it with email, try something else */
321 result = checked_hildon_uri_open (uri, NULL);
325 ModestWindow *parent =
326 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
327 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
328 _("mcen_ib_unsupported_link"));
329 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
336 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
340 gchar *uri_path = NULL;
342 uri_path = gnome_vfs_get_uri_from_local_path (path);
343 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
346 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
348 result = hildon_mime_open_file (con, uri_path);
350 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
358 } ModestPlatformPopupInfo;
361 delete_uri_popup (GtkWidget *menu,
365 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
367 g_free (popup_info->uri);
368 hildon_uri_free_actions (popup_info->actions);
374 activate_uri_popup_item (GtkMenuItem *menu_item,
378 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
379 const gchar* action_name;
381 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
383 g_printerr ("modest: no action name defined\n");
387 /* special handling for the copy menu item -- copy the uri to the clipboard */
388 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
389 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
390 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
391 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
393 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
394 action_name += strlen ("mailto:");
396 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
397 return; /* we're done */
400 /* now, the real uri-actions... */
401 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
402 HildonURIAction *action = (HildonURIAction *) node->data;
403 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
404 if (!checked_hildon_uri_open (popup_info->uri, action)) {
405 ModestWindow *parent =
406 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
407 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
408 _("mcen_ib_unsupported_link"));
416 modest_platform_show_uri_popup (const gchar *uri)
418 GSList *actions_list;
423 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
426 GtkWidget *menu = gtk_menu_new ();
427 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
429 /* don't add actions for file: uri's -- they might confuse the user,
430 * and/or might have security implications
431 * we still allow to copy the url though
433 if (!g_str_has_prefix (uri, "file:")) {
436 popup_info->actions = actions_list;
437 popup_info->uri = g_strdup (uri);
439 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
440 GtkWidget *menu_item;
441 const gchar *action_name;
442 const gchar *translation_domain;
443 HildonURIAction *action = (HildonURIAction *) node->data;
444 action_name = hildon_uri_action_get_name (action);
445 translation_domain = hildon_uri_action_get_translation_domain (action);
446 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
447 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
448 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
451 if (hildon_uri_is_default_action (action, NULL)) {
452 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
454 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
456 gtk_widget_show (menu_item);
460 /* always add the copy item */
461 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
462 "uri_link_copy_link_location"));
463 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
464 g_strconcat (URI_ACTION_COPY, uri, NULL),
466 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
467 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
468 gtk_widget_show (menu_item);
471 /* and what to do when the link is deleted */
472 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
473 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
476 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
484 modest_platform_get_icon (const gchar *name, guint icon_size)
487 GdkPixbuf* pixbuf = NULL;
488 GtkIconTheme *current_theme = NULL;
490 g_return_val_if_fail (name, NULL);
492 /* strlen == 0 is not really an error; it just
493 * means the icon is not available
495 if (!name || strlen(name) == 0)
498 current_theme = gtk_icon_theme_get_default ();
499 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
500 GTK_ICON_LOOKUP_NO_SVG,
503 g_printerr ("modest: error loading theme icon '%s': %s\n",
511 modest_platform_get_app_name (void)
513 return _("mcen_ap_name");
517 entry_insert_text (GtkEditable *editable,
526 chars = gtk_editable_get_chars (editable, 0, -1);
527 chars_length = g_utf8_strlen (chars, -1);
529 /* Show WID-INF036 */
530 if (chars_length >= 20) {
531 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
532 _CS("ckdg_ib_maximum_characters_reached"));
534 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
538 tmp = g_strndup (folder_name_forbidden_chars,
539 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
540 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
541 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
546 /* Write the text in the entry if it's valid */
547 g_signal_handlers_block_by_func (editable,
548 (gpointer) entry_insert_text, data);
549 gtk_editable_insert_text (editable, text, length, position);
550 g_signal_handlers_unblock_by_func (editable,
551 (gpointer) entry_insert_text, data);
554 /* Do not allow further processing */
555 g_signal_stop_emission_by_name (editable, "insert_text");
559 entry_changed (GtkEditable *editable,
563 GtkWidget *ok_button;
566 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
567 ok_button = GTK_WIDGET (buttons->next->data);
569 chars = gtk_editable_get_chars (editable, 0, -1);
570 g_return_if_fail (chars != NULL);
573 if (g_utf8_strlen (chars,-1) >= 21)
574 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
575 _CS("ckdg_ib_maximum_characters_reached"));
577 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
580 g_list_free (buttons);
585 checked_hildon_sort_dialog_add_sort_key (HildonSortDialog *dialog, const gchar* key, guint max)
589 g_return_val_if_fail (dialog && HILDON_IS_SORT_DIALOG(dialog), 0);
590 g_return_val_if_fail (key, 0);
592 sort_key = hildon_sort_dialog_add_sort_key (dialog, key);
593 if (sort_key < 0 || sort_key >= max) {
594 g_warning ("%s: out of range (%d) for %s", __FUNCTION__, sort_key, key);
597 return (guint)sort_key;
602 launch_sort_headers_dialog (GtkWindow *parent_window,
603 HildonSortDialog *dialog)
605 ModestHeaderView *header_view = NULL;
607 GtkSortType sort_type;
609 gint default_key = 0;
611 gboolean outgoing = FALSE;
612 gint current_sort_colid = -1;
613 GtkSortType current_sort_type;
614 gint attachments_sort_id;
615 gint priority_sort_id;
616 GtkTreeSortable *sortable;
618 /* Get header window */
619 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
620 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
621 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
626 /* Add sorting keys */
627 cols = modest_header_view_get_columns (header_view);
630 #define SORT_ID_NUM 6
631 int sort_model_ids[SORT_ID_NUM];
632 int sort_ids[SORT_ID_NUM];
634 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
635 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
637 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"),
640 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
641 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
643 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
644 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
647 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"),
650 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
651 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
653 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
654 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
656 default_key = sort_key;
658 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"),
660 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
662 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
664 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
666 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"),
668 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
669 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
670 attachments_sort_id = sort_key;
672 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"),
674 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
675 sort_ids[sort_key] = 0;
677 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"),
679 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
680 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY_MASK;
681 priority_sort_id = sort_key;
683 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model
684 (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
686 if (!gtk_tree_sortable_get_sort_column_id (sortable,
687 ¤t_sort_colid, ¤t_sort_type)) {
688 hildon_sort_dialog_set_sort_key (dialog, default_key);
689 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
691 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
692 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
693 gpointer flags_sort_type_pointer;
694 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
695 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY_MASK)
696 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
698 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
700 gint current_sort_keyid = 0;
701 while (current_sort_keyid < 6) {
702 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
705 current_sort_keyid++;
707 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
711 result = gtk_dialog_run (GTK_DIALOG (dialog));
712 if (result == GTK_RESPONSE_OK) {
713 sort_key = hildon_sort_dialog_get_sort_key (dialog);
714 if (sort_key < 0 || sort_key > SORT_ID_NUM -1) {
715 g_warning ("%s: out of range (%d)", __FUNCTION__, sort_key);
719 sort_type = hildon_sort_dialog_get_sort_order (dialog);
720 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
721 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
722 GINT_TO_POINTER (sort_ids[sort_key]));
723 /* This is a hack to make it resort rows always when flag fields are
724 * selected. If we do not do this, changing sort field from priority to
725 * attachments does not work */
726 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
728 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
729 sort_model_ids[sort_key]);
732 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
733 gtk_tree_sortable_sort_column_changed (sortable);
736 modest_widget_memory_save (modest_runtime_get_conf (),
737 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
746 on_response (GtkDialog *dialog,
750 GList *child_vbox, *child_hbox;
751 GtkWidget *hbox, *entry;
752 TnyFolderStore *parent;
753 const gchar *new_name;
756 if (response != GTK_RESPONSE_ACCEPT)
760 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
761 hbox = child_vbox->data;
762 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
763 entry = child_hbox->next->data;
765 parent = TNY_FOLDER_STORE (user_data);
766 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
769 /* Look for another folder with the same name */
770 if (modest_tny_folder_has_subfolder_with_name (parent,
777 if (TNY_IS_ACCOUNT (parent) &&
778 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
779 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
788 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
789 NULL, _CS("ckdg_ib_folder_already_exists"));
790 /* Select the text */
791 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
792 gtk_widget_grab_focus (entry);
793 /* Do not close the dialog */
794 g_signal_stop_emission_by_name (dialog, "response");
801 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
802 TnyFolderStore *parent,
803 const gchar *dialog_title,
804 const gchar *label_text,
805 const gchar *suggested_name,
808 GtkWidget *accept_btn = NULL;
809 GtkWidget *dialog, *entry, *label, *hbox;
810 GList *buttons = NULL;
813 /* Ask the user for the folder name */
814 dialog = gtk_dialog_new_with_buttons (dialog_title,
816 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
817 _("mcen_bd_dialog_ok"),
819 _("mcen_bd_dialog_cancel"),
823 /* Add accept button (with unsensitive handler) */
824 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
825 accept_btn = GTK_WIDGET (buttons->next->data);
826 /* Create label and entry */
827 label = gtk_label_new (label_text);
828 /* TODO: check that the suggested name does not exist */
829 /* We set 21 as maximum because we want to show WID-INF036
830 when the user inputs more that 20 */
831 entry = gtk_entry_new_with_max_length (21);
833 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
835 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
836 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
838 /* Connect to the response method to avoid closing the dialog
839 when an invalid name is selected*/
840 g_signal_connect (dialog,
842 G_CALLBACK (on_response),
845 /* Track entry changes */
846 g_signal_connect (entry,
848 G_CALLBACK (entry_insert_text),
850 g_signal_connect (entry,
852 G_CALLBACK (entry_changed),
855 /* Create the hbox */
856 hbox = gtk_hbox_new (FALSE, 12);
857 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
858 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
860 /* Add hbox to dialog */
861 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
862 hbox, FALSE, FALSE, 0);
864 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
865 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
867 result = gtk_dialog_run (GTK_DIALOG(dialog));
868 if (result == GTK_RESPONSE_ACCEPT)
869 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
871 gtk_widget_destroy (dialog);
873 while (gtk_events_pending ())
874 gtk_main_iteration ();
880 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
881 TnyFolderStore *parent_folder,
882 gchar *suggested_name,
885 gchar *real_suggested_name = NULL;
888 if(suggested_name == NULL)
890 const gchar *default_name = _("mcen_ia_default_folder_name");
894 for(i = 0; i < 100; ++ i) {
895 gboolean exists = FALSE;
897 sprintf(num_str, "%.2u", i);
900 real_suggested_name = g_strdup (default_name);
902 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
904 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
911 g_free (real_suggested_name);
914 /* Didn't find a free number */
916 real_suggested_name = g_strdup (default_name);
918 real_suggested_name = suggested_name;
921 result = modest_platform_run_folder_name_dialog (parent_window,
923 _("mcen_ti_new_folder"),
924 _("mcen_fi_new_folder_name"),
927 if (suggested_name == NULL)
928 g_free(real_suggested_name);
934 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
935 TnyFolderStore *parent_folder,
936 const gchar *suggested_name,
939 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
941 return modest_platform_run_folder_name_dialog (parent_window,
943 _HL("ckdg_ti_rename_folder"),
944 _HL("ckdg_fi_rename_name"),
952 on_destroy_dialog (GtkDialog *dialog)
954 gtk_widget_destroy (GTK_WIDGET(dialog));
955 if (gtk_events_pending ())
956 gtk_main_iteration ();
960 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
961 const gchar *message)
966 dialog = hildon_note_new_confirmation (parent_window, message);
967 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
968 GTK_WINDOW (dialog));
970 response = gtk_dialog_run (GTK_DIALOG (dialog));
972 on_destroy_dialog (GTK_DIALOG(dialog));
974 while (gtk_events_pending ())
975 gtk_main_iteration ();
981 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
982 const gchar *message,
983 const gchar *button_accept,
984 const gchar *button_cancel)
989 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
990 button_accept, GTK_RESPONSE_ACCEPT,
991 button_cancel, GTK_RESPONSE_CANCEL,
993 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
994 GTK_WINDOW (dialog));
996 response = gtk_dialog_run (GTK_DIALOG (dialog));
998 on_destroy_dialog (GTK_DIALOG(dialog));
1000 while (gtk_events_pending ())
1001 gtk_main_iteration ();
1007 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
1008 const gchar *message)
1013 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1014 _("mcen_bd_yes"), GTK_RESPONSE_YES,
1015 _("mcen_bd_no"), GTK_RESPONSE_NO,
1017 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
1018 response = gtk_dialog_run (GTK_DIALOG (dialog));
1020 on_destroy_dialog (GTK_DIALOG(dialog));
1022 while (gtk_events_pending ())
1023 gtk_main_iteration ();
1031 modest_platform_run_information_dialog (GtkWindow *parent_window,
1032 const gchar *message)
1036 note = hildon_note_new_information (parent_window, message);
1037 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1040 g_signal_connect_swapped (note,
1042 G_CALLBACK (on_destroy_dialog),
1045 gtk_widget_show_all (note);
1050 typedef struct _ConnectAndWaitData {
1052 GMainLoop *wait_loop;
1053 gboolean has_callback;
1055 } ConnectAndWaitData;
1059 quit_wait_loop (TnyAccount *account,
1060 ConnectAndWaitData *data)
1062 /* Set the has_callback to TRUE (means that the callback was
1063 executed and wake up every code waiting for cond to be
1065 g_mutex_lock (data->mutex);
1066 data->has_callback = TRUE;
1067 if (data->wait_loop)
1068 g_main_loop_quit (data->wait_loop);
1069 g_mutex_unlock (data->mutex);
1073 on_connection_status_changed (TnyAccount *account,
1074 TnyConnectionStatus status,
1077 TnyConnectionStatus conn_status;
1078 ConnectAndWaitData *data;
1080 /* Ignore if reconnecting or disconnected */
1081 conn_status = tny_account_get_connection_status (account);
1082 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1083 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1086 /* Remove the handler */
1087 data = (ConnectAndWaitData *) user_data;
1088 g_signal_handler_disconnect (account, data->handler);
1090 /* Quit from wait loop */
1091 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1095 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1100 /* Quit from wait loop */
1101 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1105 modest_platform_connect_and_wait (GtkWindow *parent_window,
1106 TnyAccount *account)
1108 ConnectAndWaitData *data = NULL;
1109 gboolean device_online;
1111 TnyConnectionStatus conn_status;
1112 gboolean user_requested;
1114 device = modest_runtime_get_device();
1115 device_online = tny_device_is_online (device);
1117 /* Whether the connection is user requested or automatically
1118 requested, for example via D-Bus */
1119 user_requested = (parent_window) ? TRUE : FALSE;
1121 /* If there is no account check only the device status */
1126 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1127 NULL, user_requested);
1130 /* Return if the account is already connected */
1131 conn_status = tny_account_get_connection_status (account);
1132 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1135 /* Create the helper */
1136 data = g_slice_new0 (ConnectAndWaitData);
1137 data->mutex = g_mutex_new ();
1138 data->has_callback = FALSE;
1140 /* Connect the device */
1141 if (!device_online) {
1142 /* Track account connection status changes */
1143 data->handler = g_signal_connect (account, "connection-status-changed",
1144 G_CALLBACK (on_connection_status_changed),
1146 /* Try to connect the device */
1147 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1148 NULL, user_requested);
1150 /* If the device connection failed then exit */
1151 if (!device_online && data->handler)
1154 /* Force a reconnection of the account */
1155 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1156 on_tny_camel_account_set_online_cb, data);
1159 /* Wait until the callback is executed */
1160 g_mutex_lock (data->mutex);
1161 if (!data->has_callback) {
1162 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1163 gdk_threads_leave ();
1164 g_mutex_unlock (data->mutex);
1165 g_main_loop_run (data->wait_loop);
1166 g_mutex_lock (data->mutex);
1167 gdk_threads_enter ();
1169 g_mutex_unlock (data->mutex);
1173 if (g_signal_handler_is_connected (account, data->handler))
1174 g_signal_handler_disconnect (account, data->handler);
1175 g_mutex_free (data->mutex);
1176 g_main_loop_unref (data->wait_loop);
1177 g_slice_free (ConnectAndWaitData, data);
1180 conn_status = tny_account_get_connection_status (account);
1181 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1185 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1187 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1188 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1189 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1190 /* This must be a maildir account, which does not require a connection: */
1195 return modest_platform_connect_and_wait (parent_window, account);
1199 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1202 return TRUE; /* Maybe it is something local. */
1204 gboolean result = TRUE;
1205 if (TNY_IS_FOLDER (folder_store)) {
1206 /* Get the folder's parent account: */
1207 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1208 if (account != NULL) {
1209 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1210 g_object_unref (account);
1212 } else if (TNY_IS_ACCOUNT (folder_store)) {
1213 /* Use the folder store as an account: */
1214 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1221 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1222 ModestSortDialogType type)
1224 GtkWidget *dialog = NULL;
1227 dialog = hildon_sort_dialog_new (parent_window);
1228 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1229 GTK_WINDOW (dialog));
1231 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1232 "applications_email_sort",
1233 modest_maemo_utils_get_osso_context());
1235 /* Fill sort keys */
1237 case MODEST_SORT_HEADERS:
1238 launch_sort_headers_dialog (parent_window,
1239 HILDON_SORT_DIALOG(dialog));
1244 on_destroy_dialog (GTK_DIALOG(dialog));
1249 modest_platform_set_update_interval (guint minutes)
1251 #ifdef MODEST_HAVE_LIBALARM
1253 ModestConf *conf = modest_runtime_get_conf ();
1257 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1259 /* Delete any existing alarm,
1260 * because we will replace it: */
1262 if (alarm_event_del(alarm_cookie) != 1)
1263 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1265 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1268 /* 0 means no updates: */
1273 /* Register alarm: */
1275 /* Set the interval in alarm_event_t structure: */
1276 alarm_event_t *event = g_new0(alarm_event_t, 1);
1277 event->alarm_time = minutes * 60; /* seconds */
1279 /* Set recurrence every few minutes: */
1280 event->recurrence = minutes;
1281 event->recurrence_count = -1; /* Means infinite */
1283 /* Specify what should happen when the alarm happens:
1284 * It should call this D-Bus method: */
1286 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1287 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1288 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1289 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1291 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1292 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1293 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1294 * This is why we want to use the Alarm API instead of just g_timeout_add().
1295 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1297 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1299 alarm_cookie = alarm_event_add (event);
1302 alarm_event_free (event);
1304 /* Store the alarm ID in GConf, so we can remove it later:
1305 * This is apparently valid between application instances. */
1306 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1308 if (!alarm_cookie) {
1310 const alarm_error_t alarm_error = alarmd_get_error ();
1311 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1313 /* Give people some clue: */
1314 /* The alarm API should have a function for this: */
1315 if (alarm_error == ALARMD_ERROR_DBUS) {
1316 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1317 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1318 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1319 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1320 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1321 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1322 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1323 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1324 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1325 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1326 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1331 #endif /* MODEST_HAVE_LIBALARM */
1336 modest_platform_on_new_headers_received (TnyList *header_list,
1337 gboolean show_visual)
1339 gboolean play_sound;
1341 /* Check whether or not we should play a sound */
1342 play_sound = modest_conf_get_bool (modest_runtime_get_conf (),
1343 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1347 gboolean screen_on, app_in_foreground;
1348 ModestWindow *main_window;
1350 /* Get the screen status */
1351 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1352 screen_on = modest_main_window_screen_is_on (MODEST_MAIN_WINDOW (main_window));
1354 /* Get the window status */
1355 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1357 /* If the screen is on and the app is in the
1358 foreground we don't show anything */
1359 if (!(screen_on && app_in_foreground)) {
1362 hildon_play_system_sound (MODEST_NEW_MAIL_SOUND_FILE);
1364 /* Activate LED. This must be deactivated by
1365 modest_platform_remove_new_mail_notifications */
1366 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1370 MCE_ACTIVATE_LED_PATTERN,
1372 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1375 /* We do a return here to avoid indentation with an else */
1379 #ifdef MODEST_HAVE_HILDON_NOTIFY
1380 HildonNotification *notification;
1382 GSList *notifications_list = NULL;
1384 /* Get previous notifications ids */
1385 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1386 MODEST_CONF_NOTIFICATION_IDS,
1387 MODEST_CONF_VALUE_INT, NULL);
1389 iter = tny_list_create_iterator (header_list);
1390 while (!tny_iterator_is_done (iter)) {
1391 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1392 const gchar *display_date;
1393 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1394 TnyFolder *folder = tny_header_get_folder (header);
1395 gboolean first_notification = TRUE;
1398 /* constant string, don't free */
1399 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1401 display_address = g_strdup(tny_header_get_from (header));
1402 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1404 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1405 notification = hildon_notification_new (summary,
1406 tny_header_get_subject (header),
1407 "qgn_list_messagin",
1409 /* Create the message URL */
1410 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1411 tny_header_get_uid (header));
1413 hildon_notification_add_dbus_action(notification,
1416 MODEST_DBUS_SERVICE,
1419 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1423 /* Play sound if the user wants. Show the LED
1424 pattern. Show and play just one */
1425 if (G_UNLIKELY (first_notification)) {
1426 first_notification = FALSE;
1428 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1429 "sound-file", MODEST_NEW_MAIL_SOUND_FILE);
1432 /* Set the led pattern */
1433 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1435 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1437 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1440 /* Notify. We need to do this in an idle because this function
1441 could be called from a thread */
1442 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1444 /* Save id in the list */
1445 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1446 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1447 /* We don't listen for the "closed" signal, because we
1448 don't care about if the notification was removed or
1449 not to store the list in gconf */
1451 /* Free & carry on */
1452 g_free (display_address);
1455 g_object_unref (folder);
1456 g_object_unref (header);
1457 tny_iterator_next (iter);
1459 g_object_unref (iter);
1462 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1463 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1465 g_slist_free (notifications_list);
1467 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1471 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1474 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1478 MCE_DEACTIVATE_LED_PATTERN,
1480 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1485 #ifdef MODEST_HAVE_HILDON_NOTIFY
1486 GSList *notif_list = NULL;
1488 /* Get previous notifications ids */
1489 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1490 MODEST_CONF_NOTIFICATION_IDS,
1491 MODEST_CONF_VALUE_INT, NULL);
1493 while (notif_list) {
1495 NotifyNotification *notif;
1497 /* Nasty HACK to remove the notifications, set the id
1498 of the existing ones and then close them */
1499 notif_id = GPOINTER_TO_INT(notif_list->data);
1500 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1501 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1503 /* Close the notification, note that some ids could be
1504 already invalid, but we don't care because it does
1506 notify_notification_close(notif, NULL);
1507 g_object_unref(notif);
1509 /* Delete the link, it's like going to the next */
1510 notif_list = g_slist_delete_link (notif_list, notif_list);
1514 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1515 notif_list, MODEST_CONF_VALUE_INT, NULL);
1517 g_slist_free (notif_list);
1519 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1525 modest_platform_get_global_settings_dialog ()
1527 return modest_maemo_global_settings_dialog_new ();
1531 modest_platform_show_help (GtkWindow *parent_window,
1532 const gchar *help_id)
1534 osso_return_t result;
1535 g_return_if_fail (help_id);
1537 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1538 help_id, HILDON_HELP_SHOW_DIALOG);
1540 if (result != OSSO_OK) {
1542 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1543 hildon_banner_show_information (GTK_WIDGET (parent_window),
1551 modest_platform_show_search_messages (GtkWindow *parent_window)
1553 osso_return_t result = OSSO_ERROR;
1555 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1556 "osso_global_search",
1557 "search_email", NULL, DBUS_TYPE_INVALID);
1559 if (result != OSSO_OK) {
1560 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1565 modest_platform_show_addressbook (GtkWindow *parent_window)
1567 osso_return_t result = OSSO_ERROR;
1569 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1571 "top_application", NULL, DBUS_TYPE_INVALID);
1573 if (result != OSSO_OK) {
1574 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1579 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1581 GtkWidget *widget = modest_folder_view_new (query);
1583 /* Show one account by default */
1584 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1585 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1588 /* Restore settings */
1589 modest_widget_memory_restore (modest_runtime_get_conf(),
1591 MODEST_CONF_FOLDER_VIEW_KEY);
1597 modest_platform_information_banner (GtkWidget *parent,
1598 const gchar *icon_name,
1601 hildon_banner_show_information (parent, icon_name, text);
1605 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1606 const gchar *icon_name,
1611 banner = hildon_banner_show_information (parent, icon_name, text);
1612 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1616 modest_platform_animation_banner (GtkWidget *parent,
1617 const gchar *animation_name,
1620 GtkWidget *inf_note = NULL;
1622 g_return_val_if_fail (text != NULL, NULL);
1624 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1632 TnyAccount *account;
1635 } CheckAccountIdleData;
1637 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1640 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1642 gboolean stop_trying = FALSE;
1643 g_return_val_if_fail (data && data->account, FALSE);
1645 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1646 tny_account_get_connection_status (data->account));
1648 if (data && data->account &&
1649 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1650 * after which the account is likely to be usable, or never likely to be usable soon: */
1651 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1653 data->is_online = TRUE;
1657 /* Give up if we have tried too many times: */
1658 if (data->count_tries >= NUMBER_OF_TRIES) {
1661 /* Wait for another timeout: */
1662 ++(data->count_tries);
1667 /* Allow the function that requested this idle callback to continue: */
1669 g_main_loop_quit (data->loop);
1672 g_object_unref (data->account);
1674 return FALSE; /* Don't call this again. */
1676 return TRUE; /* Call this timeout callback again. */
1680 /* Return TRUE immediately if the account is already online,
1681 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1682 * soon as the account is online, or FALSE if the account does
1683 * not become online in the NUMBER_OF_TRIES seconds.
1684 * This is useful when the D-Bus method was run immediately after
1685 * the application was started (when using D-Bus activation),
1686 * because the account usually takes a short time to go online.
1687 * The return value is maybe not very useful.
1690 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1692 g_return_val_if_fail (account, FALSE);
1694 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1696 if (!tny_device_is_online (modest_runtime_get_device())) {
1697 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1701 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1702 * so we avoid wait unnecessarily: */
1703 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1704 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1708 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1709 __FUNCTION__, tny_account_get_connection_status (account));
1711 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1712 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1713 * we want to avoid. */
1714 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1717 /* This blocks on the result: */
1718 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1719 data->is_online = FALSE;
1720 data->account = account;
1721 g_object_ref (data->account);
1722 data->count_tries = 0;
1724 GMainContext *context = NULL; /* g_main_context_new (); */
1725 data->loop = g_main_loop_new (context, FALSE /* not running */);
1727 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1729 /* This main loop will run until the idle handler has stopped it: */
1730 g_main_loop_run (data->loop);
1732 g_main_loop_unref (data->loop);
1733 /* g_main_context_unref (context); */
1735 g_slice_free (CheckAccountIdleData, data);
1737 return data->is_online;
1743 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1745 /* GTK_RESPONSE_HELP means we need to show the certificate */
1746 if (response_id == GTK_RESPONSE_HELP) {
1750 /* Do not close the dialog */
1751 g_signal_stop_emission_by_name (dialog, "response");
1753 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1754 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1755 gtk_dialog_run (GTK_DIALOG(note));
1756 gtk_widget_destroy (note);
1762 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1763 const gchar *certificate)
1767 ModestWindow *main_win;
1769 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1770 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1775 /* don't create it */
1776 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1777 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1780 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1783 note = hildon_note_new_confirmation_add_buttons (
1784 GTK_WINDOW(main_win),
1786 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1787 _("mcen_bd_view"), GTK_RESPONSE_HELP, /* abusing this... */
1788 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1791 g_signal_connect (G_OBJECT(note), "response",
1792 G_CALLBACK(on_cert_dialog_response),
1793 (gpointer) certificate);
1795 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1797 response = gtk_dialog_run(GTK_DIALOG(note));
1799 on_destroy_dialog (GTK_DIALOG(note));
1802 return response == GTK_RESPONSE_OK;
1806 modest_platform_run_alert_dialog (const gchar* prompt,
1807 gboolean is_question)
1809 ModestWindow *main_win;
1811 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1812 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1813 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1814 return is_question ? FALSE : TRUE;
1817 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1818 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1820 gboolean retval = TRUE;
1822 /* The Tinymail documentation says that we should show Yes and No buttons,
1823 * when it is a question.
1824 * Obviously, we need tinymail to use more specific error codes instead,
1825 * so we know what buttons to show. */
1826 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1828 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1829 GTK_WINDOW (dialog));
1831 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1832 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1834 on_destroy_dialog (GTK_DIALOG(dialog));
1836 /* Just show the error text and use the default response: */
1837 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1845 GtkWindow *parent_window;
1846 ModestConnectedPerformer callback;
1847 TnyAccount *account;
1854 on_went_online_info_free (OnWentOnlineInfo *info)
1856 /* And if we cleanup, we DO cleanup :-) */
1859 g_object_unref (info->device);
1862 if (info->parent_window)
1863 g_object_unref (info->parent_window);
1865 g_object_unref (info->account);
1867 g_slice_free (OnWentOnlineInfo, info);
1869 /* We're done ... */
1875 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1877 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1879 /* Now it's really time to callback to the caller. If going online didn't succeed,
1880 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1881 * canceled will be set. Etcetera etcetera. */
1883 if (info->callback) {
1884 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1887 /* This is our last call, we must cleanup here if we didn't yet do that */
1888 on_went_online_info_free (info);
1895 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1897 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1898 info->iap = g_strdup (iap_id);
1900 if (canceled || err || !info->account) {
1902 /* If there's a problem or if there's no account (then that's it for us, we callback
1903 * the caller's callback now. He'll have to handle err or canceled, of course.
1904 * We are not really online, as the account is not really online here ... */
1906 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1907 * this info. We don't cleanup err, Tinymail does that! */
1909 if (info->callback) {
1911 /* info->account can be NULL here, this means that the user did not
1912 * provide a nice account instance. We'll assume that the user knows
1913 * what he's doing and is happy with just the device going online.
1915 * We can't do magic, we don't know what account the user wants to
1916 * see going online. So just the device goes online, end of story */
1918 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1921 } else if (info->account) {
1923 /* If there's no problem and if we have an account, we'll put the account
1924 * online too. When done, the callback of bringing the account online
1925 * will callback the caller's callback. This is the most normal case. */
1927 info->device = TNY_DEVICE (g_object_ref (device));
1929 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1930 on_account_went_online, info);
1932 /* The on_account_went_online cb frees up the info, go look if you
1933 * don't believe me! (so we return here) */
1938 /* We cleanup if we are not bringing the account online too */
1939 on_went_online_info_free (info);
1945 modest_platform_connect_and_perform (GtkWindow *parent_window,
1946 TnyAccount *account,
1947 ModestConnectedPerformer callback,
1950 gboolean device_online;
1952 TnyConnectionStatus conn_status;
1953 OnWentOnlineInfo *info;
1954 gboolean user_requested;
1956 device = modest_runtime_get_device();
1957 device_online = tny_device_is_online (device);
1959 /* Whether the connection is user requested or automatically
1960 requested, for example via D-Bus */
1961 user_requested = (parent_window) ? TRUE : FALSE;
1963 /* If there is no account check only the device status */
1966 if (device_online) {
1968 /* We promise to instantly perform the callback, so ... */
1970 callback (FALSE, NULL, parent_window, account, user_data);
1975 info = g_slice_new0 (OnWentOnlineInfo);
1978 info->device = NULL;
1979 info->account = NULL;
1982 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1984 info->parent_window = NULL;
1985 info->user_data = user_data;
1986 info->callback = callback;
1988 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1989 user_requested, on_conic_device_went_online,
1992 /* We'll cleanup in on_conic_device_went_online */
1995 /* The other code has no more reason to run. This is all that we can do for the
1996 * caller (he should have given us a nice and clean account instance!). We
1997 * can't do magic, we don't know what account he intends to bring online. So
1998 * we'll just bring the device online (and await his false bug report). */
2004 /* Return if the account is already connected */
2006 conn_status = tny_account_get_connection_status (account);
2007 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2009 /* We promise to instantly perform the callback, so ... */
2011 callback (FALSE, NULL, parent_window, account, user_data);
2017 /* Else, we are in a state that requires that we go online before we
2018 * call the caller's callback. */
2020 info = g_slice_new0 (OnWentOnlineInfo);
2022 info->device = NULL;
2024 info->account = TNY_ACCOUNT (g_object_ref (account));
2027 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2029 info->parent_window = NULL;
2031 /* So we'll put the callback away for later ... */
2033 info->user_data = user_data;
2034 info->callback = callback;
2036 if (!device_online) {
2038 /* If also the device is offline, then we connect both the device
2039 * and the account */
2041 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2042 user_requested, on_conic_device_went_online,
2047 /* If the device is online, we'll just connect the account */
2049 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2050 on_account_went_online, info);
2053 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2054 * in both situations, go look if you don't believe me! */
2060 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2061 TnyFolderStore *folder_store,
2062 ModestConnectedPerformer callback,
2065 TnyAccount *account = NULL;
2067 if (!folder_store) {
2068 /* We promise to instantly perform the callback, so ... */
2070 callback (FALSE, NULL, parent_window, NULL, user_data);
2074 /* Original comment: Maybe it is something local. */
2075 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
2077 } else if (TNY_IS_FOLDER (folder_store)) {
2078 /* Get the folder's parent account: */
2079 account = tny_folder_get_account(TNY_FOLDER (folder_store));
2080 } else if (TNY_IS_ACCOUNT (folder_store)) {
2081 /* Use the folder store as an account: */
2082 account = TNY_ACCOUNT (folder_store);
2085 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2086 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
2087 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
2089 /* This IS a local account like a maildir account, which does not require
2090 * a connection. (original comment had a vague assumption in its language
2091 * usage. There's no assuming needed, this IS what it IS: a local account), */
2093 /* We promise to instantly perform the callback, so ... */
2095 callback (FALSE, NULL, parent_window, account, user_data);
2102 modest_platform_connect_and_perform (parent_window, account, callback, user_data);
2108 modest_platform_get_account_settings_dialog (ModestAccountSettings *settings)
2110 ModestAccountSettingsDialog *dialog = modest_account_settings_dialog_new ();
2112 modest_account_settings_dialog_set_account (dialog, settings);
2113 return GTK_WIDGET (dialog);
2117 modest_platform_get_account_settings_wizard ()
2119 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2121 return GTK_WIDGET (dialog);