Category: CGI
Author/Contact Info /msg sulfericacid
Description: A mailing list with a few extra features:
Auto name/time/unsub fillers
Admin login
> View specific user data
> Edit/Remove specific user data

There are four files. list-add.pl is the form in which the web user adds themself to your list. list-rem.pl lets them remove themself from your list. secure.pl views/edits user data. test.pl is the admin login and mail script.

I'd like to give a special things to:
Castaway for helping solve the great cookie crisis
Enlil for solving a really weird testing problem

list-add.pl --------------------------------------------
#!/usr/bin/perl -w

#######################################################
# Email Management System
# Created by Aaron Anderson
# Contact me at: sulfericacid@qwest.net
#######################################################


use strict;
use warnings;
use POSIX;
use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser);


# You are requested not to change any configurations in this file.
# Everything is setup to function as-is, any tamporing may damage
# the script.

require SDBM_File;

my %emails;

my $snail     = "snail.dbm";  #change to location of snail mail databa
+se
my $list      = "mylist.dbm"; #change to location of email database
my $adminmail = 'admin@test.com';
my $sendmail  = "/usr/lib/sendmail";

tie %emails, 'SDBM_File', $list, O_CREAT | O_RDWR, 0644;
if ( !tied %emails ) {
    print "database unsuccessful $!.\n";
    }


print header, start_html('Email Management');


if(param()){
    my $email   = param('email');
    my $name    = param('name');
    my $add1 = param('add1');
    my $add2 = param('add2');
    my $city = param('city');
    my $zip  = param('zip');
    my $country = param('country');
    

if (($name) && ($email)) {
  if (exists $emails{$email}) {
     print "<center><b>Email already exists in mailing list</b></cente
+r>";
  } else {
   $name =~ s/</&lt\;/g;
   $add1 =~ s/</&lt\;/g;
   $add2 =~ s/</&lt\;/g;
   $city =~ s/</&lt\;/g;
   $zip =~ s/</&lt\;/g;
   $country =~ s/</&lt\;/g;

$name =~ s/:/&\#58\;/g;
$add1 =~ s/:/&\#58\;/g;
$add2 =~ s/:/&\#58\;/g;
$city =~ s/:/&\#58\;/g;
$zip =~ s/:/&\#58\;/g;
$country =~ s/:/&\#58\;/g;

     my $info = join("::", $name, $add1, $add2, $city, $zip, $country)
+;
     $emails{$email} = $info;
     print "<center>Your information was submitted!</center>";
  }
} else {
  if ($name) {
     print "<center><b>Your email address was missing</b></center>";
  } elsif ($email) {
     print "<center><b>name is missing</b></center>";
  } else {
     print "<center><b>You can't submit an empty form</b></center>";
  }
}
}

my $name = param('name');
my $email = param('email');
my $add1 = param('add1');
my $add2 = param('add2');
my $city = param('city');
my $zip  = param('zip');
my $country = param('country');
            
print <<"END";

<form method="post" action="">
  <table width="465" border="0" align="center">
    <tr bgcolor="#666666">
      <td colspan="3"><div align="center" class="style1">Join our mail
+ing list </div></td>
    </tr>
    <tr bgcolor="#CCCCCC">
      <td colspan="3">Name:</td>
    </tr>
    <tr>
    <td colspan="3"><input name="name" value="$name" type="text" id="n
+ame" size="40" /></td>
    </tr>
    <tr bgcolor="#CCCCCC">
      <td colspan="3">Email:</td>
    </tr>
    <tr>
    <td colspan="3"><input name="email" type="text" value="$email" id=
+"email"  size="40" /></td>
    </tr>
    <tr bgcolor="#CCCCCC">
      <td colspan="3">Address line 1:</td>
    </tr>
    <tr>
      <td colspan="3"><input name="add1" type="text" value="$add1" id=
+"add1"  size="40" /></td>
    </tr>
    <tr bgcolor="#CCCCCC">
      <td colspan="3">Address line 2:</td>
    </tr>
    <tr>
      <td colspan="3"><input name="add2" type="text" value="$add2" id=
