<?php
// $Id$

/**
 * @file
 *  Restricts user login by role.
 */

/**
 * Implementation of hook_help().
 */
function role_login_help($section) {
  switch ($section) {
    case 'admin/modules#description':
      return t('Restricts user login by role.');
  
    case 'admin/user/roles/role_login':
      return t('Role Login enables login to be restricted by role. The module was developed to enable a user table to be shared between multiple instances, but still maintain control over which users can login, for example, on a dev instance versus a live site.');
  }
}

/**
 * Implementation of hook_menu().
 */
function role_login_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/user/roles/role_login',
      'title' => 'Role login',
      'description' => t('Restricts user login by role.'),
      'callback' => 'drupal_get_form',
      'callback arguments' => 'role_login_admin_settings',
      'type' => MENU_NORMAL_ITEM,
	    'access' => user_access('administer site configuration'), //do we *really* need yet another permission??
    );
  }
  return $items;
}

/**
 * Menu callback
 *
 * @return
 *   array of form content.
 */
function role_login_admin_settings() {
  $role_names = array();
  $sql = "SELECT * FROM {role} r WHERE r.rid > 2 ORDER BY name";
  $results = db_query($sql);
  while ($result = db_fetch_object($results)) {
    $role_names[$result->rid] = $result->name;
  }

  $form['role_login_roles'] = array(
    '#type' => 'select',
    '#title' => t('Role Login enabled for'),
    '#options' => $role_names,
    '#default_value' => variable_get('role_login_roles', NULL),
    '#description' => t('Select roles that can login. If no roles are selected, then the role login check will be bypassed. The superuser (account 1) can never be locked out regardless of role setting.'),
    '#multiple' => TRUE,
  );

  $form['role_login_link'] = array(
    '#type' => 'textfield',
    '#title' => t('Role Login link'),
    '#size' => 80,
    '#default_value' => variable_get('role_login_link', NULL),
    '#description' => t('Enter a fully qualified URL to display an alternate login location in the form error message.'),
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_form_alter().
 */
function role_login_form_alter($form_id, &$form) {
  switch ($form_id) {
    case 'user_login':
    case 'user_login_block':
	    $form['#validate'] = array('role_login_validate' => array()) + (array)$form['#validate'];
      break;
  }  
}

/**
 * Custom validation function for user login form.
 */
function role_login_validate($form_id, $form_values, $form) {
  $login_roles = array_keys((array)variable_get('role_login_roles', NULL));
  if (!sizeof($login_roles)) return;

  $name = $form_values['name'];
  $pass = trim($form_values['pass']);
  if ($name && $pass) {
    // We could use user_authenticate here but do not want to duplicate 
    // user_login_validate or step on any other validation. The downside is 
    // role_login will only support local users.
    if ($account = user_load(array('name' => $name, 'pass' => $pass, 'status' => 1))) {
      // Never lock out superuser
      if ($account->uid == 1) return;

      foreach (array_keys((array)$account->roles) as $rid) {
        if ($rid && in_array($rid, $login_roles)) {
          return;
        }
      }

      // User form does not honor form_set_error so we clear $form['name'] to 
      // ensure no login can proceed.
      form_set_value($form['name'], '');

      if ($url = variable_get('role_login_link', NULL)) {
        $alternate_link = ' ' . l(t('You should login here.'), $url);
      }
      form_set_error('name', t('Sorry, your account does not have the proper role to login to this site.') . $alternate_link);
      watchdog('user', t('Login attempt failed for %user due to improper role.', array('%user' => $form_values['name'])));

    }
  }
}
