[PATCH] : filter on user headers



	Hi all,
I think I was too in a hurry to send the preceding patch. Just forget it : 
this one fixes a potential crash in filter edition code (try to press 
Escape or click on the close button in the condition dialog to trigger 
it), and finally manage to have the correct behaviour for the combo list : 
each time you validate a new user header name it is appended to the combo 
list.
Have fun with it.
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 16:40:37 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,23 @@
             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=g_strdup(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);
+	    /* This piece of code replaces the combo list
+	       by a new one that contains the new string the user has entered
+	       it seems that we must reset the text to the correct string,
+	    */
+	    gtk_combo_set_popdown_strings(fe_user_header,fe_user_headers_list);
+	    gtk_entry_set_text(GTK_ENTRY(fe_user_header->entry),str);
+	    g_free(str);
+	}
+        else if (new_cnd->match_fields==CONDITION_EMPTY) {
             condition_error(_("You must specify at least one field for matching"));
             return FALSE;
         }
@@ -439,7 +506,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 +595,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:
@@ -615,9 +693,10 @@
             }
         }
     case 1:  /* Cancel button */
-        /* we only hide it because it is too expensive to destroy and
+        /* this will only hide (we have called gnome_dialog_close_hides on the dialog)
+	   it because it is too expensive to destroy and
            rebuild each time */
-        gtk_widget_hide_all(dialog);
+        gnome_dialog_close(GNOME_DIALOG(dialog));
         break;
     case 2:  /* Help button */
         /* FIXME */
@@ -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);
@@ -956,6 +1047,7 @@
             GNOME_DIALOG(gnome_dialog_new("", GNOME_STOCK_BUTTON_OK,
                                           GNOME_STOCK_BUTTON_CANCEL,
                                           GNOME_STOCK_BUTTON_HELP, NULL));
+	gnome_dialog_close_hides(condition_dialog, TRUE);
 
         gtk_signal_connect(GTK_OBJECT(condition_dialog),
                            "clicked", condition_dialog_button_clicked, NULL);
@@ -1124,6 +1216,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 +1599,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 +1679,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 +1742,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);


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