40da89c78e68d27d78de14da2911838297ac41d1
[modest] / src / maemo / modest-maemo-utils.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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.
16  *
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.
28  */
29
30 #ifndef DBUS_API_SUBJECT_TO_CHANGE
31 #define DBUS_API_SUBJECT_TO_CHANGE
32 #endif /*DBUS_API_SUBJECT_TO_CHANGE*/
33
34 #include <dbus/dbus.h>
35 #include <dbus/dbus-glib-lowlevel.h>
36 #include <glib.h>
37 #include <glib/gstdio.h>
38 #include <errno.h>
39 #include <string.h> /* for strlen */
40 #include <modest-runtime.h>
41 #include <libgnomevfs/gnome-vfs.h>
42 #include <tny-fs-stream.h>
43 #include <tny-camel-account.h>
44 #include <tny-status.h>
45 #include <tny-camel-transport-account.h>
46 #include <tny-camel-imap-store-account.h>
47 #include <tny-camel-pop-store-account.h>
48 #include "modest-hildon-includes.h"
49
50 #include "modest-maemo-utils.h"
51 #include "modest-platform.h"
52
53 /*
54  * For getting and tracking the Bluetooth name
55  */
56 #define BTNAME_SERVICE                  "org.bluez"
57 #define BTNAME_REQUEST_IF               "org.bluez.Adapter"
58 #define BTNAME_SIGNAL_IF                "org.bluez.Adapter"
59 #define BTNAME_REQUEST_PATH             "/org/bluez/hci0"
60 #define BTNAME_SIGNAL_PATH              "/org/bluez/hci0"
61
62 #define BTNAME_REQ_GET                  "GetName"
63 #define BTNAME_SIG_CHANGED              "NameChanged"
64
65 #define BTNAME_MATCH_RULE "type='signal',interface='" BTNAME_SIGNAL_IF \
66                           "',member='" BTNAME_SIG_CHANGED "'"
67
68
69 static osso_context_t *__osso_context = NULL; /* urgh global */
70
71 osso_context_t *
72 modest_maemo_utils_get_osso_context (void)
73 {
74         if (!__osso_context) 
75                 g_warning ("%s: __osso_context == NULL", __FUNCTION__);
76         
77         return __osso_context;
78 }
79
80 void
81 modest_maemo_utils_set_osso_context (osso_context_t *osso_context)
82 {
83         g_return_if_fail (osso_context);
84         __osso_context = osso_context;
85 }
86
87
88 GQuark
89 modest_maemo_utils_get_supported_secure_authentication_error_quark (void)
90 {
91         return g_quark_from_static_string("modest-maemo-utils-get-supported-secure-authentication-error-quark");
92 }
93
94 GtkWidget*
95 modest_maemo_utils_menubar_to_menu (GtkUIManager *ui_manager)
96 {
97         GtkWidget *main_menu;
98         GtkWidget *menubar;
99         GList *children, *iter;
100
101         g_return_val_if_fail (ui_manager, NULL);
102         
103         /* Create new main menu */
104         main_menu = gtk_menu_new();
105
106         /* Get the menubar from the UI manager */
107         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
108
109         iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
110         while (iter) {
111                 GtkWidget *menu;
112
113                 menu = GTK_WIDGET (iter->data);
114                 gtk_widget_reparent(menu, main_menu);
115
116                 iter = g_list_next (iter);
117         }
118         g_list_free (children);
119         return main_menu;
120 }
121
122
123 static void
124 update_device_name_from_msg (DBusMessage *message)
125 {
126         DBusError error;
127         DBusMessageIter iter;
128
129         dbus_error_init (&error);
130
131         if (dbus_set_error_from_message (&error, message)) {
132                 g_printerr ("modest: failed to get bluetooth name: %s\n", error.message);
133                 dbus_error_free (&error);
134         } else {
135                 const gchar *device_name;
136                 if (!dbus_message_iter_init (message, &iter)) {
137                         g_printerr ("modest: message did not have argument\n");
138                         return;
139                 }
140                 dbus_message_iter_get_basic (&iter, &device_name);
141                 modest_conf_set_string (modest_runtime_get_conf(),
142                                         MODEST_CONF_DEVICE_NAME, device_name,
143                                         NULL);
144         }
145 }
146
147
148 static void
149 on_device_name_received (DBusPendingCall *call, void *user_data)
150 {
151         DBusMessage *message;
152         
153         g_return_if_fail (dbus_pending_call_get_completed (call));
154         
155         message = dbus_pending_call_steal_reply (call);
156         if (!message) {
157                 g_printerr ("modest: no reply on device name query\n");
158                 return;
159         }
160
161         update_device_name_from_msg (message);
162         dbus_message_unref (message);
163 }
164
165
166 static DBusHandlerResult
167 handle_dbus_signal (DBusConnection *conn, DBusMessage *msg, gpointer data)
168 {
169         if (dbus_message_is_signal(msg, BTNAME_SIGNAL_IF, BTNAME_SIG_CHANGED))
170                 update_device_name_from_msg (msg);
171
172         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
173 }
174
175
176 static void
177 get_device_name_from_dbus ()
178 {
179         static DBusConnection *conn = NULL;
180         DBusMessage *request;
181         DBusError error;
182         DBusPendingCall *call = NULL;
183         
184         dbus_error_init (&error);
185         if (!conn) {
186                 conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
187                 if (!conn) {
188                         g_printerr ("modest: cannot get on the dbus: %s: %s\n",
189                                     error.name, error.message);
190                         dbus_error_free (&error);
191                         return;
192                 }
193         }
194         
195         request = dbus_message_new_method_call (BTNAME_SERVICE, BTNAME_REQUEST_PATH,
196                                                 BTNAME_REQUEST_IF, BTNAME_REQ_GET);
197         if (!request) {
198                 /* should we free the connection? */
199                 g_printerr ("modest: dbus_message_new_method_call failed\n");
200                 return;
201         }
202         dbus_message_set_auto_start (request, TRUE);
203         if (dbus_connection_send_with_reply (conn, request, &call, -1)) {
204                 dbus_pending_call_set_notify (call, on_device_name_received,
205                                               NULL, NULL);
206                 dbus_pending_call_unref (call);
207         }
208         dbus_message_unref (request);
209         
210         dbus_connection_setup_with_g_main (conn, NULL);
211         dbus_bus_add_match (conn, BTNAME_MATCH_RULE, &error);
212         if (dbus_error_is_set(&error)) {
213                 g_printerr ("modest: dbus_bus_add_match failed: %s\n", error.message);
214                 dbus_error_free (&error);
215         }
216
217         if (!dbus_connection_add_filter(conn, handle_dbus_signal, NULL, NULL))
218                 g_printerr ("modest: dbus_connection_add_filter failed\n");
219 }
220
221
222 void
223 modest_maemo_utils_get_device_name (void)
224 {
225         get_device_name_from_dbus ();
226 }
227
228 gboolean 
229 modest_maemo_utils_folder_writable (const gchar *filename)
230 {
231         g_return_val_if_fail (filename, FALSE);
232
233         if (!filename)
234                 return FALSE;
235         
236         if (g_strncasecmp (filename, "obex", 4) != 0) {
237                 GnomeVFSFileInfo folder_info;
238                 gchar *folder;
239                 folder = g_path_get_dirname (filename);
240                 gnome_vfs_get_file_info (folder, &folder_info,
241                                          GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS);
242                 g_free (folder);
243                 if (!((folder_info.permissions & GNOME_VFS_PERM_ACCESS_WRITABLE) ||
244                       (folder_info.permissions & GNOME_VFS_PERM_USER_WRITE))) {
245                         return FALSE;
246                 }
247         }
248         return TRUE;
249 }
250
251 gboolean 
252 modest_maemo_utils_file_exists (const gchar *filename)
253 {
254         GnomeVFSURI *uri = NULL;
255         gboolean result = FALSE;
256
257         uri = gnome_vfs_uri_new (filename);
258         if (uri) {
259                 result = gnome_vfs_uri_exists (uri);
260                 gnome_vfs_uri_unref (uri);
261         }
262         return result;
263 }
264
265 TnyFsStream *
266 modest_maemo_utils_create_temp_stream (const gchar *orig_name, const gchar *hash_base, gchar **path)
267 {
268         gint fd;
269         gchar *filepath = NULL;
270         gchar *tmpdir;
271         guint hash_number;
272
273         /* hmmm... maybe we need a modest_text_utils_validate_file_name? */
274         g_return_val_if_fail (orig_name || strlen(orig_name) == 0, NULL);
275         if (strlen(orig_name) > 200) {
276                 g_warning ("%s: filename too long ('%s')",
277                            __FUNCTION__, orig_name);
278                 return NULL;
279         }
280         
281         if (g_strstr_len (orig_name, strlen(orig_name), "/") != NULL) {
282                 g_warning ("%s: filename contains '/' character(s) (%s)",
283                            __FUNCTION__, orig_name);
284                 return NULL;
285         }
286                 
287         /* make a random subdir under /tmp or /var/tmp */
288         if (hash_base != NULL) {
289                 hash_number = g_str_hash (hash_base);
290         } else {
291                 hash_number = (guint) random ();
292         }
293         tmpdir = g_strdup_printf ("%s/%u", g_get_tmp_dir (), hash_number);
294         if ((g_access (tmpdir, R_OK) == -1) && (g_mkdir (tmpdir, 0755) == -1)) {
295                 g_warning ("%s: failed to create dir '%s': %s",
296                            __FUNCTION__, tmpdir, g_strerror(errno));
297                 g_free (tmpdir);
298                 return NULL;
299         }
300
301         /* try to write the file there */
302         filepath = g_strconcat (tmpdir, "/", orig_name, NULL);
303         fd = g_open (filepath, O_CREAT|O_WRONLY|O_TRUNC, 0644);
304         if (fd == -1) {
305                 g_warning ("%s: failed to create '%s': %s",
306                            __FUNCTION__, filepath, g_strerror(errno));
307                 g_free (tmpdir);
308                 g_free (filepath);
309                 return NULL;
310         }
311
312         g_free (tmpdir);
313
314         if (path)
315                 *path = filepath;
316
317         return TNY_FS_STREAM (tny_fs_stream_new (fd));
318 }
319
320 typedef struct 
321 {
322         gboolean cancel;
323         GList *result;
324         GtkWidget* dialog;
325         GtkWidget* progress;
326         GError* error;
327 } ModestGetSupportedAuthInfo;
328
329 static void on_camel_account_get_supported_secure_authentication_status (
330         GObject *self, TnyStatus *status, gpointer user_data)
331 {
332         /*ModestGetSupportedAuthInfo* info = (ModestGetSupportedAuthInfo*) user_data;*/
333 }
334
335 static gboolean
336 on_idle_secure_auth_finished (gpointer user_data)
337 {
338         ModestGetSupportedAuthInfo *info = (ModestGetSupportedAuthInfo*)user_data;
339         /* Operation has finished, close the dialog. Control continues after
340          * gtk_dialog_run in modest_maemo_utils_get_supported_secure_authentication_methods() */
341
342         /* This is a GDK lock because we are an idle callback and
343          * the code below is or does Gtk+ code */
344
345         gdk_threads_enter(); /* CHECKED */
346         gtk_dialog_response (GTK_DIALOG (info->dialog), GTK_RESPONSE_ACCEPT);
347         gdk_threads_leave(); /* CHECKED */
348
349         return FALSE;
350 }
351
352 static void
353 on_camel_account_get_supported_secure_authentication (
354   TnyCamelAccount *self, gboolean cancelled,
355   TnyList *auth_types, GError *err, 
356   gpointer user_data)
357 {
358         ModestGetSupportedAuthInfo *info = (ModestGetSupportedAuthInfo*)user_data;
359         g_return_if_fail (info);
360         
361
362         /* Free everything if the actual action was canceled */
363         if (info->cancel)
364         {
365                 /* The operation was canceled and the ownership of the info given to us
366                  * so that we could still check the cancel flag. */
367                 g_slice_free (ModestGetSupportedAuthInfo, info);
368                 info = NULL;
369         }
370         else
371         {
372                 if (err)
373                 {
374                         if (info->error) {
375                                 g_error_free (info->error);
376                                 info->error = NULL;
377                         }
378                         
379                         info->error = g_error_copy (err);
380                 }
381
382                 if (!auth_types) {
383                         g_warning ("DEBUG: %s: auth_types is NULL.\n", __FUNCTION__);
384                 }
385                 else if (tny_list_get_length(auth_types) == 0) {
386                         g_warning ("DEBUG: %s: auth_types is an empty TnyList.\n", __FUNCTION__);
387                 } else
388                 {
389                         ModestPairList* pairs = modest_protocol_info_get_auth_protocol_pair_list ();
390   
391                         /* Get the enum value for the strings: */
392                         GList *result = NULL;
393                         TnyIterator* iter = tny_list_create_iterator(auth_types);
394                         while (!tny_iterator_is_done(iter)) {
395                                 TnyPair *pair = TNY_PAIR(tny_iterator_get_current(iter));
396                                 const gchar *auth_name = NULL;
397                                 if (pair) {
398                                         auth_name = tny_pair_get_name(pair);
399                                         g_object_unref (pair);
400                                         pair = NULL;
401                                 }
402
403                                 printf("DEBUG: %s: auth_name=%s\n", __FUNCTION__, auth_name);
404
405                                 ModestAuthProtocol proto = modest_protocol_info_get_auth_protocol (auth_name);
406                                 if(proto != MODEST_PROTOCOL_AUTH_NONE)
407                                                 result = g_list_prepend(result, GINT_TO_POINTER(proto));
408
409                                 tny_iterator_next(iter);
410                         }
411                         g_object_unref (iter);
412
413                         modest_pair_list_free (pairs);
414         
415                         info->result = result;
416                 }
417
418                 printf("DEBUG: finished\n");
419                                 
420                 /* Close the dialog in a main thread */
421                 g_idle_add(on_idle_secure_auth_finished, info);
422         }
423 }
424
425 static void on_secure_auth_cancel(GtkWidget* dialog, int response, gpointer user_data)
426 {
427         if(response == GTK_RESPONSE_REJECT || response == GTK_RESPONSE_DELETE_EVENT)
428         {
429                 ModestGetSupportedAuthInfo *info = (ModestGetSupportedAuthInfo*)user_data;
430                 g_return_if_fail(info);
431                 /* This gives the ownership of the info to the worker thread. */
432                 info->result = NULL;
433                 info->cancel = TRUE;
434         }
435 }
436
437 GList*
438 modest_maemo_utils_get_supported_secure_authentication_methods (ModestTransportStoreProtocol proto, 
439         const gchar* hostname, gint port, const gchar* username, GtkWindow *parent_window, GError** error)
440 {
441         g_return_val_if_fail (proto != MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN, NULL);
442         
443         /* We need a connection to get the capabilities; */
444         if (!modest_platform_connect_and_wait (GTK_WINDOW (parent_window), NULL))
445                 return NULL;
446          
447         /*
448         result = g_list_append (result, GINT_TO_POINTER (MODEST_PROTOCOL_AUTH_CRAMMD5));
449         */
450         
451         /* Create a TnyCamelAccount so we can use 
452          * tny_camel_account_get_supported_secure_authentication(): */
453         TnyAccount * tny_account = NULL;
454         switch (proto) {
455         case MODEST_PROTOCOL_TRANSPORT_SENDMAIL:
456         case MODEST_PROTOCOL_TRANSPORT_SMTP:
457                 tny_account = TNY_ACCOUNT(tny_camel_transport_account_new ()); break;
458         case MODEST_PROTOCOL_STORE_POP:
459                 tny_account = TNY_ACCOUNT(tny_camel_pop_store_account_new ()); break;
460         case MODEST_PROTOCOL_STORE_IMAP:
461                 tny_account = TNY_ACCOUNT(tny_camel_imap_store_account_new ()); break;
462         case MODEST_PROTOCOL_STORE_MAILDIR:
463         case MODEST_PROTOCOL_STORE_MBOX:
464                 tny_account = TNY_ACCOUNT(tny_camel_store_account_new()); break;
465         default:
466                 tny_account = NULL;
467         }
468
469         
470         if (!tny_account) {
471                 g_printerr ("%s could not create tny account.", __FUNCTION__);
472                 return NULL;
473         }
474         
475         /* Set proto, so that the prepare_func() vfunc will work when we call 
476          * set_session(): */
477          /* TODO: Why isn't this done in account_new()? */
478         tny_account_set_proto (tny_account,
479                                modest_protocol_info_get_transport_store_protocol_name(proto));
480
481         tny_account_set_hostname (tny_account, hostname);
482         /* Required for POP, at least */
483         tny_account_set_user (tny_account, username);
484                                
485         if(port > 0)
486                 tny_account_set_port (tny_account, port);
487                 
488         /* Set the session for the account, so we can use it: */
489         ModestTnyAccountStore *account_store = modest_runtime_get_account_store ();
490         TnySessionCamel *session = 
491                 modest_tny_account_store_get_session (TNY_ACCOUNT_STORE (account_store));
492         g_return_val_if_fail (session, NULL);
493         tny_camel_account_set_session (TNY_CAMEL_ACCOUNT(tny_account), session);
494         
495         
496         /* Ask camel to ask the server, asynchronously: */
497         ModestGetSupportedAuthInfo *info = g_slice_new (ModestGetSupportedAuthInfo);
498         info->result = NULL;
499         info->cancel = FALSE;
500         info->error = NULL;
501         info->progress = gtk_progress_bar_new();
502         /* TODO: Need logical_ID for the title: */
503         info->dialog = gtk_dialog_new_with_buttons(_("Authentication"),
504                                                    parent_window, GTK_DIALOG_MODAL,
505                                                    _("mcen_bd_dialog_cancel"),
506                                                    GTK_RESPONSE_REJECT,
507                                                    NULL);
508         //gtk_window_set_default_size(GTK_WINDOW(info->dialog), 300, 100);
509         
510         g_signal_connect(G_OBJECT(info->dialog), "response", G_CALLBACK(on_secure_auth_cancel), info);
511         
512         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(info->dialog)->vbox),
513                           gtk_label_new("Checking for supported authentication types..."));
514         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(info->dialog)->vbox), info->progress);
515         gtk_widget_show_all(info->dialog);
516         gtk_progress_bar_pulse(GTK_PROGRESS_BAR(info->progress));
517         
518         printf ("DEBUG: %s: STARTING.\n", __FUNCTION__);
519         tny_camel_account_get_supported_secure_authentication (
520                 TNY_CAMEL_ACCOUNT (tny_account),
521                 on_camel_account_get_supported_secure_authentication,
522                 on_camel_account_get_supported_secure_authentication_status,
523                 info);
524
525         gtk_dialog_run (GTK_DIALOG (info->dialog));
526         
527         gtk_widget_destroy(info->dialog);
528                         
529         GList *result = info->result;
530         if (!info->cancel)
531         {
532                 if (info->error) {
533                         gchar * debug_url_string = tny_account_get_url_string  (tny_account);
534                         g_warning ("DEBUG: %s:\n  error: %s\n  account url: %s", __FUNCTION__, info->error->message, 
535                                 debug_url_string);
536                         g_free (debug_url_string);
537                         
538                         g_propagate_error(error, info->error);
539                         info->error = NULL;
540                 }
541
542                 g_slice_free (ModestGetSupportedAuthInfo, info);
543                 info = NULL;
544         }
545         else
546         {
547                 // Tell the caller that the operation was canceled so it can
548                 // make a difference
549                 g_set_error(error,
550                             modest_maemo_utils_get_supported_secure_authentication_error_quark(),
551                             MODEST_MAEMO_UTILS_GET_SUPPORTED_SECURE_AUTHENTICATION_ERROR_CANCELED,
552                             "User has canceled query");
553         }
554
555         return result;
556 }
557
558 void
559 modest_maemo_utils_setup_images_filechooser (GtkFileChooser *chooser)
560 {
561         gchar *images_folder;
562         GtkFileFilter *file_filter;
563         GList *image_mimetypes_list;
564         GList *node;
565
566         g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
567
568         /* Set the default folder to images folder */
569         images_folder = g_build_filename (g_get_home_dir (), 
570                                           MODEST_MAEMO_UTILS_MYDOCS_FOLDER,
571                                           MODEST_MAEMO_UTILS_DEFAULT_IMAGE_FOLDER, NULL);
572         gtk_file_chooser_set_current_folder (chooser, images_folder);
573         g_free (images_folder);
574
575         /* Set the images mime filter */
576         file_filter = gtk_file_filter_new ();
577 #ifdef MODEST_HAVE_HILDON0_WIDGETS
578         image_mimetypes_list = osso_mime_get_mime_types_for_category (OSSO_MIME_CATEGORY_IMAGES);
579 #else
580         image_mimetypes_list = hildon_mime_get_mime_types_for_category (HILDON_MIME_CATEGORY_IMAGES);
581 #endif
582         for (node = image_mimetypes_list; node != NULL; node = g_list_next (node)) {
583                 gtk_file_filter_add_mime_type (file_filter, node->data);
584         }
585         gtk_file_chooser_set_filter (chooser, file_filter);
586 #ifdef MODEST_HAVE_HILDON0_WIDGETS
587         osso_mime_types_list_free (image_mimetypes_list);
588 #else
589         hildon_mime_types_list_free (image_mimetypes_list);
590 #endif
591
592 }
593
594 #if 0
595 static void
596 on_hide (GtkDialog *dialog, gpointer user_data)
597 {
598         /* Just destroy the dialog: */
599         gtk_widget_destroy (GTK_WIDGET (dialog));
600 }
601 #endif
602
603 #if 0 /* Not used now. */
604 /* user_data for the idle callback: */
605 typedef struct 
606 {
607         GtkWindow *parent_window;
608         gchar *message;
609 } ModestIdleNoteInfo;
610
611 static gboolean
612 on_idle_show_information(gpointer user_data)
613 {
614         ModestIdleNoteInfo *info = (ModestIdleNoteInfo*)user_data;
615         
616         modest_maemo_show_information_note_and_forget (info->parent_window, info->message);
617         
618         g_free (info->message);
619         g_slice_free (ModestIdleNoteInfo, info);
620         
621         return FALSE; /* Don't call this again. */
622 }
623
624 void 
625 modest_maemo_show_information_note_in_main_context_and_forget (GtkWindow *parent_window, 
626                                                                const gchar* message)
627 {
628         ModestIdleNoteInfo *info = g_slice_new (ModestIdleNoteInfo);
629         info->parent_window = parent_window;
630         info->message = g_strdup (message);
631         
632         g_idle_add (on_idle_show_information, info);
633 }
634 #endif
635
636 void 
637 modest_maemo_show_dialog_and_forget (GtkWindow *parent_window, 
638                                      GtkDialog *dialog)
639 {
640         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
641         
642         /* Destroy the dialog when it is closed: */
643         g_signal_connect_swapped (dialog, 
644                                   "response", 
645                                   G_CALLBACK (gtk_widget_destroy), 
646                                   dialog);
647
648         gtk_widget_show (GTK_WIDGET (dialog));
649 }
650
651
652
653 void
654 modest_maemo_set_thumbable_scrollbar (GtkScrolledWindow *win, 
655                                       gboolean thumbable)
656 {
657         g_return_if_fail (GTK_IS_SCROLLED_WINDOW(win));
658 #ifdef MODEST_HAVE_HILDON1_WIDGETS              
659         hildon_helper_set_thumb_scrollbar (win, thumbable);
660 #endif /* MODEST_HAVE_HILDON1_WIDGETS */
661 }
662
663 void
664 modest_maemo_toggle_action_set_active_block_notify (GtkToggleAction *action, gboolean value)
665 {
666         GSList *proxies = NULL;
667
668         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
669
670         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
671              proxies != NULL; proxies = g_slist_next (proxies)) {
672                 GtkWidget *widget = (GtkWidget *) proxies->data;
673                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
674         }
675
676         gtk_toggle_action_set_active (action, value);
677
678         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
679              proxies != NULL; proxies = g_slist_next (proxies)) {
680                 GtkWidget *widget = (GtkWidget *) proxies->data;
681                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
682         }
683
684 }
685
686
687
688 FILE*
689 modest_maemo_open_mcc_mapping_file (void)
690 {
691         FILE* result;
692         
693         /* Load the file one line at a time: */
694 #ifdef MODEST_HILDON_VERSION_0
695         const gchar* filepath = PROVIDER_DATA_DIR "/mcc_mapping";
696 #else
697         const gchar* filepath = "/usr/share/operator-wizard/mcc_mapping";
698 #endif /*MODEST_HILDON_VERSION_0*/
699         
700         result = fopen (filepath, "r"); 
701         if (!result) 
702                 g_printerr ("modest: failed to open mcc mapping file");
703         
704         return result;
705 }
706
707