* small stuff
[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
521         tny_account = 
522                 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
523                                                                      account_name,
524                                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
525         if (!tny_account) {
526                 g_printerr ("modest: cannot get tny transport account for %s\n", account_name);
527                 return;
528         }
529         send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(tny_account));
530         if (!send_queue) {
531                 g_object_unref (G_OBJECT(tny_account));
532                 g_printerr ("modest: cannot get send queue for %s\n", account_name);
533                 return;
534         } 
535         //modest_tny_send_queue_flush (send_queue);
536
537         g_object_unref (G_OBJECT(send_queue));
538         g_object_unref (G_OBJECT(tny_account));
539
540         tny_account = 
541                 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
542                                                                      account_name,
543                                                                      TNY_ACCOUNT_TYPE_STORE);
544         if (!tny_account) {
545                 g_printerr ("modest: cannot get tny store account for %s\n", account_name);
546                 return;
547         }
548
549         mail_op = modest_mail_operation_new ();
550         modest_mail_operation_update_account (mail_op, TNY_STORE_ACCOUNT(tny_account));
551
552         g_object_unref (G_OBJECT(tny_account));
553         /* g_object_unref (G_OBJECT(mail_op)); FIXME: this is still in use... */
554 }
555
556
557
558 void
559 modest_ui_actions_toggle_view (GtkAction *action, ModestMainWindow *main_window)
560 {
561         ModestConf *conf;
562         GtkWidget *header_view;
563         
564         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
565
566         header_view = modest_main_window_get_child_widget (main_window,
567                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
568         if (!header_view)
569                 return;
570
571         conf = modest_runtime_get_conf ();
572         
573         /* what is saved/restored is depending on the style; thus; we save with
574          * old style, then update the style, and restore for this new style*/
575         modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
576         
577         if (modest_header_view_get_style
578             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
579                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
580                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
581         else
582                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
583                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
584
585         modest_widget_memory_restore (conf, G_OBJECT(header_view),
586                                       "header-view");
587 }
588
589
590
591 /*
592  * Marks a message as read and passes it to the msg preview widget
593  */
594 static void
595 read_msg_func (gpointer data, gpointer user_data)
596 {
597         TnyMsg *msg;
598         TnyHeader *header;
599         GetMsgAsyncHelper *helper;
600         TnyHeaderFlags header_flags;
601         GtkWidget *msg_preview;
602         
603         msg = TNY_MSG (data);
604         helper = (GetMsgAsyncHelper *) user_data;
605
606         msg_preview = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (helper->window),
607                                                            MODEST_WIDGET_TYPE_MSG_PREVIEW);
608         if (!msg_preview)
609                 return;
610         
611         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
612         header_flags = tny_header_get_flags (header);
613         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
614         g_object_unref (G_OBJECT (header));
615
616         /* Set message on msg view */
617         modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), msg);
618 }
619
620 /*
621  * This function is a generic handler for the tny_folder_get_msg_async
622  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
623  * contains a user provided function that is called inside this
624  * method. This will allow us to use this callback in many different
625  * places. This callback performs the common actions for the
626  * get_msg_async call, more specific actions will be done by the user
627  * function
628  */
629 static void
630 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
631 {
632         GetMsgAsyncHelper *helper;
633
634         helper = (GetMsgAsyncHelper *) user_data;
635
636         if ((*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) || !msg) {
637                 modest_ui_actions_on_item_not_found (NULL,
638                                                      MODEST_ITEM_TYPE_MESSAGE,
639                                                      helper->window);
640                 return;
641         }
642
643         /* Call user function */
644         helper->func (msg, user_data);
645
646         /* Process next element (if exists) */
647         tny_iterator_next (helper->iter);
648         if (tny_iterator_is_done (helper->iter)) {
649                 TnyList *headers;
650                 headers = tny_iterator_get_list (helper->iter);
651                 /* Free resources */
652                 g_object_unref (G_OBJECT (headers));
653                 g_object_unref (G_OBJECT (helper->iter));
654                 g_slice_free (GetMsgAsyncHelper, helper);
655         } else {
656                 TnyHeader *header;
657                 header = TNY_HEADER (tny_iterator_get_current (helper->iter)); 
658                 tny_folder_get_msg_async (folder, header,                         
659                                           get_msg_cb, helper);
660                 g_object_unref (G_OBJECT(header));
661         }
662 }
663
664 void 
665 modest_ui_actions_on_header_selected (ModestHeaderView *folder_view, 
666                                       TnyHeader *header,
667                                       ModestMainWindow *main_window)
668 {
669         GtkWidget *msg_preview;
670         TnyFolder *folder;
671         GetMsgAsyncHelper *helper;
672         TnyList *list;
673
674         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
675         
676         msg_preview = modest_main_window_get_child_widget(main_window,
677                                                           MODEST_WIDGET_TYPE_MSG_PREVIEW);
678         if (!msg_preview)
679                 return;
680         
681         /* when there's no header, clear the msgview */
682         if (!header) {
683                 modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), NULL);
684                 return;
685         }
686
687         folder = tny_header_get_folder (TNY_HEADER(header));
688
689         /* Create list */
690         list = tny_simple_list_new ();
691         tny_list_prepend (list, G_OBJECT (header));
692
693         /* Fill helper data */
694         helper = g_slice_new0 (GetMsgAsyncHelper);
695         helper->window = MODEST_WINDOW (main_window);
696         helper->iter = tny_list_create_iterator (list);
697         helper->func = read_msg_func;
698
699         tny_folder_get_msg_async (TNY_FOLDER(folder),
700                                   header, get_msg_cb,
701                                   helper);
702
703         /* Frees */
704         g_object_unref (G_OBJECT (folder));
705 }
706
707
708
709 void 
710 modest_ui_actions_on_header_activated (ModestHeaderView *folder_view, TnyHeader *header,
711                                        ModestMainWindow *main_window)
712 {
713         ModestWindow *win;
714         TnyFolder *folder = NULL;
715         TnyMsg    *msg    = NULL;
716         gchar *account    = NULL;
717         
718         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
719         
720         if (!header)
721                 return;
722
723         folder = tny_header_get_folder (header);
724         if (!folder) {
725                 g_printerr ("modest: cannot get folder for header\n");
726                 goto cleanup;
727         }
728
729         /* FIXME: make async?; check error  */
730         msg = tny_folder_get_msg (folder, header, NULL);
731         if (!msg) {
732                 g_printerr ("modest: cannot get msg for header\n");
733                 goto cleanup;
734         }
735
736         account =  g_strdup(modest_window_get_active_account(MODEST_WINDOW(main_window)));
737         if (!account)
738                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
739         
740         win = modest_msg_view_window_new (msg, account);
741         gtk_window_set_transient_for (GTK_WINDOW (win),
742                                       GTK_WINDOW (main_window));
743
744         gtk_widget_show_all (GTK_WIDGET(win));
745         
746 cleanup:
747         g_free (account);
748         
749         if (folder)
750                 g_object_unref (G_OBJECT (folder));
751         if (msg)
752                 g_object_unref (G_OBJECT (msg));
753 }
754
755 void 
756 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
757                                                TnyFolder *folder, 
758                                                gboolean selected,
759                                                ModestMainWindow *main_window)
760 {
761         gchar *txt;
762         ModestConf *conf;
763         GtkWidget *header_view;
764         
765         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
766
767         header_view = modest_main_window_get_child_widget(main_window,
768                                                           MODEST_WIDGET_TYPE_HEADER_VIEW);
769         if (!header_view)
770                 return;
771         
772         conf = modest_runtime_get_conf ();
773
774         if (!selected) { /* the folder was unselected; save it's settings  */
775                 modest_widget_memory_save (conf, G_OBJECT (header_view), "header-view");
776                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
777                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), NULL);
778         } else {  /* the folder was selected */
779                 if (folder) { /* folder may be NULL */
780                         guint num, unread;
781                         gchar *title;
782
783                         num    = tny_folder_get_all_count    (folder);
784                         unread = tny_folder_get_unread_count (folder);
785                         
786                         title = g_strdup_printf ("Modest: %s",
787                                                  tny_folder_get_name (folder));
788                         
789                         gtk_window_set_title (GTK_WINDOW(main_window), title);
790                         g_free (title);
791                         
792                         txt = g_strdup_printf (_("%d %s, %d unread"),
793                                                num, num==1 ? _("item") : _("items"), unread);           
794                         //gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
795                         g_free (txt);
796                 }
797                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), folder);
798                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
799                                               "header-view");
800         }
801 }
802
803
804 /****************************************************/
805 /*
806  * below some stuff to clearup statusbar messages after 1,5 seconds....
807  */
808 static gboolean
809 progress_bar_clean (GtkWidget *bar)
810 {
811         if (GTK_IS_PROGRESS_BAR(bar)) {
812                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
813                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
814         }
815         return FALSE;
816 }
817
818 static gboolean
819 statusbar_clean (GtkWidget *bar)
820 {
821         if (GTK_IS_STATUSBAR(bar))
822                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
823         return FALSE;
824 }
825
826
827 static void
828 statusbar_push (ModestMainWindow *main_window, guint context_id, const gchar *msg)
829 {
830         if (!msg)
831                 return;
832
833         GtkWidget *progress_bar, *status_bar;
834
835         progress_bar = modest_main_window_get_child_widget (main_window,
836                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);
837         status_bar = modest_main_window_get_child_widget (main_window,
838                                                           MODEST_WIDGET_TYPE_STATUS_BAR);
839         if (progress_bar) {
840                 gtk_widget_show (progress_bar);
841                 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
842         }
843         
844         if (status_bar) {
845                 gtk_widget_show (status_bar);
846                 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
847                 g_timeout_add (2500, (GSourceFunc)statusbar_clean, status_bar);
848         }
849
850 }
851 /****************************************************************************/
852
853 void 
854 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
855                                      ModestWindow *win)
856 {
857         GtkWidget *dialog;
858         gchar *txt, *item;
859         gboolean online;
860
861         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
862         
863         if (g_main_depth > 0)   
864                 gdk_threads_enter ();
865         online = tny_device_is_online (modest_runtime_get_device());
866
867         if (online) {
868                 /* already online -- the item is simply not there... */
869                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
870                                                  GTK_DIALOG_MODAL,
871                                                  GTK_MESSAGE_WARNING,
872                                                  GTK_BUTTONS_OK,
873                                                  _("The %s you selected cannot be found"),
874                                                  item);
875                 gtk_dialog_run (GTK_DIALOG(dialog));
876         } else {
877                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
878                                                       GTK_WINDOW (win),
879                                                       GTK_DIALOG_MODAL,
880                                                       GTK_STOCK_CANCEL,
881                                                       GTK_RESPONSE_REJECT,
882                                                       GTK_STOCK_OK,
883                                                       GTK_RESPONSE_ACCEPT,
884                                                       NULL);
885                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
886                                          "Do you want to get online?"), item);
887                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
888                                     gtk_label_new (txt), FALSE, FALSE, 0);
889                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
890                 g_free (txt);
891
892                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
893                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
894                         tny_device_force_online (modest_runtime_get_device());
895                 }
896         }
897         gtk_widget_destroy (dialog);
898         if (g_main_depth > 0)   
899                 gdk_threads_leave ();
900 }
901
902
903
904 void
905 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
906                                             const gchar *msg, gint num, 
907                                             gint total,  ModestMainWindow *main_window)
908 {
909         char* txt;
910         GtkWidget *progress_bar;
911
912         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
913
914         progress_bar = modest_main_window_get_child_widget (main_window, 
915                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);   
916         if (!progress_bar)
917                 return;
918         
919         if (total != 0)
920                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
921                                                (gdouble)num/(gdouble)total);
922         else
923                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
924
925         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
926         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
927         g_free (txt);
928         
929         statusbar_push (main_window, 0, msg);
930 }
931
932
933 void
934 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
935                                      ModestWindow *win)
936 {
937         g_message (__FUNCTION__);
938 }       
939
940
941 void
942 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
943                                         ModestWindow *win)
944 {
945         g_message (__FUNCTION__);
946 }
947
948 void
949 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
950                                              ModestWindow *win)
951 {
952         g_message (__FUNCTION__);
953         
954 }
955
956 void
957 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
958                                           ModestRecptView *recpt_view,
959                                           ModestWindow *win)
960 {
961         gint start, end;
962         gchar *utf_start, *utf_end;
963         gchar *full_string = NULL;
964         gchar *substring;
965
966         gtk_label_get_selection_bounds (GTK_LABEL (recpt_view), &start, &end);
967         full_string = (gchar *) gtk_label_get_text (GTK_LABEL (recpt_view));
968         utf_start = g_utf8_offset_to_pointer (full_string, start);
969         utf_end = g_utf8_offset_to_pointer (full_string, end);
970         substring = g_strndup (utf_start, utf_end - utf_start);
971         g_message ("%s %s", __FUNCTION__, substring);
972
973         g_free (substring);
974         
975 }
976
977 void
978 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
979 {
980         TnyTransportAccount *transport_account;
981         ModestMailOperation *mail_operation;
982         MsgData *data;
983         gchar *account_name, *from;
984         ModestAccountMgr *account_mgr;
985
986         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
987         
988         data = modest_msg_edit_window_get_msg_data (edit_window);
989
990         /* FIXME: Code added just for testing. The final version will
991            use the send queue provided by tinymail and some
992            classifier */
993         account_mgr = modest_runtime_get_account_mgr();
994         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
995         if (!account_name) 
996                 account_name = modest_account_mgr_get_default_account (account_mgr);
997         if (!account_name) {
998                 g_printerr ("modest: no account found\n");
999                 modest_msg_edit_window_free_msg_data (edit_window, data);
1000                 return;
1001         }
1002         transport_account =
1003                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_tny_account_by_account
1004                                       (modest_runtime_get_account_store(),
1005                                        account_name,
1006                                        TNY_ACCOUNT_TYPE_TRANSPORT));
1007         if (!transport_account) {
1008                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1009                 g_free (account_name);
1010                 modest_msg_edit_window_free_msg_data (edit_window, data);
1011                 return;
1012         }
1013         from = modest_account_mgr_get_from_string (account_mgr, account_name);
1014                 
1015         mail_operation = modest_mail_operation_new ();
1016         modest_mail_operation_send_new_mail (mail_operation,
1017                                              transport_account,
1018                                              from,
1019                                              data->to, 
1020                                              data->cc, 
1021                                              data->bcc,
1022                                              data->subject, 
1023                                              data->body, 
1024                                              NULL);
1025         /* Frees */
1026         g_free (from);
1027         g_free (account_name);
1028         g_object_unref (G_OBJECT (mail_operation));
1029         g_object_unref (G_OBJECT (transport_account));
1030
1031         modest_msg_edit_window_free_msg_data (edit_window, data);
1032
1033         /* Save settings and close the window */
1034         /* save_settings (edit_window) */
1035         gtk_widget_destroy (GTK_WIDGET (edit_window));
1036 }
1037
1038 /*
1039  * Shows a dialog with an entry that asks for some text. The returned
1040  * value must be freed by the caller. The dialog window title will be
1041  * set to @title.
1042  */
1043 static gchar *
1044 ask_for_folder_name (GtkWindow *parent_window,
1045                      const gchar *title)
1046 {
1047         GtkWidget *dialog, *entry;
1048         gchar *folder_name = NULL;
1049
1050         /* Ask for folder name */
1051         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1052                                               parent_window,
1053                                               GTK_DIALOG_MODAL,
1054                                               GTK_STOCK_CANCEL,
1055                                               GTK_RESPONSE_REJECT,
1056                                               GTK_STOCK_OK,
1057                                               GTK_RESPONSE_ACCEPT,
1058                                               NULL);
1059         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1060                             gtk_label_new(title),
1061                             FALSE, FALSE, 0);
1062                 
1063         entry = gtk_entry_new_with_max_length (40);
1064         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1065                             entry,
1066                             TRUE, FALSE, 0);    
1067         
1068         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1069         
1070         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1071                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1072
1073         gtk_widget_destroy (dialog);
1074
1075         return folder_name;
1076 }
1077
1078 void 
1079 modest_ui_actions_on_new_folder (GtkAction *action, ModestMainWindow *main_window)
1080 {
1081         TnyFolder *parent_folder;
1082         GtkWidget *folder_view;
1083         
1084         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1085
1086         folder_view = modest_main_window_get_child_widget (main_window,
1087                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1088         if (!folder_view)
1089                 return;
1090
1091         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1092         
1093         if (parent_folder) {
1094                 gchar *folder_name;
1095
1096                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1097                                                    _("Please enter a name for the new folder"));
1098
1099                 if (folder_name != NULL && strlen (folder_name) > 0) {
1100                         TnyFolder *new_folder;
1101                         ModestMailOperation *mail_op;
1102
1103                         mail_op = modest_mail_operation_new ();
1104                         new_folder = modest_mail_operation_create_folder (mail_op,
1105                                                                           TNY_FOLDER_STORE (parent_folder),
1106                                                                           (const gchar *) folder_name);
1107                         if (new_folder) {
1108                                 g_object_unref (new_folder);
1109                         } else {
1110                                 const GError *error;
1111                                 error = modest_mail_operation_get_error (mail_op);
1112                                 if (error)
1113                                         g_warning ("Error adding a subfolder: %s\n", error->message);
1114                         }
1115                         g_object_unref (mail_op);
1116                 }
1117                 g_object_unref (parent_folder);
1118         }
1119 }
1120
1121 void 
1122 modest_ui_actions_on_rename_folder (GtkAction *action,
1123                                      ModestMainWindow *main_window)
1124 {
1125         TnyFolder *folder;
1126         GtkWidget *folder_view;
1127         
1128         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1129
1130         folder_view = modest_main_window_get_child_widget (main_window,
1131                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1132         if (!folder_view)
1133                 return;
1134         
1135         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1136         
1137         if (folder) {
1138                 gchar *folder_name;
1139                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1140                                                    _("Please enter a new name for the folder"));
1141
1142                 if (folder_name != NULL && strlen (folder_name) > 0) {
1143                         ModestMailOperation *mail_op;
1144                         const GError *error;
1145
1146                         mail_op = modest_mail_operation_new ();
1147                         modest_mail_operation_rename_folder (mail_op,
1148                                                              folder,
1149                                                              (const gchar *) folder_name);
1150
1151                         error = modest_mail_operation_get_error (mail_op);
1152                         if (error)
1153                                 /* TODO: notify error ? */
1154                                 g_warning ("Could not rename a folder: %s\n", error->message);
1155
1156                         g_object_unref (mail_op);
1157                 }
1158                 g_object_unref (folder);
1159         }
1160 }
1161
1162 static void
1163 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
1164 {
1165         TnyFolder *folder;
1166         ModestMailOperation *mail_op;
1167         GtkWidget *folder_view;
1168         const GError *error;
1169         
1170         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1171
1172         folder_view = modest_main_window_get_child_widget (main_window,
1173                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1174         if (!folder_view)
1175                 return;
1176
1177         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
1178         
1179         mail_op = modest_mail_operation_new ();
1180         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1181
1182         error = modest_mail_operation_get_error (mail_op);
1183         if (error)
1184                 g_warning ("%s\n", error->message);
1185
1186         g_object_unref (G_OBJECT (mail_op));
1187         g_object_unref (G_OBJECT (folder));
1188 }
1189
1190 void 
1191 modest_ui_actions_on_delete_folder (GtkAction *action,
1192                                      ModestMainWindow *main_window)
1193 {
1194         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1195
1196         delete_folder (main_window, FALSE);
1197 }
1198
1199 void 
1200 modest_ui_actions_on_move_folder_to_trash_folder (GtkAction *action, ModestMainWindow *main_window)
1201 {
1202         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1203         
1204         delete_folder (main_window, TRUE);
1205 }
1206
1207 void
1208 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
1209                                          const gchar* account_name,
1210                                          gchar **password, 
1211                                          gboolean *cancel, 
1212                                          gboolean *remember,
1213                                          ModestMainWindow *main_window)
1214 {
1215         gchar *txt;
1216         GtkWidget *dialog, *entry, *remember_pass_check;
1217
1218         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
1219                                               NULL,
1220                                               GTK_DIALOG_MODAL,
1221                                               GTK_STOCK_CANCEL,
1222                                               GTK_RESPONSE_REJECT,
1223                                               GTK_STOCK_OK,
1224                                               GTK_RESPONSE_ACCEPT,
1225                                               NULL);
1226         gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(main_window));
1227         
1228         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
1229         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
1230                             FALSE, FALSE, 0);
1231         g_free (txt);
1232
1233         entry = gtk_entry_new_with_max_length (40);
1234         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
1235         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
1236         
1237         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
1238                             TRUE, FALSE, 0);    
1239
1240         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
1241         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
1242                             TRUE, FALSE, 0);
1243
1244         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1245         
1246         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1247                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
1248                 *cancel   = FALSE;
1249         } else {
1250                 *password = NULL;
1251                 *cancel   = TRUE;
1252         }
1253
1254         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
1255                 *remember = TRUE;
1256         else
1257                 *remember = FALSE;
1258
1259         gtk_widget_destroy (dialog);
1260 }