Index: logintoboggan.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/logintoboggan/logintoboggan.install,v
retrieving revision 1.1.2.7
diff -u -F^f -r1.1.2.7 logintoboggan.install
--- logintoboggan.install	17 Aug 2006 01:12:43 -0000	1.1.2.7
+++ logintoboggan.install	20 Sep 2006 20:28:10 -0000
@@ -2,6 +2,40 @@
 // $Id: logintoboggan.install,v 1.1.2.7 2006/08/17 01:12:43 thehunmonkgroup Exp $
 
 /**
+* Implementation of hook_install(). This creates the extra table for the 
+* "remember me" function.
+*/
+
+function logintoboggan_install() {
+switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      db_query("CREATE TABLE logintoboggan_rememberme (
+          uid int(10) unsigned NOT NULL,
+          sid varchar(32) NOT NULL default '',
+          name varchar(60) not null,
+          timestamp int(11) NOT NULL default '0',
+          KEY uid (uid),
+          PRIMARY KEY (sid),
+          KEY timestamp (timestamp)
+        )
+        DEFAULT CHARACTER SET utf8;");
+      break;
+    case 'postgresql':
+      db_query("CREATE TABLE logintoboggan_rememberme (
+          uid integer not null,
+          name varchar(60) not null,
+          sid varchar(32) NOT NULL default '',
+          timestamp integer NOT NULL default '0',
+          PRIMARY KEY (sid)
+        );
+        CREATE INDEX logintoboggan_rememberme_uid_idx ON logintoboggan_rememberme(uid);
+        CREATE INDEX logintoboggan_rememberme_timestamp_idx ON logintoboggan_rememberme(timestamp);");
+      break;
+    }
+}
+
+/**
  * Implementation of hook_update_1().  This is a placeholder in case table
  * installation is ever necessary for the module.
  */
@@ -94,4 +128,39 @@ function logintoboggan_update_5() {
 
   drupal_set_message(t('logintoboggan cleaning of user/profile data successful'));
   return array();
+}
+
+/**
+ * Implementation of hook_update_6()
+ *
+ * For sites which aren't doing a new install, we need to create the table
+ * to store the rememberme functions.
+ */
+function logintoboggan_update_6() {
+  $ret = array();
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret = db_query("CREATE TABLE {logintoboggan_rememberme} (
+          uid int(10) unsigned NOT NULL,
+          sid varchar(32) NOT NULL default '',
+          timestamp int(11) NOT NULL default '0',
+          KEY uid (uid),
+          PRIMARY KEY (sid),
+          KEY timestamp (timestamp)
+        )
+        DEFAULT CHARACTER SET utf8;");
+      break;
+    case 'postgresql':
+      $ret = db_query("CREATE TABLE {logintoboggan_rememberme} (
+          uid integer not null,
+          sid varchar(32) NOT NULL default '',
+          timestamp integer NOT NULL default '0',
+          PRIMARY KEY (sid)
+        );
+        CREATE INDEX {logintoboggan_rememberme}_uid_idx ON {logintoboggan_rememberme}(uid);
+        CREATE INDEX {logintoboggan_rememberme}_timestamp_idx ON {logintoboggan_rememberme}(timestamp);");
+      break;
+    }
+  return $ret;
 }
