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 {
56 GtkWidget *cancel_btn;
61 GtkWidget *headers_clist;
65 parameter name, default value, pointer to the prefs variable, data type,
66 pointer to the widget pointer,
67 pointer to the function for data setting,
68 pointer to the function for widget setting
72 #define VSPACING_NARROW 4
73 #define DEFAULT_ENTRY_WIDTH 80
74 #define PREFSBUFSIZE 1024
76 /* widget creating functions */
77 static void prefs_headers_create (void);
79 static void prefs_headers_set_dialog (PrefsAccount * ac);
80 static void prefs_headers_set_list (PrefsAccount * ac);
81 static gint prefs_headers_clist_set_row (PrefsAccount * ac,
84 /* callback functions */
85 static void prefs_headers_select_dest_cb (void);
86 static void prefs_headers_register_cb (void);
87 static void prefs_headers_substitute_cb (void);
88 static void prefs_headers_delete_cb (void);
89 static void prefs_headers_up (void);
90 static void prefs_headers_down (void);
91 static void prefs_headers_select (GtkCList *clist,
96 static void prefs_headers_key_pressed (GtkWidget *widget,
100 static void prefs_headers_close (GtkButton *button);
102 static void prefs_headers_ok (GtkButton *button);
103 static void prefs_headers_cancel (GtkButton *button);
105 static PrefsAccount * cur_ac = NULL;
107 void prefs_headers_open(PrefsAccount * ac)
109 if (!headers.window) {
110 prefs_headers_create();
113 manage_window_set_transient(GTK_WINDOW(headers.window));
115 gtk_widget_grab_focus(headers.close_btn);
117 gtk_widget_grab_focus(headers.ok_btn);
119 prefs_headers_set_dialog(ac);
123 gtk_widget_show(headers.window);
126 static void prefs_headers_create(void)
131 /* GtkWidget *close_btn; */
133 GtkWidget *cancel_btn;
135 GtkWidget *confirm_area;
140 GtkWidget *hdr_label;
141 GtkWidget *hdr_combo;
142 GtkWidget *key_label;
143 GtkWidget *key_entry;
149 GtkWidget *subst_btn;
153 GtkWidget *ch_scrolledwin;
154 GtkWidget *headers_clist;
160 gchar *title[] = {_("Custom headers")};
162 debug_print(_("Creating headers setting window...\n"));
164 window = gtk_window_new (GTK_WINDOW_DIALOG);
165 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
166 gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
167 gtk_window_set_modal (GTK_WINDOW (window), TRUE);
168 gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
170 vbox = gtk_vbox_new (FALSE, 6);
171 gtk_widget_show (vbox);
172 gtk_container_add (GTK_CONTAINER (window), vbox);
174 gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
175 &cancel_btn, _("Cancel"), NULL, NULL);
177 gtkut_button_set_create (&confirm_area, &close_btn, _("Close"),
178 NULL, NULL, NULL, NULL);
180 gtk_widget_show (confirm_area);
181 gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
183 gtk_widget_grab_default (close_btn);
185 gtk_widget_grab_default (ok_btn);
187 gtk_window_set_title (GTK_WINDOW(window),
188 _("Headers setting"));
189 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
190 GTK_SIGNAL_FUNC(gtk_widget_hide_on_delete), NULL);
191 gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
192 GTK_SIGNAL_FUNC(prefs_headers_key_pressed), NULL);
193 gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
194 GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
195 gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
196 GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
197 gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
198 GTK_SIGNAL_FUNC(prefs_headers_ok), NULL);
199 gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
200 GTK_SIGNAL_FUNC(prefs_headers_cancel), NULL);
202 vbox1 = gtk_vbox_new (FALSE, VSPACING);
203 gtk_widget_show (vbox1);
204 gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
205 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
207 table1 = gtk_table_new (2, 2, FALSE);
208 gtk_widget_show (table1);
209 gtk_box_pack_start (GTK_BOX (vbox1), table1,
211 gtk_table_set_row_spacings (GTK_TABLE (table1), 8);
212 gtk_table_set_col_spacings (GTK_TABLE (table1), 8);
214 hdr_label = gtk_label_new (_("Header"));
215 gtk_widget_show (hdr_label);
216 gtk_table_attach (GTK_TABLE (table1), hdr_label, 0, 1, 0, 1,
217 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
219 gtk_misc_set_alignment (GTK_MISC (hdr_label), 0, 0.5);
221 hdr_combo = gtk_combo_new ();
222 gtk_widget_show (hdr_combo);
223 gtk_table_attach (GTK_TABLE (table1), hdr_combo, 0, 1, 1, 2,
224 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
226 gtk_widget_set_usize (hdr_combo, 150 /* 96 */, -1);
227 gtkut_combo_set_items (GTK_COMBO (hdr_combo),
228 "User-Agent", "X-Operating-System", NULL);
230 key_label = gtk_label_new (_("Value"));
231 gtk_widget_show (key_label);
232 gtk_table_attach (GTK_TABLE (table1), key_label, 1, 2, 0, 1,
233 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
235 gtk_misc_set_alignment (GTK_MISC (key_label), 0, 0.5);
237 key_entry = gtk_entry_new ();
238 gtk_widget_show (key_entry);
239 gtk_table_attach (GTK_TABLE (table1), key_entry, 1, 2, 1, 2,
240 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
243 /* register / substitute / delete */
245 reg_hbox = gtk_hbox_new (FALSE, 4);
246 gtk_widget_show (reg_hbox);
247 gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox,
250 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
251 gtk_widget_show (arrow);
252 gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
253 gtk_widget_set_usize (arrow, -1, 16);
255 btn_hbox = gtk_hbox_new (TRUE, 4);
256 gtk_widget_show (btn_hbox);
257 gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
259 reg_btn = gtk_button_new_with_label (_("Add"));
260 gtk_widget_show (reg_btn);
261 gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
262 gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
263 GTK_SIGNAL_FUNC (prefs_headers_register_cb), NULL);
265 subst_btn = gtk_button_new_with_label (_(" Substitute "));
266 gtk_widget_show (subst_btn);
267 gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
268 gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
269 GTK_SIGNAL_FUNC (prefs_headers_substitute_cb),
272 del_btn = gtk_button_new_with_label (_("Delete"));
273 gtk_widget_show (del_btn);
274 gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
275 gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
276 GTK_SIGNAL_FUNC (prefs_headers_delete_cb), NULL);
279 ch_hbox = gtk_hbox_new (FALSE, 8);
280 gtk_widget_show (ch_hbox);
281 gtk_box_pack_start (GTK_BOX (vbox1), ch_hbox,
284 ch_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
285 gtk_widget_set_usize (ch_scrolledwin, -1, 100);
286 gtk_widget_show (ch_scrolledwin);
287 gtk_box_pack_start (GTK_BOX (ch_hbox), ch_scrolledwin,
289 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ch_scrolledwin),
290 GTK_POLICY_AUTOMATIC,
291 GTK_POLICY_AUTOMATIC);
293 headers_clist = gtk_clist_new_with_titles(1, title);
294 gtk_widget_show (headers_clist);
295 gtk_container_add (GTK_CONTAINER (ch_scrolledwin), headers_clist);
296 gtk_clist_set_column_width (GTK_CLIST (headers_clist), 0, 80);
297 gtk_clist_set_selection_mode (GTK_CLIST (headers_clist),
298 GTK_SELECTION_BROWSE);
299 GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (headers_clist)->column[0].button,
301 gtk_signal_connect (GTK_OBJECT (headers_clist), "select_row",
302 GTK_SIGNAL_FUNC (prefs_headers_select),
306 btn_vbox = gtk_vbox_new (FALSE, 8);
307 gtk_widget_show (btn_vbox);
308 gtk_box_pack_start (GTK_BOX (ch_hbox), btn_vbox, FALSE, FALSE, 0);
310 up_btn = gtk_button_new_with_label (_("Up"));
311 gtk_widget_show (up_btn);
312 gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
313 gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
314 GTK_SIGNAL_FUNC (prefs_headers_up), NULL);
316 down_btn = gtk_button_new_with_label (_("Down"));
317 gtk_widget_show (down_btn);
318 gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
319 gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
320 GTK_SIGNAL_FUNC (prefs_headers_down), NULL);
323 gtk_widget_show_all(window);
325 headers.window = window;
326 /* headers.close_btn = close_btn; */
327 headers.ok_btn = ok_btn;
328 headers.cancel_btn = cancel_btn;
330 headers.hdr_combo = hdr_combo;
331 headers.hdr_entry = GTK_COMBO (hdr_combo)->entry;
332 headers.key_entry = key_entry;
333 headers.headers_clist = headers_clist;
336 void prefs_headers_read_config(PrefsAccount * ac)
340 gchar buf[PREFSBUFSIZE];
343 debug_print(_("Reading headers configuration...\n"));
345 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, HEADERS_RC, NULL);
346 if ((fp = fopen(rcpath, "r")) == NULL) {
347 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
349 ac->customhdr_list = NULL;
354 /* remove all previous headers list */
355 while (ac->customhdr_list != NULL) {
356 ch = (CustomHeader *)ac->customhdr_list->data;
357 custom_header_free(ch);
358 ac->customhdr_list = g_slist_remove(ac->customhdr_list, ch);
361 while (fgets(buf, sizeof(buf), fp) != NULL) {
363 ch = custom_header_read_str(buf);
365 if (ch->account_id == ac->account_id)
367 g_slist_append(ac->customhdr_list, ch);
369 custom_header_free(ch);
376 void prefs_headers_write_config(PrefsAccount * ac)
381 gchar buf[PREFSBUFSIZE];
385 GSList *all_hdrs = NULL;
387 debug_print(_("Writing headers configuration...\n"));
389 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, HEADERS_RC, NULL);
391 if ((fp = fopen(rcpath, "r")) == NULL) {
392 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
397 while (fgets(buf, sizeof(buf), fp) != NULL) {
399 ch = custom_header_read_str(buf);
401 if (ch->account_id != ac->account_id)
403 g_slist_append(all_hdrs, ch);
405 custom_header_free(ch);
412 if ((pfile = prefs_write_open(rcpath)) == NULL) {
413 g_warning(_("failed to write configuration to file\n"));
418 for (cur = all_hdrs; cur != NULL; cur = cur->next) {
419 CustomHeader *hdr = (CustomHeader *)cur->data;
422 chstr = custom_header_get_str(hdr);
423 if (fputs(chstr, pfile->fp) == EOF ||
424 fputc('\n', pfile->fp) == EOF) {
425 FILE_OP_ERROR(rcpath, "fputs || fputc");
426 prefs_write_close_revert(pfile);
434 for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) {
435 CustomHeader *hdr = (CustomHeader *)cur->data;
438 chstr = custom_header_get_str(hdr);
439 if (fputs(chstr, pfile->fp) == EOF ||
440 fputc('\n', pfile->fp) == EOF) {
441 FILE_OP_ERROR(rcpath, "fputs || fputc");
442 prefs_write_close_revert(pfile);
452 while (all_hdrs != NULL) {
453 ch = (CustomHeader *)all_hdrs->data;
454 custom_header_free(ch);
455 all_hdrs = g_slist_remove(all_hdrs, ch);
458 if (prefs_write_close(pfile) < 0) {
459 g_warning(_("failed to write configuration to file\n"));
464 static void prefs_headers_set_dialog(PrefsAccount * ac)
466 GtkCList *clist = GTK_CLIST(headers.headers_clist);
471 gtk_clist_freeze(clist);
472 gtk_clist_clear(clist);
474 ch_str[0] = _("(New)");
475 row = gtk_clist_append(clist, ch_str);
476 gtk_clist_set_row_data(clist, row, NULL);
478 for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) {
479 CustomHeader *ch = (CustomHeader *)cur->data;
481 ch_str[0] = g_strdup_printf("%s: %s", ch->name, ch->value);
482 row = gtk_clist_append(clist, ch_str);
483 gtk_clist_set_row_data(clist, row, ch);
488 gtk_clist_thaw(clist);
491 static void prefs_headers_set_list(PrefsAccount * ac)
496 g_slist_free(ac->customhdr_list);
497 ac->customhdr_list = NULL;
499 while ((ch = gtk_clist_get_row_data(GTK_CLIST(headers.headers_clist),
501 ac->customhdr_list = g_slist_append(ac->customhdr_list,
507 #define GET_ENTRY(entry) \
508 entry_text = gtk_entry_get_text(GTK_ENTRY(entry))
510 static gint prefs_headers_clist_set_row(PrefsAccount * ac, gint row)
512 GtkCList *clist = GTK_CLIST(headers.headers_clist);
517 g_return_val_if_fail(row != 0, -1);
519 GET_ENTRY(headers.hdr_entry);
520 if (entry_text[0] == '\0') {
521 alertpanel_error(_("Header name is not set."));
525 ch = g_new0(CustomHeader, 1);
527 ch->account_id = ac->account_id;
529 ch->name = g_strdup(entry_text);
531 GET_ENTRY(headers.key_entry);
532 if (entry_text[0] != '\0')
533 ch->value = g_strdup(entry_text);
535 ch_str[0] = g_strdup_printf("%s: %s", ch->name, ch->value);
538 row = gtk_clist_append(clist, ch_str);
542 gtk_clist_set_text(clist, row, 0, ch_str[0]);
543 tmpch = gtk_clist_get_row_data(clist, row);
545 custom_header_free(tmpch);
548 gtk_clist_set_row_data(clist, row, ch);
552 prefs_headers_set_list(cur_ac);
557 static void prefs_headers_register_cb(void)
559 prefs_headers_clist_set_row(cur_ac, -1);
562 static void prefs_headers_substitute_cb(void)
564 GtkCList *clist = GTK_CLIST(headers.headers_clist);
568 if (!clist->selection) return;
570 row = GPOINTER_TO_INT(clist->selection->data);
571 if (row == 0) return;
573 ch = gtk_clist_get_row_data(clist, row);
576 prefs_headers_clist_set_row(cur_ac, row);
579 static void prefs_headers_delete_cb(void)
581 GtkCList *clist = GTK_CLIST(headers.headers_clist);
585 if (!clist->selection) return;
586 row = GPOINTER_TO_INT(clist->selection->data);
587 if (row == 0) return;
589 if (alertpanel(_("Delete header"),
590 _("Do you really want to delete this header?"),
591 _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
594 ch = gtk_clist_get_row_data(clist, row);
595 custom_header_free(ch);
596 gtk_clist_remove(clist, row);
597 cur_ac->customhdr_list = g_slist_remove(cur_ac->customhdr_list, ch);
600 static void prefs_headers_up(void)
602 GtkCList *clist = GTK_CLIST(headers.headers_clist);
605 if (!clist->selection) return;
607 row = GPOINTER_TO_INT(clist->selection->data);
609 gtk_clist_row_move(clist, row, row - 1);
610 prefs_headers_set_list(cur_ac);
614 static void prefs_headers_down(void)
616 GtkCList *clist = GTK_CLIST(headers.headers_clist);
619 if (!clist->selection) return;
621 row = GPOINTER_TO_INT(clist->selection->data);
622 if (row > 0 && row < clist->rows - 1) {
623 gtk_clist_row_move(clist, row, row + 1);
624 prefs_headers_set_list(cur_ac);
628 #define ENTRY_SET_TEXT(entry, str) \
629 gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
631 static void prefs_headers_select(GtkCList *clist, gint row, gint column,
635 CustomHeader default_ch = { 0, "", NULL };
637 ch = gtk_clist_get_row_data(clist, row);
641 ENTRY_SET_TEXT(headers.hdr_entry, ch->name);
642 ENTRY_SET_TEXT(headers.key_entry, ch->value);
645 static void prefs_headers_key_pressed(GtkWidget *widget, GdkEventKey *event,
648 if (event && event->keyval == GDK_Escape)
649 gtk_widget_hide(headers.window);
652 static void prefs_headers_ok(GtkButton *button)
654 prefs_headers_write_config(cur_ac);
655 gtk_widget_hide(headers.window);
658 static void prefs_headers_cancel(GtkButton *button)
661 prefs_headers_write_config(cur_ac);
663 prefs_headers_read_config(cur_ac);
664 gtk_widget_hide(headers.window);