2007-06-25 Johannes Schmid <johannes.schmid@openismus.com>
[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
37 #include "modest-search.h"
38 #include "widgets/modest-msg-edit-window.h"
39 #include "modest-tny-msg.h"
40 #include <libmodest-dbus-client/libmodest-dbus-client.h>
41 #include <libgnomevfs/gnome-vfs-utils.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <glib/gstdio.h>
45 #ifdef MODEST_HAVE_HILDON0_WIDGETS
46 #include <libgnomevfs/gnome-vfs-mime-utils.h>
47 #else
48 #include <libgnomevfs/gnome-vfs-mime.h>
49 #endif
50 #include <tny-fs-stream.h>
51
52 #include <tny-list.h>
53 #include <tny-iterator.h>
54 #include <tny-simple-list.h>
55
56 typedef struct 
57 {
58         gchar *to;
59         gchar *cc;
60         gchar *bcc;
61         gchar *subject;
62         gchar *body;
63         gchar *attachments;
64 } SendMailIdleData;
65
66 typedef struct 
67 {
68         gchar *to;
69         gchar *cc;
70         gchar *bcc;
71         gchar *subject;
72         gchar *body;
73         gchar *attachments;
74 } ComposeMailIdleData;
75
76 static gboolean
77 on_idle_send_mail(gpointer user_data)
78 {
79         SendMailIdleData *idle_data = (SendMailIdleData*)user_data;
80         
81         /* Get the TnyTransportAccount so we can instantiate a mail operation: */
82         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
83         gchar *account_name = modest_account_mgr_get_default_account (account_mgr);
84         if (!account_name) {
85                 g_printerr ("modest: no account found\n");
86         }
87         
88         TnyTransportAccount *transport_account = NULL;
89         if (account_mgr) {
90                 transport_account = TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_transport_account_for_open_connection
91                                       (modest_runtime_get_account_store(),
92                                        account_name));
93         }
94         
95         if (!transport_account) {
96                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
97         }
98         
99         /* Create the mail operation: */
100         if (transport_account) {        
101                 /* Use the mail operation: */
102                 gchar * from = modest_account_mgr_get_from_string (account_mgr,
103                                                                   account_name);
104                 if (!from) {
105                         g_printerr ("modest: no from address for account '%s'\n", account_name);
106                 } else {
107                         ModestMailOperation *mail_operation = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_SEND, NULL);
108                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
109                         
110                         modest_mail_operation_send_new_mail (mail_operation,
111                                              transport_account,
112                                              NULL,
113                                              from, /* from */
114                                              idle_data->to, idle_data->cc, idle_data->bcc, idle_data->subject, 
115                                              idle_data->body, /* plain_body */
116                                              NULL, /* html_body */
117                                              NULL, /* attachments_list, GSList of TnyMimePart. */
118                                              (TnyHeaderFlags)0);
119                                              
120                         g_free (from);
121                         g_object_unref (G_OBJECT (mail_operation));
122                 }
123                                      
124                 g_object_unref (G_OBJECT (transport_account));
125         }
126         
127         g_free (account_name);
128         
129         /* Free the idle data: */
130         g_free (idle_data->to);
131         g_free (idle_data->cc);
132         g_free (idle_data->bcc);
133         g_free (idle_data->subject);
134         g_free (idle_data->body);
135         g_free (idle_data->attachments);
136         g_free (idle_data);
137         
138         return FALSE; /* Do not call this callback again. */
139 }
140
141 /* TODO: Is this actually used by anything?
142  * I guess that everything uses *_compose_mail() instead. murrayc.
143  */
144 static gint on_send_mail(GArray * arguments, gpointer data, osso_rpc_t * retval)
145 {
146         if (arguments->len != MODEST_DEBUS_SEND_MAIL_ARGS_COUNT)
147         return OSSO_ERROR;
148         
149     /* Use g_idle to context-switch into the application's thread: */
150         SendMailIdleData *idle_data = g_new0(SendMailIdleData, 1); /* Freed in the idle callback. */
151         
152     /* Get the arguments: */
153         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_TO);
154         idle_data->to = g_strdup (val.value.s);
155         
156         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_CC);
157         idle_data->cc = g_strdup (val.value.s);
158         
159         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_BCC);
160         idle_data->bcc = g_strdup (val.value.s);
161         
162         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_SUBJECT);
163         idle_data->subject = g_strdup (val.value.s);
164         
165         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_BODY);
166         idle_data->body = g_strdup (val.value.s);
167         
168         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_SEND_MAIL_ARG_ATTACHMENTS);
169         idle_data->attachments = g_strdup (val.value.s);
170         
171         /* printf("  debug: to=%s\n", idle_data->to); */
172         g_idle_add(on_idle_send_mail, (gpointer)idle_data);
173         
174         /* Note that we cannot report failures during sending, 
175          * because that would be asynchronous. */
176         return OSSO_OK;
177 }
178
179 /** uri_unescape:
180  * @uri An escaped URI. URIs should always be escaped.
181  * @len The length of the @uri string, or -1 if the string is null terminated.
182  * 
183  * Decode a URI, or URI fragment, as per RFC 1738.
184  * http://www.ietf.org/rfc/rfc1738.txt
185  * 
186  * Return value: An unescaped string. This should be freed with g_free().
187  */
188 static gchar* uri_unescape(const gchar* uri, size_t len)
189 {
190         if (!uri)
191                 return NULL;
192                 
193         if (len == -1)
194                 len = strlen (uri);
195         
196         /* Allocate an extra string so we can be sure that it is null-terminated,
197          * so we can use gnome_vfs_unescape_string().
198          * This is not efficient. */
199         gchar * escaped_nullterminated = g_strndup (uri, len);
200         gchar *result = gnome_vfs_unescape_string (escaped_nullterminated, NULL);
201         g_free (escaped_nullterminated);
202         
203         return result;
204 }
205
206 /** uri_parse_mailto:
207  * @mailto A mailto URI, with the mailto: prefix.
208  * @list_items_and_values: A pointer to a list that should be filled with item namesand value strings, 
209  * with each name item being followed by a value item. This list should be freed with g_slist_free) after 
210  * all the string items have been freed. This parameter may be NULL.
211  * Parse a mailto URI as per RFC2368.
212  * http://www.ietf.org/rfc/rfc2368.txt
213  * 
214  * Return value: The to address, unescaped. This should be freed with g_free().
215  */
216 static gchar* uri_parse_mailto (const gchar* mailto, GSList** list_items_and_values)
217 {
218         const gchar* start_to = NULL;
219         /* Remove the mailto: prefix: 
220          * 7 is the length of "mailto:": */
221         if (strncmp (mailto, "mailto:", 7) == 0) {
222                 start_to = mailto + 7;
223         }
224         
225         if (!start_to)
226                 return NULL;
227         
228         /* Look for ?, or the end of the string, marking the end of the to address: */
229         const size_t len_to = strcspn (start_to, "?");
230         gchar* result_to = uri_unescape (start_to, len_to);
231         printf("debug: result_to=%s\n", result_to);
232         
233         /* Get any other items: */
234         const size_t len_mailto = strlen (start_to);
235         const gchar* p = start_to + len_to + 1; /* parsed so far. */
236         const gchar* end = start_to + len_mailto;
237         /* GSList *items = NULL; */
238         const gchar* start_item_name = p;
239         size_t len_item_name = 0;
240         const gchar* start_item_value = NULL;
241         while (p < end) {
242                 
243                 /* Looking for the end of a name; */
244                 if (start_item_name) {
245                         const size_t len = strcspn (p, "="); /* Returns whole string if none found. */
246                         if (len) {
247                                 /* This marks the end of a name and the start of the value: */
248                                 len_item_name = len;
249                                 
250                                 /* Skip over the name and mark the start of the value: */
251                                 p += (len + 1); /* Skip over the = */
252                                 start_item_value = p;
253                         }
254                 }
255                 
256                 /* Looking for the end of a value: */
257                 if (start_item_value) {
258                         const size_t len = strcspn (p, "?"); /* Returns whole string if none found. */
259                         /* ? marks the start of a new item: */
260                         if (len) {
261                                 if (start_item_name && len_item_name) {
262                                         /* Finish the previously-started item: */
263                                         gchar *item_value = uri_unescape (start_item_value, len);
264                                         gchar *item_name = g_strndup (start_item_name, len_item_name);
265                                         /* printf ("debug: item name=%s, value=%s\n", item_name, item_value); */
266                                         
267                                         /* Append the items to the list */
268                                         if(list_items_and_values) {
269                                                 *list_items_and_values = g_slist_append (*list_items_and_values, item_name);
270                                                 *list_items_and_values = g_slist_append (*list_items_and_values, item_value);
271                                         }
272                                 }
273                                 
274                                 /* Skip over the value and mark the start of a possible new name/value pair: */
275                                 p += (len + 1); /* Skip over the ? */
276                                 start_item_name = p;
277                                 len_item_name = 0;
278                                 start_item_value = NULL;
279                         }
280                 }
281                 
282         }
283         
284         return result_to;
285 }
286
287
288 static gboolean
289 on_idle_mail_to(gpointer user_data)
290 {
291         /* This is based on the implemenation of main.c:start_uil(): */
292         
293         gchar *uri = (gchar*)user_data;
294         GSList *list_names_and_values = NULL;
295         gchar *to = uri_parse_mailto (uri, &list_names_and_values);
296         
297         /* Get the TnyTransportAccount so we can instantiate a mail operation: */
298         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
299         gchar *account_name = modest_account_mgr_get_default_account (account_mgr);
300         if (!account_name) {
301                 g_printerr ("modest: no account found\n");
302         }
303         
304         TnyAccount *account = NULL;
305         if (account_mgr) {
306                 account = modest_tny_account_store_get_transport_account_for_open_connection (
307                         modest_runtime_get_account_store(), account_name);
308         }
309         
310         if (!account) {
311                 g_printerr ("modest: failed to get tny account folder'\n", account_name);
312         } else {
313                 gchar * from = modest_account_mgr_get_from_string (account_mgr,
314                                                                   account_name);
315                 if (!from) {
316                         g_printerr ("modest: no from address for account '%s'\n", account_name);
317                 } else {
318                         const gchar *cc = NULL;
319                         const gchar *bcc = NULL;
320                         const gchar *subject = NULL;
321                         const gchar *body = NULL;
322                         
323                         /* Get the relevant items from the list: */
324                         GSList *list = list_names_and_values;
325                         while (list) {
326                                 const gchar * name = (const gchar*)list->data;
327                                 GSList *list_value = g_slist_next (list);
328                                 const gchar * value = (const gchar*)list_value->data;
329                                 
330                                 if (strcmp (name, "cc") == 0) {
331                                         cc = value;
332                                 } else if (strcmp (name, "bcc") == 0) {
333                                         bcc = value;
334                                 } else if (strcmp (name, "subject") == 0) {
335                                         subject = value;
336                                 } else if (strcmp (name, "body") == 0) {
337                                         body = value;
338                                 }
339                                 
340                                 /* Go to the next pair: */
341                                 if (list_value) {
342                                         list = g_slist_next (list_value);
343                                 } else 
344                                         list = NULL;
345                         }
346                         
347                         /* Create the message: */
348                         TnyMsg *msg  = modest_tny_msg_new (to, from, 
349                                 cc, bcc, subject, body, 
350                                 NULL /* attachments */);
351                                 
352                         if (!msg) {
353                                 g_printerr ("modest: failed to create message\n");
354                         } else
355                         {
356                                 /* Add the message to a folder and show its UI for editing: */
357                                 TnyFolder *folder = modest_tny_account_get_special_folder (account,
358                                                                         TNY_FOLDER_TYPE_DRAFTS);
359                                 if (!folder) {
360                                         g_printerr ("modest: failed to find Drafts folder\n");
361                                 } else {
362                         
363                                         tny_folder_add_msg (folder, msg, NULL); /* TODO: check err */
364                 
365                                         ModestWindow *win = modest_msg_edit_window_new (msg, account_name);
366                                         gtk_widget_show_all (GTK_WIDGET (win));
367                                 
368                                         g_object_unref (G_OBJECT(folder));
369                                 }
370                         
371                                 g_object_unref (G_OBJECT(msg));
372                         }
373                         
374                         g_object_unref (G_OBJECT(account));
375                 }
376         }
377         
378         g_free (account_name);
379         
380         /* Free the list, as required by the uri_parse_mailto() documentation: */
381         if (list_names_and_values)
382                 g_slist_foreach (list_names_and_values, (GFunc)g_free, NULL);
383         g_slist_free (list_names_and_values);
384         
385         g_free(to);
386                 
387         g_free(uri);
388
389         return FALSE; /* Do not call this callback again. */
390 }
391
392 static gint on_mail_to(GArray * arguments, gpointer data, osso_rpc_t * retval)
393 {
394         if (arguments->len != MODEST_DEBUS_MAIL_TO_ARGS_COUNT)
395         return OSSO_ERROR;
396         
397     /* Use g_idle to context-switch into the application's thread: */
398  
399     /* Get the arguments: */
400         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_MAIL_TO_ARG_URI);
401         gchar *uri = g_strdup (val.value.s);
402         
403         /* printf("  debug: to=%s\n", idle_data->to); */
404         g_idle_add(on_idle_mail_to, (gpointer)uri);
405         
406         /* Note that we cannot report failures during sending, 
407          * because that would be asynchronous. */
408         return OSSO_OK;
409 }
410
411
412
413
414
415 static gboolean
416 on_idle_compose_mail(gpointer user_data)
417 {
418         ComposeMailIdleData *idle_data = (ComposeMailIdleData*)user_data;
419         gchar **list = NULL;
420         gint i = 0;
421
422         /* Get the TnyTransportAccount so we can instantiate a mail operation: */
423         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
424         gchar *account_name = modest_account_mgr_get_default_account (account_mgr);
425         if (!account_name) {
426                 g_printerr ("modest: no account found\n");
427         }
428         
429         TnyAccount *account = NULL;
430         if (account_mgr) {
431                 account = modest_tny_account_store_get_transport_account_for_open_connection (
432                         modest_runtime_get_account_store(), account_name);
433         }
434         
435         if (!account) {
436                 g_printerr ("modest: failed to get tny account folder'%s'\n", account_name);
437         } else {
438                 gchar * from = modest_account_mgr_get_from_string (account_mgr,
439                                                                   account_name);
440                 if (!from) {
441                         g_printerr ("modest: no from address for account '%s'\n", account_name);
442                 } else {
443         
444                         /* Create the message: */
445                         TnyMsg *msg  = modest_tny_msg_new (idle_data->to, from, 
446                                 idle_data->cc, idle_data->bcc, idle_data->subject, idle_data->body, 
447                                 NULL); /* NULL because m_t_m_n doesn't use it */
448                                 
449                         if (!msg) {
450                                 g_printerr ("modest: failed to create message\n");
451                         } else
452                         {
453                                 /* Add the message to a folder and show its UI for editing: */
454                                 TnyFolder *folder = modest_tny_account_get_special_folder (account,
455                                                                         TNY_FOLDER_TYPE_DRAFTS);
456                                 if (!folder) {
457                                         g_printerr ("modest: failed to find Drafts folder\n");
458                                 } else {
459                         
460                                         tny_folder_add_msg (folder, msg, NULL); /* TODO: check err */
461                 
462                                         ModestWindow *win = modest_msg_edit_window_new (msg, account_name);
463
464                                         list = g_strsplit(idle_data->attachments, ",", 0);
465                                         for (i=0; list[i] != NULL; i++) {
466                                                 modest_msg_edit_window_attach_file_noninteractive(
467                                                                 (ModestMsgEditWindow *)win, list[i]);
468                                         }
469                                         g_strfreev(list);
470                                         
471                                         gtk_widget_show_all (GTK_WIDGET (win));
472                                 
473                                         g_object_unref (G_OBJECT(folder));
474                                 }
475                         
476                                 g_object_unref (G_OBJECT(msg));
477                         }
478                         
479                         g_object_unref (G_OBJECT(account));
480                 }
481         }
482
483         /* Free the idle data: */
484         g_free (idle_data->to);
485         g_free (idle_data->cc);
486         g_free (idle_data->bcc);
487         g_free (idle_data->subject);
488         g_free (idle_data->body);
489         g_free (idle_data->attachments);
490         g_free (idle_data);
491         
492         g_free (account_name);
493         return FALSE; /* Do not call this callback again. */
494 }
495
496 static gint on_compose_mail(GArray * arguments, gpointer data, osso_rpc_t * retval)
497 {
498
499         
500         if (arguments->len != MODEST_DEBUS_COMPOSE_MAIL_ARGS_COUNT)
501         return OSSO_ERROR;
502         
503         /* Use g_idle to context-switch into the application's thread: */
504         ComposeMailIdleData *idle_data = g_new0(ComposeMailIdleData, 1); /* Freed in the idle callback. */
505         
506         /* Get the arguments: */
507         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_TO);
508         idle_data->to = g_strdup (val.value.s);
509         
510         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_CC);
511         idle_data->cc = g_strdup (val.value.s);
512         
513         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_BCC);
514         idle_data->bcc = g_strdup (val.value.s);
515         
516         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_SUBJECT);
517         idle_data->subject = g_strdup (val.value.s);
518         
519         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_BODY);
520         idle_data->body = g_strdup (val.value.s);
521         
522         val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_COMPOSE_MAIL_ARG_ATTACHMENTS);
523         idle_data->attachments = g_strdup (val.value.s);
524
525         g_idle_add(on_idle_compose_mail, (gpointer)idle_data);
526         
527         /* Note that we cannot report failures during sending, 
528          * because that would be asynchronous. */
529         return OSSO_OK;
530 }
531
532
533 static TnyMsg *
534 find_message_by_url (const char *uri, TnyAccount **ac_out)
535 {
536         ModestTnyAccountStore *astore;
537         TnyAccount            *account;
538         TnyFolder             *folder;
539         TnyMsg                *msg;
540         GError *err = NULL;
541         account = NULL;
542         msg = NULL;
543         folder = NULL;
544
545         astore = modest_runtime_get_account_store ();
546         
547         if (astore == NULL) {
548                 return NULL;
549         }
550
551         account = tny_account_store_find_account (TNY_ACCOUNT_STORE (astore),
552                                                   uri);
553         
554         if (account == NULL) {
555                 g_debug ("%s: tny_account_store_find_account() failed.\n", __FUNCTION__);
556                 return NULL;
557         }
558
559         g_debug ("%s: Found account.\n", __FUNCTION__);
560
561         if ( ! TNY_IS_STORE_ACCOUNT (account)) {
562                 goto out;
563         }
564
565         g_debug ("%s: Account is store account.\n", __FUNCTION__);
566
567         *ac_out = account;
568
569         folder = tny_store_account_find_folder (TNY_STORE_ACCOUNT (account),
570                                                 uri,
571                                                 &err);
572
573         if (folder == NULL) {
574                 g_debug ("%s: tny_store_account_find_folder() failed\naccount=%s, uri=%s.\n", __FUNCTION__, 
575                         tny_account_get_id (TNY_ACCOUNT(account)), uri);
576                 goto out;
577         }
578         g_debug ("%s: Found folder. (%s)\n",  __FUNCTION__, uri);
579         
580
581         msg = tny_folder_find_msg (folder, uri, &err);
582         
583         if (!msg) {
584                 g_debug ("%s: tny_folder_find_msg() failed for folder %s\n  with error=%s.\n",
585                          __FUNCTION__, tny_folder_get_id (folder), err->message);
586         }
587
588 out:
589         if (err)
590                 g_error_free (err);
591
592         if (account && !msg) {
593                 g_object_unref (account);
594                 *ac_out = NULL;
595         }
596
597         if (folder) {
598                 g_object_unref (folder);
599         }
600
601         return msg;
602 }
603
604 static gboolean
605 on_idle_open_message (gpointer user_data)
606 {
607         ModestWindow *msg_view;
608         TnyMsg       *msg;
609         TnyAccount   *account;
610         TnyHeader    *header; 
611         const char   *msg_uid;
612         const char   *account_name;
613         char         *uri;
614        
615         uri = (char *) user_data;
616
617         g_debug ("%s: Trying to find msg by url: %s", __FUNCTION__, uri);       
618         msg = find_message_by_url (uri, &account);
619         g_free (uri);
620
621         if (msg == NULL) {
622                 g_debug ("  %s: message not found.", __FUNCTION__);
623                 return FALSE;
624         }
625         g_debug ("  %s: Found message.", __FUNCTION__);
626
627         header = tny_msg_get_header (msg);
628         account_name = tny_account_get_name (account);
629         msg_uid = tny_header_get_uid (header);
630         
631         msg_view = modest_msg_view_window_new (msg,
632                                                account_name,
633                                                msg_uid);
634         /* TODO: does that leak the msg_view ?! */
635
636         gtk_widget_show_all (GTK_WIDGET (msg_view));
637
638         g_object_unref (header);
639         g_object_unref (account);
640         
641         return FALSE; /* Do not call this callback again. */
642 }
643
644 static gint on_open_message(GArray * arguments, gpointer data, osso_rpc_t * retval)
645 {
646         if (arguments->len != MODEST_DEBUS_OPEN_MESSAGE_ARGS_COUNT)
647         return OSSO_ERROR;
648         
649     /* Use g_idle to context-switch into the application's thread: */
650
651     /* Get the arguments: */
652         osso_rpc_t val = g_array_index(arguments, osso_rpc_t, MODEST_DEBUS_OPEN_MESSAGE_ARG_URI);
653         gchar *uri = g_strdup (val.value.s);
654         
655         /* printf("  debug: to=%s\n", idle_data->to); */
656         g_idle_add(on_idle_open_message, (gpointer)uri);
657         
658         /* Note that we cannot report failures during sending, 
659          * because that would be asynchronous. */
660         return OSSO_OK;
661 }
662
663
664 static gint
665 on_delete_message (GArray *arguments, gpointer data, osso_rpc_t *retval)
666 {
667         TnyList      *headers;
668         TnyFolder    *folder;
669         TnyIterator  *iter; 
670         TnyHeader    *header;
671         TnyHeader    *msg_header;
672         TnyMsg       *msg;
673         TnyAccount   *account;
674         GError       *error;
675         osso_rpc_t    val;
676         const char   *uri;
677         const char   *uid;
678         gint          res;
679
680         if (arguments->len != MODEST_DEBUS_DELETE_MESSAGE_ARGS_COUNT) {
681                 return OSSO_ERROR;
682         }
683
684         val = g_array_index (arguments,
685                              osso_rpc_t,
686                              MODEST_DEBUS_DELETE_MESSAGE_ARG_URI);
687
688         uri = (const char *) val.value.s;
689
690         g_debug ("Searching message (delete message)");
691         
692         msg = find_message_by_url (uri, &account);
693
694         if (msg == NULL) {
695                 return OSSO_ERROR;
696         }
697
698         g_debug ("Found message");
699         
700         msg_header = tny_msg_get_header (msg);
701         uid = tny_header_get_uid (msg_header);
702         folder = tny_msg_get_folder (msg);
703
704
705         /* tny_msg_get_header () flaw:
706          * From tinythingy doc: You can't use the returned instance with the
707          * TnyFolder operations
708          *
709          * To get a header instance that will work with these folder methods,
710          * you can use tny_folder_get_headers.
711          *
712          * Ok, we will do so then. Sigh.
713          * */
714         headers = tny_simple_list_new ();
715
716         tny_folder_get_headers (folder, headers, TRUE, NULL);
717         iter = tny_list_create_iterator (headers);
718         header = NULL;
719
720         g_debug ("Searching header for msg in folder");
721         while (!tny_iterator_is_done (iter)) {
722                 const char *cur_id;
723
724                 header = TNY_HEADER (tny_iterator_get_current (iter));
725                 cur_id = tny_header_get_uid (header);
726                 
727                 if (cur_id && uid && g_str_equal (cur_id, uid)) {
728                         g_debug ("Found correspoding header from folder");
729                         break;
730                 }
731
732                 header = NULL;
733                 g_object_unref (header);
734                 tny_iterator_next (iter);
735         }
736
737         g_object_unref (iter);
738         g_object_unref (headers);
739         
740         g_object_unref (msg_header);
741         g_object_unref (msg);
742
743         if (header == NULL) {
744                 g_object_unref (folder);
745                 return OSSO_ERROR;
746         }
747
748
749         error = NULL;
750         res = OSSO_OK;
751         tny_folder_remove_msg (folder, header, &error);
752
753         if (error != NULL) {
754                 res = OSSO_ERROR;
755                 g_error_free (error);
756         }
757
758         g_object_unref (folder);
759         return res;
760 }
761
762 static gboolean
763 on_idle_send_receive(gpointer user_data)
764 {
765         ModestWindow *win;
766
767         /* Pick the main window if it exists */
768         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
769
770         /* Send & receive all if "Update automatically" is set */
771         /* TODO: check the auto-update parameter in the configuration */
772         modest_ui_actions_do_send_receive_all (win);
773         
774         return FALSE; /* Do not call this callback again. */
775 }
776
777 static gint on_send_receive(GArray * arguments, gpointer data, osso_rpc_t * retval)
778 {       
779     /* Use g_idle to context-switch into the application's thread: */
780
781     /* This method has no arguments. */
782         
783         /* printf("  debug: to=%s\n", idle_data->to); */
784         g_idle_add(on_idle_send_receive, NULL);
785         
786         /* Note that we cannot report failures during send/receive, 
787          * because that would be asynchronous. */
788         return OSSO_OK;
789 }
790
791 static gboolean
792 on_idle_open_default_inbox(gpointer user_data)
793 {
794         ModestWindow *win = 
795                 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
796
797         /* Get the folder view */
798         GtkWidget *folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
799                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
800         modest_folder_view_select_first_inbox_or_local (
801                 MODEST_FOLDER_VIEW (folder_view));
802         
803         return FALSE; /* Do not call this callback again. */
804 }
805
806 static gint on_open_default_inbox(GArray * arguments, gpointer data, osso_rpc_t * retval)
807 {
808     /* Use g_idle to context-switch into the application's thread: */
809
810     /* This method has no arguments. */
811         
812         g_idle_add(on_idle_open_default_inbox, NULL);
813         
814         /* Note that we cannot report failures during send/receive, 
815          * because that would be asynchronous. */
816         return OSSO_OK;
817 }
818                       
819 /* Callback for normal D-BUS messages */
820 gint modest_dbus_req_handler(const gchar * interface, const gchar * method,
821                       GArray * arguments, gpointer data,
822                       osso_rpc_t * retval)
823 {
824         
825         g_debug ("debug: %s\n", __FUNCTION__);
826         g_debug ("debug: %s: method received: %s\n", __FUNCTION__, method);
827         
828         if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_SEND_MAIL) == 0) {
829                 return on_send_mail (arguments, data, retval);
830         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_MAIL_TO) == 0) {
831                 return on_mail_to (arguments, data, retval);
832         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_OPEN_MESSAGE) == 0) {
833                 return on_open_message (arguments, data, retval);
834         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_SEND_RECEIVE) == 0) {
835                 return on_send_receive (arguments, data, retval);
836         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_COMPOSE_MAIL) == 0) {
837                 return on_compose_mail (arguments, data, retval);
838         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_DELETE_MESSAGE) == 0) {
839                 return on_delete_message (arguments,data, retval);
840         } else if (g_ascii_strcasecmp(method, MODEST_DBUS_METHOD_OPEN_DEFAULT_INBOX) == 0) {
841                 return on_open_default_inbox (arguments, data, retval);
842         }
843         else { 
844                 /* We need to return INVALID here so
845                  * libosso will return DBUS_HANDLER_RESULT_NOT_YET_HANDLED,
846                  * so that our modest_dbus_req_filter will then be tried instead.
847                  * */
848                 return OSSO_INVALID;
849         }
850 }
851                                          
852 /* A complex D-Bus type (like a struct),
853  * used to return various information about a search hit.
854  */
855 #define SEARCH_HIT_DBUS_TYPE \
856         DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
857         DBUS_TYPE_STRING_AS_STRING /* msgid */ \
858         DBUS_TYPE_STRING_AS_STRING /* subject */ \
859         DBUS_TYPE_STRING_AS_STRING /* folder */ \
860         DBUS_TYPE_STRING_AS_STRING /* sender */ \
861         DBUS_TYPE_UINT64_AS_STRING /* msize */ \
862         DBUS_TYPE_BOOLEAN_AS_STRING /* has_attachment */ \
863         DBUS_TYPE_BOOLEAN_AS_STRING /* is_unread */ \
864         DBUS_TYPE_INT64_AS_STRING /* timestamp */ \
865         DBUS_STRUCT_END_CHAR_AS_STRING
866
867 static DBusMessage *
868 search_result_to_message (DBusMessage *reply,
869                            GList       *hits)
870 {
871         DBusMessageIter iter;
872         DBusMessageIter array_iter;
873         GList          *hit_iter;
874
875         dbus_message_iter_init_append (reply, &iter); 
876         dbus_message_iter_open_container (&iter,
877                                           DBUS_TYPE_ARRAY,
878                                           SEARCH_HIT_DBUS_TYPE,
879                                           &array_iter); 
880
881         for (hit_iter = hits; hit_iter; hit_iter = hit_iter->next) {
882                 DBusMessageIter  struct_iter;
883                 ModestSearchHit *hit;
884                 char            *msg_url;
885                 const char      *subject;
886                 const char      *folder;
887                 const char      *sender;
888                 guint64          size;
889                 gboolean         has_attachment;
890                 gboolean         is_unread;
891                 gint64           ts;
892
893                 hit = (ModestSearchHit *) hit_iter->data;
894
895                 msg_url = hit->msgid;
896                 subject = hit->subject;
897                 folder  = hit->folder;
898                 sender  = hit->sender;
899                 size           = hit->msize;
900                 has_attachment = hit->has_attachment;
901                 is_unread      = hit->is_unread;
902                 ts             = hit->timestamp;
903
904                 g_debug ("DEBUG: %s: Adding hit: %s", __FUNCTION__, msg_url);   
905                 
906                 dbus_message_iter_open_container (&array_iter,
907                                                   DBUS_TYPE_STRUCT,
908                                                   NULL,
909                                                   &struct_iter);
910
911                 dbus_message_iter_append_basic (&struct_iter,
912                                                 DBUS_TYPE_STRING,
913                                                 &msg_url);
914
915                 dbus_message_iter_append_basic (&struct_iter,
916                                                 DBUS_TYPE_STRING,
917                                                 &subject); 
918
919                 dbus_message_iter_append_basic (&struct_iter,
920                                                 DBUS_TYPE_STRING,
921                                                 &folder);
922
923                 dbus_message_iter_append_basic (&struct_iter,
924                                                 DBUS_TYPE_STRING,
925                                                 &sender);
926
927                 dbus_message_iter_append_basic (&struct_iter,
928                                                 DBUS_TYPE_UINT64,
929                                                 &size);
930
931                 dbus_message_iter_append_basic (&struct_iter,
932                                                 DBUS_TYPE_BOOLEAN,
933                                                 &has_attachment);
934
935                 dbus_message_iter_append_basic (&struct_iter,
936                                                 DBUS_TYPE_BOOLEAN,
937                                                 &is_unread);
938                 
939                 dbus_message_iter_append_basic (&struct_iter,
940                                                 DBUS_TYPE_INT64,
941                                                 &ts);
942
943                 dbus_message_iter_close_container (&array_iter,
944                                                    &struct_iter); 
945
946                 g_free (hit->msgid);
947                 g_free (hit->subject);
948                 g_free (hit->folder);
949                 g_free (hit->sender);
950
951                 g_slice_free (ModestSearchHit, hit);
952         }
953
954         dbus_message_iter_close_container (&iter, &array_iter);
955
956         return reply;
957 }
958
959
960 static void
961 on_dbus_method_search (DBusConnection *con, DBusMessage *message)
962 {
963         ModestDBusSearchFlags dbus_flags;
964         DBusMessage  *reply = NULL;
965         dbus_bool_t  res;
966         dbus_int64_t sd_v;
967         dbus_int64_t ed_v;
968         dbus_int32_t flags_v;
969         dbus_uint32_t size_v;
970         const char *folder;
971         const char *query;
972         time_t start_date;
973         time_t end_date;
974         GList *hits;
975
976         DBusError error;
977         dbus_error_init (&error);
978
979         sd_v = ed_v = 0;
980         flags_v = 0;
981
982         res = dbus_message_get_args (message,
983                                      &error,
984                                      DBUS_TYPE_STRING, &query,
985                                      DBUS_TYPE_STRING, &folder, /* e.g. "INBOX/drafts": TODO: Use both an ID and a display name. */
986                                      DBUS_TYPE_INT64, &sd_v,
987                                      DBUS_TYPE_INT64, &ed_v,
988                                      DBUS_TYPE_INT32, &flags_v,
989                                      DBUS_TYPE_UINT32, &size_v,
990                                      DBUS_TYPE_INVALID);
991         
992         dbus_flags = (ModestDBusSearchFlags) flags_v;
993         start_date = (time_t) sd_v;
994         end_date = (time_t) ed_v;
995
996         ModestSearch search;
997         memset (&search, 0, sizeof (search));
998         
999         /* Remember what folder we are searching in:
1000          *
1001          * Note that we don't copy the strings, 
1002          * because this struct will only be used for the lifetime of this function.
1003          */
1004         search.folder = folder;
1005
1006    /* Remember the text to search for: */
1007 #ifdef MODEST_HAVE_OGS
1008         search.query  = query;
1009 #endif
1010
1011         /* Other criteria: */
1012         search.before = start_date;
1013         search.after  = end_date;
1014         search.flags  = 0;
1015
1016         /* Text to serach for in various parts of the message: */
1017         if (dbus_flags & MODEST_DBUS_SEARCH_SUBJECT) {
1018                 search.flags |= MODEST_SEARCH_SUBJECT;
1019                 search.subject = query;
1020         }
1021
1022         if (dbus_flags & MODEST_DBUS_SEARCH_SENDER) {
1023                 search.flags |=  MODEST_SEARCH_SENDER;
1024                 search.from = query;
1025         }
1026
1027         if (dbus_flags & MODEST_DBUS_SEARCH_RECIPIENT) {
1028                 search.flags |= MODEST_SEARCH_RECIPIENT; 
1029                 search.recipient = query;
1030         }
1031
1032         if (dbus_flags & MODEST_DBUS_SEARCH_BODY) {
1033                 search.flags |=  MODEST_SEARCH_BODY; 
1034                 search.body = query;
1035         }
1036
1037         if (sd_v > 0) {
1038                 search.flags |= MODEST_SEARCH_BEFORE;
1039                 search.before = start_date;
1040         }
1041
1042         if (ed_v > 0) {
1043                 search.flags |= MODEST_SEARCH_AFTER;
1044                 search.after = end_date;
1045         }
1046
1047         if (size_v > 0) {
1048                 search.flags |= MODEST_SEARCH_SIZE;
1049                 search.minsize = size_v;
1050         }
1051
1052 #ifdef MODEST_HAVE_OGS
1053         search.flags |= MODEST_SEARCH_USE_OGS;
1054         g_debug ("%s: Starting search for %s", __FUNCTION__, search.query);
1055 #endif
1056         hits = modest_search_all_accounts (&search);
1057
1058         reply = dbus_message_new_method_return (message);
1059
1060         search_result_to_message (reply, hits);
1061
1062         if (reply == NULL) {
1063                 g_warning ("%s: Could not create reply.", __FUNCTION__);
1064         }
1065
1066         if (reply) {
1067                 dbus_uint32_t serial = 0;
1068                 dbus_connection_send (con, reply, &serial);
1069         dbus_connection_flush (con);
1070         dbus_message_unref (reply);
1071         }
1072
1073         g_list_free (hits);
1074 }
1075
1076
1077 /* A complex D-Bus type (like a struct),
1078  * used to return various information about a folder.
1079  */
1080 #define GET_FOLDERS_RESULT_DBUS_TYPE \
1081         DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
1082         DBUS_TYPE_STRING_AS_STRING /* Folder Name */ \
1083         DBUS_TYPE_STRING_AS_STRING /* Folder URI */ \
1084         DBUS_STRUCT_END_CHAR_AS_STRING
1085
1086 static DBusMessage *
1087 get_folders_result_to_message (DBusMessage *reply,
1088                            GList *folder_ids)
1089 {
1090         DBusMessageIter iter;   
1091         dbus_message_iter_init_append (reply, &iter); 
1092         
1093         DBusMessageIter array_iter;
1094         dbus_message_iter_open_container (&iter,
1095                                           DBUS_TYPE_ARRAY,
1096                                           GET_FOLDERS_RESULT_DBUS_TYPE,
1097                                           &array_iter); 
1098
1099         GList *list_iter = folder_ids;
1100         for (list_iter = folder_ids; list_iter; list_iter = list_iter->next) {
1101                 
1102                 const gchar *folder_name = (const gchar*)list_iter->data;
1103                 if (folder_name) {
1104                         g_debug ("DEBUG: %s: Adding folder: %s", __FUNCTION__, folder_name);    
1105                         
1106                         DBusMessageIter struct_iter;
1107                         dbus_message_iter_open_container (&array_iter,
1108                                                           DBUS_TYPE_STRUCT,
1109                                                           NULL,
1110                                                           &struct_iter);
1111         
1112                         /* name: */
1113                         dbus_message_iter_append_basic (&struct_iter,
1114                                                         DBUS_TYPE_STRING,
1115                                                         &folder_name); /* The string will be copied. */
1116                                                         
1117                         /* URI: This is maybe not needed by osso-global-search: */
1118                         const gchar *folder_uri = "TODO:unimplemented";
1119                         dbus_message_iter_append_basic (&struct_iter,
1120                                                         DBUS_TYPE_STRING,
1121                                                         &folder_uri); /* The string will be copied. */
1122         
1123                         dbus_message_iter_close_container (&array_iter,
1124                                                            &struct_iter); 
1125                 }
1126         }
1127
1128         dbus_message_iter_close_container (&iter, &array_iter);
1129
1130         return reply;
1131 }
1132
1133 static void
1134 add_single_folder_to_list (TnyFolder *folder, GList** list)
1135 {
1136         if (!folder)
1137                 return;
1138                 
1139         /* Add this folder to the list: */
1140         /*
1141         const gchar * folder_name = tny_folder_get_name (folder);
1142         if (folder_name)
1143                 *list = g_list_append(*list, g_strdup (folder_name));
1144         else {
1145         */
1146                 /* osso-global-search only uses one string,
1147                  * so ID is the only thing that could possibly identify a folder.
1148                  * TODO: osso-global search should probably be changed to 
1149                  * take an ID and a Name.
1150                  */
1151                 const gchar * id =  tny_folder_get_id (folder);
1152                 if (id && strlen(id))
1153                         *list = g_list_append(*list, g_strdup (id));
1154                 /*
1155                 else {
1156                         g_warning ("DEBUG: %s: folder has no name or ID.\n", __FUNCTION__);     
1157                 }
1158                 
1159         }
1160         */
1161 }
1162
1163 static void
1164 add_folders_to_list (TnyFolderStore *folder_store, GList** list)
1165 {
1166         if (!folder_store)
1167                 return;
1168         
1169         /* Add this folder to the list: */
1170         if (TNY_IS_FOLDER (folder_store)) {
1171                 add_single_folder_to_list (TNY_FOLDER (folder_store), list);
1172         }       
1173         
1174                 
1175         /* Recurse into child folders: */
1176                 
1177         /* Get the folders list: */
1178         /*
1179         TnyFolderStoreQuery *query = tny_folder_store_query_new ();
1180         tny_folder_store_query_add_item (query, NULL, 
1181                 TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
1182         */
1183         TnyList *all_folders = tny_simple_list_new ();
1184         tny_folder_store_get_folders (folder_store,
1185                                       all_folders,
1186                                       NULL /* query */,
1187                                       NULL /* error */);
1188
1189         TnyIterator *iter = tny_list_create_iterator (all_folders);
1190         while (!tny_iterator_is_done (iter)) {
1191                 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (iter));
1192                 if (TNY_IS_FOLDER_STORE (folder))
1193                         add_folders_to_list (TNY_FOLDER_STORE (folder), list);
1194                 else {
1195                         add_single_folder_to_list (TNY_FOLDER (folder), list);
1196                 }
1197                 
1198                 tny_iterator_next (iter);
1199         }
1200         g_object_unref (G_OBJECT (iter));
1201 }
1202
1203 static void
1204 on_dbus_method_get_folders (DBusConnection *con, DBusMessage *message)
1205 {
1206         DBusMessage  *reply = NULL;
1207         
1208
1209         /* Get the TnyStoreAccount so we can get the folders: */
1210         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
1211         gchar *account_name = modest_account_mgr_get_default_account (account_mgr);
1212         if (!account_name) {
1213                 g_printerr ("modest: no account found\n");
1214         }
1215         
1216         TnyAccount *account = NULL;
1217         if (account_mgr) {
1218                 account = modest_tny_account_store_get_server_account (
1219                         modest_runtime_get_account_store(), account_name, 
1220                         TNY_ACCOUNT_TYPE_STORE);
1221         }
1222         
1223         if (!account) {
1224                 g_printerr ("modest: failed to get tny account folder'%s'\n", account_name);
1225         } 
1226                 
1227         printf("DEBUG: %s: Getting folders for account name=%s\n", __FUNCTION__, account_name);
1228         g_free (account_name);
1229         account_name = NULL;
1230         
1231         GList *folder_names = NULL;
1232         add_folders_to_list (TNY_FOLDER_STORE (account), &folder_names);
1233
1234         g_object_unref (account);
1235         account = NULL;
1236         
1237         
1238         /* Also add the folders from the local folders account,
1239          * because they are (currently) used with all accounts:
1240          * TODO: This is not working. It seems to get only the Merged Folder (with an ID of "" (not NULL)).
1241          */
1242         TnyAccount *account_local = 
1243                 modest_tny_account_store_get_local_folders_account (
1244                         TNY_ACCOUNT_STORE (modest_runtime_get_account_store()));
1245         add_folders_to_list (TNY_FOLDER_STORE (account_local), &folder_names);
1246
1247         g_object_unref (account_local);
1248         account_local = NULL;
1249
1250
1251         /* Put the result in a DBus reply: */
1252         reply = dbus_message_new_method_return (message);
1253
1254         get_folders_result_to_message (reply, folder_names);
1255
1256         if (reply == NULL) {
1257                 g_warning ("%s: Could not create reply.", __FUNCTION__);
1258         }
1259
1260         if (reply) {
1261                 dbus_uint32_t serial = 0;
1262                 dbus_connection_send (con, reply, &serial);
1263         dbus_connection_flush (con);
1264         dbus_message_unref (reply);
1265         }
1266
1267         g_list_foreach (folder_names, (GFunc)g_free, NULL);
1268         g_list_free (folder_names);
1269 }
1270
1271
1272 /** This D-Bus handler is used when the main osso-rpc 
1273  * D-Bus handler has not handled something.
1274  * We use this for D-Bus methods that need to use more complex types 
1275  * than osso-rpc supports.
1276  */
1277 DBusHandlerResult
1278 modest_dbus_req_filter (DBusConnection *con,
1279                         DBusMessage    *message,
1280                         void           *user_data)
1281 {
1282         gboolean handled = FALSE;
1283
1284         if (dbus_message_is_method_call (message,
1285                                          MODEST_DBUS_IFACE,
1286                                          MODEST_DBUS_METHOD_SEARCH)) {
1287                 on_dbus_method_search (con, message);
1288                 handled = TRUE;                         
1289         } else if (dbus_message_is_method_call (message,
1290                                          MODEST_DBUS_IFACE,
1291                                          MODEST_DBUS_METHOD_GET_FOLDERS)) {
1292                 on_dbus_method_get_folders (con, message);
1293                 handled = TRUE;                         
1294         }
1295         
1296         return (handled ? 
1297                 DBUS_HANDLER_RESULT_HANDLED :
1298                 DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
1299 }
1300
1301
1302 void
1303 modest_osso_cb_hw_state_handler(osso_hw_state_t *state, gpointer data)
1304 {
1305         /* TODO? */
1306     /* printf("%s()\n", __PRETTY_FUNCTION__); */
1307
1308     if(state->system_inactivity_ind)
1309     {
1310     }
1311     else if(state->save_unsaved_data_ind)
1312     {
1313     }
1314     else
1315     {
1316     
1317     }
1318
1319     /* printf("debug: %s(): return\n", __PRETTY_FUNCTION__); */
1320 }