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>
54 #include "modest-tny-folder.h"
58 #define HILDON_OSSO_URI_ACTION "uri-action"
59 #define URI_ACTION_COPY "copy:"
61 static osso_context_t *osso_context = NULL;
64 on_modest_conf_update_interval_changed (ModestConf* self,
66 ModestConfEvent event,
67 ModestConfNotificationId id,
70 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
71 const guint update_interval_minutes =
72 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
73 modest_platform_set_update_interval (update_interval_minutes);
78 modest_platform_init (int argc, char *argv[])
80 osso_hw_state_t hw_state = { 0 };
84 osso_initialize(PACKAGE,PACKAGE_VERSION,
87 g_printerr ("modest: failed to acquire osso context\n");
91 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
92 g_printerr ("modest: could not get dbus connection\n");
97 /* Add a D-Bus handler to be used when the main osso-rpc
98 * D-Bus handler has not handled something.
99 * We use this for D-Bus methods that need to use more complex types
100 * than osso-rpc supports.
102 if (!dbus_connection_add_filter (con,
103 modest_dbus_req_filter,
107 g_printerr ("modest: Could not add D-Bus filter\n");
111 /* Register our simple D-Bus callbacks, via the osso API: */
112 osso_return_t result = osso_rpc_set_cb_f(osso_context,
116 modest_dbus_req_handler, NULL /* user_data */);
117 if (result != OSSO_OK) {
118 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
122 /* Add handler for Exit D-BUS messages.
123 * Not used because osso_application_set_exit_cb() is deprecated and obsolete:
124 result = osso_application_set_exit_cb(osso_context,
125 modest_dbus_exit_event_handler,
127 if (result != OSSO_OK) {
128 g_print("Error setting exit callback (%d)\n", result);
133 /* Register hardware event dbus callback: */
134 hw_state.shutdown_ind = TRUE;
135 osso_hw_set_event_cb(osso_context, NULL,/*&hw_state*/ modest_osso_cb_hw_state_handler, NULL);
137 /* Register osso auto-save callbacks: */
138 result = osso_application_set_autosave_cb (osso_context,
139 modest_on_osso_application_autosave, NULL /* user_data */);
140 if (result != OSSO_OK) {
141 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
146 /* Make sure that the update interval is changed whenever its gconf key
148 /* CAUTION: we're not using here the
149 modest_conf_listen_to_namespace because we know that there
150 are other parts of Modest listening for this namespace, so
151 we'll receive the notifications anyway. We basically do not
152 use it because there is no easy way to do the
153 modest_conf_forget_namespace */
154 ModestConf *conf = modest_runtime_get_conf ();
155 g_signal_connect (G_OBJECT(conf),
157 G_CALLBACK (on_modest_conf_update_interval_changed),
160 /* Get the initial update interval from gconf: */
161 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
162 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
164 /* initialize the addressbook */
165 if (!osso_abook_init (&argc, &argv, osso_context)) {
166 g_printerr ("modest: failed to initialized addressbook\n");
174 modest_platform_get_new_device (void)
176 return TNY_DEVICE (tny_maemo_conic_device_new ());
181 guess_mime_type_from_name (const gchar* name)
184 const static gchar* mime_type;
185 const static gchar* mime_map[][2] = {
186 { ".note.html", "text/note"}, /* for the osso_notes program */
187 { ".deb", "application/x-deb"},
188 { ".install", "application/x-install-instructions"},
189 { ".html", "text/html"},
190 { ".htm", "text/html"},
191 { ".pdf", "application/pdf"},
192 { ".doc", "application/msword"},
193 { ".xls", "application/excel"},
194 { ".png", "image/png" },
195 { ".gif", "image/gif" },
196 { ".jpg", "image/jpeg"},
197 { ".jpeg", "image/jpeg"},
198 { ".mp3", "audio/mp3" }
201 mime_type = "application/octet-stream";
204 gchar* lc_name = g_utf8_strdown (name, -1);
205 for (i = 0; i != G_N_ELEMENTS(mime_map); ++i) {
206 if (g_str_has_suffix (lc_name, mime_map[i][0])) {
207 mime_type = mime_map[i][1];
219 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
220 gchar **effective_mime_type)
222 GString *mime_str = NULL;
223 gchar *icon_name = NULL;
224 gchar **icons, **cursor;
226 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
227 mime_str = g_string_new (guess_mime_type_from_name(name));
229 mime_str = g_string_new (mime_type);
230 g_string_ascii_down (mime_str);
233 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
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);
256 modest_platform_activate_uri (const gchar *uri)
258 HildonURIAction *action;
259 gboolean result = FALSE;
260 GSList *actions, *iter = NULL;
263 g_return_val_if_fail (uri, FALSE);
267 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
268 actions = hildon_uri_get_actions (scheme, NULL);
270 for (iter = actions; iter; iter = g_slist_next (iter)) {
271 action = (HildonURIAction*) iter->data;
272 if (action && strcmp (hildon_uri_action_get_service (action),
273 "com.nokia.modest") == 0) {
275 result = hildon_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 = hildon_uri_open (uri, NULL, NULL);
290 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
296 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
300 gchar *uri_path = NULL;
302 uri_path = g_strconcat ("file://", path, NULL);
303 con = osso_get_dbus_connection (osso_context);
306 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
308 result = hildon_mime_open_file (con, uri_path);
310 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
318 } ModestPlatformPopupInfo;
321 delete_uri_popup (GtkWidget *menu,
325 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
327 g_free (popup_info->uri);
328 hildon_uri_free_actions (popup_info->actions);
334 activate_uri_popup_item (GtkMenuItem *menu_item,
338 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
339 const gchar* action_name;
341 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
343 g_printerr ("modest: no action name defined\n");
347 /* special handling for the copy menu item -- copy the uri to the clipboard */
348 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
349 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
350 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
351 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
353 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
354 action_name += strlen ("mailto:");
356 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
357 return; /* we're done */
360 /* now, the real uri-actions... */
361 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
362 HildonURIAction *action = (HildonURIAction *) node->data;
363 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
364 hildon_uri_open (popup_info->uri, action, NULL);
371 modest_platform_show_uri_popup (const gchar *uri)
374 GSList *actions_list;
379 scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
380 actions_list = hildon_uri_get_actions (scheme, NULL);
381 if (actions_list != NULL) {
383 GtkWidget *menu = gtk_menu_new ();
384 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
386 popup_info->actions = actions_list;
387 popup_info->uri = g_strdup (uri);
389 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
390 GtkWidget *menu_item;
391 const gchar *action_name;
392 const gchar *translation_domain;
393 HildonURIAction *action = (HildonURIAction *) node->data;
394 action_name = hildon_uri_action_get_name (action);
395 translation_domain = hildon_uri_action_get_translation_domain (action);
396 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
397 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
398 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
401 if (hildon_uri_is_default_action (action, NULL)) {
402 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
404 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
406 gtk_widget_show (menu_item);
409 /* always add the copy item */
410 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
411 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
412 g_strconcat (URI_ACTION_COPY, uri, NULL),
414 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
415 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
416 gtk_widget_show (menu_item);
419 /* and what to do when the link is deleted */
420 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
421 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
424 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
433 modest_platform_get_icon (const gchar *name)
436 GdkPixbuf* pixbuf = NULL;
437 GtkIconTheme *current_theme = NULL;
439 g_return_val_if_fail (name, NULL);
441 /* strlen == 0 is not really an error; it just
442 * means the icon is not available
444 if (!name || strlen(name) == 0)
447 #if 0 /* do we still need this? */
448 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
449 pixbuf = gdk_pixbuf_new_from_file (name, &err);
451 g_printerr ("modest: error loading icon '%s': %s\n",
459 current_theme = gtk_icon_theme_get_default ();
460 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
461 GTK_ICON_LOOKUP_NO_SVG,
464 g_printerr ("modest: error loading theme icon '%s': %s\n",
472 modest_platform_get_app_name (void)
474 return _("mcen_ap_name");
478 entry_insert_text (GtkEditable *editable,
487 chars = gtk_editable_get_chars (editable, 0, -1);
488 chars_length = g_utf8_strlen (chars, -1);
490 /* Show WID-INF036 */
491 if (chars_length >= 20) {
492 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
493 _CS("ckdg_ib_maximum_characters_reached"));
495 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
499 tmp = g_strndup (folder_name_forbidden_chars,
500 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
501 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
502 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
507 /* Write the text in the entry if it's valid */
508 g_signal_handlers_block_by_func (editable,
509 (gpointer) entry_insert_text, data);
510 gtk_editable_insert_text (editable, text, length, position);
511 g_signal_handlers_unblock_by_func (editable,
512 (gpointer) entry_insert_text, data);
515 /* Do not allow further processing */
516 g_signal_stop_emission_by_name (editable, "insert_text");
520 entry_changed (GtkEditable *editable,
524 GtkWidget *ok_button;
527 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
528 ok_button = GTK_WIDGET (buttons->next->data);
530 chars = gtk_editable_get_chars (editable, 0, -1);
531 g_return_if_fail (chars != NULL);
534 if (g_utf8_strlen (chars,-1) >= 21)
535 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
536 _CS("ckdg_ib_maximum_characters_reached"));
538 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
541 g_list_free (buttons);
546 launch_sort_headers_dialog (GtkWindow *parent_window,
547 HildonSortDialog *dialog)
549 ModestHeaderView *header_view = NULL;
551 GtkSortType sort_type;
553 gint default_key = 0;
555 gboolean outgoing = FALSE;
556 gint current_sort_colid = -1;
557 GtkSortType current_sort_type;
558 gint attachments_sort_id;
559 gint priority_sort_id;
560 GtkTreeSortable *sortable;
562 /* Get header window */
563 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
564 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
565 MODEST_WIDGET_TYPE_HEADER_VIEW));
567 if (!header_view) return;
569 /* Add sorting keys */
570 cols = modest_header_view_get_columns (header_view);
571 if (cols == NULL) return;
572 int sort_model_ids[6];
576 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
577 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
579 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
581 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
582 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
584 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
585 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
588 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
590 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
591 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
593 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
594 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
596 default_key = sort_key;
598 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
599 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
601 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
603 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
605 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
606 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
607 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
608 attachments_sort_id = sort_key;
610 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
611 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
612 sort_ids[sort_key] = 0;
614 sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
615 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
616 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY;
617 priority_sort_id = sort_key;
619 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
621 if (!gtk_tree_sortable_get_sort_column_id (sortable,
622 ¤t_sort_colid, ¤t_sort_type)) {
623 hildon_sort_dialog_set_sort_key (dialog, default_key);
624 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
626 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
627 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
628 gpointer flags_sort_type_pointer;
629 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
630 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY)
631 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
633 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
635 gint current_sort_keyid = 0;
636 while (current_sort_keyid < 6) {
637 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
640 current_sort_keyid++;
642 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
646 result = gtk_dialog_run (GTK_DIALOG (dialog));
647 if (result == GTK_RESPONSE_OK) {
648 sort_key = hildon_sort_dialog_get_sort_key (dialog);
649 sort_type = hildon_sort_dialog_get_sort_order (dialog);
650 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
651 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
652 GINT_TO_POINTER (sort_ids[sort_key]));
653 /* This is a hack to make it resort rows always when flag fields are
654 * selected. If we do not do this, changing sort field from priority to
655 * attachments does not work */
656 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
658 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
659 sort_model_ids[sort_key]);
662 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
663 gtk_tree_sortable_sort_column_changed (sortable);
666 modest_widget_memory_save (modest_runtime_get_conf (),
667 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
669 /* while (gtk_events_pending ()) */
670 /* gtk_main_iteration (); */
679 on_response (GtkDialog *dialog,
683 GList *child_vbox, *child_hbox;
684 GtkWidget *hbox, *entry;
685 TnyFolderStore *parent;
687 if (response != GTK_RESPONSE_ACCEPT)
691 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
692 hbox = child_vbox->data;
693 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
694 entry = child_hbox->next->data;
696 parent = TNY_FOLDER_STORE (user_data);
698 /* Look for another folder with the same name */
699 if (modest_tny_folder_has_subfolder_with_name (parent,
700 gtk_entry_get_text (GTK_ENTRY (entry)))) {
702 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
703 NULL, _CS("ckdg_ib_folder_already_exists"));
704 /* Select the text */
705 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
706 gtk_widget_grab_focus (entry);
707 /* Do not close the dialog */
708 g_signal_stop_emission_by_name (dialog, "response");
714 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
715 TnyFolderStore *parent,
716 const gchar *dialog_title,
717 const gchar *label_text,
718 const gchar *suggested_name,
721 GtkWidget *accept_btn = NULL;
722 GtkWidget *dialog, *entry, *label, *hbox;
723 GList *buttons = NULL;
726 /* Ask the user for the folder name */
727 dialog = gtk_dialog_new_with_buttons (dialog_title,
729 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
730 _("mcen_bd_dialog_ok"),
732 _("mcen_bd_dialog_cancel"),
736 /* Add accept button (with unsensitive handler) */
737 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
738 accept_btn = GTK_WIDGET (buttons->next->data);
739 /* Create label and entry */
740 label = gtk_label_new (label_text);
741 /* TODO: check that the suggested name does not exist */
742 /* We set 21 as maximum because we want to show WID-INF036
743 when the user inputs more that 20 */
744 entry = gtk_entry_new_with_max_length (21);
746 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
748 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
749 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
751 /* Connect to the response method to avoid closing the dialog
752 when an invalid name is selected*/
753 g_signal_connect (dialog,
755 G_CALLBACK (on_response),
758 /* Track entry changes */
759 g_signal_connect (entry,
761 G_CALLBACK (entry_insert_text),
763 g_signal_connect (entry,
765 G_CALLBACK (entry_changed),
768 /* Create the hbox */
769 hbox = gtk_hbox_new (FALSE, 12);
770 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
771 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
773 /* Add hbox to dialog */
774 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
775 hbox, FALSE, FALSE, 0);
777 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
779 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
783 result = gtk_dialog_run (GTK_DIALOG(dialog));
784 if (result == GTK_RESPONSE_ACCEPT)
785 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
787 gtk_widget_destroy (dialog);
789 while (gtk_events_pending ())
790 gtk_main_iteration ();
796 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
797 TnyFolderStore *parent_folder,
798 gchar *suggested_name,
801 gchar *real_suggested_name = NULL;
804 if(suggested_name == NULL)
806 const gchar *default_name = _("mcen_ia_default_folder_name");
810 for(i = 0; i < 100; ++ i) {
811 gboolean exists = FALSE;
813 sprintf(num_str, "%.2u", i);
816 real_suggested_name = g_strdup (default_name);
818 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
821 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
822 real_suggested_name);
827 g_free (real_suggested_name);
830 /* Didn't find a free number */
832 real_suggested_name = g_strdup (default_name);
834 real_suggested_name = suggested_name;
837 result = modest_platform_run_folder_name_dialog (parent_window,
839 _("mcen_ti_new_folder"),
840 _("mcen_fi_new_folder_name"),
843 if (suggested_name == NULL)
844 g_free(real_suggested_name);
850 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
851 TnyFolderStore *parent_folder,
852 const gchar *suggested_name,
855 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
857 return modest_platform_run_folder_name_dialog (parent_window,
859 _HL("ckdg_ti_rename_folder"),
860 _HL("ckdg_fi_rename_name"),
866 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
867 const gchar *message)
872 dialog = hildon_note_new_confirmation (parent_window, message);
873 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
875 response = gtk_dialog_run (GTK_DIALOG (dialog));
877 gtk_widget_destroy (GTK_WIDGET (dialog));
879 while (gtk_events_pending ())
880 gtk_main_iteration ();
886 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
887 const gchar *message)
892 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
893 _("mcen_bd_yes"), GTK_RESPONSE_YES,
894 _("mcen_bd_no"), GTK_RESPONSE_NO,
896 gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
898 response = gtk_dialog_run (GTK_DIALOG (dialog));
900 gtk_widget_destroy (GTK_WIDGET (dialog));
902 while (gtk_events_pending ())
903 gtk_main_iteration ();
909 modest_platform_run_information_dialog (GtkWindow *parent_window,
910 const gchar *message)
914 dialog = hildon_note_new_information (parent_window, message);
916 g_signal_connect_swapped (dialog,
918 G_CALLBACK (gtk_widget_destroy),
921 gtk_widget_show_all (dialog);
932 on_idle_connect_and_wait(gpointer user_data)
934 printf ("DEBUG: %s:\n", __FUNCTION__);
935 TnyDevice *device = modest_runtime_get_device();
936 if (!tny_device_is_online (device)) {
938 /* This is a GDK lock because we are an idle callback and
939 * tny_maemo_conic_device_connect can contain Gtk+ code */
941 gdk_threads_enter(); /* CHECKED */
942 tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
943 gdk_threads_leave(); /* CHECKED */
946 /* Allow the function that requested this idle callback to continue: */
947 UtilIdleData *data = (UtilIdleData*)user_data;
949 g_main_loop_quit (data->loop);
951 return FALSE; /* Don't call this again. */
954 static gboolean connect_request_in_progress = FALSE;
956 /* This callback is used when connect_and_wait() is already queued as an idle callback.
957 * This can happen because the gtk_dialog_run() for the connection dialog
958 * (at least in the fake scratchbox version) allows idle handlers to keep running.
961 on_idle_wait_for_previous_connect_to_finish(gpointer user_data)
963 gboolean result = FALSE;
964 TnyDevice *device = modest_runtime_get_device();
965 if (tny_device_is_online (device))
966 result = FALSE; /* Stop trying. */
968 /* Keep trying until connect_request_in_progress is FALSE. */
969 if (connect_request_in_progress)
970 result = TRUE; /* Keep trying */
972 printf ("DEBUG: %s: other idle has finished.\n", __FUNCTION__);
974 result = FALSE; /* Stop trying, now that a result should be available. */
978 if (result == FALSE) {
979 /* Allow the function that requested this idle callback to continue: */
980 UtilIdleData *data = (UtilIdleData*)user_data;
982 g_main_loop_quit (data->loop);
989 set_account_to_online (TnyAccount *account)
991 /* TODO: This is necessary to prevent a cancel of the password dialog
992 * from making a restart necessary to be asked the password again,
993 * but it causes a hang:
996 if (account && TNY_IS_CAMEL_STORE_ACCOUNT (account)) {
997 /* Make sure that store accounts are online too,
998 * because tinymail sets accounts to offline if
999 * a password dialog is ever cancelled.
1000 * We don't do this for transport accounts because
1001 * a) They fundamentally need network access, so they can't really be offline.
1002 * b) That might cause a transport connection to happen too early.
1004 GError *error = NULL;
1005 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, &error);
1007 g_warning ("%s: tny_camel_account_set_online() returned a GError:\n %s\n",
1008 __FUNCTION__, error->message);
1009 g_error_free (error);
1015 gboolean modest_platform_connect_and_wait (GtkWindow *parent_window, TnyAccount *account)
1017 if (connect_request_in_progress)
1020 printf ("DEBUG: %s:\n", __FUNCTION__);
1021 TnyDevice *device = modest_runtime_get_device();
1023 if (tny_device_is_online (device)) {
1024 printf ("DEBUG: %s: Already online.\n", __FUNCTION__);
1025 set_account_to_online (account);
1029 printf ("DEBUG: %s: tny_device_is_online() returned FALSE\n", __FUNCTION__);
1032 /* This blocks on the result: */
1033 UtilIdleData *data = g_slice_new0 (UtilIdleData);
1035 GMainContext *context = NULL; /* g_main_context_new (); */
1036 data->loop = g_main_loop_new (context, FALSE /* not running */);
1038 /* Cause the function to be run in an idle-handler, which is always
1039 * in the main thread:
1041 if (!connect_request_in_progress) {
1042 printf ("DEBUG: %s: First request\n", __FUNCTION__);
1043 connect_request_in_progress = TRUE;
1044 g_idle_add (&on_idle_connect_and_wait, data);
1047 printf ("DEBUG: %s: nth request\n", __FUNCTION__);
1048 g_idle_add_full (G_PRIORITY_LOW, &on_idle_wait_for_previous_connect_to_finish, data, NULL);
1051 /* This main loop will run until the idle handler has stopped it: */
1052 printf ("DEBUG: %s: before g_main_loop_run()\n", __FUNCTION__);
1053 GDK_THREADS_LEAVE();
1054 g_main_loop_run (data->loop);
1055 GDK_THREADS_ENTER();
1056 printf ("DEBUG: %s: after g_main_loop_run()\n", __FUNCTION__);
1057 connect_request_in_progress = FALSE;
1058 printf ("DEBUG: %s: Finished\n", __FUNCTION__);
1059 g_main_loop_unref (data->loop);
1060 /* g_main_context_unref (context); */
1062 g_slice_free (UtilIdleData, data);
1064 const gboolean result = tny_device_is_online (device);
1067 set_account_to_online (account);
1073 gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1075 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1076 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1077 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1078 /* This must be a maildir account, which does not require a connection: */
1083 return modest_platform_connect_and_wait (parent_window, account);
1086 gboolean modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1089 return TRUE; /* Maybe it is something local. */
1091 gboolean result = TRUE;
1092 if (TNY_IS_FOLDER (folder_store)) {
1093 /* Get the folder's parent account: */
1094 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1095 if (account != NULL) {
1096 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1097 g_object_unref (account);
1099 } else if (TNY_IS_ACCOUNT (folder_store)) {
1100 /* Use the folder store as an account: */
1101 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1107 gboolean modest_platform_is_network_folderstore (TnyFolderStore *folder_store)
1109 TnyAccount *account = NULL;
1110 gboolean result = TRUE;
1112 g_return_val_if_fail(TNY_IS_FOLDER_STORE(folder_store), FALSE);
1114 if (TNY_IS_FOLDER (folder_store)) {
1115 /* Get the folder's parent account: */
1116 account = tny_folder_get_account(TNY_FOLDER(folder_store));
1117 } else if (TNY_IS_ACCOUNT (folder_store)) {
1118 account = TNY_ACCOUNT(folder_store);
1119 g_object_ref(account);
1122 if (account != NULL) {
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
1127 * not require a connection: */
1131 g_object_unref (account);
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 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1198 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1199 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1200 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1202 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1203 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1204 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1205 * This is why we want to use the Alarm API instead of just g_timeout_add().
1206 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1208 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1210 alarm_cookie = alarm_event_add (event);
1213 alarm_event_free (event);
1215 /* Store the alarm ID in GConf, so we can remove it later:
1216 * This is apparently valid between application instances. */
1217 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1219 if (!alarm_cookie) {
1221 const alarm_error_t alarm_error = alarmd_get_error ();
1222 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1224 /* Give people some clue: */
1225 /* The alarm API should have a function for this: */
1226 if (alarm_error == ALARMD_ERROR_DBUS) {
1227 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1228 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1229 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1230 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1231 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1232 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1233 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1234 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1235 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1236 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1237 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1247 modest_platform_get_global_settings_dialog ()
1249 return modest_maemo_global_settings_dialog_new ();
1253 modest_platform_on_new_msg (void)
1255 #ifdef MODEST_HAVE_HILDON_NOTIFY
1256 HildonNotification *not;
1258 /* Create a new notification. TODO: per-mail data needed */
1259 not = hildon_notification_new ("TODO: (new email) Summary",
1260 "TODO: (new email) Description",
1261 "qgn_list_messagin_mail_unread",
1264 hildon_notification_add_dbus_action(not,
1267 MODEST_DBUS_SERVICE,
1270 MODEST_DBUS_METHOD_OPEN_DEFAULT_INBOX,
1273 /* Play sound SR-SND-18 */
1274 hildon_notification_set_sound (not, "/usr/share/sounds/ui-new_email.wav");
1275 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (not), "dialog-type", 4);
1277 /* Set the led pattern */
1278 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (not),
1280 "PatternCommunicationEmail");
1282 /* Notify. We need to do this in an idle because this function
1283 could be called from a thread */
1284 if (!notify_notification_show (NOTIFY_NOTIFICATION (not), NULL))
1285 g_error ("Failed to send notification");
1287 g_object_unref (not);
1288 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1293 modest_platform_show_help (GtkWindow *parent_window,
1294 const gchar *help_id)
1296 osso_return_t result;
1298 g_return_if_fail (help_id);
1299 g_return_if_fail (osso_context);
1302 #ifdef MODEST_HAVE_OSSO_HELP
1303 result = ossohelp_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1305 result = hildon_help_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1308 if (result != OSSO_OK) {
1310 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1311 hildon_banner_show_information (GTK_WIDGET (parent_window),
1319 modest_platform_show_search_messages (GtkWindow *parent_window)
1321 osso_return_t result = OSSO_ERROR;
1323 result = osso_rpc_run_with_defaults (osso_context, "osso_global_search", "search_email", NULL, DBUS_TYPE_INVALID);
1325 if (result != OSSO_OK) {
1326 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1331 modest_platform_show_addressbook (GtkWindow *parent_window)
1333 osso_return_t result = OSSO_ERROR;
1335 result = osso_rpc_run_with_defaults (osso_context, "osso_addressbook", "top_application", NULL, DBUS_TYPE_INVALID);
1337 if (result != OSSO_OK) {
1338 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1343 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1345 GtkWidget *widget = modest_folder_view_new (query);
1347 /* Show one account by default */
1348 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1349 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1352 /* Restore settings */
1353 modest_widget_memory_restore (modest_runtime_get_conf(),
1355 MODEST_CONF_FOLDER_VIEW_KEY);
1361 modest_platform_information_banner (GtkWidget *parent,
1362 const gchar *icon_name,
1365 hildon_banner_show_information (parent, icon_name, text);
1369 modest_platform_animation_banner (GtkWidget *parent,
1370 const gchar *animation_name,
1373 GtkWidget *inf_note = NULL;
1375 g_return_val_if_fail (text != NULL, NULL);
1377 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1385 TnyAccount *account;
1388 } CheckAccountIdleData;
1390 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1393 on_timeout_check_account_is_online(gpointer user_data)
1395 printf ("DEBUG: %s:\n", __FUNCTION__);
1396 CheckAccountIdleData *data = (CheckAccountIdleData*)user_data;
1399 g_warning ("%s: data is NULL.\n", __FUNCTION__);
1402 if (!(data->account)) {
1403 g_warning ("%s: data->account is NULL.\n", __FUNCTION__);
1406 if (data && data->account) {
1407 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__, tny_account_get_connection_status (data->account));
1410 gboolean stop_trying = FALSE;
1411 if (data && data->account &&
1412 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1413 * after which the account is likely to be usable, or never likely to be usable soon: */
1414 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1416 data->is_online = TRUE;
1421 /* Give up if we have tried too many times: */
1422 if (data->count_tries >= NUMBER_OF_TRIES)
1427 /* Wait for another timeout: */
1428 ++(data->count_tries);
1433 /* Allow the function that requested this idle callback to continue: */
1435 g_main_loop_quit (data->loop);
1438 g_object_unref (data->account);
1440 return FALSE; /* Don't call this again. */
1442 return TRUE; /* Call this timeout callback again. */
1446 /* Return TRUE immediately if the account is already online,
1447 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1448 * soon as the account is online, or FALSE if the account does
1449 * not become online in the NUMBER_OF_TRIES seconds.
1450 * This is useful when the D-Bus method was run immediately after
1451 * the application was started (when using D-Bus activation),
1452 * because the account usually takes a short time to go online.
1453 * The return value is maybe not very useful.
1456 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1458 g_return_val_if_fail (account, FALSE);
1460 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1462 if (!tny_device_is_online (modest_runtime_get_device())) {
1463 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1467 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1468 * so we avoid wait unnecessarily: */
1469 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1470 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1474 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1475 __FUNCTION__, tny_account_get_connection_status (account));
1477 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1478 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1479 * we want to avoid. */
1480 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1483 /* This blocks on the result: */
1484 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1485 data->is_online = FALSE;
1486 data->account = account;
1487 g_object_ref (data->account);
1488 data->count_tries = 0;
1490 GMainContext *context = NULL; /* g_main_context_new (); */
1491 data->loop = g_main_loop_new (context, FALSE /* not running */);
1493 g_timeout_add (1000, &on_timeout_check_account_is_online, data);
1495 /* This main loop will run until the idle handler has stopped it: */
1496 g_main_loop_run (data->loop);
1498 g_main_loop_unref (data->loop);
1499 /* g_main_context_unref (context); */
1501 g_slice_free (CheckAccountIdleData, data);
1503 return data->is_online;