old-www/LDP/LG/issue62/okopnik.html

431 lines
21 KiB
HTML

<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>No More Spam! LG #62</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<CENTER>
<A HREF="http://www.linuxgazette.com/">
<H1><IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.jpg"
WIDTH="600" HEIGHT="124" border="0"></H1></A>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="meek.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue62/okopnik.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="searls.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<P>
</CENTER>
<!--endcut ============================================================-->
<H4 ALIGN="center">
"Linux Gazette...<I>making Linux just a little more fun!</I>"
</H4>
<P> <HR> <P>
<!--===================================================================-->
<center>
<H1><font color="maroon">No More Spam!</FONT></H1>
<H2>(a "procmail"-based solution with tips on "fetchmail" and "mutt")</H2>
<H4>By <a href="mailto:ben-fuzzybear@yahoo.com">Ben Okopnik</a></H4>
</center>
<P> <HR> <P>
<!-- END header -->
<BLOCKQUOTE>
<tt>"Spamming is the scourge of electronic-mail and newsgroups on the
Internet. It can seriously interfere with the operation of public services,
to say nothing of the effect it may have on any individual's e-mail mail
system. ... Spammers are, in effect, taking resources away from users and
service suppliers without compensation and without authorization."</tt>
<br><tt>&nbsp;-- Vint Cerf, Senior VP, MCI and acknowledged "Father of
the Internet"</tt>
</BLOCKQUOTE>
<p>Spam. Seems like it's become a cost of having an e-mail address these
days: if you post in a newsgroup, enter something in an on-line guestbook,
or have your email address on the Net in some way, sooner or later you'll
get harvested by the spambots. Even if you don't, spam _still_ costs you
money: it takes up bandwidth that could otherwise be used for real information
transfer, leading to overall higher costs for ISPs - and consequently,
keeping up costs of service for everyone. This cost is, incidentally, up
in the <u>tens of millions</u> of dollars per month (see <a href="http://www.techweb.com/se/directlink.cgi?INW19980504S0003">http://www.techweb.com/se/directlink.cgi?INW19980504S0003</a>)
for an excellent overview) - and this translates directly to about $2 of
your monthly bill. If you pay for your access "by the byte", there is yet
another cost - and all this comes before you add in the cost of your own
wasted time.
<p>Is there anything that we can do? The answer is "yes". We can stop spam
from polluting our own mailboxes, and we can intercept it back at the ISP,
if we have access to a shell account and they implement a simple tool (and
most ISPs that provide shell accounts do). I invite those of you who would
like to fight spam at its root to take a look at <a href="http://www.cauce.org">http://www.cauce.org</a>
- these are the folks that are advocating a legislative solution to spam;
the information on their site tells you how you can help. In this article,
however, I will concentrate on stopping spam locally - at your shell account
or on your own machine.
<p>There are several ways to do this, but the most common by far - and
one that most ISPs offering shell-accounts already have - is a program called
"procmail" by Stephen R. van den Berg, an e-mail processor that uses a 'recipe'
that tells it what to keep, what to filter, and what to redirect to another
mailbox. So, we need to do two things: first, we need to tell our system to use
"procmail"; second, we need to cobble together a 'recipe' that will do what we
want.
<p>In my own case, I collect my e-mail via "fetchmail", running as a daemon.
This is something I would recommend to everyone, even if you normally collect
your mail via Netscape: fetchmail does one job (mail collection) and does
it very well, in the worst and most complex of circumstances, things that
Netscape doesn't even try to do (multiple servers with different protocols
and different usernames, for example) - and Netscape will happily read
your local mailbox instead of the ISPs.
<p>Normally, my "fetchmail" will wake up every 5 minutes, pull down the
mail from the several servers that I use, and pass it to "sendmail" which
then puts it in my mailbox. Whew. Sounds like wasted effort to me, but
I guess that's the way things are when you scale down an MTA intended for
processing big batches... Actually, using "procmail" eliminates that last
step.
<p>In my "~/.fetchmailrc", the resource file that controls what "fetchmail"
does when it runs, the pertinent line reads:
<p><tt>mda "procmail"</tt>
<p>This tells "fetchmail" to use "procmail" as the mail delivery agent
instead of "sendmail" - remember, this is for incoming mail only; your
outgoing mail will not be affected.
<br>&nbsp;
<p>The other way to do this - and this is the way I recommend if you're
filtering mail at your ISP's machine - is to create a ".forward" file in
your home directory (this tells your MTA to 'forward' the mail - in this
case to our processor.)
<p>Edit ".forward" and enter one of the following lines:
<p><tt>"|exec /usr/bin/procmail"</tt>
<p>if you're using "sendmail" (the quotes <b>are</b> necessary in this
case).
<p>If you are using "exim", use this instead:
<p><tt>|/usr/bin/procmail</tt>
<p>[ Note: According to Mike Orr, "exim" has its own procmail-like filtering
language. I haven't looked at it, but it should be in the "exim" docs.
]
<p>You'll need to double-check the actual path to "procmail": you can get
that by typing:
<p><tt>which procmail</tt>
<p>at the command prompt.
<p>Now that we have redirected all our mail to pass through procmail, the
overall effect is... nothing. Huh? Oh yeah - we still have to set up the
recipe! Let's take a look at a very simple ".procmailrc", the file in which
the recipes are kept:
<p>
<hr WIDTH="100%" NOSHADE><tt>PATH=$HOME/bin:/usr/local/bin:/usr/bin:/bin</tt>
<br><tt>MAILDIR=/var/spool/mail&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # make
sure this is right</tt>
<br><tt>DEFAULT=$MAILDIR/username&nbsp;&nbsp;&nbsp;&nbsp; # completely
optional</tt>
<br><tt>LOGFILE=/var/log/procmail.log # recommended</tt>
<p><tt>:0:</tt>
<br><tt>* ^Sender:.*owner-linux-kernel-announce@vger.rutgers.edu</tt>
<br><tt>linux-kernel-announce</tt>
<p><tt>:0:</tt>
<br><tt>* ^Resent-Sender.*debian-user-request@lists.debian.org</tt>
<br><tt>debian-user</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<br>Those top four lines, once you've checked to make sure that the variables
are correct for your system, should be in every ".procmailrc". What comes
after can be as complex as you want - you could cobble up a HUGE ".procmailrc"
that does more sorting than the main US Post Office - but for spam filtering
purposes (and that's the only thing most folks use it for), it's not very
complex at all. The above recipe simply sorts the mail into two boxes,
"linux-kernel-announce" and "debian-user" before "falling
<br>off the end" and delivering everything else into $DEFAULT.
<p>Recipes are built like this:
<br>
<hr WIDTH="100%" NOSHADE>
<br><tt>:0:</tt>
<br><tt>* ^Subject:.*test</tt>
<br><tt>joe</tt>
<br>&nbsp;
<p><tt>Notation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Meaning</tt>
<br><tt>========&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=======</tt>
<br><tt>:0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Begin a recipe</tt>
<br><tt>&nbsp; :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Use a lock file (strongly recommended)</tt>
<br><tt>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Begin a condition</tt>
<br><tt>&nbsp; ^&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Match the beginning of a line followed by....</tt>
<br><tt>&nbsp;&nbsp; Subject:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
``Subject:'' followed by....</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
any character (.) followed by....</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 or more of preceding character
(any character in</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
this case) followed by....</tt>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
test&nbsp;&nbsp; ``test''</tt>
<br><tt>joe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
If successful match, put in folder $MAILDIR/joe</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<br>What we'll do here is take a look at several people's solutions; in
order to write this article, I polled the members of the Answer Gang, and
some of their recipes - along with their rationale for them - are shown
below.
<br>&nbsp;
<p>My own recipe has been in service for quite a while. I built a rather
basic one at first, and this immediately decreased the spam volume by at
least 95%; later, I added a "blacklist" and a "whitelist" to always reject/accept
mail from certain addresses - the first is useful for spammers that manage
to get through, especially those that send their garbage multiple times,
the second one is for my friends whose mail I don't want to filter out
no matter what strange things they may put in the headers (I have some
strange friends. :)
<p>For those of you who use "mutt", here's how I add people to those lists:
in my "/etc/Muttrc", I have these lines:
<p><tt>macro index \ew '| formail -x From: | addysort &gt;&gt; ~/Mail/white.lst'</tt>
<br><tt>macro pager \ew '| formail -x From: | addysort &gt;&gt; ~/Mail/white.lst'</tt>
<br><tt>macro index \eb '| formail -x From: | addysort &gt;&gt; ~/Mail/black.lst'</tt>
<br><tt>macro pager \eb '| formail -x From: | addysort &gt;&gt; ~/Mail/black.lst'</tt>
<p>and in my "/usr/local/bin", I have a script called "addysort":
<p>
<hr WIDTH="100%" NOSHADE>
<br><tt>#!/usr/bin/perl -wn</tt>
<br><tt># Picks out the actual address from the "From:" line</tt>
<p><tt>unless (/\&lt;/) { print; } else { print /&lt;([^&gt;]+)/, "\n"; }</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<p>Given the above, all I have to do with a given spammer is hit 'Esc-b'
- and I'll never see him again. By the same token, a person whom I want
to add to the whitelist gets an 'Esc-w' - and they're permanently in my
good graces. :)
<br>&nbsp;
<p>So, here is my "~/.procmailrc":
<p>
<hr WIDTH="100%" NOSHADE>
<br><tt>PATH=/usr/local/bin:/usr/bin:/bin</tt>
<br><tt>MAILDIR=/var/spool/mail</tt>
<br><tt>DEFAULT=/var/spool/mail/ben</tt>
<br><tt>LOGFILE=/var/log/procmail</tt>
<br><tt>SPAMFILE=/var/spool/mail/spam</tt>
<br>&nbsp;
<p><tt># Test if the email's sender is whitelisted; if so, send it straight
to</tt>
<br><tt># $DEFAULT. Note that this comes before any other filters.</tt>
<br><tt>:0:</tt>
<br><tt>* ? formail -x"From" -x"From:" -x"Sender:" \</tt>
<br><tt>&nbsp;&nbsp;&nbsp; -x"Reply-To:" -x"Return-Path:" -x"To:" \</tt>
<br><tt>&nbsp;&nbsp;&nbsp; | egrep -is -f $MAILDIR/white.lst</tt>
<br><tt>$DEFAULT</tt>
<p><tt># Test if the email's sender is blacklisted; if so, send it to "/dev/null"</tt>
<br><tt>:0</tt>
<br><tt>* ? formail -x"From" -x"From:" -x"Sender:" \</tt>
<br><tt>&nbsp;&nbsp;&nbsp; -x"Reply-To:" -x"Return-Path:" -x"To:" \</tt>
<br><tt>&nbsp;&nbsp;&nbsp; | egrep -is -f $MAILDIR/black.lst</tt>
<br><tt>/dev/null</tt>
<p><tt># Here is the real spam-killer, much improved by Dan's example below:
if</tt>
<br><tt># it isn't addressed, cc'd, or in some way sent to one of my addresses
-</tt>
<br><tt># all of which contain either "fuzzybear" or "ulysses" - it's spam.
Note</tt>
<br><tt># the '!' in front of the matching expression: it inverts the sense
of the</tt>
<br><tt># match, that is "if the line _doesn't_ match these words, then
send it to</tt>
<br><tt># $SPAMFILE." "^TO" is a procmail variable that matches "To:",
"Cc:",</tt>
<br><tt># "Bcc:", and other "To:"-type headers (see 'man procmailrc'.)</tt>
<br><tt>:0:</tt>
<br><tt>* !^TO .*(fuzzybear|ulysses).*</tt>
<br><tt>$SPAMFILE</tt>
<p><tt># X-Advertisement header = spam!</tt>
<br><tt>:0:</tt>
<br><tt>* ^X-Advertisement:.*</tt>
<br><tt>$SPAMFILE</tt>
<p><tt># To nobody!</tt>
<br><tt>:0:</tt>
<br><tt>* To:[ ]*$</tt>
<br><tt>$SPAMFILE</tt>
<p><tt># No "To:" header at all!</tt>
<br><tt>:0:</tt>
<br><tt>* !^To: .*</tt>
<br><tt>$SPAMFILE</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<p>For most folks, the only thing necessary would be the last four stanzas
of the above (and of course, the variables at the beginning), with the
first stanza of that doing 95% of the work. The last three I stole from
Dan :), but I can see where they'd come in handy.
<p>By the way, yet another useful thing is a mechanism I've implemented
for reporting spammers: in my "/etc/Muttrc", I have a line that says
<p><tt>send-hook (~s\ Spammer) 'set signature="~/.mutt/spammer"'</tt>
<p>and a "signature" file, "~/.mutt/spammer" that says
<p>
<hr WIDTH="100%" NOSHADE>
<br><tt>Dear sirs:</tt>
<p><tt>I've just received mail from a spammer who seems to be coming from
your</tt>
<br><tt>domain. Please fall upon this creature and rend him to bits. His
garbage,</tt>
<br><tt>with headers, is appended.</tt>
<p><tt>Sincerely,</tt>
<br><tt>Ben Okopnik</tt>
<br><tt>-=-=-=-=-=-</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<p>&lt;grin&gt; No, I don't like spammers.
<p>So, in order to send a complaint, I look at the headers with the 'h'
key, run a 'whois' on the originating address, hit 'm' to send mail, and
type the following at the prompts:
<p><tt>To:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; abuse@&lt;domain.com&gt;</tt>
<br><tt>Subject:&nbsp;&nbsp;&nbsp; Spammer</tt>
<p>Given that keyword in the subject, "mutt" pulls up my "spammer" signature
file. I save it, append the original spam with the 'A' key, and send it.
About 15 seconds of typing, whenever I feel like getting another spam kill.
:)
<p>(Just as I was about to send off this article, I got another spam
kill, this time from UUnet. &lt;grin&gt; I collect'em.)
<br>&nbsp;
<p>On we go to other folks' recipes.
<p>LG itself is in a rather vulnerable position in regard to spam. Since
the address is posted on the Net thousands (by now, perhaps millions) of
times, it is constantly harvested by spammers. The thing is, "tight" filters
of the sort that I've described are not feasible. Consider: what would
be a safe "filter" for spam that would not also knock out a certain percentage
of our readers' mail? People send mail in from all over the world, in many
different ways, with just about every kind of client (including those that
create broken headers.) The spam rate for LG, according to Mike Orr, is
28% per month. Rejecting "Precedence: bulk" mail, which can be a good "minor"
filter, is not an option: many "News Bytes" entries (since they are bulk-mailed
news releases) are sent that way. Even the inquiry that led to the publication
of the <a href="collinge.html">HelpDex</a> cartoon series came that way.
<p>What to do?
<p>The answer seems to be careful, "accept-when-in-doubt" filtering and
checking the "spam" mailbox more often than most people. For the staff
at LG, it's just another cost of doing business. Hopefully, even their
"loose" filters decrease some of that load.
<br>&nbsp;
<p>Dan Wilder, the resident admin and system magician, had the following
"spam killer" in his "~/.procmailrc":
<p>
<hr WIDTH="100%" NOSHADE>
<br><tt>:0:</tt>
<br><tt>* !^(To:|From:|Cc:|Resent-From:|Resent-To:).*(eskimo\.com\</tt>
<br><tt>|ssc\.com\</tt>
<br><tt>|linuxjournal\.com\</tt>
<br><tt>)</tt>
<br><tt>$SPAMFILE</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<p>Pretty obvious - anything that doesn't match those three domains in
the specified headers wasn't sent to him. Dan checks his "spamfile" every
once so often - as do I, because real mail can slip by and match by mistake
- and this takes care of the tiny percentage of errors.
<p>
<hr WIDTH="100%" NOSHADE>
<br><tt>Before that is a rule that allows exemptions, as for mailing lists:</tt>
<p><tt>:0:</tt>
<br><tt>* ^(From:|To:|Cc:) .*(-list\</tt>
<br><tt>|debian\</tt>
<br><tt>|networksolutions\</tt>
<br><tt>|ciac\</tt>
<p><tt>...</tt>
<p><tt>|bugs\</tt>
<br><tt>)</tt>
<br><tt>$DEFAULT</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<p>Much the same thing as my "whitelist", but hard-coded into ".procmailrc"
itself. It's not much more difficult to add new people there, so it's just
as good a solution as mine, though perhaps a trifle less automatic.
<br>&nbsp;
<p>LG's editor, Mike Orr, does a fair bit of sorting (which I've clipped)
as well as spam-killing in his recipes (designed by Dan Wilder):
<p>
<hr WIDTH="100%" NOSHADE>
<br><tt>LOG=$HOME/log</tt>
<br><tt>#LOGFILE=$LOG/procmail-log</tt>
<br><tt>VERBOSE=no</tt>
<br><tt>SPAMFILE=$LOG/spam</tt>
<br><tt>UMASK=077</tt>
<br><tt>LOGABSTRACT=on</tt>
<br><tt>COMSAT=no</tt>
<br><tt>DEFAULT=$HOME/Mail/Maildir/new</tt>
<p><tt># The real workhorse.</tt>
<br><tt># Bogus recipient .. not To: or From: or Cc: ssc.com,</tt>
<br><tt># and has an "@" in To: (local mail from damaged MUAs may not)</tt>
<p><tt>:0:</tt>
<br><tt>* !^(To:|From:|Cc:) .*(\</tt>
<br><tt>ssc\.com\</tt>
<br><tt>|linuxjournal\.com\</tt>
<br><tt>|linuxgazette\.com\</tt>
<br><tt>)</tt>
<br><tt>* ^To: .*@</tt>
<br><tt>$SPAMFILE</tt>
<p>Hmm, looks like we have a blacklisted spammer here...
<p><tt>:0:</tt>
<br><tt>* From: .*john@songpeople.com</tt>
<br><tt>$SPAMFILE</tt>
<p><tt># if they have an X-Advertisement header, it's spam!</tt>
<p><tt>:0:</tt>
<br><tt>* ^X-Advertisement:.*</tt>
<br><tt>$SPAMFILE</tt>
<p><tt># To nobody!</tt>
<p><tt>:0:</tt>
<br><tt>* To:[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ]*$</tt>
<br><tt>$SPAMFILE</tt>
<p><tt># No To: header at all!</tt>
<br><tt>:0:</tt>
<br><tt>* !^To: .*</tt>
<br><tt>$SPAMFILE</tt>
<p><tt># Otherwise, fall off the end and default.</tt>
<br>
<hr WIDTH="100%" NOSHADE>
<p>Wow. Seems like a whole lot of stuff, doesn't it? In reality, it's minor:
<p>1) Pipe all incoming mail through "procmail".
<br>2) Build a recipe.
<p>That's it. I've thrown in a lot of tips for doing other spam-related
stuff, but the above two steps are <u>all</u> you need to do in order to
decrease or almost completely eliminate your spam. Oh, look - here comes
another tip! :)
<p>If you already have a mailbox full of spam, and you go ahead and do
the above two steps, it's really easy to filter it all in one shot:
<p><tt>cat mbox | formail -s procmail</tt>
<br>&nbsp;
<p>So, you can indeed "de-spam" your mailbox. Thanks to the power of Linux
and "procmail", you too can stare at people who complain about getting
deluged and say "Oh, yeah... I remember when <EM>I</EM> had that problem."
&lt;Laugh&gt;
<p>Happy spam-hunting!
<!-- *** BEGIN copyright *** -->
<P> <hr> <!-- P -->
<H5 ALIGN=center>
Copyright &copy; 2001, Ben Okopnik.<BR>
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
Published in Issue 62 of <i>Linux Gazette</i>, February 2001</H5>
<!-- *** END copyright *** -->
<!--startcut ==========================================================-->
<HR><P>
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="meek.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue62/okopnik.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="searls.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->