b545c480f8b336c709878b126bfaaa86292fc1c3
[modest] / src / hildon2 / 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-defs.h>
51 #include "modest-maemo-utils.h"
52 #include "modest-text-utils.h"
53 #include "modest-platform.h"
54 #include "modest-ui-constants.h"
55 #include <hildon/hildon-picker-dialog.h>
56 #ifdef MODEST_USE_IPHB
57 #include <iphbd/libiphb.h>
58 #endif
59
60 /* Label child of a captioned */
61 #define CAPTIONED_LABEL_CHILD "captioned-label"
62
63 #ifdef MODEST_PLATFORM_MAEMO
64 #define INTERNAL_MMC_USB_MODE  "/system/osso/af/internal-mmc-used-over-usb"
65 #endif
66
67 static osso_context_t *__osso_context = NULL; /* urgh global */
68
69 osso_context_t *
70 modest_maemo_utils_get_osso_context (void)
71 {
72         if (!__osso_context) 
73                 __osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
74                                                  FALSE, NULL);
75
76         return __osso_context;
77 }
78
79 static void
80 get_properties_cb (DBusMessage *message)
81 {
82         DBusMessageIter iter;
83         DBusMessageIter dict_iter;
84         DBusMessageIter dict_entry_iter;
85         DBusError err;
86         gchar *bt_name = NULL;
87         int key_type, array_type, msg_type;
88
89         dbus_error_init(&err);
90         if (dbus_set_error_from_message (&err, message)) {
91                 g_warning ("%s: %s", __FUNCTION__, err.message);
92         }
93
94         /* Get msg type */
95         dbus_message_iter_init (message, &iter);
96         msg_type = dbus_message_iter_get_arg_type (&iter);
97         dbus_message_iter_recurse (&iter, &dict_iter);
98
99         while ((array_type = dbus_message_iter_get_arg_type (&dict_iter)) == DBUS_TYPE_DICT_ENTRY) {
100
101                 dbus_message_iter_recurse (&dict_iter, &dict_entry_iter);
102
103                 while ((key_type = dbus_message_iter_get_arg_type (&dict_entry_iter)) == DBUS_TYPE_STRING) {
104                         DBusMessageIter dict_entry_content_iter;
105                         char *key;
106                         char *value;
107                         int dict_entry_type;
108                         int dict_entry_content_type;
109
110                         dbus_message_iter_get_basic (&dict_entry_iter, &key);
111                         dbus_message_iter_next (&dict_entry_iter);
112                         dict_entry_type = dbus_message_iter_get_arg_type (&dict_entry_iter);
113                         dbus_message_iter_recurse (&dict_entry_iter, &dict_entry_content_iter);
114                         dict_entry_content_type = dbus_message_iter_get_arg_type (&dict_entry_content_iter);
115
116                         if (dict_entry_content_type == DBUS_TYPE_STRING) {
117                                 dbus_message_iter_get_basic ( &dict_entry_content_iter, &value );
118
119                                 if (strcmp (key, "Name") == 0 ) {
120                                         g_debug ("-------------Name %s", value);
121                                         bt_name = value;
122                                         break;
123                                 }
124                         }
125                         dbus_message_iter_next (&dict_entry_iter);
126                 }
127
128                 if (key_type != DBUS_TYPE_INVALID)
129                         break;
130
131                 dbus_message_iter_next (&dict_iter);
132         }
133
134         /* Save device name */
135         if (bt_name) {
136                 g_debug ("Setting the device name %s", bt_name);
137                 modest_conf_set_string (modest_runtime_get_conf(),
138                                         MODEST_CONF_DEVICE_NAME, bt_name,
139                                         NULL);
140         }
141 }
142
143 static void
144 get_default_adapter_cb (DBusConnection *conn,
145                         DBusMessage *message)
146 {
147         DBusMessageIter iter;
148         gchar* path = NULL;
149         DBusError error;
150         DBusMessage *msg, *adapterMsg;
151
152         dbus_message_iter_init (message, &iter);
153         dbus_message_iter_get_basic (&iter, &path);
154
155         if (!path)
156                 return;
157
158         adapterMsg = dbus_message_new_method_call ("org.bluez", path,
159                                                    "org.bluez.Adapter",
160                                                    "GetProperties");
161
162         dbus_error_init (&error);
163         msg = dbus_connection_send_with_reply_and_block (conn, adapterMsg, -1, &error);
164         if (msg) {
165                 g_debug ("Getting the properties");
166                 get_properties_cb (msg);
167                 dbus_message_unref (msg);
168         }
169         dbus_message_unref (adapterMsg);
170 }
171
172 void
173 modest_maemo_utils_get_device_name (void)
174 {
175         static DBusConnection *conn = NULL;
176         DBusMessage *request;
177         DBusError error;
178         DBusMessage *msg;
179
180         dbus_error_init (&error);
181         if (!conn) {
182                 conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
183                 if (!conn) {
184                         g_printerr ("modest: cannot get on the dbus: %s: %s\n",
185                                     error.name, error.message);
186                         dbus_error_free (&error);
187                         return;
188                 }
189         }
190
191         /* Get the default adapter */
192         request = dbus_message_new_method_call ("org.bluez", "/" ,
193                                                 "org.bluez.Manager",
194                                                 "DefaultAdapter");
195
196         msg = dbus_connection_send_with_reply_and_block (conn, request, -1, &error);
197         if (msg) {
198                 g_debug ("Getting the default adapter");
199                 get_default_adapter_cb (conn, msg);
200                 dbus_message_unref (msg);
201         }
202
203         dbus_message_unref (request);
204         if (dbus_error_is_set (&error))
205                 dbus_error_free (&error);
206 }
207
208 void
209 modest_maemo_utils_setup_images_filechooser (GtkFileChooser *chooser)
210 {
211         GtkFileFilter *file_filter;
212         GList *image_mimetypes_list;
213         GList *node;
214         gchar *conf_folder;
215
216         g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
217
218         conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
219                                               MODEST_CONF_LATEST_INSERT_IMAGE_PATH, NULL);
220         if (conf_folder && conf_folder[0] != '\0') {
221                 gtk_file_chooser_set_current_folder_uri (chooser, conf_folder);
222         } else {
223                 gchar *images_folder;
224                 /* Set the default folder to images folder */
225                 images_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
226                 if (!images_folder) {
227                         /* fallback */
228                         images_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
229                                                           MODEST_MAEMO_UTILS_DEFAULT_IMAGE_FOLDER, NULL);
230                 }
231                 gtk_file_chooser_set_current_folder (chooser, images_folder);
232                 g_free (images_folder);
233         }
234         g_free (conf_folder);
235
236         /* Set the images mime filter */
237         file_filter = gtk_file_filter_new ();
238         image_mimetypes_list = hildon_mime_get_mime_types_for_category (HILDON_MIME_CATEGORY_IMAGES);
239         for (node = image_mimetypes_list; node != NULL; node = g_list_next (node)) {
240                 gtk_file_filter_add_mime_type (file_filter, node->data);
241         }
242         gtk_file_chooser_set_filter (chooser, file_filter);
243         hildon_mime_types_list_free (image_mimetypes_list);
244
245 }
246
247 static gboolean match_all (TnyList *list, GObject *item, gpointer match_data)
248 {
249         return TRUE;
250 }
251
252 gboolean
253 modest_maemo_utils_select_attachments (GtkWindow *window, TnyList *att_list, gboolean include_msgs)
254 {
255         GtkTreeModel *model;
256         TnyIterator *iterator;
257         GtkWidget *selector;
258         GtkCellRenderer *renderer;
259         GtkWidget *dialog;
260         gint response;
261         gboolean result = TRUE;
262         gint attachments_added = 0;
263
264         model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT));
265         for (iterator = tny_list_create_iterator (att_list);
266              !tny_iterator_is_done (iterator);
267              tny_iterator_next (iterator)) {
268                 GtkTreeIter iter;
269                 TnyMimePart *part;
270                 gchar *filename = NULL;
271
272                 part = (TnyMimePart *) tny_iterator_get_current (iterator);
273
274                 /* Ignore purged attachments and messages if ignore is
275                    set to TRUE */
276                 if (!(tny_mime_part_is_purged (part) ||
277                       (TNY_IS_MSG (part) && !include_msgs))) {
278
279                         if (TNY_IS_MSG (part)) {
280                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
281                                 filename = tny_header_dup_subject (header);
282                                 g_object_unref (header);
283                         } else {
284                                 filename = g_strdup (tny_mime_part_get_filename (part));
285                         }
286                         if ((filename == NULL) || (filename[0] == '\0')) {
287                                 g_free (filename);
288                                 filename = g_strdup (_("mail_va_no_subject"));
289                         }
290                         gtk_list_store_append (GTK_LIST_STORE (model), &iter);
291                         gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, filename, 1, part, -1);
292                         attachments_added ++;
293                         g_free (filename);
294                 }
295                 g_object_unref (part);
296         }
297         g_object_unref (iterator);
298
299         selector = GTK_WIDGET (hildon_touch_selector_new ());
300         renderer = gtk_cell_renderer_text_new ();
301         g_object_set((GObject *) renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
302         hildon_touch_selector_append_column ((HildonTouchSelector *) selector, model, renderer,
303                                              "text", 0, NULL);
304         hildon_touch_selector_set_column_selection_mode ((HildonTouchSelector *) selector, 
305                                                          HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
306
307         dialog = hildon_picker_dialog_new (window);
308         gtk_window_set_title (GTK_WINDOW (dialog), (attachments_added > 1)?
309                               _("mcen_ti_select_attachments_title"):_("mcen_ti_select_attachment_title"));
310         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), (HildonTouchSelector *) selector);
311         hildon_touch_selector_unselect_all ((HildonTouchSelector *) selector, 0);
312         hildon_picker_dialog_set_done_label (HILDON_PICKER_DIALOG (dialog), _HL("wdgt_bd_done"));
313
314         response = gtk_dialog_run (GTK_DIALOG (dialog));
315
316         if (response == GTK_RESPONSE_OK) {
317                 GList *selected_rows, *node;
318
319                 tny_list_remove_matches (att_list, match_all, NULL);
320                 selected_rows = hildon_touch_selector_get_selected_rows ((HildonTouchSelector *) selector, 0);
321                 for (node = selected_rows; node != NULL; node = g_list_next (node)) {
322                         GtkTreePath *path;
323                         GObject *selected;
324                         GtkTreeIter iter;
325
326                         path = (GtkTreePath *) node->data;
327                         gtk_tree_model_get_iter (model, &iter, path);
328                         gtk_tree_model_get (model, &iter, 1, &selected, -1);
329                         tny_list_append (att_list, selected);
330                 }
331                 if (tny_list_get_length (att_list) == 0)
332                         result = FALSE;
333
334                 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
335                 g_list_free (selected_rows);
336         } else {
337                 result = FALSE;
338         }
339
340         gtk_widget_destroy (dialog);
341
342         g_object_unref (model);
343
344         return result;
345 }
346
347 #ifdef MODEST_PLATFORM_MAEMO
348 gboolean
349 modest_maemo_utils_in_usb_mode ()
350 {
351         return modest_conf_get_bool (modest_runtime_get_conf (), INTERNAL_MMC_USB_MODE, NULL);
352 }
353 #endif
354
355 #ifdef MODEST_USE_IPHB
356
357 typedef struct _ModestHeartbeatSource {
358         GSource source;
359         iphb_t iphb;
360         GPollFD poll;
361         gint interval;
362 } ModestHeartbeatSource;
363
364 static gboolean modest_heartbeat_prepare (GSource* source, gint *timeout)
365 {
366     *timeout = -1;
367     return FALSE;
368 }
369
370 static gboolean 
371 modest_heartbeat_check(GSource* source)
372 {
373         return ((ModestHeartbeatSource *) source)->poll.revents != 0;
374 }
375
376 static gboolean modest_heartbeat_dispatch (GSource *source, GSourceFunc callback, gpointer userdata)
377 {
378     if (callback(userdata))
379     {
380             ModestHeartbeatSource *hb_source = (ModestHeartbeatSource *) source;
381
382             g_source_remove_poll (source, &(hb_source->poll));
383
384             int min = MAX(hb_source->interval - 30, 5);
385             iphb_wait(hb_source->iphb, min, min + 60, 0);
386
387             hb_source->poll.fd = iphb_get_fd(hb_source->iphb);
388             hb_source->poll.events = G_IO_IN;
389             hb_source->poll.revents = 0;
390
391             g_source_add_poll(source, &(hb_source->poll));
392
393             return TRUE;
394     } else {
395             return FALSE;
396     }
397 }
398
399 static void 
400 modest_heartbeat_finalize (GSource* source)
401 {
402         ModestHeartbeatSource* hb_source = (ModestHeartbeatSource *) source;
403         hb_source->iphb = iphb_close(hb_source->iphb);
404 }
405
406 GSourceFuncs modest_heartbeat_funcs =
407 {
408   modest_heartbeat_prepare,
409   modest_heartbeat_check,
410   modest_heartbeat_dispatch,
411   modest_heartbeat_finalize,
412   NULL,
413   NULL
414 };
415
416 static GSource *
417 modest_heartbeat_source_new (void)
418 {
419         GSource *source;
420         ModestHeartbeatSource *hb_source;
421         iphb_t iphb;
422         int hb_interval;
423
424         source = NULL;
425         hb_interval = 0;
426
427         iphb = iphb_open (&hb_interval);
428
429         if (iphb != 0) {
430                 int min;
431                 source = g_source_new (&modest_heartbeat_funcs, sizeof (ModestHeartbeatSource));
432                 hb_source = (ModestHeartbeatSource *) source;
433                 g_source_set_priority (source, G_PRIORITY_DEFAULT_IDLE);
434                 hb_source->iphb = iphb;
435                 hb_source->interval = hb_interval;
436
437                 min = MAX(hb_interval - 30, 5);
438                 iphb_wait(hb_source->iphb, min, min + 60, 0);
439
440                 hb_source->poll.fd = iphb_get_fd(hb_source->iphb);
441                 hb_source->poll.events = G_IO_IN;
442                 hb_source->poll.revents = 0;
443
444                 g_source_add_poll(source, &(hb_source->poll));
445         } else {
446                 source = g_idle_source_new ();
447         }
448
449         return source;
450 }
451
452 guint
453 modest_heartbeat_add (GSourceFunc function,
454                       gpointer userdata)
455 {
456         GSource *source;
457         guint id;
458
459         source = modest_heartbeat_source_new ();
460         g_source_set_callback (source, function, userdata, NULL);
461         id = g_source_attach (source, NULL);
462         g_source_unref (source);
463
464         return id;
465 }
466
467 #else
468 guint
469 modest_heartbeat_add (GSourceFunc function,
470                       gpointer userdata)
471 {
472         return g_idle_add (function, userdata);
473 }
474 #endif