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;
62 static void folder_name_insensitive_press (GtkWidget *widget,
63 ModestWindow *window);
66 on_modest_conf_update_interval_changed (ModestConf* self,
68 ModestConfEvent event,
69 ModestConfNotificationId id,
72 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
73 const guint update_interval_minutes =
74 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
75 modest_platform_set_update_interval (update_interval_minutes);
80 modest_platform_init (int argc, char *argv[])
82 osso_hw_state_t hw_state = { 0 };
86 osso_initialize(PACKAGE,PACKAGE_VERSION,
89 g_printerr ("modest: failed to acquire osso context\n");
93 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
94 g_printerr ("modest: could not get dbus connection\n");
99 /* Add a D-Bus handler to be used when the main osso-rpc
100 * D-Bus handler has not handled something.
101 * We use this for D-Bus methods that need to use more complex types
102 * than osso-rpc supports.
104 if (!dbus_connection_add_filter (con,
105 modest_dbus_req_filter,
109 g_printerr ("modest: Could not add D-Bus filter\n");
113 /* Register our simple D-Bus callbacks, via the osso API: */
114 osso_return_t result = osso_rpc_set_cb_f(osso_context,
118 modest_dbus_req_handler, NULL /* user_data */);
119 if (result != OSSO_OK) {
120 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
124 /* Add handler for Exit D-BUS messages.
125 * Not used because osso_application_set_exit_cb() is deprecated and obsolete:
126 result = osso_application_set_exit_cb(osso_context,
127 modest_dbus_exit_event_handler,
129 if (result != OSSO_OK) {
130 g_print("Error setting exit callback (%d)\n", result);
135 /* Register hardware event dbus callback: */
136 hw_state.shutdown_ind = TRUE;
137 osso_hw_set_event_cb(osso_context, NULL,/*&hw_state*/ modest_osso_cb_hw_state_handler, NULL);
139 /* Register osso auto-save callbacks: */
140 result = osso_application_set_autosave_cb (osso_context,
141 modest_on_osso_application_autosave, NULL /* user_data */);
142 if (result != OSSO_OK) {
143 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
148 /* Make sure that the update interval is changed whenever its gconf key
150 /* CAUTION: we're not using here the
151 modest_conf_listen_to_namespace because we know that there
152 are other parts of Modest listening for this namespace, so
153 we'll receive the notifications anyway. We basically do not
154 use it because there is no easy way to do the
155 modest_conf_forget_namespace */
156 ModestConf *conf = modest_runtime_get_conf ();
157 g_signal_connect (G_OBJECT(conf),
159 G_CALLBACK (on_modest_conf_update_interval_changed),
162 /* Get the initial update interval from gconf: */
163 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
164 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
166 /* initialize the addressbook */
167 if (!osso_abook_init (&argc, &argv, osso_context)) {
168 g_printerr ("modest: failed to initialized addressbook\n");
176 modest_platform_get_new_device (void)
178 return TNY_DEVICE (tny_maemo_conic_device_new ());
183 guess_mime_type_from_name (const gchar* name)
187 const static gchar* octet_stream= "application/octet-stream";
188 const static gchar* mime_map[][2] = {
189 { "pdf", "application/pdf"},
190 { "doc", "application/msword"},
191 { "xls", "application/excel"},
192 { "png", "image/png" },
193 { "gif", "image/gif" },
194 { "jpg", "image/jpeg"},
195 { "jpeg", "image/jpeg"},
196 { "mp3", "audio/mp3" }
202 ext = g_strrstr (name, ".");
206 for (i = 0; i != G_N_ELEMENTS(mime_map); ++i) {
207 if (!g_ascii_strcasecmp (mime_map[i][0], ext + 1)) /* +1: ignore '.'*/
208 return mime_map[i][1];
215 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
216 gchar **effective_mime_type)
218 GString *mime_str = NULL;
219 gchar *icon_name = NULL;
220 gchar **icons, **cursor;
222 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
223 mime_str = g_string_new (guess_mime_type_from_name(name));
225 mime_str = g_string_new (mime_type);
226 g_string_ascii_down (mime_str);
229 #ifdef MODEST_HAVE_OSSO_MIME
230 icons = osso_mime_get_icon_names (mime_str->str, NULL);
232 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
233 #endif /*MODEST_HAVE_OSSO_MIME*/
234 for (cursor = icons; cursor; ++cursor) {
235 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
236 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
237 icon_name = g_strdup ("qgn_list_messagin");
239 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
240 icon_name = g_strdup (*cursor);
246 if (effective_mime_type)
247 *effective_mime_type = g_string_free (mime_str, FALSE);
249 g_string_free (mime_str, TRUE);
257 #ifdef MODEST_HAVE_OSSO_MIME
259 modest_platform_activate_uri (const gchar *uri)
261 OssoURIAction *action;
262 gboolean result = FALSE;
263 GSList *actions, *iter = NULL;
266 g_return_val_if_fail (uri, FALSE);
270 /* the default action should be email */
271 scheme = osso_uri_get_scheme_from_uri (uri, NULL);
272 actions = osso_uri_get_actions (scheme, NULL);
274 for (iter = actions; iter; iter = g_slist_next (iter)) {
275 action = (OssoURIAction*) iter->data;
276 if (action && strcmp (osso_uri_action_get_name (action), "uri_link_compose_email") == 0) {
278 result = osso_uri_open (uri, action, &err);
279 if (!result && err) {
280 g_printerr ("modest: modest_platform_activate_uri : %s",
281 err->message ? err->message : "unknown error");
288 /* if we could open it with email, try something else */
290 result = osso_uri_open (uri, NULL, NULL);
294 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
298 #else /* !MODEST_HAVE_OSSO_MIME*/
301 modest_platform_activate_uri (const gchar *uri)
303 HildonURIAction *action;
304 gboolean result = FALSE;
305 GSList *actions, *iter = NULL;
308 g_return_val_if_fail (uri, FALSE);
312 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
313 actions = hildon_uri_get_actions (scheme, NULL);
315 for (iter = actions; iter; iter = g_slist_next (iter)) {
316 action = (HildonURIAction*) iter->data;
317 if (action && strcmp (hildon_uri_action_get_service (action), "com.nokia.modest") == 0) {
319 result = hildon_uri_open (uri, action, &err);
320 if (!result && err) {
321 g_printerr ("modest: modest_platform_activate_uri : %s",
322 err->message ? err->message : "unknown error");
329 /* if we could open it with email, try something else */
331 result = hildon_uri_open (uri, NULL, NULL);
334 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
340 #endif /* MODEST_HAVE_OSSO_MIME*/
343 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
347 gchar *uri_path = NULL;
348 GString *mime_str = NULL;
350 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
351 mime_str = g_string_new (guess_mime_type_from_name(path));
353 mime_str = g_string_new (mime_type);
354 g_string_ascii_down (mime_str);
357 uri_path = g_strconcat ("file://", path, NULL);
359 con = osso_get_dbus_connection (osso_context);
360 #ifdef MODEST_HAVE_OSSO_MIME
361 result = osso_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
363 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
364 #endif /*MODEST_HAVE_OSSO_MIME*/
365 g_string_free (mime_str, TRUE);
368 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
375 } ModestPlatformPopupInfo;
378 delete_uri_popup (GtkWidget *menu,
382 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
384 g_free (popup_info->uri);
385 #ifdef MODEST_HAVE_OSSO_MIME
386 osso_uri_free_actions (popup_info->actions);
388 hildon_uri_free_actions (popup_info->actions);
389 #endif /*MODEST_HAVE_OSSO_MIME*/
394 activate_uri_popup_item (GtkMenuItem *menu_item,
398 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
399 const gchar* action_name;
401 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
403 g_printerr ("modest: no action name defined\n");
407 /* special handling for the copy menu item -- copy the uri to the clipboard */
408 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
409 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
410 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
411 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
413 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
414 action_name += strlen ("mailto:");
416 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
417 return; /* we're done */
420 /* now, the real uri-actions... */
421 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
422 #ifdef MODEST_HAVE_OSSO_MIME
423 OssoURIAction *action = (OssoURIAction *) node->data;
424 if (strcmp (action_name, osso_uri_action_get_name (action))==0) {
425 osso_uri_open (popup_info->uri, action, NULL);
429 HildonURIAction *action = (HildonURIAction *) node->data;
430 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
431 hildon_uri_open (popup_info->uri, action, NULL);
434 #endif /*MODEST_HAVE_OSSO_MIME*/
439 modest_platform_show_uri_popup (const gchar *uri)
442 GSList *actions_list;
447 #ifdef MODEST_HAVE_OSSO_MIME
448 scheme = osso_uri_get_scheme_from_uri (uri, NULL);
449 actions_list = osso_uri_get_actions (scheme, NULL);
451 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
452 actions_list = hildon_uri_get_actions (scheme, NULL);
453 #endif /* MODEST_HAVE_OSSO_MIME */
454 if (actions_list != NULL) {
456 GtkWidget *menu = gtk_menu_new ();
457 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
459 popup_info->actions = actions_list;
460 popup_info->uri = g_strdup (uri);
462 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
463 GtkWidget *menu_item;
464 const gchar *action_name;
465 const gchar *translation_domain;
466 #ifdef MODEST_HAVE_OSSO_MIME
467 OssoURIAction *action = (OssoURIAction *) node->data;
468 action_name = osso_uri_action_get_name (action);
469 translation_domain = osso_uri_action_get_translation_domain (action);
470 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain,action_name));
471 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);
472 /* hack, we add it as a gobject property*/
473 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
476 if (osso_uri_is_default_action (action, NULL)) {
477 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
479 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
482 HildonURIAction *action = (HildonURIAction *) node->data;
483 action_name = hildon_uri_action_get_name (action);
484 translation_domain = hildon_uri_action_get_translation_domain (action);
485 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
486 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
487 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
490 if (hildon_uri_is_default_action (action, NULL)) {
491 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
493 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
495 #endif /*MODEST_HAVE_OSSO_MIME*/
496 gtk_widget_show (menu_item);
499 /* always add the copy item */
500 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
501 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
502 g_strconcat (URI_ACTION_COPY, uri, NULL),
504 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
505 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
506 gtk_widget_show (menu_item);
509 /* and what to do when the link is deleted */
510 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
511 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
514 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
523 modest_platform_get_icon (const gchar *name)
526 GdkPixbuf* pixbuf = NULL;
527 GtkIconTheme *current_theme = NULL;
529 g_return_val_if_fail (name, NULL);
531 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
532 pixbuf = gdk_pixbuf_new_from_file (name, &err);
534 g_printerr ("modest: error loading icon '%s': %s\n",
542 current_theme = gtk_icon_theme_get_default ();
543 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
544 GTK_ICON_LOOKUP_NO_SVG,
547 g_printerr ("modest: error loading theme icon '%s': %s\n",
555 modest_platform_get_app_name (void)
557 return _("mcen_ap_name");
561 entry_insert_text (GtkEditable *editable,
570 chars = gtk_editable_get_chars (editable, 0, -1);
571 chars_length = g_utf8_strlen (chars, -1);
573 /* Show WID-INF036 */
574 if (chars_length >= 20) {
575 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
576 _CS("ckdg_ib_maximum_characters_reached"));
578 if (chars_length == 0) {
579 /* A blank space is not valid as first character */
580 if (strcmp (text, " ")) {
581 GtkWidget *ok_button;
585 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (data)->action_area));
586 ok_button = GTK_WIDGET (buttons->next->data);
587 gtk_widget_set_sensitive (ok_button, TRUE);
588 g_list_free (buttons);
592 /* Write the text in the entry */
593 g_signal_handlers_block_by_func (editable,
594 (gpointer) entry_insert_text, data);
595 gtk_editable_insert_text (editable, text, length, position);
596 g_signal_handlers_unblock_by_func (editable,
597 (gpointer) entry_insert_text, data);
599 /* Do not allow further processing */
600 g_signal_stop_emission_by_name (editable, "insert_text");
604 entry_changed (GtkEditable *editable,
609 chars = gtk_editable_get_chars (editable, 0, -1);
610 g_return_if_fail (chars != NULL);
612 /* Dimm OK button. Do not allow also the "/" */
613 if (strlen (chars) == 0 || strchr (chars, '/')) {
614 GtkWidget *ok_button;
617 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
618 ok_button = GTK_WIDGET (buttons->next->data);
619 gtk_widget_set_sensitive (ok_button, FALSE);
621 g_list_free (buttons);
622 } else if (g_utf8_strlen (chars,-1) >= 21)
623 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
624 _CS("ckdg_ib_maximum_characters_reached"));
630 launch_sort_headers_dialog (GtkWindow *parent_window,
631 HildonSortDialog *dialog)
633 ModestHeaderView *header_view = NULL;
635 GtkSortType sort_type;
637 gint default_key = 0;
639 gboolean outgoing = FALSE;
640 gint current_sort_colid = -1;
641 GtkSortType current_sort_type;
642 gint attachments_sort_id;
643 gint priority_sort_id;
644 GtkTreeSortable *sortable;
646 /* Get header window */
647 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
648 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
649 MODEST_WIDGET_TYPE_HEADER_VIEW));
651 if (!header_view) return;
653 /* Add sorting keys */
654 cols = modest_header_view_get_columns (header_view);
655 if (cols == NULL) return;
656 int sort_model_ids[6];
660 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
661 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
663 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
665 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
666 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
668 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
669 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
672 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
674 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
675 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
677 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
678 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
680 default_key = sort_key;
682 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
683 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
685 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
687 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
689 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
690 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
691 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
692 attachments_sort_id = sort_key;
694 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
695 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
696 sort_ids[sort_key] = 0;
698 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
699 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
700 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY;
701 priority_sort_id = sort_key;
703 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
705 if (!gtk_tree_sortable_get_sort_column_id (sortable,
706 ¤t_sort_colid, ¤t_sort_type)) {
707 hildon_sort_dialog_set_sort_key (dialog, default_key);
708 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
710 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
711 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
712 gpointer flags_sort_type_pointer;
713 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
714 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY)
715 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
717 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
719 gint current_sort_keyid = 0;
720 while (current_sort_keyid < 6) {
721 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
724 current_sort_keyid++;
726 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
730 result = gtk_dialog_run (GTK_DIALOG (dialog));
731 if (result == GTK_RESPONSE_OK) {
732 sort_key = hildon_sort_dialog_get_sort_key (dialog);
733 sort_type = hildon_sort_dialog_get_sort_order (dialog);
734 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
735 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
736 GINT_TO_POINTER (sort_ids[sort_key]));
737 /* This is a hack to make it resort rows always when flag fields are
738 * selected. If we do not do this, changing sort field from priority to
739 * attachments does not work */
740 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
742 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
743 sort_model_ids[sort_key]);
746 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
747 gtk_tree_sortable_sort_column_changed (sortable);
750 modest_widget_memory_save (modest_runtime_get_conf (),
751 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
753 while (gtk_events_pending ())
754 gtk_main_iteration ();
761 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
762 const gchar *dialog_title,
763 const gchar *label_text,
764 const gchar *suggested_name,
767 GtkWidget *accept_btn = NULL;
768 GtkWidget *dialog, *entry, *label, *hbox;
769 GList *buttons = NULL;
772 /* Ask the user for the folder name */
773 dialog = gtk_dialog_new_with_buttons (dialog_title,
775 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
782 /* Add accept button (with unsensitive handler) */
783 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
784 accept_btn = GTK_WIDGET (buttons->next->data);
785 g_signal_connect (G_OBJECT (accept_btn), "insensitive-press",
786 G_CALLBACK (folder_name_insensitive_press),
789 /* Create label and entry */
790 label = gtk_label_new (label_text);
791 /* TODO: check that the suggested name does not exist */
792 /* We set 21 as maximum because we want to show WID-INF036
793 when the user inputs more that 20 */
794 entry = gtk_entry_new_with_max_length (21);
796 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
798 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
799 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
801 /* Track entry changes */
802 g_signal_connect (entry,
804 G_CALLBACK (entry_insert_text),
806 g_signal_connect (entry,
808 G_CALLBACK (entry_changed),
811 /* Create the hbox */
812 hbox = gtk_hbox_new (FALSE, 12);
813 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
814 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
816 /* Add hbox to dialog */
817 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
818 hbox, FALSE, FALSE, 0);
820 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
822 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
823 result = gtk_dialog_run (GTK_DIALOG(dialog));
824 if (result == GTK_RESPONSE_ACCEPT)
825 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
827 gtk_widget_destroy (dialog);
829 while (gtk_events_pending ())
830 gtk_main_iteration ();
836 folder_name_insensitive_press (GtkWidget *widget, ModestWindow *window)
838 hildon_banner_show_information (NULL, NULL, _CS("ckdg_ib_enter_name"));
842 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
843 TnyFolderStore *parent_folder,
844 gchar *suggested_name,
847 gchar *real_suggested_name = NULL;
850 if(suggested_name == NULL)
852 const gchar *default_name = _("mcen_ia_default_folder_name");
856 for(i = 0; i < 100; ++ i)
858 TnyList *list = tny_simple_list_new ();
859 TnyFolderStoreQuery *query = tny_folder_store_query_new ();
862 sprintf(num_str, "%.2u", i);
865 real_suggested_name = g_strdup (default_name);
867 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
870 tny_folder_store_query_add_item (query, real_suggested_name,
871 TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
873 tny_folder_store_get_folders (parent_folder, list, query, NULL);
875 length = tny_list_get_length (list);
876 g_object_unref (query);
877 g_object_unref (list);
882 g_free (real_suggested_name);
885 /* Didn't find a free number */
887 real_suggested_name = g_strdup (default_name);
891 real_suggested_name = suggested_name;
894 result = modest_platform_run_folder_name_dialog (parent_window,
895 _("mcen_ti_new_folder"),
896 _("mcen_fi_new_folder_name"),
899 if (suggested_name == NULL)
900 g_free(real_suggested_name);
906 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
907 TnyFolderStore *parent_folder,
908 const gchar *suggested_name,
911 return modest_platform_run_folder_name_dialog (parent_window,
912 _("New folder name"),
913 _("Enter new folder name:"),
919 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
920 const gchar *message)
925 dialog = hildon_note_new_confirmation (parent_window, message);
926 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
928 response = gtk_dialog_run (GTK_DIALOG (dialog));
930 gtk_widget_destroy (GTK_WIDGET (dialog));
932 while (gtk_events_pending ())
933 gtk_main_iteration ();
939 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
940 const gchar *message)
945 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
946 _("mcen_bd_yes"), GTK_RESPONSE_YES,
947 _("mcen_bd_no"), GTK_RESPONSE_NO,
949 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
951 response = gtk_dialog_run (GTK_DIALOG (dialog));
953 gtk_widget_destroy (GTK_WIDGET (dialog));
955 while (gtk_events_pending ())
956 gtk_main_iteration ();
962 modest_platform_run_information_dialog (GtkWindow *parent_window,
963 const gchar *message)
967 dialog = hildon_note_new_information (parent_window, message);
969 g_signal_connect_swapped (dialog,
971 G_CALLBACK (gtk_widget_destroy),
974 gtk_widget_show_all (dialog);
985 on_idle_connect_and_wait(gpointer user_data)
987 printf ("DEBUG: %s:\n", __FUNCTION__);
988 TnyDevice *device = modest_runtime_get_device();
989 if (!tny_device_is_online (device)) {
991 tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
995 /* Allow the function that requested this idle callback to continue: */
996 UtilIdleData *data = (UtilIdleData*)user_data;
998 g_main_loop_quit (data->loop);
1000 return FALSE; /* Don't call this again. */
1003 static gboolean connect_request_in_progress = FALSE;
1005 /* This callback is used when connect_and_wait() is already queued as an idle callback.
1006 * This can happen because the gtk_dialog_run() for the connection dialog
1007 * (at least in the fake scratchbox version) allows idle handlers to keep running.
1010 on_idle_wait_for_previous_connect_to_finish(gpointer user_data)
1012 gboolean result = FALSE;
1013 TnyDevice *device = modest_runtime_get_device();
1014 if (tny_device_is_online (device))
1015 result = FALSE; /* Stop trying. */
1017 /* Keep trying until connect_request_in_progress is FALSE. */
1018 if (connect_request_in_progress)
1019 result = TRUE; /* Keep trying */
1021 printf ("DEBUG: %s: other idle has finished.\n", __FUNCTION__);
1023 result = FALSE; /* Stop trying, now that a result should be available. */
1027 if (result == FALSE) {
1028 /* Allow the function that requested this idle callback to continue: */
1029 UtilIdleData *data = (UtilIdleData*)user_data;
1031 g_main_loop_quit (data->loop);
1038 set_account_to_online (TnyAccount *account)
1040 /* TODO: This is necessary to prevent a cancel of the password dialog
1041 * from making a restart necessary to be asked the password again,
1042 * but it causes a hang:
1045 if (account && TNY_IS_CAMEL_STORE_ACCOUNT (account)) {
1046 /* Make sure that store accounts are online too,
1047 * because tinymail sets accounts to offline if
1048 * a password dialog is ever cancelled.
1049 * We don't do this for transport accounts because
1050 * a) They fundamentally need network access, so they can't really be offline.
1051 * b) That might cause a transport connection to happen too early.
1053 GError *error = NULL;
1054 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, &error);
1056 g_warning ("%s: tny_camel_account_set_online() returned a GError:\n %s\n",
1057 __FUNCTION__, error->message);
1058 g_error_free (error);
1064 gboolean modest_platform_connect_and_wait (GtkWindow *parent_window, TnyAccount *account)
1066 if (connect_request_in_progress)
1069 printf ("DEBUG: %s:\n", __FUNCTION__);
1070 TnyDevice *device = modest_runtime_get_device();
1072 if (tny_device_is_online (device)) {
1073 printf ("DEBUG: %s: Already online.\n", __FUNCTION__);
1074 set_account_to_online (account);
1078 printf ("DEBUG: %s: tny_device_is_online() returned FALSE\n", __FUNCTION__);
1081 /* This blocks on the result: */
1082 UtilIdleData *data = g_slice_new0 (UtilIdleData);
1084 GMainContext *context = NULL; /* g_main_context_new (); */
1085 data->loop = g_main_loop_new (context, FALSE /* not running */);
1087 /* Cause the function to be run in an idle-handler, which is always
1088 * in the main thread:
1090 if (!connect_request_in_progress) {
1091 printf ("DEBUG: %s: First request\n", __FUNCTION__);
1092 connect_request_in_progress = TRUE;
1093 g_idle_add (&on_idle_connect_and_wait, data);
1096 printf ("DEBUG: %s: nth request\n", __FUNCTION__);
1097 g_idle_add_full (G_PRIORITY_LOW, &on_idle_wait_for_previous_connect_to_finish, data, NULL);
1100 /* This main loop will run until the idle handler has stopped it: */
1101 printf ("DEBUG: %s: before g_main_loop_run()\n", __FUNCTION__);
1102 GDK_THREADS_LEAVE();
1103 g_main_loop_run (data->loop);
1104 GDK_THREADS_ENTER();
1105 printf ("DEBUG: %s: after g_main_loop_run()\n", __FUNCTION__);
1106 connect_request_in_progress = FALSE;
1107 printf ("DEBUG: %s: Finished\n", __FUNCTION__);
1108 g_main_loop_unref (data->loop);
1109 /* g_main_context_unref (context); */
1111 g_slice_free (UtilIdleData, data);
1113 gboolean result = tny_device_is_online (device);
1116 set_account_to_online (account);
1121 gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1123 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1124 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1125 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1126 /* This must be a maildir account, which does not require a connection: */
1131 return modest_platform_connect_and_wait (parent_window, account);
1134 gboolean modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1137 return TRUE; /* Maybe it is something local. */
1139 gboolean result = TRUE;
1140 if (TNY_IS_FOLDER (folder_store)) {
1141 /* Get the folder's parent account: */
1142 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1143 if (account != NULL) {
1144 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1145 g_object_unref (account);
1147 } else if (TNY_IS_ACCOUNT (folder_store)) {
1148 /* Use the folder store as an account: */
1149 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1156 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1157 ModestSortDialogType type)
1159 GtkWidget *dialog = NULL;
1162 dialog = hildon_sort_dialog_new (parent_window);
1163 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
1165 /* Fill sort keys */
1167 case MODEST_SORT_HEADERS:
1168 launch_sort_headers_dialog (parent_window,
1169 HILDON_SORT_DIALOG(dialog));
1174 gtk_widget_destroy (GTK_WIDGET (dialog));
1178 gboolean modest_platform_set_update_interval (guint minutes)
1180 ModestConf *conf = modest_runtime_get_conf ();
1184 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1186 /* Delete any existing alarm,
1187 * because we will replace it: */
1189 /* TODO: What does the alarm_event_del() return value mean? */
1190 alarm_event_del(alarm_cookie);
1192 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1195 /* 0 means no updates: */
1200 /* Register alarm: */
1202 /* Set the interval in alarm_event_t structure: */
1203 alarm_event_t *event = g_new0(alarm_event_t, 1);
1204 event->alarm_time = minutes * 60; /* seconds */
1206 /* Set recurrence every few minutes: */
1207 event->recurrence = minutes;
1208 event->recurrence_count = -1; /* Means infinite */
1210 /* Specify what should happen when the alarm happens:
1211 * It should call this D-Bus method: */
1213 /* Note: I am surpised that alarmd can't just use the modest.service file
1214 * for this. murrayc. */
1215 event->dbus_path = g_strdup(PREFIX "/bin/modest");
1217 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1218 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1219 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1221 /* Otherwise, a dialog will be shown if exect_name or dbus_path is NULL,
1222 even though we have specified no dialog text: */
1223 event->flags = ALARM_EVENT_NO_DIALOG;
1225 alarm_cookie = alarm_event_add (event);
1228 alarm_event_free (event);
1230 /* Store the alarm ID in GConf, so we can remove it later:
1231 * This is apparently valid between application instances. */
1232 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1234 if (!alarm_cookie) {
1236 const alarm_error_t alarm_error = alarmd_get_error ();
1237 printf ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1239 /* Give people some clue: */
1240 /* The alarm API should have a function for this: */
1241 if (alarm_error == ALARMD_ERROR_DBUS) {
1242 printf (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1243 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1244 printf (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1245 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1246 printf (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1247 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1248 printf (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1249 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1250 printf (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1260 modest_platform_get_global_settings_dialog ()
1262 return modest_maemo_global_settings_dialog_new ();
1266 modest_platform_on_new_msg (void)
1268 #ifdef MODEST_HAVE_HILDON_NOTIFY
1269 HildonNotification *not;
1271 /* Create a new notification. FIXME put the right values, need
1273 not = hildon_notification_new ("TODO: (new email) Summary",
1274 "TODO: (new email) Description",
1275 "qgn_contact_group_chat_invitation",
1276 "system.note.dialog");
1278 /* Play sound SR-SND-18. TODO: play the right file */
1279 /* TODO: Where is this declared? hildon_notification_set_sound (not, "/usr/share/sounds/ui-new_email.wav"); */
1281 /* Set the led pattern */
1282 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (not), "led-pattern", 3);
1284 /* Notify. We need to do this in an idle because this function
1285 could be called from a thread */
1286 if (!notify_notification_show (NOTIFY_NOTIFICATION (not), NULL))
1287 g_error ("Failed to send notification");
1289 g_object_unref (not);
1290 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1295 modest_platform_show_help (GtkWindow *parent_window,
1296 const gchar *help_id)
1298 osso_return_t result;
1300 g_return_if_fail (help_id);
1301 g_return_if_fail (osso_context);
1304 #ifdef MODEST_HAVE_OSSO_HELP
1305 result = ossohelp_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1307 result = hildon_help_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1310 if (result != OSSO_OK) {
1312 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1313 hildon_banner_show_information (GTK_WIDGET (parent_window),
1321 modest_platform_show_search_messages (GtkWindow *parent_window)
1323 osso_return_t result = OSSO_ERROR;
1325 result = osso_rpc_run_with_defaults (osso_context, "osso_global_search", "search_email", NULL, DBUS_TYPE_INVALID);
1327 if (result != OSSO_OK) {
1328 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1333 modest_platform_show_addressbook (GtkWindow *parent_window)
1335 osso_return_t result = OSSO_ERROR;
1337 result = osso_rpc_run_with_defaults (osso_context, "osso_addressbook", "top_application", NULL, DBUS_TYPE_INVALID);
1339 if (result != OSSO_OK) {
1340 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1345 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1347 GtkWidget *widget = modest_folder_view_new (query);
1349 /* Show one account by default */
1350 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1351 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1354 /* Restore settings */
1355 modest_widget_memory_restore (modest_runtime_get_conf(),
1357 MODEST_CONF_FOLDER_VIEW_KEY);
1363 modest_platform_information_banner (GtkWidget *parent,
1364 const gchar *icon_name,
1367 hildon_banner_show_information (parent, icon_name, text);
1371 modest_platform_animation_banner (GtkWidget *parent,
1372 const gchar *animation_name,
1375 GtkWidget *inf_note = NULL;
1377 g_return_val_if_fail (text != NULL, NULL);
1379 inf_note = hildon_banner_show_animation (parent, animation_name, text);