+"add2"  size="40" /></td>
    </tr>
    <tr bgcolor="#CCCCCC">
      <td colspan="3">City/State:</td>
    </tr>
    <tr>
      <td colspan="3"><input name="city" type="text" value="$city" id=
+"city"  size="40" /></td>
    </tr>
    <tr>
      <td width="99" bgcolor="#CCCCCC">Zip Code: </td>
      <td colspan="2" bgcolor="#CCCCCC">Country:</td>
    </tr>
    <tr>
      <td><input name="zip" type="text" id="zip" value="$zip" size="5"
+ /></td>
      <td colspan="2"><input name="country" type="text" value="$countr
+y" id="country"  size="23" /></td>
    </tr>
    <tr>
      <td>&nbsp;</td>
      <td width="174"><div align="center">
</td>
      <td width="170"><input type="submit" name="submit" /></td>
    </tr>
    <tr>
      <td colspan="3"><p class="style2">&nbsp;</p>
        <p class="style2">* To remove yourself from our lists, only th
+e email address is required to process your request.</p>
      <p class="style2">* By submitting your information, you are gran
+ting us permission to mail you on occasion, not to sell it for profit
+. </p></td>
    </tr>
  </table>
</form>


END


            print end_html();
list-rem.pl --------------------------------------------
#!/usr/bin/perl -w

#######################################################
# Email Management System
# Created by Aaron Anderson
# Contact me at: sulfericacid@qwest.net
#######################################################


use strict;
use warnings;
use POSIX;
use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser);


# You are requested not to change any configurations in this file.
# Everything is setup to function as-is, any tamporing may damage
# the script.

require SDBM_File;

my %emails;
my %snailmail;

my $snail     = "snail.dbm";  #change to location of snail mail databa
+se
my $list      = "mylist.dbm"; #change to location of email database
my $adminmail = 'admin@test.com';
my $sendmail  = "/usr/lib/sendmail";

tie %emails, 'SDBM_File', $list, O_CREAT | O_RDWR, 0644;
if ( !tied %emails ) {
    print "database unsuccessful $!.\n";
    }


tie %snailmail, 'SDBM_File', $snail, O_CREAT | O_RDWR, 0644;
if ( !tied %snailmail ) {
    print "database unsuccessful $!.\n";
    }

print header, start_html('Email Management');


print <<"END";

<form method="post" action="list-rem.pl">
  <table width="465" border="0" align="center">
    <tr bgcolor="#666666">
      <td colspan="3"><div align="center" class="style1"><font color="
+white"> Unsubscribe from our Mailing List </div></font></td>
    </tr>
    <tr bgcolor="#CCCCCC">
      <td colspan="3">Email:</td>
    </tr>
    <tr>
      <td colspan="3"><input name="email" type="text" id="email" size=
+"40" /></td>
    </tr>
    <tr>
      <td width="170"><input type="submit" name="submit" /></td>
    </tr>
    </table>
</form>

END

if(param())
{
    my $email   = param('email');
    if(exists $emails{$email})
    {
     delete $emails{$email};
     print "<center><b>You were removed from our list.</b></center>";
     exit;
    }
      else
      {
        print "<center><b>Your email address was not found.  Please ch
+eck the spelling.<b></center>";
        exit;
      }
}



            print end_html();
secure.pl --------------------------------------------
#!/usr/bin/perl

#######################################################
# Email Management System
# Created by Aaron Anderson
# Contact me at: sulfericacid@qwest.net
#######################################################

use strict;
use warnings;
use POSIX;
use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser);
use SDBM_File;

######################################
# You may need to configure the following
######################################
my $password   = "test";
## Set the above to whatever you want the admin password to be

my $url        = "http://sulfericacid.perlmonk.org/rac/rac/secure.pl?l
+ookup=";
## The above is a link to your secure.pl file.  Change the url but it 
+must be secure.pl?lookup= at the end


######################################
# Please do not configure anything blow this line
######################################

my $cookiename = "login";
my $favorite   = param('flavor');
my $tasty      = cookie($cookiename);
my $pass       = url_param('pass');
my $edituser   = url_param('lookup');


my %emails;

my $emails     = "mylist.dbm";  #change to location of snail mail data
+base

my $lookup    = url_param('lookup');

