#!/usr/bin/perl # NOTE: You must change the line above to point to the path to Perl # on your system. Don't change the "eval" line below, though. eval("use CGI::Carp qw(fatalsToBrowser);"); ######################################################################### ##### Kristina's CGI-Subscribe v2.0.6k # ##### Copyright 1996 - 1999, Kristina Pfaff-Harris # ##### http://tesol.net/scripts/ # ##### # ##### Allows users to subscribe themselves to a mailing list of sorts # ##### so that the owner can send newsletters or other announcements to # ##### all interested parties. Also included is a way for the admin- # ##### istrator to delete subscribers if necessary (New in v1.2) and for # ##### users to unsubscribe themselves (New in v1.5). # ##### # ######################################################################### ##### Licensing: # ##### # ##### This program may be used free of charge under the following # ##### conditions: # ##### # ##### 1. All instructions and Copyright lines must remain unchanged. # ##### 2. All pages generated by the program must contain one of the # ##### following pieces of HTML code: # ##### # ##### CGI-Subscribe Copyright 1998-2000 Kristina # ##### Pfaff-Harris and can be found at: # ##### # ##### http://www.tesol.net/scripts # ##### OR: # ##### # ##### # ##### # ##### 3. You may not sell or distribute this program. You may charge # ##### a reasonable fee for installing it for a client as long as # ##### you make it clear that you are not the author, and you are # ##### not selling the program to them: only charging for installing # ##### it. # ##### 4. You agree that this program is offered without warranty of # ##### any kind, including warranty of fitness for a particular # ##### purpose. You further agree that the author and all sites # ##### associated in any way with this program are not liable for # ##### any damage or loss incurred as a result of using this program.# ##### # ##### 5. YOU MAY NOT USE THIS PROGRAM TO SEND MAIL TO A LIST THAT WAS # ##### NOT GENERATED USING THIS PROGRAM. Let me make that even more # ##### clear. You may not create, buy, or otherwise obtain a list # ##### of email addresses and use this program to send email to that # ##### list unless every person on that list has asked YOU # ##### personally to be on your list. It does not matter whether or # ##### not the person you bought the list from SAYS the people asked # ##### to be on the list. If you yourself do not have some record # ##### of the requests to be on the list, it is a violation of this # ##### license to send mail to those people. This program was created# ##### to promote consensual emailing, and is not to be used to mail # ##### anyone who has not signed up for this list voluntarily. If # ##### you really want to send bulk email, there are many other # ##### programs that will let you do that. # ######################################################################### ##### # ##### IMPORTANT INSTRUCTIONS: # ##### # ##### In this program, I have put **CHANGE** in all the places where # ##### you will need to modify the program to run on your server, so # ##### that you can easily find all the places where changes are # ##### necessary. This program must be chmod 755 or 775 in order to # ##### work, and the html and configuration files must be chmod 644. # ##### Note: on some, systems, you'll have to either make the files # ##### "subscribers.db", "optin.txt", "optout.txt", "temp_signup.txt", # ##### and "passfile.txt" world writeable (chmod 666) or you'll have # ##### to make cgisubscribe.cgi run as you (chmod 4755). Permissions # ##### are sometimes a bit tricky since there are so many different # ##### operating systems and web servers. If you encounter problems, # ##### please email me and I'll see what I can do! # ##### # ##### In addition, if you are on a Unix/Linux based web server, it must # ##### have the "sendmail" program. I think this may work with # ##### "qmail-inject," but have no way to test it, so I suspect that HTML# ##### mail may not work with qmail-inject. # ##### # ##### Please read the README.cgisubscribe file and check the FAQ at # ##### http://tesol.net/scripts/FAQ/ if you need instructions for # ##### setting this up. If all else fails, you can email me from here: # ##### http://tesol.net/scriptmail.html . Have fun! # ######################################################################### ##### # ##### Modification, copying, or distribution of this program # ##### for commercial use is strictly prohibited without permission # ##### from the author. In other words, don't sell my program! # ##### Commercial web developers, please see the Licensing section # ##### above. # ######################################################################### ################################################################# # # # Begin section where you need to change things. Keep # # going until you get the the place where it says # # "** Do not change anything beyond this point! **". # # Please read all the instructions carefully, and you # # shouldn't have any problems. :) # # # ################################################################# #### IMPORTANT! If you are having trouble setting this up, or #### finding where your files are supposed to be, you can use #### the following to get some information about what the script #### is trying to do, and where it's trying to look for files. #### You should leave this on (set to 1) until the script is set up #### and you're pretty sure everything is working. When it's all #### ready, and you've tested it, **CHANGE** $debugging = 1; to #### $debugging = 0; and you will no longer get all those debugging #### messages. $debugging = 0; ################################################################### # # # Operating System Specific Stuff # # (Windows vs. Unix/Linux) # # # ################################################################### # In this section, we're going to try to get some data that will # help us run this script whether you're using Windows NT/95/98 as # a web server, or a Unix/Linux-based web server. Here, I feel # it necessary to point out that Unix/Linux web servers tend to # be much more flexible and robust (in my experience) than Windows # ones. However, if you're stuck with Windows, we'll try to get # this working anyway. :) # If your web server is Linux/Unix based, please **CHANGE** # $opsys below to "unix" like this and go to the Unix/Linux Stuff # Section below: # $opsys = "unix"; # Otherwise, if it is a Windows-based platform, **CHANGE** $opsys to "win" # like this and go to the Windows Stuff section: # $opsys = "win"; $opsys = "unix"; ################################################################### # # # Unix/Linux Stuff # # # ################################################################### # $path_to_sendmail needs to be the FULL path to sendmail on your # server, and the name of the sendmail file itself: You will # probably be able to use what I have below, but sendmail # is sometimes located in /usr/ucblib instead of /usr/lib and # may be somewhere else altogether, like "/var/qmail/bin/qmail-inject", # /bin/easymail, or really who knows what it might be on your server! # The only way to find out is to ask the folks who run your website # sendmail or your mailer program is, just to make sure, then **CHANGE** # this to the correct path. $path_to_sendmail = "/usr/sbin/sendmail"; ################################################################### # # # Windows Stuff # # # ################################################################### # $mail_server_hostname needs to be the hostname of a mail server # that your web server is allowed to send mail through. Generally, # this will be something like "mail.yourdomain.com" but it may # be something completely different, and you may not be able to # use this at all. If your web server is also a mail server, # you may be able to use "localhost" (yes, just that one word, # no ".com" or anything -- it's a special word that means "this # machine.") You will need to ask your local technical support # people for your website what hostname to use for your outgoing # mail server, then **CHANGE** this to reflect that. For example: # $mail_server_hostname = "mail.yourdomain.com"; $mail_server_hostname = "mail.maxprog.com"; # $this_server_hostname needs to be the hostname of your web # server where this script will be run. Sometimes, just the # "www.yourdomain.com" will work, and sometimes your web # server has its own name like "web-01.nt.somedomain.com". # Again, you will need to get the hostname of this machine # from the technical support people for your web server, # and **CHANGE** this to reflect what they say. For example: # $this_server_hostname = "www.yourdomain.com"; $this_server_hostname = "www.maxprog.com"; ################################################################### # # # Various Email Preferences for this Program # # (You need this regardless of whether you have "win" or "unix".) # # # ################################################################### # $opt_in_preferences: Spam, or unsolicited email, has become a # serious problem on the Internet. Many hosting providers will terminate # your account immediately if you are even suspected of sending Spam. # Various U.S. states allow fines, civil penalties, and other legal # actions to be taken against senders of junk email. This setting will # help you make sure that only people who really want to be on your # list get on it. Read the below instructions, and **CHANGE** this # appropriately if necessary. # # opt in: People will have to sign up, receive a special token # via email, and confirm their signup if they wish to get # on the list. Note: Use of this feature is recommended. If # you use this feature, and honestly abide by it, then you will # be able to prove that you are mailing responsibly. To use this, # set: # # $opt_in_preferences = "opt in"; # # opt out: Anyone can signup for the list, but any email # they receive will allow them to opt-out or unsubscribe at # that time. Note that this will allow irresponsible people # to abuse this service by signing other people up, and could # cause trouble for you if your provider has a "No Tolerance" # policy on spam. To use this, set: # # $opt_in_preferences = "opt out"; # # Please do NOT abuse this system. Nobody loves a spammer. :) $opt_in_preferences = "opt in"; # **CHANGE** # If you would like to be notified every time someone signs up for # the list, set # $notify_me = "yes"; # Otherwise, set # $notify_me = "no"; $notify_me = "yes"; ################################################################### # # # Locations of your configuration files # # (You need this regardless of whether you have "win" or "unix".) # # In this section, we'll need to tell the program where it can # # find various files on your web server. # # # ################################################################### # **CHANGE** # $opt_out_file is the path to the file where you want to keep track # of people who have opted NOT to ever receive email from this list. # Change this to the full path of your "optout.txt" file. This file # must be writeable by the web server. Note: this is a "system" # path and not a web address, thus, it must begin with a "/" (on unix- # type systems) or "c:/" on Windows-type systems. # If your optout.txt file is in the same folder as this script, then # the below may work. Please see the FAQ (http://tesol.net/scripts/FAQ/) # for more information about things like this. $opt_out_file = "./optout.txt"; # **CHANGE** # $opt_in_file is the name of the file where you want to keep track # of people who have opted back in. I suggest you keep this # indefinitely, in case someone accuses you of spamming them. :) # Change this to the full path of your "optin.txt" file. This file # must be writeable by the web server. Note: this is a "system" # path and not a web address, thus, it must begin with a "/" (on unix- # type systems) or "c:/" on Windows-type systems. # If your optin.txt file is in the same folder as this script, then # the below may work. Please see the FAQ (http://tesol.net/scripts/FAQ/) # for more information about things like this. $opt_in_file = "./optin.txt"; # **CHANGE** # $temp_signup_file is the full system path to your temporary # signup file for users who "opt in" for your mailing list. # If you have "$opt_in_preferences = "opt in";" set, CGI-Subscribe # will need a temporary file to store a special "token" that it will # email to subscribers. When the subscriber receives the email with # their token, and clicks on the link, CGI-Subscribe will check in # this file to make sure the token really matches what we sent them. # If your temp_signup.txt file is in the same folder as this script, then # the below may work. Please see the FAQ (http://tesol.net/scripts/FAQ/) # for more information about things like this. $temp_signup_file = "./temp_signup.txt"; # $password_file is the complete path and filename of "passfile.txt". # **CHANGE** "passfile.txt" to the path and filename on your server. # This is a "system path" like "$opt_in_file" and "$opt_out_file" above, # so set it up the same way. # If your passfile.txt file is in the same folder as this script, then # the below may work. Please see the FAQ (http://tesol.net/scripts/FAQ/) # for more information about things like this. $password_file = "./passfile.txt"; # $subscribers_database should be the name of the file you want # to contain your subscribers. If you have no real preference, # you can leave this line as-is, and the program will put it in the # directory with this program. Otherwise, **CHANGE** # "subscribers.db" to the full path to the file on your server. # Again, this is the full "system path" to the subscribers.db file. # If your subscribers.db file is in the same folder as this script, then # the below may work. Please see the FAQ (http://tesol.net/scripts/FAQ/) # for more information about things like this. $subscribers_database = "./subscribers.db"; # $cgi_subscribe_url is the full web address (URL) to the # cgisubscribe.cgi program. This MUST begin with "http://" and must # point to the web address where you've set up CGI-Subscribe on your # web server. For example: # $cgisubscribe_url = "http://www.yourdomain.com/cgi-bin/cgisubscribe.cgi"; # or # $cgisubscribe_url = "http://yourdomain.com/CGI-Subscribe/cgisubscribe.cgi"; # Note: What I have below works on most systems, but does not work on # others. If you find strange things happening, especially "File not found" # errors when clicking on one of the buttons, then **CHANGE** this to # the actual full address of the script. $cgisubscribe_url = "http://$ENV{'SERVER_NAME'}$ENV{'SCRIPT_NAME'}"; ################################################################### # # # Text and Page Display Preferences for this Program # # (You need this regardless of whether you have "win" or "unix".) # # These are options for the name of your list, text to send when # # someone signs up, any HTML you would like to use for when the # # program displays pages (so you can match the look of your site) # # and so forth.) # # # ################################################################### # $listname is the "name" you want to give your list. This will # appear in the "Subject" line of the mail message you want to # send out. **CHANGE** "CGI-Subscribe v2.0.6k" to something appropriate # for your purposes. For example: "Bob's Newsletter" or # "Mathematics Weekly Update". IMPORTANT: if you use any of the # following characters in your list name: # # @ $ % " \ # # You must put a backslash in front of them like this: # # \@ \$ \% \" \\ # # If you do not, @ and " will cause an error, $ will not show up at # all, and \ may cause other characters to look strange. You MUST # always backslash these characters anywhere you put them in any of # these variables, including the ones below. $listname = "CGI-Subscribe 2.0.6k"; # $owner_name is what you want to appear in the "From" part of the # messages you send out. It can be anything, really, and does # not have to be your real name. **CHANGE** "CGI-Subscribe v2.0.6k" to the # name you want to appear in the "From" line. $owner_name = "CGI-Subscribe v2.0.6k"; # $owner_email is your own email address. This is assuming that # you don't have access to a "Listserv" or "Majordomo" type # mailing list, since, if you did, you wouldn't need this program. # (There are other cgi programs available for automating subscription # to those sorts of lists.) You MUST put a backslash (\) in front # of the "@" sign. **CHANGE** "me\@my_site.com" to your own email address. $owner_email = "me\@my_site.com"; # $htmlheader is the html header you want to use for this # subscription service as far as confirmation messages go. # Basically, this HTML code will be printed at the top of any # pages displayed by this program. It should fit in with the # rest of your pages. IMPORTANT!!!!! Any quotation marks (") # or "@" signs MUST have a backslash (\) in front of them or # the program will not run. Other characters which must be # backslashed are $, % , and \ (backslash) itself. **CHANGE** # this to a header that is appropriate to your own pages. $htmlheader = " CGI-Subscribe v2.0.6k \"CGI-Subscribe
... .

