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 void
381
modest_account_hits_hits_list_free (GList *account_hits_hits_list)
382
{
383
	GList *iter;
384
385
	if (account_hits_hits_list == NULL) {
386
		return;
387
	}
388
389
	for (iter = account_hits_hits_list; iter; iter = iter->next) {
390
		ModestGetUnreadMessagesHit *hit = (ModestGetUnreadMessagesHit *) iter->data;
391
		g_free (hit->subject);
392
		g_slice_free (ModestGetUnreadMessagesHit, hit);
393
	}
394
395
	g_list_free (account_hits_hits_list);
396
}
397
398
static void
399
modest_account_hits_free (ModestAccountHits *account_hits)
400
{
401
	g_free (account_hits->account_id);
402
	g_free (account_hits->account_name);
403
	g_free (account_hits->store_protocol);
404
	modest_account_hits_hits_list_free (account_hits->hits);
405
	g_slice_free (ModestAccountHits, account_hits);
406
}
407
408
void
409
modest_account_hits_list_free (GList *account_hits_list)
410
{
411
	GList *iter;
412
413
	if (account_hits_list == NULL) {
414
		return;
415
	}
416
417
	for (iter = account_hits_list; iter; iter = iter->next) {
418
		modest_account_hits_free ((ModestAccountHits *) iter->data);
419
	}
420
421
	g_list_free (account_hits_list);
422
}
423
424
static char *
425
_dbus_iter_get_string_or_null (DBusMessageIter *iter)
426
{
427
	const char *string = NULL;
428
	char       *ret = NULL;
429
430
	dbus_message_iter_get_basic (iter, &string);
431
	
432
	if (string && strlen (string)) {
433
		ret = g_strdup (string);
434
	}
435
436
	return ret;
437
}
438
439
static guint64
440
_dbus_iter_get_uint64 (DBusMessageIter *iter)
441
{
442
	dbus_uint64_t ui64v;
443
	guint64       ret;
444
445
	ui64v = 0;
446
	dbus_message_iter_get_basic (iter, &ui64v);
447
448
	ret = (guint64) ui64v;
449
450
	return ret;
451
}
452
453
454
static gint64
455
_dbus_iter_get_int64 (DBusMessageIter *iter)
456
{
457
	dbus_int64_t i64v;
458
	gint64       ret;
459
460
	i64v = 0;
461
	dbus_message_iter_get_basic (iter, &i64v);
462
463
	ret = (gint64) i64v;
464
465
	return ret;
466
}
467
468
static gboolean
469
_dbus_iter_get_boolean (DBusMessageIter *iter)
470
471
{
472
	dbus_bool_t  val;
473
	gboolean     ret;
474
475
	val = FALSE;
476
	dbus_message_iter_get_basic (iter, &val);
477
478
	ret = (gboolean) val;
479
480
	return ret;
481
}
482
483
/** Get the values from the complex type (SEARCH_HIT_DBUS_TYPE)
484
 * in the D-Bus return message. */
