2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
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.
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.
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.
28 #include <gdk/gdkkeysyms.h>
37 #include "prefs_headers.h"
38 #include "prefs_common.h"
39 #include "prefs_account.h"
40 #include "mainwindow.h"
41 #include "foldersel.h"
42 #include "manage_window.h"
43 #include "customheader.h"
46 #include "alertpanel.h"
49 static struct Headers {
57 GtkWidget *headers_clist;
61 parameter name, default value, pointer to the prefs variable, data type,
62 pointer to the widget pointer,
63 pointer to the function for data setting,
64 pointer to the function for widget setting
68 #define VSPACING_NARROW 4
69 #define DEFAULT_ENTRY_WIDTH 80
70 #define PREFSBUFSIZE 1024
72 /* widget creating functions */
73 static void prefs_headers_create (void);
75 static void prefs_headers_set_dialog (PrefsAccount * ac);
76 static void prefs_headers_set_list (PrefsAccount * ac);
77 static gint prefs_headers_clist_set_row (PrefsAccount * ac,
80 /* callback functions */
81 static void prefs_headers_select_dest_cb (void);
82 static void prefs_headers_register_cb (void);
83 static void prefs_headers_substitute_cb (void);
84 static void prefs_headers_delete_cb (void);
85 static void prefs_headers_up (void);
86 static void prefs_headers_down (void);
87 static void prefs_headers_select (GtkCList *clist,
92 static void prefs_headers_dest_radio_button_toggled (void);
93 static void prefs_headers_notrecv_radio_button_toggled (void);
95 static void prefs_headers_key_pressed (GtkWidget *widget,
98 static void prefs_headers_close (GtkButton *button);
100 static PrefsAccount * cur_ac = NULL;
102 void prefs_headers_open(PrefsAccount * ac)
104 if (!headers.window) {
105 prefs_headers_create();
108 manage_window_set_transient(GTK_WINDOW(headers.window));
109 gtk_widget_grab_focus(headers.close_btn);
111 prefs_headers_set_dialog(ac);
115 gtk_widget_show(headers.window);
118 static void prefs_headers_create(void)
122 GtkWidget *close_btn;
123 GtkWidget *confirm_area;
128 GtkWidget *hdr_label;
129 GtkWidget *hdr_combo;
130 GtkWidget *key_label;
131 GtkWidget *key_entry;
137 GtkWidget *subst_btn;
141 GtkWidget *ch_scrolledwin;
142 GtkWidget *headers_clist;
148 gchar *title[] = {_("Custom headers")};
150 debug_print(_("Creating headers setting window...\n"));
152 window = gtk_window_new (GTK_WINDOW_DIALOG);
153 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
154 gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
155 gtk_window_set_modal (GTK_WINDOW (window), TRUE);
156 gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
158 vbox = gtk_vbox_new (FALSE, 6);
159 gtk_widget_show (vbox);
160 gtk_container_add (GTK_CONTAINER (window), vbox);
162 gtkut_button_set_create (&confirm_area, &close_btn, _("Close"),
163 NULL, NULL, NULL, NULL);
164 gtk_widget_show (confirm_area);
165 gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
166 gtk_widget_grab_default (close_btn);
168 gtk_window_set_title (GTK_WINDOW(window),
169 _("Headers setting"));
170 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
171 GTK_SIGNAL_FUNC(gtk_widget_hide_on_delete), NULL);
172 gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
173 GTK_SIGNAL_FUNC(prefs_headers_key_pressed), NULL);
174 gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
175 GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
176 gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
177 GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
178 gtk_signal_connect (GTK_OBJECT(close_btn), "clicked",
179 GTK_SIGNAL_FUNC(prefs_headers_close), NULL);
181 vbox1 = gtk_vbox_new (FALSE, VSPACING);
182 gtk_widget_show (vbox1);
183 gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
184 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
186 table1 = gtk_table_new (2, 2, FALSE);
187 gtk_widget_show (table1);
188 gtk_box_pack_start (GTK_BOX (vbox1), table1,
190 gtk_table_set_row_spacings (GTK_TABLE (table1), 8);
191 gtk_table_set_col_spacings (GTK_TABLE (table1), 8);
193 hdr_label = gtk_label_new (_("Header"));
194 gtk_widget_show (hdr_label);
195 gtk_table_attach (GTK_TABLE (table1), hdr_label, 0, 1, 0, 1,
196 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
198 gtk_misc_set_alignment (GTK_MISC (hdr_label), 0, 0.5);
200 hdr_combo = gtk_combo_new ();
201 gtk_widget_show (hdr_combo);
202 gtk_table_attach (GTK_TABLE (table1), hdr_combo, 0, 1, 1, 2,
203 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
205 gtk_widget_set_usize (hdr_combo, 150 /* 96 */, -1);
206 gtkut_combo_set_items (GTK_COMBO (hdr_combo),
207 "User-Agent", "X-Operating-System", NULL);
209 key_label = gtk_label_new (_("Value"));
210 gtk_widget_show (key_label);
211 gtk_table_attach (GTK_TABLE (table1), key_label, 1, 2, 0, 1,
212 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
214 gtk_misc_set_alignment (GTK_MISC (key_label), 0, 0.5);
216 key_entry = gtk_entry_new ();
217 gtk_widget_show (key_entry);
218 gtk_table_attach (GTK_TABLE (table1), key_entry, 1, 2, 1, 2,
219 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
222 /* register / substitute / delete */
224 reg_hbox = gtk_hbox_new (FALSE, 4);
225 gtk_widget_show (reg_hbox);
226 gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox,
229 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
230 gtk_widget_show (arrow);
231 gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
232 gtk_widget_set_usize (arrow, -1, 16);
234 btn_hbox = gtk_hbox_new (TRUE, 4);
235 gtk_widget_show (btn_hbox);
236 gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
238 reg_btn = gtk_button_new_with_label (_("Add"));
239 gtk_widget_show (reg_btn);
240 gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
241 gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
242 GTK_SIGNAL_FUNC (prefs_headers_register_cb), NULL);
244 subst_btn = gtk_button_new_with_label (_(" Substitute "));
245 gtk_widget_show (subst_btn);
246 gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
247 gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
248 GTK_SIGNAL_FUNC (prefs_headers_substitute_cb),
251 del_btn = gtk_button_new_with_label (_("Delete"));
252 gtk_widget_show (del_btn);
253 gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
254 gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
255 GTK_SIGNAL_FUNC (prefs_headers_delete_cb), NULL);
258 ch_hbox = gtk_hbox_new (FALSE, 8);
259 gtk_widget_show (ch_hbox);
260 gtk_box_pack_start (GTK_BOX (vbox1), ch_hbox,
263 ch_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
264 gtk_widget_set_usize (ch_scrolledwin, -1, 100);
265 gtk_widget_show (ch_scrolledwin);
266 gtk_box_pack_start (GTK_BOX (ch_hbox), ch_scrolledwin,
268 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ch_scrolledwin),
269 GTK_POLICY_AUTOMATIC,
270 GTK_POLICY_AUTOMATIC);
272 headers_clist = gtk_clist_new_with_titles(1, title);
273 gtk_widget_show (headers_clist);
274 gtk_container_add (GTK_CONTAINER (ch_scrolledwin), headers_clist);
275 gtk_clist_set_column_width (GTK_CLIST (headers_clist), 0, 80);
276 gtk_clist_set_selection_mode (GTK_CLIST (headers_clist),
277 GTK_SELECTION_BROWSE);
278 GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (headers_clist)->column[0].button,
280 gtk_signal_connect (GTK_OBJECT (headers_clist), "select_row",
281 GTK_SIGNAL_FUNC (prefs_headers_select),
285 btn_vbox = gtk_vbox_new (FALSE, 8);
286 gtk_widget_show (btn_vbox);
287 gtk_box_pack_start (GTK_BOX (ch_hbox), btn_vbox, FALSE, FALSE, 0);
289 up_btn = gtk_button_new_with_label (_("Up"));
290 gtk_widget_show (up_btn);
291 gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
292 gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
293 GTK_SIGNAL_FUNC (prefs_headers_up), NULL);
295 down_btn = gtk_button_new_with_label (_("Down"));
296 gtk_widget_show (down_btn);
297 gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
298 gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
299 GTK_SIGNAL_FUNC (prefs_headers_down), NULL);
302 gtk_widget_show_all(window);
304 headers.window = window;
305 headers.close_btn = close_btn;
307 headers.hdr_combo = hdr_combo;
308 headers.hdr_entry = GTK_COMBO (hdr_combo)->entry;
309 headers.key_entry = key_entry;
310 headers.headers_clist = headers_clist;
313 void prefs_headers_read_config(PrefsAccount * ac)
317 gchar buf[PREFSBUFSIZE];
320 debug_print(_("Reading headers configuration...\n"));
322 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, HEADERS_RC, NULL);
323 if ((fp = fopen(rcpath, "r")) == NULL) {
324 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
326 ac->customhdr_list = NULL;
331 /* remove all previous headers list */
332 while (ac->customhdr_list != NULL) {
333 ch = (CustomHeader *)ac->customhdr_list->data;
334 custom_header_free(ch);
335 ac->customhdr_list = g_slist_remove(ac->customhdr_list, ch);
338 while (fgets(buf, sizeof(buf), fp) != NULL) {
340 ch = custom_header_read_str(buf);
342 if (ch->account_id == ac->account_id)
344 g_slist_append(ac->customhdr_list, ch);
346 custom_header_free(ch);
353 void prefs_headers_write_config(PrefsAccount * ac)
358 gchar buf[PREFSBUFSIZE];
362 GSList *all_hdrs = NULL;
364 debug_print(_("Writing headers configuration...\n"));
366 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, HEADERS_RC, NULL);
368 if ((fp = fopen(rcpath, "r")) == NULL) {
369 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
374 while (fgets(buf, sizeof(buf), fp) != NULL) {
376 ch = custom_header_read_str(buf);
378 if (ch->account_id != ac->account_id)
380 g_slist_append(all_hdrs, ch);
382 custom_header_free(ch);
389 if ((pfile = prefs_write_open(rcpath)) == NULL) {
390 g_warning(_("failed to write configuration to file\n"));
395 for (cur = all_hdrs; cur != NULL; cur = cur->next) {
396 CustomHeader *hdr = (CustomHeader *)cur->data;
399 chstr = custom_header_get_str(hdr);
400 if (fputs(chstr, pfile->fp) == EOF ||
401 fputc('\n', pfile->fp) == EOF) {
402 FILE_OP_ERROR(rcpath, "fputs || fputc");
403 prefs_write_close_revert(pfile);
411 for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) {
412 CustomHeader *hdr = (CustomHeader *)cur->data;
415 chstr = custom_header_get_str(hdr);
416 if (fputs(chstr, pfile->fp) == EOF ||
417 fputc('\n', pfile->fp) == EOF) {
418 FILE_OP_ERROR(rcpath, "fputs || fputc");
419 prefs_write_close_revert(pfile);
429 while (all_hdrs != NULL) {
430 ch = (CustomHeader *)all_hdrs->data;
431 custom_header_free(ch);
432 all_hdrs = g_slist_remove(all_hdrs, ch);
435 if (prefs_write_close(pfile) < 0) {
436 g_warning(_("failed to write configuration to file\n"));
441 static void prefs_headers_set_dialog(PrefsAccount * ac)
443 GtkCList *clist = GTK_CLIST(headers.headers_clist);
448 gtk_clist_freeze(clist);
449 gtk_clist_clear(clist);
451 ch_str[0] = _("(New)");
452 row = gtk_clist_append(clist, ch_str);
453 gtk_clist_set_row_data(clist, row, NULL);
455 for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) {
456 CustomHeader *ch = (CustomHeader *)cur->data;
458 ch_str[0] = g_strdup_printf("%s: %s", ch->name, ch->value);
459 row = gtk_clist_append(clist, ch_str);
460 gtk_clist_set_row_data(clist, row, ch);
465 gtk_clist_thaw(clist);
468 static void prefs_headers_set_list(PrefsAccount * ac)
473 g_slist_free(ac->customhdr_list);
474 ac->customhdr_list = NULL;
476 while ((ch = gtk_clist_get_row_data(GTK_CLIST(headers.headers_clist),
478 ac->customhdr_list = g_slist_append(ac->customhdr_list,
484 #define GET_ENTRY(entry) \
485 entry_text = gtk_entry_get_text(GTK_ENTRY(entry))
487 static gint prefs_headers_clist_set_row(PrefsAccount * ac, gint row)
489 GtkCList *clist = GTK_CLIST(headers.headers_clist);
494 g_return_val_if_fail(row != 0, -1);
496 GET_ENTRY(headers.hdr_entry);
497 if (entry_text[0] == '\0') {
498 alertpanel_error(_("Header name is not set."));
502 ch = g_new0(CustomHeader, 1);
504 ch->account_id = ac->account_id;
506 ch->name = g_strdup(entry_text);
508 GET_ENTRY(headers.key_entry);
509 if (entry_text[0] != '\0')
510 ch->value = g_strdup(entry_text);
512 ch_str[0] = g_strdup_printf("%s: %s", ch->name, ch->value);
515 row = gtk_clist_append(clist, ch_str);
519 gtk_clist_set_text(clist, row, 0, ch_str[0]);
520 tmpch = gtk_clist_get_row_data(clist, row);
522 custom_header_free(tmpch);
525 gtk_clist_set_row_data(clist, row, ch);
529 prefs_headers_set_list(cur_ac);
534 static void prefs_headers_register_cb(void)
536 prefs_headers_clist_set_row(cur_ac, -1);
539 static void prefs_headers_substitute_cb(void)
541 GtkCList *clist = GTK_CLIST(headers.headers_clist);
545 if (!clist->selection) return;
547 row = GPOINTER_TO_INT(clist->selection->data);
548 if (row == 0) return;
550 ch = gtk_clist_get_row_data(clist, row);
553 prefs_headers_clist_set_row(cur_ac, row);
556 static void prefs_headers_delete_cb(void)
558 GtkCList *clist = GTK_CLIST(headers.headers_clist);
562 if (!clist->selection) return;
563 row = GPOINTER_TO_INT(clist->selection->data);
564 if (row == 0) return;
566 if (alertpanel(_("Delete header"),
567 _("Do you really want to delete this header?"),
568 _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
571 ch = gtk_clist_get_row_data(clist, row);
572 custom_header_free(ch);
573 gtk_clist_remove(clist, row);
574 cur_ac->customhdr_list = g_slist_remove(cur_ac->customhdr_list, ch);
577 static void prefs_headers_up(void)
579 GtkCList *clist = GTK_CLIST(headers.headers_clist);
582 if (!clist->selection) return;
584 row = GPOINTER_TO_INT(clist->selection->data);
586 gtk_clist_row_move(clist, row, row - 1);
587 prefs_headers_set_list(cur_ac);
591 static void prefs_headers_down(void)
593 GtkCList *clist = GTK_CLIST(headers.headers_clist);
596 if (!clist->selection) return;
598 row = GPOINTER_TO_INT(clist->selection->data);
599 if (row > 0 && row < clist->rows - 1) {
600 gtk_clist_row_move(clist, row, row + 1);
601 prefs_headers_set_list(cur_ac);
605 #define ENTRY_SET_TEXT(entry, str) \
606 gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
608 static void prefs_headers_select(GtkCList *clist, gint row, gint column,
612 CustomHeader default_ch = { "", NULL };
614 ch = gtk_clist_get_row_data(clist, row);
618 ENTRY_SET_TEXT(headers.hdr_entry, ch->name);
619 ENTRY_SET_TEXT(headers.key_entry, ch->value);
622 static void prefs_headers_key_pressed(GtkWidget *widget, GdkEventKey *event,
625 if (event && event->keyval == GDK_Escape)
626 gtk_widget_hide(headers.window);
629 static void prefs_headers_close(GtkButton *button)
631 prefs_headers_write_config(cur_ac);
632 gtk_widget_hide(headers.window);