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