485
static ModestSearchHit *
486
modest_dbus_message_iter_get_search_hit (DBusMessageIter *parent)
487
{
488
	ModestSearchHit *hit;
489
	DBusMessageIter  child;
490
	dbus_bool_t      res;
491
	int              arg_type;
492
	gboolean         error;
493
494
	error = FALSE;
495
	hit = g_slice_new0 (ModestSearchHit);
496
497
	arg_type = dbus_message_iter_get_arg_type (parent);
498
499
	if (arg_type != 'r') {
500
		return NULL;
501
	}
502
503
	dbus_message_iter_recurse (parent, &child);
504
	
505
	/* msgid  */
506
	arg_type = dbus_message_iter_get_arg_type (&child);
507
508
	if (arg_type != DBUS_TYPE_STRING) {
509
		error = TRUE;
510
		goto out;
511
	}
512
513
	hit->msgid = _dbus_iter_get_string_or_null (&child);
514
515
	res = dbus_message_iter_next (&child);
516
	if (res == FALSE) {
517
		error = TRUE;
518
		goto out;
519
	}
520
521
	/* subject  */
522
	arg_type = dbus_message_iter_get_arg_type (&child);
523
524
	if (arg_type != DBUS_TYPE_STRING) {
525
		error = TRUE;
526
		goto out;
527
	}
528
529
	hit->subject = _dbus_iter_get_string_or_null (&child);
530
531
	res = dbus_message_iter_next (&child);
532
	if (res == FALSE) {
533
		error = TRUE;
534
		goto out;
535
	}
536
537
	/* folder  */
538
	arg_type = dbus_message_iter_get_arg_type (&child);
539
540
	if (arg_type != DBUS_TYPE_STRING) {
541
		error = TRUE;
542
		goto out;
543
	}
544
545
	hit->folder = _dbus_iter_get_string_or_null (&child);
546
547
	res = dbus_message_iter_next (&child);
548
	if (res == FALSE) {
549
		error = TRUE;
550
		goto out;
551
	}
552
553
	/* sender  */
554
	arg_type = dbus_message_iter_get_arg_type (&child);
555
556
	if (arg_type != DBUS_TYPE_STRING) {
557
		error = TRUE;
558
		goto out;
559
	}
560
561
	hit->sender = _dbus_iter_get_string_or_null (&child);
562
563
	res = dbus_message_iter_next (&child);
564
	if (res == FALSE) {
565
		error = TRUE;
566
		goto out;
567
	}
568
569
	/* msize  */
570
	arg_type = dbus_message_iter_get_arg_type (&child);
571
572
	if (arg_type != DBUS_TYPE_UINT64) {
573
		error = TRUE;
574
		goto out;
575
	}
576
577
	hit->msize = _dbus_iter_get_uint64 (&child);
578
579
	res = dbus_message_iter_next (&child);
580
	if (res == FALSE) {
581
		error = TRUE;
582
		goto out;
583
	}
584
585
	/* has_attachment  */
586
	arg_type = dbus_message_iter_get_arg_type (&child);
587
588
	if (arg_type != DBUS_TYPE_BOOLEAN) {
589
		error = TRUE;
590
		goto out;
591
	}
592
593
	hit->has_attachment = _dbus_iter_get_boolean (&child); 
594
595
	res = dbus_message_iter_next (&child);
596
	if (res == FALSE) {
597
		error = TRUE;
598
		goto out;
599
	}
600
601
	/* is_unread  */
602
	arg_type = dbus_message_iter_get_arg_type (&child);
603
604
	if (arg_type != DBUS_TYPE_BOOLEAN) {
605
		error = TRUE;
606
		goto out;
607
	}
608
609
	hit->is_unread = _dbus_iter_get_boolean (&child);  
610
611
	res = dbus_message_iter_next (&child);
612
	if (res == FALSE) {
613
		error = TRUE;
614
		goto out;
615
	}
616
617
	/* timestamp  */
618
	arg_type = dbus_message_iter_get_arg_type (&child);
619
620
	if (arg_type != DBUS_TYPE_INT64) {
621
		error = TRUE;
622
		goto out;
623
	}
624
625
	hit->timestamp = _dbus_iter_get_int64 (&child); 
626
627
	res = dbus_message_iter_next (&child);
628
	if (res == TRUE) {
629
		error = TRUE;
630
		goto out;
631
	}	
632
633
out:
634
	if (error) {
635
		g_warning ("%s: Error during unmarshalling", __FUNCTION__);
636
		modest_search_hit_free (hit);
637
		hit = NULL;
638
	}
639
640
	return hit;
641
}
642
643
static ModestGetUnreadMessagesHit *
644
modest_dbus_message_iter_get_unread_messages_hit (DBusMessageIter *parent)
645
{
646
	ModestGetUnreadMessagesHit *hit;
647
	DBusMessageIter  child;
648
	dbus_bool_t      res;
649
	int              arg_type;
650
	gboolean         error;
651
652
	error = FALSE;
653
654
	arg_type = dbus_message_iter_get_arg_type (parent);
655
656
	if (arg_type != 'r') {
657
		return NULL;
658
	}
659
660
	hit = g_slice_new0 (ModestGetUnreadMessagesHit);
661
	dbus_message_iter_recurse (parent, &child);
662
	
663
	/* timestamp  */
664
	arg_type = dbus_message_iter_get_arg_type (&child);
665
666
	if (arg_type != DBUS_TYPE_INT64) {
667
		error = TRUE;
668
		goto out;
669
	}
670
671
	hit->timestamp = _dbus_iter_get_int64 (&child); 
672
673
	res = dbus_message_iter_next (&child);
674
	if (res == FALSE) {
675
		error = TRUE;
676
		goto out;
677
	}	
678
679
	/* subject  */
680
	arg_type = dbus_message_iter_get_arg_type (&child);
681
682
	if (arg_type != DBUS_TYPE_STRING) {
683
		error = TRUE;
684
		goto out;
685
	}
686
687
	hit->subject = _dbus_iter_get_string_or_null (&child);
688
689
	res = dbus_message_iter_next (&child);
690
	if (res == TRUE) {
691
		error = TRUE;
692
		goto out;
693
	}
694
695
out:
696
	if (error) {
697
		g_warning ("%s: Error during unmarshalling", __FUNCTION__);
698
		g_slice_free (ModestGetUnreadMessagesHit, hit);
699
		hit = NULL;
700
	}
701
702
	return hit;
703
}
704
705
/**
706
 * libmodest_dbus_client_search:
707
 * @osso_ctx: A valid #osso_context_t object.
708
 * @query: The term to search for.
709
 * @folder: An url to specific folder or %NULL to search everywhere.
710
 * @start_date: Search hits before this date will be ignored.
711
 * @end_date: Search hits after this date will be ignored.
712
 * @min_size: Messagers smaller then this size will be ingored.
713
 * @flags: A list of flags where to search so the documentation 
714
 * of %ModestDBusSearchFlags for details.
715
 * @hits: A pointer to a valid GList pointer that will contain the search
716
 * hits (ModestSearchHit). The list and the items must be freed by the caller 
717
 * with modest_search_hit_list_free().
718
 *
719
 * This method will search the folder specified by a valid url in @folder or all
720
 * known accounts (local and remote) if %NULL for matches of the search term(s)
721
 * specified in @query. It is legal to specify 0 in @start_date, @end_date and
722
 * @min_size to ignore these parameters during the search otherwise those message
723
 * that do not meet the specifed dates or size will be ignored.
724
 * Where to search, be it subject, sender or the whole body can be specified by
725
 * the @flags parameter.
726
 *
727
 * Upon success TRUE is returned and @hits will include the search hits or the list
728
 * migh be empty if none of the messages matched the search criteria. The returned
729
 * list must be freed with modest_search_hit_list_free (). It is save to pass
730
 * %NULL to this function so you can call this function on the result list no matter
731
 * if a hit was found or not (means the list is empty - i.e. %NULL)
732
 * FALSE will only be return if an error during the remote procedure call (rpc) 
733
 * occured or if the specified folder could not be found.
734
 *
735
 * NOTE: The body of a message can only be searched if it was previously downloaded by
736
 * modest. This function does also not attempt do to remote searches (i.e. IMAP search).
737
 *
738
 * Example to search every account for message containing "no":
739
 * <informalexample><programlisting>
740
 * ModestDBusSearchFlags  flags;
741
 * osso_context_t        *osso_context;
742
 * GList                 *hits;
743
 * GList                 *iter;
744
 * gboolean               res;
745
 * 
746
 * [...] Initialize osso context [...]
747
 *
748
 * res = libmodest_dbus_client_search (osso_context,
749
 *				       "no",
750
 *				       NULL,
751
 *				       0,
752
 *				       0,
753
 *				       0,
754
 *				       flags,
755
 *				       &hits);
756
 * 
757
 * for (iter = hits; iter; iter = iter->next) {
758
 *	ModestSearchHit *hit = (ModestSearchHit *) iter->data;
759
 *   	
760
 *   	[...] Do something with the hit [...]
761
 *
762
 *	}
763
 *
764
 *	modest_search_hit_list_free (hits);
765
 * </programlisting></informalexample>
766
 * 
767
 * Return value: TRUE if the search succeded or FALSE for an error during the search
768
 **/
