I wrote two methods to take care of the lockout issue,
here is a sample which of course I have not tested but
I think it may be a good begining.  The two methods
are check_lockout_stautus and update_lockout_status. 
The modifications to the scoop code are marked by
"#::CHANGE DM".  If anyone of you has a better way of
doing this or other suggestions don't be affraid to
yell my way :-)

By the way, shouldn't the following conditions be
evaluated only once?  It seems excesive that all these
conditions are evaluated when only one condition
should be true and again once more at the bottom of
the method.  Hmmm.... maybe I am overlooking
something?

	# Mail password, but no username?
	if (!$uname && $mail) {
		$message = $login_err;
	}
	
	# No password?
	if (($uname && !$pass) && !$mail) {
		$message = $login_err;
	}

	# Only a password? 
	if ((!$uname && $pass) && !$mail) {
		$message = $login_err;
	}

DannyM.		
-------------- next part --------------
sub check_lockout_stautus{ #::CHANGE DM
   my $S = shift;
   my $uname = shift;
 	my $q_uname = $S->{DBH}->quote($uname);
   my $message = undef;
  	
  	my ($rv, $sth) = $S->db_select({
		   WHAT => 'failed_logins,last_failed_login',
			FROM => 'users',
       	WHERE => qq|nickname = $q_uname|});

	my $results = $sth->fetchrow_hashref;

	$message = 'Account locked on: ' . $results->{'last_failed_login'}
      if $results->{'failed_logins'} > $S->{UI}->{VARS}->{max_login_attempts};

   return $message;

}

sub update_lockout_status(  #::CHANGE DM
   my $S = shift;
   my $uname = shift;
   my $valid_login = shift;
   my $rv = undef;
   my $sth = undef;
   my $results = undef;
   my $uid = 0;
   my $failed_logins = 0;

   my $q_uname = $S->{DBH}->quote($uname);
   ($rv, $sth) = $S->db_select({
	    WHAT => 'id,failed_logins',
       FROM => 'users',
	    WHERE => qq|nickname = $q_uname|});
   $results = $sth->fetchrow_hashref

   $uid = $results->{'id'};

   if ( !$valid_login ){
  
      $failed_logins = int($results->{'failed_logins'}) + 1;

      ($rv, $sth) = $S->db_update({
	   	 WHAT  => "users",
		    SET   => qq|failed_logins = $failed_logins, last_failed_login= NOW()|,
		    WHERE => "uid = $uid"});

   }else{ #Must have been a succesfull login, reset failed logins!

      ($rv, $sth) = $S->db_update({
	   	 WHAT  => "users",
		    SET   => "failed_logins = 0",   # dont update last_failed_login date,
		    WHERE => "uid = $uid"});        # we should keep a record of when the last failed login happened

   }

   $sth->finish();
}
	
