#!/usr/local/bin/perl -w # -- E-Mail RegEx obtained from Mastering Regular Expressions: ## MOST of this script is Copyright 1999 -Sneex- (WCJones); All Rights Reserved... ## However, as I don't want to reinvent the wheel, there are portions Copyright others - ## Many thanks to Friedl & O'Reilly for writing and publishing: ## _Mastering Regular Expressions_ # WARNING: You must change all the references to 127.0.0.1 to # YOUR host.domain pair ... While I use this script at FCCJ; # I will NOT response to your customer inquiries... # A listing of changes YOU must make - each is marked with CHANGE HERE # syntax ABOVE the line which needs your attention. Hopefully you can # figure out what needs changing and why... I accept NO REPONSIBILTY # any damage this program may cause; use at your own risk! ###################################################################### ## ## ###################################################################### # # Code to build a regex to match an internet email address, # from Chapter 7 of _Mastering Regular Expressions_ (Friedl / O'Reilly) # (http://www.ora.com/catalog/regexp/) # # Optimized version. # # Copyright 1997 O'Reilly & Associates, Inc. # # Some things for avoiding backslashitis later on. my $esc = '\\\\'; my $Period = '\.'; my $space = '\040'; my $tab = '\t'; my $OpenBR = '\['; my $CloseBR = '\]'; my $OpenParen = '\('; my $CloseParen = '\)'; my $NonASCII = '\x80-\xff'; my $ctrl = '\000-\037'; my $CRlist = '\n\015'; # note: this should really be only \015. # Items 19, 20, 21 my $qtext = qq/[^$esc$NonASCII$CRlist\"]/; # for within "..." my $dtext = qq/[^$esc$NonASCII$CRlist$OpenBR$CloseBR]/; # for within [...] my $quoted_pair = qq< $esc [^$NonASCII] >; # an escaped character ############################################################################## # Items 22 and 23, comment. # Impossible to do properly with a regex, I make do by allowing at most one level of nesting. my $ctext = qq< [^$esc$NonASCII$CRlist()] >; # $Cnested matches one non-nested comment. # It is unrolled, with normal of $ctext, special of $quoted_pair. $Cnested = qq< $OpenParen # ( $ctext* # normal* (?: $quoted_pair $ctext* )* # (special normal*)* $CloseParen # ) >; # $comment allows one level of nested parentheses # It is unrolled, with normal of $ctext, special of ($quoted_pair|$Cnested) $comment = qq< $OpenParen # ( $ctext* # normal* (?: # ( (?: $quoted_pair | $Cnested ) # special $ctext* # normal* )* # )* $CloseParen # ) >; ############################################################################## # $X is optional whitespace/comments. $X = qq< [$space$tab]* # Nab whitespace. (?: $comment [$space$tab]* )* # If comment found, allow more spaces. >; # Item 10: atom $atom_char = qq/[^($space)<>\@,;:\".$esc$OpenBR$CloseBR$ctrl$NonASCII]/; $atom = qq< $atom_char+ # some number of atom characters... (?!$atom_char) # ..not followed by something that could be part of an atom >; # Item 11: doublequoted string, unrolled. $quoted_str = qq< \" # " $qtext * # normal (?: $quoted_pair $qtext * )* # ( special normal* )* \" # " >; # Item 7: word is an atom or quoted string $word = qq< (?: $atom # Atom | # or $quoted_str # Quoted string ) >; # Item 12: domain-ref is just an atom $domain_ref = $atom; # Item 13: domain-literal is like a quoted string, but [...] instead of "..." $domain_lit = qq< $OpenBR # [ (?: $dtext | $quoted_pair )* # stuff $CloseBR # ] >; # Item 9: sub-domain is a domain-ref or domain-literal $sub_domain = qq< (?: $domain_ref | $domain_lit ) $X # optional trailing comments >; # Item 6: domain is a list of subdomains separated by dots. $domain = qq< $sub_domain (?: $Period $X $sub_domain )* >; # Item 8: a route. A bunch of "@ $domain" separated by commas, followed by a colon. $route = qq< \@ $X $domain (?: , $X \@ $X $domain )* # additional domains : $X # optional trailing comments >; # Item 6: local-part is a bunch of $word separated by periods $local_part = qq< $word $X (?: $Period $X $word $X # additional words )* >; # Item 2: addr-spec is local@domain $addr_spec = qq< $local_part \@ $X $domain >; # Item 4: route-addr is $route_addr = qq[ < $X # < (?: $route )? # optional route $addr_spec # address spec > # > ]; # Item 3: phrase........ $phrase_ctrl = '\000-\010\012-\037'; # like ctrl, but without tab # Like atom-char, but without listing space, and uses phrase_ctrl. # Since the class is negated, this matches the same as atom-char plus space and tab $phrase_char = qq/[^()<>\@,;:\".$esc$OpenBR$CloseBR$NonASCII$phrase_ctrl]/; # We've worked it so that $word, $comment, and $quoted_str to not consume trailing $X # because we take care of it manually. $phrase = qq< $word # leading word $phrase_char * # "normal" atoms and/or spaces (?: (?: $comment | $quoted_str ) # "special" comment or quoted string $phrase_char * # more "normal" )* >; ## Item #1: mailbox is an addr_spec or a phrase/route_addr my $mailbox = qq< $X # optional leading comment (?: $addr_spec # address | # or $phrase $route_addr # name and address ) >; # End of Copyright 1997 O'Reilly & Associates, Inc. # End of Copyrighted code section... =pod =head1 NAME webmaster autoresponder - A script for receiving an email and immediately replying... =head1 SYNOPSIS Name this script webmaster and place in /utils directory with these permissions (chmod 0564 webmaster; chown daemon:sneex webmaster ): -r-xrw-r-- 1 daemon sneex 20248 Aug 10 08:46 webmaster (Where 'sneex' id YOUR Unix ID...) Command-line: /utils/webmaster [options] [filename] Via /etc/aliases (preferred method) webmaster: "| /util/webmaster" webmaster-owner: /dev/null owner-webmaster: /dev/null webreply: your, various, users, here =head1 DESCRIPTION I promise to do the documentation thing soon; but this script should be pretty 'self explanatory...' Note: I am trying to rid ourselves of the dreaded daemon "Sun Daemon" From: line which is confusing during replies... =head1 SPAM A list of spammers, or requested address blocking, is utilized in this release... If e-mail is recieved from a known spamming domain or if the address appears in the Address Blocked list, then the program simply exits, doing nothing... =head1 INSTALLATION Install the prerequisite Perl modules, in particular Graham Barr's excellent Mailtools package. L. In /etc/mail/aliases or /etc/aliases, put lines like this: webmaster: "| /usr/local/bin/webmaster" owner-webmaster: /dev/null webmaster-owner: /dev/null Then do a "newaliases". Edit the webmaster script and change the reply-to address to point back to one of the owner addresses. This should have the advantage that you won't see error messages generated by the autoresponder. =head1 SCRIPT CATEGORIES mailstuff =head1 PREREQUISITES The MailTools package, in particular the Mail::Internet module. L. =head1 OSNAMES any OS using sendmail or a compatible mail server =head1 AUTHOR -Sneex- (IUDICIUM) :] Chasecreek Systemhouse Email: sneex@mac.com =head1 SEE ALSO L, L =cut use strict; use diagnostics; ############################################################################ # # Configurable section # ############################################################################ my $REPLY_TO = 'info@127.0.0.1'; # # Use an entry like # # autoresponder-owner: /dev/null # # to suppress error messages from autoresponders replies. # ############################################################################ use Mail::Internet (); use Getopt::Long (); use vars qw($opt_debug $opt_verbose $opt_help); # Get dates and stuf... my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime; my $lt = sprintf("%02d%02d%02d%02d%02d%4d%d", $sec, $min, $hour, $mday, ++$mon, ($year + 1900), $wday); my $slt = scalar localtime; sub Usage() { print <new($fh, 'Modify' => 0, 'MailFrom' => 'KEEP'); my @headers = @{$msg->head()->header()}; # Test if From/Reply-To are valid: foreach my $address (@_) { my $valid = $address =~ m/^$mailbox$/xo; # printf "`$address' is syntactically %s.\n", $valid ? "valid" : "invalid"; # $error = 1 if not $valid; exit if not $valid; # This eliminates bunches and bunches of spammers... } my @body = @{$msg->body()}; foreach (@body) { # Blocked Content-Transfer-Encoding: base64 # Content-Disposition: attachment;æ filename= # Various attempts at passing computer viruses thru my AS script... :( &blocked if /btamail/i; &blocked if /Content\-Transfer\-Encoding\:/i; &blocked if /Content\-Disposition\:\s+attachment\;\s+filename\=/i; &blocked if /cannot\s+be\s+considered\s+Spam/i; } # Blocked Addresses, by request: Addresses are blocked at the wish of the requestor, see listing below... # Blocked Spamming Domains: see listing... foreach (@headers) { # Blocked Content-Transfer-Encoding: base64 # Content-Disposition: attachment;æ filename= # Various attempts at passing computer viruses thru my AS script... :( &blocked if /Content\-Transfer\-Encoding\:/i; &blocked if /Content\-Disposition\:\s+attachment\;\s+filename\=/i; # Blocked/Bad Addresses: &blocked() if /(fccj|nobody|info|webreply|postmaster|root|wcjones|sneex|bill)\@(mac|usa|fccj)\.(org|net|com|edu|cc)/i; # Example: exit if /sneex\@mac\.com/i; # Blocked by customer request... # Blocked Spammers (edit to add your own...) - &blocked() if /may be forged/i; &blocked() if /xoom/i; &blocked() if /To\:.+Undisclosed.+Recipients/i; &blocked() if /From\:.+(win|free|vacat|sex|adult).+/i; &blocked() if /inetsvr\.ghurair/i; &blocked() if /classaservice\.cc/i; &blocked() if /serverpro/i; &blocked() if /interland\.net/i; &blocked() if /\.de\s+/i; &blocked() if /\.in\s+/i; &blocked() if /(fiberia|bbn|icuasonline|excite|yahoo)\.com/i; # Sadly, I am forced to block excite, yahoo, and earthlink... &blocked() if /(uu|popsite|dialsprint|earthlink)\.net/i; &blocked() if /(myworldmail|onemain|shockwave|thefuncity|safepages)\.com/i; &blocked() if /primus\.ca/i; } # NOTE: We could add a 'finger print' that would allow valid yahoo or earthlink messages; # But how can we be sure the finger print was valid? One day we all we be using # personal certificates for authenticated digital ID and finger printing... # CHANGE HERE - Rewrite this section to suit YOUR needs... # What has been provided is an example ONLY... #================================================================================ #======== This section e-mails the original sender ============================ #================================================================================ my @message = ("Hello from the 127.0.0.1 Webmaster E-Mail AutoResponder :]\n", "Your mail was received by the autoresponder on $slt.\n", "Your mail was assigned the following (dss) Security Number: $lt.\n", " **** THIS IS AN AUTOMATED RECEIPT NOTIFICATION **** You will get this message each time you contact the Webmaster's Office; this auto-responder is version: Webmaster.4.11N dated 07/27/2001 \@ 09:30AM *************************************************** *********** WARNING - Read this first! ************ On-Line Catalog: http://www.fccj.org/catalog/ (WARNING: The Catalog is being rebuilt, therefore some links may not work...) Thank you for writing with your comments and concerns. You are receiving this automatically generated message to acknowledge that your mail has been received. All e-mails will be answered in order received by our staff. Please note that if you simply have a comment or suggestion - due to the volume of mail we receive - you may not receive a personal acknowledgment or indication of action. Please read further as many questions are answered below - --------------- Web Addresses - If you are trying to obtain specific help - the following items may prove helpful and are included for your future reference: FCCJ's Main Web: http://www.fccj.org/ On-Line Catalog: http://www.fccj.org/catalog/ (WARNING: The Catalog is being rebuilt, therefore some links may not work...) General Info Web Site: http://www.fccj.org/InfoLine/ Student Web Site: http://students.fccj.org/ Information About FCCJ Jobs: http://www.fccj.org/hr/ Information About On-Line Classes: http://www.fccj.org/OpenCampus/online.html Blackboard On-Line Class System - Web-Course-in-a-Box On-Line Class System: (Now called Blackboard.) The WCB Courseware Server was replaced with Blackboard - see: http://bb.fccj.org/ WebCT On-Line Class System: (May 14th, 2001: Moved to a new location.) http://webct.fccj.org:9988/ Class Registration: Artemis Registration System: http://artemis.fccj.org/ ------------------- On-Line Course(s) - Please contact your instructor for which course(s) you may be registered - the instructor is required to gather information needed and to make sure you are in fact registered for the course in question; additionally, if they cannot resolve the issue, they will contact the HelpDesk on your behalf. Please Note: If your request as sent to the Webmaster's Office concerns on-line classes you will be referred back to your instructor and no further action will be taken. If you feel that the instructor has not responded to your concerns in a timely manner, please contact the LSC/HD at helpdesk\@fccj.org or phone them at 904 / 632-3151 -------------------------------------------------- Student E-Mail, WWW page, and Account Activation - http://students.fccj.org/Disclaimer.html Student accounts are not normally verified, nor available, until the second week of the new term. If you already have an activated account and are having problems - please contact the FCCJ Help Desk at 904/632-3151 or via e-mail helpdesk\@fccj.org -------------------------- Requests for Information - If you simply have questions concerning information about a particular course, please contact the course instructor, if known, or send a request to the FCCJ Information Office info\@fccj.org General questions about academics, housing, operations, jobs, et al, should be directed to the FCCJ Information Office info\@fccj.org Please note: We have recently been recieving a large number of Homework related questions - we are not able to respond to these. You should consult the various on-line research sites; I highly recommend either http://google.com or http://ask.com ------------------------------------- Computer-related Security Incidents - If you are reporting a security incident, please carefully check the headers of the e-mail or USENET articles you are reporting to ensure that they are not, in fact, forgeries -- it is becoming fashionable for Internet users to do this. Send all computer security incidents to computer-security\@127.0.0.1 If you come across forged e-mail or news headers, which may have originated from FCCJ, please report it to abuse\@fccj.org - remembering to include all headers from the original e-mail. Internet and Computer Security abuse violations are presently handled by our abuse staff. If you continue to see abuses of Internet mail more than 72 hours after your original report, please note this in follow-ups. Please note, if you wish, you can avoid receiving this reply by simply sending e-mail to webreply\@127.0.0.1 in future requests; additionally, requests for blocking this e-mail will be honored. ______________________________________________________________________ Thank you for your message to webmaster\@127.0.0.1 ===== This section is included for security auditing purposes:\n", "\n", "=== (dss) Your message's E-Mail Header, as sent:\n\n", @headers, "===(dss) End of Headers\n", "\n", "=== (dss) Your message's E-Mail Body, as sent, follows:\n\n", @body, "=== (dss) End of Body\n", ); # Send to remote client: $msg = $msg->reply(); $msg->body(\@message); print("Sending to Remote Client.\n") if $opt_verbose; $msg->head()->replace('Reply-To', $REPLY_TO); $msg->head()->replace('From', 'webmaster@127.0.0.1'); print("Replying message:\n", $msg->as_string()) if $opt_verbose; $msg->smtpsend() unless $opt_debug; #================================================================================ #======== This section e-mails YOUR Internal Staff ============================ #================================================================================ @message = ("The below message was received by the Webmaster Autoresponder:\n", "This mailing was received by the autoresponder on $slt.\n", "This mailing was assigned the following (dss) Security Number: $lt.\n", "===== This section is included for security auditing purposes:\n", "\n", "=== (dss) The message's E-Mail Header, as sent:\n\n", @headers, "===(dss) End of Headers\n", "\n", "=== (dss) The message's E-Mail Body, as sent, follows:\n\n", @body, "=== (dss) End of Body\n", ); my $from = ''; foreach (@headers) { if (/^From:\s/i) { $from = $'; } } # Send to Internal Staff... $msg = $msg->reply(); $msg->body(\@message); print("Sending to FCCJ Staff.\n") if $opt_verbose; $msg->head()->replace('From', $from); $msg->head()->replace('Reply-To', $from); $msg->head()->replace('To', 'webreply@127.0.0.1'); print("Replying message:\n", $msg->as_string()) if $opt_verbose; $msg->smtpsend() unless $opt_debug; # Exit before we drop into other routines... exit; sub blocked () { # Get dates and stuf... my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime; my $lt = sprintf("%02d%02d%02d%02d%02d%4d%d", $sec, $min, $hour, $mday, ++$mon, ($year + 1900), $wday); my $slt = scalar localtime; #================================================================================ #=========== This section e-mails Blocked Message ============================= #================================================================================ @message = ("The below message was BLOCKED by the Webmaster Autoresponder:\n", "This mailing was blocked on $slt and not delivered.\n", "Blocked Message NOTICE (dss) Security Number: $lt.\n", "===== This section is included for security auditing purposes:\n", "\n", "=== (dss) The message's E-Mail Header, as sent:\n\n", @headers, "===(dss) End of Headers\n", "\n", "=== (dss) The message's E-Mail Body was DELETED and replaced with: \n\n", "Why was this e-mail NOT DELIVERED? Most likely because the sending\n", "ISP (see the above headers) is a known origin for spam or that the\n", "domain hosting the ISP has unsecured email servers (passing viruses, etc...)\n", "\nThe rule set used for blocking this e-mail is very complex and may\n", "have blocked your address in error; if you believe this is the case,\n", "please forward this entire message, unedited, to the helpdesk\@127.0.0.1\n", "someone will complete an investigation and follow-up with you concerning\n", "results and any steps you may take to avoid being blocked in the future.\n", "\nPlease note: If you feel you have recieved this message in error,\n", "you may contact the YOUR LSC/HD at 123 / 456-7890 for assistance...\n", ); # Send to remote client: $msg = $msg->reply(); $msg->body(\@message); print("Sending to Remote Client.\n") if $opt_verbose; $msg->head()->replace('Reply-To', 'owner-autoresponder@127.0.0.1'); $msg->head()->replace('From', 'autoresponder-owner@127.0.0.1'); print("Replying message:\n", $msg->as_string()) if $opt_verbose; $msg->smtpsend() unless $opt_debug; exit; }