769
gboolean
770
libmodest_dbus_client_search (osso_context_t          *osso_ctx,
771
			      const gchar             *query,
772
			      const gchar             *folder,
773
			      time_t		       start_date,
774
			      time_t 		       end_date,
775
			      guint32                  min_size,
776
			      ModestDBusSearchFlags    flags,
777
			      GList                  **hits)
778
{
779
780
	DBusMessage *msg;
781
	dbus_bool_t res;
782
	DBusConnection *con;
783
	DBusMessageIter iter;
784
	DBusMessageIter child;
785
	DBusMessage *reply = NULL;
786
	gint timeout;
787
	int arg_type;
788
	dbus_int64_t sd_v;
789
	dbus_int64_t ed_v;
790
	dbus_int32_t flags_v;
791
	dbus_uint32_t size_v;
792
793
	if (query == NULL) {
794
		return FALSE;
795
	}
796
797
	con = osso_get_dbus_connection (osso_ctx);
798
799
	if (con == NULL) {
800
		g_warning ("Could not get dbus connection\n");
801
		return FALSE;
802
803
	}
804
805
806
	msg = dbus_message_new_method_call (MODEST_DBUS_SERVICE,
807
		MODEST_DBUS_OBJECT,
808
		MODEST_DBUS_IFACE,
809
		MODEST_DBUS_METHOD_SEARCH);
810
811
    if (msg == NULL) {
812
       	//ULOG_ERR_F("dbus_message_new_method_call failed");
813
		return OSSO_ERROR;
814
    }
815
816
	if (folder == NULL) {
817
		folder = "";
818
	}
819
820
	sd_v = (dbus_int64_t) start_date;
821
	ed_v = (dbus_int64_t) end_date;
822
	flags_v = (dbus_int32_t) flags;
823
	size_v = (dbus_uint32_t) min_size;
824
825
	res  = dbus_message_append_args (msg,
826
					 DBUS_TYPE_STRING, &query,
827
					 DBUS_TYPE_STRING, &folder,
828
					 DBUS_TYPE_INT64, &sd_v,
829
					 DBUS_TYPE_INT64, &ed_v,
830
					 DBUS_TYPE_INT32, &flags_v,
831
					 DBUS_TYPE_UINT32, &size_v,
832
					 DBUS_TYPE_INVALID);
833
834
	dbus_message_set_auto_start (msg, TRUE);
835
836
	/* Use a long timeout (2 minutes) because the search currently 
837
	 * gets folders and messages from the servers. */
838
	timeout = 120000; //milliseconds.
839
	//osso_rpc_get_timeout (osso_ctx, &timeout);
840
841
    /*printf("DEBUG: %s: Before dbus_connection_send_with_reply_and_block().\n", 
842
		__FUNCTION__); */
843
	/* TODO: Detect the timeout somehow. */
844
	DBusError err;
845
	dbus_error_init (&err);
846
	reply = dbus_connection_send_with_reply_and_block (con,
847
							   msg, 
848
							   timeout,
849
							   &err);
850
	/* printf("DEBUG: %s: dbus_connection_send_with_reply_and_block() finished.\n", 
851
		__FUNCTION__); */
852
853
	dbus_message_unref (msg);
854
855
	if (!reply) {
856
		g_warning("%s: dbus_connection_send_with_reply_and_block() error: %s", 
857
			__FUNCTION__, err.message);
858
		return FALSE;
859
	}
860
861
	switch (dbus_message_get_type (reply)) {
862
863
		case DBUS_MESSAGE_TYPE_ERROR:
864
			dbus_set_error_from_message (&err, reply);
865
			//XXX to GError?!
866
			dbus_error_free (&err);
867
			dbus_message_unref (reply);
868
			return FALSE;
869
870
		case DBUS_MESSAGE_TYPE_METHOD_RETURN:
871
			/* ok we are good to go
872
			 * lets drop outa here and handle that */
873
			break;
874
		default:
875
			//ULOG_WARN_F("got unknown message type as reply");
876
			//retval->type = DBUS_TYPE_STRING;
877
			//retval->value.s = g_strdup("Invalid return value");
878
			//XXX to GError?! 
879
			dbus_message_unref (reply);
880
			return FALSE;
881
	}
882
883
	g_debug ("%s: message return", __FUNCTION__);
884
885
	dbus_message_iter_init (reply, &iter);
886
	arg_type = dbus_message_iter_get_arg_type (&iter);
887
	
888
	dbus_message_iter_recurse (&iter, &child);
889
	*hits = NULL;
890
891
	do {
892
		ModestSearchHit *hit;
893
894
		hit = modest_dbus_message_iter_get_search_hit (&child);
895
896
		if (hit) {
897
			*hits = g_list_prepend (*hits, hit);	
898
		}
899
900
	} while (dbus_message_iter_next (&child));
901
902
	dbus_message_unref (reply);
903
904
905
	/* TODO: This is from osso source, do we need it? */
906
#if 0
907
	/* Tell TaskNavigator to show "launch banner" */
908
	msg = dbus_message_new_method_call (TASK_NAV_SERVICE,
909
					    APP_LAUNCH_BANNER_METHOD_PATH,
910
					    APP_LAUNCH_BANNER_METHOD_INTERFACE,
911
					    APP_LAUNCH_BANNER_METHOD);
912
913
	if (msg == NULL) {
914
		g_warn ("dbus_message_new_method_call failed");
915
	}
916
917
918
919
	dbus_message_append_args (msg,
920
				  DBUS_TYPE_STRING,
921
				  &service,
922
				  DBUS_TYPE_INVALID);
923
924
	b = dbus_connection_send (conn, msg, NULL);
925
926
	if (b == NULL) {
927
		ULOG_WARN_F("dbus_connection_send failed");
928
	}
929
930
	dbus_message_unref (msg);
931
#endif
932
933
	return TRUE;
934
}
935
936
937
static ModestAccountHits *
938
modest_dbus_message_iter_get_account_hits (DBusMessageIter *parent)
939
{
940
941
	ModestAccountHits *account_hits;
942
	int              arg_type;
943
	gboolean         error;
944
	dbus_bool_t      res;
945
	DBusMessageIter  child, traverse;
946
947
	error = FALSE;
948
	account_hits = g_slice_new0 (ModestAccountHits);
949
950
	arg_type = dbus_message_iter_get_arg_type (parent);
951
952
	if (arg_type != 'r') {
953
		return NULL;
954
	}
955
956
	dbus_message_iter_recurse (parent, &child);
957
	
958
	/* accountid  */
959
	arg_type = dbus_message_iter_get_arg_type (&child);
960
961
	if (arg_type != DBUS_TYPE_STRING) {
962
		error = TRUE;
963
		goto out;
964
	}
965
966
	account_hits->account_id = _dbus_iter_get_string_or_null (&child);
967
968
	res = dbus_message_iter_next (&child);
969
	if (res == FALSE) {
970
		error = TRUE;
971
		goto out;
972
	}
973
974
	/* account name */
975
	arg_type = dbus_message_iter_get_arg_type (&child);
976
977
	if (arg_type != DBUS_TYPE_STRING) {
978
		error = TRUE;
979
		goto out;
980
	}
981
982
	account_hits->account_name = _dbus_iter_get_string_or_null (&child);
983
984
	res = dbus_message_iter_next (&child);
985
	if (res == FALSE) {
986
		error = TRUE;
987
		goto out;
988
	}
989
990
	/* store protocol */
991
	arg_type = dbus_message_iter_get_arg_type (&child);
992
993
	if (arg_type != DBUS_TYPE_STRING) {
994
		error = TRUE;
995
		goto out;
996
	}
997
998
	account_hits->store_protocol = _dbus_iter_get_string_or_null (&child);
999
1000
	res = dbus_message_iter_next (&child);
1001
	if (res == FALSE) {
1002
		error = TRUE;
1003
		goto out;
1004
	}
1005
1006
	/* unread count */
1007
	arg_type = dbus_message_iter_get_arg_type (&child);
1008
1009
	if (arg_type != DBUS_TYPE_INT64) {
1010
		error = TRUE;
1011
		goto out;
1012
	}
1013
1014
	account_hits->unread_count = _dbus_iter_get_int64 (&child);
1015
1016
	res = dbus_message_iter_next (&child);
1017
	if (res == FALSE) {
1018
		error = TRUE;
1019
		goto out;
1020
	}
1021
1022
	/* list of hits  */
1023
	dbus_message_iter_recurse (&child, &traverse);
1024
	account_hits->hits = NULL;
1025
1026
	do {
1027
		ModestGetUnreadMessagesHit *hit;
1028
1029
		hit = modest_dbus_message_iter_get_unread_messages_hit (&traverse);
1030
		if (hit) {
1031
			account_hits->hits = g_list_prepend (account_hits->hits, hit);
1032
		}
1033
	} while (dbus_message_iter_next (&traverse));
1034
out:
1035
	if (error) {
1036
		g_warning ("%s: Error during unmarshalling", __FUNCTION__);
1037
		modest_account_hits_free (account_hits);
1038
		account_hits = NULL;
1039
	}
1040
1041
	return account_hits;
1042
}
1043
1044
gboolean
1045
libmodest_dbus_client_get_unread_messages (osso_context_t          *osso_ctx,
1046
					   gint msgs_per_account,
1047
					   GList **account_hits_lists)
