Index: modules/contact/contact.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/contact/contact.module,v
retrieving revision 1.91
diff -u -r1.91 contact.module
--- modules/contact/contact.module 26 Jun 2007 22:21:08 -0000 1.91
+++ modules/contact/contact.module 27 Jun 2007 13:59:08 -0000
@@ -360,15 +360,9 @@
* Process the personal contact page form submission.
*/
function contact_mail_user_submit($form, &$form_state) {
- global $user;
+ global $user, $language;
$account = user_load(array('uid' => arg(1), 'status' => 1));
- // Compose the body:
- $message[] = "$account->name,";
- $message[] = t("!name (!name-url) has sent you a message via your contact form (!form-url) at !site.", array('!name' => $user->name, '!name-url' => url("user/$user->uid", array('absolute' => TRUE)), '!form-url' => url($_GET['q'], array('absolute' => TRUE)), '!site' => variable_get('site_name', 'Drupal')));
- $message[] = t("If you don't want to receive such e-mails, you can change your settings at !url.", array('!url' => url("user/$account->uid", array('absolute' => TRUE))));
- $message[] = t('Message:');
- $message[] = $form_state['values']['message'];
// Prepare all fields:
$to = $account->mail;
@@ -378,13 +372,16 @@
$subject = '['. variable_get('site_name', 'Drupal') .'] '. $form_state['values']['subject'];
// Prepare the body:
- $body = drupal_wrap_mail(implode("\n\n", $message));
+ $values = $form_state['values'];
+ $values['account'] = $account;
+ $body = _contact_mail('user_mail_body', $values, user_language($account));
// Send the e-mail:
drupal_mail('contact-user-mail', $to, $subject, $body, $from);
- // Send a copy if requested:
+ // Send a copy if requested, using current language:
if ($form_state['values']['copy']) {
+ $body = _contact_mail('user_mail_body', $values, $language);
drupal_mail('contact-user-copy', $from, $subject, $body, $from);
}
@@ -504,35 +501,38 @@
* Process the site-wide contact page form submission.
*/
function contact_mail_page_submit($form, &$form_state) {
-
+ global $language;
+
// E-mail address of the sender: as the form field is a text field,
// all instances of \r and \n have been automatically stripped from it.
$from = $form_state['values']['mail'];
- // Compose the body:
- $message[] = t("!name sent a message using the contact form at !form.", array('!name' => $form_state['values']['name'], '!form' => url($_GET['q'], array('absolute' => TRUE))));
- $message[] = $form_state['values']['message'];
-
// Load the category information:
$contact = db_fetch_object(db_query("SELECT * FROM {contact} WHERE cid = %d", $form_state['values']['cid']));
- // Format the category:
- $subject = t('[!category] !subject', array('!category' => $contact->category, '!subject' => $form_state['values']['subject']));
-
- // Prepare the body:
- $body = drupal_wrap_mail(implode("\n\n", $message));
-
- // Send the e-mail to the recipients:
- drupal_mail('contact-page-mail', $contact->recipients, $subject, $body, $from);
+ // Prepare parameters
+ $values = $form_state['values'];
+ $values['contact'] = $contact;
+
+ // Send the e-mail to the recipients using default language:
+ drupal_mail('contact-page-mail', $contact->recipients,
+ _contact_mail('page_mail_subject', $values),
+ _contact_mail('page_mail_body', $values),
+ $from);
- // If the user requests it, send a copy.
+ // If the user requests it, send a copy using current language.
if ($form_state['values']['copy']) {
- drupal_mail('contact-page-copy', $from, $subject, $body, $from);
+ drupal_mail('contact-page-copy', $from,
+ _contact_mail('page_mail_subject', $values, $language),
+ _contact_mail('page_mail_body', $values, $language),
+ $from);
}
- // Send an auto-reply if necessary:
+ // Send an auto-reply if necessary using current language:
if ($contact->reply) {
- drupal_mail('contact-page-autoreply', $from, $subject, drupal_wrap_mail($contact->reply), $contact->recipients);
+ drupal_mail('contact-page-autoreply', $from,
+ _contact_mail('page_mail_subject', $values, $language),
+ drupal_wrap_mail($contact->reply), $contact->recipients);
}
// Log the operation:
@@ -546,3 +546,28 @@
$form_state['redirect'] = '';
return;
}
+
+/**
+ * Get mail parts localized for the selected language
+ */
+function _contact_mail($op, $values = array(), $language = NULL) {
+ $language = $language ? $language : language_default();
+ switch ($op) {
+ case 'page_mail_subject':
+ $contact = $values['contact'];
+ return t('[!category] !subject', array('!category' => $contact->category, '!subject' => $values['subject']), $language->language);
+ case 'page_mail_body':
+ $contact = $values['contact'];
+ $message[] = t("!name sent a message using the contact form at !form.", array('!name' => $values['name'], '!form' => url($_GET['q'], array('absolute' => TRUE, 'language' => $language))), $language->language);
+ $message[] = $values['message'];
+ return drupal_wrap_mail(implode("\n\n", $message));
+ case 'user_mail_body':
+ $account = $values['account'];
+ $message[] = "$account->name,";
+ $message[] = t("!name (!name-url) has sent you a message via your contact form (!form-url) at !site.", array('!name' => $user->name, '!name-url' => url("user/$user->uid", array('absolute' => TRUE, 'language' => $language)), '!form-url' => url($_GET['q'], array('absolute' => TRUE, 'language' => $language)), '!site' => variable_get('site_name', 'Drupal')), $language->language);
+ $message[] = t("If you don't want to receive such e-mails, you can change your settings at !url.", array('!url' => url("user/$account->uid", array('absolute' => TRUE))), $language->language);
+ $message[] = t('Message:', $language->language);
+ $message[] = $values['message'];
+ return drupal_wrap_mail(implode("\n\n", $message));
+ }
+}
\ No newline at end of file
Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.180
diff -u -r1.180 locale.module
--- modules/locale/locale.module 18 Jun 2007 16:09:38 -0000 1.180
+++ modules/locale/locale.module 27 Jun 2007 13:59:09 -0000
@@ -186,12 +186,14 @@
* Implementation of hook_user().
*/
function locale_user($type, $edit, &$user, $category = NULL) {
- if ($type == 'form' && $category == 'account' && variable_get('language_count', 1) > 1 && variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) == LANGUAGE_NEGOTIATION_PATH) {
+ global $language;
+ if (variable_get('language_count', 1) > 1 && ($type == 'register' && user_access('administer users') || $type == 'form' && $category == 'account' )) {
$languages = language_list('enabled');
$languages = $languages['1'];
- if ($user->language == '') {
- $user->language = language_default('language');
- }
+
+ // If user ir being created, so we set user language to the current page one
+ $user_language = $user ? user_language($user) : $language;
+
$names = array();
foreach ($languages as $langcode => $language) {
$names[$langcode] = t($language->name) .' ('. $language->native .')';
@@ -200,11 +202,12 @@
'#title' => t('Interface language settings'),
'#weight' => 1,
);
+
$form['locale']['language'] = array('#type' => 'radios',
'#title' => t('Language'),
- '#default_value' => $user->language,
+ '#default_value' => $user_language->language,
'#options' => $names,
- '#description' => t('Selecting a different locale will change the interface language of the site.'),
+ '#description' => t('Selecting a locale will set the default site interface and mail language for this account.'),
);
return $form;
}
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.808
diff -u -r1.808 user.module
--- modules/user/user.module 26 Jun 2007 22:21:08 -0000 1.808
+++ modules/user/user.module 27 Jun 2007 13:59:12 -0000
@@ -1232,9 +1232,11 @@
}
function user_pass_submit($form, &$form_state) {
+ global $language;
+
$account = $form_state['values']['account'];
- // Mail one time login URL and instructions.
- $mail_success = _user_mail_notify('password_reset', $account);
+ // Mail one time login URL and instructions using current language
+ $mail_success = _user_mail_notify('password_reset', $account, $language);
if ($mail_success) {
watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
@@ -1420,12 +1422,14 @@
return;
}
else {
+ // Add plain text password into user account to generate mail tokens
+ $account->password = $pass;
if ($admin && !$notify) {
drupal_set_message(t('Created a new user account. No e-mail has been sent.'));
}
else if (!variable_get('user_email_verification', TRUE) && $account->status && !$admin) {
// No e-mail verification is required, create new user account, and login user immediately.
- _user_mail_notify('register_no_approval_required', $account, $pass);
+ _user_mail_notify('register_no_approval_required', $account);
user_authenticate($account->name, trim($pass));
$form_state['redirect'] = '';
return;
@@ -1433,7 +1437,7 @@
else if ($account->status || $notify) {
// Create new user account, no administrator approval required.
$op = $notify ? 'register_admin_created' : 'register_no_approval_required';
- _user_mail_notify($op, $account, $pass);
+ _user_mail_notify($op, $account);
if ($notify) {
drupal_set_message(t('Password and further instructions have been e-mailed to the new user %user.', array('%user' => $name)));
}
@@ -1445,7 +1449,7 @@
}
else {
// Create new user account, administrator approval required.
- _user_mail_notify('register_pending_approval', $account, $pass);
+ _user_mail_notify('register_pending_approval', $account);
drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.
In the meantime, your password and further instructions have been sent to your e-mail address.'));
}
@@ -1709,8 +1713,10 @@
/*** Administrative features ***********************************************/
-function _user_mail_text($messageid, $variables = array()) {
-
+function _user_mail_text($messageid, $account, $language = NULL) {
+ // Get account language if no one has been passed
+ $language = $language ? $language : user_language($account);
+ $variables = user_mail_tokens($account, $language);
// Check if an admin setting overrides the default string.
if ($admin_setting = variable_get('user_mail_'. $messageid, FALSE)) {
return strtr($admin_setting, $variables);
@@ -1719,31 +1725,33 @@
else {
switch ($messageid) {
case 'register_no_approval_required_subject':
- return t('Account details for !username at !site', $variables);
+ return t('Account details for !username at !site', $variables, $language->language);
case 'register_no_approval_required_body':
- return t("!username,\n\nThank you for registering at !site. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables);
+ return t("!username,\n\nThank you for registering at !site. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables, $language->language);
case 'register_admin_created_subject':
- return t('An administrator created an account for you at !site', $variables);
+ return t('An administrator created an account for you at !site', $variables, $language->language);
case 'register_admin_created_body':
- return t("!username,\n\nA site administrator at !site has created an account for you. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables);
+ return t("!username,\n\nA site administrator at !site has created an account for you. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n-- !site team", $variables, $language->language);
case 'register_pending_approval_subject':
- return t('Account details for !username at !site (pending admin approval)', $variables);
+ return t('Account details for !username at !site (pending admin approval)', $variables, $language->language);
case 'register_pending_approval_body':
- return t("!username,\n\nThank you for registering at !site. Your application for an account is currently pending approval. Once it has been approved, you will receive another e-mail containing information about how to log in, set your password, and other details.\n\n\n-- !site team", $variables);
+ return t("!username,\n\nThank you for registering at !site. Your application for an account is currently pending approval. Once it has been approved, you will receive another e-mail containing information about how to log in, set your password, and other details.\n\n\n-- !site team", $variables, $language->language);
+ case 'register_pending_approval_admin_body':
+ return t("!username has applied for an account.\n\n!edit_uri", $variables, $language->language);
case 'password_reset_subject':
- return t('Replacement login information for !username at !site', $variables);
+ return t('Replacement login information for !username at !site', $variables, $language->language);
case 'password_reset_body':
- return t("!username,\n\nA request to reset the password for your account has been made at !site.\n\nYou may now log in to !uri_brief clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.", $variables);
+ return t("!username,\n\nA request to reset the password for your account has been made at !site.\n\nYou may now log in to !uri_brief clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.", $variables, $language->language);
case 'status_activated_subject':
- return t('Account details for !username at !site (approved)', $variables);
+ return t('Account details for !username at !site (approved)', $variables, $language->language);
case 'status_activated_body':
return "!username,\n\nYour account at !site has been activated.\n\nYou may now log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\nOnce you have set your own password, you will be able to log in to !login_uri in the future using the following username:\n\nusername: !username\n";
case 'status_blocked_subject':
- return t('Account details for !username at !site (blocked)', $variables);
+ return t('Account details for !username at !site (blocked)', $variables, $language->language);
case 'status_blocked_body':
return "!username,\n\nYour account on !site has been blocked.";
case 'status_deleted_subject':
- return t('Account details for !username at !site (deleted)', $variables);
+ return t('Account details for !username at !site (deleted)', $variables, $language->language);
case 'status_deleted_body':
return "!username,\n\nYour account on !site has been deleted.";
}
@@ -3091,12 +3099,12 @@
* @param $account
* The user object of the account being notified. Must contain at
* least the fields 'uid', 'name', and 'mail'.
- * @param $password
- * Optional string containing the user's current password (if known).
+ * @param $language
+ * Language for the tokens
* @return
* Array of mappings from token names to values (for use with strtr()).
*/
-function user_mail_tokens($account, $password = NULL) {
+function user_mail_tokens($account, $language) {
global $base_url;
$tokens = array(
'!username' => $account->name,
@@ -3105,17 +3113,33 @@
'!uri' => $base_url,
'!uri_brief' => substr($base_url, strlen('http://')),
'!mailto' => $account->mail,
- '!date' => format_date(time()),
- '!login_uri' => url('user', array('absolute' => TRUE)),
- '!edit_uri' => url('user/'. $account->uid .'/edit', array('absolute' => TRUE)),
+ '!date' => format_date(time(), 'medium', '', NULL, $language->language),
+ '!login_uri' => url('user', array('absolute' => TRUE, 'language' => $language)),
+ '!edit_uri' => url('user/'. $account->uid .'/edit', array('absolute' => TRUE, 'language' => $language)),
);
- if (!empty($password)) {
- $tokens['!password'] = $password;
+ if (!empty($account->password)) {
+ $tokens['!password'] = $account->password;
}
return $tokens;
}
/**
+ * Get user language
+ *
+ * @param $account
+ * User account
+ * @param $default
+ * Optional default language if account has no valid language
+ */
+function user_language($account, $default = NULL) {
+ $language_list = language_list();
+ if ($account->language && isset($language_list[$account->language])) {
+ return $language_list[$account->language];
+ } else {
+ return $default ? $default : language_default();
+ }
+}
+/**
* Conditionally create and send a notification email when a certain
* operation happens on the given user account.
*
@@ -3136,13 +3160,12 @@
* The user object of the account being notified. Must contain at
* least the fields 'uid', 'name', and 'mail'.
*
- * @param $password
- * Optional string containing the user's current password (if known).
- *
+ * @param $language
+ * Optional anguage to use for the notification, overriding account language
* @return
* The return value from drupal_mail(), if ends up being called.
*/
-function _user_mail_notify($op, $account, $password = NULL) {
+function _user_mail_notify($op, $account, $language = NULL) {
$mail_id = 'user-'. strtr($op, '_', '-');
if ($op == 'register_pending_approval') {
// Special case, since we need to distinguish what we send to the
@@ -3155,13 +3178,15 @@
$result = NULL;
if ($notify) {
$from = variable_get('site_mail', ini_get('sendmail_from'));
- $variables = user_mail_tokens($account, $password);
- $subject = _user_mail_text($op .'_subject', $variables);
- $body = drupal_wrap_mail(_user_mail_text($op .'_body', $variables));
+ $subject = _user_mail_text($op .'_subject', $account, $language);
+ $body = drupal_wrap_mail(_user_mail_text($op .'_body', $account, $language));
$result = drupal_mail($mail_id, $account->mail, $subject, $body, $from);
if ($op == 'register_pending_approval') {
// If a user registered requiring admin approval, notify the admin, too.
- drupal_mail('user-register-approval-admin', $from, $subject, t("!username has applied for an account.\n\n!edit_uri", $variables), $from);
+ // We use the site default language for this
+ $subject = _user_mail_text('register_pending_approval_subject', $account, language_default());
+ $body = drupal_wrap_mail(_user_mail_text('register_pending_approval_admin_body', $account, language_default()));
+ drupal_mail('user-register-approval-admin', $from, $subject, $body, $from);
}
}
return $result;
Index: modules/user/Copy of user.module
===================================================================
RCS file: modules/user/Copy of user.module
diff -N modules/user/Copy of user.module
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/user/Copy of user.module 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,3232 @@
+ array(
+ 'arguments' => array('account' => NULL),
+ ),
+ 'user_profile' => array(
+ 'arguments' => array('account' => NULL),
+ 'file' => 'user_profile',
+ ),
+ 'user_profile_category' => array(
+ 'arguments' => array('element' => NULL),
+ 'file' => 'user_profile_category',
+ ),
+ 'user_profile_item' => array(
+ 'arguments' => array('element' => NULL),
+ 'file' => 'user_profile_item',
+ ),
+ 'user_list' => array(
+ 'arguments' => array('users' => NULL, 'title' => NULL),
+ ),
+ 'user_admin_perm' => array(
+ 'arguments' => array('form' => NULL),
+ ),
+ 'user_admin_new_role' => array(
+ 'arguments' => array('form' => NULL),
+ ),
+ 'user_admin_account' => array(
+ 'arguments' => array('form' => NULL),
+ ),
+ 'user_filter_form' => array(
+ 'arguments' => array('form' => NULL),
+ ),
+ 'user_filters' => array(
+ 'arguments' => array('form' => NULL),
+ ),
+ 'user_signature' => array(
+ 'arguments' => array('signature' => NULL),
+ ),
+ );
+}
+
+function user_external_load($authname) {
+ $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname);
+
+ if ($user = db_fetch_array($result)) {
+ return user_load($user);
+ }
+ else {
+ return 0;
+ }
+}
+
+/**
+ * Perform standard Drupal login operations for a user object. The
+ * user object must already be authenticated. This function verifies
+ * that the user account is not blocked/denied and then performs the login,
+ * updates the login timestamp in the database, invokes hook_user('login'),
+ * regenerates the session, etc.
+ *
+ * @param $account
+ * An authenticated user object to be set as the currently logged
+ * in user.
+ * @param $edit
+ * The array of form values submitted by the user, if any.
+ * @return boolean
+ * TRUE if the login succeeds, FALSE otherwise.
+ */
+function user_external_login($account, $edit = array()) {
+ $form = drupal_get_form('user_login');
+
+ $state['values'] = $edit;
+ if (empty($state['values']['name'])) {
+ $state['values']['name'] = $account->name;
+ }
+
+ user_login_name_validate($form, $state, (array)$account);
+ if (form_get_errors()) {
+ return FALSE;
+ }
+ global $user;
+ $user = $account;
+ user_login_submit($form, $state, (array)$account);
+ return TRUE;
+}
+
+/**
+ * Fetch a user object.
+ *
+ * @param $array
+ * An associative array of attributes to search for in selecting the
+ * user, such as user name or e-mail address.
+ *
+ * @return
+ * A fully-loaded $user object upon successful user load or FALSE if user cannot be loaded.
+ */
+function user_load($array = array()) {
+ // Dynamically compose a SQL query:
+ $query = array();
+ $params = array();
+
+ if (is_numeric($array)) {
+ $array = array('uid' => $array);
+ }
+ elseif (!is_array($array)) {
+ return FALSE;
+ }
+
+ foreach ($array as $key => $value) {
+ if ($key == 'uid' || $key == 'status') {
+ $query[] = "$key = %d";
+ $params[] = $value;
+ }
+ else if ($key == 'pass') {
+ $query[] = "pass = '%s'";
+ $params[] = md5($value);
+ }
+ else {
+ $query[]= "LOWER($key) = LOWER('%s')";
+ $params[] = $value;
+ }
+ }
+ $result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params);
+
+ if (db_num_rows($result)) {
+ $user = db_fetch_object($result);
+ $user = drupal_unpack($user);
+
+ $user->roles = array();
+ if ($user->uid) {
+ $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
+ }
+ else {
+ $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
+ }
+ $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid);
+ while ($role = db_fetch_object($result)) {
+ $user->roles[$role->rid] = $role->name;
+ }
+ user_module_invoke('load', $array, $user);
+ }
+ else {
+ $user = FALSE;
+ }
+
+ return $user;
+}
+
+/**
+ * Save changes to a user account or add a new user.
+ *
+ * @param $account
+ * The $user object for the user to modify or add. If $user->uid is
+ * omitted, a new user will be added.
+ *
+ * @param $array
+ * An array of fields and values to save. For example array('name' => 'My name');
+ * Setting a field to NULL deletes it from the data column.
+ *
+ * @param $category
+ * (optional) The category for storing profile information in.
+ */
+function user_save($account, $array = array(), $category = 'account') {
+ // Dynamically compose a SQL query:
+ $user_fields = user_fields();
+ if (is_object($account) && $account->uid) {
+ user_module_invoke('update', $array, $account, $category);
+ if (isset($array['status']) && $array['status'] != $account->status) {
+ // The user's status is changing, conditionally send notification email.
+ $op = $array['status'] == 1 ? 'status_activated' : 'status_blocked';
+ _user_mail_notify($op, $account);
+ }
+ $query = '';
+ $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
+ foreach ($array as $key => $value) {
+ if ($key == 'pass' && !empty($value)) {
+ $query .= "$key = '%s', ";
+ $v[] = md5($value);
+ }
+ else if ((substr($key, 0, 4) !== 'auth') && ($key != 'pass')) {
+ if (in_array($key, $user_fields)) {
+ // Save standard fields
+ $query .= "$key = '%s', ";
+ $v[] = $value;
+ }
+ else if ($key != 'roles') {
+ // Roles is a special case: it used below.
+ if ($value === NULL) {
+ unset($data[$key]);
+ }
+ else {
+ $data[$key] = $value;
+ }
+ }
+ }
+ }
+ $query .= "data = '%s' ";
+ $v[] = serialize($data);
+
+ db_query("UPDATE {users} SET $query WHERE uid = %d", array_merge($v, array($account->uid)));
+
+ // Reload user roles if provided
+ if (isset($array['roles']) && is_array($array['roles'])) {
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
+
+ foreach (array_keys($array['roles']) as $rid) {
+ if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
+ db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $account->uid, $rid);
+ }
+ }
+ }
+
+ // Delete a blocked user's sessions to kick them if they are online.
+ if (isset($array['status']) && $array['status'] == 0) {
+ sess_destroy_uid($account->uid);
+ }
+
+ // If the password changed, delete all open sessions and recreate
+ // the current one.
+ if (isset($array['pass'])) {
+ sess_destroy_uid($account->uid);
+ sess_regenerate();
+ }
+
+ // Refresh user object
+ $user = user_load(array('uid' => $account->uid));
+ user_module_invoke('after_update', $array, $user, $category);
+ }
+ else {
+ if (!isset($array['created'])) { // Allow 'created' to be set by the caller
+ $array['created'] = time();
+ }
+
+ // Note, we wait with saving the data column to prevent module-handled
+ // fields from being saved there. We cannot invoke hook_user('insert') here
+ // because we don't have a fully initialized user object yet.
+ foreach ($array as $key => $value) {
+ switch ($key) {
+ case 'pass':
+ $fields[] = $key;
+ $values[] = md5($value);
+ $s[] = "'%s'";
+ break;
+ case 'mode': case 'sort':
+ case 'threshold': case 'created': case 'access':
+ case 'login': case 'status':
+ $fields[] = $key;
+ $values[] = $value;
+ $s[] = "%d";
+ break;
+ default:
+ if (substr($key, 0, 4) !== 'auth' && in_array($key, $user_fields)) {
+ $fields[] = $key;
+ $values[] = $value;
+ $s[] = "'%s'";
+ }
+ break;
+ }
+ }
+ db_query('INSERT INTO {users} ('. implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values);
+ $array['uid'] = db_last_insert_id('users', 'uid');
+
+ // Build the initial user object.
+ $user = user_load(array('uid' => $array['uid']));
+
+ user_module_invoke('insert', $array, $user, $category);
+
+ // Build and save the serialized data field now
+ $data = array();
+ foreach ($array as $key => $value) {
+ if ((substr($key, 0, 4) !== 'auth') && ($key != 'roles') && (!in_array($key, $user_fields)) && ($value !== NULL)) {
+ $data[$key] = $value;
+ }
+ }
+ db_query("UPDATE {users} SET data = '%s' WHERE uid = %d", serialize($data), $user->uid);
+
+ // Save user roles (delete just to be safe).
+ if (isset($roles) && is_array($array['roles'])) {
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $array['uid']);
+ foreach (array_keys($array['roles']) as $rid) {
+ if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
+ db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $array['uid'], $rid);
+ }
+ }
+ }
+
+ // Build the finished user object.
+ $user = user_load(array('uid' => $array['uid']));
+ }
+
+ // Save distributed authentication mappings
+ $authmaps = array();
+ foreach ($array as $key => $value) {
+ if (substr($key, 0, 4) == 'auth') {
+ $authmaps[$key] = $value;
+ }
+ }
+ if (sizeof($authmaps) > 0) {
+ user_set_authmaps($user, $authmaps);
+ }
+
+ return $user;
+}
+
+/**
+ * Verify the syntax of the given name.
+ */
+function user_validate_name($name) {
+ if (!strlen($name)) return t('You must enter a username.');
+ if (substr($name, 0, 1) == ' ') return t('The username cannot begin with a space.');
+ if (substr($name, -1) == ' ') return t('The username cannot end with a space.');
+ if (strpos($name, ' ') !== FALSE) return t('The username cannot contain multiple spaces in a row.');
+ if (ereg("[^\x80-\xF7 [:alnum:]@_.-]", $name)) return t('The username contains an illegal character.');
+ if (preg_match('/[\x{80}-\x{A0}'. // Non-printable ISO-8859-1 + NBSP
+ '\x{AD}'. // Soft-hyphen
+ '\x{2000}-\x{200F}'. // Various space characters
+ '\x{2028}-\x{202F}'. // Bidirectional text overrides
+ '\x{205F}-\x{206F}'. // Various text hinting characters
+ '\x{FEFF}'. // Byte order mark
+ '\x{FF01}-\x{FF60}'. // Full-width latin
+ '\x{FFF9}-\x{FFFD}'. // Replacement characters
+ '\x{0}]/u', // NULL byte
+ $name)) {
+ return t('The username contains an illegal character.');
+ }
+ if (strpos($name, '@') !== FALSE && !eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return t('The username is not a valid authentication ID.');
+ if (strlen($name) > USERNAME_MAX_LENGTH) return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
+}
+
+function user_validate_mail($mail) {
+ if (!$mail) return t('You must enter an e-mail address.');
+ if (!valid_email_address($mail)) {
+ return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
+ }
+}
+
+function user_validate_picture(&$form, &$form_state) {
+ // If required, validate the uploaded picture.
+ $validators = array(
+ 'file_validate_is_image' => array(),
+ 'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
+ 'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
+ );
+ if ($file = file_save_upload('picture_upload', $validators)) {
+ // The image was saved using file_save_upload() and was added to the
+ // files table as a temorary file. We'll make a copy and let the garbage
+ // collector delete the original upload.
+ $info = image_get_info($file->filepath);
+ $destination = variable_get('user_picture_path', 'pictures') .'/picture-'. $form['#uid'] .'.'. $info['extension'];
+ if (file_copy($file, $destination, FILE_EXISTS_REPLACE)) {
+ $form_state['values']['picture'] = $file->filepath;
+ }
+ else {
+ form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
+ }
+ }
+}
+
+/**
+ * Generate a random alphanumeric password.
+ */
+function user_password($length = 10) {
+ // This variable contains the list of allowable characters for the
+ // password. Note that the number 0 and the letter 'O' have been
+ // removed to avoid confusion between the two. The same is true
+ // of 'I', 1, and l.
+ $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
+
+ // Zero-based count of characters in the allowable list:
+ $len = strlen($allowable_characters) - 1;
+
+ // Declare the password as a blank string.
+ $pass = '';
+
+ // Loop the number of times specified by $length.
+ for ($i = 0; $i < $length; $i++) {
+
+ // Each iteration, pick a random character from the
+ // allowable string and append it to the password:
+ $pass .= $allowable_characters[mt_rand(0, $len)];
+ }
+
+ return $pass;
+}
+
+/**
+ * Determine whether the user has a given privilege.
+ *
+ * @param $string
+ * The permission, such as "administer nodes", being checked for.
+ * @param $account
+ * (optional) The account to check, if not given use currently logged in user.
+ *
+ * @return
+ * boolean TRUE if the current user has the requested permission.
+ *
+ * All permission checks in Drupal should go through this function. This
+ * way, we guarantee consistent behavior, and ensure that the superuser
+ * can perform all actions.
+ */
+function user_access($string, $account = NULL) {
+ global $user;
+ static $perm = array();
+
+ if (is_null($account)) {
+ $account = $user;
+ }
+
+ // User #1 has all privileges:
+ if ($account->uid == 1) {
+ return TRUE;
+ }
+
+ // To reduce the number of SQL queries, we cache the user's permissions
+ // in a static variable.
+ if (!isset($perm[$account->uid])) {
+ $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', array_keys($account->roles)));
+
+ $perm[$account->uid] = '';
+ while ($row = db_fetch_object($result)) {
+ $perm[$account->uid] .= "$row->perm, ";
+ }
+ }
+
+ if (isset($perm[$account->uid])) {
+ return strpos($perm[$account->uid], "$string, ") !== FALSE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Checks for usernames blocked by user administration
+ *
+ * @return boolean TRUE for blocked users, FALSE for active
+ */
+function user_is_blocked($name) {
+ $deny = db_fetch_object(db_query("SELECT name FROM {users} WHERE status = 0 AND name = LOWER('%s')", $name));
+
+ return $deny;
+}
+
+function user_fields() {
+ static $fields;
+
+ if (!$fields) {
+ $result = db_query('SELECT * FROM {users} WHERE uid = 1');
+ if (db_num_rows($result)) {
+ $fields = array_keys(db_fetch_array($result));
+ }
+ else {
+ // Make sure we return the default fields at least
+ $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data');
+ }
+ }
+
+ return $fields;
+}
+
+/**
+ * Implementation of hook_perm().
+ */
+function user_perm() {
+ return array('administer access control', 'administer users', 'access user profiles', 'change own username');
+}
+
+/**
+ * Implementation of hook_file_download().
+ *
+ * Ensure that user pictures (avatars) are always downloadable.
+ */
+function user_file_download($file) {
+ if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
+ $info = image_get_info(file_create_path($file));
+ return array('Content-type: '. $info['mime_type']);
+ }
+}
+
+/**
+ * Implementation of hook_search().
+ */
+function user_search($op = 'search', $keys = NULL, $skip_access_check = FALSE) {
+ switch ($op) {
+ case 'name':
+ if ($skip_access_check || user_access('access user profiles')) {
+ return t('Users');
+ }
+ case 'search':
+ if (user_access('access user profiles')) {
+ $find = array();
+ // Replace wildcards with MySQL/PostgreSQL wildcards.
+ $keys = preg_replace('!\*+!', '%', $keys);
+ if (user_access('administer users')) {
+ // Administrators can also search in the otherwise private email field.
+ $result = pager_query("SELECT name, uid, mail FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%') OR LOWER(mail) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys, $keys);
+ while ($account = db_fetch_object($result)) {
+ $find[] = array('title' => $account->name .' ('. $account->mail .')', 'link' => url('user/'. $account->uid, array('absolute' => TRUE)));
+ }
+ }
+ else {
+ $result = pager_query("SELECT name, uid FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
+ while ($account = db_fetch_object($result)) {
+ $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid, array('absolute' => TRUE)));
+ }
+ }
+ return $find;
+ }
+ }
+}
+
+/**
+ * Implementation of hook_user().
+ */
+function user_user($type, &$edit, &$account, $category = NULL) {
+ if ($type == 'view') {
+ $account->content['user_picture'] = array(
+ '#value' => theme('user_picture', $account),
+ '#weight' => -10,
+ );
+ if (!isset($account->content['summary'])) {
+ $account->content['summary'] = array();
+ }
+ $account->content['summary'] += array(
+ '#type' => 'user_profile_category',
+ '#attributes' => array('class' => 'user-member'),
+ '#weight' => -5,
+ '#title' => t('History'),
+ );
+ $account->content['summary']['member_for'] = array(
+ '#type' => 'user_profile_item',
+ '#title' => t('Member for'),
+ '#value' => format_interval(time() - $account->created),
+ );
+ }
+ if ($type == 'form' && $category == 'account') {
+ $form_state = array();
+ return user_edit_form($form_state, arg(1), $edit);
+ }
+
+ if ($type == 'validate' && $category == 'account') {
+ return _user_edit_validate(arg(1), $edit);
+ }
+
+ if ($type == 'submit' && $category == 'account') {
+ return _user_edit_submit(arg(1), $edit);
+ }
+
+ if ($type == 'categories') {
+ return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
+ }
+}
+
+function user_login_block() {
+ $form = array(
+ '#action' => url($_GET['q'], array('query' => drupal_get_destination())),
+ '#id' => 'user-login-form',
+ '#validate' => user_login_default_validators(),
+ '#submit' => array('user_login_submit'),
+ );
+ $form['name'] = array('#type' => 'textfield',
+ '#title' => t('Username'),
+ '#maxlength' => USERNAME_MAX_LENGTH,
+ '#size' => 15,
+ '#required' => TRUE,
+ );
+ $form['pass'] = array('#type' => 'password',
+ '#title' => t('Password'),
+ '#maxlength' => 60,
+ '#size' => 15,
+ '#required' => TRUE,
+ );
+ $form['submit'] = array('#type' => 'submit',
+ '#value' => t('Log in'),
+ );
+ $items = array();
+ if (variable_get('user_register', 1)) {
+ $items[] = l(t('Create new account'), 'user/register', array('title' => t('Create a new user account.')));
+ }
+ $items[] = l(t('Request new password'), 'user/password', array('title' => t('Request new password via e-mail.')));
+ $form['links'] = array('#value' => theme('item_list', $items));
+ return $form;
+}
+
+/**
+ * Implementation of hook_block().
+ */
+function user_block($op = 'list', $delta = 0, $edit = array()) {
+ global $user;
+
+ if ($op == 'list') {
+ $blocks[0]['info'] = t('User login');
+ $blocks[1]['info'] = t('Navigation');
+ $blocks[2]['info'] = t('Who\'s new');
+ $blocks[3]['info'] = t('Who\'s online');
+
+ return $blocks;
+ }
+ else if ($op == 'configure' && $delta == 2) {
+ $form['user_block_whois_new_count'] = array(
+ '#type' => 'select',
+ '#title' => t('Number of users to display'),
+ '#default_value' => variable_get('user_block_whois_new_count', 5),
+ '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
+ );
+ return $form;
+ }
+ else if ($op == 'configure' && $delta == 3) {
+ $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
+ $form['user_block_seconds_online'] = array('#type' => 'select', '#title' => t('User activity'), '#default_value' => variable_get('user_block_seconds_online', 900), '#options' => $period, '#description' => t('A user is considered online for this long after they have last viewed a page.'));
+ $form['user_block_max_list_count'] = array('#type' => 'select', '#title' => t('User list length'), '#default_value' => variable_get('user_block_max_list_count', 10), '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100)), '#description' => t('Maximum number of currently online users to display.'));
+
+ return $form;
+ }
+ else if ($op == 'save' && $delta == 2) {
+ variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
+ }
+ else if ($op == 'save' && $delta == 3) {
+ variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
+ variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
+ }
+ else if ($op == 'view') {
+ $block = array();
+
+ switch ($delta) {
+ case 0:
+ // For usability's sake, avoid showing two login forms on one page.
+ if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
+
+ $block['subject'] = t('User login');
+ $block['content'] = drupal_get_form('user_login_block');
+ }
+ return $block;
+
+ case 1:
+ if ($menu = menu_tree()) {
+ $block['subject'] = $user->uid ? check_plain($user->name) : t('Navigation');
+ $block['content'] = $menu;
+ }
+ return $block;
+
+ case 2:
+ if (user_access('access content')) {
+ // Retrieve a list of new users who have subsequently accessed the site successfully.
+ $result = db_query_range('SELECT uid, name FROM {users} WHERE status != 0 AND access != 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5));
+ while ($account = db_fetch_object($result)) {
+ $items[] = $account;
+ }
+ $output = theme('user_list', $items);
+
+ $block['subject'] = t('Who\'s new');
+ $block['content'] = $output;
+ }
+ return $block;
+
+ case 3:
+ if (user_access('access content')) {
+ // Count users active within the defined period.
+ $interval = time() - variable_get('user_block_seconds_online', 900);
+
+ // Perform database queries to gather online user lists. We use s.timestamp
+ // rather than u.access because it is much faster.
+ $anonymous_count = sess_count($interval);
+ $authenticated_users = db_query('SELECT DISTINCT u.uid, u.name, s.timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= %d AND s.uid > 0 ORDER BY s.timestamp DESC', $interval);
+ $authenticated_count = db_num_rows($authenticated_users);
+
+ // Format the output with proper grammar.
+ if ($anonymous_count == 1 && $authenticated_count == 1) {
+ $output = t('There is currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests')));
+ }
+ else {
+ $output = t('There are currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests')));
+ }
+
+ // Display a list of currently online users.
+ $max_users = variable_get('user_block_max_list_count', 10);
+ if ($authenticated_count && $max_users) {
+ $items = array();
+
+ while ($max_users-- && $account = db_fetch_object($authenticated_users)) {
+ $items[] = $account;
+ }
+
+ $output .= theme('user_list', $items, t('Online users'));
+ }
+
+ $block['subject'] = t('Who\'s online');
+ $block['content'] = $output;
+ }
+ return $block;
+ }
+ }
+}
+
+function theme_user_picture($account) {
+ if (variable_get('user_pictures', 0)) {
+ if (!empty($account->picture) && file_exists($account->picture)) {
+ $picture = file_create_url($account->picture);
+ }
+ else if (variable_get('user_picture_default', '')) {
+ $picture = variable_get('user_picture_default', '');
+ }
+
+ if (isset($picture)) {
+ $alt = t("@user's picture", array('@user' => $account->name ? $account->name : variable_get('anonymous', t('Anonymous'))));
+ $picture = theme('image', $picture, $alt, $alt, '', FALSE);
+ if (!empty($account->uid) && user_access('access user profiles')) {
+ $picture = l($picture, "user/$account->uid", array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE));
+ }
+
+ return "
'. check_plain($msg) .'
'); + } + $form['name'] = array('#type' => 'textfield', + '#title' => t('Username'), + '#size' => 60, + '#maxlength' => USERNAME_MAX_LENGTH, + '#required' => TRUE, + '#attributes' => array('tabindex' => '1'), + ); + + $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal'))); + $form['pass'] = array('#type' => 'password', + '#title' => t('Password'), + '#description' => t('Enter the password that accompanies your username.'), + '#required' => TRUE, + '#attributes' => array('tabindex' => '2'), + ); + $form['#validate'] = user_login_default_validators(); + $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'), '#weight' => 2, '#attributes' => array('tabindex' => '3')); + + return $form; +} + +/** + * Setup a series for validators which check for blocked/denied users, + * then authenticate against local database, then return an error if + * authentication fails. Distributed authentication modules (e.g. + * drupal.module) are welcome to use hook_form_alter() to change this + * series in order to authenticate against their user database instead + * of local users table. + * + * We use three validators instead of one since external authentication + * modules usually only need to alter the second validator. See + * drupal_form_alter() in drupal.module for an example of altering + * this series of validators. + * + * @return array + * A simple list of validate functions. + **/ +function user_login_default_validators() { + return array('user_login_name_validate', 'user_login_authenticate_validate', 'user_login_final_validate'); +} + +/** + * A FAPI validate handler. Sets an error is supplied username has been blocked or denied access. + * + * @return void + **/ +function user_login_name_validate($form, &$form_state) { + if (isset($form_state['values']['name'])) { + if (user_is_blocked($form_state['values']['name'])) { + // blocked in user administration + form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name']))); + } + else if (drupal_is_denied('user', $form_state['values']['name'])) { + // denied by access controls + form_set_error('name', t('The name %name is a reserved username.', array('%name' => $form_state['values']['name']))); + } + } +} + +/** + * A validate handler on the login form. Check supplied username/password against local users table. + * If successful, sets the global $user object. + + * @return void + **/ +function user_login_authenticate_validate($form, &$form_state) { + user_authenticate($form_state['values']['name'], trim($form_state['values']['pass'])); +} + +/** + * A validate handler on the login form. Should be the last validator. Sets an error if + * user has not been authenticated yet. + * + * @return void + **/ +function user_login_final_validate($form, &$form_state) { + global $user; + if (!$user->uid) { + form_set_error('name', t('Sorry, unrecognized username or password. Have you forgotten your password?', array('@password' => url('user/password')))); + watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name'])); + } +} + +/** + * Try to log in the user locally. + * + * @return + * A $user object, if successful. + **/ +function user_authenticate($name, $pass) { + global $user; + + if ($account = user_load(array('name' => $name, 'pass' => $pass, 'status' => 1))) { + $user = $account; + return $user; + } +} + +/** + * A validate handler on the login form. Update user's login timestamp, fire hook_user('login), and generate new session ID. + * + * @return void + **/ +function user_login_submit($form, &$form_state) { + global $user; + if ($user->uid) { + watchdog('user', 'Session opened for %name.', array('%name' => $user->name)); + + // Update the user table timestamp noting user has logged in. + db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $user->uid); + + user_module_invoke('login', $form_state['values'], $user); + + sess_regenerate(); + $form_state['redirect'] = 'user/'. $user->uid; + return; + } +} + +/** + * Helper function for authentication modules. Either login in or registers the current user, based on username. + * Either way, the global $user object is populated based on $name. + * + * @return void + **/ +function user_external_login_register($name, $module) { + global $user; + + $user = user_load(array('name' => $name)); + if (!isset($user->uid)) { + // Register this new user. + $userinfo = array('name' => $name, 'pass' => user_password(), 'init' => $name, 'status' => 1, "authname_$module" => $name); + $user = user_save('', $userinfo); + watchdog('user', 'New external user: %name using module %module.', array('%name' => $name, '%module' => $module), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit')); + } +} + +/** + * Menu callback; logs the current user out, and redirects to the home page. + */ +function user_logout() { + global $user; + + watchdog('user', 'Session closed for %name.', array('%name' => $user->name)); + + // Destroy the current session: + session_destroy(); + module_invoke_all('user', 'logout', NULL, $user); + + // Load the anonymous user + $user = drupal_anonymous_user(); + + drupal_goto(); +} + +function user_pass() { + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Username or e-mail address'), + '#size' => 60, + '#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH), + '#required' => TRUE, + ); + $form['submit'] = array('#type' => 'submit', '#value' => t('E-mail new password')); + + return $form; +} + +function user_pass_validate($form, &$form_state) { + $name = trim($form_state['values']['name']); + if (valid_email_address($name)) { + $account = user_load(array('mail' => $name, 'status' => 1)); + } + else { + $account = user_load(array('name' => $name, 'status' => 1)); + } + if (isset($account->uid)) { + form_set_value(array('#parents' => array('account')), $account, $form_state); + } + else { + form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name))); + } +} + +function user_pass_submit($form, &$form_state) { + $account = $form_state['values']['account']; + // Mail one time login URL and instructions. + $mail_success = _user_mail_notify('password_reset', $account); + if ($mail_success) { + watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)); + drupal_set_message(t('Further instructions have been sent to your e-mail address.')); + } + else { + watchdog('user', 'Error mailing password reset instructions to %name at %email.', array('%name' => $account->name, '%email' => $account->mail), WATCHDOG_ERROR); + drupal_set_message(t('Unable to send mail. Please contact the site admin.')); + } + $form_state['redirect'] = 'user'; + return; +} + +/** + * Menu callback; process one time login link and redirects to the user page on success. + */ +function user_pass_reset(&$form_state, $uid, $timestamp, $hashed_pass, $action = NULL) { + global $user; + + // Check if the user is already logged in. The back button is often the culprit here. + if ($user->uid) { + drupal_set_message(t('You have already used this one-time login link. It is not necessary to use this link to login anymore. You are already logged in.')); + drupal_goto(); + } + else { + // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds. + $timeout = 86400; + $current = time(); + // Some redundant checks for extra security ? + if ($timestamp < $current && $account = user_load(array('uid' => $uid, 'status' => 1)) ) { + // No time out for first time login. + if ($account->login && $current - $timestamp > $timeout) { + drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.')); + drupal_goto('user/password'); + } + else if ($account->uid && $timestamp > $account->login && $timestamp < $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) { + // First stage is a confirmation form, then login + if ($action == 'login') { + watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp)); + // Update the user table noting user has logged in. + // And this also makes this hashed password a one-time-only login. + db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid); + // Now we can set the new user. + $user = $account; + // And proceed with normal login, going to user page. + $edit = array(); + user_module_invoke('login', $edit, $user); + drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to login. Please change your password.')); + drupal_goto('user/'. $user->uid .'/edit'); + } + else { + $form['message'] = array('#value' => t('This is a one-time login for %user_name and will expire on %expiration_date
Click on this button to login to the site and change your password.
', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout)))); + $form['help'] = array('#value' => ''. t('This login can be used only once.') .'
'); + $form['submit'] = array('#type' => 'submit', '#value' => t('Log in')); + $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login"); + return $form; + } + } + else { + drupal_set_message(t('You have tried to use a one-time login link which has either been used or is no longer valid. Please request a new one using the form below.')); + drupal_goto('user/password'); + } + } + else { + // Deny access, no more clues. + // Everything will be in the watchdog's URL for the administrator to check. + drupal_access_denied(); + } + } +} + +function user_pass_reset_url($account) { + $timestamp = time(); + return url("user/reset/$account->uid/$timestamp/". user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE)); +} + +function user_pass_rehash($password, $timestamp, $login) { + return md5($timestamp . $password . $login); +} + +function user_register() { + global $user; + + $admin = user_access('administer users'); + + // If we aren't admin but already logged on, go to the user page instead. + if (!$admin && $user->uid) { + drupal_goto('user/'. $user->uid); + } + + $form = array(); + + // Display the registration form. + if (!$admin) { + $form['user_registration_help'] = array('#value' => filter_xss_admin(variable_get('user_registration_help', ''))); + } + + // Merge in the default user edit fields. + $form = array_merge($form, user_edit_form($form_state, NULL, NULL, TRUE)); + if ($admin) { + $form['account']['notify'] = array( + '#type' => 'checkbox', + '#title' => t('Notify user of new account') + ); + // Redirect back to page which initiated the create request; usually admin/user/user/create + $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']); + } + + // Create a dummy variable for pass-by-reference parameters. + $null = NULL; + $extra = _user_forms($null, NULL, NULL, 'register'); + + // Remove form_group around default fields if there are no other groups. + if (!$extra) { + foreach (array('name', 'mail', 'pass', 'status', 'roles', 'notify') as $key) { + if (isset($form['account'][$key])) { + $form[$key] = $form['account'][$key]; + } + } + unset($form['account']); + } + else { + $form = array_merge($form, $extra); + } + $form['submit'] = array('#type' => 'submit', '#value' => t('Create new account'), '#weight' => 30); + $form['#validate'][] = 'user_register_validate'; + + return $form; +} + +function user_register_validate($form, &$form_state) { + user_module_invoke('validate', $form_state['values'], $form_state['values'], 'account'); +} + +function user_register_submit($form, &$form_state) { + global $base_url; + $admin = user_access('administer users'); + + $mail = $form_state['values']['mail']; + $name = $form_state['values']['name']; + if (!variable_get('user_email_verification', TRUE) || $admin) { + $pass = $form_state['values']['pass']; + } + else { + $pass = user_password(); + }; + $notify = isset($form_state['values']['notify']) ? $form_state['values']['notify'] : NULL; + $from = variable_get('site_mail', ini_get('sendmail_from')); + if (isset($form_state['values']['roles'])) { + $roles = array_filter($form_state['values']['roles']); // Remove unset roles + } + else { + $roles = array(); + } + + if (!$admin && array_intersect(array_keys($form_state['values']), array('uid', 'roles', 'init', 'session', 'status'))) { + watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING); + $form_state['redirect'] = 'user/register'; + return; + } + //the unset below is needed to prevent these form values from being saved as user data + unset($form_state['values']['form_token'], $form_state['values']['submit'], $form_state['values']['op'], $form_state['values']['notify'], $form_state['values']['form_id'], $form_state['values']['affiliates'], $form_state['values']['destination']); + + $merge_data = array('pass' => $pass, 'init' => $mail, 'roles' => $roles); + if (!$admin) { + // Set the user's status because it was not displayed in the form. + $merge_data['status'] = variable_get('user_register', 1) == 1; + } + $account = user_save('', array_merge($form_state['values'], $merge_data)); + $form_state['user'] = $account; + + watchdog('user', 'New user: %name (%email).', array('%name' => $name, '%email' => $mail), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit')); + + // The first user may login immediately, and receives a customized welcome e-mail. + if ($account->uid == 1) { + drupal_set_message(t('Welcome to Drupal. You are now logged in as user #1, which gives you full control over your website.
')); + if (variable_get('user_email_verification', TRUE)) { + drupal_set_message(t('Your password is %pass. You may change your password below.
', array('%pass' => $pass))); + } + + user_authenticate($account->name, trim($pass)); + + $form_state['redirect'] = 'user/1/edit'; + return; + } + else { + if ($admin && !$notify) { + drupal_set_message(t('Created a new user account. No e-mail has been sent.')); + } + else if (!variable_get('user_email_verification', TRUE) && $account->status && !$admin) { + // No e-mail verification is required, create new user account, and login user immediately. + _user_mail_notify('register_no_approval_required', $account, $pass); + user_authenticate($account->name, trim($pass)); + $form_state['redirect'] = ''; + return; + } + else if ($account->status || $notify) { + // Create new user account, no administrator approval required. + $op = $notify ? 'register_admin_created' : 'register_no_approval_required'; + _user_mail_notify($op, $account, $pass); + if ($notify) { + drupal_set_message(t('Password and further instructions have been e-mailed to the new user %user.', array('%user' => $name))); + } + else { + drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.')); + $form_state['redirect'] = ''; + return; + } + } + else { + // Create new user account, administrator approval required. + _user_mail_notify('register_pending_approval', $account, $pass); + drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.