Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.172 diff -u -p -r1.172 bootstrap.inc --- includes/bootstrap.inc 15 Jun 2007 06:45:05 -0000 1.172 +++ includes/bootstrap.inc 1 Jul 2007 19:07:56 -0000 @@ -1030,9 +1030,17 @@ function language_list($field = 'languag // Init language list if (!isset($languages)) { - $result = db_query('SELECT * FROM {languages} ORDER BY weight ASC, name ASC'); - while ($row = db_fetch_object($result)) { - $languages['language'][$row->language] = $row; + if (variable_get('language_count', 1) > 1) { + $result = db_query('SELECT * FROM {languages} ORDER BY weight ASC, name ASC'); + while ($row = db_fetch_object($result)) { + $languages['language'][$row->language] = $row; + } + } + else { + // One language only, the locale tables might not even + // be in place, so use the default language only. + $default = language_default(); + $languages['language'][$default->language] = $default; } } Index: includes/mail.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/mail.inc,v retrieving revision 1.2 diff -u -p -r1.2 mail.inc --- includes/mail.inc 28 Jun 2007 07:48:40 -0000 1.2 +++ includes/mail.inc 1 Jul 2007 19:07:56 -0000 @@ -2,81 +2,183 @@ // $Id: mail.inc,v 1.2 2007/06/28 07:48:40 dries Exp $ /** - * Send an e-mail message, using Drupal variables and default settings. - * More information in the - * PHP function reference for mail() + * Compose and optionally send an e-mail message. * - * @param $mailkey - * A key to identify the mail sent, for altering. + * Sending an e-mail works with defining an e-mail template (subject, text + * and possibly e-mail headers) and the replacement values to use in the + * appropriate places in the template. Processed e-mail templates are + * requested from hook_mail() from the module sending the e-mail. Any module + * can modify the composed e-mail message array using hook_mail_alter(). + * Finally drupal_mail_send() sends the e-mail, which can be reused + * if the exact same composed e-mail is to be sent to multiple recipients. + * + * Finding out what language to send the e-mail with needs some consideration. + * If you send e-mail to a user, her preferred language should be fine, so + * use user_preferred_language(). If you send email based on form values + * filled on the page, there are two additional choices if you are not + * sending the e-mail to a user on the site. You can either use the language + * used to generate the page ($language global variable) or the site default + * language. See language_default(). The former is good if sending e-mail to + * the person filling the form, the later is good if you send e-mail to an + * address previously set up (like contact addresses in a contact form). + * + * Taking care of always using the proper language is even more important + * when sending e-mails in a row to multiple users. Hook_mail() abstracts + * whether the mail text comes from an administrator setting or is + * static in the source code. It should also deal with common mail tokens, + * only receiving $params which are unique to the actual e-mail at hand. + * + * An example: + * + * @code + * function example_notify($accounts) { + * foreach ($accounts as $account) { + * $params['account'] = $account; + * // example_mail() will be called based on the first drupal_mail() parameter. + * drupal_mail('example', 'notify', $account->mail, user_preferred_language($account), $params); + * } + * } + * + * function example_mail($key, &$message, $params) { + * $language = $message['language']; + * $variables = user_mail_tokens($params['account'], $language); + * switch($key) { + * case 'notice': + * $message['subject'] = t('Notification from !site', $variables, $language->language); + * $message['body'] = t("Dear !username\n\nThere is new content available on the site.", $variables, $language->language); + * break; + * } + * } + * @endcode + * + * @param $module + * A module name to invoke hook_mail() on. The {$module}_mail() hook will be + * called to complete the $message structure which will already contain common + * defaults. + * @param $key + * A key to identify the e-mail sent. The final e-mail id for e-mail altering + * will be {$module}_{$key}. * @param $to - * The mail address or addresses where the message will be send to. The + * The e-mail address or addresses where the message will be sent to. The * formatting of this string must comply with RFC 2822. Some examples are: * user@example.com * user@example.com, anotheruser@example.com * User * User , Another User - * @param $subject - * Subject of the e-mail to be sent. This must not contain any newline - * characters, or the mail may not be sent properly. - * @param $body - * Message to be sent. Accepts both CRLF and LF line-endings. - * E-mail bodies must be wrapped. You can use drupal_wrap_mail() for - * smart plain text wrapping. + * @param $language + * Language object to use to compose the e-mail. + * @param $params + * Optional parameters to build the e-mail. * @param $from * Sets From, Reply-To, Return-Path and Error-To to this value, if given. - * @param $headers - * Associative array containing the headers to add. This is typically - * used to add extra headers (From, Cc, and Bcc). - * When sending mail, the mail must contain a From header. - * @return Returns TRUE if the mail was successfully accepted for delivery, - * FALSE otherwise. + * @param $send + * Send the message directly, without calling drupal_mail_send() manually. + * @return + * The $message array structure containing all details of the + * message. If already sent ($send = TRUE), then the 'result' element + * will contain the success indicator of the e-mail. */ -function drupal_mail($mailkey, $to, $subject, $body, $from = NULL, $headers = array()) { - $defaults = array( - 'MIME-Version' => '1.0', - 'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes', +function drupal_mail($module, $key, $to, $language, $params = array(), $from = NULL, $send = TRUE) { + $default_from = variable_get('site_mail', ini_get('sendmail_from')); + + // Bundle up the variables into a structured array for altering. + $message = array( + 'id' => $module .'_'. $key, + 'to' => $to, + 'from' => isset($from) ? $from : $default_from, + 'language' => $language, + 'params' => $params, + 'subject' => '', + 'body' => array() + ); + + // Build the default headers + $headers = array( + 'MIME-Version' => '1.0', + 'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes', 'Content-Transfer-Encoding' => '8Bit', - 'X-Mailer' => 'Drupal' + 'X-Mailer' => 'Drupal' ); - // To prevent e-mail from looking like spam, the addresses in the Sender and - // Return-Path headers should have a domain authorized to use the originating - // SMTP server. Errors-To is redundant, but shouldn't hurt. - $default_from = variable_get('site_mail', ini_get('sendmail_from')); if ($default_from) { - $defaults['From'] = $defaults['Reply-To'] = $defaults['Sender'] = $defaults['Return-Path'] = $defaults['Errors-To'] = $default_from; + // To prevent e-mail from looking like spam, the addresses in the Sender and + // Return-Path headers should have a domain authorized to use the originating + // SMTP server. Errors-To is redundant, but shouldn't hurt. + $headers['From'] = $headers['Reply-To'] = $headers['Sender'] = $headers['Return-Path'] = $headers['Errors-To'] = $default_from; } if ($from) { - $defaults['From'] = $defaults['Reply-To'] = $from; + $headers['From'] = $headers['Reply-To'] = $from; } - $headers = array_merge($defaults, $headers); - - // Bundle up the variables into a structured array for altering. - $message = array('#mail_id' => $mailkey, '#to' => $to, '#subject' => $subject, '#body' => $body, '#from' => $from, '#headers' => $headers); + $message['headers'] = $headers; + + // Build the e-mail (get subject and body, allow additional headers) by + // invoking hook_mail() on this module. We cannot use module_invoke() as + // we need to have $message by reference in hook_mail(). + if (function_exists($function = $module .'_mail')) { + $function($key, $message, $params); + } + + // Invoke hook_mail_alter() to allow all modules to alter the resulting e-mail. drupal_alter('mail', $message); - $mailkey = $message['#mail_id']; - $to = $message['#to']; - $subject = $message['#subject']; - $body = $message['#body']; - $from = $message['#from']; - $headers = $message['#headers']; - // Allow for custom mail backend + // Concatenate and wrap the e-mail body. + $message['body'] = is_array($message['body']) ? drupal_wrap_mail(implode("\n\n", $message['body'])) : drupal_wrap_mail($message['body']); + + // Optionally send e-mail. + if ($send) { + $message['result'] = drupal_mail_send($message); + } + + return $message; +} + +/** + * Send an e-mail message, using Drupal variables and default settings. + * More information in the + * PHP function reference for mail(). See drupal_mail() for information on + * how $message is composed. + * + * @param $message + * Message array with at least the following elements: + * - id + * A unique identifier of the e-mail type. Examples: 'contact_user_copy', + * 'user_password_reset'. + * - to + * The mail address or addresses where the message will be sent to. The + * formatting of this string must comply with RFC 2822. Some examples are: + * user@example.com + * user@example.com, anotheruser@example.com + * User + * User , Another User + * - subject + * Subject of the e-mail to be sent. This must not contain any newline + * characters, or the mail may not be sent properly. + * - body + * Message to be sent. Accepts both CRLF and LF line-endings. + * E-mail bodies must be wrapped. You can use drupal_wrap_mail() for + * smart plain text wrapping. + * - headers + * Associative array containing all mail headers. + * @return + * Returns TRUE if the mail was successfully accepted for delivery, + * FALSE otherwise. + */ +function drupal_mail_send($message) { + // Allow for a custom mail backend. if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) { include_once './' . variable_get('smtp_library', ''); - return drupal_mail_wrapper($mailkey, $to, $subject, $body, $from, $headers); + return drupal_mail_wrapper($message); } else { - // Note: e-mail uses CRLF for line-endings, but PHP's API requires LF. - // They will appear correctly in the actual e-mail that is sent. - $mimeheaders = array(); - foreach ($headers as $name => $value) { + foreach ($message['headers'] as $name => $value) { $mimeheaders[] = $name .': '. mime_header_encode($value); } return mail( - $to, - mime_header_encode($subject), - str_replace("\r", '', $body), + $message['to'], + mime_header_encode($message['subject']), + // Note: e-mail uses CRLF for line-endings, but PHP's API requires LF. + // They will appear correctly in the actual e-mail that is sent. + str_replace("\r", '', $message['body']), join("\n", $mimeheaders) ); } @@ -127,7 +229,7 @@ function drupal_wrap_mail($text, $indent /** * Transform an HTML string into plain text, preserving the structure of the - * markup. Useful for preparing the body of a node to be sent by email. + * markup. Useful for preparing the body of a node to be sent by e-mail. * * The output will be suitable for use as 'format=flowed; delsp=yes' text * (RFC 3676) and can be passed directly to drupal_mail() for sending. Index: modules/contact/contact.module =================================================================== RCS file: /cvs/drupal/drupal/modules/contact/contact.module,v retrieving revision 1.92 diff -u -p -r1.92 contact.module --- modules/contact/contact.module 30 Jun 2007 19:46:55 -0000 1.92 +++ modules/contact/contact.module 1 Jul 2007 19:07:56 -0000 @@ -360,48 +360,37 @@ function contact_mail_user(&$form_state, * 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: + // Send from the current user to the requested user. $to = $account->mail; $from = $user->mail; - // Format the subject: - $subject = '['. variable_get('site_name', 'Drupal') .'] '. $form_state['values']['subject']; - - // Prepare the body: - $body = drupal_wrap_mail(implode("\n\n", $message)); + // Save both users and all form values for email composition. + $values = $form_state['values']; + $values['account'] = $account; + $values['user'] = $user; - // Send the e-mail: - drupal_mail('contact-user-mail', $to, $subject, $body, $from); + // Send the e-mail in the requested user language. + drupal_mail('contact', 'user_mail', $to, user_preferred_language($account), $values, $from); - // Send a copy if requested: + // Send a copy if requested, using current page language. if ($form_state['values']['copy']) { - drupal_mail('contact-user-copy', $from, $subject, $body, $from); + drupal_mail('contact', 'user_copy', $from, $language, $values, $from); } - // Log the operation: flood_register_event('contact'); watchdog('mail', '%name-from sent %name-to an e-mail.', array('%name-from' => $user->name, '%name-to' => $account->name)); - - // Set a status message: drupal_set_message(t('The message has been sent.')); - - // Jump to the user's profile page: + + // Back to the requested users profile page. $form_state['redirect'] = "user/$account->uid"; - return; } /** - * Site-wide contact page + * Site-wide contact page. */ function contact_site_page() { global $user; @@ -504,45 +493,68 @@ function contact_mail_page_validate($for * Process the site-wide contact page form submission. */ function contact_mail_page_submit($form, &$form_state) { + global $language; + + $values = $form_state['values']; // 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)); + $from = $values['mail']; - // Send the e-mail to the recipients: - drupal_mail('contact-page-mail', $contact->recipients, $subject, $body, $from); + // Load category properties and save form values for email composition. + $contact = db_fetch_object(db_query("SELECT * FROM {contact} WHERE cid = %d", $values['cid'])); + $values['contact'] = $contact; + + // Send the e-mail to the recipients using the site default language. + drupal_mail('contact', 'page_mail', $contact->recipients, language_default(), $values, $from); - // If the user requests it, send a copy. - if ($form_state['values']['copy']) { - drupal_mail('contact-page-copy', $from, $subject, $body, $from); + // If the user requests it, send a copy using the current language. + if ($values['copy']) { + drupal_mail('contact', 'page_copy', $from, $language, $values, $from); } - // Send an auto-reply if necessary: + // Send an auto-reply if necessary using the 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, $language, $values, $contact->recipients); } - // Log the operation: flood_register_event('contact'); - watchdog('mail', '%name-from sent an e-mail regarding %category.', array('%name-from' => $form_state['values']['name'] ." [$from]", '%category' => $contact->category)); - - // Update user: + watchdog('mail', '%name-from sent an e-mail regarding %category.', array('%name-from' => $values['name'] ." [$from]", '%category' => $contact->category)); drupal_set_message(t('Your message has been sent.')); - // Jump to home page rather than back to contact page to avoid contradictory messages if flood control has been activated. + // Jump to home page rather than back to contact page to avoid + // contradictory messages if flood control has been activated. $form_state['redirect'] = ''; - return; +} + +/** + * Implementation of hook_mail(). + */ +function contact_mail($key, &$message, $params) { + $language = $message['language']; + switch ($key) { + case 'page_mail': + case 'page_copy': + $contact = $params['contact']; + $message['subject'] .= t('[!category] !subject', array('!category' => $contact->category, '!subject' => $params['subject']), $language->language); + $message['body'][] = t("!name sent a message using the contact form at !form.", array('!name' => $params['name'], '!form' => url($_GET['q'], array('absolute' => TRUE, 'language' => $language))), $language->language); + $message['body'][] = $params['message']; + break; + case 'page_autoreply': + $contact = $params['contact']; + $message['subject'] .= t('[!category] !subject', array('!category' => $contact->category, '!subject' => $params['subject']), $language->language); + $message['body'][] = $contact->reply; + break; + case 'user_mail': + case 'user_copy': + $user = $params['user']; + $account = $params['account']; + $message['subject'] .= '['. variable_get('site_name', 'Drupal') .'] '. $params['subject']; + $message['body'][] = "$account->name,"; + $message['body'][] = 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['body'][] = 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))), $language->language); + $message['body'][] = t('Message:', NULL, $language->language); + $message['body'][] = $params['message']; + break; + } } Index: modules/locale/locale.module =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v retrieving revision 1.182 diff -u -p -r1.182 locale.module --- modules/locale/locale.module 30 Jun 2007 21:00:51 -0000 1.182 +++ modules/locale/locale.module 1 Jul 2007 19:07:57 -0000 @@ -190,25 +190,33 @@ function locale_locale($op = 'groups') { * 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 we have more then one language and either creating a user on the + // admin interface or edit the user, show the language selector. + 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 the user is being created, we set the user language to the page language. + $user_language = $user ? user_language($user) : $language; + $names = array(); foreach ($languages as $langcode => $language) { $names[$langcode] = t($language->name) .' ('. $language->native .')'; } - $form['locale'] = array('#type' => 'fieldset', - '#title' => t('Interface language settings'), + $form['locale'] = array( + '#type' => 'fieldset', + '#title' => t('Language settings'), '#weight' => 1, ); - $form['locale']['language'] = array('#type' => 'radios', + + $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('Sets the default site interface and e-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.813 diff -u -p -r1.813 user.module --- modules/user/user.module 30 Jun 2007 19:46:58 -0000 1.813 +++ modules/user/user.module 1 Jul 2007 19:07:59 -0000 @@ -1232,9 +1232,11 @@ function user_pass_validate($form, &$for } 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 @@ function user_register_submit($form, &$f 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 for %name. No e-mail has been sent.', array('@url' => url("user/$account->uid"), '%name' => $account->name))); } 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 @@ function user_register_submit($form, &$f 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 %name.', array('@url' => url("user/$account->uid"), '%name' => $account->name))); } @@ -1445,7 +1449,7 @@ function user_register_submit($form, &$f } 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.')); } @@ -1707,49 +1711,66 @@ function user_build_content($account) { return $account->content; } -/*** Administrative features ***********************************************/ - -function _user_mail_text($messageid, $variables = array()) { +/** + * Implementation of hook_mail(). + */ +function user_mail($key, &$message, $params) { + $language = $message['language']; + $variables = user_mail_tokens($params['account'], $language); + $message['subject'] .= _user_mail_text($key. '_subject', $language, $variables); + $message['body'][] = _user_mail_text($key. '_body', $language, $variables); +} - // Check if an admin setting overrides the default string. - if ($admin_setting = variable_get('user_mail_'. $messageid, FALSE)) { +/** + * Returns a mail string for a variable name. + * + * Used by user_mail() and the settings forms to retrieve strings. + */ +function _user_mail_text($key, $language = NULL, $variables = array()) { + if ($admin_setting = variable_get('user_mail_'. $key, FALSE)) { + // An admin setting overrides the default string. return strtr($admin_setting, $variables); } - // No override, return with default strings. else { - switch ($messageid) { + // No override, return default string. + switch ($key) { 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); + case 'pending_approval_admin_subject': + 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"; + return t("!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", $variables, $language->language); 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."; + return t("!username,\n\nYour account on !site has been blocked.", $variables, $language->language); 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."; + return t("!username,\n\nYour account on !site has been deleted.", $variables, $language->language); } } } +/*** Administrative features ***********************************************/ + function user_admin_check_user() { $form['user'] = array('#type' => 'fieldset', '#title' => t('Username')); $form['user']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a username to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => USERNAME_MAX_LENGTH); @@ -3091,12 +3112,12 @@ function theme_user_signature($signature * @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 object to generate the tokens with. * @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 +3126,40 @@ function user_mail_tokens($account, $pas '!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 the language object preferred by the user. This user preference can + * be set on the user account editing page, and is only available if there + * are more than one languages enabled on the site. If the user did not + * choose a preferred language, or is the anonymous user, the $default + * value, or if it is not set, the site default language will be returned. + * + * @param $account + * User account to look up language for. + * @param $default + * Optional default language object to return if the account + * has no valid language. + */ +function user_preferred_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. * @@ -3135,36 +3179,26 @@ function user_mail_tokens($account, $pas * @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 + * Optional language to use for the notification, overriding account language. * @return - * The return value from drupal_mail(), if ends up being called. + * The return value from drupal_mail_send(), if ends up being called. */ -function _user_mail_notify($op, $account, $password = NULL) { - $mail_id = 'user-'. strtr($op, '_', '-'); - if ($op == 'register_pending_approval') { - // Special case, since we need to distinguish what we send to the - // user and what we send to the administrator, handled below. - $mail_id .= '-user'; - } +function _user_mail_notify($op, $account, $language = NULL) { // By default, we always notify except for deleted and blocked. $default_notify = ($op != 'status_deleted' && $op != 'status_blocked'); $notify = variable_get('user_mail_'. $op .'_notify', $default_notify); - $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)); - $result = drupal_mail($mail_id, $account->mail, $subject, $body, $from); + $params['account'] = $account; + $language = $language ? $language : user_preferred_language($account); + $mail = drupal_mail('user', $op, $account->mail, $language, $params); 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. + drupal_mail('user', 'register_pending_approval_admin', variable_get('site_mail', ini_get('sendmail_from')), language_default(), $params); } } - return $result; + return empty($mail) ? NULL : $mail['result']; } /**