#!/usr/bin/perl # Be sure that the line above points to where perl 5 is # on your system. ################################################################## # nmmdadmin.cgi: subscription e-mail collector with subscribe # and unsubscribe features. # Release 1.1 on 02/03/02 # (C) 1999-2002 BigNoseBird.Com, Inc. This program is freeware and may # be used at no cost to you (just leave this notice intact). # Feel free to modify, hack, and play with this script. # It is provided AS-IS with no warranty of any kind. # We also cannot assume responsibility for either any programs # provided here, or for any advice that is given since we have no # control over what happens after our code or words leave this site. # Always use prudent judgment in implementing any program- and # always make a backup first! # Thanks to James Ryley for some excellent cleanup work! # ################################################################## use Socket; $|=1; ## SECURITY NOTICE # SECURITY NOTICE # SECURITY NOTICE ########### # # This script has NO security features built in. Please # consult the README.TXT file for information on securing # this script from abuse. # ################################################################## #### USER CONFIGURATION SECTION ################################## # delimiter is the character that divides your e-mail list file. # $delimiter = "\\t" # tab $delimiter = "\\|"; # pipe # $BASEDIR is the full directory path to where you will store your # mail list (mbz) files and letter (ltr) files. Be certain that # the script can write to this directory $BASEDIR="/www/mydomain/cgi-bin/nomodomo"; # $TEMPDIR is the location of the system temporary directory. The # setting below is fine for all unix systems. $TEMPDIR="/tmp"; # $SCRIPT_URL is the URL (not path) of this script. $SCRIPT_URL="/cgi-bin/nomodomo/nmmdadmin.cgi"; # $SMTP_SERVER is the name of the sendmail or SMTP host that will # send your mail. This script uses the SOCKETS method, and does # not use sendmail or BLAT.EXE for cross-platform use and ease of # installation. The value below should work on almost all systems # that are capable of sending mail. Use your ISP's mail server # such as mail.xxxyyyzzz.net if your host cannot originate mail. $SMTP_SERVER="localhost"; # In case you don't have access to SMTP, try commenting out the # line above with a # mark at the start of the line, and uncomment # the SENDMAIL below. # $SEND_MAIL="/usr/lib/sendmail -t"; # $DEFAULT_EMAIL is used as the default 'from' e-mail address # for your mailings. You can type over this value when sending # mail. $DEFAULT_EMAIL="me\@mydomain.com"; ################################################################## &test_dirs; &setup; if ($ENV{'REQUEST_METHOD'} ne "POST" && $ENV{'QUERY_STRING'} eq "") { &query_form; exit; } &decode_vars; if ($ENV{'REQUEST_METHOD'} eq "POST" && $fields{'action'} eq "LIST") { &get_list; exit; } if ($ENV{'REQUEST_METHOD'} eq "POST" && $fields{'action'} eq "SENDMAIL") { &fire_mail; exit; } if ($ENV{'REQUEST_METHOD'} eq "POST" && $fields{'action'} eq "POSTLETTER") { &post_letter; exit; } if ($ENV{'REQUEST_METHOD'} eq "POST" && $fields{'action'} eq "EDIT") { <r_editor; exit; } if ($ENV{'REQUEST_METHOD'} eq "POST" && $fields{'action'} eq "PURGE") { &purge_names; exit; } &error_report("Called without proper options set"); ################################################################## sub query_form { print "Content-type: text/html\n\n"; $fileselect = &get_files("filename","mbz"); $ltrselect = &get_files("lfilename","ltr"); print <<__QUERY_FORM__;

BNB's NoMoDoMo

 
Welcome to BNB's NoMoDomo Subscription Manager Control Panel! The forms below will allow you to manage your mailing lists, create and edit your letters, and send out mailings.
 
