#!/usr/local/bin/perl5 # ___________ documentation __________________________________________ # # author: Doug Sanderson # # This perl script controls all screens and forms associated with the # "sports date" program. Users can register their sports interests # and query for other registered users with similar interests. The # data is kept in an ascii file, with one line per registered user, and # the backquote character used to separate field tokens on one line. # Output data is initially written to a tmp file, and when complete, # the contents of the tmp file are sent to the client. If an error # is encountered part-way through the creation of a new page, only the # error message will be returned to the user, and the partially constructed # page will be disgarded. # ___________ global stuff ___________________________________________ use Text::ParseWords; @INPUT_DATA; # holds values passed into this program by the # REQUEST_METHOD @page_types = ("TOP", "TOP_QUERY", "QUERY_PREFERENCES", "SEND_EMAIL", "TOP_ADD", "ADD_ME", "TOP_NUKE", "NUKE_ME"); $page_type; # TOP, QUERY_PREFERENCES, etc $io_dir="."; # holds temp i/o files $dat_file="$io_dir/date.dat"; # holds the database data $out_file=""; # output will initially be redirected into this file, and # if there are no errors, we will cat file to stdout # (the actual filename will be determined by a random # number generator) # Each line of the dat file will have these tokens, with the ` (backslash) # character acting as the separator between tokens: # nickname (user defined nickname, not the user's actual name) # email (user's email address) # sport (such as "whitewater kayaking" or "hiking") # level (0 to 10, where 0=no_experience, 10=expert) # age (user's age) # sex (m or f) # want_sex (male (user looking for male companion), female, or either) # want_level_min (0 to 10; looking for at least this much experience) # want_level_max (0 to 10; looking for not more than this much experience) # want_age_min (looking for a person at least this old) # want_age_max (looking for a person not older than this) # city # state (2 letter abbreviation) # greeting (optional personal greeting) # NOTE: any line beginning with a # will be considered a comment. @field_name = ("nickname", "email", "sport", "level", "age", "sex", "want_sex", "want_level_min", "want_level_max", "want_age_min", "want_age_max", "city", "state", "greeting"); foreach $field (@field_name) { $searcher{$field} = ""; # the "searcher" associative array contains data # from the user who submitted the query or request $db{$field} = ""; # the "db" associative array contains data # from-or-going-to the database } $content_type = ""; $author = ""; @sexual_preference = ("either", "male", "female"); # ___________ the "main" perl code starts here _______________________ srand; # used to randomly select tmp filenames &open_out_file (); &parse_input_data (); &validate_page_type(); if ( $page_type eq TOP ) { &create_top(); } elsif ( $page_type eq TOP_QUERY ) { &create_query_options(); } elsif ( $page_type eq QUERY_PREFERENCES ) { &create_query_results(); } elsif ( $page_type eq SEND_EMAIL ) { &email_to_nickname(); } elsif ( $page_type eq TOP_ADD ) { &create_add_form(); } elsif ( $page_type eq ADD_ME ) { &add_new_user(); } elsif ( $page_type eq TOP_NUKE ) { &create_nuke_form(); } elsif ( $page_type eq NUKE_ME ) { &nuke_old_user(); } close (OUT_MAIN); print `/bin/cat $out_file`; unlink $out_file; exit 0; # ___________________________________________________________________ sub open_out_file { # all non-error output will be loaded into a temp file; if there are no # errors, this file will be printed to stdout (back to client) $i = ( rand() * 100 ) % 100; $out_file = "$io_dir/tmp_$i"; open (OUT_MAIN, ">$out_file") || &fatal_error("open_out_file", "failed to open $out_file"); } # ___________________________________________________________________ sub parse_input_data { # All the parameters passed into this program will be placed in the # key-value array INPUT_DATA. Also, the variable page_type will be # assigned a value. local ( $request_method, $query_string, @key_value_pairs, $key_value, $key, $value, $new_data); $new_data = "no"; $page_type = TOP; # invoke the main greeting screen unless told otherwise # is the request method valid? $request_method = $ENV{'REQUEST_METHOD'}; if ($request_method eq "GET") { $query_string = $ENV{'QUERY_STRING'}; if ( $query_string ne "" ) { $new_data = "yes"; } } elsif ($request_method eq "POST") { read (STDIN, $query_string, $ENV{'CONTENT_LENGTH'}); if ( $query_string ne "" ) { $new_data = "yes"; } } if ($new_data eq "yes") { # split the whole query_string into key_value_pairs (the '&' # character separates pairs) @key_value_pairs = split (/&/, $query_string); foreach $key_value (@key_value_pairs) { # the '=' character separates the key from the value ($key, $value) = split (/=/, $key_value); # the '+' was used to get rid of blanks (put them back now) $value =~ tr/+/ /; # translate any special characters from hex (0-9 and a-f) # to the ascii equivalent $value =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack ("C", hex ($1))/eg; # if we got scrolled list that looks like this: # Numbers=One&Numbers=Two&Numbers=Three # then turn it into something that looks like this: # key=NUMBERS value=One\0Two\0Three if (defined($INPUT_DATA{$key})) { $INPUT_DATA{$key} = join ("\0", $INPUT_DATA{$key}, $value); } else { $INPUT_DATA{$key} = $value; } } # if there was a query_string, then page_type had better be one # of the data values $page_type = $INPUT_DATA{page_type}; if ( $page_type eq "" ) { # its an error; it will cause a fatal_error call soon $page_type = "none-supplied"; } } } # ___________________________________________________________________ sub validate_page_type { $found = nope; foreach $page_value (@page_types) { if ($page_value eq $page_type) { $found = yes; last; } } if ($found eq nope) { &fatal_error("validate_page_type", "invalid page type $page_type"); } } # ____________________________________________________________________ # # This function is called in response to a request to display the toplevel # page of the sports date senerio. sub create_top { local ($title="welcome to sports date"); print OUT_MAIN "Content-type: text/html\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n\n$content_type\n$author\n$title\n\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN " \n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "
Query the Sports Date database to see who is doing what \n"; print OUT_MAIN "in your area. If you see someone you would like to \"share the \n"; print OUT_MAIN "experience\" with, you can contact the person via Sports Date \n"; print OUT_MAIN "email. Be sure to register yourself before you try to contact other \n"; print OUT_MAIN "Sports Date members.
Register yourself in the Sports Date database. \n"; print OUT_MAIN "You can specify who you are, which sport you enjoy, and who you would like \n"; print OUT_MAIN "to \"share the experience\" with.  Register more than once for \n"; print OUT_MAIN "more than one sports interest.
Remove one or more of your prior Sports Date registrations.
\n"; print OUT_MAIN "

