#!/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_ # # 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 a mail and immediately replying. =head1 SYNOPSIS webmaster [options] [filename] =head1 DESCRIPTION See the 'autoresponder' for documentation... 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- :] FCCJ Systems Hacker 501 W State St Jacksonville, FL 32202 Email: sneex@fccj.org =head1 SEE ALSO L, L =cut use strict; use diagnostics; ############################################################################ # # Configurable section # ############################################################################ my $REPLY_TO = 'info@fccj.org'; # # 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; } my @body = @{$msg->body()}; # Blocked Addresses, by request: Addresses are blocked at the wish of the requestor, see listing below... # Blocked Spamming Domains: see listing... foreach (@headers) { # Blocked/Bad Addresses: &blocked() if /(fccj|nobody|info|webreply|postmaster|root|wcjones|sneex|bill)\@(usa|fccj)\.(org|net|com|edu|cc)/i; exit if /kimbo614\@yahoo\.com/i; exit if /smithle\@hotmail\.com/i; exit if /almaytroy\@hotmail\.com/i; # Blocked Spammers: &blocked() if /may be forged/i; &blocked() if /xoom/i; &blocked() if /To\:.+Undisclosed.+Recipients/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|yahoo)\.com/i; &blocked() if /(uu|popsite|dialsprint|earthlink)\.net/i; &blocked() if /(myworldmail|onemain|shockwave|thefuncity|safepages)\.com/i; &blocked() if /primus\.ca/i; } #================================================================================ #======== This section e-mails the remote Client ============================== #================================================================================ my @message = ("Hello from the FCCJ 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.3.00N dated 12/01/2000 \@ 11:30AM *************************************************** *********** WARNING - Read this first! ************ 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. --------------- Web Addresses - If you are trying to obtain specific help - the following items may prove helpful and are included for your future reference: 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 Web-Course-in-a-Box On-Line Class System: http://www.opencampus.org/wcb/ WebCT On-Line Class System: http://www.distancelearning.org:8080/ ------------------- 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; and, if they cannot resolve the issue, 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. You can determine the page author's e-mail address like this - Say you are trying to get to WC Jones' web site, but are having trouble. WC Jones' web pages look like: http://web.fccj.org/~example/somepage.html You will need to notice the ~ (tilde) in the URL above - where it shows /~example/ - this helps to indicate the web page author's e-mail user id; in this case 'example'. The actual e-mail for this author would work out to be example\@fccj.org. It would be prudent to e-mail them regarding any trouble(s) you may be having trying to access their web pages or other content. Also, with regard to the On-Line Course system(s) themselves - you can determine the page author's e-mail address like this - Say you are trying to get to WC Jones' on-line web course site, but are having trouble. WC Jones' on-line web course pages look like: http://www.distancelearning.org:8080/SCRIPT/CGS2283_example/scripts/serve_home or, depending upon the system, maybe something like: http://www.opencampus.org/wcb/schools/FCCJ/acct/example/9/ These are a little more difficult, but the e-mail address is in the URL(s) above - in the first example, where it shows /CGS2283_example/scripts/ - the e-mail ID is between the Course ID (CGS2282_) and the /scripts. So the e-mail user id is, in this case, 'example'. The actual e-mail for this author would work out to be example\@fccj.org. In the second example, the ID can be found by reading the URL backwards - starting at /9/, the next area is /example/ - by eliminating the /'s you see 'example' -- which will be the e-mail ID to use. At any rate, if you are reporting problems with the On-Line classes you must provide the following information if you wish assistance: The Course ID, Instructor Name, ID and PW the instructor assigned you; the ID and PW you tried to create for yourself for your global WebCT ID. It really would be best if you contacted your instructor first, that way they can contact the Help Desk IF you are enrolled in their course. -------------------------------------------------- Student E-Mail, WWW page, and Account Activation - 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 ------------------------------------- Computer-related Security Incidents - Also, 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\@fccj.org 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\@fccj.org in future requests. ______________________________________________________________________ Thank you for your message to webmaster\@fccj.org ===== 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@fccj.org'); print("Replying message:\n", $msg->as_string()) if $opt_verbose; $msg->smtpsend() unless $opt_debug; #================================================================================ #======== This section e-mails internal FCCJ 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 FCCJ 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@fccj.org'); 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...\n\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@fccj.org'); $msg->head()->replace('From', 'autoresponder-owner@fccj.org'); print("Replying message:\n", $msg->as_string()) if $opt_verbose; $msg->smtpsend() unless $opt_debug; exit; }