Maintain Mailing Lists
This form allows you to edit the mailing lists collected by your BNB Subscription Manager. Please use the selection bar to pick the mailing list file you wish to review. You may also enter an e-mail address, or part of one into the search box and the script will return all all matching records. If you want to select the entire contents of a file, just leave the search box empty. Click on GO-GET-EM! when ready.
Please select a list file $fileselect
Partial address to search on
Fire when ready
Maintain Letters
To create a new form letter file, select the YES button for Create new letter. To edit an existing letter, simply pull down on the selector bar and pick the desired letter file. Click on DO-IT! when ready.
Please select a letter file $ltrselect
Create a new letter? NO YES
Fire when ready
Send out Mailing
This form allows you to send out e-mail to your subscribers. Use the selector bars to pick your mailing list and form letter file. You may also enter a subject line and return e-mail address. Of course- be very careful to pick the correct letter and list before sending! As the mail is being sent, you will see each address and it's status displayed. In the event the script is interrupted, you will know where it left off. Click on MAIL-EM! when ready.
Please select a LIST file $fileselect
Please select a LETTER file $ltrselect
From
Subject Line
Fire when ready
$cpr
__QUERY_FORM__ } sub fire_mail { if ($fields{'filename'} eq "" or $fields{'lfilename'} eq "") { &error_report("No letter file or mail list file selected"); } if ($fields{'from'} eq "" or &valid_address($fields{'from'}) != 1) { &error_report("The from e-mail is missing or invalid"); } if (!-e "$BASEDIR/$fields{'filename'}") { &error_report("unable to find $fields{'filename'} file"); } if (!-e "$BASEDIR/$fields{'lfilename'}") { &error_report("unable to find $fields{'filename'} file"); } $lettext=""; open (INMLTR,"<$BASEDIR/$fields{'lfilename'}"); while ($ir=) { chop $ir; if (($ir eq "") || ($ir eq "\r")){ $ir="\n"; } $lettext .= $ir; } close(INMLTR); &get_the_lock; @thelist=(); open (INFA,"<$BASEDIR/$fields{'filename'}"); while ($tl=) { chop $tl; @ems=split(/$delimiter/,$tl); push(@thelist,$ems[0]); } close(INFA); &drop_the_lock; print "Content-type: text/html\n\n"; print "
Mail being sent to subscribed members of $fields{'filename'}\n";
  print "using letter $fields{'lfilename'}\n\n";

  foreach $em (@thelist)
   {
     $mailresult=&sendmail($fields{from}, $fields{from}, $em, $SMTP_SERVER, $fields{subject}, $lettext); 
     if ($mailresult eq "1")
      {print "$em: SENT\n";}
      else 
      {print "$em: MAIL NOT SENT: $mailcodes{'$mailresult'}\n";}
   }
   print"\nProcessing completed!\n";
}

##################################################################
sub get_list
{

 if (!-w "$BASEDIR/$fields{'filename'}")
   {&error_report("Write permission on requested $fields{'filename'} file are not turned on. 
Try CHMOD 666 $fields{'filename'}");} print "Content-type: text/html\n\n"; print <<__HEADER__;
__HEADER__ open (INF,"<$BASEDIR/$fields{'filename'}"); @thelist=(); close(INF); foreach $em (@thelist) { chop $em; if ( $em =~/^$fields{'search'}/i || $fields{'search'} eq "") { @ems=split(/$delimiter/,$em); @dt=split(/ /,$ems[2]); print <<__STOP__; __STOP__ } } print <<__FOOTER__;

EDIT MAILING LIST: $fields{'filename'}

Return to Management Page

Check to
Delete
E-Mail Address IP Address Subscribed
Date & Time
$ems[0] $ems[1] $dt[0] $dt[1]
Pressing will delete all checked addresses!

$cpr

__FOOTER__ } ################################################################## sub get_the_lock { $lockfile="$TEMPDIR/subscribe.lck"; local ($endtime); $endtime = 60; $endtime = time + $endtime; while (-e $lockfile && time < $endtime) { # Do Nothing } open(LOCK_FILE, ">$lockfile"); } ################################################################## sub drop_the_lock { close($lockfile); unlink($lockfile); } ################################################################## sub decode_vars { @killist=(); $i=0; read(STDIN,$temp,$ENV{'CONTENT_LENGTH'}); @pairs=split(/&/,$temp); foreach $item(@pairs) { ($key,$content)=split(/=/,$item,2); $content=~tr/+/ /; $content=~s/%(..)/pack("c",hex($1))/ge; $content=~s/\t/ /g; $fields{$key}=$content; if ($key eq "filename" && taint_test($fields{'filename'}) != 1) { &error_report("mail list filename contains illegal characters."); } if ($key eq "lfilename" && taint_test($fields{'lfilename'}) != 1) { &error_report("letter filename contains illegal characters."); } if ($key eq "thisname") { $content=~s/ //g; push(@killist,$content); } } } ################################################################## sub setup { $cpr=<<__CPR__;
Another FREE Script from
BigNoseBird.Com
__CPR__ %mailcodes=('1','success', '-1', 'smtphost unknown', '-2', 'socket() failed', '-3', 'connect() failed', '-4', 'service not available', '-5', 'unspecified communication error', '-6', 'local user to unknown on host smtp', '-7', 'transmission of message failed', '-8', 'argument to empty'); } ################################################################## sub purge_names { &get_the_lock; open (RDR,"<$BASEDIR/$fields{'filename'}"); @biglist=; close(RDR); open (ODR,"> $BASEDIR/$fields{'filename'}"); foreach $em(@biglist) { $skip=0; chop $em; @rms=split(/$delimiter/,$em); foreach $ds (@killist) { if ($rms[0] eq $ds) {$skip=1;break;} } if ($skip == 1) {next;} print ODR "$em\n"; } close(ODR); &drop_the_lock; print "Location: $SCRIPT_URL\n\n"; } ################################################################## sub get_files { local($style,$exten) = @_; local(@items, $item); opendir(MBZDIR, "$BASEDIR"); @items = grep(/$exten/,readdir(MBZDIR)); closedir(MBZDIR); $fs="\n"; return $fs; } ################################################################## sub ltr_editor { if (!-w "$BASEDIR/$fields{'lfilename'}") {&error_report("Write permission on requested $fields{'lfilename'} file are not turned on.
Try CHMOD 666 $fields{'lfilename'}");} print "Content-type: text/html\n\n"; if ( $fields{'newfile'} eq "NO") { $lettext=""; open (INLTR,"<$BASEDIR/$fields{'lfilename'}"); while ($ir=) { $lettext .= $ir; } close(INLTR); $namehide=""; $header="

EDIT LETTER FILE: $fields{'lfilename'}

"; } else { $header ="

CREATE LETTER FILE: "; $header .= "

"; $header .= ""; } print <<__HEADER1__;
$header Return to Management Page

$namehide Pressing will save your letter file

$cpr

__HEADER1__ } ################################################################## sub post_letter { if ( $fields{'newfile'} eq "YES") {$fn="$fields{'lfilename'}.ltr";} else {$fn=$fields{'lfilename'};} open (OTLTR,"> $BASEDIR/$fn"); print OTLTR "$fields{'lettext'}"; close (OTLTR); print "Location: $SCRIPT_URL\n\n"; } ################################################################## sub taint_test { local($testvalue) = @_; if ($testvalue=~ /^([-\@\w.]+)$/) {return 1;} else {return 0;} } ################################################################## sub error_report { local($errormsg) = @_; print "Content-type: text/html\n\n"; print <<__ERROR_MESSAGE__;

