[PATCH]



	Hi all,
I have done a patch to answer a request from Brian IIRC to add the 
capability for filters to match on user headers. Ie now in the filters 
edit dialog you have 2 new fields (I also have reorganized the dialog a 
bit) in the matching fields frame to let you specify a user header name to 
match on (it is done with a combo list so that it'll propose you the list 
of the user headers already used in all filters).

I had a problem : I wanted to add a newly entered user string in the list 
using gtk_combo_set_popdown_strings but this seemed to confuse gtk. So how 
should I do it?

Please try and comment before I submit it to Pawel.
Thanks
Bye
Manu
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-file.c balsa-test/libbalsa/filter-file.c
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-file.c	Mon Mar 18 16:05:31 2002
+++ balsa-test/libbalsa/filter-file.c	Tue May 28 16:56:37 2002
@@ -72,6 +72,8 @@
     newc->type          = gnome_config_get_int("Type");
     newc->condition_not = gnome_config_get_bool("Condition-not");
     newc->match_fields  = gnome_config_get_int("Match-fields");
+    if (CONDITION_CHKMATCH(newc,CONDITION_MATCH_US_HEAD))
+	newc->user_header = gnome_config_get_string("User-header");
 
     switch(newc->type) {
     case CONDITION_SIMPLE:
@@ -244,12 +246,10 @@
 	g_free(newf->sound);
 	newf->sound=NULL;
     }
-    else FILTER_SETFLAG(newf,FILTER_SOUND);
-    if (newf->popup_text=='\0') {
+    if (newf->popup_text[0]=='\0') {
 	g_free(newf->popup_text);
 	newf->popup_text=NULL;
     }
-    else FILTER_SETFLAG(newf,FILTER_POPUP);
 
     return newf;
 }
@@ -277,6 +277,10 @@
 	gnome_config_clean_key("High-date");
     }
     if (cond->type!=CONDITION_FLAG) gnome_config_clean_key("Flags");
+    if (!CONDITION_CHKMATCH(cond,CONDITION_MATCH_US_HEAD))
+	gnome_config_clean_key("User-header");
+    else
+	gnome_config_set_string("User-header",cond->user_header);
 
     switch(cond->type) {
     case CONDITION_SIMPLE:
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-funcs.c balsa-test/libbalsa/filter-funcs.c
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-funcs.c	Sun Feb 24 16:27:43 2002
+++ balsa-test/libbalsa/filter-funcs.c	Tue May 28 16:56:37 2002
@@ -75,6 +75,8 @@
 	/* to avoid warnings */
 	break;
     }
+    if (cond->user_header)
+	g_free(cond->user_header);
     g_free(cond);
 }	                       /* end libbalsa_condition_free() */
 
@@ -96,8 +98,9 @@
 
     newc->type = CONDITION_NONE;
     newc->match_fields = CONDITION_EMPTY;
-    newc->condition_not=FALSE;
+    newc->condition_not = FALSE;
     newc->match.string = NULL;
+    newc->user_header = NULL;
     filter_errno=FILTER_NOERR;
 
     return newc;
@@ -132,6 +135,7 @@
     new_cnd->condition_not = cnd->condition_not;
     new_cnd->match_fields  = cnd->match_fields;
     new_cnd->type          = cnd->type;
