* Added src/widgets/modest-recpt-view.[ch].
[modest] / src / modest-ui-actions.c
1 /* Copyright (c) 2006, 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 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <glib/gi18n.h>
35 #include <string.h>
36 #include <modest-runtime.h>
37 #include <modest-tny-msg.h>
38 #include <modest-tny-account.h>
39
40 #include "modest-ui-actions.h"
41
42 #include "modest-tny-platform-factory.h"
43
44 #include <widgets/modest-main-window.h>
45 #include <widgets/modest-msg-view-window.h>
46 #include <widgets/modest-account-view-window.h>
47
48 #include "modest-account-mgr-helpers.h"
49 #include "modest-mail-operation.h"
50 #include <modest-widget-memory.h>
51 #include <tny-error.h>
52 #include <tny-simple-list.h>
53 #include <tny-msg-view.h>
54 #include <tny-device.h>
55
56
57 typedef struct _GetMsgAsyncHelper {
58         ModestWindow *window;
59         TnyIterator *iter;
60         GFunc func;
61         gpointer user_data;
62 } GetMsgAsyncHelper;
63
64 typedef enum _ReplyForwardAction {
65         ACTION_REPLY,
66         ACTION_REPLY_TO_ALL,
67         ACTION_FORWARD
68 } ReplyForwardAction;
69
70 typedef struct _ReplyForwardHelper {
71 guint reply_forward_type;
72         ReplyForwardAction action;
73         gchar *account_name;
74 } ReplyForwardHelper;
75
76
77 static void     reply_forward_func     (gpointer data, gpointer user_data);
78 static void     read_msg_func          (gpointer data, gpointer user_data);
79 static void     get_msg_cb             (TnyFolder *folder, TnyMsg *msg, GError **err, 
80                                         gpointer user_data);
81 static void     reply_forward          (ReplyForwardAction action, ModestWindow *win);
82 static gchar*   ask_for_folder_name    (GtkWindow *parent_window, const gchar *title);
83
84
85 void   
86 modest_ui_actions_on_about (GtkAction *action, ModestWindow *win)
87 {
88         GtkWidget *about;
89         const gchar *authors[] = {
90                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
91                 NULL
92         };
93         about = gtk_about_dialog_new ();
94         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
95         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
96         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
97                                         _("Copyright (c) 2006, Nokia Corporation\n"
98                                           "All rights reserved."));
99         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
100                                        _("a modest e-mail client\n\n"
101                                          "design and implementation: Dirk-Jan C. Binnema\n"
102                                          "contributions from the fine people at KernelConcepts and Igalia\n"
103                                          "uses the tinymail email framework written by Philip van Hoof"));
104         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
105         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
106         
107         gtk_dialog_run (GTK_DIALOG (about));
108         gtk_widget_destroy(about);
109 }
110
111
112 static TnyList *
113 get_selected_headers (ModestWindow *win)
114 {
115         if (MODEST_IS_MAIN_WINDOW(win)) {
116                 GtkWidget *header_view;         
117                 
118                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
119                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
120                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
121                 
122         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
123                 /* for MsgViewWindows, we simply return a list with one element */
124                 TnyMsg *msg;
125                 TnyHeader *header;
126                 TnyList *list = NULL;
127                 
128                 msg  = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
129                 if (msg) {
130                         header = tny_msg_get_header (msg);
131                         list = tny_simple_list_new ();
132                         tny_list_prepend (list, G_OBJECT(header));
133                         g_object_unref (G_OBJECT(header));
134                 }
135                 return list;
136
137         } else
138                 return NULL;
139 }
140
141 void
142 modest_ui_actions_on_delete (GtkAction *action, ModestWindow *win)
143 {
144         TnyList *header_list;
145         TnyIterator *iter;
146
147         g_return_if_fail (MODEST_IS_WINDOW(win));
148                 
149         header_list = get_selected_headers (win);
150         
151         if (header_list) {
152                 iter = tny_list_create_iterator (header_list);
153                 do {
154                         TnyHeader *header;
155                         ModestMailOperation *mail_op;
156
157                         header = TNY_HEADER (tny_iterator_get_current (iter));
158                         /* TODO: thick grain mail operation involving
159                            a list of objects. Composite pattern ??? */
160                         mail_op = modest_mail_operation_new ();
161
162                         /* TODO: add confirmation dialog */
163
164                         /* Move to trash. TODO: Still not supported */
165                         modest_mail_operation_remove_msg (mail_op, header, FALSE);
166
167                         if (modest_mail_operation_get_status (mail_op) !=
168                             MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
169                                 const GError *error;
170                                 error = modest_mail_operation_get_error (mail_op);
171                                 if (error)
172                                         g_warning (error->message);
173                         }
174
175                         g_object_unref (G_OBJECT (mail_op));
176                         g_object_unref (header);
177                         tny_iterator_next (iter);
178
179                 } while (!tny_iterator_is_done (iter));
180         }
181 }
182
183
184 void
185 modest_ui_actions_on_quit (GtkAction *action, ModestWindow *win)
186 {
187         /* FIXME: save size of main window */
188 /*      save_sizes (main_window); */
189         gtk_widget_destroy (GTK_WIDGET (win));
190 }
191
192 void
193 modest_ui_actions_on_accounts (GtkAction *action, ModestWindow *win)
194 {
195         /* GtkDialog *account_win; */
196 /*      account_win = GTK_DIALOG(modest_account_view_window_new ()); */
197         
198
199 /*      gtk_dialog_run (account_win); */
200         //gtk_widget_destroy (GTK_WIDGET(account_win));
201  GtkWidget *dialog, *label;
202    
203    /* Create the widgets */
204    
205    dialog = gtk_dialog_new_with_buttons ("Message",
206                                          GTK_WINDOW(win),
207                                          GTK_DIALOG_DESTROY_WITH_PARENT,
208                                          GTK_STOCK_OK,
209                                          GTK_RESPONSE_NONE,
210                                          NULL);
211    label = gtk_label_new ("Hello World!");
212    
213    /* Ensure that the dialog box is destroyed when the user responds. */
214    
215    g_signal_connect_swapped (dialog, "response", 
216                              G_CALLBACK (gtk_widget_destroy),
217                              dialog);
218
219    /* Add the label, and show everything we've added to the dialog. */
220
221    gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
222                       label);
223    gtk_widget_show_all (dialog);
224 }
225
226 void
227 modest_ui_actions_on_new_msg (GtkAction *action, ModestWindow *win)
228 {
229         ModestWindow *msg_win;
230         TnyMsg *msg = NULL;
231         TnyFolder *folder = NULL;
232         gchar *account_name = NULL;
233         gchar *from_str = NULL;
234         GError *err = NULL;
235         TnyAccount *account;
236         
237         account_name = g_strdup(modest_window_get_active_account (win));
238         if (!account_name)
239                 account_name = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
240         
241         account = modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
242                                                                        account_name,
243                                                                        TNY_ACCOUNT_TYPE_STORE);
244         if (!account) {
245                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", account_name);
246                 goto cleanup;
247         }
248
249         from_str = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(), account_name);
250
251         msg    = modest_tny_msg_new ("", from_str, "", "", "", "", NULL);
252         if (!msg) {
253                 g_printerr ("modest: failed to create new msg\n");
254                 goto cleanup;
255         }
256         
257         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
258         if (!folder) {
259                 g_printerr ("modest: failed to find Drafts folder\n");
260                 goto cleanup;
261         }
262         
263         tny_folder_add_msg (folder, msg, &err);
264         if (err) {
265                 g_printerr ("modest: error adding msg to Drafts folder: %s",
266                             err->message);
267                 g_error_free (err);
268                 goto cleanup;
269         }
270
271         msg_win = modest_msg_edit_window_new (msg, account_name);
272         if (win)
273                 gtk_window_set_transient_for (GTK_WINDOW (msg_win),
274                                               GTK_WINDOW (win));        
275         gtk_widget_show_all (GTK_WIDGET (msg_win));
276
277 cleanup:
278         g_free (account_name);
279         g_free (from_str);
280         if (account)
281                 g_object_unref (G_OBJECT(account));
282         if (msg)
283                 g_object_unref (G_OBJECT(msg));
284         if (folder)
285                 g_object_unref (G_OBJECT(folder));
286 }
287
288
289 void
290 modest_ui_actions_on_open (GtkAction *action, ModestWindow *win)
291 {
292         modest_runtime_not_implemented (GTK_WINDOW(win)); /* FIXME */
293 }
294
295
296
297 static void
298 reply_forward_func (gpointer data, gpointer user_data)
299 {
300         TnyMsg *msg, *new_msg;
301         GetMsgAsyncHelper *helper;
302         ReplyForwardHelper *rf_helper;
303         ModestWindow *msg_win;
304         ModestEditType edit_type;
305         gchar *from;
306         GError *err = NULL;
307         TnyFolder *folder = NULL;
308         TnyAccount *account = NULL;
309         
310         msg = TNY_MSG (data);
311         helper = (GetMsgAsyncHelper *) user_data;
312         rf_helper = (ReplyForwardHelper *) helper->user_data;
313
314         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
315                                                    rf_helper->account_name);
316         /* Create reply mail */
317         switch (rf_helper->action) {
318         case ACTION_REPLY:
319                 new_msg = 
320                         modest_mail_operation_create_reply_mail (msg,  from, 
321                                                                  rf_helper->reply_forward_type,
322                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
323                 break;
324         case ACTION_REPLY_TO_ALL:
325                 new_msg = 
326                         modest_mail_operation_create_reply_mail (msg, from, rf_helper->reply_forward_type,
327                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
328                 edit_type = MODEST_EDIT_TYPE_REPLY;
329                 break;
330         case ACTION_FORWARD:
331                 new_msg = 
332                         modest_mail_operation_create_forward_mail (msg, from, rf_helper->reply_forward_type);
333                 edit_type = MODEST_EDIT_TYPE_FORWARD;
334                 break;
335         default:
336                 g_return_if_reached ();
337                 return;
338         }
339
340         if (!new_msg) {
341                 g_printerr ("modest: failed to create message\n");
342                 goto cleanup;
343         }
344
345         account = modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
346                                                                        rf_helper->account_name,
347                                                                        TNY_ACCOUNT_TYPE_STORE);
348         if (!account) {
349                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", rf_helper->account_name);
350                 goto cleanup;
351         }
352
353         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
354         if (!folder) {
355                 g_printerr ("modest: failed to find Drafts folder\n");
356                 goto cleanup;
357         }
358         
359         tny_folder_add_msg (folder, msg, &err);
360         if (err) {
361                 g_printerr ("modest: error adding msg to Drafts folder: %s",
362                             err->message);
363                 g_error_free (err);
364                 goto cleanup;
365         }       
366                         
367         /* Show edit window */
368         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name);
369         gtk_widget_show_all (GTK_WIDGET (msg_win));
370
371 cleanup:
372         if (new_msg)
373                 g_object_unref (G_OBJECT (new_msg));
374         if (folder)
375                 g_object_unref (G_OBJECT (folder));
376         if (account)
377                 g_object_unref (G_OBJECT (account));
378         
379         g_free (rf_helper->account_name);
380         g_slice_free (ReplyForwardHelper, rf_helper);
381 }
382 /*
383  * Common code for the reply and forward actions
384  */
385 static void
386 reply_forward (ReplyForwardAction action, ModestWindow *win)
387 {
388         TnyList *header_list;
389         guint reply_forward_type;
390         TnyHeader *header;
391         TnyFolder *folder;
392         GetMsgAsyncHelper *helper;
393         ReplyForwardHelper *rf_helper;
394         
395         g_return_if_fail (MODEST_IS_WINDOW(win));
396
397         header_list = get_selected_headers (win);
398         if (!header_list)
399                 return;
400         
401         reply_forward_type = modest_conf_get_int (modest_runtime_get_conf (),
402                                                   (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE,
403                                                   NULL);
404         /* We assume that we can only select messages of the
405            same folder and that we reply all of them from the
406            same account. In fact the interface currently only
407            allows single selection */
408         
409         /* Fill helpers */
410         rf_helper = g_slice_new0 (ReplyForwardHelper);
411         rf_helper->reply_forward_type = reply_forward_type;
412         rf_helper->action = action;
413
414         rf_helper->account_name = g_strdup (modest_window_get_active_account (win));
415         if (!rf_helper->account_name)
416                 rf_helper->account_name =
417                         modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
418
419         helper = g_slice_new0 (GetMsgAsyncHelper);
420         helper->window = win;
421         helper->func = reply_forward_func;
422         helper->iter = tny_list_create_iterator (header_list);
423         helper->user_data = rf_helper;
424
425         if (MODEST_IS_MSG_VIEW_WINDOW(win)) {
426                 TnyMsg *msg;
427                 msg = modest_msg_view_window_get_message(MODEST_MSG_VIEW_WINDOW(win));
428                 if (!msg) {
429                         g_printerr ("modest: no message found\n");
430                         return;
431                 } else
432                         reply_forward_func (msg, helper);
433         } else {
434                 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
435                 folder = tny_header_get_folder (header);
436                 if (folder) {
437                         /* The callback will call it per each header */
438                         tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
439                         g_object_unref (G_OBJECT (folder));
440                 } else 
441                         g_printerr ("modest: no folder for header\n");
442                 
443                 /* Clean */
444                 g_object_unref (G_OBJECT (header));
445         }
446 }
447
448
449 void
450 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
451 {
452         g_return_if_fail (MODEST_IS_WINDOW(win));
453
454         reply_forward (ACTION_REPLY, win);
455 }
456
457 void
458 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
459 {
460         g_return_if_fail (MODEST_IS_WINDOW(win));
461
462         reply_forward (ACTION_FORWARD, win);
463 }
464
465 void
466 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
467 {
468         g_return_if_fail (MODEST_IS_WINDOW(win));
469
470         reply_forward (ACTION_REPLY_TO_ALL, win);
471 }
472
473 void 
474 modest_ui_actions_on_next (GtkAction *action, 
475                            ModestMainWindow *main_window)
476 {
477         GtkWidget *header_view;
478         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
479
480         header_view = modest_main_window_get_child_widget (main_window,
481                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
482         if (!header_view)
483                 return;
484         
485         modest_header_view_select_next (MODEST_HEADER_VIEW(header_view)); 
486 }
487
488 void 
489 modest_ui_actions_on_prev (GtkAction *action, 
490                            ModestMainWindow *main_window)
491 {
492         GtkWidget *header_view;
493         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
494
495         header_view = modest_main_window_get_child_widget (main_window,
496                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
497         if (!header_view)
498                 return;
499         
500         modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view)); 
501 }
502
503
504 void
505 modest_ui_actions_on_send_receive (GtkAction *action,  ModestWindow *win)
506 {
507         gchar *account_name;
508         TnyAccount *tny_account;
509         //ModestTnySendQueue *send_queue;
510         ModestMailOperation *mail_op;
511         
512         account_name =
513                 g_strdup(modest_window_get_active_account(MODEST_WINDOW(win)));
514         if (!account_name)
515                 account_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
516         if (!account_name) {
517                 g_printerr ("modest: cannot get account\n");
518                 return;
519         }
520         /* FIXME */
521 #if 0
522         tny_account = 
523                 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
524                                                                      account_name,
525                                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
526         if (!tny_account) {
527                 g_printerr ("modest: cannot get tny transport account for %s\n", account_name);
528                 return;
529         }
530
531         send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(tny_account));
532         if (!send_queue) {
533                 g_object_unref (G_OBJECT(tny_account));
534                 g_printerr ("modest: cannot get send queue for %s\n", account_name);
535                 return;
536         } 
537         modest_tny_send_queue_flush (send_queue);
538
539         g_object_unref (G_OBJECT(send_queue));
540         g_object_unref (G_OBJECT(tny_account));
541 #endif /*  0 */
542         tny_account = 
543                 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
544                                                                      account_name,
545                                                                      TNY_ACCOUNT_TYPE_STORE);
546         if (!tny_account) {
547                 g_printerr ("modest: cannot get tny store account for %s\n", account_name);
548                 return;
549         }
550
551         mail_op = modest_mail_operation_new ();
552         modest_mail_operation_update_account (mail_op, TNY_STORE_ACCOUNT(tny_account));
553
554         g_object_unref (G_OBJECT(tny_account));
555         /* g_object_unref (G_OBJECT(mail_op)); FIXME: this is still in use... */
556 }
557
558
559
560 void
561 modest_ui_actions_toggle_view (GtkAction *action, ModestMainWindow *main_window)
562 {
563         ModestConf *conf;
564         GtkWidget *header_view;
565         
566         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
567
568         header_view = modest_main_window_get_child_widget (main_window,
569                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
570         if (!header_view)
571                 return;
572
573         conf = modest_runtime_get_conf ();
574         
575         /* what is saved/restored is depending on the style; thus; we save with
576          * old style, then update the style, and restore for this new style*/
577         modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
578         
579         if (modest_header_view_get_style
580             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
581                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
582                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
583         else
584                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
585                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
586
587         modest_widget_memory_restore (conf, G_OBJECT(header_view),
588                                       "header-view");
589 }
590
591
592
593 /*
594  * Marks a message as read and passes it to the msg preview widget
595  */
596 static void
597 read_msg_func (gpointer data, gpointer user_data)
598 {
599         TnyMsg *msg;
600         TnyHeader *header;
601         GetMsgAsyncHelper *helper;
602         TnyHeaderFlags header_flags;
603         GtkWidget *msg_preview;
604         
605         msg = TNY_MSG (data);
606         helper = (GetMsgAsyncHelper *) user_data;
607
608         msg_preview = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (helper->window),
609                                                            MODEST_WIDGET_TYPE_MSG_PREVIEW);
610         if (!msg_preview)
611                 return;
612         
613         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
614         header_flags = tny_header_get_flags (header);
615         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
616         g_object_unref (G_OBJECT (header));
617
618         /* Set message on msg view */
619         modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), msg);
620 }
621
622 /*
623  * This function is a generic handler for the tny_folder_get_msg_async
624  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
625  * contains a user provided function that is called inside this
626  * method. This will allow us to use this callback in many different
627  * places. This callback performs the common actions for the
628  * get_msg_async call, more specific actions will be done by the user
629  * function
630  */
631 static void
632 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
633 {
634         GetMsgAsyncHelper *helper;
635
636         helper = (GetMsgAsyncHelper *) user_data;
637
638         if ((*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) || !msg) {
639                 modest_ui_actions_on_item_not_found (NULL,
640                                                      MODEST_ITEM_TYPE_MESSAGE,
641                                                      helper->window);
642                 return;
643         }
644
645         /* Call user function */
646         helper->func (msg, user_data);
647
648         /* Process next element (if exists) */
649         tny_iterator_next (helper->iter);
650         if (tny_iterator_is_done (helper->iter)) {
651                 TnyList *headers;
652                 headers = tny_iterator_get_list (helper->iter);
653                 /* Free resources */
654                 g_object_unref (G_OBJECT (headers));
655                 g_object_unref (G_OBJECT (helper->iter));
656                 g_slice_free (GetMsgAsyncHelper, helper);
657         } else {
658                 TnyHeader *header;
659                 header = TNY_HEADER (tny_iterator_get_current (helper->iter)); 
660                 tny_folder_get_msg_async (folder, header,                         
661                                           get_msg_cb, helper);
662                 g_object_unref (G_OBJECT(header));
663         }
664 }
665
666 void 
667 modest_ui_actions_on_header_selected (ModestHeaderView *folder_view, 
668                                       TnyHeader *header,
669                                       ModestMainWindow *main_window)
670 {
671         GtkWidget *msg_preview;
672         TnyFolder *folder;
673         GetMsgAsyncHelper *helper;
674         TnyList *list;
675
676         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
677         
678         msg_preview = modest_main_window_get_child_widget(main_window,
679                                                           MODEST_WIDGET_TYPE_MSG_PREVIEW);
680         if (!msg_preview)
681                 return;
682         
683         /* when there's no header, clear the msgview */
684         if (!header) {
685                 modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), NULL);
686                 return;
687         }
688
689         folder = tny_header_get_folder (TNY_HEADER(header));
690
691         /* Create list */
692         list = tny_simple_list_new ();
693         tny_list_prepend (list, G_OBJECT (header));
694
695         /* Fill helper data */
696         helper = g_slice_new0 (GetMsgAsyncHelper);
697         helper->window = MODEST_WINDOW (main_window);
698         helper->iter = tny_list_create_iterator (list);
699         helper->func = read_msg_func;
700
701         tny_folder_get_msg_async (TNY_FOLDER(folder),
702                                   header, get_msg_cb,
703                                   helper);
704
705         /* Frees */
706         g_object_unref (G_OBJECT (folder));
707 }
708
709
710
711 void 
712 modest_ui_actions_on_header_activated (ModestHeaderView *folder_view, TnyHeader *header,
713                                        ModestMainWindow *main_window)
714 {
715         ModestWindow *win;
716         TnyFolder *folder = NULL;
717         TnyMsg    *msg    = NULL;
718         gchar *account    = NULL;
719         
720         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
721         
722         if (!header)
723                 return;
724
725         folder = tny_header_get_folder (header);
726         if (!folder) {
727                 g_printerr ("modest: cannot get folder for header\n");
728                 goto cleanup;
729         }
730
731         /* FIXME: make async?; check error  */
732         msg = tny_folder_get_msg (folder, header, NULL);
733         if (!msg) {
734                 g_printerr ("modest: cannot get msg for header\n");
735                 goto cleanup;
736         }
737
738         account =  g_strdup(modest_window_get_active_account(MODEST_WINDOW(main_window)));
739         if (!account)
740                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
741         
742         win = modest_msg_view_window_new (msg, account);
743         gtk_window_set_transient_for (GTK_WINDOW (win),
744                                       GTK_WINDOW (main_window));
745
746         gtk_widget_show_all (GTK_WIDGET(win));
747         
748 cleanup:
749         g_free (account);
750         
751         if (folder)
752                 g_object_unref (G_OBJECT (folder));
753         if (msg)
754                 g_object_unref (G_OBJECT (msg));
755 }
756
757 void 
758 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
759                                                TnyFolder *folder, 
760                                                gboolean selected,
761                                                ModestMainWindow *main_window)
762 {
763 //      GtkLabel *folder_info_label;
764         gchar *txt;     
765         ModestConf *conf;
766         GtkWidget *header_view;
767         
768 /*      folder_info_label =  */
769 /*              GTK_LABEL (modest_widget_factory_get_folder_info_label */
770 /*                         (modest_runtime_get_widget_factory())); */
771
772 /*      if (!folder) { */
773 /*              gtk_label_set_label (GTK_LABEL(folder_info_label), ""); */
774 /*              return; */
775 /*      } */
776         
777         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
778
779         header_view = modest_main_window_get_child_widget(main_window,
780                                                           MODEST_WIDGET_TYPE_HEADER_VIEW);
781         if (!header_view)
782                 return;
783         
784         conf = modest_runtime_get_conf ();
785
786         if (!selected) { /* the folder was unselected; save it's settings  */
787                 modest_widget_memory_save (conf, G_OBJECT (header_view), "header-view");
788                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
789                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), NULL);
790         } else {  /* the folder was selected */
791                 if (folder) { /* folder may be NULL */
792                         guint num, unread;
793                         gchar *title;
794
795                         num    = tny_folder_get_all_count    (folder);
796                         unread = tny_folder_get_unread_count (folder);
797                         
798                         title = g_strdup_printf ("Modest: %s",
799                                                  tny_folder_get_name (folder));
800                         
801                         gtk_window_set_title (GTK_WINDOW(main_window), title);
802                         g_free (title);
803                         
804                         txt = g_strdup_printf (_("%d %s, %d unread"),
805                                                num, num==1 ? _("item") : _("items"), unread);           
806                         //gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
807                         g_free (txt);
808                 }
809                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), folder);
810                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
811                                               "header-view");
812         }
813 }
814
815
816 /****************************************************/
817 /*
818  * below some stuff to clearup statusbar messages after 1,5 seconds....
819  */
820 static gboolean
821 progress_bar_clean (GtkWidget *bar)
822 {
823         if (GTK_IS_PROGRESS_BAR(bar)) {
824                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
825                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
826         }
827         return FALSE;
828 }
829
830 static gboolean
831 statusbar_clean (GtkWidget *bar)
832 {
833         if (GTK_IS_STATUSBAR(bar))
834                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
835         return FALSE;
836 }
837
838
839 static void
840 statusbar_push (ModestMainWindow *main_window, guint context_id, const gchar *msg)
841 {
842         if (!msg)
843                 return;
844
845         GtkWidget *progress_bar, *status_bar;
846
847         progress_bar = modest_main_window_get_child_widget (main_window,
848                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);
849         status_bar = modest_main_window_get_child_widget (main_window,
850                                                           MODEST_WIDGET_TYPE_STATUS_BAR);
851         if (progress_bar) {
852                 gtk_widget_show (progress_bar);
853                 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
854         }
855         
856         if (status_bar) {
857                 gtk_widget_show (status_bar);
858                 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
859                 g_timeout_add (2500, (GSourceFunc)statusbar_clean, status_bar);
860         }
861
862 }
863 /****************************************************************************/
864
865 void 
866 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
867                                      ModestWindow *win)
868 {
869         GtkWidget *dialog;
870         gchar *txt, *item;
871         gboolean online;
872
873         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
874         
875         if (g_main_depth > 0)   
876                 gdk_threads_enter ();
877         online = tny_device_is_online (modest_runtime_get_device());
878
879         if (online) {
880                 /* already online -- the item is simply not there... */
881                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
882                                                  GTK_DIALOG_MODAL,
883                                                  GTK_MESSAGE_WARNING,
884                                                  GTK_BUTTONS_OK,
885                                                  _("The %s you selected cannot be found"),
886                                                  item);
887                 gtk_dialog_run (GTK_DIALOG(dialog));
888         } else {
889                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
890                                                       GTK_WINDOW (win),
891                                                       GTK_DIALOG_MODAL,
892                                                       GTK_STOCK_CANCEL,
893                                                       GTK_RESPONSE_REJECT,
894                                                       GTK_STOCK_OK,
895                                                       GTK_RESPONSE_ACCEPT,
896                                                       NULL);
897                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
898                                          "Do you want to get online?"), item);
899                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
900                                     gtk_label_new (txt), FALSE, FALSE, 0);
901                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
902                 g_free (txt);
903
904                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
905                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
906                         tny_device_force_online (modest_runtime_get_device());
907                 }
908         }
909         gtk_widget_destroy (dialog);
910         if (g_main_depth > 0)   
911                 gdk_threads_leave ();
912 }
913
914
915
916 void
917 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
918                                             const gchar *msg, gint num, 
919                                             gint total,  ModestMainWindow *main_window)
920 {
921         char* txt;
922         GtkWidget *progress_bar;
923
924         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
925
926         progress_bar = modest_main_window_get_child_widget (main_window, 
927                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);   
928         if (!progress_bar)
929                 return;
930         
931         if (total != 0)
932                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
933                                                (gdouble)num/(gdouble)total);
934         else
935                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
936
937         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
938         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
939         g_free (txt);
940         
941         statusbar_push (main_window, 0, msg);
942 }
943
944
945 void
946 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
947                                      ModestWindow *win)
948 {
949         g_message (__FUNCTION__);
950 }       
951
952
953 void
954 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
955                                         ModestWindow *win)
956 {
957         g_message (__FUNCTION__);
958 }
959
960 void
961 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
962                                              ModestWindow *win)
963 {
964         g_message (__FUNCTION__);
965         
966 }
967
968 void
969 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
970                                           ModestRecptView *recpt_view,
971                                           ModestWindow *win)
972 {
973         gint start, end;
974         gchar *utf_start, *utf_end;
975         gchar *full_string = NULL;
976         gchar *substring;
977
978         gtk_label_get_selection_bounds (GTK_LABEL (recpt_view), &start, &end);
979         full_string = (gchar *) gtk_label_get_text (GTK_LABEL (recpt_view));
980         utf_start = g_utf8_offset_to_pointer (full_string, start);
981         utf_end = g_utf8_offset_to_pointer (full_string, end);
982         substring = g_strndup (utf_start, utf_end - utf_start);
983         g_message ("%s %s", __FUNCTION__, substring);
984
985         g_free (substring);
986         
987 }
988
989 void
990 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
991 {
992         TnyTransportAccount *transport_account;
993         ModestMailOperation *mail_operation;
994         MsgData *data;
995         gchar *account_name, *from;
996         ModestAccountMgr *account_mgr;
997
998         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
999         
1000         data = modest_msg_edit_window_get_msg_data (edit_window);
1001
1002         /* FIXME: Code added just for testing. The final version will
1003            use the send queue provided by tinymail and some
1004            classifier */
1005         account_mgr = modest_runtime_get_account_mgr();
1006         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
1007         if (!account_name) 
1008                 account_name = modest_account_mgr_get_default_account (account_mgr);
1009         if (!account_name) {
1010                 g_printerr ("modest: no account found\n");
1011                 modest_msg_edit_window_free_msg_data (edit_window, data);
1012                 return;
1013         }
1014         transport_account =
1015                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_tny_account_by_account
1016                                       (modest_runtime_get_account_store(),
1017                                        account_name,
1018                                        TNY_ACCOUNT_TYPE_TRANSPORT));
1019         if (!transport_account) {
1020                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1021                 g_free (account_name);
1022                 modest_msg_edit_window_free_msg_data (edit_window, data);
1023                 return;
1024         }
1025         from = modest_account_mgr_get_from_string (account_mgr, account_name);
1026                 
1027         mail_operation = modest_mail_operation_new ();
1028         modest_mail_operation_send_new_mail (mail_operation,
1029                                              transport_account,
1030                                              from,
1031                                              data->to, 
1032                                              data->cc, 
1033                                              data->bcc,
1034                                              data->subject, 
1035                                              data->body, 
1036                                              NULL);
1037         /* Frees */
1038         g_free (from);
1039         g_free (account_name);
1040         g_object_unref (G_OBJECT (mail_operation));
1041         g_object_unref (G_OBJECT (transport_account));
1042
1043         modest_msg_edit_window_free_msg_data (edit_window, data);
1044
1045         /* Save settings and close the window */
1046         /* save_settings (edit_window) */
1047         gtk_widget_destroy (GTK_WIDGET (edit_window));
1048 }
1049
1050 /*
1051  * Shows a dialog with an entry that asks for some text. The returned
1052  * value must be freed by the caller. The dialog window title will be
1053  * set to @title.
1054  */
1055 static gchar *
1056 ask_for_folder_name (GtkWindow *parent_window,
1057                      const gchar *title)
1058 {
1059         GtkWidget *dialog, *entry;
1060         gchar *folder_name = NULL;
1061
1062         /* Ask for folder name */
1063         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1064                                               parent_window,
1065                                               GTK_DIALOG_MODAL,
1066                                               GTK_STOCK_CANCEL,
1067                                               GTK_RESPONSE_REJECT,
1068                                               GTK_STOCK_OK,
1069                                               GTK_RESPONSE_ACCEPT,
1070                                               NULL);
1071         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1072                             gtk_label_new(title),
1073                             FALSE, FALSE, 0);
1074                 
1075         entry = gtk_entry_new_with_max_length (40);
1076         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1077                             entry,
1078                             TRUE, FALSE, 0);    
1079         
1080         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1081         
1082         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1083                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1084
1085         gtk_widget_destroy (dialog);
1086
1087         return folder_name;
1088 }
1089
1090 void 
1091 modest_ui_actions_on_new_folder (GtkAction *action, ModestMainWindow *main_window)
1092 {
1093         TnyFolder *parent_folder;
1094         GtkWidget *folder_view;
1095         
1096         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1097
1098         folder_view = modest_main_window_get_child_widget (main_window,
1099                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1100         if (!folder_view)
1101                 return;
1102
1103         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1104         
1105         if (parent_folder) {
1106                 gchar *folder_name;
1107
1108                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1109                                                    _("Please enter a name for the new folder"));
1110
1111                 if (folder_name != NULL && strlen (folder_name) > 0) {
1112                         TnyFolder *new_folder;
1113                         ModestMailOperation *mail_op;
1114
1115                         mail_op = modest_mail_operation_new ();
1116                         new_folder = modest_mail_operation_create_folder (mail_op,
1117                                                                           TNY_FOLDER_STORE (parent_folder),
1118                                                                           (const gchar *) folder_name);
1119                         if (new_folder) {
1120                                 g_object_unref (new_folder);
1121                         } else {
1122                                 const GError *error;
1123                                 error = modest_mail_operation_get_error (mail_op);
1124                                 if (error)
1125                                         g_warning ("Error adding a subfolder: %s\n", error->message);
1126                         }
1127                         g_object_unref (mail_op);
1128                 }
1129                 g_object_unref (parent_folder);
1130         }
1131 }
1132
1133 void 
1134 modest_ui_actions_on_rename_folder (GtkAction *action,
1135                                      ModestMainWindow *main_window)
1136 {
1137         TnyFolder *folder;
1138         GtkWidget *folder_view;
1139         
1140         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1141
1142         folder_view = modest_main_window_get_child_widget (main_window,
1143                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1144         if (!folder_view)
1145                 return;
1146         
1147         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1148         
1149         if (folder) {
1150                 gchar *folder_name;
1151                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1152                                                    _("Please enter a new name for the folder"));
1153
1154                 if (folder_name != NULL && strlen (folder_name) > 0) {
1155                         ModestMailOperation *mail_op;
1156                         const GError *error;
1157
1158                         mail_op = modest_mail_operation_new ();
1159                         modest_mail_operation_rename_folder (mail_op,
1160                                                              folder,
1161                                                              (const gchar *) folder_name);
1162
1163                         error = modest_mail_operation_get_error (mail_op);
1164                         if (error)
1165                                 /* TODO: notify error ? */
1166                                 g_warning ("Could not rename a folder: %s\n", error->message);
1167
1168                         g_object_unref (mail_op);
1169                 }
1170                 g_object_unref (folder);
1171         }
1172 }
1173
1174 static void
1175 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
1176 {
1177         TnyFolder *folder;
1178         ModestMailOperation *mail_op;
1179         GtkWidget *folder_view;
1180         const GError *error;
1181         
1182         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1183
1184         folder_view = modest_main_window_get_child_widget (main_window,
1185                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1186         if (!folder_view)
1187                 return;
1188
1189         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1190         
1191         mail_op = modest_mail_operation_new ();
1192         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1193
1194         error = modest_mail_operation_get_error (mail_op);
1195         if (error)
1196                 g_warning ("%s\n", error->message);
1197
1198         g_object_unref (mail_op);
1199 }
1200
1201 void 
1202 modest_ui_actions_on_delete_folder (GtkAction *action,
1203                                      ModestMainWindow *main_window)
1204 {
1205         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1206
1207         delete_folder (main_window, FALSE);
1208 }
1209
1210 void 
1211 modest_ui_actions_on_move_folder_to_trash_folder (GtkAction *action, ModestMainWindow *main_window)
1212 {
1213         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1214         
1215         delete_folder (main_window, TRUE);
1216 }
1217
1218 void
1219 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
1220                                          const gchar* account_name,
1221                                          gchar **password, 
1222                                          gboolean *cancel, 
1223                                          gboolean *remember,
1224                                          ModestMainWindow *main_window)
1225 {
1226         gchar *txt;
1227         GtkWidget *dialog, *entry, *remember_pass_check;
1228
1229         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
1230                                               NULL,
1231                                               GTK_DIALOG_MODAL,
1232                                               GTK_STOCK_CANCEL,
1233                                               GTK_RESPONSE_REJECT,
1234                                               GTK_STOCK_OK,
1235                                               GTK_RESPONSE_ACCEPT,
1236                                               NULL);
1237         gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(main_window));
1238         
1239         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
1240         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
1241                             FALSE, FALSE, 0);
1242         g_free (txt);
1243
1244         entry = gtk_entry_new_with_max_length (40);
1245         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
1246         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
1247         
1248         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
1249                             TRUE, FALSE, 0);    
1250
1251         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
1252         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
1253                             TRUE, FALSE, 0);
1254
1255         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1256         
1257         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1258                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
1259                 *cancel   = FALSE;
1260         } else {
1261                 *password = NULL;
1262                 *cancel   = TRUE;
1263         }
1264
1265         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
1266                 *remember = TRUE;
1267         else
1268                 *remember = FALSE;
1269
1270         gtk_widget_destroy (dialog);
1271 }