Index: update_status.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/update_status/update_status.module,v
retrieving revision 1.83.2.45
diff -u -p -r1.83.2.45 update_status.module
--- update_status.module	4 Jun 2009 22:38:39 -0000	1.83.2.45
+++ update_status.module	10 Jun 2009 00:32:46 -0000
@@ -44,6 +44,16 @@ define('UPDATE_STATUS_NOT_CHECKED', -1);
  */
 define('UPDATE_STATUS_UNKNOWN', -2);
 
+/**
+ * There was a failure fetching available update data for this project.
+ */
+define('UPDATE_STATUS_NOT_FETCHED', -3);
+
+/**
+ * Maximum number of attempts to fetch available update data from a given host.
+ */
+define('UPDATE_STATUS_MAX_FETCH_ATTEMPTS', 2);
+
 
 /**
  * Implementation of hook_help().
@@ -432,6 +442,7 @@ function _update_status_requirement_chec
       break;
     case UPDATE_STATUS_UNKNOWN:
     case UPDATE_STATUS_NOT_CHECKED:
+    case UPDATE_STATUS_NOT_FETCHED:
       $requirement_label = isset($project['reason']) ? $project['reason'] : t('Can not determine status');
       $requirement['severity'] = REQUIREMENT_WARNING;      
       break;
@@ -573,6 +584,7 @@ function _update_status_message_text($ms
 
     case UPDATE_STATUS_UNKNOWN:
     case UPDATE_STATUS_NOT_CHECKED:
+    case UPDATE_STATUS_NOT_FETCHED:
       if ($msg_type == 'core') {
         $text = t('There was a problem determining the status of available updates for your version of Drupal.');
       }
@@ -594,7 +606,7 @@ function _update_status_message_text($ms
  */
 function update_status_manual_status() {
   if (update_status_refresh()) {
-    drupal_set_message(t('Fetched information about all available new releases and updates.'));
+    drupal_set_message(t('Attempted to fetch information about all available new releases and updates.'));
   }
   else {
     drupal_set_message(t('Unable to fetch any information on available new releases and updates.'), 'error');
@@ -923,6 +935,11 @@ function update_status_calculate_project
               'data' => t('This project is no longer supported, and is no longer available for download. Disabling everything included by this project is strongly recommended!'),
             );
             break;
+          case 'not-fetched':
+            $projects[$project]['status'] = UPDATE_STATUS_NOT_FETCHED;
+            $projects[$project]['reason'] = t('Failed to fetch available update data');
+            break;
+
           default:
             // Assume anything else (e.g. 'published') is valid and we should
             // perform the rest of the logic in this function.
@@ -1247,6 +1264,7 @@ function theme_update_status_report($dat
         break;
 
       case UPDATE_STATUS_UNKNOWN:
+      case UPDATE_STATUS_NOT_FETCHED:
         $class = 'unknown';
         $icon = theme('image', 'misc/watchdog-warning.png', t('unknown'), t('unknown'));
         break;
@@ -1413,6 +1431,7 @@ function theme_update_status_version($ve
  */
 function update_status_refresh() {
   global $base_url;
+  static $fail = array();
 
   // Since we're fetching new available update data, we want to clear
   // our cache of both the projects we care about, and the current update
@@ -1438,24 +1457,44 @@ function update_status_refresh() {
   // to clear out the stale data at this point.
   _update_status_cache_clear('update_status_available_releases');
   
+  $max_fetch_attempts = variable_get('update_status_max_fetch_attempts', UPDATE_STATUS_MAX_FETCH_ATTEMPTS);
+
   foreach ($projects as $key => $project) {
     $url = _update_status_build_fetch_url($project, $site_key);
-    $xml = drupal_http_request($url);
-    if (isset($xml->data)) {
-      $data[] = $xml->data;
+    $fetch_url_base = _update_status_get_fetch_url_base($project);
+    if (empty($fail[$fetch_url_base]) || count($fail[$fetch_url_base]) < $max_fetch_attempts) {
+      $xml = drupal_http_request($url);
+      if (isset($xml->data)) {
+        $data[] = $xml->data;
+      }
+      else {
+        // Connection likely broken; prepare to give up.
+        $fail[$fetch_url_base][$key] = 1;
+      }
+    }
+    else {
+      // Didn't bother trying to fetch.
+      $fail[$fetch_url_base][$key] = 1;
     }
   }
 
   if ($data) {
     $parser = new update_status_xml_parser;
     $available = $parser->parse($data);
+    // Record the projects where we failed to fetch data.
+    foreach ($fail as $fetch_url_base => $failures) {
+      foreach ($failures as $key => $value) {
+        $available[$key]['project_status'] = 'not-fetched';
+      }
+    }
     _update_status_cache_set('update_status_available_releases', serialize($available), time() + (60 * 60 * 24));
-    variable_set('update_status_last', time());
-    watchdog('update_status', t('Fetched information about all available new releases and updates.'), WATCHDOG_NOTICE, l(t('view'), 'admin/logs/updates'));
+    watchdog('update_status', t('Attempted to fetch information about all available new releases and updates.'), WATCHDOG_NOTICE, l(t('view'), 'admin/logs/updates'));
   }
   else {
     watchdog('update_status', 'Unable to fetch any information on available new releases and updates.', WATCHDOG_ERROR, l(t('view'), 'admin/logs/updates'));
   }
+  // Whether this worked or not, we did just (try to) check for updates.
+  variable_set('update_status_last', time());
   return $available;
 }
 
@@ -1475,12 +1514,8 @@ function update_status_refresh() {
  * @see update_status_get_projects()
  */
 function _update_status_build_fetch_url($project, $site_key = '') {
-  $default_url = variable_get('update_status_fetch_url', UPDATE_STATUS_DEFAULT_URL);
-  if (!isset($project['info']['project status url'])) {
-    $project['info']['project status url'] = $default_url;
-  }
   $name = $project['name'];
-  $url = $project['info']['project status url'];
+  $url = _update_status_get_fetch_url_base($project);
   $url .= '/'. $name .'/'. UPDATE_STATUS_CORE_VERSION;
   if (!empty($site_key)) {
     $url .= (strpos($url, '?') === TRUE) ? '&' : '?';
@@ -1495,6 +1530,22 @@ function _update_status_build_fetch_url(
 }
 
 /**
+ * Return the base of the URL to fetch available update data for a project.
+ *
+ * @param $project
+ *   The array of project information from update_status_get_projects().
+ * @return
+ *   The base of the URL used for fetching available update data. This does
+ *   not include the path elements to specify a particular project, version,
+ *   site_key, etc.
+ *
+ * @see _update_status_build_fetch_url()
+ */
+function _update_status_get_fetch_url_base($project) {
+  return isset($project['info']['project status url']) ? $project['info']['project status url'] : variable_get('update_status_fetch_url', UPDATE_STATUS_DEFAULT_URL);
+}
+
+/**
  * Internal helper to try to get the update information from the cache
  * if possible, and to refresh the cache when necessary.
  *