+    new_cnd->user_header   = g_strdup(cnd->user_header);
     switch (new_cnd->type) {
     case CONDITION_SIMPLE:
         new_cnd->match.string=g_strdup(cnd->match.string);
@@ -207,8 +211,8 @@
  *
  * Position filter_errno (by calling condition_regcomp)
  */
-static void
-condition_compile_regexs(LibBalsaCondition* cond)
+void
+libbalsa_condition_compile_regexs(LibBalsaCondition* cond)
 {
     GSList * regex;
 
@@ -231,6 +235,8 @@
 filter_condition_validity(LibBalsaFilter* fil, LibBalsaCondition* cond)
 {
     /* Test validity of condition */
+    if (CONDITION_CHKMATCH(cond,CONDITION_MATCH_US_HEAD) && (!cond->user_header || cond->user_header[0]=='\0'))
+	FILTER_CLRFLAG(fil,FILTER_VALID);
     switch (cond->type) {
     case CONDITION_SIMPLE:
 	if (!cond->match.string)
@@ -281,7 +287,7 @@
     if (fil->conditions) {
 	GSList * lst;
 	for (lst=fil->conditions;lst && filter_errno==FILTER_NOERR;lst=g_slist_next(lst))
-	    condition_compile_regexs((LibBalsaCondition*) lst->data);
+	    libbalsa_condition_compile_regexs((LibBalsaCondition*) lst->data);
 	if (filter_errno != FILTER_NOERR) {
 	    gchar * errorstring =
                 g_strdup_printf("Unable to compile filter %s", fil->name);
@@ -406,6 +412,7 @@
 	    str=g_string_append(str,"\"Subject\"");
 	coma=TRUE;
     }
+    /* FIXME : see how to export conditions matching user headers */
     g_string_append(str,"] ");
     if (str->len>3) {
 	gchar * temp=g_strdup_printf(str_format,"header",str->str);
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-funcs.h balsa-test/libbalsa/filter-funcs.h
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-funcs.h	Mon Nov 26 10:07:00 2001
+++ balsa-test/libbalsa/filter-funcs.h	Tue May 28 16:56:37 2002
@@ -44,7 +44,7 @@
 LibBalsaCondition* libbalsa_condition_clone(LibBalsaCondition* cnd);
 void libbalsa_condition_regex_free(LibBalsaConditionRegex *, gpointer);
 void regexs_free(GSList *);
-
+void libbalsa_condition_compile_regexs(LibBalsaCondition* cond);
 /* Filters */
 /* Free a filter
  * free_condition is a gint into a gpointer : if <>0 the function frees filter conditions also
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-private.h balsa-test/libbalsa/filter-private.h
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/filter-private.h	Mon Nov 26 10:07:00 2001
+++ balsa-test/libbalsa/filter-private.h	Tue May 28 16:56:37 2002
@@ -50,6 +50,7 @@
 #define CONDITION_MATCH_FROM    1<<1	/* match in the From: field */
 #define CONDITION_MATCH_SUBJECT 1<<2	/* match in the Subject field */
 #define CONDITION_MATCH_CC      1<<3	/* match in the cc: field */
+#define CONDITION_MATCH_US_HEAD 1<<4    /* match in a user header */
 #define CONDITION_MATCH_BODY    1<<7	/* match in the body */
 
 /* match_fields macros */
@@ -74,8 +75,6 @@
 #define FILTER_VALID         1<<1	/* ready to filter (eg regex strings 
 					   have been compiled with regcomp(), with no errors...) */					
 #define FILTER_COMPILED      1<<2	/* the filter needs to be compiled (ie there are uncompiled regex) */
-#define FILTER_SOUND         1<<4	/* play a sound when matches */
-#define FILTER_POPUP         1<<5	/* popup text when matches */
 
 /* flag operation macros */
 #define FILTER_SETFLAG(x, y) ((((LibBalsaFilter*)(x))->flags) |= (y))
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/filter.c balsa-test/libbalsa/filter.c
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/filter.c	Thu May 16 06:34:55 2002
+++ balsa-test/libbalsa/filter.c	Tue May 28 16:56:37 2002
@@ -120,6 +120,18 @@
 	    g_free(str);
 	    if (match) break;
 	}
+	if (CONDITION_CHKMATCH(cond,CONDITION_MATCH_US_HEAD)) {
+	    if (cond->user_header) {
+		GList * header =
+		    libbalsa_message_find_user_hdr(message, cond->user_header);
+
+		if (header) {
+		    gchar ** tmp = header->data;
+		    match = in_string(tmp[1],cond->match.string);
+		    if (match) break;
+		}
+	    }
+	}
 	if (CONDITION_CHKMATCH(cond,CONDITION_MATCH_BODY)) {
 	    gboolean is_new = (message->flags & LIBBALSA_MESSAGE_FLAG_NEW);
 	    if (!libbalsa_message_body_ref(message)) {
@@ -166,6 +178,18 @@
 		g_free(str);
 		if (match) break;
 	    }
+	    if (CONDITION_CHKMATCH(cond,CONDITION_MATCH_US_HEAD)) {
+		if (cond->user_header) {
+		    GList * header =
+			libbalsa_message_find_user_hdr(message, cond->user_header);
+		    
+		    if (header) {
+			gchar ** tmp = header->data;
+			if (tmp[1] && (match=REGEXEC(*(regex->compiled),tmp[1])==0))
+			    break;
+		    }
+		}
+	    }
 	    if (CONDITION_CHKMATCH(cond,CONDITION_MATCH_BODY)) {
                 gboolean is_new = (message->flags & LIBBALSA_MESSAGE_FLAG_NEW);
 		if (!libbalsa_message_body_ref(message)) {
@@ -254,6 +278,7 @@
             query = extend_query(query, "CC", cond->match.string, op);
 	if (CONDITION_CHKMATCH(cond,CONDITION_MATCH_BODY))
             query = extend_query(query, "TEXT", cond->match.string, op);
+	/* FIXME : extend that for user headers matching */
     }
     str = query->str;
     g_string_free(query, FALSE);
@@ -262,8 +287,6 @@
 
 /*--------- Filtering functions -------------------------------*/
 
-/* FIXME : Add error reporting for each filter */
-
 gint
 filters_prepare_to_run(GSList * filters)
 {
@@ -287,21 +310,18 @@
 /*
  * Run all filters until one matches (so order of filter is important)
  * filters must be valid and compiled (ie filters_prepare_to_run have been called before)
- * Assume that all messages come from ONE mailbox
- * returns TRUE if the trash bin has been filled
- * FIXME : Should position filter_errno on errors (bad command action,bad destination mailbox...)
+ * In general you'll call this function with mailbox lock held (ie you locked the mailbox
+ * you're filtering before calling this function)
  */
 
-gboolean
-filters_run_on_messages(GSList * filter_list, GList * messages)
+void
+libbalsa_filter_match(GSList * filter_list, GList * messages)
 {
     gint match;
     GSList * lst;
-    GList * lst_messages;
     LibBalsaFilter * filt=NULL;
-    gboolean result=FALSE;
 
-    if (!filter_list || ! messages) return FALSE;
+    if (!filter_list || ! messages) return;
 
     for (;messages;messages=g_list_next(messages)) {
 
@@ -316,17 +336,38 @@
 	    filt->matching_messages=g_list_prepend(filt->matching_messages,LIBBALSA_MESSAGE(messages->data));
 	}
     }
+}
+
+void libbalsa_filter_match_mailbox(GSList * filter_list, LibBalsaMailbox * mbox)
+{
+    LOCK_MAILBOX(mbox);
+    libbalsa_filter_match(filter_list, mbox->message_list);
+    UNLOCK_MAILBOX(mbox);
+}
+
+/* Apply all filters on their matching messages (call libbalsa_filter_match before)
+ * returns TRUE if the trash bin has been filled
+ * FIXME : Should position filter_errno on errors (bad command action,bad destination mailbox...)
+ */
+
+gboolean
+libbalsa_filter_apply(GSList * filter_list)
+{
+    GSList * lst;
+    GList * lst_messages;
+    LibBalsaFilter * filt=NULL;
+    gboolean result=FALSE;
+    LibBalsaMailbox *mbox;
 
-    /* OK we have done all the matching thing, now we take every action for matching messages */
+    if (!filter_list) return FALSE;
 
     for (lst=filter_list;lst;lst=g_slist_next(lst)) {
-	LibBalsaMailbox *mbox;
  
 	filt=(LibBalsaFilter*)lst->data;
-	if (FILTER_CHKFLAG(filt,FILTER_SOUND)) {
+	if (filt->sound) {
 	    /* FIXME : Emit sound */
 	}
-	if (FILTER_CHKFLAG(filt,FILTER_POPUP)) {
+	if (filt->popup_text) {
 	    /* FIXME : Print popup text */
 	}
 	if (filt->matching_messages) {
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/filter.h balsa-test/libbalsa/filter.h
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/filter.h	Thu May 16 06:34:55 2002
+++ balsa-test/libbalsa/filter.h	Tue May 28 16:56:37 2002
@@ -74,6 +74,8 @@
 	LibBalsaMessageFlag flags;
     } match;
     guint match_fields;         /* Contains the flag mask for CONDITION_FLAG type */
+    gchar * user_header;        /* This is !=NULL and gives the name of the user
+				   header against which we make the match */
 } LibBalsaCondition;
 
 /* Filter definition :
@@ -178,13 +180,27 @@
 
 gint filters_prepare_to_run(GSList * filters);
 
-/* filters_run_on_messages run all filters on the list of messages
+/* libbalsa_filter_match run all filters on the list of messages
+   each filter is stuffed with the list of its matching messages
+   you must call libbalsa_filter_apply after to make the filters
+   act on their matching messages (this split is needed for proper
+   locking)
+ */
+
+void libbalsa_filter_match(GSList * filter_list, GList * messages);
+
+/* Same but on mailbox, convenience function that locks the mailbox
+   before calling libbalsa_filter_match */
+
+void libbalsa_filter_match_mailbox(GSList * filter_list, LibBalsaMailbox * mbox);
+
+/* libbalsa_filter_apply will let all filters to apply on their
+ * matching messages (you must call libbalsa_filters_match before)
  * It returns TRUE if the trash bin has been filled with something
  * this is used to call enable_empty_trash after
- * FIXME : No locking is done for now
  */
 
-gboolean filters_run_on_messages(GSList * filter_list, GList * messages);
+gboolean libbalsa_filter_apply(GSList * filter_list);
 
 /* libalsa_extract_new_messages : returns a sublist of the messages list containing all
    "new" messages, ie just retrieved mails
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/mailbox_local.c balsa-test/libbalsa/mailbox_local.c
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/mailbox_local.c	Fri May 17 08:15:11 2002
+++ balsa-test/libbalsa/mailbox_local.c	Tue May 28 16:56:37 2002
@@ -239,14 +239,18 @@
                                             FILTER_WHEN_INCOMING);
     /* We apply filter if needed */
     if (filters) {
+	LOCK_MAILBOX(mailbox);
 	new_messages=libbalsa_extract_new_messages(mailbox->message_list);
 	if (new_messages) {
-	    if (filters_prepare_to_run(filters))
-		filters_run_on_messages(filters, new_messages);
-	    /* FIXME : do better error report */
-	    else g_warning("Filter error\n");
+	    if (filters_prepare_to_run(filters)) {
+		libbalsa_filter_match(filters, new_messages);
+		UNLOCK_MAILBOX(mailbox);
+		libbalsa_filter_apply(filters);
+	    }
+	    else UNLOCK_MAILBOX(mailbox);
 	    g_list_free(new_messages);
 	}
+	else UNLOCK_MAILBOX(mailbox);
 	g_slist_free(filters);
     }
 }
diff -u /home/manu/prog/balsa-cvs/balsa/libbalsa/mailbox_pop3.c balsa-test/libbalsa/mailbox_pop3.c
--- /home/manu/prog/balsa-cvs/balsa/libbalsa/mailbox_pop3.c	Thu May 16 06:35:01 2002
+++ balsa-test/libbalsa/mailbox_pop3.c	Tue May 28 16:56:37 2002
@@ -308,10 +308,10 @@
         filters = libbalsa_mailbox_filters_when(mailbox->filters,
 						FILTER_WHEN_INCOMING);
 	if (filters) {
-	    if (filters_prepare_to_run(filters))
-		filters_run_on_messages(filters, tmp_mailbox->message_list);
-	    /* FIXME : do better error report */
-	    else g_warning("Filter error\n");
+	    if (filters_prepare_to_run(filters)) {
+		libbalsa_filter_match(filters, tmp_mailbox->message_list);
+		libbalsa_filter_apply(filters);
+	    }
 	    g_slist_free(filters);
 	}
 
diff -u /home/manu/prog/balsa-cvs/balsa/src/filter-edit-callbacks.c balsa-test/src/filter-edit-callbacks.c
--- /home/manu/prog/balsa-cvs/balsa/src/filter-edit-callbacks.c	Wed May  8 08:49:07 2002
+++ balsa-test/src/filter-edit-callbacks.c	Thu May 30 15:21:03 2002
@@ -43,10 +43,14 @@
 extern option_list fe_search_type[4];
 extern GtkWidget * build_option_menu(option_list options[], gint num, 
                                      GtkSignalFunc func);
+extern GList * fe_user_headers_list;
+
 static void fe_add_pressed(GtkWidget * widget, gpointer throwaway);
 static void fe_remove_pressed(GtkWidget * widget, gpointer throwaway);
 static void fe_regexs_select_row(GtkWidget * widget, gint row, gint column,
                                  GdkEventButton * bevent, gpointer data);
+static void fe_free_associated_filters(void);
+static void fe_free_associated_conditions(void);
 
 /* The dialog widget (we need it to be able to close dialog on error) */
 
@@ -74,6 +78,9 @@
 GtkWidget *fe_matching_fields_from;
 GtkWidget *fe_matching_fields_subject;
 GtkWidget *fe_matching_fields_cc;
+/* Combo list for user headers and check button*/
+GtkCombo * fe_user_header;
+GtkWidget * fe_matching_fields_us_head;
 
 /* widget for the conditions */
 extern GtkCList *fe_conditions_list;
@@ -155,6 +162,28 @@
  */
 static GList * new_filters_names=NULL;
 
+/* Free filters associated with clist row */
+static void
+fe_free_associated_filters(void)
+{
+    gint row;
+
+    for (row=0;row<fe_filters_list->rows;row++)
+	libbalsa_filter_free((LibBalsaFilter*)
+                             gtk_clist_get_row_data(fe_filters_list,row),
+                             GINT_TO_POINTER(TRUE));
+}
+
+static void
+fe_free_associated_conditions(void)
+{
+    gint row;
+
+    for (row=0; row<fe_conditions_list->rows; row++)
+	libbalsa_condition_free((LibBalsaCondition *)
+                                gtk_clist_get_row_data(fe_conditions_list,row));
+}
+
 /*
  * unique_filter_name()
  *
@@ -325,14 +354,21 @@
     gboolean active=GPOINTER_TO_INT(data)!=3;  /* 3== uncheck all buttons */
 
     condition_has_changed=TRUE;
-    if (!active || GPOINTER_TO_INT(data)==1) /* 1== check all buttons */
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_body),active);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_body),active);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_to),active);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_from),active);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_subject),active);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_cc),active);
 }                       /* end fe_match_fields_buttons_cb */
 
