Index: modules/update/update.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.module,v
retrieving revision 1.19
diff -u -p -r1.19 update.module
--- modules/update/update.module	6 May 2008 12:18:53 -0000	1.19
+++ modules/update/update.module	19 May 2008 05:41:12 -0000
@@ -160,6 +160,9 @@ function update_theme() {
     'update_version' => array(
       'arguments' => array('version' => NULL, 'tag' => NULL, 'class' => NULL),
     ),
+    'update_unknown_version' => array(
+      'arguments' => array(),
+    ),
   );
 }
 
Index: modules/update/update.compare.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.compare.inc,v
retrieving revision 1.9
diff -u -p -r1.9 update.compare.inc
--- modules/update/update.compare.inc	14 Apr 2008 17:48:43 -0000	1.9
+++ modules/update/update.compare.inc	19 May 2008 05:41:12 -0000
@@ -74,6 +74,7 @@ function _update_process_info_list(&$pro
     }
 
     $project_name = $file->info['project'];
+    $file_version = isset($file->info['version']) ? $file->info['version'] : theme('update_unknown_version');
     if (!isset($projects[$project_name])) {
       // Only process this if we haven't done this project, since a single
       // project can have multiple modules or themes.
@@ -82,11 +83,34 @@ function _update_process_info_list(&$pro
         'info' => $file->info,
         'datestamp' => isset($file->info['datestamp']) ? $file->info['datestamp'] : 0,
         'includes' => array($file->name => $file->info['name']),
+        'included_versions' => array($file->name => $file_version),
         'project_type' => $project_name == 'drupal' ? 'core' : $project_type,
       );
     }
     else {
+      // Record the name and version of each module or theme.
       $projects[$project_name]['includes'][$file->name] = $file->info['name'];
+      $projects[$project_name]['included_versions'][$file->name] = $file_version;
+      // If we find an older datestamp, use that as the overall project
+      // value.  This is to try to catch cases where an out of date
+      // module might be running alongside up to date modules in the same
+      // project.
+      if (isset($file->info['datestamp']) && $file->info['datestamp'] < $projects[$project_name]['datestamp']) {
+        $projects[$project_name]['info'] = $file->info;
+        $projects[$project_name]['datestamp'] = $file->info['datestamp'];
+      }
+      // Even if the datestamps are the same, we still attempt to label
+      // the overall project with the oldest version string found in its
+      // component modules or themes.
+      elseif ((!isset($file->info['datestamp']) || $file->info['datestamp'] == $projects[$project_name]['datestamp']) && $file->info['version'] !== $projects[$project_name]['info']['version']) {
+        if (strnatcasecmp($file->info['version'], $projects[$project_name]['info']['version']) < 0) {
+          $projects[$project_name]['info'] = $file->info;
+        }
+      }
+      // We always store the most recent time that any of the .info files
+      // were changed, since this is used in update_get_available() to
+      // determine if any modules have been installed since the last time
+      // we checked for updates.
       $projects[$project_name]['info']['_info_file_ctime'] = max($projects[$project_name]['info']['_info_file_ctime'], $file->info['_info_file_ctime']);
     }
   }
@@ -152,7 +176,7 @@ function update_process_project_info(&$p
     else {
       // No version info available at all.
       $install_type = 'unknown';
-      $info['version'] = t('Unknown');
+      $info['version'] = theme('update_unknown_version');
       $info['major'] = -1;
     }
 
@@ -595,3 +619,13 @@ function update_project_cache($cid) {
   }
   return $projects;
 }
+
+/**
+ * Theme the message that is printed when the version of a project is
+ * unknown.
+ *
+ * @ingroup themeable
+ */
+function theme_update_unknown_version() {
+  return t('Unknown');
+}
Index: modules/update/update.report.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/update/update.report.inc,v
retrieving revision 1.12
diff -u -p -r1.12 update.report.inc
--- modules/update/update.report.inc	14 Apr 2008 17:48:43 -0000	1.12
+++ modules/update/update.report.inc	19 May 2008 05:41:12 -0000
@@ -177,9 +177,25 @@ function theme_update_report($data) {
     }
 
     $row .= '<div class="includes">';
-    sort($project['includes']);
-    $row .= t('Includes: %includes', array('%includes' => implode(', ', $project['includes'])));
-    $row .= "</div>\n";
+    asort($project['includes']);
+    // If there is a version mismatch within the project, print out the
+    // version strings along with the included modules.
+    $version_mismatch = (count(array_unique($project['included_versions'])) > 1);
+    if ($version_mismatch) {
+      foreach ($project['includes'] as $filename => $includes) {
+        $project['includes'][$filename] = check_plain($includes . ' (' . $project['included_versions'][$filename] . ')');
+        // Highlight the modules that are holding the overall project back.
+        if ($project['included_versions'][$filename] == $project['existing_version']) {
+          $project['includes'][$filename] = '<strong>' . $project['includes'][$filename] . '</strong>';
+        }
+      }
+    $row .= t('This project includes modules with conflicting versions: !includes', array('!includes' => '<em>' . implode(', ', $project['includes']) . '</em>'));
+    }
+    // Otherwise, just print the included modules.
+    else {
+      $row .= t('Includes: %includes', array('%includes' => implode(', ', $project['includes'])));
+    }
+    $row .= "</div>\n"; // includes div.
 
     $row .= "</div>\n"; // info div.
 