"; # NOTE: this quote and semicolon (;) are necessary. Don't backslash # them. # $htmlfooter is the (you guessed it!) html footer for confirmation # and error messages. The best thing to do here is to just cut and # paste the HTML from one of your pages. Don't forget to backslash # our favorite ", @, $ and other characters...(This is a backslash: \) $htmlfooter = "


"; # Again, this quote and semicolon are necessary. # $confirm_subscription_message is the message that you want to # send out to your subscribers to let them know that they've # successfully subscribed. You can have any message you want, # but please pay attention to the same characters as in # $htmlheader and $htmlfooter -- they will need to be backslashed # here too. You may **CHANGE** this to anything you want, but the # text should stay between the two dashed (---------) lines. # Again, backslash those @, ", $ and so forth. $confirm_subscription_message = " ----------------------------------------------------------- Thank you for subscribing to the mailing list. ----------------------------------------------------------- "; # <-- This quote and semicolon are necessary. Don't remove them! # $extra_fields is a bit complicated, so please just leave this alone # if you don't understand it. Otherwise, read carefully. :) If you # want to collect other data from your subscribers, such as FullName, # StreetAddress, ZipCode, TelephoneNumber, etc, then you should define # these fields here. Basically, it should look something like this: # $extra_fields = "Full Name,Street Address,Zip Code, Telephone Number"; # NOTE: You may NOT have any commas in the field names, since this will # confuse the program. The program thinks that if it sees a comma, that # means it is a separate field. You may ONLY use letters, numbers, -, _, # or spaces in a field name. These fields will be shown on the subscribe # form in the order you place them here and after "Name" and "Email address." $extra_fields = "Name"; # $required_extra_fields should look almost the same as "$extra_fields." # However, these are only the fields that you want to require the user # to enter. For example, if I wanted to require that they enter the Zip # code and the state, I would put: # $required_extra_fields = "Zip Code, State"; # here. This can be blank if you don't want to require the extra fields. # You may not have anything in $required_extra_fields that is not also # in $extra_fields. $required_extra_fields = "Name"; # $path_to_extra_fields_file is the full system path to the extra_fields.txt # file. This must NOT begin with "http://" and must end with # extra_fields.txt . Sometimes, if the extra fields file is in the same # folder with this script, then what I have below will work. Otherwise, you # will need to **CHANGE** it to something like "c:/scripts/extra_fields.txt" # or "/home/users/yourname/extra_fields.txt". Note: "c:/scripts" and # "/home/users/yourname" is almost certainly NOT what you have to put here. # They are just examples of how the paths may look. You must find out the # system path to your files from your web hosting provider. :-) $path_to_extra_fields_file = "./extra_fields.txt"; ############################################################### # # # Congratulations! You're all done! # # # # ** Do not change anything beyond this point! ** # # You should NOT have to change anything beyond this # # point. You can read through the code, though, if # # that sort of thing interests you. :) # # # ############################################################### # Some debugging stuff here... &clear_all(); %data = &get_data(); print "Content-type: text/html\n\n" if $data{'FA'} ne "Download"; &check_required(); &debug("I think the current working directory is $ENV{'PWD'}") if $ENV{'PWD'} ne ""; &debug("\$path_to_sendmail is $path_to_sendmail\n"); &debug("\$subscribers_database is $subscribers_database\n"); &debug("\$password_file is $password_file\n"); if($ENV{'HTTP_HOST'} ne ""){ $ENV{'SERVER_NAME'} = $ENV{'HTTP_HOST'}; } &debug("\$cgisubscribe_url is $cgisubscribe_url\n"); ########### Set up some variables from the form ############# ##### ##### You should not need to change any of these. In fact, ##### doing so may adversely affect the operation of the ##### program. # For opting out $data_em = $data{'em'}; $data_em =~ s/\s+//sg; $data_Name = $data{'Name'}; # From the subscribe form $name = $data_Name; $name =~ s/\r//sg;$name =~ s/\n//sg;$name =~ s/\r\n//sg; if($name eq ""){ $name = "$listname Subscriber"; } $data_Email = $data{'Email'}; $data_Email =~ s/\s+//sg; if($data_Email){ &check_email($data_Email); } $email = $data_Email; # From the subscribe form $suggestions = $data{'Suggestions'}; # From the subscribe form $message = $data{'Message'}; # From the subscribe form $password = $data{'Password'}; # From the mail-all form $send_mail = $data{'Send_mail'}; # From the mail-all form # Put any extra fields into an array so we can get them out individually # later. @extra_fields = split(/,/, $extra_fields); # Do the same with required_extra_fields so we can compare them. @required_extra_fields = split(/,/, $required_extra_fields); ################## Variables used only by the program ############# ##### ##### Don't change these!!! $change_password = $data{"Change_password"}; $action = $data{"Action"}; $new_password1 = $data{"New_password"}; $new_password2 = $data{"New_password2"}; $confirm = $data{'Confirm'}; # From the mail-all confirm $Confirm_deletion = $data{'Confirm_deletion'}; $delete_address = $data{'Delete_address'}; $address_to_delete = $data{'Address_to_delete'}; $user_delete = $data{'UD'}; ####################################################################### # First we'll grab the date and put it into a variable using the get_date # subroutine. We'll print the date as part of the subject line # in the messages we send out with this. $date = &get_date; # Now, just some shorthand... $fa = $data{'FA'}; $admformtop = "
"; # If you remove this link, without replacing it with a similar # HTML comment (as above in the License section) you are in violation # of the license for this program. No, I don't have the resources to # enforce this, and I know that some people will remove it anyway. # But honestly, since you didn't have to pay for this, is the link # really too much to ask? :) $htmlfooter = "
CGI-Subscribe v2.0.6k Copyright © 2001, Kristina Pfaff-Harris and can be found at http://www.tesol.net/scripts.
$htmlfooter"; ################################################################# ##### # ##### Start the actual Program # ##### # ################################################################# # If we get a value of "Yes" from the "Subscribe" hidden tag on # the form, then this request is from someone who wants to # subscribe themselves to the list, so run the subscribe # routine, and ... if ($fa eq "Subscribe") { &subscribe_to_list; } elsif($fa eq "oi"){ &opt_in; } elsif($fa eq "oo"){ &opt_out; } elsif($fa eq "Admin Menu"){ &check_password; &admin_menu; } elsif($ENV{'QUERY_STRING'} eq "admin"){ &admin_login; } elsif($fa eq "Change Password"){ &check_password; &change_password; } elsif($fa eq "Mailall"){ &check_password; &confirm_mail; } elsif($fa eq "Merge Info"){ &check_password; &merge_extra_fields; } elsif($fa eq "Download"){ &check_password; &download_extra_fields; } elsif ($fa eq "Mailall Confirmed") { &check_password; &oh_fork_it; # &mail_subscribers; } elsif ($fa eq "Delete Users") { &check_password; &delete_subscriber; } elsif($data{'UD'} eq "yes"){ $address_to_delete = $data{'AD'}; $Confirm_deletion = "Yes"; &delete_subscriber; } else { &default_page; exit(); } ################################################################# ##### # ##### Subroutines Start here: # ################################################################# ##### 1. subscribe_to_list: opens up the subscribers.db # ##### file and puts the person on the list after # ##### performing some rudimentary checks to see if # ##### they entered their name and something resembling # ##### an email address. # ################################################################# sub subscribe_to_list { # Check to make sure they entered their name. If not, warn them. :) if ($name eq ""){ $error = "Sorry, you forgot to enter your name. Please try again.