This page designed and maintained by Doug Sanderson.\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; } # ____________________________________________________________________ # # This function is called when the user wants to look at the database # entries. We will return a form that allows the user to indicate # her areas of interest. sub create_query_options { local ($title="sports date query options"); print OUT_MAIN "Content-type: text/html\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n\n$content_type\n$author\n$title\n\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "

Look For A Sports Date

\n"; print OUT_MAIN "

Use the selections below to specify which sport you are \n"; print OUT_MAIN "interested in, and what kind of person you would like to \n"; print OUT_MAIN "\"share the experience\" with.\n"; print OUT_MAIN "

\n"; print OUT_MAIN "\n"; print OUT_MAIN "

\n"; print OUT_MAIN "name of sport: "; print OUT_MAIN ""; print OUT_MAIN "(optional field; its ok to abbreviate sport name)\n"; print OUT_MAIN "
\n"; print OUT_MAIN "your sexual preference: "; print OUT_MAIN "\n"; print OUT_MAIN "
\n"; print OUT_MAIN "his/her minimum skill level: "; print OUT_MAIN "\n"; print OUT_MAIN "(the minimum skill level of interest; 0=beginner)\n"; print OUT_MAIN "
\n"; print OUT_MAIN "his/her maximum skill level: "; print OUT_MAIN "\n"; print OUT_MAIN "(the maximum skill level of interest; 10=expert)\n"; print OUT_MAIN "
\n"; print OUT_MAIN "his/her minimum age: "; print OUT_MAIN "\n"; print OUT_MAIN "
\n"; print OUT_MAIN "his/her maximum age: "; print OUT_MAIN "\n"; print OUT_MAIN "
\n"; print OUT_MAIN "his/her city: "; print OUT_MAIN "\n"; print OUT_MAIN "(optional field)\n"; print OUT_MAIN "
\n"; print OUT_MAIN "his/her state: "; print OUT_MAIN "\n"; print OUT_MAIN "(optional field)\n"; print OUT_MAIN "
\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "

\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; } # ____________________________________________________________________ # # This function generates a html page filled with entries from the # database which match the search parameters input by the user. sub create_query_results { local $found_match = "no"; local $matching_nickname; local @all_matches; local $all_length = 0; if ($INPUT_DATA{decision} ne "ok") { &create_top(); } else { # I'm going to use java script to pre-validate fields, so lets assume # everything is cool by the time it gets to us. foreach $field (@field_name) { $searcher{$field} = $INPUT_DATA{$field}; } open (DB_FILE, "$dat_file") || &fatal_error("create_query_results", "failed to open $dat_file"); print OUT_MAIN "Content-type: text/html\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n\n$content_type\n$author\n$title\n\n"; # add JavaScript error checking print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; while ( ) { $matching_nickname = &query_check("$_"); if ($matching_nickname ne "") { if ($found_match eq "no") { $found_match = "yes"; print OUT_MAIN "

