Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.30
diff -u -r1.30 system.admin.inc
--- modules/system/system.admin.inc	27 Nov 2007 21:06:28 -0000	1.30
+++ modules/system/system.admin.inc	2 Dec 2007 05:45:49 -0000
@@ -566,6 +566,7 @@
  *   The form array.
  */
 function system_modules($form_state = array()) {
+  include_once './includes/install.inc'; // for uninstallation checks
   drupal_rebuild_theme_registry();
   node_types_rebuild();
   menu_rebuild();
@@ -585,6 +586,21 @@
 
   // Create storage for disabled modules as browser will disable checkboxes.
   $form['disabled_modules'] = array('#type' => 'value', '#value' => array());
+  
+  // Create links for module dashboard
+  $form['module_menu'] = array('#type' => 'value', '#value' => array());
+  
+  // Retrieve help links that 'help' knows about
+  $help_menu = module_invoke('help', 'menu');
+  $help_links = array();
+  if (is_array($help_menu)) {
+    foreach ($help_menu as $path => $info) {
+      if (!isset($info['title'])) continue;
+      $help_links[$info['title']] = $path;
+    }
+  }
+  
+  
 
   // Traverse the files, checking for compatibility
   $incompatible_core = array();
@@ -605,6 +621,7 @@
   $throttle = array();
   // Traverse the files retrieved and build the form.
   foreach ($files as $filename => $file) {
+    module_load_install($filename); // so that we can inspect hooks, SECURITY RISK!
     $form['name'][$filename] = array('#value' => $file->info['name']);
     $form['version'][$filename] = array('#value' => $file->info['version']);
     $form['description'][$filename] = array('#value' => t($file->info['description']));
@@ -621,6 +638,14 @@
     if ($file->throttle) {
       $throttle[] = $file->name;
     }
+    
+    $menu = system_get_module_admin_tasks($filename);
+    if (isset($help_links[$filename])) {
+      $form['module_menu']['#value'][$filename][] = '<a href="'. url($help_links[$filename]) .'">'. t('Help') .'</a>';
+    }
+    foreach ($menu as $link) {
+      $form['module_menu']['#value'][$filename][] = $link;
+    }
 
     $dependencies = array();
     // Check for missing dependencies.
@@ -680,6 +705,13 @@
     $disabled[] = $required;
     $form['disabled_modules']['#value'][$required] = TRUE;
   }
+  
+  // Determine which modules can be uninstalled
+  $uninstallable_modules = _system_modules_get_uninstallable_modules();
+  while ($module = db_fetch_object($uninstallable_modules)) {
+    if (!module_hook($module->name, 'uninstall')) continue;
+    $form['module_menu']['#value'][$module->name][] = '<a href="'. url('admin/build/modules/uninstall/confirm/'. $module->name) .'">'. t('Uninstall') .'</a>';
+  }
 
   // Handle status checkboxes, including overriding
   // the generated checkboxes for required modules.
@@ -716,7 +748,6 @@
     '#value' => t('Save configuration'),
   );
   $form['#action'] = url('admin/build/modules/list/confirm');
-
   return $form;
 }
 
@@ -936,7 +967,7 @@
   $form = array();
 
   // Pull all disabled modules from the system table.
-  $disabled_modules = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' AND status = 0 AND schema_version > %d ORDER BY name", SCHEMA_UNINSTALLED);
+  $disabled_modules = _system_modules_get_uninstallable_modules();
   while ($module = db_fetch_object($disabled_modules)) {
 
     // Grab the module info
@@ -951,6 +982,18 @@
       $options[$module->name] = '';
     }
   }