+static void
+fe_match_field_user_header_cb(GtkWidget * widget)
+{
+    gtk_widget_set_sensitive(GTK_WIDGET(fe_user_header),
+			     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fe_matching_fields_us_head)));
+    condition_has_changed=TRUE;
+}
+
 /* FIXME : to insure consistency and keep it simple I use a modal dialog box for condition edition/creation
  * but I have to avoid libbalsa_information (this is not modal and does not get the focus because mine is modal
  * so you end up with the small info box floating around and insensitive), so I use this function
@@ -348,6 +384,20 @@
     gnome_dialog_run(err_dia);
 }
 
+void
+fe_add_new_user_header(const gchar * str)
+{
+    GList * lst = fe_user_headers_list;
+
+    for (;lst;lst=g_list_next(lst))
+	if (g_strcasecmp(str,(gchar *)lst->data)==0) return;
+
+    /* It's a new string, add it */
+    fe_user_headers_list=g_list_insert_sorted(fe_user_headers_list,
+					      g_strdup(str),
+					      (GCompareFunc)g_strcasecmp);
+}
+
 /* conditon_validate is responsible of validating
  * the changes to the current condition, according to the widgets
  * Performs sanity check on the widgets 
@@ -363,6 +413,7 @@
     gchar * str,* p;
     gint match,row,col;
     struct tm date;
+    GList * lst;
 
     /* Sanity checks, prevent "empty" condition */
 
