1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "maemo/modest-maemo-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <osso-helplib.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <libosso-abook/osso-abook.h>
42 #include <maemo/modest-osso-autosave-callbacks.h>
44 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
45 #include <tny-maemo-conic-device.h>
46 #include <tny-simple-list.h>
47 #include <tny-folder.h>
48 #include <tny-camel-imap-store-account.h>
49 #include <tny-camel-pop-store-account.h>
50 #include <gtk/gtkicontheme.h>
51 #include <gtk/gtkmenuitem.h>
52 #include <gtk/gtkmain.h>
53 #include <modest-text-utils.h>
57 #define HILDON_OSSO_URI_ACTION "uri-action"
58 #define URI_ACTION_COPY "copy:"
60 static osso_context_t *osso_context = NULL;
63 on_modest_conf_update_interval_changed (ModestConf* self,
65 ModestConfEvent event,
66 ModestConfNotificationId id,
69 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
70 const guint update_interval_minutes =
71 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
72 modest_platform_set_update_interval (update_interval_minutes);
77 modest_platform_init (int argc, char *argv[])
79 osso_hw_state_t hw_state = { 0 };
83 osso_initialize(PACKAGE,PACKAGE_VERSION,
86 g_printerr ("modest: failed to acquire osso context\n");
90 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
91 g_printerr ("modest: could not get dbus connection\n");
96 /* Add a D-Bus handler to be used when the main osso-rpc
97 * D-Bus handler has not handled something.
98 * We use this for D-Bus methods that need to use more complex types
99 * than osso-rpc supports.
101 if (!dbus_connection_add_filter (con,
102 modest_dbus_req_filter,
106 g_printerr ("modest: Could not add D-Bus filter\n");
110 /* Register our simple D-Bus callbacks, via the osso API: */
111 osso_return_t result = osso_rpc_set_cb_f(osso_context,
115 modest_dbus_req_handler, NULL /* user_data */);
116 if (result != OSSO_OK) {
117 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
121 /* Add handler for Exit D-BUS messages.
122 * Not used because osso_application_set_exit_cb() is deprecated and obsolete:
123 result = osso_application_set_exit_cb(osso_context,
124 modest_dbus_exit_event_handler,
126 if (result != OSSO_OK) {
127 g_print("Error setting exit callback (%d)\n", result);
132 /* Register hardware event dbus callback: */
133 hw_state.shutdown_ind = TRUE;
134 osso_hw_set_event_cb(osso_context, NULL,/*&hw_state*/ modest_osso_cb_hw_state_handler, NULL);
136 /* Register osso auto-save callbacks: */
137 result = osso_application_set_autosave_cb (osso_context,
138 modest_on_osso_application_autosave, NULL /* user_data */);
139 if (result != OSSO_OK) {
140 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
145 /* Make sure that the update interval is changed whenever its gconf key
147 /* CAUTION: we're not using here the
148 modest_conf_listen_to_namespace because we know that there
149 are other parts of Modest listening for this namespace, so
150 we'll receive the notifications anyway. We basically do not
151 use it because there is no easy way to do the
152 modest_conf_forget_namespace */
153 ModestConf *conf = modest_runtime_get_conf ();
154 g_signal_connect (G_OBJECT(conf),
156 G_CALLBACK (on_modest_conf_update_interval_changed),
159 /* Get the initial update interval from gconf: */
160 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
161 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
163 /* initialize the addressbook */
164 if (!osso_abook_init (&argc, &argv, osso_context)) {
165 g_printerr ("modest: failed to initialized addressbook\n");
173 modest_platform_get_new_device (void)
175 return TNY_DEVICE (tny_maemo_conic_device_new ());
180 guess_mime_type_from_name (const gchar* name)
184 const static gchar* octet_stream= "application/octet-stream";
185 const static gchar* mime_map[][2] = {
186 { "pdf", "application/pdf"},
187 { "doc", "application/msword"},
188 { "xls", "application/excel"},
189 { "png", "image/png" },
190 { "gif", "image/gif" },
191 { "jpg", "image/jpeg"},
192 { "jpeg", "image/jpeg"},
193 { "mp3", "audio/mp3" }
199 ext = g_strrstr (name, ".");
203 for (i = 0; i != G_N_ELEMENTS(mime_map); ++i) {
204 if (!g_ascii_strcasecmp (mime_map[i][0], ext + 1)) /* +1: ignore '.'*/
205 return mime_map[i][1];
212 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
213 gchar **effective_mime_type)
215 GString *mime_str = NULL;
216 gchar *icon_name = NULL;
217 gchar **icons, **cursor;
219 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
220 mime_str = g_string_new (guess_mime_type_from_name(name));
222 mime_str = g_string_new (mime_type);
223 g_string_ascii_down (mime_str);
226 #ifdef MODEST_HAVE_OSSO_MIME
227 icons = osso_mime_get_icon_names (mime_str->str, NULL);
229 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
230 #endif /*MODEST_HAVE_OSSO_MIME*/
231 for (cursor = icons; cursor; ++cursor) {
232 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
233 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
234 icon_name = g_strdup ("qgn_list_messagin");
236 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
237 icon_name = g_strdup (*cursor);
243 if (effective_mime_type)
244 *effective_mime_type = g_string_free (mime_str, FALSE);
246 g_string_free (mime_str, TRUE);
254 #ifdef MODEST_HAVE_OSSO_MIME
256 modest_platform_activate_uri (const gchar *uri)
258 OssoURIAction *action;
259 gboolean result = FALSE;
260 GSList *actions, *iter = NULL;
263 g_return_val_if_fail (uri, FALSE);
267 /* the default action should be email */
268 scheme = osso_uri_get_scheme_from_uri (uri, NULL);
269 actions = osso_uri_get_actions (scheme, NULL);
271 for (iter = actions; iter; iter = g_slist_next (iter)) {
272 action = (OssoURIAction*) iter->data;
273 if (action && strcmp (osso_uri_action_get_name (action), "uri_link_compose_email") == 0) {
275 result = osso_uri_open (uri, action, &err);
276 if (!result && err) {
277 g_printerr ("modest: modest_platform_activate_uri : %s",
278 err->message ? err->message : "unknown error");
285 /* if we could open it with email, try something else */
287 result = osso_uri_open (uri, NULL, NULL);
291 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
295 #else /* !MODEST_HAVE_OSSO_MIME*/
298 modest_platform_activate_uri (const gchar *uri)
300 HildonURIAction *action;
301 gboolean result = FALSE;
302 GSList *actions, *iter = NULL;
305 g_return_val_if_fail (uri, FALSE);
309 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
310 actions = hildon_uri_get_actions (scheme, NULL);
312 for (iter = actions; iter; iter = g_slist_next (iter)) {
313 action = (HildonURIAction*) iter->data;
314 if (action && strcmp (hildon_uri_action_get_service (action), "com.nokia.modest") == 0) {
316 result = hildon_uri_open (uri, action, &err);
317 if (!result && err) {
318 g_printerr ("modest: modest_platform_activate_uri : %s",
319 err->message ? err->message : "unknown error");
326 /* if we could open it with email, try something else */
328 result = hildon_uri_open (uri, NULL, NULL);
331 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
337 #endif /* MODEST_HAVE_OSSO_MIME*/
340 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
344 gchar *uri_path = NULL;
345 GString *mime_str = NULL;
347 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
348 mime_str = g_string_new (guess_mime_type_from_name(path));
350 mime_str = g_string_new (mime_type);
351 g_string_ascii_down (mime_str);
354 uri_path = g_strconcat ("file://", path, NULL);
356 con = osso_get_dbus_connection (osso_context);
357 #ifdef MODEST_HAVE_OSSO_MIME
358 result = osso_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
360 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
361 #endif /*MODEST_HAVE_OSSO_MIME*/
362 g_string_free (mime_str, TRUE);
365 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
372 } ModestPlatformPopupInfo;
375 delete_uri_popup (GtkWidget *menu,
379 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
381 g_free (popup_info->uri);
382 #ifdef MODEST_HAVE_OSSO_MIME
383 osso_uri_free_actions (popup_info->actions);
385 hildon_uri_free_actions (popup_info->actions);
386 #endif /*MODEST_HAVE_OSSO_MIME*/
391 activate_uri_popup_item (GtkMenuItem *menu_item,
395 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
396 const gchar* action_name;
398 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
400 g_printerr ("modest: no action name defined\n");
404 /* special handling for the copy menu item -- copy the uri to the clipboard */
405 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
406 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
407 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
408 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
410 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
411 action_name += strlen ("mailto:");
413 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
414 return; /* we're done */
417 /* now, the real uri-actions... */
418 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
419 #ifdef MODEST_HAVE_OSSO_MIME
420 OssoURIAction *action = (OssoURIAction *) node->data;
421 if (strcmp (action_name, osso_uri_action_get_name (action))==0) {
422 osso_uri_open (popup_info->uri, action, NULL);
426 HildonURIAction *action = (HildonURIAction *) node->data;
427 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
428 hildon_uri_open (popup_info->uri, action, NULL);
431 #endif /*MODEST_HAVE_OSSO_MIME*/
436 modest_platform_show_uri_popup (const gchar *uri)
439 GSList *actions_list;
444 #ifdef MODEST_HAVE_OSSO_MIME
445 scheme = osso_uri_get_scheme_from_uri (uri, NULL);
446 actions_list = osso_uri_get_actions (scheme, NULL);
448 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
449 actions_list = hildon_uri_get_actions (scheme, NULL);
450 #endif /* MODEST_HAVE_OSSO_MIME */
451 if (actions_list != NULL) {
453 GtkWidget *menu = gtk_menu_new ();
454 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
456 popup_info->actions = actions_list;
457 popup_info->uri = g_strdup (uri);
459 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
460 GtkWidget *menu_item;
461 const gchar *action_name;
462 const gchar *translation_domain;
463 #ifdef MODEST_HAVE_OSSO_MIME
464 OssoURIAction *action = (OssoURIAction *) node->data;
465 action_name = osso_uri_action_get_name (action);
466 translation_domain = osso_uri_action_get_translation_domain (action);
467 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain,action_name));
468 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);
469 /* hack, we add it as a gobject property*/
470 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
473 if (osso_uri_is_default_action (action, NULL)) {
474 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
476 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
479 HildonURIAction *action = (HildonURIAction *) node->data;
480 action_name = hildon_uri_action_get_name (action);
481 translation_domain = hildon_uri_action_get_translation_domain (action);
482 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
483 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
484 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
487 if (hildon_uri_is_default_action (action, NULL)) {
488 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
490 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
492 #endif /*MODEST_HAVE_OSSO_MIME*/
493 gtk_widget_show (menu_item);
496 /* always add the copy item */
497 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
498 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
499 g_strconcat (URI_ACTION_COPY, uri, NULL),
501 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
502 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
503 gtk_widget_show (menu_item);
506 /* and what to do when the link is deleted */
507 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
508 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
511 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
520 modest_platform_get_icon (const gchar *name)
523 GdkPixbuf* pixbuf = NULL;
524 GtkIconTheme *current_theme = NULL;
526 g_return_val_if_fail (name, NULL);
528 #if 0 /* do we still need this? */
529 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
530 pixbuf = gdk_pixbuf_new_from_file (name, &err);
532 g_printerr ("modest: error loading icon '%s': %s\n",
540 current_theme = gtk_icon_theme_get_default ();
541 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
542 GTK_ICON_LOOKUP_NO_SVG,
545 g_printerr ("modest: error loading theme icon '%s': %s\n",
553 modest_platform_get_app_name (void)
555 return _("mcen_ap_name");
559 entry_insert_text (GtkEditable *editable,
568 chars = gtk_editable_get_chars (editable, 0, -1);
569 chars_length = g_utf8_strlen (chars, -1);
571 /* Show WID-INF036 */
572 if (chars_length >= 20) {
573 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
574 _CS("ckdg_ib_maximum_characters_reached"));
576 GtkWidget *ok_button;
579 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (data)->action_area));
580 ok_button = GTK_WIDGET (buttons->next->data);
582 gtk_widget_set_sensitive (ok_button,
583 modest_text_utils_validate_folder_name (chars));
584 g_list_free (buttons);
586 /* Write the text in the entry */
587 g_signal_handlers_block_by_func (editable,
588 (gpointer) entry_insert_text, data);
589 gtk_editable_insert_text (editable, text, length, position);
590 g_signal_handlers_unblock_by_func (editable,
591 (gpointer) entry_insert_text, data);
593 /* Do not allow further processing */
594 g_signal_stop_emission_by_name (editable, "insert_text");
598 entry_changed (GtkEditable *editable,
602 GtkWidget *ok_button;
605 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
606 ok_button = GTK_WIDGET (buttons->next->data);
608 chars = gtk_editable_get_chars (editable, 0, -1);
609 g_return_if_fail (chars != NULL);
612 if (g_utf8_strlen (chars,-1) >= 21)
613 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
614 _CS("ckdg_ib_maximum_characters_reached"));
616 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
619 g_list_free (buttons);
624 launch_sort_headers_dialog (GtkWindow *parent_window,
625 HildonSortDialog *dialog)
627 ModestHeaderView *header_view = NULL;
629 GtkSortType sort_type;
631 gint default_key = 0;
633 gboolean outgoing = FALSE;
634 gint current_sort_colid = -1;
635 GtkSortType current_sort_type;
636 gint attachments_sort_id;
637 gint priority_sort_id;
638 GtkTreeSortable *sortable;
640 /* Get header window */
641 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
642 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
643 MODEST_WIDGET_TYPE_HEADER_VIEW));
645 if (!header_view) return;
647 /* Add sorting keys */
648 cols = modest_header_view_get_columns (header_view);
649 if (cols == NULL) return;
650 int sort_model_ids[6];
654 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
655 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
657 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
659 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
660 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
662 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
663 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
666 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
668 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
669 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
671 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
672 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
674 default_key = sort_key;
676 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
677 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
679 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
681 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
683 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
684 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
685 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
686 attachments_sort_id = sort_key;
688 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
689 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
690 sort_ids[sort_key] = 0;
692 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
693 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
694 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY;
695 priority_sort_id = sort_key;
697 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
699 if (!gtk_tree_sortable_get_sort_column_id (sortable,
700 ¤t_sort_colid, ¤t_sort_type)) {
701 hildon_sort_dialog_set_sort_key (dialog, default_key);
702 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
704 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
705 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
706 gpointer flags_sort_type_pointer;
707 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
708 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY)
709 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
711 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
713 gint current_sort_keyid = 0;
714 while (current_sort_keyid < 6) {
715 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
718 current_sort_keyid++;
720 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
724 result = gtk_dialog_run (GTK_DIALOG (dialog));
725 if (result == GTK_RESPONSE_OK) {
726 sort_key = hildon_sort_dialog_get_sort_key (dialog);
727 sort_type = hildon_sort_dialog_get_sort_order (dialog);
728 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
729 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
730 GINT_TO_POINTER (sort_ids[sort_key]));
731 /* This is a hack to make it resort rows always when flag fields are
732 * selected. If we do not do this, changing sort field from priority to
733 * attachments does not work */
734 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
736 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
737 sort_model_ids[sort_key]);
740 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
741 gtk_tree_sortable_sort_column_changed (sortable);
744 modest_widget_memory_save (modest_runtime_get_conf (),
745 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
747 while (gtk_events_pending ())
748 gtk_main_iteration ();
755 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
756 const gchar *dialog_title,
757 const gchar *label_text,
758 const gchar *suggested_name,
761 GtkWidget *accept_btn = NULL;
762 GtkWidget *dialog, *entry, *label, *hbox;
763 GList *buttons = NULL;
766 /* Ask the user for the folder name */
767 dialog = gtk_dialog_new_with_buttons (dialog_title,
769 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
776 /* Add accept button (with unsensitive handler) */
777 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
778 accept_btn = GTK_WIDGET (buttons->next->data);
779 /* Create label and entry */
780 label = gtk_label_new (label_text);
781 /* TODO: check that the suggested name does not exist */
782 /* We set 21 as maximum because we want to show WID-INF036
783 when the user inputs more that 20 */
784 entry = gtk_entry_new_with_max_length (21);
786 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
788 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
789 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
791 /* Track entry changes */
792 g_signal_connect (entry,
794 G_CALLBACK (entry_insert_text),
796 g_signal_connect (entry,
798 G_CALLBACK (entry_changed),
801 /* Create the hbox */
802 hbox = gtk_hbox_new (FALSE, 12);
803 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
804 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
806 /* Add hbox to dialog */
807 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
808 hbox, FALSE, FALSE, 0);
810 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
812 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
813 result = gtk_dialog_run (GTK_DIALOG(dialog));
814 if (result == GTK_RESPONSE_ACCEPT)
815 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
817 gtk_widget_destroy (dialog);
819 while (gtk_events_pending ())
820 gtk_main_iteration ();
826 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
827 TnyFolderStore *parent_folder,
828 gchar *suggested_name,
831 gchar *real_suggested_name = NULL;
834 if(suggested_name == NULL)
836 const gchar *default_name = _("mcen_ia_default_folder_name");
840 for(i = 0; i < 100; ++ i)
842 TnyList *list = tny_simple_list_new ();
843 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
846 sprintf(num_str, "%.2u", i);
849 real_suggested_name = g_strdup (default_name);
851 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
854 tny_folder_store_query_add_item (query, real_suggested_name,
855 TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
857 tny_folder_store_get_folders (parent_folder, list, query, NULL);
859 length = tny_list_get_length (list);
860 g_object_unref (query);
861 g_object_unref (list);
866 g_free (real_suggested_name);
869 /* Didn't find a free number */
871 real_suggested_name = g_strdup (default_name);
875 real_suggested_name = suggested_name;
878 result = modest_platform_run_folder_name_dialog (parent_window,
879 _("mcen_ti_new_folder"),
880 _("mcen_fi_new_folder_name"),
883 if (suggested_name == NULL)
884 g_free(real_suggested_name);
890 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
891 TnyFolderStore *parent_folder,
892 const gchar *suggested_name,
895 return modest_platform_run_folder_name_dialog (parent_window,
896 _("New folder name"),
897 _("Enter new folder name:"),
903 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
904 const gchar *message)
909 dialog = hildon_note_new_confirmation (parent_window, message);
910 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
912 response = gtk_dialog_run (GTK_DIALOG (dialog));
914 gtk_widget_destroy (GTK_WIDGET (dialog));
916 while (gtk_events_pending ())
917 gtk_main_iteration ();
923 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
924 const gchar *message)
929 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
930 _("mcen_bd_yes"), GTK_RESPONSE_YES,
931 _("mcen_bd_no"), GTK_RESPONSE_NO,
933 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
935 response = gtk_dialog_run (GTK_DIALOG (dialog));
937 gtk_widget_destroy (GTK_WIDGET (dialog));
939 while (gtk_events_pending ())
940 gtk_main_iteration ();
946 modest_platform_run_information_dialog (GtkWindow *parent_window,
947 const gchar *message)
951 dialog = hildon_note_new_information (parent_window, message);
953 g_signal_connect_swapped (dialog,
955 G_CALLBACK (gtk_widget_destroy),
958 gtk_widget_show_all (dialog);
969 on_idle_connect_and_wait(gpointer user_data)
971 printf ("DEBUG: %s:\n", __FUNCTION__);
972 TnyDevice *device = modest_runtime_get_device();
973 if (!tny_device_is_online (device)) {
975 tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
979 /* Allow the function that requested this idle callback to continue: */
980 UtilIdleData *data = (UtilIdleData*)user_data;
982 g_main_loop_quit (data->loop);
984 return FALSE; /* Don't call this again. */
987 static gboolean connect_request_in_progress = FALSE;
989 /* This callback is used when connect_and_wait() is already queued as an idle callback.
990 * This can happen because the gtk_dialog_run() for the connection dialog
991 * (at least in the fake scratchbox version) allows idle handlers to keep running.
994 on_idle_wait_for_previous_connect_to_finish(gpointer user_data)
996 gboolean result = FALSE;
997 TnyDevice *device = modest_runtime_get_device();
998 if (tny_device_is_online (device))
999 result = FALSE; /* Stop trying. */
1001 /* Keep trying until connect_request_in_progress is FALSE. */
1002 if (connect_request_in_progress)
1003 result = TRUE; /* Keep trying */
1005 printf ("DEBUG: %s: other idle has finished.\n", __FUNCTION__);
1007 result = FALSE; /* Stop trying, now that a result should be available. */
1011 if (result == FALSE) {
1012 /* Allow the function that requested this idle callback to continue: */
1013 UtilIdleData *data = (UtilIdleData*)user_data;
1015 g_main_loop_quit (data->loop);
1022 set_account_to_online (TnyAccount *account)
1024 /* TODO: This is necessary to prevent a cancel of the password dialog
1025 * from making a restart necessary to be asked the password again,
1026 * but it causes a hang:
1029 if (account && TNY_IS_CAMEL_STORE_ACCOUNT (account)) {
1030 /* Make sure that store accounts are online too,
1031 * because tinymail sets accounts to offline if
1032 * a password dialog is ever cancelled.
1033 * We don't do this for transport accounts because
1034 * a) They fundamentally need network access, so they can't really be offline.
1035 * b) That might cause a transport connection to happen too early.
1037 GError *error = NULL;
1038 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, &error);
1040 g_warning ("%s: tny_camel_account_set_online() returned a GError:\n %s\n",
1041 __FUNCTION__, error->message);
1042 g_error_free (error);
1048 gboolean modest_platform_connect_and_wait (GtkWindow *parent_window, TnyAccount *account)
1050 if (connect_request_in_progress)
1053 printf ("DEBUG: %s:\n", __FUNCTION__);
1054 TnyDevice *device = modest_runtime_get_device();
1056 if (tny_device_is_online (device)) {
1057 printf ("DEBUG: %s: Already online.\n", __FUNCTION__);
1058 set_account_to_online (account);
1062 printf ("DEBUG: %s: tny_device_is_online() returned FALSE\n", __FUNCTION__);
1065 /* This blocks on the result: */
1066 UtilIdleData *data = g_slice_new0 (UtilIdleData);
1068 GMainContext *context = NULL; /* g_main_context_new (); */
1069 data->loop = g_main_loop_new (context, FALSE /* not running */);
1071 /* Cause the function to be run in an idle-handler, which is always
1072 * in the main thread:
1074 if (!connect_request_in_progress) {
1075 printf ("DEBUG: %s: First request\n", __FUNCTION__);
1076 connect_request_in_progress = TRUE;
1077 g_idle_add (&on_idle_connect_and_wait, data);
1080 printf ("DEBUG: %s: nth request\n", __FUNCTION__);
1081 g_idle_add_full (G_PRIORITY_LOW, &on_idle_wait_for_previous_connect_to_finish, data, NULL);
1084 /* This main loop will run until the idle handler has stopped it: */
1085 printf ("DEBUG: %s: before g_main_loop_run()\n", __FUNCTION__);
1086 GDK_THREADS_LEAVE();
1087 g_main_loop_run (data->loop);
1088 GDK_THREADS_ENTER();
1089 printf ("DEBUG: %s: after g_main_loop_run()\n", __FUNCTION__);
1090 connect_request_in_progress = FALSE;
1091 printf ("DEBUG: %s: Finished\n", __FUNCTION__);
1092 g_main_loop_unref (data->loop);
1093 /* g_main_context_unref (context); */
1095 g_slice_free (UtilIdleData, data);
1097 gboolean result = tny_device_is_online (device);
1100 set_account_to_online (account);
1105 gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1107 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1108 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1109 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1110 /* This must be a maildir account, which does not require a connection: */
1115 return modest_platform_connect_and_wait (parent_window, account);
1118 gboolean modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1121 return TRUE; /* Maybe it is something local. */
1123 gboolean result = TRUE;
1124 if (TNY_IS_FOLDER (folder_store)) {
1125 /* Get the folder's parent account: */
1126 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1127 if (account != NULL) {
1128 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1129 g_object_unref (account);
1131 } else if (TNY_IS_ACCOUNT (folder_store)) {
1132 /* Use the folder store as an account: */
1133 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1140 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1141 ModestSortDialogType type)
1143 GtkWidget *dialog = NULL;
1146 dialog = hildon_sort_dialog_new (parent_window);
1147 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
1149 /* Fill sort keys */
1151 case MODEST_SORT_HEADERS:
1152 launch_sort_headers_dialog (parent_window,
1153 HILDON_SORT_DIALOG(dialog));
1158 gtk_widget_destroy (GTK_WIDGET (dialog));
1162 gboolean modest_platform_set_update_interval (guint minutes)
1164 ModestConf *conf = modest_runtime_get_conf ();
1168 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1170 /* Delete any existing alarm,
1171 * because we will replace it: */
1173 /* TODO: What does the alarm_event_del() return value mean? */
1174 alarm_event_del(alarm_cookie);
1176 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1179 /* 0 means no updates: */
1184 /* Register alarm: */
1186 /* Set the interval in alarm_event_t structure: */
1187 alarm_event_t *event = g_new0(alarm_event_t, 1);
1188 event->alarm_time = minutes * 60; /* seconds */
1190 /* Set recurrence every few minutes: */
1191 event->recurrence = minutes;
1192 event->recurrence_count = -1; /* Means infinite */
1194 /* Specify what should happen when the alarm happens:
1195 * It should call this D-Bus method: */
1197 /* Note: I am surpised that alarmd can't just use the modest.service file
1198 * for this. murrayc. */
1199 event->dbus_path = g_strdup(PREFIX "/bin/modest");
1201 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1202 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1203 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1205 /* Otherwise, a dialog will be shown if exect_name or dbus_path is NULL,
1206 even though we have specified no dialog text: */
1207 event->flags = ALARM_EVENT_NO_DIALOG;
1209 alarm_cookie = alarm_event_add (event);
1212 alarm_event_free (event);
1214 /* Store the alarm ID in GConf, so we can remove it later:
1215 * This is apparently valid between application instances. */
1216 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1218 if (!alarm_cookie) {
1220 const alarm_error_t alarm_error = alarmd_get_error ();
1221 printf ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1223 /* Give people some clue: */
1224 /* The alarm API should have a function for this: */
1225 if (alarm_error == ALARMD_ERROR_DBUS) {
1226 printf (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1227 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1228 printf (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1229 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1230 printf (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1231 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1232 printf (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1233 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1234 printf (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1244 modest_platform_get_global_settings_dialog ()
1246 return modest_maemo_global_settings_dialog_new ();
1250 modest_platform_on_new_msg (void)
1252 #ifdef MODEST_HAVE_HILDON_NOTIFY
1253 HildonNotification *not;
1255 /* Create a new notification. FIXME put the right values, need
1257 not = hildon_notification_new ("TODO: (new email) Summary",
1258 "TODO: (new email) Description",
1259 "qgn_contact_group_chat_invitation",
1260 "system.note.dialog");
1262 /* Play sound SR-SND-18. TODO: play the right file */
1263 /* TODO: Where is this declared? hildon_notification_set_sound (not, "/usr/share/sounds/ui-new_email.wav"); */
1265 /* Set the led pattern */
1266 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (not), "led-pattern", 3);
1268 /* Notify. We need to do this in an idle because this function
1269 could be called from a thread */
1270 if (!notify_notification_show (NOTIFY_NOTIFICATION (not), NULL))
1271 g_error ("Failed to send notification");
1273 g_object_unref (not);
1274 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1279 modest_platform_show_help (GtkWindow *parent_window,
1280 const gchar *help_id)
1282 osso_return_t result;
1284 g_return_if_fail (help_id);
1285 g_return_if_fail (osso_context);
1288 #ifdef MODEST_HAVE_OSSO_HELP
1289 result = ossohelp_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1291 result = hildon_help_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1294 if (result != OSSO_OK) {
1296 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1297 hildon_banner_show_information (GTK_WIDGET (parent_window),
1305 modest_platform_show_search_messages (GtkWindow *parent_window)
1307 osso_return_t result = OSSO_ERROR;
1309 result = osso_rpc_run_with_defaults (osso_context, "osso_global_search", "search_email", NULL, DBUS_TYPE_INVALID);
1311 if (result != OSSO_OK) {
1312 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1317 modest_platform_show_addressbook (GtkWindow *parent_window)
1319 osso_return_t result = OSSO_ERROR;
1321 result = osso_rpc_run_with_defaults (osso_context, "osso_addressbook", "top_application", NULL, DBUS_TYPE_INVALID);
1323 if (result != OSSO_OK) {
1324 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1329 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1331 GtkWidget *widget = modest_folder_view_new (query);
1333 /* Show one account by default */
1334 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1335 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1338 /* Restore settings */
1339 modest_widget_memory_restore (modest_runtime_get_conf(),
1341 MODEST_CONF_FOLDER_VIEW_KEY);
1347 modest_platform_information_banner (GtkWidget *parent,
1348 const gchar *icon_name,
1351 hildon_banner_show_information (parent, icon_name, text);
1355 modest_platform_animation_banner (GtkWidget *parent,
1356 const gchar *animation_name,
1359 GtkWidget *inf_note = NULL;
1361 g_return_val_if_fail (text != NULL, NULL);
1363 inf_note = hildon_banner_show_animation (parent, animation_name, text);