spamass-milt-list
[Top][All Lists]
Advanced

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

patch as per pevious discussion on -b -B -r switches


From: Joe Maimon
Subject: patch as per pevious discussion on -b -B -r switches
Date: Thu, 11 Nov 2004 17:18:18 -0500
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040616 Mnenhy/0.6.0.101

Attached patch is an extemely rough recent draft of a patch (filled with noob code ime sure) that supports most of what was discussed previously about the -b -B -r switches (I have been working on this because.....because.... I dont actualy have a good reason)

I have been thinking of using this to feed high scoring emails for auto-DSBL blocklisting while simultanesouly sending them to a another address for review and potential whitelisting (again a DNS-WL) and similar.


Here is some of the embedded comments

/*
* This supports syntaxes like these:
* -b"<=20>=10,address@hidden"
* -b">10,address@hidden"
* -b">=10,address@hidden"
* -b">=10<=20,address@hidden"
* -b"<20>10,address@hidden"
* -b"<20>10,address@hidden;<30>40,address@hidden"
* -b"\<address@hidden>"
* -b"\<address@hidden> \<address@hidden>"
* -r"20,Depart from here spammer trash"
* -r
* -r '-1'
* -r20
* -r"20Go away\, now please"
* -r"disappear"
*
* -b and -B are interchangeable except -B means remove all
*  real recipients.
*
*  The argument value can ne concatenated with a ';' and will
*  be interpreted as if two of the same options were given.
*
* The charachter [<>,;] should be escaped with \ unless they
* mean score is less than, score is greater than or start of
* rejection message or bucket destination or additional argument
* , repsectively.
*/


Even though it appears to work for the simpler syntaxes I have thrown at it undoubtedtly it is far from finished and there is a whole lot more cleanup,commenting and debugging I need to do on this and also a discard message switch I would like to add.

I will probably keep at this until I lose interest anyways so....

Any and all feedback welcome,
Joe


diff -urN spamass-milt.orig/Makefile.am spamass-milt.bBranges/Makefile.am
--- spamass-milt.orig/Makefile.am       2004-11-11 16:19:27.000000000 -0500
+++ spamass-milt.bBranges/Makefile.am   2004-11-07 15:35:54.000000000 -0500
@@ -44,7 +44,7 @@
                contrib/spamass-milter.spec.in
 FBSD_CONTRIB = contrib/spamass-milter.sh
 MISC_CONTRIB = contrib/README.gnus
-spamass_milter_SOURCES = spamass-milter.cpp spamass-milter.h 
+spamass_milter_SOURCES = spamass-milter.cpp spamass-milter.h llist.c llist.h 
 spamass_milter_LDADD = @LIBOBJS@
 EXTRA_DIST =   $(DEB_CONTRIB) \
                $(RH_CONTRIB) \
@@ -54,3 +54,4 @@
                subst_poll.h
 
 spamass-milter.cpp: spamass-milter.h
+llist.c: llist.h
diff -urN spamass-milt.orig/configure.in spamass-milt.bBranges/configure.in
--- spamass-milt.orig/configure.in      2004-11-11 16:19:27.000000000 -0500
+++ spamass-milt.bBranges/configure.in  2004-11-08 23:43:40.000000000 -0500
@@ -100,8 +100,8 @@
 DN_WITH_DMALLOC
 
 # Checks for library functions.
-AC_CHECK_FUNCS([vsyslog vasprintf vsnprintf])
-AC_CHECK_FUNCS([asprintf snprintf])
+AC_CHECK_FUNCS([vsyslog])
+AC_CHECK_FUNCS([snprintf vsnprintf],have_vsnprintf="yes")
 AC_SEARCH_LIBS(gethostbyname, nsl)
 AC_SEARCH_LIBS(connect, socket)
 AC_SEARCH_LIBS(inet_aton, resolv)
@@ -112,6 +112,11 @@
 AC_LANG_PUSH(C)
 AC_REPLACE_FUNCS(strsep daemon)
 AC_CHECK_DECLS([strsep, daemon])
+AC_CHECK_FUNCS([vasprintf],AC_DEFINE(HAVE_VASPRINTF,[1]),AC_DEFINE(HAVE_VASPRINTF,[0]))
 
+AC_CHECK_FUNCS([asprintf],AC_DEFINE(HAVE_ASPRINTF,[1]),AC_DEFINE(HAVE_ASPRINTF,[0]))
 
+if test x$have_vsnprintf = xyes; then 
+       AC_LIBOBJ([vsnprintf_alloc])
+fi
 AC_LANG_POP(C)
 
 # Check for libmilter and its header files in the usual locations