@@ -380,7 +431,24 @@
             CONDITION_SETMATCH(new_cnd,CONDITION_MATCH_FROM);
         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fe_matching_fields_cc)))
             CONDITION_SETMATCH(new_cnd,CONDITION_MATCH_CC);
-        if (new_cnd->match_fields==CONDITION_EMPTY) {
+        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fe_matching_fields_us_head))) {
+	    CONDITION_SETMATCH(new_cnd,CONDITION_MATCH_US_HEAD);
+	    str=gtk_entry_get_text(GTK_ENTRY(fe_user_header->entry));
+	    if (!str[0]) {
+		condition_error(_("You must specify the name of the user header to match on"));
+		return FALSE;
+	    }
+	    fe_add_new_user_header(str);
+	    /* Update combo */
+	    /* FIXME : this piece of code is supposed to replace the combo list
+	       by a new one that contains the new string the user has entered
+	       but this seems to confuse the whole thing
+	    gtk_combo_set_popdown_strings(fe_user_header,fe_user_headers_list);
+	    gtk_entry_set_text(GTK_ENTRY(fe_user_header->entry),str);
+	    for (lst=fe_user_headers_list;lst;lst=g_list_next(lst))
+	    g_print("String = %s\n",(gchar*) lst->data);*/
+	}
+        else if (new_cnd->match_fields==CONDITION_EMPTY) {
             condition_error(_("You must specify at least one field for matching"));
             return FALSE;
         }
