? .DS_Store
? head.db
? menu_parent_selector_13.patch
? updates-395474-111.patch
? updates-395474-133.patch
? updates-395474-135.patch
? updates-395474-136.patch
? sites/default/files
? sites/default/settings.php
Index: update.php
===================================================================
RCS file: /cvs/drupal/drupal/update.php,v
retrieving revision 1.291
diff -u -p -r1.291 update.php
--- update.php	23 Jun 2009 12:06:09 -0000	1.291
+++ update.php	13 Jul 2009 04:12:38 -0000
@@ -651,102 +651,112 @@ function update_check_requirements() {
   }
 }
 
-// Some unavoidable errors happen because the database is not yet up-to-date.
-// Our custom error handler is not yet installed, so we just suppress them.
-ini_set('display_errors', FALSE);
-
-// We prepare a minimal bootstrap for the update requirements check to avoid
-// reaching the PHP memory limit.
-require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
-update_prepare_d7_bootstrap();
-
-// Determine if the current user has access to run update.php.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
-$update_access_allowed = !empty($update_free_access) || $user->uid == 1;
-
-// Only allow the requirements check to proceed if the current user has access
-// to run updates (since it may expose sensitive information about the site's
-// configuration).
-$op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
-if (empty($op) && $update_access_allowed) {
-  require_once DRUPAL_ROOT . '/includes/install.inc';
-  require_once DRUPAL_ROOT . '/includes/file.inc';
-  require_once DRUPAL_ROOT . '/modules/system/system.install';
-
-  // Load module basics.
-  include_once DRUPAL_ROOT . '/includes/module.inc';
-  $module_list['system']['filename'] = 'modules/system/system.module';
-  $module_list['filter']['filename'] = 'modules/filter/filter.module';
-  module_list(TRUE, FALSE, $module_list);
-  drupal_load('module', 'system');
-  drupal_load('module', 'filter');
-
-  // Set up $language, since the installer components require it.
-  drupal_init_language();
-
-  // Set up theme system for the maintenance page.
-  drupal_maintenance_theme();
-
-  // Check the update requirements for Drupal.
-  update_check_requirements();
-
-  // Redirect to the update information page if all requirements were met.
-  install_goto('update.php?op=info');
-}
-
-drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-drupal_maintenance_theme();
+/**
+ * Main update function: decides which forms to show and shows them.
+ */
+function update_run_updates() {
+  // Some unavoidable errors happen because the database is not yet up-to-date.
+  // Our custom error handler is not yet installed, so we just suppress them.
+  ini_set('display_errors', FALSE);
+
+  // We prepare a minimal bootstrap for the update requirements check to avoid
+  // reaching the PHP memory limit.
+  require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+  update_prepare_d7_bootstrap();
+
+  // Determine if the current user has access to run update.php.
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
+  global $user, $update_free_access;
+  $update_access_allowed = !empty($update_free_access) || $user->uid == 1;
+
+  // Only allow the requirements check to proceed if the current user has access
+  // to run updates (since it may expose sensitive information about the site's
+  // configuration).
+  $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
+  if (empty($op) && $update_access_allowed) {
+    require_once DRUPAL_ROOT . '/includes/install.inc';
+    require_once DRUPAL_ROOT . '/includes/file.inc';
+    require_once DRUPAL_ROOT . '/modules/system/system.install';
+
+    // Load module basics.
+    include_once DRUPAL_ROOT . '/includes/module.inc';
+    $module_list['system']['filename'] = 'modules/system/system.module';
+    $module_list['filter']['filename'] = 'modules/filter/filter.module';
+    module_list(TRUE, FALSE, $module_list);
+    drupal_load('module', 'system');
+    drupal_load('module', 'filter');
+
+    // Set up $language, since the installer components require it.
+    drupal_init_language();
 
-// Turn error reporting back on. From now on, only fatal errors (which are
-// not passed through the error handler) will cause a message to be printed.
-ini_set('display_errors', TRUE);
-
-// Only proceed with updates if the user is allowed to run them.
-if ($update_access_allowed) {
-
-  include_once DRUPAL_ROOT . '/includes/install.inc';
-  include_once DRUPAL_ROOT . '/includes/batch.inc';
-  drupal_load_updates();
+    // Set up theme system for the maintenance page.
+    drupal_maintenance_theme();
 
-  update_fix_d7_requirements();
-  update_fix_compatibility();
+    // Check the update requirements for Drupal.
+    update_check_requirements();
 
-  $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
-  switch ($op) {
-    // update.php ops
+    // Redirect to the update information page if all requirements were met.
+    install_goto('update.php?op=info');
+  }
 
-    case 'selection':
-      if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) {
-        $output = update_selection_page();
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+  drupal_maintenance_theme();
+  
+  // Turn error reporting back on. From now on, only fatal errors (which are
+  // not passed through the error handler) will cause a message to be printed.
+  ini_set('display_errors', TRUE);
+  
+  // Only proceed with updates if the user is allowed to run them.
+  if ($update_access_allowed) {
+  
+    include_once DRUPAL_ROOT . '/includes/install.inc';
+    include_once DRUPAL_ROOT . '/includes/batch.inc';
+    drupal_load_updates();
+  
+    update_fix_d7_requirements();
+    update_fix_compatibility();
+  
+    $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
+    switch ($op) {
+      // update.php ops
+  
+      case 'selection':
+        if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) {
+          $output = update_selection_page();
+          break;
+        }
+  
+      case 'Apply pending updates':
+        if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) {
+          update_batch();
+          break;
+        }
+  
+      case 'info':
+        $output = update_info_page();
         break;
-      }
-
-    case 'Apply pending updates':
-      if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) {
-        update_batch();
+  
+      case 'results':
+        $output = update_results_page();
         break;
-      }
-
-    case 'info':
-      $output = update_info_page();
-      break;
-
-    case 'results':
-      $output = update_results_page();
-      break;
-
-    // Regular batch ops : defer to batch processing API
-    default:
-      update_task_list('run');
-      $output = _batch_page();
-      break;
+  
+      // Regular batch ops : defer to batch processing API
+      default:
+        update_task_list('run');
+        $output = _batch_page();
+        break;
+    }
+  }
+  else {
+    $output = update_access_denied_page();
+  }
+  if (isset($output) && $output) {
+    // We defer the display of messages until all updates are done.
+    $progress_page = ($batch = batch_get()) && isset($batch['running']);
+    print theme('update_page', $output, !$progress_page);
   }
 }