"; &default_page; exit(); } if (length($name) > 150){ $error = "Sorry, \"Name\" must be less than 150 characters. Please try again.

"; &default_page; exit(); } # If they did enter their name, but their email address is # blank or incorrect (as we see it), print them an error # message and give them a chance to go back to the form # again. &check_email($email); # Now, check for extra required fields if($opt_in_preferences ne "opt in"){ &check_required_extra_fields; } # ... if they entered suggestions, run the mail_suggestions # routine to send them to the owner. if ($suggestions ne ""){ &mail_suggestions; } # Check for duplicate subscriptions &check_for_duplicates; # Check opt in/opt out status to make sure we don't subscribe someone # who has opted out. &check_for_opt_out unless $fa eq "oi"; # Open the subscribers database file for appending, so we don't # overwrite all the other subscribers. open(FILE, ">>$subscribers_database") || &debug("Can't open subscribers database '$subscribers_database' to add subscriber: $!"); if($opsys eq "unix"){ flock(FILE, 2); } else { binmode(FILE); } seek(FILE, 0, 2); # Append the person's name and email address into the file in # the form "Bob Smith " print FILE "$name <$email>\n"; # and close the database file. close(FILE); # If opt_in_preferences is "opt_in", then we already saved these when # they first signed up. Otherwise, we need to save them now. if($opt_in_preferences ne "opt in"){ &save_extra_fields; } # Now, we'll email the user a note that says we've subscribed him # or her: $subj = "$listname Registration"; $mesg = "$confirm_subscription_message"; $mesg .= " To permanently opt out of our subscription service, and place your email address in our \"Off Limits\" database: $cgisubscribe_url?FA=oo&em=$email"; &send_mail("$email","$name","$owner_email","$owner_name","", "","$subj","$mesg","$mail_server_hostname", "$this_server_hostname","$opsys"); # Otherwise, if they didn't have any suggestions, mail you a # note that says that you have a new subscriber. if($notify_me eq "yes"){ $subj = "Re: $listname Registration"; $mesg = "**** Automatic Mail From $listname ****\n\n"; $mesg .= "$date: $name ($email) has registered.\n\n"; &send_mail("$owner_email","$owner_name","$owner_email","$owner_name", "$email","$name","$subj","$mesg","$mail_server_hostname", "$this_server_hostname","$opsys"); } # Print the user a message telling them they've successfully # subscribed to the list. print "$htmlheader
Success! You have been added to our mailing list. If you entered suggestions, they have been mailed to $owner_name.
$htmlfooter\n"; exit(); } ################################################################# ##### 2. mail_suggestions: Opens the mailing program and # ##### sends any suggestions to the owner. # ################################################################# sub mail_suggestions { # The rest of this sends you an email message that says # something like "Bob Smith offers the following suggestions: # blah blah blah". if($email eq ""){$email2 = $owner_email;} else {$email2 = $email;} if($name eq ""){$name2 = $owner_email;} else {$name2 = $name;} $message = "**** Automatic Mail From $listname ****\n\n"; $message .= "$name offers the following suggestions:\n\n$suggestions\n"; &send_mail("$owner_email","$owner_name", "$owner_email","$owner_name","$email2", "$name2","CGI-Subscribe ($listname) Page", "$message","$mail_server_hostname", "$this_server_hostname","$opsys"); } ######################################################################### ##### 3. check_password: encrypts the password and checks # ##### it against the encrypted site maintenance password. # ######################################################################### sub check_password { # Read the password from the password file... open (FILE, "$password_file") || &debug("Can't read password file '$password_file'"); $real_password = ; close(FILE); $real_password =~ s/\n+//g; # This program ships with a password of "password" in plain text. # If that's the case, encrypt it. if($real_password eq "password"){ open(FILE, ">$password_file") || &debug("Can't open password file '$password_file': $!"); print FILE crypt("password",time.$$)."\n"; close(FILE); $real_password = crypt("password",time.$$); } foreach $key (keys(%data)){ &debug("$key $data{$key}"); } # If they match, it's okay. if ($real_password eq crypt($password,$real_password) && $password ne ""){ $pass_check = 1; $adminfooter = "$admformtop $htmlfooter"; } # If they don't match, print out an "Incorrect Password" message, # allowing you to go back and change it, and exit the program. else { $pass_check = 0; print "$htmlheader
Sorry, incorrect password. Please try again.
$htmlfooter\n"; exit(); } } ######################################################################### ##### 4. confirm_mail: prints out your message and allows you # ##### view it before sending. # ######################################################################### sub confirm_mail { print "$htmlheader
Please confirm that you wish to send this message. If anything is incorrect, you may go back and change it. You entered the following:
Your message begins below this line for confirmation:

"; # Bug fix for some systems: Takes out any <,>, or " and replaces # them with the HTML codes. When we send the message, we put # them all back. Since those characters are used by HTML tags, # some web servers would cut off the message as soon as they hit # one of those characters causing much anger and gnashing of # teeth. $newmessage = $message; $newmessage =~ s//>/g; $newmessage =~ s/\"/"/g; if($data{'HTMLMail'} eq "yes"){ $showmessage = $message; } elsif($data{'HTMLMail'} eq "both") { eval("use LWP::Simple;"); unless($@){ eval("use HTML::Parse;"); } unless($@){ $textmessage = parse_html($message)->as_text; } else { $textmessage = $newmessage; } $showmessage = "$message


$textmessage
"; } else { $showmessage = "
$newmessage
"; } print "$showmessage
Your message ends above this line

$admformtop \n
$adminfooter"; } ######################################################################### ##### 5. mail_subscribers: This routine just opens the subscribers # ##### database file, puts it into an address variable, and # ##### uses sendmail to mail your message to everyone. # ######################################################################### sub mail_subscribers { $date = &get_date(); # Open the subscribers database file and read all the addresses # into a variable. # Bizarre SvTYPE [146] at c:\inetpub\scripts\cgisubscribe.pl line 851 open(FILE, "<$subscribers_database") || &debug("Can't read subscribers database '$subscribers_database': $!"); # Open sendmail and send a message to each of the subscribers # individually. This way, a massive Bcc field will not keep # the message from going out if one or two addresses are bad, # and your list members won't see everyone else's addresses. # Using "while" keeps us from having to read all the subscribers # into memory, and should speed things up a bit (well, not much, # to be honest) and keep us from running out of memory if we have # a huge list. while(){ $subscriber = $_; chomp($subscriber); $fromname = $owner_name; $fromemail = $owner_email; $toname = "$listname subscriber"; # We're going to split each line into name and email $subscriber =~ /^(.*?)(\s+)(<.*>)$/; $toname = $1; $toemail = $3; $toemail =~ s///g; $subj = "$listname $date"; # Here's where we put the characters back before we send the message # out to our subscribers, so that our subscribers don't get # messages with """ and other weirdness. $newmessage = $message; $newmessage =~ s/<//g; $newmessage =~ s/"/\"/g; $unsubscribelink = "$cgisubscribe_url?UD=yes&AD=$toemail"; $optoutlink = "$cgisubscribe_url?FA=oo&em=$toemail"; if($data{'HTMLMail'} eq "yes" || $data{'HTMLMail'} eq "both"){ $sendmesg = "$newmessage