The following error has occurred:

$errormsg

__ERROR_MESSAGE__ exit; } ################################################################## sub test_dirs { if (!-w $BASEDIR) {&error_report("The BASEDIR does not have write permission turned on!
Try CHMOD 777 $BASEDIR");} if (!-w $TEMPDIR) {&error_report("The BASEDIR does not have write permission turned on!
Try CHMOD 777 $TEMPDIR");} } ################################################################### ################################################################### sub sendmail { # error codes below for those who bother to check result codes # 1 success # -1 $smtphost unknown # -2 socket() failed # -3 connect() failed # -4 service not available # -5 unspecified communication error # -6 local user $to unknown on host $smtp # -7 transmission of message failed # -8 argument $to empty # # Sample call: # # &sendmail($from, $reply, $to, $smtp, $subject, $message ); # # Note that there are several commands for cleaning up possible bad inputs - if you # are hard coding things from a library file, so of those are unnecesssary # my ($fromaddr, $replyaddr, $to, $smtp, $subject, $message) = @_; $to =~ s/[ \t]+/, /g; # pack spaces and add comma $fromaddr =~ s/.*<([^\s]*?)>/$1/; # get from email address $replyaddr =~ s/.*<([^\s]*?)>/$1/; # get reply email address $replyaddr =~ s/^([^\s]+).*/$1/; # use first address $message =~ s/^\./\.\./gm; # handle . as first character $message =~ s/\r\n/\n/g; # handle line ending $message =~ s/\n/\r\n/g; $smtp =~ s/^\s+//g; # remove spaces around $smtp $smtp =~ s/\s+$//g; if (!$to) { return(-8); } if ($SMTP_SERVER ne "") { my($proto) = (getprotobyname('tcp'))[2]; my($port) = (getservbyname('smtp', 'tcp'))[2]; my($smtpaddr) = ($smtp =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) ? pack('C4',$1,$2,$3,$4) : (gethostbyname($smtp))[4]; if (!defined($smtpaddr)) { return(-1); } if (!socket(MAIL, AF_INET, SOCK_STREAM, $proto)) { return(-2); } if (!connect(MAIL, pack('Sna4x8', AF_INET, $port, $smtpaddr))) { return(-3); } my($oldfh) = select(MAIL); $| = 1; select($oldfh); $_ = ; if (/^[45]/) { close(MAIL); return(-4); } print MAIL "helo $SMTP_SERVER\r\n"; $_ = ; if (/^[45]/) { close(MAIL); return(-5); } print MAIL "mail from: <$fromaddr>\r\n"; $_ = ; if (/^[45]/) { close(MAIL); return(-5); } foreach (split(/, /, $to)) { print MAIL "rcpt to: <$_>\r\n"; $_ = ; if (/^[45]/) { close(MAIL); return(-6); } } print MAIL "data\r\n"; $_ = ; if (/^[45]/) { close MAIL; return(-5); } } if ($SEND_MAIL ne "") { open (MAIL,"| $SEND_MAIL"); } print MAIL "To: $to\n"; print MAIL "From: $fromaddr\n"; print MAIL "Reply-to: $replyaddr\n" if $replyaddr; print MAIL "X-Mailer: Perl Powered Socket Mailer\n"; print MAIL "Subject: $subject\n\n"; print MAIL "$message"; print MAIL "\n.\n"; if ($SMTP_SERVER ne "") { $_ = ; if (/^[45]/) { close(MAIL); return(-7); } print MAIL "quit\r\n"; $_ = ; } close(MAIL); return(1); } ################################################################## sub valid_address { local($testmail) = @_; if ($testmail eq "") {return 0;} if ($testmail =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ || $testmail !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/) { return 0;} else { return 1;} }