evolution-3.6.4/plugins/email-custom-header/email-custom-header.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Ashish Shrivastava <shashish@novell.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include <string.h>
 28 #include <glib/gi18n.h>
 29 #include "mail/em-utils.h"
 30 #include "mail/em-event.h"
 31 #include "composer/e-msg-composer.h"
 32 #include "e-util/e-config.h"
 33 #include "e-util/e-util.h"
 34 #include "email-custom-header.h"
 35 
 36 #define d(x)
 37 
 38 #define ECM_SETTINGS_ID  "org.gnome.evolution.plugin.email-custom-header"
 39 #define ECM_SETTINGS_KEY "custom-header"
 40 
 41 #define CUSTOM_HEADER_OPTIONS_DIALOG_GET_PRIVATE(obj) \
 42 	(G_TYPE_INSTANCE_GET_PRIVATE \
 43 	((obj), EMAIL_CUSTOM_HEADER_OPTIONS_DIALOG, CustomHeaderOptionsDialogPrivate))
 44 
 45 typedef struct {
 46         GtkWidget *treeview;
 47         GtkWidget *header_add;
 48         GtkWidget *header_edit;
 49         GtkWidget *header_remove;
 50         GtkListStore *store;
 51 } ConfigData;
 52 
 53 enum {
 54         HEADER_KEY_COLUMN,
 55 	HEADER_VALUE_COLUMN,
 56         HEADER_N_COLUMNS
 57 };
 58 
 59 struct _CustomHeaderOptionsDialogPrivate {
 60 	GtkBuilder *builder;
 61 	/*Widgets*/
 62 	GtkWidget *main;
 63 	GtkWidget *page;
 64 	GtkWidget *header_table;
 65 	GtkWidget *header_type_name_label;
 66 	GArray *combo_box_header_value;
 67 	GArray *email_custom_header_details;
 68 	GArray *header_index_type;
 69 	gint flag;
 70 	gchar *help_section;
 71 };
 72 
 73 /* epech - e-plugin email custom header*/
 74 GType custom_header_options_dialog_get_type (void);
 75 static void epech_dialog_finalize (GObject *object);
 76 static void epech_setup_widgets (CustomHeaderOptionsDialog *mch);
 77 static gint epech_check_existing_composer_window (gconstpointer a, gconstpointer b);
 78 static void commit_changes (ConfigData *cd);
 79 gint e_plugin_lib_enable (EPlugin *ep, gint enable);
 80 GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl);
 81 gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer);
 82 GtkWidget *org_gnome_email_custom_header_config_option (EPlugin *epl, struct _EConfigHookItemFactoryData *data);
 83 
 84 G_DEFINE_TYPE (
 85 	CustomHeaderOptionsDialog,
 86 	custom_header_options_dialog,
 87 	G_TYPE_OBJECT)
 88 
 89 gint
 90 e_plugin_lib_enable (EPlugin *ep,
 91                      gint enable)
 92 {
 93 	return 0;
 94 }
 95 
 96 static void
 97 epech_get_widgets_data (CustomHeaderOptionsDialog *mch)
 98 {
 99 	CustomHeaderOptionsDialogPrivate *priv;
100 	HeaderValueComboBox *sub_combo_box_get;
101 	gint selected_item;
102 	gint index_column;
103 
104 	priv = mch->priv;
105 	priv->header_index_type = g_array_new (FALSE, FALSE, sizeof (gint));
106 	priv->flag++;
107 
108 	for (index_column = 0;
109 		index_column < priv->email_custom_header_details->len; index_column++) {
110 
111 		sub_combo_box_get = &g_array_index (priv->combo_box_header_value, HeaderValueComboBox,index_column);
112 		selected_item = gtk_combo_box_get_active ((GtkComboBox *) sub_combo_box_get->header_value_combo_box);
113 		g_array_append_val (priv->header_index_type, selected_item);
114 	}
115 }
116 
117 static gboolean
118 epech_get_widgets (CustomHeaderOptionsDialog *mch)
119 {
120 	CustomHeaderOptionsDialogPrivate *priv;
121 	priv = mch->priv;
122 
123 #define EMAIL_CUSTOM_HEADER(name) e_builder_get_widget (priv->builder, name)
124 	priv->main = EMAIL_CUSTOM_HEADER ("email-custom-header-dialog");
125 
126 	if (!priv->main)
127 		return FALSE;
128 
129 	priv->page  = EMAIL_CUSTOM_HEADER ("email-custom-header-vbox");
130 	priv->header_table = EMAIL_CUSTOM_HEADER ("email-custom-header-options");
131 #undef EMAIL_CUSTOM_HEADER
132 
133 	return (priv->page
134 		&&priv->header_table);
135 }
136 
137 static void
138 epech_fill_widgets_with_data (CustomHeaderOptionsDialog *mch)
139 {
140 	CustomHeaderOptionsDialogPrivate *priv;
141 	HeaderValueComboBox *sub_combo_box_fill;
142 	gint set_index_column;
143 
144 	priv = mch->priv;
145 	priv->help_section = g_strdup ("mail-composer-custom-header-lines");
146 
147 	for (set_index_column = 0;
148 		set_index_column < priv->email_custom_header_details->len; set_index_column++) {
149 		sub_combo_box_fill = &g_array_index (priv->combo_box_header_value, HeaderValueComboBox,set_index_column);
150 
151 		if (priv->flag == 0) {
152 			gtk_combo_box_set_active ((GtkComboBox *) sub_combo_box_fill->header_value_combo_box,0);
153 		} else {
154 			gtk_combo_box_set_active (
155 				(GtkComboBox *) sub_combo_box_fill->header_value_combo_box,
156 				g_array_index (priv->header_index_type, gint, set_index_column));
157 		}
158 	}
159 }
160 
161 CustomHeaderOptionsDialog *
162 epech_dialog_new (void)
163 {
164 	return g_object_new (EMAIL_CUSTOM_HEADER_OPTIONS_DIALOG, NULL);
165 }
166 
167 static void
168 epech_header_options_cb (GtkDialog *dialog,
169                          gint state,
170                          gpointer func_data)
171 {
172 	CustomHeaderOptionsDialogPrivate *priv;
173 	CustomHeaderOptionsDialog *mch;
174 
175 	mch = func_data;
176 	priv = mch->priv;
177 
178 	switch (state) {
179 		case GTK_RESPONSE_OK:
180 			epech_get_widgets_data (mch);
181 		case GTK_RESPONSE_CANCEL:
182 			gtk_widget_hide (priv->main);
183 			gtk_widget_destroy (priv->main);
184 			g_object_unref (priv->builder);
185 			break;
186 		case GTK_RESPONSE_HELP:
187 			e_display_help (
188 				GTK_WINDOW (priv->main),
189 				priv->help_section);
190 			break;
191 	}
192 
193 	g_signal_emit (func_data, signals[MCH_RESPONSE], 0, state);
194 }
195 
196 static gboolean
197 epech_dialog_run (CustomHeaderOptionsDialog *mch,
198                   GtkWidget *parent)
199 {
200 	CustomHeaderOptionsDialogPrivate *priv;
201 	GSettings *settings;
202 	GtkWidget *toplevel;
203 
204 	g_return_val_if_fail (mch != NULL || EMAIL_CUSTOM_HEADER_OPTIONS_IS_DIALOG (mch), FALSE);
205 	priv = mch->priv;
206 
207 	settings = g_settings_new (ECM_SETTINGS_ID);
208 	epech_load_from_settings (settings, ECM_SETTINGS_KEY, mch);
209 	g_object_unref (settings);
210 
211 	priv->builder = gtk_builder_new ();
212 	e_load_ui_builder_definition (
213 		priv->builder, "org-gnome-email-custom-header.ui");
214 
215 	if (!epech_get_widgets (mch)) {
216 		g_object_unref (priv->builder);
217 		d (printf ("\n Could not get the Widgets\n"));
218 	}
219 
220 	epech_setup_widgets (mch);
221 	toplevel =  gtk_widget_get_toplevel (priv->main);
222 
223 	if (parent)
224 		gtk_window_set_transient_for (GTK_WINDOW (toplevel),GTK_WINDOW (parent));
225 
226 	epech_fill_widgets_with_data (mch);
227 	g_signal_connect (
228 		priv->main, "response",
229 		G_CALLBACK (epech_header_options_cb), mch);
230 	gtk_widget_show (priv->main);
231 
232 	return TRUE;
233 }
234 
235 static void
236 epech_load_from_settings (GSettings *settings,
237                           const gchar *key,
238                           CustomHeaderOptionsDialog *mch)
239 {
240 	CustomHeaderOptionsDialogPrivate *priv;
241 	EmailCustomHeaderDetails temp_header_details= {-1, -1, NULL, NULL};
242 	CustomSubHeader temp_header_value_details =  {NULL};
243 	gchar **headers;
244 	gint index,pos;
245 
246 	priv = mch->priv;
247 	priv->email_custom_header_details = g_array_new (TRUE, TRUE, sizeof (EmailCustomHeaderDetails));
248 	headers = g_settings_get_strv (settings, key);
249 
250 	for (pos = 0; headers && headers[pos]; pos++) {
251 		gchar **parse_header_list;
252 
253 		memset (&temp_header_value_details, 0, sizeof (CustomSubHeader));
254 		temp_header_details.sub_header_type_value = g_array_new (TRUE, TRUE, sizeof (CustomSubHeader));
255 		parse_header_list = g_strsplit_set (headers[pos], "=;,", -1);
256 		temp_header_details.header_type_value = g_string_new ("");
257 		if (temp_header_details.header_type_value) {
258 			g_string_assign (temp_header_details.header_type_value, parse_header_list[0]);
259 		}
260 
261 		for (index = 0; parse_header_list[index + 1] ; ++index) {
262 			temp_header_value_details.sub_header_string_value = g_string_new ("");
263 
264 			if (temp_header_value_details.sub_header_string_value) {
265 				g_string_assign (temp_header_value_details.sub_header_string_value, parse_header_list[index + 1]);
266 			}
267 
268 			g_array_append_val (temp_header_details.sub_header_type_value, temp_header_value_details);
269 		}
270 
271 		temp_header_details.number_of_subtype_header = index;
272 		g_array_append_val (priv->email_custom_header_details, temp_header_details);
273 	}
274 
275 	temp_header_details.number_of_header = pos;
276 
277 	g_strfreev (headers);
278 }
279 
280 static void
281 epech_setup_widgets (CustomHeaderOptionsDialog *mch)
282 {
283 	CustomHeaderOptionsDialogPrivate *priv;
284 	EmailCustomHeaderDetails *temp_header_ptr,*temp;
285 	CustomSubHeader *temp_header_value_ptr;
286 	HeaderValueComboBox sub_combo_box = {NULL};
287 	HeaderValueComboBox *sub_combo_box_ptr;
288 	gint sub_index,row_combo,column_combo;
289 	gint header_section_id,sub_type_index,row,column;
290 	gint i;
291 	const gchar *str;
292 	static const gchar *security_field = NC_("email-custom-header-Security", "Security:");
293 	static struct _security_values {
294 		const gchar *value, *str;
295 	} security_values[] = {
296 		{ "Personal",     NC_("email-custom-header-Security", "Personal") } ,
297 		{ "Unclassified", NC_("email-custom-header-Security", "Unclassified") },
298 		{ "Protected",    NC_("email-custom-header-Security", "Protected") },
299 		{ "InConfidence", NC_("email-custom-header-Security", "Confidential") },
300 		{ "Secret",       NC_("email-custom-header-Security", "Secret") },
301 		{ "Topsecret",    NC_("email-custom-header-Security", "Top secret") },
302 		{ NULL, NULL }
303 	};
304 
305 	priv = mch->priv;
306 	priv->combo_box_header_value = g_array_new (TRUE, FALSE, sizeof (HeaderValueComboBox));
307 
308 	for (header_section_id = 0,row = 0,column = 1;
309 		header_section_id < priv->email_custom_header_details->len; header_section_id++,row++,column++) {
310 
311 		/* To create an empty label widget. Text will be added dynamically. */
312 		priv->header_type_name_label = gtk_label_new ("");
313 		temp_header_ptr = &g_array_index (priv->email_custom_header_details, EmailCustomHeaderDetails,header_section_id);
314 		str = (temp_header_ptr->header_type_value)->str;
315 		if (strcmp (str, security_field) == 0)
316 			str = g_dpgettext2 (GETTEXT_PACKAGE, "email-custom-header-Security", security_field);
317 		gtk_label_set_markup (GTK_LABEL (priv->header_type_name_label), str);
318 
319 		gtk_table_attach (
320 			GTK_TABLE (priv->header_table),
321 			priv->header_type_name_label, 0, 1, row, column,
322 			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
323 			(GtkAttachOptions) (0), 0, 0);
324 
325 		gtk_misc_set_alignment (GTK_MISC (priv->header_type_name_label), 0, 0.5);
326 		gtk_widget_show (priv->header_type_name_label);
327 		sub_combo_box.header_value_combo_box = gtk_combo_box_text_new ();
328 		g_array_append_val (priv->combo_box_header_value, sub_combo_box);
329 	}
330 
331 	for (sub_index = 0,row_combo = 0,column_combo = 1; sub_index < priv->combo_box_header_value->len;
332 		sub_index++,row_combo++,column_combo++) {
333 		temp = &g_array_index (priv->email_custom_header_details, EmailCustomHeaderDetails,sub_index);
334 
335 		sub_combo_box_ptr = &g_array_index (priv->combo_box_header_value, HeaderValueComboBox,sub_index);
336 		gtk_table_attach (
337 			GTK_TABLE (priv->header_table),
338 			sub_combo_box_ptr->header_value_combo_box, 1, 2, row_combo, column_combo,
339 			(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
340 			(GtkAttachOptions) (GTK_FILL), 0, 0);
341 
342 		for (sub_type_index = 0; sub_type_index < temp->number_of_subtype_header; sub_type_index++) {
343 			temp_header_value_ptr = &g_array_index (temp->sub_header_type_value, CustomSubHeader,sub_type_index);
344 			str = (temp_header_value_ptr->sub_header_string_value)->str;
345 			for (i = 0; security_values[i].value != NULL; i++) {
346 				if (strcmp (str, security_values[i].value) == 0) {
347 					str = g_dpgettext2 (GETTEXT_PACKAGE, "email-custom-header-Security", security_values[i].str);
348 					break;
349 				}
350 			}
351 			gtk_combo_box_text_append_text (
352 				GTK_COMBO_BOX_TEXT (
353 				sub_combo_box_ptr->header_value_combo_box), str);
354 		}
355 
356 		/* Translators: "None" as an email custom header option in a dialog invoked by Insert->Custom Header from Composer,
357 		 * indicating the header will not be added to a mail message */
358 		gtk_combo_box_text_append_text (
359 			GTK_COMBO_BOX_TEXT (
360 			sub_combo_box_ptr->header_value_combo_box),
361 			C_("email-custom-header", "None"));
362 		gtk_widget_show (sub_combo_box_ptr->header_value_combo_box);
363 	}
364 }
365 
366 static void
367 custom_header_options_dialog_class_init (CustomHeaderOptionsDialogClass *class)
368 {
369 	GObjectClass *object_class;
370 
371 	g_type_class_add_private (
372 		class, sizeof (CustomHeaderOptionsDialogPrivate));
373 
374 	object_class = G_OBJECT_CLASS (class);
375 	object_class->finalize = epech_dialog_finalize;
376 
377 	signals[MCH_RESPONSE] = g_signal_new (
378 		"emch_response",
379 		G_TYPE_FROM_CLASS (class),
380 		G_SIGNAL_RUN_FIRST,
381 		G_STRUCT_OFFSET (CustomHeaderOptionsDialogClass, emch_response),
382 		NULL, NULL,
383 		g_cclosure_marshal_VOID__INT,
384 		G_TYPE_NONE, 1,
385 		G_TYPE_INT);
386 }
387 
388 static void
389 custom_header_options_dialog_init (CustomHeaderOptionsDialog *mch)
390 {
391 	mch->priv = CUSTOM_HEADER_OPTIONS_DIALOG_GET_PRIVATE (mch);
392 }
393 
394 static void
395 epech_dialog_finalize (GObject *object)
396 {
397 	CustomHeaderOptionsDialogPrivate *priv;
398 
399 	priv = CUSTOM_HEADER_OPTIONS_DIALOG_GET_PRIVATE (object);
400 
401 	g_free (priv->help_section);
402 
403 	/* Chain up to parent's finalize() method. */
404 	G_OBJECT_CLASS (custom_header_options_dialog_parent_class)->finalize (object);
405 }
406 
407 static void
408 epech_append_to_custom_header (CustomHeaderOptionsDialog *dialog,
409                                gint state,
410                                gpointer data)
411 {
412 	EMsgComposer *composer;
413 	CustomHeaderOptionsDialogPrivate *priv;
414 	EmailCustomHeaderDetails *temp_header_ptr;
415 	CustomSubHeader *temp_header_value_ptr;
416 	gint index_subtype,sub_type_index;
417 
418 	composer = (EMsgComposer *) data;
419 	priv = dialog->priv;
420 
421 	if (state == GTK_RESPONSE_OK) {
422 
423 		for (index_subtype = 0; index_subtype < priv->email_custom_header_details->len; index_subtype++) {
424 
425 			temp_header_ptr = &g_array_index (priv->email_custom_header_details, EmailCustomHeaderDetails,index_subtype);
426 
427 			for (sub_type_index = 0; sub_type_index < temp_header_ptr->number_of_subtype_header; sub_type_index++) {
428 				temp_header_value_ptr = &g_array_index (temp_header_ptr->sub_header_type_value, CustomSubHeader,sub_type_index);
429 
430 				if (sub_type_index == g_array_index (priv->header_index_type, gint, index_subtype)) {
431 					e_msg_composer_set_header (
432 						composer, (temp_header_ptr->header_type_value)->str,
433 						(temp_header_value_ptr->sub_header_string_value)->str);
434 				}
435 			}
436 		}
437 	}
438 }
439 
440 static void
441 epech_custom_header_options_commit (EMsgComposer *comp,
442                                     gpointer user_data)
443 {
444 	EMsgComposer *composer;
445 	EmailCustomHeaderWindow *new_email_custom_header_window = NULL;
446 	CustomHeaderOptionsDialog *current_dialog = NULL;
447 
448 	composer = (EMsgComposer *) user_data;
449 
450 	if (!user_data || !EMAIL_CUSTOM_HEADER_OPTIONS_IS_DIALOG (user_data))
451 		return;
452 
453 	new_email_custom_header_window = g_object_get_data ((GObject *) composer, "compowindow");
454 
455 	if (new_email_custom_header_window) {
456 		current_dialog = new_email_custom_header_window->epech_dialog;
457 	}
458 
459 	if (current_dialog) {
460 		g_free (current_dialog);
461 		current_dialog = NULL;
462 	}
463 
464 	if (new_email_custom_header_window) {
465 		g_free (new_email_custom_header_window);
466 		new_email_custom_header_window = NULL;
467 	}
468 }
469 
470 static gint
471 epech_check_existing_composer_window (gconstpointer compowindow,
472                                       gconstpointer other_compowindow)
473 {
474 	if ((compowindow) && (other_compowindow)) {
475 		if (((EmailCustomHeaderWindow *) compowindow)->epech_window == (GdkWindow *) other_compowindow) {
476 			return 0;
477 		}
478 	}
479 
480 	return -1;
481 }
482 
483 static void
484 destroy_compo_data (gpointer data)
485 {
486 	EmailCustomHeaderWindow *compo_data = (EmailCustomHeaderWindow *) data;
487 
488 	if (!compo_data)
489 		return;
490 
491 	g_free (compo_data);
492 }
493 
494 static void action_email_custom_header_cb (GtkAction *action, EMsgComposer *composer)
495 
496 {
497 	GtkUIManager *ui_manager;
498 	GtkWidget *menuitem;
499 	GdkWindow *window;
500 	CustomHeaderOptionsDialog *dialog = NULL;
501 	EmailCustomHeaderWindow *new_email_custom_header_window = NULL;
502 
503 	ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer));
504 	menuitem = gtk_ui_manager_get_widget (ui_manager, "/main-menu/insert-menu/insert-menu-top/Custom Header");
505 
506 	new_email_custom_header_window = g_object_get_data ((GObject *) composer, "compowindow");
507 
508 	window = gtk_widget_get_window (menuitem);
509 	if (epech_check_existing_composer_window (new_email_custom_header_window,window) == 0) {
510 		dialog = new_email_custom_header_window->epech_dialog;
511 	} else {
512 		dialog = epech_dialog_new ();
513 		if (dialog) {
514 			EmailCustomHeaderWindow *new_email_custom_header_window;
515 			new_email_custom_header_window = g_new0 (EmailCustomHeaderWindow, 1);
516 			new_email_custom_header_window->epech_window = window;
517 			new_email_custom_header_window->epech_dialog = dialog;
518 			g_object_set_data_full ((GObject *) composer, "compowindow", new_email_custom_header_window, destroy_compo_data);
519 		}
520 	}
521 
522 	epech_dialog_run (dialog, GTK_WIDGET (composer));
523 	g_signal_connect (
524 		dialog, "emch_response",
525 		G_CALLBACK (epech_append_to_custom_header), composer);
526 	g_signal_connect (
527 		composer, "destroy",
528 		G_CALLBACK (epech_custom_header_options_commit), composer);
529 }
530 
531 static GtkActionEntry entries[] = {
532 
533 	{ "Custom Header",
534 	  NULL,
535 	  N_("_Custom Header"),
536 	  NULL,
537 	  NULL,
538 	  G_CALLBACK (action_email_custom_header_cb) }
539 };
540 
541 gboolean
542 e_plugin_ui_init (GtkUIManager *ui_manager,
543                   EMsgComposer *composer)
544 {
545 	GtkhtmlEditor *editor;
546 
547 	editor = GTKHTML_EDITOR (composer);
548 
549 	/* Add actions to the "composer" action group. */
550 	gtk_action_group_add_actions (
551 		gtkhtml_editor_get_action_group (editor, "composer"),
552 		entries, G_N_ELEMENTS (entries), composer);
553 
554 	return TRUE;
555 }
556 
557 static void
558 commit_changes (ConfigData *cd)
559 {
560 	GtkTreeModel *model = NULL;
561 	GPtrArray *headers;
562 	GtkTreeIter iter;
563 	gboolean valid;
564 	GSettings *settings;
565 
566 	headers = g_ptr_array_new_full (3, g_free);
567 
568 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview));
569 	valid = gtk_tree_model_get_iter_first (model, &iter);
570 
571 	while (valid) {
572 		gchar *keyword = NULL, *value = NULL;
573 
574 		gtk_tree_model_get (
575 			model, &iter,
576 			HEADER_KEY_COLUMN, &keyword,
577 			HEADER_VALUE_COLUMN, &value,
578 			-1);
579 
580                 /* Check if the keyword is not empty */
581 		if ((keyword) && (g_utf8_strlen (g_strstrip (keyword), -1) > 0)) {
582 			if ((value) && (g_utf8_strlen (g_strstrip (value), -1) > 0)) {
583 				gchar *tmp = keyword;
584 
585 				keyword = g_strconcat (keyword, "=", value, NULL);
586 				g_free (tmp);
587 			}
588 			g_ptr_array_add (headers, g_strdup (keyword));
589 		}
590 
591 		g_free (keyword);
592 		g_free (value);
593 
594 		valid = gtk_tree_model_iter_next (model, &iter);
595 	}
596 
597 	g_ptr_array_add (headers, NULL);
598 
599 	settings = g_settings_new (ECM_SETTINGS_ID);
600 	g_settings_set_strv (settings, ECM_SETTINGS_KEY, (const gchar * const *) headers->pdata);
601 	g_object_unref (settings);
602 
603 	g_ptr_array_free (headers, TRUE);
604 }
605 
606 static void
607 cell_edited_cb (GtkCellRendererText *cell,
608                 gchar *path_string,
609                 gchar *new_text,
610                 ConfigData *cd)
611 {
612 	GtkTreeModel *model;
613 	GtkTreeIter iter;
614 
615 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview));
616 	gtk_tree_model_get_iter_from_string (model, &iter, path_string);
617 
618 	if (new_text == NULL || *g_strstrip (new_text) == '\0')
619 		gtk_button_clicked (GTK_BUTTON (cd->header_remove));
620 	else {
621 		gtk_list_store_set (
622 			GTK_LIST_STORE (model), &iter,
623 			HEADER_KEY_COLUMN, new_text, -1);
624 		commit_changes (cd);
625 	}
626 }
627 
628 static void
629 cell_editing_canceled_cb (GtkCellRenderer *cell,
630                           ConfigData *cd)
631 {
632 	gtk_button_clicked (GTK_BUTTON (cd->header_remove));
633 }
634 
635 static void
636 cell_value_edited_cb (GtkCellRendererText *cell,
637                       gchar *path_string,
638                       gchar *new_text,
639                       ConfigData *cd)
640 {
641 	GtkTreeModel *model;
642 	GtkTreeIter iter;
643 
644 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview));
645 
646 	gtk_tree_model_get_iter_from_string (model, &iter, path_string);
647 
648 	gtk_list_store_set (
649 		GTK_LIST_STORE (model), &iter,
650 		HEADER_VALUE_COLUMN, new_text, -1);
651 
652 	commit_changes (cd);
653 }
654 
655 static void
656 header_add_clicked (GtkButton *button,
657                     ConfigData *cd)
658 {
659 	GtkTreeModel *model;
660 	GtkTreeView *tree_view;
661 	GtkTreeViewColumn *column;
662 	GtkTreePath *path;
663 	GtkTreeIter iter;
664 
665 	tree_view = GTK_TREE_VIEW (cd->treeview);
666 	model = gtk_tree_view_get_model (tree_view);
667 
668 	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
669 
670 	path = gtk_tree_model_get_path (model, &iter);
671 	column = gtk_tree_view_get_column (tree_view, HEADER_KEY_COLUMN);
672 	gtk_tree_view_set_cursor (tree_view, path, column, TRUE);
673 	gtk_tree_view_row_activated (tree_view, path, column);
674 	gtk_tree_path_free (path);
675 }
676 
677 static void
678 header_remove_clicked (GtkButton *button,
679                        ConfigData *cd)
680 {
681 	GtkTreeSelection *selection;
682 	GtkTreeModel *model;
683 	GtkTreeIter iter;
684 	GtkTreePath *path;
685 	gboolean valid;
686 	gint len;
687 
688 	valid = FALSE;
689 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->treeview));
690 	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
691 		return;
692 
693 	/* Get the path and move to the previous node :) */
694 	path = gtk_tree_model_get_path (model, &iter);
695 	if (path)
696 		valid = gtk_tree_path_prev (path);
697 
698 	gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
699 
700 	len = gtk_tree_model_iter_n_children (model, NULL);
701 	if (len > 0) {
702 		if (gtk_list_store_iter_is_valid (GTK_LIST_STORE (model), &iter)) {
703 			gtk_tree_selection_select_iter (selection, &iter);
704 		} else {
705 			if (path && valid) {
706 				gtk_tree_model_get_iter (model, &iter, path);
707 				gtk_tree_selection_select_iter (selection, &iter);
708 			}
709 		}
710 	} else {
711 		gtk_widget_set_sensitive (cd->header_edit, FALSE);
712 		gtk_widget_set_sensitive (cd->header_remove, FALSE);
713 	}
714 
715 	gtk_widget_grab_focus (cd->treeview);
716 	gtk_tree_path_free (path);
717 
718 	commit_changes (cd);
719 }
720 
721 static void
722 header_edit_clicked (GtkButton *button,
723                      ConfigData *cd)
724 {
725 	GtkTreeSelection *selection;
726 	GtkTreeModel *model;
727 	GtkTreePath *path;
728 	GtkTreeIter iter;
729 	GtkTreeViewColumn *focus_col;
730 
731 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->treeview));
732 	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
733 		return;
734 
735 	focus_col = gtk_tree_view_get_column (GTK_TREE_VIEW (cd->treeview), HEADER_KEY_COLUMN);
736 	path = gtk_tree_model_get_path (model, &iter);
737 
738 	if (path) {
739 		gtk_tree_view_set_cursor (GTK_TREE_VIEW (cd->treeview), path, focus_col, TRUE);
740 		gtk_tree_path_free (path);
741 	}
742 }
743 
744 static void
745 selection_changed (GtkTreeSelection *selection,
746                    ConfigData *cd)
747 {
748 	GtkTreeModel *model;
749 	GtkTreeIter iter;
750 
751 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
752 		gtk_widget_set_sensitive (cd->header_edit, TRUE);
753 		gtk_widget_set_sensitive (cd->header_remove, TRUE);
754 	} else {
755 		gtk_widget_set_sensitive (cd->header_edit, FALSE);
756 		gtk_widget_set_sensitive (cd->header_remove, FALSE);
757 	}
758 }
759 
760 static void
761 destroy_cd_data (gpointer data)
762 {
763 	ConfigData *cd = (ConfigData *) data;
764 
765 	if (!cd)
766 		return;
767 
768 	g_free (cd);
769 }
770 
771 GtkWidget *
772 e_plugin_lib_get_configure_widget (EPlugin *epl)
773 {
774 	GtkCellRenderer *renderer;
775 	GtkTreeSelection *selection;
776 	GtkTreeIter iter;
777 	GtkWidget *hbox;
778 	gchar **headers;
779 	gint index;
780 	GtkTreeViewColumn *col;
781 	gint col_pos;
782 	GSettings *settings;
783 	ConfigData *cd = g_new0 (ConfigData, 1);
784 
785 	GtkWidget *ech_configuration_box;
786 	GtkWidget *vbox2;
787 	GtkWidget *label1;
788 	GtkWidget *header_configuration_box;
789 	GtkWidget *header_container;
790 	GtkWidget *scrolledwindow1;
791 	GtkWidget *header_treeview;
792 	GtkWidget *vbuttonbox1;
793 	GtkWidget *header_add;
794 	GtkWidget *header_edit;
795 	GtkWidget *header_remove;
796 
797 	ech_configuration_box = gtk_vbox_new (FALSE, 6);
798 	gtk_widget_show (ech_configuration_box);
799 
800 	vbox2 = gtk_vbox_new (FALSE, 0);
801 	gtk_widget_show (vbox2);
802 	gtk_box_pack_start (GTK_BOX (ech_configuration_box), vbox2, FALSE, FALSE, 0);
803 
804 	/* To translators: This string is used while adding a new message header to configuration, to specifying the format of the key values */
805 	label1 = gtk_label_new (_("The format for specifying a Custom Header key value is:\nName of the Custom Header key values separated by \";\"."));
806 	gtk_widget_show (label1);
807 	gtk_box_pack_start (GTK_BOX (vbox2), label1, FALSE, TRUE, 0);
808 	gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_CENTER);
809 	gtk_label_set_line_wrap (GTK_LABEL (label1), TRUE);
810 
811 	header_configuration_box = gtk_vbox_new (FALSE, 6);
812 	gtk_widget_show (header_configuration_box);
813 	gtk_box_pack_start (GTK_BOX (ech_configuration_box), header_configuration_box, TRUE, TRUE, 0);
814 
815 	header_container = gtk_hbox_new (FALSE, 12);
816 	gtk_widget_show (header_container);
817 	gtk_box_pack_start (GTK_BOX (header_configuration_box), header_container, TRUE, TRUE, 0);
818 
819 	scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
820 	gtk_widget_show (scrolledwindow1);
821 	gtk_box_pack_start (GTK_BOX (header_container), scrolledwindow1, TRUE, TRUE, 0);
822 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
823 
824 	header_treeview = gtk_tree_view_new ();
825 	gtk_widget_show (header_treeview);
826 	gtk_container_add (GTK_CONTAINER (scrolledwindow1), header_treeview);
827 	gtk_container_set_border_width (GTK_CONTAINER (header_treeview), 1);
828 
829 	vbuttonbox1 = gtk_vbutton_box_new ();
830 	gtk_widget_show (vbuttonbox1);
831 	gtk_box_pack_start (GTK_BOX (header_container), vbuttonbox1, FALSE, TRUE, 0);
832 	gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox1), GTK_BUTTONBOX_START);
833 	gtk_box_set_spacing (GTK_BOX (vbuttonbox1), 6);
834 
835 	header_add = gtk_button_new_from_stock ("gtk-add");
836 	gtk_widget_show (header_add);
837 	gtk_container_add (GTK_CONTAINER (vbuttonbox1), header_add);
838 	gtk_widget_set_can_default (header_add, TRUE);
839 
840 	header_edit = gtk_button_new_from_stock ("gtk-edit");
841 	gtk_widget_show (header_edit);
842 	gtk_container_add (GTK_CONTAINER (vbuttonbox1), header_edit);
843 	gtk_widget_set_can_default (header_edit, TRUE);
844 
845 	header_remove = gtk_button_new_from_stock ("gtk-remove");
846 	gtk_widget_show (header_remove);
847 	gtk_container_add (GTK_CONTAINER (vbuttonbox1), header_remove);
848 	gtk_widget_set_can_default (header_remove, TRUE);
849 
850 	cd->treeview = header_treeview;
851 
852 	cd->store = gtk_list_store_new (HEADER_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
853 
854 	gtk_tree_view_set_model (GTK_TREE_VIEW (cd->treeview), GTK_TREE_MODEL (cd->store));
855 
856 	renderer = gtk_cell_renderer_text_new ();
857 	col_pos = gtk_tree_view_insert_column_with_attributes (
858 		GTK_TREE_VIEW (cd->treeview), -1, _("Key"),
859 		renderer, "text", HEADER_KEY_COLUMN, NULL);
860 	col = gtk_tree_view_get_column (GTK_TREE_VIEW (cd->treeview), col_pos -1);
861 	gtk_tree_view_column_set_resizable (col, TRUE);
862 	gtk_tree_view_column_set_reorderable (col, TRUE);
863 	g_object_set (col, "min-width", 50, NULL);
864 
865 	g_object_set (renderer, "editable", TRUE, NULL);
866 	g_signal_connect (
867 		renderer, "edited",
868 		G_CALLBACK (cell_edited_cb), cd);
869 	g_signal_connect (
870 		renderer, "editing-canceled",
871 		G_CALLBACK (cell_editing_canceled_cb), cd);
872 
873 	renderer = gtk_cell_renderer_text_new ();
874 	col_pos = gtk_tree_view_insert_column_with_attributes (
875 		GTK_TREE_VIEW (cd->treeview), -1, _("Values"),
876 			renderer, "text", HEADER_VALUE_COLUMN, NULL);
877 	col = gtk_tree_view_get_column (GTK_TREE_VIEW (cd->treeview), col_pos -1);
878 	gtk_tree_view_column_set_resizable (col, TRUE);
879 	gtk_tree_view_column_set_reorderable (col, TRUE);
880 	g_object_set (renderer, "editable", TRUE, NULL);
881 
882 	g_signal_connect (
883 		renderer, "edited",
884 		G_CALLBACK (cell_value_edited_cb), cd);
885 
886 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->treeview));
887 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
888 	g_signal_connect (
889 		selection, "changed",
890 		G_CALLBACK (selection_changed), cd);
891 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (cd->treeview), TRUE);
892 
893 	cd->header_add = header_add;
894 	g_signal_connect (
895 		cd->header_add, "clicked",
896 		G_CALLBACK (header_add_clicked), cd);
897 
898 	cd->header_remove = header_remove;
899 	g_signal_connect (
900 		cd->header_remove, "clicked",
901 		G_CALLBACK (header_remove_clicked), cd);
902 	gtk_widget_set_sensitive (cd->header_remove, FALSE);
903 
904 	cd->header_edit = header_edit;
905 	g_signal_connect (
906 		cd->header_edit, "clicked",
907 		G_CALLBACK (header_edit_clicked), cd);
908 	gtk_widget_set_sensitive (cd->header_edit, FALSE);
909 
910 	/* Populate tree view with values from settings */
911 	settings = g_settings_new (ECM_SETTINGS_ID);
912 	headers = g_settings_get_strv (settings, ECM_SETTINGS_KEY);
913 	g_object_unref (settings);
914 
915 	if (headers) {
916 		gint ii;
917 
918 		for (ii = 0; headers[ii]; ii++) {
919 			gchar **parse_header_list;
920 
921 			gtk_list_store_append (cd->store, &iter);
922 
923 			parse_header_list = g_strsplit_set (headers[ii], "=,", -1);
924 
925 			gtk_list_store_set (cd->store, &iter, HEADER_KEY_COLUMN, parse_header_list[0], -1);
926 
927 			for (index = 0; parse_header_list[index + 1] ; ++index) {
928 				gtk_list_store_set (cd->store, &iter, HEADER_VALUE_COLUMN, parse_header_list[index + 1], -1);
929 			}
930 		}
931 
932 		g_strfreev (headers);
933 	}
934 
935 	/* Add the list here */
936 
937 	hbox = gtk_vbox_new (FALSE, 0);
938 
939 	gtk_box_pack_start (GTK_BOX (hbox), ech_configuration_box, TRUE, TRUE, 0);
940 
941 	/* to let free data properly on destroy of configuration widget */
942 	g_object_set_data_full (G_OBJECT (hbox), "mycd-data", cd, destroy_cd_data);
943 
944 	return hbox;
945 }
946 
947 /* Configuration in Mail Prefs Page goes here */
948 
949 GtkWidget *
950 org_gnome_email_custom_header_config_option (EPlugin *epl,
951                                              struct _EConfigHookItemFactoryData *data)
952 {
953 	/* This function and the hook needs to be removed,
954 	once the configure code is thoroughly tested */
955 
956 	return NULL;
957 
958 }