Work to improve drafts folder management (fixes NB#56483).
[modest] / src / dbus_api / modest-dbus-callbacks.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 "modest-dbus-callbacks.h"
31 #include "modest-runtime.h"
32 #include "modest-account-mgr.h"
33 #include "modest-account-mgr-helpers.h"
34 #include "modest-tny-account.h"
35 #include "modest-ui-actions.h"
36 #include "modest-search.h"
37 #include "widgets/modest-msg-edit-window.h"
38 #include "modest-tny-msg.h"
39 #include <libmodest-dbus-client/libmodest-dbus-client.h>
40 #include <libgnomevfs/gnome-vfs-utils.h>
41 #include <stdio.h>
42 #include <string.h>
43
44 #include <tny-list.h>
45 #include <tny-iterator.h>
46 #include <tny-simple-list.h>
47
48 typedef struct 
49 {
50         gchar *to;
51         gchar *cc;
52         gchar *bcc;
53         gchar *subject;
54         gchar *body;
55 } SendMailIdleData;
56
57 typedef struct 
58 {
59         gchar *to;
60         gchar *cc;
61         gchar *bcc;
62         gchar *subject;
63         gchar *body;
64         GSList *attachments;
65 } ComposeMailIdleData;
66
67 static gboolean
68 on_idle_send_mail(gpointer user_data)
69 {
70         SendMailIdleData *idle_data = (SendMailIdleData*)user_data;
71         
72         /* Get the TnyTransportAccount so we can instantiate a mail operation: */
73         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
74         gchar *account_name = modest_account_mgr_get_default_account (account_mgr);
75         if (!account_name) {
76                 g_printerr ("modest: no account found\n");
77         }
78         
79         TnyTransportAccount *transport_account = NULL;
80         if (account_mgr) {
81                 transport_account = TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_transport_account_for_open_connection
82                                       (modest_runtime_get_account_store(),
83                                        account_name));
84         }
85         
86         if (!transport_account) {
87                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
88         }
89         
90         /* Create the mail operation: */
91         if (transport_account) {        
92                 /* Use the mail operation: */
93                 gchar * from = modest_account_mgr_get_from_string (account_mgr,
94                                                                   account_name);
95                 if (!from) {
96                         g_printerr ("modest: no from address for account '%s'\n", account_name);
97                 } else {
98                         ModestMailOperation *mail_operation = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_SEND, NULL);
99                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
100                         
101                         modest_mail_operation_send_new_mail (mail_operation,
102                                              transport_account,
103                                              NULL,
104                                              from, /* from */
105                                              idle_data->to, idle_data->cc, idle_data->bcc, idle_data->subject, 
106                                              idle_data->body, /* plain_body */
107                                              NULL, /* html_body */
108                                              NULL, /* attachments_list, GSList of TnyMimePart. */
109                                              (TnyHeaderFlags)0);
110                                              
111                         g_free (from);
112                         g_object_unref (G_OBJECT (mail_operation));
113                 }
114                                      
115                 g_object_unref (G_OBJECT (transport_account));
116         }
117         
118         g_free (account_name);
119         
120         /* Free the idle data: */
121         g_free (idle_data->to);
122         g_free (idle_data->cc);
123         g_free (idle_data->bcc);
124         g_free (idle_data->subject);
125         g_free (idle_data->body);
126         g_free (idle_data);
127         
128         return FALSE; /* Do not call this callback again. */
129 }
130
131 static gint on_send_mail(GArray * arguments, gpointer data, osso_rpc_t * retval)
132 {
133         if (arguments->len != MODEST_DEBUS_SEND_MAIL_ARGS_COUNT)
134         return OSSO_ERROR;
135         
136     /* Use g_idle to context-switch into the application's thread: */
137         SendMailIdleData *idle_data = g_new0(SendMailIdleData, 1); /* Freed in the idle callback. */
138         
139     /* Get the arguments: */
140         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_TO);
141         idle_data->to = g_strdup (val.value.s);
142         
143         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_CC);
144         idle_data->cc = g_strdup (val.value.s);
145         
146         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_BCC);
147         idle_data->bcc = g_strdup (val.value.s);
148         
149         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_SUBJECT);
150         idle_data->subject = g_strdup (val.value.s);
151         
152         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_BODY);
153         idle_data->body = g_strdup (val.value.s);
154         
155         /* printf("  debug: to=%s\n", idle_data->to); */
156         g_idle_add(on_idle_send_mail, (gpointer)idle_data);
157         
158         /* Note that we cannot report failures during sending, 
159          * because that would be asynchronous. */
160         return OSSO_OK;
161 }
162
163 /** uri_unescape:
164  * @uri An escaped URI. URIs should always be escaped.
165  * @len The length of the @uri string, or -1 if the string is null terminated.
166  * 
167  * Decode a URI, or URI fragment, as per RFC 1738.
168  * http://www.ietf.org/rfc/rfc1738.txt
169  * 
170  * Return value: An unescaped string. This should be freed with g_free().
171  */
172 static gchar* uri_unescape(const gchar* uri, size_t len)
173 {
174         if (!uri)
175                 return NULL;
176                 
177         if (len == -1)
178                 len = strlen (uri);
179         
180         /* Allocate an extra string so we can be sure that it is null-terminated,
181          * so we can use gnome_vfs_unescape_string().
182          * This is not efficient. */
183         gchar * escaped_nullterminated = g_strndup (uri, len);
184         gchar *result = gnome_vfs_unescape_string (escaped_nullterminated, NULL);
185         g_free (escaped_nullterminated);
186         
187         return result;
188 }
189
190 /** uri_parse_mailto:
191  * @mailto A mailto URI, with the mailto: prefix.
192  * @list_items_and_values: A pointer to a list that should be filled with item namesand value strings, 
193  * with each name item being followed by a value item. This list should be freed with g_slist_free) after 
194  * all the string items have been freed. This parameter may be NULL.
195  * Parse a mailto URI as per RFC2368.
196  * http://www.ietf.org/rfc/rfc2368.txt
197  * 
198  * Return value: The to address, unescaped. This should be freed with g_free().
199  */
200 static gchar* uri_parse_mailto (const gchar* mailto, GSList** list_items_and_values)
201 {
202         const gchar* start_to = NULL;
203         /* Remove the mailto: prefix: 
204          * 7 is the length of "mailto:": */
205         if (strncmp (mailto, "mailto:", 7) == 0) {
206                 start_to = mailto + 7;
207         }
208         
209         if (!start_to)
210                 return NULL;
211         
212         /* Look for ?, or the end of the string, marking the end of the to address: */
213         const size_t len_to = strcspn (start_to, "?");
214         gchar* result_to = uri_unescape (start_to, len_to);
215         printf("debug: result_to=%s\n", result_to);
216         
217         /* Get any other items: */
218         const size_t len_mailto = strlen (start_to);
219         const gchar* p = start_to + len_to + 1; /* parsed so far. */
220         const gchar* end = start_to + len_mailto;
221         /* GSList *items = NULL; */
222         const gchar* start_item_name = p;
223         size_t len_item_name = 0;
224         const gchar* start_item_value = NULL;
225         while (p < end) {
226                 
227                 /* Looking for the end of a name; */
228                 if (start_item_name) {
229                         const size_t len = strcspn (p, "="); /* Returns whole string if none found. */
230                         if (len) {
231                                 /* This marks the end of a name and the start of the value: */
232                                 len_item_name = len;
233                                 
234                                 /* Skip over the name and mark the start of the value: */
235                                 p += (len + 1); /* Skip over the = */
236                                 start_item_value = p;
237                         }
238                 }
239                 
240                 /* Looking for the end of a value: */
241                 if (start_item_value) {
242                         const size_t len = strcspn (p, "?"); /* Returns whole string if none found. */
243                         /* ? marks the start of a new item: */
244                         if (len) {
245                                 if (start_item_name && len_item_name) {
246                                         /* Finish the previously-started item: */
247                                         gchar *item_value = uri_unescape (start_item_value, len);
248                                         gchar *item_name = g_strndup (start_item_name, len_item_name);
249                                         /* printf ("debug: item name=%s, value=%s\n", item_name, item_value); */
250                                         
251                                         /* Append the items to the list */
252                                         if(list_items_and_values) {
253                                                 *list_items_and_values = g_slist_append (*list_items_and_values, item_name);
254                                                 *list_items_and_values = g_slist_append (*list_items_and_values, item_value);
255                                         }
256                                 }
257                                 
258                                 /* Skip over the value and mark the start of a possible new name/value pair: */
259                                 p += (len + 1); /* Skip over the ? */
260                                 start_item_name = p;
261                                 len_item_name = 0;
262                                 start_item_value = NULL;
263                         }
264                 }
265                 
266         }
267         
268         return result_to;
269 }
270
271
272 static gboolean
273 on_idle_mail_to(gpointer user_data)
274 {
275         /* This is based on the implemenation of main.c:start_uil(): */
276         
277         gchar *uri = (gchar*)user_data;
278         GSList *list_names_and_values = NULL;
279         gchar *to = uri_parse_mailto (uri, &list_names_and_values);
280         
281         /* Get the TnyTransportAccount so we can instantiate a mail operation: */
282         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
283         gchar *account_name = modest_account_mgr_get_default_account (account_mgr);
284         if (!account_name) {
285                 g_printerr ("modest: no account found\n");
286         }
287         
288         TnyAccount *account = NULL;
289         if (account_mgr) {
290                 account = modest_tny_account_store_get_transport_account_for_open_connection (
291                         modest_runtime_get_account_store(), account_name);
292         }
293         
294         if (!account) {
295                 g_printerr ("modest: failed to get tny account folder'\n", account_name);
296         } else {
297                 gchar * from = modest_account_mgr_get_from_string (account_mgr,
298                                                                   account_name);
299                 if (!from) {
300                         g_printerr ("modest: no from address for account '%s'\n", account_name);
301                 } else {
302                         const gchar *cc = NULL;
303                         const gchar *bcc = NULL;
304                         const gchar *subject = NULL;
305                         const gchar *body = NULL;
306                         
307                         /* Get the relevant items from the list: */
308                         GSList *list = list_names_and_values;
309                         while (list) {
310                                 const gchar * name = (const gchar*)list->data;
311                                 GSList *list_value = g_slist_next (list);
312                                 const gchar * value = (const gchar*)list_value->data;
313                                 
314                                 if (strcmp (name, "cc") == 0) {
315                                         cc = value;
316                                 } else if (strcmp (name, "bcc") == 0) {
317                                         bcc = value;
318                                 } else if (strcmp (name, "subject") == 0) {
319                                         subject = value;
320                                 } else if (strcmp (name, "body") == 0) {
321                                         body = value;
322                                 }
323                                 
324                                 /* Go to the next pair: */
325                                 if (list_value) {
326                                         list = g_slist_next (list_value);
327                                 } else 
328                                         list = NULL;
329                         }
330                         
331                         /* Create the message: */
332                         TnyMsg *msg  = modest_tny_msg_new (to, from, 
333                                 cc, bcc, subject, body, 
334                                 NULL /* attachments */);
335                                 
336                         if (!msg) {
337                                 g_printerr ("modest: failed to create message\n");
338                         } else
339                         {
340                                 /* Add the message to a folder and show its UI for editing: */
341                                 TnyFolder *folder = modest_tny_account_get_special_folder (account,
342                                                                         TNY_FOLDER_TYPE_DRAFTS);
343                                 if (!folder) {
344                                         g_printerr ("modest: failed to find Drafts folder\n");
345                                 } else {
346                         
347                                         tny_folder_add_msg (folder, msg, NULL); /* TODO: check err */
348                 
349                                         ModestWindow *win = modest_msg_edit_window_new (msg, account_name);
350                                         gtk_widget_show_all (GTK_WIDGET (win));
351                                 
352                                         g_object_unref (G_OBJECT(folder));
353                                 }
354                         
355                                 g_object_unref (G_OBJECT(msg));
356                         }
357                         
358                         g_object_unref (G_OBJECT(account));
359                 }
360         }
361         
362         g_free (account_name);
363         
364         /* Free the list, as required by the uri_parse_mailto() documentation: */
365         if (list_names_and_values)
366                 g_slist_foreach (list_names_and_values, (GFunc)g_free, NULL);
367         g_slist_free (list_names_and_values);
368         
369         g_free(to);
370                 
371         g_free(uri);
372
373         return FALSE; /* Do not call this callback again. */
374 }
375
376 static gint on_mail_to(GArray * arguments, gpointer data, osso_rpc_t * retval)
377 {
378         if (arguments->len != MODEST_DEBUS_MAIL_TO_ARGS_COUNT)
379         return OSSO_ERROR;
380         
381     /* Use g_idle to context-switch into the application's thread: */
382  
383     /* Get the arguments: */
384         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_MAIL_TO_ARG_URI);
385         gchar *uri = g_strdup (val.value.s);
386         
387         /* printf("  debug: to=%s\n", idle_data->to); */
388         g_idle_add(on_idle_mail_to, (gpointer)uri);
389         
390         /* Note that we cannot report failures during sending, 
391          * because that would be asynchronous. */
392         return OSSO_OK;
393 }
394
395
396 static gboolean
397 on_idle_compose_mail(gpointer user_data)
398 {
399         ComposeMailIdleData *idle_data = (ComposeMailIdleData*)user_data;
400
401         /* Get the TnyTransportAccount so we can instantiate a mail operation: */
402         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
403         gchar *account_name = modest_account_mgr_get_default_account (account_mgr);
404         if (!account_name) {
405                 g_printerr ("modest: no account found\n");
406         }
407         
408         TnyAccount *account = NULL;
409         if (account_mgr) {
410                 account = modest_tny_account_store_get_transport_account_for_open_connection (
411                         modest_runtime_get_account_store(), account_name);
412         }
413         
414         if (!account) {
415                 g_printerr ("modest: failed to get tny account folder'\n", account_name);
416         } else {
417                 gchar * from = modest_account_mgr_get_from_string (account_mgr,
418                                                                   account_name);
419                 if (!from) {
420                         g_printerr ("modest: no from address for account '%s'\n", account_name);
421                 } else {
422                         
423                         /* Create the message: */
424                         TnyMsg *msg  = modest_tny_msg_new (idle_data->to, from, 
425                                 idle_data->cc, idle_data->bcc, idle_data->subject, idle_data->body, 
426                                 idle_data->attachments);
427                                 
428                         if (!msg) {
429                                 g_printerr ("modest: failed to create message\n");
430                         } else
431                         {
432                                 /* Add the message to a folder and show its UI for editing: */
433                                 TnyFolder *folder = modest_tny_account_get_special_folder (account,
434                                                                         TNY_FOLDER_TYPE_DRAFTS);
435                                 if (!folder) {
436                                         g_printerr ("modest: failed to find Drafts folder\n");
437                                 } else {
438                         
439                                         tny_folder_add_msg (folder, msg, NULL); /* TODO: check err */
440                 
441                                         ModestWindow *win = modest_msg_edit_window_new (msg, account_name);
442                                         gtk_widget_show_all (GTK_WIDGET (win));
443                                 
444                                         g_object_unref (G_OBJECT(folder));
445                                 }
446                         
447                                 g_object_unref (G_OBJECT(msg));
448                         }
449                         
450                         g_object_unref (G_OBJECT(account));
451                 }
452         }
453
454         /* Free the idle data: */
455         g_free (idle_data->to);
456         g_free (idle_data->cc);
457         g_free (idle_data->bcc);
458         g_free (idle_data->subject);
459         g_free (idle_data->body);
460         g_free (idle_data->attachments);
461         g_free (idle_data);
462         
463         g_free (account_name);
464         return FALSE; /* Do not call this callback again. */
465 }
466
467 static gint on_compose_mail(GArray * arguments, gpointer data, osso_rpc_t * retval)
468 {
469         gchar **list = NULL;
470         gint i = 0;
471         
472         if (arguments->len != MODEST_DEBUS_COMPOSE_MAIL_ARGS_COUNT)
473         return OSSO_ERROR;
474         
475         /* Use g_idle to context-switch into the application's thread: */
476         ComposeMailIdleData *idle_data = g_new0(ComposeMailIdleData, 1); /* Freed in the idle callback. */
477         
478         /* Get the arguments: */
479         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_TO);
480         idle_data->to = g_strdup (val.value.s);
481         
482         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_CC);
483         idle_data->cc = g_strdup (val.value.s);
484         
485         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_BCC);
486         idle_data->bcc = g_strdup (val.value.s);
487         
488         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_SUBJECT);
489         idle_data->subject = g_strdup (val.value.s);
490         
491         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_BODY);
492         idle_data->body = g_strdup (val.value.s);
493         
494         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_ATTACHMENTS);
495         gchar *attachments_str = g_strdup (val.value.s);
496
497         list = g_strsplit(attachments_str, ",", 0);
498         for (i=0; list[i] != NULL; i++) {
499                 idle_data->attachments = g_slist_append(idle_data->attachments, g_strdup(list[i]));
500         }
501         g_strfreev(list);
502
503         
504         /* printf("  debug: to=%s\n", idle_data->to); */
505         g_idle_add(on_idle_compose_mail, (gpointer)idle_data);
506         
507         /* Note that we cannot report failures during sending, 
508          * because that would be asynchronous. */
509         return OSSO_OK;
510 }
511
512
513 static TnyMsg *
514 find_message_by_url (const char *uri, TnyAccount **ac_out)
515 {
516
517         ModestTnyAccountStore *astore;
518         TnyAccount            *account;
519         TnyFolder             *folder;
520         TnyMsg                *msg;
521
522         account = NULL;
523         msg = NULL;
524         folder = NULL;
525
526         astore = modest_runtime_get_account_store ();
527         
528         if (astore == NULL) {
529                 return NULL;
530         }
531         
532         g_debug ("Got AccountStore, lets go");
533
534         account = tny_account_store_find_account (TNY_ACCOUNT_STORE (astore),
535                                                   uri);
536         
537         if (account == NULL) {
538                 return NULL;
539         }
540
541         g_debug ("Found account");
542
543         if ( ! TNY_IS_STORE_ACCOUNT (account)) {
544                 goto out;
545         }
546
547         g_debug ("Account is store account");
548
549         *ac_out = account;
550
551         folder = tny_store_account_find_folder (TNY_STORE_ACCOUNT (account),
552                                                 uri,
553                                                 NULL);
554
555         if (folder == NULL) {
556                 goto out;
557         }
558         g_debug ("Found folder");
559         
560
561         msg = tny_folder_find_msg (folder, uri, NULL);
562
563 out:
564         if (account && !msg) {
565                 g_object_unref (account);
566                 *ac_out = NULL;
567         }
568
569         if (folder) {
570                 g_object_unref (folder);
571         }
572
573         return msg;
574 }
575
576 static gboolean
577 on_idle_open_message (gpointer user_data)
578 {
579         ModestWindow *msg_view;
580         TnyMsg       *msg;
581         TnyAccount   *account;
582         TnyHeader    *header; 
583         const char   *msg_uid;
584         const char   *account_name;
585         char         *uri;
586        
587         uri = (char *) user_data;
588
589         g_debug ("Trying to find msg by url: %s", uri); 
590         msg = find_message_by_url (uri, &account);
591         g_free (uri);
592
593         if (msg == NULL) {
594                 return FALSE;
595         }
596         g_debug ("Found message");
597
598         header = tny_msg_get_header (msg);
599         account_name = tny_account_get_name (account);
600         msg_uid = tny_header_get_uid (header);
601         
602         msg_view = modest_msg_view_window_new (msg,
603                                                account_name,
604                                                msg_uid);
605         /* TODO: does that leak the msg_view ?! */
606
607         gtk_widget_show_all (GTK_WIDGET (msg_view));
608
609         g_object_unref (header);
610         g_object_unref (account);
611         
612         return FALSE; /* Do not call this callback again. */
613 }
614
615 static gint on_open_message(GArray * arguments, gpointer data, osso_rpc_t * retval)
616 {
617         if (arguments->len != MODEST_DEBUS_OPEN_MESSAGE_ARGS_COUNT)
618         return OSSO_ERROR;
619         
620     /* Use g_idle to context-switch into the application's thread: */
621
622     /* Get the arguments: */
623         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_OPEN_MESSAGE_ARG_URI);
624         gchar *uri = g_strdup (val.value.s);
625         
626         /* printf("  debug: to=%s\n", idle_data->to); */
627         g_idle_add(on_idle_open_message, (gpointer)uri);
628         
629         /* Note that we cannot report failures during sending, 
630          * because that would be asynchronous. */
631         return OSSO_OK;
632 }
633
634
635 static gint
636 on_delete_message (GArray *arguments, gpointer data, osso_rpc_t *retval)
637 {
638         TnyList      *headers;
639         TnyFolder    *folder;
640         TnyIterator  *iter; 
641         TnyHeader    *header;
642         TnyHeader    *msg_header;
643         TnyMsg       *msg;
644         TnyAccount   *account;
645         GError       *error;
646         osso_rpc_t    val;
647         const char   *uri;
648         const char   *uid;
649         gint          res;
650
651         if (arguments->len != MODEST_DEBUS_DELETE_MESSAGE_ARGS_COUNT) {
652                 return OSSO_ERROR;
653         }
654
655         val = g_array_index (arguments,
656                              osso_rpc_t,
657                              MODEST_DEBUS_DELETE_MESSAGE_ARG_URI);
658
659         uri = (const char *) val.value.s;
660
661         g_debug ("Searching message (delete message)");
662         
663         msg = find_message_by_url (uri, &account);
664
665         if (msg == NULL) {
666                 return OSSO_ERROR;
667         }
668
669         g_debug ("Found message");
670         
671         msg_header = tny_msg_get_header (msg);
672         uid = tny_header_get_uid (msg_header);
673         folder = tny_msg_get_folder (msg);
674
675
676         /* tny_msg_get_header () flaw:
677          * From tinythingy doc: You can't use the returned instance with the
678          * TnyFolder operations
679          *
680          * To get a header instance that will work with these folder methods,
681          * you can use tny_folder_get_headers.
682          *
683          * Ok, we will do so then. Sigh.
684          * */
685         headers = tny_simple_list_new ();
686
687         tny_folder_get_headers (folder, headers, TRUE, NULL);
688         iter = tny_list_create_iterator (headers);
689         header = NULL;
690
691         g_debug ("Searching header for msg in folder");
692         while (!tny_iterator_is_done (iter)) {
693                 const char *cur_id;
694
695                 header = TNY_HEADER (tny_iterator_get_current (iter));
696                 cur_id = tny_header_get_uid (header);
697                 
698                 if (cur_id && uid && g_str_equal (cur_id, uid)) {
699                         g_debug ("Found correspoding header from folder");
700                         break;
701                 }
702
703                 header = NULL;
704                 g_object_unref (header);
705                 tny_iterator_next (iter);
706         }
707
708         g_object_unref (iter);
709         g_object_unref (headers);
710         
711         g_object_unref (msg_header);
712         g_object_unref (msg);
713
714         if (header == NULL) {
715                 g_object_unref (folder);
716                 return OSSO_ERROR;
717         }
718
719
720         error = NULL;
721         res = OSSO_OK;
722         tny_folder_remove_msg (folder, header, &error);
723
724         if (error != NULL) {
725                 res = OSSO_ERROR;
726                 g_error_free (error);
727         }
728
729         g_object_unref (folder);
730         return res;
731 }
732
733 static gboolean
734 on_idle_send_receive(gpointer user_data)
735 {
736         ModestWindow *win;
737
738         /* Pick the main window if it exists */
739         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
740
741         /* Send & receive all if "Update automatically" is set */
742         /* TODO: check the auto-update parameter in the configuration */
743         modest_ui_actions_do_send_receive_all (win);
744         
745         return FALSE; /* Do not call this callback again. */
746 }
747
748 static gint on_send_receive(GArray * arguments, gpointer data, osso_rpc_t * retval)
749 {       
750     /* Use g_idle to context-switch into the application's thread: */
751
752     /* This method has no arguments. */
753         
754         /* printf("  debug: to=%s\n", idle_data->to); */
755         g_idle_add(on_idle_send_receive, NULL);
756         
757         /* Note that we cannot report failures during send/receive, 
758          * because that would be asynchronous. */
759         return OSSO_OK;
760 }
761                       
762 /* Callback for normal D-BUS messages */
763 gint modest_dbus_req_handler(const gchar * interface, const gchar * method,
764                       GArray * arguments, gpointer data,
765                       osso_rpc_t * retval)
766 {
767         
768         g_debug ("modest_dbus_req_handler()\n");
769         g_debug ("debug: method received: %s\n", method);
770         
771         if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_SEND_MAIL) == 0) {
772                 return on_send_mail (arguments, data, retval);
773         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_MAIL_TO) == 0) {
774                 return on_mail_to (arguments, data, retval);
775         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_OPEN_MESSAGE) == 0) {
776                 return on_open_message (arguments, data, retval);
777         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_SEND_RECEIVE) == 0) {
778                 return on_send_receive (arguments, data, retval);
779         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_COMPOSE_MAIL) == 0) {
780                 return on_compose_mail (arguments, data, retval);
781         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_DELETE_MESSAGE) == 0) {
782                 return on_delete_message (arguments,data, retval);
783         }
784         else { 
785                 /* We need to return INVALID here so
786                  * osso is returning DBUS_HANDLER_RESULT_NOT_YET_HANDLED 
787                  * so our modest_dbus_req_filter can kick in!
788                  * */
789                 return OSSO_INVALID;
790         }
791 }
792
793 #define SEARCH_HIT_DBUS_TYPE \
794         DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
795         DBUS_TYPE_STRING_AS_STRING \
796         DBUS_TYPE_STRING_AS_STRING \
797         DBUS_TYPE_STRING_AS_STRING \
798         DBUS_TYPE_STRING_AS_STRING \
799         DBUS_TYPE_UINT64_AS_STRING \
800         DBUS_TYPE_BOOLEAN_AS_STRING \
801         DBUS_TYPE_BOOLEAN_AS_STRING \
802         DBUS_TYPE_INT64_AS_STRING \
803         DBUS_STRUCT_END_CHAR_AS_STRING
804
805 static DBusMessage *
806 search_result_to_messsage (DBusMessage *reply,
807                            GList       *hits)
808 {
809         DBusMessageIter iter;
810         DBusMessageIter array_iter;
811         GList          *hit_iter;
812
813         dbus_message_iter_init_append (reply, &iter); 
814         dbus_message_iter_open_container (&iter,
815                                           DBUS_TYPE_ARRAY,
816                                           SEARCH_HIT_DBUS_TYPE,
817                                           &array_iter); 
818
819         for (hit_iter = hits; hit_iter; hit_iter = hit_iter->next) {
820                 DBusMessageIter  struct_iter;
821                 ModestSearchHit *hit;
822                 char            *msg_url;
823                 const char      *subject;
824                 const char      *folder;
825                 const char      *sender;
826                 guint64          size;
827                 gboolean         has_attachment;
828                 gboolean         is_unread;
829                 gint64           ts;
830
831                 hit = (ModestSearchHit *) hit_iter->data;
832
833                 msg_url = hit->msgid;
834                 subject = hit->subject;
835                 folder  = hit->folder;
836                 sender  = hit->sender;
837                 size           = hit->msize;
838                 has_attachment = hit->has_attachment;
839                 is_unread      = hit->is_unread;
840                 ts             = hit->timestamp;
841
842                 g_debug ("Adding hit: %s", msg_url);    
843                 
844                 dbus_message_iter_open_container (&array_iter,
845                                                   DBUS_TYPE_STRUCT,
846                                                   NULL,
847                                                   &struct_iter);
848
849                 dbus_message_iter_append_basic (&struct_iter,
850                                                 DBUS_TYPE_STRING,
851                                                 &msg_url);
852
853                 dbus_message_iter_append_basic (&struct_iter,
854                                                 DBUS_TYPE_STRING,
855                                                 &subject); 
856
857                 dbus_message_iter_append_basic (&struct_iter,
858                                                 DBUS_TYPE_STRING,
859                                                 &folder);
860
861                 dbus_message_iter_append_basic (&struct_iter,
862                                                 DBUS_TYPE_STRING,
863                                                 &sender);
864
865                 dbus_message_iter_append_basic (&struct_iter,
866                                                 DBUS_TYPE_UINT64,
867                                                 &size);
868
869                 dbus_message_iter_append_basic (&struct_iter,
870                                                 DBUS_TYPE_BOOLEAN,
871                                                 &has_attachment);
872
873                 dbus_message_iter_append_basic (&struct_iter,
874                                                 DBUS_TYPE_BOOLEAN,
875                                                 &is_unread);
876                 
877                 dbus_message_iter_append_basic (&struct_iter,
878                                                 DBUS_TYPE_INT64,
879                                                 &ts);
880
881                 dbus_message_iter_close_container (&array_iter,
882                                                    &struct_iter); 
883
884                 g_free (hit->msgid);
885                 g_free (hit->subject);
886                 g_free (hit->folder);
887                 g_free (hit->sender);
888
889                 g_slice_free (ModestSearchHit, hit);
890         }
891
892         dbus_message_iter_close_container (&iter, &array_iter);
893
894         return reply;
895 }
896
897 DBusHandlerResult
898 modest_dbus_req_filter (DBusConnection *con,
899                         DBusMessage    *message,
900                         void           *user_data)
901 {
902         gboolean  handled = FALSE;
903         DBusError error;
904
905         if (dbus_message_is_method_call (message,
906                                          MODEST_DBUS_IFACE,
907                                          MODEST_DBUS_METHOD_SEARCH)) {
908                 ModestDBusSearchFlags dbus_flags;
909                 ModestSearch  search;
910                 DBusMessage  *reply = NULL;
911                 dbus_bool_t  res;
912                 dbus_int64_t sd_v;
913                 dbus_int64_t ed_v;
914                 dbus_int32_t flags_v;
915                 dbus_uint32_t serial;
916                 dbus_uint32_t size_v;
917                 char *folder;
918                 char *query;
919                 time_t start_date;
920                 time_t end_date;
921                 GList *hits;
922
923                 handled = TRUE;
924
925                 dbus_error_init (&error);
926
927                 sd_v = ed_v = 0;
928                 flags_v = 0;
929
930                 res = dbus_message_get_args (message,
931                                              &error,
932                                              DBUS_TYPE_STRING, &query,
933                                              DBUS_TYPE_STRING, &folder,
934                                              DBUS_TYPE_INT64, &sd_v,
935                                              DBUS_TYPE_INT64, &ed_v,
936                                              DBUS_TYPE_INT32, &flags_v,
937                                              DBUS_TYPE_UINT32, &size_v,
938                                              DBUS_TYPE_INVALID);
939                 
940                 dbus_flags = (ModestDBusSearchFlags) flags_v;
941                 start_date = (time_t) sd_v;
942                 end_date = (time_t) ed_v;
943
944                 memset (&search, 0, sizeof (search));
945 #ifdef MODEST_HAVE_OGS
946                 search.query  = query;
947 #endif
948                 search.before = start_date;
949                 search.after  = end_date;
950                 search.flags  = 0;
951
952                 if (dbus_flags & MODEST_DBUS_SEARCH_SUBJECT) {
953                         search.flags |= MODEST_SEARCH_SUBJECT;
954                         search.subject = query;
955                 }
956
957                 if (dbus_flags & MODEST_DBUS_SEARCH_SENDER) {
958                         search.flags |=  MODEST_SEARCH_SENDER;
959                         search.from = query;
960                 }
961
962                 if (dbus_flags & MODEST_DBUS_SEARCH_RECIPIENT) {
963                         search.flags |= MODEST_SEARCH_RECIPIENT; 
964                         search.recipient = query;
965                 }
966
967                 if (dbus_flags & MODEST_DBUS_SEARCH_BODY) {
968                         search.flags |=  MODEST_SEARCH_BODY; 
969                         search.subject = query;
970                 }
971
972                 if (sd_v > 0) {
973                         search.flags |= MODEST_SEARCH_BEFORE;
974                         search.before = start_date;
975                 }
976
977                 if (ed_v > 0) {
978                         search.flags |= MODEST_SEARCH_AFTER;
979                         search.after = end_date;
980                 }
981
982                 if (size_v > 0) {
983                         search.flags |= MODEST_SEARCH_SIZE;
984                         search.minsize = size_v;
985                 }
986
987 #ifdef MODEST_HAVE_OGS
988                 search.flags |= MODEST_SEARCH_USE_OGS;
989                 g_debug ("Starting search for %s", search.query);
990 #endif
991                 hits = modest_search_all_accounts (&search);
992
993                 reply = dbus_message_new_method_return (message);
994
995                 search_result_to_messsage (reply, hits);
996
997                 if (reply == NULL) {
998                         g_warning ("Could not create reply");
999                 }
1000
1001                 if (reply) {
1002                         dbus_connection_send (con, reply, &serial);
1003                         dbus_connection_flush (con);
1004                         dbus_message_unref (reply);
1005                 }
1006
1007                 g_list_free (hits);
1008
1009         }
1010         
1011
1012         return (handled ? 
1013                 DBUS_HANDLER_RESULT_HANDLED :
1014                 DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
1015 }
1016
1017 void
1018 modest_osso_cb_hw_state_handler(osso_hw_state_t *state, gpointer data)
1019 {
1020         /* TODO? */
1021     /* printf("%s()\n", __PRETTY_FUNCTION__); */
1022
1023     if(state->system_inactivity_ind)
1024     {
1025     }
1026     else if(state->save_unsaved_data_ind)
1027     {
1028     }
1029     else
1030     {
1031     
1032     }
1033
1034     /* printf("debug: %s(): return\n", __PRETTY_FUNCTION__); */
1035 }