tie %emails, 'SDBM_File', $emails, O_CREAT | O_RDWR, 0644;
if ( !tied %emails ) {
    print "database unsuccessful $!.\n";
    }


# No cookie, so if no favourite value, print new form
unless ($tasty eq $password)
{
 print header(-expires=>'now'), start_html("Denied");
print "DENIED";
 exit;
}


print header();
print start_html('Email Management- Address lookup');

#################################################
# User update checking
#################################################
if (param('update'))
{
my $name    = param('name');
my $email   = param('email');
my $add1    = param('add1');
my $add2    = param('add2');
my $city    = param('city');
my $zip     = param('zip');
my $country = param('country');

 if($email && $name)
 {
   if ( exists $emails{$email} && $lookup ne $email) 

   {
     print "<font color=red>This email address is already being used, 
+please select another.</font>";
   }
   else
   {
   my $info = join("::", $name, $add1, $add2, $city, $zip, $country);

   delete $emails{$edituser};
   $emails{$email} = "$info";
   print "<font color=blue>Updated!</font>";
   print "<SCRIPT LANGUAGE=\"JAVASCRIPT\">";
   print "document.location.href=\"$url$email\";";
   print "</SCRIPT>";

   #exit;
   } 
}
 else
 {
  print "<font color=red>A name and email address are required.</font>
+";
 }
}

#################################################
# Edit/Delete button checking
#################################################
if (param('delete'))
{
  delete $emails{$edituser};
  print "<b>User information was deleted!</b>";
  exit;
}

if (param('edit'))
{
  my ($name, $add1, $add2, $city, $zip, $country) = split(/::/, $email
+s{$edituser});

print start_form(), table(
    Tr(
        td("Name: "),
        td(
            textfield(
                -name => 'name',
                -default =>"$name",
                -size => 40
            )
        )
    ),
        Tr(
        td("Email: "),
        td(
            textfield(
                -name => 'email',
                -default =>"$edituser",
                -size => 40
            )
        )
    ),
    Tr(
        td("Address 1: "),
        td(
            textfield(
                -name => 'add1',
                -default =>"$add1",
                -size => 40
            )
        )
    ),
    Tr(
        td("Address 2: "),
        td(
            textfield(
                -name => 'add2',
                -default =>"$add2",
                -size => 40
            )
        )
    ),
    Tr(
        td("City/State: "),
        td(
            textfield(
                -name => 'city',
                -default =>"$city",
                -size => 40
            )
        )
    ),
    Tr(
        td("Zip: "),
        td(
            textfield(
                -name => 'zip',
                -default =>"$zip",
                -size => 40
            )
        )
    ),
    Tr(
        td("Country: "),
        td(
            textfield(
                -name => 'country',
                -default =>"$country",
                -size => 40
            )
        )
    ),
    Tr( td(), td(submit('update')) ),
  ),
  end_form();

exit;
}

#################################################
# Determine if user is found in database, if so print user data and fo
+rm buttons
#################################################
if ($edituser)
{
  if (exists $emails{$edituser})
  {
    
     my ($name, $add1, $add2, $city, $zip, $country) = split(/::/, $em
+ails{$edituser});
     my $email = $emails{$_};
     print "<b><center>Address information for $name</center></b>";

     print "<table width=100%><tr><td>";
     print "$name<br>";
if ($add1)
{     
print "$add1<br>";
}
     if ($add2 ne "") {
     print "$add2<br>";
     }
if ($city) 
{
     print "$city<br>";
}
if ($zip)
{
     print "$zip<br>";
}
if ($country)
{
     print "$country<br>";
}
if ($edituser)
{
     print "<br>$edituser<br>";
}
     print "</td><td>";
     print start_form(), 
     submit('edit'),
     end_form();

     print start_form(), 
     submit('delete'),
     end_form();

     print "</td></tr></table>";


    exit;
  }
    else
    {
       print "User does not exist";
       exit;
    }
}

#########################################################
# EDIT user information settings
#########################################################
if (param('edit')) 
{
print "Edit";
exit;
}

#########################################################
# Main page prints below -- User List
#########################################################
my $count = "0";

foreach (keys %emails)
 {
   ++$count;
  }

