Index: update.php
===================================================================
RCS file: /cvs/drupal/drupal/update.php,v
retrieving revision 1.285
diff -u -p -r1.285 update.php
--- update.php	24 May 2009 17:39:30 -0000	1.285
+++ update.php	30 May 2009 23:47:36 -0000
@@ -292,9 +292,9 @@ function update_batch() {
 
   // During the update, bring the site offline so that schema changes do not
   // affect visiting users.
-  drupal_set_session('site_offline', variable_get('site_offline', FALSE));
-  if ($_SESSION['site_offline'] == FALSE) {
-    variable_set('site_offline', TRUE);
+  drupal_set_session('maintenance_mode', variable_get('maintenance_mode', FALSE));
+  if ($_SESSION['maintenance_mode'] == FALSE) {
+    variable_set('maintenance_mode', TRUE);
   }
 
   $operations = array();
@@ -331,10 +331,10 @@ function update_finished($success, $resu
   drupal_set_session('updates_remaining', $operations);
 
   // Now that the update is done, we can put the site back online if it was
-  // previously turned off.
-  if (isset($_SESSION['site_offline']) && $_SESSION['site_offline'] == FALSE) {
-    variable_set('site_offline', FALSE);
-    unset($_SESSION['site_offline']);
+  // previously in maintenance mode.
+  if (isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) {
+    variable_set('maintenance_mode', FALSE);
+    unset($_SESSION['maintenance_mode']);
   }
 }
 
@@ -635,6 +635,8 @@ function update_prepare_d7_bootstrap() {
  * made which make it impossible to continue using the prior version.
  */
 function update_fix_d7_requirements() {
+  global $conf;
+
   $ret = array();
 
   // Rewrite the settings.php file if necessary.
@@ -653,6 +655,12 @@ function update_fix_d7_requirements() {
     variable_set('update_d7_requirements', TRUE);
   }
 
+  // Rename 'site_offline_message' variable to 'maintenance_mode_message'.
+  // Old variable is removed in update for system.module.
+  if ($message = variable_get('site_offline_message', NULL)) {
+    variable_set('maintenance_mode_message', $message);
+  }
+
   return $ret;
 }
 
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.913
diff -u -p -r1.913 common.inc
--- includes/common.inc	27 May 2009 14:33:41 -0000	1.913
+++ includes/common.inc	30 May 2009 23:33:45 -0000
@@ -346,7 +346,7 @@ function drupal_site_offline() {
   drupal_maintenance_theme();
   drupal_set_header('503 Service unavailable');
   drupal_set_title(t('Site offline'));
-  print theme('maintenance_page', filter_xss_admin(variable_get('site_offline_message',
+  print theme('maintenance_page', filter_xss_admin(variable_get('maintenance_mode_message',
     t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))))));
 }
 
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.326
diff -u -p -r1.326 menu.inc
--- includes/menu.inc	30 May 2009 13:11:38 -0000	1.326
+++ includes/menu.inc	30 May 2009 23:34:05 -0000
@@ -2710,36 +2710,42 @@ function menu_path_is_external($path) {
 }
 
 /**
- * Checks whether the site is offline for maintenance.
+ * Check whether the site is in maintenance mode.
  *
  * This function will log the current user out and redirect to front page
- * if the current user has no 'administer site configuration' permission.
+ * if the current user has no 'access site in maintenance mode' permission.
  *
  * @return
- *   FALSE if the site is not offline or its the login page or the user has
- *     'administer site configuration' permission.
- *   TRUE for anonymous users not on the login page if the site is offline.
+ *   FALSE if the site is not in maintenance mode, the user login page is
+ *   displayed, or the user has the 'access site in maintenance mode'
+ *   permission. TRUE for anonymous users not being on the login page when the
+ *   site is in maintenance mode.
  */
 function _menu_site_is_offline() {
-  // Check if site is set to maintenance mode.
-  if (variable_get('site_offline', 0)) {
-    // Check if the user has administration privileges.
-    if (user_access('administer site configuration')) {
-      // Ensure that the offline message is displayed only once [allowing for
-      // page redirects], and specifically suppress its display on the site
-      // maintenance page.
-      if (drupal_get_normal_path($_GET['q']) != 'admin/settings/maintenance-mode') {
-        drupal_set_message(t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/settings/maintenance-mode'))), 'status', FALSE);
+  // Check if site is in maintenance mode.
+  if (variable_get('maintenance_mode', 0)) {
+    if (user_access('access site in maintenance mode')) {
+      // Ensure that the maintenance mode message is displayed only once
+      // (allowing for page redirects) and specifically suppress its display on
+      // the maintenance mode settings page.
+      if ($_GET['q'] != 'admin/settings/maintenance-mode') {
+        if (user_access('administer site configuration')) {
+          drupal_set_message(t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/settings/maintenance-mode'))), 'status', FALSE);
+        }
+        else {
+          drupal_set_message(t('Operating in maintenance mode.'), 'status', FALSE);
+        }
       }
     }
     else {
       // Anonymous users get a FALSE at the login prompt, TRUE otherwise.
       if (user_is_anonymous()) {
-        return $_GET['q'] != 'user' && $_GET['q'] != 'user/login';
+        return ($_GET['q'] != 'user' && $_GET['q'] != 'user/login');
       }
       // Logged in users are unprivileged here, so they are logged out.
-      require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'user') . '/user.pages.inc';
-      user_logout();
+      elseif (drupal_function_exists('user_logout')) {
+        user_logout();
+      }
     }
   }
   return FALSE;
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.151
diff -u -p -r1.151 system.admin.inc
--- modules/system/system.admin.inc	29 May 2009 19:51:43 -0000	1.151
+++ modules/system/system.admin.inc	30 May 2009 23:35:29 -0000
@@ -1703,18 +1703,15 @@ function system_date_time_lookup() {
  * @see system_settings_form()
  */
 function system_site_maintenance_mode() {
-
-  $form['site_offline'] = array(
-    '#type' => 'radios',
-    '#title' => t('Site status'),
+  $form['maintenance_mode'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Put site into maintenance mode'),
     '#default_value' => 0,
-    '#options' => array(t('Online'), t('Offline')),
-    '#description' => t('When set to "Online", all visitors will be able to browse your site normally. When set to "Offline", only users with the "administer site configuration" permission will be able to access your site to perform maintenance; all other visitors will see the site offline message configured below. Authorized users can log in during "Offline" mode directly via the <a href="@user-login">user login</a> page.', array('@user-login' => url('user'))),
+    '#description' => t('When enabled, only users with the "Access site in maintenance mode" <a href="@permissions-url">permission</a> are able to access your site to perform maintenance; all other visitors see the maintenance mode message configured below. Authorized users can log in directly via the <a href="@user-login">user login</a> page.', array('@permissions-url' => url('admin/user/permissions'), '@user-login' => url('user'))),
   );
-
-  $form['site_offline_message'] = array(
+  $form['maintenance_mode_message'] = array(
     '#type' => 'textarea',
-    '#title' => t('Site offline message'),
+    '#title' => t('Maintenance mode message'),
     '#default_value' => t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))),
     '#description' => t('Message to show visitors when the site is in maintenance mode.')
   );
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.332
diff -u -p -r1.332 system.install
--- modules/system/system.install	27 May 2009 18:34:01 -0000	1.332
+++ modules/system/system.install	30 May 2009 23:48:26 -0000
@@ -3496,6 +3496,33 @@ function system_update_7023() {
 }
 
 /**
+ * Split the 'access site in maintenance mode' permission from 'administer site configuration'.
+ */
+function system_update_7024() {
+  $ret = array();
+  // Get existing roles that can 'administer site configuration'.
+  $rids = db_query("SELECT rid FROM {role_permission} WHERE permission = :perm", array(':perm' => 'administer site configuration'))->fetchCol();
+  // None found.
+  if (empty($rids)) {
+    return $ret;
+  }
+  $insert = db_insert('role_permission')->fields(array('rid', 'permission'));
+  foreach ($rids as $rid) {
+    $insert->values(array(
+      'rid' => $rid,
+      'permission' => 'access site in maintenance mode',
+    ));
+  }
+  $insert->execute();
+
+  // Remove obsolete variable 'site_offline_message'.
+  // @see update.php
+  variable_del('site_offline_message');
+
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.705
diff -u -p -r1.705 system.module
--- modules/system/system.module	29 May 2009 03:57:04 -0000	1.705
+++ modules/system/system.module	30 May 2009 23:37:36 -0000
@@ -193,6 +193,10 @@ function system_perm() {
       'title' => t('Access administration pages'),
       'description' => t('View the administration panel and browse the help system.'),
     ),
+    'access site in maintenance mode' => array(
+      'title' => t('Access site in maintenance mode'),
+      'description' => t('Log in when the site is in maintenance mode.'),
+    ),
     'access site reports' => array(
       'title' => t('Access site reports'),
       'description' => t('View reports from system logs and other status information.'),
Index: modules/system/system.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.test,v
retrieving revision 1.46
diff -u -p -r1.46 system.test
--- modules/system/system.test	27 May 2009 18:34:01 -0000	1.46
+++ modules/system/system.test	30 May 2009 23:37:53 -0000
@@ -610,6 +610,89 @@ class PageNotFoundTestCase extends Drupa
 }
 
 /**
+ * Tests site maintenance functionality.
+ */
+class SiteMaintenanceTestCase extends DrupalWebTestCase {
+  protected $admin_user;
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Site maintenance mode functionality'),
+      'description' => t('Test access to site while in maintenance mode.'),
+      'group' => t('System'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    // Create a user allowed to access site in maintenance mode.
+    $this->user = $this->drupalCreateUser(array('access site in maintenance mode'));
+    // Create an administrative user.
+    $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'access site in maintenance mode'));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  function testSiteOffline() {
+    // Set site offline.
+    $edit = array(
+      'maintenance_mode' => 1,
+    );
+    $this->drupalPost('admin/settings/maintenance-mode', $edit, t('Save configuration'));
+
+    $admin_message = t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/settings/maintenance-mode')));
+    $user_message = t('Operating in maintenance mode.');
+    $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')));
+
+    $this->drupalGet('');
+    $this->assertRaw($admin_message, t('Found the site maintenance mode message.'));
+
+    // Logout and verify that offline message is displayed.
+    $this->drupalLogout();
+    $this->drupalGet('');
+    $this->assertText($offline_message);
+    $this->drupalGet('node');
+    $this->assertText($offline_message);
+    $this->drupalGet('user/register');
+    $this->assertText($offline_message);
+    $this->drupalGet('user/password');
+    $this->assertText($offline_message);
+
+    // Verify that user is able to log in.
+    $this->drupalGet('user');
+    $this->assertNoText($offline_message);
+    $this->drupalGet('user/login');
+    $this->assertNoText($offline_message);
+
+    // Log in user and verify that maintenance mode message is displayed
+    // directly after login.
+    $edit = array(
+      'name' => $this->user->name,
+      'pass' => $this->user->pass_raw,
+    );
+    $this->drupalPost(NULL, $edit, t('Log in'));
+    $this->assertText($user_message);
+
+    // Log in administrative user and configure a custom site offline message.
+    $this->drupalLogout();
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/settings/maintenance-mode');
+    $this->assertNoRaw($admin_message, t('Site maintenance mode message not displayed.'));
+
+    $offline_message = 'Sorry, not online.';
+    $edit = array(
+      'maintenance_mode_message' => $offline_message,
+    );
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
+
+    // Logout and verify that custom site offline message is displayed.
+    $this->drupalLogout();
+    $this->drupalGet('');
+    $this->assertRaw($offline_message, t('Found the site offline message.'));
+  }
+}
+
+/**
  * Tests generic date and time handling capabilities of Drupal.
  */
 class DateTimeFunctionalTest extends DrupalWebTestCase {
