--- modules/system/system.install.old2	2008-05-05 00:18:25.000000000 -0400
+++ modules/system/system.module	2008-05-04 13:41:13.000000000 -0400
@@ -1,2520 +1,1899 @@
 <?php
-// $Id: system.install,v 1.238.2.1 2008/02/08 17:07:55 goba Exp $
+// $Id: system.module,v 1.585.2.11 2008/04/09 21:11:49 goba Exp $
 
 /**
- * Test and report Drupal installation requirements.
- *
- * @param $phase
- *   The current system installation phase.
- * @return
- *   An array of system requirements.
+ * @file
+ * Configuration system that lets administrators modify the workings of the site.
  */
-function system_requirements($phase) {
-  $requirements = array();
-  // Ensure translations don't break at install time
-  $t = get_t();
-
-  // Report Drupal version
-  if ($phase == 'runtime') {
-    $requirements['drupal'] = array(
-      'title' => $t('Drupal'),
-      'value' => VERSION,
-      'severity' => REQUIREMENT_INFO,
-      'weight' => -10,
-    );
-  }
-
-  // Web server information.
-  $software = $_SERVER['SERVER_SOFTWARE'];
-  $requirements['webserver'] = array(
-    'title' => $t('Web server'),
-    'value' => $software,
-  );
-
-  // Test PHP version
-  $requirements['php'] = array(
-    'title' => $t('PHP'),
-    'value' => ($phase == 'runtime') ? l(phpversion(), 'admin/reports/status/php') : phpversion(),
-  );
-  if (version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) {
-    $requirements['php']['description'] = $t('Your PHP installation is too old. Drupal requires at least PHP %version.', array('%version' => DRUPAL_MINIMUM_PHP));
-    $requirements['php']['severity'] = REQUIREMENT_ERROR;
-  }
-
-  // Test PHP register_globals setting.
-  $requirements['php_register_globals'] = array(
-    'title' => $t('PHP register globals'),
-  );
-  $register_globals = trim(ini_get('register_globals'));
-  // Unfortunately, ini_get() may return many different values, and we can't
-  // be certain which values mean 'on', so we instead check for 'not off'
-  // since we never want to tell the user that their site is secure
-  // (register_globals off), when it is in fact on. We can only guarantee
-  // register_globals is off if the value returned is 'off', '', or 0.
-  if (!empty($register_globals) && strtolower($register_globals) != 'off') {
-    $requirements['php_register_globals']['description'] = $t('<em>register_globals</em> is enabled. Drupal requires this configuration directive to be disabled. Your site may not be secure when <em>register_globals</em> is enabled. The PHP manual has instructions for <a href="http://php.net/configuration.changes">how to change configuration settings</a>.');
-    $requirements['php_register_globals']['severity'] = REQUIREMENT_ERROR;
-    $requirements['php_register_globals']['value'] = $t("Enabled ('@value')", array('@value' => $register_globals));
-  }
-  else {
-    $requirements['php_register_globals']['value'] = $t('Disabled');
-  }
-
-  // Test PHP memory_limit
-  $memory_limit = ini_get('memory_limit');
-  $requirements['php_memory_limit'] = array(
-    'title' => $t('PHP memory limit'),
-    'value' => $memory_limit,
-  );
-
-  if ($memory_limit && parse_size($memory_limit) < parse_size(DRUPAL_MINIMUM_PHP_MEMORY_LIMIT)) {
-    $description = '';
-    if ($phase == 'install') {
-      $description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the installation process.', array('%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
-    }
-    elseif ($phase == 'update') {
-      $description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the update process.', array('%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
-    }
-    elseif ($phase == 'runtime') {
-      $description = $t('Depending on your configuration, Drupal can run with a %memory_limit PHP memory limit. However, a %memory_minimum_limit PHP memory limit or above is recommended, especially if your site uses additional custom or contributed modules.', array('%memory_limit' => $memory_limit, '%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
-    }
 
-    if (!empty($description)) {
-      if ($php_ini_path = get_cfg_var('cfg_file_path')) {
-        $description .= ' '. $t('Increase the memory limit by editing the memory_limit parameter in the file %configuration-file and then restart your web server (or contact your system administrator or hosting provider for assistance).', array('%configuration-file' => $php_ini_path));
-      }
-      else {
-        $description .= ' '. $t('Contact your system administrator or hosting provider for assistance with increasing your PHP memory limit.');
-      }
+/**
+ * The current system version.
+ */
+define('VERSION', '6.2');
 
-      $requirements['php_memory_limit']['description'] = $description .' '. $t('See the <a href="@url">Drupal requirements</a> for more information.', array('@url' => 'http://drupal.org/requirements'));
-      $requirements['php_memory_limit']['severity'] = REQUIREMENT_WARNING;
-    }
-  }
+/**
+ * Core API compatibility.
+ */
+define('DRUPAL_CORE_COMPATIBILITY', '6.x');
 
-  // Test DB version
-  global $db_type;
-  if (function_exists('db_status_report')) {
-    $requirements += db_status_report($phase);
-  }
+/**
+ * Minimum supported version of PHP.
+ */
+define('DRUPAL_MINIMUM_PHP',    '4.3.5');
 
-  // Test settings.php file writability
-  if ($phase == 'runtime') {
-    $conf_dir = drupal_verify_install_file(conf_path(), FILE_NOT_WRITABLE, 'dir');
-    $conf_file = drupal_verify_install_file(conf_path() .'/settings.php', FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE);
-    if (!$conf_dir || !$conf_file) {
-      $requirements['settings.php'] = array(
-        'value' => $t('Not protected'),
-        'severity' => REQUIREMENT_ERROR,
-        'description' => '',
-      );
-      if (!$conf_dir) {
-        $requirements['settings.php']['description'] .= $t('The directory %file is not protected from modifications and poses a security risk. You must change the directory\'s permissions to be non-writable. ', array('%file' => conf_path()));
-      }
-      if (!$conf_file) {
-        $requirements['settings.php']['description'] .= $t('The file %file is not protected from modifications and poses a security risk. You must change the file\'s permissions to be non-writable.', array('%file' => conf_path() .'/settings.php'));
-      }
-    }
-    else {
-      $requirements['settings.php'] = array(
-        'value' => $t('Protected'),
-      );
-    }
-    $requirements['settings.php']['title'] = $t('Configuration file');
-  }
+/**
+ * Minimum recommended value of PHP memory_limit.
+ */
+define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT',    '16M');
 
-  // Report cron status.
-  if ($phase == 'runtime') {
-    // Cron warning threshold defaults to two days.
-    $threshold_warning = variable_get('cron_threshold_warning', 172800);
-    // Cron error threshold defaults to two weeks.
-    $threshold_error = variable_get('cron_threshold_error', 1209600);
-    // Cron configuration help text.
-    $help = $t('For more information, see the online handbook entry for <a href="@cron-handbook">configuring cron jobs</a>.', array('@cron-handbook' => 'http://drupal.org/cron'));
-
-    // Determine when cron last ran. If never, use the install time to
-    // determine the warning or error status.
-    $cron_last = variable_get('cron_last', NULL);
-    $never_run = FALSE;
-    if (!is_numeric($cron_last)) {
-      $never_run = TRUE;
-      $cron_last = variable_get('install_time', 0);
-    }
-
-    // Determine severity based on time since cron last ran.
-    $severity = REQUIREMENT_OK;
-    if (time() - $cron_last > $threshold_error) {
-      $severity = REQUIREMENT_ERROR;
-    }
-    else if ($never_run || (time() - $cron_last > $threshold_warning)) {
-      $severity = REQUIREMENT_WARNING;
-    }
-
-    // If cron hasn't been run, and the user is viewing the main
-    // administration page, instead of an error, we display a helpful reminder
-    // to configure cron jobs.
-    if ($never_run && $severity != REQUIREMENT_ERROR && $_GET['q'] == 'admin' && user_access('administer site configuration')) {
-      drupal_set_message($t('Cron has not run. Please visit the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))));
-    }
-
-    // Set summary and description based on values determined above.
-    if ($never_run) {
-      $summary = $t('Never run');
-      $description = $t('Cron has not run.') .' '. $help;
-    }
-    else {
-      $summary = $t('Last run !time ago', array('!time' => format_interval(time() - $cron_last)));
-      $description = '';
-      if ($severity != REQUIREMENT_OK) {
-        $description = $t('Cron has not run recently.') .' '. $help;
-      }
-    }
+/**
+ * Minimum supported version of MySQL, if it is used.
+ */
+define('DRUPAL_MINIMUM_MYSQL',  '4.1.1');
 
-    $requirements['cron'] = array(
-      'title' => $t('Cron maintenance tasks'),
-      'severity' => $severity,
-      'value' => $summary,
-      'description' => $description .' '. $t('You can <a href="@cron">run cron manually</a>.', array('@cron' => url('admin/reports/status/run-cron'))),
-    );
-  }
+/**
+ * Minimum supported version of PostgreSQL, if it is used.
+ */
+define('DRUPAL_MINIMUM_PGSQL',  '7.4');
 
-  // Test files directory
-  $directory = file_directory_path();
-  $requirements['file system'] = array(
-    'title' => $t('File system'),
-  );
-
-  // For installer, create the directory if possible.
-  if ($phase == 'install' && !is_dir($directory) && @mkdir($directory)) {
-    @chmod($directory, 0775); // Necessary for non-webserver users.
-  }
-
-  $is_writable = is_writable($directory);
-  $is_directory = is_dir($directory);
-  if (!$is_writable || !$is_directory) {
-    $description = '';
-    $requirements['file system']['value'] = $t('Not writable');
-    if (!$is_directory) {
-      $error = $t('The directory %directory does not exist.', array('%directory' => $directory));
-    }
-    else {
-      $error = $t('The directory %directory is not writable.', array('%directory' => $directory));
-    }
-    // The files directory requirement check is done only during install and runtime.
-    if ($phase == 'runtime') {
-      $description = $error .' '. $t('You may need to set the correct directory at the <a href="@admin-file-system">file system settings page</a> or change the current directory\'s permissions so that it is writable.', array('@admin-file-system' => url('admin/settings/file-system')));
-    }
-    elseif ($phase == 'install') {
-      // For the installer UI, we need different wording. 'value' will
-      // be treated as version, so provide none there.
-      $description = $error .' '. $t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually, or ensure that the installer has the permissions to create it automatically. For more information, please see INSTALL.txt or the <a href="@handbook_url">on-line handbook</a>.', array('@handbook_url' => 'http://drupal.org/server-permissions'));
-      $requirements['file system']['value'] = '';
-    }
-    if (!empty($description)) {
-      $requirements['file system']['description'] = $description;
-      $requirements['file system']['severity'] = REQUIREMENT_ERROR;
-    }
-  }
-  else {
-    if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) {
-      $requirements['file system']['value'] = $t('Writable (<em>public</em> download method)');
-    }
-    else {
-      $requirements['file system']['value'] = $t('Writable (<em>private</em> download method)');
-    }
-  }
+/**
+ * Maximum age of temporary files in seconds.
+ */
+define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 1440);
 
-  // See if updates are available in update.php.
-  if ($phase == 'runtime') {
-    $requirements['update'] = array(
-      'title' => $t('Database updates'),
-      'severity' => REQUIREMENT_OK,
-      'value' => $t('Up to date'),
-    );
+/**
+ * Implementation of hook_help().
+ */
+function system_help($path, $arg) {
+  global $base_url;
 
-    // Check installed modules.
-    foreach (module_list() as $module) {
-      $updates = drupal_get_schema_versions($module);
-      if ($updates !== FALSE) {
-        $default = drupal_get_installed_schema_version($module);
-        if (max($updates) > $default) {
-          $requirements['update']['severity'] = REQUIREMENT_ERROR;
-          $requirements['update']['value'] = $t('Out of date');
-          $requirements['update']['description'] = $t('Some modules have database schema updates to install. You should run the <a href="@update">database update script</a> immediately.', array('@update' => base_path() .'update.php'));
-          break;
-        }
+  switch ($path) {
+    case 'admin/help#system':
+      $output = '<p>'. t('The system module is at the foundation of your Drupal website, and provides basic but extensible functionality for use by other modules and themes. Some integral elements of Drupal are contained in and managed by the system module, including caching, enabling or disabling of modules and themes, preparing and displaying the administrative page, and configuring fundamental site settings. A number of key system maintenance operations are also part of the system module.') .'</p>';
+      $output .= '<p>'. t('The system module provides:') .'</p>';
+      $output .= '<ul><li>'. t('support for enabling and disabling <a href="@modules">modules</a>. Drupal comes packaged with a number of core modules; each module provides a discrete set of features and may be enabled depending on the needs of your site. A wide array of additional modules contributed by members of the Drupal community are available for download at the <a href="@drupal-modules">Drupal.org module page</a>.', array('@modules' => url('admin/build/modules'), '@drupal-modules' => 'http://drupal.org/project/modules')) .'</li>';
+      $output .= '<li>'. t('support for enabling and disabling <a href="@themes">themes</a>, which determine the design and presentation of your site. Drupal comes packaged with several core themes and additional contributed themes are available at the <a href="@drupal-themes">Drupal.org theme page</a>.', array('@themes' => url('admin/build/themes'), '@drupal-themes' => 'http://drupal.org/project/themes')) .'</li>';
+      $output .= '<li>'. t('a robust <a href="@cache-settings">caching system</a> that allows the efficient re-use of previously-constructed web pages and web page components. Drupal stores the pages requested by anonymous users in a compressed format; depending on your site configuration and the amount of your web traffic tied to anonymous visitors, Drupal\'s caching system may significantly increase the speed of your site.', array('@cache-settings' => url('admin/settings/performance'))) .'</li>';
+      $output .= '<li>'. t('a set of routine administrative operations that rely on a correctly-configured <a href="@cron">cron maintenance task</a> to run automatically. A number of other modules, including the feed aggregator, ping module and search also rely on <a href="@cron">cron maintenance tasks</a>. For more information, see the online handbook entry for <a href="@handbook">configuring cron jobs</a>.', array('@cron' => url('admin/reports/status'), '@handbook' => 'http://drupal.org/cron')) .'</li>';
+      $output .= '<li>'. t('basic configuration options for your site, including <a href="@date-settings">date and time settings</a>, <a href="@file-system">file system settings</a>, <a href="@clean-url">clean URL support</a>, <a href="@site-info">site name and other information</a>, and a <a href="@site-maintenance">site maintenance</a> function for taking your site temporarily off-line.', array('@date-settings' => url('admin/settings/date-time'), '@file-system' => url('admin/settings/file-system'), '@clean-url' => url('admin/settings/clean-urls'), '@site-info' => url('admin/settings/site-information'), '@site-maintenance' => url('admin/settings/site-maintenance'))) .'</li></ul>';
+      $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@system">System module</a>.', array('@system' => 'http://drupal.org/handbook/modules/system/')) .'</p>';
+      return $output;
+    case 'admin':
+      return '<p>'. t('Welcome to the administration section. Here you may control how your site functions.') .'</p>';
+    case 'admin/by-module':
+      return '<p>'. t('This page shows you all available administration tasks for each module.') .'</p>';
+    case 'admin/build/themes':
+      $output = '<p>'. t('Select which themes are available to your users and specify the default theme. To configure site-wide display settings, click the "configure" task above. Alternatively, to override these settings in a specific theme, click the "configure" link for that theme. Note that different themes may have different regions available for displaying content; for consistency in presentation, you may wish to enable only one theme.') .'</p>';
+      $output .= '<p>'. t('To change the appearance of your site, a number of <a href="@themes">contributed themes</a> are available.', array('@themes' => 'http://drupal.org/project/themes')) .'</p>';
+      return $output;
+    case 'admin/build/themes/settings/'. $arg[4]:
+      $reference = explode('.', $arg[4], 2);
+      $theme = array_pop($reference);
+      return '<p>'. t('These options control the display settings for the <code>%template</code> theme. When your site is displayed using this theme, these settings will be used. By clicking "Reset to defaults," you can choose to use the <a href="@global">global settings</a> for this theme.', array('%template' => $theme, '@global' => url('admin/build/themes/settings'))) .'</p>';
+    case 'admin/build/themes/settings':
+      return '<p>'. t('These options control the default display settings for your entire site, across all themes. Unless they have been overridden by a specific theme, these settings will be used.') .'</p>';
+    case 'admin/build/modules':
+      $output = '<p>'. t('Modules are plugins that extend Drupal\'s core functionality. Enable modules by selecting the <em>Enabled</em> checkboxes below and clicking the <em>Save configuration</em> button. Once a module is enabled, new <a href="@permissions">permissions</a> may be available. To reduce server load, modules with their <em>Throttle</em> checkbox selected are temporarily disabled when your site becomes extremely busy. (Note that the <em>Throttle</em> checkbox is only available if the Throttle module is enabled.)', array('@permissions' => url('admin/user/permissions')));
+      if (module_exists('throttle')) {
+        $output .= ' '. t('The auto-throttle functionality must be enabled on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.', array('@throttle' => url('admin/settings/throttle')));
       }
-    }
-  }
-
-  // Verify the update.php access setting
-  if ($phase == 'runtime') {
-    if (!empty($GLOBALS['update_free_access'])) {
-      $requirements['update access'] = array(
-        'value' => $t('Not protected'),
-        'severity' => REQUIREMENT_ERROR,
-        'description' => $t('The update.php script is accessible to everyone without authentication check, which is a security risk. You must change the $update_free_access value in your settings.php back to FALSE.'),
-      );
-    }
-    else {
-      $requirements['update access'] = array(
-        'value' => $t('Protected'),
-      );
-    }
-    $requirements['update access']['title'] = $t('Access to update.php');
-  }
-
-  // Test Unicode library
-  include_once './includes/unicode.inc';
-  $requirements = array_merge($requirements, unicode_requirements());
-
-  // Check for update status module.
-  if ($phase == 'runtime') {
-    if (!module_exists('update')) {
-      $requirements['update status'] = array(
-        'value' => $t('Not enabled'),
-        'severity' => REQUIREMENT_ERROR,
-        'description' => $t('Update notifications are not enabled. It is <strong>highly recommended</strong> that you enable the update status module from the <a href="@module">module administration page</a> in order to stay up-to-date on new releases. For more information please read the <a href="@update">Update status handbook page</a>.', array('@update' => 'http://drupal.org/handbook/modules/update', '@module' => url('admin/build/modules'))),
-      );
-    }
-    else {
-      $requirements['update status'] = array(
-        'value' => $t('Enabled'),
-      );
-      if (variable_get('drupal_http_request_fails', FALSE)) {
-        $requirements['http requests'] = array(
-          'title' => $t('HTTP request status'),
-          'value' => $t('Fails'),
-          'severity' => REQUIREMENT_ERROR,
-          'description' => $t('Your system or network configuration does not allow Drupal to access web pages, resulting in reduced functionality. This could be due to your webserver configuration or PHP settings, and should be resolved in order to download information about available updates, fetch aggregator feeds, sign in via OpenID, or use other network-dependent services.'),
-        );
+      $output .= '</p>';
+      $output .= '<p>'. t('It is important that <a href="@update-php">update.php</a> is run every time a module is updated to a newer version.', array('@update-php' => $base_url .'/update.php')) .'</p>';
+      $output .= '<p>'. t('You can find all administration tasks belonging to a particular module on the <a href="@by-module">administration by module page</a>.', array('@by-module' => url('admin/by-module'))) .'</p>';
+      $output .= '<p>'. t('To extend the functionality of your site, a number of <a href="@modules">contributed modules</a> are available.', array('@modules' => 'http://drupal.org/project/modules')) .'</p>';
+      return $output;
+    case 'admin/build/modules/uninstall':
+      return '<p>'. t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it. Not all modules support this feature.') .'</p>';
+    case 'admin/build/block/configure':
+      if ($arg[4] == 'system' && $arg[5] == 0) {
+        return '<p>'. t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') .'</p>';
       }
-    }
-    $requirements['update status']['title'] = $t('Update notifications');
+      break;
+    case 'admin/settings/actions':
+    case 'admin/settings/actions/manage':
+      $output = '<p>'. t('Actions are individual tasks that the system can do, such as unpublishing a piece of content or banning a user. Modules, such as the trigger module, can fire these actions when certain system events happen; for example, when a new post is added or when a user logs in. Modules may also provide additional actions.') .'</p>';
+      $output .= '<p>'. t('There are two types of actions: simple and advanced. Simple actions do not require any additional configuration, and are listed here automatically. Advanced actions can do more than simple actions; for example, send an e-mail to a specified address, or check for certain words within a piece of content. These actions need to be created and configured first before they may be used. To create an advanced action, select the action from the drop-down below and click the <em>Create</em> button.') .'</p>';
+      if (module_exists('trigger')) {
+        $output .= '<p>'. t('You may proceed to the <a href="@url">Triggers</a> page to assign these actions to system events.', array('@url' => url('admin/build/trigger'))) .'</p>';
+      }
+      return $output;
+    case 'admin/settings/actions/configure':
+      return t('An advanced action offers additional configuration options which may be filled out below. Changing the <em>Description</em> field is recommended, in order to better identify the precise action taking place. This description will be displayed in modules such as the trigger module when assigning actions to system events, so it is best if it is as descriptive as possible (for example, "Send e-mail to Moderation Team" rather than simply "Send e-mail").');
+    case 'admin/reports/status':
+      return '<p>'. t("Here you can find a short overview of your site's parameters as well as any problems detected with your installation. It may be useful to copy and paste this information into support requests filed on drupal.org's support forums and project issue queues.") .'</p>';
   }
-
-  return $requirements;
 }
 
 /**
- * Implementation of hook_install().
+ * Implementation of hook_theme().
  */
-function system_install() {
-  if ($GLOBALS['db_type'] == 'pgsql') {
-    // Create unsigned types.
-    db_query("CREATE DOMAIN int_unsigned integer CHECK (VALUE >= 0)");
-    db_query("CREATE DOMAIN smallint_unsigned smallint CHECK (VALUE >= 0)");
-    db_query("CREATE DOMAIN bigint_unsigned bigint CHECK (VALUE >= 0)");
-
-    // Create functions.
-    db_query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric) RETURNS numeric AS
-      \'SELECT CASE WHEN (($1 > $2) OR ($2 IS NULL)) THEN $1 ELSE $2 END;\'
-      LANGUAGE \'sql\''
-    );
-    db_query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric, numeric) RETURNS numeric AS
-      \'SELECT greatest($1, greatest($2, $3));\'
-      LANGUAGE \'sql\''
-    );
-    if (!db_result(db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'"))) {
-      db_query('CREATE OR REPLACE FUNCTION "rand"() RETURNS float AS
-        \'SELECT random();\'
-        LANGUAGE \'sql\''
-      );
-    }
-
-    if (!db_result(db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'concat'"))) {
-      db_query('CREATE OR REPLACE FUNCTION "concat"(text, text) RETURNS text AS
-        \'SELECT $1 || $2;\'
-        LANGUAGE \'sql\''
-      );
-    }
-    db_query('CREATE OR REPLACE FUNCTION "if"(boolean, text, text) RETURNS text AS
-      \'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\'
-      LANGUAGE \'sql\''
-    );
-    db_query('CREATE OR REPLACE FUNCTION "if"(boolean, integer, integer) RETURNS integer AS
-      \'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\'
-      LANGUAGE \'sql\''
-    );
-  }
-
-  // Create tables.
-  $modules = array('system', 'filter', 'block', 'user', 'node', 'comment', 'taxonomy');
-  foreach ($modules as $module) {
-    drupal_install_schema($module);
-  }
-
-  // Load system theme data appropriately.
-  system_theme_data();
-
-  // Inserting uid 0 here confuses MySQL -- the next user might be created as
-  // uid 2 which is not what we want. So we insert the first user here, the
-  // anonymous user. uid is 1 here for now, but very soon it will be changed
-  // to 0.
-  db_query("INSERT INTO {users} (name, mail) VALUES('%s', '%s')", '', '');
-  // We need some placeholders here as name and mail are uniques and data is
-  // presumed to be a serialized array. Install will change uid 1 immediately
-  // anyways. So we insert the superuser here, the uid is 2 here for now, but
-  // very soon it will be changed to 1.
-  db_query("INSERT INTO {users} (name, mail, created, data) VALUES('%s', '%s', %d, '%s')", 'placeholder-for-uid-1', 'placeholder-for-uid-1', time(), serialize(array()));
-  // This sets the above two users uid 0 (anonymous). We avoid an explicit 0
-  // otherwise MySQL might insert the next auto_increment value.
-  db_query("UPDATE {users} SET uid = uid - uid WHERE name = '%s'", '');
-  // This sets uid 1 (superuser). We skip uid 2 but that's not a big problem.
-  db_query("UPDATE {users} SET uid = 1 WHERE name = '%s'", 'placeholder-for-uid-1');
-
-  db_query("INSERT INTO {role} (name) VALUES ('%s')", 'anonymous user');
-  db_query("INSERT INTO {role} (name) VALUES ('%s')", 'authenticated user');
-  // Similar to the need to reset uids above, this does the same for rids
-  db_query("UPDATE {role} SET rid = 1 WHERE name = '%s'", 'anonymous user');
-  db_query("UPDATE {role} SET rid = 2 WHERE name = '%s'", 'authenticated user');
-
-  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 1, 'access content', 0);
-  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 2, 'access comments, access content, post comments, post comments without approval', 0);
-
-  db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'theme_default', 's:7:"garland";');
-  db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 1, 'theme', 'garland');
-  db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', '0', 'garland', 1, 0, 'left', '', -1);
-  db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', '1', 'garland', 1, 0, 'left', '', -1);
-  db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'system', '0', 'garland', 1, 10, 'footer', '', -1);
-
-  db_query("INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, '%s', %d, %d, %d)", 0, 0, 'all', 1, 0, 0);
-
-  // Add input formats.
-  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Filtered HTML', ',1,2,', 1);
-  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Full HTML', '', 1);
-
-  // Enable filters for each input format.
-
-  // Filtered HTML:
-  // URL filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 2, 0);
-  // HTML filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 0, 1);
-  // Line break filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 1, 2);
-  // HTML corrector filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 3, 10);
-
-  // Full HTML:
-  // URL filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 2, 0);
-  // Line break filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 1, 1);
-  // HTML corrector filter.
-  db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 3, 10);
-
-  db_query("INSERT INTO {variable} (name, value) VALUES ('%s','%s')", 'filter_html_1', 'i:1;');
-
-  db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'node_options_forum', 'a:1:{i:0;s:6:"status";}');
-}
-
-/**
- * Implementation of hook_schema().
- */
-function system_schema() {
-  // NOTE: {variable} needs to be created before all other tables, as
-  // some database drivers, e.g. Oracle and DB2, will require variable_get()
-  // and variable_set() for overcoming some database specific limitations.
-  $schema['variable'] = array(
-    'description' => t('Named variable/value pairs created by Drupal core or any other module or theme. All variables are cached in memory at the start of every Drupal request so developers should not be careless about what is stored here.'),
-    'fields' => array(
-      'name' => array(
-        'description' => t('The name of the variable.'),
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => ''),
-      'value' => array(
-        'description' => t('The value of the variable.'),
-        'type' => 'text',
-        'not null' => TRUE,
-        'size' => 'big'),
-      ),
-    'primary key' => array('name'),
-    );
-
-  $schema['actions'] = array(
-    'description' => t('Stores action information.'),
-    'fields' => array(
-      'aid' => array(
-        'description' => t('Primary Key: Unique actions ID.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '0'),
-      'type' => array(
-        'description' => t('The object that that action acts on (node, user, comment, system or custom types.)'),
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => ''),
-      'callback' => array(
-        'description' => t('The callback function that executes when the action runs.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'parameters' => array(
-        'description' => t('Parameters to be passed to the callback function.'),
-        'type' => 'text',
-        'not null' => TRUE,
-        'size' => 'big'),
-      'description' => array(
-        'description' => t('Description of the action.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '0'),
-      ),
-    'primary key' => array('aid'),
-    );
-
-  $schema['actions_aid'] = array(
-    'description' => t('Stores action IDs for non-default actions.'),
-    'fields' => array(
-      'aid' => array(
-        'description' => t('Primary Key: Unique actions ID.'),
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE),
-      ),
-    'primary key' => array('aid'),
-    );
-
-  $schema['batch'] = array(
-    'description' => t('Stores details about batches (processes that run in multiple HTTP requests).'),
-    'fields' => array(
-      'bid' => array(
-        'description' => t('Primary Key: Unique batch ID.'),
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE),
-      'token' => array(
-        'description' => t("A string token generated against the current user's session id and the batch id, used to ensure that only the user who submitted the batch can effectively access it."),
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE),
-      'timestamp' => array(
-        'description' => t('A Unix timestamp indicating when this batch was submitted for processing. Stale batches are purged at cron time.'),
-        'type' => 'int',
-        'not null' => TRUE),
-      'batch' => array(
-        'description' => t('A serialized array containing the processing data for the batch.'),
-        'type' => 'text',
-        'not null' => FALSE,
-        'size' => 'big')
-      ),
-    'primary key' => array('bid'),
-    'indexes' => array('token' => array('token')),
-    );
+function system_theme() {
+  return array_merge(drupal_common_theme(), array(
+    'system_theme_select_form' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'system_themes_form' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'system_modules' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'system_modules_uninstall' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'status_report' => array(
+      'arguments' => array('requirements' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'admin_page' => array(
+      'arguments' => array('blocks' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'admin_block' => array(
+      'arguments' => array('block' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'admin_block_content' => array(
+      'arguments' => array('content' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'system_admin_by_module' => array(
+      'arguments' => array('menu_items' => NULL),
+      'file' => 'system.admin.inc',
+    ),
+    'system_powered_by' => array(
+      'arguments' => array('image_path' => NULL),
+    ),
+  ));
+}
 
-  $schema['cache'] = array(
-    'description' => t('Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.'),
-    'fields' => array(
-      'cid' => array(
-        'description' => t('Primary Key: Unique cache ID.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'data' => array(
-        'description' => t('A collection of data to cache.'),
-        'type' => 'blob',
-        'not null' => FALSE,
-        'size' => 'big'),
-      'expire' => array(
-        'description' => t('A Unix timestamp indicating when the cache entry should expire, or 0 for never.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'created' => array(
-        'description' => t('A Unix timestamp indicating when the cache entry was created.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'headers' => array(
-        'description' => t('Any custom HTTP headers to be added to cached data.'),
-        'type' => 'text',
-        'not null' => FALSE),
-      'serialized' => array(
-        'description' => t('A flag to indicate whether content is serialized (1) or not (0).'),
-        'type' => 'int',
-        'size' => 'small',
-        'not null' => TRUE,
-        'default' => 0)
-      ),
-    'indexes' => array('expire' => array('expire')),
-    'primary key' => array('cid'),
-    );
+/**
+ * Implementation of hook_perm().
+ */
+function system_perm() {
+  return array('administer site configuration', 'access administration pages', 'administer actions', 'access site reports', 'select different theme', 'administer files');
+}
 
-  $schema['cache_form'] = $schema['cache'];
-  $schema['cache_form']['description'] = t('Cache table for the form system to store recently built forms and their storage data, to be used in subsequent page requests.');
-  $schema['cache_page'] = $schema['cache'];
-  $schema['cache_page']['description'] = t('Cache table used to store compressed pages for anonymous users, if page caching is enabled.');
-  $schema['cache_menu'] = $schema['cache'];
-  $schema['cache_menu']['description'] = t('Cache table for the menu system to store router information as well as generated link trees for various menu/page/user combinations.');
-
-  $schema['files'] = array(
-    'description' => t('Stores information for uploaded files.'),
-    'fields' => array(
-      'fid' => array(
-        'description' => t('Primary Key: Unique files ID.'),
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE),
-      'uid' => array(
-        'description' => t('The {users}.uid of the user who is associated with the file.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'filename' => array(
-        'description' => t('Name of the file.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'filepath' => array(
-        'description' => t('Path of the file relative to Drupal root.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'filemime' => array(
-        'description' => t('The file MIME type.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'filesize' => array(
-        'description' => t('The size of the file in bytes.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'status' => array(
-        'description' => t('A flag indicating whether file is temporary (1) or permanent (0).'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'timestamp' => array(
-        'description' => t('UNIX timestamp for when the file was added.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      ),
-    'indexes' => array(
-      'uid' => array('uid'),
-      'status' => array('status'),
-      'timestamp' => array('timestamp'),
-      ),
-    'primary key' => array('fid'),
-    );
+/**
+ * Implementation of hook_elements().
+ */
+function system_elements() {
+  // Top level form
+  $type['form'] = array('#method' => 'post', '#action' => request_uri());
 
-  $schema['flood'] = array(
-    'description' => t('Flood controls the threshold of events, such as the number of contact attempts.'),
-    'fields' => array(
-      'fid' => array(
-        'description' => t('Unique flood event ID.'),
-        'type' => 'serial',
-        'not null' => TRUE),
-      'event' => array(
-        'description' => t('Name of event (e.g. contact).'),
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'default' => ''),
-      'hostname' => array(
-        'description' => t('Hostname of the visitor.'),
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => ''),
-      'timestamp' => array(
-        'description' => t('Timestamp of the event.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0)
-      ),
-    'primary key' => array('fid'),
-    'indexes' => array(
-      'allow' => array('event', 'hostname', 'timestamp'),
-    ),
-    );
+  // Inputs
+  $type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'));
+  $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE, '#process' => array('form_expand_ahah'));
+  $type['image_button'] = array('#input' => TRUE, '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'), '#return_value' => TRUE, '#has_garbage_value' => TRUE, '#src' => NULL);
+  $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE, '#process' => array('form_expand_ahah'));
+  $type['password'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#process' => array('form_expand_ahah'));
+  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
+  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE, '#process' => array('form_expand_ahah'));
+  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
+  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL, '#process' => array('form_expand_ahah'));
+  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
+  $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1, '#process' => array('form_expand_ahah'));
+  $type['select'] = array('#input' => TRUE, '#size' => 0, '#multiple' => FALSE, '#process' => array('form_expand_ahah'));
+  $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight', 'form_expand_ahah'));
+  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
+  $type['file'] = array('#input' => TRUE, '#size' => 60);
 
-  $schema['history'] = array(
-    'description' => t('A record of which {users} have read which {node}s.'),
-    'fields' => array(
-      'uid' => array(
-        'description' => t('The {users}.uid that read the {node} nid.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'nid' => array(
-        'description' => t('The {node}.nid that was read.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'timestamp' => array(
-        'description' => t('The Unix timestamp at which the read occurred.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0)
-      ),
-    'primary key' => array('uid', 'nid'),
-    'indexes' => array(
-      'nid' => array('nid'),
-    ),
-    );
-  $schema['menu_router'] = array(
-    'description' => t('Maps paths to various callbacks (access, page and title)'),
-    'fields' => array(
-      'path' => array(
-        'description' => t('Primary Key: the Drupal path this entry describes'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'load_functions' => array(
-        'description' => t('A serialized array of function names (like node_load) to be called to load an object corresponding to a part of the current path.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'to_arg_functions' => array(
-        'description' => t('A serialized array of function names (like user_current_to_arg) to be called to replace a part of the router path with another string.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'access_callback' => array(
-        'description' => t('The callback which determines the access to this router path. Defaults to user_access.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'access_arguments' => array(
-        'description' => t('A serialized array of arguments for the access callback.'),
-        'type' => 'text',
-        'not null' => FALSE),
-      'page_callback' => array(
-        'description' => t('The name of the function that renders the page.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'page_arguments' => array(
-        'description' => t('A serialized array of arguments for the page callback.'),
-        'type' => 'text',
-        'not null' => FALSE),
-      'fit' => array(
-        'description' => t('A numeric representation of how specific the path is.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'number_parts' => array(
-        'description' => t('Number of parts in this router path.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      'tab_parent' => array(
-        'description' => t('Only for local tasks (tabs) - the router path of the parent page (which may also be a local task).'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'tab_root' => array(
-        'description' => t('Router path of the closest non-tab parent page. For pages that are not local tasks, this will be the same as the path.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'title' => array(
-        'description' => t('The title for the current page, or the title for the tab if this is a local task.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'title_callback' => array(
-        'description' => t('A function which will alter the title. Defaults to t()'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'title_arguments' => array(
-        'description' => t('A serialized array of arguments for the title callback. If empty, the title will be used as the sole argument for the title callback.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'type' => array(
-        'description' => t('Numeric representation of the type of the menu item, like MENU_LOCAL_TASK.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'block_callback' => array(
-        'description' => t('Name of a function used to render the block on the system administration page for this item.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'description' => array(
-        'description' => t('A description of this item.'),
-        'type' => 'text',
-        'not null' => TRUE),
-      'position' => array(
-        'description' => t('The position of the block (left or right) on the system administration page for this item.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'weight' => array(
-        'description' => t('Weight of the element. Lighter weights are higher up, heavier weights go down.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'file' => array(
-        'description' => t('The file to include for this element, usually the page callback function lives in this file.'),
-        'type' => 'text',
-        'size' => 'medium')
-      ),
-    'indexes' => array(
-      'fit' => array('fit'),
-      'tab_parent' => array('tab_parent')
-      ),
-    'primary key' => array('path'),
-    );
+  // Form structure
+  $type['item'] = array('#value' => '');
+  $type['hidden'] = array('#input' => TRUE, '#process' => array('form_expand_ahah'));
+  $type['value'] = array('#input' => TRUE);
+  $type['markup'] = array('#prefix' => '', '#suffix' => '');
+  $type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL, '#process' => array('form_expand_ahah'));
+  $type['token'] = array('#input' => TRUE);
+  return $type;
+}
 
-  $schema['menu_links'] = array(
-    'description' => t('Contains the individual links within a menu.'),
-    'fields' => array(
-     'menu_name' => array(
-        'description' => t("The menu name. All links with the same menu name (such as 'navigation') are part of the same menu."),
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => ''),
-      'mlid' => array(
-        'description' => t('The menu link ID (mlid) is the integer primary key.'),
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE),
-      'plid' => array(
-        'description' => t('The parent link ID (plid) is the mlid of the link above in the hierarchy, or zero if the link is at the top level in its menu.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'link_path' => array(
-        'description' => t('The Drupal path or external path this link points to.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'router_path' => array(
-        'description' => t('For links corresponding to a Drupal path (external = 0), this connects the link to a {menu_router}.path for joins.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'link_title' => array(
-      'description' => t('The text displayed for the link, which may be modified by a title callback stored in {menu_router}.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'options' => array(
-        'description' => t('A serialized array of options to be passed to the url() or l() function, such as a query string or HTML attributes.'),
-        'type' => 'text',
-        'not null' => FALSE),
-      'module' => array(
-        'description' => t('The name of the module that generated this link.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => 'system'),
-      'hidden' => array(
-        'description' => t('A flag for whether the link should be rendered in menus. (1 = a disabled menu item that may be shown on admin screens, -1 = a menu callback, 0 = a normal, visible link)'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      'external' => array(
-        'description' => t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      'has_children' => array(
-        'description' => t('Flag indicating whether any links have this link as a parent (1 = children exist, 0 = no children).'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      'expanded' => array(
-        'description' => t('Flag for whether this link should be rendered as expanded in menus - expanded links always have their child links displayed, instead of only when the link is in the active trail (1 = expanded, 0 = not expanded)'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      'weight' => array(
-        'description' => t('Link weight among links in the same menu at the same depth.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'depth' => array(
-        'description' => t('The depth relative to the top level. A link with plid == 0 will have depth == 1.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      'customized' => array(
-        'description' => t('A flag to indicate that the user has manually created or edited the link (1 = customized, 0 = not customized).'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      'p1' => array(
-        'description' => t('The first mlid in the materialized path. If N = depth, then pN must equal the mlid. If depth > 1 then p(N-1) must equal the plid. All pX where X > depth must equal zero. The columns p1 .. p9 are also called the parents.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p2' => array(
-        'description' => t('The second mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p3' => array(
-        'description' => t('The third mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p4' => array(
-        'description' => t('The fourth mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p5' => array(
-        'description' => t('The fifth mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p6' => array(
-        'description' => t('The sixth mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p7' => array(
-        'description' => t('The seventh mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p8' => array(
-        'description' => t('The eighth mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'p9' => array(
-        'description' => t('The ninth mlid in the materialized path. See p1.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0),
-      'updated' => array(
-        'description' => t('Flag that indicates that this link was generated during the update from Drupal 5.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small'),
-      ),
-    'indexes' => array(
-      'path_menu' => array(array('link_path', 128), 'menu_name'),
-      'menu_plid_expand_child' => array(
-        'menu_name', 'plid', 'expanded', 'has_children'),
-      'menu_parents' => array(
-        'menu_name', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'),
-      'router_path' => array(array('router_path', 128)),
-      ),
-    'primary key' => array('mlid'),
-    );
+/**
+ * Implementation of hook_menu().
+ */
+function system_menu() {
+  $items['system/files'] = array(
+    'title' => 'File download',
+    'page callback' => 'file_download',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin'] = array(
+    'title' => 'Administer',
+    'access arguments' => array('access administration pages'),
+    'page callback' => 'system_main_admin_page',
+    'weight' => 9,
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/compact'] = array(
+    'title' => 'Compact mode',
+    'page callback' => 'system_admin_compact_page',
+    'access arguments' => array('access administration pages'),
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/by-task'] = array(
+    'title' => 'By task',
+    'page callback' => 'system_main_admin_page',
+    'access arguments' => array('access administration pages'),
+    'file' => 'system.admin.inc',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  $items['admin/by-module'] = array(
+    'title' => 'By module',
+    'page callback' => 'system_admin_by_module',
+    'access arguments' => array('access administration pages'),
+    'file' => 'system.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 2,
+  );
+  $items['admin/content'] = array(
+    'title' => 'Content management',
+    'description' => "Manage your site's content.",
+    'position' => 'left',
+    'weight' => -10,
+    'page callback' => 'system_admin_menu_block_page',
+    'access arguments' => array('access administration pages'),
+    'file' => 'system.admin.inc',
+  );
 
-  $schema['sessions'] = array(
-    'description' => t("Drupal's session handlers read and write into the sessions table. Each record represents a user session, either anonymous or authenticated."),
-    'fields' => array(
-      'uid' => array(
-        'description' => t('The {users}.uid corresponding to a session, or 0 for anonymous user.'),
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE),
-      'sid' => array(
-        'description' => t("Primary key: A session ID. The value is generated by PHP's Session API."),
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'default' => ''),
-      'hostname' => array(
-        'description' => t('The IP address that last used this session ID (sid).'),
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => ''),
-      'timestamp' => array(
-        'description' => t('The Unix timestamp when this session last requested a page. Old records are purged by PHP automatically.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'cache' => array(
-        'description' => t("The time of this user's last post. This is used when the site has specified a minimum_cache_lifetime. See cache_get()."),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'session' => array(
-        'description' => t('The serialized contents of $_SESSION, an array of name/value pairs that persists across page requests by this session ID. Drupal loads $_SESSION from here at the start of each request and saves it at the end.'),
-        'type' => 'text',
-        'not null' => FALSE,
-        'size' => 'big')
-      ),
-    'primary key' => array('sid'),
-    'indexes' => array(
-      'timestamp' => array('timestamp'),
-      'uid' => array('uid')
-      ),
-    );
+  // menu items that are basically just menu blocks
+  $items['admin/settings'] = array(
+    'title' => 'Site configuration',
+    'description' => 'Adjust basic site configuration options.',
+    'position' => 'right',
+    'weight' => -5,
+    'page callback' => 'system_settings_overview',
+    'access arguments' => array('access administration pages'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/build'] = array(
+    'title' => 'Site building',
+    'description' => 'Control how your site looks and feels.',
+    'position' => 'right',
+    'weight' => -10,
+    'page callback' => 'system_admin_menu_block_page',
+    'access arguments' => array('access administration pages'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/admin'] = array(
+    'title' => 'Administration theme',
+    'description' => 'Settings for how your administrative pages should look.',
+    'position' => 'left',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_admin_theme_settings'),
+    'access arguments' => array('administer site configuration'),
+    'block callback' => 'system_admin_theme_settings',
+    'file' => 'system.admin.inc',
+  );
+  // Themes:
+  $items['admin/build/themes'] = array(
+    'title' => 'Themes',
+    'description' => 'Change which theme your site uses or allows users to set.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_themes_form', NULL),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/build/themes/select'] = array(
+    'title' => 'List',
+    'description' => 'Select the default theme.',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -1,
+  );
+  $items['admin/build/themes/settings'] = array(
+    'title' => 'Configure',
+    'page arguments' => array('system_theme_settings'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_LOCAL_TASK,
+  );
+  // Theme configuration subtabs
+  $items['admin/build/themes/settings/global'] = array(
+    'title' => 'Global settings',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -1,
+  );
 
-  $schema['system'] = array(
-    'description' => t("A list of all modules, themes, and theme engines that are or have been installed in Drupal's file system."),
-    'fields' => array(
-      'filename' => array(
-        'description' => t('The path of the primary file for this item, relative to the Drupal root; e.g. modules/node/node.module.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'name' => array(
-        'description' => t('The name of the item; e.g. node.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'type' => array(
-        'description' => t('The type of the item, either module, theme, or theme_engine.'),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'owner' => array(
-        'description' => t("A theme's 'parent'. Can be either a theme or an engine."),
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => ''),
-      'status' => array(
-        'description' => t('Boolean indicating whether or not this item is enabled.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'throttle' => array(
-        'description' => t('Boolean indicating whether this item is disabled when the throttle.module disables throttleable items.'),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny'),
-      'bootstrap' => array(
-        'description' => t("Boolean indicating whether this module is loaded during Drupal's early bootstrapping phase (e.g. even before the page cache is consulted)."),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'schema_version' => array(
-        'description' => t("The module's database schema version number. -1 if the module is not installed (its tables do not exist); 0 or the largest N of the module's hook_update_N() function that has either been run or existed when the module was first installed."),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => -1,
-        'size' => 'small'),
-      'weight' => array(
-        'description' => t("The order in which this module's hooks should be invoked relative to other modules. Equal-weighted modules are ordered by name."),
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0),
-      'info' => array(
-        'description' => t("A serialized array containing information from the module's .info file; keys can include name, description, package, version, core, dependencies, dependents, and php."),
-        'type' => 'text',
-        'not null' => FALSE)
-      ),
-    'primary key' => array('filename'),
-    'indexes' =>
-      array(
-        'modules' => array(array('type', 12), 'status', 'weight', 'filename'),
-        'bootstrap' => array(array('type', 12), 'status', 'bootstrap', 'weight', 'filename'),
-      ),
+  foreach (list_themes() as $theme) {
+    $items['admin/build/themes/settings/'. $theme->name] = array(
+      'title' => $theme->info['name'],
+      'page arguments' => array('system_theme_settings', $theme->name),
+      'type' => MENU_LOCAL_TASK,
+      'access callback' => '_system_themes_access',
+      'access arguments' => array($theme),
     );
+  }
 
-  $schema['url_alias'] = array(
-    'description' => t('A list of URL aliases for Drupal paths; a user may visit either the source or destination path.'),
-    'fields' => array(
-      'pid' => array(
-        'description' => t('A unique path alias identifier.'),
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE),
-      'src' => array(
-        'description' => t('The Drupal path this alias is for; e.g. node/12.'),
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => ''),
-      'dst' => array(
-        'description' => t('The alias for this path; e.g. title-of-the-story.'),
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => ''),
-      'language' => array(
-        'description' => t('The language this alias is for; if blank, the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.'),
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '')
-      ),
-    'unique keys' => array('dst_language' => array('dst', 'language')),
-    'primary key' => array('pid'),
-    'indexes' => array('src' => array('src')),
-    );
+  // Modules:
+  $items['admin/build/modules'] = array(
+    'title' => 'Modules',
+    'description' => 'Enable or disable add-on modules for your site.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_modules'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/build/modules/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  $items['admin/build/modules/list/confirm'] = array(
+    'title' => 'List',
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/build/modules/uninstall'] = array(
+    'title' => 'Uninstall',
+    'page arguments' => array('system_modules_uninstall'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['admin/build/modules/uninstall/confirm'] = array(
+    'title' => 'Uninstall',
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+  );
 
-  return $schema;
-}
+  // Actions:
+  $items['admin/settings/actions'] = array(
+    'title' => 'Actions',
+    'description' => 'Manage the actions defined for your site.',
+    'access arguments' => array('administer actions'),
+    'page callback' => 'system_actions_manage'
+  );
+  $items['admin/settings/actions/manage'] = array(
+    'title' => 'Manage actions',
+    'description' => 'Manage the actions defined for your site.',
+    'page callback' => 'system_actions_manage',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -2,
+  );
+  $items['admin/settings/actions/configure'] = array(
+    'title' => 'Configure an advanced action',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_actions_configure'),
+    'access arguments' => array('administer actions'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/settings/actions/delete/%actions'] = array(
+    'title' => 'Delete action',
+    'description' => 'Delete an action.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_actions_delete_form', 4),
+    'access arguments' => array('administer actions'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/settings/actions/orphan'] = array(
+    'title' => 'Remove orphans',
+    'page callback' => 'system_actions_remove_orphans',
+    'access arguments' => array('administer actions'),
+    'type' => MENU_CALLBACK,
+  );
 
-// Updates for core.
+  // Settings:
+  $items['admin/settings/site-information'] = array(
+    'title' => 'Site information',
+    'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_site_information_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/error-reporting'] = array(
+    'title' => 'Error reporting',
+    'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_error_reporting_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/logging'] = array(
+    'title' => 'Logging and alerts',
+    'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destination, such as syslog, database, email, ...etc.",
+    'page callback' => 'system_logging_overview',
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/performance'] = array(
+    'title' => 'Performance',
+    'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_performance_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/file-system'] = array(
+    'title' => 'File system',
+    'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_file_system_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/image-toolkit'] = array(
+    'title' => 'Image toolkit',
+    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_image_toolkit_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/content/rss-publishing'] = array(
+    'title' => 'RSS publishing',
+    'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_rss_feeds_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/date-time'] = array(
+    'title' => 'Date and time',
+    'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.",
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_date_time_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/date-time/lookup'] = array(
+    'title' => 'Date and time lookup',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'system_date_time_lookup',
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/site-maintenance'] = array(
+    'title' => 'Site maintenance',
+    'description' => 'Take the site off-line for maintenance or bring it back online.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_site_maintenance_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/clean-urls'] = array(
+    'title' => 'Clean URLs',
+    'description' => 'Enable or disable clean URLs for your site.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_clean_url_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/settings/clean-urls/check'] = array(
+    'title' => 'Clean URL check',
+    'page callback' => 'drupal_json',
+    'page arguments' => array(array('status' => TRUE)),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  // Menu handler to test that drupal_http_request() works locally.
+  // @see system_check_http_request()
+  $items['admin/reports/request-test'] = array(
+    'title' => 'Request test',
+    'page callback' => 'printf',
+    'page arguments' => array('request test'),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
 
-function system_update_last_removed() {
-  return 1021;
+  // Reports:
+  $items['admin/reports'] = array(
+    'title' => 'Reports',
+    'description' => 'View reports from system logs and other status information.',
+    'page callback' => 'system_admin_menu_block_page',
+    'access arguments' => array('access site reports'),
+    'weight' => 5,
+    'position' => 'left',
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/reports/status'] = array(
+    'title' => 'Status report',
+    'description' => "Get a status report about your site's operation and any detected problems.",
+    'page callback' => 'system_status',
+    'weight' => 10,
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/reports/status/run-cron'] = array(
+    'title' => 'Run cron',
+    'page callback' => 'system_run_cron',
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/reports/status/php'] = array(
+    'title' => 'PHP',
+    'page callback' => 'system_php',
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/reports/status/sql'] = array(
+    'title' => 'SQL',
+    'page callback' => 'system_sql',
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
+  // Default page for batch operations
+  $items['batch'] = array(
+    'page callback' => 'system_batch_page',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
+  return $items;
 }
 
 /**
- * @defgroup updates-5.x-extra Extra system updates for 5.x
- * @{
+ * Menu item access callback - only admin or enabled themes can be accessed.
  */
-
-/**
- * Add index on users created column.
- */
-function system_update_1022() {
-  $ret = array();
-  db_add_index($ret, 'users', 'created', array('created'));
-  // Also appears as system_update_6004(). Ensure we don't update twice.
-  variable_set('system_update_1022', TRUE);
-  return $ret;
+function _system_themes_access($theme) {
+  return user_access('administer site configuration') && ($theme->status || $theme->name == variable_get('admin_theme', '0'));
 }
 
 /**
- * @} End of "defgroup updates-5.x-extra"
+ * Implementation of hook_init().
  */
-
-/**
- * @defgroup updates-5.x-to-6.x System updates from 5.x to 6.x
- * @{
- */
-
-/**
- * Remove auto_increment from {boxes} to allow adding custom blocks with
- * visibility settings.
- */
-function system_update_6000() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      $max = (int)db_result(db_query('SELECT MAX(bid) FROM {boxes}'));
-      $ret[] = update_sql('ALTER TABLE {boxes} CHANGE COLUMN bid bid int NOT NULL');
-      $ret[] = update_sql("REPLACE INTO {sequences} VALUES ('{boxes}_bid', $max)");
-      break;
+function system_init() {
+  // Use the administrative theme if the user is looking at a page in the admin/* path.
+  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
+    global $custom_theme;
+    $custom_theme = variable_get('admin_theme', '0');
+    drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module');
   }
-  return $ret;
+
+  // Add the CSS for this module.
+  drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module');
+  drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module');
+  drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
 }
 
 /**
- * Add version id column to {term_node} to allow taxonomy module to use revisions.
+ * Implementation of hook_user().
+ *
+ * Allows users to individually set their theme and time zone.
  */
-function system_update_6001() {
-  $ret = array();
-
-  // Add vid to term-node relation.  The schema says it is unsigned.
-  db_add_field($ret, 'term_node', 'vid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
-  db_drop_primary_key($ret, 'term_node');
-  db_add_primary_key($ret, 'term_node', array('vid', 'tid', 'nid'));
-  db_add_index($ret, 'term_node', 'vid', array('vid'));
+function system_user($type, $edit, &$user, $category = NULL) {
+  if ($type == 'form' && $category == 'account') {
+    $form['theme_select'] = system_theme_select_form(t('Selecting a different theme will change the look and feel of the site.'), isset($edit['theme']) ? $edit['theme'] : NULL, 2);
+
+    if (variable_get('configurable_timezones', 1)) {
+      $zones = _system_zonelist();
+      $form['timezone'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Locale settings'),
+        '#weight' => 6,
+        '#collapsible' => TRUE,
+      );
+      $form['timezone']['timezone'] = array(
+        '#type' => 'select',
+        '#title' => t('Time zone'),
+        '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', 0),
+        '#options' => $zones,
+        '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'),
+      );
+    }
 
-  db_query('UPDATE {term_node} t SET vid = (SELECT vid FROM {node} n WHERE t.nid = n.nid)');
-  return $ret;
+    return $form;
+  }
 }
 
 /**
- * Increase the maximum length of variable names from 48 to 128.
+ * Implementation of hook_block().
+ *
+ * Generate a block with a promotional link to Drupal.org.
  */
-function system_update_6002() {
-  $ret = array();
-  db_drop_primary_key($ret, 'variable');
-  db_change_field($ret, 'variable', 'name', 'name', array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
-  db_add_primary_key($ret, 'variable', array('name'));
-  return $ret;
+function system_block($op = 'list', $delta = 0, $edit = NULL) {
+  switch ($op) {
+    case 'list':
+      $blocks[0] = array(
+        'info' => t('Powered by Drupal'),
+        'weight' => '10',
+         // Not worth caching.
+        'cache' => BLOCK_NO_CACHE,
+      );
+      return $blocks;
+    case 'configure':
+      // Compile a list of fields to show
+      $form['wrapper']['color'] = array(
+        '#type' => 'select',
+        '#title' => t('Badge color'),
+        '#default_value' => variable_get('drupal_badge_color', 'powered-blue'),
+        '#options' => array('powered-black' => t('Black'), 'powered-blue' => t('Blue'), 'powered-gray' => t('Gray')),
+      );
+      $form['wrapper']['size'] = array(
+        '#type' => 'select',
+        '#title' => t('Badge size'),
+        '#default_value' => variable_get('drupal_badge_size', '80x15'),
+        '#options' => array('80x15' => t('Small'), '88x31' => t('Medium'), '135x42' => t('Large')),
+      );
+      return $form;
+    case 'save':
+      variable_set('drupal_badge_color', $edit['color']);
+      variable_set('drupal_badge_size', $edit['size']);
+      break;
+    case 'view':
+      $image_path = 'misc/'. variable_get('drupal_badge_color', 'powered-blue') .'-'. variable_get('drupal_badge_size', '80x15') .'.png';
+      $block['subject'] = NULL; // Don't display a title
+      $block['content'] = theme('system_powered_by', $image_path);
+      return $block;
+  }
 }
 
 /**
- * Add index on comments status column.
+ * Provide a single block on the administration overview page.
+ *
+ * @param $item
+ *   The menu item to be displayed.
  */
-function system_update_6003() {
-  $ret = array();
-  db_add_index($ret, 'comments', 'status', array('status'));
-  return $ret;
+function system_admin_menu_block($item) {
+  $content = array();
+  if (!isset($item['mlid'])) {
+    $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path']));
+  }
+  $result = db_query("
+    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.*
+    FROM {menu_links} ml
+    LEFT JOIN {menu_router} m ON ml.router_path = m.path
+    WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']);
+  while ($item = db_fetch_array($result)) {
+    _menu_link_translate($item);
+    if (!$item['access']) {
+      continue;
+    }
+    // The link 'description' either derived from the hook_menu 'description' or
+    // entered by the user via menu module is saved as the title attribute.
+    if (!empty($item['localized_options']['attributes']['title'])) {
+      $item['description'] = $item['localized_options']['attributes']['title'];
+    }
+    // Prepare for sorting as in function _menu_tree_check_access().
+    // The weight is offset so it is always positive, with a uniform 5-digits.
+    $content[(50000 + $item['weight']) .' '. $item['title'] .' '. $item['mlid']] = $item;
+  }
+  ksort($content);
+  return $content;
 }
 
 /**
- * This update used to add an index on users created column (#127941).
- * However, system_update_1022() does the same thing.  This update
- * tried to detect if 1022 had already run but failed to do so,
- * resulting in an "index already exists" error.
- *
- * Adding the index here is never necessary.  Sites installed before
- * 1022 will run 1022, getting the update.  Sites installed on/after 1022
- * got the index when the table was first created.  Therefore, this
- * function is now a no-op.
+ * Process admin theme form submissions.
  */
-function system_update_6004() {
-  return array();
+function system_admin_theme_submit($form, &$form_state) {
+  // If we're changing themes, make sure the theme has its blocks initialized.
+  if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
+    $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme']));
+    if (!$result) {
+      system_initialize_theme_blocks($form_state['values']['admin_theme']);
+    }
+  }
 }
 
 /**
- * Add language to url_alias table and modify indexes.
+ * Returns a fieldset containing the theme select form.
+ *
+ * @param $description
+ *    description of the fieldset
+ * @param $default_value
+ *    default value of theme radios
+ * @param $weight
+ *    weight of the fieldset
+ * @return
+ *    a form array
  */
-function system_update_6005() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'pgsql':
-      db_add_column($ret, 'url_alias', 'language', 'varchar(12)', array('default' => "''", 'not null' => TRUE));
+function system_theme_select_form($description = '', $default_value = '', $weight = 0) {
+  if (user_access('select different theme')) {
+    $enabled = array();
+    $themes = list_themes();
 
-      // As of system.install:1.85 (before the new language
-      // subsystem), new installs got a unique key named
-      // url_alias_dst_key on url_alias.dst.  Unfortunately,
-      // system_update_162 created a unique key inconsistently named
-      // url_alias_dst_idx on url_alias.dst (keys should have the _key
-      // suffix, indexes the _idx suffix).  Therefore, sites installed
-      // before system_update_162 have a unique key with a different
-      // name than sites installed after system_update_162().  Now, we
-      // want to drop the unique key on dst which may have either one
-      // of two names and create a new unique key on (dst, language).
-      // There is no way to know which key name exists so we have to
-      // drop both, causing an SQL error.  Thus, we just hide the
-      // error and only report the update_sql results that work.
-      $err = error_reporting(0);
-      $ret1 = update_sql('DROP INDEX {url_alias}_dst_idx');
-      if ($ret1['success']) {
-  $ret[] = $ret1;
+    foreach ($themes as $theme) {
+      if ($theme->status) {
+        $enabled[] = $theme;
       }
-      $ret1 = array();
-      db_drop_unique_key($ret, 'url_alias', 'dst');
-      foreach ($ret1 as $r) {
-  if ($r['success']) {
-    $ret[] = $r;
-  }
+    }
+
+    if (count($enabled) > 1) {
+      ksort($enabled);
+
+      $form['themes'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Theme configuration'),
+        '#description' => $description,
+        '#collapsible' => TRUE,
+        '#theme' => 'system_theme_select_form'
+      );
+
+      foreach ($enabled as $info) {
+        // For the default theme, revert to an empty string so the user's theme updates when the site theme is changed.
+        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
+
+        $screenshot = NULL;
+        $theme_key = $info->name;
+        while ($theme_key) {
+          if (file_exists($themes[$theme_key]->info['screenshot'])) {
+            $screenshot = $themes[$theme_key]->info['screenshot'];
+            break;
+          }
+          $theme_key = isset($themes[$theme_key]->info['base theme']) ? $themes[$theme_key]->info['base theme'] : NULL;
+        }
+
+        $screenshot = $screenshot ? theme('image', $screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot');
+
+        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
+        $form['themes'][$info->key]['description'] = array('#type' => 'item', '#title' => $info->name, '#value' => dirname($info->filename) . ($info->name == variable_get('theme_default', 'garland') ? '<br /> <em>'. t('(site default theme)') .'</em>' : ''));
+        $options[$info->key] = '';
       }
-      error_reporting($err);
 
-      $ret[] = update_sql('CREATE UNIQUE INDEX {url_alias}_dst_language_idx ON {url_alias}(dst, language)');
-      break;
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("ALTER TABLE {url_alias} ADD language varchar(12) NOT NULL default ''");
-      $ret[] = update_sql("ALTER TABLE {url_alias} DROP INDEX dst");
-      $ret[] = update_sql("ALTER TABLE {url_alias} ADD UNIQUE dst_language (dst, language)");
-      break;
+      $form['themes']['theme'] = array('#type' => 'radios', '#options' => $options, '#default_value' => $default_value ? $default_value : '');
+      $form['#weight'] = $weight;
+      return $form;
+    }
   }
-  return $ret;
 }
 
 /**
- * Drop useless indices on node_counter table.
+ * Checks the existence of the directory specified in $form_element. This
+ * function is called from the system_settings form to check both the
+ * file_directory_path and file_directory_temp directories. If validation
+ * fails, the form element is flagged with an error from within the
+ * file_check_directory function.
+ *
+ * @param $form_element
+ *   The form element containing the name of the directory to check.
  */
-function system_update_6006() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'pgsql':
-      $ret[] = update_sql('DROP INDEX {node_counter}_daycount_idx');
-      $ret[] = update_sql('DROP INDEX {node_counter}_totalcount_idx');
-      $ret[] = update_sql('DROP INDEX {node_counter}_timestamp_idx');
-      break;
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("ALTER TABLE {node_counter} DROP INDEX daycount");
-      $ret[] = update_sql("ALTER TABLE {node_counter} DROP INDEX totalcount");
-      $ret[] = update_sql("ALTER TABLE {node_counter} DROP INDEX timestamp");
-      break;
+function system_check_directory($form_element) {
+  file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
+  return $form_element;
+}
+
+/**
+ * Retrieves the current status of an array of files in the system table.
+ *
+ * @param $files
+ *   An array of files to check.
+ * @param $type
+ *   The type of the files.
+ */
+function system_get_files_database(&$files, $type) {
+  // Extract current files from database.
+  $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type);
+  while ($file = db_fetch_object($result)) {
+    if (isset($files[$file->name]) && is_object($files[$file->name])) {
+      $file->old_filename = $file->filename;
+      foreach ($file as $key => $value) {
+        if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) {
+          $files[$file->name]->$key = $value;
+        }
+      }
+    }
   }
-  return $ret;
 }
 
 /**
- * Change the severity column in the watchdog table to the new values.
+ * Prepare defaults for themes.
+ *
+ * @return
+ *   An array of default themes settings.
  */
-function system_update_6007() {
-  $ret = array();
-  $ret[] = update_sql("UPDATE {watchdog} SET severity = ". WATCHDOG_NOTICE ." WHERE severity = 0");
-  $ret[] = update_sql("UPDATE {watchdog} SET severity = ". WATCHDOG_WARNING ." WHERE severity = 1");
-  $ret[] = update_sql("UPDATE {watchdog} SET severity = ". WATCHDOG_ERROR ." WHERE severity = 2");
-  return $ret;
+function system_theme_default() {
+  return array(
+    'regions' => array(
+      'left' => 'Left sidebar',
+      'right' => 'Right sidebar',
+      'content' => 'Content',
+      'header' => 'Header',
+      'footer' => 'Footer',
+    ),
+    'description' => '',
+    'features' => array(
+      'comment_user_picture',
+      'favicon',
+      'mission',
+      'logo',
+      'name',
+      'node_user_picture',
+      'search',
+      'slogan',
+      'primary_links',
+      'secondary_links',
+    ),
+    'stylesheets' => array(
+      'all' => array('style.css')
+    ),
+    'scripts' => array('script.js'),
+    'screenshot' => 'screenshot.png',
+    'php' => DRUPAL_MINIMUM_PHP,
+  );
 }
 
 /**
- * Add info files to themes.  The info and owner columns are added by
- * update_fix_d6_requirements() in update.php to avoid a large number
- * of error messages from update.php.  All we need to do here is copy
- * description to owner and then drop description.
+ * Collect data about all currently available themes.
+ *
+ * @return
+ *   Array of all available themes and their data.
  */
-function system_update_6008() {
-  $ret = array();
-  $ret[] = update_sql('UPDATE {system} SET owner = description');
-  db_drop_field($ret, 'system', 'description');
+function system_theme_data() {
+  // Scan the installation theme .info files and their engines.
+  $themes = _system_theme_data();
 
-  // Rebuild system table contents.
-  module_rebuild_cache();
-  system_theme_data();
+  // Extract current files from database.
+  system_get_files_database($themes, 'theme');
 
-  return $ret;
+  db_query("DELETE FROM {system} WHERE type = 'theme'");
+
+  foreach ($themes as $theme) {
+    if (!isset($theme->owner)) {
+      $theme->owner = '';
+    }
+
+    db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
+  }
+
+  return $themes;
 }
 
 /**
- * The PHP filter is now a separate module.
+ * Helper function to scan and collect theme .info data and their engines.
+ *
+ * @return
+ *   An associative array of themes information.
  */
-function system_update_6009() {
-  $ret = array();
+function _system_theme_data() {
+  static $themes_info = array();
+
+  if (empty($theme_info)) {
+    // Find themes
+    $themes = drupal_system_listing('\.info$', 'themes');
+    // Find theme engines
+    $engines = drupal_system_listing('\.engine$', 'themes/engines');
+
+    $defaults = system_theme_default();
+
+    $sub_themes = array();
+    // Read info files for each theme
+    foreach ($themes as $key => $theme) {
+      $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults;
+
+      // Invoke hook_system_info_alter() to give installed modules a chance to
+      // modify the data in the .info files if necessary.
+      drupal_alter('system_info', $themes[$key]->info, $themes[$key]);
+
+      if (!empty($themes[$key]->info['base theme'])) {
+        $sub_themes[] = $key;
+      }
+      if (empty($themes[$key]->info['engine'])) {
+        $filename = dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.theme';
+        if (file_exists($filename)) {
+          $themes[$key]->owner = $filename;
+          $themes[$key]->prefix = $key;
+        }
+      }
+      else {
+        $engine = $themes[$key]->info['engine'];
+        if (isset($engines[$engine])) {
+          $themes[$key]->owner = $engines[$engine]->filename;
+          $themes[$key]->prefix = $engines[$engine]->name;
+          $themes[$key]->template = TRUE;
+        }
+      }
+
+      // Give the stylesheets proper path information.
+      $pathed_stylesheets = array();
+      foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) {
+        foreach ($stylesheets as $stylesheet) {
+          $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filename) .'/'. $stylesheet;
+        }
+      }
+      $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
+
+      // Give the scripts proper path information.
+      $scripts = array();
+      foreach ($themes[$key]->info['scripts'] as $script) {
+        $scripts[$script] = dirname($themes[$key]->filename) .'/'. $script;
+      }
+      $themes[$key]->info['scripts'] = $scripts;
+      // Give the screenshot proper path information.
+      if (!empty($themes[$key]->info['screenshot'])) {
+        $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['screenshot'];
+      }
+    }
+
+    // Now that we've established all our master themes, go back and fill in
+    // data for subthemes.
+    foreach ($sub_themes as $key) {
+      $base_key = system_find_base_theme($themes, $key);
+      if (!$base_key) {
+        continue;
+      }
+      // Copy the 'owner' and 'engine' over if the top level theme uses a
+      // theme engine.
+      if (isset($themes[$base_key]->owner)) {
+        if (isset($themes[$base_key]->info['engine'])) {
+          $themes[$key]->info['engine'] = $themes[$base_key]->info['engine'];
+          $themes[$key]->owner = $themes[$base_key]->owner;
+          $themes[$key]->prefix = $themes[$base_key]->prefix;
+        }
+        else {
+          $themes[$key]->prefix = $key;
+        }
+      }
+    }
 
-  // If any input format used the Drupal 5 PHP filter.
-  if (db_result(db_query("SELECT COUNT(format) FROM {filters} WHERE module = 'filter' AND delta = 1"))) {
-    // Enable the PHP filter module.
-    $ret[] = update_sql("UPDATE {system} SET status = 1 WHERE name = 'php' AND type = 'module'");
-    // Update the input filters.
-    $ret[] = update_sql("UPDATE {filters} SET delta = 0, module = 'php' WHERE module = 'filter' AND delta = 1");
+    $themes_info = $themes;
   }
 
-  // With the removal of the PHP evaluator filter, the deltas of the line break
-  // and URL filter have changed.
-  $ret[] = update_sql("UPDATE {filters} SET delta = 1 WHERE module = 'filter' AND delta = 2");
-  $ret[] = update_sql("UPDATE {filters} SET delta = 2 WHERE module = 'filter' AND delta = 3");
-
-  return $ret;
+  return $themes_info;
 }
 
 /**
- * Add variable replacement for watchdog messages.
+ * Recursive function to find the top level base theme. Themes can inherit
+ * templates and function implementations from earlier themes.
  *
- * The variables field is NOT NULL and does not have a default value.
- * Existing log messages should not be translated in the new system,
- * so we insert 'N;' (serialize(NULL)) as the temporary default but
- * then remove the default value to match the schema.
- */
-function system_update_6010() {
-  $ret = array();
-  db_add_field($ret, 'watchdog', 'variables', array('type' => 'text', 'size' => 'big', 'not null' => TRUE, 'initial' => 'N;'));
-  return $ret;
-}
-
-/**
- * Add language support to nodes
+ * @param $themes
+ *   An array of available themes.
+ * @param $key
+ *   The name of the theme whose base we are looking for.
+ * @param $used_keys
+ *   A recursion parameter preventing endless loops.
+ * @return
+ *   Returns the top level parent that has no ancestor or returns NULL if there isn't a valid parent.
  */
-function system_update_6011() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'pgsql':
-      db_add_column($ret, 'node', 'language', 'varchar(12)', array('default' => "''", 'not null' => TRUE));
-      break;
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("ALTER TABLE {node} ADD language varchar(12) NOT NULL default ''");
-      break;
+function system_find_base_theme($themes, $key, $used_keys = array()) {
+  $base_key = $themes[$key]->info['base theme'];
+  // Does the base theme exist?
+  if (!isset($themes[$base_key])) {
+    return NULL;
   }
-  return $ret;
-}
-
-/**
- * Add serialized field to cache tables.  This is now handled directly
- * by update.php, so this function is a no-op.
- */
-function system_update_6012() {
-  return array();
-}
-
-/**
- * Rebuild cache data for theme system changes
- */
-function system_update_6013() {
-  // Rebuild system table contents.
-  module_rebuild_cache();
-  system_theme_data();
-
-  return array(array('success' => TRUE, 'query' => 'Cache rebuilt.'));
-}
-
-/**
- * Record that the installer is done, so it is not
- * possible to run the installer on upgraded sites.
- */
-function system_update_6014() {
-  variable_set('install_task', 'done');
 
-  return array(array('success' => TRUE, 'query' => "variable_set('install_task')"));
+  // Is the base theme itself a child of another theme?
+  if (isset($themes[$base_key]->info['base theme'])) {
+    // Prevent loops.
+    if (!empty($used_keys[$base_key])) {
+      return NULL;
+    }
+    $used_keys[$base_key] = TRUE;
+    return system_find_base_theme($themes, $base_key, $used_keys);
+  }
+  // If we get here, then this is our parent theme.
+  return $base_key;
 }
 
 /**
- * Add the form cache table.
+ * Get a list of available regions from a specified theme.
+ *
+ * @param $theme_key
+ *   The name of a theme.
+ * @return
+ *   An array of regions in the form $region['name'] = 'description'.
  */
-function system_update_6015() {
-  $ret = array();
+function system_region_list($theme_key) {
+  static $list = array();
 
-  switch ($GLOBALS['db_type']) {
-    case 'pgsql':
-      $ret[] = update_sql("CREATE TABLE {cache_form} (
-        cid varchar(255) NOT NULL default '',
-        data bytea,
-        expire int NOT NULL default '0',
-        created int NOT NULL default '0',
-        headers text,
-        serialized smallint NOT NULL default '0',
-        PRIMARY KEY (cid)
-    )");
-      $ret[] = update_sql("CREATE INDEX {cache_form}_expire_idx ON {cache_form} (expire)");
-      break;
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("CREATE TABLE {cache_form} (
-        cid varchar(255) NOT NULL default '',
-        data longblob,
-        expire int NOT NULL default '0',
-        created int NOT NULL default '0',
-        headers text,
-        serialized int(1) NOT NULL default '0',
-        PRIMARY KEY (cid),
-        INDEX expire (expire)
-      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
-      break;
+  if (!array_key_exists($theme_key, $list)) {
+    $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)));
+    $list[$theme_key] = array_map('t', $info['regions']);
   }
 
-  return $ret;
+  return $list[$theme_key];
 }
 
 /**
- * Make {node}'s primary key be nid, change nid,vid to a unique key.
- * Add primary keys to block, filters, flood, permission, and term_relation.
+ * Get the name of the default region for a given theme.
+ *
+ * @param $theme
+ *   The name of a theme.
+ * @return
+ *   A string that is the region name.
  */
-function system_update_6016() {
-  $ret = array();
-
-  switch ($GLOBALS['db_type']) {
-    case 'pgsql':
-      $ret[] = update_sql("ALTER TABLE {node} ADD CONSTRAINT {node}_nid_vid_key UNIQUE (nid, vid)");
-      db_add_column($ret, 'blocks', 'bid', 'serial');
-      $ret[] = update_sql("ALTER TABLE {blocks} ADD PRIMARY KEY (bid)");
-      db_add_column($ret, 'filters', 'fid', 'serial');
-      $ret[] = update_sql("ALTER TABLE {filters} ADD PRIMARY KEY (fid)");
-      db_add_column($ret, 'flood', 'fid', 'serial');
-      $ret[] = update_sql("ALTER TABLE {flood} ADD PRIMARY KEY (fid)");
-      db_add_column($ret, 'permission', 'pid', 'serial');
-      $ret[] = update_sql("ALTER TABLE {permission} ADD PRIMARY KEY (pid)");
-      db_add_column($ret, 'term_relation', 'trid', 'serial');
-      $ret[] = update_sql("ALTER TABLE {term_relation} ADD PRIMARY KEY (trid)");
-      db_add_column($ret, 'term_synonym', 'tsid', 'serial');
-      $ret[] = update_sql("ALTER TABLE {term_synonym} ADD PRIMARY KEY (tsid)");
-      break;
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql('ALTER TABLE {node} ADD UNIQUE KEY nid_vid (nid, vid)');
-      $ret[] = update_sql("ALTER TABLE {blocks} ADD bid int NOT NULL AUTO_INCREMENT PRIMARY KEY");
-      $ret[] = update_sql("ALTER TABLE {filters} ADD fid int NOT NULL AUTO_INCREMENT PRIMARY KEY");
-      $ret[] = update_sql("ALTER TABLE {flood} ADD fid int NOT NULL AUTO_INCREMENT PRIMARY KEY");
-      $ret[] = update_sql("ALTER TABLE {permission} ADD pid int NOT NULL AUTO_INCREMENT PRIMARY KEY");
-      $ret[] = update_sql("ALTER TABLE {term_relation} ADD trid int NOT NULL AUTO_INCREMENT PRIMARY KEY");
-      $ret[] = update_sql("ALTER TABLE {term_synonym} ADD tsid int NOT NULL AUTO_INCREMENT PRIMARY KEY");
-      break;
-  }
-
-  return $ret;
+function system_default_region($theme) {
+  $regions = array_keys(system_region_list($theme));
+  return isset($regions[0]) ? $regions[0] : '';
 }
 
 /**
- * Rename settings related to user.module email notifications.
+ * Assign an initial, default set of blocks for a theme.
+ *
+ * This function is called the first time a new theme is enabled. The new theme
+ * gets a copy of the default theme's blocks, with the difference that if a
+ * particular region isn't available in the new theme, the block is assigned
+ * to the new theme's default region.
+ *
+ * @param $theme
+ *   The name of a theme.
  */
-function system_update_6017() {
-  $ret = array();
-  // Maps old names to new ones.
-  $var_names = array(
-    'admin'    => 'register_admin_created',
-    'approval' => 'register_pending_approval',
-    'welcome'  => 'register_no_approval_required',
-    'pass'     => 'password_reset',
-  );
-  foreach ($var_names as $old => $new) {
-    foreach (array('_subject', '_body') as $suffix) {
-      $old_name = 'user_mail_'. $old . $suffix;
-      $new_name = 'user_mail_'. $new . $suffix;
-      if ($old_val = variable_get($old_name, FALSE)) {
-        variable_set($new_name, $old_val);
-        variable_del($old_name);
-        $ret[] = array('success' => TRUE, 'query' => "variable_set($new_name)");
-        $ret[] = array('success' => TRUE, 'query' => "variable_del($old_name)");
-        if ($old_name == 'user_mail_approval_body') {
-          drupal_set_message('Saving an old value of the welcome message body for users that are pending administrator approval. However, you should consider modifying this text, since Drupal can now be configured to automatically notify users and send them their login information when their accounts are approved. See the <a href="'. url('admin/user/settings') .'">User settings</a> page for details.');
-        }
+function system_initialize_theme_blocks($theme) {
+  // Initialize theme's blocks if none already registered.
+  if (!(db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $theme)))) {
+    $default_theme = variable_get('theme_default', 'garland');
+    $regions = system_region_list($theme);
+    $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme);
+    while ($block = db_fetch_array($result)) {
+      // If the region isn't supported by the theme, assign the block to the theme's default region.
+      if (!array_key_exists($block['region'], $regions)) {
+        $block['region'] = system_default_region($theme);
       }
+      db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, %d)",
+          $block['module'], $block['delta'], $theme, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle'], $block['cache']);
     }
   }
-  return $ret;
 }
 
 /**
- * Add HTML corrector to HTML formats or replace the old module if it was in use.
+ * Add default buttons to a form and set its prefix.
+ *
+ * @ingroup forms
+ * @see system_settings_form_submit()
+ * @param $form
+ *   An associative array containing the structure of the form.
+ * @return
+ *   The form structure.
  */
-function system_update_6018() {
-  $ret = array();
-
-  // Disable htmlcorrector.module, if it exists and replace its filter.
-  if (module_exists('htmlcorrector')) {
-    module_disable(array('htmlcorrector'));
-    $ret[] = update_sql("UPDATE {filter_formats} SET module = 'filter', delta = 3 WHERE module = 'htmlcorrector'");
-    $ret[] = array('success' => TRUE, 'query' => 'HTML Corrector module was disabled; this functionality has now been added to core.');
-    return $ret;
-  }
+function system_settings_form($form) {
+  $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') );
+  $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') );
 
-  // Otherwise, find any format with 'HTML' in its name and add the filter at the end.
-  $result = db_query("SELECT format, name FROM {filter_formats} WHERE name LIKE '%HTML%'");
-  while ($format = db_fetch_object($result)) {
-    $weight = db_result(db_query("SELECT MAX(weight) FROM {filters} WHERE format = %d", $format->format));
-    db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", $format->format, 'filter', 3, max(10, $weight + 1));
-    $ret[] = array('success' => TRUE, 'query' => "HTML corrector filter added to the '". $format->name ."' input format.");
+  if (!empty($_POST) && form_get_errors()) {
+    drupal_set_message(t('The settings have not been saved because of the errors.'), 'error');
   }
-
-  return $ret;
+  $form['#submit'][] = 'system_settings_form_submit';
+  $form['#theme'] = 'system_settings_form';
+  return $form;
 }
 
 /**
- * Reconcile small differences in the previous, manually created mysql
- * and pgsql schemas so they are the same and can be represented by a
- * single schema structure.
+ * Execute the system_settings_form.
  *
- * Note that the mysql and pgsql cases make different changes.  This
- * is because each schema needs to be tweaked in different ways to
- * conform to the new schema structure.  Also, since they operate on
- * tables defined by many optional core modules which may not ever
- * have been installed, they must test each table for existence.  If
- * the modules are first installed after this update exists the tables
- * will be created from the schema structure and will start out
- * correct.
+ * If you want node type configure style handling of your checkboxes,
+ * add an array_filter value to your form.
  */
-function system_update_6019() {
-  $ret = array();
-
-  switch ($GLOBALS['db_type']) {
-    case 'pgsql':
-      // Remove default ''.
-      if (db_table_exists('aggregator_feed')) {
-        db_field_set_no_default($ret, 'aggregator_feed', 'description');
-        db_field_set_no_default($ret, 'aggregator_feed', 'image');
-      }
-      db_field_set_no_default($ret, 'blocks', 'pages');
-      if (db_table_exists('contact')) {
-        db_field_set_no_default($ret, 'contact', 'recipients');
-        db_field_set_no_default($ret, 'contact', 'reply');
-      }
-      db_field_set_no_default($ret, 'watchdog', 'location');
-      db_field_set_no_default($ret, 'node_revisions', 'body');
-      db_field_set_no_default($ret, 'node_revisions', 'teaser');
-      db_field_set_no_default($ret, 'node_revisions', 'log');
-
-      // Update from pgsql 'float' (which means 'double precision') to
-      // schema 'float' (which in pgsql means 'real').
-      if (db_table_exists('search_index')) {
-        db_change_field($ret, 'search_index', 'score', 'score', array('type' => 'float'));
-      }
-      if (db_table_exists('search_total')) {
-        db_change_field($ret, 'search_total', 'count', 'count', array('type' => 'float'));
-      }
+function system_settings_form_submit($form, &$form_state) {
+  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
 
-      // Replace unique index dst_language with a unique constraint.  The
-      // result is the same but the unique key fits our current schema
-      // structure.  Also, the postgres documentation implies that
-      // unique constraints are preferable to unique indexes.  See
-      // http://www.postgresql.org/docs/8.2/interactive/indexes-unique.html.
-      if (db_table_exists('url_alias')) {
-        db_drop_index($ret, 'url_alias', 'dst_language');
-        db_add_unique_key($ret, 'url_alias', 'dst_language',
-          array('dst', 'language'));
-      }
-
-      // Fix term_node pkey: mysql and pgsql code had different orders.
-      if (db_table_exists('term_node')) {
-        db_drop_primary_key($ret, 'term_node');
-        db_add_primary_key($ret, 'term_node', array('vid', 'tid', 'nid'));
-      }
-
-      // Make boxes.bid unsigned.
-      db_drop_primary_key($ret, 'boxes');
-      db_change_field($ret, 'boxes', 'bid', 'bid', array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), array('primary key' => array('bid')));
+  // Exclude unnecessary elements.
+  unset($form_state['values']['submit'], $form_state['values']['reset'], $form_state['values']['form_id'], $form_state['values']['op'], $form_state['values']['form_token'], $form_state['values']['form_build_id']);
 
-      // Fix primary key
-      db_drop_primary_key($ret, 'node');
-      db_add_primary_key($ret, 'node', array('nid'));
-
-      break;
-
-    case 'mysql':
-    case 'mysqli':
-      // Rename key 'link' to 'url'.
-      if (db_table_exists('aggregator_feed')) {
-        db_drop_unique_key($ret, 'aggregator_feed', 'link');
-        db_add_unique_key($ret, 'aggregator_feed', 'url', array('url'));
-      }
-
-      // Change to size => small.
-      if (db_table_exists('boxes')) {
-        db_change_field($ret, 'boxes', 'format', 'format', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0));
-      }
-
-      // Change to size => small.
-      // Rename index 'lid' to 'nid'.
-      if (db_table_exists('comments')) {
-        db_change_field($ret, 'comments', 'format', 'format', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0));
-        db_drop_index($ret, 'comments', 'lid');
-        db_add_index($ret, 'comments', 'nid', array('nid'));
-      }
-
-      // Change to size => small.
-      db_change_field($ret, 'cache', 'serialized', 'serialized', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0));
-      db_change_field($ret, 'cache_filter', 'serialized', 'serialized', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0));
-      db_change_field($ret, 'cache_page', 'serialized', 'serialized', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0));
-      db_change_field($ret, 'cache_form', 'serialized', 'serialized', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0));
-
-      // Remove default => 0, set auto increment.
-      $new_uid = 1 + db_result(db_query('SELECT MAX(uid) FROM {users}'));
-      $ret[] = update_sql('UPDATE {users} SET uid = '. $new_uid .' WHERE uid = 0');
-      db_drop_primary_key($ret, 'users');
-      db_change_field($ret, 'users', 'uid', 'uid', array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), array('primary key' => array('uid')));
-      $ret[] = update_sql('UPDATE {users} SET uid = 0 WHERE uid = '. $new_uid);
-
-      // Special field names.
-      $map = array('node_revisions' => 'vid');
-      // Make sure these tables have proper auto_increment fields.
-      foreach (array('boxes', 'files', 'node', 'node_revisions') as $table) {
-        $field = isset($map[$table]) ? $map[$table] : $table[0] .'id';
-        db_drop_primary_key($ret, $table);
-        db_change_field($ret, $table, $field, $field, array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), array('primary key' => array($field)));
+  foreach ($form_state['values'] as $key => $value) {
+    if ($op == t('Reset to defaults')) {
+      variable_del($key);
+    }
+    else {
+      if (is_array($value) && isset($form_state['values']['array_filter'])) {
+        $value = array_keys(array_filter($value));
       }
-
-      break;
+      variable_set($key, $value);
+    }
+  }
+  if ($op == t('Reset to defaults')) {
+    drupal_set_message(t('The configuration options have been reset to their default values.'));
+  }
+  else {
+    drupal_set_message(t('The configuration options have been saved.'));
   }
 
-  return $ret;
+  cache_clear_all();
+  drupal_rebuild_theme_registry();
 }
 
 /**
- * Create the tables for the new menu system.
+ * Helper function to sort requirements.
  */
-function system_update_6020() {
-  $ret = array();
-
-  $schema['menu_router'] = array(
-    'fields' => array(
-      'path'             => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'load_functions'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'to_arg_functions' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'access_callback'  => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'access_arguments' => array('type' => 'text', 'not null' => FALSE),
-      'page_callback'    => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'page_arguments'   => array('type' => 'text', 'not null' => FALSE),
-      'fit'              => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'number_parts'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-      'tab_parent'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'tab_root'         => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'title'            => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'title_callback'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'title_arguments'  => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'type'             => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'block_callback'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'description'      => array('type' => 'text', 'not null' => TRUE),
-      'position'         => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'weight'           => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'file'             => array('type' => 'text', 'size' => 'medium')
-    ),
-    'indexes' => array(
-      'fit'        => array('fit'),
-      'tab_parent' => array('tab_parent')
-    ),
-    'primary key' => array('path'),
-  );
-
-  $schema['menu_links'] = array(
-    'fields' => array(
-      'menu_name'    => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
-      'mlid'         => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
-      'plid'         => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'link_path'    => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'router_path'  => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'link_title'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'options'      => array('type' => 'text', 'not null' => FALSE),
-      'module'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'system'),
-      'hidden'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-      'external'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-      'has_children' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-      'expanded'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-      'weight'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'depth'        => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-      'customized'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-      'p1'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p2'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p3'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p4'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p5'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p6'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p7'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p8'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'p9'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'updated'      => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
-    ),
-    'indexes' => array(
-      'path_menu'              => array(array('link_path', 128), 'menu_name'),
-      'menu_plid_expand_child' => array('menu_name', 'plid', 'expanded', 'has_children'),
-      'menu_parents'           => array('menu_name', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'),
-      'router_path'            => array(array('router_path', 128)),
-    ),
-    'primary key' => array('mlid'),
-  );
-
-  foreach ($schema as $name => $table) {
-    db_create_table($ret, $name, $table);
+function _system_sort_requirements($a, $b) {
+  if (!isset($a['weight'])) {
+    if (!isset($b['weight'])) {
+      return strcmp($a['title'], $b['title']);
+    }
+    return -$b['weight'];
   }
-  return $ret;
+  return isset($b['weight']) ? $a['weight'] - $b['weight'] : $a['weight'];
 }
 
 /**
- * Migrate the menu items from the old menu system to the new menu_links table.
+ * Implementation of hook_node_type().
+ *
+ * Updates theme settings after a node type change.
  */
-function system_update_6021() {
-  $ret = array('#finished' => 0);
-  $menus = array(
-    'navigation' => array(
-      'menu_name' => 'navigation',
-      'title' => 'Navigation',
-      'description' => 'The navigation menu is provided by Drupal and is the main interactive menu for any site. It is usually the only menu that contains personalized links for authenticated users, and is often not even visible to anonymous users.',
-    ),
-    'primary-links' => array(
-      'menu_name' => 'primary-links',
-      'title' => 'Primary links',
-      'description' => 'Primary links are often used at the theme layer to show the major sections of a site. A typical representation for primary links would be tabs along the top.',
-    ),
-    'secondary-links' => array(
-      'menu_name' => 'secondary-links',
-      'title' => 'Secondary links',
-      'description' => 'Secondary links are often used for pages like legal notices, contact details, and other secondary navigation items that play a lesser role than primary links',
-    ),
-  );
-  // Multi-part update
-  if (!isset($_SESSION['system_update_6021'])) {
-    db_add_field($ret, 'menu', 'converted', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'));
-    $_SESSION['system_update_6021_max'] = db_result(db_query('SELECT COUNT(*) FROM {menu}'));
-    $_SESSION['menu_menu_map'] = array(1 => 'navigation');
-    // 0 => FALSE is for new menus, 1 => FALSE is for the navigation.
-    $_SESSION['menu_item_map'] = array(0 => FALSE, 1 => FALSE);
-    $table = array(
-      'fields' => array(
-        'menu_name'   => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
-        'title'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-        'description' => array('type' => 'text', 'not null' => FALSE),
-      ),
-      'primary key' => array('menu_name'),
-    );
-    db_create_table($ret, 'menu_custom', $table);
-    db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", $menus['navigation']);
-    $_SESSION['system_update_6021'] = 0;
-  }
-
-  $limit = 50;
-  while ($limit-- && ($item = db_fetch_array(db_query_range('SELECT * FROM {menu} WHERE converted = 0', 0, 1)))) {
-    // If it's not a menu...
-    if ($item['pid']) {
-      // Let's climb up until we find an item with a converted parent.
-      $item_original = $item;
-      while ($item && !isset($_SESSION['menu_item_map'][$item['pid']])) {
-        $item = db_fetch_array(db_query('SELECT * FROM {menu} WHERE mid = %d', $item['pid']));
-      }
-      // This can only occur if the menu entry is a leftover in the menu table.
-      // These do not appear in Drupal 5 anyways, so we skip them.
-      if (!$item) {
-        db_query('UPDATE {menu} SET converted = %d WHERE mid = %d', 1, $item_original['mid']);
-        $_SESSION['system_update_6021']++;
-        continue;
-      }
-    }
-    // We need to recheck because item might have changed.
-    if ($item['pid']) {
-      // Fill the new fields.
-      $item['link_title'] = $item['title'];
-      $item['link_path'] = drupal_get_normal_path($item['path']);
-      // We know the parent is already set. If it's not FALSE then it's an item.
-      if ($_SESSION['menu_item_map'][$item['pid']]) {
-        // The new menu system parent link id.
-        $item['plid'] = $_SESSION['menu_item_map'][$item['pid']]['mlid'];
-        // The new menu system menu name.
-        $item['menu_name'] = $_SESSION['menu_item_map'][$item['pid']]['menu_name'];
-      }
-      else {
-        // This a top level element.
-        $item['plid'] = 0;
-        // The menu name is stored among the menus.
-        $item['menu_name'] = $_SESSION['menu_menu_map'][$item['pid']];
-      }
-      // Is the element visible in the menu block?
-      $item['hidden'] = !($item['type'] & MENU_VISIBLE_IN_TREE);
-      // Is it a custom(ized) element?
-      if ($item['type'] & (MENU_CREATED_BY_ADMIN | MENU_MODIFIED_BY_ADMIN)) {
-        $item['customized'] = TRUE;
-      }
-      // Items created via the menu module need to be assigned to it.
-      if ($item['type'] & MENU_CREATED_BY_ADMIN) {
-        $item['module'] = 'menu';
-        $item['router_path'] = '';
-        $item['updated'] = TRUE;
-      }
-      else {
-        $item['module'] = 'system';
-        $item['router_path'] = $item['path'];
-        $item['updated'] = FALSE;
-      }
-      // Save the link.
-      menu_link_save($item);
-      $_SESSION['menu_item_map'][$item['mid']] = array('mlid' => $item['mlid'], 'menu_name' => $item['menu_name']);
-    }
-    elseif (!isset($_SESSION['menu_menu_map'][$item['mid']])) {
-      $item['menu_name'] = 'menu-'. preg_replace('/[^a-zA-Z0-9]/', '-', strtolower($item['title']));
-      $item['menu_name'] = substr($item['menu_name'], 0, 20);
-      $original_menu_name = $item['menu_name'];
-      $i = 0;
-      while (db_result(db_query("SELECT menu_name FROM {menu_custom} WHERE menu_name = '%s'", $item['menu_name']))) {
-        $item['menu_name'] = $original_menu_name . ($i++);
-      }
-      if ($item['path']) {
-        // Another bunch of bogus entries. Apparently, these are leftovers
-        // from Drupal 4.7 .
-        $_SESSION['menu_bogus_menus'][] = $item['menu_name'];
-      }
-      else {
-        // Add this menu to the list of custom menus.
-        db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '')", $item['menu_name'], $item['title']);
-      }
-      $_SESSION['menu_menu_map'][$item['mid']] = $item['menu_name'];
-      $_SESSION['menu_item_map'][$item['mid']] = FALSE;
-    }
-    db_query('UPDATE {menu} SET converted = %d WHERE mid = %d', 1, $item['mid']);
-    $_SESSION['system_update_6021']++;
-  }
+function system_node_type($op, $info) {
+  if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
+    $old = 'toggle_node_info_'. $info->old_type;
+    $new = 'toggle_node_info_'. $info->type;
 
-  if ($_SESSION['system_update_6021'] >= $_SESSION['system_update_6021_max']) {
-    if (!empty($_SESSION['menu_bogus_menus'])) {
-      // Remove entries in bogus menus. This is secure because we deleted
-      // every non-alpanumeric character from the menu name.
-      $ret[] = update_sql("DELETE FROM {menu_links} WHERE menu_name IN ('". implode("', '", $_SESSION['menu_bogus_menus']) ."')");
-    }
-
-    $menu_primary_menu = variable_get('menu_primary_menu', 0);
-    // Ensure that we wind up with a system menu named 'primary-links'.
-    if (isset($_SESSION['menu_menu_map'][2])) {
-      // The primary links menu that ships with Drupal 5 has mid = 2.  If this
-      // menu hasn't been deleted by the site admin, we use that.
-      $updated_primary_links_menu = 2;
-    }
-    elseif (isset($_SESSION['menu_menu_map'][$menu_primary_menu]) && $menu_primary_menu > 1) {
-      // Otherwise, we use the menu that is currently assigned to the primary
-      // links region of the theme, as long as it exists and isn't the
-      // Navigation menu.
-      $updated_primary_links_menu = $menu_primary_menu;
-    }
-    else {
-      // As a last resort, create 'primary-links' as a new menu.
-      $updated_primary_links_menu = 0;
-      db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", $menus['primary-links']);
-    }
-
-    if ($updated_primary_links_menu) {
-      // Change the existing menu name to 'primary-links'.
-      $replace = array('%new_name' => 'primary-links', '%desc' => $menus['primary-links']['description'], '%old_name' => $_SESSION['menu_menu_map'][$updated_primary_links_menu]);
-      $ret[] = update_sql(strtr("UPDATE {menu_custom} SET menu_name = '%new_name', description = '%desc' WHERE menu_name = '%old_name'", $replace));
-      $ret[] = update_sql("UPDATE {menu_links} SET menu_name = 'primary-links' WHERE menu_name = '". $_SESSION['menu_menu_map'][$updated_primary_links_menu] ."'");
-      $_SESSION['menu_menu_map'][$updated_primary_links_menu] = 'primary-links';
-    }
-
-    $menu_secondary_menu = variable_get('menu_secondary_menu', 0);
-    // Ensure that we wind up with a system menu named 'secondary-links'.
-    if (isset($_SESSION['menu_menu_map'][$menu_secondary_menu]) && $menu_secondary_menu > 1 && $menu_secondary_menu != $updated_primary_links_menu) {
-      // We use the menu that is currently assigned to the secondary links
-      // region of the theme, as long as (a) it exists, (b) it isn't the
-      // Navigation menu, (c) it isn't the same menu we assigned as the
-      // system 'primary-links' menu above, and (d) it isn't the same menu
-      // assigned to the primary links region of the theme.
-      $updated_secondary_links_menu = $menu_secondary_menu;
-    }
-    else {
-      // Otherwise, create 'secondary-links' as a new menu.
-      $updated_secondary_links_menu = 0;
-      db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", $menus['secondary-links']);
-    }
-
-    if ($updated_secondary_links_menu) {
-      // Change the existing menu name to 'secondary-links'.
-      $replace = array('%new_name' => 'secondary-links', '%desc' => $menus['secondary-links']['description'], '%old_name' => $_SESSION['menu_menu_map'][$updated_secondary_links_menu]);
-      $ret[] = update_sql(strtr("UPDATE {menu_custom} SET menu_name = '%new_name', description = '%desc' WHERE menu_name = '%old_name'", $replace));
-      $ret[] = update_sql("UPDATE {menu_links} SET menu_name = 'secondary-links' WHERE menu_name = '". $_SESSION['menu_menu_map'][$updated_secondary_links_menu] ."'");
-      $_SESSION['menu_menu_map'][$updated_secondary_links_menu] = 'secondary-links';
-    }
-
-    // Update menu OTF preferences.
-    $mid = variable_get('menu_parent_items', 0);
-    $menu_name = ($mid && isset($_SESSION['menu_menu_map'][$mid])) ? $_SESSION['menu_menu_map'][$mid] : 'navigation';
-    variable_set('menu_default_node_menu', $menu_name);
-    variable_del('menu_parent_items');
-
-    // Update the source of the primary and secondary links.
-    $menu_name = ($menu_primary_menu && isset($_SESSION['menu_menu_map'][$menu_primary_menu])) ? $_SESSION['menu_menu_map'][$menu_primary_menu] : '';
-    variable_set('menu_primary_links_source', $menu_name);
-    variable_del('menu_primary_menu');
-
-    $menu_name = ($menu_secondary_menu && isset($_SESSION['menu_menu_map'][$menu_secondary_menu])) ? $_SESSION['menu_menu_map'][$menu_secondary_menu] : '';
-    variable_set('menu_secondary_links_source', $menu_name);
-    variable_del('menu_secondary_menu');
-
-    // Skip the navigation menu - it is handled by the user module.
-    unset($_SESSION['menu_menu_map'][1]);
-    // Update the deltas for all menu module blocks.
-    foreach ($_SESSION['menu_menu_map'] as $mid => $menu_name) {
-      // This is again secure because we deleted every non-alpanumeric
-      // character from the menu name.
-      $ret[] = update_sql("UPDATE {blocks} SET delta = '". $menu_name ."' WHERE module = 'menu' AND delta = '". $mid ."'");
-      $ret[] = update_sql("UPDATE {blocks_roles} SET delta = '". $menu_name ."' WHERE module = 'menu' AND delta = '". $mid ."'");
-    }
-    $ret[] = array('success' => TRUE, 'query' => 'Relocated '. $_SESSION['system_update_6021'] .' existing items to the new menu system.');
-    $ret[] = update_sql("DROP TABLE {menu}");
-    unset($_SESSION['system_update_6021'], $_SESSION['system_update_6021_max'], $_SESSION['menu_menu_map'], $_SESSION['menu_item_map'], $_SESSION['menu_bogus_menus']);
-    // Create the menu overview links - also calls menu_rebuild(). If menu is
-    // disabled, then just call menu_rebuild.
-    if (function_exists('menu_enable')) {
-      menu_enable();
+    $theme_settings = variable_get('theme_settings', array());
+    if (isset($theme_settings[$old])) {
+      $theme_settings[$new] = $theme_settings[$old];
+      unset($theme_settings[$old]);
+      variable_set('theme_settings', $theme_settings);
     }
-    else {
-      menu_rebuild();
-    }
-    $ret['#finished'] = 1;
-  }
-  else {
-    $ret['#finished'] = $_SESSION['system_update_6021'] / $_SESSION['system_update_6021_max'];
   }
-  return $ret;
 }
 
 /**
- * Update files tables to associate files to a uid by default instead of a nid.
- * Rename file_revisions to upload since it should only be used by the upload
- * module used by upload to link files to nodes.
+ * Output a confirmation form
+ *
+ * This function returns a complete form for confirming an action. A link is
+ * offered to go back to the item that is being changed in case the user changes
+ * his/her mind.
+ *
+ * If the submit handler for this form is invoked, the user successfully
+ * confirmed the action. You should never directly inspect $_POST to see if an
+ * action was confirmed.
+ *
+ * @ingroup forms
+ * @param $form
+ *   Additional elements to inject into the form, for example hidden elements.
+ * @param $question
+ *   The question to ask the user (e.g. "Are you sure you want to delete the
+ *   block <em>foo</em>?").
+ * @param $path
+ *   The page to go to if the user denies the action.
+ *   Can be either a drupal path, or an array with the keys 'path', 'query', 'fragment'.
+ * @param $description
+ *   Additional text to display (defaults to "This action cannot be undone.").
+ * @param $yes
+ *   A caption for the button which confirms the action (e.g. "Delete",
+ *   "Replace", ...).
+ * @param $no
+ *   A caption for the link which denies the action (e.g. "Cancel").
+ * @param $name
+ *   The internal name used to refer to the confirmation item.
+ * @return
+ *   The form.
  */
-function system_update_6022() {
-  $ret = array();
+function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') {
+  $description = isset($description) ? $description : t('This action cannot be undone.');
 
-  // Rename the nid field to vid, add status and timestamp fields, and indexes.
-  db_drop_index($ret, 'files', 'nid');
-  db_change_field($ret, 'files', 'nid', 'uid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
-  db_add_field($ret, 'files', 'status', array('type' => 'int', 'not null' => TRUE, 'default' => 0));
-  db_add_field($ret, 'files', 'timestamp', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
-  db_add_index($ret, 'files', 'uid', array('uid'));
-  db_add_index($ret, 'files', 'status', array('status'));
-  db_add_index($ret, 'files', 'timestamp', array('timestamp'));
-
-  // Rename the file_revisions table to upload then add nid column. Since we're
-  // changing the table name we need to drop and re-add the indexes and
-  // the primary key so both mysql and pgsql end up with the correct index
-  // names.
-  db_drop_primary_key($ret, 'file_revisions');
-  db_drop_index($ret, 'file_revisions', 'vid');
-  db_rename_table($ret, 'file_revisions', 'upload');
-  db_add_field($ret, 'upload', 'nid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
-  db_add_index($ret, 'upload', 'nid', array('nid'));
-  db_add_primary_key($ret, 'upload', array('vid', 'fid'));
-  db_add_index($ret, 'upload', 'fid', array('fid'));
-
-  // The nid column was renamed to uid. Use the old nid to find the node's uid.
-  update_sql('UPDATE {files} SET uid = (SELECT n.uid FROM {node} n WHERE {files}.uid = n.nid)');
-  update_sql('UPDATE {upload} SET nid = (SELECT r.nid FROM {node_revisions} r WHERE {upload}.vid = r.vid)');
+  // Prepare cancel link
+  $query = $fragment = NULL;
+  if (is_array($path)) {
+    $query = isset($path['query']) ? $path['query'] : NULL;
+    $fragment = isset($path['fragment']) ? $path['fragment'] : NULL;
+    $path = isset($path['path']) ? $path['path'] : NULL;
+  }
+  $cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment));
 
-  // Mark all existing files as FILE_STATUS_PERMANENT.
-  $ret[] = update_sql('UPDATE {files} SET status = 1');
+  drupal_set_title($question);
 
-  return $ret;
-}
+  // Confirm form fails duplication check, as the form values rarely change -- so skip it.
+  $form['#skip_duplicate_check'] = TRUE;
 
-function system_update_6023() {
-  $ret = array();
+  $form['#attributes'] = array('class' => 'confirmation');
+  $form['description'] = array('#value' => $description);
+  $form[$name] = array('#type' => 'hidden', '#value' => 1);
 
-  // nid is DEFAULT 0
-  db_drop_index($ret, 'node_revisions', 'nid');
-  db_change_field($ret, 'node_revisions', 'nid', 'nid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
-  db_add_index($ret, 'node_revisions', 'nid', array('nid'));
-  return $ret;
+  $form['actions'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
+  $form['actions']['submit'] = array('#type' => 'submit', '#value' => $yes ? $yes : t('Confirm'));
+  $form['actions']['cancel'] = array('#value' => $cancel);
+  $form['#theme'] = 'confirm_form';
+  return $form;
 }
 
 /**
- * Add translation fields to nodes used by translation module.
+ * Determine if a user is in compact mode.
  */
-function system_update_6024() {
-  $ret = array();
-  db_add_field($ret, 'node', 'tnid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
-  db_add_field($ret, 'node', 'translate', array('type' => 'int', 'not null' => TRUE, 'default' => 0));
-  db_add_index($ret, 'node', 'tnid', array('tnid'));
-  db_add_index($ret, 'node', 'translate', array('translate'));
-  return $ret;
+function system_admin_compact_mode() {
+  global $user;
+  return (isset($user->admin_compact_mode)) ? $user->admin_compact_mode : variable_get('admin_compact_mode', FALSE);
 }
 
 /**
- * Increase the maximum length of node titles from 128 to 255.
+ * Generate a list of tasks offered by a specified module.
+ *
+ * @param $module
+ *   Module name.
+ * @return
+ *   An array of task links.
  */
-function system_update_6025() {
-  $ret = array();
-  db_drop_index($ret, 'node', 'node_title_type');
-  db_change_field($ret, 'node', 'title', 'title', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
-  db_add_index($ret, 'node', 'node_title_type', array('title', array('type', 4)));
-  db_change_field($ret, 'node_revisions', 'title', 'title', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
-  return $ret;
-}
+function system_get_module_admin_tasks($module) {
+  static $items;
 
-/**
- * Display warning about new Update status module.
- */
-function system_update_6026() {
-  $ret = array();
+  $admin_access = user_access('administer permissions');
+  $admin_tasks = array();
+
+  if (!isset($items)) {
+    $result = db_query("
+       SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, ml.*
+       FROM {menu_links} ml INNER JOIN {menu_router} m ON ml.router_path = m.path WHERE ml.link_path LIKE 'admin/%' AND hidden >= 0 AND module = 'system' AND m.number_parts > 2");
+    $items = array();
+    while ($item = db_fetch_array($result)) {
+      _menu_link_translate($item);
+      if ($item['access']) {
+        $items[$item['router_path']] = $item;
+      }
+    }
+  }
+  $admin_tasks = array();
+  $admin_task_count = 0;
+  // Check for permissions.
+  if (module_hook($module, 'perm') && $admin_access) {
+    $admin_tasks[-1] = l(t('Configure permissions'), 'admin/user/permissions', array('fragment' => 'module-'. $module));
+  }
 
-  // Notify user that new update module exists.
-  drupal_set_message('Drupal can check periodically for important bug fixes and security releases using the new update status module. This module can be turned on from the <a href="'. url('admin/build/modules') .'">modules administration page</a>. For more information please read the <a href="http://drupal.org/handbook/modules/update">Update status handbook page</a>.');
+  // Check for menu items that are admin links.
+  if ($menu = module_invoke($module, 'menu')) {
+    foreach (array_keys($menu) as $path) {
+      if (isset($items[$path])) {
+        $admin_tasks[$items[$path]['title'] . $admin_task_count ++] = l($items[$path]['title'], $path);
+      }
+    }
+  }
 
-  return $ret;
+  return $admin_tasks;
 }
 
 /**
- * Add block cache.
+ * Implementation of hook_cron().
+ *
+ * Remove older rows from flood and batch table. Remove old temporary files.
  */
-function system_update_6027() {
-  $ret = array();
-
-  // Create the blocks.cache column.
-  db_add_field($ret, 'blocks', 'cache', array('type' => 'int', 'not null' => TRUE, 'default' => 1, 'size' => 'tiny'));
-
-  // The cache_block table is created in update_fix_d6_requirements() since
-  // calls to cache_clear_all() would otherwise cause warnings.
-
-  // Fill in the values for the new 'cache' column in the {blocks} table.
-  foreach (module_list() as $module) {
-    if ($module_blocks = module_invoke($module, 'block', 'list')) {
-      foreach ($module_blocks as $delta => $block) {
-        if (isset($block['cache'])) {
-          db_query("UPDATE {blocks} SET cache = %d WHERE module = '%s' AND delta = %d", $block['cache'], $module, $delta);
-        }
+function system_cron() {
+  // Cleanup the flood.
+  db_query('DELETE FROM {flood} WHERE timestamp < %d', time() - 3600);
+  // Cleanup the batch table.
+  db_query('DELETE FROM {batch} WHERE timestamp < %d', time() - 864000);
+
+  // Remove temporary files that are older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+  $result = db_query('SELECT * FROM {files} WHERE status = %d and timestamp < %d', FILE_STATUS_TEMPORARY, time() - DRUPAL_MAXIMUM_TEMP_FILE_AGE);
+  while ($file = db_fetch_object($result)) {
+    if (file_exists($file->filepath)) {
+      // If files that exist cannot be deleted, continue so the database remains
+      // consistent.
+      if (!file_delete($file->filepath)) {
+        watchdog('file system', 'Could not delete temporary file "%path" during garbage collection', array('%path' => $file->filepath), 'error');
+        continue;
       }
     }
+    db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+  }
+  $core = array('cache', 'cache_block', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
+  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
+  foreach ($cache_tables as $table) {
+    cache_clear_all(NULL, $table);
   }
-
-  return $ret;
 }
 
 /**
- * Add the node load cache table.
+ * Implementation of hook_hook_info().
  */
-function system_update_6028() {
-  // Removed node_load cache to discuss it more for Drupal 7.
-  return array();
+function system_hook_info() {
+  return array(
+    'system' => array(
+      'cron' => array(
+        'run' => array(
+          'runs when' => t('When cron runs'),
+        ),
+      ),
+    ),
+  );
 }
 
 /**
- * Enable the dblog module on sites that upgrade, since otherwise
- * watchdog logging will stop unexpectedly.
+ * Implementation of hook_action_info().
  */
-function system_update_6029() {
-  // The watchdog table is now owned by dblog, which is not yet
-  // "installed" according to the system table, but the table already
-  // exists.  We set the module as "installed" here to avoid an error
-  // later.
-  //
-  // Although not the case for the initial D6 release, it is likely
-  // that dblog.install will have its own update functions eventually.
-  // However, dblog did not exist in D5 and this update is part of the
-  // initial D6 release, so we know that dblog is not installed yet.
-  // It is therefore correct to install it as version 0.  If
-  // dblog updates exist, the next run of update.php will get them.
-  drupal_set_installed_schema_version('dblog', 0);
-  module_enable(array('dblog'));
-  menu_rebuild();
-  return array(array('success' => TRUE, 'query' => "'dblog' module enabled."));
+function system_action_info() {
+  return array(
+    'system_message_action' => array(
+      'type' => 'system',
+      'description' => t('Display a message to the user'),
+      'configurable' => TRUE,
+      'hooks' => array(
+        'nodeapi' => array('view', 'insert', 'update', 'delete'),
+        'comment' => array('view', 'insert', 'update', 'delete'),
+        'user' => array('view', 'insert', 'update', 'delete', 'login'),
+        'taxonomy' => array('insert', 'update', 'delete'),
+      ),
+    ),
+    'system_send_email_action' => array(
+      'description' => t('Send e-mail'),
+      'type' => 'system',
+      'configurable' => TRUE,
+      'hooks' => array(
+        'nodeapi' => array('view', 'insert', 'update', 'delete'),
+        'comment' => array('view', 'insert', 'update', 'delete'),
+        'user' => array('view', 'insert', 'update', 'delete', 'login'),
+        'taxonomy' => array('insert', 'update', 'delete'),
+      )
+    ),
+    'system_goto_action' => array(
+      'description' => t('Redirect to URL'),
+      'type' => 'system',
+      'configurable' => TRUE,
+      'hooks' => array(
+        'nodeapi' => array('view', 'insert', 'update', 'delete'),
+        'comment' => array('view', 'insert', 'update', 'delete'),
+        'user' => array('view', 'insert', 'update', 'delete', 'login'),
+      )
+    )
+  );
 }
 
 /**
- * Add the tables required by actions.inc.
+ * Menu callback. Display an overview of available and configured actions.
  */
-function system_update_6030() {
-  $ret = array();
-
-  // Rename the old contrib actions table if it exists so the contrib version
-  // of the module can do something with the old data.
-  if (db_table_exists('actions')) {
-    db_rename_table($ret, 'actions', 'actions_old_contrib');
+function system_actions_manage() {
+  $output = '';
+  $actions = actions_list();
+  actions_synchronize($actions);
+  $actions_map = actions_actions_map($actions);
+  $options = array(t('Choose an advanced action'));
+  $unconfigurable = array();
+
+  foreach ($actions_map as $key => $array) {
+    if ($array['configurable']) {
+      $options[$key] = $array['description'] .'...';
+    }
+    else {
+      $unconfigurable[] = $array;
+    }
   }
 
-  $schema['actions'] = array(
-    'fields' => array(
-      'aid' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0'),
-      'type' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
-      'callback' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'parameters' => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
-      'description' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0'),
-    ),
-    'primary key' => array('aid'),
+  $row = array();
+  $instances_present = db_fetch_object(db_query("SELECT aid FROM {actions} WHERE parameters != ''"));
+  $header = array(
+    array('data' => t('Action type'), 'field' => 'type'),
+    array('data' => t('Description'), 'field' => 'description'),
+    array('data' => $instances_present ? t('Operations') : '', 'colspan' => '2')
   );
+  $sql = 'SELECT * FROM {actions}';
+  $result = pager_query($sql . tablesort_sql($header), 50);
+  while ($action = db_fetch_object($result)) {
+    $row[] = array(
+      array('data' => $action->type),
+      array('data' => $action->description),
+      array('data' => $action->parameters ? l(t('configure'), "admin/settings/actions/configure/$action->aid") : ''),
+      array('data' => $action->parameters ? l(t('delete'), "admin/settings/actions/delete/$action->aid") : '')
+    );
+  }
 
-  $schema['actions_aid'] = array(
-    'fields' => array(
-      'aid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
-    ),
-    'primary key' => array('aid'),
-  );
+  if ($row) {
+    $pager = theme('pager', NULL, 50, 0);
+    if (!empty($pager)) {
+      $row[] = array(array('data' => $pager, 'colspan' => '3'));
+    }
+    $output .= '<h3>'. t('Actions available to Drupal:') .'</h3>';
+    $output .= theme('table', $header, $row);
+  }
 
-  db_create_table($ret, 'actions', $schema['actions']);
-  db_create_table($ret, 'actions_aid', $schema['actions_aid']);
+  if ($actions_map) {
+    $output .= drupal_get_form('system_actions_manage_form', $options);
+  }
 
-  return $ret;
+  return $output;
 }
 
 /**
- * Ensure that installer cannot be run again after updating from Drupal 5.x to 6.x
- * Actually, this is already done by system_update_6014(), so this is now a no-op.
+ * Define the form for the actions overview page.
+ *
+ * @see system_actions_manage_form_submit()
+ * @ingroup forms
+ * @param $form_state
+ *   An associative array containing the current state of the form; not used.
+ * @param $options
+ *   An array of configurable actions.
+ * @return
+ *   Form definition.
  */
-function system_update_6031() {
-  return array();
+function system_actions_manage_form($form_state, $options = array()) {
+  $form['parent'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Make a new advanced action available'),
+    '#prefix' => '<div class="container-inline">',
+    '#suffix' => '</div>',
+  );
+  $form['parent']['action'] = array(
+    '#type' => 'select',
+    '#default_value' => '',
+    '#options' => $options,
+    '#description' => '',
+  );
+  $form['parent']['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Create'),
+  );
+  return $form;
 }
 
 /**
- * profile_fields.name used to be nullable but is part of a unique key
- * and so shouldn't be.
+ * Process system_actions_manage form submissions.
  */
-function system_update_6032() {
-  $ret = array();
-  if (db_table_exists('profile_fields')) {
-    db_drop_unique_key($ret, 'profile_fields', 'name');
-    db_change_field($ret, 'profile_fields', 'name', 'name', array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
-    db_add_unique_key($ret, 'profile_fields', 'name', array('name'));
+function system_actions_manage_form_submit($form, &$form_state) {
+  if ($form_state['values']['action']) {
+    $form_state['redirect'] = 'admin/settings/actions/configure/'. $form_state['values']['action'];
   }
-  return $ret;
 }
 
 /**
- * Change node_comment_statistics to be not autoincrement.
+ * Menu callback. Create the form for configuration of a single action.
+ *
+ * We provide the "Description" field. The rest of the form
+ * is provided by the action. We then provide the Save button.
+ * Because we are combining unknown form elements with the action
+ * configuration form, we use actions_ prefix on our elements.
+ *
+ * @see system_actions_configure_validate()
+ * @see system_actions_configure_submit()
+ * @param $action
+ *   md5 hash of action ID or an integer. If it's an md5 hash, we
+ *   are creating a new instance. If it's an integer, we're editing
+ *   an existing instance.
+ * @return
+ *   Form definition.
  */
-function system_update_6033() {
-  $ret = array();
-  if (db_table_exists('node_comment_statistics')) {
-    // On pgsql but not mysql, db_change_field() drops all keys
-    // involving the changed field, which in this case is the primary
-    // key.  The normal approach is explicitly drop the pkey, change the
-    // field, and re-create the pkey.
-    //
-    // Unfortunately, in this case that won't work on mysql; we CANNOT
-    // drop the pkey because on mysql auto-increment fields must be
-    // included in at least one key or index.
-    //
-    // Since we cannot drop the pkey before db_change_field(), after
-    // db_change_field() we may or may not still have a pkey.  The
-    // simple way out is to re-create the pkey only when using pgsql.
-    // Realistic requirements trump idealistic purity.
-    db_change_field($ret, 'node_comment_statistics', 'nid', 'nid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
-    if ($GLOBALS['db_type'] == 'pgsql') {
-      db_add_primary_key($ret, 'node_comment_statistics', array('nid'));
+function system_actions_configure($form_state, $action = NULL) {
+  if ($action === NULL) {
+    drupal_goto('admin/settings/actions');
+  }
+
+  $actions_map = actions_actions_map(actions_list());
+  $edit = array();
+
+  // Numeric action denotes saved instance of a configurable action;
+  // else we are creating a new action instance.
+  if (is_numeric($action)) {
+    $aid = $action;
+    // Load stored parameter values from database.
+    $data = db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid = %d", intval($aid)));
+    $edit['actions_description'] = $data->description;
+    $edit['actions_type'] = $data->type;
+    $function = $data->callback;
+    $action = md5($data->callback);
+    $params = unserialize($data->parameters);
+    if ($params) {
+      foreach ($params as $name => $val) {
+        $edit[$name] = $val;
+      }
     }
   }
-  return $ret;
-}
+  else {
+    $function = $actions_map[$action]['callback'];
+    $edit['actions_description'] = $actions_map[$action]['description'];
+    $edit['actions_type'] = $actions_map[$action]['type'];
+  }
 
-/**
- * Rename permission "administer access control" to "administer permissions".
- */
-function system_update_6034() {
-  $ret = array();
-  $result = db_query("SELECT rid, perm FROM {permission} ORDER BY rid");
-  while ($role = db_fetch_object($result)) {
-    $renamed_permission = preg_replace('/administer access control/', 'administer permissions', $role->perm);
-    if ($renamed_permission != $role->perm) {
-      $ret[] = update_sql("UPDATE {permission} SET perm = '$renamed_permission' WHERE rid = $role->rid");
-    }
+  $form['actions_description'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Description'),
+    '#default_value' => $edit['actions_description'],
+    '#maxlength' => '255',
+    '#description' => t('A unique description for this advanced action. This description will be displayed in the interface of modules that integrate with actions, such as Trigger module.'),
+    '#weight' => -10
+  );
+  $action_form = $function .'_form';
+  $form = array_merge($form, $action_form($edit));
+  $form['actions_type'] = array(
+    '#type' => 'value',
+    '#value' => $edit['actions_type'],
+  );
+  $form['actions_action'] = array(
+    '#type' => 'hidden',
+    '#value' => $action,
+  );
+  // $aid is set when configuring an existing action instance.
+  if (isset($aid)) {
+    $form['actions_aid'] = array(
+      '#type' => 'hidden',
+      '#value' => $aid,
+    );
   }
-  return $ret;
+  $form['actions_configured'] = array(
+    '#type' => 'hidden',
+    '#value' => '1',
+  );
+  $form['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#weight' => 13
+  );
+
+  return $form;
 }
 
 /**
- * Change index on system table for better performance.
+ * Validate system_actions_configure form submissions.
  */
-function system_update_6035() {
-  $ret = array();
-  db_drop_index($ret, 'system', 'weight');
-  db_add_index($ret, 'system', 'modules', array(array('type', 12), 'status', 'weight', 'filename'));
-  db_add_index($ret, 'system', 'bootstrap', array(array('type', 12), 'status', 'bootstrap', 'weight', 'filename'));
-  return $ret;
+function system_actions_configure_validate($form, $form_state) {
+  $function = actions_function_lookup($form_state['values']['actions_action']) .'_validate';
+  // Hand off validation to the action.
+  if (function_exists($function)) {
+    $function($form, $form_state);
+  }
 }
 
 /**
- * Change the search schema and indexing.
- *
- * The table data is preserved where possible in MYSQL and MYSQLi using
- * ALTER IGNORE. Other databases don't support that, so for them the
- * tables are dropped and re-created, and will need to be re-indexed
- * from scratch.
+ * Process system_actions_configure form submissions.
  */
-function system_update_6036() {
-  $ret = array();
-  if (db_table_exists('search_index')) {
-    // Create the search_dataset.reindex column.
-    db_add_field($ret, 'search_dataset', 'reindex', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
+function system_actions_configure_submit($form, &$form_state) {
+  $function = actions_function_lookup($form_state['values']['actions_action']);
+  $submit_function = $function .'_submit';
 
-    // Drop the search_index.from fields which are no longer used.
-    db_drop_index($ret, 'search_index', 'from_sid_type');
-    db_drop_field($ret, 'search_index', 'fromsid');
-    db_drop_field($ret, 'search_index', 'fromtype');
+  // Action will return keyed array of values to store.
+  $params = $submit_function($form, $form_state);
+  $aid = isset($form_state['values']['actions_aid']) ? $form_state['values']['actions_aid'] : NULL;
 
-    // Drop the search_dataset.sid_type index, so that it can be made unique.
-    db_drop_index($ret, 'search_dataset', 'sid_type');
+  actions_save($function, $form_state['values']['actions_type'], $params, $form_state['values']['actions_description'], $aid);
+  drupal_set_message(t('The action has been successfully saved.'));
 
-    // Create the search_node_links Table.
-    $search_node_links_schema = array(
-      'fields' => array(
-        'sid'      => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-        'type'     => array('type' => 'varchar', 'length' => 16, 'not null' => TRUE, 'default' => ''),
-        'nid'      => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-        'caption'    => array('type' => 'text', 'size' => 'big', 'not null' => FALSE),
-      ),
-      'primary key' => array('sid', 'type', 'nid'),
-      'indexes' => array('nid' => array('nid')),
-    );
-    db_create_table($ret, 'search_node_links', $search_node_links_schema);
-
-    // with the change to search_dataset.reindex, the search queue is handled differently,
-    // and this is no longer needed
-    variable_del('node_cron_last');
-
-    // Add a unique index for the search_index.
-    if ($GLOBALS['db_type'] == 'mysql' || $GLOBALS['db_type'] == 'mysqli') {
-      // Since it's possible that some existing sites have duplicates,
-      // create the index using the IGNORE keyword, which ignores duplicate errors.
-      // However, pgsql doesn't support it
-      $ret[] = update_sql("ALTER IGNORE TABLE {search_index} ADD UNIQUE KEY word_sid_type (word, sid, type)");
-      $ret[] = update_sql("ALTER IGNORE TABLE {search_dataset} ADD UNIQUE KEY sid_type (sid, type)");
+  $form_state['redirect'] = 'admin/settings/actions/manage';
+}
 
-      // Everything needs to be reindexed.
-      $ret[] = update_sql("UPDATE {search_dataset} SET reindex = 1");
-    }
-    else {
-      // Delete the existing tables if there are duplicate values
-      if (db_result(db_query("SELECT sid FROM {search_dataset} GROUP BY sid, type HAVING COUNT(*) > 1")) || db_result(db_query("SELECT sid FROM {search_index} GROUP BY word, sid, type HAVING COUNT(*) > 1"))) {
-        $ret[] = update_sql('DELETE FROM {search_dataset}');
-        $ret[] = update_sql('DELETE FROM {search_index}');
-        $ret[] = update_sql('DELETE FROM {search_total}');
-      }
-      else {
-        // Everything needs to be reindexed.
-        $ret[] = update_sql("UPDATE {search_dataset} SET reindex = 1");
-      }
+/**
+ * Create the form for confirmation of deleting an action.
+ *
+ * @ingroup forms
+ * @see system_actions_delete_form_submit()
+ */
+function system_actions_delete_form($form_state, $action) {
 
-      // create the new indexes
-      db_add_unique_key($ret, 'search_index', 'word_sid_type', array('word', 'sid', 'type'));
-      db_add_unique_key($ret, 'search_dataset', 'sid_type', array('sid', 'type'));
-    }
-  }
-  return $ret;
+  $form['aid'] = array(
+    '#type' => 'hidden',
+    '#value' => $action->aid,
+  );
+  return confirm_form($form,
+    t('Are you sure you want to delete the action %action?', array('%action' => $action->description)),
+    'admin/settings/actions/manage',
+    t('This cannot be undone.'),
+    t('Delete'), t('Cancel')
+  );
 }
 
 /**
- * Create consistent empty region for disabled blocks.
+ * Process system_actions_delete form submissions.
+ *
+ * Post-deletion operations for action deletion.
  */
-function system_update_6037() {
-  $ret = array();
-  db_change_field($ret, 'blocks', 'region', 'region', array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''));
-  $ret[] = update_sql("UPDATE {blocks} SET region = '' WHERE status = 0");
-  return $ret;
+function system_actions_delete_form_submit($form, &$form_state) {
+  $aid = $form_state['values']['aid'];
+  $action = actions_load($aid);
+  actions_delete($aid);
+  $description = check_plain($action->description);
+  watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $description));
+  drupal_set_message(t('Action %action was deleted', array('%action' => $description)));
+  $form_state['redirect'] = 'admin/settings/actions/manage';
 }
 
 /**
- * Ensure that "Account" is not used as a Profile category.
+ * Post-deletion operations for deleting action orphans.
+ *
+ * @param $orphaned
+ *   An array of orphaned actions.
  */
-function system_update_6038() {
-  $ret = array();
-  if (db_table_exists('profile_fields')) {
-    $ret[] = update_sql("UPDATE {profile_fields} SET category = 'Account settings' WHERE LOWER(category) = 'account'");
-    if ($affectedrows = db_affected_rows()) {
-      drupal_set_message('There were '. $affectedrows .' profile fields that used a reserved category name. They have been assigned to the category "Account settings".');
-    }
+function system_action_delete_orphans_post($orphaned) {
+  foreach ($orphaned as $callback) {
+    drupal_set_message(t("Deleted orphaned action (%action).", array('%action' => $callback)));
   }
-  return $ret;
 }
 
 /**
- * Rename permissions "edit foo content" to "edit any foo content".
- * Also update poll module permission "create polls" to "create
- * poll content".
+ * Remove actions that are in the database but not supported by any enabled module.
  */
-function system_update_6039() {
-  $ret = array();
-  $result = db_query("SELECT rid, perm FROM {permission} ORDER BY rid");
-  while ($role = db_fetch_object($result)) {
-    $renamed_permission = preg_replace('/(?<=^|,\ )edit\ ([a-zA-Z0-9_\-]+)\ content(?=,|$)/', 'edit any $1 content', $role->perm);
-    $renamed_permission = preg_replace('/(?<=^|,\ )create\ polls(?=,|$)/', 'create poll content', $renamed_permission);
-    if ($renamed_permission != $role->perm) {
-      $ret[] = update_sql("UPDATE {permission} SET perm = '$renamed_permission' WHERE rid = $role->rid");
-    }
-  }
-  return $ret;
+function system_actions_remove_orphans() {
+  actions_synchronize(actions_list(), TRUE);
+  drupal_goto('admin/settings/actions/manage');
 }
 
 /**
- * Add a weight column to the upload table.
+ * Return a form definition so the Send email action can be configured.
+ *
+ * @see system_send_email_action_validate()
+ * @see system_send_email_action_submit()
+ * @param $context
+ *   Default values (if we are editing an existing action instance).
+ * @return
+ *   Form definition.
  */
-function system_update_6040() {
-  $ret = array();
-  if (db_table_exists('upload')) {
-    db_add_field($ret, 'upload', 'weight', array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'));
-  }
-  return $ret;
+function system_send_email_action_form($context) {
+  // Set default values for form.
+  if (!isset($context['recipient'])) {
+    $context['recipient'] = '';
+  }
+  if (!isset($context['subject'])) {
+    $context['subject'] = '';
+  }
+  if (!isset($context['message'])) {
+    $context['message'] = '';
+  }
+
+  $form['recipient'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Recipient'),
+    '#default_value' => $context['recipient'],
+    '#maxlength' => '254',
+    '#description' => t('The email address to which the message should be sent OR enter %author if you would like to send an e-mail to the author of the original post.', array('%author' => '%author')),
+  );
+  $form['subject'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Subject'),
+    '#default_value' => $context['subject'],
+    '#maxlength' => '254',
+    '#description' => t('The subject of the message.'),
+  );
+  $form['message'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Message'),
+    '#default_value' => $context['message'],
+    '#cols' => '80',
+    '#rows' => '20',
+    '#description' => t('The message that should be sent. You may include the following variables: %site_name, %username, %node_url, %node_type, %title, %teaser, %body. Not all variables will be available in all contexts.'),
+  );
+  return $form;
 }
 
 /**
- * Change forum vocabulary not to be required by default and set the weight of the forum.module 1 higher than the taxonomy.module.
+ * Validate system_send_email_action form submissions.
  */
-function system_update_6041() {
-  $weight = intval((db_result(db_query("SELECT weight FROM {system} WHERE name = 'taxonomy'"))) + 1);
-  $ret = array();
-  $vid = intval(variable_get('forum_nav_vocabulary', ''));
-  if (db_table_exists('vocabulary') && $vid) {
-    $ret[] = update_sql("UPDATE {vocabulary} SET required = 0 WHERE vid = " . $vid);
-    $ret[] = update_sql("UPDATE {system} SET weight = ". $weight ." WHERE name = 'forum'");
+function system_send_email_action_validate($form, $form_state) {
+  $form_values = $form_state['values'];
+  // Validate the configuration form.
+  if (!valid_email_address($form_values['recipient']) && $form_values['recipient'] != '%author') {
+    // We want the literal %author placeholder to be emphasized in the error message.
+    form_set_error('recipient', t('Please enter a valid email address or %author.', array('%author' => '%author')));
   }
-  return $ret;
 }
 
 /**
- * Upgrade recolored theme stylesheets to new array structure.
+ * Process system_send_email_action form submissions.
  */
-function system_update_6042() {
-  foreach (list_themes() as $theme) {
-    $stylesheet = variable_get('color_'. $theme->name .'_stylesheet', NULL);
-    if (!empty($stylesheet)) {
-      variable_set('color_'. $theme->name .'_stylesheets', array($stylesheet));
-      variable_del('color_'. $theme->name .'_stylesheet');
-    }
-  }
-  return array();
+function system_send_email_action_submit($form, $form_state) {
+  $form_values = $form_state['values'];
+  // Process the HTML form to store configuration. The keyed array that
+  // we return will be serialized to the database.
+  $params = array(
+    'recipient' => $form_values['recipient'],
+    'subject'   => $form_values['subject'],
+    'message'   => $form_values['message'],
+  );
+  return $params;
 }
 
 /**
- * Update table indices to make them more rational and useful.
+ * Implementation of a configurable Drupal action. Sends an email.
  */
-function system_update_6043() {
-  $ret = array();
-  // Required modules first.
-  // Add new system module indexes.
-  db_add_index($ret, 'flood', 'allow', array('event', 'hostname', 'timestamp'));
-  db_add_index($ret, 'history', 'nid', array('nid'));
-  // Change length of theme field in {blocks} to be consistent with module, and
-  // to avoid a MySQL error regarding a too-long index.  Also add new indices.
-  db_change_field($ret, 'blocks', 'theme', 'theme', array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),array(
-                  'unique keys' => array('tmd' => array('theme', 'module', 'delta'),),
-                  'indexes' => array('list' => array('theme', 'status', 'region', 'weight', 'module'),),));
-  db_add_index($ret, 'blocks_roles', 'rid', array('rid'));
-  // Improve filter module indices.
-  db_drop_index($ret, 'filters', 'weight');
-  db_add_unique_key($ret, 'filters', 'fmd', array('format', 'module', 'delta'));
-  db_add_index($ret, 'filters', 'list', array('format', 'weight', 'module', 'delta'));
-  // Drop unneeded keys form the node table.
-  db_drop_index($ret, 'node', 'status');
-  db_drop_unique_key($ret, 'node', 'nid_vid');
-  // Improve user module indices.
-  db_add_index($ret, 'users', 'mail', array('mail'));
-  db_add_index($ret, 'users_roles', 'rid', array('rid'));
+function system_send_email_action($object, $context) {
+  global $user;
 
-  // Optional modules - need to check if the tables exist.
-  // Alter aggregator module's tables primary keys to make them more useful.
-  if (db_table_exists('aggregator_category_feed')) {
-    db_drop_primary_key($ret, 'aggregator_category_feed');
-    db_add_primary_key($ret, 'aggregator_category_feed', array('cid', 'fid'));
-    db_add_index($ret, 'aggregator_category_feed', 'fid', array('fid'));
-  }
-  if (db_table_exists('aggregator_category_item')) {
-    db_drop_primary_key($ret, 'aggregator_category_item');
-    db_add_primary_key($ret, 'aggregator_category_item', array('cid', 'iid'));
-    db_add_index($ret, 'aggregator_category_item', 'iid', array('iid'));
-  }
-  // Alter contact module's table to add an index.
-  if (db_table_exists('contact')) {
-    db_add_index($ret, 'contact', 'list', array('weight', 'category'));
-  }
-  // Alter locale table to add a primary key, drop an index.
-  if (db_table_exists('locales_target')) {
-    db_add_primary_key($ret, 'locales_target', array('language', 'lid', 'plural'));
-  }
-  // Alter a poll module table to add a primary key.
-  if (db_table_exists('poll_votes')) {
-    db_drop_index($ret, 'poll_votes', 'nid');
-    db_add_primary_key($ret, 'poll_votes', array('nid', 'uid', 'hostname'));
-  }
-  // Alter a profile module table to add a primary key.
-  if (db_table_exists('profile_values')) {
-    db_drop_index($ret, 'profile_values', 'uid');
-    db_drop_index($ret, 'profile_values', 'fid');
-    db_change_field($ret,'profile_values' ,'fid', 'fid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0,), array('indexes' => array('fid' => array('fid'),)));
-    db_change_field($ret,'profile_values' ,'uid', 'uid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0,));
-    db_add_primary_key($ret, 'profile_values', array('uid', 'fid'));
-  }
-  // Alter a statistics module table to add an index.
-  if (db_table_exists('accesslog')) {
-    db_add_index($ret, 'accesslog', 'uid', array('uid'));
-  }
-  // Alter taxonomy module's tables.
-  if (db_table_exists('term_data')) {
-    db_drop_index($ret, 'term_data', 'vid');
-    db_add_index($ret, 'term_data', 'vid_name', array('vid', 'name'));
-    db_add_index($ret, 'term_data', 'taxonomy_tree', array('vid', 'weight', 'name'));
+  switch ($context['hook']) {
+    case 'nodeapi':
+      // Because this is not an action of type 'node' the node
+      // will not be passed as $object, but it will still be available
+      // in $context.
+      $node = $context['node'];
+      break;
+    // The comment hook provides nid, in $context.
+    case 'comment':
+      $comment = $context['comment'];
+      $node = node_load($comment->nid);
+      break;
+    case 'user':
+      // Because this is not an action of type 'user' the user
+      // object is not passed as $object, but it will still be available
+      // in $context.
+      $account = $context['account'];
+      if (isset($context['node'])) {
+        $node = $context['node'];
+      }
+      elseif ($context['recipient'] == '%author') {
+        // If we don't have a node, we don't have a node author.
+        watchdog('error', 'Cannot use %author token in this context.');
+        return;
+      }
+      break;
+    default:
+      // We are being called directly.
+      $node = $object;
   }
-  if (db_table_exists('term_node')) {
-    db_drop_primary_key($ret, 'term_node');
-    db_drop_index($ret, 'term_node', 'tid');
-    db_add_primary_key($ret, 'term_node', array('tid', 'vid'));
+
+  $recipient = $context['recipient'];
+
+  if (isset($node)) {
+    if (!isset($account)) {
+      $account = user_load(array('uid' => $node->uid));
+    }
+    if ($recipient == '%author') {
+      $recipient = $account->mail;
+    }
   }
-  if (db_table_exists('term_relation')) {
-    db_drop_index($ret, 'term_relation', 'tid1');
-    db_add_unique_key($ret, 'term_relation', 'tid1_tid2', array('tid1', 'tid2'));
+
+  if (!isset($account)) {
+    $account = $user;
+
   }
-  if (db_table_exists('term_synonym')) {
-    db_drop_index($ret, 'term_synonym', 'name');
-    db_add_index($ret, 'term_synonym', 'name_tid', array('name', 'tid'));
+  $language = user_preferred_language($account);
+  $params = array('account' => $account, 'object' => $object, 'context' => $context);
+  if (isset($node)) {
+    $params['node'] = $node;
   }
-  if (db_table_exists('vocabulary')) {
-    db_add_index($ret, 'vocabulary', 'list', array('weight', 'name'));
+
+  if (drupal_mail('system', 'action_send_email', $recipient, $language, $params)) {
+    watchdog('action', 'Sent email to %recipient', array('%recipient' => $recipient));
   }
-  if (db_table_exists('vocabulary_node_types')) {
-    db_drop_primary_key($ret, 'vocabulary_node_types');
-    db_add_primary_key($ret, 'vocabulary_node_types', array('type', 'vid'));
-    db_add_index($ret, 'vocabulary_node_types', 'vid', array('vid'));
+  else {
+    watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $recipient));
   }
-  // If we updated in RC1 or before ensure we don't update twice.
-  variable_set('system_update_6043_RC2', TRUE);
-
-  return $ret;
 }
 
 /**
- * RC1 to RC2 index cleanup.
+ * Implementation of hook_mail().
  */
-function system_update_6044() {
-  $ret = array();
+function system_mail($key, &$message, $params) {
+  $account = $params['account'];
+  $context = $params['context'];
+  $variables = array(
+    '%site_name' => variable_get('site_name', 'Drupal'),
+    '%username' => $account->name,
+  );
+  if ($context['hook'] == 'taxonomy') {
+    $object = $params['object'];
+    $vocabulary = taxonomy_vocabulary_load($object->vid);
+    $variables += array(
+      '%term_name' => $object->name,
+      '%term_description' => $object->description,
+      '%term_id' => $object->tid,
+      '%vocabulary_name' => $vocabulary->name,
+      '%vocabulary_description' => $vocabulary->description,
+      '%vocabulary_id' => $vocabulary->vid,
+    );
+  }
 
-  // Delete invalid entries in {term_node} after system_update_6001.
-  $ret[] = update_sql("DELETE FROM {term_node} WHERE vid = 0");
+  // Node-based variable translation is only available if we have a node.
+  if (isset($params['node'])) {
+    $node = $params['node'];
+    $variables += array(
+      '%uid' => $node->uid,
+      '%node_url' => url('node/'. $node->nid, array('absolute' => TRUE)),
+      '%node_type' => node_get_types('name', $node),
+      '%title' => $node->title,
+      '%teaser' => $node->teaser,
+      '%body' => $node->body,
+    );
+  }
+  $subject = strtr($context['subject'], $variables);
+  $body = strtr($context['message'], $variables);
+  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
+  $message['body'][] = drupal_html_to_text($body);
+}
+
+function system_message_action_form($context) {
+  $form['message'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Message'),
+    '#default_value' => isset($context['message']) ? $context['message'] : '',
+    '#required' => TRUE,
+    '#rows' => '8',
+    '#description' => t('The message to be displayed to the current user. You may include the following variables: %site_name, %username, %node_url, %node_type, %title, %teaser, %body. Not all variables will be available in all contexts.'),
+  );
+  return $form;
+}
 
-  // Only execute the rest of this function if 6043 was run in RC1 or before.
-  if (variable_get('system_update_6043_RC2', FALSE)) {
-    variable_del('system_update_6043_RC2');
-    return $ret;
-  }
+function system_message_action_submit($form, $form_state) {
+  return array('message' => $form_state['values']['message']);
+}
 
-  // User module indices.
-  db_drop_unique_key($ret, 'users', 'mail');
-  db_add_index($ret, 'users', 'mail', array('mail'));
+/**
+ * A configurable Drupal action. Sends a message to the current user's screen.
+ */
+function system_message_action(&$object, $context = array()) {
+  global $user;
+  $variables = array(
+    '%site_name' => variable_get('site_name', 'Drupal'),
+    '%username' => $user->name ? $user->name : variable_get('anonymous', t('Anonymous')),
+  );
 
-  // Optional modules - need to check if the tables exist.
-  // Alter taxonomy module's tables.
-  if (db_table_exists('term_data')) {
-    db_drop_unique_key($ret, 'term_data', 'vid_name');
-    db_add_index($ret, 'term_data', 'vid_name', array('vid', 'name'));
-  }
-  if (db_table_exists('term_synonym')) {
-    db_drop_unique_key($ret, 'term_synonym', 'name_tid', array('name', 'tid'));
-    db_add_index($ret, 'term_synonym', 'name_tid', array('name', 'tid'));
+  // This action can be called in any context, but if placeholders
+  // are used a node object must be present to be the source
+  // of substituted text.
+  switch ($context['hook']) {
+    case 'nodeapi':
+      // Because this is not an action of type 'node' the node
+      // will not be passed as $object, but it will still be available
+      // in $context.
+      $node = $context['node'];
+      break;
+    // The comment hook also provides the node, in context.
+    case 'comment':
+      $comment = $context['comment'];
+      $node = node_load($comment->nid);
+      break;
+    case 'taxonomy':
+      $vocabulary = taxonomy_vocabulary_load($object->vid);
+      $variables = array_merge($variables, array(
+        '%term_name' => $object->name,
+        '%term_description' => $object->description,
+        '%term_id' => $object->tid,
+        '%vocabulary_name' => $vocabulary->name,
+        '%vocabulary_description' => $vocabulary->description,
+        '%vocabulary_id' => $vocabulary->vid,
+        )
+      );
+      break;
+    default:
+      // We are being called directly.
+      $node = $object;
   }
 
-  return $ret;
+  if (isset($node) && is_object($node)) {
+    $variables = array_merge($variables, array(
+      '%uid' => $node->uid,
+      '%node_url' => url('node/'. $node->nid, array('absolute' => TRUE)),
+      '%node_type' => check_plain(node_get_types('name', $node)),
+      '%title' => filter_xss($node->title),
+      '%teaser' => filter_xss($node->teaser),
+      '%body' => filter_xss($node->body),
+      )
+    );
+  }
+  $context['message'] = strtr($context['message'], $variables);
+  drupal_set_message($context['message']);
 }
 
 /**
- * Update blog, book and locale module permissions.
- *
- * Blog module got "edit own blog" replaced with the more granular "create
- * blog entries", "edit own blog entries" and "delete own blog entries"
- * permissions. We grant create and edit to previously privileged users, but
- * delete is not granted to be in line with other permission changes in Drupal 6.
- *
- * Book module's "edit book pages" was upgraded to the bogus "edit book content"
- * in Drupal 6 RC1 instead of "edit any book content", which would be correct.
- *
- * Locale module introduced "administer languages" and "translate interface"
- * in place of "administer locales".
- *
- * Modeled after system_update_6039().
+ * Implementation of a configurable Drupal action. Redirect user to a URL.
  */
-function system_update_6045() {
-  $ret = array();
-  $result = db_query("SELECT rid, perm FROM {permission} ORDER BY rid");
-  while ($role = db_fetch_object($result)) {
-    $renamed_permission = preg_replace('/(?<=^|,\ )edit\ own\ blog(?=,|$)/', 'create blog entries, edit own blog entries', $role->perm);
-    $renamed_permission = preg_replace('/(?<=^|,\ )edit\ book\ content(?=,|$)/', 'edit any book content', $renamed_permission);
-    $renamed_permission = preg_replace('/(?<=^|,\ )administer\ locales(?=,|$)/', 'administer languages, translate interface', $renamed_permission);
-    if ($renamed_permission != $role->perm) {
-      $ret[] = update_sql("UPDATE {permission} SET perm = '$renamed_permission' WHERE rid = $role->rid");
-    }
-  }
+function system_goto_action_form($context) {
+  $form['url'] = array(
+    '#type' => 'textfield',
+    '#title' => t('URL'),
+    '#description' => t('The URL to which the user should be redirected. This can be an internal URL like node/1234 or an external URL like http://drupal.org.'),
+    '#default_value' => isset($context['url']) ? $context['url'] : '',
+    '#required' => TRUE,
+  );
+  return $form;
+}
 
-  // Notify user that delete permissions may have been changed. This was in
-  // effect since system_update_6039(), but there was no user notice.
-  drupal_set_message('Drupal now has separate edit and delete permissions. Previously, users who were able to edit content were automatically allowed to delete it. For added security, delete permissions for individual core content types have been <strong>removed</strong> from all roles on your site (only roles with the "administer nodes" permission can now delete these types of content). If you would like to reenable any individual delete permissions, you can do this at the <a href="'. url('admin/user/permissions', array('fragment' => 'module-node')) .'">permissions page</a>.');
-  return $ret;
+function system_goto_action_submit($form, $form_state) {
+  return array(
+    'url' => $form_state['values']['url']
+  );
+}
+
+function system_goto_action($object, $context) {
+  drupal_goto($context['url']);
 }
 
 /**
- * Ensure that the file_directory_path variable is set (using the old 5.x
- * default, if necessary), so that the changed 6.x default won't break
- * existing sites.
+ * Generate an array of time zones and their local time&date.
  */
-function system_update_6046() {
-  $ret = array();
-  if (!variable_get('file_directory_path', FALSE)) {
-    variable_set('file_directory_path', 'files');
-    $ret[] = array('success' => TRUE, 'query' => "variable_set('file_directory_path')");
+function _system_zonelist() {
+  $timestamp = time();
+  $zonelist = array(-11, -10, -9.5, -9, -8, -7, -6, -5, -4, -3.5, -3, -2, -1, 0, 1, 2, 3, 3.5, 4, 5, 5.5, 5.75, 6, 6.5, 7, 8, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 14);
+  $zones = array();
+  foreach ($zonelist as $offset) {
+    $zone = $offset * 3600;
+    $zones[$zone] = format_date($timestamp, 'custom', variable_get('date_format_long', 'l, F j, Y - H:i') .' O', $zone);
   }
-  return $ret;
+  return $zones;
 }
 
 /**
- * Fix cache mode for blocks inserted in system_install() in fresh installs of previous RC.
+ * Checks whether the server is capable of issuing HTTP requests.
+ *
+ * The function sets the drupal_http_request_fail system variable to TRUE if
+ * drupal_http_request() does not work and then the system status report page
+ * will contain an error.
+ *
+ * @return
+ *  Whether the admin/reports/request-test page can be requested via HTTP
+ *  and contains the same output as if called via the menu system.
  */
-function system_update_6047() {
-  $ret = array();
-  $ret[] = update_sql("UPDATE {blocks} SET cache = -1 WHERE module = 'user' AND delta IN ('0', '1')");
-  $ret[] = update_sql("UPDATE {blocks} SET cache = -1 WHERE module = 'system' AND delta = '0'");
-  return $ret;
+function system_check_http_request() {
+  // Check whether we can do any request at all. First get the results for
+  // a very simple page which has access TRUE set via the menu system. Then,
+  // try to drupal_http_request() the same page and compare.
+  ob_start();
+  $path = 'admin/reports/request-test';
+  menu_execute_active_handler($path);
+  $nothing = ob_get_contents();
+  ob_end_clean();
+  $result = drupal_http_request(url($path, array('absolute' => TRUE)));
+  $works = isset($result->data) && $result->data == $nothing;
+  variable_set('drupal_http_request_fails', !$works);
+  return $works;
 }
 
 /**
- * @} End of "defgroup updates-5.x-to-6.x"
- * The next series of updates should start at 7000.
+ * Format the Powered by Drupal text.
+ *
+ * @ingroup themeable
  */
+function theme_system_powered_by($image_path) {
+  $image = theme('image', $image_path, t('Powered by Drupal, an open source content management system'), t('Powered by Drupal, an open source content management system'));
+  return l($image, 'http://drupal.org', array('html' => TRUE, 'absolute' => TRUE, 'external' => TRUE));
+}
