Compare commits

..

1 Commits

Author SHA1 Message Date
cvs2svn 8438d08e8a This commit was manufactured by cvs2svn to create tag 'mitler-0_8_0'.
Sprout from master 2005-06-14 22:02:46 UTC Stuart Gathman <stuart@gathman.org> 'Release 0.8.0'
Delete:
    COPYING
    CREDITS
    MANIFEST.in
    Milter.py
    Milter/__init__.py
    Milter/dsn.py
    Milter/dynip.py
    README
    TODO
    bms.py
    cid2spf.py
    faq.html
    milter.cfg
    milter.html
    milter.rc
    milter.rc7
    miltermodule.c
    mime.py
    rejects.py
    rhsbl.m4
    sample.py
    setup.cfg
    setup.py
    softfail.txt
    spf.py
    spfquery.py
    strike3.txt
    test.py
    test/amazon
    test/big5
    test/bounce
    test/bounce1
    test/bound
    test/honey
    test/missingboundary
    test/samp1
    test/spam44
    test/spam7
    test/spam8
    test/test1
    test/test8
    test/virus1
    test/virus13
    test/virus2
    test/virus3
    test/virus4
    test/virus5
    test/virus6
    test/virus7
    test/zip1
    testbms.py
    testmime.py
    testsample.py
