Added OpenEditAccountsDialog service to libmodest dbus client
[modest] / libmodest-dbus-client / src / libmodest-dbus-client.c
1 /* Copyright (c) 2007, 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 #include "libmodest-dbus-client.h"
31 #include "libmodest-dbus-api.h" /* For the API strings. */
32
33 //#define DBUS_API_SUBJECT_TO_CHANGE 1
34 #include <dbus/dbus.h>
35 #include <dbus/dbus-glib-lowlevel.h>
36 #include <string.h>
37
38
39
40 /** Get a comma-separated list of attachement URI strings, 
41  * from a list of strings.
42  */
43 static gchar* get_attachments_string (GSList *attachments)
44 {
45         if (!attachments)
46                 return NULL;
47
48         gchar *attachments_str = g_strdup("");
49
50         GSList *iter = attachments;
51         while (iter)
52         {
53                 if (iter->data) {
54                         gchar *escaped;
55                         gchar *tmp;
56                         escaped = g_uri_escape_string ((const gchar *) (iter->data), NULL, TRUE);
57                         tmp = g_strconcat(attachments_str, ",", escaped, NULL);
58                         g_free(escaped);
59                         g_free(attachments_str);
60                         attachments_str = tmp;
61                 }
62                 iter = g_slist_next(iter);
63         }
64         return attachments_str;
65 }
66
67 /**
68  * libmodest_dbus_client_mail_to:
69  * @osso_context: a valid #osso_context_t object.
70  * @mailto_uri: A mailto URI.
71  * 
72  * This function will try to do a remote procedure call (rpc)
73  * into modest (or start it if necessary) and open a composer
74  * window with the supplied parameters prefilled.
75  *
76  * Return value: Whether or not the rpc call to modest
77  * was successfull
78  **/
79 gboolean 
80 libmodest_dbus_client_mail_to (osso_context_t *osso_context, const gchar *mailto_uri)
81 {
82         osso_rpc_t retval = { 0 };
83         const osso_return_t ret = osso_rpc_run_with_defaults(osso_context, 
84                    MODEST_DBUS_NAME, 
85                    MODEST_DBUS_METHOD_MAIL_TO, &retval, 
86                    DBUS_TYPE_STRING, mailto_uri, 
87                    DBUS_TYPE_INVALID);
88                 
89         if (ret != OSSO_OK) {
90                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
91                 return FALSE;
92         } else {
93                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
94         }
95         
96         osso_rpc_free_val(&retval);
97         
98         return TRUE;
99 }
100
101 /**
102  * libmodest_dbus_client_compose_mail:
103  * @osso_context: a valid #osso_context_t object.
104  * @to: The Recipients (From: line)
105  * @cc: Recipients for carbon copies
106  * @bcc: Recipients for blind carbon copies
107  * @subject: Subject line
108  * @body: The actual body of the mail to compose.
109  * @attachments: Additional list of attachments. A list of URI strings.
110  * 
111  * This function will try to do a remote procedure call (rpc)
112  * into modest (or start it if necessary) and open a composer
113  * window with the supplied parameters prefilled.
114  *
115  * Return value: Whether or not the rpc call to modest
116  * was successfull
117  **/
118 gboolean
119 libmodest_dbus_client_compose_mail (osso_context_t *osso_context, const gchar *to, const gchar *cc, 
120         const gchar *bcc, const gchar* subject, const gchar* body, GSList *attachments)
121 {
122         osso_rpc_t retval = { 0 };
123
124         gchar *attachments_str = get_attachments_string(attachments);
125
126         const osso_return_t ret = osso_rpc_run_with_defaults(osso_context,
127                    MODEST_DBUS_NAME, 
128                    MODEST_DBUS_METHOD_COMPOSE_MAIL, &retval, 
129                    DBUS_TYPE_STRING, to, 
130                    DBUS_TYPE_STRING, cc, 
131                    DBUS_TYPE_STRING, bcc, 
132                    DBUS_TYPE_STRING, subject, 
133                    DBUS_TYPE_STRING, body,
134                    DBUS_TYPE_STRING, attachments_str,
135                    DBUS_TYPE_INVALID);
136
137         g_free (attachments_str);
138
139         if (ret != OSSO_OK) {
140                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
141                 return FALSE;
142         } else {
143                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
144         }
145
146         osso_rpc_free_val(&retval);
147
148
149         return TRUE;
150 }
151
152 /**
153  * libmodest_dbus_client_open_message:
154  * @osso_context: a valid #osso_context_t object.
155  * @msg_uri: A valid url to a mail
156  *
157  * This method will try to find the message supplied
158  * by @msg_uri and open it for display if found. 
159  * It will use remote procedure calls (rpc) over 
160  * dbus to do so.
161  *  
162  * Return value: TRUE on successs, FALSE on error
163  **/
164 gboolean 
165 libmodest_dbus_client_open_message (osso_context_t *osso_context, const gchar *mail_uri)
166 {
167         osso_rpc_t retval = { 0 };
168         const osso_return_t ret = osso_rpc_run_with_defaults(osso_context, 
169                    MODEST_DBUS_NAME, 
170                    MODEST_DBUS_METHOD_OPEN_MESSAGE, &retval, 
171                    DBUS_TYPE_STRING, mail_uri, 
172                    DBUS_TYPE_INVALID);
173                 
174         if (ret != OSSO_OK) {
175                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
176                 return FALSE;
177         } else {
178                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
179         }
180         
181         osso_rpc_free_val(&retval);
182         
183         return TRUE;
184 }
185
186 gboolean 
187 libmodest_dbus_client_send_and_receive (osso_context_t *osso_context)
188 {
189         osso_rpc_t retval = { 0 };
190         const osso_return_t ret = osso_rpc_run_with_defaults(osso_context, 
191                    MODEST_DBUS_NAME, 
192                    MODEST_DBUS_METHOD_SEND_RECEIVE, &retval, 
193                    DBUS_TYPE_INVALID);
194                 
195         if (ret != OSSO_OK) {
196                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
197                 return FALSE;
198         } else {
199                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
200         }
201         
202         osso_rpc_free_val(&retval);
203         
204         return TRUE;
205 }
206
207 gboolean 
208 libmodest_dbus_client_send_and_receive_full (osso_context_t *osso_context, 
209                                              const gchar *account, 
210                                              gboolean manual)
211 {
212         osso_rpc_t retval = { 0 };
213         const osso_return_t ret = osso_rpc_run_with_defaults(osso_context, 
214                                                              MODEST_DBUS_NAME,
215                                                              MODEST_DBUS_METHOD_SEND_RECEIVE_FULL, &retval,
216                                                              DBUS_TYPE_STRING, account,
217                                                              DBUS_TYPE_BOOLEAN, manual,
218                                                              DBUS_TYPE_INVALID);
219                 
220         if (ret != OSSO_OK) {
221                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
222                 return FALSE;
223         } else {
224                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
225         }
226         
227         osso_rpc_free_val(&retval);
228         
229         return TRUE;
230 }
231
232 gboolean 
233 libmodest_dbus_client_open_default_inbox (osso_context_t *osso_context)
234 {
235         osso_rpc_t retval = { 0 };
236         const osso_return_t ret = osso_rpc_run_with_defaults(osso_context, 
237                    MODEST_DBUS_NAME, 
238                    MODEST_DBUS_METHOD_OPEN_DEFAULT_INBOX, &retval, 
239                    DBUS_TYPE_INVALID);
240                 
241         if (ret != OSSO_OK) {
242                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
243                 return FALSE;
244         } else {
245                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
246         }
247         
248         osso_rpc_free_val(&retval);
249         
250         return TRUE;
251 }
252
253 gboolean
254 libmodest_dbus_client_open_account (osso_context_t *osso_context,
255                                     const gchar *account_id)
256 {
257         osso_rpc_t retval = { 0 };
258         const osso_return_t ret =
259                 osso_rpc_run_with_defaults(osso_context,
260                                            MODEST_DBUS_NAME,
261                                            MODEST_DBUS_METHOD_OPEN_ACCOUNT, &retval,
262                                            DBUS_TYPE_STRING, account_id,
263                                            DBUS_TYPE_INVALID);
264
265         if (ret != OSSO_OK) {
266                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
267                 return FALSE;
268         } else {
269                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
270         }
271
272         osso_rpc_free_val(&retval);
273
274         return TRUE;
275 }
276
277 gboolean
278 libmodest_dbus_client_open_edit_accounts_dialog (osso_context_t *osso_context)
279 {
280         osso_rpc_t retval = { 0 };
281         const osso_return_t ret =
282                 osso_rpc_run_with_defaults(osso_context,
283                                            MODEST_DBUS_NAME,
284                                            MODEST_DBUS_METHOD_OPEN_EDIT_ACCOUNTS_DIALOG, &retval,
285                                            DBUS_TYPE_INVALID);
286
287         if (ret != OSSO_OK) {
288                 printf("debug: %s: osso_rpc_run() failed.\n", __FUNCTION__);
289                 return FALSE;
290         } else {
291                 printf("debug: %s: osso_rpc_run() succeeded.\n", __FUNCTION__);
292         }
293
294         osso_rpc_free_val(&retval);
295
296         return TRUE;
297 }
298
299 /**
300  * libmodest_dbus_client_delete_message:
301  * @osso_context: a valid #osso_context_t object.
302  * @msg_uri: A valid url to a mail 
303  *
304  * This method will try to find the message supplied
305  * by @msg_uri and if found delete it. It will use
306  * remote procedure calls (rpc) over dbus to do so.
307  * 
308  * Return value: TRUE on successs, FALSE on error
309  **/
310 gboolean
311 libmodest_dbus_client_delete_message (osso_context_t   *osso_ctx,
312                                       const char       *msg_uri)
313 {
314         osso_rpc_t    retval = { 0 };
315         osso_return_t ret;
316        
317         ret = osso_rpc_run_with_defaults (osso_ctx, 
318                                           MODEST_DBUS_NAME, 
319                                           MODEST_DBUS_METHOD_DELETE_MESSAGE, &retval, 
320                                           DBUS_TYPE_STRING, msg_uri, 
321                                           DBUS_TYPE_INVALID);
322                 
323         if (ret != OSSO_OK) {
324                 g_debug ("debug: osso_rpc_run() failed.\n");
325         } else {
326                 g_debug ("debug: osso_rpc_run() succeeded.\n");
327         }
328         
329         osso_rpc_free_val (&retval);
330
331         return ret == OSSO_OK;
332 }
333
334 static void
335 modest_search_hit_free (ModestSearchHit *hit)
336 {
337         g_free (hit->msgid);
338         g_slice_free (ModestSearchHit, hit);
339 }
340
341 void
342 modest_search_hit_list_free (GList *hits)
343 {
344         GList *iter;
345
346         if (hits == NULL) {
347                 return;
348         }
349
350         for (iter = hits; iter; iter = iter->next) {
351                 modest_search_hit_free ((ModestSearchHit *) iter->data);
352         }
353
354         g_list_free (hits);
355 }
356
357 static char *
358 _dbus_iter_get_string_or_null (DBusMessageIter *iter)
359 {
360         const char *string = NULL;
361         char       *ret = NULL;
362
363         dbus_message_iter_get_basic (iter, &string);
364         
365         if (string && strlen (string)) {
366                 ret = g_strdup (string);
367         }
368
369         return ret;
370 }
371
372 static guint64
373 _dbus_iter_get_uint64 (DBusMessageIter *iter)
374 {
375         dbus_uint64_t ui64v;
376         guint64       ret;
377
378         ui64v = 0;
379         dbus_message_iter_get_basic (iter, &ui64v);
380
381         ret = (guint64) ui64v;
382
383         return ret;
384 }
385
386
387 static gint64
388 _dbus_iter_get_int64 (DBusMessageIter *iter)
389 {
390         dbus_int64_t i64v;
391         gint64       ret;
392
393         i64v = 0;
394         dbus_message_iter_get_basic (iter, &i64v);
395
396         ret = (gint64) i64v;
397
398         return ret;
399 }
400
401 static gboolean
402 _dbus_iter_get_boolean (DBusMessageIter *iter)
403
404 {
405         dbus_bool_t  val;
406         gboolean     ret;
407
408         val = FALSE;
409         dbus_message_iter_get_basic (iter, &val);
410
411         ret = (gboolean) val;
412
413         return ret;
414 }
415
416 /** Get the values from the complex type (SEARCH_HIT_DBUS_TYPE)
417  * in the D-Bus return message. */
418 static ModestSearchHit *
419 modest_dbus_message_iter_get_search_hit (DBusMessageIter *parent)
420 {
421         ModestSearchHit *hit;
422         DBusMessageIter  child;
423         dbus_bool_t      res;
424         int              arg_type;
425         gboolean         error;
426
427         error = FALSE;
428         hit = g_slice_new0 (ModestSearchHit);
429
430         arg_type = dbus_message_iter_get_arg_type (parent);
431
432         if (arg_type != 'r') {
433                 return NULL;
434         }
435
436         dbus_message_iter_recurse (parent, &child);
437         
438         /* msgid  */
439         arg_type = dbus_message_iter_get_arg_type (&child);
440
441         if (arg_type != DBUS_TYPE_STRING) {
442                 error = TRUE;
443                 goto out;
444         }
445
446         hit->msgid = _dbus_iter_get_string_or_null (&child);
447
448         res = dbus_message_iter_next (&child);
449         if (res == FALSE) {
450                 error = TRUE;
451                 goto out;
452         }
453
454         /* subject  */
455         arg_type = dbus_message_iter_get_arg_type (&child);
456
457         if (arg_type != DBUS_TYPE_STRING) {
458                 error = TRUE;
459                 goto out;
460         }
461
462         hit->subject = _dbus_iter_get_string_or_null (&child);
463
464         res = dbus_message_iter_next (&child);
465         if (res == FALSE) {
466                 error = TRUE;
467                 goto out;
468         }
469
470         /* folder  */
471         arg_type = dbus_message_iter_get_arg_type (&child);
472
473         if (arg_type != DBUS_TYPE_STRING) {
474                 error = TRUE;
475                 goto out;
476         }
477
478         hit->folder = _dbus_iter_get_string_or_null (&child);
479
480         res = dbus_message_iter_next (&child);
481         if (res == FALSE) {
482                 error = TRUE;
483                 goto out;
484         }
485
486         /* sender  */
487         arg_type = dbus_message_iter_get_arg_type (&child);
488
489         if (arg_type != DBUS_TYPE_STRING) {
490                 error = TRUE;
491                 goto out;
492         }
493
494         hit->sender = _dbus_iter_get_string_or_null (&child);
495
496         res = dbus_message_iter_next (&child);
497         if (res == FALSE) {
498                 error = TRUE;
499                 goto out;
500         }
501
502         /* msize  */
503         arg_type = dbus_message_iter_get_arg_type (&child);
504
505         if (arg_type != DBUS_TYPE_UINT64) {
506                 error = TRUE;
507                 goto out;
508         }
509
510         hit->msize = _dbus_iter_get_uint64 (&child);
511
512         res = dbus_message_iter_next (&child);
513         if (res == FALSE) {
514                 error = TRUE;
515                 goto out;
516         }
517
518         /* has_attachment  */
519         arg_type = dbus_message_iter_get_arg_type (&child);
520
521         if (arg_type != DBUS_TYPE_BOOLEAN) {
522                 error = TRUE;
523                 goto out;
524         }
525
526         hit->has_attachment = _dbus_iter_get_boolean (&child); 
527
528         res = dbus_message_iter_next (&child);
529         if (res == FALSE) {
530                 error = TRUE;
531                 goto out;
532         }
533
534         /* is_unread  */
535         arg_type = dbus_message_iter_get_arg_type (&child);
536
537         if (arg_type != DBUS_TYPE_BOOLEAN) {
538                 error = TRUE;
539                 goto out;
540         }
541
542         hit->is_unread = _dbus_iter_get_boolean (&child);  
543
544         res = dbus_message_iter_next (&child);
545         if (res == FALSE) {
546                 error = TRUE;
547                 goto out;
548         }
549
550         /* timestamp  */
551         arg_type = dbus_message_iter_get_arg_type (&child);
552
553         if (arg_type != DBUS_TYPE_INT64) {
554                 error = TRUE;
555                 goto out;
556         }
557
558         hit->timestamp = _dbus_iter_get_int64 (&child); 
559
560         res = dbus_message_iter_next (&child);
561         if (res == TRUE) {
562                 error = TRUE;
563                 goto out;
564         }       
565
566 out:
567         if (error) {
568                 g_warning ("%s: Error during unmarshalling", __FUNCTION__);
569                 modest_search_hit_free (hit);
570                 hit = NULL;
571         }
572
573         return hit;
574 }
575
576 /**
577  * libmodest_dbus_client_search:
578  * @osso_ctx: A valid #osso_context_t object.
579  * @query: The term to search for.
580  * @folder: An url to specific folder or %NULL to search everywhere.
581  * @start_date: Search hits before this date will be ignored.
582  * @end_date: Search hits after this date will be ignored.
583  * @min_size: Messagers smaller then this size will be ingored.
584  * @flags: A list of flags where to search so the documentation 
585  * of %ModestDBusSearchFlags for details.
586  * @hits: A pointer to a valid GList pointer that will contain the search
587  * hits (ModestSearchHit). The list and the items must be freed by the caller 
588  * with modest_search_hit_list_free().
589  *
590  * This method will search the folder specified by a valid url in @folder or all
591  * known accounts (local and remote) if %NULL for matches of the search term(s)
592  * specified in @query. It is legal to specify 0 in @start_date, @end_date and
593  * @min_size to ignore these parameters during the search otherwise those message
594  * that do not meet the specifed dates or size will be ignored.
595  * Where to search, be it subject, sender or the whole body can be specified by
596  * the @flags parameter.
597  *
598  * Upon success TRUE is returned and @hits will include the search hits or the list
599  * migh be empty if none of the messages matched the search criteria. The returned
600  * list must be freed with modest_search_hit_list_free (). It is save to pass
601  * %NULL to this function so you can call this function on the result list no matter
602  * if a hit was found or not (means the list is empty - i.e. %NULL)
603  * FALSE will only be return if an error during the remote procedure call (rpc) 
604  * occured or if the specified folder could not be found.
605  *
606  * NOTE: The body of a message can only be searched if it was previously downloaded by
607  * modest. This function does also not attempt do to remote searches (i.e. IMAP search).
608  *
609  * Example to search every account for message containing "no":
610  * <informalexample><programlisting>
611  * ModestDBusSearchFlags  flags;
612  * osso_context_t        *osso_context;
613  * GList                 *hits;
614  * GList                 *iter;
615  * gboolean               res;
616  * 
617  * [...] Initialize osso context [...]
618  *
619  * res = libmodest_dbus_client_search (osso_context,
620  *                                     "no",
621  *                                     NULL,
622  *                                     0,
623  *                                     0,
624  *                                     0,
625  *                                     flags,
626  *                                     &hits);
627  * 
628  * for (iter = hits; iter; iter = iter->next) {
629  *      ModestSearchHit *hit = (ModestSearchHit *) iter->data;
630  *      
631  *      [...] Do something with the hit [...]
632  *
633  *      }
634  *
635  *      modest_search_hit_list_free (hits);
636  * </programlisting></informalexample>
637  * 
638  * Return value: TRUE if the search succeded or FALSE for an error during the search
639  **/
640 gboolean
641 libmodest_dbus_client_search (osso_context_t          *osso_ctx,
642                               const gchar             *query,
643                               const gchar             *folder,
644                               time_t                   start_date,
645                               time_t                   end_date,
646                               guint32                  min_size,
647                               ModestDBusSearchFlags    flags,
648                               GList                  **hits)
649 {
650
651         DBusMessage *msg;
652         dbus_bool_t res;
653         DBusConnection *con;
654         DBusMessageIter iter;
655         DBusMessageIter child;
656         DBusMessage *reply = NULL;
657         gint timeout;
658         int arg_type;
659         dbus_int64_t sd_v;
660         dbus_int64_t ed_v;
661         dbus_int32_t flags_v;
662         dbus_uint32_t size_v;
663
664         if (query == NULL) {
665                 return FALSE;
666         }
667
668         con = osso_get_dbus_connection (osso_ctx);
669
670         if (con == NULL) {
671                 g_warning ("Could not get dbus connection\n");
672                 return FALSE;
673
674         }
675
676
677         msg = dbus_message_new_method_call (MODEST_DBUS_SERVICE,
678                 MODEST_DBUS_OBJECT,
679                 MODEST_DBUS_IFACE,
680                 MODEST_DBUS_METHOD_SEARCH);
681
682     if (msg == NULL) {
683         //ULOG_ERR_F("dbus_message_new_method_call failed");
684                 return OSSO_ERROR;
685     }
686
687         if (folder == NULL) {
688                 folder = "";
689         }
690
691         sd_v = (dbus_int64_t) start_date;
692         ed_v = (dbus_int64_t) end_date;
693         flags_v = (dbus_int32_t) flags;
694         size_v = (dbus_uint32_t) min_size;
695
696         res  = dbus_message_append_args (msg,
697                                          DBUS_TYPE_STRING, &query,
698                                          DBUS_TYPE_STRING, &folder,
699                                          DBUS_TYPE_INT64, &sd_v,
700                                          DBUS_TYPE_INT64, &ed_v,
701                                          DBUS_TYPE_INT32, &flags_v,
702                                          DBUS_TYPE_UINT32, &size_v,
703                                          DBUS_TYPE_INVALID);
704
705         dbus_message_set_auto_start (msg, TRUE);
706
707         /* Use a long timeout (2 minutes) because the search currently 
708          * gets folders and messages from the servers. */
709         timeout = 120000; //milliseconds.
710         //osso_rpc_get_timeout (osso_ctx, &timeout);
711
712     /*printf("DEBUG: %s: Before dbus_connection_send_with_reply_and_block().\n", 
713                 __FUNCTION__); */
714         /* TODO: Detect the timeout somehow. */
715         DBusError err;
716         dbus_error_init (&err);
717         reply = dbus_connection_send_with_reply_and_block (con,
718                                                            msg, 
719                                                            timeout,
720                                                            &err);
721         /* printf("DEBUG: %s: dbus_connection_send_with_reply_and_block() finished.\n", 
722                 __FUNCTION__); */
723
724         dbus_message_unref (msg);
725
726         if (!reply) {
727                 g_warning("%s: dbus_connection_send_with_reply_and_block() error: %s", 
728                         __FUNCTION__, err.message);
729                 return FALSE;
730         }
731
732         switch (dbus_message_get_type (reply)) {
733
734                 case DBUS_MESSAGE_TYPE_ERROR:
735                         dbus_set_error_from_message (&err, reply);
736                         //XXX to GError?!
737                         dbus_error_free (&err);
738                         dbus_message_unref (reply);
739                         return FALSE;
740
741                 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
742                         /* ok we are good to go
743                          * lets drop outa here and handle that */
744                         break;
745                 default:
746                         //ULOG_WARN_F("got unknown message type as reply");
747                         //retval->type = DBUS_TYPE_STRING;
748                         //retval->value.s = g_strdup("Invalid return value");
749                         //XXX to GError?! 
750                         dbus_message_unref (reply);
751                         return FALSE;
752         }
753
754         g_debug ("%s: message return", __FUNCTION__);
755
756         dbus_message_iter_init (reply, &iter);
757         arg_type = dbus_message_iter_get_arg_type (&iter);
758         
759         dbus_message_iter_recurse (&iter, &child);
760         *hits = NULL;
761
762         do {
763                 ModestSearchHit *hit;
764
765                 hit = modest_dbus_message_iter_get_search_hit (&child);
766
767                 if (hit) {
768                         *hits = g_list_prepend (*hits, hit);    
769                 }
770
771         } while (dbus_message_iter_next (&child));
772
773         dbus_message_unref (reply);
774
775
776         /* TODO: This is from osso source, do we need it? */
777 #if 0
778         /* Tell TaskNavigator to show "launch banner" */
779         msg = dbus_message_new_method_call (TASK_NAV_SERVICE,
780                                             APP_LAUNCH_BANNER_METHOD_PATH,
781                                             APP_LAUNCH_BANNER_METHOD_INTERFACE,
782                                             APP_LAUNCH_BANNER_METHOD);
783
784         if (msg == NULL) {
785                 g_warn ("dbus_message_new_method_call failed");
786         }
787
788
789
790         dbus_message_append_args (msg,
791                                   DBUS_TYPE_STRING,
792                                   &service,
793                                   DBUS_TYPE_INVALID);
794
795         b = dbus_connection_send (conn, msg, NULL);
796
797         if (b == NULL) {
798                 ULOG_WARN_F("dbus_connection_send failed");
799         }
800
801         dbus_message_unref (msg);
802 #endif
803
804         return TRUE;
805 }
806
807
808 static void
809 modest_folder_result_free (ModestFolderResult *item)
810 {
811         g_free (item->folder_name);
812         g_free (item->folder_uri);
813         g_slice_free (ModestFolderResult, item);
814 }
815
816 void
817 modest_folder_result_list_free (GList *list)
818 {
819         GList *iter;
820
821         if (list == NULL) {
822                 return;
823         }
824
825         for (iter = list; iter; iter = iter->next) {
826                 modest_folder_result_free ((ModestFolderResult *) iter->data);
827         }
828
829         g_list_free (list);
830 }
831
832
833 /** Get the values from the complex type (GET_FOLDERS_RESULT_DBUS_TYPE)
834  * in the D-Bus return message. */
835 static ModestFolderResult *
836 modest_dbus_message_iter_get_folder_item (DBusMessageIter *parent)
837 {
838         gboolean error = FALSE;
839         ModestFolderResult *item = g_slice_new0 (ModestFolderResult);
840
841         int arg_type = dbus_message_iter_get_arg_type (parent);
842
843         if (arg_type != 'r') {
844                 return NULL;
845         }
846
847         DBusMessageIter  child;
848         dbus_message_iter_recurse (parent, &child);
849         
850         /* folder name: */
851         arg_type = dbus_message_iter_get_arg_type (&child);
852
853         if (arg_type != DBUS_TYPE_STRING) {
854                 error = TRUE;
855                 goto out;
856         }
857
858         item->folder_name = _dbus_iter_get_string_or_null (&child);
859         
860         
861         dbus_bool_t res = dbus_message_iter_next (&child);
862         if (res == FALSE) {
863                 error = TRUE;
864                 goto out;
865         }
866
867         /* folder URI:  */
868         arg_type = dbus_message_iter_get_arg_type (&child);
869
870         if (arg_type != DBUS_TYPE_STRING) {
871                 error = TRUE;
872                 goto out;
873         }
874
875         item->folder_uri = _dbus_iter_get_string_or_null (&child);
876
877
878 out:
879         if (error) {
880                 g_warning ("%s: Error during unmarshalling", __FUNCTION__);
881                 modest_folder_result_free (item);
882                 item = NULL;
883         }
884
885         return item;
886 }
887
888 /**
889  * libmodest_dbus_client_get_folders:
890  * @osso_ctx: A valid #osso_context_t object.
891  * @folders: A pointer to a valid GList pointer that will contain the folder items
892  * (ModestFolderResult). The list and the items must be freed by the caller 
893  * with modest_folder_result_list_free().
894  *
895  * This method will obtain a list of folders in the default account.
896  *
897  * Upon success TRUE is returned and @folders will include the folders or the list
898  * might be empty if there are no folders. The returned
899  * list must be freed with modest_folder_result_list_free ().
900  *
901  * NOTE: A folder will only be retrieved if it was previously downloaded by
902  * modest. This function does also not attempt do to remote refreshes (i.e. IMAP).
903  * 
904  * Return value: TRUE if the request succeded or FALSE for an error.
905  **/
906 gboolean
907 libmodest_dbus_client_get_folders (osso_context_t          *osso_ctx,
908                               GList                  **folders)
909 {
910         /* Initialize output argument: */
911         if (folders)
912                 *folders = NULL;
913         else
914                 return FALSE;
915
916         DBusConnection *con = osso_get_dbus_connection (osso_ctx);
917
918         if (con == NULL) {
919                 g_warning ("Could not get dbus connection\n");
920                 return FALSE;
921
922         }
923
924         DBusMessage *msg = dbus_message_new_method_call (MODEST_DBUS_SERVICE,
925                 MODEST_DBUS_OBJECT,
926                 MODEST_DBUS_IFACE,
927                 MODEST_DBUS_METHOD_GET_FOLDERS);
928
929     if (msg == NULL) {
930         //ULOG_ERR_F("dbus_message_new_method_call failed");
931                 return OSSO_ERROR;
932     }
933
934         dbus_message_set_auto_start (msg, TRUE);
935
936         /* Use a long timeout (2 minutes) because the search currently 
937          * gets folders from the servers. */
938         gint timeout = 120000;
939         //osso_rpc_get_timeout (osso_ctx, &timeout);
940
941         DBusError err;
942         dbus_error_init (&err);
943         DBusMessage *reply = dbus_connection_send_with_reply_and_block (con,
944                                                            msg, 
945                                                            timeout,
946                                                            &err);
947
948         dbus_message_unref (msg);
949         msg = NULL;
950
951         if (reply == NULL) {
952                 g_warning("%s: dbus_connection_send_with_reply_and_block() error:\n   %s", 
953                         __FUNCTION__, err.message);
954                 return FALSE;
955         }
956
957         switch (dbus_message_get_type (reply)) {
958
959                 case DBUS_MESSAGE_TYPE_ERROR:
960                         dbus_set_error_from_message (&err, reply);
961                         //XXX to GError?!
962                         dbus_error_free (&err);
963                         dbus_message_unref (reply);
964                         return FALSE;
965
966                 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
967                         /* ok we are good to go
968                          * lets drop outa here and handle that */
969                         break;
970                 default:
971                         //ULOG_WARN_F("got unknown message type as reply");
972                         //retval->type = DBUS_TYPE_STRING;
973                         //retval->value.s = g_strdup("Invalid return value");
974                         //XXX to GError?! 
975                         dbus_message_unref (reply);
976                         return FALSE;
977         }
978
979         g_debug ("%s: message return", __FUNCTION__);
980
981         DBusMessageIter iter;
982         dbus_message_iter_init (reply, &iter);
983         /* int arg_type = dbus_message_iter_get_arg_type (&iter); */
984         
985         DBusMessageIter child;
986         dbus_message_iter_recurse (&iter, &child);
987
988         do {
989                 ModestFolderResult *item = modest_dbus_message_iter_get_folder_item (&child);
990
991                 if (item) {
992                         *folders = g_list_append (*folders, item);      
993                 }
994
995         } while (dbus_message_iter_next (&child));
996
997         dbus_message_unref (reply);
998
999
1000         /* TODO: This is from osso source, do we need it? */
1001 #if 0
1002         /* Tell TaskNavigator to show "launch banner" */
1003         msg = dbus_message_new_method_call (TASK_NAV_SERVICE,
1004                                             APP_LAUNCH_BANNER_METHOD_PATH,
1005                                             APP_LAUNCH_BANNER_METHOD_INTERFACE,
1006                                             APP_LAUNCH_BANNER_METHOD);
1007
1008         if (msg == NULL) {
1009                 g_warn ("dbus_message_new_method_call failed");
1010         }
1011
1012
1013
1014         dbus_message_append_args (msg,
1015                                   DBUS_TYPE_STRING,
1016                                   &service,
1017                                   DBUS_TYPE_INVALID);
1018
1019         b = dbus_connection_send (conn, msg, NULL);
1020
1021         if (b == NULL) {
1022                 ULOG_WARN_F("dbus_connection_send failed");
1023         }
1024
1025         dbus_message_unref (msg);
1026 #endif
1027
1028         return TRUE;
1029 }
1030
1031