1048
{
1049
1050
	dbus_bool_t res;
1051
	DBusMessageIter iter;
1052
	DBusMessageIter child;
1053
	DBusMessage *reply = NULL;
1054
	int arg_type;
1055
1056
	DBusConnection *con;
1057
	DBusMessage *msg;
1058
	dbus_int32_t msgs_per_account_v;
1059
	DBusError err;
1060
	gint timeout;
1061
1062
	if (msgs_per_account < 1) {
1063
		return FALSE;
1064
	}
1065
1066
	con = osso_get_dbus_connection (osso_ctx);
1067
1068
	if (con == NULL) {
1069
		g_warning ("Could not get dbus connection\n");
1070
		return FALSE;
1071
1072
	}
1073
1074
1075
	msg = dbus_message_new_method_call (MODEST_DBUS_SERVICE,
1076
		MODEST_DBUS_OBJECT,
1077
		MODEST_DBUS_IFACE,
1078
		MODEST_DBUS_METHOD_GET_UNREAD_MESSAGES);
1079
1080
	if (msg == NULL) {
1081
		//ULOG_ERR_F("dbus_message_new_method_call failed");
1082
		return OSSO_ERROR;
1083
	}
1084
1085
	msgs_per_account_v = (dbus_int32_t) msgs_per_account;
1086
1087
	res  = dbus_message_append_args (msg,
1088
					 DBUS_TYPE_INT32, &msgs_per_account,
1089
					 DBUS_TYPE_INVALID);
1090
1091
	dbus_message_set_auto_start (msg, TRUE);
1092
1093
	timeout = 120000; //milliseconds.
1094
1095
	dbus_error_init (&err);
1096
	reply = dbus_connection_send_with_reply_and_block (con,
1097
							   msg, 
1098
							   timeout,
1099
							   &err);
1100
1101
	dbus_message_unref (msg);
1102
1103
	if (!reply) {
1104
		g_warning("%s: dbus_connection_send_with_reply_and_block() error: %s", 
1105
			__FUNCTION__, err.message);
1106
		return FALSE;
1107
	}
1108
1109
	switch (dbus_message_get_type (reply)) {
1110
1111
		case DBUS_MESSAGE_TYPE_ERROR:
1112
			dbus_set_error_from_message (&err, reply);
1113
			//XXX to GError?!
1114
			dbus_error_free (&err);
1115
			dbus_message_unref (reply);
1116
			return FALSE;
1117
1118
		case DBUS_MESSAGE_TYPE_METHOD_RETURN:
1119
			/* ok we are good to go
1120
			 * lets drop outa here and handle that */
1121
			break;
1122
		default:
1123
			//ULOG_WARN_F("got unknown message type as reply");
1124
			//retval->type = DBUS_TYPE_STRING;
1125
			//retval->value.s = g_strdup("Invalid return value");
1126
			//XXX to GError?! 
1127
			dbus_message_unref (reply);
1128
			return FALSE;
1129
	}
1130
1131
	g_debug ("%s: message return", __FUNCTION__);
1132
1133
	dbus_message_iter_init (reply, &iter);
1134
	arg_type = dbus_message_iter_get_arg_type (&iter);
1135
	
1136
	dbus_message_iter_recurse (&iter, &child);
1137
	*account_hits_lists = NULL;
1138
1139
	do {
1140
		ModestAccountHits *account_hits;
1141
1142
		account_hits = modest_dbus_message_iter_get_account_hits (&child);
1143
1144
		if (account_hits) {
1145
			*account_hits_lists = g_list_prepend (*account_hits_lists, account_hits);	
1146
		}
1147
1148
	} while (dbus_message_iter_next (&child));
1149
1150
	dbus_message_unref (reply);
1151
1152
1153
	return TRUE;
1154
}
1155
1156
1157
static void
1158
modest_folder_result_free (ModestFolderResult *item)
1159
{
1160
	g_free (item->folder_name);
1161
	g_free (item->folder_uri);
1162
	g_slice_free (ModestFolderResult, item);
1163
}
1164
1165
void
1166
modest_folder_result_list_free (GList *list)
1167
{
1168
	GList *iter;
1169
1170
	if (list == NULL) {
1171
		return;
1172
	}
1173
1174
	for (iter = list; iter; iter = iter->next) {
1175
		modest_folder_result_free ((ModestFolderResult *) iter->data);
1176
	}
1177
1178
	g_list_free (list);
1179
}
1180
1181
1182
/** Get the values from the complex type (GET_FOLDERS_RESULT_DBUS_TYPE)
1183
 * in the D-Bus return message. */