@@ -439,7 +507,8 @@
     /* Sanity checks OK, retrieve datas from widgets */
 
     new_cnd->condition_not=condition_not;
-
+    if (CONDITION_CHKMATCH(new_cnd,CONDITION_MATCH_US_HEAD))
+	new_cnd->user_header=g_strdup(gtk_entry_get_text(GTK_ENTRY(fe_user_header->entry)));
     /* Set the type specific fields of the condition */
     switch (new_cnd->type) {
     case CONDITION_SIMPLE:
@@ -527,6 +596,16 @@
                                  CONDITION_CHKMATCH(cnd,CONDITION_MATCH_SUBJECT) && andmask);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_cc),
                                  CONDITION_CHKMATCH(cnd,CONDITION_MATCH_CC) && andmask);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_matching_fields_us_head),
+                                 CONDITION_CHKMATCH(cnd,CONDITION_MATCH_US_HEAD) && andmask);
+    if (CONDITION_CHKMATCH(cnd,CONDITION_MATCH_US_HEAD) && andmask) {
+	gtk_widget_set_sensitive(GTK_WIDGET(fe_user_header),TRUE);
+	gtk_entry_set_text(GTK_ENTRY(fe_user_header->entry),cnd->user_header ? cnd->user_header : "");
+    }
+    else {
+	gtk_widget_set_sensitive(GTK_WIDGET(fe_user_header),FALSE);
+	gtk_entry_set_text(GTK_ENTRY(fe_user_header->entry),"");
+    }	
     /* Next update type specific fields */
     switch (cnd->type) {
     case CONDITION_SIMPLE:
@@ -636,7 +715,7 @@
     GtkWidget *button;
     gint row,col;
     static gchar * flag_names[]=
-        {N_("New"), N_("Deleted"), N_("Replied"), N_("Flagged")};
+        {N_("Unread"), N_("Deleted"), N_("Replied"), N_("Flagged")};
 
     /* The notebook */
 
@@ -814,7 +893,7 @@
 {
     GtkWidget * table,* frame,* button,* page,* box;
 
-    page = gtk_table_new(3, 7, FALSE);
+    page = gtk_table_new(7, 2, FALSE);
     /* builds the toggle buttons to specify fields concerned by the conditions of
      * the filter */
     
@@ -824,32 +903,24 @@
     gtk_frame_set_shadow_type(GTK_FRAME(fe_match_frame), GTK_SHADOW_ETCHED_IN);
     gtk_table_attach(GTK_TABLE(page),
                      fe_match_frame,
-                     0, 3, 0, 2,
+                     0, 2, 0, 2,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 5, 5);
     
-    table = gtk_table_new(3, 3, TRUE);
+    table = gtk_table_new(5, 2, TRUE);
     gtk_container_add(GTK_CONTAINER(fe_match_frame), table);
     
     button = gtk_button_new_with_label(_("All"));
     gtk_table_attach(GTK_TABLE(table),
                      button,
-                     0, 1, 2, 3,
+                     0, 1, 4, 5,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2); 
     gtk_signal_connect(GTK_OBJECT(button),"clicked",
                        GTK_SIGNAL_FUNC(fe_match_fields_buttons_cb),
                        GINT_TO_POINTER(1));
-    button = gtk_button_new_with_label(_("All headers"));
-    gtk_table_attach(GTK_TABLE(table),
-                     button,
-                     1, 2, 2, 3,
-                     GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
-    gtk_signal_connect(GTK_OBJECT(button),"clicked",
-                       GTK_SIGNAL_FUNC(fe_match_fields_buttons_cb),
-                       GINT_TO_POINTER(2));
     button = gtk_button_new_with_label(_("Clear"));
     gtk_table_attach(GTK_TABLE(table),
                      button,
-                     2, 3, 2, 3,
+                     1, 2, 4, 5,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
     gtk_signal_connect(GTK_OBJECT(button),"clicked",
                        GTK_SIGNAL_FUNC(fe_match_fields_buttons_cb),
@@ -867,7 +938,7 @@
     fe_matching_fields_to = gtk_check_button_new_with_label(_("To:"));
     gtk_table_attach(GTK_TABLE(table),
                      fe_matching_fields_to,
-                     1, 2, 0, 1,
+                     0, 1, 1, 2,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
     gtk_signal_connect(GTK_OBJECT(fe_matching_fields_to),
                        "toggled",
@@ -885,7 +956,7 @@
     fe_matching_fields_subject = gtk_check_button_new_with_label(_("Subject"));
     gtk_table_attach(GTK_TABLE(table),
                      fe_matching_fields_subject,
-                     2, 3, 0, 1,
+                     0, 1, 2, 3,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
     gtk_signal_connect(GTK_OBJECT(fe_matching_fields_subject),
                        "toggled",
@@ -894,20 +965,40 @@
     fe_matching_fields_cc = gtk_check_button_new_with_label(_("Cc:"));
     gtk_table_attach(GTK_TABLE(table),
                      fe_matching_fields_cc,
-                     2, 3, 1, 2,
+                     1, 2, 2, 3,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
     gtk_signal_connect(GTK_OBJECT(fe_matching_fields_cc),
                        "toggled",
                        GTK_SIGNAL_FUNC(fe_condition_changed_cb),
                        NULL);
-
+    fe_matching_fields_us_head = gtk_check_button_new_with_label(_("User header:"));
+    gtk_table_attach(GTK_TABLE(table),
+                     fe_matching_fields_us_head,
+                     0, 1, 3, 4,
+                     GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+    gtk_signal_connect(GTK_OBJECT(fe_matching_fields_us_head),
+                       "toggled",
+                       GTK_SIGNAL_FUNC(fe_match_field_user_header_cb),
+                       NULL);
+    fe_user_header = GTK_COMBO(gtk_combo_new());
+    gtk_combo_set_value_in_list(fe_user_header,FALSE,FALSE);
+    gtk_combo_set_case_sensitive(fe_user_header,FALSE);
+    gtk_combo_set_popdown_strings(fe_user_header,fe_user_headers_list);
+    gtk_signal_connect(GTK_OBJECT(fe_user_header->entry),
+                       "changed", GTK_SIGNAL_FUNC(fe_condition_changed_cb), 
+                       NULL);
+    gtk_table_attach(GTK_TABLE(table),
+                     GTK_WIDGET(fe_user_header),
+                     1, 2, 3, 4,
+                     GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+    
     frame = gtk_frame_new(_("Selected condition search type:"));
     gtk_frame_set_label_align(GTK_FRAME(frame), GTK_POS_LEFT, GTK_POS_TOP);
     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
     gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
     gtk_table_attach(GTK_TABLE(page),
                      frame,
-                     0, 3, 2, 3,
+                     0, 2, 2, 3,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 5, 5);
     box = gtk_hbox_new(FALSE, 5);
     gtk_container_add(GTK_CONTAINER(frame), box);
@@ -920,7 +1011,7 @@
     build_type_notebook();
     gtk_table_attach(GTK_TABLE(page),
                      fe_type_notebook,
-                     0, 3, 3, 7,
+                     0, 2, 3, 7,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, 5, 5);
     gtk_box_pack_start(GTK_BOX(condition_dialog->vbox),page,FALSE,FALSE,2);
@@ -939,10 +1030,10 @@
     LibBalsaCondition* cnd=NULL;
     gint row=-1;
 
-    if (!fe_filters_list->selection || 
-        (!is_new_cnd && !fe_conditions_list->selection)) return;
-
     is_new_condition=GPOINTER_TO_INT(is_new_cnd);
+
+    if (!fe_filters_list->selection && !is_new_condition) return;
+
     if (!is_new_condition) {
         row=GPOINTER_TO_INT(fe_conditions_list->selection->data);
         cnd=(LibBalsaCondition*)gtk_clist_get_row_data(fe_conditions_list,row);
@@ -1124,6 +1215,11 @@
     new_filters_names=NULL;
 
     fe_already_open=FALSE;
+
+    /* free all strings in fe_user_headers_list */
+    g_list_foreach(fe_user_headers_list,(GFunc)g_free,NULL);
+    g_list_free(fe_user_headers_list);
+    fe_user_headers_list = NULL;
 }
 
 /*
@@ -1502,38 +1598,30 @@
     if (fil->action!=FILTER_TRASH)
         fil->action_string=g_strdup(mailbox_name);
 
-    if (GTK_TOGGLE_BUTTON(fe_popup_button)->active) {
+    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fe_popup_button))) {
         static gchar defstring[19] = N_("Filter has matched");
         gchar *tmpstr;
         
-        FILTER_SETFLAG(fil, FILTER_POPUP);
         tmpstr = gtk_entry_get_text(GTK_ENTRY(fe_popup_entry));
         
         fil->popup_text=g_strdup(((!tmpstr)
                                   || (tmpstr[0] ==
                                       '\0')) ? _(defstring) : tmpstr);
     }
-    else {
-        g_free(fil->popup_text);
-        fil->popup_text=NULL;
-    }
 
 #ifdef HAVE_LIBESD
-    if (GTK_TOGGLE_BUTTON(fe_sound_button)->active) {
+    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fe_sound_button))) {
         gchar *tmpstr;
         
         FILTER_SETFLAG(fil, FILTER_SOUND);
         tmpstr = gtk_entry_get_text(GTK_ENTRY(fe_sound_entry));
         if ((!tmpstr) || (tmpstr[0] == '\0')) {
             libbalsa_filter_free(fil, GINT_TO_POINTER(TRUE));
-            /* FIXME error_dialog("You must provide a sound to play") */
+	    balsa_information(LIBBALSA_INFORMATION_ERROR,
+			      _("You must provide a sound to play"));
             return;
         }
-        fil->popup_sound(tmpstr);
-    }
-    else {
-        g_free(fil->sound);
-        fil->sound=NULL;
+        fil->sound=g_strdup(tmpstr);
     }
 #endif
     /* New filter is OK, we replace the old one */
@@ -1590,14 +1678,14 @@
     /* Populate all fields with filter data */
     gtk_entry_set_text(GTK_ENTRY(fe_name_entry),fil->name);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_popup_button),
-                                 FILTER_CHKFLAG(fil,FILTER_POPUP));
+                                 fil->popup_text!=NULL);
     gtk_entry_set_text(GTK_ENTRY(fe_popup_entry),
-                       FILTER_CHKFLAG(fil,FILTER_POPUP) 
+                       fil->popup_text!=NULL
                        ? fil->popup_text : "");
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fe_sound_button),
-                                 FILTER_CHKFLAG(fil,FILTER_SOUND));
+                                 fil->sound!=NULL);
     gtk_entry_set_text(GTK_ENTRY(gnome_file_entry_gtk_entry(GNOME_FILE_ENTRY(fe_sound_entry))),
-                       FILTER_CHKFLAG(fil,FILTER_SOUND) ? fil->sound : "");
+                       fil->sound!=NULL ? fil->sound : "");
     
     gtk_option_menu_set_history(GTK_OPTION_MENU(fe_action_option_menu), 
                                 fil->action-1);
@@ -1653,4 +1741,3 @@
     gtk_widget_set_sensitive(fe_revert_button, TRUE);
     fe_enable_right_page(TRUE);
 }                      /* end fe_clist_select_row */
-
diff -u /home/manu/prog/balsa-cvs/balsa/src/filter-edit-dialog.c balsa-test/src/filter-edit-dialog.c
--- /home/manu/prog/balsa-cvs/balsa/src/filter-edit-dialog.c	Sat May 18 14:29:10 2002
+++ balsa-test/src/filter-edit-dialog.c	Tue May 28 16:56:37 2002
@@ -57,6 +57,9 @@
 /* widget for the conditions */
 GtkCList *fe_conditions_list;
 
+/* List of strings in the combo of user headers name */
+GList * fe_user_headers_list;
+
 /* notification field */
 GtkWidget *fe_sound_button;
 GtkWidget *fe_sound_entry;
@@ -156,28 +159,6 @@
     return (option_menu);
 }				/* end build_option_menu */
 
-/* Free filters associated with clist row */
-void
-fe_free_associated_filters(void)
-{
-    gint row;
-
-    for (row=0;row<fe_filters_list->rows;row++)
-	libbalsa_filter_free((LibBalsaFilter*)
-                             gtk_clist_get_row_data(fe_filters_list,row),
-                             GINT_TO_POINTER(TRUE));
-}
-
-void
-fe_free_associated_conditions(void)
-{
-    gint row;
-
-    for (row=0; row<fe_conditions_list->rows; row++)
-	libbalsa_condition_free((LibBalsaCondition *)
-                                gtk_clist_get_row_data(fe_conditions_list,row));
-}
-
 static void
 fe_clist_unselect_row(GtkWidget * widget, gint row, gint column, 
                       GdkEventButton *event, gpointer data)
@@ -416,8 +397,9 @@
     gtk_frame_set_label_align(GTK_FRAME(frame), GTK_POS_LEFT, GTK_POS_TOP);
     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
     gtk_box_pack_start(GTK_BOX(page), frame, FALSE, FALSE, 2);
+    gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
 
-    table = gtk_table_new(2, 2, FALSE);
+    table = gtk_table_new(3, 2, FALSE);
     gtk_container_add(GTK_CONTAINER(frame), table);
 
     /* Notification buttons */
@@ -587,6 +569,7 @@
     gtk_widget_set_sensitive(fe_right_page, FALSE);
     gtk_box_pack_start(GTK_BOX(hbox), piece, TRUE, TRUE, 2);
 
+    fe_user_headers_list=NULL;
     /* Populate the clist of filters */
 
     for(filter_list=balsa_app.filters; 
@@ -618,6 +601,12 @@
             LibBalsaCondition *c = (LibBalsaCondition*)cnds->data;
 	    cpfil->conditions = 
                 g_slist_prepend(cpfil->conditions,libbalsa_condition_clone(c));
+
+	    /* If this condition is a match on a user header,
+	       add the user header name to the combo list */
+	    if (CONDITION_CHKMATCH(c,CONDITION_MATCH_US_HEAD) &&
+		c->user_header && c->user_header[0])
+		fe_add_new_user_header(c->user_header);
         }
 	cpfil->conditions=g_slist_reverse(cpfil->conditions);
 
@@ -631,6 +620,8 @@
 	gtk_clist_set_row_data(fe_filters_list,row,(gpointer)cpfil);
     }
 
