Fixes NB#143352, add a DBus API to request inmmediate Send&Receive (like manual send...
[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 /**
278  * libmodest_dbus_client_delete_message:
279  * @osso_context: a valid #osso_context_t object.
280  * @msg_uri: A valid url to a mail 
281  *
282  * This method will try to find the message supplied
283  * by @msg_uri and if found delete it. It will use
284  * remote procedure calls (rpc) over dbus to do so.
285  * 
286  * Return value: TRUE on successs, FALSE on error
287  **/
288 gboolean
289 libmodest_dbus_client_delete_message (osso_context_t   *osso_ctx,
290                                       const char       *msg_uri)
291 {
292         osso_rpc_t    retval = { 0 };
293         osso_return_t ret;
294        
295         ret = osso_rpc_run_with_defaults (osso_ctx, 
296                                           MODEST_DBUS_NAME, 
297                                           MODEST_DBUS_METHOD_DELETE_MESSAGE, &retval, 
298                                           DBUS_TYPE_STRING, msg_uri, 
299                                           DBUS_TYPE_INVALID);
300                 
301         if (ret != OSSO_OK) {
302                 g_debug ("debug: osso_rpc_run() failed.\n");
303         } else {
304                 g_debug ("debug: osso_rpc_run() succeeded.\n");
305         }
306         
307         osso_rpc_free_val (&retval);
308
309         return ret == OSSO_OK;
310 }
311
312 static void
313 modest_search_hit_free (ModestSearchHit *hit)
314 {
315         g_free (hit->msgid);
316         g_slice_free (ModestSearchHit, hit);
317 }
318
319 void
320 modest_search_hit_list_free (GList *hits)
321 {
322         GList *iter;
323
324         if (hits == NULL) {
325                 return;
326         }
327
328         for (iter = hits; iter; iter = iter->next) {
329                 modest_search_hit_free ((ModestSearchHit *) iter->data);
330         }
331
332         g_list_free (hits);
333 }
334
335 static char *
336 _dbus_iter_get_string_or_null (DBusMessageIter *iter)
337 {
338         const char *string = NULL;
339         char       *ret = NULL;
340
341         dbus_message_iter_get_basic (iter, &string);
342         
343         if (string && strlen (string)) {
344                 ret = g_strdup (string);
345         }
346
347         return ret;
348 }
349
350 static guint64
351 _dbus_iter_get_uint64 (DBusMessageIter *iter)
352 {
353         dbus_uint64_t ui64v;
354         guint64       ret;
355
356         ui64v = 0;
357         dbus_message_iter_get_basic (iter, &ui64v);
358
359         ret = (guint64) ui64v;
360
361         return ret;
362 }
363
364
365 static gint64
366 _dbus_iter_get_int64 (DBusMessageIter *iter)
367 {
368         dbus_int64_t i64v;
369         gint64       ret;
370
371         i64v = 0;
372         dbus_message_iter_get_basic (iter, &i64v);
373
374         ret = (gint64) i64v;
375
376         return ret;
377 }
378
379 static gboolean
380 _dbus_iter_get_boolean (DBusMessageIter *iter)
381
382 {
383         dbus_bool_t  val;
384         gboolean     ret;
385
386         val = FALSE;
387         dbus_message_iter_get_basic (iter, &val);
388
389         ret = (gboolean) val;
390
391         return ret;
392 }
393
394 /** Get the values from the complex type (SEARCH_HIT_DBUS_TYPE)
395  * in the D-Bus return message. */
396 static ModestSearchHit *
397 modest_dbus_message_iter_get_search_hit (DBusMessageIter *parent)
398 {
399         ModestSearchHit *hit;
400         DBusMessageIter  child;
401         dbus_bool_t      res;
402         int              arg_type;
403         gboolean         error;
404
405         error = FALSE;
406         hit = g_slice_new0 (ModestSearchHit);
407
408         arg_type = dbus_message_iter_get_arg_type (parent);
409
410         if (arg_type != 'r') {
411                 return NULL;
412         }
413
414         dbus_message_iter_recurse (parent, &child);
415         
416         /* msgid  */
417         arg_type = dbus_message_iter_get_arg_type (&child);
418
419         if (arg_type != DBUS_TYPE_STRING) {
420                 error = TRUE;
421                 goto out;
422         }
423
424         hit->msgid = _dbus_iter_get_string_or_null (&child);
425
426         res = dbus_message_iter_next (&child);
427         if (res == FALSE) {
428                 error = TRUE;
429                 goto out;
430         }
431
432         /* subject  */
433         arg_type = dbus_message_iter_get_arg_type (&child);
434
435         if (arg_type != DBUS_TYPE_STRING) {
436                 error = TRUE;
437                 goto out;
438         }
439
440         hit->subject = _dbus_iter_get_string_or_null (&child);
441
442         res = dbus_message_iter_next (&child);
443         if (res == FALSE) {
444                 error = TRUE;
445                 goto out;
446         }
447
448         /* folder  */
449         arg_type = dbus_message_iter_get_arg_type (&child);
450
451         if (arg_type != DBUS_TYPE_STRING) {
452                 error = TRUE;
453                 goto out;
454         }
455
456         hit->folder = _dbus_iter_get_string_or_null (&child);
457
458         res = dbus_message_iter_next (&child);
459         if (res == FALSE) {
460                 error = TRUE;
461                 goto out;
462         }
463
464         /* sender  */
465         arg_type = dbus_message_iter_get_arg_type (&child);
466
467         if (arg_type != DBUS_TYPE_STRING) {
468                 error = TRUE;
469                 goto out;
470         }
471
472         hit->sender = _dbus_iter_get_string_or_null (&child);
473
474         res = dbus_message_iter_next (&child);
475         if (res == FALSE) {
476                 error = TRUE;
477                 goto out;
478         }
479
480         /* msize  */
481         arg_type = dbus_message_iter_get_arg_type (&child);
482
483         if (arg_type != DBUS_TYPE_UINT64) {
484                 error = TRUE;
485                 goto out;
486         }
487
488         hit->msize = _dbus_iter_get_uint64 (&child);
489
490         res = dbus_message_iter_next (&child);
491         if (res == FALSE) {
492                 error = TRUE;
493                 goto out;
494         }
495
496         /* has_attachment  */
497         arg_type = dbus_message_iter_get_arg_type (&child);
498
499         if (arg_type != DBUS_TYPE_BOOLEAN) {
500                 error = TRUE;
501                 goto out;
502         }
503
504         hit->has_attachment = _dbus_iter_get_boolean (&child); 
505
506         res = dbus_message_iter_next (&child);
507         if (res == FALSE) {
508                 error = TRUE;
509                 goto out;
510         }
511
512         /* is_unread  */
513         arg_type = dbus_message_iter_get_arg_type (&child);
514
515         if (arg_type != DBUS_TYPE_BOOLEAN) {
516                 error = TRUE;
517                 goto out;
518         }
519
520         hit->is_unread = _dbus_iter_get_boolean (&child);  
521
522         res = dbus_message_iter_next (&child);
523         if (res == FALSE) {
524                 error = TRUE;
525                 goto out;
526         }
527
528         /* timestamp  */
529         arg_type = dbus_message_iter_get_arg_type (&child);
530
531         if (arg_type != DBUS_TYPE_INT64) {
532                 error = TRUE;
533                 goto out;
534         }
535
536         hit->timestamp = _dbus_iter_get_int64 (&child); 
537
538         res = dbus_message_iter_next (&child);
539         if (res == TRUE) {
540                 error = TRUE;
541                 goto out;
542         }       
543
544 out:
545         if (error) {
546                 g_warning ("%s: Error during unmarshalling", __FUNCTION__);
547                 modest_search_hit_free (hit);
548                 hit = NULL;
549         }
550
551         return hit;
552 }
553
554 /**
555  * libmodest_dbus_client_search:
556  * @osso_ctx: A valid #osso_context_t object.
557  * @query: The term to search for.
558  * @folder: An url to specific folder or %NULL to search everywhere.
559  * @start_date: Search hits before this date will be ignored.
560  * @end_date: Search hits after this date will be ignored.
561  * @min_size: Messagers smaller then this size will be ingored.
562  * @flags: A list of flags where to search so the documentation 
563  * of %ModestDBusSearchFlags for details.
564  * @hits: A pointer to a valid GList pointer that will contain the search
565  * hits (ModestSearchHit). The list and the items must be freed by the caller 
566  * with modest_search_hit_list_free().
567  *
568  * This method will search the folder specified by a valid url in @folder or all
569  * known accounts (local and remote) if %NULL for matches of the search term(s)
570  * specified in @query. It is legal to specify 0 in @start_date, @end_date and
571  * @min_size to ignore these parameters during the search otherwise those message
572  * that do not meet the specifed dates or size will be ignored.
573  * Where to search, be it subject, sender or the whole body can be specified by
574  * the @flags parameter.
575  *
576  * Upon success TRUE is returned and @hits will include the search hits or the list
577  * migh be empty if none of the messages matched the search criteria. The returned
578  * list must be freed with modest_search_hit_list_free (). It is save to pass
579  * %NULL to this function so you can call this function on the result list no matter
580  * if a hit was found or not (means the list is empty - i.e. %NULL)
581  * FALSE will only be return if an error during the remote procedure call (rpc) 
582  * occured or if the specified folder could not be found.
583  *
584  * NOTE: The body of a message can only be searched if it was previously downloaded by
585  * modest. This function does also not attempt do to remote searches (i.e. IMAP search).
586  *
587  * Example to search every account for message containing "no":
588  * <informalexample><programlisting>
589  * ModestDBusSearchFlags  flags;
590  * osso_context_t        *osso_context;
591  * GList                 *hits;
592  * GList                 *iter;
593  * gboolean               res;
594  * 
595  * [...] Initialize osso context [...]
596  *
597  * res = libmodest_dbus_client_search (osso_context,
598  *                                     "no",
599  *                                     NULL,
600  *                                     0,
601  *                                     0,
602  *                                     0,
603  *                                     flags,
604  *                                     &hits);
605  * 
606  * for (iter = hits; iter; iter = iter->next) {
607  *      ModestSearchHit *hit = (ModestSearchHit *) iter->data;
608  *      
609  *      [...] Do something with the hit [...]
610  *
611  *      }
612  *
613  *      modest_search_hit_list_free (hits);
614  * </programlisting></informalexample>
615  * 
616  * Return value: TRUE if the search succeded or FALSE for an error during the search
617  **/
618 gboolean
619 libmodest_dbus_client_search (osso_context_t          *osso_ctx,
620                               const gchar             *query,
621                               const gchar             *folder,
622                               time_t                   start_date,
623                               time_t                   end_date,
624                               guint32                  min_size,
625                               ModestDBusSearchFlags    flags,
626                               GList                  **hits)
627 {
628
629         DBusMessage *msg;
630         dbus_bool_t res;
631         DBusConnection *con;
632         DBusMessageIter iter;
633         DBusMessageIter child;
634         DBusMessage *reply = NULL;
635         gint timeout;
636         int arg_type;
637         dbus_int64_t sd_v;
638         dbus_int64_t ed_v;
639         dbus_int32_t flags_v;
640         dbus_uint32_t size_v;
641
642         if (query == NULL) {
643                 return FALSE;
644         }
645
646         con = osso_get_dbus_connection (osso_ctx);
647
648         if (con == NULL) {
649                 g_warning ("Could not get dbus connection\n");
650                 return FALSE;
651
652         }
653
654
655         msg = dbus_message_new_method_call (MODEST_DBUS_SERVICE,
656                 MODEST_DBUS_OBJECT,
657                 MODEST_DBUS_IFACE,
658                 MODEST_DBUS_METHOD_SEARCH);
659
660     if (msg == NULL) {
661         //ULOG_ERR_F("dbus_message_new_method_call failed");
662                 return OSSO_ERROR;
663     }
664
665         if (folder == NULL) {
666                 folder = "";
667         }
668
669         sd_v = (dbus_int64_t) start_date;
670         ed_v = (dbus_int64_t) end_date;
671         flags_v = (dbus_int32_t) flags;
672         size_v = (dbus_uint32_t) min_size;
673
674         res  = dbus_message_append_args (msg,
675                                          DBUS_TYPE_STRING, &query,
676                                          DBUS_TYPE_STRING, &folder,
677                                          DBUS_TYPE_INT64, &sd_v,
678                                          DBUS_TYPE_INT64, &ed_v,
679                                          DBUS_TYPE_INT32, &flags_v,
680                                          DBUS_TYPE_UINT32, &size_v,
681                                          DBUS_TYPE_INVALID);
682
683         dbus_message_set_auto_start (msg, TRUE);
684
685         /* Use a long timeout (2 minutes) because the search currently 
686          * gets folders and messages from the servers. */
687         timeout = 120000; //milliseconds.
688         //osso_rpc_get_timeout (osso_ctx, &timeout);
689
690     /*printf("DEBUG: %s: Before dbus_connection_send_with_reply_and_block().\n", 
691                 __FUNCTION__); */
692         /* TODO: Detect the timeout somehow. */
693         DBusError err;
694         dbus_error_init (&err);
695         reply = dbus_connection_send_with_reply_and_block (con,
696                                                            msg, 
697                                                            timeout,
698                                                            &err);
699         /* printf("DEBUG: %s: dbus_connection_send_with_reply_and_block() finished.\n", 
700                 __FUNCTION__); */
701
702         dbus_message_unref (msg);
703
704         if (!reply) {
705                 g_warning("%s: dbus_connection_send_with_reply_and_block() error: %s", 
706                         __FUNCTION__, err.message);
707                 return FALSE;
708         }
709
710         switch (dbus_message_get_type (reply)) {
711
712                 case DBUS_MESSAGE_TYPE_ERROR:
713                         dbus_set_error_from_message (&err, reply);
714                         //XXX to GError?!
715                         dbus_error_free (&err);
716                         dbus_message_unref (reply);
717                         return FALSE;
718
719                 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
720                         /* ok we are good to go
721                          * lets drop outa here and handle that */
722                         break;
723                 default:
724                         //ULOG_WARN_F("got unknown message type as reply");
725                         //retval->type = DBUS_TYPE_STRING;
726                         //retval->value.s = g_strdup("Invalid return value");
727                         //XXX to GError?! 
728                         dbus_message_unref (reply);
729                         return FALSE;
730         }
731
732         g_debug ("%s: message return", __FUNCTION__);
733
734         dbus_message_iter_init (reply, &iter);
735         arg_type = dbus_message_iter_get_arg_type (&iter);
736         
737         dbus_message_iter_recurse (&iter, &child);
738         *hits = NULL;
739
740         do {
741                 ModestSearchHit *hit;
742
743                 hit = modest_dbus_message_iter_get_search_hit (&child);
744
745                 if (hit) {
746                         *hits = g_list_prepend (*hits, hit);    
747                 }
748
749         } while (dbus_message_iter_next (&child));
750
751         dbus_message_unref (reply);
752
753
754         /* TODO: This is from osso source, do we need it? */
755 #if 0
756         /* Tell TaskNavigator to show "launch banner" */
757         msg = dbus_message_new_method_call (TASK_NAV_SERVICE,
758                                             APP_LAUNCH_BANNER_METHOD_PATH,
759                                             APP_LAUNCH_BANNER_METHOD_INTERFACE,
760                                             APP_LAUNCH_BANNER_METHOD);
761
762         if (msg == NULL) {
763                 g_warn ("dbus_message_new_method_call failed");
764         }
765
766
767
768         dbus_message_append_args (msg,
769                                   DBUS_TYPE_STRING,
770                                   &service,
771                                   DBUS_TYPE_INVALID);
772
773         b = dbus_connection_send (conn, msg, NULL);
774
775         if (b == NULL) {
776                 ULOG_WARN_F("dbus_connection_send failed");
777         }
778
779         dbus_message_unref (msg);
780 #endif
781
782         return TRUE;
783 }
784
785
786 static void
787 modest_folder_result_free (ModestFolderResult *item)
788 {
789         g_free (item->folder_name);
790         g_free (item->folder_uri);
791         g_slice_free (ModestFolderResult, item);
792 }
793
794 void
795 modest_folder_result_list_free (GList *list)
796 {
797         GList *iter;
798
799         if (list == NULL) {
800                 return;
801         }
802
803         for (iter = list; iter; iter = iter->next) {
804                 modest_folder_result_free ((ModestFolderResult *) iter->data);
805         }
806
807         g_list_free (list);
808 }
809
810
811 /** Get the values from the complex type (GET_FOLDERS_RESULT_DBUS_TYPE)
812  * in the D-Bus return message. */
813 static ModestFolderResult *
814 modest_dbus_message_iter_get_folder_item (DBusMessageIter *parent)
815 {
816         gboolean error = FALSE;
817         ModestFolderResult *item = g_slice_new0 (ModestFolderResult);
818
819         int arg_type = dbus_message_iter_get_arg_type (parent);
820
821         if (arg_type != 'r') {
822                 return NULL;
823         }
824
825         DBusMessageIter  child;
826         dbus_message_iter_recurse (parent, &child);
827         
828         /* folder name: */
829         arg_type = dbus_message_iter_get_arg_type (&child);
830
831         if (arg_type != DBUS_TYPE_STRING) {
832                 error = TRUE;
833                 goto out;
834         }
835
836         item->folder_name = _dbus_iter_get_string_or_null (&child);
837         
838         
839         dbus_bool_t res = dbus_message_iter_next (&child);
840         if (res == FALSE) {
841                 error = TRUE;
842                 goto out;
843         }
844
845         /* folder URI:  */
846         arg_type = dbus_message_iter_get_arg_type (&child);
847
848         if (arg_type != DBUS_TYPE_STRING) {
849                 error = TRUE;
850                 goto out;
851         }
852
853         item->folder_uri = _dbus_iter_get_string_or_null (&child);
854
855
856 out:
857         if (error) {
858                 g_warning ("%s: Error during unmarshalling", __FUNCTION__);
859                 modest_folder_result_free (item);
860                 item = NULL;
861         }
862
863         return item;
864 }
865
866 /**
867  * libmodest_dbus_client_get_folders:
868  * @osso_ctx: A valid #osso_context_t object.
869  * @folders: A pointer to a valid GList pointer that will contain the folder items
870  * (ModestFolderResult). The list and the items must be freed by the caller 
871  * with modest_folder_result_list_free().
872  *
873  * This method will obtain a list of folders in the default account.
874  *
875  * Upon success TRUE is returned and @folders will include the folders or the list
876  * might be empty if there are no folders. The returned
877  * list must be freed with modest_folder_result_list_free ().
878  *
879  * NOTE: A folder will only be retrieved if it was previously downloaded by
880  * modest. This function does also not attempt do to remote refreshes (i.e. IMAP).
881  * 
882  * Return value: TRUE if the request succeded or FALSE for an error.
883  **/
884 gboolean
885 libmodest_dbus_client_get_folders (osso_context_t          *osso_ctx,
886                               GList                  **folders)
887 {
888         /* Initialize output argument: */
889         if (folders)
890                 *folders = NULL;
891         else
892                 return FALSE;
893
894         DBusConnection *con = osso_get_dbus_connection (osso_ctx);
895
896         if (con == NULL) {
897                 g_warning ("Could not get dbus connection\n");
898                 return FALSE;
899
900         }
901
902         DBusMessage *msg = dbus_message_new_method_call (MODEST_DBUS_SERVICE,
903                 MODEST_DBUS_OBJECT,
904                 MODEST_DBUS_IFACE,
905                 MODEST_DBUS_METHOD_GET_FOLDERS);
906
907     if (msg == NULL) {
908         //ULOG_ERR_F("dbus_message_new_method_call failed");
909                 return OSSO_ERROR;
910     }
911
912         dbus_message_set_auto_start (msg, TRUE);
913
914         /* Use a long timeout (2 minutes) because the search currently 
915          * gets folders from the servers. */
916         gint timeout = 120000;
917         //osso_rpc_get_timeout (osso_ctx, &timeout);
918
919         DBusError err;
920         dbus_error_init (&err);
921         DBusMessage *reply = dbus_connection_send_with_reply_and_block (con,
922                                                            msg, 
923                                                            timeout,
924                                                            &err);
925
926         dbus_message_unref (msg);
927         msg = NULL;
928
929         if (reply == NULL) {
930                 g_warning("%s: dbus_connection_send_with_reply_and_block() error:\n   %s", 
931                         __FUNCTION__, err.message);
932                 return FALSE;
933         }
934
935         switch (dbus_message_get_type (reply)) {
936
937                 case DBUS_MESSAGE_TYPE_ERROR:
938                         dbus_set_error_from_message (&err, reply);
939                         //XXX to GError?!
940                         dbus_error_free (&err);
941                         dbus_message_unref (reply);
942                         return FALSE;
943
944                 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
945                         /* ok we are good to go
946                          * lets drop outa here and handle that */
947                         break;
948                 default:
949                         //ULOG_WARN_F("got unknown message type as reply");
950                         //retval->type = DBUS_TYPE_STRING;
951                         //retval->value.s = g_strdup("Invalid return value");
952                         //XXX to GError?! 
953                         dbus_message_unref (reply);
954                         return FALSE;
955         }
956
957         g_debug ("%s: message return", __FUNCTION__);
958
959         DBusMessageIter iter;
960         dbus_message_iter_init (reply, &iter);
961         /* int arg_type = dbus_message_iter_get_arg_type (&iter); */
962         
963         DBusMessageIter child;
964         dbus_message_iter_recurse (&iter, &child);
965
966         do {
967                 ModestFolderResult *item = modest_dbus_message_iter_get_folder_item (&child);
968
969                 if (item) {
970                         *folders = g_list_append (*folders, item);      
971                 }
972
973         } while (dbus_message_iter_next (&child));
974
975         dbus_message_unref (reply);
976
977
978         /* TODO: This is from osso source, do we need it? */
979 #if 0
980         /* Tell TaskNavigator to show "launch banner" */
981         msg = dbus_message_new_method_call (TASK_NAV_SERVICE,
982                                             APP_LAUNCH_BANNER_METHOD_PATH,
983                                             APP_LAUNCH_BANNER_METHOD_INTERFACE,
984                                             APP_LAUNCH_BANNER_METHOD);
985
986         if (msg == NULL) {
987                 g_warn ("dbus_message_new_method_call failed");
988         }
989
990
991
992         dbus_message_append_args (msg,
993                                   DBUS_TYPE_STRING,
994                                   &service,
995                                   DBUS_TYPE_INVALID);
996
997         b = dbus_connection_send (conn, msg, NULL);
998
999         if (b == NULL) {
1000                 ULOG_WARN_F("dbus_connection_send failed");
1001         }
1002
1003         dbus_message_unref (msg);
1004 #endif
1005
1006         return TRUE;
1007 }
1008
1009