1184
static ModestFolderResult *
1185
modest_dbus_message_iter_get_folder_item (DBusMessageIter *parent)
1186
{
1187
	gboolean error = FALSE;
1188
	ModestFolderResult *item = g_slice_new0 (ModestFolderResult);
1189
1190
	int arg_type = dbus_message_iter_get_arg_type (parent);
1191
1192
	if (arg_type != 'r') {
1193
		return NULL;
1194
	}
1195
1196
	DBusMessageIter  child;
1197
	dbus_message_iter_recurse (parent, &child);
1198
	
1199
	/* folder name: */
1200
	arg_type = dbus_message_iter_get_arg_type (&child);
1201
1202
	if (arg_type != DBUS_TYPE_STRING) {
1203
		error = TRUE;
1204
		goto out;
1205
	}
1206
1207
	item->folder_name = _dbus_iter_get_string_or_null (&child);
1208
	
1209
	
1210
	dbus_bool_t res = dbus_message_iter_next (&child);
1211
	if (res == FALSE) {
1212
		error = TRUE;
1213
		goto out;
1214
	}
1215
1216
	/* folder URI:  */
1217
	arg_type = dbus_message_iter_get_arg_type (&child);
1218
1219
	if (arg_type != DBUS_TYPE_STRING) {
1220
		error = TRUE;
1221
		goto out;
1222
	}
1223
1224
	item->folder_uri = _dbus_iter_get_string_or_null (&child);
1225
1226
1227
out:
1228
	if (error) {
1229
		g_warning ("%s: Error during unmarshalling", __FUNCTION__);
1230
		modest_folder_result_free (item);
1231
		item = NULL;
1232
	}
1233
1234
	return item;
1235
}
1236
1237
/**
1238
 * libmodest_dbus_client_get_folders:
1239
 * @osso_ctx: A valid #osso_context_t object.
1240
 * @folders: A pointer to a valid GList pointer that will contain the folder items
1241
 * (ModestFolderResult). The list and the items must be freed by the caller 
1242
 * with modest_folder_result_list_free().
1243
 *
1244
 * This method will obtain a list of folders in the default account.
1245
 *
1246
 * Upon success TRUE is returned and @folders will include the folders or the list
1247
 * might be empty if there are no folders. The returned
1248
 * list must be freed with modest_folder_result_list_free ().
1249
 *
1250
 * NOTE: A folder will only be retrieved if it was previously downloaded by
1251
 * modest. This function does also not attempt do to remote refreshes (i.e. IMAP).
1252
 * 
1253
 * Return value: TRUE if the request succeded or FALSE for an error.
1254
 **/
