f51eac2ada319cbb230d31f525ba37bbf1ca4076
[claws.git] / src / selective_download.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2002 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 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <gtk/gtk.h>
28 #include <gtk/gtkoptionmenu.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "intl.h"
34 #include "main.h"
35 #include "prefs.h"
36 #include "account.h"
37 #include "mainwindow.h"
38 #include "manage_window.h"
39 #include "menu.h"
40 #include "stock_pixmap.h"
41 #include "inc.h"
42 #include "utils.h"
43 #include "alertpanel.h"
44 #include "inc.h"
45 #include "filtering.h"
46 #include "matcher.h"
47 #include "procheader.h"
48 #include "selective_download.h"
49
50
51 static struct _SDView {
52         MainWindow *mainwin;
53
54         GtkWidget *window;
55         GtkWidget *clist;
56         GtkWidget *preview_btn;
57         GtkWidget *remove_btn;
58         GtkWidget *download_btn;
59         GtkWidget *ac_button;
60         GtkWidget *ac_label;
61         GtkWidget *ac_menu;
62         GtkWidget *preview_popup;
63         GtkWidget *msgs_label;
64         GtkWidget *show_old_chkbtn;
65
66 }selective;
67
68 /* clist pixmaps */
69 static GdkPixmap *checkboxonxpm;
70 static GdkBitmap *checkboxonxpmmask;
71 static GdkPixmap *checkboxoffxpm;
72 static GdkBitmap *checkboxoffxpmmask;
73 static GdkPixmap *markxpm;
74 static GdkBitmap *markxpmmask;
75 static GdkPixmap *deletedxpm;
76 static GdkBitmap *deletedxpmmask;
77
78 /* local functions */
79 static void sd_clear_msglist                    (void);
80 static void sd_remove_header_files              (void);
81 static void sd_toggle_btn                       (void);
82 static SD_State sd_header_filter                (MsgInfo        *msginfo);
83 static MsgInfo *sd_get_msginfo_from_file        (const gchar    *filename);
84
85 static void sd_clist_set_pixmap                 (HeaderItems    *items,
86                                                  gint            row);
87 static void sd_clist_get_items                  (void);
88 static void sd_clist_set_items                  (void);
89 static void sd_update_msg_num                   (PrefsAccount   *acc);
90
91 enum {
92         PREVIEW_NEW,
93         PREVIEW_ALL,
94         REMOVE,
95         DOWNLOAD,
96         DONE,
97         CHECKBTN,
98 };
99
100 /* callbacks */
101 static void sd_action_cb        (GtkWidget      *widget,
102                                  guint           action);
103
104 static void sd_select_row_cb    (GtkCList       *clist,
105                                  gint            row,
106                                  gint            column,
107                                  GdkEvent       *event,
108                                  gpointer        user_data);
109 static gint sd_key_pressed      (GtkWidget      *widget,
110                                  GdkEventKey    *event,
111                                  gpointer        data);
112 static gint sd_delete_event_cb  (GtkWidget      *widget, 
113                                  GdkEvent       *event,
114                                  gpointer        data);
115
116 /* account menu */
117 static gint sd_ac_label_pressed         (GtkWidget      *widget, 
118                                          GdkEventButton *event,
119                                          gpointer        data);
120
121 static void sd_ac_menu_popup_closed     (GtkMenuShell   *menu_shell);
122 static void sd_ac_menu_cb               (GtkMenuItem    *menuitem,
123                                          gpointer        data);
124 static void sd_ac_menu_set              (void);
125
126 /* preview popup */
127 static void sd_preview_popup_closed     (GtkMenuShell   *menu_shell);
128 static gint sd_preview_popup_cb         (GtkWidget      *widget,
129                                          GdkEventButton *event,
130                                          gpointer        data);
131
132 static GtkItemFactoryEntry preview_popup_entries[] =
133 {
134         {N_("/Preview _new messages"), NULL, sd_action_cb, PREVIEW_NEW, NULL},
135         {N_("/Preview _all messages"), NULL, sd_action_cb, PREVIEW_ALL, NULL}
136 };
137
138 /* create dialog */
139 static void sd_window_create    (MainWindow     *mainwin);
140 static void sd_create_toolbar   (MainWindow     *mainwin,
141                                  GtkWidget      *container);
142
143 /* pixmaps */
144 void sd_init_pixmaps            (MainWindow     *mainwin);
145
146 void selective_download(MainWindow *mainwin)
147 {
148         summary_write_cache(mainwin->summaryview);
149
150         sd_remove_header_files();
151         
152         inc_lock();
153         
154         if (!selective.window) {
155                 sd_init_pixmaps(mainwin);
156                 sd_window_create(mainwin);
157         }
158
159         manage_window_set_transient(GTK_WINDOW(selective.window));
160         gtk_widget_show(selective.window);
161         sd_clear_msglist();
162         sd_ac_menu_set();
163         gtk_clist_clear(GTK_CLIST(selective.clist));
164 }
165
166 void sd_init_pixmaps(MainWindow *mainwin)
167 {
168         GtkWidget *widget = mainwin->window;
169
170         g_return_if_fail(mainwin != NULL);
171
172         /* clist pixmaps */
173         stock_pixmap_gdk(widget, STOCK_PIXMAP_CHECKBOX_OFF,
174                          &checkboxoffxpm, &checkboxoffxpmmask);
175         stock_pixmap_gdk(widget, STOCK_PIXMAP_CHECKBOX_ON,
176                          &checkboxonxpm, &checkboxonxpmmask);
177         stock_pixmap_gdk(widget, STOCK_PIXMAP_DELETED,
178                          &deletedxpm, &deletedxpmmask);
179         stock_pixmap_gdk(widget, STOCK_PIXMAP_MARK,
180                          &markxpm, &markxpmmask);
181 }
182
183 void sd_reflect_prefs_pixmap_theme()
184 {
185         if (selective.window) 
186                 selective.window = NULL;
187 }
188
189 static void sd_clear_msglist()
190 {
191         PrefsAccount *acc = cur_account;
192         while (acc->msg_list != NULL) {
193                 HeaderItems *item = (HeaderItems*)acc->msg_list->data;
194
195                 acc->msg_list = g_slist_remove(acc->msg_list, item);
196                 g_free(item->from);
197                 g_free(item->subject);
198                 g_free(item->date);
199                 g_free(item);
200         }       
201         g_slist_free(acc->msg_list);
202         sd_update_msg_num(acc);
203 }
204
205 /* sd_remove_header_files()
206  * 
207  * - removes any stale header files in HEADER_CACHE_DIR 
208  *
209  */
210 static void sd_remove_header_files()
211 {
212         gchar *path = g_strconcat(get_header_cache_dir(), G_DIR_SEPARATOR_S, NULL);
213         
214         remove_all_files(path);
215         g_free(path);
216 }
217
218 /* sd_toggle_btn()
219  *
220  * - checks whether at least on email is selected 
221  *   if so, untoggle remove / download button
222  */
223 static void sd_toggle_btn()
224 {
225         PrefsAccount *acc = cur_account;
226         GSList *cur;
227         
228         for (cur = acc->msg_list; cur != NULL; cur = cur->next) {
229                 HeaderItems *items = (HeaderItems*)cur->data;
230                 
231                 if (items->state == SD_CHECKED) {
232                         gtk_widget_set_sensitive (selective.remove_btn, TRUE);
233                         gtk_widget_set_sensitive (selective.download_btn, TRUE);
234                         return;
235                 }
236         }
237
238         gtk_widget_set_sensitive (selective.remove_btn, FALSE);
239 }
240
241 /* sd_header_filter(MsgInfo *msginfo)
242  *
243  * - parse header line and look for any applying filtering rules
244  * - if message matches other MATCHACTION --> return
245  *
246  */
247 SD_State sd_header_filter(MsgInfo *msginfo)
248 {
249         GSList *rules;
250
251         /* parse header line for line */
252         for (rules = global_processing; rules != NULL; rules = rules->next) { 
253
254                 FilteringProp *prop = (FilteringProp*) rules->data; 
255
256                 if ( matcherlist_match(prop->matchers, msginfo) ) {
257                         if (prop->action->type == MATCHACTION_DELETE_ON_SERVER) {
258                                 debug_print(_("action matched\n"));
259                                 return SD_CHECKED;
260                         }
261                         else {
262                                 debug_print(_("action not matched\n"));
263                                 return SD_UNCHECKED;
264                         }
265                 }
266         }
267         return SD_UNCHECKED;
268 }
269
270 /* sd_get_msginfo_from_file(const gchar *filename)
271  *
272  * - retrieve msginfo from saved header files
273  */
274 static MsgInfo *sd_get_msginfo_from_file(const gchar *filename)
275 {
276         MsgInfo  *msginfo;
277         MsgFlags  msgflags = { 0, 0 };
278         gchar     date[80];
279
280         msginfo = procheader_parse_file(filename, msgflags, TRUE, FALSE);
281
282         if (msginfo && msginfo->date_t) {
283                 procheader_date_get_localtime(date, sizeof date, msginfo->date_t);
284                 if (msginfo->date) g_free(msginfo->date);
285                 msginfo->date = g_strdup(date);
286         } 
287
288         if (!msginfo)
289                 msginfo = g_new0(MsgInfo, 1);
290
291         if (!msginfo->date) 
292                 msginfo->date = g_strdup(_("(No date)"));
293         if (!msginfo->from)
294                 msginfo->from = g_strdup(_("(No sender)"));
295         if (!msginfo->subject)
296                 msginfo->subject = g_strdup(_("(No subject)"));
297                 
298         return msginfo;
299 }
300
301 static void sd_clist_set_pixmap(HeaderItems *items, gint row)
302 {
303         
304         switch (items->state) {
305         case SD_REMOVED:
306                 gtk_clist_set_pixmap (GTK_CLIST (selective.clist), 
307                                       row, 0,
308                                      deletedxpm, deletedxpmmask);
309                 break;
310         case SD_CHECKED:
311                 gtk_clist_set_pixmap (GTK_CLIST (selective.clist), 
312                                       row, 0,
313                                       checkboxonxpm, checkboxonxpmmask);
314                 break;
315         case SD_DOWNLOADED:
316                 gtk_clist_set_pixmap (GTK_CLIST (selective.clist), 
317                                       row, 0,
318                                       markxpm, markxpmmask);
319                 break;          
320         default:
321                 gtk_clist_set_pixmap (GTK_CLIST (selective.clist), 
322                                       row, 0,
323                                       checkboxoffxpm, checkboxoffxpmmask);
324                 break;
325         }
326 }
327
328 static void sd_clist_set_items()
329 {
330         PrefsAccount *acc = cur_account;
331         GSList *cur;
332         gboolean show_old = 
333                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(selective.show_old_chkbtn));
334         
335         gtk_clist_clear(GTK_CLIST(selective.clist));
336         gtk_clist_freeze(GTK_CLIST(selective.clist));
337
338         for (cur = acc->msg_list; cur != NULL; cur = cur->next) {
339                 HeaderItems *items = (HeaderItems*)cur->data;
340                 gchar *row[5];
341                 gint row_num;
342                 
343                 row[0] = ("");
344                 row[1] = items->from;
345                 row[2] = items->subject;
346                 row[3] = items->date;
347                 row[4] = g_strdup_printf("%i KB", items->size/1024);
348                 
349                 switch (items->state) {
350                 case SD_REMOVED:
351                 case SD_DOWNLOADED:
352                         items->del_by_old_session = TRUE;
353                 default:
354                         break;
355                 }
356                 if (show_old) {
357                         if (items->received) {
358                                 row_num = gtk_clist_append(GTK_CLIST(selective.clist), row);
359                                 sd_clist_set_pixmap(items, row_num);
360                         }
361                 }
362                 else {
363                         row_num = gtk_clist_append(GTK_CLIST(selective.clist), row);
364                         sd_clist_set_pixmap(items, row_num);
365                 }
366                 g_free(row[4]);
367         }
368
369         gtk_clist_thaw(GTK_CLIST(selective.clist));
370         sd_toggle_btn();
371 }
372
373 /* sd_update_msg_num(PrefsAccount *acc)
374  * - keep track of msgs still on server
375  * - count UNCHECKED items as well as downloaded but not removed
376  */
377 static void sd_update_msg_num(PrefsAccount *acc)
378 {
379         GSList *cur;
380         gint msg_num = g_slist_length(acc->msg_list);
381         gchar *text;
382
383         for (cur = acc->msg_list; cur != NULL; cur = cur->next) {
384                 HeaderItems *items = (HeaderItems*) cur->data;
385
386                 if (items->state != SD_UNCHECKED)
387                         msg_num--;
388                 if (items->state == SD_DOWNLOADED)
389                         if (!acc->sd_rmmail_on_download)
390                                 msg_num++;
391         }
392
393         text = g_strdup_printf("%i Messages", msg_num);
394         gtk_label_set_text(GTK_LABEL(selective.msgs_label), text);
395
396         g_free(text);
397 }
398
399 /* sd_clist_get_items()
400  *
401  * - get items for clist from Files
402  */
403 static void sd_clist_get_items(void)
404 {
405         GSList *cur;
406         PrefsAccount *acc = cur_account;
407         gchar *path = g_strconcat(get_header_cache_dir(), G_DIR_SEPARATOR_S, NULL);
408         
409         for (cur = acc->msg_list; cur != NULL; cur = cur->next) {
410
411                 HeaderItems *items = (HeaderItems*) cur->data;
412                 gchar *filename    = g_strdup_printf("%s%i", path, items->index);
413                 MsgInfo *msginfo   = sd_get_msginfo_from_file(filename);
414                 
415                 items->from        = g_strdup(msginfo->from);
416                 items->subject     = g_strdup(msginfo->subject);
417                 items->date        = g_strdup(msginfo->date);
418                 
419                 msginfo->folder = folder_get_default_processing();
420
421                 /* move msg file to drop folder */
422                 if ((msginfo->msgnum = folder_item_add_msg(msginfo->folder, 
423                                                            filename, TRUE)) < 0) {
424                         unlink(filename);
425                         return;
426                 }
427                 
428                 if (acc->sd_filter_on_recv)
429                         items->state = sd_header_filter(msginfo);
430
431                 folder_item_remove_msg(msginfo->folder, msginfo->msgnum);
432                 g_free(filename);
433                 procmsg_msginfo_free(msginfo);
434         }
435
436         g_free(path);
437 }
438
439 /* --- Callbacks -- */
440 static void sd_action_cb(GtkWidget *widget, guint action)
441 {
442         PrefsAccount *acc = cur_account;
443         
444         switch(action) {
445         case PREVIEW_NEW:
446         case PREVIEW_ALL:
447                 if ( (acc->protocol != A_APOP) &&
448                      (acc->protocol != A_POP3) ) {
449                         alertpanel_error(
450                                 _("Selected account \"%s\" is not a POP mail server.\nPlease select a different account"), acc->account_name);
451                         return;
452                 }
453                 sd_clear_msglist();
454                 if (action == PREVIEW_NEW) {
455                         gtk_widget_set_sensitive(selective.show_old_chkbtn, FALSE);
456                         inc_selective_download(selective.mainwin, acc, STYPE_PREVIEW_NEW);
457                 }
458                 else {
459                         gtk_widget_set_sensitive(selective.show_old_chkbtn, TRUE);
460                         inc_selective_download(selective.mainwin, acc, STYPE_PREVIEW_ALL);
461                 }
462                 
463                 gtk_clist_clear(GTK_CLIST(selective.clist));
464                 sd_clist_get_items();   
465                 sd_clist_set_items();
466                 break;
467         case REMOVE:
468                 inc_selective_download(selective.mainwin, acc, STYPE_DELETE);
469                 sd_clist_set_items();
470                 break;
471         case DOWNLOAD:
472                 inc_selective_download(selective.mainwin, acc, STYPE_DOWNLOAD);
473                 sd_clist_set_items();
474                 break;
475         case DONE:
476                 sd_remove_header_files();
477                 sd_clear_msglist();
478                 gtk_widget_hide(selective.window);
479                 inc_unlock();
480                 break;
481         case CHECKBTN:
482                 sd_clist_set_items();
483                 break;
484         default:
485                 break;
486         }
487         
488         sd_update_msg_num(acc);
489 }
490
491 /* Events */
492 static void sd_select_row_cb(GtkCList *clist, gint row, gint column,
493                              GdkEvent *event, gpointer user_data)
494 {
495         if ((row >= 0) && (column >= 0)) {
496                 PrefsAccount *acc  = cur_account;
497                 HeaderItems *items = (HeaderItems*) g_slist_nth_data (acc->msg_list, row);
498
499                 if (!items) return;
500                 if (!gtk_clist_get_selectable(GTK_CLIST(selective.clist), row)) return;
501
502                 if (items->state == SD_UNCHECKED) {
503                         items->state = SD_CHECKED;
504                         gtk_clist_set_pixmap (GTK_CLIST (selective.clist), row, 0,
505                                               checkboxonxpm, checkboxonxpmmask);
506                 } else if (items->state == SD_CHECKED) {
507                         items->state = SD_UNCHECKED;
508                         gtk_clist_set_pixmap (GTK_CLIST (selective.clist), row, 0,
509                                               checkboxoffxpm, checkboxoffxpmmask);
510                 }
511                 sd_toggle_btn();
512         }
513 }
514
515 static gint sd_key_pressed(GtkWidget *widget,
516                            GdkEventKey *event,
517                            gpointer data)
518 {
519         if (event && event->keyval == GDK_Escape) {
520                 sd_action_cb(widget, DONE);
521                 return TRUE;
522         }
523         return FALSE;
524 }
525
526 static gint sd_delete_event_cb(GtkWidget *widget, 
527                               GdkEvent *event,
528                               gpointer data)
529 {
530         sd_action_cb(widget, DONE);
531         return TRUE;
532 }
533
534 /* account menu */
535 static gint sd_ac_label_pressed(GtkWidget *widget, GdkEventButton *event,
536                                     gpointer data)
537 {
538         if (!event) return FALSE;
539
540         gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
541         gtk_object_set_data(GTK_OBJECT(selective.ac_menu), "menu_button",
542                             widget);
543
544         gtk_menu_popup(GTK_MENU(selective.ac_menu), NULL, NULL,
545                        menu_button_position, widget,
546                        event->button, event->time);
547         return TRUE;
548 }
549
550 static void sd_ac_menu_popup_closed(GtkMenuShell *menu_shell)
551 {
552         GtkWidget *button;
553
554         button = gtk_object_get_data(GTK_OBJECT(menu_shell), "menu_button");
555         if (!button) return;
556         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
557         gtk_clist_clear(GTK_CLIST(selective.clist));
558         sd_clear_msglist();
559         sd_toggle_btn();
560         gtk_object_remove_data(GTK_OBJECT(selective.ac_menu), "menu_button");
561 }
562
563 static void sd_ac_menu_cb(GtkMenuItem *menuitem, gpointer data)
564 {
565         cur_account = (PrefsAccount *)data;
566         gtk_label_set_text(GTK_LABEL(selective.ac_label), cur_account->account_name);
567         gtk_widget_queue_resize(selective.ac_button);
568         main_window_reflect_prefs_all();
569 }
570
571 static void sd_ac_menu_set()
572 {
573         GList *cur_ac, *cur_item;
574         GtkWidget *menuitem;
575         PrefsAccount *ac_prefs;
576         GList *account_list = account_get_list();
577
578         /* destroy all previous menu item */
579         cur_item = GTK_MENU_SHELL(selective.ac_menu)->children;
580         while (cur_item != NULL) {
581                 GList *next = cur_item->next;
582                 gtk_widget_destroy(GTK_WIDGET(cur_item->data));
583                 cur_item = next;
584         }
585
586         gtk_label_set_text(GTK_LABEL(selective.ac_label), cur_account->account_name);
587
588         for (cur_ac = account_list; cur_ac != NULL; cur_ac = cur_ac->next) {
589                 ac_prefs = (PrefsAccount *)cur_ac->data;
590                 
591                 menuitem = gtk_menu_item_new_with_label
592                         (ac_prefs->account_name
593                          ? ac_prefs->account_name : _("Untitled"));
594                 gtk_widget_show(menuitem);
595                 gtk_menu_append(GTK_MENU(selective.ac_menu), menuitem);
596                 gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
597                                            GTK_SIGNAL_FUNC(sd_ac_menu_cb),
598                                            ac_prefs);
599         }
600 }
601
602 /* receive button popup */
603 static void sd_preview_popup_closed(GtkMenuShell *menu_shell)
604 {
605         gtk_button_set_relief(GTK_BUTTON(selective.preview_btn), GTK_RELIEF_NORMAL);
606         manage_window_focus_in(selective.window, NULL, NULL);
607 }
608
609 static gint sd_preview_popup_cb(GtkWidget *widget, GdkEventButton *event,
610                                 gpointer data)
611 {
612         if (!event) return FALSE;
613         
614         if (event->button == 1) {
615                 gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NORMAL);
616                 gtk_menu_popup(GTK_MENU(selective.preview_popup), NULL, NULL,
617                        menu_button_position, widget,
618                        event->button, event->time);
619                 return TRUE;
620         }
621         return FALSE;
622 }
623
624 static void sd_create_toolbar(MainWindow *mainwin, GtkWidget *container)
625 {
626         GtkWidget *toolbar;
627         GtkWidget *tmp_toolbar_icon;
628         GtkWidget *preview_btn;
629         GtkWidget *remove_btn;
630         GtkWidget *download_btn;
631         GtkWidget *done_btn;
632         GtkWidget *preview_popup;
633         gint n_menu_entries;
634
635         toolbar = gtk_toolbar_new (GTK_ORIENTATION_VERTICAL, GTK_TOOLBAR_BOTH);
636
637         gtk_container_add (GTK_CONTAINER(container), toolbar);
638         gtk_container_set_border_width (GTK_CONTAINER(container), 2);
639
640         gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 30);
641         gtk_toolbar_set_space_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_SPACE_LINE);
642         
643         tmp_toolbar_icon = stock_pixmap_widget (container, STOCK_PIXMAP_MAIL_RECEIVE);
644         preview_btn = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
645                                                   GTK_TOOLBAR_CHILD_BUTTON,
646                                                   NULL,
647                                                   _("Preview mail"),
648                                                   _("Preview old/new mail on account"), NULL,
649                                                   tmp_toolbar_icon, NULL, NULL);
650
651         n_menu_entries = sizeof (preview_popup_entries)/sizeof (preview_popup_entries[0]);
652         preview_popup = popupmenu_create (preview_btn, preview_popup_entries, n_menu_entries,
653                                       "<SelectiveDownload>", mainwin);
654
655         gtk_signal_connect (GTK_OBJECT(preview_popup), "selection_done",
656                             GTK_SIGNAL_FUNC(sd_preview_popup_closed), NULL);
657
658         gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
659         
660         tmp_toolbar_icon = stock_pixmap_widget (container, STOCK_PIXMAP_CLOSE);
661         remove_btn = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
662                                                  GTK_TOOLBAR_CHILD_BUTTON,
663                                                  NULL,
664                                                  _("Remove"),
665                                                  _("Remove selected mail"), NULL,
666                                                  tmp_toolbar_icon, NULL, NULL);
667
668         gtk_widget_set_sensitive (remove_btn, FALSE);
669
670         tmp_toolbar_icon = stock_pixmap_widget(container, STOCK_PIXMAP_DOWN_ARROW);
671         download_btn = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
672                                                    GTK_TOOLBAR_CHILD_BUTTON,
673                                                    NULL,
674                                                    _("Download"),
675                                                    _("Download selected mail"), NULL,
676                                                    tmp_toolbar_icon, NULL, NULL);
677
678         gtk_widget_set_sensitive (download_btn, FALSE);
679
680         gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
681
682         tmp_toolbar_icon = stock_pixmap_widget (container, STOCK_PIXMAP_COMPLETE);
683         
684         done_btn = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
685                                                GTK_TOOLBAR_CHILD_BUTTON,
686                                                NULL, 
687                                                _("Done"),
688                                                _("Exit dialog"), NULL ,
689                                                tmp_toolbar_icon, NULL, NULL);
690
691         gtk_signal_connect (GTK_OBJECT (preview_btn), "button_press_event",
692                             GTK_SIGNAL_FUNC (sd_preview_popup_cb),
693                             NULL);
694         gtk_signal_connect (GTK_OBJECT (remove_btn), "clicked",
695                             GTK_SIGNAL_FUNC (sd_action_cb),
696                             GUINT_TO_POINTER(REMOVE));
697         gtk_signal_connect (GTK_OBJECT (download_btn), "clicked",
698                             GTK_SIGNAL_FUNC (sd_action_cb),
699                             GUINT_TO_POINTER(DOWNLOAD));
700         gtk_signal_connect (GTK_OBJECT (done_btn), "clicked",
701                             GTK_SIGNAL_FUNC (sd_action_cb),
702                             GUINT_TO_POINTER(DONE));
703
704         selective.preview_btn     = preview_btn;
705         selective.remove_btn      = remove_btn;
706         selective.download_btn    = download_btn;
707         selective.preview_popup   = preview_popup;
708
709 }
710
711 static void sd_window_create(MainWindow *mainwin)
712 {
713         GtkWidget *window;
714         GtkWidget *table;
715         GtkWidget *msgs_label;
716         GtkWidget *bottom_hbox;
717         GtkWidget *fixed_label;
718         GtkWidget *expand_label;
719         GtkWidget *ac_button;
720         GtkWidget *ac_label;
721         GtkWidget *ac_menu;
722         GtkWidget *show_old_chkbtn;
723         GtkWidget *scrolledwindow;
724         GtkWidget *clist;
725         GtkWidget *state_label;
726         GtkWidget *from_label;
727         GtkWidget *subject_label;
728         GtkWidget *size_label;
729         GtkWidget *date_label;
730         GtkWidget *toolbar_hbox;
731
732         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
733         gtk_object_set_data (GTK_OBJECT (window), "window", window);
734         gtk_window_set_title (GTK_WINDOW (window), _("Selective download"));
735         gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
736         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
737         gtk_window_set_policy (GTK_WINDOW (window), TRUE, TRUE, TRUE);
738         /* avoids GDK warning (pixmap with NULL window) */ 
739         gtk_widget_realize (window);
740
741         table = gtk_table_new (2, 2, FALSE);
742         gtk_container_add (GTK_CONTAINER (window), table);
743
744         msgs_label = gtk_label_new (_("0 messages"));
745         gtk_table_attach (GTK_TABLE (table), msgs_label, 1, 2, 1, 2,
746                           (GtkAttachOptions) (GTK_FILL),
747                           (GtkAttachOptions) (0), 0, 0);
748         gtk_misc_set_alignment (GTK_MISC (msgs_label), 0, 0.5);
749
750         bottom_hbox = gtk_hbox_new (FALSE, 0);
751         gtk_table_attach (GTK_TABLE (table), bottom_hbox, 0, 1, 1, 2,
752                           (GtkAttachOptions) (GTK_FILL),
753                           (GtkAttachOptions) (GTK_FILL), 0, 0);
754
755         show_old_chkbtn = gtk_check_button_new_with_label("Show only old messages");
756         gtk_box_pack_start (GTK_BOX(bottom_hbox), show_old_chkbtn, FALSE, FALSE, 0);
757
758         gtk_signal_connect (GTK_OBJECT(show_old_chkbtn), "toggled",
759                             GTK_SIGNAL_FUNC(sd_action_cb), GUINT_TO_POINTER(CHECKBTN));
760         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(show_old_chkbtn), FALSE);
761         GTK_WIDGET_UNSET_FLAGS (show_old_chkbtn, GTK_CAN_FOCUS);
762
763         expand_label = gtk_label_new (" ");
764         gtk_box_pack_start (GTK_BOX (bottom_hbox), expand_label, TRUE, TRUE, 0);
765         
766         fixed_label = gtk_label_new (_(" contains "));
767         gtk_box_pack_end (GTK_BOX (bottom_hbox), fixed_label, FALSE, FALSE, 0);
768
769         ac_menu = gtk_menu_new();
770         gtk_signal_connect (GTK_OBJECT(ac_menu), "selection_done",
771                             GTK_SIGNAL_FUNC(sd_ac_menu_popup_closed), NULL);
772         ac_button = gtk_button_new();
773         gtk_button_set_relief (GTK_BUTTON(ac_button), GTK_RELIEF_NONE);
774         GTK_WIDGET_UNSET_FLAGS (ac_button, GTK_CAN_FOCUS);
775         gtk_widget_set_usize (ac_button, -1, 1);
776         gtk_box_pack_start (GTK_BOX(bottom_hbox), ac_button, FALSE, FALSE, 0);
777         gtk_signal_connect (GTK_OBJECT(ac_button), "button_press_event",
778                             GTK_SIGNAL_FUNC(sd_ac_label_pressed), GTK_OBJECT(ac_menu));
779
780         ac_label = gtk_label_new("");
781         gtk_container_add (GTK_CONTAINER(ac_button), ac_label);
782
783         scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
784         gtk_table_attach (GTK_TABLE (table), scrolledwindow, 0, 1, 0, 1,
785                           (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
786                           (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
787         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), 
788                                         GTK_POLICY_NEVER, 
789                                         GTK_POLICY_AUTOMATIC);
790         
791         clist = gtk_clist_new (5);
792         gtk_container_add (GTK_CONTAINER (scrolledwindow), clist);
793         gtk_container_set_border_width (GTK_CONTAINER (clist), 5);
794         gtk_clist_set_column_width (GTK_CLIST (clist), 0, 20);
795         gtk_clist_set_column_width (GTK_CLIST (clist), 1, 150);
796         gtk_clist_set_column_width (GTK_CLIST (clist), 2, 150);
797         gtk_clist_set_column_width (GTK_CLIST (clist), 3, 100);
798         gtk_clist_set_column_width (GTK_CLIST (clist), 4, 30);
799         gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE);
800         gtk_clist_column_titles_show (GTK_CLIST (clist));
801         
802         state_label = gtk_label_new (_("#"));
803         gtk_clist_set_column_widget (GTK_CLIST (clist), 0, state_label);
804         
805         from_label = gtk_label_new (_("From"));
806         gtk_clist_set_column_widget (GTK_CLIST (clist), 1, from_label);
807
808         subject_label = gtk_label_new (_("Subject"));
809         gtk_clist_set_column_widget (GTK_CLIST (clist), 2, subject_label);
810         
811         date_label = gtk_label_new (_("Date"));
812         gtk_clist_set_column_widget (GTK_CLIST (clist), 3, date_label);
813
814         size_label = gtk_label_new (_("Size"));
815         gtk_widget_ref (size_label);
816         gtk_clist_set_column_widget (GTK_CLIST (clist), 4, size_label);
817         
818         /* create toolbar */
819         toolbar_hbox = gtk_hbox_new (FALSE, 0);
820
821         gtk_table_attach (GTK_TABLE (table), toolbar_hbox, 1, 2, 0, 1,
822                           (GtkAttachOptions) (GTK_FILL),
823                           (GtkAttachOptions) (GTK_FILL), 0, 0);
824         sd_create_toolbar(mainwin, toolbar_hbox);
825
826
827         gtk_signal_connect (GTK_OBJECT (window), "delete_event",
828                             GTK_SIGNAL_FUNC (sd_delete_event_cb),
829                             NULL);
830         gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
831                             GTK_SIGNAL_FUNC(sd_key_pressed),
832                             NULL);
833         MANAGE_WINDOW_SIGNALS_CONNECT (window);
834
835         gtk_signal_connect (GTK_OBJECT (clist), "select_row",
836                             GTK_SIGNAL_FUNC (sd_select_row_cb),
837                             NULL);
838
839         selective.mainwin         = mainwin;
840         selective.window          = window;
841         selective.clist           = clist;
842         selective.ac_label        = ac_label;
843         selective.ac_button       = ac_button;
844         selective.ac_menu         = ac_menu;
845         selective.msgs_label      = msgs_label;
846         selective.show_old_chkbtn = show_old_chkbtn;
847
848         gtk_widget_show_all(window);
849 }