This message was sent to $subscriber

To unsubscribe, go to:
$unsubscribelink
To permanently opt out of our service and place your email address in our \"Off Limits\" database:
$optoutlink
\n
"; } else { $sendmesg = "$message =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= This message was sent to $subscriber To unsubscribe, go to: $unsubscribelink To permanently opt out of our service and place your email address in our \"Off Limits\" database: $optoutlink =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; } &send_mail($toemail,"$toname",$fromemail,"$fromname", "","",$subj,$sendmesg, $mail_server_hostname, $this_server_hostname,$opsys, $data{'HTMLMail'}) if $toemail ne ""; $mailed_to = $mailed_to + 1 if $toemail ne ""; # We will only send one mail per second to be kind to the mail # server. :-) sleep 1; } # End of while() # Now close the subscribers database file. close(FILE); # After closing sendmail and sending off the message, send # a confirmation message for you that tells you that your # message was sent off. if($data{'HTMLMail'} eq "yes" || $data{'HTMLMail'} eq "both"){ $separator = "
\n
\n"; } else { $separator = "\n\n"; } &send_mail($owner_email,$owner_name,$owner_email,$owner_name, '','',"Mailing Finished"," Your message was emailed to all $mailed_to of your subscribers for $listname. Message follows:$separator$sendmesg", $mail_server_hostname, $this_server_hostname, $opsys, $data{'HTMLMail'}); exit(); } ################################################################# ##### 6. get_date: just uses Perl's localtime() function to # ##### parse the date into a usable form so we can put it # ##### into the message. # ################################################################# sub get_date { ($sec,$min,$hour,$mday,$mon,$year) = (localtime(time))[0,1,2,3,4,5]; $month = sprintf("%.2d", ($mon + 1)); $mday = sprintf("%.2d", $mday); $sec = sprintf("%.2d", $sec); $min = sprintf("%.2d", $min); $hour = sprintf("%.2d", $hour); $year += 1900; if($_[0] eq "long"){ $date = "$month/$mday/$year $hour:$min:$sec"; } else { $date = "[$month/$mday/$year]"; } $date; } ######################################################################### ##### 7. change_password: Allows you to change your password # ##### with some minor error checking to make sure that your # ##### new password matches. # ######################################################################### sub change_password { if ($pass_check != 1) { print "$htmlheader
Error: Incorrect Old Password. Please try again:

Old Password:
New Password:
Confirm New Password:

$adminfooter"; exit(); } if ($new_password1 ne $new_password2 || $new_password1 eq "") { print "$htmlheader
Error: New Password and Confirm New Password do not match. Please try again:

$admformtop
New Password:
Confirm New Password:


$adminfooter"; exit(); } if ($pass_check == 1 && $new_password1 eq $new_password2){ $new_password1 = crypt($new_password1, time.$$); open (PASSFILE, ">$password_file") || &debug("Can't open password file '$password_file' to change password. The system responded: $!"); print PASSFILE "$new_password1"; close(PASSFILE); print "$htmlheader
Password Successfully Changed!


$htmlfooter"; } } ######################################################################### ##### 8. delete_subscriber: Allows you to "unsubscribe" people # ##### from your list. # ######################################################################### sub delete_subscriber { if ($Confirm_deletion eq "NeedConfirm") { &check_password; open(FILE, "$subscribers_database") || &debug("Can't open subscribers database for reading: $!"); @addresses = sort(grep(!/^#/, )); close(FILE); print "$htmlheader\n
Please Confirm Deletion:

Please choose the address you wish to delete. Note: there is no confirmation beyond this point. Please make sure you are deleting the address you want.

"; for($i = 0; $i <= $#addresses; $i++) { chomp($addresses[$i]); if(($addresses[$i] =~ /$delete_address/i) || (($delete_address =~ /all/i) && ($addresses[$i] ne /\b(\s)*\b/ && $addresses[$i] ne "\n"))){ $counter = 1; $newaddress = $addresses[$i]; $newaddress =~ s//>/; print " $admformtop \n"; } } if ($counter != 1) { print "
$newaddress


No entries were found matching your query.
$adminfooter"; } else { print "
$adminfooter\n"; } } elsif ($Confirm_deletion eq "Yes") { &check_password if $user_delete ne "yes"; $newfile = ""; open(FILE, "+<$subscribers_database") || &debug("Can't open subscribers database for reading: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("could not lock file: $!"); } else { binmode(FILE); } @addresses = ; $address_to_delete =~ s/>/>/;$address_to_delete =~ s/</. Otherwise, we'll find it # as a whole entry. This should keep from deleting all partial # addresses, while still allowing admin to delete entries. if($del_address =~ /\s+<$address_to_delete>$/ || $del_address eq "$address_to_delete"){ $deleted_it = 1; } else { $newfile .= "$del_address\n"; } } truncate(FILE, length($newfile)); seek(FILE, 0, 0); print FILE $newfile; close(FILE); $address_to_delete =~ s/>/>/; $address_to_delete =~ s/ Address $address_to_delete successfully deleted.

" if $deleted_it == 1; if($data{'UD'} ne ""){ $printmsg = "You have been removed from our mailing list. Thanks for having been with us!

$htmlfooter"; } else { $printmsg = "You may go back the previous page and reload it to make sure the address is really gone. If your browser has automatic caching, it may not have sent your command.

$adminfooter"; } print "$printmsg\n" if $deleted_it == 1; print "$htmlheader\n

No such address '$address_to_delete'

It appears that the address you are trying to delete does not appear on the list. Please check and make sure that your mail program has not cut off the link.


$htmlfooter" if $deleted_it != 1; } else { print "$htmlheader $admformtop Please enter an address (or part of an address) to search for, or \"All\" to browse all entries:

$adminfooter"; } } ######################################################################### ##### 9. debug: Just prints debugging messages so you can see where # ##### you might be having problems. # ######################################################################### sub debug { if($debugging == 1 && $data{'FA'} ne "Download"){ if($ap != 1){ print "(Don't forget to set \$debugging = 0 in the script when you have set the script up, it's running, and you no longer want to see these \"DEBUGGING INFO\" messages.)

"; $ap = 1; } print "DEBUGGING INFO:$$: $_[0]
\n"; } } ######################################################################### ##### 10. get_data: Parses the input from the HTML forms # ######################################################################### sub get_data { local($string); # get data if ($ENV{'REQUEST_METHOD'} eq 'GET') { $string = $ENV{'QUERY_STRING'}; } else { read(STDIN, $string, $ENV{'CONTENT_LENGTH'}); } # split data into name=value pairs @data = split(/&/, $string); # split into name=value pairs in associative array foreach (@data) { split(/=/, $_); $_[0] =~ s/\+/ /g; # plus to space $_[0] =~ s/%00//g; # We don' need no steenking nulls :) $_[0] =~ s/%0a/newline/g; $_[0] =~ s/%(..)/pack("c", hex($1))/ge; # hex to alphanumeric if(defined($data{$_[0]})){ $data{$_[0]} .= "\0"; $data{$_[0]} .= "$_[1]"; } else { $data{"$_[0]"} = $_[1]; } } # translate special characters foreach (keys %data) { $data{"$_"} =~ s/\+/ /g; # plus to space $data{"$_"} =~ s/%00//g; # We don' need no steenking nulls :) $data{"$_"} =~ s/%0a/newline/g; $data{"$_"} =~ s/%(..)/pack("c", hex($1))/ge; # hex to alphanumeric } %data; # return associative array of name=value } ######################################################################### ##### 11. send_mail: Tries to send email correctly on NT or Unix # ##### operating systems. For CGI-Subscribe, also tries to send # ##### HTML mail if you request it. # ######################################################################### sub send_mail { my($toemail,$toname,$fromemail,$fromname, $replytoemail,$replytoname,$subject, $message,$mail_server_hostname,$this_server_hostname,$opsys, $htmlmail) = @_; $CRLF = "\015\012"; my @headervars = ('toemail','toname','fromemail','fromname', 'replytoemail','replytoname','subject'); # Basically, we're taking out any newlines or extraneous spaces # plus any ", <>, commas, or single quotes as well before we # attempt to send. my ($hvar); foreach $hvar (@headervars){ ${$hvar} =~ s/\s+/ /sg; ${$hvar} =~ s/[\"<>,']//sg; } # Also, the message needs to have CRLF on the end of each line or # qmail will be unhappy. $message =~ s/\r\n/\n/sg; $message =~ s/\r/\n/sg; $message =~ s/\n/$CRLF/sg; &debug("Attempting to send message \"$subject\" to $toemail"); my($boundary) = crypt("blah",time.$$).time.$$; # Try to convert HTML to good text if we're sending in both text and # html. if($htmlmail eq "both"){ eval("use LWP::Simple;"); unless($@){ eval("use HTML::Parse;"); } unless($@){ $textmessage = parse_html($message)->as_text; } else { $textmessage = $message; } } if($opsys eq "unix"){ # Allow for qmail-inject ~sigh~ # Most other mailer thingies do use the -t option like # sendmail in order to be compatible, but apparently # qmail-inject does not. Oh well... if($path_to_sendmail !~ /qmail-inject/){ $path_to_sendmail = "$path_to_sendmail -t"; } open(MAIL, "|$path_to_sendmail") || &debug("Could not open sendmail: $!"); print MAIL "X-From-IP-Address: $ENV{'REMOTE_ADDR'}\n"; print MAIL "To: \"$toname\" <$toemail>\n"; print MAIL "From: \"$fromname\" <$fromemail>\n"; if($replytoemail ne ""){ print MAIL "Reply-to: \"$replytoname\" <$replytoemail>\n"; } print MAIL "Subject: $subject\n"; if($htmlmail eq "yes"){ print MAIL "X-Mailer: CGI-Subscribe v2.0.6k\n"; print MAIL "MIME-Version: 1.0\n"; print MAIL "Content-type: text/html;\n\n"; print MAIL "$message\n"; print MAIL "\n\n"; } elsif($htmlmail eq "both"){ print MAIL "X-Mailer: CGI-Subscribe v2.0.6k\n"; print MAIL "MIME-Version: 1.0\n"; print MAIL "Content-type: MULTIPART/MIXED; BOUNDARY=\"$boundary\"\n"; print MAIL "--$boundary\n"; print MAIL "Content-type: text/html;\n\n"; print MAIL "$message\n"; print MAIL "\n\n"; print MAIL "--$boundary\n"; print MAIL "Content-type: TEXT/PLAIN; charset=US-ASCII\n\n"; $message =~ s/
/=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=/g; print MAIL "$textmessage\n--$boundary--\n"; } else { print MAIL "X-Mailer: CGI-Subscribe v2.0.6k\n"; print MAIL "\n"; print MAIL "$message\n"; } close(MAIL) || &debug("Sending mail got an error: $! $?"); &debug("Sending mail done."); } else { my($port,$them,$sockaddr,$hostname,$name,$aliases,$proto,$port, $type,$len,$thisaddr,$thataddr,$this,$that); $port = 25; $them = "$mail_server_hostname"; $AF_INET = 2; $SOCK_STREAM = 1; $SIG{'INT'} = 'dokill'; sub dokill { kill 9,$child if $child; } $sockaddr = 'S n a4 x8'; $hostname = "$this_server_hostname"; ($name,$aliases,$proto) = getprotobyname('tcp'); ($name,$aliases,$port) = getservbyname($port,'tcp') unless $port =~ /^\d+$/;; ($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname); ($name,$aliases,$type,$len,$thataddr) = gethostbyname($them); $this = pack($sockaddr, $AF_INET, 0, $thisaddr); $that = pack($sockaddr, $AF_INET, $port, $thataddr); if (socket(S, $AF_INET, $SOCK_STREAM, $proto)) { } else { &debug("Could not create socket for mail: $!"); } if (bind(S, $this)) { } else { &debug("Could not bind to socket (this may be okay anyway): $!"); } if (connect(S,$that)) { } else { &debug("Could not connect to socket: $!"); } select(S); $| = 1; select(STDOUT); $a=; print S "HELO $this_server_hostname\n"; $a=; &debug("Mail server responded: $a"); print S "MAIL FROM:<$fromemail>\r\n"; $a=; &debug("Mail server responded: $a"); print S "RCPT TO:<$toemail>\r\n"; $a=; &debug("Mail server responded: $a"); print S "DATA \r\n"; $a=; &debug("Mail server responded: $a"); print S "X-From-IP-Address: $ENV{'REMOTE_ADDR'}\n"; print S "To: $toname <$toemail>\n"; print S "From: $fromname <$fromemail>\n"; if($replytoemail ne ""){ print S "Reply-to: $replytoname <$replytoemail>\n"; } print S "Subject: $subject\n"; if($htmlmail eq "yes"){ print S "X-Mailer: CGI-Subscribe v2.0.6k\n"; print S "MIME-Version: 1.0\n"; print S "Content-type: text/html;\n\n"; print S "$message\n"; } elsif($htmlmail eq "both"){ print S "X-Mailer: CGI-Subscribe v2.0.6k\n"; print S "MIME-Version: 1.0\n"; print S "Content-type: MULTIPART/MIXED; BOUNDARY=\"$boundary\"\n"; print S "--$boundary\n"; print S "Content-type: text/html;\n\n"; print S "$message\n"; print S "\n\n"; print S "--$boundary\n"; print S "Content-type: TEXT/PLAIN; charset=US-ASCII\n\n"; $message =~ s/
/=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=/g; print S "$textmessage\n--$boundary--\n"; } else { print S "X-Mailer: CGI-Subscribe v2.0.6k\n"; print S "\n"; print S "$message\n"; } print S ".\n"; $a=; &debug("Mail server responded: $a"); print S "QUIT"; &debug("Sending mail done."); } } ######################################################################### ##### 12. opt_out: routines for letting people opt out of the list. # ######################################################################### sub opt_out { my $email = $data_em; if($email eq ""){ print "$htmlheader Error: no email