print "<b>User List:</b> ($count)<br>";

foreach (reverse sort keys %emails) {
my ($name, $add1, $add2, $city, $zip, $country) = split(/::/, $emails{
+$_});

print <<"END";
<A HREF="javascript:window.open('secure.pl?lookup=$_', 
'','scrollbars,width=500,height=250'); void('');">$name</a><br>
END

}

exit;
test.pl --------------------------------------------
#!/usr/bin/perl

#######################################################
# Email Management System
# Created by Aaron Anderson
# Contact me at: sulfericacid@qwest.net
#######################################################




########################################
# You may need to configure the following
########################################
my $pw        = "test";
##  Change the above to the administrator password

my $adminmail = "admin\@test.com";
## Change the above to the administrator email address (this appears a
+s a Reply-To to the emails you send).
## The \ before the @ is NOT optional

my $sendmail  = "/usr/lib/sendmail";
## Change the above to the location of sendmail on your server

my $unsub     = "list-add.pl";  # unsub link
## Change the above to the location of list-rem.pl on your server




########################################
# Please do not alter anything below this line
########################################


use strict;
use warnings;
use POSIX;
use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser);
require SDBM_File;

my $cookiename = "login";
my $favorite   = param('flavor');
my $tasty      = cookie($cookiename);
my $pass       = url_param('pass');
my $edituser   = url_param('lookup');

my (%sig, %emails);
my $sigsave   = "sig.dbm";
my $list      = "mylist.dbm";


# First check if we saved a cookie last time
if($tasty)
{
  print header(-expires=>'now'),
  start_html("Email Control Panel");


my %snailmail;


my $lookup   = url_param('lookup');
my $edituser = url_param('edit');
my %snailmail;

tie %emails, 'SDBM_File', $list, O_CREAT | O_RDWR, 0644;
if ( !tied %emails ) {
    print "database unsuccessful $!.\n";
}

tie %sig, 'SDBM_File', $sigsave, O_CREAT | O_RDWR, 0644;
if ( !tied %sig ) {
    print "database unsuccessful $!.\n";
}


####################################################
# Save signature if requested
####################################################
if (param('save')) {
$sig{'default'} = param('signature');
}

###################################################
# Form checking
###################################################
if ( param('submit') ) {

# rid ourselves from those nasty params
my $message   = param('message');
my $password  = param('password');
my $subject   = param('subject');
my $signature = param('signature');
my $save      = param('save');
my $use       = param('use');
my $time      = localtime;

    if ( $message eq "" || $subject eq "" ) {
        print "<center><font color=red>Your subject or email content w
+as missing.</font></center>\n";
        #exit;
    }
    else {
    
        if ( $save eq "yes" ) {
        print "<br>";
        print "Saving to database...<br>\n";
                $sig{'default'} = $signature;
                $sig{'stored'} = $sig{'default'};
        print "<center><font color=blue>Your Signature has been saved.
+</font><br><br>\n";
    }
        print "<br>\n";

        foreach(keys %emails) {
        my ($name, $add1, $add2, $city, $zip, $country) = split(/::/, 
+$emails{$_});
                    # Email Subs, special commands
            my $editmes = $message;             # let's not edit $mess
+age
            $editmes =~ s/\[name\]/$name/g;    #[name] = user name
            $editmes =~ s/\[time\]/$time/g;     #[time] = time sent 
            $editmes =~ s/\[unsub\]/$unsub/g;   #[unsub] = unsubscribe
+ email  

            my $editsig = $signature;           # let's not edit $sign
+ature
            $editsig =~ s/\[name\]/$name/g;    #[name] = user name
            $editsig =~ s/\[time\]/$time/g;     #[time] = time sent 
            $editsig =~ s/\[unsub\]/$unsub/g;   #[unsub] = unsubscribe
+ email   
            
            my $editsub = $subject;             # let's not edit $subj
+ect
            $editsub =~ s/\[name\]/$name/g;    # [name] = user name   
+    
       
            open( MAIL, "| $sendmail -t" );
            print MAIL "To: $_\n";
            print MAIL "From: $adminmail\n";
            print MAIL "Subject: $editsub\n\n";
            print MAIL "$editmes\n";
             if ($use ne "" && $signature ne "" ) {          
                print MAIL "$editsig\n";
            }
            print MAIL ".\n";
            close(MAIL);         
        }
my $time      = localtime;
print "<center><font color=blue>Email successfully sent on $time</font
+></center>";
    }

}




###################################################
# Begin printing everything
###################################################

print <<"ALL";
<center>
<IFRAME NAME="iframe1" SRC="secure.pl" ALIGN="top" HEIGHT="200" WIDTH=
+"200" HSPACE="5" VSPACE="5"></IFRAME>

<table width="470" border="0">
<form name="form" method="post" action="test.pl">
  <tr bgcolor="#666666">
    <td colspan="2"><div align="center">Email Management - Emailer </d
+iv></td>
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">Subject:</td>
  </tr>
  <tr>
    <td colspan="2">

ALL

if (param('subject')) {
my $subject = param('subject');
   print "<input name=\"subject\" type=\"text\" value=\"$subject\" siz
+e=\"45\"> </td>";
} else {
 print "<input name=\"subject\" type=\"text\" size=\"45\"> </td>";
}

print <<"ALL";
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">Message:</td>
  </tr>
  <tr>

ALL

if (param('message')) {
my $message = param('message');
   print "<td colspan=\"2\"><textarea name=\"message\" cols=\"40\" row
+s=\"5\" id=\"message\">$message</textarea></td>";
   } else {
   print "<td colspan=\"2\"><textarea name=\"message\" cols=\"40\" row
+s=\"5\" id=\"message\"></textarea></td>";
   }

print <<"ALL";
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">Signature:</td>
  </tr>
  <tr>
    <td width="270"><p>

ALL

if (exists $sig{'default'}) {
   print "<textarea name=\"signature\" cols=\"40\" rows=\"5\" id=\"sig
+nature\">$sig{'default'}</textarea>";
   } else {
   print "<textarea name=\"signature\" cols=\"40\" rows=\"5\" id=\"sig
+nature\"></textarea>";
   }

print <<"ALL";

      </p>    </td>
    <td width="163"><p>
      <input name="use" type="checkbox" id="use" value="use">
  Use signature<br>
  <input name="save" type="checkbox" id="save" value="save">
Save signature    </p>    </td>
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">
      <div align="center">
        <input type="submit" name="submit" value="submit">
      </div></td>
  </tr>
</form>
</table>
</center>
ALL


print "</td> </tr> </table>";

  print end_html();
  exit;
}

