--- ../src/patterns/patterns.module	2008-10-13 18:08:44.000000000 -0400
+++ patterns.module	2008-11-22 21:10:36.000000000 -0500
@@ -35,7 +35,6 @@ function patterns_perm() {
  */ 
 function patterns_menu($may_cache) {
   $items = array();
-  
   if ($may_cache) {
     $items[] = array('path' => 'admin/build/patterns',
       'description' => t('Administer patterns available for your site'),
@@ -90,10 +89,17 @@ function patterns_menu($may_cache) {
       'callback arguments' => array('patterns_disable_pattern'),
       'type' => MENU_CALLBACK
     );
-    $items[] = array('path' => 'admin/build/patterns/modules',
+    $items[] = array('path' => 'admin/build/patterns/modules' . arg(4),
       'access' => user_access('administer patterns'),
       'title' => t('Pattern Modules'),
       'callback' => 'patterns_modules_page',
+      'callback arguments' => arg(4),
+      'type' => MENU_CALLBACK
+    );
+    $items[] = array('path' => 'admin/build/patterns/modules/' . arg(4) . "/get_module",
+      'access' => user_access('administer patterns'),
+      'title' => t('Pattern Modules'),
+      'callback' => '_patterns_get_module',
       'type' => MENU_CALLBACK
     );
     $items[] = array('path' => 'admin/build/patterns/revert',
@@ -136,7 +142,6 @@ function patterns_menu($may_cache) {
       'type' => MENU_LOCAL_TASK
     );
   }
-
   return $items;
 }
 
@@ -421,6 +426,7 @@ function theme_patterns_list($form) { 
       $cells[] = '';
       $info = drupal_render($form['description'][$key]);
       $info .= '<div class="pattern-links">'. l(t('View details'), 'admin/build/patterns/info/'. $key) .'</div>';
+      $info .= '<div class="pattern-links">'. l(t('View included modules'), 'admin/build/patterns/modules/'. $key) .'</div>';
       $cells[] = array('data' => $info, 'colspan' => 5);
       $rows[$title][] = array('data' => $cells, 'id' => 'pid-'. $key .'-info', 'class' => 'pattern-info');
       
@@ -635,6 +641,10 @@ function patterns_modules_page($pid) {
   drupal_set_title($pattern->title .' '. t('(Pattern Modules)'));
   
   $modules = patterns_modules($pattern);
+  if(!$modules) {
+    drupal_set_message("This pattern doesn't seem to have any modules", "error");
+    drupal_goto("/admin/build/patterns");
+  }
   $modules_info = module_rebuild_cache();
   $modules_list = module_list();
   
@@ -646,10 +656,15 @@ function patterns_modules_page($pid) {
     $delete = is_array($module) ? $module['delete'] : false;
     $module = is_array($module) ? $module['value'] : $module;
     $available = array_key_exists($module, $modules_info);
+    if(!$available) {
+      $module_info = _patterns_get_module_links(array($module));
+    }
     $enabled = array_key_exists($module, $modules_list);
-    $row[] = $module;
-    $row[] = $available ? t('Yes') : '<span class="alert">'. t('No') .'</span>';
-    $row[] = $enabled ? t('Yes') : '<span class="alert">'. t('No') .'</span>';
+    $row[] = $available ? $module : $module . "<br />" . "Likely location: " . $module_info[$module]['link'];
+    $row[] = $available ? t('Yes') : '<span class="alert">'. t('No') . " (" .
+      l("download", "admin/build/patterns/modules/". arg(4) . "/get_module", array(), "url=".$module_info[$module]['link'])
+      . ")" . '</span>';
+    $row[] = $enabled ? t('Yes') : '<span class="alert">'. t('No') . '</span>';
     $row[] = $delete ? t('Delete') : t('Enable');
     $rows[] = $row;
     
@@ -665,7 +680,9 @@ function patterns_modules_page($pid) {
     drupal_set_message(t('All modules required by this module are available. Click !here to run this pattern.', array('!here' => l(t('here'), 'admin/build/patterns/enable/'. $pid))));
   }
   
-  return theme('table', array(t('Name'), t('Available'), t('Enabled'), t('Pattern Action')), $rows, t('Modules used for this pattern'));
+  //return theme('table', array(t('Name'), t('Available'), t('Enabled'), t('Pattern Action')), $rows, t('Modules used for this pattern'));
+  $output = theme('table', array(t('Name'), t('Available'), t('Enabled'), t('Pattern Action')), $rows, t('Modules used for this pattern'));
+  return $output;
 }
 
 function patterns_load() {
@@ -1536,3 +1553,68 @@ function theme_patterns_form_helper($for
   
   return $output;
 }
+
+function _patterns_get_module_links($modules) {
+  $links = Array();
+  foreach($modules as $module) {
+    $url = "http://www.drupal.org/project/" . $module;
+    $page = drupal_http_request($url);
+    //TODO: better checking of results here
+    if($page->data) {
+      //TODO: Select version depending on Drupal version dynamically
+      $did_match = preg_match("/http.*?".$module.".*?5.x.*?gz/", $page->data, $module_link);
+    }
+    if($did_match) {
+      $links[$module]['found'] = TRUE;
+      $links[$module]['link'] = $module_link[0];
+    }
+    else {
+      $links[$module]['found'] = FALSE;
+    }
+  }
+  return $links;
+}
+
+function _patterns_get_module() {
+  $url = $_GET['url'];
+  if($url) {
+    $result = _patterns_http_get_file($url);
+  }
+  if($result) {
+    drupal_set_message("Retrieved $url");
+    chdir($_SERVER['DOCUMENT_ROOT'] . "/sites/all/modules/");
+    exec("tar zxvf " . $result, $_null, $exec_result);
+    if($exec_result !== 0) {
+      drupal_set_message("Decompression failed", "error");
+    }
+    else {
+      drupal_set_message("Decompressed $result");
+    }
+    exec("rm " . $result, $_null, $exec_result);
+    if($exec_result !== 0) {
+      drupal_set_message("Cleanup failed", "error");
+    }
+    else {
+      drupal_set_message("Removed $result");
+    }
+    chdir($_SERVER['DOCUMENT_ROOT']);
+  }
+  drupal_goto("/admin/build/patterns/modules/" . arg(4));
+}
+
+function _patterns_http_get_file($url)  {
+  define('BUFSIZ', 4095);
+  $dir = $_SERVER['DOCUMENT_ROOT'] . "/sites/all/modules/";
+  $module_dir_is_writable = file_check_directory($dir);
+  if(!$module_dir_is_writable) {
+    drupal_set_message("Modules directory is not writable", "error");
+    return FALSE;
+  }
+  $rfile = fopen($url, 'r');
+  $lfile = fopen($dir . basename($url), 'w');
+  while(!feof($rfile))
+  fwrite($lfile, fread($rfile, BUFSIZ), BUFSIZ);
+  fclose($rfile);
+  fclose($lfile);
+  return $dir . "/" . basename($url);
+}
\ No newline at end of file