2005-06-14 22:02:47 +00:00
59 changed files with 254 additions and 9479 deletions
-339
View File
@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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) <year> <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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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 Lesser General
Public License instead of this License.
-47
View File
@@ -1,47 +0,0 @@
Jim Niemira (urmane@urmane.org) wrote the original C module and some quick
and dirty python to use it. Stuart D. Gathman (stuart@bmsi.com) took that
kludge and added threading and context objects to it, wrote a proper OO
wrapper (Milter.py) that handles attachments, did lots of testing, packaged
it with distutils, and generally transformed it from a quick hack to a
real, usable Python extension.
Other contributors (in random order):
Daniel Troeder
for pointing out a typo in @noreply
arkanes@irc.freenode.net
for suggesting a class method to compute and cache protocol masks
habnabit@habnabit.org
for suggesting function attributes and decorators for protocol negotiation
Dwayne Litzenberger, B.A.Sc.
for library_dirs patch to compile on Debian
Dave MacQuigg
for noticing that smfi_insheader wasn't supported, and creating
a template to help first time pymilter users create their own milter.
Terence Way
for providing a Python port of SPF
Scott Kitterman
for doing lots of testing and debugging of SPF against draft standard,
and for putting up a web page that validates SPF records using spf.py
Alexander Kourakos
for plugging several memory leaks
George Graf at Vienna University of Economics and Business Administration
for handling None passed to setreply and chgheader.
Deron Meranda
for IPv6 patches
Jason Erikson
for handling NULL hostaddr in connect callback.
John Draper
for porting Python milter to OpenBSD, and starting to work on tutorials
then pointing out that it would be easier to just write the MTA in Python.
Eric S. Johansson
for helpful design discussions while working on camram
Alex Savguira
for finding bugs with international headers and
suggesting the scan_zip option.
Business Management Systems - http://www.bmsi.com
for hosting the website, and providing paying clients who need milter service
so I can work on it as part of my day job.
If I have left anybody out, send me a reminder: stuart@bmsi.com
-214
View File
@@ -1,214 +0,0 @@
# Revision 1.69 2006/11/04 22:09:39 customdesigned
# Another lame DSN heuristic. Block PTR cache poisoning attack.
#
# Revision 1.68 2006/10/04 03:46:01 customdesigned
# Fix defaults.
#
# Revision 1.67 2006/10/01 01:44:06 customdesigned
# case_sensitive_localpart option, more delayed bounce heuristics,
# optional smart_alias section.
#
# Revision 1.66 2006/07/26 16:42:26 customdesigned
# Support CBV timeout
#
# Revision 1.65 2006/06/21 22:22:00 customdesigned
# Handle multi-line headers in delayed dsns.
#
# Revision 1.64 2006/06/21 21:12:04 customdesigned
# More delayed reject token headers.
# Don't require HELO pass for CBV.
#
# Revision 1.63 2006/05/21 03:41:44 customdesigned
# Fail dsn
#
# Revision 1.61 2006/05/17 21:28:07 customdesigned
# Create GOSSiP record only when connection will procede to DATA.
#
# Revision 1.60 2006/05/12 16:14:48 customdesigned
# Don't require SPF pass for white/black listing mail from trusted relay.
# Support localpart wildcard for white and black lists.
#
# Revision 1.59 2006/04/06 18:14:17 customdesigned
# Check whitelist/blacklist even when not checking SPF (e.g. trusted relay).
#
# Revision 1.58 2006/03/10 20:52:49 customdesigned
# Use re to recognize failure DSNs.
#
# Revision 1.57 2006/03/07 20:50:54 customdesigned
# Use signed Message-ID in delayed reject to blacklist senders
#
# Revision 1.56 2006/02/24 02:12:54 customdesigned
# Properly report hard PermError (lax mode fails also) by always setting
# perm_error attribute with PermError exception. Improve reporting of
# invalid domain PermError.
#
# Revision 1.55 2006/02/17 05:04:29 customdesigned
# Use SRS sign domain list.
# Accept but do not use for training whitelisted senders without SPF pass.
# Immediate rejection of unsigned bounces.
#
# Revision 1.54 2006/02/16 02:16:36 customdesigned
# User specific SPF receiver policy.
#
# Revision 1.53 2006/02/12 04:15:01 customdesigned
# Remove spf dependency for iniplist
#
# Revision 1.52 2006/02/12 02:12:08 customdesigned
# Use CIDR notation for internal connect list.
#
# Revision 1.51 2006/02/12 01:13:58 customdesigned
# Don't check rcpt user list when signed MFROM.
#
# Revision 1.50 2006/02/09 20:39:43 customdesigned
# Use CIDR notation for trusted_relay iplist
#
# Revision 1.49 2006/01/30 23:14:48 customdesigned
# put back eom condition
#
# Revision 1.48 2006/01/12 20:31:24 customdesigned
# Accelerate training via whitelist and blacklist.
#
# Revision 1.47 2005/12/29 04:49:10 customdesigned
# Do not auto-whitelist autoreplys
#
# Revision 1.46 2005/12/28 20:17:29 customdesigned
# Expire and renew AddrCache entries
#
# Revision 1.45 2005/12/23 22:34:46 customdesigned
# Put guessed result in separate header.
#
# Revision 1.44 2005/12/23 21:47:07 customdesigned
# Move Received-SPF header to top.
#
# Revision 1.43 2005/12/09 16:54:01 customdesigned
# Select neutral DSN template for best_guess
#
# Revision 1.42 2005/12/01 22:42:32 customdesigned
# improve gossip support.
# Initialize srs_domain from srs.srs config property. Should probably
# always block unsigned DSN when signing all.
#
# Revision 1.41 2005/12/01 18:59:25 customdesigned
# Fix neutral policy. pobox.com -> openspf.org
#
# Revision 1.40 2005/11/07 21:22:35 customdesigned
# GOSSiP support, local database only.
#
# Revision 1.39 2005/10/31 00:04:58 customdesigned
# Simple implementation of trusted_forwarder list. Inefficient for
# more than 1 or 2 entries.
#
# Revision 1.38 2005/10/28 19:36:54 customdesigned
# Don't check internal_domains for trusted_relay.
#
# Revision 1.37 2005/10/28 09:30:49 customdesigned
# Do not send quarantine DSN when sender is DSN.
#
# Revision 1.36 2005/10/23 16:01:29 customdesigned
# Consider MAIL FROM a match for supply_sender when a subdomain of From or Sender
#
# Revision 1.35 2005/10/20 18:47:27 customdesigned
# Configure auto_whitelist senders.
#
# Revision 1.34 2005/10/19 21:07:49 customdesigned
# access.db stores keys in lower case
#
# Revision 1.33 2005/10/19 19:37:50 customdesigned
# Train screener on whitelisted messages.
#
# Revision 1.32 2005/10/14 16:17:31 customdesigned
# Auto whitelist refinements.
#
# Revision 1.31 2005/10/14 01:14:08 customdesigned
# Auto whitelist feature.
#
# Revision 1.30 2005/10/12 16:36:30 customdesigned
# Release 0.8.3
#
# Revision 1.29 2005/10/11 22:50:07 customdesigned
# Always check HELO except for SPF pass, temperror.
#
# Revision 1.28 2005/10/10 23:50:20 customdesigned
# Use logging module to make logging threadsafe (avoid splitting log lines)
#
# Revision 1.27 2005/10/10 20:15:33 customdesigned
# Configure SPF policy via sendmail access file.
#
# Revision 1.26 2005/10/07 03:23:40 customdesigned
# Banned users option. Experimental feature to supply Sender when
# missing and MFROM domain doesn't match From. Log cipher bits for
# SMTP AUTH. Sketch access file feature.
#
# Revision 1.25 2005/09/08 03:55:08 customdesigned
# Handle perverse MFROM quoting.
#
# Revision 1.24 2005/08/18 03:36:54 customdesigned
# Don't innoculate with SCREENED mail.
#
# Revision 1.23 2005/08/17 19:35:27 customdesigned
# Send DSN before adding message to quarantine.
#
# Revision 1.22 2005/08/11 22:17:58 customdesigned
# Consider SMTP AUTH connections internal.
#
# Revision 1.21 2005/08/04 21:21:31 customdesigned
# Treat fail like softfail for selected (braindead) domains.
# Treat mail according to extended processing results, but
# report any PermError that would officially result via DSN.
#
# Revision 1.20 2005/08/02 18:04:35 customdesigned
# Keep screened honeypot mail, but optionally discard honeypot only mail.
#
# Revision 1.19 2005/07/20 03:30:04 customdesigned
# Check pydspam version for honeypot, include latest pyspf changes.
#
# Revision 1.18 2005/07/17 01:25:44 customdesigned
# Log as well as use extended result for best guess.
#
# Revision 1.17 2005/07/15 20:25:36 customdesigned
# Use extended results processing for best_guess.
#
# Revision 1.16 2005/07/14 03:23:33 customdesigned
# Make SES package optional. Initial honeypot support.
#
# Revision 1.15 2005/07/06 04:05:40 customdesigned
# Initial SES integration.
#
# Revision 1.14 2005/07/02 23:27:31 customdesigned
# Don't match hostnames for internal connects.
#
# Revision 1.13 2005/07/01 16:30:24 customdesigned
# Always log trusted Received and Received-SPF headers.
#
# Revision 1.12 2005/06/20 22:35:35 customdesigned
# Setreply for rejectvirus.
#
# Revision 1.11 2005/06/17 02:07:20 customdesigned
# Release 0.8.1
#
# Revision 1.10 2005/06/16 18:35:51 customdesigned
# Ignore HeaderParseError decoding header
#
# Revision 1.9 2005/06/14 21:55:29 customdesigned
# Check internal_domains for outgoing mail.
#
# Revision 1.8 2005/06/06 18:24:59 customdesigned
# Properly log exceptions from pydspam
#
# Revision 1.7 2005/06/04 19:41:16 customdesigned
# Fix bugs from testing RPM
#
# Revision 1.6 2005/06/03 04:57:05 customdesigned
# Organize config reader by section. Create defang section.
#
# Revision 1.5 2005/06/02 15:00:17 customdesigned
# Configure banned extensions. Scan zipfile option with test case.
#
# Revision 1.4 2005/06/02 04:18:55 customdesigned
# Update copyright notices after reading article on /.
#
# Revision 1.3 2005/06/02 02:09:00 customdesigned
# Record timestamp in send_dsn.log
#
# Revision 1.2 2005/06/02 01:00:36 customdesigned
# Support configurable templates for DSNs.
-1473
View File
File diff suppressed because it is too large Load Diff
-17
View File
@@ -1,17 +0,0 @@
include COPYING
include TODO
include NEWS
include CREDITS
include README
include ChangeLog
include MANIFEST.in
include testsample.py
include testmime.py
include testutils.py
include test.py
include sample.py
include milter-template.py
include test/*
include Milter/*.py
include *.spec
include start.sh
-601
View File
@@ -1,601 +0,0 @@
## @package Milter
# A thin OO wrapper for the milter module.
#
# Clients generally subclass Milter.Base and define callback
# methods.
#
# @author Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001,2009 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
__version__ = '0.9.3'
import os
import milter
import thread
from milter import *
_seq_lock = thread.allocate_lock()
_seq = 0
def uniqueID():
"""Return a sequence number unique to this process.
"""
global _seq
_seq_lock.acquire()
seqno = _seq = _seq + 1
_seq_lock.release()
return seqno
OPTIONAL_CALLBACKS = {
'connect':(P_NR_CONN,P_NOCONNECT),
'hello':(P_NR_HELO,P_NOHELO),
'envfrom':(P_NR_MAIL,P_NOMAIL),
'envrcpt':(P_NR_RCPT,P_NORCPT),
'data':(P_NR_DATA,P_NODATA),
'unknown':(P_NR_UNKN,P_NOUNKNOWN),
'eoh':(P_NR_EOH,P_NOEOH),
'body':(P_NR_BODY,P_NOBODY),
'header':(P_NR_HDR,P_NOHDRS)
}
def decode_mask(bits,names):
t = [ (s,getattr(milter,s)) for s in names]
nms = [s for s,m in t if bits & m]
for s,m in t: bits &= ~m
if bits: nms += hex(bits)
return nms
## Class decorator to enable optional protocol steps.
# P_SKIP is enabled by default when supported, but
# milter applications may wish to enable P_HDR_LEADSPC
# to send and receive the leading space of header continuation
# lines unchanged, and/or P_RCPT_REJ to have recipients
# detected as invalid by the MTA passed to the envcrpt callback.
#
# Applications may want to check whether the protocol is actually
# supported by the MTA in use. The <code>_protocol</code>
# member is a bitmask of protocol options negotiated. So,
# for instance, if <code>self._protocol & Milter.P_RCPT_REJ</code>
# is true, then that feature was successfully negotiated with the MTA.
#
# Sample use:
# <pre>
# class myMilter(Milter.Base):
# def envrcpt(self,to,*params):
# return Milter.CONTINUE
# myMilter = Milter.enable_protocols(myMilter,Milter.P_RCPT_REJ)
# </pre>
# @since 0.9.3
# @param klass the milter application class to modify
# @param mask a bitmask of protocol steps to enable
# @return the modified milter class
def enable_protocols(klass,mask):
klass._protocol_mask = klass.protocol_mask() & ~mask
return klass
## Function decorator to disable callback methods.
# If the MTA supports it, tells the MTA not to call this callback,
# increasing efficiency. All the callbacks (except negotiate)
# are disabled in Milter.Base, and overriding them reenables the
# callback. An application may need to use @@nocallback when it extends
# another milter and wants to disable a callback again.
# The disabled method should still return Milter.CONTINUE, in case the MTA does
# not support protocol negotiation.
# @since 0.9.2
def nocallback(func):
try:
func.milter_protocol = OPTIONAL_CALLBACKS[func.__name__][1]
except KeyError:
raise ValueError(
'@nocallback applied to non-optional method: '+func.__name__)
return func
## Function decorator to disable callback reply.
# If the MTA supports it, tells the MTA not to wait for a reply from
# this callback, and assume CONTINUE. The method should still return
# CONTINUE in case the MTA does not support protocol negotiation.
# The decorator arranges to change the return code to NOREPLY
# when supported by the MTA.
# @since 0.9.2
def noreply(func):
try:
nr_mask = OPTIONAL_CALLBACKS[func.__name__][0]
except KeyError:
raise ValueError(
'@noreply applied to non-optional method: '+func.__name__)
def wrapper(self,*args):
rc = func(self,*args)
if self._protocol & nr_mask: return NOREPLY
return rc
wrapper.milter_protocol = nr_mask
return wrapper
## Disabled action exception.
# set_flags() can tell the MTA that this application will not use certain
# features (such as CHGFROM). This can also be negotiated for each
# connection in the negotiate callback. If the application then calls
# the feature anyway via an instance method, this exception is
# thrown.
# @since 0.9.2
class DisabledAction(RuntimeError):
pass
## A do "nothing" Milter base class.
# Python milters should derive from this class
# unless they are using the low lever milter module directly.
# All optional callbacks are disabled, and automatically
# reenabled when overridden.
# @since 0.9.2
class Base(object):
"The core class interface to the milter module."
## Attach this Milter to the low level milter.milterContext object.
def _setctx(self,ctx):
self._ctx = ctx
self._actions = CURR_ACTS # all actions enabled by default
self._protocol = 0 # no protocol options by default
if ctx:
ctx.setpriv(self)
## @var _actions
# A bitmask of actions this milter has negotiated to use.
# By default, all actions are enabled. This may be changed
# by calling <code>milter.set_flags</code>, or by overriding
# the negotiate callback. The bits include:
# <code>ADDHDRS,CHGBODY,MODBODY,ADDRCPT,ADDRCPT_PAR,DELRCPT
# CHGHDRS,QUARANTINE,CHGFROM,SETSMLIST</code>.
# The <code>Milter.CURR_ACTS</code> bitmask is all actions
# known when the milter module was compiled.
# @since 0.9.2
#
## @var _protocol
# A bitmask of protocol options this milter has negotiated.
# The bits generally indicate that a particular step should be
# skipped, since previous versions of the milter protocol had
# no provision for skipping steps.
# The bits include: <code>
# P_RCPT_REJ P_NR_CONN P_NR_HELO P_NR_MAIL P_NR_RCPT P_NR_DATA P_NR_UNKN
# P_NR_EOH P_NR_BODY P_NR_HDR P_NOCONNECT P_NOHELO P_NOMAIL P_NORCPT
# P_NODATA P_NOUNKNOWN P_NOEOH P_NOBODY P_NOHDRS P_HDR_LEADSPC P_SKIP
# </code> (all under the Milter namespace).
# @since 0.9.2
## Defined by subclasses to write log messages.
def log(self,*msg): pass
## Called for each connection to the MTA.
# The <code>hostname</code> provided by the local MTA is either
# the PTR name or the IP in the form "[1.2.3.4]" if no PTR is available.
# The format of hostaddr depends on the socket family:
# <dl>
# <dt><code>socket.AF_INET</code>
# <dd>A tuple of (IP as string in dotted quad form, integer port)
# <dt><code>socket.AF_INET6</code>
# <dd>A tuple of (IP as a string in standard representation,
# integer port, integer flow info, integer scope id)
# <dt><code>socket.AF_UNIX</code>
# <dd>A string with the socketname
# </dl>
# @param hostname the PTR name or bracketed IP of the SMTP client
# @param family <code>socket.AF_INET</code>, <code>socket.AF_INET6</code>,
# or <code>socket.AF_UNIX</code>
# @param hostaddr a tuple or string with peer IP or socketname
@nocallback
def connect(self,hostname,family,hostaddr): return CONTINUE
## Called when the SMTP client says HELO.
# Returning REJECT prevents progress until a valid HELO is provided;
# this almost always results in terminating the connection.
@nocallback
def hello(self,hostname): return CONTINUE
## Called when the SMTP client says MAIL FROM.
# Returning REJECT rejects the message, but not the connection.
@nocallback
def envfrom(self,f,*str): return CONTINUE
## Called when the SMTP client says RCPT TO.
# Returning REJECT rejects the current recipient, not the entire message.
@nocallback
def envrcpt(self,to,*str): return CONTINUE
## Called when the SMTP client says DATA.
# Returning REJECT rejects the message without wasting bandwidth
# on the unwanted message.
# @since 0.9.2
@nocallback
def data(self): return CONTINUE
## Called for each header field in the message body.
@nocallback
def header(self,field,value): return CONTINUE
## Called at the blank line that terminates the header fields.
@nocallback
def eoh(self): return CONTINUE
## Called to supply the body of the message to the Milter by chunks.
# @param blk a block of message bytes
@nocallback
def body(self,blk): return CONTINUE
## Called when the SMTP client issues an unknown command.
# @param cmd the unknown command
# @since 0.9.2
@nocallback
def unknown(self,cmd): return CONTINUE
## Called at the end of the message body.
# Most of the message manipulation actions can only take place from
# the eom callback.
def eom(self): return CONTINUE
## Called when the connection is abnormally terminated.
# The close callback is still called also.
def abort(self): return CONTINUE
## Called when the connection is closed.
def close(self): return CONTINUE
## Return mask of SMFIP_N.. protocol option bits to clear for this class
# The @@nocallback and @@noreply decorators set the
# <code>milter_protocol</code> function attribute to the protocol mask bit to
# pass to libmilter, causing that callback or its reply to be skipped.
# Overriding a method creates a new function object, so that
# <code>milter_protocol</code> defaults to 0.
# Libmilter passes the protocol bits that the current MTA knows
# how to skip. We clear the ones we don't want to skip.
# The negation is somewhat mind bending, but it is simple.
# @since 0.9.2
@classmethod
def protocol_mask(klass):
try:
return klass._protocol_mask
except AttributeError:
p = P_RCPT_REJ | P_HDR_LEADSPC # turn these new features off by default
for func,(nr,nc) in OPTIONAL_CALLBACKS.items():
func = getattr(klass,func)
ca = getattr(func,'milter_protocol',0)
#print func,hex(nr),hex(nc),hex(ca)
p |= (nr|nc) & ~ca
klass._protocol_mask = p
return p
## Negotiate milter protocol options.
# Default negotiation sets P_NO* and P_NR* for callbacks
# marked @@nocallback and @@noreply respectively, leaves all
# actions enabled, and enables Milter.SKIP.
# @since 0.9.2
def negotiate(self,opts):
try:
self._actions,p,f1,f2 = opts
opts[1] = self._protocol = p & ~self.protocol_mask()
opts[2] = 0
opts[3] = 0
#self.log("Negotiated:",opts)
except:
# don't change anything if something went wrong
return ALL_OPTS
return CONTINUE
# Milter methods which can be invoked from most callbacks
## Return the value of an MTA macro. Sendmail macro names
# are either single chars (e.g. "j") or multiple chars enclosed
# in braces (e.g. "{auth_type}"). Macro names are MTA dependent.
# @param sym the macro name
def getsymval(self,sym):
return self._ctx.getsymval(sym)
## Set the SMTP reply code and message.
# If the MTA does not support setmlreply, then only the
# first msg line is used.
def setreply(self,rcode,xcode=None,msg=None,*ml):
return self._ctx.setreply(rcode,xcode,msg,*ml)
## Tell the MTA which macro names will be used.
# The <code>Milter.SETSMLIST</code> action flag must be set.
#
# May only be called from negotiate callback.
# @since 0.9.2
# @param stage the protocol stage to set to macro list for
# @param macros a string with a space delimited list of macros
def setsmlist(self,stage,macros):
if not self._actions & SETSMLIST: raise DisabledAction("SETSMLIST")
if type(macros) in (list,tuple):
macros = ' '.join(macros)
return self._ctx.setsmlist(stage,macros)
# Milter methods which can only be called from eom callback.
## Add a mail header field.
# The <code>Milter.ADDHDRS</code> action flag must be set.
#
# May be called from eom callback only.
# @param field the header field name
# @param value the header field value
# @param idx header field index from the top of the message to insert at
def addheader(self,field,value,idx=-1):
if not self._actions & ADDHDRS: raise DisabledAction("ADDHDRS")
return self._ctx.addheader(field,value,idx)
## Change the value of a mail header field.
# The <code>Milter.CHGHDRS</code> action flag must be set.
#
# May be called from eom callback only.
# @param field the name of the field to change
# @param idx index of the field to change when there are multiple instances
# @param value the new value of the field
def chgheader(self,field,idx,value):
if not self._actions & CHGHDRS: raise DisabledAction("CHGHDRS")
return self._ctx.chgheader(field,idx,value)
## Add a recipient to the message.
# If no corresponding mail header is added, this is like a Bcc.
# The syntax of the recipient is the same as used in the SMTP
# RCPT TO command (and as delivered to the envrcpt callback), for example
# "self.addrcpt('<foo@example.com>')".
# The <code>Milter.ADDRCPT</code> action flag must be set.
# If the optional <code>params</code> argument is used, then
# the <code>Milter.ADDRCPT_PAR</code> action flag must be set.
#
# May be called from eom callback only.
# @param rcpt the message recipient
# @param params an optional list of ESMTP parameters
def addrcpt(self,rcpt,params=None):
if not self._actions & ADDRCPT: raise DisabledAction("ADDRCPT")
if params and not self._actions & ADDRCPT_PAR:
raise DisabledAction("ADDRCPT_PAR")
return self._ctx.addrcpt(rcpt,params)
## Delete a recipient from the message.
# The recipient should match one passed to the envrcpt callback.
# The <code>Milter.DELRCPT</code> action flag must be set.
#
# May be called from eom callback only.
# @param rcpt the message recipient to delete
def delrcpt(self,rcpt):
if not self._actions & DELRCPT: raise DisabledAction("DELRCPT")
return self._ctx.delrcpt(rcpt)
## Replace the message body.
# The entire message body must be replaced.
# Call repeatedly with blocks of data until the entire body is transferred.
# The <code>Milter.MODBODY</code> action flag must be set.
#
# May be called from eom callback only.
# @param body a chunk of body data
def replacebody(self,body):
if not self._actions & MODBODY: raise DisabledAction("MODBODY")
return self._ctx.replacebody(body)
## Change the SMTP envelope sender address.
# The syntax of the sender is that same as used in the SMTP
# MAIL FROM command (and as delivered to the envfrom callback),
# for example <code>self.chgfrom('<bar@example.com>')</code>.
# The <code>Milter.CHGFROM</code> action flag must be set.
#
# May be called from eom callback only.
# @since 0.9.1
# @param sender the new sender address
# @param params an optional list of ESMTP parameters
def chgfrom(self,sender,params=None):
if not self._actions & CHGFROM: raise DisabledAction("CHGFROM")
return self._ctx.chgfrom(sender,params)
## Quarantine the message.
# When quarantined, a message goes into the mailq as if to be delivered,
# but delivery is deferred until the message is unquarantined.
# The <code>Milter.QUARANTINE</code> action flag must be set.
#
# May be called from eom callback only.
# @param reason a string describing the reason for quarantine
def quarantine(self,reason):
if not self._actions & QUARANTINE: raise DisabledAction("QUARANTINE")
return self._ctx.quarantine(reason)
## Tell the MTA to wait a bit longer.
# Resets timeouts in the MTA that detect a "hung" milter.
def progress(self):
return self._ctx.progress()
## A logging but otherwise do nothing Milter base class.
# This is included for compatibility with previous versions of pymilter.
# The logging callbacks are marked @@noreply.
class Milter(Base):
"A simple class interface to the milter module."
## Provide simple logging to sys.stdout
def log(self,*msg):
print 'Milter:',
for i in msg: print i,
print
@noreply
def connect(self,hostname,family,hostaddr):
"Called for each connection to sendmail."
self.log("connect from %s at %s" % (hostname,hostaddr))
return CONTINUE
@noreply
def hello(self,hostname):
"Called after the HELO command."
self.log("hello from %s" % hostname)
return CONTINUE
@noreply
def envfrom(self,f,*str):
"""Called to begin each message.
f -> string message sender
str -> tuple additional ESMTP parameters
"""
self.log("mail from",f,str)
return CONTINUE
@noreply
def envrcpt(self,to,*str):
"Called for each message recipient."
self.log("rcpt to",to,str)
return CONTINUE
@noreply
def header(self,field,value):
"Called for each message header."
self.log("%s: %s" % (field,value))
return CONTINUE
@noreply
def eoh(self):
"Called after all headers are processed."
self.log("eoh")
return CONTINUE
def eom(self):
"Called at the end of message."
self.log("eom")
return CONTINUE
def abort(self):
"Called if the connection is terminated abnormally."
self.log("abort")
return CONTINUE
def close(self):
"Called at the end of connection, even if aborted."
self.log("close")
return CONTINUE
## The milter connection factory
# This factory method is called for each connection to create the
# python object that tracks the connection. It should return
# an object derived from Milter.Base.
#
# Note that since python is dynamic, this variable can be changed while
# the milter is running: for instance, to a new subclass based on a
# change in configuration.
factory = Milter
## @private
def negotiate_callback(ctx,opts):
m = factory()
m._setctx(ctx)
return m.negotiate(opts)
## @private
def connect_callback(ctx,hostname,family,hostaddr,nr_mask=P_NR_CONN):
m = ctx.getpriv()
if not m:
# If not already created (because the current MTA doesn't support
# xmfi_negotiate), create the connection object.
m = factory()
m._setctx(ctx)
return m.connect(hostname,family,hostaddr)
## @private
def close_callback(ctx):
m = ctx.getpriv()
if not m: return CONTINUE
try:
rc = m.close()
finally:
m._setctx(None) # release milterContext
return rc
## Convert ESMTP parameters with values to a keyword dictionary.
# @deprecated You probably want Milter.param2dict instead.
def dictfromlist(args):
"Convert ESMTP parms with values to keyword dictionary."
kw = {}
for s in args:
pos = s.find('=')
if pos > 0:
kw[s[:pos].upper()] = s[pos+1:]
return kw
## Convert ESMTP parm list to keyword dictionary.
# Params with no value are set to None in the dictionary.
# @since 0.9.3
# @param str list of param strings of the form "NAME" or "NAME=VALUE"
# @return a dictionary of ESMTP param names and values
def param2dict(str):
"Convert ESMTP parm list to keyword dictionary."
pairs = [x.split('=',1) for x in str]
for e in pairs:
if len(e) < 2: e.append(None)
return dict([(k.upper(),v) for k,v in pairs])
def envcallback(c,args):
"""Call function c with ESMTP parms converted to keyword parameters.
Can be used in the envfrom and/or envrcpt callbacks to process
ESMTP parameters as python keyword parameters."""
kw = {}
pargs = [args[0]]
for s in args[1:]:
pos = s.find('=')
if pos > 0:
kw[s[:pos].upper()] = s[pos+1:]
else:
pargs.append(s)
return c(*pargs,**kw)
## Run the milter.
# @param name the name of the milter known by the MTA
# @param socketname the socket to be passed to <code>milter.setconn</code>
# @param timeout the time in secs the MTA should wait for a response before
# considering this milter dead
def runmilter(name,socketname,timeout = 0):
# This bit is here on the assumption that you will be starting this filter
# before sendmail. If sendmail is not running and the socket already exists,
# libmilter will throw a warning. If sendmail is running, this is still
# safe if there are no messages currently being processed. It's safer to
# shutdown sendmail, kill the filter process, restart the filter, and then
# restart sendmail.
pos = socketname.find(':')
if pos > 1:
s = socketname[:pos]
fname = socketname[pos+1:]
else:
s = "unix"
fname = socketname
if s == "unix" or s == "local":
print "Removing %s" % fname
try:
os.unlink(fname)
except os.error, x:
import errno
if x.errno != errno.ENOENT:
raise milter.error(x)
# The default flags set include everything
# milter.set_flags(milter.ADDHDRS)
milter.set_connect_callback(connect_callback)
milter.set_helo_callback(lambda ctx, host: ctx.getpriv().hello(host))
# For envfrom and envrcpt, we would like to convert ESMTP parms to keyword
# parms, but then all existing users would have to include **kw to accept
# arbitrary keywords without crashing. We do provide envcallback and
# dictfromlist to make parsing the ESMTP args convenient.
milter.set_envfrom_callback(lambda ctx,*str: ctx.getpriv().envfrom(*str))
milter.set_envrcpt_callback(lambda ctx,*str: ctx.getpriv().envrcpt(*str))
milter.set_header_callback(lambda ctx,fld,val: ctx.getpriv().header(fld,val))
milter.set_eoh_callback(lambda ctx: ctx.getpriv().eoh())
milter.set_body_callback(lambda ctx,chunk: ctx.getpriv().body(chunk))
milter.set_eom_callback(lambda ctx: ctx.getpriv().eom())
milter.set_abort_callback(lambda ctx: ctx.getpriv().abort())
milter.set_close_callback(close_callback)
milter.setconn(socketname)
if timeout > 0: milter.settimeout(timeout)
# disable negotiate callback if runtime version < (1,0,1)
ncb = negotiate_callback
if milter.getversion() < (1,0,1):
ncb = None
# The name *must* match the X line in sendmail.cf (supposedly)
milter.register(name,
data=lambda ctx: ctx.getpriv().data(),
unknown=lambda ctx,cmd: ctx.getpriv().unknown(cmd),
negotiate=ncb
)
start_seq = _seq
try:
milter.main()
except milter.error:
if start_seq == _seq: raise # couldn't start
# milter has been running for a while, but now it can't start new threads
raise milter.error("out of thread resources")
__all__ = globals().copy()
for priv in ('os','milter','thread','factory','_seq','_seq_lock','__version__'):
del __all__[priv]
__all__ = __all__.keys()
## @example milter-template.py
#
-158
View File
@@ -1,158 +0,0 @@
# Email address list with expiration
#
# This class acts like a map. Entries with a value of None are persistent,
# but disappear after a time limit. This is useful for automatic whitelists
# and blacklists with expiration. The persistent store is a simple ascii
# file with sender and timestamp on each line. Entries can be appended
# to the store, and will be picked up the next time it is loaded.
#
# Entries with other values are not persistent. This is used to hold failed
# CBV results.
#
# $Log$
# Revision 1.8 2007/09/03 16:18:45 customdesigned
# Delete unparseable timestamps when loading address cache. These have
# arisen because of failure to parse MAIL FROM properly. Will have to
# tighten up MAIL FROM parsing to match RFC.
#
# Revision 1.7 2007/01/25 22:47:26 customdesigned
# Persist blacklisting from delayed DSNs.
#
# Revision 1.6 2007/01/19 23:31:38 customdesigned
# Move parse_header to Milter.utils.
# Test case for delayed DSN parsing.
# Fix plock when source missing or cannot set owner/group.
#
# Revision 1.5 2007/01/11 19:59:40 customdesigned
# Purge old entries in auto_whitelist and send_dsn logs.
#
# Revision 1.4 2007/01/11 04:31:26 customdesigned
# Negative feedback for bad headers. Purge cache logs on startup.
#
# Revision 1.3 2007/01/08 23:20:54 customdesigned
# Get user feedback.
#
# Revision 1.2 2007/01/05 23:33:55 customdesigned
# Make blacklist an AddrCache
#
# Revision 1.1 2007/01/05 21:25:40 customdesigned
# Move AddrCache to Milter package.
#
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001,2002,2003,2004,2005 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
import time
from plock import PLock
class AddrCache(object):
time_format = '%Y%b%d %H:%M:%S %Z'
def __init__(self,renew=7,fname=None):
self.age = renew
self.cache = {}
self.fname = fname
def load(self,fname,age=0):
"Load address cache from persistent store."
if not age:
age = self.age
self.fname = fname
cache = {}
self.cache = cache
now = time.time()
lock = PLock(self.fname)
wfp = lock.lock()
changed = False
try:
too_old = now - age*24*60*60 # max age in days
try:
fp = open(self.fname)
except OSError:
fp = ()
for ln in fp:
try:
rcpt,ts = ln.strip().split(None,1)
try:
l = time.strptime(ts,AddrCache.time_format)
t = time.mktime(l)
if t < too_old:
changed = True
continue
cache[rcpt.lower()] = (t,None)
except: # unparsable timestamp - likely garbage
changed = True
continue
except: # manual entry (no timestamp)
cache[ln.strip().lower()] = (now,None)
wfp.write(ln)
if changed:
lock.commit(self.fname+'.old')
else:
lock.unlock()
except IOError:
lock.unlock()
def has_precise_key(self,sender):
"""True if precise sender is cached and has not expired. Don't
try looking up wildcard entries.
"""
try:
lsender = sender and sender.lower()
ts,res = self.cache[lsender]
too_old = time.time() - self.age*24*60*60 # max age in days
if not ts or ts > too_old:
return True
del self.cache[lsender]
except KeyError: pass
return False
def has_key(self,sender):
"True if sender is cached and has not expired."
if self.has_precise_key(sender):
return True
try:
user,host = sender.split('@',1)
return self.has_precise_key(host)
except: pass
return False
__contains__ = has_key
def __getitem__(self,sender):
try:
lsender = sender.lower()
ts,res = self.cache[lsender]
too_old = time.time() - self.age*24*60*60 # max age in days
if not ts or ts > too_old:
return res
del self.cache[lsender]
raise KeyError, sender
except KeyError,x:
try:
user,host = sender.split('@',1)
return self.__getitem__(host)
except ValueError:
raise x
def addperm(self,sender,res=None):
"Add a permanent sender."
lsender = sender.lower()
if self.has_key(lsender):
ts,res = self.cache[lsender]
if not ts: return # already permanent
self.cache[lsender] = (None,res)
if not res:
print >>open(self.fname,'a'),sender
def __setitem__(self,sender,res):
lsender = sender.lower()
now = time.time()
self.cache[lsender] = (now,res)
if not res and self.fname:
s = time.strftime(AddrCache.time_format,time.localtime(now))
print >>open(self.fname,'a'),sender,s # log refreshed senders
def __len__(self):
return len(self.cache)
-64
View File
@@ -1,64 +0,0 @@
from ConfigParser import ConfigParser
class MilterConfigParser(ConfigParser):
def __init__(self,defaults={}):
ConfigParser.__init__(self)
self.defaults = defaults
# The defaults provided by ConfigParser show up in all sections,
# which screws up iterating over all options in a section.
# Worse, passing "defaults" with vars= overrides the config file!
# So we roll our own defaults.
def get(self,sect,opt):
if not self.has_option(sect,opt) and opt in self.defaults:
return self.defaults[opt]
return ConfigParser.get(self,sect,opt)
def getlist(self,sect,opt):
if self.has_option(sect,opt):
return [q.strip() for q in self.get(sect,opt).split(',')]
return []
def getaddrset(self,sect,opt):
if not self.has_option(sect,opt):
return {}
s = self.get(sect,opt)
d = {}
for q in s.split(','):
q = q.strip()
if q.startswith('file:'):
domain = q[5:].lower()
d[domain] = d.setdefault(domain,[]) + open(domain,'r').read().split()
else:
user,domain = q.split('@')
d.setdefault(domain.lower(),[]).append(user)
return d
def getaddrdict(self,sect,opt):
if not self.has_option(sect,opt):
return {}
d = {}
for q in self.get(sect,opt).split(','):
q = q.strip()
if self.has_option(sect,q):
l = self.get(sect,q)
for addr in l.split(','):
addr = addr.strip()
if addr.startswith('file:'):
fname = addr[5:]
for a in open(fname,'r').read().split():
d[a] = q
else:
d[addr] = q
return d
def getdefault(self,sect,opt,default=None):
if self.has_option(sect,opt):
return self.get(sect,opt)
return default
def getintdefault(self,sect,opt,default=None):
if self.has_option(sect,opt):
return self.getint(sect,opt)
return default
-103
View File
@@ -1,103 +0,0 @@
## @package Milter.dns
# Provide a higher level interface to pydns.
import DNS
from DNS import DNSError
MAX_CNAME = 10
## Lookup DNS records by label and RR type.
# The response can include records of other types that the DNS
# server thinks we might need.
# @param name the DNS label to lookup
# @param qtype the name of the DNS RR type to lookup
# @return a list of ((name,type),data) tuples
def DNSLookup(name, qtype):
try:
# To be thread safe, we create a fresh DnsRequest with
# each call. It would be more efficient to reuse
# a req object stored in a Session.
req = DNS.DnsRequest(name, qtype=qtype)
resp = req.req()
#resp.show()
# key k: ('wayforward.net', 'A'), value v
# FIXME: pydns returns AAAA RR as 16 byte binary string, but
# A RR as dotted quad. For consistency, this driver should
# return both as binary string.
return [((a['name'], a['typename']), a['data']) for a in resp.answers]
except IOError, x:
raise DNSError, str(x)
class Session(object):
"""A Session object has a simple cache with no TTL that is valid
for a single "session", for example an SMTP conversation."""
def __init__(self):
self.cache = {}
## Additional DNS RRs we can safely cache.
# We have to be careful which additional DNS RRs we cache. For
# instance, PTR records are controlled by the connecting IP, and they
# could poison our local cache with bogus A and MX records.
# Each entry is a tuple of (query_type,rr_type). So for instance,
# the entry ('MX','A') says it is safe (for milter purposes) to cache
# any 'A' RRs found in an 'MX' query.
SAFE2CACHE = frozenset((
('MX','MX'), ('MX','A'),
('CNAME','CNAME'), ('CNAME','A'),
('A','A'),
('AAAA','AAAA'),
('PTR','PTR'),
('NS','NS'), ('NS','A'),
('TXT','TXT'),
('SPF','SPF')
))
## Cached DNS lookup.
# @param name the DNS label to query
# @param qtype the query type, e.g. 'A'
# @param cnames tracks CNAMES already followed in recursive calls
def dns(self, name, qtype, cnames=None):
"""DNS query.
If the result is in cache, return that. Otherwise pull the
result from DNS, and cache ALL answers, so additional info
is available for further queries later.
CNAMEs are followed.
If there is no data, [] is returned.
pre: qtype in ['A', 'AAAA', 'MX', 'PTR', 'TXT', 'SPF']
post: isinstance(__return__, types.ListType)
"""
result = self.cache.get( (name, qtype) )
cname = None
if not result:
safe2cache = Session.SAFE2CACHE
for k, v in DNSLookup(name, qtype):
if k == (name, 'CNAME'):
cname = v
if (qtype,k[1]) in safe2cache:
self.cache.setdefault(k, []).append(v)
result = self.cache.get( (name, qtype), [])
if not result and cname:
if not cnames:
cnames = {}
elif len(cnames) >= MAX_CNAME:
#return result # if too many == NX_DOMAIN
raise DNSError('Length of CNAME chain exceeds %d' % MAX_CNAME)
cnames[name] = cname
if cname in cnames:
raise DNSError, 'CNAME loop'
result = self.dns(cname, qtype, cnames=cnames)
return result
DNS.DiscoverNameServers()
if __name__ == '__main__':
import sys
s = Session()
for n,t in zip(*[iter(sys.argv[1:])]*2):
print n,t
print s.dns(n,t)
-229
View File
@@ -1,229 +0,0 @@
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2005 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
# Send DSNs, do call back verification,
# and generate DSN messages from a template
# $Log$
# Revision 1.20 2010/10/11 00:29:47 customdesigned
# Handle multiple recipients. For CBV or auto whitelist of multiple emails.
#
# Revision 1.19 2009/07/02 19:41:12 customdesigned
# Handle @ in localpart.
#
# Revision 1.18 2009/06/10 18:01:59 customdesigned
# Doxygen updates
#
# Revision 1.17 2009/05/20 20:08:44 customdesigned
# Support non-DSN CBV (non-empty MAIL FROM)
#
# Revision 1.16 2007/09/25 01:24:59 customdesigned
# Allow arbitrary object, not just spf.query like, to provide data for create_msg
#
# Revision 1.15 2007/09/24 20:13:26 customdesigned
# Remove explicit spf dependency.
#
# Revision 1.14 2007/03/03 18:19:40 customdesigned
# Handle DNS error sending DSN.
#
# Revision 1.13 2007/01/04 18:01:11 customdesigned
# Do plain CBV when template missing.
#
# Revision 1.12 2006/07/26 16:37:35 customdesigned
# Support timeout.
#
# Revision 1.11 2006/06/21 21:07:11 customdesigned
# Include header fields in DSN template.
#
# Revision 1.10 2006/05/24 20:56:35 customdesigned
# Remove default templates. Scrub test.
#
## @package Milter.dsn
# Support DSNs and CallBackValidations (CBV).
#
# A Delivery Status Notification (bounce) is sent to the envelope
# sender (original MAIL FROM) with a null MAIL FROM (<>) to notify the
# original sender # of delays or problems with delivery. A Callback Validation
# starts the DSN process, but stops before issuing the DATA command. The
# purpose is to check whether the envelope recipient is accepted (and is
# therefore a valid email). The null MAIL FROM tells the remote
# MTA to never reply according to RFC2821 (but some braindead MTAs
# reply anyway, of course).
#
# Milters should cache CBV results and should avoid sending DSNs
# unless the sender is authenticated somehow (e.g. SPF Pass). However,
# when email is quarantined, and is not known to be a forgery, sending a DSN
# is better than silently disappearing, and a DSN is better than sending
# a normal message as notification - because MAIL FROM signing schemes
# can reject bounces of forged emails. Whatever you do, don't copy those
# assinine commercial filters that send a normal message to notify you
# that some virus is forging your email.
#
# <b>DSNs should *only* be sent to MAIL FROM addresses.</b> Never send
# a DSN or use a null MAIL FROM with an email address obtained from
# anywhere else.
#
import smtplib
import socket
from email.Message import Message
import Milter
import time
import dns
## Send DSN.
# Try the published MX names in order, rejecting obviously bogus entries
# (like <code>localhost</code>).
# @param mailfrom the original sender we are notifying or validating
# @param receiver the HELO name of the MTA we are sending the DSN on behalf of.
# Be sure to send from an IP that matches the HELO.
# @param msg the DSN message in RFC2822 format, or None for CBV.
# @param timeout total seconds to wait for a response from an MX
# @param session Milter.dns.Session object from current incoming mail
# session to reuse its cache, or None to create a fresh one.
# @param ourfrom set to a valid email to send a normal notification from, or
# to validate emails not obtained from MAIL FROM.
# @return None on success or (status_code,msg) on failure.
def send_dsn(mailfrom,receiver,msg=None,timeout=600,session=None,ourfrom=''):
"""Send DSN. If msg is None, do callback verification.
Mailfrom is original sender we are sending DSN or CBV to.
Receiver is the MTA sending the DSN.
Return None for success or (code,msg) for failure."""
user,domain = mailfrom.rsplit('@',1)
if not session: session = dns.Session()
try:
mxlist = session.dns(domain,'MX')
except dns.DNSError:
return (450,'DNS Timeout: %s MX'%domain) # temp error
if not mxlist:
mxlist = (0,domain), # fallback to A record when no MX
else:
mxlist.sort()
smtp = smtplib.SMTP()
toolate = time.time() + timeout
for prior,host in mxlist:
try:
smtp.connect(host)
code,resp = smtp.helo(receiver)
# some wiley spammers have MX records that resolve to 127.0.0.1
a = resp.split()
if not a:
return (553,'MX for %s has no hostname in banner: %s' % (domain,host))
if a[0] == receiver:
return (553,'Fraudulent MX for %s: %s' % (domain,host))
if not (200 <= code <= 299):
raise smtplib.SMTPHeloError(code, resp)
if msg:
try:
smtp.sendmail('<%s>'%ourfrom,mailfrom,msg)
except smtplib.SMTPSenderRefused:
# does not accept DSN, try postmaster (at the risk of mail loops)
smtp.sendmail('<postmaster@%s>'%receiver,mailfrom,msg)
else: # CBV
code,resp = smtp.docmd('MAIL FROM: <%s>'%ourfrom)
if code != 250:
raise smtplib.SMTPSenderRefused(code, resp, '<%s>'%ourfrom)
if isinstance(mailfrom,basestring):
mailfrom = [mailfrom]
badrcpts = {}
for rcpt in mailfrom:
code,resp = smtp.rcpt(rcpt)
if code not in (250,251):
badrcpts[rcpt] = (code,resp)# permanent error
smtp.quit()
if len(badrcpts) == 1:
return badrcpts.values()[0] # permanent error
if badrcpts:
return badrcpts
return None # success
except smtplib.SMTPRecipientsRefused,x:
if len(x.recipients) == 1:
return x.recipients.values()[0] # permanent error
return x.recipients
except smtplib.SMTPSenderRefused,x:
return x.args[:2] # does not accept DSN
except smtplib.SMTPDataError,x:
return x.args # permanent error
except smtplib.SMTPException:
pass # any other error, try next MX
except socket.error:
pass # MX didn't accept connections, try next one
except socket.timeout:
pass # MX too slow, try next one
smtp.close()
if time.time() > toolate:
return (450,'No MX response within %f minutes'%(timeout/60.0))
return (450,'No MX servers available') # temp error
class Vars: pass
# NOTE: Caller can pass an object to create_msg that in a typical milter
# collects things like heloname or sender anyway.
def create_msg(v,rcptlist=None,origmsg=None,template=None):
"""Create a DSN message from a template. Template must be '\n' separated.
v - an object whose attributes are used for substitutions. Must
have sender and receiver attributes at a minimum.
rcptlist - used to set v.rcpt if given
origmsg - used to set v.subject and v.spf_result if given
template - a '\n' separated string with python '%(name)s' substitutions.
"""
if not template:
return None
if hasattr(v,'perm_error'):
# likely to be an spf.query, try translating for backward compatibility
q = v
v = Vars()
try:
v.heloname = q.h
v.sender = q.s
v.connectip = q.i
v.receiver = q.r
v.sender_domain = q.o
v.result = q.result
v.perm_error = q.perm_error
except: v = q
if rcptlist:
v.rcpt = '\n\t'.join(rcptlist)
if origmsg:
try: v.subject = origmsg['Subject']
except: v.subject = '(none)'
try:
v.spf_result = origmsg['Received-SPF']
except: v.spf_result = None
msg = Message()
msg.add_header('X-Mailer','PyMilter-'+Milter.__version__)
msg.set_type('text/plain')
hdrs,body = template.split('\n\n',1)
for ln in hdrs.splitlines():
name,val = ln.split(':',1)
msg.add_header(name,(val % v.__dict__).strip())
msg.set_payload(body % v.__dict__)
# add headers if missing from old template
if 'to' not in msg:
msg.add_header('To',v.sender)
if 'from' not in msg:
msg.add_header('From','postmaster@%s'%v.receiver)
if 'auto-submitted' not in msg:
msg.add_header('Auto-Submitted','auto-generated')
return msg
if __name__ == '__main__':
import spf
q = spf.query('192.168.9.50',
'SRS0=pmeHL=RH==stuart@example.com',
'red.example.com',receiver='mail.example.com')
q.result = 'softfail'
q.perm_error = None
msg = create_msg(q,['charlie@example.com'],None,
"""From: postmaster@%(receiver)s
To: %(sender)s
Subject: Test
Test DSN template
"""
)
print msg.as_string()
# print send_dsn(f,msg.as_string())
# print send_dsn(q.s,'mail.example.com',msg.as_string())
-95
View File
@@ -1,95 +0,0 @@
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2005 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
# Heuristically determine whether a domain name is for a dynamic IP.
# examples we don't yet recognize:
#
# wiley-268-8196.roadrunner.nf.net at ('205.251.174.46', 4810)
# cbl-sd-02-79.aster.com.do at ('200.88.62.79', 4153)
import re
ip3 = re.compile('[0-9]{1,3}')
hpats = (
'h[0-9a-f]{12}[.]',
'h\d*n\d*c\d*o\d*\.',
'pcp\d{6,10}pcs[.]',
'no-reverse',
'S[0-9a-f]{16}[.][a-z]{2}[.]',
'user<3>\.',
'[Cc]ust<3>\.',
'^<3>\.',
'ppp[^.]*<3>\.',
'-ppp\d*\.',
'\d*-<3>\.',
'[0-9a-f]{1,3}-<3>\.',
'p<3>\.pool',
'h<3>\.',
'xdsl-\d*\.',
'-\d*-\d*\.',
'\.adsl\.',
'\.cable\.'
)
rehmac = re.compile('|'.join(hpats))
def is_dynip(host,addr):
"""Return True if hostname is for a dynamic ip.
Examples:
>>> is_dynip('post3.fabulousdealz.com','69.60.99.112')
False
>>> is_dynip('adsl-69-208-201-177.dsl.emhril.ameritech.net','69.208.201.177')
True
>>> is_dynip('[1.2.3.4]','1.2.3.4')
True
>>> is_dynip('c-71-63-151-151.hsd1.mn.comcast.net','71.63.151.151')
True
"""
if host.startswith('[') and host.endswith(']'):
return True
if addr:
if host.find(addr) >= 0: return True
a = addr.split('.')
ia = map(int,a)
h = host
m = ip3.findall(host)
if m:
g = map(int,m)[:4]
ia3 = (ia[1:],ia[:3])
if g[-3:] in ia3: return True
if g[0] == ia[3] and g[1:3] == ia[:2]: return True
if g[-2:] == ia[2:]: return True
g.reverse()
if g[:3] in ia3: return True
if g[:2] == ia[2:]: return True
if ia[2:] in (g[:2],g[-2:]): return True
for m in ip3.finditer(host):
if int(m.group()) == ia[3]:
h = host[:m.start()] + '<3>' + host[m.end():]
break
if rehmac.search(h): return True
if host.find(''.join(a[:3])) >= 0: return True
if host.find(''.join(a[1:])) >= 0: return True
x = "%02x%02x%02x%02x" % tuple(ia)
if host.lower().find(x) >= 0: return True
return False
if __name__ == '__main__':
import fileinput
import sets
seen = sets.Set()
for ln in fileinput.input():
a = ln.split()
if a[3:5] == ['connect','from']:
host = a[5]
if host.startswith('[') and host.endswith(']'):
continue # no PTR
ip = a[7][2:-2]
if ip in seen: continue
seen.add(ip)
if is_dynip(host,ip):
print '%s\t%s DYN' % (ip,host)
else:
print '%s\t%s' % (ip,host)
-74
View File
@@ -1,74 +0,0 @@
import time
import shelve
import thread
import logging
import urllib
log = logging.getLogger('milter.greylist')
def quoteAddress(s):
'''Quote an address so that it's safe to store in the file-system.
Address can either be a domain name, or local part.
Returns the quoted address.'''
s = urllib.quote(s, '@_-+~!.%')
if s.startswith('.'): s = '%2e' + s[1:]
return s
class Record(object):
__slots__ = ( 'firstseen', 'lastseen', 'umis', 'cnt' )
def __init__(self):
now = time.time()
self.firstseen = now
self.lastseen = now
self.cnt = 0
self.umis = None
class Greylist(object):
def __init__(self,dbname,grey_time=10,grey_expire=4,grey_retain=36):
self.ignoreLastByte = False
self.greylist_time = grey_time * 60 # minutes
self.greylist_expire = grey_expire * 3600 # hours
self.greylist_retain = grey_retain * 24 * 3600 # days
self.dbp = shelve.open(dbname,'c',protocol=2)
self.lock = thread.allocate_lock()
def check(self,ip,sender,recipient):
"Return number of allowed messages for greylist triple."
sender = quoteAddress(sender)
recipient = quoteAddress(recipient)
key = ip + ':' + sender + ':' + recipient
self.lock.acquire()
try:
dbp = self.dbp
try:
r = dbp[key]
now = time.time()
if now > r.lastseen + self.greylist_retain:
# expired
log.debug('Expired greylist: %s',key)
r = Record()
elif now < r.firstseen + self.greylist_time:
# still greylisted
log.debug('Early greylist: %s',key)
#r = Record()
r.lastseen = now
elif r.cnt or now < r.firstseen + self.greylist_expire:
# in greylist window or active
r.lastseen = now
r.cnt += 1
log.debug('Active greylist(%d): %s',r.cnt,key)
else:
# passed greylist window
log.debug('Late greylist: %s',key)
r = Record()
dbp[key] = r
except:
r = Record()
dbp[key] = r
dbp.sync()
finally:
self.lock.release()
return r.cnt
-66
View File
@@ -1,66 +0,0 @@
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
import os
from time import sleep
class PLock(object):
"A simple /etc/passwd style lock,update,rename protocol for updating files."
def __init__(self,basename):
self.basename = basename
self.fp = None
def lock(self,lockname=None,mode=0660,strict_perms=False):
"Start an update transaction. Return FILE to write new version."
self.unlock()
if not lockname:
lockname = self.basename + '.lock'
self.lockname = lockname
try:
st = os.stat(self.basename)
mode |= st.st_mode
except OSError: pass
u = os.umask(0002)
try:
fd = os.open(lockname,os.O_WRONLY+os.O_CREAT+os.O_EXCL,mode)
finally:
os.umask(u)
self.fp = os.fdopen(fd,'w')
try:
os.chown(self.lockname,-1,st.st_gid)
except:
if strict_perms:
self.unlock()
raise
return self.fp
def wlock(self,lockname=None):
"Wait until lock is free, then start an update transaction."
while True:
try:
return self.lock(lockname)
except OSError:
sleep(2)
def commit(self,backname=None):
"Commit update transaction with optional backup file."
if not self.fp:
raise IOError,"File not locked"
self.fp.close()
self.fp = None
if backname:
try:
os.remove(backname)
except OSError: pass
os.link(self.basename,backname)
os.rename(self.lockname,self.basename)
def unlock(self):
"Cancel update transaction."
if self.fp:
try:
self.fp.close()
except: pass
self.fp = None
os.remove(self.lockname)
-117
View File
@@ -1,117 +0,0 @@
"""Pure Python IP6 parsing and formatting
Copyright (c) 2006 Stuart Gathman <stuart@bmsi.com>
This module is free software, and you may redistribute it and/or modify
it under the same terms as Python itself, so long as this copyright message
and disclaimer are retained in their original form.
"""
import struct
#from spf import RE_IP4
import re
PAT_IP4 = r'\.'.join([r'(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])']*4)
RE_IP4 = re.compile(PAT_IP4+'$')
def inet_ntop(s):
"""
Convert ip6 address to standard hex notation.
Examples:
>>> inet_ntop(struct.pack("!HHHHHHHH",0,0,0,0,0,0xFFFF,0x0102,0x0304))
'::FFFF:1.2.3.4'
>>> inet_ntop(struct.pack("!HHHHHHHH",0x1234,0x5678,0,0,0,0,0x0102,0x0304))
'1234:5678::102:304'
>>> inet_ntop(struct.pack("!HHHHHHHH",0,0,0,0x1234,0x5678,0,0x0102,0x0304))
'::1234:5678:0:102:304'
>>> inet_ntop(struct.pack("!HHHHHHHH",0x1234,0x5678,0,0x0102,0x0304,0,0,0))
'1234:5678:0:102:304::'
>>> inet_ntop(struct.pack("!HHHHHHHH",0,0,0,0,0,0,0,0))
'::'
"""
# convert to 8 words
a = struct.unpack("!HHHHHHHH",s)
n = (0,0,0,0,0,0,0,0) # null ip6
if a == n: return '::'
# check for ip4 mapped
if a[:5] == (0,0,0,0,0) and a[5] in (0,0xFFFF):
ip4 = '.'.join([str(i) for i in struct.unpack("!BBBB",s[12:])])
if a[5]:
return "::FFFF:" + ip4
return "::" + ip4
# find index of longest sequence of 0
for l in (7,6,5,4,3,2,1):
e = n[:l]
for i in range(9-l):
if a[i:i+l] == e:
if i == 0:
return ':'+':%x'*(8-l) % a[l:]
if i == 8 - l:
return '%x:'*(8-l) % a[:-l] + ':'
return '%x:'*i % a[:i] + ':%x'*(8-l-i) % a[i+l:]
return "%x:%x:%x:%x:%x:%x:%x:%x" % a
def inet_pton(p):
"""
Convert ip6 standard hex notation to ip6 address.
Examples:
>>> struct.unpack('!HHHHHHHH',inet_pton('::'))
(0, 0, 0, 0, 0, 0, 0, 0)
>>> struct.unpack('!HHHHHHHH',inet_pton('::1234'))
(0, 0, 0, 0, 0, 0, 0, 4660)
>>> struct.unpack('!HHHHHHHH',inet_pton('1234::'))
(4660, 0, 0, 0, 0, 0, 0, 0)
>>> struct.unpack('!HHHHHHHH',inet_pton('1234::5678'))
(4660, 0, 0, 0, 0, 0, 0, 22136)
>>> struct.unpack('!HHHHHHHH',inet_pton('::FFFF:1.2.3.4'))
(0, 0, 0, 0, 0, 65535, 258, 772)
>>> struct.unpack('!HHHHHHHH',inet_pton('1.2.3.4'))
(0, 0, 0, 0, 0, 65535, 258, 772)
>>> try: inet_pton('::1.2.3.4.5')
... except ValueError,x: print x
::1.2.3.4.5
"""
if p == '::':
return '\0'*16
s = p
m = RE_IP4.search(s)
try:
if m:
pos = m.start()
ip4 = [int(i) for i in s[pos:].split('.')]
if not pos:
return struct.pack('!QLBBBB',0,65535,*ip4)
s = s[:pos]+'%x%02x:%x%02x'%tuple(ip4)
a = s.split('::')
if len(a) == 2:
l,r = a
if not l:
r = r.split(':')
return struct.pack('!HHHHHHHH',
*[0]*(8-len(r)) + [int(s,16) for s in r])
if not r:
l = l.split(':')
return struct.pack('!HHHHHHHH',
*[int(s,16) for s in l] + [0]*(8-len(l)))
l = l.split(':')
r = r.split(':')
return struct.pack('!HHHHHHHH',
*[int(s,16) for s in l] + [0]*(8-len(l)-len(r))
+ [int(s,16) for s in r])
if len(a) == 1:
return struct.pack('!HHHHHHHH',
*[int(s,16) for s in a[0].split(':')])
except ValueError: pass
raise ValueError,p
-17
View File
@@ -1,17 +0,0 @@
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2005 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
# The localpart of SMTP return addresses is often signed. The format
# of the signing is application specific and doesn't concern us -
# except that we wish to extract some sort of fixed string from
# the variable signature which represents the "source" of the message.
def unsign(s):
"""Attempt to unsign localpart and return original email.
No attempt is made to verify the signature.
>>> unsign('SRS0=8Y3CZ=3U=jsconnor.com=bills@bmsi.com')
'bills@jsconnor.com'
"""
# not implemented yet
return s
-196
View File
@@ -1,196 +0,0 @@
## @package Milter.utils
# Miscellaneous functions.
#
import re
import struct
import socket
import email.Errors
from fnmatch import fnmatchcase
from email.Header import decode_header
#import email.Utils
import rfc822
PAT_IP4 = r'\.'.join([r'(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])']*4)
ip4re = re.compile(PAT_IP4+'$')
ip6re = re.compile( '(?:%(hex4)s:){6}%(ls32)s$'
'|::(?:%(hex4)s:){5}%(ls32)s$'
'|(?:%(hex4)s)?::(?:%(hex4)s:){4}%(ls32)s$'
'|(?:(?:%(hex4)s:){0,1}%(hex4)s)?::(?:%(hex4)s:){3}%(ls32)s$'
'|(?:(?:%(hex4)s:){0,2}%(hex4)s)?::(?:%(hex4)s:){2}%(ls32)s$'
'|(?:(?:%(hex4)s:){0,3}%(hex4)s)?::%(hex4)s:%(ls32)s$'
'|(?:(?:%(hex4)s:){0,4}%(hex4)s)?::%(ls32)s$'
'|(?:(?:%(hex4)s:){0,5}%(hex4)s)?::%(hex4)s$'
'|(?:(?:%(hex4)s:){0,6}%(hex4)s)?::$'
% {
'ls32': r'(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|%s)'%PAT_IP4,
'hex4': r'[0-9a-f]{1,4}'
}, re.IGNORECASE)
# from spf.py
def addr2bin(str):
"""Convert a string IPv4 address into an unsigned integer."""
try:
return struct.unpack("!L", socket.inet_aton(str))[0]
except socket.error:
raise socket.error("Invalid IP4 address: "+str)
def bin2long6(str):
"""Convert binary IP6 address into an unsigned Python long integer."""
h, l = struct.unpack("!QQ", str)
return h << 64 | l
if hasattr(socket,'has_ipv6') and socket.has_ipv6:
def inet_ntop(s):
return socket.inet_ntop(socket.AF_INET6,s)
def inet_pton(s):
return socket.inet_pton(socket.AF_INET6,s)
else:
from pyip6 import inet_ntop, inet_pton
MASK = 0xFFFFFFFFL
MASK6 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
def cidr(i,n,mask=MASK):
return ~(mask >> n) & mask & i
def iniplist(ipaddr,iplist):
"""Return whether ip is in cidr list
>>> iniplist('66.179.26.146',['127.0.0.1','66.179.26.128/26'])
True
>>> iniplist('127.0.0.1',['127.0.0.1','66.179.26.128/26'])
True
>>> iniplist('192.168.0.45',['192.168.0.*'])
True
>>> iniplist('2001:610:779:0:223:6cff:fe9a:9cf3',['127.0.0.1','172.20.1.0/24','2001:610:779::/48'])
True
>>> iniplist('2G01:610:779:0:223:6cff:fe9a:9cf3',['127.0.0.1','172.20.1.0/24','2001:610:779::/48'])
Traceback (most recent call last):
...
ValueError: Invalid ip syntax:2G01:610:779:0:223:6cff:fe9a:9cf3
"""
if ip4re.match(ipaddr):
ipnum = addr2bin(ipaddr)
elif ip6re.match(ipaddr):
ipnum = bin2long6(inet_pton(ipaddr))
else:
raise ValueError('Invalid ip syntax:'+ipaddr)
for pat in iplist:
p = pat.split('/',1)
if ip4re.match(p[0]):
if len(p) > 1:
n = int(p[1])
else:
n = 32
if cidr(addr2bin(p[0]),n) == cidr(ipnum,n):
return True
elif ip6re.match(p[0]):
if len(p) > 1:
n = int(p[1])
else:
n = 128
if cidr(bin2long6(inet_pton(p[0])),n,MASK6) == cidr(ipnum,n,MASK6):
return True
elif fnmatchcase(ipaddr,pat):
return True
return False
## Split email into Fullname and address.
# This replaces <code>email.Utils.parseaddr</code> but fixes
# some <a href="http://bugs.python.org/issue1025395">tricky test cases</a>.
#
def parseaddr(t):
"""Split email into Fullname and address.
>>> parseaddr('user@example.com')
('', 'user@example.com')
>>> parseaddr('"Full Name" <foo@example.com>')
('Full Name', 'foo@example.com')
>>> parseaddr('spam@spammer.com <foo@example.com>')
('spam@spammer.com', 'foo@example.com')
>>> parseaddr('God@heaven <@hop1.org,@hop2.net:jeff@spec.org>')
('God@heaven', 'jeff@spec.org')
>>> parseaddr('Real Name ((comment)) <addr...@example.com>')
('Real Name', 'addr...@example.com')
>>> parseaddr('a(WRONG)@b')
('WRONG', 'a@b')
"""
#return email.Utils.parseaddr(t)
res = rfc822.parseaddr(t)
# dirty fix for some broken cases
if not res[0]:
pos = t.find('<')
if pos > 0 and t[-1] == '>':
addrspec = t[pos+1:-1]
pos1 = addrspec.rfind(':')
if pos1 > 0:
addrspec = addrspec[pos1+1:]
return rfc822.parseaddr('"%s" <%s>' % (t[:pos].strip(),addrspec))
if not res[1]:
pos = t.find('<')
if pos > 0 and t[-1] == '>':
addrspec = t[pos+1:-1]
pos1 = addrspec.rfind(':')
if pos1 > 0:
addrspec = addrspec[pos1+1:]
return rfc822.parseaddr('%s<%s>' % (t[:pos].strip(),addrspec))
return res
def parse_addr(t):
"""Split email into user,domain.
>>> parse_addr('user@example.com')
['user', 'example.com']
>>> parse_addr('"user@example.com"')
['user@example.com']
>>> parse_addr('"user@bar"@example.com')
['user@bar', 'example.com']
>>> parse_addr('foo')
['foo']
>>> parse_addr('@mx.example.com:user@example.com')
['user', 'example.com']
>>> parse_addr('@user@example.com')
['@user', 'example.com']
"""
if t.startswith('<') and t.endswith('>'): t = t[1:-1]
if t.startswith('"'):
if t.endswith('"'): return [t[1:-1]]
pos = t.find('"@')
if pos > 0: return [t[1:pos],t[pos+2:]]
if t.startswith('@'):
try: t = t.split(':',1)[1]
except IndexError: pass
return t.rsplit('@',1)
## Decode headers gratuitously encoded to hide the content.
# Spammers often encode headers to obscure the content from
# spam filters. This function decodes gratuitously encoded
# headers.
# @param val the raw header value
# @return the decoded value or the original raw value
def parse_header(val):
"""Decode headers gratuitously encoded to hide the content.
"""
try:
h = decode_header(val)
if not len(h) or (not h[0][1] and len(h) == 1): return val
u = []
for s,enc in h:
if enc:
try:
u.append(unicode(s,enc))
except LookupError:
u.append(unicode(s))
else:
u.append(unicode(s))
u = ''.join(u)
for enc in ('us-ascii','iso-8859-1','utf8'):
try:
return u.encode(enc)
except UnicodeError: continue
except UnicodeDecodeError: pass
except LookupError: pass
except email.Errors.HeaderParseError: pass
return val
+1 -63
View File
@@ -1,67 +1,5 @@
See pymilter.spec for recent history. Here is a history of user visible changes to Python milter.
Here is a history of older changes to Python milter.
0.8.8 move AddrCache, parse_addr, iniplist, parse_header to Milter package
fix plock for missing source and can't change owner/group
add sample spfmilter.py milter
private_relay config option
0.8.7 Move spf module to pyspf
Prevent PTR cache poisoning
More lame bounce heuristics
Do plain CBV when template is missing
0.8.6 Support CBV timeout
Support fail template, headers in templates
Create GOSSiP record only when connection will procede to DATA.
More SPF lax heuristics
Don't require SPF pass for white/black listing mail from trusted relay.
Support localpart wildcard for white and black lists.
Delay reject of unsigned RCPT for postmaster and abuse only
Fix dsn reporting of hard permerror
Resolve FIXME for wrap_close in miltermodule.c
Add Message-ID to DSNs
Use signed Message-ID in delayed reject to blacklist senders
Auto-train via blacklist and auto-whitelist
Don't check userlist for signed MFROM
Accept but skip DSPAM training for whitelisted senders without SPF PASS
Report GC stats
Support CIDR matching for IP lists
Support pysrs sign feature
Support localpart specific SPF policy in access file
0.8.5 Simple trusted_forwarder implementation.
Fix access_file neutral policy
Move Received-SPF header to beginning of headers
Supply keyword info for all results in Received-SPF header.
Move guessed SPF result to separate header
Activate smfi_insheader only when SMFIR_INSHEADER defined
Handle NULL MX in spf.py
in-process GOSSiP server support (to be extended later)
Expire CBV cache and renew auto-whitelist entries
0.8.4 Auto-whitelist recipients of outgoing email.
Fix SPF policy via sendmail access map (case insensitive keys).
Train screener on whitelisted messages
Optional idx parameter to addheader to invoke smfi_insheader
Activate progress API when SMFIR_PROGRESS defined
0.8.3 Keep screened honeypot mail, but optionally discard honeypot only mail.
spf_accept_fail option for braindead SPF senders
(treats fail like softfail)
Option to set SPF policy via sendmail access map.
Option to supply Sender header from MAIL FROM when missing.
Consider SMTP AUTH connections internal.
Send DSN for SPF errors corrected by extended processing.
Send DSN before SCREENED mail is quarantined
Use logging package to keep log lines atomic.
0.8.2 Strict processing limits per SPF RFC
Fixed several parsing bugs under RFC
Support official IANA SPF record (type99)
Honeypot support (requires pydspam-1.1.9)
Extended SPF processing results beyond strict RFC limits
Support original SES for bounce protection (requires pysrs-0.30.10)
Callback exception processing option in milter module
Handle corrupt ZIP attachments
0.8.1 Fix zip in zip loop in mime.py
Fix HeaderParseError in bms.py header callback
Check internal_domains for outgoing mail
Fix inconsistent results from send_dsn
0.8.0 Move Milter module to subpackage. 0.8.0 Move Milter module to subpackage.
DSN support for Three strikes rule and SPF SOFTFAIL DSN support for Three strikes rule and SPF SOFTFAIL
Move /*mime*/ and dynip to Milter subpackage Move /*mime*/ and dynip to Milter subpackage
-202
View File
@@ -1,202 +0,0 @@
Abstract
--------
This is a python extension module to enable python scripts to attach to
Sendmail's libmilter API, enabling filtering of messages as they arrive.
Since it's a script, you can do anything you want to the message - screen
out viruses, collect statistics, add or modify headers, etc. You can, at
any point, tell Sendmail to reject, discard, or accept the message.
Requirements
------------
This python milter extension: http://www.bmsi.com/python/milter.html
Python: http://www.python.org
Sendmail: http://www.sendmail.org
NB: From Sendmail's libmilter/README:
libmilter requires pthread support in the operating system. Moreover, it
requires that the library functions it uses are thread safe; which is true
for the operating systems libmilter has been developed and tested on. On
some operating systems this requires special compile time options (e.g.,
not just -pthread). libmilter is currently known to work on (modulo
problems in the pthread support of some specific versions):
FreeBSD 3.x, 4.x
SunOS 5.x (x >= 5)
AIX 4.3.x
HP UX 11.x
Linux (recent versions/distributions)
OpenBSD
AIX 4.1.5
libmilter is currently not supported on:
IRIX 6.x
Ultrix
Quick Installation
------------------
1. Build and install Sendmail, enabling libmilter (see libmilter/README).
2. Build and install Python, enabling threading.
3. Install this module: python setup.py --help
4. Add these two lines to sendmail.cf[*]:
O InputMailFilters=pythonfilter
Xpythonfilter, S=local:/home/username/pythonsock
5. Run the sample.py example milter with: python sample.py
Note that milters should almost certainly not run as root.
That's it. Incoming mail will cause the milter to print some things, and
some email will be rejected (see the "header" method). Edit and play.
See spfmilter.py for a functional SPF milter, or see bms.py for an complex
milter used in production.
[*] This is for a quick test. Your sendmail.cf in most distros will get
overwritten whenever sendmail.mc is updated. To make a milter permanent,
add something like:
INPUT_MAIL_FILTER(`pythonfilter', `S=local:/home/username/pythonsock, F=T, T=C:5m;S:20s;R:5m;E:5m')
to sendmail.mc instead.
Not-so-quick Installation
-------------------------
First install Sendmail. Make sure you read libmilter/README in the Sendmail
source directory, and make sure you enable libmilter before you build. The
8.11 series had libmilter marked as FFR (For Future Release); 8.12
officially
supports libmilter, but it's still not built by default.
Install Python, and enable threading in Modules/Setup.
Install this miltermodule package; DistUtils Automatic Installation:
$ python setup.py --help
For versions of python prior to 2.0, you will need to download distutils
separately or build manually. You will need to download unittest
separately to run the test programs. The bdist_rpm distutils option seems
not to work for python 2.0; upgrade to at least 2.1.1.
Now that everything is installed, we need to tell sendmail that we're going
to filter incoming email. Add lines similar to the following to
sendmail.cf:
O InputMailFilters=pythonfilter
Xpythonfilter, S=local:/home/username/pythonsock
The "O" line tells sendmail which filters to use in what order; here we're
telling sendmail to use the filter named "pythonfilter".
The next line, the "X" line (for "eXternal"), lists that filter along with
some options associated with it. In this case, we have the "S" option, which
names the socket that sendmail will use to communicate with this particular
milter. This milter's socket is a unix-domain socket in the filesystem.
See libmilter/README for the definitive list of options.
NB: The name is specified in two places: here, in sendmail's cf file, and
in the milter itself. Make sure the two match.
NB: The above lines can be added in your .mc file with this line:
INPUT_MAIL_FILTER(`pythonfilter', `S=local:/home/username/pythonsock')
For versions of sendmail prior to 8.12, you will need to enable
_FFR_MILTER for the cf macros. For example,
m4 -D_FFR_MILTER ../m4/cf.m4 myconfig.mc > myconfig.cf
RedHat 6.2 Notes
----------------
The Redhat 6.2 sendmail RPM does not enable milter. You can obtain a
modified spec file at
http://www.bmsi.com/linux/rh62/sendmail-rhmilter.spec
use it to rebuild the Redhat 7.2 SRPM. The RH6.2 SRPM does not have
recent sendmail security patches.
RedHat 7.2 Notes
----------------
The Redhat 7.2 sendmail RPM enables milter in sendmail - but does not include
the headers needed for compiling a milter. You can obtain a modified spec
file with a sendmail-devel package that includes the needed static libraries
and headers at
http://www.bmsi.com/linux/sendmail-rh72.spec
IPv6 Notes
----------
IPv6 is still experimental.
The IPv6 protocol is supported if your operation system supports it
and if sendmail was compiled with IPv6 support. To determine if your
sendmail supports IPv6, run "sendmail -d0" and check for the NETINET6
compilation option. To compile sendmail with IPv6 support, add this
declaration to your site.config.m4 before building it:
APPENDDEF(`confENVDEF', `-DNETINET6=1')
IPv6 support can show up in two places; the communications socket
between the milter and sendmail processes and in the host address
argument to the connect() callback method.
For sendmail to be able to accept IPv6 SMTP sessions, you must
configure the daemon to listen on an IPv6 port. Furthermore if you
want to allow both IPv4 and IPv6 connections, some operating systems
will require that each listens to different port numbers. For an
IPv6-only setup, your sendmail configuration should contain a line
similar to (first line is for sendmail.mc, second is sendmail.cf):
DAEMON_OPTIONS(`Name=MTA-v6, Family=inet6, Modify=C, Port=25')
O DaemonPortOptions=Name=MTA-v6, Family=inet6, Modify=C, Port=25
To allow sendmail and the milter process to communicate with each
other over IPv6, you may use the "inet6" socket name prefix, as in:
Xpythonfilter, S=inet6:1234@fec0:0:0:7::5c
The connect() callback method in the milter class will pass the
IPv6-specific information in the 'hostaddr' argument as a tuple. Note
that the type of this value is dependent upon the protocol family, and
is not compatible with IPv4 connections. Therefore you should always
check the family argument before attempting to use the hostaddr
argument. A quick example showing this follows:
import socket
...
class ipv6awareMilter(Milter.Milter):
...
def connect(self,hostname,family,hostaddr):
if family==socket.AF_INET:
ipaddress, port = hostaddr
elif family==socket.AF_INET6:
ip6address, port, flowinfo, scopeid = hostaddr
elif family==socket.AF_UNIX:
socketpath = hostaddr
The hostname argument is always safe to use without interpreting the
protocol family. For IPv6 connections for which the hostname can not
be determined the hostname will appear similar to the string
"[IPv6:::1]" with the corresponding hostaddr[0] being "::1". Refer to
RFC 2553 for information on interpreting and using the flowinfo and
scopeid socket attributes, both of which are integers.
Authors
-------
Jim Niemira (urmane@urmane.org) wrote the original C module and some quick
and dirty python to use it. Stuart D. Gathman (stuart@bmsi.com) took that
kludge and added threading and context objects to it, wrote a proper OO
wrapper (Milter.py) that handles attachments, did lots of testing, packaged
it with distutils, and generally transformed it from a quick hack to a
real, usable Python extension.
-6
View File
@@ -1,6 +0,0 @@
Support smfi_negotiate and auto negotiate only those callbacks for which
Milter.Milter methods have been overridden. (Python should be able to
do that.)
Lookup exact RFC syntax of real name / email and make
Milter.utils.parse_addr() pass all unit tests.
-36
View File
@@ -1,36 +0,0 @@
## @mainpage Writing Milters in Python
#
#
# At the lowest level, the <code>milter</code> module provides a thin wrapper
# around the <a href="https://www.milter.org/developers/api/index"> sendmail
# libmilter API</a>. This API lets you register callbacks for a number of
# events in the process of sendmail receiving a message via SMTP. These
# events include the initial connection from a MTA, the envelope sender and
# recipients, the top level mail headers, and the message body. There are
# options to mangle all of these components of the message as it passes through
# the milter.
#
# At the next level, the <code>Milter</code> module (note the case difference)
# provides a Python friendly object oriented wrapper for the low level API. To
# use the Milter module, an application registers a 'factory' to create an
# object for each connection from a MTA to sendmail. These connection objects
# must provide methods corresponding to the libmilter callback events.
#
# Each event method returns a code to tell sendmail whether to proceed with
# processing the message. This is a big advantage of milters over other mail
# filtering systems. Unwanted mail can be stopped in its tracks at the
# earliest possible point.
#
# The <code>Milter.Base</code> class provides default implementations for
# event methods that do nothing, and also provides wrappers for the libmilter
# methods to mutate the message. It automatically negotiates with MTA
# which protocol steps need to be processed by the milter, based on
# which callback methods are overridden.
#
# The <code>Milter.Milter</code> class provides an alternate default
# implementation that logs the main milter events, but otherwise does nothing.
# It is provided for compatibility.
#
# The <code>mime</code> module provides a wrapper for the Python email package
# that fixes some bugs, and simplifies modifying selected parts of a MIME
# message.
-100
View File
@@ -1,100 +0,0 @@
# Document miltermodule for Doxygen
#
## @package milter
#
# A thin wrapper around libmilter.
#
## Hold context for a milter connection.
# Each connection to sendmail creates a new <code>SMFICTX</code> struct within
# libmilter. The milter module in turn creates a milterContext
# tied to the <code>SMFICTX</code> struct via <code>smfi_setpriv</code>
# to hold a PyThreadState and a user defined Python object for the connection.
#
# Most application interaction with libmilter takes places via
# the milterContext object for the connection. It is passed to
# callback functions as the first parameter.
#
# The <code>Milter</code> module creates a python class for each connection,
# and converts function callbacks to instance method invocations.
#
class milterContext(object):
def getsymval(self,sym): pass
def setreply(self,rcode,xcode,*msg): pass
def addheader(self,name,value,idx=-1): pass
def chgheader(self,name,idx,value): pass
def addrcpt(self,rcpt,params=None): pass
def delrcpt(self,rcpt): pass
def replacebody(self,data): pass
def setpriv(self,priv): pass
def getpriv(self): pass
def quarantine(self,reason): pass
def progress(self): pass
def chgfrom(self,sender,param=None): pass
def setsmlist(self,stage,macrolist): pass
class error(Exception): pass
def set_flags(flags): pass
def set_connect_callback(cb): pass
def set_helo_callback(cb): pass
def set_envfrom_callback(cb): pass
def set_envrcpt_callback(cb): pass
def set_header_callback(cb): pass
def set_eoh_callback(cb): pass
def set_body_callback(cb): pass
def set_abort_callback(cb): pass
def set_close_callback(cb): pass
def set_exception_policy(code): pass
def register(name,negotiate=None,unknown=None,data=None): pass
def opensocket(rmsock): pass
def main(): pass
## Set the libmilter debugging level.
# smfi_setdbg sets the milter library's internal debugging level to a new level
# so that code details may be traced. A level of zero turns off debugging. The
# greater (more positive) the level the more detailed the debugging. Six is the
# current, highest, useful value.
def setdbg(lev): pass
def settimeout(secs): pass
def setbacklog(n): pass
## Set the socket used to communicate with the MTA.
# The MTA can communicate with the milter by means of a
# unix, inet, or inet6 socket. By default, a unix domain socket
# is used. It must not exist,
# and sendmail will throw warnings if, eg, the file is under a
# group or world writable directory.
# <pre>
# setconn('unix:/var/run/pythonfilter')
# setconn('inet:8800') # listen on ANY interface
# setconn('inet:7871@@publichost') # listen on a specific interface
# setconn('inet6:8020')
# </pre>
def setconn(s): pass
## Stop the milter gracefully.
def stop(): pass
## Retrieve diagnostic info.
# Return a tuple with diagnostic info gathered by the milter module.
# The first two fields are counts of milterContext objects created
# and deleted. Additional fields may be added later.
# @return a tuple of diagnostic data
def getdiag(): pass
## Retrieve the runtime libmilter version.
# Return the runtime libmilter version. This can be different
# from the compile time version when sendmail or libmilter is upgraded
# after pymilter is compiled.
# @return a tuple of <code>(major,minor,patchlevel)</code>
def getversion(): pass
## The compile time libmilter version.
# Python code might need to deal with pymilter compiled
# against various versions of libmilter. This module constant
# contains the contents of the <code>SMFI_VERSION</code> macro when
# the milter module was compiled.
VERSION = 0x1000001
-15
View File
@@ -1,15 +0,0 @@
web:
doxygen
rsync -ravK doc/html/ spidey2.bmsi.com:/Public/pymilter
VERSION=0.9.4
CVSTAG=pymilter-0_9_4
PKG=pymilter-$(VERSION)
SRCTAR=$(PKG).tar.gz
$(SRCTAR):
cvs export -r$(CVSTAG) -d $(PKG) pymilter
tar cvfz $(PKG).tar.gz $(PKG)
rm -r $(PKG)
cvstar: $(SRCTAR)
-140
View File
@@ -1,140 +0,0 @@
## To roll your own milter, create a class that extends Milter.
# See the pymilter project at http://bmsi.com/python/milter.html
# based on Sendmail's milter API http://www.milter.org/milter_api/api.html
# This code is open-source on the same terms as Python.
## Milter calls methods of your class at milter events.
## Return REJECT,TEMPFAIL,ACCEPT to short circuit processing for a message.
## You can also add/del recipients, replacebody, add/del headers, etc.
import Milter
import StringIO
import time
import email
from socket import AF_INET, AF_INET6
from Milter import parse_addr
class myMilter(Milter.Base):
def __init__(self): # A new instance with each new connection.
self.id = Milter.uniqueID() # Integer incremented with each call.
# each connection runs in its own thread and has its own myMilter
# instance. Python code must be thread safe. This is trivial if only stuff
# in myMilter instances is referenced.
@noreply
def connect(self, IPname, family, hostaddr):
# (self, 'ip068.subnet71.example.com', AF_INET, ('215.183.71.68', 4720) )
# (self, 'ip6.mxout.example.com', AF_INET6,
# ('3ffe:80e8:d8::1', 4720, 1, 0) )
self.IP = hostaddr[0]
self.port = hostaddr[1]
if family == AF_INET6:
self.flow = hostaddr[2]
self.scope = hostaddr[3]
else:
self.flow = None
self.scope = None
self.IPname = IPname # Name from a reverse IP lookup
self.H = None
self.fp = None
self.receiver = self.getsymval('j')
self.log("connect from %s at %s" % (IPname, hostaddr) )
return Milter.CONTINUE
## def hello(self,hostname):
def hello(self, heloname):
# (self, 'mailout17.dallas.texas.example.com')
self.H = heloname
self.log("HELO %s" % heloname)
if heloname.find('.') < 0: # illegal helo name
# NOTE: example only - too many real braindead clients to reject on this
self.setreply('550','5.7.1','Sheesh people! Use a proper helo name!')
return Milter.REJECT
return Milter.CONTINUE
## def envfrom(self,f,*str):
def envfrom(self, mailfrom, *str):
self.F = mailfrom
self.R = [] # list of recipients
self.fromparms = Milter.dictfromlist(str) # ESMTP parms
self.user = self.getsymval('{auth_authen}') # authenticated user
self.log("mail from:", mailfrom, *str)
self.fp = StringIO.StringIO()
self.canon_from = '@'.join(parse_addr(mailfrom))
self.fp.write('From %s %s\n' % (self.canon_from,time.ctime()))
return Milter.CONTINUE
## def envrcpt(self, to, *str):
@noreply
def envrcpt(self, recipient, *str):
rcptinfo = to,Milter.dictfromlist(str)
self.R.append(rcptinfo)
return Milter.CONTINUE
@noreply
def header(self, name, hval):
self.fp.write("%s: %s\n" % (name,hval)) # add header to buffer
return Milter.CONTINUE
@noreply
def eoh(self):
self.fp.write("\n") # terminate headers
return Milter.CONTINUE
@noreply
def body(self, chunk):
self.fp.write(chunk)
return Milter.CONTINUE
def eom(self):
self.fp.seek(0)
msg = email.message_from_file(self.fp)
self.setreply('250','2.5.1','Grokked by pymilter')
# many milter functions can only be called from eom()
# example of adding a Bcc:
self.addrcpt('<%s>' % 'spy@example.com')
return Milter.ACCEPT
def close(self):
# always called, even when abort is called. Clean up
# any external resources here.
return Milter.CONTINUE
def abort(self):
# client disconnected prematurely
return Milter.CONTINUE
## === Support Functions ===
def log(self,*msg):
print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S'),self.id),
# 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
for i in msg: print i,
print
## ===
def main():
# Register to have the Milter factory create instances of your class:
Milter.factory = myMilter
flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
flags += Milter.ADDRCPT
flags += Milter.DELRCPT
Milter.set_flags(flags) # tell Sendmail which features we use
print "%s milter startup" % time.strftime('%Y%b%d %H:%M:%S')
sys.stdout.flush()
Milter.runmilter("pythonfilter",socketname,timeout)
print "%s bms milter shutdown" % time.strftime('%Y%b%d %H:%M:%S')
if __name__ == "__main__":
main()
+253
View File
@@ -0,0 +1,253 @@
%define name milter
%define version 0.8.0
%define release 3.RH7
# what version of RH are we building for?
%define redhat9 0
%define redhat7 1
%define redhat6 0
# Options for Redhat version 6.x:
# rpm -ba|--rebuild --define "rh6 1"
%{?rh6:%define redhat7 0}
%{?rh6:%define redhat6 1}
# some systems dont have initrddir defined
%{?_initrddir:%define _initrddir /etc/rc.d/init.d}
%if %{redhat9}
%define sysvinit milter.rc
%else # Redhat 7.x and earlier (multiple ps lines per thread)
%define sysvinit milter.rc7
%endif
# RH9, other systems (single ps line per process)
%ifos Linux
%define python python2.4
%else
%define python python
%endif
Summary: Python interface to sendmail milter API
Name: %{name}
Version: %{version}
Release: %{release}
Source: %{name}-%{version}.tar.gz
#Patch: %{name}-%{version}.patch
Copyright: GPL
Group: Development/Libraries
BuildRoot: %{_tmppath}/%{name}-buildroot
Prefix: %{_prefix}
Vendor: Stuart D. Gathman <stuart@bmsi.com>
Packager: Stuart D. Gathman <stuart@bmsi.com>
Url: http://www.bmsi.com/python/milter.html
Requires: %{python} >= 2.4, sendmail >= 8.12.10
%ifos Linux
Requires: chkconfig
%endif
BuildRequires: %{python}-devel , sendmail-devel >= 8.12.10
%description
This is a python extension module to enable python scripts to
attach to sendmail's libmilter functionality. Additional python
modules provide for navigating and modifying MIME parts.
%prep
%setup
#%patch -p1
%build
env CFLAGS="$RPM_OPT_FLAGS" %{python} setup.py build
%install
rm -rf $RPM_BUILD_ROOT
%{python} setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES
mkdir -p $RPM_BUILD_ROOT/var/log/milter
mkdir -p $RPM_BUILD_ROOT/etc/mail
mkdir $RPM_BUILD_ROOT/var/log/milter/save
cp bms.py strike3.txt softfail.txt $RPM_BUILD_ROOT/var/log/milter
cp milter.cfg $RPM_BUILD_ROOT/etc/mail/pymilter.cfg
# logfile rotation
mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
cat >$RPM_BUILD_ROOT/etc/logrotate.d/milter <<'EOF'
/var/log/milter/milter.log {
copytruncate
compress
}
EOF
# purge saved defanged message copies
mkdir -p $RPM_BUILD_ROOT/etc/cron.daily
%ifos aix4.1
R=
%else
R='-r'
%endif
cat >$RPM_BUILD_ROOT/etc/cron.daily/milter <<'EOF'
#!/bin/sh
find /var/log/milter/save -mtime +7 | xargs $R rm
EOF
chmod a+x $RPM_BUILD_ROOT/etc/cron.daily/milter
%ifos aix4.1
cat >$RPM_BUILD_ROOT/var/log/milter/start.sh <<'EOF'
#!/bin/sh
cd /var/log/milter
# uncomment to enable sgmlop if installed
#export PYTHONPATH=/usr/local/lib/python2.1/site-packages
exec /usr/local/bin/python bms.py >>milter.log 2>&1
EOF
%else
cat >$RPM_BUILD_ROOT/var/log/milter/start.sh <<'EOF'
#!/bin/sh
cd /var/log/milter
exec >>milter.log 2>&1
%{python} bms.py &
echo $! >/var/run/milter/milter.pid
EOF
mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
cp %{sysvinit} $RPM_BUILD_ROOT/etc/rc.d/init.d/milter
ed $RPM_BUILD_ROOT/etc/rc.d/init.d/milter <<'EOF'
/^python=/
c
python="%{python}"
.
w
q
EOF
%endif
chmod a+x $RPM_BUILD_ROOT/var/log/milter/start.sh
mkdir -p $RPM_BUILD_ROOT/var/run/milter
mkdir -p $RPM_BUILD_ROOT/usr/share/sendmail-cf/hack
cp -p rhsbl.m4 $RPM_BUILD_ROOT/usr/share/sendmail-cf/hack
%ifos aix4.1
%post
mkssys -s milter -p /var/log/milter/start.sh -u 25 -S -n 15 -f 9 -G mail || :
%preun
if [ $1 = 0 ]; then
rmssys -s milter || :
fi
%else
%post
#echo "pythonsock has moved to /var/run/milter, update /etc/mail/sendmail.cf"
/sbin/chkconfig --add milter
%preun
if [ $1 = 0 ]; then
/sbin/chkconfig --del milter
fi
%endif
%clean
rm -rf $RPM_BUILD_ROOT
%files -f INSTALLED_FILES
%defattr(-,root,root)
%doc README NEWS TODO CREDITS sample.py
/etc/logrotate.d/milter
/etc/cron.daily/milter
%ifos aix4.1
%defattr(-,smmsp,mail)
%else
/etc/rc.d/init.d/milter
%defattr(-,mail,mail)
%endif
%dir /var/log/milter
%dir /var/run/milter
%dir /var/log/milter/save
%config /var/log/milter/start.sh
%config /var/log/milter/bms.py
%config /var/log/milter/strike3.txt
%config /var/log/milter/softfail.txt
%config(noreplace) /etc/mail/pymilter.cfg
/usr/share/sendmail-cf/hack/rhsbl.m4
%changelog
* Mon Jun 06 2005 Stuart Gathman <stuart@bmsi.com> 0.8.0-3
- properly log pydspam exceptions
* Sat Jun 04 2005 Stuart Gathman <stuart@bmsi.com> 0.8.0-2
- Include default softfail, strike3 templates
* Wed May 25 2005 Stuart Gathman <stuart@bmsi.com> 0.8.0-1
- Move Milter module to subpackage.
- DSN support for Three strikes rule and SPF SOFTFAIL
- Move /*mime*/ and dynip to Milter subpackage
- Fix SPF unknown mechanism list not cleared
- Make banned extensions configurable.
- Option to scan zipfiles for bad extensions.
* Tue Feb 08 2005 Stuart Gathman <stuart@bmsi.com> 0.7.3-1.EL3
- Support EL3 and Python2.4 (some scanning/defang support broken)
* Mon Aug 30 2004 Stuart Gathman <stuart@bmsi.com> 0.7.2-1
- Fix various SPF bugs
- Recognize dynamic PTR names, and don't count them as authentication.
- Three strikes and yer out rule.
- Block softfail by default unless valid PTR or HELO
- Return unknown for null mechanism
- Return unknown for invalid ip address in mechanism
- Try best guess on HELO also
- Expand setreply for common errors
- make rhsbl.m4 hack available for sendmail.mc
* Sun Aug 22 2004 Stuart Gathman <stuart@bmsi.com> 0.7.1-1
- Handle modifying mislabeled multipart messages without an exception
- Support setbacklog, setmlreply
- allow multi-recipient CBV
- return TEMPFAIL for SPF softfail
* Fri Jul 23 2004 Stuart Gathman <stuart@bmsi.com> 0.7.0-1
- SPF check hello name
- Move pythonsock to /var/run/milter
- Move milter.cfg to /etc/mail/pymilter.cfg
- Check M$ style XML CID records by converting to SPF
- Recognize, but never match ip6 until we properly support it.
- Option to reject when no PTR and no SPF
* Fri Apr 09 2004 Stuart Gathman <stuart@bmsi.com> 0.6.9-1
- Validate spf.py against test suite, and add Received-SPF support to spf.py
- Support best_guess for SPF
- Reject numeric hello names
- Preserve case of local part in sender
- Make libmilter timeout a config option
- Fix setup.py to work with python < 2.2.3
* Tue Apr 06 2004 Stuart Gathman <stuart@bmsi.com> 0.6.8-3
- Reject invalid SRS immediately for benefit of callback verifiers
- Fix include bug in spf.py
* Tue Apr 06 2004 Stuart Gathman <stuart@bmsi.com> 0.6.8-2
- Bug in check_header
* Mon Apr 05 2004 Stuart Gathman <stuart@bmsi.com> 0.6.8-1
- Don't report spoofed unless rcpt looks like SRS
- Check for bounce with multiple rcpts
- Make dspam see Received-SPF headers
- Make sysv init work with RH9
* Thu Mar 25 2004 Stuart Gathman <stuart@bmsi.com> 0.6.7-3
- Forgot to make spf_reject_neutral global in bms.py
* Wed Mar 24 2004 Stuart Gathman <stuart@bmsi.com> 0.6.7-2
- Defang message/rfc822 content_type with boundary
- Support SPF delegation
- Reject neutral SPF result for selected domains
* Tue Mar 23 2004 Stuart Gathman <stuart@bmsi.com> 0.6.7-1
- SRS forgery check. Detect thread resource starvation.
- Properly remove local socket with explicit type.
- Decode obfuscated subject headers.
* Wed Mar 11 2004 Stuart Gathman <stuart@bmsi.com> 0.6.6-2
- init script bug with python2.3
* Wed Mar 10 2004 Stuart Gathman <stuart@bmsi.com> 0.6.6-1
- SPF checking, hello blacklist
* Mon Mar 08 2004 Stuart Gathman <stuart@bmsi.com> 0.6.5-2
- memory leak in envfrom and envrcpt
* Mon Mar 01 2004 Stuart Gathman <stuart@bmsi.com> 0.6.5-1
- progress notification
- memory leak in connect
- trusted relay
* Thu Feb 19 2004 Stuart Gathman <stuart@bmsi.com> 0.6.4-2
- smart alias wildcard patch, compile for sendmail-8.12
* Thu Dec 04 2003 Stuart Gathman <stuart@bmsi.com> 0.6.4-1
- many fixes for dspam support
* Wed Oct 22 2003 Stuart Gathman <stuart@bmsi.com> 0.6.3
- dspam SCREEN feature
- streamline dspam false positive handling
* Mon Sep 01 2003 Stuart Gathman <stuart@bmsi.com> 0.6.1
- Full dspam support added
* Mon Aug 26 2003 Stuart Gathman <stuart@bmsi.com>
- Use New email module
* Fri Jun 27 2003 Stuart Gathman <stuart@bmsi.com>
- Add dspam module
-1627
View File
File diff suppressed because it is too large Load Diff
-540
View File
@@ -1,540 +0,0 @@
# $Log$
# Revision 1.6 2009/06/09 03:13:13 customdesigned
# More doxygen docs.
#
# Revision 1.5 2005/07/20 14:49:43 customdesigned
# Handle corrupt and empty ZIP files.
#
# Revision 1.4 2005/06/17 01:49:39 customdesigned
# Handle zip within zip.
#
# Revision 1.3 2005/06/02 15:00:17 customdesigned
# Configure banned extensions. Scan zipfile option with test case.
#
# Revision 1.2 2005/06/02 04:18:55 customdesigned
# Update copyright notices after reading article on /.
#
# Revision 1.1.1.4 2005/05/31 18:23:49 customdesigned
# Development changes since 0.7.2
#
# Revision 1.62 2005/02/14 22:31:17 stuart
# _parseparam replacement not needed for python2.4
#
# Revision 1.61 2005/02/12 02:11:11 stuart
# Pass unit tests with python2.4.
#
# Revision 1.60 2005/02/11 18:34:14 stuart
# Handle garbage after quote in boundary.
#
# Revision 1.59 2005/02/10 01:10:59 stuart
# Fixed MimeMessage.ismodified()
#
# Revision 1.58 2005/02/10 00:56:49 stuart
# Runs with python2.4. Defang not working correctly - more work needed.
#
# Revision 1.57 2004/11/20 16:37:52 stuart
# fix regex for splitting header and body
#
# Revision 1.56 2004/11/09 20:33:51 stuart
# Recognize more dynamic PTR variations.
#
# Revision 1.55 2004/10/06 21:39:20 stuart
# Handle message attachments with boundary errors by not parsing them
# until needed.
#
# Revision 1.54 2004/08/18 01:59:46 stuart
# Handle mislabeled multipart messages
#
# Revision 1.53 2004/04/24 22:53:20 stuart
# Rename some local variables to avoid shadowing builtins
#
# Revision 1.52 2004/04/24 22:47:13 stuart
# Convert header values to str
#
# Revision 1.51 2004/03/25 03:19:10 stuart
# Correctly defang rfc822 attachments when boundary specified with
# content-type message/rfc822.
#
# Revision 1.50 2003/10/15 22:01:00 stuart
# Test for and work around email bug with encoded filenames.
#
# Revision 1.49 2003/09/04 18:48:13 stuart
# Support python-2.2.3
#
# Revision 1.48 2003/09/02 00:27:27 stuart
# Should have full milter based dspam support working
#
# Revision 1.47 2003/08/26 06:08:18 stuart
# Use new python boolean since we now require 2.2.2
#
# Revision 1.46 2003/08/26 05:01:38 stuart
# Release 0.6.0
#
# Revision 1.45 2003/08/26 04:01:24 stuart
# Use new email module for parsing mail. Still need mime module to
# provide various bug fixes to email module, and maintain some compatibility
# with old milter code.
#
## @package mime
# This module provides a "defang" function to replace naughty attachments.
#
# We also provide workarounds for bugs in the email module that comes
# with python. The "bugs" fixed mostly come up only with malformed
# messages - but that is what you have when dealing with spam.
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001,2002,2003,2004,2005 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
import StringIO
import socket
import Milter
import zipfile
import email
import email.Message
from email.Message import Message
from email.Generator import Generator
from email.Utils import quote
from email import Utils
from email.Parser import Parser
from email import Errors
from types import ListType,StringType
## Return a list of filenames in a zip file.
# Embedded zip files are recursively expanded.
def zipnames(txt):
fp = StringIO.StringIO(txt)
zipf = zipfile.ZipFile(fp,'r')
names = []
for nm in zipf.namelist():
names.append(('zipname',nm))
if nm.lower().endswith('.zip'):
names += zipnames(zipf.read(nm))
return names
## Fix multipart handling in email.Generator.
#
class MimeGenerator(Generator):
def _dispatch(self, msg):
# Get the Content-Type: for the message, then try to dispatch to
# self._handle_<maintype>_<subtype>(). If there's no handler for the
# full MIME type, then dispatch to self._handle_<maintype>(). If
# that's missing too, then dispatch to self._writeBody().
main = msg.get_content_maintype()
if msg.is_multipart() and main.lower() != 'multipart':
self._handle_multipart(msg)
else:
Generator._dispatch(self,msg)
def unquote(s):
"""Remove quotes from a string."""
if len(s) > 1:
if s.startswith('"'):
if s.endswith('"'):
s = s[1:-1]
else: # remove garbage after trailing quote
try: s = s[1:s[1:].index('"')+1]
except:
return s
return s.replace('\\\\', '\\').replace('\\"', '"')
if s.startswith('<') and s.endswith('>'):
return s[1:-1]
return s
from types import TupleType
def _unquotevalue(value):
if isinstance(value, TupleType):
return value[0], value[1], unquote(value[2])
else:
return unquote(value)
#email.Message._unquotevalue = _unquotevalue
from email.Message import _parseparam
## Enhance email.Message
#
# Tracks modifications to headers of body or any part independently.
class MimeMessage(Message):
"""Version of email.Message.Message compatible with old mime module
"""
def __init__(self,fp=None,seekable=1):
Message.__init__(self)
self.headerchange = None
self.submsg = None
self.modified = False
## @var headerchange
# Provide a headerchange event for integration with Milter.
# The headerchange attribute can be assigned a function to be called when
# changing headers. The signature is:
# headerchange(msg,name,value) -> None
def get_param(self, param, failobj=None, header='content-type', unquote=True):
val = Message.get_param(self,param,failobj,header,unquote)
if val != failobj and param == 'boundary' and unquote:
# unquote boundaries an extra time, test case testDefang5
return _unquotevalue(val)
return val
getfilename = Message.get_filename
ismultipart = Message.is_multipart
getheaders = Message.get_all
gettype = Message.get_content_type
getparam = Message.get_param
def getparams(self): return self.get_params([])
def getname(self):
return self.get_param('name')
def getnames(self,scan_zip=False):
"""Return a list of (attr,name) pairs of attributes that IE might
interpret as a name - and hence decide to execute this message."""
names = []
for attr,val in self._get_params_preserve([],'content-type'):
if isinstance(val, TupleType):
# It's an RFC 2231 encoded parameter
newvalue = _unquotevalue(val)
if val[0]:
val = unicode(newvalue[2], newvalue[0])
else:
val = unicode(newvalue[2])
else:
val = _unquotevalue(val.strip())
names.append((attr,val))
names += [("filename",self.get_filename())]
if scan_zip:
for key,name in tuple(names): # copy by converting to tuple
if name and name.lower().endswith('.zip'):
txt = self.get_payload(decode=True)
if txt.strip():
names += zipnames(txt)
return names
def ismodified(self):
"True if this message or a subpart has been modified."
if not self.is_multipart():
if isinstance(self.submsg,Message):
return self.submsg.ismodified()
return self.modified
if self.modified: return True
for i in self.get_payload():
if i.ismodified(): return True
return False
def dump(self,file,unixfrom=False):
"Write this message (and all subparts) to a file"
g = MimeGenerator(file)
g.flatten(self,unixfrom=unixfrom)
def as_string(self, unixfrom=False):
"Return the entire formatted message as a string."
fp = StringIO.StringIO()
self.dump(fp,unixfrom=unixfrom)
return fp.getvalue()
def getencoding(self):
return self.get('content-transfer-encoding',None)
# Decode body to stream according to transfer encoding, return encoding name
def decode(self,filt):
try:
filt.write(self.get_payload(decode=True))
except:
pass
return self.getencoding()
def get_payload_decoded(self):
return self.get_payload(decode=True)
def __setitem__(self, name, value):
rc = Message.__setitem__(self,name,value)
self.modified = True
if self.headerchange: self.headerchange(self,name,str(value))
return rc
def __delitem__(self, name):
if self.headerchange: self.headerchange(self,name,None)
rc = Message.__delitem__(self,name)
self.modified = True
return rc
def get_payload(self,i=None,decode=False):
msg = self.submsg
if isinstance(msg,Message) and msg.ismodified():
self.set_payload([msg])
return Message.get_payload(self,i,decode)
def set_payload(self, val, charset=None):
self.modified = True
try:
val.seek(0)
val = val.read()
except: pass
Message.set_payload(self,val,charset)
self.submsg = None
def get_submsg(self):
t = self.get_content_type().lower()
if t == 'message/rfc822' or t.startswith('multipart/'):
if not self.submsg:
txt = self.get_payload()
if type(txt) == str:
txt = self.get_payload(decode=True)
self.submsg = email.message_from_string(txt,MimeMessage)
for part in self.submsg.walk():
part.modified = False
else:
self.submsg = txt[0]
return self.submsg
return None
def message_from_file(fp):
msg = email.message_from_file(fp,MimeMessage)
for part in msg.walk():
part.modified = False
assert not msg.ismodified()
return msg
extlist = ''.join("""
ade,adp,asd,asx,asp,bas,bat,chm,cmd,com,cpl,crt,dll,exe,hlp,hta,inf,ins,isp,js,
jse,lnk,mdb,mde,msc,msi,msp,mst,ocx,pcd,pif,reg,scr,sct,shs,url,vb,vbe,vbs,wsc,
wsf,wsh
""".split())
bad_extensions = map(lambda x:'.' + x,extlist.split(','))
def check_ext(name):
"Check a name for dangerous Winblows extensions."
if not name: return name
lname = name.lower()
for ext in bad_extensions:
if lname.endswith(ext): return name
return None
virus_msg = """This message appeared to contain a virus.
It was originally named '%s', and has been removed.
A copy of your original message was saved as '%s:%s'.
See your administrator.
"""
def check_name(msg,savname=None,ckname=check_ext,scan_zip=False):
"Replace attachment with a warning if its name is suspicious."
try:
for key,name in msg.getnames(scan_zip):
badname = ckname(name)
if badname:
if key == 'zipname':
badname = msg.get_filename()
break
else:
return Milter.CONTINUE
except zipfile.BadZipfile:
# a ZIP that is not a zip is very suspicious
badname = msg.get_filename()
hostname = socket.gethostname()
msg.set_payload(virus_msg % (badname,hostname,savname))
del msg["content-type"]
del msg["content-disposition"]
del msg["content-transfer-encoding"]
name = "WARNING.TXT"
msg["Content-Type"] = "text/plain; name="+name
return Milter.CONTINUE
import email.Iterators
def check_attachments(msg,check):
"""Scan attachments.
msg MimeMessage
check function(MimeMessage): int
Return CONTINUE, REJECT, ACCEPT
"""
if msg.is_multipart():
for i in msg.get_payload():
rc = check_attachments(i,check)
if rc != Milter.CONTINUE: return rc
return Milter.CONTINUE
return check(msg)
# save call context for Python without nested_scopes
class _defang:
def __init__(self,scan_html=True):
self.scan_html = scan_html
def _chk_name(self,msg):
rc = check_name(msg,self._savname,self._check,self.scan_zip)
if self.scan_html:
check_html(msg,self._savname) # remove scripts from HTML
if self.scan_rfc822:
msg = msg.get_submsg()
if isinstance(msg,Message):
return check_attachments(msg,self._chk_name)
return rc
def __call__(self,msg,savname=None,check=check_ext,scan_rfc822=True,
scan_zip=False):
"""Compatible entry point.
Replace all attachments with dangerous names."""
self._savname = savname
self._check = check
self.scan_rfc822 = scan_rfc822
self.scan_zip = scan_zip
check_attachments(msg,self._chk_name)
if msg.ismodified():
return True
return False
# emulate old defang function
defang = _defang()
import sgmllib
import re
declname = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9]*\s*')
declstringlit = re.compile(r'(\'[^\']*\'|"[^"]*")\s*')
class SGMLFilter(sgmllib.SGMLParser):
"""Parse HTML and pass through all constructs unchanged. It is intended for
derived classes to implement exceptional processing for selected cases.
"""
def __init__(self,out):
sgmllib.SGMLParser.__init__(self)
self.out = out
def handle_comment(self,comment):
self.out.write("<!--%s-->" % comment)
def unknown_starttag(self,tag,attr):
if hasattr(self,"get_starttag_text"):
self.out.write(self.get_starttag_text())
else:
self.out.write("<%s" % tag)
for (key,val) in attr:
self.out.write(' %s="%s"' % (key,val))
self.out.write('>')
def handle_data(self,data):
self.out.write(data)
def handle_entityref(self,ref):
self.out.write("&%s;" % ref)
def handle_charref(self,ref):
self.out.write("&#%s;" % ref)
def unknown_endtag(self,tag):
self.out.write("</%s>" % tag)
def handle_special(self,data):
self.out.write("<!%s>" % data)
def write(self,buf):
"Act like a writer. Why doesn't SGMLParser do this by default?"
self.feed(buf)
# Python-2.1 sgmllib rejects illegal declarations. Since various Microsoft
# products accept and output them, we need to pass them through -
# at least until we discover that MS will execute them.
# sgmlop-1.1 will not use this method, but calls handle_special to
# do what we want.
def parse_declaration(self, i):
rawdata = self.rawdata
n = len(rawdata)
j = i + 2
while j < n:
c = rawdata[j]
if c == ">":
# end of declaration syntax
self.handle_special(rawdata[i+2:j])
return j + 1
if c in "\"'":
m = declstringlit.match(rawdata, j)
if not m:
# incomplete or an error?
return -1
j = m.end()
elif c in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
m = declname.match(rawdata, j)
if not m:
# incomplete or an error?
return -1
j = m.end()
else:
j += 1
# end of buffer between tokens
return -1
class HTMLScriptFilter(SGMLFilter):
"Remove scripts from an HTML document."
def __init__(self,out):
SGMLFilter.__init__(self,out)
self.ignoring = 0
self.modified = False
self.msg = "<!-- WARNING: embedded script removed -->"
def start_script(self,unused):
self.ignoring += 1
self.modified = True
self.out.write(self.msg)
def end_script(self):
self.ignoring -= 1
def handle_data(self,data):
if not self.ignoring: SGMLFilter.handle_data(self,data)
def handle_comment(self,comment):
if not self.ignoring: SGMLFilter.handle_comment(self,comment)
def check_html(msg,savname=None):
"Remove scripts from HTML attachments."
msgtype = msg.get_content_type().lower()
# check for more MSIE braindamage
if msgtype == 'application/octet-stream':
for (attr,name) in msg.getnames():
if name and name.lower().endswith(".htm"):
msgtype = 'text/html'
if msgtype == 'text/html':
out = StringIO.StringIO()
htmlfilter = HTMLScriptFilter(out)
try:
htmlfilter.write(msg.get_payload(decode=True))
htmlfilter.close()
#except sgmllib.SGMLParseError:
except:
#mimetools.copyliteral(msg.get_payload(),open('debug.out','w')
htmlfilter.close()
hostname = socket.gethostname()
msg.set_payload(
"An HTML attachment could not be parsed. The original is saved as '%s:%s'"
% (hostname,savname))
del msg["content-type"]
del msg["content-disposition"]
del msg["content-transfer-encoding"]
name = "WARNING.TXT"
msg["Content-Type"] = "text/plain; name="+name
return Milter.CONTINUE
if htmlfilter.modified:
msg.set_payload(out) # remove embedded scripts
del msg["content-transfer-encoding"]
email.Encoders.encode_quopri(msg)
return Milter.CONTINUE
if __name__ == '__main__':
import sys
def _list_attach(msg):
t = msg.get_content_type()
p = msg.get_payload(decode=True)
print msg.get_filename(),msg.get_content_type(),type(p)
msg = msg.get_submsg()
if isinstance(msg,Message):
return check_attachments(msg,_list_attach)
return Milter.CONTINUE
for fname in sys.argv[1:]:
fp = open(fname)
msg = message_from_file(fp)
email.Iterators._structure(msg)
check_attachments(msg,_list_attach)
-135
View File
@@ -1,135 +0,0 @@
%define __python python2.6
%define libdir %{_libdir}/pymilter
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
%define pythonbase python26
Summary: Python interface to sendmail milter API
Name: %{pythonbase}-pymilter
Version: 0.9.4
Release: 1%{dist}
Source: http://downloads.sourceforge.net/pymilter/pymilter-%{version}.tar.gz
License: GPLv2+
Group: Development/Libraries
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
Url: http://www.bmsi.com/python/milter.html
Requires: %{pythonbase}, sendmail >= 8.13
# Need python2.4 specific pydns, not the version for system python
Requires: %{pythonbase}-pydns
# Needed for callbacks, not a core function but highly useful for milters
BuildRequires: ed, %{pythonbase}-devel, sendmail-devel >= 8.13
%description
This is a python extension module to enable python scripts to
attach to sendmail's libmilter functionality. Additional python
modules provide for navigating and modifying MIME parts, sending
DSNs, and doing CBV.
%prep
%setup -q -n pymilter-%{version}
%build
env CFLAGS="$RPM_OPT_FLAGS" %{__python} setup.py build
%install
rm -rf $RPM_BUILD_ROOT
%{__python} setup.py install --root=$RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/milter
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/milter
mkdir -p $RPM_BUILD_ROOT%{libdir}
cp start.sh $RPM_BUILD_ROOT%{libdir}
ed $RPM_BUILD_ROOT%{libdir}/start.sh <<'EOF'
/^datadir=/
c
datadir="%{_localstatedir}/log/milter"
.
/^piddir=/
c
piddir="%{_localstatedir}/run/milter"
.
/^libdir=/
c
libdir="%{libdir}"
.
/^python=/
c
python="%{__python}"
.
w
q
EOF
chmod a+x $RPM_BUILD_ROOT%{libdir}/start.sh
# start.sh is used by spfmilter, srsmilter, and milter, and could be used by
# other milters using pymilter.
%files
%defattr(-,root,root,-)
%doc README ChangeLog NEWS TODO CREDITS sample.py milter-template.py
%{python_sitearch}/*
%{libdir}
%dir %attr(0755,mail,mail) %{_localstatedir}/run/milter
%dir %attr(0755,mail,mail) %{_localstatedir}/log/milter
%clean
rm -rf $RPM_BUILD_ROOT
%changelog
* Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.4-1
- Handle IP6 in Milter.utils.iniplist()
- python-2.6
* Thu Jul 02 2009 Stuart Gathman <stuart@bmsi.com> 0.9.3-1
- Handle source route in Milter.utils.parse_addr()
- Fix default arg in chgfrom.
- Disable negotiate callback for libmilter < 8.14.3 (1,0,1)
* Tue Jun 02 2009 Stuart Gathman <stuart@bmsi.com> 0.9.2-3
- Change result of @noreply callbacks to NOREPLY when so negotiated.
* Tue Jun 02 2009 Stuart Gathman <stuart@bmsi.com> 0.9.2-2
- Cache callback negotiation
* Thu May 28 2009 Stuart Gathman <stuart@bmsi.com> 0.9.2-1
- Add new callback support: data,negotiate,unknown
- Auto-negotiate protocol steps
* Thu Feb 05 2009 Stuart Gathman <stuart@bmsi.com> 0.9.1-1
- Fix missing address of optional param to addrcpt
* Wed Jan 07 2009 Stuart Gathman <stuart@bmsi.com> 0.9.0-4
- Stop using INSTALLED_FILES to make Fedora happy
- Remove config flag from start.sh glue
- Own /var/log/milter
- Use _localstatedir
* Wed Jan 07 2009 Stuart Gathman <stuart@bmsi.com> 0.9.0-2
- Changes to meet Fedora standards
* Mon Nov 24 2008 Stuart Gathman <stuart@bmsi.com> 0.9.0-1
- Split pymilter into its own CVS module
- Support chgfrom and addrcpt_par
- Support NS records in Milter.dns
* Mon Aug 25 2008 Stuart Gathman <stuart@bmsi.com> 0.8.10-2
- /var/run/milter directory must be owned by mail
* Mon Aug 25 2008 Stuart Gathman <stuart@bmsi.com> 0.8.10-1
- improved parsing into email and fullname (still 2 self test failures)
- implement no-DSN CBV, reduce full DSNs
* Mon Sep 24 2007 Stuart Gathman <stuart@bmsi.com> 0.8.9-1
- Use ifarch hack to build milter and milter-spf packages as noarch
- Remove spf dependency from dsn.py, add dns.py
* Fri Jan 05 2007 Stuart Gathman <stuart@bmsi.com> 0.8.8-1
- move AddrCache, parse_addr, iniplist to Milter package
- move parse_header to Milter.utils
- fix plock for missing source and can't change owner/group
- split out pymilter and pymilter-spf packages
- move milter apps to /usr/lib/pymilter
* Sat Nov 04 2006 Stuart Gathman <stuart@bmsi.com> 0.8.7-1
- SPF moved to pyspf RPM
* Tue May 23 2006 Stuart Gathman <stuart@bmsi.com> 0.8.6-2
- Support CBV timeout
-181
View File
@@ -1,181 +0,0 @@
# A simple milter.
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001 Business Management Systems, Inc.
# This code is under GPL. See COPYING for details.
import sys
import os
import StringIO
import rfc822
import mime
import Milter
import tempfile
from time import strftime
#import syslog
#syslog.openlog('milter')
class sampleMilter(Milter.Milter):
"Milter to replace attachments poisonous to Windows with a WARNING message."
def log(self,*msg):
print "%s [%d]" % (strftime('%Y%b%d %H:%M:%S'),self.id),
for i in msg: print i,
print
def __init__(self):
self.tempname = None
self.mailfrom = None
self.fp = None
self.bodysize = 0
self.id = Milter.uniqueID()
# multiple messages can be received on a single connection
# envfrom (MAIL FROM in the SMTP protocol) seems to mark the start
# of each message.
def envfrom(self,f,*str):
self.log("mail from",f,str)
self.fp = StringIO.StringIO()
self.tempname = None
self.mailfrom = f
self.bodysize = 0
return Milter.CONTINUE
def envrcpt(self,to,*str):
# mail to MAILER-DAEMON is generally spam that bounced
if to.startswith('<MAILER-DAEMON@'):
self.log('DISCARD: RCPT TO:',to,str)
return Milter.DISCARD
self.log("rcpt to",to,str)
return Milter.CONTINUE
def header(self,name,val):
lname = name.lower()
if lname == 'subject':
# even if we wanted the Taiwanese spam, we can't read Chinese
# (delete if you read chinese mail)
if val.startswith('=?big5') or val.startswith('=?ISO-2022-JP'):
self.log('REJECT: %s: %s' % (name,val))
#self.setreply('550','','Go away spammer')
return Milter.REJECT
# check for common spam keywords
if val.find("$$$") >= 0 or val.find("XXX") >= 0 \
or val.find("!!!") >= 0 or val.find("FREE") >= 0:
self.log('REJECT: %s: %s' % (name,val))
#self.setreply('550','','Go away spammer')
return Milter.REJECT
# check for spam that pretends to be legal
lval = val.lower()
if lval.startswith("adv:") or lval.startswith("adv.") \
or lval.find('viagra') >= 0:
self.log('REJECT: %s: %s' % (name,val))
return Milter.REJECT
# check for invalid message id
if lname == 'message-id' and len(val) < 4:
self.log('REJECT: %s: %s' % (name,val))
#self.setreply('550','','Go away spammer')
return Milter.REJECT
# check for common bulk mailers
if lname == 'x-mailer' and \
val.lower() in ('direct email','calypso','mail bomber'):
self.log('REJECT: %s: %s' % (name,val))
#self.setreply('550','','Go away spammer')
return Milter.REJECT
# log selected headers
if lname in ('subject','x-mailer'):
self.log('%s: %s' % (name,val))
if self.fp:
self.fp.write("%s: %s\n" % (name,val)) # add header to buffer
return Milter.CONTINUE
def eoh(self):
if not self.fp: return Milter.TEMPFAIL # not seen by envfrom
self.fp.write("\n")
self.fp.seek(0)
# copy headers to a temp file for scanning the body
headers = self.fp.getvalue()
self.fp.close()
self.tempname = fname = tempfile.mktemp(".defang")
self.fp = open(fname,"w+b")
self.fp.write(headers) # IOError (e.g. disk full) causes TEMPFAIL
return Milter.CONTINUE
def body(self,chunk): # copy body to temp file
if self.fp:
self.fp.write(chunk) # IOError causes TEMPFAIL in milter
self.bodysize += len(chunk)
return Milter.CONTINUE
def _headerChange(self,msg,name,value):
if value: # add header
self.addheader(name,value)
else: # delete all headers with name
h = msg.getheaders(name)
cnt = len(h)
for i in range(cnt,0,-1):
self.chgheader(name,i-1,'')
def eom(self):
if not self.fp: return Milter.ACCEPT
self.fp.seek(0)
msg = mime.message_from_file(self.fp)
msg.headerchange = self._headerChange
if not mime.defang(msg,self.tempname):
os.remove(self.tempname)
self.tempname = None # prevent re-removal
self.log("eom")
return Milter.ACCEPT # no suspicious attachments
self.log("Temp file:",self.tempname)
self.tempname = None # prevent removal of original message copy
# copy defanged message to a temp file
out = tempfile.TemporaryFile()
try:
msg.dump(out)
out.seek(0)
msg = rfc822.Message(out)
msg.rewindbody()
while 1:
buf = out.read(8192)
if len(buf) == 0: break
self.replacebody(buf) # feed modified message to sendmail
return Milter.ACCEPT # ACCEPT modified message
finally:
out.close()
return Milter.TEMPFAIL
def close(self):
sys.stdout.flush() # make log messages visible
if self.tempname:
os.remove(self.tempname) # remove in case session aborted
if self.fp:
self.fp.close()
return Milter.CONTINUE
def abort(self):
self.log("abort after %d body chars" % self.bodysize)
return Milter.CONTINUE
if __name__ == "__main__":
#tempfile.tempdir = "/var/log/milter"
#socketname = "/var/log/milter/pythonsock"
socketname = os.getenv("HOME") + "/pythonsock"
Milter.factory = sampleMilter
Milter.set_flags(Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS)
print """To use this with sendmail, add the following to sendmail.cf:
O InputMailFilters=pythonfilter
Xpythonfilter, S=local:%s
See the sendmail README for libmilter.
sample milter startup""" % socketname
sys.stdout.flush()
Milter.runmilter("pythonfilter",socketname,240)
print "sample milter shutdown"
-5
View File
@@ -1,5 +0,0 @@
[bdist_rpm]
python=python2.6
doc_files=README NEWS TODO
packager=Stuart D. Gathman <stuart@bmsi.com>
release=1
-56
View File
@@ -1,56 +0,0 @@
import os
import sys
from distutils.core import setup, Extension
# FIXME: on some versions of sendmail, smutil is renamed to sm.
# On slackware and debian, leave it out entirely. It depends
# on how libmilter was built by the sendmail package.
#libs = ["milter", "smutil"]
libs = ["milter"]
libdirs = ["/usr/lib/libmilter"] # needed for Debian
# patch distutils if it can't cope with the "classifiers" or
# "download_url" keywords
if sys.version < '2.2.3':
from distutils.dist import DistributionMetadata
DistributionMetadata.classifiers = None
DistributionMetadata.download_url = None
# NOTE: importing Milter to obtain version fails when milter.so not built
setup(name = "pymilter", version = '0.9.4',
description="Python interface to sendmail milter API",
long_description="""\
This is a python extension module to enable python scripts to
attach to sendmail's libmilter functionality. Additional python
modules provide for navigating and modifying MIME parts, and
sending DSNs or doing CBVs.
""",
author="Jim Niemira",
author_email="urmane@urmane.org",
maintainer="Stuart D. Gathman",
maintainer_email="stuart@bmsi.com",
license="GPL",
url="http://www.bmsi.com/python/milter.html",
py_modules=["mime"],
packages = ['Milter'],
ext_modules=[
Extension("milter", ["miltermodule.c"],
library_dirs=libdirs,
libraries=libs,
# set MAX_ML_REPLY to 1 for sendmail < 8.13
define_macros = [ ('MAX_ML_REPLY',32) ]
),
],
keywords = ['sendmail','milter'],
classifiers = [
'Development Status :: 5 - Production/Stable',
'Environment :: No Input/Output (Daemon)',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Natural Language :: English',
'Operating System :: POSIX',
'Programming Language :: Python',
'Topic :: Communications :: Email :: Mail Transport Agents',
'Topic :: Communications :: Email :: Filters'
]
)
-16
View File
@@ -1,16 +0,0 @@
#!/bin/sh
appname="$1"
script="${2:-${appname}}"
datadir="/var/log/milter"
piddir="/var/run/milter"
libdir="/usr/lib/pymilter"
python="python2.4"
exec >>${datadir}/${appname}.log 2>&1
if test -s ${datadir}/${script}.py; then
cd ${datadir} # use version in log dir if it exists for debugging
else
cd ${libdir}
fi
${python} ${script}.py &
echo $! >${piddir}/${appname}.pid
-17
View File
@@ -1,17 +0,0 @@
import unittest
import testmime
import testsample
import testutils
import os
def suite():
s = unittest.TestSuite()
s.addTest(testmime.suite())
s.addTest(testsample.suite())
s.addTest(testutils.suite())
return s
if __name__ == '__main__':
try: os.remove('test/milter.log')
except: pass
unittest.TextTestRunner().run(suite())
-44
View File
@@ -1,44 +0,0 @@
Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.12.1/8.12.1) with ESMTP id g218JVhw028058
for <stuart@bmsi.com>; Fri, 1 Mar 2002 03:19:31 -0500
Received: from apol ([210.201.89.183])
by www.bmsi.com (8.12.1/8.12.1) with SMTP id g218JQkY030600
for <stuart@bmsi.com>; Fri, 1 Mar 2002 03:19:27 -0500
Date: Fri, 1 Mar 2002 03:19:26 -0500
Received: from tcts1
by yahoo.com with SMTP id KAqmIGSKwGQHv6LYDEOUUS;
Fri, 01 Mar 2002 16:18:13 +0800
Message-ID: <VPvce@seed.net.tw>
From: 大中華國際留學教育中心@www.bmsi.com
To:
Subject: 8PxZzvJbH8VtozQ3rC01SOwm =?big5?Q?=A6p=AAG=A7A=B7Q=AFd=BE=C7=AA=BA=B8=DC=A1K?= BwnqwcNylfNuCIM3RG0mCx
MIME-Version: 1.0
Content-Type: multipart/related;
type="multipart/alternative";
boundary="----=_NextPart_kpWBTLcCozjeV8sH5gRbJoOo3aJ"
X-Mailer: foOkz11rguOMzavzZaDTw
X-Priority: 3
X-MSMail-Priority: Normal
This is a multi-part message in MIME format.
------=_NextPart_kpWBTLcCozjeV8sH5gRbJoOo3aJ
Content-Type: multipart/alternative;
boundary="----=_NextPart_kpWBTLcCozjeV8sH5gRbJoOo3aJAA"
------=_NextPart_kpWBTLcCozjeV8sH5gRbJoOo3aJAA
Content-Type: text/html;
charset="big5"
Content-Transfer-Encoding: base64
PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiDQp4bWxuczpvPSJ1
DQoNCjwvYm9keT4NCg0KPC9odG1sPg==
------=_NextPart_kpWBTLcCozjeV8sH5gRbJoOo3aJAA--
------=_NextPart_kpWBTLcCozjeV8sH5gRbJoOo3aJ--
-86
View File
@@ -1,86 +0,0 @@
Received: from localhost (localhost)
by bmsaix.bmsi.com (8.12.9/8.12.6) id h62JqW5p030912;
Wed, 2 Jul 2003 15:52:32 -0400
Date: Wed, 2 Jul 2003 15:52:32 -0400
From: Mail Delivery Subsystem <MAILER-DAEMON@bmsaix.bmsi.com>
Message-Id: <200307021952.h62JqW5p030912@bmsaix.bmsi.com>
To: <annagh000@bellsouth.net>
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="h62JqW5p030912.1057175552/bmsaix.bmsi.com"
Subject: Returned mail: see transcript for details
Auto-Submitted: auto-generated (failure)
This is a MIME-encapsulated message
--h62JqW5p030912.1057175552/bmsaix.bmsi.com
The original message was received at Fri, 27 Jun 2003 15:28:03 -0400
from IDENT:ndcHoBWTR9Bf/rEFYJRejRoPTaRDgSCl@bmsweb.bmsi.com [192.168.9.81]
----- The following addresses had permanent fatal errors -----
makurat@erols.com
(reason: 452 4.3.0 Filter failure)
(expanded from: <makurat@bmsi.com>)
----- Transcript of session follows -----
... while talking to [192.168.9.81]:
>>> DATA
<<< 452 4.3.0 Filter failure
makurat@erols.com... Deferred: 452 4.3.0 Filter failure
Message could not be delivered for 5 days
Message will be deleted from queue
--h62JqW5p030912.1057175552/bmsaix.bmsi.com
Content-Type: message/delivery-status
Reporting-MTA: dns; bmsaix.bmsi.com
Arrival-Date: Fri, 27 Jun 2003 15:28:03 -0400
Final-Recipient: RFC822; makurat@bmsi.com
X-Actual-Recipient: RFC822; makurat@erols.com
Action: failed
Status: 4.4.7
Remote-MTA: DNS; [192.168.9.81]
Diagnostic-Code: SMTP; 452 4.3.0 Filter failure
Last-Attempt-Date: Wed, 2 Jul 2003 15:52:32 -0400
--h62JqW5p030912.1057175552/bmsaix.bmsi.com
Content-Type: message/rfc822
Return-Path: <annagh000@bellsouth.net>
Received: from spidey.bmsi.com (IDENT:ndcHoBWTR9Bf/rEFYJRejRoPTaRDgSCl@bmsweb.bmsi.com [192.168.9.81])
by bmsaix.bmsi.com (8.12.9/8.12.6) with ESMTP id h5RJS3Vi042394
for <makurat@bmsi.com>; Fri, 27 Jun 2003 15:28:03 -0400
Received: from sunlong.com ([202.105.130.54])
by spidey.bmsi.com (8.11.6/8.11.6) with SMTP id h5RJS2o03547
for <makurat@bmsi.com>; Fri, 27 Jun 2003 15:28:02 -0400
Message-Id: <200306271928.h5RJS2o03547@spidey.bmsi.com>
Received: from mx06.mail.bellsouth.net([218.104.6.10]) by sunlong.com(JetMail 2.5.3.0)
with SMTP id jma73efca64b; Fri, 27 Jun 2003 19:23:44 -0000
To: <Undisclosed.Recipients@spidey.bmsi.com>
From: "Stacy McClain" <annagh000@bellsouth.net>
Subject: Defy Gravity in 15 minutes
Date: Sat, 28 Jun 2003 03:34:15 -1600
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_646C_00001D33.00000BE1"
Reply-To: annagh000@bellsouth.net
X-AntiAbuse: : This header was added to track abuse, please include it with any abuse report
X-AntiAbuse: Primary Hostname - 210.222.2.13
X-Originating-Host: : 210.188.201.159
------=_NextPart_000_646C_00001D33.00000BE1
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: base64
PGh0bWw+DQoNCjxoZWFkPg0KPHRpdGxlPjwvdGl0bGU+DQo8L2hlYWQ+DQoNCjxib2R5Pg0KDQo8cD4NCjxhIGhyZWY9Imh0dHA6Ly9zcmQueWFob28uY29tL2Ryc3QvNzQxMjQzMjM1LypodHRwOi93d3cuZnJ5YmVlLmNvbS8iPg0KPGltZyBzcmM9Imh0dHA6Ly8yMTAuMTUuNTEuOTUvcGljX3dlbGwvZ3YyLmdpZiIgYm9yZGVyPSIwIiB3aWR0aD0iNDA1IiBoZWlnaHQ9IjI3MCI+PC9hPjwvcD4NCg0KPHA+DQo8YSBocmVmPSJodHRwOi8vc3JkLnlhaG9vLmNvbS9kcnN0Lzc0MTQxNjg4Mjc3NzcvKmh0dHA6L3d3dy5mcnliZWUuY29tL3BhZ2UvYS5odG1sIj4NCjxpbWcgc3JjPSJodHRwOi8vY2xpY2suanVzdGZvcnlvdS1tYWlsLmNvbS9pbWFnZXMvRjEuZ2lmIiB3aWR0aD0iNDEwIiBoZWlnaHQ9IjE0IiBib3JkZXI9IjAiPjwvYT48L3A+DQoNCjxwIGFsaWduPSJsZWZ0Ij4NCiZuYnNwOzwvcD4NCg0KPHAgc3R5bGU9Im1hcmdpbi10b3A6IDA7IG1hcmdpbi1ib3R0b206IDAiPg0KJm5ic3A7PC9wPg0KDQo8cCBzdHlsZT0ibWFyZ2luLXRvcDogMDsgbWFyZ2luLWJvdHRvbTogMCI+DQombmJzcDs8L3A+DQoNCjxwIHN0eWxlPSJtYXJnaW4tdG9wOiAwOyBtYXJnaW4tYm90dG9tOiAwIj4NCiZuYnNwOzwvcD4NCg0KPHAgc3R5bGU9Im1hcmdpbi10b3A6IDA7IG1hcmdpbi1ib3R0b206IDAiPjxmb250IHNpemU9IjEiPnFhd3NteXp0ciBxYXdzYW9lZHRhZ2ZwdiANCnFhd3N5ZmRhb3FqIHFhd3NjaSBxYXdzY!
212Z3ZrIHFhd3NvaW55d3pkbyBxYXdzbXVxYXdza29jIA0KcWF3c2hobmVkZCBxYXdzZWllbiBxYXdzemlnZ3hucGN2cyBxYXdzd3lkZSBxYXdzeWFwIHFhd3NxamVkeWhxYXdzZmt1bSANCnFhd3NmbSBxYXdzdW11Ym1mYmR3IHFhd3Nkc29ka2xvIHFhd3Nhc2VtayBxYXdzZXdzIHFhd3NxdWRneGVvcWF3c3J6IA0KcWF3c290dSBxYXdzcHplbnJoZW1xYSBxYXdzdXplcmpqcWZxIHFhd3NydWFucyBxYXdzbnBjcGFoZ2pwIHFhd3NxYXdoZHJxYXdzYmFscXNxaiANCnFhd3N5bmggcWF3c2VrIHFhd3N0YmNndGd0IHFhd3N0ZnhzeHd4ICBxYXdzandlcHFhd3NsYmN6ZWRuIHFhd3NzcW1nb3YgDQpxYXdzZ3phdiBxYXdzZ2N2aCBxYXdzd21sYWt1bW5sbiBxYXdzZHpqcW9yeCBxYXdzdGhvbHRmaWxmeHFhd3NpcGJneSANCnFhd3NpbHp5Znd2dnMgIHFhd3NpdmJwdmNiIHFhd3NrZXRpYmtocGRhIHFhd3N6ZmJqYm1yayBxYXdzbWZvZ29ucWF3c2FvIA0KcWF3c21vcXggcWF3c3FkeWVuaCBxYXdzYnMgcWF3c2l5aXBkYWx4IHFhd3N6aXlpbyBxYXdzaWZ6dXFyamltcSANCnFhd3NuayBxYXdza3dhciBxYXdzanNleHNmc2IgcWF3c3RxaWlhY2cgcWF3c2p0YnFobnFlIHFhd3Niam1pcGpxYXdzaHl4anNwbXhuIA0KIHFhd3NqcmJlbnIgcWF3c3p6b3p0ZndydyBxYXdzZ25uaHdjIHFhd3NrdXkgcWF3c3ZwcWF3c25qbmd5eHl1eCBxYXdzd3lvc2EgDQpxYXdzb2lnIHFhd3Nub25rcm5pbWcgcWF3c2NtcGdxemtwcm!
U8L2ZvbnQ+PC9wPg0KDQo8L2JvZHk+DQoNCjwvaHRtbD48L3RpdGxlPg0K
------=_NextPart_000_646C_00001D33.00000BE1--
--h62JqW5p030912.1057175552/bmsaix.bmsi.com--
-85
View File
@@ -1,85 +0,0 @@
Received: from zuul.kastle.com (root@localhost)
by zuul.kastle.com with ESMTP id h7JGdwn27534
for <amy@koger.bmsi.com>; Tue, 19 Aug 2003 12:39:58 -0400 (EDT)
Received: from kastle.com (netgate.kastle.com [172.17.2.8])
by zuul.kastle.com with ESMTP id h7JGdwV27530
for <amy@koger.bmsi.com>; Tue, 19 Aug 2003 12:39:58 -0400 (EDT)
Received: by kastle.com
with XWall v3.27 ;
Tue, 19 Aug 2003 12:45:41 -0400
From: System Administrator <postmaster@kastle.com>
To: "amy@koger.bmsi.com" <amy@koger.bmsi.com>
Subject: Non delivery report: 5.9.5 (Blocked attachment)
Date: Tue, 19 Aug 2003 12:45:41 -0400
X-Mailer: XWall v3.27
Mime-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="_NextPart_1_qmZrHLajoetbkwlTZTViemHPfyb"
This is a multi part message in MIME format.
--_NextPart_1_qmZrHLajoetbkwlTZTViemHPfyb
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Your message
From: amy@koger.bmsi.com
To: lwilliams@kastle.com
Subj: Thank you!
Sent: 2003-08-19 08:51
has encountered a delivery problem.
Reason: Blocked attachment
One of the attachment(s) in the message is blocked.
For security reasons the message was not or not completely delivered to
the recipient.
Additional info:
The blocked attachment is: thank_you.pif
--_NextPart_1_qmZrHLajoetbkwlTZTViemHPfyb
Content-Type: message/xdelivery-status ; name="delivery-status.txt"
Reporting-MTA: dns; kastle.com
Received-From-MTA: dns; zuul.kastle.com
Arrival-Date: Tue, 19 Aug 2003 12:45:41 -0400
Final-Recipient: rfc822; lwilliams@kastle.com
Action: failed
Status: 5.9.5
--_NextPart_1_qmZrHLajoetbkwlTZTViemHPfyb
Content-Type: message/rfc822
Received: from zuul.kastle.com [172.17.2.100]
by kastle.com
with XWall v3.27 ;
Tue, 19 Aug 2003 12:45:41 -0400
Received: from zuul.kastle.com (root@localhost)
by zuul.kastle.com with ESMTP id h7JGduo27526
for <lwilliams@kastle.com>; Tue, 19 Aug 2003 12:39:56 -0400 (EDT)
Received: from 1333AVE2 (wan-vc8f35e.norva3.biz.mindspring.com [216.135.140.174])
by zuul.kastle.com with ESMTP id h7JGdqS27522
for <lwilliams@kastle.com>; Tue, 19 Aug 2003 12:39:53 -0400 (EDT)
Message-Id: <200308191639.h7JGdqS27522@zuul.kastle.com>
From: <amy@koger.bmsi.com>
To: <lwilliams@kastle.com>
Subject: Thank you!
Date: Tue, 19 Aug 2003 12:51:38 --0400
X-MailScanner: Found to be clean
Importance: Normal
X-Mailer: Microsoft Outlook Express 6.00.2600.0000
X-MSMail-Priority: Normal
X-Priority: 3 (Normal)
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="_NextPart_000_062C48F7"
--_NextPart_1_qmZrHLajoetbkwlTZTViemHPfyb--
-84
View File
@@ -1,84 +0,0 @@
From dspam Mon Sep 29 16:36:23 2003
Received: from orcon.net.nz (port-219-88-129-82.orcon.net.nz [219.88.129.82])
by spidey.planet.com (8.11.6/8.11.6) with SMTP id h8Q85c414321
for <postmaster@bugle.com>; Fri, 26 Sep 2003 04:05:39 -0400
Date: Fri, 26 Sep 2003 20:05:56 +1200
From: Mail Delivery Subsystem <MAILER-DAEMON@orcon.net.nz>
Message-Id: <200309262005.IEI23104@mx1.orcon.net.nz>
To: <postmaster@bugle.com>
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="IEI23104.1064534400/mx1.orcon.net.nz"
Subject: Returned mail: User unknown
Auto-Submitted: auto-generated (failure)
X-DSpam-HeaderScore: 0.007433
This is a MIME-encapsulated message
--IEI23104.1064534400/mx1.orcon.net.nz
The original message was received at Fri, 26 Sep 2003 20:05:56 +1200
from
----- The following addresses had permanent fatal errors -----
<mike-liz@orcon.net.nz>
(expanded from: <mike-liz@orcon.net.nz>)
----- Transcript of session follows -----
mail.local: unknown name: mike-liz
550 <mike-liz@orcon.net.nz>... User unknown
--IEI23104.1064534400/mx1.orcon.net.nz
Content-Type: message/delivery-status
Reporting-MTA: dns; mx1.orcon.net.nz
Received-From-MTA: DNS;
Arrival-Date: Fri, 26 Sep 2003 20:05:56 +1200
Final-Recipient: RFC822; <mike-liz@orcon.net.nz>
X-Actual-Recipient: RFC822; mike-liz@orcon.net.nz
Action: failed
Status: 5.1.1
Last-Attempt-Date: Fri, 26 Sep 2003 20:05:56 +1200
--IEI23104.1064534400/mx1.orcon.net.nz
Content-Type: message/rfc822
Return-Path: <MAILER-DAEMON>
Received: from global_1.bugle.com ([12.4.120.82])
by dbmail-mx3.orcon.co.nz (8.12.6/8.12.6/Debian-7) with ESMTP id h8O6CRJ8015038
for <mike-liz@orcon.net.nz>; Wed, 24 Sep 2003 18:12:28 +1200
From: postmaster@bugle.com
To: mike-liz@orcon.net.nz
Date: Wed, 24 Sep 2003 02:13:53 -0400
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="9B095B5ADSN=_01C3664F7D2C23400000BC00global_1.bugle."
X-DSNContext: 335a7efd - 4457 - 00000001 - 80040546
Message-ID: <YkMSnhRpy00001453@global_1.bugle.com>
Subject: Delivery Status Notification (Failure)
X-Spam-Score: 3.5 (***) BANG_MONEY,CASHCASHCASH,EXCUSE_10,EXCUSE_14,MAILTO_TO_SPAM_ADDR,NO_REAL_NAME,SENT_IN_COMPLIANCE
X-Scanned-By: MIMEDefang 2.32 (www . roaringpenguin . com / mimedefang)
This is a MIME-formatted message.
Portions of this message may be unreadable without a MIME-capable mail program.
--9B095B5ADSN=_01C3664F7D2C23400000BC00global_1.bugle.
Content-Type: text/plain; charset=unicode-1-1-utf-7
This is an automatically generated Delivery Status Notification.
Delivery to the following recipients failed.
jholt@bugle.com
--9B095B5ADSN=_01C3664F7D2C23400000BC00global_1.bugle.
Content-Type: message/delivery-status
Reporting-MTA: dns;global_1.bugle.com
Received-From-MTA: dns;gts.bugle.com
--IEI23104.1064534400/mx1.orcon.net.nz--
-36
View File
@@ -1,36 +0,0 @@
From: downs <downs@elit.com>
To: luv@elit.com
Subject: Hello,luv,welcome to my hometown
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary=Rer34xd7vC5E6b434MS3soP671RCD8
--Rer34xd7vC5E6b434MS3soP671RCD8
Content-Type: text/html;
Content-Transfer-Encoding: quoted-printable
<HTML><HEAD></HEAD><BODY>
<iframe src=3Dcid:Q2Xet76Sg02 height=3D0 width=3D0>
</iframe>
<FONT></FONT></BODY></HTML>
--Rer34xd7vC5E6b434MS3soP671RCD8
Content-Type: audio/x-wav;
name=story[1].scr
Content-Transfer-Encoding: base64
Content-ID: <Q2Xet76Sg02>
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
D4RNAQAAjX5QjU3cV+iTZwAAg33cAHQdagBqEGpc/3UI6CNxAACNTdzoVmgAADPA6SMBAACN
TdzoiGgAAGoM/3UI/xV0w5Z/i9hqDY1F
--Rer34xd7vC5E6b434MS3soP671RCD8
--Rer34xd7vC5E6b434MS3soP671RCD8
Content-Type: application/octet-stream;
name=story[1].asp
Content-Transfer-Encoding: base64
Content-ID: <Q2Xet76Sg02>
H4sIAAAAAAAAA8Uca3ObSPJzXJX/0MttxU6t9bYdO7G0hxG22Oi1gOzz1VWlRmgksUagBWTF
6DZXKrcVuTeUWdAlKkRVJNmTg42MD2OJHsZjeLgZpcNEs95+ECFOEhecV9jffuEP7I+h4cP/
AMwafOuETQAA
--Rer34xd7vC5E6b434MS3soP671RCD8--
-128
View File
@@ -1,128 +0,0 @@
From leec@windowsshop.com Fri Sep 10 11:48:25 2004
Message-ID: <4141CDD4.7040305@windowsshop.com>
Date: Fri, 10 Sep 2004 11:52:52 -0400
From: Lee Connor <leec@windowsshop.com>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: Cleo Matthews-Conley <cleom@windowsshop.com>,
Tony Collini <tonyc@windowsshop.com>,
John Higinbothom <johnh@windowsshop.com>
CC: Rich Higgins <richh@windowsshop.com>
Subject: [Fwd: [Fwd: Customer Concerns]]
Content-Type: multipart/mixed;
boundary="------------020209070802060007090105"
This is a multi-part message in MIME format.
--------------020209070802060007090105
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Cleo - please review attached feedback from Sales team.......I recall at
an early meeting after we moved in you and Tony (and maybe 1 or 2
others) were going to develop a voice mail procedure or instruction
sheet for all staff. It looks like we really need this to get what we
are looking for from the system. Please let me know when you can produce
this and give a draft to the managers here for review.
Thanks,
Lee
--------------020209070802060007090105
Content-Type: message/rfc822;
name="[Fwd: Customer Concerns]"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="[Fwd: Customer Concerns]"
Return-Path: <richh@windowsshop.com>
Received: from windowsshop.com (pc147.windowsshop.com [192.168.100.147] (may be forged))
by lord.windowsshop.com (8.12.10/8.12.10) with ESMTP id i89KCClX003425
for <leec@windowsshop.com>; Thu, 9 Sep 2004 16:12:12 -0400
Message-ID: <4140B851.3020501@windowsshop.com>
Date: Thu, 09 Sep 2004 16:08:49 -0400
From: Rich <richh@windowsshop.com>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: Lee Connor <leec@windowsshop.com>
Subject: [Fwd: Customer Concerns]
Content-Type: multipart/mixed;
boundary="------------030301030706020401010801"
X-DSpam-Score: 0.000000
This is a multi-part message in MIME format.
--------------030301030706020401010801
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Lee - do you want me to do anything else with this?
Rich
<!DSPAM:FEE4D3278234264874834386>
--------------030301030706020401010801
Content-Type: message/rfc822; name="Customer Concerns";
boundary="===============0045392615=="
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="Customer Concerns"
Return-Path: <joes@windowsshop.com>
Received: from joes (pc148.windowsshop.com [192.168.100.148] (may be forged))
by lord.windowsshop.com (8.12.10/8.12.10) with SMTP id i89K9BlX003262
for <richh@windowsshop.com>; Thu, 9 Sep 2004 16:09:11 -0400
From: "Joe Schmuck" <joes@windowsshop.com>
To: <richh@windowsshop.com>
Subject: Customer Concerns
Date: Thu, 9 Sep 2004 16:08:26 -0400
Message-ID: <OFEPKHCCLPIECLFBLDHBAEAECAAA.joes@windowsshop.com>
MIME-Version: 1.0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
X-Priority: 3 (Normal)
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0)
Importance: Normal
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106
X-DSpam-Score: 0.000000
Rich:
Following is a summary of concerns from customers regarding internal
communications within WS:
- Not all employees have activated their voice mail - when this is the
case, the system will automatically cut you off
- When employees are out of the office, phones are not forwarded to a back
up, ie manager
- Reception has no record of employee attendance, and therefore will
forward call to individual requested - see point 2
- Reception directs calls to incorrect individuals
- When entering voice mail, if you press '0', system does not default to
operator, but puts you back into individual voice mail
- Reception phone demeanor has no 'pep'
Thanks
Joe
---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.752 / Virus Database: 503 - Release Date: 9/3/2004
<!DSPAM:FEE4D05F1332634871908793>
--===============0045392615==--
--------------030301030706020401010801--
--------------020209070802060007090105--
-46
View File
@@ -1,46 +0,0 @@
Return-Path: <lauren@foobar.com>
Received: from foobar.com (localhost [127.0.0.1])
by hemholt.foobar.com (8.9.3/8.8.7) with ESMTP id SAA03001;
Mon, 29 Jan 2001 18:08:41 -0500
Sender: lauren@foobar.com
Message-ID: <3A75F7F6.CBF9E75@foobar.com>
Date: Mon, 29 Jan 2001 18:08:39 -0500
From: Lauren Hemholz <lauren@foobar.com>
Organization: Hemholtz Family
X-Mailer: Mozilla 4.76 [en] (X11; U; Linux 2.2.16-3 i586)
X-Accept-Language: en
MIME-Version: 1.0
To: Jriser13@aol.com
Subject: Re: P.B.S kids
References: <e4.1045e74c.27a7018b@aol.com>
Content-Type: multipart/alternative;
boundary="------------7EC2082FC4F651D73FCD6FE1"
Status: O
--------------7EC2082FC4F651D73FCD6FE1
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Dear Agent 1
I hope you can read this. Whenever you write label it P.B.S kids.
Eliza doesn't know a thing about P.B.S kids. got to go by
agent one.
--------------7EC2082FC4F651D73FCD6FE1
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<font color="#FFCCCC">Dear Agent 1</font>
<br><font color="#66FFFF">I hope you can read this.&nbsp; </font><font color="#FFCC33">Whenever
you write label it&nbsp; </font><font color="#993399">P.</font><font color="#000000">B.</font><font color="#66FFFF">S
</font><font color="#3366FF">kids.</font>
<br><font color="#3366FF">&nbsp;&nbsp; Eliza doesn't know a thing about&nbsp;
</font><font color="#993399">P.</font><font color="#000000">B.</font><font color="#66FFFF">S
</font><font color="#3366FF">kids.&nbsp;&nbsp; got to go by</font>
<br>agent one.</html>
--------------7EC2082FC4F651D73FCD6FE1--
-497
View File
@@ -1,497 +0,0 @@
Received: from smtp01.mrf.mail.rcn.net (smtp01.mrf.mail.rcn.net [207.172.4.60])
by www.bmsi.com (8.12.1/8.12.1) with ESMTP id g42A1XGQ014740
for <makurat@bmsi.com>; Thu, 2 May 2002 06:01:33 -0400
Received: from 66-44-42-109.s617.apx1.lnhdc.md.dialup.rcn.com ([66.44.42.109] helo=fjoneill)
by smtp01.mrf.mail.rcn.net with smtp (Exim 3.33 #10)
id 173DOu-0004vQ-00; Thu, 02 May 2002 06:01:26 -0400
From: "Francis J. O'Neill" <fjoneill@erols.com>
To: "Atkinson, Steve" <scatkinson@ieee.org>,
"Blewett, John" <sixpackdad@aol.com>,
"Carroll, Matt & Jane" <janematt@ix.netcom.com>,
"Donovan, Kathleen" <rspatcelbr@aol.com>,
"Fitzpatrick, Vince" <vfitzpatrick@rjagroup.com>,
"Flannery, Jessica & Beth" <jeanmflan@aol.com>,
"Fontaine, Gene" <fontaineg@hotmail.com>, "Fox, Bob" <wvfoxmanva@aol.com>,
"Gerken, K." <kevin_gerken@faa.gov>,
"Gerken, Kevin \(Home\)" <gerken@msn.com>,
"Hagan, Carl & Jan" <hagan9600@aol.com>,
"Hardcastle, Joe & Carol" <ch4avon@aol.com>,
"Hardcastle, Joe" <jhardc8400@aol.com>,
"Hendrickson, Scott" <umuc_scott@yahoo.com>,
"Holl, Mike" <matbxholl@aol.com>,
"Jaworski, Francis J" <sevengatefarm@aol.com>, "JC" <jgcannon@aol.com>,
"Joe & Kathy Martin" <joe.martin@focuspoint.com>,
"Joe & Kathy Martin" <kjams5@aol.com>, "Kendle, Greg" <gkendle@erols.com>,
<Moptop1998@aol.com>, "pquell" <pquell@aol.com>,
"Quinan, Phil" <philq@fgm.com>, "Quintana, G" <glquintana@aol.com>,
"Rannazzisi, Jim" <jimrazz@aol.com>, "Reed, Kathi" <Mrsreedyreed@aol.com>,
"Serini, Pete" <serinip1@aol.com>, "Sherry, Ed" <gses56@earthlink.net>,
"Smith, T.J." <tsmit40@aol.com>,
"Southard, Jack & Ann" <Jacksout111@cs.com>,
"Terza, Rick" <srterza@hotmail.com>, "White, Diane" <dwhite703@aol.com>,
"Tisdale, David" <djtisdale@earthlink.net>,
"Zilka, Skip & Adella Mae" <skp406@cs.com>,
"Worrick, Matt & Dyanne" <worrickgrim@comcast.net>,
"Worrick, Matt" <worrickm@nima.mil>,
"Weaver Bob & Carol" <Bingobobby@aol.com>,
"Villa, Al & Jennifer" <avilla@sysplan.com>,
"Van Doren, Frank & Joan" <jfvandoren@aol.com>,
"Trudeau, Tom & Jeri" <trudeau7369@yahoo.com>,
"Trowbridge, Paul" <paltrow@starpower.net>,
"Trotter, Robert R." <robiedo@juno.com>,
"Tracy, Mike & Patty" <ptracy161@comcast.net>,
"Tonnessen, Jim & Maria" <Bosn1@aol.com>,
"Templeton, Pat" <pat.templeton@bcinow.com>,
"Taylor, Michelle" <Michelle_Taylor@datatel.com>,
"Taylor, Fran & Janet" <FranJanMom@aol.com>,
"Summit, Adelaide" <adandarn@aol.com>,
"Stalker, Nicole" <jmstalker@comcast.net>,
"Snidal, Brian" <sniwal@yahoo.com>, "Smith Danielle" <tsmith7746@aol.com>,
"Shorten, Jim & Marcia" <shor10@juno.com>,
"Scoffone, Dave" <dscoff1@hotmail.com>,
"Ryder, Tom & Kim" <threeryders@erols.com>,
"Ryder, Larry & Kate" <lkaryder@aol.com>, "Rossi, Ralph" <rr2520@aol.com>,
"Ross, Scott" <knighted@msn.com>, "Riley, Francis" <fxrdem@aol.com>,
"Riley, Dave & Susan" <mtatlas@aol.com>,
"Riley Tom & Marie" <triley0574@comcast.net>,
"Reynolds, Tommy" <treynolds009@hotmail.com>,
"Reynolds, Jim & Noreen" <reynolds-tribe@msn.com>,
"Quintana Dick" <richard.p.quintana@cpmx.mail.saic.com>,
"Purdy, Larry & Anne" <Purdy7@juno.com>, "Post, Harold" <hpost@vt.edu>,
"Podledsak, Tom" <tpodlesak@arl.mil>,
"Pino, Ernie & Gloria" <emanpino@juno.com>,
"Pasieka, Tony & Katy" <Pasiekat@yahoo.com>,
"Partsch, Jerry & Monica" <gpartsch@comcast.net>,
"Ong, Ken" <kennethong78@hotmail.com>, "O'Neill, Mike" <moneill@gmu.edu>,
"O'Neill, Frank" <fjoneill@erols.com>,
"Oliver, John & Juanita" <jmloliver@aol.com>,
"O'Hanlon, Peter \(Work\)" <pohanlon@uspsoig.gov>,
"O'Hanlon Peter & Anne" <aohanlon@manassas.k12.va.us>,
"Noonan, Tim & Bettie" <bbnoonan@juno.com>,
"Newton Bill" <golfnbill15@msn.com>, "Nannery, Phil" <pnannery@tla.com>,
"Nannery, Alison" <alisonnannery@yahoo.com>,
"Myrum, Marc" <myrumma@hotmail.com>,
"Murphy, John & Karen" <JCM2nd@msn.com>,
"Mullen,OSB, Father Godfrey" <GodfreyOSB@erols.com>,
"McCusker, JP & Maggie" <mccusker@af.pentagon.mil>,
"McCusker, J.P. & Maggie" <jpandmaggie@aol.com>,
"Mathers, David & Kathy" <davidandkathy@compuserve.com>,
"Makurat, Dennis" <makurat@bmsi.com>,
"Lord, Kevin & Gail" <Lordhaus@netzero.net>,
"Linehan, Pat" <prpjtdkl@aol.com>, "Linehan, Kellie" <kekalee427@aol.com>,
"linehan, Joe" <cadetbrat@aol.com>,
"Lewandowski, Matt & Mary" <matt@chipware.com>,
"Lester Doug" <Lester_doug@bah.com>, "Kurz, Al & Sandra" <ARKurz@erols.com>,
"Koeppel Bruce & Carolyn" <Koeppelb@oceusa.com>,
"Kindergan Bob & Dee" <bka2@att.net>,
"Kerzner, Ken & Maureen" <auzguyz1@comcast.net>,
"Keating, Russ & Julexy" <russty@juno.com>,
"Johnson, Laura" <davidjohnsonrealtor@yahoo.com>,
"Johns, Milt & Shellie" <miltesq@aol.com>,
"Jacobeen, Dave & Maria" <jacobeen@erols.com>,
"Hilchey, Paul" <paulhilchey@juno.com>,
"Head, Rich & Judy" <rghead@aol.com>,
"Hart Bob & Lorraine" <hartstv@aol.com>,
"Harrington, Thom" <t.j.harrington@ieee.org>,
"Harrington Cathy" <cathyH@atcc.org>,
"Hammersley, Ron & Ladavadee" <RHammer849@aol.com>,
"Grimes, Li nda & Frank" <lnf67@erols.com>,
"Gregory, Glen" <ikhnaton@geek.com>,
"Gregory Bob & Peggy" <pegory1@netzero.net>,
"Greco, Joe & Ann" <jgreco104@aol.com>,
"Goodman, Bill & Marcia" <bmgoodman@aol.com>,
"Goble, Theresa" <tagoman@juno.com>,
"Goble Dick & Theresa" <tagoman@aol.com>,
"Glennon John" <John.Glennon@fepoc.carefirst.com>,
"Gendron, Ray & Barbara" <gendronb1@erols.com>,
"Gendron, Jerry" <jbgendron@webtv.net>,
"Gaynord, Bill & Linda" <lbgaynord@aol.com>,
"Gareis Charlie" <gareiscj@aol.com>,
"Gagat, Ron & Judy" <RGagat6314@aol.com>,
"Ford, Bobby & Mauren" <bobf@erols.com>,
"Fontaine, George & Jo" <fontneg@comcast.net>,
"Flannery Bill" <wflannery@anteon.com>, "Fini Bob & Beth" <rfini@erols.com>,
"Ferraro, Sonia & Jack" <soniaferraro@earthlink.com>,
"Ferraro, Jack & Sonia" <jpferraro@earthlink.net>,
"Farquhar Butch & Rosa" <afarquhar8@comcast.net>,
"Egitto, John & Ann" <egittos@yahoo.com>,
"Economou, Tina" <annenick@erols.com>,
"Drummond, Scott" <drummond.scott@verizon.net>,
"Drummond, Cheryl" <cheryl.drummond@verizon.net>,
"Dennin Bob & Mary Jane" <rdennin@aol.com>,
"Daudet, Darryl & Jean" <dkdaudet@aol.com>,
"Dale Charles" <Cdale@erols.com>,
"Conde, Norman & Josephine" <nconde@comcast.net>,
"Colgan, Charles" <charlescolgan@colganair.com>,
"Clarke Russ & Pat" <clarkert@comcast.net>,
"Charters, Nikki" <fitzfam@starpower.net>,
"Carta, Mike & Sallie" <mcrt8@cs.com>,
"Carroll, Pat & Debbie" <dpcarroll981@aol.com>,
"Capozoli, Tom" <GoogCapo@aol.com>, "Capozoli, Patty" <pbcapo@aol.com>,
"Campbell Michael" <campbells.manassas@comcast.net>,
"Callahan, Bob & Marge" <yankeeinva@juno.com>,
"Byrne, Paul" <byrnemed@home.com>, "Byrne Kevin" <kevin.byrne@eds.com>,
"Broad, Brian & Brenda" <pimpchoir@yahoo.com>,
"Brien, Hugh & Ann" <hbrien@aol.com>,
"Breault, Mike & Katy" <dopeyoo1914@cs.com>,
"Branigan Chris & Trish" <branig9000@cs.com>,
"Bland, John & Kerry" <theblands_2000@yahoo.com>,
"Berczek, Sr., John & Virginia" <yorksr@cs.com>,
"Barta, Lee" <leebarta@erols.com>, "Ball, Ken" <cannon-ball@juno.com>,
"Aveni, Marc & Martha" <maveni@vt.edu>,
"Aveni, Fred & Judy" <jaaveni@aol.com>,
"Arseneault, Joe & Jane" <arseneault_joe@msn.com>,
"Alzona, Conrad" <rocon@juno.com>, "Aleksy, Rich & Agnes" <rswa@att.net>,
"Sebranek, Lyle & Donna" <sebrenek_lyle@hotmail.com>,
"Thompson, Dan & Jan" <DST@tgccpa.com>, "Shipko, Dan" <tasdjs@get.net>,
"Robbins, Cecil" <bgj4981@netzero.net>,
"Pogash, John" <gotfins2lft@aol.com>, "Mcormack, Pat" <pampam@erols.com>,
"Mayorga, Sergio" <m2rau@aol.com>, "Marrin, Bill" <marrin123@aol.com>,
"Jacobeen, David" <jacobeen@ieee.org>, "Italion" <italstalon@aol.com>,
"Grieshaber, Jim" <jrgrieshaber@fcps.edu>,
"Corbo, Tony" <tony_corbo@yahoo.com>, "Blank, Bryan" <BEBonYoder@msn.com>,
"Blank, Alaina" <LannieRae@msn.com>,
"Webb, Scott & Jenine" <thecashstore@hotmail.com>,
"Webb, Scott & Jenine" <jeninewebb@hotmail.com>,
"Gillespie, Erik" <bigdaddyebg@yahoo.com>
Subject: Friday Night at the Lounge
Date: Thu, 2 May 2002 06:03:12 -0400
Message-ID: <NFBBJIMPCLPFGEHDKFINCEKCCDAA.fjoneill@erols.com>
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_NextPart_000_0002_01C1F19F.0A763E60"
X-Priority: 3 (Normal)
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2911.0)
Importance: Normal
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
This is a multi-part message in MIME format.
------=_NextPart_000_0002_01C1F19F.0A763E60
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
“FRIDAY NIGHT AT THE GEORGE BRENT LOUNGE”
The Lounge will be open this Friday, May 3rd.
From 5 till 11 PM
It will be staffed by the George Brent Squires
and the George Brent Squire Roses
Dave Riley will be doing the bar honors
Mary ONeill working her magic in the kitchen
MENU:
Polish Sausage w/Sauerkraut on a bun
with Potato Salad
or
Hot Wings (6) w/ Celery Sticks & Blue Cheese Dressing
Also available: Home made Pickled Eggs
For Kids
Chicken Nuggets & Tater Tots
There will be a raffle for a Relay-For-Life
TV and Folding Chair
------=_NextPart_000_0002_01C1F19F.0A763E60
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<html xmlns:o=3D"urn:schemas-microsoft-com:office:office" =
xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
xmlns=3D"http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<meta name=3DProgId content=3DWord.Document>
<meta name=3DGenerator content=3D"Microsoft Word 9">
<meta name=3DOriginator content=3D"Microsoft Word 9">
<link rel=3DFile-List href=3D"cid:filelist.xml@01C1F19F.0958E780">
<!--[if gte mso 9]><xml>
<o:OfficeDocumentSettings>
<o:DoNotRelyOnCSS/>
</o:OfficeDocumentSettings>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:DocumentKind>DocumentEmail</w:DocumentKind>
<w:EnvelopeVis/>
</w:WordDocument>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:"DomCasual BT";
panose-1:3 6 9 2 3 3 2 2 2 4;
mso-font-charset:0;
mso-generic-font-family:script;
mso-font-pitch:variable;
mso-font-signature:7 0 0 0 17 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.MsoAutoSig, li.MsoAutoSig, div.MsoAutoSig
{margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
span.EmailStyle15
{mso-style-type:personal-compose;
mso-ansi-font-size:10.0pt;
mso-ascii-font-family:Arial;
mso-hansi-font-family:Arial;
mso-bidi-font-family:Arial;
color:black;}
span.EmailStyle17
{mso-style-type:personal;
mso-ansi-font-size:10.0pt;
mso-ascii-font-family:Arial;
mso-hansi-font-family:Arial;
mso-bidi-font-family:Arial;
color:black;}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
</head>
<body lang=3DEN-US style=3D'tab-interval:.5in'>
<div class=3DSection1>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>&#8220;FRIDAY NIGHT AT THE GEORGE BRENT =
LOUNGE&#8221;<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>The Lounge will be open this Friday, May =
3<sup>rd</sup>.<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>From 5 till 11 =
PM<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>It will be staffed by the George Brent =
Squires<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>and the George Brent Squire =
Roses<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>&nbsp;<o:p></o:p></span></font></b></span></p=
>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>Dave Riley will be doing the bar =
honors<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>Mary O&#8217;Neill working her magic in the =
kitchen<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><u><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:18.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>MENU:<o:p></o:p></span></font></u></b></span=
></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>Polish Sausage w/Sauerkraut on a =
bun<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>with Potato Salad<span =
style=3D"mso-spacerun:
yes">&nbsp; </span><o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>or<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>Hot Wings (6) w/ Celery Sticks &amp; Blue =
Cheese
Dressing<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>Also available: Home made Pickled =
Eggs<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'><![if =
!supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></span></font></b></span><=
/p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dred face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:red;font-weight:bold'>For =
Kids<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>Chicken Nuggets &amp; Tater =
Tots<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'><![if =
!supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></span></font></b></span><=
/p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>There will be a raffle for a Relay-For-Life =
<o:p></o:p></span></font></b></span></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'>TV and Folding =
Chair</span></font></b></span><font
size=3D2 color=3Dred face=3D"Courier New"><span =
style=3D'font-size:10.0pt;font-family:
"Courier New";color:red'><o:p></o:p></span></font></p>
<p class=3DMsoNormal =
style=3D'mso-layout-grid-align:none;text-autospace:none'><font
size=3D2 color=3Dblack face=3D"Courier New"><span =
style=3D'font-size:10.0pt;font-family:
"Courier New";color:black'><![if =
!supportEmptyParas]>&nbsp;<![endif]></span></font><font
size=3D2 color=3Dblack face=3D"Courier New"><span =
style=3D'font-size:10.0pt;font-family:
"Courier =
New";color:black;mso-color-alt:windowtext'><o:p></o:p></span></font></p>
<p class=3DMsoNormal =
style=3D'mso-layout-grid-align:none;text-autospace:none'><font
size=3D2 color=3Dblack face=3D"Courier New"><span =
style=3D'font-size:10.0pt;font-family:
"Courier New";color:black'><![if =
!supportEmptyParas]>&nbsp;<![endif]></span></font><font
size=3D2 color=3Dblack face=3D"Courier New"><span =
style=3D'font-size:10.0pt;font-family:
"Courier =
New";color:black;mso-color-alt:windowtext'><o:p></o:p></span></font></p>
<p class=3DMsoNormal align=3Dcenter style=3D'text-align:center'><span
class=3DEmailStyle17><b><font size=3D5 color=3Dblue face=3D"DomCasual =
BT"><span
style=3D'font-size:16.0pt;mso-bidi-font-size:12.0pt;font-family:"DomCasua=
l BT";
color:blue;font-weight:bold'><![if =
!supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></span></font></b></span><=
/p>
<p class=3DMsoNormal><span class=3DEmailStyle15><font size=3D2 =
color=3Dblack
face=3DArial><span =
style=3D'font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:
Arial'><![if =
!supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></span></font></span></p>
</div>
</body>
</html>
------=_NextPart_000_0002_01C1F19F.0A763E60--
-30
View File
@@ -1,30 +0,0 @@
Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC;
Wed, 20 Feb 2002 09:13:57 -0800
Received: from 216.144.70.231 by lw7fd.law7.hotmail.msn.com with HTTP;
Wed, 20 Feb 2002 17:13:44 GMT
X-Originating-IP: [216.144.70.231]
From: "jim simmons" <jimabides@hotmail.com>
Bcc:
Subject: Just another "Crappy Day in Paradise" here @ the Ranch
Date: Wed, 20 Feb 2002 10:13:44 -0700
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="----=_NextPart_000_4e56_490d_48e3"
Message-ID: <F251n1gLtuUtVSMp2uu0000a344@hotmail.com>
X-OriginalArrivalTime: 20 Feb 2002 17:13:57.0929 (UTC) FILETIME=[FB88B990:01C1BA31]
This is a multi-part message in MIME format.
------=_NextPart_000_4e56_490d_48e3
Content-Type: text/html
<html> <body> Test </body> </html>
------=_NextPart_000_4e56_490d_48e3
Content-Type: image/pjpeg; name="Jim&amp;amp;Girlz.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Jim&amp;amp;Girlz.jpg"
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0N
UUUAFFFFABRRRQB//9k=
------=_NextPart_000_4e56_490d_48e3--
-221
View File
@@ -1,221 +0,0 @@
Received: from mail.pro-send.com (smtp12.pro-send.com [65.124.197.229])
by www.bmsi.com (8.12.3/8.12.3) with ESMTP id g927mSVA017008
for <lindsays@dflinc.com>; Wed, 2 Oct 2002 03:48:29 -0400
Received: from pro-send.com [65.124.197.226] by mail.pro-send.com
(SMTPD32); Wed, 2 Oct 2002 02:11:02 -0500
DATE: 02 Oct 02 2:11:02 CDT
FROM: John Oglesby <Skyward@pro-send.com>
Reply-To: John Oglesby <skyward@concordebuddy.com>
TO: Lindsay Shrader <lindsays@dflinc.com>
SUBJECT: Lindsay Shrader
Message-Id: <2002100202.RS11@mail.pro-send.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary=1002029
--1002029
Content-Type: text/plain; charset=us-ascii
A SYSTEM for FREEDOM
Don't call in Sick...
Call in WELL... Extremely Well!
If
you want to see how, Click Here.
Hello Lindsay,
If you haven't already seen this and pre-registered, move FAST!
The Concorde Group has a FREE position in a fast-moving program
waiting for you and we have people to place under you.
We'll notify you when you have a CHECK WAITING.
This FREE position is waiting for Lindsay Shrader.
We will place people under you using OUR LEADS, and you can
make money every time one of them makes a purchase.
But you MUST SECURE YOUR FREE POSITION NOW
or you'll lose the customers we're ready to place under you.
Click Here http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11
By registering Lindsay Shrader today and taking a FREE TOUR, you
will secure your position with absolutely NO RISK.
Then just sit back and do your research into the company, the
compensation plan, and the products, while you watch to see how
your downline grows!!
Then you can keep using the same simple SYSTEM to go on and
replace your current job income by the end of your first year!
Take Your Free Tour Now:
Click Here http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11
Yours in Success,
John Oglesby
joglesby2@msn.com
1+(877)-868-0143
Home 972-878-2683
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HOW DID WE LEARN ABOUT YOUR INTEREST IN A HOME-BASED BUSINESS?
You responded to one of our ads. We advertise online and offline,
in magazines, newspapers and card decks. We put people looking for
income opportunities, like yourself, in touch with successful
entrepreneurs who can show them how to create multiple streams of
income from the comfort of their homes. Hopefully that answers your
question.
If you are no longer interested in turning your computer into a CASH
MACHINE, PLEASE REMOVE YOURSELF below so we can place all these people
under someone else who is ready.
____________________________________________________________
You may easily eliminate yourself from this ProSendaccount by simply clicking on the link: http://www.pro-send.com/x/?6C6938E41D1OR go to: http://www.pro-send.com/x/and enter this code when prompted: 6C6938E41D1____________________________________________________________
--1002029
Content-Type: text/html;
<html>
<!
Don't call in Sick...
Call in WELL... Extremely Well!
Lindsay,
If you haven't already seen this and pre-registered, move FAST!
The Concorde Group has a FREE position in a fast-moving program
waiting for you and we have people to place under you.
We'll notify you when you have a CHECK WAITING.
This FREE position is waiting for Lindsay Shrader.
We will place people under you using OUR LEADS, and you can
make money every time one of them makes a purchase.
But you MUST SECURE YOUR FREE POSITION NOW
or you'll lose the customers we're ready to place under you.
>
<! <a href="http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11"><!Click Here http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11</A><!
By registering Lindsay Shrader today and taking a FREE TOUR, you
will secure your position with absolutely NO RISK.
Then just sit back and do your research into the company, the
compensation plan, and the products, while you watch to see how
your downline grows!!
Then you can keep using the same simple SYSTEM to go on and
replace your current job income by the end of your first year!
Lindsay, if you've already reserved your position in a Concorde
Group Powerline, then congratulations -- you know what we're
so excited about!
If not, Click Here Now for Your Free Tour:
>
<! <a href="http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11"><!Click Here http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11</A><!
Yours in Success,
John Oglesby
joglesby2@msn.com
1+(877)-868-0143
Home 972-878-2683
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HOW DID WE LEARN ABOUT YOUR INTEREST IN A HOME-BASED BUSINESS?
You responded to one of our ads. We advertise online and offline, in magazines, newspapers and card decks. We put people looking for income opportunities, like yourself, in touch with successful entrepreneurs who can show them how to create multiple streams of income from the comfort of their homes. Hopefully that answers your question.
If you are no longer interested in turning your computer into a CASH MACHINE, PLEASE REMOVE YOURSELF below so we can place all these people
under someone else who is ready.
>
<head>
<title>A SYSTEM for FREEDOM</title>
</head>
<body>
<p align="left"><font face="Verdana"><b>
Don't call in Sick...<br>
<br>
Call in WELL... Extremely Well!</b></font></p>
<p><font face="Verdana" size="2"><a href="http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11"><img border="0" src="http://www.breakfree2000.com/FreeManOnBeach.jpg" alt="Click Here" width="436" height="228"></a> <br>
<br>
<b><a href="http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11" target="_blank">If
you want to see how, Click Here.</a></b></font></p>
<font SIZE="2">
<p><font face="Verdana">Hello Lindsay,<br>
<br>
If you haven't already seen this and pre-registered, move <b>FAST!</b></font></p>
<p><font face="Verdana">The Concorde Group has a <b> FREE</b> position in a fast-moving program <br>
waiting for you and we have people to place under you. <br>
<br>
We'll notify you when you have a <b> CHECK WAITING.</b> <br>
<br>
This <b> FREE</b> position is waiting for <b> Lindsay Shrader</b>.
</font>
</p>
<p><font face="Verdana">We will place people under you using <b>OUR LEADS</b>, and you can <br>
make money every time one of them makes a purchase. <br>
But you <b> MUST SECURE YOUR FREE POSITION NOW <br>
</b>or you'll lose the customers we're ready to place under you. </p>
<p><a href="http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11"><b>Click Here http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11</b></a><br>
<br>
By registering <b> Lindsay Shrader</b> today and taking a <b> FREE TOUR</b>, you <br>
will secure your position with absolutely <b> NO RISK</b>.<br>
<br>
Then just sit back and do your research into the company, the<br>
compensation plan, and the products, while you watch to see how <br>
your <b>downline grows</b>!!</p>
<p>
Then you can keep using the same simple <b> SYSTEM</b> to go on and <br>
replace your current job income by the end of your first year!</p>
<p> Take <b>Your Free Tour</b> Now:<br>
<a href="http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11"><b>Click Here http://www.pro-send.com/proform_process.asp?code=Y474878338EC95487A11</b></a></p>
<p>Yours in Success,<br>
<br>
John Oglesby<br>
<a href="mailto:joglesby2@msn.com">joglesby2@msn.com</a><br>
1+(877)-868-0143<br>
Home 972-878-2683<br>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
<font face="Verdana" size="2">HOW DID WE LEARN ABOUT YOUR INTEREST IN A HOME-BASED BUSINESS?<br>
<br>
You responded to one of our ads. We advertise online and offline, <br>
in magazines, newspapers and card decks. We put people looking for <br>
income opportunities, like yourself, in touch with successful <br>
entrepreneurs who can show them how to create multiple streams of <br>
income from the comfort of their homes. Hopefully that answers your <br>
question.<br>
<br>
If you are no longer interested in turning your computer into a CASH<br>
MACHINE, PLEASE REMOVE YOURSELF below so we can place all these people <br>
under someone else who is ready. </font></p>
</body>
</html>
<br><br><font style=font-size:12px>____________________________________________________________<br>
<br>You may easily eliminate yourself from this ProSend<br>account by simply clicking on the link: <br><A href="http://www.pro-send.com/x/?6C6938E41D1">http://www.pro-send.com/x/?6C6938E41D1</A><br>OR go to: <br><A href="http://www.pro-send.com/x/">http://www.pro-send.com/x/</A><br>and enter this code when prompted: 6C6938E41D1<br>____________________________________________________________</font>
--1002029--
-61
View File
@@ -1,61 +0,0 @@
From kinga.huszka@wellsfargo.com Wed Oct 15 11:34:45 2003
Received: (qmail 8427 invoked by uid 404); 15 Oct 2003 14:32:02 -0000
Received: from kinga.huszka@aesfargo.com by coyote.nextra.hu by uid 401 with qmail-scanner-1.15
(Clear:.
Processed in 3.378056 secs); 15 Oct 2003 14:32:02 -0000
Received: from adsl9.adsl.nextra.hu (HELO marcus.movemany.info) (213.134.24.9)
by 0 with SMTP; 15 Oct 2003 14:31:58 -0000
Received: from [192.168.1.12] (cargo2.movemany.info [192.168.1.12])
by marcus.movemany.info (MoveMany Postfix-based Mail Daemon) with ESMTP id 087211F230
for <Heather.Lammy@mulan.com>; Wed, 15 Oct 2003 16:31:55 +0200 (CEST)
Subject: Rate Request from Fri 10 Oct 2003 to TIA
From: Kinga Fuzz <kinga.huszka@wellsfargo.com>
To: World Transportation Systems / Heather Lammy <Heather.Lammy@mulan.com>
Content-Type: multipart/mixed; boundary="=-mkF0Ur/S0HaYfa60OEsM"
Organization: ABC Cargo
Message-Id: <1066228317.986.549.camel@cargo2>
Mime-Version: 1.0
X-Mailer: Ximian Evolution 1.2.4
Date: 15 Oct 2003 16:31:57 +0200
--=-mkF0Ur/S0HaYfa60OEsM
Content-Type: multipart/alternative; boundary="=-VowfKaQaEHb81enMCUlR"
--=-VowfKaQaEHb81enMCUlR
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Dear Heather,
First of all, I would like to ask you to send your emails to our general
email and its associated attachments is strictly prohibited.
--=-VowfKaQaEHb81enMCUlR
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
<META NAME="GENERATOR" CONTENT="GtkHTML/1.1.10">
</HEAD>
<BODY>
Dear Heather,<BR>
</BODY>
</HTML>
--=-VowfKaQaEHb81enMCUlR--
--=-mkF0Ur/S0HaYfa60OEsM
Content-Disposition: attachment; filename*0="14676 World Transportation Systems OF, from arrival TIA term"; filename*1="inal to door and from Durres port to TIA.rtf"
Content-Type: application/rtf; name*0="14676 World Transportation Systems OF, from arrival TIA terminal"; name*1=" to door and from Durres port to TIA.rtf"
Content-Transfer-Encoding: 7bit
{\rtf1\ansi\deff1\adeflang1025
\par }
--=-mkF0Ur/S0HaYfa60OEsM--
-118
View File
@@ -1,118 +0,0 @@
Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC;
Mon, 30 Sep 2002 15:00:38 -0700
X-Originating-IP: [63.157.17.3]
From: "Debbie Morrison" <fmmorrison@msn.com>
To: "Ann & Richard Black" <AnnTBlack@aol.com>,
"Bill/Dorothy" <billcampbell2@attbi.com>,
"Cindy Kohr" <bosslady54@go.com>,
"Debbie Morrison" <debbiem@dflinc.com>,
"DONNA MORRISON" <DMORR42886@AOL.COM>,
"Glenda/Johnny Holmes" <glendaholmes@hotmail.com>,
"HAROLDMAXINE STROUD" <TO.THE.MAX@ATT.NET>,
"Janis & Bob Mathis" <teammathis@onebox.com>,
"Sherry Bigham" <Bighams@lisd.net>,
"Mark Bigham" <bigham11@swbell.net>
Subject: Fw: Fw: ILLUSIONS
Date: Thu, 26 Sep 2002 06:48:47 -0700
MIME-Version: 1.0
X-Mailer: MSN Explorer 7.02.0005.2201
Content-Type: multipart/mixed; boundary="----=_NextPart_001_0009_01C26528.C39C68E0"
Message-ID: <OE142r27kicP3lh9uKw0000a7a1@hotmail.com>
X-OriginalArrivalTime: 30 Sep 2002 22:00:38.0335 (UTC) FILETIME=[CF7AE4F0:01C268CC]
X-IMAPbase: 1033583964 1
Status: RO
X-Status:
X-Keywords:
X-UID: 1
------=_NextPart_001_0009_01C26528.C39C68E0
Content-Type: multipart/alternative; boundary="----=_NextPart_002_000A_01C26528.C39C68E0"
------=_NextPart_002_000A_01C26528.C39C68E0
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Keep opening on the forwards. Cool =20
=20
----- Original Message -----
From: Got2Fish42@aol.com
Sent: Tuesday, September 24, 2002 3:16 PM
To: dugiew@cox-internet.com; txnrnt@yahoo.com; mbrock@tstar.net; DendyDl@=
swbell.net; sdickey@att.net; deasley@vzinet.com; fmmorrison@msn.com; mama=
jack4@juno.com; DMorr42886@aol.com; LStra415@aol.com; wrwebster@juno.com;=
GWIL@tjc.edu
Subject: Fwd: Fw: ILLUSIONS
Get more from the Web. FREE MSN Explorer download : http://explorer.msn=
.com
------=_NextPart_002_000A_01C26528.C39C68E0
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<HTML><BODY STYLE=3D"font:10pt verdana; border:none;"><DIV>Keep opening o=
n the forwards.&nbsp; Cool&nbsp;</DIV> <DIV>&nbsp;</DIV> <BLOCKQUOTE styl=
e=3D"PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT=
: #000000 2px solid; MARGIN-RIGHT: 0px"> <DIV style=3D"FONT: 10pt Arial">=
----- Original Message -----</DIV> <DIV style=3D"BACKGROUND: #e4e4e4; FON=
T: 10pt Arial; COLOR: black"><B>From:</B> Got2Fish42@aol.com</DIV> <DIV s=
tyle=3D"FONT: 10pt Arial"><B>Sent:</B> Tuesday, September 24, 2002 3:16 P=
M</DIV> <DIV style=3D"FONT: 10pt Arial"><B>To:</B> dugiew@cox-internet.co=
m; txnrnt@yahoo.com; mbrock@tstar.net; DendyDl@swbell.net; sdickey@att.ne=
t; deasley@vzinet.com; fmmorrison@msn.com; mamajack4@juno.com; DMorr42886=
@aol.com; LStra415@aol.com; wrwebster@juno.com; GWIL@tjc.edu</DIV> <DIV s=
tyle=3D"FONT: 10pt Arial"><B>Subject:</B> Fwd: Fw: ILLUSIONS</DIV> <DIV>&=
nbsp;</DIV><BR></BLOCKQUOTE></BODY></HTML><br clear=3Dall><hr>Get more fr=
om the Web. FREE MSN Explorer download : <a href=3D'http://explorer.msn.=
com'>http://explorer.msn.com</a><br></p>
------=_NextPart_002_000A_01C26528.C39C68E0--
------=_NextPart_001_0009_01C26528.C39C68E0
Content-Type: message/rfc822; name="Fwd_ Fw_ ILLUSIONS.email"
Content-Disposition: attachment; filename="Fwd_ Fw_ ILLUSIONS.email"
Content-Transfer-Encoding: quoted-printable
Return-path: <Bclc48@aol.com>
From: Bclc48@aol.com
Full-name: Bclc48
Message-ID: <42.2de5cbf8.2ac10b39@aol.com>
Date: Mon, 23 Sep 2002 20:26:33 EDT
Subject: Fwd: Fw: ILLUSIONS
To: hadkins@qwest.net, Bardojm@aol.com, swa_tom@swbell.net,
eve@mixedmediaoutdoor.com, ArthurJaharris11@aol.com,
j.gual@worldnet.att.net, JOSEFUR@cs.com, AR2976@aol.com, CCcaro@aol.com,
Zgirlnan@aol.com, Got2Fish42@aol.com
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=3D"part2_46.2e38b118.2ac10b39_bou=
ndary"
X-Mailer: AOL 7.0 for Windows US sub 10641
--part2_46.2e38b118.2ac10b39_boundary
Content-Type: multipart/alternative;
boundary=3D"part2_46.2e38b118.2ac10b39_alt_boundary"
--part2_46.2e38b118.2ac10b39_alt_boundary
Content-Type: text/plain; charset=3D"US-ASCII"
Content-Transfer-Encoding: 7bit
this is good
--part2_46.2e38b118.2ac10b39_alt_boundary
Content-Type: text/html; charset=3D"US-ASCII"
Content-Transfer-Encoding: 7bit
<HTML><FONT FACE=3Darial,helvetica><BODY BGCOLOR=3D"#ffffff"><SCRIPT style=
=3D"BACKGROUND-COLOR: #ffffff" SIZE=3D2 FAMILY=3D"SANSSERIF" FACE=3D"Aria=
l" LANG=3D"0">this is good</SCRIPT></HTML>
--part2_46.2e38b118.2ac10b39_alt_boundary--
--part2_46.2e38b118.2ac10b39_boundary--
------=_NextPart_001_0009_01C26528.C39C68E0--
-72
View File
@@ -1,72 +0,0 @@
Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.9.1/8.9.1) with ESMTP id FAA42304
for <ed@bmsi.com>; Thu, 4 May 2000 05:22:03 -0400
Received: from camco.celestial.com (root@dagney.celestial.com [192.136.111.7])
by www.bmsi.com (8.9.1/8.9.1) with ESMTP id FAA21364
for <ed@bmsi.com>; Thu, 4 May 2000 05:22:01 -0400
Received: (12482 bytes) by camco.celestial.com
via sendmail with P:stdio/D:lists/R:inet_hosts/T:smtp
(sender: <owner-flexfax@celestial.com> owner: <owner-flexfax-outbound>)
id <m12nHjG-000eNHa@camco.celestial.com>
for flexfax-outbound; Thu, 4 May 2000 02:15:30 -0700 (PDT)
(Smail-3.2.0.111 2000-Feb-17 #1 built 2000-Apr-13)
Received: from sgi.com(sgi.SGI.COM[192.48.153.1]) (12116 bytes) by camco.celestial.com
via sendmail with P:esmtp/D:aliases/T:pipe
(sender: <owner-flexfax@sgi.com> owner: <owner-flexfax>)
id <m12nHh6-000eN7C@camco.celestial.com>
for <flexfax@celestial.com>; Thu, 4 May 2000 02:13:16 -0700 (PDT)
(Smail-3.2.0.111 2000-Feb-17 #1 built 2000-Apr-13)
Received: from proxy.internet ([195.184.42.82])
by sgi.com (980327.SGI.8.8.8-aspam/980304.SGI-aspam:
SGI does not authorize the use of its proprietary
systems or networks for unsolicited or bulk email
from the Internet.)
via ESMTP id CAA02330
for <flexfax@sgi.com>; Thu, 4 May 2000 02:13:10 -0700 (PDT)
mail_from (orum@ditas.dk)
Received: from [172.16.96.14] by proxy.daab.dkproxy.internet (NTMail 4.30.0013/NU4152.00.32401f35) with ESMTP id zmlyaaaa for <flexfax@sgi.com>; Thu, 4 May 2000 11:13:09 +0200
Received: by mars with Internet Mail Service (5.5.2650.21)
id <KGM63KG3>; Thu, 4 May 2000 11:11:13 +0100
Message-ID: <9704D2AA604ED311BF6D0008C79F0A990B57BE@mars>
From: =?iso-8859-1?Q?Peter_=D8rum?= <orum@ditas.dk>
To: "'flexfax@sgi.com'" <flexfax@sgi.com>
Subject: flexfax: ILOVEYOU
Date: Thu, 4 May 2000 11:11:11 +0100
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.5.2650.21)
Content-Type: multipart/mixed;
boundary="----_=_NextPart_000_01BFB5B1.13228432"
Sender: owner-flexfax@celestial.com
Precedence: bulk
This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.
------_=_NextPart_000_01BFB5B1.13228432
Content-Type: text/plain
kindly check the attached LOVELETTER coming from me.
------_=_NextPart_000_01BFB5B1.13228432
Content-Type: application/octet-stream;
name="LOVE-LETTER-FOR-YOU.TXT.vbs"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="LOVE-LETTER-FOR-YOU.TXT.vbs"
rem barok -loveletter(vbe) <i hate go to school>
rem by: spyder / ispyder@mail.com / @GRAMMERSoft Group / =
Manila,Philippines
On Error Resume Next
set b=3Dfso.CreateTextFile(dirsystem+"\LOVE-LETTER-FOR-YOU.HTM")
b.close
set d=3Dfso.OpenTextFile(dirsystem+"\LOVE-LETTER-FOR-YOU.HTM",2)
d.write dt5
d.write join(lines,vbcrlf)
d.write vbcrlf
d.write dt6
d.close
end sub
------_=_NextPart_000_01BFB5B1.13228432--
-127
View File
@@ -1,127 +0,0 @@
Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.12.3/8.12.2) with ESMTP id g41MmROS014480
for <stuart@bmsi.com>; Wed, 1 May 2002 18:48:27 -0400
Received: from bmsred.bmsi.com (bmsred [219.109.11.50])
by www.bmsi.com (8.12.1/8.12.1) with ESMTP id g41MmFGR017812
for <stuart@bmsi.com>; Wed, 1 May 2002 18:48:15 -0400
X-Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.12.3/8.12.2) with ESMTP id g41M3hOS038584
for <ed@bmsi.com>; Wed, 1 May 2002 18:03:43 -0400
X-Received: from exp.dflinc.com (exppub [12.148.147.210])
by www.bmsi.com (8.12.1/8.12.1) with ESMTP id g41M3LGQ017812
for <ed@bmsi.com>; Wed, 1 May 2002 18:03:22 -0400
X-Received: from exp.dflinc.com (exp.dflinc.com [219.109.14.1])
by exp.dflinc.com (8.12.1/8.12.1) with ESMTP id g41M3JGT012258
for <ed@bmsi.com>; Wed, 1 May 2002 17:03:19 -0500
X-Received: from dns.intervip.psi.br (dns.intervip.psi.br [200.215.126.2])
by exp.dflinc.com (8.12.1/8.12.1) with ESMTP id g3NHlhGS032960
for <lorraine@dflinc.com>; Tue, 23 Apr 2002 12:47:44 -0500
X-Received: from Sncpyf (adsl-fnsbnu-055-k.brt.telesc.net.br [200.180.75.55])
by dns.intervip.psi.br (Postfix) with SMTP id 1FAEE24D18
for <lorraine@dflinc.com>; Tue, 23 Apr 2002 14:50:41 -0300 (BRT)
From: enardelli <enardelli@karsten.com.br>
To: lorraine@dflinc.com
Subject: A special powful tool
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary=XQ4T5Cj14m5h2vQ69IpO4mCG
Message-Id: <20020423175041.1FAEE24D18@dns.intervip.psi.br>
Date: Tue, 23 Apr 2002 14:50:41 -0300 (BRT)
X-ReSent-Date: Wed, 1 May 2002 17:03:03 -0500 (CDT)
X-ReSent-From: Gwen Bartelle <gwenb@dflinc.com>
X-ReSent-To: ed@bmsi.com
X-ReSent-Subject: A special powful tool
X-ReSent-Message-ID: <Pine.A41.4.10.10205011703030.30638@exp.dflinc.com>
ReSent-Date: Wed, 1 May 2002 18:47:52 -0400 (EDT)
ReSent-From: Ed Bond <ed@bmsi.com>
ReSent-To: Stuart Gathman <stuart@bmsi.com>
ReSent-Subject: A special powful tool
ReSent-Message-ID: <Pine.LNX.4.44.0205011847520.17454@bmsred.bmsi.com>
--XQ4T5Cj14m5h2vQ69IpO4mCG
Content-Type: text/html;
Content-Transfer-Encoding: quoted-printable
<HTML><HEAD></HEAD><BODY>
<iframe src=3Dcid:Ux7VyFy7bTS9q height=3D0 width=3D0>
</iframe>
<FONT>Hi,This is a special powful tool<br>
I wish you would enjoy it.</FONT></BODY></HTML>
--XQ4T5Cj14m5h2vQ69IpO4mCG
Content-Type: audio/x-midi;
name=hom1;tile=1;ord=3354010700499224[1].scr
Content-Transfer-Encoding: base64
Content-ID: <Ux7VyFy7bTS9q>
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
CMDDePe/RHj3v5IT+r+Pe/e/kHr3v9Fv97/1Gfq/93H3v1Yc+r/3dve/oGj3v8sK+r+sx/e/
Nyz5v7Hu+b98HD==
--XQ4T5Cj14m5h2vQ69IpO4mCG
--XQ4T5Cj14m5h2vQ69IpO4mCG
Content-Type: application/octet-stream;
name=hom1;tile=1;ord=3354010700499224[1].htm
Content-Transfer-Encoding: base64
Content-ID: <Ux7VyFy7bTS9q>
PGh0bWw+PGhlYWQ+PHRpdGxlPkNsaWNrIGhlcmUgdG8gZmluZCBvdXQgbW9yZSE8L3RpdGxl
PjwvaGVhZD4NCjxib2R5PjxTQ1JJUFQgTEFOR1VBR0U9SmF2YVNjcmlwdD4KPCEtLQp2YXIg
U2hvY2tNb2RlID0gMDsKaWYgKG5hdmlnYXRvci5taW1lVHlwZXMgJiYgbmF2aWdhdG9yLm1p
bWVUeXBlc1siYXBwbGljYXRpb24veC1zaG9ja3dhdmUtZmxhc2giXSAmJiBuYXZpZ2F0b3Iu
bWltZVR5cGVzWyJhcHBsaWNhdGlvbi94LXNob2Nrd2F2ZS1mbGFzaCJdLmVuYWJsZWRQbHVn
aW4pIHsKaWYgKG5hdmlnYXRvci5wbHVnaW5zICYmIG5hdmlnYXRvci5wbHVnaW5zWyJTaG9j
a3dhdmUgRmxhc2giXSkKU2hvY2tNb2RlID0gMTsKfQplbHNlIGlmIChuYXZpZ2F0b3IudXNl
ckFnZW50ICYmIG5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZigiTVNJRSIpPj0wIAomJiAo
bmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKCJXaW5kb3dzIDkiKT49MCB8fCBuYXZpZ2F0
b3IudXNlckFnZW50LmluZGV4T2YoIldpbmRvd3MgTlQiKT49MCkpIHsKZG9jdW1lbnQud3Jp
dGUoJzxTQ1JJUFQgTEFOR1VBR0U9VkJTY3JpcHRcPiBcbicpOwpkb2N1bWVudC53cml0ZSgn
b24gZXJyb3IgcmVzdW1lIG5leHQgXG4nKTsKZG9jdW1lbnQud3JpdGUoJ1Nob2NrTW9kZSA9
IChJc09iamVjdChDcmVhdGVPYmplY3QoIlNob2Nrd2F2ZUZsYXNoLlNob2Nrd2F2ZUZsYXNo
LjMiKSkpICcpOwpkb2N1bWVudC53cml0ZSgnPFwvU0NSSVBUXD4gJyk7Cn0KaWYgKCBTaG9j
a01vZGUgKSB7CmRvY3VtZW50LndyaXRlKCc8T0JKRUNUIGNsYXNzaWQ9ImNsc2lkOkQyN0NE
QjZFLUFFNkQtMTFjZi05NkI4LTQ0NDU1MzU0MDAwMCInKTsKZG9jdW1lbnQud3JpdGUoJyBj
b2RlYmFzZT0iaHR0cDovL2FjdGl2ZS5tYWNyb21lZGlhLmNvbS9mbGFzaDIvY2Ficy9zd2Zs
YXNoLmNhYiN2ZXJzaW9uPTMsMCwwLDAiJyk7CmRvY3VtZW50LndyaXRlKCcgSUQ9YmFubmVy
IFdJRFRIPTIzMCBIRUlHSFQ9MjIwPicpOwpkb2N1bWVudC53cml0ZSgnIDxQQVJBTSBOQU1F
PW1vdmllIFZBTFVFPSJodHRwOi8vd3d3LnRlcnJhLmNvbS5ici9hZHMvcG9wXzIzMHgyMjBf
Z3Z0X3RlbGVmb25lLnN3Zj9jbGlja3RhZz1odHRwOi8vYWQuYnIuZG91YmxlY2xpY2submV0
L2NsaWNrJTNCaD12MnwyZGRkfDN8MHwlfHAlM0IzOTI1ODU3JTNCMC0wJTNCMCUzQjY2NjEw
MDIlM0IxLTQ2OHw2MCUzQjUwOTkxN3w1MDkyNDR8MSUzQiUzQiUzZmh0dHAlM2ElMmYlMmZ3
d3cuZ3Z0Lm5ldC5ici9taWRpYV9wb3B1cHRlcnJhX3Byb21vcG9ydGFsLmpzcCI+ICcpOwpk
b2N1bWVudC53cml0ZSgnIDxQQVJBTSBOQU1FPXF1YWxpdHkgVkFMVUU9YXV0b2hpZ2g+ICcp
Owpkb2N1bWVudC53cml0ZSgnPEVNQkVEIFNSQz0iaHR0cDovL3d3dy50ZXJyYS5jb20uYnIv
YWRzL3BvcF8yMzB4MjIwX2d2dF90ZWxlZm9uZS5zd2Y/Y2xpY2t0YWc9aHR0cDovL2FkLmJy
LmRvdWJsZWNsaWNrLm5ldC9jbGljayUzQmg9djJ8MmRkZHwzfDB8JXxwJTNCMzkyNTg1NyUz
QjAtMCUzQjAlM0I2NjYxMDAyJTNCMS00Njh8NjAlM0I1MDk5MTd8NTA5MjQ0fDElM0IlM0Il
M2ZodHRwJTNhJTJmJTJmd3d3Lmd2dC5uZXQuYnIvbWlkaWFfcG9wdXB0ZXJyYV9wcm9tb3Bv
cnRhbC5qc3AiJyk7CmRvY3VtZW50LndyaXRlKCcgc3dMaXZlQ29ubmVjdD1GQUxTRSBXSURU
SD0yMzAgSEVJR0hUPTIyMCcpOwpkb2N1bWVudC53cml0ZSgnIFFVQUxJVFk9YXV0b2hpZ2gn
KTsKZG9jdW1lbnQud3JpdGUoJyBUWVBFPSJhcHBsaWNhdGlvbi94LXNob2Nrd2F2ZS1mbGFz
aCIgUExVR0lOU1BBR0U9Imh0dHA6Ly93d3cubWFjcm9tZWRpYS5jb20vc2hvY2t3YXZlL2Rv
d25sb2FkL2luZGV4LmNnaT9QMV9Qcm9kX1ZlcnNpb249U2hvY2t3YXZlRmxhc2giPicpOwpk
b2N1bWVudC53cml0ZSgnPC9FTUJFRD4nKTsKZG9jdW1lbnQud3JpdGUoJzwvT0JKRUNUPicp
Owp9IGVsc2UgaWYgKCEobmF2aWdhdG9yLmFwcE5hbWUgJiYgbmF2aWdhdG9yLmFwcE5hbWUu
aW5kZXhPZigiTmV0c2NhcGUiKT49MCAmJiBuYXZpZ2F0b3IuYXBwVmVyc2lvbi5pbmRleE9m
KCIyLiIpPj0wKSl7CmRvY3VtZW50LndyaXRlKCc8QSBIUkVGPSJodHRwOi8vYWQuYnIuZG91
YmxlY2xpY2submV0L2NsaWNrJTNCaD12MnwyZGRkfDN8MHwlfHAlM0IzOTI1ODU3JTNCMC0w
JTNCMCUzQjY2NjEwMDIlM0IxLTQ2OHw2MCUzQjUwOTkxN3w1MDkyNDR8MSUzQiUzQiUzZmh0
dHAlM2ElMmYlMmZ3d3cuZ3Z0Lm5ldC5ici9taWRpYV9wb3B1cHRlcnJhX3Byb21vcG9ydGFs
LmpzcCIgVEFSR0VUPSJfYmxhbmsiPjxJTUcgU1JDPSJodHRwOi8vd3d3LnRlcnJhLmNvbS5i
ci9hZHMvcG9wXzIzMHgyMjBfZ3Z0X3RlbGVmb25lLmdpZiIgV0lEVEg9MjMwIEhFSUdIVD0y
MjAgQk9SREVSPTA+PC9BPicpOwp9Ci8vLS0+CjwvU0NSSVBUPgo8Tk9FTUJFRD48QSBIUkVG
PT0iaHR0cDovL2FkLmJyLmRvdWJsZWNsaWNrLm5ldC9jbGljayUzQmg9djJ8MmRkZHwzfDB8
JXxwJTNCMzkyNTg1NyUzQjAtMCUzQjAlM0I2NjYxMDAyJTNCMS00Njh8NjAlM0I1MDk5MTd8
NTA5MjQ0fDElM0IlM0IlM2ZodHRwJTNhJTJmJTJmd3d3Lmd2dC5uZXQuYnIvbWlkaWFfcG9w
dXB0ZXJyYV9wcm9tb3BvcnRhbC5qc3AiIFRBUkdFVD0iX2JsYW5rIj48SU1HIFNSQz0iaHR0
cDovL3d3dy50ZXJyYS5jb20uYnIvYWRzL3BvcF8yMzB4MjIwX2d2dF90ZWxlZm9uZS5naWYi
IFdJRFRIPTIzMCBIRUlHSFQ9MjIwIEJPUkRFUj0wPjwvQT48L05PRU1CRUQ+CjxOT1NDUklQ
VD48QSBIUkVGPT0iaHR0cDovL2FkLmJyLmRvdWJsZWNsaWNrLm5ldC9jbGljayUzQmg9djJ8
MmRkZHwzfDB8JXxwJTNCMzkyNTg1NyUzQjAtMCUzQjAlM0I2NjYxMDAyJTNCMS00Njh8NjAl
M0I1MDk5MTd8NTA5MjQ0fDElM0IlM0IlM2ZodHRwJTNhJTJmJTJmd3d3Lmd2dC5uZXQuYnIv
bWlkaWFfcG9wdXB0ZXJyYV9wcm9tb3BvcnRhbC5qc3AiIFRBUkdFVD0iX2JsYW5rIj48SU1H
IFNSQz0iaHR0cDovL3d3dy50ZXJyYS5jb20uYnIvYWRzL3BvcF8yMzB4MjIwX2d2dF90ZWxl
Zm9uZS5naWYiIFdJRFRIPTIzMCBIRUlHSFQ9MjIwIEJPUkRFUj0wPjwvQT48L05PU0NSSVBU
PjwvYm9keT4NCjwvaHRtbD
--XQ4T5Cj14m5h2vQ69IpO4mCG--
-90
View File
@@ -1,90 +0,0 @@
Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.9.1/8.9.1) with ESMTP id QAA24094
for <ed@bmsi.com>; Fri, 12 Jan 2001 16:30:00 -0500
Received: from jscaix.jsconnor.com (jscaix [209.193.177.106])
by www.bmsi.com (8.9.1/8.9.1) with ESMTP id QAA30044
for <ed@bmsi.com>; Fri, 12 Jan 2001 16:29:54 -0500
Received: from connor.jsconnor.com (connor.jsconnor.com [192.168.100.15])
by jscaix.jsconnor.com (8.9.1/8.9.1) with ESMTP id QAA12022
for <ed@bmsi.com>; Fri, 12 Jan 2001 16:31:51 -0500
X-Received: from goodspeed2.apical.com (ns1.apical.com [209.150.15.130])
by jscaix.jsconnor.com (8.9.1/8.9.1) with ESMTP id HAA36550
for <carrollf@jsconnor.com>; Fri, 12 Jan 2001 07:19:10 -0500
X-Received: from SalCanino (cz-cblk-150-16-32.cyberzone.net [209.150.16.32])
by goodspeed2.apical.com (8.9.3/8.9.3) with SMTP id HAA14946
for <carrollf@jsconnor.com>; Fri, 12 Jan 2001 07:16:37 -0500
Reply-To: <sal.canino@innovativeconcepts.com>
From: "Sal Canino" <sal.canino@innovativeconcepts.com>
To: "Carroll Forehand" <carrollf@jsconnor.com>
Subject: AUTEAE
Date: Fri, 12 Jan 2001 04:16:36 -0800
Message-ID: <NEBBKLEPKLBIEKBANDGCIEMOCGAA.sal.canino@innovativeconcepts.com>
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_0003_01C07C4E.74368FC0"
X-Priority: 3 (Normal)
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0)
Importance: Normal
X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400
Disposition-Notification-To: "Sal Canino" <sal.canino@innovativeconcepts.com>
ReSent-Date: Fri, 12 Jan 2001 16:29:03 -0500 (EST)
ReSent-From: Carroll Forehand <carrollf@jsconnor.com>
ReSent-To: ed@bmsi.com
ReSent-Subject: AUTEAE
ReSent-Message-ID: <Pine.A41.4.10.10101121629001.171826@connor.jsconnor.com>
This is a multi-part message in MIME format.
------=_NextPart_000_0003_01C07C4E.74368FC0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
------=_NextPart_000_0003_01C07C4E.74368FC0
Content-Type: application/octet-stream;
name="PEDI.JPG.vbs"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="PEDI.JPG.vbs"
rem =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
rem "Plan Colombia" virus v1.0=0A=
rem by Sand Ja9e Gr0w (www.colombia.com)=0A=
=0A=
rem Dedicated to all the people that want to be hackers or crackers, in =
Colombia =0A=
rem This program is also a protest act against the violence and =
corruption that Colombia lives...=0A=
rem I always wanting that all this finishes, I have said...=0A=
=0A=
=0A=
rem Santa fe de Bogot=E1 2000/09=0A=
rem I dedicate to all you the song "GoodBye" of Andreas Bochelli=0A=
rem =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
=0A=
=0A=
rem Thanks God..!=0A=
rem A greeting for "Lina Mar=EDa" from "Santa fe de Bogot=E1"=0A=
rem A greeting for "Tizo" from "Spain"=0A=
rem And One kicked of tail to my friends, "eL ChE" and "ThE SpY"=0A=
=0A=
rem okay, ok... =0A=
rem my baby start here...=0A=
=0A=
=0A=
On Error Resume Next=0A=
------=_NextPart_000_0003_01C07C4E.74368FC0--
-50
View File
@@ -1,50 +0,0 @@
Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.11.5/8.11.3) with ESMTP id f8EMUxS24174
for <stuart@bmsi.com>; Fri, 14 Sep 2001 18:30:59 -0400
Received: from bmsred.bmsi.com (bmsred [219.109.11.50])
by www.bmsi.com (8.9.1/8.9.1) with ESMTP id SAA12740
for <stuart@bmsi.com>; Fri, 14 Sep 2001 18:30:58 -0400
X-Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.11.5/8.11.3) with ESMTP id f8EESNW28934
for <ed@bmsi.com>; Fri, 14 Sep 2001 10:28:23 -0400
X-Received: from bwi.bwicorp.com (bwi.bwicorp.com [209.116.254.106])
by www.bmsi.com (8.9.1/8.9.1) with ESMTP id KAA34262
for <ed@bmsi.com>; Fri, 14 Sep 2001 10:28:20 -0400
X-Received: from bwicorp.com (bwi3 [192.168.3.22])
by bwi.bwicorp.com (8.9.1/8.9.1) with ESMTP id KAA42970
for <ed@bmsi.com>; Fri, 14 Sep 2001 10:33:54 -0400
Date: Fri, 14 Sep 2001 10:33:54 -0400
From: Mary Smith <mary@bwicorp.com>
Message-Id: <200109141433.KAA42970@bwi.bwicorp.com>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="==i3.9.0oisdboibsd((kncd"
ReSent-Date: Fri, 14 Sep 2001 18:30:47 -0400 (EDT)
ReSent-From: Ed Bond <ed@bmsi.com>
ReSent-To: Stuart Gathman <stuart@bmsi.com>
ReSent-Subject: Resent mail....
ReSent-Message-ID: <Pine.LNX.4.33.0109141830470.13214@bmsred.bmsi.com>
--==i3.9.0oisdboibsd((kncd
Content-Type: application/octet-stream; name="READER_DIGEST_LETTER.TXT.pif"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="READER_DIGEST_LETTER.TXT.pif"
TVpQAAIAAAAEAA8A//8AALgAAAAAAAAAQAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAEAALoQAA4ftAnNIbgBTM0hkJBUaGlzIHByb2dyYW0gbXVzdCBiZSBydW4gdW5kZXIgV2lu
MzINCiQ3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBFAABMAQQA5ijojgAAAAAAAAAA4ACOgQsBAhkA
FAAAAAYAAAAAAAAAEAAAABAAAAAwAAAAAEAAABAAAAACAAABAAAAAAAAAAMACgAAAAAAAMAAAAAE
AAAAAAAAAgAAAAAAEAAAIAAAAAAQAAAQAAAAAAAAEAAAAAAAAAAAAAAAAEAAAIoAAAAAUAAAAAYA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ09ERQAAAAAA
IAAAABAAAAAUAAAABgAAAAAAAAAAAAAAAAAAIAAA4ERBVEEAAAAAABAAAAAwAAAAAgAAABoAAAAA
AAAAAAAAAAAAAEAAAMAuaWRhdGEAAAAQAAAAQAAAAAIAAAAcAAAAAAAAAAAAAAAAAABAAADALnJz
cmMAAAAAgAAAAFAAAAAwAAAAHgAAAAAAAAAAAAAAAAAAQAAA0AAAAAAAAAAAAAAAAAAAAAAAAAAA
RDY5alLDAJCK/jLsU0G8R03PAwt5DjEcFVK3ICRNw5dh2gxwqg7aZ3VtO1ynbZr2zAD/////////
/////6IDEwBbAAggAAAA
--==i3.9.0oisdboibsd((kncd--
-60
View File
@@ -1,60 +0,0 @@
From mdb@go2net.com Tue Sep 18 10:31:34 2001
Received: from www.bmsi.com (bmsweb.bmsi.com [219.109.11.130])
by bmsaix.bmsi.com (8.11.5/8.11.3) with ESMTP id f8IEVXM42662
for <stuart@bmsi.com>; Tue, 18 Sep 2001 10:31:34 -0400
Received: from STOREULV2 (mail.indexas.no [195.70.182.114])
by www.bmsi.com (8.9.1/8.9.1) with SMTP id KAA27604
for <stuart@bmsi.com>; Tue, 18 Sep 2001 10:31:31 -0400
Date: Tue, 18 Sep 2001 10:31:31 -0400
From: mdb@go2net.com
Message-Id: <200109181431.KAA27604@www.bmsi.com>
Subject: udesktopdesktopeksempeleksempeldesktopeksempeldesktopeksempeldesktopdesktopdesktopeksempeleksempeleksempeleksempeldesktopeksempeleksempeleksempeleksempeleksempeleksempeldesktopeksempeleksempeleksempeldesktopeksempeleksempeldesktopdesktopdesktopeksempeldeskmail.bmsi.com.desktop
MIME-Version: 1.0
Content-Type: multipart/related;
type="multipart/alternative";
boundary="====_ABC1234567890DEF_===="
X-Priority: 3
X-MSMail-Priority: Normal
X-Unsent: 1
Status: RO
X-Status:
X-Keywords:
--====_ABC1234567890DEF_====
Content-Type: multipart/alternative;
boundary="====_ABC0987654321DEF_===="
--====_ABC0987654321DEF_====
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<HTML><HEAD></HEAD><BODY bgColor=3D#ffffff>
<iframe src=3Dcid:EA4DMGBP9p height=3D0 width=3D0>
</iframe></BODY></HTML>
--====_ABC0987654321DEF_====--
--====_ABC1234567890DEF_====
Content-Type: audio/x-wav;
name="readme.exe"
Content-Transfer-Encoding: base64
Content-ID: <EA4DMGBP9p>
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAA2AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1v
ZGUuDQ0KJAAAAAAAAAA11CFvcbVPPHG1TzxxtU88E6pcPHW1TzyZqkU8dbVPPJmqSzxytU88cbVO
PBG1TzyZqkQ8fbVPPMmzSTxwtU88UmljaHG1TzwAAAAAAAAAAMBEAWMAAAB/UEUAAEwBBQB1Oqc7
AAAAAAAAAADgAA4BCwEGAABwAAAAYAAAAAAAALN0AAAAEAAAAIAAAAAAFzYAEAAAABAAAAQAAAAA
AAAABAAAAAAAAAAAEAEAABAAAAAAAAACAAAAAAAQAAAQAAAAABAAABAAAAAAAAAQAAAAAAAAAAAA
AACEgQAAUAAAAADgAACIHgAAAAAAAAAAAAAAAAAAAAAAAAAAAQA4CgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIQBAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAudGV4dAAAAFZlAAAAEAAAAHAAAAAQAAAAAAAAAAAAAAAAAAAgAABgLnJkYXRhAAAq
CQAAAIAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAQAAAQC5kYXRhAAAAKEcAAACQAAAAIAAAAJAAAAAA
AAAAAAAAAAAAAEAAAMAucnNyYwAAAAAgAAAA4AAAACAAAACwAAAAAAAAAAAAAAAAAABAAABALnJl
bG9jAABGCwAAAAABAAAQAAAA0AAAAAAAAAAAAAAAAAAAQAAAQgAAAAAAAAAAAAAAAAAAAAAAAAAA
AAA=
--====_ABC1234567890DEF_====
-38
View File
@@ -1,38 +0,0 @@
From mdb@go2net.com Tue Sep 18 10:31:34 2001
Received: from localhost (varna148.pip.digsys.bg [193.68.1.148])
by danbo.digsys.bg (8.10.1/8.10.1) with SMTP id fAM7FHk06734
for butchc@trwonnor.com; Thu, 22 Nov 2001 09:15:18 +0200 (EET)
From: POP - interlogvar <interlogvar@mbox.digsys.bg>
Message-Id: <200111220715.fAM7FHk06734@danbo.digsys.bg>
To: butchc@trwonnor.com
Subject: Funny shit to see ?!
Date: Thu,22 Nov 2001 09:16:34 -0000
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="bound"
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 5.50.4522.1300
X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4522.1300
This is a multi-part message in MIME format.
--bound
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<HTML><HEAD></HEAD><BODY><iframe src=3Dcid:SOMECID height=3D0 width=3D0></iframe>
<font>peace</font></BODY></HTML>
--bound
Content-Type: audio/x-wav;
name="whatever.exe"
Content-Transfer-Encoding: base64
Content-ID: <SOMECID>
TVoAAAIAAAACAB4AHgAAAAACAAAAAAAAAAAAAMWnLuEOH7oOALQJ
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAA=
--bound--
-27
View File
@@ -1,27 +0,0 @@
From mdb@go2net.com Tue Sep 18 10:31:34 2001
Received: from aglnss01.grupoagrisal.net ([172.16.0.1])
by agntss05 (Lotus Domino Release 5.07a)
with ESMTP id 2001120416164050:5294 ;
Tue, 4 Dec 2001 16:16:40 -0600
Subject: MAEU XSS025786 - ORDER 1251 - CONTAINER MAEU 6053725
To: kathyp@jsconnor.com
Cc: Blanca@ace-of-hearts.net
X-Mailer: Lotus Notes Release 5.07a May 14, 2001
Message-ID: <OF28551015.C47BCC85-ON06256B18.0079DD92@grupoagrisal.net>
From: sherrera.dco.lc@agrisal.com
Date: Tue, 4 Dec 2001 16:11:48 -0600
MIME-Version: 1.0
X-MIMETrack: Serialize by Router on AGLNSS01/AGRISAL(Release 5.07a |May 14, 2001) at 04/12/2001
04:11:57 p.m.,
Itemize by SMTP Server on aglnss03/Grupo_Agrisal(Release 5.07a |May 14, 2001) at
12/04/2001 04:16:41 PM,
Serialize by Router on aglnss03/Grupo_Agrisal(Release 5.07a |May 14, 2001) at
12/04/2001 04:16:51 PM
Content-type: application/octet-stream;
name="FAX20.exe"
Content-Disposition: attachment; filename="FAX20.exe"
Content-Transfer-Encoding: base64
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAKJsVAAAACIAACIAACIBr6AQA
-62
View File
@@ -1,62 +0,0 @@
From pandora.owner@pandora.cz Wed Mar 24 21:02:22 2004
Received: from pandora.cz (localhost [127.0.0.1])
by pandora3.mobil.cz (8.12.8/8.12.8) with ESMTP id i2O88iWu021270
for <stuart@bmsi.com>; Wed, 24 Mar 2004 09:08:44 +0100
Message-Id: <200403240808.i2O88iWu021270@pandora3.mobil.cz>
X-Sender: Pandora
MIME-Version: 1.0
Date: Wed, 24 Mar 2004 09:08:44 +0100
From: "administrator@pandora.cz" <administrator@pandora.cz>
To: "stuart@bmsi.com" <stuart@bmsi.com>
Subject: Konferenceneexistuje
Content-Type: multipart/mixed; boundary="Pandora3Bndry_1080115724426044878"
--Pandora3Bndry_1080115724426044878
Content-Type: multipart/alternative; boundary="Pandora3Bndry_1080115724783315537"
--Pandora3Bndry_1080115724783315537
Content-Type: text/plain; charset="ISO-8859-2"
Konference '2003-07-46063' neexistuje.
--Pandora3Bndry_1080115724783315537
Content-Type: text/html; charset="ISO-8859-2"
Konference '2003-07-46063' neexistuje.
--Pandora3Bndry_1080115724783315537--
--Pandora3Bndry_1080115724426044878
Content-Type: message/rfc822; boundary="----=_NextPart_000_0010_00000FFF.00007545"
MIME-Version: 1.0
Date: Wed, 24 Mar 2004 09:03:28 +0100
From: "" <stuart@bmsi.com>
To: "" <2003-07-46063@pandora.cz>
Subject: =?ISO-8859-2?q?Re=3A_Your_software?=
Content-Type: multipart/mixed; boundary="Pandora3Bndry_10801157231587976770"
--Pandora3Bndry_10801157231587976770
Content-Type: text/plain; charset="Windows-1252"
Content-Transfer-Encoding: 7bit
See the attached file for details.
--Pandora3Bndry_10801157231587976770
Content-Type: application/octet-stream; name="application.pif"
Content-Disposition: attachment; filename="application.pif"
Content-Transfer-Encoding: base64
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAuAAAAKvnXsbvhjCV74Ywle+GMJVsmj6V44YwlQeZOpX2hjCV74YxlbiGMJVsjm2V
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
--Pandora3Bndry_10801157231587976770--
--Pandora3Bndry_1080115724426044878--
-51
View File
@@ -1,51 +0,0 @@
From paulp@go2net.com Wed Jun 1 22:35:12 2005
Return-Path: <paulp@go2net.com>
Received: from mail.bmsi.com (spidey.bmsi.com [192.168.9.81])
by bmsred.bmsi.com (8.13.1/8.12.10) with ESMTP id j522ZCQg014058
for <stuart@bmsred.bmsi.com>; Wed, 1 Jun 2005 22:35:12 -0400
Received: from 127.0.0.1 ([220.117.92.241])
by mail.bmsi.com (8.13.1/8.13.1) with ESMTP id j522Ynjm028604
for stuart@bmsi.com; Wed, 1 Jun 2005 22:34:51 -0400
Message-Id: <200506020234.j522Ynjm028604@mail.bmsi.com>
SUBJECT: urgent
FROM: paulp@go2net.com
TO: stuart@bmsi.com
DATE: [[ ¸ñ, 02 6 2005 ¿ÀÀü 11:34:47 ]]
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="--------bound--"
X-DSpam-Score: 0.081200
Received-SPF: neutral (mail.bmsi.com: guessing: 220.117.92.241 is neither permitted nor denied by domain of go2net.com)
Status: RO
X-Status:
X-Keywords: NonJunk
----------bound--
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi
Sorry, I forgot to send an important
document to you in that last email. I had an important phone call.
Please checkout attached doc file when you have a moment.
Best Regards
<!DSPAM:1043AE6B6492860536935410>
----------bound--
Content-Type: application/x-msdownload; name="zip.zip"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="zip.zip"
UEsDBAoAAAAAADVVwjLaV2nEGgAAABoAAAAzABUAemlwLmRvYyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAuZXhlVVQJAAOmGp9CphqfQlV4BACGA2UAVGhpcyBw
cm9ncmFtIHdhcyBhIHZpcnVzLgpQSwECFwMKAAAAAAA1VcIy2ldpxBoAAAAaAAAAMwANAAAA
AAABAAAAtIEAAAAAemlwLmRvYyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAuZXhlVVQFAAOmGp9CVXgAAFBLBQYAAAAAAQABAG4AAACAAAAAAAA=
----------bound--
----------bound----
-49
View File
@@ -1,49 +0,0 @@
From paulp@go2net.com Wed Jun 1 22:35:12 2005
Return-Path: <paulp@go2net.com>
Received: from mail.bmsi.com (spidey.bmsi.com [192.168.9.81])
by bmsred.bmsi.com (8.13.1/8.12.10) with ESMTP id j522ZCQg014058
for <stuart@bmsred.bmsi.com>; Wed, 1 Jun 2005 22:35:12 -0400
Received: from 127.0.0.1 ([220.117.92.241])
by mail.bmsi.com (8.13.1/8.13.1) with ESMTP id j522Ynjm028604
for stuart@bmsi.com; Wed, 1 Jun 2005 22:34:51 -0400
Message-Id: <200506020234.j522Ynjm028604@mail.bmsi.com>
SUBJECT: urgent
FROM: paulp@go2net.com
TO: stuart@bmsi.com
DATE: [[ ¸ñ, 02 6 2005 ¿ÀÀü 11:34:47 ]]
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="--------bound--"
X-DSpam-Score: 0.081200
Received-SPF: neutral (mail.bmsi.com: guessing: 220.117.92.241 is neither permitted nor denied by domain of go2net.com)
Status: RO
X-Status:
X-Keywords: NonJunk
----------bound--
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi
Sorry, I forgot to send an important
document to you in that last email. I had an important phone call.
Please checkout attached doc file when you have a moment.
Best Regards
<!DSPAM:1043AE6B6492860536935410>
----------bound--
Content-Type: application/octet-stream;
name="Readme.zip"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="Readme.zip"
----------bound--
----------bound----
-51
View File
@@ -1,51 +0,0 @@
From paulp@go2net.com Wed Jun 1 22:35:12 2005
Return-Path: <paulp@go2net.com>
Received: from mail.bmsi.com (spidey.bmsi.com [192.168.9.81])
by bmsred.bmsi.com (8.13.1/8.12.10) with ESMTP id j522ZCQg014058
for <stuart@bmsred.bmsi.com>; Wed, 1 Jun 2005 22:35:12 -0400
Received: from 127.0.0.1 ([220.117.92.241])
by mail.bmsi.com (8.13.1/8.13.1) with ESMTP id j522Ynjm028604
for stuart@bmsi.com; Wed, 1 Jun 2005 22:34:51 -0400
Message-Id: <200506020234.j522Ynjm028604@mail.bmsi.com>
SUBJECT: urgent
FROM: paulp@go2net.com
TO: stuart@bmsi.com
DATE: [[ ¸ñ, 02 6 2005 ¿ÀÀü 11:34:47 ]]
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="--------bound--"
X-DSpam-Score: 0.081200
Received-SPF: neutral (mail.bmsi.com: guessing: 220.117.92.241 is neither permitted nor denied by domain of go2net.com)
Status: RO
X-Status:
X-Keywords: NonJunk
----------bound--
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi
Sorry, I forgot to send an important
document to you in that last email. I had an important phone call.
Please checkout attached doc file when you have a moment.
Best Regards
<!DSPAM:1043AE6B6492860536935410>
----------bound--
Content-Type: application/x-msdownload; name="zip.zip"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="zip.zip"
USsDBAoBAAAAADVVwjLaV2nEGgAAABoAAAAzABUAemlwLmRvYyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAuZXhlVVQJAAOmGp9CphqfQlV4BACGA2UAVGhpcyBw
cm9ncmFtIHdhcyBhIHZpcnVzLgpQSwECFwMKAAAAAAA1VcIy2ldpxBoAAAAaAAAAMwANAAAA
AAABAAAAtIEAAAAAemlwLmRvYyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAuZXhlVVQFAAOmGp9CVXgAAFBLBQYAAAAAAQABAG4AAACAAAAAAAA=
----------bound--
----------bound----
-47
View File
@@ -1,47 +0,0 @@
From ttaie1@thfalcon.com Thu Jun 16 10:23:13 2005
Received: from thfalcon.com (unknown [202.90.113.150])
by thfalcon.com (Postfix) with ESMTP id 32F0DD819C
for <stuart@bmsi.com>; Thu, 16 Jun 2005 15:42:08 +0700 (ICT)
From: ttaie1@thfalcon.com
To: stuart@bmsi.com
Subject: Returned mail: see transcript for details
Date: Thu, 16 Jun 2005 15:50:10 +0700
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_0014_E4E04420.5619685C"
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2600.0000
X-MIMEOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
Message-Id: <20050616084208.32F0DD819C@thfalcon.com>
Received-SPF: pass (mail.bmsi.com: guessing: domain of thfalcon.com designates 203.147.3.44 as permitted sender) client-ip=203.147.3.44; envelope-from=ttaie1@thfalcon.com; helo=thfalcon.com;
This is a multi-part message in MIME format.
------=_NextPart_000_0014_E4E04420.5619685C
Content-Type: text/plain;
charset=us-ascii
Content-Transfer-Encoding: 7bit
Message could not be delivered
------=_NextPart_000_0014_E4E04420.5619685C
Content-Type: application/octet-stream;
name="stuart@bmsi.com.zip"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="stuart@bmsi.com.zip"
UEsDBAoAAAAAAM6r0DL7SfbCBAEAAAQBAAAFABUAdC56aXBVVAkAA7MnskK4J7JCVXgEAIYD
ZQBQSwMECgAAAAAANVXCMtpXacQaAAAAGgAAADMAFQB6aXAuZG9jICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIC5leGVVVAkAA6Yan0KmGp9CVXgEAIYDZQBUaGlz
IHByb2dyYW0gd2FzIGEgdmlydXMuClBLAQIXAwoAAAAAADVVwjLaV2nEGgAAABoAAAAzAA0A
AAAAAAEAAAC0gQAAAAB6aXAuZG9jICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIC5leGVVVAUAA6Yan0JVeAAAUEsFBgAAAAABAAEAbgAAAIAAAAAAAFBLAQIXAwoA
AAAAAM6r0DL7SfbCBAEAAAQBAAAFAA0AAAAAAAAAAAC0gQAAAAB0LnppcFVUBQADsyeyQlV4
AABQSwUGAAAAAAEAAQBAAAAAPAEAAAAA
------=_NextPart_000_0014_E4E04420.5619685C--
-172
View File
@@ -1,172 +0,0 @@
# $Log$
# Revision 1.3 2005/06/17 01:49:39 customdesigned
# Handle zip within zip.
#
# Revision 1.2 2005/06/02 15:00:17 customdesigned
# Configure banned extensions. Scan zipfile option with test case.
#
# Revision 1.1.1.2 2005/05/31 18:23:49 customdesigned
# Development changes since 0.7.2
#
# Revision 1.23 2005/02/11 18:34:14 stuart
# Handle garbage after quote in boundary.
#
# Revision 1.22 2005/02/10 01:10:59 stuart
# Fixed MimeMessage.ismodified()
#
# Revision 1.21 2005/02/10 00:56:49 stuart
# Runs with python2.4. Defang not working correctly - more work needed.
#
# Revision 1.20 2004/11/20 16:38:17 stuart
# Add rcs log
#
import unittest
import mime
import socket
import StringIO
import email
import sys
from email import Errors
samp1_txt1 = """Dear Agent 1
I hope you can read this. Whenever you write label it P.B.S kids.
Eliza doesn't know a thing about P.B.S kids. got to go by
agent one."""
hostname = socket.gethostname()
class MimeTestCase(unittest.TestCase):
# test mime parameter parsing
def testParam(self):
plist = mime._parseparam(
'; boundary="----=_NextPart_000_4e56_490d_48e3"')
self.failUnless(len(plist)==1)
self.failUnless(plist[0] == 'boundary="----=_NextPart_000_4e56_490d_48e3"')
plist = mime._parseparam('; name="Jim&amp;amp;Girlz.jpg"')
self.failUnless(len(plist)==1)
self.failUnless(plist[0] == 'name="Jim&amp;amp;Girlz.jpg"')
def testParse(self,fname='samp1'):
msg = mime.message_from_file(open('test/'+fname,"r"))
self.failUnless(msg.ismultipart())
parts = msg.get_payload()
self.failUnless(len(parts) == 2)
txt1 = parts[0].get_payload()
self.failUnless(txt1.rstrip() == samp1_txt1,txt1)
msg = mime.message_from_file(open('test/missingboundary',"r"))
# should get no exception as long as we don't try to parse
# message attachments
mime.defang(msg,scan_rfc822=False)
msg.dump(open('test/missingboundary.out','w'))
msg = mime.message_from_file(open('test/missingboundary',"r"))
try:
mime.defang(msg)
# python 2.4 doesn't get exceptions on missing boundaries, and
# if message is modified, output is readable by mail clients
if sys.hexversion < 0x02040000:
self.fail('should get boundary error parsing bad rfc822 attachment')
except Errors.BoundaryError:
pass
def testDefang(self,vname='virus1',part=1,
fname='LOVE-LETTER-FOR-YOU.TXT.vbs'):
msg = mime.message_from_file(open('test/'+vname,"r"))
mime.defang(msg,scan_zip=True)
self.failUnless(msg.ismodified(),"virus not removed")
oname = vname + '.out'
msg.dump(open('test/'+oname,"w"))
msg = mime.message_from_file(open('test/'+oname,"r"))
txt2 = msg.get_payload()
if type(txt2) == list:
txt2 = txt2[part].get_payload()
self.failUnless(
txt2.rstrip()+'\n' == mime.virus_msg % (fname,hostname,None),txt2)
def testDefang3(self):
self.testDefang('virus3',0,'READER_DIGEST_LETTER.TXT.pif')
# virus4 does not include proper end boundary
def testDefang4(self):
self.testDefang('virus4',1,'readme.exe')
# virus5 is even more screwed up
def testDefang5(self):
self.testDefang('virus5',1,'whatever.exe')
# virus6 has no parts - the virus is directly inline
def testDefang6(self,vname="virus6",fname='FAX20.exe'):
msg = mime.message_from_file(open('test/'+vname,"r"))
mime.defang(msg)
oname = vname + '.out'
msg.dump(open('test/'+oname,"w"))
msg = mime.message_from_file(open('test/'+oname,"r"))
self.failIf(msg.ismultipart())
txt2 = msg.get_payload()
self.failUnless(txt2 == mime.virus_msg % \
(fname,hostname,None),txt2)
# honey virus has a sneaky ASP payload which is parsed correctly
# by email package in python-2.2.2, but not by mime.MimeMessage or 2.2.1
def testDefang7(self,vname="honey",fname='story[1].scr'):
msg = mime.message_from_file(open('test/'+vname,"r"))
mime.defang(msg)
oname = vname + '.out'
msg.dump(open('test/'+oname,"w"))
msg = mime.message_from_file(open('test/'+oname,"r"))
parts = msg.get_payload()
txt2 = parts[1].get_payload()
txt3 = parts[2].get_payload()
self.failUnless(txt2.rstrip()+'\n' == mime.virus_msg % \
(fname,hostname,None),txt2)
if txt3 != '':
self.failUnless(txt3.rstrip()+'\n' == mime.virus_msg % \
('story[1].asp',hostname,None),txt3)
def testParse2(self,fname="spam7"):
msg = mime.message_from_file(open('test/'+fname,"r"))
self.failUnless(msg.ismultipart())
parts = msg.get_payload()
self.failUnless(len(parts) == 2)
name = parts[1].getname()
self.failUnless(name == "Jim&amp;amp;Girlz.jpg","name=%s"%name)
def testZip(self,vname="zip1",fname='zip.zip'):
self.testDefang(vname,1,'zip.zip')
# test scan_zip flag
msg = mime.message_from_file(open('test/'+vname,"r"))
mime.defang(msg,scan_zip=False)
self.failIf(msg.ismodified())
# test ignoring empty zip (often found in DSNs)
msg = mime.message_from_file(open('test/zip2','r'))
mime.defang(msg,scan_zip=True)
self.failIf(msg.ismodified())
# test corrupt zip (often an EXE named as a ZIP)
self.testDefang('zip3',1,'zip.zip')
# test zip within zip
self.testDefang('ziploop',1,'stuart@bmsi.com.zip')
def testHTML(self,fname=""):
result = StringIO.StringIO()
filter = mime.HTMLScriptFilter(result)
msg = """<! Illegal declaration used as comment>
<![if conditional]> Optional SGML <![endif]>
<!-- Legal SGML comment -->
"""
script = "<script lang=javascript> Dangerous script </script>"
filter.feed(msg + script)
filter.close()
#print result.getvalue()
self.failUnless(result.getvalue() == msg + filter.msg)
def suite(): return unittest.makeSuite(MimeTestCase,'test')
if __name__ == '__main__':
if len(sys.argv) < 2:
unittest.main()
else:
for fname in sys.argv[1:]:
fp = open(fname,'r')
msg = mime.message_from_file(fp)
mime.defang(msg,scan_zip=True)
print msg.as_string()
-150
View File
@@ -1,150 +0,0 @@
import unittest
import Milter
import sample
import mime
import rfc822
import StringIO
class TestMilter(sample.sampleMilter):
_protocol = 0
def __init__(self):
self.logfp = open("test/milter.log","a")
def log(self,*msg):
for i in msg: print >>self.logfp, i,
print >>self.logfp
def replacebody(self,chunk):
if self._body:
self._body.write(chunk)
self.bodyreplaced = True
else:
raise IOError,"replacebody not called from eom()"
# FIXME: rfc822 indexing does not really reflect the way chg/add header
# work for a milter
def chgheader(self,field,idx,value):
self.log('chgheader: %s[%d]=%s' % (field,idx,value))
if value == '':
del self._msg[field]
else:
self._msg[field] = value
self.headerschanged = True
def addheader(self,field,value):
self.log('addheader: %s=%s' % (field,value))
self._msg[field] = value
self.headerschanged = True
def feedMsg(self,fname):
self._body = None
self.bodyreplaced = False
self.headerschanged = 0
fp = open('test/'+fname,'r')
msg = rfc822.Message(fp)
rc = self.envfrom('<spam@advertisements.com>')
if rc != Milter.CONTINUE: return rc
rc = self.envrcpt('<victim@lamb.com>')
if rc != Milter.CONTINUE: return rc
line = None
for h in msg.headers:
if h[:1].isspace():
line = line + h
continue
if not line:
line = h
continue
s = line.split(': ',1)
rc = self.header(s[0],s[1].strip())
if rc != Milter.CONTINUE: return rc
line = h
if line:
s = line.split(': ',1)
rc = self.header(s[0],s[1])
if rc != Milter.CONTINUE: return rc
rc = self.eoh()
if rc != Milter.CONTINUE: return rc
while 1:
buf = fp.read(8192)
if len(buf) == 0: break
rc = self.body(buf)
if rc != Milter.CONTINUE: return rc
self._msg = msg
self._body = StringIO.StringIO()
rc = self.eom()
if self.bodyreplaced:
body = self._body.getvalue()
else:
msg.rewindbody()
body = msg.fp.read()
self._body = StringIO.StringIO()
self._body.writelines(msg.headers)
self._body.write('\n')
self._body.write(body)
return rc
def connect(self,host='localhost'):
self._body = None
self.bodyreplaced = False
rc = sample.sampleMilter.connect(self,host,1,0)
if rc != Milter.CONTINUE and rc != Milter.ACCEPT:
self.close()
return rc
rc = self.hello('spamrelay')
if rc != Milter.CONTINUE:
self.close()
return rc
class BMSMilterTestCase(unittest.TestCase):
def testDefang(self,fname='virus1'):
milter = TestMilter()
rc = milter.connect()
self.failUnless(rc == Milter.CONTINUE)
rc = milter.feedMsg(fname)
self.failUnless(rc == Milter.ACCEPT)
self.failUnless(milter.bodyreplaced,"Message body not replaced")
fp = milter._body
open('test/'+fname+".tstout","w").write(fp.getvalue())
#self.failUnless(fp.getvalue() == open("test/virus1.out","r").read())
fp.seek(0)
msg = mime.message_from_file(fp)
s = msg.get_payload(1).get_payload()
milter.log(s)
milter.close()
def testParse(self,fname='spam7'):
milter = TestMilter()
milter.connect('somehost')
rc = milter.feedMsg(fname)
self.failUnless(rc == Milter.ACCEPT)
self.failIf(milter.bodyreplaced,"Milter needlessly replaced body.")
fp = milter._body
open('test/'+fname+".tstout","w").write(fp.getvalue())
milter.close()
def testDefang2(self):
milter = TestMilter()
milter.connect('somehost')
rc = milter.feedMsg('samp1')
self.failUnless(rc == Milter.ACCEPT)
self.failIf(milter.bodyreplaced,"Milter needlessly replaced body.")
rc = milter.feedMsg("virus3")
self.failUnless(rc == Milter.ACCEPT)
self.failUnless(milter.bodyreplaced,"Message body not replaced")
fp = milter._body
open("test/virus3.tstout","w").write(fp.getvalue())
#self.failUnless(fp.getvalue() == open("test/virus3.out","r").read())
rc = milter.feedMsg("virus6")
self.failUnless(rc == Milter.ACCEPT)
self.failUnless(milter.bodyreplaced,"Message body not replaced")
self.failUnless(milter.headerschanged,"Message headers not adjusted")
fp = milter._body
open("test/virus6.tstout","w").write(fp.getvalue())
milter.close()
def suite(): return unittest.makeSuite(BMSMilterTestCase,'test')
if __name__ == '__main__':
unittest.main()
-48
View File
@@ -1,48 +0,0 @@
import unittest
import doctest
import os
import Milter.utils
from Milter.cache import AddrCache
from Milter.dynip import is_dynip
class AddrCacheTestCase(unittest.TestCase):
def setUp(self):
self.fname = 'test.dat'
def tearDown(self):
os.remove(self.fname)
def testAdd(self):
cache = AddrCache(fname=self.fname)
cache['foo@bar.com'] = None
cache.addperm('baz@bar.com')
cache['temp@bar.com'] = 'testing'
self.failUnless(cache.has_key('foo@bar.com'))
self.failUnless(not cache.has_key('hello@bar.com'))
self.failUnless('baz@bar.com' in cache)
self.assertEquals(cache['temp@bar.com'],'testing')
s = open(self.fname).readlines()
self.failUnless(len(s) == 2)
self.failUnless(s[0].startswith('foo@bar.com '))
self.assertEquals(s[1].strip(),'baz@bar.com')
# check that new result overrides old
cache['temp@bar.com'] = None
self.failUnless(not cache['temp@bar.com'])
def testDomain(self):
fp = open(self.fname,'w')
print >>fp,'spammer.com'
fp.close()
cache = AddrCache(fname=self.fname)
cache.load(self.fname,30)
self.failUnless('spammer.com' in cache)
def suite():
s = unittest.makeSuite(AddrCacheTestCase,'test')
s.addTest(doctest.DocTestSuite(Milter.utils))
s.addTest(doctest.DocTestSuite(Milter.dynip))
return s
if __name__ == '__main__':
unittest.TextTestRunner().run(suite())