1255
gboolean
1256
libmodest_dbus_client_get_folders (osso_context_t          *osso_ctx,
1257
			      GList                  **folders)
1258
{
1259
	/* Initialize output argument: */
1260
	if (folders)
1261
		*folders = NULL;
1262
	else
1263
		return FALSE;
1264
1265
	DBusConnection *con = osso_get_dbus_connection (osso_ctx);
1266
1267
	if (con == NULL) {
1268
		g_warning ("Could not get dbus connection\n");
1269
		return FALSE;
1270
1271
	}
1272
1273
	DBusMessage *msg = dbus_message_new_method_call (MODEST_DBUS_SERVICE,
1274
		MODEST_DBUS_OBJECT,
1275
		MODEST_DBUS_IFACE,
1276
		MODEST_DBUS_METHOD_GET_FOLDERS);
1277
1278
    if (msg == NULL) {
1279
       	//ULOG_ERR_F("dbus_message_new_method_call failed");
1280
		return OSSO_ERROR;
1281
    }
1282
1283
	dbus_message_set_auto_start (msg, TRUE);
1284
1285
	/* Use a long timeout (2 minutes) because the search currently 
1286
	 * gets folders from the servers. */
1287
	gint timeout = 120000;
1288
	//osso_rpc_get_timeout (osso_ctx, &timeout);
1289
1290
  	DBusError err;
1291
  	dbus_error_init (&err);
1292
	DBusMessage *reply = dbus_connection_send_with_reply_and_block (con,
1293
							   msg, 
1294
							   timeout,
1295
							   &err);
1296
1297
	dbus_message_unref (msg);
1298
	msg = NULL;
1299
1300
	if (reply == NULL) {
1301
		g_warning("%s: dbus_connection_send_with_reply_and_block() error:\n   %s", 
1302
			__FUNCTION__, err.message);
1303
		return FALSE;
1304
	}
1305
1306
	switch (dbus_message_get_type (reply)) {
1307
1308
		case DBUS_MESSAGE_TYPE_ERROR:
1309
			dbus_set_error_from_message (&err, reply);
1310
			//XXX to GError?!
1311
			dbus_error_free (&err);
1312
			dbus_message_unref (reply);
1313
			return FALSE;
1314
1315
		case DBUS_MESSAGE_TYPE_METHOD_RETURN:
1316
			/* ok we are good to go
1317
			 * lets drop outa here and handle that */
1318
			break;
1319
		default:
1320
			//ULOG_WARN_F("got unknown message type as reply");
1321
			//retval->type = DBUS_TYPE_STRING;
1322
			//retval->value.s = g_strdup("Invalid return value");
1323
			//XXX to GError?! 
1324
			dbus_message_unref (reply);
1325
			return FALSE;
1326
	}
1327
1328
	g_debug ("%s: message return", __FUNCTION__);
1329
1330
	DBusMessageIter iter;
1331
	dbus_message_iter_init (reply, &iter);
1332
	/* int arg_type = dbus_message_iter_get_arg_type (&iter); */
1333
	
1334
	DBusMessageIter child;
1335
	dbus_message_iter_recurse (&iter, &child);
1336
1337
	do {
1338
		ModestFolderResult *item = modest_dbus_message_iter_get_folder_item (&child);
1339
1340
		if (item) {
1341
			*folders = g_list_append (*folders, item);	
1342
		}
1343
1344
	} while (dbus_message_iter_next (&child));
1345
1346
	dbus_message_unref (reply);
1347
1348
1349
	/* TODO: This is from osso source, do we need it? */
1350
#if 0
1351
	/* Tell TaskNavigator to show "launch banner" */
1352
	msg = dbus_message_new_method_call (TASK_NAV_SERVICE,
1353
					    APP_LAUNCH_BANNER_METHOD_PATH,
1354
					    APP_LAUNCH_BANNER_METHOD_INTERFACE,
1355
					    APP_LAUNCH_BANNER_METHOD);
1356
1357
	if (msg == NULL) {
1358
		g_warn ("dbus_message_new_method_call failed");
1359
	}
1360
1361
1362
1363
	dbus_message_append_args (msg,
1364
				  DBUS_TYPE_STRING,
1365
				  &service,
1366
				  DBUS_TYPE_INVALID);
1367
1368
	b = dbus_connection_send (conn, msg, NULL);
1369
1370
	if (b == NULL) {
1371
		ULOG_WARN_F("dbus_connection_send failed");
1372
	}
1373
1374
	dbus_message_unref (msg);
1375
#endif
1376
1377
	return TRUE;
1378
}