Please enter your email address. This email address will be removed from our list, and placed in our \"opt out\" database so that it cannot be subscribed again.
$htmlfooter"; exit(); } open(FILE, "+<$subscribers_database") || &debug("Could not open $subscribers_database (Subscribers file) for read/write. System returned: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("Could not lock $subscribers_database (Subscribers file). The system returned $!"); } else { binmode(FILE); } @lines = grep(!/^#/, ); foreach $line (@lines){ if($line !~ /<$email>$/i){ $newfile .= $line; } } truncate(FILE, length($newfile)); seek(FILE, 0, 0); print FILE $newfile; close(FILE); $newfile = ""; # If they're in the tmp signup file, get 'em out of there too. open(FILE, "+<$temp_signup_file") || &debug("Could not open $temp_signup_file (Temp. signup file) for read/write. System returned: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("Could not lock $temp_signup_file (Temp. signup file). The system returned $!"); } else { binmode(FILE); } @lines = ; foreach $line (@lines){ if($line !~ /^\Q$email\E\|/i){ $newfile .= $line; } } truncate(FILE, length($newfile)); seek(FILE, 0, 0); print FILE $newfile; close(FILE); $newfile = ""; # Put it on the opt-out list open(FILE, ">>$opt_out_file") || &debug("Could not open $opt_out_file (opt-out file) for writing. System returned: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("Could not lock $opt_out_file. $!"); } else { binmode(FILE); } seek(FILE, 0, 2); print FILE "$data_em\n"; close(FILE); print "$htmlheader $data_em successfully deleted. This address has been removed from the list, and added to our \"Off-Limits\" database so that no one may subscribe with this address in the future. Should you wish to subscribe to $listname in the future, please choose the \"Opt In\" button or contact the webmaster. $htmlfooter"; exit(); } ######################################################################### ##### 13. check_foropt_out: makes sure the user is not in the opt # ##### out database before we subscribe them. # ######################################################################### sub check_for_opt_out { $checked_for_opt_out = 1; if($opt_in_preferences eq "opt in"){ if(&check_opt_in != 1 && $data{'tk'} eq ""){ $data{'Send'} = "Token"; &opt_in("Quiet"); print "$htmlheader
Confirmation Required


The $listname service requires a confirmation in order to prevent others from subscribing you to the list without your consent. You have been sent an email with a special link. When you receive the email, please click on the link, or copy and paste it into your browser to enable your subscription. $htmlfooter"; exit(); } } open(FILE, "<$opt_out_file") || &debug("Could not open $opt_out_file (opt out file) for reading. The system returned $!"); while(){ if($_ =~ /^\Q$email\E$/i){ print "$htmlheader
Error: $email has opted out


The owner of the email address $email has used the \"opt out\" feature of this service. This means that this email address may no longer be subscribed to our list. If this is your email address, and you wish to opt back in, please click the button.
$htmlfooter"; close(FILE); exit(); } } close(FILE); } ######################################################################### ##### 14. opt_in: Various stuff to let users opt_in to the system. # ######################################################################### sub opt_in { &check_for_opt_out if $data{'wasoo'} ne "Yes" && $checked_for_opt_out !=1; if($data{'Send'} eq "Token"){ for($i = 0; $i < 50; $i++){ $rand[$i] = $i; } $token = crypt(int(rand(@rand)),time.$$); # Save any extra fields they entered... &save_extra_fields; open(FILE, ">>$temp_signup_file") || &debug("Could not open temporary signup file for writing: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("could not lock ($temp_signup_file) temporary signup file. $!"); } else { binmode(FILE); } my $date = &get_date("long"); print FILE "$email|$token|$name|$ENV{'REMOTE_ADDR'}|$date\n"; close(FILE); $mailmessage = " Hello. Someone has requested to \"opt in\" to our mailing list $listname using this email address: $email To prevent abuse of the system, we are sending this confirmation message to you to let you decide if this is what you want. If you wish to subscribe, please use this link: $cgisubscribe_url?FA=oi&tk=$token&em=$email If you do not wish to subscribe, just ignore this message and no action will be taken. To permanently opt out of our subscription service: $cgisubscribe_url?FA=oo&em=$email --- $owner_name $owner_email"; &send_mail($email,"$email",$owner_email,$owner_name, $owner_email,$owner_name,"Confirm Opt-In",$mailmessage, $mail_server_hostname,$this_server_hostname,$opsys); print "$htmlheader
Opt-In Process Begun


