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