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