#!/usr/bin/perl -w ############################################################################### # users.pl - this code is for user creation and administration # # Copyright (C) 1997 Rob "CmdrTaco" Malda # malda@slashdot.org # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # $Id: users.pl,v 1.22 2000/09/25 17:11:44 pudge Exp $ ############################################################################### use strict; use lib '../'; use vars '%I'; use Slash; ################################################################# sub main { *I = getSlashConf(); getSlash(); my $op = $I{F}{op}; if ($op eq "userlogin" and $I{U}{uid} > 0) { my $refer = 'disc.pl'; redirect($refer); return; } header("$I{sitename} Users"); print < 0 && $op ne "userclose";

[ User Info | Edit User Info | Edit Homepage | Edit Comments | Logout ]

EOT # and now the carnage begins if ($op eq "newuser") { newUser(); } elsif ($op eq "edituser") { # the users_prefs table if ($I{U}{uid} > 0) { editUser($I{U}{nickname}); } else { displayForm(); #crapMesg(); } } elsif ($op eq "edithome" || $op eq "preferences") { # also known as the user_index table if ($I{U}{uid} > 0) { editHome($I{U}{nickname}); } else { displayForm(); #crapMesg(); } } elsif ($op eq "editcomm") { # also known as the user_comments table if ($I{U}{uid} > 0) { editComm($I{U}{nickname}); } else { displayForm(); #crapMesg(); } } elsif ($op eq "userinfo" || !$op) { if ($I{F}{nick}) { userInfo($I{F}{nick}); } elsif ($I{U}{uid} < 1) { displayForm(); } else { userInfo($I{U}{nickname}); } } elsif ($op eq "saveuser") { saveUser($I{U}{uid}); userInfo($I{U}{nickname}); } elsif ($op eq "savecomm") { saveComm($I{U}{uid}); userInfo($I{U}{nickname}); } elsif ($op eq "savehome") { saveHome($I{U}{uid}); userInfo($I{U}{nickname}); } elsif ($op eq "sendpw") { mailPassword($I{U}{nickname}); } elsif ($op eq "mailpasswd") { mailPassword($I{F}{unickname}); } elsif ($op eq "suedituser" && $I{U}{aseclev} > 100) { editUser($I{F}{name}); } elsif ($op eq "susaveuser" && $I{U}{aseclev} > 100) { saveUser($I{F}{uid}); } elsif ($op eq "sudeluser" && $I{U}{aseclev} > 100) { delUser($I{F}{uid}); } elsif ($op eq "userclose") { print "Thank you. Please come again."; displayForm(); } elsif ($op eq "userlogin" && $I{U}{uid} > 0) { # print $query->redirect("$I{rootdir}/index.pl"); userInfo($I{U}{nickname}); } elsif ($op eq "preview") { previewSlashbox(); } elsif ($I{U}{uid} > 0) { userInfo($I{F}{nick}); } else { displayForm(); } miniAdminMenu() if $I{U}{aseclev} > 100; writelog("users", $I{U}{nickname}); footer(); } ################################################################# sub crapMesg { print <Error

Our system doesn't remember who you are, yet you think you are logged in. This could be because you are using an older browser. Or are behind a firewall or proxy or something that is stripping cookies. If you think none of these are the problem, please send us your browser version, nickname, uid, platform, and any other details that seem relavant. Optionally, you might not have actually ever logged in, please click here to login.

EOT } ################################################################# sub checkList { my $string = shift; $string = substr($string, 0, -1); $string =~ s/[^\w,-]//g; my @e = split m/,/, $string; $string = sprintf "'%s'", join "','", @e; if (length($string) > 254) { print "You selected too many options
"; $string = substr($string, 0, 255); $string =~ s/,'??\w*?$//g; } elsif (length $string < 3) { $string = ""; } return $string; } ################################################################# sub previewSlashbox { my ($title, $content, $url) = sqlSelect( "title,block,url", "blocks, sectionblocks", "blocks.bid = sectionblocks.bid AND blocks.bid = " . $I{dbh}->quote($I{F}{bid}) ); my $cleantitle = $title; $cleantitle =~ s/<(.*?)>//g; titlebar("100%","Preview $cleantitle"); print <What you see on the right hand side is a preview of the block labeled "$cleantitle". If you select it from the Preferences Page, you will have that little block added to the right hand side of your Custom $I{sitename} page. Exciting? Not really, but its a great way to waste time.