Matches From The Sports Date Database

\n"; } $all_matches[$all_length] = $matching_nickname; ++$all_length; &write_query_match("$_"); } } close DB_FILE; if ($found_match eq "yes") { &add_contact_information(@all_matches); } else { &write_query_no_match(); } print OUT_MAIN "
\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; } } # ____________________________________________________________________ sub query_check { local ($db_line) = @_; local $i = 0; local $outcome = "match"; local $matching_nickname = ""; if ( $db_line =~ /^ *#/ ) # ignore comment lines { $outcome = "no match"; } else { @tokens = split(/`/, $db_line); # use ' as field delimeter foreach $field (@field_name) { $db{$field} = @tokens[$i]; ++$i; } if ( $searcher{sport} ne "" ) { if ( $db{sport} !~ /$searcher{sport}/ ) { $outcome = "no match"; } } if ( ($searcher{want_level_min} > $db{level}) || ($searcher{want_level_max} < $db{level}) ) { $outcome = "no match"; } if ( ($searcher{want_age_min} > $db{age}) || ($searcher{want_age_max} < $db{age}) ) { $outcome = "no match"; } if ( $searcher{want_sex} ne "either" ) { if ( $searcher{want_sex} ne $db{sex} ) { $outcome = "no match"; } } if ( $searcher{city} ne "" ) { if ( $db{city} !~ /$searcher{city}/ ) { $outcome = "no match"; } } if ( $searcher{state} ne "" ) { if ( $db{state} !~ /$searcher{state}/ ) { $outcome = "no match"; } } } if ($outcome eq "match") { $matching_nickname = $db{nickname};} $matching_nickname; } # ____________________________________________________________________ sub write_query_match { print OUT_MAIN "

$db{nickname}

\n"; print OUT_MAIN "$db{nickname} is a $db{age} year old \n"; if ($db{sex} eq "male") { print OUT_MAIN "male \n"; } else { print OUT_MAIN "female \n"; } print OUT_MAIN "from $db{city}, $db{state}. $db{nickname} has achieved \n"; print OUT_MAIN "skill level $db{level} in $db{sport}, and would like to \n"; print OUT_MAIN "meet a \n"; if ($db{want_sex} eq "male") { print OUT_MAIN "male \n"; } elsif ($db{want_sex} eq "female") { print OUT_MAIN "female \n"; } else { print OUT_MAIN "male or female \n"; } print OUT_MAIN "between the ages of $db{want_age_min} and \n"; print OUT_MAIN "$db{want_age_max} with a skill level between \n"; print OUT_MAIN "$db{want_level_min} and $db{want_level_max}. \n"; print OUT_MAIN "Here is a personal greeting from $db{nickname}: \n"; print OUT_MAIN "$db{greeting}\n"; } # ____________________________________________________________________ sub add_contact_information { local (@all_nicknames) = @_; local $all_length = @all_nicknames; local $i; print OUT_MAIN "


Contact One Of The Above People

\n"; print OUT_MAIN "Fill out the information below, and click on ok. \n"; print OUT_MAIN "An email message will then be sent to the person you \n"; print OUT_MAIN "selected. This message will contain your email address \n"; print OUT_MAIN "from the Sports Date database. \n"; print OUT_MAIN "You must already be registered in the Sports Date \n"; print OUT_MAIN "database before you can contact another Sports Date member.\n"; print OUT_MAIN "
\n"; print OUT_MAIN "\n"; print OUT_MAIN "

\n"; print OUT_MAIN "nickname of person you wish to contact: "; print OUT_MAIN "\n"; print OUT_MAIN "

\n"; print OUT_MAIN "nickname: "; print OUT_MAIN "\n"; print OUT_MAIN "(your nickname, as registered in the Sports Date database)\n"; print OUT_MAIN "

\n"; print OUT_MAIN "email: "; print OUT_MAIN "\n"; print OUT_MAIN "(your email address, as registered in the Sports Date database)\n"; print OUT_MAIN "
\n"; print OUT_MAIN "\n"; print OUT_MAIN "\n"; print OUT_MAIN "

\n"; } # ____________________________________________________________________ sub write_query_no_match { print OUT_MAIN "

No Matches Found

\n"; print OUT_MAIN "There were no matches in the current Sports Date \n"; print OUT_MAIN "database that matched these parameters:\n"; print OUT_MAIN "