Thank you for your request to opt in to the $listname mailing list. We have sent an email to $email with a special link to confirm that you truly do wish to opt in. When you receive the email, please click on that link, or copy it and paste it into your browser. At that time, you will be subscribed to the list. $htmlfooter" unless $_[0] eq "Quiet"; exit() unless $_[0] eq "Quiet"; } else { # Look for them in the temp signup file to match their token, and # take them out if we do find them... open(FILE, "+<$temp_signup_file") || &debug("Could not open $temp_signup_file for read/write: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("could not lock $temp_signup_file: $!"); } else { binmode(FILE); } @lines = ; foreach $line (@lines){ if($line =~ /^$data_em\|$data{'tk'}\|/i){ $foundit = 1; $oldline = $line; } else { $newfile .= $line; } } truncate(FILE, length($newfile)); seek(FILE, 0,0); print FILE $newfile; close(FILE); $newfile = ""; if($foundit == 1){ open(FILE,"+<$opt_out_file") || &debug("Could not open $opt_out_file for writing: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("Could not lock $opt_out_file: $!"); } else { binmode(FILE); } @lines = ; foreach $line (@lines){ if($line !~ /^\Q$data_em\E$/){ $newfile .= $line; } } truncate(FILE, length($newfile)); seek(FILE, 0, 0); print FILE $newfile; close(FILE); $newfile = ""; # Put them on the opt-in list for proof later... open(FILE, ">>$opt_in_file") || &debug("Could not open $opt_in_file for writing: $!"); if($opsys eq "unix"){ flock(FILE, 2) || &debug("Could not lock $opt_in_file: $!"); } else { binmode(FILE); } seek(FILE, 0, 2); chomp($oldline); my $date = &get_date("long"); $oldline = "$oldline|$ENV{'REMOTE_ADDR'}|$date\n"; print FILE $oldline; close(FILE); ($email,$name) = (split(/\|/, $oldline))[0,2]; &subscribe_to_list; exit(); } else { # Check if they're already subscribed $email = $data_em; &check_for_duplicates; print "$htmlheader
Error: Token not found or does not match email address!


When you signed up, we emailed you a link with a special token. The link looks something like this:

$cgisubscribe_url?FA=oi&tk=97ch56XNTyh/A&em=you\@your_email_address

Some email programs will not let you click on the link directly, or they may not include the whole link. If this is the case, please go back to your mail program and make sure to copy the full link and paste it into your browser. If you continue to experience this error, please contact the webmaster. $htmlfooter"; exit(); } } } ######################################################################### ##### 15. check_opt_in: Checks to see if they're allowed to subscribe.# ######################################################################### sub check_opt_in { my($foundit); # check to see if they're on the opt-in list, and # if not open(FILE, "<$opt_in_file"); while(){ if($_ =~ /^\Q$email\E\|/i){ $foundit = 1; last; } } close(FILE); $foundit; } ######################################################################### ##### 16. check_for_duplicates: don't let them subscribe twice. :) # ######################################################################### sub check_for_duplicates { # Check for duplicates open(FILE, "<$subscribers_database") || &debug("Can't open subscribers database ($subscribers_database) to add subscriber. The system responded: $!"); $testemail = (grep(/\Q<$email>\E$/i, ))[0]; close(FILE); chomp($testemail); if($testemail =~ /\Q<$email>\E/i){ print "$htmlheader


Error: Duplicate Email

We're sorry, but the email address you entered ($email) is already subscribed to our mailing list. There is no need to subscribe again. If you entered suggestions, they have been mailed to $owner_name.
$htmlfooter\n"; exit(); } } ######################################################################### ##### 17. admin_login: print the admin login screen. # ######################################################################### sub admin_login { print "$htmlheader
Please enter your password for CGI-Subscribe Administration:
$htmlfooter"; exit(); } ######################################################################### ##### 18. admin_menu: print the admin menu # ######################################################################### sub admin_menu { print "$htmlheader Welcome to CGI-Subscribe Administration.

From this menu, you may mail all your subscribers, change your password, view a list of your subscribers, or delete a subscriber. $admformtop $admformtop
Mail Your Subscribers
Enter a message in the area below to mail all the subscribers on your list.
Mail format: Plain text HTML Plain and HTML

Change Password
New Password:
Confirm Password:
Subscriber Management
$admformtop Extra Fields
Update extra fields data to match active subscribers database, and download an ascii file of that data for import into Excel and other such programs: $admformtop
$htmlfooter"; } ######################################################################### ##### 19. default_page: If we don't know what they're trying to do, # ##### we'll just print them the subscription form. :) # ######################################################################### sub default_page { foreach $x_field (@extra_fields){ $x_field =~ s/^\s+//g; $x_field =~ s/\s+$//g; $xfhtml .= "$x_field:
\n"; } print <Subscription Form for $listname

$error Use this form to subscribe to the list. Be sure and enter your complete email address, so we can make sure to reach you!

$xfhtml
E-Mail Address:
Comments? Suggestions? Feedback is welcome!
$htmlfooter EOF exit(); } sub save_extra_fields { # Okay, and we'll also save any extra fields they entered. But first, # if by some bizarre chance they entered a | symbol, let's get rid of # that, and any newline characters as well: open(XF, ">>$path_to_extra_fields_file") || &debug("Can't open extra fields file '$path_to_extra_fields_file': $!"); if($opsys eq "unix"){ flock(XF, 2); } else { binmode(XF); } seek(XF, 0, 2); if($data_Name eq ""){ $data_Name = "$listname Subscriber"; } # | to | (HTML representation of |) $data_Name =~ s/\|/|/g; $data_Email =~ s/\|/|/g; # carriage-return/line feed to space $data_Name =~ s/\s+/ /sg; # Email doesn't need spaces. $data_Email =~ s/\s+//sg; print XF "$data_Name|$data_Email"; foreach $x_field (@extra_fields){ $x_field =~ s/^\s+//sg;$x_field =~ s/\s+$//sg; $data{$x_field} =~ s/\|/|/sg; $data{$x_field} =~ s/\s+/ /sg; print XF "|$data{$x_field}"; } print XF "\n"; close(XF); } sub check_required_extra_fields { foreach $x_field (@extra_fields){ # Strip spaces from beggining and end $x_field =~ s/^\s+//g; $x_field =~ s/\s+$//g; foreach $r_field (@required_extra_fields){ $r_field =~ s/^\s+//g; $r_field =~ s/\s+$//g; if($r_field eq $x_field && $data{$x_field} eq ""){ $error = "Error: the \"$x_field\" field is required.

"; &default_page; } } } } # Goes through the subscribers database file, and removes # any entries from the extra fields file that are not actually # subscribed. When you are done, extra fields file should have # only the information from the users in subscribers.db. sub merge_extra_fields { open(S, "<$subscribers_database") || &debug("Could not read subscribers database $subscribers_database: $!"); open(F, "+<$path_to_extra_fields_file") || &debug("Could not open extra fields file $path_to_extra_fields_file for read/write: $!"); if($opsys eq "unix"){ flock(F, 2);} else { binmode(F); } @fields = ; FIELDS: while(){ $_ =~ /^(.*?)(\s+)(<.*>)$/; $name = $1; $email = $3; chomp($email); $email =~ s///g; foreach $field (@fields){ ($fname,$femail,@stuff) = split(/\|/, $field); if($femail eq $email){ $newfields .= "$field"; next FIELDS; } } } truncate(F, length($newfields)); seek(F, 0, 0); print F $newfields; close(F); close(S); print "$htmlheader Additional fields data have been merged to the existing subscriber list.
$admformtop You may download the extra_fields file as plain text for import into a spreadsheet or other program.
Separate fields with (one character): $htmlfooter"; exit(); } sub download_extra_fields { print "Content-type: text/plain\n\n"; open(F, "<$path_to_extra_fields_file"); while(){ $_ =~ s/\|/$data{'delim'}/g; $stuff = $_; chomp($stuff); if($stuff ne ""){$found = 1;} print; } close(F); if($found ne "1"){ print "No entries found."; } exit(); } # Trying to reliably fork a process under Windows or Unix. # Perl under Windows just does not fork reliably. So, under Windows # we'll just try to detach the process. This has been tested to work # under Windows 2000 Professional and IIS with ActiveState Perl 5.6.1 # build 633 with a list of up to 35,000 members. Any other O/S and # you're on your own. sub oh_fork_it { # Count the number of subscribers. open(FILE, "<$subscribers_database") || &debug("Can't read subscribers database '$subscribers_database': $!"); while(){ $number_of_subscribers++; } close(FILE); # Since we wait 1 second between mails, it will take approximately as # many seconds as there are list members to mail everyone. $timetomail = $number_of_subscribers; # This is a kludgey way to determine how many hours, minutes, seconds # there are in that total number of seconds. if($timetomail >= 60){ $minutes = int($timetomail / 60); } if($minutes >= 60){ $hours = int($minutes / 60); $minutes = ($timetomail - ($hours * 60 * 60)) / 60; } $seconds = $timetomail - ($minutes * 60) - ($hours * 60 * 60); # Make a nice 00:00:00 type of time display. $totaltime = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes) . ":" . sprintf("%02d", $seconds); # Pretty much most unixy systems support fork. if($opsys eq "unix"){ $pid = fork(); &debug("Fork failed: $!") unless defined $pid; if($pid){ print "$htmlheader
Mailing in progress!

Your message is being sent to your $number_of_subscribers subscribers. Depending upon the number of subscribers, this may take anywhere from a few seconds to a few hours. Estimated mail time: $totaltime. In order to try to reduce the load on your server, CGI-Subscribe sends no more than one message per second. When the mailing is complete, you will receive a confirmation email.


$adminfooter