+  
+  if (arg(4) == 'confirm' && $module = arg(5)) {
+    if (isset($form['modules'][$module])) {
+      $storage['uninstall'][$module] = $module;
+      if ($confirm_form = system_modules_uninstall_confirm_form($storage)) {
+        return $confirm_form;
+      }
+    }
+    else {
+      form_set_error('system_modules_uninstall', 'Cannot uninstall '. $module .'; module either does not exist or is active.');
+    }
+  }
 
   // Only build the rest of the form if there are any modules available to uninstall.
   if (!empty($options)) {
@@ -1055,6 +1098,14 @@
 }
 
 /**
+ * Returns a list of modules that have been deactivated, and thus
+ * are eligible for uninstallation.
+ */
+function _system_modules_get_uninstallable_modules() {
+  return db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' AND status = 0 AND schema_version > %d ORDER BY name", SCHEMA_UNINSTALLED);
+}
+
+/**
  * Form builder; The general site information form.
  *
  * @ingroup forms
@@ -1931,6 +1982,10 @@
     foreach ($modules as $key => $module) {
       $row = array();
       $description = drupal_render($form['description'][$key]);
+      if (isset($form['module_menu']['#value'][$key])) {
+        // add module links
+        $description .= '<div class="menu">'. t('Menu: ') . implode(' | ', $form['module_menu']['#value'][$key]) .'</div>';
+      }
       if (isset($form['status']['#incompatible_modules_core'][$key])) {
         unset($form['status'][$key]);
         $status = theme('image', 'misc/watchdog-error.png', t('incompatible'), t('Incompatible with this version of Drupal core'));
@@ -1963,7 +2018,11 @@
 
       $row[] = drupal_render($form['version'][$key]);
       $row[] = array('data' => $description, 'class' => 'description');
-      $rows[] = $row;
+      
+      $extended_row = array('data' => $row);
+      if ($form['status'][$key]['#value']) $extended_row['class'] = 'enabled';
+      
+      $rows[] = $extended_row;
     }
     $fieldset = array(
       '#title' => t($package),
Index: modules/system/system.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.css,v
retrieving revision 1.41
diff -u -r1.41 system.css
--- modules/system/system.css	20 Nov 2007 10:18:43 -0000	1.41
+++ modules/system/system.css	1 Dec 2007 22:54:17 -0000
@@ -495,6 +495,16 @@
   font-weight: bold;
 }
 
+#system-modules div.menu {
+  color: #444;
+  font-size: 0.9em;
+}
+
+#system-modules tr.enabled {
+  background:#B6EFA4;
+  border-color:#80CF67;
+}
+
 /*
 ** Styles for the system themes page (admin/build/themes)
 */
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.200
diff -u -r1.200 system.install
--- modules/system/system.install	30 Nov 2007 18:11:29 -0000	1.200
+++ modules/system/system.install	2 Dec 2007 05:39:35 -0000
@@ -263,14 +263,14 @@
       \'SELECT greatest($1, greatest($2, $3));\'
       LANGUAGE \'sql\''
     );
-    if (!db_result(db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'"))) {
+    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'"))) {
+    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\''
@@ -2602,7 +2602,7 @@
   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");
+      $ret[] = update_sql("UPDATE {permission} SET perm = '%s' WHERE rid = %d", $renamed_permission, $role->rid);
     }
   }
   return $ret;
@@ -2713,7 +2713,7 @@
     $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");
+      $ret[] = update_sql("UPDATE {permission} SET perm = '%s' WHERE rid = %d", $renamed_permission, $role->rid);
     }
   }
   return $ret;
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.556
diff -u -r1.556 system.module
--- modules/system/system.module	30 Nov 2007 12:19:10 -0000	1.556
+++ modules/system/system.module	2 Dec 2007 05:29:08 -0000
@@ -136,7 +136,7 @@
   // 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['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'));
@@ -507,7 +507,7 @@
  * Generate a block with a promotional link to Drupal.org.
  */
 function system_block($op = 'list', $delta = 0, $edit = NULL) {
-  switch($op) {
+  switch ($op) {
     case 'list':
       $blocks[0] = array(
         'info' => t('Powered by Drupal'),
@@ -1203,7 +1203,7 @@
   }
 
   $row = array();
-  $instances_present = db_fetch_object(db_query("SELECT aid FROM {actions} WHERE parameters != ''"));
+  $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'),