\ No newline at end of file
Index: logintoboggan.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/logintoboggan/logintoboggan.module,v
retrieving revision 1.7.2.49
diff -u -F^f -r1.7.2.49 logintoboggan.module
--- logintoboggan.module	20 Sep 2006 14:31:40 -0000	1.7.2.49
+++ logintoboggan.module	20 Sep 2006 20:28:12 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: logintoboggan.module,v 1.7.2.49 2006/09/20 14:31:40 thehunmonkgroup Exp $
+// $Id: logintoboggan.module,v 1.7.2.46 2006/09/08 16:08:58 thehunmonkgroup Exp $
 
 /**
  * @todo
@@ -114,6 +114,13 @@ function logintoboggan_form_alter($form_
       }
       break;
     case 'user_login':
+      if (variable_get('rememberme_username_status', 0) > 0) {
+        // pre-fill username for login PAGE if this is something we're remembering
+        if ($_COOKIE['LTRM_sessid']) {
+          $account = db_fetch_object(db_query('SELECT name FROM {logintoboggan_rememberme} ltrm WHERE sid = \'%s\'', $_COOKIE['LTRM_sessid']));          
+          $form['name']['#default_value'] = $account->name;
+        }
+      }
     case 'user_login_block':
       if (variable_get('login_with_mail', 0)) {
         $form['#validate'] = array('logintoboggan_user_login_validate' => array());
@@ -128,6 +135,22 @@ function logintoboggan_form_alter($form_
           $form['#redirect'] = logintoboggan_destination();
         }
       }
+      if (variable_get('rememberme_username_status', 0) > 0 && variable_get('cache', 0) == 0) {
+        // pre-fill username for the login BLOCK only if page cache is OFF
+        if ($_COOKIE['LTRM_sessid']) {
+          $account = db_fetch_object(db_query('SELECT name FROM {logintoboggan_rememberme} ltrm WHERE sid = \'%s\'', $_COOKIE['LTRM_sessid']));          
+          $form['name']['#default_value'] = $account->name;
+        }
+      }
+      if (variable_get('rememberme_login_status', 0) == 1 || variable_get('rememberme_username_status', 0) == 1) {
+        // add a rememberme checkbox
+        $form['rememberme'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('remember me'),
+          '#default_value' => 1,
+        );
+      }
+      
 
       // The $_POST check is a temporary hack to make sure the user login block doesn't get processed
       if (($form_id == 'user_login_block') && isset($_POST['logintoboggan']['login_block'])) {
@@ -232,21 +255,21 @@ function logintoboggan_user_register_sub
   $login_url = ($reg_pass_set && variable_get('user_register', 1) == 1) ? logintoboggan_eml_validate_url($account) : user_pass_reset_url($account);
   $variables = array('%username' => $name, '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen(_logintoboggan_protocol() .'://')), '%mailto' => $mail, '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), '%login_url' => $login_url);
 
-  //compose the appropriate user message--admin approvals don't require a validation email
-  if(variable_get('reg_passwd_set', 0) && variable_get('user_register', 1) == 1) {
+  //compose the appropriate user message
+  if(variable_get('reg_passwd_set', 0)) {
     $message = t('A validation e-mail has been sent to your e-mail address. In order to gain full access to the site, you will need to follow the instructions in that message.');
 
   } else {
     $message = t('Your password and further instructions have been sent to your e-mail address.');
   }
 
-  if (variable_get('user_register', 1) == 1) {
+  if ($account->status) {
 
     // Create new user account, no administrator approval required.
     $subject = _user_mail_text('welcome_subject', $variables);
     $body = _user_mail_text('welcome_body', $variables);
 
-  } elseif (variable_get('user_register', 1) == 2) {
+  } else {
 
     // Create new user account, administrator approval required.
     $subject = _user_mail_text('approval_subject', $variables);
@@ -254,7 +277,7 @@ function logintoboggan_user_register_sub
 
     $message = t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />') . $message;
 
-    user_mail(variable_get('site_mail', ini_get('sendmail_from')), $subject, t("%u has applied for an account, and has automatically received the permissions of the LoginToboggan validating role.  To give the user full site permissions, click the link below:\n\n%validating_url\n\nAlternatively, you may visit their user account listed below and remove them from the validating role. \n\n%uri", array('%u' => $account->name, '%validating_url' => logintoboggan_eml_validate_url($account), '%uri' => url("user/$account->uid/edit", NULL, NULL, TRUE))), "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
+    user_mail(variable_get('site_mail', ini_get('sendmail_from')), $subject, t("%u has applied for an account, and has automatically received the permissions of the LoginToboggan validating role.  To give the user full site permissions, visit their user account listed below and remove them from the validating role. \n\n%uri", array('%u' => $account->name, '%uri' => url("user/$account->uid/edit", NULL, NULL, TRUE))), "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
 
   }
 
@@ -347,6 +370,24 @@ function logintoboggan_user_register_val
 function logintoboggan_init() {
 
   global $user;
+  
+  // rememberme: first see if a login should be activated
+  if ($user->uid == 0 && variable_get('rememberme_login_status', 0) > 0 && $_COOKIE['LTRM_sessid']) {
+    // got an anonymous user, a rememberme cookie, and we're go for remembering logins...
+    $rememberme = db_fetch_object(db_query('SELECT uid, timestamp FROM {logintoboggan_rememberme} WHERE sid = \'%s\'', $_COOKIE['LTRM_sessid']));
+    if ($rememberme->uid > 0 && $rememberme->timestamp > (time() - variable_get('rememberme_username_life', 0))) {
+      // uid is still present (didn't logout) and timestamp is within login_life
+      // so that means we're a go to restart the session
+      $user = user_load(array('uid' => $rememberme->uid));
+      // refresh timestamp
+      db_query('UPDATE {logintoboggan_rememberme} SET timestamp = %d WHERE sid = \'%s\' AND uid = %d', time(), $_COOKIE['LTRM_sessid'], $user->uid);
+    }
+  }
+  elseif ($user->uid > 0 && variable_get('rememberme_login_status', 0) > 0 && $_COOKIE['LTRM_sessid']) {
+    // if the system is active and there's a login and cookie, refresh cookie
+    _logintoboggan_rememberme_setcookie($_COOKIE['LTRM_sessid']);
+    db_query('UPDATE {logintoboggan_rememberme} SET timestamp = %d WHERE sid = \'%s\' AND uid = %d', time(), $_COOKIE['LTRM_sessid'], $user->uid);
+  }
 
   // If it's not an anonymous user, and the user has the pre-auth role, and the pre-auth role
   // isn't also the auth role, then unset the auth role for this user--they haven't validated yet.
@@ -358,6 +399,11 @@ function logintoboggan_init() {
       unset($user->roles[2]);
     }
   }
+  if (variable_get('rememberme_username_status', 0) > 0) {
+    // must prevent caching of /user page in order to remember usernames
+    global $base_url;
+    db_query('DELETE FROM {cache} WHERE cid = \'%s\'', $base_url.'/user');
+  }
 }
 
 /**
@@ -385,6 +431,18 @@ function logintoboggan_menu($may_cache) 
       'title' => t('access denied'),
       'type' => MENU_CALLBACK,
       );
+    $items[] = array('path' => 'admin/settings/logintoboggan/settings',
+      'access' => user_access('access administration pages'),
+      'title' => t('general'),
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'weight' => -10,
+    ); 
+    $items[] = array('path' => 'admin/settings/logintoboggan/remember',
+      'access' => user_access('access administration pages'),
+      'callback' => 'logintoboggan_rememberme_admin',
+      'title' => t('remember me'),
+      'type' => MENU_LOCAL_TASK,
+      );  
   }
   else {
 
@@ -518,7 +576,7 @@ function _logintoboggan_toggleboggan ($f
 }
 
 function logintoboggan_settings() {
-  $version .= str_replace(array('$Re'.'vision:', '$Da'.'te:', '$'), array('', '', ''), '<p style="font-size:x-small">Login Toboggan version: <b>$Revision: 1.7.2.49 $</b>, $Date: 2006/09/20 14:31:40 $</p>');
+  $version .= str_replace(array('$Re'.'vision:', '$Da'.'te:', '$'), array('', '', ''), '<p style="font-size:x-small">Login Toboggan version: <b>$Revision: 1.7.2.46 $</b>, $Date: 2006/09/08 16:08:58 $</p>');
 
   $_disabled = t('disabled');
   $_enabled = t('enabled');
@@ -820,6 +878,16 @@ function logintoboggan_user($op, &$edit,
   } elseif ($op == 'login' && variable_get('login_successful', 0)) {
     drupal_set_message(t('Login successful.'));
   }
+  if ($op == 'login') {
+    // compressed all the logic for what and if to set into it's own function
+    _logintoboggan_rememberme_login($edit['rememberme']);
+  }
+  elseif ($op == 'logout') {
+    if ($_COOKIE['LTRM_sessid']) {
+      // set uid = 0 so login won't happen again, but keep the username to prefill
+      db_query('UPDATE {logintoboggan_rememberme} SET uid = 0 WHERE sid = \'%s\'', $_COOKIE['LTRM_sessid']);
+    }
+  }
 }
 
 /**
@@ -847,4 +915,123 @@ function logintoboggan_resend_validation
 
 function _logintoboggan_protocol() {
   return (($_SERVER['HTTPS'] == 'on') ? 'https' : 'http');
+}
+
+function logintoboggan_rememberme_admin() {
+  drupal_set_title(t('logintoboggan: %name', array('%name' => t('remember me'))));
+  $time = (variable_get('rememberme_login_status', 0) > 0) ? variable_get('rememberme_login_life', 0) : ini_get('session.gc_maxlifetime');
+  $output = '<p>'.t('Use the %name feature to extend this for users on your site, and/or to pre-fill their login name the next time they come to the site. Your current user login sessions will last <strong>%time DAYS</strong>.', array('%time' => round($time / 24 / 3600, 1), '%name' => t('remember me'))).'</p>';
+  if (variable_get('rememberme_login_status', 0) == 1) {
+    $output .= '<p>'.t('Sessions for users who do not use the %name checkbox will last <strong>%time DAYS</strong>', array('%name' => t('remember me'), '%time' => round(ini_get('session.gc_maxlifetime') / 24 / 3600, 1))).'</p>';
+  }
+  $form = array();
+  $form['login'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('logins'),
+    '#collapsible' => TRUE,
+    '#description' => t('These settings control the %name function for automatically logging users in. Note that this presents a security vulnerability in that the browser the user used to access your site will be able to auto-log-in for however long you choose here!', array('%name' => t('remember me'))),
+  );
+  $form['login']['login_status'] = array(
+    '#type' => 'radios',
+    '#title' => t('status for logins', array('%name' => t('remember me'))),
+    '#options' => array('Off', 'On w/Checkbox', 'On Always'),
+    '#default_value' => variable_get('rememberme_login_status', 1),
+    '#description' => t('Choose whether or not to enable the %name feature to log users in automatically, either through a checkbox on user login forms, or else as an always-on feature.', array('%name' => t('remember me'))),
+  );
+  $form['login']['login_life'] = array(
+    '#type' => 'textfield',
+    '#size' => 10,
+    '#title' => t('session lifetime'),
+    '#default_value' => round(variable_get('rememberme_login_life', $time) / 24 / 3600, 1),
+    '#description' => t('Time in DAYS that you wish the auto-login feature to remain active. In other words: how long can a user be away from the site, and still find themselves logged when they return using the same computer.'),
+  );
+  $form['username'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('username'),
+    '#collapsible' => TRUE,
+    '#description' => t('These settings control the %name function for remebering usernames and pre-filling the login form with that value.', array('%name' => t('remember me'))),
+  );
+  $form['username']['username_status'] = array(
+    '#type' => 'radios',
+    '#title' => t('status for usernames', array('%name' => t('remember me'))),
+    '#options' => array('Off', 'On w/Checkbox', 'On Always'),
+    '#default_value' => variable_get('rememberme_username_status', 2),
+    '#description' => t('Choose whether or not to enable the %name feature to remember usernames automatically, either with a checkbox on user login forms, or else as an always-on feature.', array('%name' => t('remember me'))),
+  );
+  $form['username']['username_life'] = array(
+    '#type' => 'textfield',
+    '#size' => 10,
+    '#title' => t('username remember lifetime'),
+    '#default_value' => round(variable_get('rememberme_username_life', $time * 2) / 24 / 3600, 1),
+    '#description' => t('Time in DAYS that you wish to remember usernames. If you are also using the login setting, this should probably be longer.'),
+  );
+  
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('submit'),
+  );
+  $output .= drupal_get_form('logintoboggan_rememberme', $form);
+  return $output;
+}
+
+function logintoboggan_rememberme_submit($form_id, $form) {
+  variable_set('rememberme_login_status', $form['login_status']);
+  variable_set('rememberme_login_life', $form['login_life'] * 24 * 3600);
+  variable_set('rememberme_username_status', $form['username_status']);
+  variable_set('rememberme_username_life', $form['username_life'] * 24 * 3600);
+  drupal_set_message(t('configuration options saved'));
+}
+
+/**
+* Shorthand for the logic stuff for logins.
+*
+* This compares the status of the settings with the presence of the "remember 
+* me" checkbox on the login form and tells us whether or not to remember what.
+*/
+
+function _logintoboggan_rememberme_login($checkbox = FALSE) {
+  global $user;
+  if ($_COOKIE['LTRM_sessid']) {
+    // out with the old, just in case
+    db_query('DELETE FROM {logintoboggan_rememberme} WHERE sid = \'%s\'', $_COOKIE['LTRM_sessid']);
+  }
+  if (variable_get('rememberme_login_status', 0) > 0 || variable_get('rememberme_username_status', 0) > 0) {
+    // system is active, continue
+    if ((variable_get('rememberme_login_status', 0) == 1 && $checkbox) || variable_get('rememberme_login_status', 0) == 2) {
+      // we're supposed to remember the uid (auto re-login)
+      $uid = $user->uid;
+    }
+    else {
+      // store 0 for the uid, but we may stlll remember the login name for pre-fill
+      $uid = 0;
+    }
+    if ((variable_get('rememberme_username_status', 0) == 1 && $checkbox) || variable_get('rememberme_username_status', 0) == 2) {
+      // we're supposed to remember the username (prefill login form)
+      // if we're allowing email addys, store that instead for prefill
+      $name = variable_get('login_with_mail', 0) ? $user->mail : $user->name;
+    }
+    else {
+      // store nothing for the username
+      $name = '';
+    }
+    $token = md5(time()/$user->created); // should be pretty safe
+    _logintoboggan_rememberme_setcookie($token);
+    db_query('INSERT INTO {logintoboggan_rememberme} (uid, name, sid, timestamp) VALUES(%d, \'%s\', \'%s\', %d)', $uid, $name, $token, time());
+    watchdog('user', t('Session remembered for %name.', array('%name' => theme('placeholder', $user->name))));
+  }
+}
+
+/**
+* Set our Logintoboggan Rememberme Session cookie (LTRM_sessid)
+*/
+
+function _logintoboggan_rememberme_setcookie($token) {
+  global $base_url;
+  $url = str_replace('http://', '', $base_url);
+  $url = explode('/', $url);
+  $domain = array_shift($url);
+  $path = '/'.implode('/', $url);
+  // get the longer lifetime for cookie life; this should generally be username, but just in case...
+  $lifetime = ((variable_get('rememberme_username_life', 0) > (variable_get('rememberme_login_life', 0))) ? variable_get('rememberme_username_life', 0) : variable_get('rememberme_login_life', 0));
+  setcookie('LTRM_sessid', $token, time() + $lifetime, $path, $domain);
 }
\ No newline at end of file