# No cookie, so let's print a new form
unless ($favorite eq "$pw")
{
       print header(-expires=>'now'), start_html("Email Management- Ad
+ministrator Login"),
       hr(), start_form(),
       p("Please enter your password: ", textfield("flavor",$tasty)),
       end_form(), hr();

  if (param())
  {
     if ($favorite ne "$pw") 
     {
         
         print "<b>Wrong password!</b>";
         exit;
     }

  exit;
  }
exit;
}



# Favourite value was '$pass', save cookie to browser
my $cookie = cookie(
 -NAME    => $cookiename,
 -VALUE   => $favorite,
 #-PATH    => "/",
 -EXPIRES => "+2y",
);

print header(-COOKIE => $cookie, -expires=>'now');
print start_html("Email Control Panel");


tie %emails, 'SDBM_File', $list, O_CREAT | O_RDWR, 0644;
if ( !tied %emails ) {
    print "database unsuccessful $!.\n";
}

tie %sig, 'SDBM_File', $sigsave, O_CREAT | O_RDWR, 0644;
if ( !tied %sig ) {
    print "database unsuccessful $!.\n";
}


###################################################
# Begin printing everything
###################################################

print <<"ALL";
<center>
<IFRAME NAME="iframe1" SRC="secure.pl" ALIGN="top" HEIGHT="200" WIDTH=
+"200" HSPACE="5" VSPACE="5"></IFRAME>

<table width="470" border="0">
<form name="form" method="post" action="test.pl">
  <tr bgcolor="#666666">
    <td colspan="2"><div align="center">Email Management - Emailer </d
+iv></td>
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">Subject:</td>
  </tr>
  <tr>
    <td colspan="2">

ALL

if (param('subject')) {
my $subject = param('subject');
   print "<input name=\"subject\" type=\"text\" value=\"$subject\" siz
+e=\"45\"> </td>";
} else {
 print "<input name=\"subject\" type=\"text\" size=\"45\"> </td>";
}

print <<"ALL";
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">Message:</td>
  </tr>
  <tr>

ALL

if (param('message')) {
my $message = param('message');
   print "<td colspan=\"2\"><textarea name=\"message\" cols=\"40\" row
+s=\"5\" id=\"message\">$message</textarea></td>";
   } else {
   print "<td colspan=\"2\"><textarea name=\"message\" cols=\"40\" row
+s=\"5\" id=\"message\"></textarea></td>";
   }

print <<"ALL";
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">Signature:</td>
  </tr>
  <tr>
    <td width="270"><p>

ALL

if (exists $sig{'default'}) {
   print "<textarea name=\"signature\" cols=\"40\" rows=\"5\" id=\"sig
+nature\">$sig{'default'}</textarea>";
   } else {
   print "<textarea name=\"signature\" cols=\"40\" rows=\"5\" id=\"sig
+nature\"></textarea>";
   }

print <<"ALL";

      </p>    </td>
    <td width="163"><p>
      <input name="use" type="checkbox" id="use" value="use">
  Use signature<br>
  <input name="save" type="checkbox" id="save" value="save">
Save signature    </p>    </td>
  </tr>
  <tr bgcolor="#CCCCCC">
    <td colspan="2">
      <div align="center">
        <input type="submit" name="submit" value="submit">
      </div></td>
  </tr>
</form>
</table>
</center>
ALL



  print end_html();
  exit;
Replies are listed 'Best First'.
Re: Mailing List
by b10m (Vicar) on Jan 01, 2004 at 14:27 UTC
    foreach(keys %emails) { my ($name, $add1, $add2, $city, $zip, $country) = split(/::/, $ +emails{$_}); # Email Subs, special commands my $editmes = $message; # let's not edit $messa +ge $editmes =~ s/\[name\]/$name/g; #[name] = user name $editmes =~ s/\[time\]/$time/g; #[time] = time sent $editmes =~ s/\[unsub\]/$unsub/g; #[unsub] = unsubscribe +email my $editsig = $signature; # let's not edit $signa +ture $editsig =~ s/\[name\]/$name/g; #[name] = user name $editsig =~ s/\[time\]/$time/g; #[time] = time sent $editsig =~ s/\[unsub\]/$unsub/g; #[unsub] = unsubscribe +email my $editsub = $subject; # let's not edit $subje +ct $editsub =~ s/\[name\]/$name/g; # [name] = user name + open( MAIL, "| $sendmail -t" ); print MAIL "To: $_\n"; print MAIL "From: $adminmail\n"; print MAIL "Subject: $editsub\n\n"; print MAIL "$editmes\n"; if ($use ne "" && $signature ne "" ) { print MAIL "$editsig\n"; } print MAIL ".\n"; close(MAIL); }

    The problem with this setup is that, if your mailing list contains a vast quantity of recipients, you put a big load on the system/MTA, for you open a connection for each individual recipient. A "better" way to me, would be the use of one e-mail with the recipients listed in the Bcc field. That would dramastically take some load of the script, for this way, only one connection will be made to $sendmail. The script would be faster too :)

    But implementing this Bcc way, would take away the "personalized" e-mails system you implemented (the [name] stuff wouldn't work anymore). It's up to anyone, of course, but I would sacrifice the personal touch over the speed increase and load decrease.

    I am interested in your motive that made you write this script though. There are some rather good mailing list programs, such as Majordomo (Perl :), Mailman (Python/C) out there already. Not even mentioning googling.

    --
    b10m
      Thank you for your comments on the script. I had a feeling that when the database of names got large enough that it would take a lot longer for the system to complete the task..but I personally won't ever have that many people in my list.

      I didn't quite understand your idea, but I wouldn't take that route if it takes away the function of [name]. That's one of the reasons I went with writing my own script, besides the fact I really wanted to see if I could write one.

      Thanks for your comments.



      "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

      sulfericacid