+    /* To make sure we have at least one item in the combo list */
+    fe_add_new_user_header("X-Mailer");
     if (filter_errno!=FILTER_NOERR) {
 	filter_perror(filter_strerror(filter_errno));
 	gnome_dialog_close(fe_window);
diff -u /home/manu/prog/balsa-cvs/balsa/src/filter-edit.h balsa-test/src/filter-edit.h
--- /home/manu/prog/balsa-cvs/balsa/src/filter-edit.h	Wed May  8 08:49:12 2002
+++ balsa-test/src/filter-edit.h	Tue May 28 16:56:37 2002
@@ -47,9 +47,6 @@
     GtkWidget *widget;
 } option_list;
 
-/* Free filters associated with filters clist row */
-void fe_free_associated_filters(void);
-
 /* destroy calback */
 void fe_destroy_window_cb(GtkWidget *,gpointer);
 
@@ -77,9 +74,6 @@
 /*op codes callback */
 void fe_op_codes_toggled(GtkWidget * widget, gpointer data);
 
-/* Free copied conditions */
-void fe_free_associated_conditions(void);
-
 /* Conditions callbacks */
 void fe_conditions_select_row(GtkWidget * widget, gint row, gint column,
 			      GdkEventButton * bevent, gpointer data);
@@ -90,4 +84,5 @@
 void fe_action_selected(GtkWidget * widget, gpointer data);
 void fe_enable_right_page(gboolean enabled);
 