EOT print < 999;

Edit $I{F}{bid}

EOT print qq!!; print portalbox($I{fancyboxwidth}, $title, $content, "", $url); } ################################################################# sub miniAdminMenu { print < [ Admin | ] EOT } ################################################################# sub newUser { # Check if User Exists $I{F}{newuser} =~ s/\s+/ /g; $I{F}{newuser} =~ s/[^ a-zA-Z0-9\$_.+!*'(),-]+//g; $I{F}{newuser} = substr($I{F}{newuser}, 0, 20); (my $matchname = lc $I{F}{newuser}) =~ s/[^a-zA-Z0-9]//g; my($cnt) = sqlSelect( "matchname","users", "matchname=" . $I{dbh}->quote($matchname) ) || sqlSelect( "realemail","users", " realemail=" . $I{dbh}->quote($I{F}{email}) ); if ($matchname ne '' && $I{F}{newuser} ne '' && !$cnt && $I{F}{email} =~ /\@/) { titlebar("100%", "User $I{F}{newuser} created."); $I{F}{pubkey} = stripByMode($I{F}{pubkey}, "html"); sqlInsert("users", { realemail => $I{F}{email}, nickname => $I{F}{newuser}, matchname => $matchname, passwd => changePassword() }); my($uid) = sqlSelect("LAST_INSERT_ID()"); sqlInsert("users_info", { uid => $uid, -lastaccess=>'now()' } ); sqlInsert("users_prefs", { uid => $uid } ); sqlInsert("users_comments", { uid => $uid } ); sqlInsert("users_index", { uid => $uid } ); # sqlInsert("users_key", { uid => $uid } ); # Not necessary print <Email: =$I{F}{email}

User ID: =$uid

Nick: =$I{F}{newuser}

Password: =mailed to $I{F}{email}

Once you receive your password, you can log in and set your account up

EOT mailPassword($I{F}{newuser}); } else { # Duplicate User displayForm(); } } ################################################################# sub changePassword { my @chars = grep !/[0O1Iil]/, 0..9, 'A'..'Z', 'a'..'z'; return join '', map { $chars[rand @chars] } 0 .. 7; } ################################################################# sub mailPassword { my($name) = @_; my($nickname, $passwd, $email) = sqlSelect( "nickname,passwd,realemail", "users", "nickname=" . $I{dbh}->quote($name) ); my $msg = blockCache("newusermsg"); $msg = prepBlock($msg); $msg = eval $msg; if ($name ne '' && (lc($name) eq lc($nickname))) { sendEmail($email, "$I{sitename} user password for $name", $msg) if $name; print "

Password for $name was just emailed.

\n"; } else { print "

$name was not found. No Password mailed.

\n"; } } ################################################################# sub userInfo { my($nick) = @_; my $c = $I{dbh}->prepare( "SELECT homepage,fakeemail,users.uid,bio, seclev,karma FROM users, users_info WHERE users.uid = users_info.uid AND nickname=" . $I{dbh}->quote($nick) . " and users.uid > 0" ); $c->execute; if (my($home, $email, $uid, $bio, $useclev, $karma) = $c->fetchrow) { $bio = stripByMode($bio, "html"); if ($I{U}{nickname} eq $nick) { my $sth = $I{dbh}->prepare("SELECT points FROM users_comments WHERE uid=$uid"); $sth->execute; my $points = $sth->fetchrow_array; $sth->finish; titlebar("95%", "Welcome back $nick ($uid)"); print <This is your user info page. There are thousands more, but this one is yours. You most likely are not so interested in you, and probably would be most interested in clicking the "Edit User Info" and "Customize..." links you see up top there so you can customize $I{sitename}, or change your password.

EOT # Users should be able to see their own points. if ($I{U}{uid} == $uid && $points > 0) { print <You're a moderator with $points points. Please read the Moderator Guidelines before you do any moderation.


EOT } print <
EOT } else { titlebar("95%", "User Info for $nick ($uid)"); } print qq!$home
$email
!; print "

Karma $karma (mostly the sum of moderation done to users comments)

" if $I{U}{aseclev} || $I{U}{uid} == $uid; print "User Bio
$bio

" if $bio; my($k) = sqlSelect("pubkey", "users_key", "uid=$uid"); $k = stripByMode($k, "html"); print "Public Key

\n$k

