Bug Fix #596834 and #596832
[claws.git] / src / toolbar.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * General functions for accessing address book files.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "defs.h"
29
30 #include <glib.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <dirent.h>
34 #include <sys/stat.h>
35 #include <math.h>
36 #include <setjmp.h>
37
38 #include "intl.h"
39 #include "utils.h"
40 #include "xml.h"
41 #include "mgutils.h"
42 #include "prefs.h"
43 #include "codeconv.h"
44 #include "stock_pixmap.h"
45 #include "mainwindow.h"
46 #include "prefs_common.h"
47 #include "menu.h"
48 #include "prefs_actions.h"
49 #include "manage_window.h"
50
51 #include "toolbar.h"
52 #include "prefs_toolbar.h"
53
54 /* elements */
55 #define TOOLBAR_TAG_INDEX        "toolbar"
56 #define TOOLBAR_TAG_ITEM         "item"
57 #define TOOLBAR_TAG_SEPARATOR    SEPARATOR
58
59 jmp_buf    jumper;
60
61 GSList *toolbar_list;
62
63 MainWindow *mwin;
64
65 #define TOOLBAR_ICON_FILE   "file"    
66 #define TOOLBAR_ICON_TEXT   "text"     
67 #define TOOLBAR_ICON_ACTION "action"    
68
69 gboolean      toolbar_is_duplicate           (gint action);
70 static void   toolbar_parse_item             (XMLFile *file);
71 static gint   toolbar_ret_val_from_text      (gchar *text);
72
73
74 /* callback functions */
75 static void toolbar_inc_cb              (GtkWidget      *widget,
76                                          gpointer        data);
77
78 static void toolbar_inc_all_cb          (GtkWidget      *widget,
79                                          gpointer        data);
80
81 static void toolbar_send_cb             (GtkWidget      *widget,
82                                          gpointer        data);
83
84 static void toolbar_compose_cb          (GtkWidget      *widget,
85                                          gpointer        data);
86
87 static void toolbar_reply_cb            (GtkWidget      *widget,
88                                          gpointer        data);
89
90 static void toolbar_reply_to_all_cb     (GtkWidget      *widget,
91                                          gpointer        data);
92
93 static void toolbar_reply_to_sender_cb  (GtkWidget      *widget,
94                                          gpointer        data);
95
96 static void toolbar_forward_cb          (GtkWidget      *widget,
97                                          gpointer        data);
98
99 static void toolbar_delete_cb           (GtkWidget      *widget,
100                                          gpointer        data);
101
102 static void toolbar_exec_cb             (GtkWidget      *widget,
103                                          gpointer        data);
104
105 static void toolbar_next_unread_cb      (GtkWidget      *widget,
106                                          gpointer        data);
107
108 static void toolbar_actions_execute_cb  (GtkWidget      *widget,
109                                          gpointer        data);
110
111 static void toolbar_reply_popup_cb             (GtkWidget       *widget,
112                                                 GdkEventButton  *event,
113                                                 gpointer         data);
114 static void toolbar_reply_popup_closed_cb      (GtkMenuShell    *menu_shell,
115                                                 gpointer         data);
116
117 static void toolbar_reply_to_all_popup_cb      (GtkWidget       *widget,
118                                                 GdkEventButton  *event,
119                                                 gpointer         data);
120
121 static void toolbar_reply_to_all_popup_closed_cb
122                                         (GtkMenuShell   *menu_shell,
123                                          gpointer        data);
124
125 static void toolbar_reply_to_sender_popup_cb(GtkWidget  *widget,
126                                          GdkEventButton *event,
127                                          gpointer        data);
128 static void toolbar_reply_to_sender_popup_closed_cb
129                                         (GtkMenuShell   *menu_shell,
130                                          gpointer        data);
131
132 static void toolbar_forward_popup_cb     (GtkWidget      *widget,
133                                          GdkEventButton    *event,
134                                          gpointer        data);
135
136 static void toolbar_forward_popup_closed_cb             
137                                         (GtkMenuShell   *menu_shell,
138                                          gpointer        data);
139
140 static void activate_compose_button     (MainToolbar       *toolbar,
141                                          ToolbarStyle      style,
142                                          ComposeButtonType type);
143 static ToolbarAction t_action[] = 
144 {
145         { "A_RECEIVE_ALL",   N_("Receive Mail on all Accounts"),    toolbar_inc_all_cb        },
146         { "A_RECEIVE_CUR",   N_("Receive Mail on current Account"), toolbar_inc_cb            },
147         { "A_SEND_QUEUED",   N_("Send Queued Message(s)"),          toolbar_send_cb           },
148         { "A_COMPOSE_EMAIL", N_("Compose Email"),                   toolbar_compose_cb        },
149         { "A_REPLY_MESSAGE", N_("Reply to Message"),                toolbar_reply_cb          },
150         { "A_REPLY_SENDER",  N_("Reply to Sender"),                 toolbar_reply_to_sender_cb},
151         { "A_REPLY_ALL",     N_("Reply to All"),                    toolbar_reply_to_all_cb   },
152         { "A_FORWARD",       N_("Forward Message"),                 toolbar_forward_cb        },
153         { "A_DELETE",        N_("Delete Message"),                  toolbar_delete_cb         },
154         { "A_EXECUTE",       N_("Execute"),                         toolbar_exec_cb           },
155         { "A_GOTO_NEXT",     N_("Goto Next Message"),               toolbar_next_unread_cb    },
156         { "A_SYL_ACTIONS",   N_("Sylpheed Actions Feature"),        toolbar_actions_execute_cb},
157
158         { "A_COMPOSE_NEWS",  N_("Compose News"),                    toolbar_compose_cb        },    
159         { "A_SEPARATOR",     SEPARATOR,                             NULL                      }
160 };
161
162 static GtkItemFactoryEntry reply_popup_entries[] =
163 {
164         {N_("/Reply with _quote"), NULL, reply_cb, COMPOSE_REPLY_WITH_QUOTE, NULL},
165         {N_("/_Reply without quote"), NULL, reply_cb, COMPOSE_REPLY_WITHOUT_QUOTE, NULL}
166 };
167 static GtkItemFactoryEntry replyall_popup_entries[] =
168 {
169         {N_("/Reply to all with _quote"), "<shift>A", reply_cb, COMPOSE_REPLY_TO_ALL_WITH_QUOTE, NULL},
170         {N_("/_Reply to all without quote"), "a", reply_cb, COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE, NULL}
171 };
172 static GtkItemFactoryEntry replysender_popup_entries[] =
173 {
174         {N_("/Reply to sender with _quote"), NULL, reply_cb, COMPOSE_REPLY_TO_SENDER_WITH_QUOTE, NULL},
175         {N_("/_Reply to sender without quote"), NULL, reply_cb, COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE, NULL}
176 };
177 static GtkItemFactoryEntry fwd_popup_entries[] =
178 {
179         {N_("/_Forward message (inline style)"), "f", reply_cb, COMPOSE_FORWARD_INLINE, NULL},
180         {N_("/Forward message as _attachment"), "<shift>F", reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL}
181 };
182
183
184 void toolbar_actions_cb(GtkWidget *widget, ToolbarItem *toolbar_item)
185 {
186         if (toolbar_item->action < sizeof(t_action) / sizeof(t_action[0]))
187                 t_action[toolbar_item->action].func(widget, mwin);
188 }
189
190 gint toolbar_ret_val_from_descr(gchar *descr)
191 {
192         gint i;
193         
194         for (i = 0; i < sizeof(t_action) / sizeof(t_action[0]); i++) {
195                 if (g_strcasecmp(t_action[i].descr, descr) == 0)
196                                 return i;
197         }
198         
199         return -1;
200 }
201
202 gchar *toolbar_ret_descr_from_val(gint val)
203 {
204         g_return_val_if_fail(val >=0 && val <= sizeof(t_action) / sizeof(t_action[0]), NULL);
205
206         return t_action[val].descr;
207
208 }
209
210 static gint toolbar_ret_val_from_text(gchar *text)
211 {
212         gint i;
213         
214         for (i = 0; i < sizeof(t_action) / sizeof(t_action[0]); i++) {
215                 if (g_strcasecmp(t_action[i].action_text, text) == 0)
216                                 return i;
217         }
218         
219         return -1;
220 }
221
222 gchar *toolbar_ret_text_from_val(gint val)
223 {
224         g_return_val_if_fail(val >=0 && val <= sizeof(t_action) / sizeof(t_action[0]), NULL);
225
226         return t_action[val].action_text;
227 }
228
229 gboolean toolbar_is_duplicate(gint action)
230 {
231         GSList *cur;
232
233         if ((action == A_SEPARATOR) || (action == A_SYL_ACTIONS)) 
234                 return FALSE;
235
236         for (cur = toolbar_list; cur != NULL; cur = cur->next) {
237                 ToolbarItem *item = (ToolbarItem*) cur->data;
238                 
239                 if (item->action == action)
240                         return TRUE;
241         }
242         return FALSE;
243 }
244
245 GList *toolbar_get_action_items(void)
246 {
247         GList *items = NULL;
248         gint i;
249         
250         for (i = 0; i < N_ACTION_VAL; i++) {
251                 items = g_list_append(items, t_action[i].descr);
252         }
253
254         return items;
255 }
256
257 static void toolbar_parse_item(XMLFile *file)
258 {
259         GList *attr;
260         gchar *name, *value;
261         ToolbarItem *item = NULL;
262
263         attr = xml_get_current_tag_attr(file);
264         item = g_new0(ToolbarItem, 1);
265         while( attr ) {
266                 name = ((XMLAttr *)attr->data)->name;
267                 value = ((XMLAttr *)attr->data)->value;
268                 
269                 if (g_strcasecmp(name, TOOLBAR_ICON_FILE) == 0) 
270                         item->file = g_strdup (value);
271                 else if (g_strcasecmp(name, TOOLBAR_ICON_TEXT) == 0)
272                         item->text = g_strdup (value);
273                 else if (g_strcasecmp(name, TOOLBAR_ICON_ACTION) == 0)
274                         item->action = toolbar_ret_val_from_text(value);
275
276                 attr = g_list_next(attr);
277         }
278         if (item->action != -1) {
279                 
280                 if ( !toolbar_is_duplicate(item->action)) 
281                         toolbar_list = g_slist_append(toolbar_list, item);
282         }
283 }
284
285 void toolbar_set_default_toolbar(void)
286 {
287         gint i;
288         /* create default toolbar */
289         struct _default_toolbar {
290                 gint action;
291                 gint icon;
292                 gchar *text;
293         } default_toolbar[] = {
294                 { A_RECEIVE_CUR,   STOCK_PIXMAP_MAIL_RECEIVE,         _("Get")     },
295                 { A_RECEIVE_ALL,   STOCK_PIXMAP_MAIL_RECEIVE_ALL,     _("Get All") },
296                 { A_SEPARATOR,     0,                                 ("")         }, 
297                 { A_SEND_QUEUED,   STOCK_PIXMAP_MAIL_SEND_QUEUE,      _("Send")    },
298                 { A_COMPOSE_EMAIL, STOCK_PIXMAP_MAIL_COMPOSE,         _("Email")   },
299                 { A_SEPARATOR,     0,                                 ("")         },
300                 { A_REPLY_MESSAGE, STOCK_PIXMAP_MAIL_REPLY,           _("Reply")   }, 
301                 { A_REPLY_ALL,     STOCK_PIXMAP_MAIL_REPLY_TO_ALL,    _("All")     },
302                 { A_REPLY_SENDER,  STOCK_PIXMAP_MAIL_REPLY_TO_AUTHOR, _("Sender")  },
303                 { A_FORWARD,       STOCK_PIXMAP_MAIL_FORWARD,         _("Forward") },
304                 { A_SEPARATOR,     0,                                 ("")         },
305                 { A_DELETE,        STOCK_PIXMAP_CLOSE,                _("Delete")  },
306                 { A_EXECUTE,       STOCK_PIXMAP_EXEC,                 _("Execute") },
307                 { A_GOTO_NEXT,     STOCK_PIXMAP_DOWN_ARROW,           _("Next")    },
308         };
309                 
310         for (i = 0; i < sizeof(default_toolbar) / sizeof(default_toolbar[0]); i++) {
311                 
312                 ToolbarItem *toolbar_item = g_new0(ToolbarItem, 1);
313                 
314                 if (default_toolbar[i].action != A_SEPARATOR) {
315                         
316                         gchar *file = stock_pixmap_get_name((StockPixmap)default_toolbar[i].icon);
317                         
318                         toolbar_item->file   = g_strdup(file);
319                         toolbar_item->action = default_toolbar[i].action;
320                         toolbar_item->text   = g_strdup(default_toolbar[i].text);
321                 } else {
322
323                         toolbar_item->file   = g_strdup(SEPARATOR);
324                         toolbar_item->action = A_SEPARATOR;
325                 }
326                 
327                 if (toolbar_item->action != -1) {
328                         
329                         if ( !toolbar_is_duplicate(toolbar_item->action)) 
330                                 toolbar_list = g_slist_append(toolbar_list, toolbar_item);
331                 }       
332         }
333 }
334
335 void toolbar_save_config_file()
336 {
337         GSList *cur;
338         FILE *fp;
339         PrefFile *pfile;
340         gchar *fileSpec = NULL;
341
342         debug_print("save Toolbar Configuration\n");
343
344         fileSpec = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, TOOLBAR_FILE, NULL );
345         pfile = prefs_write_open(fileSpec);
346         g_free( fileSpec );
347         if( pfile ) {
348                 fp = pfile->fp;
349                 fprintf(fp, "<?xml version=\"1.0\" encoding=\"%s\" ?>\n",
350                         conv_get_current_charset_str());
351
352                 fprintf(fp, "<%s>\n", TOOLBAR_TAG_INDEX);
353
354                 for (cur = toolbar_list; cur != NULL; cur = cur->next) {
355                         ToolbarItem *toolbar_item = (ToolbarItem*) cur->data;
356                         
357                         if (g_strcasecmp(toolbar_item->file, SEPARATOR) != 0) 
358                                 fprintf(fp, "\t<%s %s=\"%s\" %s=\"%s\" %s=\"%s\"/>\n",
359                                         TOOLBAR_TAG_ITEM, 
360                                         TOOLBAR_ICON_FILE, toolbar_item->file,
361                                         TOOLBAR_ICON_TEXT, toolbar_item->text,
362                                         TOOLBAR_ICON_ACTION, 
363                                         toolbar_ret_text_from_val(toolbar_item->action));
364                         else 
365                                 fprintf(fp, "\t<%s/>\n", TOOLBAR_TAG_SEPARATOR); 
366                 }
367
368                 fprintf(fp, "</%s>\n", TOOLBAR_TAG_INDEX);      
369         
370                 if (prefs_write_close (pfile) < 0 ) 
371                         g_warning("failed to write toolbar configuration to file\n");
372         } else
373                 g_warning("failed to open toolbar configuration file for writing\n");
374 }
375
376 void toolbar_clear_list()
377 {
378         while (toolbar_list != NULL) {
379                 ToolbarItem *item = (ToolbarItem*) toolbar_list->data;
380                 
381                 toolbar_list = g_slist_remove(toolbar_list, item);
382                 if (item->file)
383                         g_free(item->file);
384                 if (item->text)
385                         g_free(item->text);
386                 g_free(item);   
387         }
388         g_slist_free(toolbar_list);
389 }
390
391 void toolbar_read_config_file(void)
392 {
393         XMLFile *file   = NULL;
394         gchar *fileSpec = NULL;
395         GList *attr;
396         gboolean retVal;
397
398         debug_print("read Toolbar Configuration\n");
399
400         fileSpec = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, TOOLBAR_FILE, NULL );
401         file = xml_open_file(fileSpec);
402         g_free(fileSpec);
403
404         toolbar_clear_list();
405
406         if (file) {
407                 if ((setjmp(jumper))
408                 || (xml_get_dtd(file))
409                 || (xml_parse_next_tag(file))
410                 || (!xml_compare_tag(file, TOOLBAR_TAG_INDEX))) {
411                         xml_close_file(file);
412                         return;
413                 }
414
415                 attr = xml_get_current_tag_attr(file);
416                 
417                 retVal = TRUE;
418                 for (;;) {
419                         if (!file->level) 
420                                 break;
421                         /* Get item tag */
422                         if (xml_parse_next_tag(file)) 
423                                 longjmp(jumper, 1);
424
425                         /* Get next tag (icon, icon_text or icon_action) */
426                         if (xml_compare_tag(file, TOOLBAR_TAG_ITEM)) {
427                                 toolbar_parse_item(file);
428                         } else if (xml_compare_tag(file, TOOLBAR_TAG_SEPARATOR)) {
429                                 ToolbarItem *item = g_new0(ToolbarItem, 1);
430                         
431                                 item->file   = g_strdup(SEPARATOR);
432                                 item->action = A_SEPARATOR;
433                                 toolbar_list = g_slist_append(toolbar_list, item);
434                         }
435
436                 }
437                 xml_close_file(file);
438         }
439         else {
440                 /* save default toolbar */
441                 toolbar_set_default_toolbar();
442                 toolbar_save_config_file();
443         }
444 }
445
446 static void toolbar_actions_execute_cb(GtkWidget *widget,
447                                        gpointer  data)
448 {
449         gint i = 0;
450         GSList *cur, *lop;
451         MainWindow *mainwin = (MainWindow*)data;
452         gchar *action, *action_p;
453         gboolean found = FALSE;
454
455         for (cur = mainwin->toolbar->syl_action; cur != NULL;  cur = cur->next) {
456                 ToolbarSylpheedActions *act = (ToolbarSylpheedActions*)cur->data;
457
458                 if (widget == act->widget) {
459                         
460                         for (lop = prefs_common.actions_list; lop != NULL; lop = lop->next) {
461                                 action = g_strdup((gchar*)lop->data);
462
463                                 action_p = strstr(action, ": ");
464                                 action_p[0] = 0x00;
465                                 if (g_strcasecmp(act->name, action) == 0) {
466                                         found = TRUE;
467                                         g_free(action);
468                                         break;
469                                 } else 
470                                         i++;
471                                 g_free(action);
472                         }
473                         if (found) 
474                                 break;
475                 }
476         }
477
478         if (found)
479                 actions_execute(mwin, i, widget);
480         else
481                 g_warning ("Error: did not find Sylpheed Action to execute");
482 }
483
484 static void toolbar_inc_cb               (GtkWidget     *widget,
485                                           gpointer       data)
486 {
487         MainWindow *mainwin = (MainWindow *)data;
488
489         inc_mail_cb(mainwin, 0, NULL);
490 }
491
492 static void toolbar_inc_all_cb  (GtkWidget      *widget,
493                                  gpointer        data)
494 {
495         MainWindow *mainwin = (MainWindow *)data;
496
497         inc_all_account_mail_cb(mainwin, 0, NULL);
498 }
499
500 static void toolbar_send_cb     (GtkWidget      *widget,
501                                  gpointer        data)
502 {
503         MainWindow *mainwin = (MainWindow *)data;
504
505         send_queue_cb(mainwin, 0, NULL);
506 }
507
508 static void toolbar_compose_cb  (GtkWidget      *widget,
509                                  gpointer        data)
510 {
511         MainWindow *mainwin = (MainWindow *)data;
512
513         if (mainwin->toolbar->compose_btn_type == COMPOSEBUTTON_NEWS) 
514                 compose_news_cb(mainwin, 0, NULL);
515         else
516                 compose_mail_cb(mainwin, 0, NULL);
517 }
518
519 static void toolbar_reply_cb(GtkWidget *widget, gpointer data)
520 {
521         MainWindow *mainwin = (MainWindow *)data;
522
523         reply_cb(mainwin, 
524                  prefs_common.reply_with_quote ? COMPOSE_REPLY_WITH_QUOTE 
525                  : COMPOSE_REPLY_WITHOUT_QUOTE,
526                  NULL);
527 }
528
529 static void toolbar_reply_to_all_cb(GtkWidget *widget, gpointer data)
530 {
531         MainWindow *mainwin = (MainWindow *)data;
532
533         reply_cb(mainwin, 
534                  prefs_common.reply_with_quote ? COMPOSE_REPLY_TO_ALL_WITH_QUOTE 
535                  : COMPOSE_REPLY_TO_ALL_WITHOUT_QUOTE, 
536                  NULL);
537 }
538
539
540 static void toolbar_reply_to_sender_cb(GtkWidget *widget, gpointer data)
541 {
542         MainWindow *mainwin = (MainWindow *)data;
543
544         reply_cb(mainwin, 
545                  prefs_common.reply_with_quote ? COMPOSE_REPLY_TO_SENDER_WITH_QUOTE 
546                  : COMPOSE_REPLY_TO_SENDER_WITHOUT_QUOTE, 
547                  NULL);
548 }
549
550 static void toolbar_forward_cb  (GtkWidget      *widget,
551                                  gpointer        data)
552 {
553         MainWindow *mainwin = (MainWindow *)data;
554
555         if (prefs_common.forward_as_attachment)
556                 reply_cb(mainwin, COMPOSE_FORWARD_AS_ATTACH, NULL);
557         else
558                 reply_cb(mainwin, COMPOSE_FORWARD, NULL);
559 }
560
561 static void toolbar_delete_cb   (GtkWidget      *widget,
562                                  gpointer        data)
563 {
564         MainWindow *mainwin = (MainWindow *)data;
565
566         summary_delete(mainwin->summaryview);
567 }
568
569 static void toolbar_exec_cb     (GtkWidget      *widget,
570                                  gpointer        data)
571 {
572         MainWindow *mainwin = (MainWindow *)data;
573
574         summary_execute(mainwin->summaryview);
575 }
576
577 static void toolbar_next_unread_cb      (GtkWidget      *widget,
578                                          gpointer        data)
579 {
580         MainWindow *mainwin = (MainWindow *)data;
581
582         next_unread_cb(mainwin, 0, NULL);
583 }
584
585 /* popup callback functions */
586 static void toolbar_reply_popup_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
587 {
588         MainWindow *mainwindow = (MainWindow *) data;
589         
590         if (!event) return;
591
592         if (event->button == 3) {
593                 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
594                 gtk_menu_popup(GTK_MENU(mainwindow->toolbar->reply_popup), NULL, NULL,
595                        menu_button_position, widget,
596                        event->button, event->time);
597         }
598 }
599
600 static void toolbar_reply_popup_closed_cb(GtkMenuShell *menu_shell, gpointer data)
601 {
602         MainWindow *mainwin = (MainWindow *)data;
603
604         gtk_button_set_relief(GTK_BUTTON(mainwin->toolbar->reply_btn), GTK_RELIEF_NONE);
605         manage_window_focus_in(mainwin->window, NULL, NULL);
606 }
607
608 static void toolbar_reply_to_all_popup_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
609 {
610         MainWindow *mainwindow = (MainWindow *) data;
611         
612         if (!event) return;
613
614         if (event->button == 3) {
615                 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
616                 gtk_menu_popup(GTK_MENU(mainwindow->toolbar->replyall_popup), NULL, NULL,
617                        menu_button_position, widget,
618                        event->button, event->time);
619         }
620 }
621
622 static void toolbar_reply_to_all_popup_closed_cb(GtkMenuShell *menu_shell, gpointer data)
623 {
624         MainWindow *mainwin = (MainWindow *)data;
625
626         gtk_button_set_relief(GTK_BUTTON(mainwin->toolbar->replyall_btn), GTK_RELIEF_NONE);
627         manage_window_focus_in(mainwin->window, NULL, NULL);
628 }
629
630 static void toolbar_reply_to_sender_popup_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
631 {
632         MainWindow *mainwindow = (MainWindow *) data;
633
634         if (!event) return;
635
636         if (event->button == 3) {
637                 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
638                 gtk_menu_popup(GTK_MENU(mainwindow->toolbar->replysender_popup), NULL, NULL,
639                        menu_button_position, widget,
640                        event->button, event->time);
641         }
642 }
643
644 static void toolbar_reply_to_sender_popup_closed_cb(GtkMenuShell *menu_shell, gpointer data)
645 {
646         MainWindow *mainwin = (MainWindow *)data;
647
648         gtk_button_set_relief(GTK_BUTTON(mainwin->toolbar->replysender_btn), GTK_RELIEF_NONE);
649         manage_window_focus_in(mainwin->window, NULL, NULL);
650 }
651
652 static void toolbar_forward_popup_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
653 {
654         MainWindow *mainwindow = (MainWindow *) data;
655         
656         if (!event) return;
657
658         if (event->button == 3) {
659                 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
660                 gtk_menu_popup(GTK_MENU(mainwindow->toolbar->fwd_popup), NULL, NULL,
661                        menu_button_position, widget,
662                        event->button, event->time);
663         }
664 }
665
666 static void toolbar_forward_popup_closed_cb (GtkMenuShell *menu_shell, 
667                                              gpointer     data)
668 {
669         MainWindow *mainwin = (MainWindow *)data;
670
671         gtk_button_set_relief(GTK_BUTTON(mainwin->toolbar->fwd_btn), GTK_RELIEF_NONE);
672         manage_window_focus_in(mainwin->window, NULL, NULL);
673 }
674
675 static void activate_compose_button (MainToolbar       *toolbar,
676                                      ToolbarStyle      style,
677                                      ComposeButtonType type)
678 {
679         if ((!toolbar->compose_mail_btn) || (!toolbar->compose_news_btn))
680                 return;
681
682         gtk_widget_hide(type == COMPOSEBUTTON_NEWS ? toolbar->compose_mail_btn 
683                         : toolbar->compose_news_btn);
684         gtk_widget_show(type == COMPOSEBUTTON_NEWS ? toolbar->compose_news_btn
685                         : toolbar->compose_mail_btn);
686         toolbar->compose_btn_type = type;       
687 }
688
689 void toolbar_set_compose_button (MainToolbar       *toolbar, 
690                                  ComposeButtonType compose_btn_type)
691 {
692         if (toolbar->compose_btn_type != compose_btn_type)
693                 activate_compose_button(toolbar, 
694                                         prefs_common.toolbar_style,
695                                         compose_btn_type);
696 }
697
698 void toolbar_set_sensitive(MainWindow *mainwin)
699 {
700         SensitiveCond state;
701         gboolean sensitive;
702         MainToolbar *toolbar = mainwin->toolbar;
703         GSList *cur;
704         GSList *entry_list = NULL;
705         
706         typedef struct _Entry Entry;
707         struct _Entry {
708                 GtkWidget *widget;
709                 SensitiveCond cond;
710                 gboolean empty;
711         };
712
713 #define SET_WIDGET_COND(w, c)     \
714 { \
715         Entry *e = g_new0(Entry, 1); \
716         e->widget = w; \
717         e->cond   = c; \
718         entry_list = g_slist_append(entry_list, e); \
719 }
720
721         SET_WIDGET_COND(toolbar->get_btn, M_HAVE_ACCOUNT|M_UNLOCKED);
722         SET_WIDGET_COND(toolbar->getall_btn, M_HAVE_ACCOUNT|M_UNLOCKED);
723         SET_WIDGET_COND(toolbar->compose_news_btn, M_HAVE_ACCOUNT);
724         SET_WIDGET_COND(toolbar->reply_btn,
725                         M_HAVE_ACCOUNT|M_SINGLE_TARGET_EXIST);
726         SET_WIDGET_COND(toolbar->replyall_btn,
727                         M_HAVE_ACCOUNT|M_SINGLE_TARGET_EXIST);
728         SET_WIDGET_COND(toolbar->replysender_btn,
729                         M_HAVE_ACCOUNT|M_SINGLE_TARGET_EXIST);
730         SET_WIDGET_COND(toolbar->fwd_btn, M_HAVE_ACCOUNT|M_TARGET_EXIST);
731
732         SET_WIDGET_COND(toolbar->next_btn, M_MSG_EXIST);
733         SET_WIDGET_COND(toolbar->delete_btn,
734                         M_TARGET_EXIST|M_ALLOW_DELETE|M_UNLOCKED);
735         SET_WIDGET_COND(toolbar->exec_btn, M_MSG_EXIST|M_EXEC|M_UNLOCKED);
736
737         for (cur = toolbar->syl_action; cur != NULL;  cur = cur->next) {
738                 ToolbarSylpheedActions *act = (ToolbarSylpheedActions*)cur->data;
739                 
740                 SET_WIDGET_COND(act->widget, M_TARGET_EXIST|M_UNLOCKED);
741         }
742
743 #undef SET_WIDGET_COND
744
745         state = main_window_get_current_state(mainwin);
746
747         for (cur = entry_list; cur != NULL; cur = cur->next) {
748                 Entry *e = (Entry*) cur->data;
749
750                 if (e->widget != NULL) {
751                         sensitive = ((e->cond & state) == e->cond);
752                         gtk_widget_set_sensitive(e->widget, sensitive); 
753                 }
754         }
755         
756         while (entry_list != NULL) {
757                 Entry *e = (Entry*) entry_list->data;
758
759                 if (e)
760                         g_free(e);
761                 entry_list = g_slist_remove(entry_list, e);
762         }
763
764         g_slist_free(entry_list);
765
766         activate_compose_button(toolbar, 
767                                 prefs_common.toolbar_style,
768                                 toolbar->compose_btn_type);
769 }
770
771 void toolbar_update(void)
772 {
773         gtk_container_remove(GTK_CONTAINER(mwin->handlebox), 
774                              GTK_WIDGET(mwin->toolbar->toolbar));
775         
776         mwin->toolbar->toolbar    = NULL;
777         mwin->toolbar->get_btn    = NULL;
778         mwin->toolbar->getall_btn = NULL;
779         mwin->toolbar->send_btn   = NULL;
780         mwin->toolbar->compose_mail_btn = NULL;
781         mwin->toolbar->compose_news_btn = NULL;
782         mwin->toolbar->reply_btn        = NULL; 
783         mwin->toolbar->replyall_btn     = NULL; 
784         mwin->toolbar->replysender_btn  = NULL; 
785         mwin->toolbar->fwd_btn    = NULL;       
786         mwin->toolbar->delete_btn = NULL;       
787         mwin->toolbar->next_btn   = NULL;       
788         mwin->toolbar->exec_btn   = NULL;
789
790         toolbar_destroy(mwin);
791         toolbar_create(mwin, mwin->handlebox);
792         toolbar_set_sensitive(mwin);
793
794 }
795
796 void toolbar_destroy(MainWindow *mainwin)
797 {
798         ToolbarSylpheedActions *syl_action;
799
800         toolbar_clear_list();
801         
802         while (mainwin->toolbar->syl_action != NULL) {
803                 syl_action = (ToolbarSylpheedActions*)mainwin->toolbar->syl_action->data;
804
805                 mainwin->toolbar->syl_action = g_slist_remove(mainwin->toolbar->syl_action, syl_action);
806                 if (syl_action->name)
807                         g_free(syl_action->name);
808                 g_free(syl_action);
809         }
810
811         g_slist_free(mainwin->toolbar->syl_action);
812 }
813
814 void toolbar_create(MainWindow *mainwin,
815                     GtkWidget *container)
816 {
817         ToolbarItem *toolbar_item;
818
819         GtkWidget *toolbar;
820         GtkWidget *icon_wid  = NULL;
821         GtkWidget *icon_news = NULL;
822         GtkWidget *item_news = NULL;
823         GtkWidget *item;
824         GtkTooltips *toolbar_tips;
825         ToolbarSylpheedActions *syl_action;
826         GSList *cur;
827
828         guint n_menu_entries;
829         GtkWidget *reply_popup;
830         GtkWidget *replyall_popup;
831         GtkWidget *replysender_popup;
832         GtkWidget *fwd_popup;
833
834         toolbar_tips = gtk_tooltips_new();
835
836         /* store mainwin localy */
837         mwin = mainwin;
838
839         if (mainwin->toolbar != NULL) {
840                 toolbar_destroy(mainwin);
841                 g_free(mainwin->toolbar);
842         }
843
844         toolbar_read_config_file();
845
846         mainwin->toolbar = g_new0(MainToolbar, 1); 
847
848         toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
849                                   GTK_TOOLBAR_BOTH);
850         gtk_container_add(GTK_CONTAINER(container), toolbar);
851         gtk_container_set_border_width(GTK_CONTAINER(container), 2);
852         gtk_toolbar_set_button_relief(GTK_TOOLBAR(toolbar), GTK_RELIEF_NONE);
853         gtk_toolbar_set_space_style(GTK_TOOLBAR(toolbar),
854                                     GTK_TOOLBAR_SPACE_LINE);
855         
856         for (cur = toolbar_list; cur != NULL; cur = cur->next) {
857                 toolbar_item  = (ToolbarItem*) cur->data;
858                 
859
860                 if (g_strcasecmp(toolbar_item->file, SEPARATOR) == 0) {
861                         gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
862                         continue;
863                 }
864
865                 icon_wid = stock_pixmap_widget(container, stock_pixmap_get_icon(toolbar_item->file));
866                 item  = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
867                                                 toolbar_item->text,
868                                                 (""),
869                                                 (""),
870                                                 icon_wid, toolbar_actions_cb, 
871                                                 toolbar_item);
872                 
873                 switch (toolbar_item->action) {
874                 case A_RECEIVE_ALL:
875                         mainwin->toolbar->getall_btn = item;
876                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
877                                              mainwin->toolbar->getall_btn, 
878                                            _("Receive Mail on all Accounts"), NULL);
879                         break;
880                 case A_RECEIVE_CUR:
881                         mainwin->toolbar->get_btn = item;
882                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
883                                              mainwin->toolbar->get_btn,
884                                            _("Receive Mail on current Account"), NULL);
885                         break;
886                 case A_SEND_QUEUED:
887                         mainwin->toolbar->send_btn = item; 
888                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
889                                              mainwin->toolbar->send_btn,
890                                            _("Send Queued Message(s)"), NULL);
891                         break;
892                 case A_COMPOSE_EMAIL:
893                         icon_news = stock_pixmap_widget(container, STOCK_PIXMAP_NEWS_COMPOSE);
894                         item_news = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
895                                                             _("News"),
896                                                             toolbar_ret_descr_from_val(A_COMPOSE_NEWS),
897                                                             (""),
898                                                             icon_news, toolbar_actions_cb, 
899                                                             toolbar_item);
900                         mainwin->toolbar->compose_mail_btn = item; 
901                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
902                                              mainwin->toolbar->compose_mail_btn,
903                                            _("Compose Email"), NULL);
904                         mainwin->toolbar->compose_news_btn = item_news;
905                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
906                                              mainwin->toolbar->compose_news_btn,
907                                            _("Compose News"), NULL);
908                         break;
909                 case A_REPLY_MESSAGE:
910                         mainwin->toolbar->reply_btn = item;
911                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
912                                              mainwin->toolbar->reply_btn,
913                                            _("Reply to Message"), NULL);
914                         gtk_signal_connect(GTK_OBJECT(mainwin->toolbar->reply_btn), 
915                                            "button_press_event",
916                                            GTK_SIGNAL_FUNC(toolbar_reply_popup_cb),
917                                            mainwin);
918                         n_menu_entries = sizeof(reply_popup_entries) /
919                                 sizeof(reply_popup_entries[0]);
920                         reply_popup = popupmenu_create(mainwin->window, reply_popup_entries, n_menu_entries,
921                                                        "<ReplyPopup>", mainwin);
922                         gtk_signal_connect(GTK_OBJECT(reply_popup), "selection_done",
923                                            GTK_SIGNAL_FUNC(toolbar_reply_popup_closed_cb), mainwin);
924                         mainwin->toolbar->reply_popup       = reply_popup;
925                         break;
926                 case A_REPLY_SENDER:
927                         mainwin->toolbar->replysender_btn = item;
928                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
929                                              mainwin->toolbar->replysender_btn,
930                                            _("Reply to Sender"), NULL);
931                         gtk_signal_connect(GTK_OBJECT(mainwin->toolbar->replysender_btn), 
932                                            "button_press_event",
933                                            GTK_SIGNAL_FUNC(toolbar_reply_to_sender_popup_cb),
934                                            mainwin);
935                         n_menu_entries = sizeof(replysender_popup_entries) /
936                                 sizeof(replysender_popup_entries[0]);
937                         replysender_popup = popupmenu_create(mainwin->window, 
938                                                              replysender_popup_entries, n_menu_entries,
939                                                              "<ReplySenderPopup>", mainwin);
940                         gtk_signal_connect(GTK_OBJECT(replysender_popup), "selection_done",
941                                            GTK_SIGNAL_FUNC(toolbar_reply_to_sender_popup_closed_cb), mainwin);
942                         mainwin->toolbar->replysender_popup = replysender_popup;
943                         break;
944                 case A_REPLY_ALL:
945                         mainwin->toolbar->replyall_btn = item;
946                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
947                                              mainwin->toolbar->replyall_btn,
948                                            _("Reply to All"), NULL);
949                         gtk_signal_connect(GTK_OBJECT(mainwin->toolbar->replyall_btn), 
950                                            "button_press_event",
951                                            GTK_SIGNAL_FUNC(toolbar_reply_to_all_popup_cb),
952                                            mainwin);
953                         n_menu_entries = sizeof(replyall_popup_entries) /
954                                 sizeof(replyall_popup_entries[0]);
955                         replyall_popup = popupmenu_create(mainwin->window, 
956                                                           replyall_popup_entries, n_menu_entries,
957                                                           "<ReplyAllPopup>", mainwin);
958                         gtk_signal_connect(GTK_OBJECT(replyall_popup), "selection_done",
959                                            GTK_SIGNAL_FUNC(toolbar_reply_to_all_popup_closed_cb), mainwin);
960                         mainwin->toolbar->replyall_popup    = replyall_popup;
961                         break;
962                 case A_FORWARD:
963                         mainwin->toolbar->fwd_btn = item;
964                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
965                                              mainwin->toolbar->fwd_btn,
966                                            _("Forward Message"), NULL);
967                         gtk_signal_connect(GTK_OBJECT(mainwin->toolbar->fwd_btn), 
968                                            "button_press_event",
969                                            GTK_SIGNAL_FUNC(toolbar_forward_popup_cb),
970                                            mainwin);
971                         n_menu_entries = sizeof(fwd_popup_entries) /
972                                 sizeof(fwd_popup_entries[0]);
973                         fwd_popup = popupmenu_create(mainwin->window, 
974                                                      fwd_popup_entries, n_menu_entries,
975                                                      "<ForwardPopup>", mainwin);
976                         gtk_signal_connect(GTK_OBJECT(fwd_popup), "selection_done",
977                                            GTK_SIGNAL_FUNC(toolbar_forward_popup_closed_cb), mainwin);
978                         mainwin->toolbar->fwd_popup         = fwd_popup;
979                         break;
980                 case A_DELETE:
981                         mainwin->toolbar->delete_btn = item;
982                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
983                                              mainwin->toolbar->delete_btn,
984                                            _("Delete Message"), NULL);
985                         break;
986                 case A_EXECUTE:
987                         mainwin->toolbar->exec_btn = item;
988                         break;
989                 case A_GOTO_NEXT:
990                         mainwin->toolbar->next_btn = item;
991                         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
992                                              mainwin->toolbar->next_btn,
993                                            _("Goto Next Message"), NULL);
994                         break;
995                 case A_SYL_ACTIONS:
996                         syl_action = g_new0(ToolbarSylpheedActions, 1);
997                         syl_action->widget = item;
998                         syl_action->name   = g_strdup(toolbar_item->text);
999
1000                         mainwin->toolbar->syl_action = g_slist_append(mainwin->toolbar->syl_action,
1001                                                                       syl_action);
1002                         gtk_widget_show(item);
1003                         break;
1004                 default:
1005                         break;
1006                 }
1007         }
1008
1009         mainwin->toolbar->toolbar = toolbar;
1010
1011         /* we always create an exec button, if there isn't one yet 
1012            the user might decide to change prefs_common.immediate_exec 
1013            --> better be prepared 
1014         */
1015         if (!mainwin->toolbar->exec_btn) {
1016                 toolbar_item = g_new0(ToolbarItem, 1);
1017                 toolbar_item->action = A_EXECUTE;
1018                 toolbar_item->file   = stock_pixmap_get_name(STOCK_PIXMAP_EXEC);
1019                 toolbar_item->text   = toolbar_ret_descr_from_val(A_EXECUTE);
1020
1021                 icon_wid = stock_pixmap_widget(container, STOCK_PIXMAP_EXEC);
1022                 item = gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
1023                                                toolbar_item->text,
1024                                                (""),
1025                                                (""),
1026                                                icon_wid, toolbar_actions_cb,
1027                                                toolbar_item);
1028                 mainwin->toolbar->exec_btn = item;
1029                 g_free(toolbar_item);
1030         }
1031
1032         gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tips), 
1033                              mainwin->toolbar->exec_btn,
1034                              _("Execute"), NULL);
1035
1036         activate_compose_button(mainwin->toolbar, 
1037                                 prefs_common.toolbar_style, 
1038                                 mainwin->toolbar->compose_btn_type);
1039
1040         gtk_widget_show_all(toolbar);
1041 }