<?php

/**
 * Implements hook_menu().
 */
function forgotten_login_menu() {
  $items = array();

  $items['admin/config/people/forgotten_login'] = array(
    'title' => 'Forgotten Login',
    'description' => 'Configure the settings for Forgotten Login module.',
    'access arguments' => array('administer forgotten login'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('forgotten_login_admin_settings'),
  );

  return $items;
}

/**
 * Implements hook_permission().
 */
function forgotten_login_permission() {
  return array(
    'administer forgotten login' => array(
      'title' => t('Administer Forgotten Login'), 
      'description' => t('Change the settings for Forgotten Login.'),
    ),
  );
}

/**
 * Implements hook_help().
 */
function forgotten_login_help($path, $arg) {
  switch ($path) {
    case 'admin/config/people/forgotten_login':
      return '<p>' . t('Forgotten login will automatically send an e-mail to a user who fails to login more than the configured amount of times. The (default) value of 0 failed attempts will stop the module working and reset the failed attempts count for all users.') . '</p>';
  }
}

/**
 * Creates the form for setting the forgotten login email settings
 *
 * @ingroup forms
 */
function forgotten_login_admin_settings() {
  $form = array();

  $form['forgotten_login_failed_attempts'] = array(
    '#type' => 'textfield',
    '#title' => t('Failed attempts'),
    '#description' => t('After how many attempts should the automatic e-mail be sent. Setting this to 0 will disable the email.'),
    '#default_value' => variable_get('forgotten_login_failed_attempts', 0),
    '#required' => TRUE,
  );

  $form['forgotten_login_email_from'] = array(
    '#type' => 'textfield',
    '#title' => t('Email From'),
    '#description' => t('Who the forgotten password e-mail should come from'),
    '#default_value' => variable_get('forgotten_login_email_from', variable_get('site_mail', '')),
    '#required' => TRUE,
  );

  $tokens = '!username, !site, !login_url, !mailto, !date';
  $form['forgotten_login_email_subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Email Subject'),
    '#description' => t('The subject of the forgotten password e-mail. Available tokens are: @tokens', array('@tokens' => $tokens)),
    '#default_value' => variable_get('forgotten_login_email_subject', variable_get('site_name', '') . ': Forgotten password'),
    '#required' => TRUE,
  );

  $default_content = "Hi !username,\n\nYou appear to be having difficulty signing in to !site. To help, we have sent you a link which will give you access to your account:\n\n!login_url\n\nRegards,\n!site";
  $form['forgotten_login_email_content'] = array(
    '#type' => 'textarea',
    '#rows' => 10,
    '#title' => t('Email Content'),
    '#description' => t('The content of the forgotten password e-mail. Available tokens are: @tokens', array('@tokens' => $tokens)),
    '#default_value' => variable_get('forgotten_login_email_content', $default_content),
    '#required' => TRUE,
  );

  $form['#submit'] = array('forgotten_login_admin_settings_submit');

  return system_settings_form($form);
}

/**
 * Form validater for the forgotten login email settings.
 *
 * @see forgotten_login_admin_settings()
 * @see forgotten_login_admin_settings_submit()
 * @ingroup forms
 */
function forgotten_login_admin_settings_validate($form, &$form_state) {
  $values = $form_state['values'];

  $failed_attempts = $values['forgotten_login_failed_attempts'];
  if (!preg_match('/^[0-9]+$/', $failed_attempts)) {
    form_set_error('forgotten_login_failed_attempts', t('The number of failed attempts must be numeric and positive'));
  }
}

/**
 * Form submit function for the forgotten login email settings. Simply sets
 * all users' login attempts to 0 if the module is "disabled".
 *
 * @see forgotten_login_admin_settings()
 * @see forgotten_login_admin_settings_validate()
 * @ingroup forms
 */
function forgotten_login_admin_settings_submit($form, &$form_state) {
  if ($form_state['values']['forgotten_login_failed_attempts'] == 0) {
    db_query('UPDATE {users} SET forgotten_login_attempts = 0');
  }
}

/**
 * Implements hook_form_alter().
 *
 * Adds a validation handler to handle failed logins
 *
 * @see forgotten_login_check_login().
 */
function forgotten_login_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'user_login' || $form_id == 'user_login_block') {
    if (!is_array($form['#validate'])) {
      $form['#validate'] = array($form['#validate']);
    }
    $form['#validate'][] = 'forgotten_login_check_login';
  }
}

/**
 * Implements hook_user_login().
 */
function forgotten_login_user_login(&$edit, &$account) {
  // On a valid login, simply reset the login attempts back to 0
  $args = array('uid' => $account->uid);
  db_query('UPDATE {users} SET forgotten_login_attempts = 0 WHERE uid = :uid', $args);
}

/**
 * Validate function for the user_login and user_login_block forms.
 *
 * This function is called after the user's details are validated, if they
 * don't have a UID now, they failed to login.
 */
function forgotten_login_check_login($form, &$form_state) {
  global $user;
  if ($user->uid == 0) {
    // Check the trigger value here - if it's 0 we're disabled so no need to proceed
    $trigger_value = variable_get('forgotten_login_failed_attempts', 0);
    if ($trigger_value == 0) {
      return;
    }

    // Attempt to find the uid for the account they tried to log in to
    $uid = db_query('SELECT u.uid FROM {users} u WHERE u.status <> 0 AND u.name = :name', array(':name' => $form_state['values']['name']))->fetchField();
    if ($uid == FALSE) {
      // No user id found...
      return;
    }

    // Increment the login attempts value
    db_query('UPDATE {users} SET forgotten_login_attempts = forgotten_login_attempts + 1 WHERE uid = :uid', array(':uid' => $uid));

    // Check the value and send an email if needed
    $attempts = db_query('SELECT forgotten_login_attempts FROM {users} WHERE uid = :uid', array(':uid' => $uid))->fetchField();

    // We only check for an exact value so we send the email once until a valid login happens
    if ($attempts == $trigger_value) {
      global $language;
      $account = user_load($uid);
      $params = array('account' => $account);
      $language = $language ? $language : user_preferred_language($account);
      $message = drupal_mail('forgotten_login', 'forgotten_login_email', $account->mail, $language, $params);
      if ($message['result']) {
        if (module_exists('rules')) {
          rules_invoke_event('forgotten_login_email_sent', $account);
        }
        watchdog('forgotten_login', 'User %account was sent a login link after a total of %logins failed attempts.', array('%account' => $account->name, '%logins' => $attempts));
      }
    }
  }
}

/**
 * Implementation of hook_mail().
 */
function forgotten_login_mail($key, &$message, $params) {
  $language = $message['language'];
  $variables = array();

  // Create the tokens from D6's user_mail_tokens() to help upgrades.
  $variables['!username'] = $params['account']->name;
  $variables['!site'] = variable_get('site_name', 'Drupal');
  $variables['!login_url'] = user_pass_reset_url($params['account']);
  $variables['!mailto'] = $params['account']->mail;
  $variables['!date'] = date(time());

  $default_content = "Hi !username,\n\nYou appear to be having difficulty signing in to !site. To help, we have sent you a link which will give you access to your account:\n\n!login_url\n\nRegards,\n!site";

  $message['subject'] = strtr(variable_get('forgotten_login_email_subject', variable_get('site_name', '') . ': Forgotten password'), $variables);
  $message['body'] = array(strtr(variable_get('forgotten_login_email_content', $default_content), $variables));
}