" if $k; $I{F}{min} = 0 unless $I{F}{min}; my $sqlquery = "SELECT pid,sid,cid,subject," . getDateFormat("date","d") . ",points FROM comments WHERE uid=$uid "; $sqlquery .= " ORDER BY date DESC LIMIT $I{F}{min},50 "; my $comments = $I{dbh}->prepare($sqlquery); $comments->execute; print "

$nick has posted " . $comments->rows . " comments (this only counts the last few weeks)

"; my $x; while (my($pid, $sid, $cid, $subj, $cdate, $pts) = $comments->fetchrow) { $x++; my($r) = sqlSelect("count(*)", "comments", "sid='$sid' and pid=$cid"); my $replies = " Replies:$r" if $r; print <$x $subj posted on $cdate (Score:$pts$replies)

EOT my $S = sqlSelectHashref("section, title, writestatus", "stories", "sid='$sid'"); if ($S) { my $href = $S->{writestatus} == 10 ? "$I{rootdir}/$S->{section}/$sid.shtml" : "$I{rootdir}/article.pl?sid=$sid"; print qq!

attached to $S->{title}

!; # $S->{section}/$sid.shtml } else { my $P = sqlSelectHashref("question", "pollquestions", "qid='$sid'"); print qq!
attached to $P->{question}! if $P->{question}; } print "
"; } $comments->finish; } else { print "

$nick not found.

"; } $c->finish; } ################################################################# sub editKey { my($k) = sqlSelect("pubkey", "users_key", "uid=$_[0]"); printf qq!

Public Key
!, stripByMode($k, 'literal'); } ################################################################# sub editUser { my($name) = @_; my($uid, $realname, $realemail, $fakeemail, $homepage, $nickname, $passwd, $sig, $useclev, $bio, $maillist) = sqlSelect( "users.uid, realname, realemail, fakeemail, homepage, nickname, " . "passwd, sig, seclev, bio, maillist", "users, users_info", "users.uid=users_info.uid AND nickname=" . $I{dbh}->quote($name) ); return if $uid < 1; titlebar("100%", "Editing $name ($uid) $realemail"); print qq!
!; $homepage ||= "http://"; my $tempnick = $nickname; $tempnick =~ s/ /+/g; print <You can automatically login by clicking This Link and Bookmarking the resulting page. Please note: this is insecure, but very convenient.

Real Name (optional)

Real Email (required but never displayed publicly. This is where your passwd is mailed. If you change your email, notification will be sent)

Fake Email (optional:This email publicly displayed by your comments, you may spam proof it, leave it blank, or just type in your address)

Homepage (optional:you must enter a fully qualified URL!)

Headline Mailing List EOT selectForm("maillist", "maillist", $maillist); printf <Signature (appended to the end of your comments.)

Biography (Information publicly displayed on your user page.)
EOT editKey($uid); print <Password Enter new passwd twice to change it. (must be 6-12 chars long)

EOT # print " " if $I{U}{aseclev}> 499; } ################################################################# sub tildeEd { my($extid, $exsect, $exaid, $exboxes, $userspace) = @_; titlebar("100%", "Exclude Stories from the Homepage"); print < Authors Topics Sections EOT # Customizable Authors Thingee my $C = sqlSelectMany("aid", "authors", "seclev > 99", "order by aid"); while (my($aid) = $C->fetchrow) { my $checked = ($exaid =~ /'$aid'/) ? ' CHECKED' : ''; print qq!$aid
\n!; } $C->finish; # Customizable Topic print qq!!; $C = sqlSelectMany("tid,alttext", "topics", "1=1 ", "order by tid"); while (my($tid, $alttext) = $C->fetchrow) { my $checked = ($extid =~ /'$tid'/) ? ' CHECKED' : ''; print qq!$alttext
\n! if $tid; } $C->finish; print "
"; # Customizable Sections print ''; $C = sqlSelectMany("section,title", "sections", "isolate=0", "order by title"); while (my($section,$title) = $C->fetchrow) { my $checked = ($exsect =~ /'$section'/) ? " CHECKED" : ""; print qq!$title
\n! if $section; } $C->finish; print ""; print "

"; titlebar("100%", "Customize InfoBoxes"); $userspace = stripByMode($userspace, 'literal'); print <

Configuration Options Important: If you leave these all unchecked, it means you want the default selection of boxes. If you start selecting boxes, remember to set all of them that you want because the default selection will be ignored. Default entries are bolded.