##############################
# Looks for "uname" and "pass" form elements, and 
# calls $S->check_password to see if they're valid.
# Returns the $uid of a confirmed user, or '0' if no
# user is found, for whatever reason
##############################
sub check_for_login {
	my $S = shift;
	my $uname = $S->{CGI}->param('uname') || undef;
	my $pass = $S->{CGI}->param('pass') || undef;
	my $mail = $S->{CGI}->param('mailpass') || undef;
	my $uid = 0;
	my $message = '';

	my $login_err;
	my $login_mail;
	my $login_mail_fail;

	# Blocks aren't loaded yet!
	my ($rv, $sth) = $S->db_select({
				WHAT => 'bid, block',
				FROM => 'blocks',
				WHERE => "bid='login_error_message' OR bid='login_mail_message' OR bid='login_mail_failed'"});
	while (my $results = $sth->fetchrow_hashref) {
		if ( $results->{bid} eq "login_error_message" ) {
			$login_err = $results->{block};
		} elsif ( $results->{bid} eq "login_mail_message" ) {
			$login_mail = $results->{block};
		} elsif ( $results->{bid} eq "login_mail_failed" ) {
			$login_mail_fail = $results->{block};
		} else {
			warn "got a bid I wasn't expecting..." if $DEBUG;
		}
	}

	# Mail password, but no username?
	if (!$uname && $mail) {
		$message = $login_err;
	}
	
	# No password?
	if (($uname && !$pass) && !$mail) {
		$message = $login_err;
	}

	# Only a password? 
	if ((!$uname && $pass) && !$mail) {
		$message = $login_err;
	}		

	# Standard case
	if (($uname && $pass) && !$mail) {

      $message = check_lockout_status($uname) 
         if $S->{UI}->{VARS}->{max_login_attempts};#::CHANGE DM

      if ( !$message ){ #::CHANGE DM
   		$uid = $S->check_password($uname, $pass);
	   	unless ($uid) {

		   	$message = $login_err;

			   if ($S->{DEBUG}->{LOGIN}) {warn "  (Scoop::check_for_login) UID came back $uid. That's all I can do.";}
    		}
      }
	}

	# Show the preferences if the user logs in for the first time
	# and the respective var is set. 	
	# Set is_new_account=0 if it was previously 1.
	if($uid) {				
		my $user=$S->user_data($uid);
		if ($user->{is_new_account}) {
			# Run user_confirm hook
			$S->run_hook('user_confirm', $user->{nickname});
			
			if($S->{UI}->{VARS}->{show_prefs_on_first_login}) {
				
				warn "  (Scoop::check_for_login) First login for user ID <<$uid>>, showing preferences page\n" if ($DEBUG);							
				$S->param->{'op'}="user";
				$S->param->{'tool'}="prefs";
				$S->param->{'uid'}=$uid;
				$S->param->{'nick'}=$user->{nickname};
				# this is passed to the prefs page so it can display a welcome message
				$S->param->{'firstlogin'}="1";
			}
			warn "  (Scoop::check_for_login) First login for user ID <<$uid>>, setting is_new_account=0\n" if ($DEBUG);
			my ($rv, $sth) = $S->db_update({
			 WHAT  => "users",
			 SET   => qq|is_new_account = 0|,
			 WHERE => "uid = $uid"});
			$sth->finish();
		
		}
		
	}	


	# User clicked "Mail password":
	# Send new password to user. Both passwords will be valid until
	# new one is set.	
	if ($uname && $mail) {
		my $mailed = $S->_mailpass($uname);
		if ($mailed) {
			$message = $login_mail;
		} else {

			$message = $login_mail_fail;
		}
	}
	$message =~ s/%%uname%%/$uname/g;
	$S->{LOGIN_ERROR} = $message;
	
	return $uid;
}


##############################
# Takes a username and a password and checks the users
# DB for them. If found, it returns the uid. Otherwise
# It returns '0'.
##############################
sub check_password {
	my $S = shift;
	my ($uname, $pass) = @_;

	#crypt the passwd received
	my $c_pass = $S->crypt_pass($pass);
	warn "  (Scoop::check_password) Crypted pass is: $c_pass\n"	if ($DEBUG);
	
	my $q_cpass = $S->{DBH}->quote($c_pass);
	my $q_uname = $S->{DBH}->quote($uname);
	
	my ($rv, $sth) = $S->db_select({
		WHAT => 'uid',
		FROM => 'users',
		WHERE => qq|nickname = $q_uname AND passwd = $q_cpass|});
		
	if ($rv != 1) {
		$sth->finish;
		
		# check if user logged in using new password, and if he did,
		# reset the password.
		
		($rv, $sth) = $S->db_select({
			WHAT => 'uid',
			FROM => 'users',
			WHERE => qq|nickname = $q_uname AND newpasswd = $q_cpass|
		});
		if ($rv !=1) {
			$sth->finish;
			warn "  (Scoop::check_password) Login ERROR: incorrect password for $uname."	if $DEBUG;

         update_lockout_status($uname,0) if $S->{UI}->{VARS}->{'max_login_attempts'};#::CHANGE DM

			return 0;
		} else {
			my ($rv2, $sth2) = $S->db_update({
				WHAT => 'users',
				SET => qq|newpasswd="",passwd=$q_cpass|,
				WHERE => qq|nickname = $q_uname AND newpasswd = $q_cpass|
			});
			$sth2->finish;
   
         update_lockout_status($uname,1) if $S->{UI}->{VARS}->{'max_login_attempts'};#::CHANGE DM
		}
			
	}
	
	warn "  (Scoop::check_password) Login SUCCESS: Valid password for $uname."	if $DEBUG;
	my $uidref = $sth->fetchrow_hashref();
	$sth->finish;
	my $uid = $uidref->{'uid'};

   update_lockout_status($uname,1) if $S->{UI}->{VARS}->{'max_login_attempts'};#::CHANGE DM
	
   return $uid;
}