-else {
-  $output = update_access_denied_page();
-}
-if (isset($output) && $output) {
-  // We defer the display of messages until all updates are done.
-  $progress_page = ($batch = batch_get()) && isset($batch['running']);
-  print theme('update_page', $output, !$progress_page);
+
+if ($_SERVER['SCRIPT_FILENAME'] == __FILE__) {
+  update_run_updates();
 }
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.722
diff -u -p -r1.722 system.module
--- modules/system/system.module	5 Jul 2009 18:00:10 -0000	1.722
+++ modules/system/system.module	13 Jul 2009 04:12:39 -0000
@@ -1268,27 +1268,28 @@ function system_filetransfer_backend_for
 function _system_filetransfer_backend_form_common() {
   $form = array();
   
-  $form['hostname'] = array (
+  $form['hostname'] = array(
     '#type' => 'textfield',
     '#title' => t('Host'),
     '#default_value' => 'localhost',
   );
-  
-  $form['port'] = array (
+
+  $form['port'] = array(
     '#type' => 'textfield',
     '#title' => t('Port'),
     '#default_value' => NULL,
   );
-  
-  $form['username'] = array (
+
+  $form['username'] = array(
     '#type' => 'textfield',
     '#title' => t('Username'),
   );
-  
-  $form['password'] = array (
+
+  $form['password'] = array(
     '#type' => 'password',
     '#title' => t('Password'),
     '#description' => t('This is not saved in the database and is only used to test the connection'),
+    '#filetransfer_save' => FALSE,
   );
   
   return $form;
Index: modules/update/update.admin.inc
===================================================================
RCS file: modules/update/update.admin.inc
diff -N modules/update/update.admin.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/update/update.admin.inc	13 Jul 2009 04:12:39 -0000
@@ -0,0 +1,241 @@
+<?php
+// $Id$
+
+/**
+ * Menu callback; main updates form.
+ */
+function update_update_form($form_state) {
+  $form = array();
+
+  if (isset($_SESSION['update_install_batch_results']) && $results = $_SESSION['update_install_batch_results']) {
+    unset($_SESSION['update_install_batch_results']);
+    if ($results['success']) {
+      drupal_set_message(t("Update was completed successfully!  Your site has been taken out of maintinance mode."));
+    }
+    drupal_set_message(t("Update failed! See the log below for more information. Your site is still in maintenance mode"), 'error');
+
+    $form['log'] = array(
+      '#type' => 'item',
+      '#title' => t('Update log'),
+      '#markup' => theme('item_list', $results['messages']),
+    );
+    return $form;
+  }
+  $form['#theme'] = 'update_available_updates_form';
+  if (!isset($form_state['values'])) {
+    $form['projects'] = array();
+    // First step.
+    $options = array();
+    if ($available = update_get_available(TRUE)) {
+      module_load_include('inc', 'update', 'update.compare');
+      $project_data = update_calculate_project_data($available);
+      foreach ($project_data as $name => $project) {
+        // Filter out projects which are dev versions, updated or core
+        if (($project['install_type'] != 'dev') && ($project['project_type'] != 'core')) {
+          switch ($project['status']) {
+            case UPDATE_NOT_SECURE:
+            case UPDATE_REVOKED:
+              $options[$name]['title'] .= t(' (Security Update)');
+              $options[$name]['#weight'] = -2;
+              $type = 'security';
+              break;
+            case UPDATE_NOT_SUPPORTED:
+              $type = 'unsupported';
+              $options[$name]['title'] .= t(' (Unsupported)');
+              $options[$name]['#weight'] = -1;
+              break;
+            case UPDATE_UNKNOWN:
+            case UPDATE_NOT_FETCHED:
+            case UPDATE_NOT_CHECKED:
+            case UPDATE_NOT_CURRENT:
+              $type = 'recommended';
+              break;
+            default:
+              // Continues out of the switch and then out of the foreach.
+              continue 2;
+          }
+          $options[$name]['title'] = l($project['title'], $project['link']);
+          if ($project['project_type'] == 'theme') {
+            $options[$name]['title'] .= t(' (Theme)');
+          }
+          $options[$name]['#attributes'] = array('class' => 'update-' . $type);
+          $options[$name]['installed_version'] = $project['existing_version'];
+          $options[$name]['recommended_version'] = l($project['recommended'], $project['releases'][$project['recommended']]['release_link'], array('attributes' => array('title' => t('Release notes for @project_name', array('@project_name' => $project['title'])))));
+        }
+      }
+    }
+    else {
+      $form['message'] = array(
+        '#markup' => t('There was a problem getting update information.  Please try again later.'),
+      );
+      return $form;
+    }
+
+    if (!count($options)) {
+      $form['message'] = array(
+        '#markup' => t('All of your projects are up to date.'),
+      );
+      return $form;
+    }
+    $form['projects'] = array(
+      '#type' => 'tableselect',
+      '#options' => $options,
+      '#header' => array('title' => array('data' => t('Name'), 'class' => 'update-project-name'), 'installed_version' => t('Installed version'), 'recommended_version' => t('Recommended version')),
+    );
+    
+    $form['#attached_css'][] = drupal_get_path('module', 'update') . '/update.css';
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Continue'),
+      '#weight' => 100,
+    );
+  }
+  else if (is_array($form_state['values']) && array_filter($form_state['values']['projects'])) {
+    $form['#attached_js'][] = drupal_get_path('module', 'update') . '/update.js';
+    // Get all the available ways to transfer files.
+    $available_backends = module_invoke_all('filetransfer_backends');
+    if (!count($available_backends)) {
+      // @TODO: Clean up this error handling
+      drupal_set_message(t('Unable to continue, not available methods of file transfer'), 'error');
+      return array();
+    }
+
+    $form['information']['#weight'] = -100;
+    $form['information']['backup_header'] = array(
+      '#prefix' => '<h3>',
+      '#value' => t('Step 1: Backup your site'),
+      '#suffix' => '</h3>',
+    );
+
+    $form['information']['backup_message'] = array(
+      '#prefix' => '<p>',
+      '#value' => t('We do not currently have a web based backup tool. <a href="@backup_url">Learn more about how to take a backup</a>.', array('@backup_url' => url('http://drupal.org/node/22281'))),
+      '#suffix' => '</p>',
+    );
+
+    $form['information']['main_header'] = array(
+      '#prefix' => '<h3>',
+      '#value' => t('Step 2: Provide your server connection details'),
+      '#suffix' => '</h3>',
+    );
+
+    uasort($available_backends, 'drupal_sort_weight');
+
+    // Decide on a default backend.
+    if (isset($form_state['values']['connection_settings']['update_filetransfer_default'])) {
+      $update_filetransfer_default = $form_state['values']['connection_settings']['update_filetransfer_default'];
+    }
+    elseif ($update_filetransfer_default = variable_get('update_filetransfer_default', NULL));
+    else {
+      $update_filetransfer_default = key($available_backends);
+    }
+
+    $form['connection_settings']['#tree'] = TRUE;
+    $form['connection_settings']['update_filetransfer_default'] = array(
+      '#type' => 'select',
+      '#title' => t('Connection method'),
+      '#default_value' => array($update_filetransfer_default),
+    );
+
+    // Build a hidden fieldset for each one.
+    foreach ($available_backends as $name => $backend) {
+      $form['connection_settings']['update_filetransfer_default']['#options'][$name] = $backend['title'];
+      $form['connection_settings'][$name] = array (
+        '#type' => 'fieldset',
+        '#attributes' => array('class' => "filetransfer-$name filetransfer"),
+        '#title' => t('@backend connection settings', array('@backend' => $backend['title'])),
+      );
+      $current_settings = variable_get("update_filetransfer_connection_settings_" . $name, array());
+      $form['connection_settings'][$name] += system_get_filetransfer_settings_form($name, $current_settings);
+    }
+
+    $form['submit'] = array(
+      '#name' => 'process_updates',
+      '#type' => 'submit',
+      '#value' => (variable_get('site_offline', FALSE) == FALSE) ? t('Put site into maintenance mode and install updates') : t('Install updates'),
+      '#weight' => 100,
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Validate function for the main update form.
+ * 
+ * @see update_update_form
+ */
+function update_update_form_validate($form, &$form_state) {
+  if (isset($form_state['values']['connection_settings'])) {
+    $backend = $form_state['values']['connection_settings']['update_filetransfer_default'];
+    $filetransfer = update_get_filetransfer($backend, $form_state['values']['connection_settings'][$backend]);
+    try {
+      $filetransfer->connect();
+    }
+    catch(Exception $e) {
+      form_set_error('connection_settings', $e->getMessage());
+    }
+  }
+}
+
+/**
+ * Submit function for the main update form.
+ * 
+ * @see update_update_form
+ */
+function update_update_form_submit($form, &$form_state) {
+  if ($form_state['clicked_button']['#name'] == 'process_updates') {
+    // Save the connection settings to the DB.
+    $filetransfer_backend = $form_state['values']['connection_settings']['update_filetransfer_default'];
+
+    $connection_settings = array();
+    foreach ($form_state['values']['connection_settings'][$filetransfer_backend] as $key => $value) {
+      if (!isset($form['connection_settings'][$filetransfer_backend][$key]['#filetransfer_save']) ||
+        $form['connection_settings'][$filetransfer_backend][$key]['#filetransfer_save']) {
+        $connection_settings[$key] = $value;
+      }
+    }
+    // Set this one as the default update method.
+    variable_set('update_filetransfer_default', $filetransfer_backend);
+    // Save the connection settings minus the password.
+    variable_set("update_filetransfer_connection_settings_" . $filetransfer_backend, $connection_settings);
+    
+    $operations = array();
+    foreach ($form_state['storage']['projects'] as $project) {
+      // Put this in the begining (download everything first)
+      $operations[] = array('update_get_extension', array($project));
+      // Put these on the end
+      $operations[] = array(
+        'update_copy_extension',
+        array(
+          $project,
+          update_get_filetransfer($filetransfer_backend, $form_state['values']['connection_settings'][$filetransfer_backend])
+        ),
+      );
+    }
+    $batch = array(
+      'title' => t('Installing updates'),
+      'init_message' => t('Preparing update operation'),
+      'operations' => $operations,
+      'finished' => 'update_batch_finished',
+    );
+    batch_set($batch);
+  }
+  else {
+    $form_state['storage']['projects'] = array_keys(array_filter($form_state['values']['projects']));
+  }
+}
+
+/**
+ * Theme main updates page.
+ *
+ * @ingroup themeable
+ */
+function theme_update_available_updates_form($form) {
+  $last = variable_get('update_last_check', 0);
+  $output = '<div class="update checked">' . ($last ? t('Last checked: @time ago', array('@time' => format_interval(REQUEST_TIME - $last))) : t('Last checked: never'));
+  $output .= ' <span class="check-manually">(' . l(t('Check manually'), 'admin/reports/updates/check') . ')</span>';
+  $output .= "</div>\n";
+  $output .= drupal_render_children($form);
+  return $output;
+}
Index: modules/update/update.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.css,v
retrieving revision 1.5
diff -u -p -r1.5 update.css
--- modules/update/update.css	29 Apr 2009 03:57:21 -0000	1.5
+++ modules/update/update.css	13 Jul 2009 04:12:39 -0000
@@ -1,110 +1,10 @@
-/* $Id: update.css,v 1.5 2009/04/29 03:57:21 webchick Exp $ */
+/* $Id$ */
 
-.update .project {
-  font-weight: bold;
-  font-size: 110%;
-  padding-left: .25em; /* LTR */
-  height: 22px;
-}
-
-.update .version-status {
-  float: right; /* LTR */
-  padding-right: 10px; /* LTR */
-  font-size: 110%;
-  height: 20px;
-}
-
-.update .version-status .icon {
-  padding-left: .5em; /* LTR */
-}
-
-.update .version-date {
-  white-space: nowrap;
-}
-
-.update .info {
-  margin: 0;
-  padding: 1em 1em .25em 1em;
-}
-
-.update tr td {
-  border-top: 1px solid #ccc;
-  border-bottom: 1px solid #ccc;
-}
-
-.update tr.error {
+table tbody tr.update-security,
+table tbody tr.update-unsupported {
   background: #fcc;
 }
 
-.update tr.error .version-recommended {
-  background: #fdd;
-}
-
-.update tr.ok {
-  background: #dfd;
-}
-
-.update tr.warning {
-  background: #ffd;
-}
-
-.update tr.warning .version-recommended {
-  background: #ffe;
-}
-
-.current-version, .new-version {
-  direction: ltr; /* Note: version numbers should always be LTR. */
-}
-
-.update tr.unknown {
-  background: #ddd;
-}
-
-table.update,
-.update table.version {
-  width: 100%;
-  margin-top: .5em;
-}
-
-.update table.version tbody {
-  border: none;
-}
-
-.update table.version tr,
-.update table.version td {
-  line-height: .9em;
-  padding: 0;
-  margin: 0;
-  border: none;
-}
-
-.update table.version .version-title {
-  padding-left: 1em; /* LTR */
-  width: 14em;
-}
-
-.update table.version .version-details {
-  padding-right: .5em; /* LTR */
-}
-
-.update table.version .version-links {
-  text-align: right; /* LTR */
-  padding-right: 1em; /* LTR */
-}
-
-.update table.version-security .version-title {
-  color: #970F00;
-}
-
-.update table.version-recommended-strong .version-title {
-  font-weight: bold;
-}
-
-.update .security-error {
-  font-weight: bold;
-  color: #970F00;
-}
-
-.update .check-manually {
-  padding-left: 1em; /* LTR */
-}
+th.update-project-name {
+  width: 50%;
+}
\ No newline at end of file
Index: modules/update/update.info
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.info,v
retrieving revision 1.5
diff -u -p -r1.5 update.info
--- modules/update/update.info	11 Oct 2008 02:33:12 -0000	1.5
+++ modules/update/update.info	13 Jul 2009 04:12:39 -0000
@@ -7,6 +7,7 @@ core = 7.x
 files[] = update.module
 files[] = update.compare.inc
 files[] = update.fetch.inc
-files[] = update.report.inc
+files[] = update.admin.inc
 files[] = update.settings.inc
 files[] = update.install
+files[] = update.js
Index: modules/update/update.js
===================================================================
RCS file: modules/update/update.js
diff -N modules/update/update.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/update/update.js	13 Jul 2009 04:12:39 -0000
@@ -0,0 +1,13 @@
+// $Id$
+(function ($) {
+
+Drupal.behaviors.updateFileTransferForm = {
+  attach: function(context) {
+    $('#edit-connection-settings-update-filetransfer-default').change(function() {
+      $('.filetransfer').hide().filter('.filetransfer-' + $(this).val()).show();
+    });
+    $('.filetransfer').hide().filter('.filetransfer-' + $('#edit-connection-settings-update-filetransfer-default').val()).show();
+  }
+}
+
+})(jQuery);
\ No newline at end of file
Index: modules/update/update.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.module,v
retrieving revision 1.37
diff -u -p -r1.37 update.module
--- modules/update/update.module	8 Jun 2009 05:00:11 -0000	1.37
+++ modules/update/update.module	13 Jul 2009 04:12:39 -0000
@@ -69,8 +69,7 @@ function update_help($path, $arg) {
     case 'admin/reports/updates':
       global $base_url;
       $output = '<p>' . t('Here you can find information about available updates for your installed modules and themes. Note that each module or theme is part of a "project", which may or may not have the same name, and might include multiple modules or themes within it.') . '</p>';
-      $output .= '<p>' . t('To extend the functionality or to change the look of your site, a number of contributed <a href="@modules">modules</a> and <a href="@themes">themes</a> are available.', array('@modules' => 'http://drupal.org/project/modules', '@themes' => 'http://drupal.org/project/themes')) . '</p>';
-      $output .= '<p>' . t('Each time Drupal core or a contributed module or theme is updated, it is important that <a href="@update-php">update.php</a> is run.', array('@update-php' => url($base_url . '/update.php', array('external' => TRUE)))) . '</p>';
+
       return $output;
     case 'admin/build/themes':
     case 'admin/build/modules':
@@ -129,7 +128,8 @@ function update_menu() {
   $items['admin/reports/updates'] = array(
     'title' => 'Available updates',
     'description' => 'Get a status report about available updates for your installed modules and themes.',
-    'page callback' => 'update_status',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('update_update_form'),
     'access arguments' => array('administer site configuration'),
     'weight' => 10,
   );
@@ -155,15 +155,9 @@ function update_menu() {
  */
 function update_theme() {
   return array(
-    'update_settings' => array(
+    'update_available_updates_form' => array(
       'arguments' => array('form' => NULL),
     ),
-    'update_report' => array(
-      'arguments' => array('data' => NULL),
-    ),
-    'update_version' => array(
-      'arguments' => array('version' => NULL, 'tag' => NULL, 'class' => NULL),
-    ),
   );
 }
 
@@ -632,3 +626,209 @@ function update_flush_caches() {
 /**
  * @} End of "defgroup update_status_cache".
  */
+
+/**
+ * Get the latest version of a project.
+ */
+function _update_get_latest_version($name) {
+  if ($available = update_get_available(FALSE)) {
+    module_load_include('inc', 'update', 'update.compare');
+    $extension_data = update_calculate_project_data($available);
+    $project = $extension_data[$name];
+    return $project['releases'][$project['latest_version']];
+  }
+}
+
+/**
+ * Get a file from the server, or if it was already downloaded, get the local
+ * path to the file.
+ * 
+ * @param $url
+ *   The URL of the file on the server.
+ */
+function update_get_file($url) {
+  // Get each of the specified files.
+  $parsed_url = parse_url($url);
+  $local = file_directory_temp() . '/update-cache/' . basename($parsed_url['path']);
+  if (!file_exists(file_directory_temp() . '/update-cache/')) {
+    mkdir(file_directory_temp() . '/update-cache/');
+  }
+  // Check the cache and download the file if needed.
+  if (!file_exists($local)) {
+    return system_retrieve_file($url, $local);
+  }
+  else {
+    return $local;
+  }
+}
+
+/**
+ * Untar a file, using the Archive_Tar class.
+ */
+function update_untar($file) {
+  $extraction_dir = file_directory_temp() . '/update-extraction';
+  if (!file_exists($extraction_dir)) {
+    mkdir($extraction_dir);
+  }
+  $archive_tar = new Archive_Tar($file);
+  return $archive_tar->extract($extraction_dir);
+}
+
+/**
+ * Download an extension from the server and put it in a temporary cache.
+ */
+function update_get_extension($extension_name, &$context) {
+  if (!isset($context['sandbox']['started'])) {
+    $context['sandbox']['started'] = TRUE;
+    $context['message'] = t('Downloading %extension', array('%extension' => $extension_name));
+    $context['finished'] = 0;
+    return;
+  }
+  $latest_version = _update_get_latest_version($extension_name);
+  if (update_get_file($latest_version['download_link'])) {
+    watchdog('update', t('Downloaded %extension to %local_cache', array('%extension' => $extension_name, '%local_cache' => $local_cache)));
+  }
+  else {
+    $context['success'] = FALSE;
+    $content['results'][] = t('Failed to download %extension', array('%extension' => $extension_name));
+  }
+  
+  $context['finished'] = 1;
+}
+
+/**
+ * Copy an extension to it's proper place.
+ */
+function update_copy_extension($extension_name, $filetransfer, &$context) {
+  if (!isset($context['sandbox']['starting'])) {
+    $context['sandbox']['starting'] = 1;
+    $context['message'] = t('Copying %extension to server', array('%extension' => $extension_name));
+    $context['finished'] = 0;
+    return;
+  }
+
+  $latest_version = _update_get_latest_version($extension_name);
+  $local_cache = update_get_file($latest_version['download_link']);
+
+  list($type, $location) = _update_get_extension_type_and_location($project);
+  $extension_destination_dir = DRUPAL_ROOT . '/' . $location;
+  if (!$extension_destination_dir) {
+    throw new Exception(t("Unable to find %extension_name", array('%extension_name' => $extension_destination_dir)));
+  }
+
+  if (update_untar($local_cache)) {
+    $extension_source_dir = file_directory_temp() . '/update-extraction/' . $extension_name;  
+  }
+  try {
+    $filetransfer->removeDirectory($extension_destination_dir);
+    $filetransfer->copyDirectory($extension_source_dir, $extension_destination_dir);
+  }
+  catch (Exception $e) {
+    drupal_set_message(t($e->getMessage(), $e->arguments), 'error');
+    // Some better error handling is needed, but batch API doesn't seem to support any.
+    throw $e;
+  }
+  $context['finished'] = 1;
+}
+
+/**
+ * Helper function, returns a an associative array of an extension's type and
+ * location returns false on failure.
+ */
+function _update_get_extension_type_and_location($name) {
+  foreach (array('module', 'theme') as $type) {
+    if ($dir = drupal_get_path($type, $name)) {
+      return array('type' => $type, 'location' => $dir);
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Set the batch to run the update functions.
+ */
+function update_update_extensions($projects, &$context) {
+  $operations = array();
+  include_once './update.php';
+
+  foreach (_update_get_schema_updates($project) as $update) {
+    $operations[] = array('update_do_one', array($project, $update));  
+  }
+  
+  $batch = array(
+    'title' => t('Installing updates'),
+    'init_message' => t('Preparing update operation'),
+    'operations' => $operations,
+    'finished' => 'update_batch_finished',
+  );
+  batch_set($batch);
+}
+
+/**
+ * Run a single update. This is a wrapper around update_do_one, which includes
+ * the files needed.
+ * 
+ * @see update_do_one
+ */
+function update_run_update($project, $update, &$context) {
+  include_once './update.php';
+  module_load_include('install', $project);
+  update_do_one($project, $update, $context);
+}
+
+/**
+ * Batch callback for when the batch is finished.
+ */
+function update_batch_finished($success, $results) {
+  if ($success) {
+    variable_set('site_offline', FALSE);
+  }
+  $_SESSION['update_batch_results']['success'] = $success;
+  $_SESSION['update_batch_results']['messages'] = $results;
+}
+
+/**
+ * Get a filetransfer class.
+ * 
+ * @param $method
+ *   The filetransfer method to get the class for.
+ * @param $overrides
+ *   A set of overrides over the defaults.
+ */
+function update_get_filetransfer($method, $overrides = array()) {
+  // Fire up the connection class
+  $settings = variable_get("update_filetransfer_connection_settings_" . $method, array());
+  $settings = array_merge($settings, $overrides);
+  $available_backends = module_invoke_all('filetransfer_backends');
+  $filetransfer = call_user_func_array($available_backends[$method]['class'] . '::factory', array(DRUPAL_ROOT, $settings));
+  return $filetransfer;
+}
+
+/**
+ * Returns the available updates for a given module in an array
+ *
+ * @param $project
+ *  The name of the module.
+ */
+function _update_get_schema_updates($project) {
+  list($type, $location) = _update_get_extension_type_and_location($project);
+  if ($type != 'module') {
+    return array();
+  }
+  module_load_include('install', $project);
+  
+  if (!$updates = drupal_get_schema_versions($project)) {
+    return array();
+  }
+  $updates_to_run = array();
+  $version = drupal_get_installed_schema_version($project, FALSE);
+  $max_version = max($updates);
+  if ($version < $max_version) {
+    foreach ($updates as $update) {
+      if ($update > $version) {
+        $updates_to_run[] = $update;
+      }
+    }
+  }
+  return $updates_to_run;
+}
Index: modules/update/update.report.inc
===================================================================
RCS file: modules/update/update.report.inc
diff -N modules/update/update.report.inc
--- modules/update/update.report.inc	6 Jun 2009 06:26:13 -0000	1.18
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,243 +0,0 @@
-<?php
-// $Id: update.report.inc,v 1.18 2009/06/06 06:26:13 webchick Exp $
-
-/**
- * @file
- * Code required only when rendering the available updates report.
- */
-
-/**
- * Menu callback. Generate a page about the update status of projects.
- */
-function update_status() {
-  if ($available = update_get_available(TRUE)) {
-    module_load_include('inc', 'update', 'update.compare');
-    $data = update_calculate_project_data($available);
-    return theme('update_report', $data);
-  }
-  else {
-    return theme('update_report', _update_no_data());
-  }
-}
-
-/**
- * Theme project status report.
- *
- * @ingroup themeable
- */
-function theme_update_report($data) {
-  $last = variable_get('update_last_check', 0);
-  $output = '<div class="update checked">' . ($last ? t('Last checked: @time ago', array('@time' => format_interval(REQUEST_TIME - $last))) : t('Last checked: never'));
-  $output .= ' <span class="check-manually">(' . l(t('Check manually'), 'admin/reports/updates/check') . ')</span>';
-  $output .= "</div>\n";
-
-  if (!is_array($data)) {
-    $output .= '<p>' . $data . '</p>';
-    return $output;
-  }
-
-  $header = array();
-  $rows = array();
-
-  $notification_level = variable_get('update_notification_threshold', 'all');
-
-  foreach ($data as $project) {
-    switch ($project['status']) {
-      case UPDATE_CURRENT:
-        $class = 'ok';
-        $icon = theme('image', 'misc/watchdog-ok.png', t('ok'), t('ok'));
-        break;
-      case UPDATE_UNKNOWN:
-      case UPDATE_NOT_FETCHED:
-        $class = 'unknown';
-        $icon = theme('image', 'misc/watchdog-warning.png', t('warning'), t('warning'));
-        break;
-      case UPDATE_NOT_SECURE:
-      case UPDATE_REVOKED:
-      case UPDATE_NOT_SUPPORTED:
-        $class = 'error';
-        $icon = theme('image', 'misc/watchdog-error.png', t('error'), t('error'));
-        break;
-      case UPDATE_NOT_CHECKED:
-      case UPDATE_NOT_CURRENT:
-      default:
-        $class = 'warning';
-        $icon = theme('image', 'misc/watchdog-warning.png', t('warning'), t('warning'));
-        break;
-    }
-
-    $row = '<div class="version-status">';
-    switch ($project['status']) {
-      case UPDATE_NOT_SECURE:
-        $row .= '<span class="security-error">' . t('Security update required!') . '</span>';
-        break;
-      case UPDATE_REVOKED:
-        $row .= '<span class="revoked">' . t('Revoked!') . '</span>';
-        break;
-      case UPDATE_NOT_SUPPORTED:
-        $row .= '<span class="not-supported">' . t('Not supported!') . '</span>';
-        break;
-      case UPDATE_NOT_CURRENT:
-        $row .= '<span class="not-current">' . t('Update available') . '</span>';
-        break;
-      case UPDATE_CURRENT:
-        $row .= '<span class="current">' . t('Up to date') . '</span>';
-        break;
-      default:
-        $row .= check_plain($project['reason']);
-        break;
-    }
-    $row .= '<span class="icon">' . $icon . '</span>';
-    $row .= "</div>\n";
-
-    $row .= '<div class="project">';
-    if (isset($project['title'])) {
-      if (isset($project['link'])) {
-        $row .= l($project['title'], $project['link']);
-      }
-      else {
-        $row .= check_plain($project['title']);
-      }
-    }
-    else {
-      $row .= check_plain($project['name']);
-    }
-    $row .= ' ' . check_plain($project['existing_version']);
-    if ($project['install_type'] == 'dev' && !empty($project['datestamp'])) {
-      $row .= ' <span class="version-date">(' . format_date($project['datestamp'], 'custom', 'Y-M-d') . ')</span>';
-    }
-    $row .= "</div>\n";
-
-    $row .= "<div class=\"versions\">\n";
-
-    if (isset($project['recommended'])) {
-      if ($project['status'] != UPDATE_CURRENT || $project['existing_version'] !== $project['recommended']) {
-
-        // First, figure out what to recommend.
-        // If there's only 1 security update and it has the same version we're
-        // recommending, give it the same CSS class as if it was recommended,
-        // but don't print out a separate "Recommended" line for this project.
-        if (!empty($project['security updates']) && count($project['security updates']) == 1 && $project['security updates'][0]['version'] === $project['recommended']) {
-          $security_class = ' version-recommended version-recommended-strong';
-        }
-        else {
-          $security_class = '';
-          $version_class = 'version-recommended';
-          // Apply an extra class if we're displaying both a recommended
-          // version and anything else for an extra visual hint.
-          if ($project['recommended'] !== $project['latest_version']
-              || !empty($project['also'])
-              || ($project['install_type'] == 'dev'
-                && isset($project['dev_version'])
-                && $project['latest_version'] !== $project['dev_version']
-                && $project['recommended'] !== $project['dev_version'])
-              || (isset($project['security updates'][0])
-                && $project['recommended'] !== $project['security updates'][0])
-              ) {
-            $version_class .= ' version-recommended-strong';
-          }
-          $row .= theme('update_version', $project['releases'][$project['recommended']], t('Recommended version:'), $version_class);
-        }
-
-        // Now, print any security updates.
-        if (!empty($project['security updates'])) {
-          foreach ($project['security updates'] as $security_update) {
-            $row .= theme('update_version', $security_update, t('Security update:'), 'version-security' . $security_class);
-          }
-        }
-      }
-
-      if ($project['recommended'] !== $project['latest_version']) {
-        $row .= theme('update_version', $project['releases'][$project['latest_version']], t('Latest version:'), 'version-latest');
-      }
-      if ($project['install_type'] == 'dev'
-          && $project['status'] != UPDATE_CURRENT
-          && isset($project['dev_version'])
-          && $project['recommended'] !== $project['dev_version']) {
-        $row .= theme('update_version', $project['releases'][$project['dev_version']], t('Development version:'), 'version-latest');
-      }
-    }
-
-    if (isset($project['also'])) {
-      foreach ($project['also'] as $also) {
-        $row .= theme('update_version', $project['releases'][$also], t('Also available:'), 'version-also-available');
-      }
-    }
-
-    $row .= "</div>\n"; // versions div.
-
-    $row .= "<div class=\"info\">\n";
-    if (!empty($project['extra'])) {
-      $row .= '<div class="extra">' . "\n";
-      foreach ($project['extra'] as $key => $value) {
-        $row .= '<div class="' . $value['class'] . '">';
-        $row .= check_plain($value['label']) . ': ';
-        $row .= theme('placeholder', $value['data']);
-        $row .= "</div>\n";
-      }
-      $row .= "</div>\n";  // extra div.
-    }
-
-    $row .= '<div class="includes">';
-    sort($project['includes']);
-    $row .= t('Includes: %includes', array('%includes' => implode(', ', $project['includes'])));
-    $row .= "</div>\n";
-
-    $row .= "</div>\n"; // info div.
-
-    if (!isset($rows[$project['project_type']])) {
-      $rows[$project['project_type']] = array();
-    }
-    $rows[$project['project_type']][] = array(
-      'class' => $class,
-      'data' => array($row),
-    );
-  }
-
-  $project_types = array(
-    'core' => t('Drupal core'),
-    'module' => t('Modules'),
-    'theme' => t('Themes'),
-    'disabled-module' => t('Disabled modules'),
-    'disabled-theme' => t('Disabled themes'),
-  );
-  foreach ($project_types as $type_name => $type_label) {
-    if (!empty($rows[$type_name])) {
-      $output .= "\n<h3>" . $type_label . "</h3>\n";
-      $output .= theme('table', $header, $rows[$type_name], array('class' => 'update'));
-    }
-  }
-  drupal_add_css(drupal_get_path('module', 'update') . '/update.css');
-  return $output;
-}
-
-/**
- * Theme the version display of a project.
- *
- * @ingroup themeable
- */
-function theme_update_version($version, $tag, $class) {
-  $output = '';
-  $output .= '<table class="version ' . $class . '">';
-  $output .= '<tr>';
-  $output .= '<td class="version-title">' . $tag . "</td>\n";
-  $output .= '<td class="version-details">';
-  $output .= l($version['version'], $version['release_link']);
-  $output .= ' <span class="version-date">(' . format_date($version['date'], 'custom', 'Y-M-d') . ')</span>';
-  $output .= "</td>\n";
-  $output .= '<td class="version-links">';
-  $links = array();
-  $links['update-download'] = array(
-    'title' => t('Download'),
-    'href' => $version['download_link'],
-  );
-  $links['update-release-notes'] = array(
-    'title' => t('Release notes'),
-    'href' => $version['release_link'],
-  );
-  $output .= theme('links', $links);
-  $output .= '</td>';
-  $output .= '</tr>';
-  $output .= "</table>\n";
-  return $output;
-}