diff -urN spamass-milt.orig/llist.c spamass-milt.bBranges/llist.c
--- spamass-milt.orig/llist.c   1969-12-31 19:00:00.000000000 -0500
+++ spamass-milt.bBranges/llist.c       2004-11-08 23:35:36.000000000 -0500
@@ -0,0 +1,406 @@
+/*
+       llist A linked list and manipulation "library"
+
+        Copyright 2002, Joe Maimon, New York USA
+
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "llist.h"
+
+#ifdef _LLIST_ERROR_
+#include "llist_error.h"
+#endif /* _LLIST_ERROR_ */
+
+struct linked_list *
+add_linked_list_item(struct linked_list *list,char *data)
+{
+       list = push_linked_list_item(list,(void *)data,strlen(data)+1); 
+       return(list);
+}
+
+struct linked_list *
+push_linked_list_item(struct linked_list * list,void * data,size_t size)
+{
+       struct linked_list * newlist = NULL;
+
+       
+       if (!(size && data))
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(EINVAL,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(list);
+       }
+       
+       newlist = (struct linked_list *) malloc ( sizeof(struct linked_list));
+       if (!newlist)
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(ENOMEM,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(list);
+       }
+
+       newlist->data = NULL;
+       newlist->next = NULL;
+       newlist->prev = NULL;
+       newlist->size = size;
+       
+
+       newlist->data = (void *) malloc ( newlist->size );
+       if (!newlist->data)
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(ENOMEM,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               free(newlist);
+               return(list);
+       }
+       
+       memcpy(newlist->data,data,newlist->size);
+       
+       if (list)
+       {
+               list->next = newlist;
+               newlist->prev = list;
+       }
+       
+       return(newlist);
+}
+
+struct linked_list *
+del_linked_list_item(struct linked_list *list)
+{
+       struct linked_list *newlist = NULL;
+       struct linked_list *nlistp = NULL;
+       
+       if (!list)
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(EINVAL,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(NULL);
+       }
+
+       /* First the data */
+       /* If you have use of the data, set list->data=NULL before calling this 
*/
+       if (list->data)
+               free(list->data);
+       
+       if (list->next == NULL && list->prev != NULL)
+       {
+               /* We are at the end, more behind us and nothing in front */
+               newlist = list->prev;
+               newlist->next = NULL;
+               free(list);
+               return(newlist);
+       }
+       if (list->next != NULL && list->prev == NULL)
+       {
+               /* We are at the begining, more to come and nothing behind */
+               newlist = list->next;
+               newlist->prev = NULL;
+               free(list);
+               return(newlist);
+       }
+       if (list->next != NULL && list->prev != NULL)
+       {
+               /* We are in the middle of it now */
+               /* We choose to advance the pointer 'forward' */
+               newlist = list->next;
+               nlistp = list->prev;
+               nlistp->next = newlist;
+               newlist->prev = nlistp;
+               free(list);
+               return(newlist);
+       }
+       if (list->next == NULL && list->prev == NULL)
+       {
+               /* Last remaining Item */
+               free(list);
+               return(NULL);
+       }
+       /* 
+       * We should never get here. 
+       * At this point we are looking at a big bug
+       */
+#ifdef _LLIST_ERROR_
+       LLIST_ERROR_THROW(LLIST_ERROR_EDELE,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+       return(list);
+               
+}
+       
+struct linked_list *
+del_linked_list(struct linked_list *list)
+{
+       while (list)
+               list = del_linked_list_item(list);
+       
+       return(list);
+}
+
+struct linked_list *
+popdel_linked_list_item(struct linked_list * list,void ** data,size_t * len)
+{
+       if(!(data && list && list->data))
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(EINVAL,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(list);
+       }
+       *data = linked_list_data(list, len);
+       list->data = NULL; /* So that the list forgets about this item */
+       list = del_linked_list_item(list);
+       return (list);
+}
+
+struct linked_list *
+pop_linked_list_item(struct linked_list * list,void ** data,size_t * len)
+{
+       if(!(data && list && list->data))
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(EINVAL,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(list);
+       }
+       *data = linked_list_data(list, len);
+       return(list);
+       
+}
+
+struct linked_list *
+getanddel_linked_list_item(struct linked_list * list,void ** data,size_t * len)
+{
+       return(popdel_linked_list_item(list,data,len));
+                       
+}
+
+struct linked_list *
+popnext_linked_list_item(struct linked_list * list,void ** data,size_t * len)
+{
+       struct linked_list * nlistp = NULL; 
+       *data = linked_list_data(list, len);
+       if( (nlistp = next_linked_list_item(list)) )
+               return(nlistp);
+       else
+       if( (nlistp = prev_linked_list_item(list)) )
+               return(nlistp);
+       else
+               return(list);
+       
+}      
+
+void *
+linked_list_data(struct linked_list * list, size_t * len)
+{
+       if(!list)
+               return(NULL);
+       
+       if(len)
+               *len = list->size;
+       return(list->data);
+}      
+
+char *
+linked_list_item(struct linked_list * list)
+{
+       return((char *) linked_list_data(list,0));
+}
+
+
+struct linked_list *
+next_linked_list_item(struct linked_list * list)
+{
+       list = step_linked_list(list,1);
+       return(list);
+}
+
+struct linked_list *
+prev_linked_list_item(struct linked_list * list)
+{
+       list = step_linked_list(list,0);
+       return(list);
+}
+
+struct linked_list *
+step_linked_list(struct linked_list * list,const int dir)
+{
+       /* 0 == FIFO, 0< == LIFO */     
+
+       if (!list)
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(EINVAL,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(list);
+       }
+
+       if (!dir)
+       {
+               list = list->prev;
+       }
+       else
+       {
+               list = list->next;
+       }
+       return(list);
+       
+}
+
+
+struct linked_list *
+orient_linked_list(struct linked_list * list,const int dir)
+{
+       if (!list)
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(EINVAL,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(list);
+       }
+
+       if (!dir)
+       {
+               while (list->prev)
+                       list = list->prev;      
+       }
+       else
+       {
+               while (list->next)
+                       list = list->next;
+       }
+       return(list);
+}
+
+struct linked_list *
+rewind_linked_list(struct linked_list * list)
+{
+       return(orient_linked_list(list,0));
+}
+
+struct linked_list *
+ffrwrd_linked_list(struct linked_list * list)
+{
+       return(orient_linked_list(list,1));
+}
+
+
+
+size_t 
+count_linked_list_data(struct linked_list * list)
+{
+       size_t size = 0;
+       
+       if(!list)
+       {
+               return(size);
+       }
+
+       list = orient_linked_list(list,0);
+
+       if(!list)
+       {
+#ifdef _LLIST_ERROR_
+               
LLIST_ERROR_THROW(LLIST_ERROR_EORIENT,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(size);
+       }
+       return(count_linked_list_data_dir(list, 1));
+}      
+
+size_t
+count_linked_list_data_dir(struct linked_list * list, int direction)
+{
+       size_t size = 0;
+       
+       if(!list)
+               return(size);
+
+       while(list)
+       {
+               size += list->size; 
+               list = step_linked_list(list, direction);
+       }
+       return(size);
+}
+
+unsigned int
+count_linked_list_items(struct linked_list * list)
+{
+       int count = 0;
+
+       if(!list)
+       {
+               return(0);
+       }
+
+       list = orient_linked_list(list,0);
+
+       if(!list)
+               return(0);
+
+       while(list)
+       {
+               count++;
+               list = next_linked_list_item(list);
+       }
+       return(count);
+}
+       
+unsigned int
+count_linked_list(struct linked_list * list,const int dir)
+{
+       int count = 0;
+
+       if(!list)
+       {
+               return(0);
+       }
+
+       while(list)
+       {
+               count++;
+               list = step_linked_list(list,dir);
+       }
+       return(count);
+}
+
+struct linked_list *
+search_linked_list(struct linked_list * list, int (*cmp_func)(void *, void *), 
void * needle, int direction)
+{
+
+       if(!list || !cmp_func)
+       {
+#ifdef _LLIST_ERROR_
+               LLIST_ERROR_THROW(EINVAL,__FILE__,__LINE__,__func__);
+#endif /* _LLIST_ERROR_ */
+               return(NULL);
+       }
+       
+       while(list)
+       {
+               if((*cmp_func)(linked_list_data(list, NULL), needle) == 0)
+                       return list;
+                       
+               list = step_linked_list(list, direction);
+       }
+       return(NULL);
+}
diff -urN spamass-milt.orig/llist.h spamass-milt.bBranges/llist.h
--- spamass-milt.orig/llist.h   1969-12-31 19:00:00.000000000 -0500
+++ spamass-milt.bBranges/llist.h       2004-11-08 23:34:54.000000000 -0500
@@ -0,0 +1,252 @@
+/*
+       llist.h, llist.c
+       Routines to implement linked lists.
+        
+       Copyright 2002, Joe Maimon, New York USA
+
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#ifndef INCLUDED_LINK_LIST
+       #define INCLUDED_LINK_LIST 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* A bi-directional list originaly designed for char strings
+* Can theoreticaly be used for anything.
+* 
+* DO NOT define space for the structure, just a pointer.
+* When handed a NULL for the first time add_linked_list_item || 
push_linked_list_item
+* will allocate all neccessary and initialize.
+* 
+* If handed garbage, you will get a segfault. SO initialize your pointer to 
NULL.
+* To use:
+* struct linked_list * list = NULL;
+*/
+
+struct linked_list
+{
+        void  * data;
+        struct linked_list *next;
+        struct linked_list *prev;
+       size_t size;
+};
+
+
+/* takes a list pointer and char string pointer, stores it and returns list 
address
+* If the list does not currently exist, ensure the pointer *list == NULL and a 
new chain will be malloced.
+* Returns *list (arg 1) on error (No mem)
+* This is safe to use with primary list handle as it will not lose a valid 
list pointer.
+* 
+* TO detect whether value was stored correctly, compare return poiinter with 
input pointer. 
+* If they match, no storage was done.
+* 
+* This is a wrapper arounf push_linked_list_item for char strings.
+* TO Use:
+* list = add_linked_list_item(list, string);
+*/
+
+struct linked_list *
+add_linked_list_item(struct linked_list *list,char *data);
+
+/*See add_linked_list_item()
+ *
+ * This is the general case of the above, it takes a (void *) to an opaque 
data structure.
+ * You must supply the size.
+ * 
+ * TO Use:
+ * list = push_linked_list_item(list,(void *)data,(int) data_size);
+ */
+struct linked_list *
+push_linked_list_item(struct linked_list * list,void * data, size_t size);
+
+/* takes list pointer. Free char string and list item. Direction is default to 
LIFO
+* returns a new list pointer or NULL if the list is done for.
+*
+* This is safe to use on primary list handle because when you get NULL back, 
+* there is nothing left to lose.
+*/
+
+struct linked_list *
+del_linked_list_item(struct linked_list *list);
+
+/* Takes list pointer. recursively calls del_linked_list_item until list is no 
more
+* Returns NULL.
+* 
+* Use this on the primary list handle because it should be NULL after you call 
this.
+* 
+*/
+
+struct linked_list *
+del_linked_list(struct linked_list *list);
+
+/* These two pop the data pointer and unlink/free the current list entry. 
+ * There is NO mallocing here, the data pointer is copied.
+ *
+ * Refer to pop_linked_list_item and del_linked_list_item
+ */
+
+struct linked_list *
+getanddel_linked_list_item(struct linked_list *list,void ** data,size_t * len);
+
+struct linked_list *
+popdel_linked_list_item(struct linked_list * list,void ** data,size_t * len);
+
+/* Takes a list pointer, a pointer to a pointer of proper type, and a pointer 
to a size_t variable.
+ * If data pointer is NULL nothing is stored there. If length pointer is NULL, 
length information is NOT stored there.
+ * You need to make sure you can detect the end of the data refereneced by the 
pointer in that case.
+ *
+ * Does not delete the list item.
+ * Does not move the list position.
+ * Will not alter list value.
+ *
+ * You must use this in conjunction with {step|next|prev}_linked_list_item 
which may return a NULL
+ * Test for NULL before assigning it your list handle because otherwise you 
risk a memory leak.
+ *
+ * Call count_linked_list_items to obtain a loop countdown.
+ *
+ * If there is an error data will remain NULL and so will len.
+ *
+ * Advice: use linked_list_data() instead.
+ */
+
+struct linked_list *
+pop_linked_list_item(struct linked_list * list,void ** data,size_t * len);
+
+/* The only difference in this one is that the list posistion is moved.
+ * If not possible (because the end of the list is here) it will return list 
verbatim. 
+ * It is a good idea to orient the list while using this.
+ * 
+ * DO NOT test for NULL to terminate while loops while using this. Instead 
call count_linked_list_items.
+ * No deleting
+ *
+ * Advice: If possible use linked_list_data() followed by step_linked_list() 
instead.
+ */
+
+struct linked_list *
+popnext_linked_list_item(struct linked_list * list,void ** data,size_t * len);
+
+/*
+ * Returns a pointer to the linked lists data. Does not free.
+ * Sets size value.
+ */
+
+void *
+linked_list_data(struct linked_list * list, size_t * len);
+
+/* Calls above but assumes char *
+ */
+
+char *
+linked_list_item(struct linked_list * list);
+
+
+/* Takes list pointer and moves forward */
+struct linked_list *
+next_linked_list_item(struct linked_list * list);
+
+/* Takes list pointer and moves backwards */
+struct linked_list *
+prev_linked_list_item(struct linked_list * list);
+
+/* Steps one link in any direction of list 
+ * (DIR) ? LIFO : FIFO
+ */
+struct linked_list *
+step_linked_list(struct linked_list * list,int dir);
+
+/* Takes list pointer and flag for which direction to orient list
+* (DIR) ? LIFO : FIFO
+*/
+
+struct linked_list *
+orient_linked_list(struct linked_list *list,const int dir);
+
+/*
+ * Convenience functions for above
+ */
+struct linked_list *
+rewind_linked_list(struct linked_list *list);
+
+struct linked_list *
+ffrwrd_linked_list(struct linked_list *list);
+
+/*
+* Takes pointer to list; returns total byte count of all data pointed to 
list->data_ptr
+* On error will return 0, same as no data.
+*/
+
+size_t count_linked_list_data(struct linked_list * list);
+
+/*
+ * Same as ABove but only counts data in direction indicated (1 forward 0 
reverse) until
+ * end of list
+*/
+
+size_t count_linked_list_data_dir(struct linked_list * list, int direction);
+
+/*
+* Takes pointer to list; return count of ALL linked_list structures pointed to.
+* 
+* Return 0 on error (passing a null or bad list in)
+*/
+
+unsigned int 
+count_linked_list_items(struct linked_list * list);
+
+/*
+* Takes pointer to list; return count of linked_list structures. 
+* This will only count till the end of the list in the direction you specify.
+* Return 0 on error (passing a null or bad list in)
+*/
+
+unsigned int 
+count_linked_list(struct linked_list * list,const int dir);
+
+/*
+ * Takes pointer to list, address of function that return an int and takes two 
+ * arguments of pointer to void, a pointer to void and a direction to search 
+ * the list till end.
+ *
+ * Returns NULL or pointer to list if passed in function returns 0 
+ *
+ * The passed in function will be called with a pointer to the data in the 
+ * list item and the third argument. If it return 0 than, this function will 
return
+ * the pointer to the list which contained that piece of data.
+ *
+ * If no items in the list produce the return value of 0 from the passed in 
function
+ * or if the passed in arguments are invalid, NULL will be returned.
+ *
+ * Side effects: None except any caused by passed in function.
+ *
+ * Advice: You should consider rewind_linked_list() or ffrwrd_linked_list 
before calling this.
+ */
+struct linked_list *
+search_linked_list(struct linked_list * list, int(*cmp_func)(void * data, void 
* needle), void * needle, const int dir);
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif /* INCLUDED_LINK_LIST */
diff -urN spamass-milt.orig/llist_error.c spamass-milt.bBranges/llist_error.c
--- spamass-milt.orig/llist_error.c     1969-12-31 19:00:00.000000000 -0500
+++ spamass-milt.bBranges/llist_error.c 2004-11-08 21:28:03.000000000 -0500
@@ -0,0 +1,139 @@
+#include "llist.h"
+#include "llist_error.h"
+
+struct llist_error_FLAGS llist_error_flags = { 0,0,0,0 };
+
+static unsigned int
+llist_error_index(unsigned int);
+
+static void
+llist_error_action(unsigned int,const char *);
+
+static void
+llist_error_perror_arg(unsigned int, const char *);
+
+static unsigned int
+llist_error_get(void);
+
+static struct llist_error llist_error_table [] =
+{ 
+       { LLIST_ERROR_EGIGO , "garbage in, garbage out" , 0 },
+       { LLIST_ERROR_EDELE , "deletion routine reaached impossible code 
branch", 1},
+       { LLIST_ERROR_EORIENT, "a call to orient_linked_list returned NULL", 0}
+
+};
+
+static unsigned int llist_errno = 0;
+
+static unsigned int 
+llist_error_index(unsigned int ui)
+{
+       int i = 0;
+       
+       while(i < sizeof(llist_error_table)/sizeof(llist_error_table[0]) )
+       {
+               if(llist_error_table[i].llist_errno == ui)
+                       return(i);
+
+               i++;
+       }
+       return(0);
+}
+
+static void
+llist_error_action(unsigned int ui,const char *s)
+{
+       if(llist_error_flags.print)
+                llist_error_perror_arg(ui,s);
+
+
+        if(ui > LLIST_ERROR_FIRST)
+        {
+
+                if( (llist_error_table[llist_error_index(ui)].severity)
+                  &&(llist_error_flags.llist_abort) )
+                        exit(EX_FAIL);
+        }
+        if(ui < LLIST_ERROR_FIRST)
+        {
+                if(llist_error_flags.sys_abort)
+                        exit( (ui <= sys_nerr) ? ui : EX_FAIL);
+        }
+        return;
+
+}
+
+static void
+llist_error_perror_arg(unsigned int ui,const char *s)
+{
+       char * s2 = NULL;
+       
+        if(ui < LLIST_ERROR_FIRST)
+       {
+                 s2 = strerror((int)ui);
+                fprintf(stderr,"%s : %s\n",s,s2);
+       }
+
+        if(llist_errno > LLIST_ERROR_FIRST)
+                fprintf(stderr,"%s : 
%s\n",s,llist_error_table[llist_error_index(ui)].llist_error_string);
+
+        if(ui == LLIST_ERROR_FIRST)
+                fprintf(stderr,"%s : %s\n",s,"Not an error");
+
+        return;
+}
+
+
+void llist_error_throw(unsigned int ui,const char * s)
+{
+       llist_errno = ui;
+
+       llist_error_action(ui,s);
+       
+       return;
+}
+
+unsigned int llist_error_catch(const char * s)
+{
+       unsigned int ui = llist_error_get();
+
+       if(s)
+               llist_error_action(ui,s);
+       if(llist_error_flags.clear)
+               llist_error_clear();
+       return(ui);
+}
+
+void llist_error_clear(void)
+{
+       llist_errno = 0;
+}
+
+static unsigned int llist_error_get(void)
+{
+       return(llist_errno);
+}
+
+unsigned int llist_error_errno(void)
+{
+       return(llist_error_get());
+}
+
+char * 
+llist_error_strerror(unsigned int ui)
+{
+       if(ui < LLIST_ERROR_FIRST)
+               return(strerror((int) ui));
+       
+       if(ui > LLIST_ERROR_FIRST)
+               
return(llist_error_table[llist_error_index(ui)].llist_error_string);
+
+       return("");
+}
+
+void llist_error_perror(const char * s)
+{
+       (void) llist_error_perror_arg(llist_error_errno(),s);
+
+       return;
+}
diff -urN spamass-milt.orig/llist_error.h spamass-milt.bBranges/llist_error.h
--- spamass-milt.orig/llist_error.h     1969-12-31 19:00:00.000000000 -0500
+++ spamass-milt.bBranges/llist_error.h 2004-11-08 21:28:58.000000000 -0500
@@ -0,0 +1,62 @@
+#ifndef HAVE_LLIST_ERROR_INCLUDE
+       #define HAVE_LLIST_ERROR_INCLUDE
+#include <errno.h>
+#include <sys/errno.h>
+#include <sysexits.h>
+
+#ifndef EX_FAIL
+       #define EX_FAIL 63
+#endif /* EX_FAIL */
+
+struct llist_error
+{
+       unsigned int llist_errno;
+       char * llist_error_string;
+       unsigned int severity;
+};
+
+enum 
+{
+       LLIST_ERROR_FIRST = 1000,
+       LLIST_ERROR_EGIGO,
+       LLIST_ERROR_EDELE,
+       LLIST_ERROR_EORIENT,
+
+
+
+       LLIST_ERROR_LAST
+} llist_errors;
+
+struct llist_error_FLAGS
+{
+       char    llist_abort; /* bail on severe errors */
+       char    sys_abort;  /* bail on system errors */
+       char    print; /* library prints errors or not? */
+       char    clear; /* clear error from llist_error_catch */
+
+} llist_error_flags ;
+
+
+
+void llist_error_throw(unsigned int,const char *);
+
+void llist_error_clear(void);
+
+unsigned int llist_error_errno(void);
+
+char * llist_error_strerror(unsigned int);
+
+void llist_error_perror(const char *);
+
+#ifndef MAX_BUF
+       #define MAX_BUF 1024
+#endif /* MAX_BUF */
+
+#define LLIST_ERROR_THROW(w,x,y,z)     \
+{\
+       char buf[MAX_BUF];\
+       snprintf(buf,sizeof(buf),"%s:%d %s()",x,y,z);\
+       llist_error_throw(w,buf);\
+}
+
+#endif /* HAVE_LLIST_ERROR_INCLUDE */
diff -urN spamass-milt.orig/spamass-milter.cpp 
spamass-milt.bBranges/spamass-milter.cpp
--- spamass-milt.orig/spamass-milter.cpp        2004-11-11 16:19:27.000000000 
-0500
+++ spamass-milt.bBranges/spamass-milter.cpp    2004-11-11 13:11:40.000000000 
-0500
@@ -102,6 +102,8 @@
 
 #include "libmilter/mfapi.h"
 //#include "libmilter/mfdef.h"
+#include "vsnprintf_alloc.h"
+#include "llist.h"
 
 #if !HAVE_DECL_STRSEP
 char *strsep(char **stringp, const char *delim);
@@ -127,6 +129,9 @@
 
 // }}} 
 
+struct linked_list * bBra_list = NULL;
+int bBra_search_dir = 0; /* search list in reverse order of entry*/
+
 static const char Id[] = "$Id: spamass-milter.cpp,v 1.85 2004/09/24 04:42:16 
dnelson Exp $";
 
 struct smfiDesc smfilter =
@@ -165,7 +170,6 @@
 int spamc_argc;
 char **spamc_argv;
 bool flag_bucket = false;
-bool flag_bucket_only = false;
 char *spambucket;
 bool flag_full_email = false;          /* pass full email address to spamc */
 bool flag_expand = false;      /* alias/virtusertable expansion */
@@ -180,11 +184,17 @@
 main(int argc, char* argv[])
 {
    int c, err = 0;
+#if defined(_GNU_SOURCE)
+   const char *args = "fd:mMp:P:r::u:D:i:b:B:e:x";
+#else
    const char *args = "fd:mMp:P:r:u:D:i:b:B:e:x";
+#endif
    char *sock = NULL;
    bool dofork = false;
    char *pidfilename = NULL;
    FILE *pidfile = NULL;
+   struct bBrAction bbra;
+   char *p;
 
 #ifdef HAVE_VERBOSE_TERMINATE_HANDLER
        std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
@@ -229,7 +239,12 @@
                                break;
                        case 'r':
                                flag_reject = true;
-                               reject_score = atoi(optarg);
+                               p = optarg;
+                               do {
+                                       bbra = parse_bBr_arg(c, p, &p); 
+                                       bBra_list = 
push_linked_list_item(bBra_list, (void*) &bbra,
+                                               sizeof(struct bBrAction)); 
+                               } while (p);
                                break;
                        case 'u':
                                flag_sniffuser = true;
@@ -237,24 +252,24 @@
                                break;
                        case 'b':
                        case 'B':
-                               if (flag_bucket)
-                               {
-                                       fprintf(stderr, "Can only have one -b 
or -B flag\n");
-                                       err = 1;
-                                       break;
-                               }
                                flag_bucket = true;
                                if (c == 'b')
                                {
-                                       flag_bucket_only = true;
                                        smfilter.xxfi_flags |= SMFIF_DELRCPT; 
// May delete recipients
                                }
-                               // we will modify the recipient list; if spamc 
returns
-                               // indicating that this mail is spam, the 
message will be
-                               // sent to <optarg>@localhost
-                               smfilter.xxfi_flags |= SMFIF_ADDRCPT; // May 
add recipients
-                               // XXX we should probably verify that optarg is 
vaguely sane
-                               spambucket = strdup( optarg );
+                               smfilter.xxfi_flags |= SMFIF_ADDRCPT; 
+                               p = optarg;
+                               do {
+                                       bbra = parse_bBr_arg(c, p, &p); 
+                                       if (!bbra.bucket)
+                                       {
+                                               fprintf(stderr, "-%c arg 
requires a bucket address\n", c);
+                                               err = 1;
+                                       }
+                                       else
+                                               bBra_list = 
push_linked_list_item(bBra_list, (void*) &bbra,
+                                                       sizeof(struct 
bBrAction)); 
+                               } while (p);
                                break;
                        case 'x':
                                flag_expand = true;
@@ -414,6 +429,16 @@
   string::size_type eoh2 = assassin->d().find("\n\r\n");
   string::size_type eoh = (eoh1 < eoh2) ? eoh1 : eoh2;
   string::size_type bob = assassin->d().find_first_not_of("\r\n", eoh);
+  struct bBrAction bbra; 
+  struct bBrAction * bbra_p = NULL;
+  int score = 0;
+  bool flag_score = false;
+  struct linked_list * rcpt_list = NULL;
+  struct linked_list * bbra_list;
+  bool flag_bucket_only = false;
+
+  bBra_list = orient_linked_list(bBra_list, (bBra_search_dir) ? 0 : 1);
+  memset(&bbra, '\0', sizeof(bbra));
 
   if (bob == string::npos)
        bob = assassin->d().size();
@@ -421,64 +446,140 @@
   update_or_insert(assassin, ctx, assassin->spam_flag(), 
&SpamAssassin::set_spam_flag, "X-Spam-Flag");
   update_or_insert(assassin, ctx, assassin->spam_status(), 
&SpamAssassin::set_spam_status, "X-Spam-Status");
 
-  /* Summarily reject the message if SA tagged it, or if we have a minimum
-     score, reject if it exceeds that score. */
+  if (flag_reject || flag_bucket)
+  {
+         /* we need the score now */
+       int rv;
+       const char *spam_status = assassin->spam_status().c_str();
+       /* SA 3.0 uses the keyword "score" */
+       rv = sscanf(spam_status,"%*s score=%d", &score);
+       if (rv != 1)
+       {
+               /* SA 2.x uses the keyword "hits" */
+               rv = sscanf(spam_status,"%*s hits=%d", &score);
+       }
+       if (rv != 1)
+               debug(D_ALWAYS, "Could not extract score from <%s>", 
spam_status);
+       else 
+       {
+               bbra.score = score;
+               bbra.score_flag = true;
+               debug(D_MISC, "SA score: %d", score);
+       }
+  }
+
+  /* Summarily reject the message if SA tagged it and we have a reject action 
+   * that matches this scores. Otherwise reject it if there is a matching 
reject action
+   * for this score.
+   */
   if (flag_reject)
   {
        bool do_reject = false;
-       if (reject_score == -1 && !assassin->spam_flag().empty())
-               do_reject = true;
-       if (reject_score != -1)
-       {
-               int score, rv;
-               const char *spam_status = assassin->spam_status().c_str();
-               /* SA 3.0 uses the keyword "score" */
-               rv = sscanf(spam_status,"%*s score=%d", &score);
-               if (rv != 1)
-               {
-                       /* SA 2.x uses the keyword "hits" */
-                       rv = sscanf(spam_status,"%*s hits=%d", &score);
-               }
-               if (rv != 1)
-                       debug(D_ALWAYS, "Could not extract score from <%s>", 
spam_status);
-               else 
-               {
-                       debug(D_MISC, "SA score: %d", score);
-                       if (score >= reject_score)
-                               do_reject = true;
-               }
-       }
+       bbra_list = bBra_list;
+       bbra.bBr[0] = 'r';
+       do
+       {
+               bbra_list = search_linked_list(bbra_list, bBr_cmp,(void *) 
&bbra, bBra_search_dir);
+               if (!bbra_list)
+                       break;
+
+               bbra_p = (struct bBrAction *) linked_list_data(bbra_list, NULL);
+               bbra_list = step_linked_list(bbra_list, bBra_search_dir);
+               if (!bbra_p)
+                       continue;
+               
+               if (bbra_p->min_flag || bbra_p->max_flag)
+                       do_reject = true;
+               else if (!assassin->spam_flag().empty())
+                       do_reject = true;
+               
+       } while(!do_reject);
+       
        if (do_reject)
        {
+               char * p = (bbra_p && bbra_p->bucket && *bbra_p->bucket) ? 
+                       bbra_p->bucket : (char *)"Blocked by SpamAssassin";
                debug(D_MISC, "Rejecting");
-               smfi_setreply(ctx, "550", "5.7.1", "Blocked by SpamAssassin");
-
+               smfi_setreply(ctx, "550", "5.7.1", p);
+                       //(bbra_p && bbra_p->bucket) ? bbra_p->bucket : (char 
*)"Blocked by SpamAssassin");
 
                if (flag_bucket)
                {
+                       bbra.bBr[0] = 'B';
+                       bbra.bBr[1] = 'b';
+                       bbra.bBr[2] = '\0';
+                       bbra_list = bBra_list;
+                       do 
+                       {
+                               bbra_list = search_linked_list(bbra_list, 
bBr_cmp, (void*) &bbra, bBra_search_dir); 
+                               if(bbra_list)
+                               {       
+                                       bbra_p = (struct bBrAction 
*)linked_list_data(bbra_list, NULL);
+                                       bbra_list = step_linked_list(bbra_list, 
bBra_search_dir);
+                                       rcpt_list = 
add_linked_list_item(rcpt_list, bbra_p->bucket);
+                               }
+                       } while (bbra_list);
+               }
+
+               if (rcpt_list)
+               {
                        /* If we also want a copy of the spam, shell out to 
sendmail and
                           send another copy.  The milter API will not let you 
send the
                           message AND return a failure code to the sender, so 
this is
                           the only way to do it. */
+#if defined(__FreeBSD__)
                        int rv;
-                       
-#if defined(HAVE_ASPRINTF)
+#endif
+#if defined(HAVE_SNPRINTF)
                        char *buf;
+                       char *buf2;
 #else
-                       char buf[1024];
+                       char buf[4096];
+                       char buf2[4096];
+                       char bp1 = buf;
+                       char bp2 = buf2;
 #endif
                        char *fmt="%s \"%s\"";
                        FILE *p;
 
-#if defined(HAVE_ASPRINTF)
-                       asprintf(&buf, fmt, SENDMAIL, spambucket);
-#else
+
 #if defined(HAVE_SNPRINTF)
-                       snprintf(buf, sizeof(buf)-1, fmt, SENDMAIL, spambucket);
+                       asprintf(&buf,"%s --", SENDMAIL);
+                       while (buf && rcpt_list)
+                       {
+                               char * rcpt = NULL;
+                               rcpt_list = 
popdel_linked_list_item(rcpt_list,(void **) &rcpt, NULL);
+                               asprintf(&buf2, fmt, buf, (rcpt) ? rcpt : "" );
+                               if (buf2)
+                               {
+                                       free(buf);
+                                       buf = buf2;
+                               }
+                               if (rcpt)
+                               {
+                                       free(rcpt);
+                                       rcpt = NULL;
+                               }
+                       }
 #else
                        /* XXX possible buffer overflow here */
-                       sprintf(buf, fmt, SENDMAIL, spambucket);
-#endif
+                       sprintf(buf, "%s --", SENDMAIL);
+                       while (rcpt_list)
+                       {
+                               char * rcpt = NULL;
+                               char * bp3;
+                               
+                               rcpt_list = popdel_linked_list_item(rcpt_list, 
&rcpt, NULL);
+                               sprintf(bp2, fmt, bp1, (rcpt) ? rcpt : "");
+                               bp3 = bp2;
+                               bp2 = bp1;
+                               bp1 = bp3;
+                               if (rcpt)
+                               {
+                                       free(rcpt);
+                                       rcpt = NULL;
+                               }
+                       }
 #endif
 
                        debug(D_COPY, "calling %s", buf);
@@ -508,7 +609,7 @@
                                abort();
                        }               
 #endif
-#if defined(HAVE_ASPRINTF)
+#if defined(HAVE_SNPRINTF)
                        free(buf);
 #endif 
                }
@@ -516,16 +617,56 @@
        }
   }
 
-  /* Drop the message into the spam bucket if it's spam */
-  if ( flag_bucket ) {
-        if (!assassin->spam_flag().empty()) {
-          // first, add the spambucket address
-          if ( smfi_addrcpt( ctx, spambucket ) != MI_SUCCESS ) {
-                throw string( "Failed to add spambucket to recipients" );
-          }
-          if (flag_bucket_only) {
-                // Move recipients to a non-active header, one at a
-                // time. Note, this may generate multiple X-Spam-Orig-To
+  /* Drop the message into the spam bucket if it's score matches an -bB action 
or
+   * if the message is tagged as spam and there is a scoreless -bB action */
+  if (flag_bucket && flag_score)
+  {
+       
+       bbra.bBr[0] = 'B';
+       bbra.bBr[1] = '\0';
+       bbra_list = bBra_list;
+       do
+       {
+               bbra_list = search_linked_list(bbra_list, bBr_cmp,(void *) 
&bbra, bBra_search_dir);
+               if (bbra_list)
+               {
+                       bbra_p = (struct bBrAction 
*)linked_list_data(bbra_list, NULL);
+                       bbra_list = step_linked_list(bbra_list, 
bBra_search_dir);
+                       if (!bbra_p)
+                               continue; /* should never happen */
+                       if (!bbra_p->min_flag && !bbra_p->max_flag && 
assassin->spam_flag().empty())
+                       {
+                               /* caught scoreless && not tagged as spam, 
throw it back */
+                               continue;
+                       }
+                       
+                       if (bbra.bBr[0] == 'B')
+                               flag_bucket_only = true;
+                       rcpt_list = add_linked_list_item(rcpt_list, 
bbra_p->bucket); 
+               }
+               else if (bbra.bBr[0] == 'B')
+               {
+                       bbra.bBr[0] = 'b';
+                       bbra_list = bBra_list; /* start from end of list again 
*/
+               }
+
+       } while (bbra_list);
+  }
+
+  if (rcpt_list) { 
+       
+       do {
+               char * rcpt;
+
+               rcpt_list = popdel_linked_list_item(rcpt_list,(void **) &rcpt, 
NULL);
+               if (smfi_addrcpt(ctx, rcpt) != MI_SUCCESS ) {
+                       throw string( "Failed to add spambucket to recipients");
+               }
+       } while (rcpt_list);
+               
+       if (flag_bucket_only) {
+               // Move recipients to a non-active header, one at a
+               // time. Note, this may generate multiple X-Spam-Orig-To
                 // headers, but that's okay.
                 while( !assassin->recipients.empty()) {
                   if ( smfi_addheader( ctx, "X-Spam-Orig-To", (char 
*)assassin->recipients.front().c_str()) != MI_SUCCESS ) {
@@ -539,10 +680,9 @@
                   }
                   assassin->recipients.pop_front();
                 }
-          }
         }
   }
-
+  
   update_or_insert(assassin, ctx, assassin->spam_report(), 
&SpamAssassin::set_spam_report, "X-Spam-Report");
   update_or_insert(assassin, ctx, assassin->spam_prev_content_type(), 
&SpamAssassin::set_spam_prev_content_type, "X-Spam-Prev-Content-Type");
   update_or_insert(assassin, ctx, assassin->spam_level(), 
&SpamAssassin::set_spam_level, "X-Spam-Level");
@@ -804,7 +944,9 @@
        struct context *sctx = (struct context*)smfi_getpriv(ctx);
        SpamAssassin* assassin = sctx->assassin;
        FILE *p;
+#if defined(__FreeBSD__) /* popen bug - see PR bin/50770 */
        int rv;
+#endif
 
        debug(D_FUNC, "mlfi_envrcpt: enter");
 
@@ -1900,26 +2042,22 @@
                vsyslog(LOG_ERR, fmt, vl);
                va_end(vl);
 #else
-#if defined(HAVE_VASPRINTF)
+#if defined(HAVE_VSNPRINTF)
                char *buf;
 #else
                char buf[1024];
 #endif
                va_list vl;
                va_start(vl, fmt);
-#if defined(HAVE_VASPRINTF)
-               vasprintf(&buf, fmt, vl);
-#else
 #if defined(HAVE_VSNPRINTF)
-               vsnprintf(buf, sizeof(buf)-1, fmt, vl);
+               vasprintf(&buf, fmt, vl);
 #else
                /* XXX possible buffer overflow here; be careful what you pass 
to debug() */
                vsprintf(buf, fmt, vl);
 #endif
-#endif
                va_end(vl);
                syslog(LOG_ERR, "%s", buf);
-#if defined(HAVE_VASPRINTF)
+#if defined(HAVE_VSNPRINTF)
                free(buf);
 #endif 
 #endif /* vsyslog */
@@ -1976,6 +2114,239 @@
 
 }
 
+/*
+ * This supports syntaxes like these:
+ * -b"<=20>=10,address@hidden"
+ * -b">10,address@hidden"
+ * -b">=10,address@hidden"
+ * -b">=10<=20,address@hidden"
+ * -b"<20>10,address@hidden"
+ * -b"<20>10,address@hidden;<30>40,address@hidden"
+ * -b"\<address@hidden>"
+ * -b"\<address@hidden> \<address@hidden>"
+ * -r"20,Depart from here spammer trash"
+ * -r
+ * -r '-1'
+ * -r20
+ * -r"20Go away\, now please"
+ * -r"disappear"
+ *
+ * -b and -B are interchangeable except -B means remove all 
+ *  real recipients.
+ *
+ *  The argument value can ne concatenated with a ';' and will
+ *  be interpreted as if two of the same options were given.
+ *  
+ * The charachter [<>,;] should be escaped with \ unless they
+ * mean score is less than, score is greater than or start of
+ * rejection message or bucket destination or additional argument 
+ * , repsectively.
+ */
+struct bBrAction parse_bBr_arg(char opt, char * optarg, char **end_p)
+{
+       struct bBrAction bbra;
+       char * gt_str = NULL;
+       char * lt_str = NULL;
+       char * bucket_str = NULL;
+       int i;
+       int in_escape = 0;
+       char *p, *q;
+       char end_p_sav = '\0';
+
+       memset(&bbra, '\0', sizeof(bbra));
+       bbra.bBr[0] = opt;
+       bbra.bBr[1] = '\0';
+
+       p = optarg;
+       i = 0;
+       /* find first unescaped <>,*/ 
+       while (p && *p)
+       {
+               int in_escape = 0;
+
+               if(*p == '>' && !gt_str && !in_escape)
+                       gt_str = p + 1;
+               else if (*p == '<' && !lt_str && !in_escape)
+                       lt_str = p + 1;
+               else if (*p == ',' && !bucket_str && !in_escape)
+                       bucket_str = p + 1;
+               else if (*p == ';' && end_p && !in_escape)
+               {
+                       *end_p = p + 1;
+                       end_p_sav = *p;
+                       *p = '\0';
+                       break;
+               }
+               else if (*p == '\\' && !in_escape)
+                       in_escape = 1;
+               else
+                       in_escape = 0;
+               p++;
+       }
+
+       if (end_p && !end_p_sav)
+               *end_p = NULL;
+
+       if (gt_str)
+       {
+               int str_off = 0;
+               
+               if (*(gt_str) == '=')
+                       str_off = 1;
+               bbra.min_score = strtol(gt_str+str_off, &p, 0);
+               bbra.min_score += (str_off) ? 1 : 0;
+               if (p != (gt_str + str_off))
+                       bbra.min_flag = 1;
+       }
+
+       if (lt_str)
+       {
+               int str_off = 0;
+               
+               if (*(lt_str) == '=')
+                       str_off = 1;
+               bbra.max_score = strtol(lt_str+str_off, &p, 0);
+               bbra.max_score -= (str_off) ? 0 : 1;
+               if (p != (lt_str + str_off))
+                       bbra.max_flag = 1;
+       }
+               
+       
+       if (!gt_str && !lt_str && optarg)
+       {
+               /* score may be there without <=>*/
+               p = optarg;
+#if BBR_REQUIRE_COMMA
+               /* no score if no ',' unless option is -r*/
+               if (opt == 'r' || bucket_str)
+#endif
+                       bbra.min_score = strtol(optarg, &p, 0);
+               /*only -r supports legacy -1 argument*/
+               if (p != optarg && (opt != 'r' || bbra.min_score != -1))
+                       bbra.min_flag = 1;
+#if !BBR_REQUIRE_COMMA
+               /* XXX no requirement for comma to seperate score,bucket*/
+               if (!bucket_str)
+                       bucket_str = p;
+       }
+       else if (!bucket_str && optarg)
+       {
+               /* no unescaped ',' in optarg */
+               /* advance pointer past all numeric stuff */
+               p = (gt_str > lt_str) ? gt_str : lt_str;
+               p++;
+               if (*(p+1) == '=')
+                       p++;
+               (void) strtol(p, &q, 0);
+               if (q)
+                       bucket_str = q;
+#endif
+       }
+               
+       /* strip escaping */
+       p = q = bucket_str;
+       i = 0;
+       while (p && p[i])
+       {
+               in_escape = 0;
+               if ((p[i]) == '\\' && !in_escape)       
+                       in_escape = 1;
+               else
+               {
+                       in_escape = 0;
+                       *q = *(p + i); 
+                       q++;
+               }
+               i++;
+       }
+       bbra.bucket = p;
+
+       if (end_p_sav && end_p && *end_p)
+               *(*end_p - 1) = end_p_sav;
+               
+       return(bbra);
+}
+
+static void
+bBr_print_list (struct linked_list * bbra_list)
+{
+       struct bBrAction bbra;
+
+       bbra_list = rewind_linked_list(bbra_list);
+
+       while (bbra_list)
+       {
+               memcpy(&bbra, linked_list_data(bbra_list,NULL), sizeof(bbra));
+               bbra_list = next_linked_list_item(bbra_list);
+       }
+}
+
+int bBr_cmp(void * p1, void * p2)
+{
+       struct bBrAction * bbra1 = (struct bBrAction *)p1;
+       struct bBrAction * bbra2 = (struct bBrAction *)p2;
+
+       char * s1 = bbra1->bucket;
+       char * s2 = bbra2->bucket;
+       int max1 = bbra1->max_score;
+       int max2 = bbra2->max_score;
+       int min1 = bbra1->min_score;
+       int min2 = bbra2->min_score;
+       int min1_f = bbra1->min_flag;
+       int min2_f = bbra2->min_flag;
+       int max1_f = bbra1->max_flag;
+       int max2_f = bbra2->max_flag;
+       int score2 = bbra2->score;
+       int score1 = bbra1->score;
+       int score1_f = bbra1->score_flag;
+       int score2_f = bbra2->score_flag;
+       char * bBr1 = bbra1->bBr;
+       char * bBr2 = bbra2->bBr;
+       int result_flag = 0;
+       int i, j;
+
+       for (i = 0; bBr2[i]; i++)
+       {
+               /* see if any of the actions match */
+               for (j = 0; bBr1[j]; j++)
+               {
+                       if (bBr1[j] == bBr2[i])
+                       {
+                               result_flag = 1;
+                               break;
+                       }
+               }
+               if (result_flag)
+                       break;
+       }               
+                               
+       if (result_flag)
+       {
+               if (s2) /* compare bucket strings */
+                       return (strcasecmp(s1,s2));
+
+               if (score2 || score2_f) /* comparing score */
+               {
+                       if ((score2 <= max1 && max1_f == score2_f) || max1_f < 
score2_f)
+                       {
+                               if ((score2 >= min1 && min1_f == score2_f) || 
min1_f < score2_f)
+                                       return 0; /* match */
+                       }
+                       if (score2 == score1 && score1_f == score2_f)
+                                       return 0; /* match */
+                       return 1;
+               }
+               /* comparing minmin maxmax pairs */     
+               if (!((max1 <= max2) && (max1_f == max2_f)) || !(max1_f < 
max2_f))
+                       return 1;
+               if (!((min1 >= min2) && (min1_f == min2_f)) || !(min1_f < 
min2_f))
+                       return 1;
+
+               return 0; /* match */
+       }
+       return 1;
+
+}
 /* closeall() - close all FDs >= a specified value */ 
 void closeall(int fd) 
 {
diff -urN spamass-milt.orig/spamass-milter.h 
spamass-milt.bBranges/spamass-milter.h
--- spamass-milt.orig/spamass-milter.h  2004-11-11 16:19:27.000000000 -0500
+++ spamass-milt.bBranges/spamass-milter.h      2004-11-10 22:09:22.000000000 
-0500
@@ -70,6 +70,19 @@
 };
 
 
+struct bBrAction
+{
+       char * bucket;
+       int max_score;
+       int max_flag;
+       int min_score;
+       int min_flag;
+       int score;
+       int score_flag;
+       char bBr[4];
+};
+
+
 // Debug tokens.
 enum debuglevel 
 {
@@ -185,5 +198,7 @@
 int ip_in_networklist(struct in_addr ip, struct networklist *list);
 void parse_debuglevel(char* string);
 char *strlwr(char *str);
+int bBr_cmp(void *, void *);
+struct bBrAction parse_bBr_arg(char opt, char * optarg, char **end_p);
 
 #endif
diff -urN spamass-milt.orig/vsnprintf_alloc.c 
spamass-milt.bBranges/vsnprintf_alloc.c
--- spamass-milt.orig/vsnprintf_alloc.c 1969-12-31 19:00:00.000000000 -0500
+++ spamass-milt.bBranges/vsnprintf_alloc.c     2004-11-07 15:58:34.000000000 
-0500
@@ -0,0 +1,191 @@
+#ifdef  __cplusplus
+extern "C" {
+#endif
+#include "vsnprintf_alloc.h"
+
+
+
+int
+vsnprintf_alloc(char **p, size_t len, const char * fmt, va_list argp)
+{
+       char    *buf = NULL;
+       char    *bufp = NULL;
+       short   we_malloced = 0;
+       int     retlen = 0;
+       size_t  print_len = (len) ? len : strlen(fmt) + BUFSIZ;
+
+       if(!fmt || !p || len < 0)
+       {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if(*p)
+       {
+               buf = realloc(*p, print_len + 1);
+               if(!buf)
+                       return -1;
+               *p = buf;
+       }
+       else
+       {
+               if((buf = malloc(print_len + 1)))
+                       we_malloced = 1;
+               else
+                       return -1;
+       }
+
+       while(1)        
+       {
+               retlen  = vsnprintf(buf, print_len + 1, fmt, argp);
+               
+               buf[print_len] = '\0';
+                       
+               if(retlen == -1)
+               {
+                       if(errno == EINVAL)
+                       {
+                               if(we_malloced)
+                                       free(buf);
+                               else
+                                       *p = buf;
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       /* For optimization, switch this to doubling? */
+                       print_len += BUFSIZ;
+               } 
+               else if(retlen > print_len) 
+               {
+                       /* C99 */
+                       print_len = retlen;
+               }
+               else
+               {
+                       /* Sucess */
+                       break;
+               }
+
+               if(len && print_len > len)
+                       print_len = len;
+               
+               bufp = realloc(buf, print_len + 1);
+               if(!bufp)
+               {
+                       if(we_malloced)
+                               free(buf);
+                       else
+                               *p = buf;
+                       return -1;
+               }
+               else
+                       buf = bufp;
+       }
+
+       
+       *p = buf;
+       return(retlen);
+}
+
+int
+vsprintf_alloc(char **p, const char * fmt, va_list argp)
+{
+       if(!fmt || !p)
+       {       
+               errno = EINVAL;
+               return -1;
+       }
+
+       return(vsnprintf_alloc(p, 0, fmt, argp));
+}      
+
+int
+snprintf_alloc(char **p, size_t len, const char * fmt, ...)
+{
+       int retlen = 0;
+       va_list argp;
+
+       if(!fmt || !p || len < 0)
+       {       
+               errno = EINVAL;
+               return -1;
+       }
+
+       va_start(argp, fmt);
+       retlen = vsnprintf_alloc(p, len, fmt, argp);
+       va_end(argp);
+
+       return(retlen);
+}      
+
+int
+sprintf_alloc(char **p, const char * fmt, ...)
+{
+       int retlen = 0;
+       va_list argp;
+
+       if(!fmt || !p)
+       {       
+               errno = EINVAL;
+               return -1;
+       }
+
+       va_start(argp, fmt);
+       retlen = vsprintf_alloc(p, fmt, argp);
+       va_end(argp);
+
+       return(retlen);
+}      
+
+struct vsnprintf_alloc_cfg *
+vsnprintf_alloc_configure(struct vsnprintf_alloc_cfg * cfg)
+{
+
+}
+
+#if !HAVE_ASPRINTF
+int
+asprintf(char **p, const char * fmt, ...)
+{
+       int retlen = 0;
+       char * buf = NULL;
+       va_list argp;
+
+       if(!fmt || !p)
+       {       
+               errno = EINVAL;
+               return -1;
+       }
+
+       va_start(argp, fmt);
+       retlen = vsprintf_alloc(&buf, fmt, argp);
+       if(retlen >= 0)
+               *p = buf;
+       va_end(argp);
+
+       return(retlen);
+}
+#endif /* !HAVE_ASPRINTF */
+
+#if !HAVE_VASPRINTF
+int
+vasprintf(char **p, const char * fmt, va_list argp)
+{
+       char * buf = NULL;
+       int retlen = 0;
+
+       if(!fmt || !p)
+       {       
+               errno = EINVAL;
+               return -1;
+       }
+
+       retlen = vsnprintf_alloc(&buf, 0, fmt, argp);
+       if(retlen >= 0)
+               *p = buf;
+       return(retlen);
+}      
+#endif /* !HAVE_VASPRINTF */ 
+#ifdef  __cplusplus
+}
+#endif
diff -urN spamass-milt.orig/vsnprintf_alloc.h 
spamass-milt.bBranges/vsnprintf_alloc.h
--- spamass-milt.orig/vsnprintf_alloc.h 1969-12-31 19:00:00.000000000 -0500
+++ spamass-milt.bBranges/vsnprintf_alloc.h     2004-11-07 16:14:09.000000000 
-0500
@@ -0,0 +1,96 @@
+#ifndef VSNPRINTF_ALLOC_H
+       #define VSNPRINTF_ALLOC_H
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#ifndef HAVE_VASPRINTF
+       #include "config.h"
+#endif
+
+#ifndef BUFSIZ
+       #define BUFSIZ  4096
+#endif
+
+/*
+ * Takes: address of pointer to char, optional maximum length, printf(3) 
format string, and a variable list of arguments
+ * Returns: -1 for error or number of bytes (that would have been) printed 
into string.
+ * 
+ * The address of pointer to char MUST not be null. 
+ *
+ * If the pointer to char is NOT null, it MUST be a valid malloc'd memory 
string.
+ * 
+ * if pointer to char is null, malloc will be called and the address stored 
back in the passed in addressed pointer
+ * otherwise realloc will be used as needed on the passed in pointer address 
with the result stored back in.
+ *
+ * 
+ * Passing in a NULL address or a negative length or a NULL format string 
+ * OR
+ * Running out of memory will return -1.  
+ *
+ * Doing the former will result in errno == EINVAL. 
+ * Presumably the latter will result in errno == ENOMEM.
+ *
+ * On error the pointer to char will be valid if it was originaly supplied by 
you and you must free it.
+ *
+ * Passing in a length of zero will allow the function to allocate memory 
until the entire string is printed.
+ * Otherwise it will only allocate and print into the string up to the size 
specified, including terminating '\0'.
+ *
+ * 
+ */
+int
+snprintf_alloc(char **p, size_t len, const char *fmt, ...);
+
+/*
+ * Same as above except 0 is assumed for length
+ */
+int
+sprintf_alloc(char **p, const char *fmt, ...);
+
+/*
+ * same as snprintf_alloc except you pass it argp instead of variable list of 
arguments
+ */
+int
+vsnprintf_alloc(char **p, size_t len, const char *fmt, va_list argp);
+
+/*
+ * same as above except 0 is assumed for length
+ */
+int
+vsprintf_alloc(char **p, const char *fmt, va_list argp);
+
+#if !HAVE_ASPRINTF
+/*
+ * like sprintf_alloc except does not support privately allocated memory. Also 
does not require *p to be NULL/
+ * On error *p should NOT be used and will probably be NULL.
+ *
+ * WARNING: Passing in address of valid pointer for p will lead to memory 
leaks! 
+ */
+int
+asprintf(char **p, const char *fmt, ...);
+#endif /* !HAVE_ASPRINF */
+
+#if !HAVE_VASPRINTF
+/*
+ * like vsprintf_alloc except does not support privately allocated memory. 
Also does not require *p to be NULL/
+ * On error *p should NOT be used and will probably be NULL.
+ *
+ * WARNING: Passing in address of valid pointer for p will lead to memory 
leaks! 
+ */
+int
+vasprintf(char **p, const char *fmt, va_list argp);
+#endif /* !HAVE_VASPRINF */
+
+
+struct vsnprintf_alloc_cfg 
+{
+       void (*malloc) (size_t);
+       void (*free) (void *, size_t);
+       short   multiply;
+       short   assertive;
+       size_t  internal_limit; 
+       short   free_on_error;
+};
+
+#endif /* VSNPRINTF_ALLOC_H */
Binary files spamass-milt.orig/vsnprintf_alloc.o and 
spamass-milt.bBranges/vsnprintf_alloc.o differ

reply via email to

[Prev in Thread] Current Thread [Next in Thread]