summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL22
-rw-r--r--LICENSE341
-rw-r--r--doc/INSTRUCTION151
-rw-r--r--doc/README25
-rw-r--r--src/Makefile102
-rw-r--r--src/config.c715
-rw-r--r--src/config.h80
-rw-r--r--src/dbase.c281
-rw-r--r--src/dbase.h86
-rw-r--r--src/dstring.c111
-rw-r--r--src/dstring.h86
-rw-r--r--src/global.h44
-rw-r--r--src/kbs.c147
-rw-r--r--src/kbsrc91
-rw-r--r--src/msg.h45
-rw-r--r--src/pop3.c530
-rw-r--r--src/pop3.h90
-rw-r--r--src/rexp.c63
-rw-r--r--src/rexp.h52
-rw-r--r--src/util.c79
-rw-r--r--src/util.h58
21 files changed, 3199 insertions, 0 deletions
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5674bb7
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,22 @@
+
+This program does not unfortunately use the configure script, but I have been
+careful to write is as portably as possible to unix systems.
+
+To build the software, type the following:
+
+ cd src
+ make depend
+ make
+
+Then copy the kbs executable wherever you want.
+
+
+Other or broken systems
+=======================
+
+If the Makefile is not usable on your system, you simply need to compile all
+the .c files and produce a single kbs object. E.g. (using the cc command
+as an example):
+
+ cd src
+ cc -o casm *.c
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..abd3cf7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/doc/INSTRUCTION b/doc/INSTRUCTION
new file mode 100644
index 0000000..d4ffc69
--- /dev/null
+++ b/doc/INSTRUCTION
@@ -0,0 +1,151 @@
+
+Usage
+=====
+
+ kbs
+
+
+Description
+===========
+
+kbs works on the simple premise that most people know who will be sending them
+email, or at least have a few trusted domains. It also makes it easy for
+a special keyword in a subject header to be used.
+
+
+Config file format
+==================
+
+The kbs config file is read from $HOME/.kbsrc and is in the form:
+
+[config settings]
+
+[trusted settings]
+
+[domain settings]
+
+Note it is *highly* recommended to set .kbsrc to be only readable by the
+user - this is as passwords are stored in there.
+
+Blank lines and text proceeded with a hash (#) are ignored.
+
+Each token is delimited with white space - if the value you want to use
+includes spaces, simple quote them (with either single or double quotes).
+
+Note that escapes aren't used (to make regular expression writing easier), so
+if you want to include a quote in a string, simply use the other sort of quote.
+If you want both, you're stuck!
+
+To see and example kbsrc file, see kbsrc in the src directory.
+
+
+Config settings
+===============
+
+The config settings are in the general form:
+
+ set variable=value
+
+And understand the following variables:
+
+
+ hostname <FQDN> The Fully Qualified Domain Name of the POP3 server.
+ Defaults to localhost.
+
+ port <port number> The port number to connect to.
+ Defaults to 110.
+
+ username <username> The username to give to the server.
+ Defaults to guest.
+
+ password <username> The password to give to the server.
+ Defaults to an empty string.
+
+ log <path> Log information to the given file (note the file is
+ appended to).
+ If not used, or is an illegal path, logging is to
+ stdout.
+
+ delete_log <path> Logs deleted messages to the given file, which is
+ appended to.
+ If not used, or is an illegal path, logging is to
+ $HOME/.kbs-deletelog.
+
+ timeout <seconds> Number of seconds to allow for no response from the
+ server.
+ Defaults to 60 seconds.
+
+ casesense <on|off> Whether regular expressions are case sensitive.
+ Defaults to case insensitive (off).
+
+ dejunk <on|off> Whether subjects are dejunked before checking.
+ Dejunking here means that anything an alphanumeric
+ character is stripped, and all contiguos white space
+ is reduced to one space.
+ Defaults to off.
+
+ blockhtml <on|off> Whether messages that are pure HTML (content part just
+ reported as "text/html" are blocked.
+ Defaults to off.
+
+ testmode <on|off> Whether things will be really deleted, or just
+ the actions logged. Note that the delete_log is still
+ filled out as if the deletion occured.
+ Defaults to off, though it is recommended to use this
+ for early runs to ensure your rules are not too harsh
+ (or too easy for that matter).
+
+
+Trusted settings
+================
+
+These define users and domains for which mail is let thorugh, regardless of
+other tests.
+
+ trusted_users
+ {
+ username
+ [username]
+ }
+
+ trusted_domains
+ {
+ domain
+ [domain]
+ }
+
+
+Domain settings
+===============
+
+These define the rules applied to a certain domain. Note the order these
+appear in is important, as the first match when checking domain names will
+be used.
+
+ domain <regular expression>
+ {
+ [default block|allow]
+ [block_user <username>]
+ [allow_subject <regular expression>]
+ [block_subject <regular expression>]
+ }
+
+The default says what to do if neither the allow_subject or block_subject are
+matched. If not specified, the default is to allow.
+
+The block user allows a specific username to be blocked. For instance, I've
+noticed that spammers have a great love of emailing from your username at
+a different domain.
+
+The allow_subject means that subjects that match that regular expression are
+always let through.
+
+The block_subject means that subjects that match that regular expression are
+always blocked and deleted.
+
+Note that multiple allow_subject and block_subject commands can be in one
+domain.
+
+
+-------------------------------------------------------------------------------
+$Id: INSTRUCTION,v 1.1.1.1 2003-12-04 01:54:55 ianc Exp $
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..facf09f
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,25 @@
+ kbs - A simple (very) POP3 filter
+ =================================
+
+ Copyright 2003 Ian Cowburn
+
+
+ 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
+
+
+ See INSTRUCTION for instructions on use.
+
+-------------------------------------------------------------------------------
+$Id: README,v 1.1.1.1 2003-12-04 01:54:55 ianc Exp $
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..22cc523
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,102 @@
+# kbs - Simple, easily fooled, POP3 spam filter
+#
+# Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+#
+# 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
+#
+# -------------------------------------------------------------------------
+#
+# $Id: Makefile,v 1.1.1.1 2003-12-04 01:54:55 ianc Exp $
+#
+
+CFLAGS += -g
+
+TARGET = kbs
+
+SOURCE = kbs.c \
+ pop3.c \
+ config.c \
+ rexp.c \
+ dbase.c \
+ dstring.c \
+ util.c
+
+OBJECTS = kbs.o \
+ pop3.o \
+ config.o \
+ rexp.o \
+ dbase.o \
+ dstring.o \
+ util.o
+
+$(TARGET): $(OBJECTS)
+ $(CC) $(CLAGS) -o $(TARGET) $(OBJECTS)
+
+clean:
+ rm -f $(TARGET) $(OBJECTS) core
+
+depend:
+ make clean
+ makedepend -- $(CFLAGS) -- $(SOURCE)
+ if test -e Makefile ; then rm -f Makefile.bak ; fi
+
+# DO NOT DELETE THIS LINE -- make depend depends on it
+
+kbs.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+kbs.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+kbs.o: /usr/include/limits.h /usr/include/sys/limits.h
+kbs.o: /usr/include/machine/_limits.h /usr/include/sys/syslimits.h
+kbs.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+kbs.o: /usr/include/stdarg.h /usr/include/time.h /usr/include/sys/timespec.h
+kbs.o: /usr/include/errno.h global.h config.h pop3.h msg.h rexp.h util.h
+pop3.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+pop3.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+pop3.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+pop3.o: /usr/include/stdarg.h /usr/include/ctype.h /usr/include/runetype.h
+pop3.o: /usr/include/sys/types.h /usr/include/machine/endian.h
+pop3.o: /usr/include/sys/select.h /usr/include/sys/_sigset.h
+pop3.o: /usr/include/sys/_timeval.h /usr/include/sys/timespec.h
+pop3.o: /usr/include/sys/socket.h /usr/include/sys/_iovec.h
+pop3.o: /usr/include/machine/param.h /usr/include/netinet/in.h
+pop3.o: /usr/include/netinet6/in6.h /usr/include/netinet/tcp.h
+pop3.o: /usr/include/netdb.h global.h pop3.h msg.h dstring.h util.h
+config.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+config.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+config.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+config.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/runetype.h
+config.o: global.h config.h dstring.h dbase.h msg.h rexp.h util.h
+rexp.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+rexp.o: /usr/include/sys/_types.h /usr/include/machine/_types.h global.h
+rexp.o: rexp.h
+dbase.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+dbase.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+dbase.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+dbase.o: /usr/include/ctype.h /usr/include/runetype.h global.h dbase.h msg.h
+dbase.o: dstring.h config.h rexp.h util.h
+dstring.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+dstring.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+dstring.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+dstring.o: /usr/include/stdarg.h /usr/include/ctype.h /usr/include/runetype.h
+dstring.o: /usr/include/sys/types.h /usr/include/machine/endian.h
+dstring.o: /usr/include/sys/select.h /usr/include/sys/_sigset.h
+dstring.o: /usr/include/sys/_timeval.h /usr/include/sys/timespec.h
+dstring.o: /usr/include/sys/socket.h /usr/include/sys/_iovec.h
+dstring.o: /usr/include/machine/param.h /usr/include/netinet/in.h
+dstring.o: /usr/include/netinet6/in6.h /usr/include/netinet/tcp.h
+dstring.o: /usr/include/netdb.h global.h dstring.h util.h
+util.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+util.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+util.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+util.o: global.h util.h
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..af55d58
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,715 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Config
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "config.h"
+#include "dstring.h"
+#include "dbase.h"
+#include "rexp.h"
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+typedef enum {
+ TOK_Expression,
+ TOK_Set,
+ TOK_OpenBracket,
+ TOK_CloseBracket,
+ TOK_Domain,
+ TOK_TrustedUsers,
+ TOK_TrustedDomains,
+ TOK_Default,
+ TOK_BlockUser,
+ TOK_AllowSubject,
+ TOK_BlockSubject,
+ TOK_VarHostname,
+ TOK_VarPort,
+ TOK_VarUsername,
+ TOK_VarPassword,
+ TOK_VarLog,
+ TOK_VarTimeout,
+ TOK_VarCasesense,
+ TOK_VarDejunk,
+ TOK_VarTestmode,
+ TOK_VarBlockHTML,
+ TOK_VarDeletelog,
+ TOK_ConstOn,
+ TOK_ConstOff,
+ TOK_ConstBlock,
+ TOK_ConstAllow,
+ TOK_EOF
+ } Token;
+
+typedef struct Command
+ {
+ const char *cmd;
+ Token token;
+ } Command;
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static DString error;
+static char *hostname="localhost";
+static char *username="nobody";
+static char *password="";
+static char *log="";
+static char *deletelog="";
+static int port=110;
+static int timeout=60;
+static int casesense=FALSE;
+static int dejunk=FALSE;
+static int testmode=FALSE;
+static int blockhtml=FALSE;
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+static const Command cmd_table[]=
+ {
+ /* Commands and main tokens
+ */
+ {"set", TOK_Set},
+ {"trusted_users", TOK_TrustedUsers},
+ {"trusted_domains", TOK_TrustedDomains},
+ {"{", TOK_OpenBracket},
+ {"}", TOK_CloseBracket},
+ {"domain", TOK_Domain},
+ {"default", TOK_Default},
+ {"block_user", TOK_BlockUser},
+ {"allow_subject", TOK_AllowSubject},
+ {"block_subject", TOK_BlockSubject},
+
+ /* Variables
+ */
+ {"hostname", TOK_VarHostname},
+ {"port", TOK_VarPort},
+ {"username", TOK_VarUsername},
+ {"password", TOK_VarPassword},
+ {"log", TOK_VarLog},
+ {"timeout", TOK_VarTimeout},
+ {"casesense", TOK_VarCasesense},
+ {"dejunk", TOK_VarDejunk},
+ {"testmode", TOK_VarTestmode},
+ {"blockhtml", TOK_VarBlockHTML},
+
+ /* Constants
+ */
+ {"on", TOK_ConstOn},
+ {"off", TOK_ConstOff},
+ {"block", TOK_ConstBlock},
+ {"allow", TOK_ConstAllow},
+
+ /* End of table
+ */
+ {NULL, TOK_EOF}
+ };
+
+
+/* ---------------------------------------- REQUIRED PROTOS
+*/
+static Token GetToken(FILE *fp, DString ret);
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+static int DoSet(FILE *fp)
+{
+# define TYPE_STR 0
+# define TYPE_INT 1
+# define TYPE_ONOFF 2
+
+ static const struct VarTable
+ {
+ Token token;
+ int type;
+ void *ptr;
+ } var_table[]=
+ {
+ {TOK_VarHostname, TYPE_STR, (void *)&hostname},
+ {TOK_VarPort, TYPE_INT, (void *)&port},
+ {TOK_VarUsername, TYPE_STR, (void *)&username},
+ {TOK_VarPassword, TYPE_STR, (void *)&password},
+ {TOK_VarLog, TYPE_STR, (void *)&log},
+ {TOK_VarTimeout, TYPE_INT, (void *)&timeout},
+ {TOK_VarCasesense, TYPE_ONOFF, (void *)&casesense},
+ {TOK_VarDejunk, TYPE_ONOFF, (void *)&dejunk},
+ {TOK_VarTestmode, TYPE_ONOFF, (void *)&testmode},
+ {TOK_VarBlockHTML, TYPE_ONOFF, (void *)&blockhtml},
+ {TOK_VarDeletelog, TYPE_STR, (void *)&deletelog},
+ {TOK_EOF,0,NULL}
+ };
+
+ const struct VarTable *vt=NULL;
+ DString ds;
+ Token tok;
+ int status=TRUE;
+ int f;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ for(f=0;var_table[f].token!=TOK_EOF && !vt;f++)
+ if (var_table[f].token==tok)
+ vt=var_table+f;
+
+ if (vt)
+ {
+ char **cp;
+ int *ip;
+
+ switch(vt->type)
+ {
+ case TYPE_STR:
+ cp=vt->ptr;
+ tok=GetToken(fp,ds);
+ *cp=CopyStr(ds->text);
+ break;
+
+ case TYPE_INT:
+ ip=vt->ptr;
+ tok=GetToken(fp,ds);
+ *ip=atoi(ds->text);
+ break;
+
+ case TYPE_ONOFF:
+ ip=vt->ptr;
+ tok=GetToken(fp,ds);
+
+ switch(tok)
+ {
+ case TOK_ConstOn:
+ *ip=TRUE;
+ break;
+
+ case TOK_ConstOff:
+ *ip=FALSE;
+ break;
+
+ default:
+ status=FALSE;
+ DSAddCP(error,"Expected on/off. Got: ");
+ DSAddDS(error,ds);
+ }
+ break;
+ }
+ }
+ else
+ {
+ status=FALSE;
+ DSAddCP(error,"Unrecognised variable: ");
+ DSAddDS(error,ds);
+ }
+
+ DSFree(ds);
+
+# undef TYPE_STR
+# undef TYPE_INT
+# undef TYPE_ONOFF
+
+ return status;
+}
+
+
+static int DoDomain(FILE *fp)
+{
+ DString ds;
+ Token tok;
+ int status=TRUE;
+ Domain *domain;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_Expression)
+ {
+ DSAddCP(error,"Domain must be followed by expression. Got: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ if (RExpSearch(ds->text,"dummy")==RE_BadExpression)
+ {
+ DSAddCP(error,"Bad regular expression: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ domain=DBNewDomain(ds->text);
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_OpenBracket)
+ {
+ DSAddCP(error,"Missing opening bracket in domain");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ while((tok=GetToken(fp,ds))!=TOK_CloseBracket)
+ {
+ if (tok==TOK_EOF)
+ {
+ DSAddCP(error,"Missing close bracket in domain");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ switch(tok)
+ {
+ case TOK_Default:
+ switch(GetToken(fp,ds))
+ {
+ case TOK_ConstAllow:
+ DBDefault(domain,FALSE);
+ break;
+
+ case TOK_ConstBlock:
+ DBDefault(domain,TRUE);
+ break;
+
+ default:
+ DSAddCP(error,"Unexpected value in default command: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ break;
+ }
+
+ break;
+
+ case TOK_BlockUser:
+ GetToken(fp,ds);
+ DBBlockUser(domain,ds->text);
+ break;
+
+ case TOK_AllowSubject:
+ GetToken(fp,ds);
+
+ if (RExpSearch(ds->text,"dummy")==RE_BadExpression)
+ {
+ DSAddCP(error,"Bad regular expression: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ DBAllowSubject(domain,ds->text);
+ break;
+
+ case TOK_BlockSubject:
+ GetToken(fp,ds);
+
+ if (RExpSearch(ds->text,"dummy")==RE_BadExpression)
+ {
+ DSAddCP(error,"Bad regular expression: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ DBBlockSubject(domain,ds->text);
+ break;
+
+ default:
+ DSAddCP(error,"Unexpected string in domain command: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ break;
+ }
+ }
+
+ DSFree(ds);
+
+ return TRUE;
+}
+
+
+static int DoTrustedUsers(FILE *fp)
+{
+ DString ds;
+ Token tok;
+ int status=TRUE;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_OpenBracket)
+ {
+ DSAddCP(error,"Missing opening bracket in trusted_users");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ while((tok=GetToken(fp,ds))!=TOK_CloseBracket)
+ {
+ if (tok==TOK_EOF)
+ {
+ DSAddCP(error,"Missing close bracket in trusted_users");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ DBTrustedUser(ds->text);
+ }
+
+ DSFree(ds);
+
+ return TRUE;
+}
+
+
+static int DoTrustedDomains(FILE *fp)
+{
+ DString ds;
+ Token tok;
+ int status=TRUE;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_OpenBracket)
+ {
+ DSAddCP(error,"Missing opening bracket in trusted_domains");
+ return FALSE;
+ }
+
+ while((tok=GetToken(fp,ds))!=TOK_CloseBracket)
+ {
+ if (tok==TOK_EOF)
+ {
+ DSAddCP(error,"Missing close bracket in trusted_domains");
+ return FALSE;
+ }
+
+ DBTrustedDomain(ds->text);
+ }
+
+ return TRUE;
+}
+
+
+/* ---------------------------------------- PRVIVATE FUNCTIONS
+*/
+static int Getc(FILE *fp)
+{
+ int ch;
+
+ ch=fgetc(fp);
+
+ if (ch=='#')
+ {
+ ch=fgetc(fp);
+
+ while(ch!=EOF && ch!='\n')
+ ch=fgetc(fp);
+ }
+
+ return ch;
+}
+
+
+static int SkipWS(FILE *fp)
+{
+ int ch;
+
+ ch=Getc(fp);
+
+ while(isspace(ch))
+ ch=Getc(fp);
+
+ if (ch==EOF)
+ return FALSE;
+ else
+ {
+ ungetc(ch,fp);
+ return TRUE;
+ }
+}
+
+
+static Token FindToken(const char *p)
+{
+ int f;
+
+ for(f=0;cmd_table[f].cmd;f++)
+ if (strcmp(cmd_table[f].cmd,p)==0)
+ return cmd_table[f].token;
+
+ return TOK_Expression;
+}
+
+
+static int IsTerm(int ch)
+{
+ return isspace(ch) || ch=='#';
+}
+
+
+static Token GetToken(FILE *fp, DString ret)
+{
+ int ch;
+ int done=FALSE;
+ int quote=0;
+ Token tok;
+
+ ret=DSReset(ret);
+
+ if (feof(fp))
+ {
+ DSAddCP(ret,"EOF");
+ return TOK_EOF;
+ }
+
+ if (!SkipWS(fp))
+ {
+ DSAddCP(ret,"EOF");
+ return TOK_EOF;
+ }
+
+ while(!done)
+ {
+ ch=fgetc(fp);
+
+ if (quote)
+ {
+ if (ch==EOF)
+ {
+ done=TRUE;
+
+ DSAddCP(error,"Unexpected EOF in string");
+ tok=TOK_EOF;
+ }
+ else if (ch==quote)
+ {
+ done=TRUE;
+ tok=FindToken(ret->text);
+ }
+ else
+ {
+ DSAddChar(ret,ch);
+ }
+ }
+ else
+ {
+ if (ch==EOF)
+ {
+ done=TRUE;
+
+ if (ret->len)
+ tok=FindToken(ret->text);
+ else
+ tok=TOK_EOF;
+ }
+ else if (IsTerm(ch))
+ {
+ ungetc(ch,fp);
+ done=TRUE;
+ tok=FindToken(ret->text);
+ }
+ else if (ch=='\'' || ch=='"')
+ {
+ quote=ch;
+ }
+ else
+ {
+ DSAddChar(ret,ch);
+ }
+ }
+ }
+
+ return tok;
+}
+
+
+static int Parse(FILE *fp)
+{
+ DString txt;
+ Token tok;
+ char *p;
+
+ txt=DSInit();
+
+ while((tok=GetToken(fp,txt))!=TOK_EOF)
+ {
+ int ok=TRUE;
+
+ switch(tok)
+ {
+ case TOK_Set:
+ if (!DoSet(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_Domain:
+ if (!DoDomain(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_TrustedUsers:
+ if (!DoTrustedUsers(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_TrustedDomains:
+ if (!DoTrustedDomains(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_Expression:
+ DSAddCP(error,"Unknown command in config file: ");
+ DSAddDS(error,txt);
+ ok=FALSE;
+ break;
+
+ default:
+ DSAddCP(error,"Unexpected token in config file: ");
+ DSAddDS(error,txt);
+ ok=FALSE;
+ break;
+ }
+
+ if (!ok)
+ break;
+
+ txt=DSReset(txt);
+ }
+
+ DSFree(txt);
+
+ return error->len==0;
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+int ConfigLoad(void)
+{
+ DString ds;
+ FILE *fp;
+ int ret;
+
+ error=DSInit();
+
+ if (!getenv("HOME"))
+ return FALSE;
+
+ ds=DSInit();
+
+ DSAddCP(ds,getenv("HOME"));
+ DSAddChar(ds,'/');
+ DSAddCP(ds,".kbsrc");
+
+ if ((fp=fopen(ds->text,"r")))
+ ret=Parse(fp);
+ else
+ ret=FALSE;
+
+ DSFree(ds);
+
+ return ret;
+}
+
+
+const char *ConfigError(void)
+{
+ if (strlen(error->text))
+ return error->text;
+ else
+ return strerror(errno);
+}
+
+
+const char *ConfigString(ConfigStringVar var)
+{
+ switch(var)
+ {
+ case CONFIG_HOSTNAME:
+ return hostname;
+
+ case CONFIG_USERNAME:
+ return username;
+
+ case CONFIG_PASSWORD:
+ return password;
+
+ case CONFIG_LOG:
+ return log;
+
+ case CONFIG_DELETE_LOG:
+ return deletelog;
+
+ default:
+ return "";
+ }
+}
+
+
+int ConfigInt(ConfigIntVar var)
+{
+ switch(var)
+ {
+ case CONFIG_PORT:
+ return port;
+
+ case CONFIG_TIMEOUT:
+ return timeout;
+
+ case CONFIG_CASESENSE:
+ return casesense;
+
+ case CONFIG_DEJUNK:
+ return dejunk;
+
+ case CONFIG_TESTMODE:
+ return testmode;
+
+ case CONFIG_BLOCKHTML:
+ return blockhtml;
+
+ default:
+ return 0;
+ }
+}
+
+
+/* END OF FILE */
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..a2ddc78
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,80 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Config file.
+
+*/
+
+#ifndef KBS_CONFIG_H
+#define KBS_CONFIG_H
+
+
+/* ---------------------------------------- VARIABLE NAMES
+*/
+
+/* char* variables
+*/
+typedef enum
+ {
+ CONFIG_HOSTNAME,
+ CONFIG_USERNAME,
+ CONFIG_PASSWORD,
+ CONFIG_LOG,
+ CONFIG_DELETE_LOG
+ } ConfigStringVar;
+
+
+/* int/boolean variables
+*/
+typedef enum
+ {
+ CONFIG_PORT,
+ CONFIG_TIMEOUT,
+ CONFIG_CASESENSE,
+ CONFIG_DEJUNK,
+ CONFIG_TESTMODE,
+ CONFIG_BLOCKHTML
+ } ConfigIntVar;
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Loads in config file. Returns FALSE for problems.
+*/
+int ConfigLoad(void);
+
+
+/* Returns a reason for config load failure
+*/
+const char *ConfigError(void);
+
+
+/* Query interfaces for variables
+*/
+const char *ConfigString(ConfigStringVar var);
+int ConfigInt(ConfigIntVar var);
+
+#endif
+
+/* END OF FILE */
diff --git a/src/dbase.c b/src/dbase.c
new file mode 100644
index 0000000..5eca1a9
--- /dev/null
+++ b/src/dbase.c
@@ -0,0 +1,281 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Rules database
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "dbase.h"
+#include "dstring.h"
+#include "config.h"
+#include "rexp.h"
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+struct Domain
+ {
+ char *name;
+ int def_block;
+ int no_user;
+ int no_block;
+ int no_allow;
+ char **user;
+ char **block;
+ char **allow;
+ Domain *next;
+ Domain *prev;
+ };
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static Domain *head;
+static Domain *tail;
+
+static int no_trusted_users=0;
+static int no_trusted_domains=0;
+
+static char **trusted_user=NULL;
+static char **trusted_domain=NULL;
+
+
+/* ---------------------------------------- PRVIVATE FUNCTIONS
+*/
+static int IsTrustedUser(const char *username)
+{
+ int f;
+
+ for(f=0;f<no_trusted_users;f++)
+ {
+ if (strcasecmp(username,trusted_user[f])==0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static int IsTrustedDomain(const char *domain)
+{
+ int f;
+
+ for(f=0;f<no_trusted_domains;f++)
+ {
+ if (strcasecmp(domain,trusted_domain[f])==0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static const Domain *GetDomain(const char *domain)
+{
+ Domain *dom;
+
+ dom=head;
+
+ while(dom)
+ {
+ if (RExpSearch(dom->name,domain)==RE_Found)
+ return dom;
+
+ dom=dom->next;
+ }
+
+ return NULL;
+}
+
+
+static void DeJunk(DString ds, const char *p)
+{
+ int last_ws=FALSE;
+
+ while(*p)
+ {
+ if (isspace(*p))
+ {
+ if (!last_ws)
+ DSAddChar(ds,' ');
+
+ last_ws=TRUE;
+ }
+ else
+ last_ws=FALSE;
+
+ if (isalnum(*p))
+ {
+ DSAddChar(ds,*p);
+ }
+
+ p++;
+ }
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+Domain *DBNewDomain(const char *regexp)
+{
+ Domain *dom;
+
+ dom=Malloc(sizeof *dom);
+
+ dom->name=CopyStr(regexp);
+ dom->def_block=FALSE;
+
+ dom->no_user=0;
+ dom->no_block=0;
+ dom->no_allow=0;
+
+ dom->user=NULL;
+ dom->block=NULL;
+ dom->allow=NULL;
+
+ if (tail)
+ tail->next=dom;
+ else
+ head=tail=dom;
+
+ dom->prev=tail;
+ dom->next=NULL;
+
+ return dom;
+}
+
+
+void DBDefault(Domain *domain, int block)
+{
+ domain->def_block=block;
+}
+
+
+void DBBlockUser(Domain *domain, const char *username)
+{
+ domain->no_user++;
+ domain->user=Realloc(domain->user,sizeof(char *)*domain->no_user);
+ domain->user[domain->no_user-1]=CopyStr(username);
+}
+
+
+void DBAllowSubject(Domain *domain, const char *regexp)
+{
+ domain->no_allow++;
+ domain->allow=Realloc(domain->allow,sizeof(char *)*domain->no_allow);
+ domain->allow[domain->no_allow-1]=CopyStr(regexp);
+}
+
+
+void DBBlockSubject(Domain *domain, const char *regexp)
+{
+ domain->no_block++;
+ domain->block=Realloc(domain->block,sizeof(char *)*domain->no_block);
+ domain->block[domain->no_block-1]=CopyStr(regexp);
+}
+
+
+void DBTrustedUser(const char *username)
+{
+ no_trusted_users++;
+ trusted_user=Realloc(trusted_user,sizeof(char *)*no_trusted_users);
+ trusted_user[no_trusted_users-1]=CopyStr(username);
+}
+
+
+void DBTrustedDomain(const char *domain)
+{
+ no_trusted_domains++;
+ trusted_domain=Realloc(trusted_domain,sizeof(char *)*no_trusted_domains);
+ trusted_domain[no_trusted_domains-1]=CopyStr(domain);
+}
+
+
+int DBBlockMessage(const POP3Message *msg)
+{
+ DString ds;
+ const Domain *dom;
+ int f;
+
+ if (IsTrustedDomain(msg->from_domain))
+ return FALSE;
+
+ if (IsTrustedUser(msg->from_uname))
+ return FALSE;
+
+ if (!(dom=GetDomain(msg->from_domain)))
+ return FALSE;
+
+ for(f=0;f<dom->no_user;f++)
+ {
+ if (ConfigInt(CONFIG_CASESENSE))
+ {
+ if (strcmp(dom->user[f],msg->from_uname)==0)
+ return TRUE;
+ }
+ else
+ {
+ if (strcasecmp(dom->user[f],msg->from_uname)==0)
+ return TRUE;
+ }
+ }
+
+ ds=DSInit();
+
+ if (ConfigInt(CONFIG_DEJUNK))
+ DeJunk(ds,msg->subject);
+ else
+ DSAddCP(ds,msg->subject);
+
+ for(f=0;f<dom->no_allow;f++)
+ {
+ if (RExpSearch(dom->allow[f],ds->text)==RE_Found)
+ {
+ DSFree(ds);
+ return FALSE;
+ }
+ }
+
+ for(f=0;f<dom->no_block;f++)
+ {
+ if (RExpSearch(dom->block[f],ds->text)==RE_Found)
+ {
+ DSFree(ds);
+ return TRUE;
+ }
+ }
+
+ DSFree(ds);
+ return dom->def_block;
+}
+
+
+/* END OF FILE */
diff --git a/src/dbase.h b/src/dbase.h
new file mode 100644
index 0000000..df64927
--- /dev/null
+++ b/src/dbase.h
@@ -0,0 +1,86 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Rules database
+
+*/
+
+#ifndef KBS_DBASE_H
+#define KBS_DBASE_H
+
+#include "msg.h"
+
+/* ---------------------------------------- TYPES
+*/
+struct Domain;
+
+typedef struct Domain Domain;
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Add a new domain and define the regular expression that defines it
+*/
+Domain *DBNewDomain(const char *regexp);
+
+
+/* Define the default mode for a domain
+*/
+void DBDefault(Domain *domain, int block);
+
+
+/* Adds a disallowed username for a domain
+*/
+void DBBlockUser(Domain *domain, const char *username);
+
+
+/* Add an allowable subject for a domain
+*/
+void DBAllowSubject(Domain *domain, const char *regexp);
+
+
+/* Adds a disallowed subject for a domain
+*/
+void DBBlockSubject(Domain *domain, const char *regexp);
+
+
+/* Adds a trusted username
+*/
+void DBTrustedUser(const char *username);
+
+
+/* Adds a trusted domain
+*/
+void DBTrustedDomain(const char *domain);
+
+
+/* Returns TRUE if message is to be blocked
+*/
+int DBBlockMessage(const POP3Message *msg);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/dstring.c b/src/dstring.c
new file mode 100644
index 0000000..e614e83
--- /dev/null
+++ b/src/dstring.c
@@ -0,0 +1,111 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Dynamic strings
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include "global.h"
+#include "dstring.h"
+#include "util.h"
+
+
+/* ---------------------------------------- CONSTANTS
+*/
+#define BLOCKSIZE 512
+
+
+/* ---------------------------------------- INTERFACES
+*/
+DString DSInit(void)
+{
+ DString ds;
+
+ ds=Malloc(sizeof *ds);
+
+ ds->len=0;
+ ds->text=Malloc(BLOCKSIZE);
+ ds->text[0]=0;
+
+ return ds;
+}
+
+
+void DSFree(DString ds)
+{
+ free(ds->text);
+ free(ds);
+}
+
+
+DString DSReset(DString ds)
+{
+ DSFree(ds);
+ return DSInit();
+}
+
+
+DString DSAddChar(DString to, char c)
+{
+ if (((to->len+2)%BLOCKSIZE)==0)
+ {
+ to->text=Realloc(to->text,(((to->len+2)/BLOCKSIZE)+1)*BLOCKSIZE);
+ }
+
+ to->text[to->len++]=c;
+ to->text[to->len]=0;
+}
+
+
+DString DSAddCP(DString to, const char *from)
+{
+ to->len+=strlen(from);
+ to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE);
+
+ strcat(to->text,from);
+}
+
+
+DString DSAddDS(DString to, const DString from)
+{
+ to->len+=from->len;
+ to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE);
+
+ strcat(to->text,from->text);
+}
+
+
+/* END OF FILE */
diff --git a/src/dstring.h b/src/dstring.h
new file mode 100644
index 0000000..db6454f
--- /dev/null
+++ b/src/dstring.h
@@ -0,0 +1,86 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Dynamic strings
+
+*/
+
+#ifndef KBS_DSTRING_H
+#define KBS_DSTRING_H
+
+/* ---------------------------------------- TYPES
+*/
+typedef struct
+ {
+ size_t len;
+ char *text;
+ } *DString;
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Sets a DString up for use. Note when reusing the same DString, remember
+ to call DSReset() and get the return.
+
+ Returns the new DString.
+*/
+DString DSInit();
+
+
+/* Frees a DString.
+*/
+void DSFree(DString ds);
+
+
+/* Resets a string. Basically calls DSFree() then DSInit().
+
+ Returns the parameter.
+*/
+DString DSReset(DString ds);
+
+
+/* Adds a character onto a DString.
+
+ Returns the passed DString.
+*/
+DString DSAddChar(DString to, char c);
+
+
+/* Adds a nul-terminated char pointer onto a DString.
+
+ Returns the passed DString.
+*/
+DString DSAddCP(DString to, const char *p);
+
+
+/* Adds another DString.
+
+ Returns the passed to DString.
+*/
+DString DSAddDS(DString to, const DString from);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/global.h b/src/global.h
new file mode 100644
index 0000000..6fcfe52
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,44 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Global include
+
+*/
+
+#ifndef KBS_GLOBAL_H
+#define KBS_GLOBAL_H
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#endif
+
+/* END OF FILE */
diff --git a/src/kbs.c b/src/kbs.c
new file mode 100644
index 0000000..25afe5f
--- /dev/null
+++ b/src/kbs.c
@@ -0,0 +1,147 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+#include "global.h"
+#include "config.h"
+#include "pop3.h"
+#include "dbase.h"
+#include "util.h"
+
+/* ---------------------------------------- MACROS
+*/
+#define LOG (logfp ? logfp:stderr)
+
+
+/* ---------------------------------------- TYPES
+*/
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static const char *name=NULL;
+static FILE *logfp=NULL;
+
+
+/* ---------------------------------------- PROTOS
+*/
+
+
+/* ---------------------------------------- MAIN
+*/
+int main(int argc, char *argv[])
+{
+ POP3Message *msg;
+
+ if (strchr(argv[0],'/'))
+ name=strchr(argv[0],'/')+1;
+ else
+ name=argv[0];
+
+ if (!ConfigLoad())
+ {
+ fprintf(stderr,"%s\n",ConfigError());
+ exit(EXIT_FAILURE);
+ }
+
+ switch(POP3Connect(ConfigString(CONFIG_HOSTNAME),
+ ConfigInt(CONFIG_PORT),
+ ConfigString(CONFIG_USERNAME),
+ ConfigString(CONFIG_PASSWORD),
+ ConfigInt(CONFIG_TIMEOUT)))
+ {
+ case POP3_OK:
+ break;
+
+ case POP3_COMMERROR:
+ fprintf(LOG,"Comms error (errno = %d)\n",errno);
+ exit(EXIT_FAILURE);
+ break;
+
+ case POP3_NOCONNECT:
+ fprintf(LOG,"No connection to host (errno = %d)\n",errno);
+ exit(EXIT_FAILURE);
+ break;
+
+ case POP3_BADUSER:
+ fprintf(LOG,"Bad username\n");
+ exit(EXIT_FAILURE);
+ break;
+
+ case POP3_BADPASSWD:
+ fprintf(LOG,"Bad password\n");
+ exit(EXIT_FAILURE);
+ break;
+
+ default:
+ break;
+ }
+
+ if ((msg=POP3GetList()))
+ {
+ int f;
+ int tot=0;
+ int block=0;
+
+ for(f=0;msg[f].to;f++)
+ {
+ tot++;
+ printf("Num %d\n",msg[f].id);
+ printf(" From : %s@%s\n",msg[f].from_uname,msg[f].from_domain);
+ printf(" Subject : %s\n",msg[f].subject);
+
+ if (DBBlockMessage(msg+f))
+ {
+ printf(" BLOCKED : YES\n\n");
+ block++;
+ }
+ else
+ printf(" BLOCKED : NO\n\n");
+ }
+
+ printf("%d messages, %d blocked\n",tot,block);
+
+ POP3FreeList(msg);
+ }
+ else
+ {
+ printf("No messages\n");
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+/* ---------------------------------------- UTIL
+*/
+
+/* END OF FILE */
diff --git a/src/kbsrc b/src/kbsrc
new file mode 100644
index 0000000..e59e512
--- /dev/null
+++ b/src/kbsrc
@@ -0,0 +1,91 @@
+# Simple example KBS config file
+#
+
+# Set variables
+#
+set hostname mail.myisp.co.uk
+set username foobar
+set password raboof
+set casesense off
+set dejunk on
+set testmode on
+
+
+# Trusted people (from my address book)
+#
+trusted_users
+{
+ family@aol.com
+ fred@foobar.org
+ mailinglist@wibblesticks.com
+}
+
+trusted_domains
+{
+ my-place-of-work.com
+ freebsd.org
+}
+
+
+# Domain based rules
+#
+# Remember that the domain is defined in the form of a regular expression!
+#
+
+# Anyone who doesn't know me, has to include the string ansi-c to
+# get through from a .net address.
+#
+domain "\.net$"
+{
+ default block
+ allow_subject ".*ansi-c.*"
+}
+
+# 'Blacklist' a specific domain
+#
+domain "^wretched-hive-of-scum-and-villainy\.com$"
+{
+ default block
+}
+
+
+# Or alternatively apply general rules to all untrusted messages
+#
+domain "."
+{
+ default allow
+
+ # Apologies in advance if you have the same user ID as me...
+ #
+ block_user emailname
+
+ # Obviously, things like "credit card" will not be blocked from the bank
+ # as that's in the trusted_domains.
+ #
+ # And some of these may be accidently found in normal words, so remember
+ # to check the delete logs once in a while.
+ #
+ # And to avoid insulting anyone, there are some obvious words missing
+ # from this example list... If you're old enough, add them yourself.
+ #
+ # And finally remember a few variants - spelling isn't what it once was
+ # amongst spammers...
+ #
+ block_subject ".* ?penis ?.*"
+ block_subject ".* ?teenz ?.*"
+ block_subject ".* ?viagra ?.*"
+ block_subject ".* ?free all you can download ?.*"
+ block_subject ".* ?mortgage ?.*"
+ block_subject ".* ?credit card ?.*"
+ block_subject ".* ?miracle pill ?.*"
+ block_subject ".* ?teenage girl ?.*"
+ block_subject ".* ?video tape ?.*"
+ block_subject ".* ?sexy? ?.*"
+ block_subject ".* ?naked ?.*"
+ block_subject ".* ?nigeria ?.*"
+
+ # Why would anyone sane want to use my username in a subject?
+ # I know who I am!
+ #
+ block_subject "emailname@my-isp.co.uk"
+}
diff --git a/src/msg.h b/src/msg.h
new file mode 100644
index 0000000..314e9a7
--- /dev/null
+++ b/src/msg.h
@@ -0,0 +1,45 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Defines a POP3 message
+
+*/
+
+#ifndef KBS_MSG_H
+#define KBS_MSG_H
+
+typedef struct
+ {
+ int id;
+ char *to;
+ char *from;
+ char *from_uname;
+ char *from_domain;
+ char *subject;
+ char *content_type;
+ } POP3Message;
+
+#endif
+
+/* END OF FILE */
diff --git a/src/pop3.c b/src/pop3.c
new file mode 100644
index 0000000..8fd2750
--- /dev/null
+++ b/src/pop3.c
@@ -0,0 +1,530 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ POP3 Interface
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include "global.h"
+#include "pop3.h"
+#include "dstring.h"
+#include "util.h"
+
+
+/* ---------------------------------------- CONSTANTS
+*/
+#define BLOCKSIZE 512
+
+#define HDR_UNKNOWN -1
+#define HDR_SUBJECT 0
+#define HDR_FROM 1
+#define HDR_TO 2
+#define HDR_CONTENT_TYPE 3
+
+/* ---------------------------------------- TYPES
+*/
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static int sock;
+static int timeout;
+static int connected=FALSE;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Chomp(char *p)
+{
+ size_t l;
+
+ l=strlen(p);
+
+ if (l && p[l-1]=='\012')
+ {
+ p[--l]=0;
+ }
+
+ if (l && p[l-1]=='\015')
+ {
+ p[--l]=0;
+ }
+}
+
+
+static char *ChompQuotesWS(char *p)
+{
+ size_t l;
+
+ l=strlen(p);
+
+ while (l && (p[l-1]=='"' || isspace(p[l-1])))
+ {
+ p[--l]=0;
+ }
+
+ while (l && (p[0]=='"' || isspace(p[0])))
+ memmove(p,p+1,--l);
+
+ return p;
+}
+
+
+static int Connect(const char *hostname, int port)
+{
+ struct hostent *remote;
+ struct sockaddr_in addr;
+
+ if (!(remote=gethostbyname(hostname)))
+ {
+ return FALSE;
+ }
+
+ memcpy(&addr.sin_addr,remote->h_addr,remote->h_length);
+
+ if ((sock=socket(PF_INET,SOCK_STREAM,0))==-1)
+ return FALSE;
+
+ addr.sin_family=AF_INET;
+ addr.sin_port=htons(port);
+
+ if (connect(sock,(const void *)&addr,sizeof(addr))==-1)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static int SendSock(const char *p, size_t len)
+{
+ size_t sent=0;
+
+ while(sent<len)
+ {
+ ssize_t w;
+
+ w=write(sock,p+sent,len-sent);
+
+ if (w==-1)
+ return -1;
+
+ if (w==0)
+ return 0;
+
+ sent+=w;
+ }
+
+ return 1;
+}
+
+
+static int Send(const char *cmd, ...)
+{
+ va_list ap;
+ const char *p;
+ int status;
+
+ va_start(ap,cmd);
+
+ status=SendSock(cmd,strlen(cmd));
+
+ p=va_arg(ap,const char *);
+
+ while (p && status==1)
+ {
+ status=SendSock(p,strlen(p));
+ p=va_arg(ap,const char *);
+ }
+
+ va_end(ap);
+
+ if (status==1)
+ status=SendSock("\015\012",2);
+
+ return status;
+}
+
+
+static int GetChar(void)
+{
+ static char buff[BLOCKSIZE];
+ static ssize_t len=0;
+ static int ptr=0;
+ int ch;
+
+ if (len==0 || ptr==len)
+ {
+ struct timeval tv;
+ fd_set set;
+
+ tv.tv_sec=timeout;
+ tv.tv_usec=timeout;
+
+ FD_ZERO(&set);
+ FD_SET(sock,&set);
+
+ if (select(sock+1,&set,NULL,NULL,&tv)==-1)
+ return -1;
+
+ if (!FD_ISSET(sock,&set))
+ return -1;
+
+ if ((len=read(sock,buff,sizeof buff))<1)
+ return -1;
+
+ ptr=0;
+ }
+
+ return buff[ptr++];
+}
+
+
+static int GetLine(DString t)
+{
+ size_t size;
+ int done;
+ int ch;
+ int last;
+
+ done=FALSE;
+
+ while(!done && (ch=GetChar())!=-1)
+ {
+ DSAddChar(t,ch);
+
+ if (last=='\015' && ch=='\012')
+ done=TRUE;
+
+ last=ch;
+ }
+
+ if (ch==-1)
+ return FALSE;
+
+ Chomp(t->text);
+
+ return TRUE;
+}
+
+
+static int GetResponse(DString ret)
+{
+ DString t;
+ int flag;
+
+ t=DSInit();
+
+ if (GetLine(t))
+ flag=t->text[0]=='+';
+ else
+ flag=FALSE;
+
+ if (ret)
+ DSAddDS(ret,t);
+
+ DSFree(t);
+
+ return flag;
+}
+
+
+static int GetMultiLine(DString ret)
+{
+ int flag;
+
+ if (GetLine(ret))
+ flag=TRUE;
+ else
+ flag=FALSE;
+
+ return flag;
+}
+
+
+static void ParseHeader(POP3Message *msg, char *line)
+{
+ static const struct
+ {
+ const char *text;
+ int type;
+ } field[]=
+ {
+ {"Subject: ", HDR_SUBJECT},
+ {"From: ", HDR_FROM},
+ {"To: ", HDR_TO},
+ {"Content-type: ", HDR_CONTENT_TYPE},
+ {"Content-Type: ", HDR_CONTENT_TYPE},
+ {NULL, HDR_UNKNOWN}
+ };
+
+ int f;
+ int type=HDR_UNKNOWN;
+
+ for(f=0;type==HDR_UNKNOWN && field[f].text;f++)
+ if (strncmp(field[f].text,line,strlen(field[f].text))==0)
+ {
+ type=field[f].type;
+ line+=strlen(field[f].text);
+ }
+
+ switch(type)
+ {
+ case HDR_SUBJECT:
+ msg->subject=CopyStr(line);
+ break;
+
+ case HDR_FROM:
+ if (strchr(line,'<'))
+ {
+ char *t[3];
+
+ for(f=0;f<3 && t[f-1];f++)
+ t[f]=strtok(f==0 ? line:NULL,"<>@");
+
+ msg->from=CopyStr(t[0] ? ChompQuotesWS(t[0]) : "UNKNOWN");
+ msg->from_uname=CopyStr(t[1] ? t[1] : "UNKNOWN");
+ msg->from_domain=CopyStr(t[2] ? t[2] : "UNKNOWN");
+ }
+ else
+ {
+ char *t[2];
+
+ for(f=0;f<2 && t[f-1];f++)
+ t[f]=strtok(f==0 ? line:NULL,"@");
+
+ msg->from=CopyStr("UNKNOWN");
+ msg->from_uname=CopyStr(t[0] ? t[0] : "UNKNOWN");
+ msg->from_domain=CopyStr(t[1] ? t[1] : "UNKNOWN");
+ }
+ break;
+
+ case HDR_TO:
+ msg->to=CopyStr(line);
+ break;
+
+ case HDR_CONTENT_TYPE:
+ msg->content_type=CopyStr(line);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+POP3Status POP3Connect(const char *hostname, int port,
+ const char *username, const char *passwd,
+ int t)
+{
+ timeout=t;
+ connected=FALSE;
+
+ if (port==0)
+ {
+ struct servent *ent;
+
+ if ((ent=getservbyname("pop3","tcp")))
+ port=ntohs(ent->s_port);
+ else
+ port=110;
+ }
+
+ if (!Connect(hostname,port))
+ return POP3_NOCONNECT;
+
+ if (!GetResponse(NULL))
+ return POP3_COMMERROR;
+
+ if (Send("USER ",username,(const char *)NULL)!=1)
+ return POP3_COMMERROR;
+
+ if (!GetResponse(NULL))
+ return POP3_BADUSER;
+
+ if (Send("PASS ",passwd,(const char *)NULL)!=1)
+ return POP3_COMMERROR;
+
+ if(!GetResponse(NULL))
+ return POP3_BADPASSWD;
+
+ connected=TRUE;
+
+ return POP3_OK;
+}
+
+
+POP3Message *POP3GetList(void)
+{
+ POP3Message *msg=NULL;
+ DString t;
+ char *p;
+ int no;
+ int f;
+
+ if (!connected)
+ return NULL;
+
+ t=DSInit();
+
+ Send("STAT",(const char *)NULL);
+
+ if (!GetResponse(t))
+ goto end;
+
+ p=strtok(t->text," ");
+
+ if (p)
+ p=strtok(NULL," ");
+
+ if (!p)
+ goto end;
+
+ no=atoi(p);
+
+ msg=Malloc(sizeof *msg * (no+1));
+
+ for(f=0;f<no;f++)
+ {
+ char cmd[64];
+ int done=FALSE;
+
+ msg[f].id=f+1;
+ msg[f].to=NULL;
+ msg[f].from=NULL;
+ msg[f].from_uname=NULL;
+ msg[f].from_domain=NULL;
+ msg[f].subject=NULL;
+ msg[f].content_type=NULL;
+
+ sprintf(cmd,"TOP %d 0",f+1);
+
+ Send(cmd,(const char *)NULL);
+
+ if (!GetResponse(NULL))
+ {
+ free(msg);
+ msg=NULL;
+ goto end;
+ }
+
+ while(!done)
+ {
+ t=DSReset(t);
+
+ if (!GetMultiLine(t))
+ {
+ free(msg);
+ msg=NULL;
+ goto end;
+ }
+
+ if (strcmp(t->text,".")==0)
+ done=TRUE;
+ else
+ {
+ ParseHeader(msg+f,t->text);
+ }
+ }
+
+ if (!msg[f].to)
+ msg[f].to=CopyStr("UNKNOWN");
+
+ if (!msg[f].from)
+ msg[f].from=CopyStr("UNKNOWN");
+
+ if (!msg[f].from_uname)
+ msg[f].from_uname=CopyStr("UNKNOWN");
+
+ if (!msg[f].from_domain)
+ msg[f].from_domain=CopyStr("UNKNOWN");
+
+ if (!msg[f].subject)
+ msg[f].subject=CopyStr("UNKNOWN");
+
+ if (!msg[f].content_type)
+ msg[f].content_type=CopyStr("UNKNOWN");
+ }
+
+ msg[no].id=0;
+ msg[no].to=NULL;
+ msg[no].from=NULL;
+ msg[no].from_uname=NULL;
+ msg[no].from_domain=NULL;
+ msg[no].subject=NULL;
+
+end:
+ DSFree(t);
+ return msg;
+}
+
+
+POP3Status POP3Delete(int msg)
+{
+ return POP3_OK;
+}
+
+
+void POP3Logoff(void)
+{
+ Send("QUIT",(const char *)NULL);
+ GetResponse(NULL);
+}
+
+
+void POP3FreeList(POP3Message *list)
+{
+ if (list)
+ {
+ int f;
+
+ for(f=0;list[f].to;f++)
+ {
+ free(list[f].to);
+ free(list[f].from);
+ free(list[f].from_uname);
+ free(list[f].from_domain);
+ free(list[f].subject);
+ }
+
+ free(list);
+ }
+}
+
+
+/* END OF FILE */
diff --git a/src/pop3.h b/src/pop3.h
new file mode 100644
index 0000000..c684634
--- /dev/null
+++ b/src/pop3.h
@@ -0,0 +1,90 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ POP3 Interface
+
+*/
+
+#ifndef KBS_POP3_H
+#define KBS_POP3_H
+
+#include "msg.h"
+
+/* ---------------------------------------- TYPES AND CONSTANTS
+*/
+typedef enum
+ {
+ POP3_OK,
+ POP3_COMMERROR,
+ POP3_NOCONNECT,
+ POP3_BADUSER,
+ POP3_BADPASSWD
+ } POP3Status;
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Connect to a POP3 server. Pass a port number of zero to use the
+ default. Returns POP_OK if connected OK, otherwise one of the POP_x errors.
+*/
+POP3Status POP3Connect(const char *hostname, int port,
+ const char *username, const char *passwd,
+ int timeout);
+
+
+/* Collect information from the POP3 server. Returns a list of POP3Messages,
+ terminated with a NULL to entry, or NULL for not connected or error.
+ Note that fields that weren't present in a message will be set to
+ "UNKOWN".
+
+ Note that if the TOP command is unimplemented on the server, then all the
+ fields in the message will be set to UNKNOWN.
+
+ Obviously, this isn't much use.
+*/
+POP3Message *POP3GetList(void);
+
+
+/* Deletes the specified message. Returns POP_OK if deleted OK, otherwise
+ one of the POP_x errors.
+
+ Remember that POP3 messages are number 1 .. N (so use the id field in
+ POP3Message).
+*/
+POP3Status POP3Delete(int msg);
+
+
+/* Logoff
+*/
+void POP3Logoff(void);
+
+
+/* Couresy function to free a message list.
+*/
+void POP3FreeList(POP3Message *list);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/rexp.c b/src/rexp.c
new file mode 100644
index 0000000..0311c44
--- /dev/null
+++ b/src/rexp.c
@@ -0,0 +1,63 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Common utilities
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <regex.h>
+
+#include "global.h"
+#include "rexp.h"
+#include "config.h"
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+RExpStatus RExpSearch(const char *regexpr, const char *string)
+{
+ regex_t re;
+ int flags;
+ int res;
+
+ flags=REG_EXTENDED|REG_NOSUB;
+
+ if (!ConfigInt(CONFIG_CASESENSE))
+ flags|=REG_ICASE;
+
+ if (regcomp(&re,regexpr,flags))
+ return RE_BadExpression;
+
+ res=regexec(&re,string,0,NULL,0);
+
+ regfree(&re);
+
+ /* printf("RExpSearch(%s,%s)=%d\n",regexpr,string,res); */
+
+ return res ? RE_NotFound : RE_Found;
+}
+
+
+/* END OF FILE */
diff --git a/src/rexp.h b/src/rexp.h
new file mode 100644
index 0000000..04d1bb6
--- /dev/null
+++ b/src/rexp.h
@@ -0,0 +1,52 @@
+/*
+
+ kbs - Simple, easily fooled, REXP spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Regular expressions
+
+*/
+
+#ifndef KBS_REXP_H
+#define KBS_REXP_H
+
+#include <stdlib.h>
+
+/* ---------------------------------------- INTERFACES
+*/
+
+typedef enum
+ {
+ RE_Found,
+ RE_NotFound,
+ RE_BadExpression,
+ } RExpStatus;
+
+
+/* Search string for regexpr
+*/
+RExpStatus RExpSearch(const char *regexpr, const char *string);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..b65ac01
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,79 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Common utilities
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "global.h"
+#include "util.h"
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+char *CopyStr(const char *p)
+{
+ char *new;
+
+ new=Malloc(strlen(p)+1);
+ strcpy(new,p);
+ return new;
+}
+
+
+void *F_Malloc(const char *file, int line, size_t len)
+{
+ void *new;
+
+ if (!(new=malloc(len)))
+ {
+ fprintf(stderr,"Unable to allocate %lu bytes for %s:%d\n",
+ (unsigned long)len,file,line);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+void *F_Realloc(const char *file, int line, void *p, size_t len)
+{
+ void *new;
+
+ if (!(new=realloc(p,len)))
+ {
+ fprintf(stderr,"Unable to reallocate %lu bytes for %s:%d\n",
+ (unsigned long)len,file,line);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+/* END OF FILE */
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..f37eb12
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,58 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Common utilities
+
+*/
+
+#ifndef KBS_UTIL_H
+#define KBS_UTIL_H
+
+#include <stdlib.h>
+
+/* ---------------------------------------- INTERFACES
+*/
+
+#define Malloc(l) F_Malloc(__FILE__,__LINE__,(l))
+#define Realloc(p,l) F_Realloc(__FILE__,__LINE__,(p),(l))
+
+
+/* Copy a string
+*/
+char *CopyStr(const char *p);
+
+
+/* Malloc wrapper. Just use free() to free.
+*/
+void *F_Malloc(const char *file, int line, size_t len);
+
+
+/* Realloc wrapper. Just use free() to free.
+*/
+void *F_Realloc(const char *file, int line, void *p, size_t len);
+
+
+#endif
+
+/* END OF FILE */