+void fe_add_new_user_header(const gchar *);
 #endif /*__FILTER_EDIT_H__ */
diff -u /home/manu/prog/balsa-cvs/balsa/src/filter-run-callbacks.c balsa-test/src/filter-run-callbacks.c
--- /home/manu/prog/balsa-cvs/balsa/src/filter-run-callbacks.c	Sun Dec 16 10:29:21 2001
+++ balsa-test/src/filter-run-callbacks.c	Tue May 28 16:56:37 2002
@@ -28,6 +28,7 @@
 #include <gnome.h>
 
 #include <string.h>
+
 #include "mailbox-filter.h"
 #include "filter-private.h"
 #include "filter-funcs.h"
@@ -95,7 +96,8 @@
     if (!filters_prepare_to_run(filters))
 	return FALSE;
     gtk_clist_freeze(GTK_CLIST(balsa_app.mblist));
-    if (filters_run_on_messages(filters,mbox->message_list))
+    libbalsa_filter_match_mailbox(filters,mbox);
+    if (libbalsa_filter_apply(filters))
 	enable_empty_trash(TRASH_FULL);
     gtk_clist_thaw(GTK_CLIST(balsa_app.mblist));
     g_slist_free(filters);
diff -u /home/manu/prog/balsa-cvs/balsa/src/sendmsg-window.c balsa-test/src/sendmsg-window.c
--- /home/manu/prog/balsa-cvs/balsa/src/sendmsg-window.c	Wed May 29 19:21:08 2002
+++ balsa-test/src/sendmsg-window.c	Tue May 28 16:56:28 2002
@@ -3516,6 +3516,9 @@
     gboolean thereturn;
     LibBalsaMessage *message;
     
+    if (!is_ready_to_send(bsmsg)) 
+        return;
+
     message = bsmsg2message(bsmsg);
     gtk_object_ref(GTK_OBJECT(message));
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]