User Space (check 'user space' below and whatever you place here will appear your custom $I{sitename})

EOT $C = sqlSelectMany("bid,title,ordernum", "sectionblocks", "portal=1", "order by bid"); while (my($bid,$title,$o) = $C->fetchrow) { my $checked = ($exboxes =~ /'$bid'/) ? " CHECKED" : ""; $title =~ s/<(.*?)>//g; print "" if $o > 0; print qq!! . qq!!; unless ($bid eq "srandblock") { print $title; } else { print "Semi-Random Box"; } print "
\n"; print "
" if $o > 0; } $C->finish; print <

If you have reasonable suggestions for boxes that can be added here, or a problem with one of the boxes already here, email $I{siteadmin_name}.

The preferred format is the Netscape RDF format that is rapidly becoming the de facto format for exchanging headlines between sites. EOT print "

"; } ################################################################# sub editHome { my($name) = @_; my($uid, $willing, $tzformat, $tzcode, $noicons, $light, $userspace, $extid, $exaid, $exsect, $exboxes, $maxstories, $noboxes) = sqlSelect("users.uid, willing, dfid, tzcode, noicons, light, " . "mylinks, users_index.extid, users_index.exaid, " . "users_index.exsect, users_index.exboxes, users_index.maxstories, " . "users_index.noboxes", "users, users_prefs, users_index", "users.uid=users_prefs.uid AND users.uid=users_index.uid AND " . "users.nickname=" . $I{dbh}->quote($name) ); return if $uid < 1; titlebar("100%", "Customize $I{sitename}'s Display"); print <
Date/Time Format
EOT selectGeneric("dateformats", "tzformat", "id", "description", $tzformat); selectGeneric("tzcodes", "tzcode", "tz", "description", $tzcode); print "
"; my $l_check = $light ? " CHECKED" : ""; my $b_check = $noboxes ? " CHECKED" : ""; my $i_check = $noicons ? " CHECKED" : ""; my $w_check = $willing ? " CHECKED" : ""; print < Light (reduce the complexity of $I{sitename}'s HTML for slow connections)

Deactivate Slashboxes (just the news, please.)

No Icons (disable topic icon images on stories)

Maximum Stories The default is 12. The main column displays 1/3rd of these at minimum, and all of today's stories at maximum.

Willing to Moderate By default all users are willing to Moderate. Uncheck this if you aren't interested.

EOT tildeEd($extid, $exsect, $exaid, $exboxes, $userspace); print qq!\t\n!; # print qq!\t ! if $I{U}{aseclev}> 499; print "\t\n\n"; } ################################################################# sub editComm { my($name) = @_; my($uid, $points, $posttype, $defaultpoints, $maxcommentsize, $clsmall, $clbig, $reparent, $noscores, $highlightthresh, $commentlimit, $nosigs, $commentspill, $commentsort, $mode, $threshold, $hardthresh) = sqlSelect("users.uid, points, posttype, defaultpoints, " . "maxcommentsize, clsmall, clbig, reparent, noscores, " . "highlightthresh, commentlimit, nosigs, commentspill, " . "commentsort, mode, threshold, hardthresh", "users, users_comments","users.uid=users_comments.uid AND nickname=" . $I{dbh}->quote($name) ); titlebar("100%", "Comment Options"); print <
EOT print "Display Mode"; selectGeneric("commentmodes", "umode", "mode", "name", $mode); print "

Sort Order\n"; selectForm("sortcodes", "commentsort", $commentsort); print "

Threshold"; selectGeneric("threshcodes", "uthreshold", "thresh", "description", $threshold); print <(comments scored less than this setting will be ignored. Anonymous posts start at 0, logged in posts start at 1. Moderators add and subtract points according to the Guidelines. EOT print "

Highlight Threshold"; selectGeneric("threshcodes", "highlightthresh", "thresh", "description", $highlightthresh); print "
(comments scoring this are displayed even after an article spills into index mode)"; my $h_check = $hardthresh ? " CHECKED" : ""; my $r_check = $reparent ? " CHECKED" : ""; my $n_check = $noscores ? " CHECKED" : ""; my $s_check = $nosigs ? " CHECKED" : ""; print <Hard Thresholds (Hides 'X Replies Below Current Threshold' Message from Threads)

Reparent Highly Rated Comments (causes comments to be displayed even if they are replies to comments under current threshold)

Do Not Display Scores (Hides score: They still apply you just don't see them.)

Limit only display this many comments. For best results, set this to a low number and sort by score.

Index Spill (When an article has this many comments, it switches to indexed mode)

Small Comment Penalty (Assign -1 to comments smaller than this many characters. This might cause some comments to be rated -2 and hence rendered invisible!)

Long Comment Bonus (Assign +1 to lengthy comments)

Max Comment Size (Truncates long comments, and adds a \"Read More\" link. Set really big to disable)

Disable Sigs (strip sig quotes from comments)

Comment Post Mode EOT selectGeneric("postmodes", "posttype", "code", "name", $posttype); print <

EOT # print qq! ! if $I{U}{aseclev}> 499; } ################################################################# sub saveUser { my $uid = $I{U}{aseclev} ? shift : $I{U}{uid}; my $name = $I{U}{aseclev} && $I{F}{name} ? $I{F}{name} : $I{U}{nickname}; $name = substr($name, 0, 20); return unless $uid > 0; print "

Saving $name

"; print <Your browser didn't save a cookie properly. This could mean you are behind a filter that eliminates them, you are using a browser that doesn't support them, or you rejected it.

EOT # stripByMode _after_ fitting sig into schema, 120 chars $I{F}{sig} = stripByMode(substr($I{F}{sig}, 0, 120), 'html'); $I{F}{fakeemail} = chopEntity(stripByMode($I{F}{fakeemail}, 'attribute'), 50); $I{F}{homepage} = "" if $I{F}{homepage} eq "http://"; $I{F}{homepage} = fixurl($I{F}{homepage}); # for the users table my $H = { sig => $I{F}{sig}, homepage => $I{F}{homepage}, fakeemail => $I{F}{fakeemail} }; # for the users_info table my $H2 = { maillist => $I{F}{maillist}, realname => $I{F}{realname}, bio => $I{F}{bio} }; my($oldEmail) = sqlSelect("realemail", "users", "nickname=" . $I{dbh}->quote($name)); if ($oldEmail ne $I{F}{realemail}) { $H->{realemail} = chopEntity(stripByMode($I{F}{realemail}, 'attribute'), 50); print "\nNotifying $oldEmail of the change to their account.
\n"; sendEmail($oldEmail, "$I{sitename} user email change for $name", < 5) { $H->{passwd} = $I{F}{pass1}; print qq!Password Changed (You'll need to log back in now.)
!; } elsif ($I{F}{pass1} ne $I{F}{pass2}) { print "

Passwords don't match. Password not changed.

"; } elsif (length $I{F}{pass1} < 6 && $I{F}{pass1}) { print "

Password is too short and was not changed.

"; } # update the public key sqlReplace("users_key", { uid => $uid, pubkey => $I{F}{pubkey} } ); # Update users with the $H thing we've been playing with for this whole damn sub sqlUpdate("users", $H, "uid=" . $uid . " AND uid>0", 1); # Update users with the $H thing we've been playing with for this whole damn sub sqlUpdate("users_info", $H2, "uid=" . $uid . " AND uid>0", 1); } ################################################################# sub saveComm { my $uid = $I{U}{aseclev} ? shift : $I{U}{uid}; my $name = $I{U}{aseclev} && $I{F}{name} ? $I{F}{name} : $I{U}{nickname}; $name = substr($name, 0, 20); return unless $uid > 0; print "

Saving $name

"; print <Your browser didn't save a cookie properly. This could mean you are behind a filter that eliminates them, you are using a browser that doesn't support them, or you rejected it.

EOT # Take care of the lists # Enforce Ranges for variables that need it $I{F}{commentlimit} = 0 if $I{F}{commentlimit} < 1; $I{F}{commentspill} = 0 if $I{F}{commentspill} < 1; # for users_comments my $H = { clbig => $I{F}{clbig}, clsmall => $I{F}{clsmall}, mode => $I{F}{umode}, posttype => $I{F}{posttype}, commentsort => $I{F}{commentsort}, threshold => $I{F}{uthreshold}, commentlimit => $I{F}{commentlimit}, commentspill => $I{F}{commentspill}, maxcommentsize => $I{F}{maxcommentsize}, highlightthresh => $I{F}{highlightthresh}, nosigs => ($I{F}{nosigs} ? "1" : "0"), reparent => ($I{F}{reparent} ? "1" : "0"), noscores => ($I{F}{noscores} ? "1" : "0"), hardthresh => ($I{F}{hardthresh} ? "1" : "0"), }; # Update users with the $H thing we've been playing with for this whole damn sub sqlUpdate("users_comments", $H, "uid=" . $uid . " AND uid>0", 1); } ################################################################# sub saveHome { my $uid = $I{U}{aseclev} ? shift : $I{U}{uid}; my $name = $I{U}{aseclev} && $I{F}{name} ? $I{F}{name} : $I{U}{nickname}; $name = substr($name, 0, 20); return unless $uid > 0; print "

Saving $name

"; print <Your browser didn't save a cookie properly. This could mean you are behind a filter that eliminates them, you are using a browser that doesn't support them, or you rejected it.

EOT my($extid, $exaid, $exsect) = ""; my($exboxes) = sqlSelect("exboxes", "users_index", "uid=$uid"); $exboxes =~ s/'//g; my @b = split m/,/, $exboxes; foreach (@b) { $_ = "" unless $I{F}{"exboxes_$_"}; } $exboxes = sprintf "'%s',", join "','", @b; $exboxes =~ s/'',//g; foreach my $k (keys %{$I{F}}) { if ($k =~ /^extid_(.*)/) { $extid .= "'$1'," } if ($k =~ /^exaid_(.*)/) { $exaid .= "'$1'," } if ($k =~ /^exsect_(.*)/) { $exsect .="'$1'," } if ($k =~ /^exboxes_(.*)/) { # Only Append a box if it doesn't exist my $box = $1; $exboxes .= "'$box'," unless $exboxes =~ /'$box'/; } } $I{F}{maxstories} = 66 if $I{F}{maxstories} > 66; $I{F}{maxstories} = 1 if $I{F}{maxstories} < 1; # Take care of the preferences table # for users_index my $H = { extid => checkList($extid), exaid => checkList($exaid), exsect => checkList($exsect), exboxes => checkList($exboxes), maxstories => $I{F}{maxstories}, noboxes => ($I{F}{noboxes} ? "1" : "0"), }; # for users_prefs my $H2 = { light => ($I{F}{light} ? "1" : "0"), noicons => ($I{F}{noicons} ? "1" : "0"), willing => ($I{F}{willing} ? "1" : "0"), }; if (defined $I{F}{tzcode} && defined $I{F}{tzformat}) { $H2->{tzcode} = $I{F}{tzcode}; $H2->{dfid} = $I{F}{tzformat}; } $H2->{mylinks} = $I{F}{mylinks} if $I{F}{mylinks}; # If a user is unwilling to moderate, we should cancel all points, lest # they be preserved when they shouldn't be. sqlUpdate("users_comments", { points => 0 }, "uid=$uid AND uid>0", 1) unless $I{F}{willing}; # Update users with the $H thing we've been playing with for this whole damn sub sqlUpdate("users_index", $H, "uid=" . $uid . " AND uid>0", 1); # Update users with the $H thing we've been playing with for this whole damn sub sqlUpdate("users_prefs", $H2, "uid=" . $uid . " AND uid>0", 1); } ################################################################# sub displayForm { print <

EOT titlebar("100%", $I{F}{unickname} ? "Error Logging In" : "Login"); print $I{F}{unickname} ? <Error. Login Failed! Please try again, or click that mail password button if you forgot your password.

EOT1

Logging in will allow you to post comments as yourself. If you don't login, you will only be able to post as $I{anon_name}.

EOT2

Logging in will allow you to post comments. If you don't login, you will not be able to post.

EOT3 $I{F}{unickname} ||= $I{F}{newuser}; print <Nick: (maximum 20 characters long)

Password: (6-12 characters long)

Forgotten Your Password?
Type your nickname in the box above and click the button below. We'll email you your password in the next two minutes.

EOT titlebar("100%", $I{F}{newuser} ? "Duplicate Account!" : "I'm a New User!"); print $I{F}{newuser} ? <Apparently you tried to register with a duplicate nickname, a duplicate email address, or an invalid email. You can try another below, or use the form on the left to either login, or retrieve your forgotten password. EOT1

1. Enter your preferred nickname:
EOT2 print <

2. Now enter a valid email address address to send your registration information.

This address will not be displayed on $I{sitename}.

3. Click the button to be mailed a password.

I declare that I am at least 18 years of age.

EOT } main(); $I{dbh}->disconnect if $I{dbh}; 1;