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