? 157694_project_port_6.patch
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/project.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.inc,v
retrieving revision 1.124
diff -u -p -r1.124 project.inc
--- project.inc	15 Mar 2008 20:09:39 -0000	1.124
+++ project.inc	27 Apr 2008 16:49:46 -0000
@@ -30,7 +30,9 @@ function project_project_form($node) {
     // saved in this node (i.e. we're editing an existing project) and
     // if so, extract the right default values for our custom form
     // elements...
-    if ($node->taxonomy) {
+    $current_top = NULL;
+    $current_options = array();
+    if (!empty($node->taxonomy)) {
       foreach ($node->taxonomy as $tid => $obj) {
         if ($top_level[$tid]) {
           $current_top = $tid;
@@ -169,7 +171,7 @@ function project_project_validate(&$node
   }
 
   // Make sure title isn't already in use
-  if (db_num_rows(db_query("SELECT nid FROM {node} WHERE type = '%s' AND status = 1 AND title = '%s' AND nid <> %d", $node->type, $node->title, $node->nid))) {
+  if (db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = '%s' AND status = 1 AND title = '%s' AND nid <> %d", $node->type, $node->title, $node->nid))) {
     form_set_error('title', t('This project name is already in use.'));
   }
 
@@ -194,7 +196,7 @@ function project_project_validate(&$node
         }
       }
     }
-    if (in_array(strtolower($node->uri), $reserved_names) || db_num_rows(db_query("SELECT nid FROM {project_projects} WHERE uri = '%s' AND nid <> %d", $node->uri, $node->nid))) {
+    if (in_array(strtolower($node->uri), $reserved_names) || db_result(db_query("SELECT COUNT(*) FROM {project_projects} WHERE uri = '%s' AND nid <> %d", $node->uri, $node->nid))) {
       form_set_error('uri', t('This project name is already in use.'));
     }
   }
@@ -244,11 +246,16 @@ function project_project_set_breadcrumb(
   $breadcrumb[] = l(t('Home'), NULL);
 
   // Find out if the site has created a menu name for /project and use that
+  // @TODO:  In D6, multiple menu links can point to the same path.  So there's
+  // not really an equivalent for the 3 lines below, according to chx.  He
+  // suggested using "SELECT * FROM {menu_links} ml INNER JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.link_path='project"
+  // but on the drupalorg_testing profile at least that returns two links, one in the primary links block
+  // and one on the regular navigation bar.
   $pid = $_menu['path index']['project'];
   $name = $_menu['items'][$pid]['title'];
   $breadcrumb[] = l($name, 'project', array('title' => t('Browse projects')));
 
-  if (!empty($node) && project_use_taxonomy()) {
+  if (!empty($node->nid) && project_use_taxonomy()) {
     $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid INNER JOIN {term_node} r ON t.tid = r.tid WHERE h.parent = 0 AND t.vid = %d AND r.nid = %d', 't', 'tid'), _project_get_vid(), $node->nid);
     $term = db_fetch_object($result);
     $breadcrumb[] = l($term->name, 'project/'. $term->name);
@@ -310,10 +317,10 @@ function project_project_view($node, $te
     );
     $links = array();
     if ($view_issues) {
-      $links['all_support'] = l(t('View all support requests'), 'project/issues/'. $node->uri, null, 'categories=support&states=all', null);
-      $links['pending_support'] = l(t('View pending support requests'), 'project/issues/'. $node->uri, null, 'categories=support', null);
-      $links['pending_bugs'] = l(t('View pending bug reports'), 'project/issues/'. $node->uri, null, 'categories=bug', null);
-      $links['pending_features'] = l(t('View pending feature requests'), 'project/issues/'. $node->uri, null, 'categories=feature', null);
+      $links['all_support'] = l(t('View all support requests'), 'project/issues/'. $node->uri, array('attributes' => null, 'query' => 'categories=support&states=all', 'fragment' => null));
+      $links['pending_support'] = l(t('View pending support requests'), 'project/issues/'. $node->uri, array('attributes' => null, 'query' => 'categories=support', 'fragment' => null));
+      $links['pending_bugs'] = l(t('View pending bug reports'), 'project/issues/'. $node->uri, array('attributes' => null, 'query' => 'categories=bug', 'fragment' => null));
+      $links['pending_features'] = l(t('View pending feature requests'), 'project/issues/'. $node->uri, array('attributes' => null, 'query' => 'categories=feature', 'fragment' => null));
     }
     if ($make_issues) {
       $links['request_support'] = l(t('Request support'), 'node/add/project_issue/'. $node->uri .'/support');
@@ -333,8 +340,8 @@ function project_project_view($node, $te
     );
     $links = array();
     if ($view_issues) {
-      $links['pending_patches'] = l(t('View pending patches'), 'project/issues/'. $node->uri, null, 'states=8,13,14', null);
-      $links['available_tasks'] = l(t('View available tasks'), 'project/issues/'. $node->uri, null, 'categories=task', null);
+      $links['pending_patches'] = l(t('View pending patches'), 'project/issues/'. $node->uri, array('attributes' => null, 'query' => 'states=8,13', 'absolute' => TRUE, 'html' => TRUE));
+      $links['available_tasks'] = l(t('View available tasks'), 'project/issues/'. $node->uri, array('attributes' => null, 'query' => 'categories=task', 'fragment' => null));
       $links['pending_issues'] = l(t('View all pending issues'), 'project/issues/'. $node->uri);
     }
 
@@ -408,9 +415,7 @@ function project_project_delete($node) {
   db_query('DELETE FROM {project_projects} WHERE nid = %d', $node->nid);
 }
 
-function project_project_access($op, $node) {
-  global $user;
-
+function project_project_access($op, $node, $account) {
   switch ($op) {
     case 'view':
       // Since this function is shared for project_release nodes, we have to
@@ -426,11 +431,11 @@ function project_project_access($op, $no
       }
       break;
     case 'create':
-      if ($user->uid && user_access('maintain projects')) {
+      if ($account->uid && user_access('maintain projects')) {
         // Since this CVS access checking is non-standard, we need to
         // special-case uid 1 to always allow everything.
-        if ($user->uid != 1 && module_exists('cvs') && variable_get('cvs_restrict_project_creation', 1)) {
-          return db_result(db_query("SELECT uid FROM {cvs_accounts} WHERE uid = %d AND status = %d", $user->uid, CVS_APPROVED)) ? TRUE : FALSE;
+        if ($account->uid != 1 && module_exists('cvs') && variable_get('cvs_restrict_project_creation', 1)) {
+          return db_result(db_query("SELECT uid FROM {cvs_accounts} WHERE uid = %d AND status = %d", $account->uid, CVS_APPROVED)) ? TRUE : FALSE;
         }
         else {
           return TRUE;
@@ -456,7 +461,7 @@ function project_project_retrieve($key =
       return node_load(array('nid' => $key, 'type' => 'project_project'));
     }
     else {
-      $nid = db_result(db_query("SELECT nid FROM {project_projects} WHERE uri = '%s'", $key), 0);
+      $nid = db_result(db_query("SELECT nid FROM {project_projects} WHERE uri = '%s' LIMIT 1", $key));
       if (!$nid) {
         return new StdClass();
       }
@@ -510,27 +515,27 @@ function _project_save_taxonomy(&$node) 
     // This way, we're sure to clear out things that have been changed.
     $vid = _project_get_vid();
     $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
-    $items = array();
+    $args = array($node->nid);
     while ($item = db_fetch_object($result)) {
-      $items[] = "tid = $item->tid";
+      $args[] = $item->tid;
     }
-    if ($items) {
-      $sql = 'DELETE FROM {term_node} WHERE nid = %d AND ('. implode(' OR ', $items) . ')';
-      db_query($sql, $node->nid);
+    if (count($args) > 1) {
+      $sql = 'DELETE FROM {term_node} WHERE nid = %d AND tid IN ('. implode(',', array_fill(0, count($args), '%d')) .')';
+      db_query($sql, $args);
     }
     $tid = $node->project_type;
-    _project_db_save_taxonomy($node->nid, $tid);
+    _project_db_save_taxonomy($node->nid, $tid, $node->vid);
     $tid_field = 'tid_' . $tid;
     if (isset($node->$tid_field)) {
       foreach ($node->$tid_field as $tid) {
-        _project_db_save_taxonomy($node->nid, $tid);
+        _project_db_save_taxonomy($node->nid, $tid, $node->vid);
       }
     }
   }
 }
 
-function _project_db_save_taxonomy($nid, $tid) {
-  db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid);
+function _project_db_save_taxonomy($nid, $tid, $vid) {
+  db_query('INSERT INTO {term_node} (nid, tid, vid) VALUES (%d, %d, %d)', $nid, $tid, $vid);
 }
 
 /**
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/project.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.info,v
retrieving revision 1.2
diff -u -p -r1.2 project.info
--- project.info	13 Jun 2007 19:33:16 -0000	1.2
+++ project.info	27 Apr 2008 16:49:46 -0000
@@ -2,3 +2,4 @@
 name = Project
 description = Provides a project node type and browsing of projects.
 package = Project
+core = 6.x
\ No newline at end of file
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/project.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.install,v
retrieving revision 1.20
diff -u -p -r1.20 project.install
--- project.install	8 Mar 2008 16:48:12 -0000	1.20
+++ project.install	27 Apr 2008 16:49:46 -0000
@@ -3,39 +3,10 @@
 // $Name:  $
 
 function project_install() {
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      db_query("CREATE TABLE {project_projects} (
-          nid int(10) unsigned NOT NULL default '0',
-          uri varchar(50) NOT NULL default '',
-          homepage varchar(255) NOT NULL default '',
-          changelog varchar(255) NOT NULL default '',
-          cvs varchar(255) NOT NULL default '',
-          demo varchar(255) NOT NULL default '',
-          documentation varchar(255) not null default '',
-          screenshots varchar(255) not null default '',
-          license varchar(255) not null default '',
-          PRIMARY KEY (`nid`),
-          KEY project_projects_uri (uri(8))
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-    case 'pgsql':
-      db_query("CREATE TABLE {project_projects} (
-          nid int NOT NULL default '0',
-          uri varchar(50) NOT NULL default '',
-          homepage varchar(255) NOT NULL default '',
-          changelog varchar(255) NOT NULL default '',
-          cvs varchar(255) NOT NULL default '',
-          demo varchar(255) NOT NULL default '',
-          screenshots varchar(255) default '' not null,
-          documentation varchar(255) default '' not null,
-          license varchar(255) default '' not null,
-          PRIMARY KEY (nid)
-        );");
-      break;
-  }
+  // Create the database tables.
+  drupal_install_schema('project');
 
+  // Make this module heavier than the default module weight.
   db_query("UPDATE {system} SET weight = 2 WHERE name = 'project'");
 }
 
@@ -43,9 +14,8 @@ function project_install() {
  * Implementation of hook_uninstall().
  */
 function project_uninstall() {
-  if (db_table_exists('project_projects')) {
-    db_query("DROP TABLE {project_projects}");
-  }
+  // Drop database tables.
+  drupal_uninstall_schema('project');
 
   $variables = array(
     'project_browse_nodes',
@@ -62,199 +32,81 @@ function project_uninstall() {
   }
 }
 
-function project_update_1() {
-  return _system_update_utf8(array('project_projects', 'project_releases', 'project_issues', 'project_comments', 'project_subscriptions', 'project_issue_state'));
-}
-
-function project_update_2() {
-  $ret = array();
-  $ret[] = update_sql("UPDATE {system} SET weight = 2 WHERE name = 'project'");
-  return $ret;
-}
-
 /**
- * Remove stale records from tables that weren't cleaned up properly
- * when project nodes were deleted.  See http://drupal.org/node/67877
+ * Implementation of hook_schema().
  */
-function project_update_3() {
-  $ret = array();
-  $can_use_subselect = TRUE;
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      if (version_compare(mysql_get_server_info(), '4.1.0', '<')) {
-        $can_use_subselect = FALSE;
-      }
-      break;
-  }
-
-  $tables = array(
-    "{project_releases}",
-    "{project_comments}",
-    "{project_subscriptions}",
+function project_schema() {
+  $schema['project_projects'] = array(
+    'description' => t('The base table for project_project nodes.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Primary Key: The {node}.nid of the project_project node.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'uri' => array(
+        'description' => t('The short name of the project.'),
+        'type' => 'varchar',
+        'length' => 50,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'homepage' => array(
+        'description' => t("An external link to the project's homepage."),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'changelog' => array(
+        'description' => t('An external link to a log of changes for the project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'cvs' => array(
+        'description' => t('Path of the CVS repository for the project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'demo' => array(
+        'description' => t('An external link to a demonstration site for the project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'documentation' => array(
+        'description' => t('An external link to documentation for the project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'screenshots' => array(
+        'description' => t('An external link screenshots of the project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'license' => array(
+        'description' => t('An external link to the license of the project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('nid'),
+    'indexes' => array(
+      'project_projects_uri' => array(array('uri', 8)),
+    ),
   );
-
-  foreach ($tables as $table) {
-    $res = array();
-    if ($can_use_subselect) {
-      $res = update_sql("DELETE FROM $table WHERE nid NOT IN (SELECT nid FROM {node})");
-      $ret[] = $res;
-    }
-    else {
-      $result = db_query("SELECT p.nid FROM $table p LEFT JOIN {node} n ON p.nid = n.nid WHERE n.nid IS NULL");
-      $nids = array();
-      while ($nid = db_fetch_object($result)) {
-        $nids[] = $nid->nid;
-      }
-      if (!empty($nids)) {
-        $res = update_sql("DELETE FROM $table WHERE nid IN (" . implode(',', $nids) . ')');
-        $ret[] = $res;
-      }
-    }
-    if ($res['success']) {
-       $num = db_affected_rows();
-       $ret[] = array('success' => TRUE, 'query' => check_plain("$num rows deleted from $table"));
-    }
-  }
-  return $ret;
-}
-
-function project_update_4() {
-  $ret = array();
-
-  // PostgreSQL needs CREATE TABLE foobar _AS_ SELECT ...
-  $AS = ($GLOBALS['db_type'] == 'pgsql') ? 'AS' : '';
-
-  // Create temporary table to build the new {project_projects} and
-  // {project_issue_projects} tables from.
-  $ret[] = update_sql("CREATE TABLE {project_projects_tmp} $AS SELECT * FROM {project_projects}");
-
-  if (db_table_exists('project_issue_projects')) {
-    $ret[] = update_sql("DROP TABLE {project_issue_projects}");
-  }
-  $ret[] = update_sql("DROP TABLE {project_projects}");
-
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("CREATE TABLE {project_projects} (
-          nid int(10) unsigned NOT NULL default '0',
-          uri varchar(50) NOT NULL default '',
-          homepage varchar(255) NOT NULL default '',
-          changelog varchar(255) NOT NULL default '',
-          cvs varchar(255) NOT NULL default '',
-          demo varchar(255) NOT NULL default '',
-          release_directory varchar(255) NOT NULL default '',
-          version int(10) unsigned NOT NULL default '0',
-          mail varchar(255) NOT NULL default '',
-          documentation varchar(255) not null default '',
-          screenshots varchar(255) not null default '',
-          license varchar(255) not null default '',
-          PRIMARY KEY (`nid`),
-          KEY project_projects_uri (uri(8))
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      $ret[] = update_sql("CREATE TABLE {project_issue_projects} (
-          nid int(10) unsigned NOT NULL default '0',
-          issues tinyint(4) NOT NULL default '0',
-          components text,
-          help text,
-          mail_digest varchar(255) NOT NULL default '',
-          mail_copy varchar(255) NOT NULL default '',
-          mail_copy_filter varchar(255) NOT NULL default '',
-          mail_copy_filter_state varchar(255) NOT NULL default '',
-          mail_reminder tinyint(4) NOT NULL default '0',
-          PRIMARY KEY (nid)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-    case 'pgsql':
-      $ret[] = update_sql("CREATE TABLE {project_projects} (
-          nid int NOT NULL default '0',
-          uri varchar(50) NOT NULL default '',
-          homepage varchar(255) NOT NULL default '',
-          changelog varchar(255) NOT NULL default '',
-          cvs varchar(255) NOT NULL default '',
-          demo varchar(255) NOT NULL default '',
-          release_directory varchar(255) NOT NULL default '',
-          version int NOT NULL default '0',
-          mail varchar(255) not null default '',
-          screenshots varchar(255) default '' not null,
-          documentation varchar(255) default '' not null,
-          license varchar(255) default '' not null,
-          PRIMARY KEY (nid)
-        );");
-      $ret[] = update_sql("CREATE TABLE {project_issue_projects} (
-          nid int NOT NULL default '0',
-          issues smallint NOT NULL default '0',
-          components text,
-          help text,
-          mail_digest varchar(255) not null default '',
-          mail_copy varchar(255) not null default '',
-          mail_copy_filter varchar(255) not null default '',
-          mail_copy_filter_state varchar(255) default '' not null,
-          mail_reminder smallint NOT NULL default '0',
-          PRIMARY KEY (nid)
-        );");
-      break;
-  }
-
-  $ret[] = update_sql("INSERT INTO {project_projects} SELECT DISTINCT nid, uri, homepage, changelog, cvs, demo, release_directory, version, mail, documentation, screenshots, license FROM {project_projects_tmp}");
-  $ret[] = update_sql("INSERT INTO {project_issue_projects} SELECT DISTINCT nid, issues, components, help, mail_digest, mail_copy, mail_copy_filter, mail_copy_filter_state, mail_reminder FROM {project_projects_tmp}");
-
-  $ret[] = update_sql("DROP TABLE {project_projects_tmp}");
-
-  foreach (array('reply_to', 'digest_last', 'digest_interval', 'reminder_last', 'reminder_interval') as $varname) {
-    $val = variable_get("project_$varname", NULL);
-    if (isset($val)) {
-      variable_set("project_issue_$varname", $val);
-      $ret[] = update_sql("DELETE FROM {variable} WHERE name = 'project_" . $varname . "'");
-    }
-  }
-
-  return $ret;
-}
-
-/**
- * 5.x specific updates.
- */
-
-/**
- * Remove a stale variable setting.
- */
-function project_update_5000() {
-  variable_del('project_support_forum');
-  return array();
-}
-
-/**
- * Get rid of the per-project mail address (used only for the issue
- * email From: header) which has numerous problems.
- * See http://drupal.org/node/36619 and http://drupal.org/node/189210
- */
-function project_update_5001() {
-  $ret = array();
-  // PgSQL and MySQL have the same syntax for this.
-  $ret[] = update_sql('ALTER TABLE {project_projects} DROP COLUMN mail');
-  return $ret;
-}
-
-/**
- * Get rid of the 'version' column in the {project_projects} table.
- * See http://drupal.org/node/231392
- */
-function project_update_5002() {
-  $ret = array();
-  // PgSQL and MySQL have the same syntax for this.
-  $ret[] = update_sql('ALTER TABLE {project_projects} DROP COLUMN version');
-  return $ret;
-}
-
-/**
- * Get rid of the 'release_directory' column in the {project_projects} table.
- * See http://drupal.org/node/231558
- */
-function project_update_5003() {
-  $ret = array();
-  // PgSQL and MySQL have the same syntax for this.
-  $ret[] = update_sql('ALTER TABLE {project_projects} DROP COLUMN release_directory');
-  return $ret;
+  return $schema;
 }
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/project.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.module,v
retrieving revision 1.310
diff -u -p -r1.310 project.module
--- project.module	14 Apr 2008 06:03:32 -0000	1.310
+++ project.module	27 Apr 2008 16:49:46 -0000
@@ -7,19 +7,19 @@ if (file_exists("$path/project.inc")) {
   require_once "$path/project.inc";
 }
 
-function project_help($section) {
-  switch ($section) {
+function project_help($path, $arg) {
+  switch ($path) {
     case 'admin/project/project-settings':
       if (project_use_taxonomy()) {
         return _project_taxonomy_help();
       }
       break;
-  }
-  if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'taxonomy') {
-    $vid = _project_get_vid();
-    if (arg(3) == $vid) {
-      return _project_taxonomy_help($vid, FALSE);
-    }
+    case 'admin/content/taxonomy':
+      $vid = _project_get_vid();
+      if ($arg[3] == $vid) {
+        return _project_taxonomy_help($vid, FALSE);
+      }
+      break;
   }
 }
 
@@ -35,7 +35,7 @@ function _project_taxonomy_help($vid = 0
   if (!$vid) {
     $vid = _project_get_vid();
   }
-  $vocabulary = taxonomy_get_vocabulary($vid);
+  $vocabulary = taxonomy_vocabulary_load($vid);
   $text = '<p>'. t('The project module makes special use of the taxonomy (category) system. A special vocabulary, %vocabulary_name, has been created automatically.', array('%vocabulary_name' => $vocabulary->name)) .'</p>';
   $text .= '<p>'. t('To take full advantage of project categorization, add at least two levels of terms to this vocabulary. The first level will be the basic project types, e.g., "Modules", "Themes", "Translations".') .'</p>';
   $text .= '<p>'. t('Subterms of each of these types will be the categories that users can select to classify the projects. For example, "Modules" might have sub-terms including "Mail" and "XML".') .'</p>';
@@ -211,41 +211,44 @@ function project_find_alias($query, $tab
  * Callback for the main settings page.
  */
 function project_settings_form() {
-  $sort_methods = drupal_map_assoc(array_keys(module_invoke_all('project_sort_methods', 'methods')));
-
-  if (project_use_taxonomy()) {
-
-    // For now, date-based browsing doesn't work once you disable
-    // taxonomy (only because the code involved is rather complicated
-    // and needs to be majorly refactored and cleaned up).
-    $form['project_sort_method'] = array(
-      '#type' => 'radios',
-      '#title' => t('Default sort option'),
-      '#default_value' => variable_get('project_sort_method', 'category'),
-      '#options' => $sort_methods,
-      '#description' => t('Default sorting option to use on the overview page'),
-    );
-    $form['sort_methods'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Enabled sorting options'),
-      '#description' => t('Each type of project on your site will have its own project browsing page at %link. Each browsing page can be configured for different browsing options (by name, by date, etc). The settings below determine which browsing methods are available for each project type.', array('%link' => url('project', NULL, NULL, TRUE) . '/[type]')),
-    );
-    $tree = taxonomy_get_tree(_project_get_vid(), 0 , -1, 1);
-    foreach ($tree as $term) {
-      $form['sort_methods']['project_sort_method_used_' . $term->tid] = array(
-        '#type' => 'checkboxes',
-        '#title' => $term->name,
-        '#default_value' => array_filter(variable_get('project_sort_method_used_'. $term->tid, array_keys($sort_methods))),
-        '#options' => $sort_methods,
-      );
-    }
-  }
-  $form['project_browse_nodes'] = array(
-    '#type' => 'select', '#title' => t('Number of projects to list in paged browsing'),
-    '#default_value' => variable_get('project_browse_nodes', 30),
-    '#options' =>  drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50)),
-    '#description' => t('The default maximum number of projects to list when browsing lists, e.g., by category.')
-  );
+  $form = array();
+  // @TODO:  We should be able to delete these settings below since they won't
+  // be necessary with views handling project browsing.
+  //$sort_methods = drupal_map_assoc(array_keys(module_invoke_all('project_sort_methods', 'methods')));
+  //
+  //if (project_use_taxonomy()) {
+  //
+  //  // For now, date-based browsing doesn't work once you disable
+  //  // taxonomy (only because the code involved is rather complicated
+  //  // and needs to be majorly refactored and cleaned up).
+  //  $form['project_sort_method'] = array(
+  //    '#type' => 'radios',
+  //    '#title' => t('Default sort option'),
+  //    '#default_value' => variable_get('project_sort_method', 'category'),
+  //    '#options' => $sort_methods,
+  //    '#description' => t('Default sorting option to use on the overview page'),
+  //  );
+  //  $form['sort_methods'] = array(
+  //    '#type' => 'fieldset',
+  //    '#title' => t('Enabled sorting options'),
+  //    '#description' => t('Each type of project on your site will have its own project browsing page at %link. Each browsing page can be configured for different browsing options (by name, by date, etc). The settings below determine which browsing methods are available for each project type.', array('%link' => url('project', array('absolute' => TRUE)) . '/[type]')),
+  //  );
+  //  $tree = taxonomy_get_tree(_project_get_vid(), 0 , -1, 1);
+  //  foreach ($tree as $term) {
+  //    $form['sort_methods']['project_sort_method_used_' . $term->tid] = array(
+  //      '#type' => 'checkboxes',
+  //      '#title' => $term->name,
+  //      '#default_value' => array_filter(variable_get('project_sort_method_used_'. $term->tid, array_keys($sort_methods))),
+  //      '#options' => $sort_methods,
+  //    );
+  //  }
+  //}
+  //$form['project_browse_nodes'] = array(
+  //  '#type' => 'select', '#title' => t('Number of projects to list in paged browsing'),
+  //  '#default_value' => variable_get('project_browse_nodes', 30),
+  //  '#options' =>  drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50)),
+  //  '#description' => t('The default maximum number of projects to list when browsing lists, e.g., by category.')
+  //);
 
   return system_settings_form($form);
 }
@@ -316,102 +319,134 @@ function project_taxonomy($op, $type, $o
   }
 }
 
-function project_menu($may_cache) {
+/**
+ * Determine if the currently logged in user could have access to any project_project nodes.
+ */
+function project_project_access_any() {
+  return user_access('access projects') || user_access('access own projects') || user_access('administer projects');
+}
+
+function project_menu() {
   $items = array();
-  global $user;
 
-  if ($may_cache) {
-    // User pages:
-    $access_all = user_access('access projects');
-    $access_own = user_access('access own projects');
-    $access_admin = user_access('administer projects');
-    $access = $access_all || $access_own || $access_admin;
-
-    $items[] = array('path' => 'project',
-      'title' => t('Projects'),
-      'callback' => 'project_page_overview',
-      'access' => $access,
-      'type' => MENU_NORMAL_ITEM);
-
-    $items[] = array('path' => 'project/autocomplete',
-      'title' => t('Autocomplete project'),
-      'callback' => 'project_autocomplete',
-      'access' => $access,
-      'type' => MENU_CALLBACK);
-
-    // Project browsing pages
-    if (project_use_taxonomy()) {
-      $default_sort = variable_get('project_sort_method', 'category');
-      $sort_methods = module_invoke_all('project_sort_methods', 'methods');
-      $terms = taxonomy_get_tree(_project_get_vid());
-      $releases = variable_get('project_release_browse_versions', 0);
-      foreach ($terms as $i => $term) {
-        // Only use the first-level terms.
-        if ($term->depth == 0) {
-          $items[] = array('path' => 'project/'. $term->name,
-                           'title' => $term->name,
-                           'access' => $access,
-                           'type' => MENU_NORMAL_ITEM,
-                           'weight' => $term->weight,
-                           'callback arguments' => array($term->name));
-          $j = 0;
-          $term_methods = array_keys(array_filter(variable_get('project_sort_method_used_'. $term->tid, $sort_methods)));
-          foreach ($term_methods as $sort_method) {
-            $items[] = array('path' => 'project/' . $term->name . '/'. $sort_method,
-                 'title' => t('Browse by !sort_method', array('!sort_method' => $sort_method)),
-                 'access' => $access,
-                 // It's a default task if a) sort method matches default, or b) default sort isn't
-                 // in the list of sort methods, and it's the first tab.
-                 'type' => (($sort_method == $default_sort || (($j == 0) && !in_array($default_sort, $term_methods))) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK),
-                 'weight' => ($sort_method == $default_sort) ? -10 : $j,
-                 'callback arguments' => array($term->name, $sort_method));
-            $j++;
-          }
-        }
-      }
-    }
+  $items['project'] = array(
+    'title' => 'Projects',
+    'page callback' => 'project_page_overview',
+    'access callback' => 'project_project_access_any',
+    'type' => MENU_NORMAL_ITEM);
+
+  $items['project/autocomplete'] = array(
+    'title' => 'Autocomplete project',
+    'page callback' => 'project_autocomplete',
+    'access callback' => 'project_project_access_any',
+    'type' => MENU_CALLBACK);
+
+  // Project browsing pages
+  // TODO:  We can remove this block below when we add views support.
+  //if (project_use_taxonomy()) {
+  //  $default_sort = variable_get('project_sort_method', 'category');
+  //  $sort_methods = module_invoke_all('project_sort_methods', 'methods');
+  //  $terms = taxonomy_get_tree(_project_get_vid());
+  //  $releases = variable_get('project_release_browse_versions', 0);
+  //  foreach ($terms as $i => $term) {
+  //    // Only use the first-level terms.
+  //    if ($term->depth == 0) {
+  //      $items['project/'. $term->name] = array(
+  //        'title' => $term->name,   // TODO:  Fix?
+  //        'access callback' => 'project_check_access_any',
+  //        'type' => MENU_NORMAL_ITEM,
+  //        'weight' => $term->weight,
+  //        'page arguments' => array($term->name),
+  //      );
+  //      $j = 0;
+  //      $term_methods = array_keys(array_filter(variable_get('project_sort_method_used_'. $term->tid, $sort_methods)));
+  //      foreach ($term_methods as $sort_method) {
+  //        $items['project/' . $term->name . '/'. $sort_method] = array(
+  //             'title' => "Browse by $sort_method",   // TODO:  Fix?
+  //             'access callback' => 'project_check_access_any',
+  //             // It's a default task if a) sort method matches default, or b) default sort isn't
+  //             // in the list of sort methods, and it's the first tab.
+  //             'type' => (($sort_method == $default_sort || (($j == 0) && !in_array($default_sort, $term_methods))) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK),
+  //             'weight' => ($sort_method == $default_sort) ? -10 : $j,
+  //             'page arguments' => array($term->name, $sort_method));
+  //        $j++;
+  //      }
+  //    }
+  //  }
+  //}
+
+  // Developers
+  $items['project/developers'] = array(
+    'title' => 'Developers',
+    'page callback' => 'project_developers',
+    'access callback' => 'project_project_access_any',
+    'type' => MENU_CALLBACK,
+  );
 
-    // Developers
-    $items[] = array('path' => 'project/developers', 'title' => t('Developers'), 'callback' => 'project_developers', 'access' => $access, 'type' => MENU_CALLBACK);
+  // CVS messages:
+  $items['project/cvs'] = array(
+    'title' => 'CVS',
+    'page callback' => 'project_cvs',
+    'access callback' => 'project_project_access_any',
+    'type' => MENU_CALLBACK,
+  );
+
+  // Administration pages
+  $items['admin/project'] = array(
+    'title' => 'Project administration',
+    'description' => 'Administrative interface for project management and related modules.',
+    'page callback' => 'system_admin_menu_block_page',
+    'access arguments' => array('administer projects'),
+    'file' => 'system.admin.inc',
+    'file path' => drupal_get_path('module', 'system'),
+    'type' => MENU_NORMAL_ITEM,
+  );
+  $items['admin/project/project-settings'] = array(
+    'title' => 'Project settings',
+    'description' => 'Configure the behavior and appearance of the project browsing pages and other settings for the Project module.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('project_settings_form'),
+    'access arguments' => array('administer projects'),
+    'type' => MENU_NORMAL_ITEM,
+  );
 
-    // CVS messages:
-    $items[] = array('path' => 'project/cvs', 'title' => t('CVS'), 'callback' => 'project_cvs', 'access' => $access, 'type' => MENU_CALLBACK);
+  $items['node/%project_edit_project/edit/project'] = array(
+    'title' => 'Project',
+    'page callback' => 'node_page',
+    'page arguments' => array(1),
+    'access callback' => 'node_access',
+    'access arguments' => array('update', 1), 
+    'weight' => -5, 'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  return $items;
+}
+
+
+/**
+ * Implementation of hook_init().
+ */
+function project_init() {
+  drupal_add_css(drupal_get_path('module', 'project') .'/project.css');
+}
 
-    // Administration pages
-    $items[] = array(
-      'path' => 'admin/project',
-      'title' => t('Project administration'),
-      'description' => t('Administrative interface for project management and related modules.'),
-      'callback' => 'system_admin_menu_block_page',
-      'access' => $access_admin,
-      'type' => MENU_NORMAL_ITEM,
-    );
-    $items[] = array(
-      'path' => 'admin/project/project-settings',
-      'title' => t('Project settings'),
-      'description' => t('Configure the behavior and appearance of the project browsing pages and other settings for the Project module.'),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => array('project_settings_form'),
-      'access' => $access_admin,
-      'type' => MENU_NORMAL_ITEM,
-    );
+/**
+ * Menu loader callback.  Load a project_project node if the given
+ * nid is a project_project node and if the user has permission to edit
+ * the project and if either the project_issue or project_release module
+ * exists.
+ */
+function project_edit_project_load($nid) {
+  if (!is_numeric($nid)) {
+    return FALSE;
   }
-  else {
-    drupal_add_css(drupal_get_path('module', 'project') .'/project.css');
-    if (arg(0) == 'node' && is_numeric(arg(1))) {
-      $node = node_load(arg(1));
-      if ($node->type == 'project_project' && node_access('update', $node) &&
-          (module_exists('project_issue') || module_exists('project_release'))) {
-        $items[] = array(
-          'path' => 'node/'. arg(1) .'/edit/project',
-          'title' => t('Project'),
-          'callback' => 'node_page',
-          'weight' => -5, 'type' => MENU_DEFAULT_LOCAL_TASK,
-        );
-      }
-    }
+  $node = node_load($nid);
+  if (!isset($node->type) || $node->type != 'project_project') {
+    return FALSE;
   }
-  return $items;
+  if (!module_exists('project_issue') && !module_exists('project_release')) {
+    return FALSE;
+  }
+  return $node;
 }
 
 function project_check_admin_access($project, $cvs_access = NULL) {
@@ -432,7 +467,7 @@ function project_check_admin_access($pro
   // If $cvs_access is not defined, check to make sure the user has cvs access
   // and that the user's cvs account is approved.
   if (project_use_cvs($project_obj) && !isset($cvs_access)) {
-    if (db_num_rows(db_query("SELECT * FROM {cvs_accounts} WHERE uid = %d AND status = %d", $user->uid, CVS_APPROVED))) {
+    if (db_result(db_query("SELECT COUNT(*) FROM {cvs_accounts} WHERE uid = %d AND status = %d", $user->uid, CVS_APPROVED))) {
       $cvs_access = TRUE;
     }
     else {
@@ -445,7 +480,7 @@ function project_check_admin_access($pro
        return TRUE;
     }
     if (project_use_cvs($project_obj) && $cvs_access) {
-      if (db_num_rows(db_query("SELECT * FROM {cvs_project_maintainers} WHERE uid = %d AND nid = %d", $user->uid, $project_obj->nid))) {
+      if (db_result(db_query("SELECT COUNT(*) FROM {cvs_project_maintainers} WHERE uid = %d AND nid = %d", $user->uid, $project_obj->nid))) {
         return TRUE;
       }
     }
@@ -458,7 +493,7 @@ function project_check_admin_access($pro
  * taxonomy.module's form_alter() so we can do our own taxonomy
  * selection.
  */
-function project_form_alter($form_id, &$form) {
+function project_form_alter(&$form, &$form_state, $form_id) {
   if ($form_id == 'project_project_node_form') {
     $vid = _project_get_vid();
     if (isset($form['taxonomy'][$vid])) {
@@ -466,7 +501,7 @@ function project_form_alter($form_id, &$
     }
     // If there are no children elements, we should unset the entire
     // thing so we don't end up with an empty fieldset.
-    if (!element_children($form['taxonomy'])) {
+    if (!empty($form['taxonomy']) && (element_children($form['taxonomy']))) {
       unset($form['taxonomy']);
     }
 
@@ -514,309 +549,310 @@ function project_page() {
   }
 }
 
+// @TODO Delete this function if possible.
 function project_page_overview($termname = NULL, $sort_method = NULL) {
-  global $form_values;
-
-  project_project_set_breadcrumb();
-  $sort_methods = module_invoke_all('project_sort_methods', 'methods');
-
-  $output = '';
-  if (module_exists('project_release') && variable_get('project_release_browse_versions', 0)) {
-    $version_form = drupal_get_form('project_release_version_filter_form');
-    $output .= $version_form;
-    // Read in requested version, if any.
-    $version = isset($_SESSION['project_version']) ? $_SESSION['project_version'] : variable_get('project_release_overview', -1);
-  }
-
-  // If browsing by taxonomy, only fetch projects for this term.
-  if (project_use_taxonomy()) {
-    $vid = _project_get_vid();
-    if ($termname) {
-
-      $type = db_fetch_object(db_query(db_rewrite_sql("SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_hierarchy} th ON t.tid = th.tid WHERE t.vid = %d AND th.parent = 0 AND t.name = '%s'", 't', 'tid'), $vid, $termname));
-      // Bad project category passed, return page not found.
-      if (!$type) {
-        return drupal_not_found();
-      }
-      if (!$sort_method) {
-        // For the default, we use the overall default if enabled for this term, and if not we use the first enabled method.
-        $term_methods = array_filter(variable_get('project_sort_method_used_' . $type->tid, array_keys($sort_methods)));
-        $sort_method = in_array(variable_get('project_sort_method', 'category'), $term_methods) ? variable_get('project_sort_method', 'category') : array_shift($term_methods);
-      }
-
-      if ($type->description) {
-        $output .= '<p>' . filter_xss($type->description) . '</p>';
-      }
-
-      $module = $sort_methods[$sort_method];
-      // Bad sort method passed, return page not found.
-      if (!isset($module)) {
-        return drupal_not_found();
-      }
-      if (module_invoke($module, 'project_sort_methods', 'set term', $sort_method)) {
-        $tree = taxonomy_get_tree(_project_get_vid(), $type->tid);
-        $terms = array();
-        if ($tree) {
-          $tids = array();
-          if (variable_get('project_release_browse_versions', 0)) {
-            $version_params = array();
-            if ($version != -1) {
-              $version_where = 'tr.tid = %d';
-              $version_params[] = $version;
-            }
-            else {
-              $placeholders = array();
-              $active_tids = project_release_compatibility_list();
-              foreach ($active_tids as $tid => $api_term) {
-                $placeholders[] = '%d';
-                $version_params[] = $tid;
-              }
-              $version_where = 'tr.tid IN ('. implode(',', $placeholders) .')';
-            }
-            // Find all terms associated with the requested version.
-            $result = db_query("SELECT tp.tid, COUNT(DISTINCT(n.nid)) AS count FROM {term_node} tp INNER JOIN {project_release_nodes} p ON tp.nid = p.pid INNER JOIN {node} n ON n.nid = p.pid INNER JOIN {term_node} tr ON tr.nid = p.nid WHERE $version_where AND (n.status = 1) GROUP BY tp.tid", $version_params);
-            $tids = array();
-            while ($item = db_fetch_object($result)) {
-              $tids[$item->tid] = $item->count;
-            }
-          }
-          foreach ($tree as $cterm) {
-            if (!variable_get('project_release_browse_versions', 0) || ($version == -1) || array_key_exists($cterm->tid, $tids)) {
-              if ($tids[$cterm->tid]) {
-                $cterm->count = $tids[$cterm->tid];
-              }
-              else {
-                // We don't use taxonomy_term_count_nodes() because it includes child terms' counts.
-                $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 AND t.tid = %d GROUP BY t.tid'), $cterm->tid);
-                $term = db_fetch_object($result);
-                $cterm->count = $term->c;
-              }
-              $terms[] = $cterm;
-            }
-          }
-        }
-
-        // Look for a specific category term.
-        if ($arg = arg(3)) {
-          // Bad term, return page not found.
-          if (!($term = taxonomy_get_term($arg))) {
-            return drupal_not_found();
-          }
-        }
-      }
-      // The sorting method is not supported by the module, so any term passed is invalid.
-      // Return page not found if one is found.
-      elseif (arg(3)) {
-        return drupal_not_found();
-      }
-
-      // Set the default elements that will be used to construct the SQL statement.
-      $sql_elements = project_empty_query();
-      $sql_elements['fields']['pieces'] = array(
-        'DISTINCT(n.nid)',
-        'n.title',
-        'n.sticky',
-        'n.type',
-        'nr.teaser',
-        'nr.format',
-      );
-      $sql_elements['from']['pieces'] = array(
-        '{node} n '
-      );
-      $sql_elements['joins']['pieces'] = array(
-        'INNER JOIN {node_revisions} nr ON n.vid = nr.vid',
-        'INNER JOIN {project_projects} p ON n.nid = p.nid',
-        'LEFT JOIN {term_node} r ON n.nid = r.nid'
-      );
-      $sql_elements['wheres']['pieces'] = array(
-        'n.status = 1',
-        'r.tid = %d'
-      );
-      $sql_elements['parameters']['pieces'] = array(
-        isset($term) ? $term->tid : $type->tid
-      );
-
-      // If the site has enabled issue tracking via the project_issue
-      // module, we want to add 1 more field and JOIN to our query so
-      // we can provide the link for "Bugs and feature requests"...
-      if (module_exists('project_issue')) {
-        $sql_elements['fields']['pieces'][] = 'pip.issues';
-        $sql_elements['joins']['pieces'][] = 'INNER JOIN {project_issue_projects} pip ON n.nid = pip.nid';
-      }
-
-      // Only the 'pieces' are returned; the prefix and glue elements remain unchanged.
-      $sql_settings = module_invoke($module, 'project_sort_methods', 'sql_settings', $sort_method);
-      if (empty($sql_settings)) {
-        $sql_settings = array();
-      }
-
-      if (module_exists('project_release')) {
-        $project_release_sql = array(
-          'joins' => array('INNER JOIN {project_release_projects} prp ON n.nid = prp.nid'),
-          'wheres' => array('prp.releases = 1'),
-        );
-        $sql_settings = array_merge_recursive($sql_settings, $project_release_sql);
-      }
-
-      if (variable_get('project_release_browse_versions', 0)) {
-        $release_settings = array(
-          'fields' => array('prn.file_path', 'prn.version', 'MAX(prn.file_date) AS changed', 'COUNT(*) AS release_count'),
-          'group_bys' => array('n.nid'),
-        );
-        $release_settings['joins'] = array(
-          'INNER JOIN {project_release_nodes} prn ON n.nid = prn.pid',
-          'INNER JOIN {term_node} tr ON tr.nid = prn.nid',
-          'INNER JOIN {node} rn ON rn.nid = prn.nid',
-        );
-        $release_settings['wheres'][] = 'rn.status = 1';
-        if ($version != -1) {
-          $release_settings['wheres'][] = 'tr.tid = %d';
-          $release_settings['parameters'][] = $version;
-        }
-        else {
-          $placeholders = array();
-          $active_tids = project_release_compatibility_list();
-          foreach ($active_tids as $tid => $compatibility_term) {
-            $placeholders[] = '%d';
-            $release_settings['parameters'][] = $tid;
-          }
-          $where = 'tr.tid IN ('. implode(',', $placeholders) .')';
-          $release_settings['wheres'][] = $where;
-
-          // We need to grab the uid for the project node, so
-          // that node_access() will work properly without a full
-          // node_load() when we're generating the download table in
-          // project_release_table().
-          $release_settings['fields'][] = 'n.uid';
-        }
-        $sql_settings = array_merge_recursive($sql_settings, $release_settings);
-      }
-
-      // Merge in $sql_elements
-      if (!empty($sql_settings)) {
-        foreach(array_keys($sql_settings) as $key) {
-          $sql_elements[$key]['pieces'] = array_merge($sql_elements[$key]['pieces'], $sql_settings[$key]);
-          $sql_elements[$key]['pieces'] = array_unique($sql_elements[$key]['pieces']);
-        }
-      }
-
-      $parameters = $sql_elements['parameters']['pieces'];
-
-      $sql = project_build_query($sql_elements);
-
-      $pager = module_invoke($module, 'project_sort_methods', 'pager', $sort_method);
-      if ($pager) {
-        $first_field = array_shift($sql_elements['fields']['pieces']);
-        if (count($sql_elements['group_bys']['pieces'])) {
-          $first_field = 'DISTINCT(' . $sql_elements['group_bys']['pieces'][0] . ')';
-          $sql_elements['group_bys']['pieces'] = array();
-        }
-        $sql_elements['fields']['pieces'] = array("COUNT($first_field)");
-        // ORDER BY can screw up COUNT(DISTINCT), and we don't care
-        // about the order for the count query.
-        unset($sql_elements['order_bys']);
-        $count_query = project_build_query($sql_elements);
-        $result = pager_query($sql, variable_get('project_browse_nodes', 30), 0, $count_query, $parameters);
-      }
-      else {
-        $result = db_query($sql, $parameters);
-      }
-
-      // If we've just switched versions, we may have a term requested but no matching projects.
-      // In that case, we returned an uncollapsed fieldset.
-      if (module_invoke($module, 'project_sort_methods', 'set term', $sort_method)) {
-        $output .= theme('fieldset', array('#title' => t('Categories'), '#collapsible' => TRUE, '#collapsed' =>  (arg(3) && db_num_rows($result)) ? TRUE : FALSE, '#children' => theme('project_term_list', $terms, "project/$termname/$sort_method")));
-        if (!arg(3) || !db_num_rows($result)) {
-          return $output;
-        }
-        drupal_set_title(t('@project_type: %category', array('@project_type' => $type->name, '%category' => $term->name)));
-      }
-      else {
-        drupal_set_title(check_plain($type->name));
-      }
-    }
-    // If taxonomy is enabled but no termname is selected, show a list of terms to choose from.
-    else {
-      $tree = taxonomy_get_tree($vid, 0, -1, 1);
-      $items = array();
-      foreach ($tree as $term) {
-        $items[] = theme('project_type', $term);
-      }
-      drupal_set_title(t('Project types'));
-      return theme('item_list', $items);
-    }
-  }
-  // If taxonomy is not enabled, fetch all projects
-  else {
-    // Any terms passed without taxonomy module enabled are bogus -- return page not found.
-    if (isset($termname)) {
-      return drupal_not_found();
-    }
-    // If the site has enabled issue tracking via the project_issue
-    // module, we want to add 1 more field and JOIN to our query so
-    // we can provide the link for "Bugs and feature requests"...
-    if (module_exists('project_issue')) {
-      $ISSUES = ', pip.issues';
-      $ISSUE_JOIN ='INNER JOIN {project_issue_projects} pip ON n.nid = pip.nid';
-    }
-    $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, nr.teaser, nr.format$ISSUES FROM {node} n INNER JOIN {node_revisions} nr ON n.vid = nr.vid $ISSUE_JOIN WHERE n.status = 1 AND n.type = 'project_project' ORDER BY n.title ASC"));
-  }
-  $projects = '';
-  $class = 'even';
-  while ($project = db_fetch_object($result)) {
-    $project->body = check_markup($project->teaser, $project->format, FALSE);
-    if (module_exists('taxonomy')) {
-      $project->taxonomy = taxonomy_node_get_terms($project->nid);
-      if (isset($type)) {
-        // Hide the top-level project type term from the links, but add it to
-        // the $project object for theme_project_summary() to use if it wants.
-        unset($project->taxonomy[$type->tid]);
-        $project->term = $termname;
-      }
-      $project->terms = taxonomy_link('taxonomy terms', $project);
-    }
-
-    // Make sure we have the latest release
-    if (isset($project->release_count) && $project->release_count > 1 && $version != -1) {
-      $latest = db_fetch_object(db_query_range("SELECT file_path, version, file_date FROM {project_release_nodes} p INNER JOIN {node} n ON p.nid = n.nid INNER JOIN {term_node} t ON p.nid = t.nid LEFT JOIN {project_release_default_versions} prdv ON p.pid = prdv.nid AND prdv.tid = t.tid AND prdv.major = p.version_major WHERE p.pid = %d AND t.tid = %d AND n.status = 1 ORDER BY prdv.nid DESC, p.rebuild ASC, p.version_major ASC, p.version_minor DESC, p.version_patch DESC, p.file_date DESC", $project->nid, $version, 0, 1));
-      $project->file_path = $latest->file_path;
-      $project->version = $latest->version;
-    }
-
-    $project->links = array();
-    if ($version != -1) {
-      if ($project->file_path) {
-        $project->links['project_download'] = theme('project_release_download_link', $project->file_path, t('Download'), 'array');
-      }
-    }
-    else {
-      $project->download_table = theme('project_release_table_overview', $project, 'recommended', 'all', t('Version'), FALSE);
-    }
-
-    $project->links['project_more_info'] = array(
-      'title' => t('Find out more'),
-      'href' => "node/$project->nid",
-    );
-    if ($project->issues) {
-      $project->links['project_issues'] = array(
-        'title' => t('Bugs and feature requests'),
-        'href' => "project/issues/$project->nid",
-      );
-    }
-    if (module_invoke($module, 'project_sort_methods', 'group by date', $sort_method) && $date = _project_date($project->changed)) {
-      $projects .= "<h3>$date</h3>";
-    }
-    $project->class = ($class == 'even') ? 'odd': 'even';
-    $projects .= theme('project_summary', $project);
-    $class = $project->class;
-  }
-
-  $output .= '<div class="project" id="project-overview">' . $projects . '</div>';
-
-  if (!empty($pager)) {
-    $output .= theme('pager', NULL, variable_get('project_browse_nodes', 30));
-  }
-  return $output;
+//  global $form_values;
+//
+//  project_project_set_breadcrumb();
+//  $sort_methods = module_invoke_all('project_sort_methods', 'methods');
+//
+//  $output = '';
+//  if (module_exists('project_release') && variable_get('project_release_browse_versions', 0)) {
+//    $version_form = drupal_get_form('project_release_version_filter_form');
+//    $output .= $version_form;
+//    // Read in requested version, if any.
+//    $version = isset($_SESSION['project_version']) ? $_SESSION['project_version'] : variable_get('project_release_overview', -1);
+//  }
+//
+//  // If browsing by taxonomy, only fetch projects for this term.
+//  if (project_use_taxonomy()) {
+//    $vid = _project_get_vid();
+//    if ($termname) {
+//
+//      $type = db_fetch_object(db_query(db_rewrite_sql("SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_hierarchy} th ON t.tid = th.tid WHERE t.vid = %d AND th.parent = 0 AND t.name = '%s'", 't', 'tid'), $vid, $termname));
+//      // Bad project category passed, return page not found.
+//      if (!$type) {
+//        return drupal_not_found();
+//      }
+//      if (!$sort_method) {
+//        // For the default, we use the overall default if enabled for this term, and if not we use the first enabled method.
+//        $term_methods = array_filter(variable_get('project_sort_method_used_' . $type->tid, array_keys($sort_methods)));
+//        $sort_method = in_array(variable_get('project_sort_method', 'category'), $term_methods) ? variable_get('project_sort_method', 'category') : array_shift($term_methods);
+//      }
+//
+//      if ($type->description) {
+//        $output .= '<p>' . filter_xss($type->description) . '</p>';
+//      }
+//
+//      $module = $sort_methods[$sort_method];
+//      // Bad sort method passed, return page not found.
+//      if (!isset($module)) {
+//        return drupal_not_found();
+//      }
+//      if (module_invoke($module, 'project_sort_methods', 'set term', $sort_method)) {
+//        $tree = taxonomy_get_tree(_project_get_vid(), $type->tid);
+//        $terms = array();
+//        if ($tree) {
+//          $tids = array();
+//          if (variable_get('project_release_browse_versions', 0)) {
+//            $version_params = array();
+//            if ($version != -1) {
+//              $version_where = 'tr.tid = %d';
+//              $version_params[] = $version;
+//            }
+//            else {
+//              $placeholders = array();
+//              $active_tids = project_release_compatibility_list();
+//              foreach ($active_tids as $tid => $api_term) {
+//                $placeholders[] = '%d';
+//                $version_params[] = $tid;
+//              }
+//              $version_where = 'tr.tid IN ('. implode(',', $placeholders) .')';
+//            }
+//            // Find all terms associated with the requested version.
+//            $result = db_query("SELECT tp.tid, COUNT(DISTINCT(n.nid)) AS count FROM {term_node} tp INNER JOIN {project_release_nodes} p ON tp.nid = p.pid INNER JOIN {node} n ON n.nid = p.pid INNER JOIN {term_node} tr ON tr.nid = p.nid WHERE $version_where AND (n.status = 1) GROUP BY tp.tid", $version_params);
+//            $tids = array();
+//            while ($item = db_fetch_object($result)) {
+//              $tids[$item->tid] = $item->count;
+//            }
+//          }
+//          foreach ($tree as $cterm) {
+//            if (!variable_get('project_release_browse_versions', 0) || ($version == -1) || array_key_exists($cterm->tid, $tids)) {
+//              if ($tids[$cterm->tid]) {
+//                $cterm->count = $tids[$cterm->tid];
+//              }
+//              else {
+//                // We don't use taxonomy_term_count_nodes() because it includes child terms' counts.
+//                $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 AND t.tid = %d GROUP BY t.tid'), $cterm->tid);
+//                $term = db_fetch_object($result);
+//                $cterm->count = $term->c;
+//              }
+//              $terms[] = $cterm;
+//            }
+//          }
+//        }
+//
+//        // Look for a specific category term.
+//        if ($arg = arg(3)) {
+//          // Bad term, return page not found.
+//          if (!($term = taxonomy_get_term($arg))) {
+//            return drupal_not_found();
+//          }
+//        }
+//      }
+//      // The sorting method is not supported by the module, so any term passed is invalid.
+//      // Return page not found if one is found.
+//      elseif (arg(3)) {
+//        return drupal_not_found();
+//      }
+//
+//      // Set the default elements that will be used to construct the SQL statement.
+//      $sql_elements = project_empty_query();
+//      $sql_elements['fields']['pieces'] = array(
+//        'DISTINCT(n.nid)',
+//        'n.title',
+//        'n.sticky',
+//        'n.type',
+//        'nr.teaser',
+//        'nr.format',
+//      );
+//      $sql_elements['from']['pieces'] = array(
+//        '{node} n '
+//      );
+//      $sql_elements['joins']['pieces'] = array(
+//        'INNER JOIN {node_revisions} nr ON n.vid = nr.vid',
+//        'INNER JOIN {project_projects} p ON n.nid = p.nid',
+//        'LEFT JOIN {term_node} r ON n.nid = r.nid'
+//      );
+//      $sql_elements['wheres']['pieces'] = array(
+//        'n.status = 1',
+//        'r.tid = %d'
+//      );
+//      $sql_elements['parameters']['pieces'] = array(
+//        isset($term) ? $term->tid : $type->tid
+//      );
+//
+//      // If the site has enabled issue tracking via the project_issue
+//      // module, we want to add 1 more field and JOIN to our query so
+//      // we can provide the link for "Bugs and feature requests"...
+//      if (module_exists('project_issue')) {
+//        $sql_elements['fields']['pieces'][] = 'pip.issues';
+//        $sql_elements['joins']['pieces'][] = 'INNER JOIN {project_issue_projects} pip ON n.nid = pip.nid';
+//      }
+//
+//      // Only the 'pieces' are returned; the prefix and glue elements remain unchanged.
+//      $sql_settings = module_invoke($module, 'project_sort_methods', 'sql_settings', $sort_method);
+//      if (empty($sql_settings)) {
+//        $sql_settings = array();
+//      }
+//
+//      if (module_exists('project_release')) {
+//        $project_release_sql = array(
+//          'joins' => array('INNER JOIN {project_release_projects} prp ON n.nid = prp.nid'),
+//          'wheres' => array('prp.releases = 1'),
+//        );
+//        $sql_settings = array_merge_recursive($sql_settings, $project_release_sql);
+//      }
+//
+//      if (variable_get('project_release_browse_versions', 0)) {
+//        $release_settings = array(
+//          'fields' => array('prn.file_path', 'prn.version', 'MAX(prn.file_date) AS changed', 'COUNT(*) AS release_count'),
+//          'group_bys' => array('n.nid'),
+//        );
+//        $release_settings['joins'] = array(
+//          'INNER JOIN {project_release_nodes} prn ON n.nid = prn.pid',
+//          'INNER JOIN {term_node} tr ON tr.nid = prn.nid',
+//          'INNER JOIN {node} rn ON rn.nid = prn.nid',
+//        );
+//        $release_settings['wheres'][] = 'rn.status = 1';
+//        if ($version != -1) {
+//          $release_settings['wheres'][] = 'tr.tid = %d';
+//          $release_settings['parameters'][] = $version;
+//        }
+//        else {
+//          $placeholders = array();
+//          $active_tids = project_release_compatibility_list();
+//          foreach ($active_tids as $tid => $compatibility_term) {
+//            $placeholders[] = '%d';
+//            $release_settings['parameters'][] = $tid;
+//          }
+//          $where = 'tr.tid IN ('. implode(',', $placeholders) .')';
+//          $release_settings['wheres'][] = $where;
+//
+//          // We need to grab the uid for the project node, so
+//          // that node_access() will work properly without a full
+//          // node_load() when we're generating the download table in
+//          // project_release_table().
+//          $release_settings['fields'][] = 'n.uid';
+//        }
+//        $sql_settings = array_merge_recursive($sql_settings, $release_settings);
+//      }
+//
+//      // Merge in $sql_elements
+//      if (!empty($sql_settings)) {
+//        foreach(array_keys($sql_settings) as $key) {
+//          $sql_elements[$key]['pieces'] = array_merge($sql_elements[$key]['pieces'], $sql_settings[$key]);
+//          $sql_elements[$key]['pieces'] = array_unique($sql_elements[$key]['pieces']);
+//        }
+//      }
+//
+//      $parameters = $sql_elements['parameters']['pieces'];
+//
+//      $sql = project_build_query($sql_elements);
+//
+//      $pager = module_invoke($module, 'project_sort_methods', 'pager', $sort_method);
+//      if ($pager) {
+//        $first_field = array_shift($sql_elements['fields']['pieces']);
+//        if (count($sql_elements['group_bys']['pieces'])) {
+//          $first_field = 'DISTINCT(' . $sql_elements['group_bys']['pieces'][0] . ')';
+//          $sql_elements['group_bys']['pieces'] = array();
+//        }
+//        $sql_elements['fields']['pieces'] = array("COUNT($first_field)");
+//        // ORDER BY can screw up COUNT(DISTINCT), and we don't care
+//        // about the order for the count query.
+//        unset($sql_elements['order_bys']);
+//        $count_query = project_build_query($sql_elements);
+//        $result = pager_query($sql, variable_get('project_browse_nodes', 30), 0, $count_query, $parameters);
+//      }
+//      else {
+//        $result = db_query($sql, $parameters);
+//      }
+//
+//      // If we've just switched versions, we may have a term requested but no matching projects.
+//      // In that case, we returned an uncollapsed fieldset.
+//      if (module_invoke($module, 'project_sort_methods', 'set term', $sort_method)) {
+//        $output .= theme('fieldset', array('#title' => t('Categories'), '#collapsible' => TRUE, '#collapsed' =>  (arg(3) && db_num_rows($result)) ? TRUE : FALSE, '#children' => theme('project_term_list', $terms, "project/$termname/$sort_method")));
+//        if (!arg(3) || !db_num_rows($result)) {
+//          return $output;
+//        }
+//        drupal_set_title(t('@project_type: %category', array('@project_type' => $type->name, '%category' => $term->name)));
+//      }
+//      else {
+//        drupal_set_title(check_plain($type->name));
+//      }
+//    }
+//    // If taxonomy is enabled but no termname is selected, show a list of terms to choose from.
+//    else {
+//      $tree = taxonomy_get_tree($vid, 0, -1, 1);
+//      $items = array();
+//      foreach ($tree as $term) {
+//        $items[] = theme('project_type', $term);
+//      }
+//      drupal_set_title(t('Project types'));
+//      return theme('item_list', $items);
+//    }
+//  }
+//  // If taxonomy is not enabled, fetch all projects
+//  else {
+//    // Any terms passed without taxonomy module enabled are bogus -- return page not found.
+//    if (isset($termname)) {
+//      return drupal_not_found();
+//    }
+//    // If the site has enabled issue tracking via the project_issue
+//    // module, we want to add 1 more field and JOIN to our query so
+//    // we can provide the link for "Bugs and feature requests"...
+//    if (module_exists('project_issue')) {
+//      $ISSUES = ', pip.issues';
+//      $ISSUE_JOIN ='INNER JOIN {project_issue_projects} pip ON n.nid = pip.nid';
+//    }
+//    $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, nr.teaser, nr.format$ISSUES FROM {node} n INNER JOIN {node_revisions} nr ON n.vid = nr.vid $ISSUE_JOIN WHERE n.status = 1 AND n.type = 'project_project' ORDER BY n.title ASC"));
+//  }
+//  $projects = '';
+//  $class = 'even';
+//  while ($project = db_fetch_object($result)) {
+//    $project->body = check_markup($project->teaser, $project->format, FALSE);
+//    if (module_exists('taxonomy')) {
+//      $project->taxonomy = taxonomy_node_get_terms($project->nid);
+//      if (isset($type)) {
+//        // Hide the top-level project type term from the links, but add it to
+//        // the $project object for theme_project_summary() to use if it wants.
+//        unset($project->taxonomy[$type->tid]);
+//        $project->term = $termname;
+//      }
+//      $project->terms = taxonomy_link('taxonomy terms', $project);
+//    }
+//
+//    // Make sure we have the latest release
+//    if (isset($project->release_count) && $project->release_count > 1 && $version != -1) {
+//      $latest = db_fetch_object(db_query_range("SELECT file_path, version, file_date FROM {project_release_nodes} p INNER JOIN {node} n ON p.nid = n.nid INNER JOIN {term_node} t ON p.nid = t.nid LEFT JOIN {project_release_default_versions} prdv ON p.pid = prdv.nid AND prdv.tid = t.tid AND prdv.major = p.version_major WHERE p.pid = %d AND t.tid = %d AND n.status = 1 ORDER BY prdv.nid DESC, p.rebuild ASC, p.version_major ASC, p.version_minor DESC, p.version_patch DESC, p.file_date DESC", $project->nid, $version, 0, 1));
+//      $project->file_path = $latest->file_path;
+//      $project->version = $latest->version;
+//    }
+//
+//    $project->links = array();
+//    if ($version != -1) {
+//      if ($project->file_path) {
+//        $project->links['project_download'] = theme('project_release_download_link', $project->file_path, t('Download'), 'array');
+//      }
+//    }
+//    else {
+//      $project->download_table = theme('project_release_table_overview', $project, 'recommended', 'all', t('Version'), FALSE);
+//    }
+//
+//    $project->links['project_more_info'] = array(
+//      'title' => t('Find out more'),
+//      'href' => "node/$project->nid",
+//    );
+//    if ($project->issues) {
+//      $project->links['project_issues'] = array(
+//        'title' => t('Bugs and feature requests'),
+//        'href' => "project/issues/$project->nid",
+//      );
+//    }
+//    if (module_invoke($module, 'project_sort_methods', 'group by date', $sort_method) && $date = _project_date($project->changed)) {
+//      $projects .= "<h3>$date</h3>";
+//    }
+//    $project->class = ($class == 'even') ? 'odd': 'even';
+//    $projects .= theme('project_summary', $project);
+//    $class = $project->class;
+//  }
+//
+//  $output .= '<div class="project" id="project-overview">' . $projects . '</div>';
+//
+//  if (!empty($pager)) {
+//    $output .= theme('pager', NULL, variable_get('project_browse_nodes', 30));
+//  }
+//  return $output;
 }
 
 /**
@@ -999,6 +1035,8 @@ function _project_date($timestamp) {
  */
 function project_projects_select_options(&$project_urls, $issues = TRUE, $key_prefix = NULL) {
   $projects = array();
+  $ISSUE_JOIN = '';
+  $ISSUE_WHERE = '';
   if ($issues && module_exists('project_issue')) {
     $ISSUE_JOIN ='INNER JOIN {project_issue_projects} pip ON n.nid = pip.nid';
     $ISSUE_WHERE = 'AND pip.issues = 1';
@@ -1049,9 +1087,9 @@ function project_quick_navigate_form() {
   return $form;
 }
 
-function project_quick_navigate_form_submit($form_id, $form_values) {
-  if (!empty($form_values['project_goto']) && (string)$form_values['project_goto'] != '0') {
-    drupal_goto($form_values['project_goto']);
+function project_quick_navigate_form_submit($form, &$form_state) {
+  if (!empty($form_state['values']['project_goto']) && (string)$form_state['values']['project_goto'] != '0') {
+    drupal_goto($form_state['values']['project_goto']);
   }
 }
 
@@ -1061,7 +1099,7 @@ function theme_project_term_list($terms,
   $depth = 0;
   $output = "\n<ul class=\"project-terms\">\n";
   foreach ($terms as $term) {
-    $link = l($term->name .' ('. $term->count .')', "$path/$term->tid", array('title' => strip_tags($term->description)));
+    $link = l($term->name .' ('. $term->count .')', "$path/$term->tid", array('attributes' => array('title' => strip_tags($term->description))));
     $output .= '<li class="leaf">' . $link . "</li>\n";
   }
   $output .= "\n</ul>\n";
@@ -1159,3 +1197,27 @@ function project_use_cvs($project) {
   }
 }
 
+/**
+ * Implementation of hook_theme().
+ */
+function project_theme() {
+  return array(
+    'project_term_list' => array(
+      'arguments' => array(
+        'terms' => NULL,
+        'path' => NULL,
+      ),
+    ),
+    'project_type' => array(
+      'arguments' => array(
+        'term' => NULL,
+      ),
+    ),
+    'project_summary' => array(
+      'arguments' => array(
+        'project' => NULL,
+      )
+    )
+  );
+}
+
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/release/project-release-create-history.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/release/project-release-create-history.php,v
retrieving revision 1.12
diff -u -p -r1.12 project-release-create-history.php
--- release/project-release-create-history.php	29 Mar 2008 08:23:38 -0000	1.12
+++ release/project-release-create-history.php	27 Apr 2008 16:49:47 -0000
@@ -196,7 +196,7 @@ function project_release_history_generat
   }
 
   $xml .= '<project_status>'. $project_status ."</project_status>\n";
-  $xml .= '<link>'. url("node/$project->nid", NULL, NULL, TRUE) ."</link>\n";
+  $xml .= '<link>'. url("node/$project->nid", array('absolute' => TRUE)) ."</link>\n";
 
   // Now, build the query for all the releases for this project and term.
   $joins = array();
@@ -274,7 +274,7 @@ function project_release_history_generat
     if ($release->status) {
       // Published, so we should include the links.
       $xml .= "  <status>published</status>\n";
-      $xml .= '  <release_link>'. url("node/$release->nid", NULL, NULL, TRUE) ."</release_link>\n";
+      $xml .= '  <release_link>'. url("node/$release->nid", array('absolute' => TRUE)) ."</release_link>\n";
       if (!empty($release->file_path)) {
         $download_link = theme('project_release_download_link', $release->file_path, NULL, TRUE);
         $xml .= '  <download_link>'. $download_link['href'] ."</download_link>\n";
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/release/project_release.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/release/project_release.info,v
retrieving revision 1.3
diff -u -p -r1.3 project_release.info
--- release/project_release.info	9 Aug 2007 23:38:52 -0000	1.3
+++ release/project_release.info	27 Apr 2008 16:49:47 -0000
@@ -2,4 +2,6 @@
 name = Project releases
 description = Provides a release node type to represent releases of projects.
 package = Project
-dependencies = project taxonomy
+dependencies[] = project
+dependencies[] = taxonomy
+core = 6.x
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/release/project_release.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/release/project_release.install,v
retrieving revision 1.16
diff -u -p -r1.16 project_release.install
--- release/project_release.install	19 Jan 2008 07:10:59 -0000	1.16
+++ release/project_release.install	27 Apr 2008 16:49:47 -0000
@@ -3,136 +3,20 @@
 // $Name:  $
 
 function project_release_install() {
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      db_query("CREATE TABLE IF NOT EXISTS {project_release_nodes} (
-          nid int unsigned NOT NULL default '0',
-          pid int unsigned NOT NULL default '0',
-          version varchar(255) NOT NULL default '',
-          tag varchar(255) NOT NULL default '',
-          file_path varchar(255) NOT NULL default '',
-          file_date int unsigned NOT NULL default '0',
-          file_hash varchar(32) NOT NULL default '',
-          rebuild tinyint default '0',
-          version_major int default NULL,
-          version_minor int default NULL,
-          version_patch int default NULL,
-          version_extra varchar(255) default NULL,
-          PRIMARY KEY (nid),
-          KEY project_releases_pid (pid)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE IF NOT EXISTS {project_release_projects} (
-          nid int unsigned NOT NULL default '0',
-          releases tinyint NOT NULL default '1',
-          version_format varchar(255) NOT NULL default '',
-          PRIMARY KEY (nid),
-          KEY project_release_projects_releases (releases)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE IF NOT EXISTS {project_release_supported_versions} (
-          nid int unsigned NOT NULL default '0',
-          tid int unsigned NOT NULL default '0',
-          major int unsigned NOT NULL default '0',
-          supported tinyint unsigned NOT NULL default '1',
-          recommended tinyint unsigned NOT NULL default '0',
-          snapshot tinyint unsigned NOT NULL default '0',
-          PRIMARY KEY (nid, tid, major)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE IF NOT EXISTS {project_release_package_errors} (
-          nid int unsigned NOT NULL default '0',
-          messages text,
-          PRIMARY KEY (nid)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE IF NOT EXISTS {cache_project_release} (
-        cid varchar(255) BINARY NOT NULL default '',
-        data longblob,
-        expire int NOT NULL default '0',
-        created int NOT NULL default '0',
-        headers text,
-        PRIMARY KEY (cid),
-        INDEX expire (expire)
-      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
-      break;
+  // Create the database tables.
+  drupal_install_schema('project_release');
 
-    case 'pgsql':
-      if (!db_table_exists('project_release_nodes')) {
-        db_query("CREATE TABLE {project_release_nodes} (
-            nid int NOT NULL default '0',
-            pid int NOT NULL default '0',
-            version varchar(255) NOT NULL default '',
-            tag varchar(255) NOT NULL default '',
-            file_path varchar(255) NOT NULL default '',
-            file_date int NOT NULL default '0',
-            file_hash varchar(32) NOT NULL default '',
-            rebuild smallint default '0',
-            version_major int default NULL,
-            version_minor int default NULL,
-            version_patch int default NULL,
-            version_extra varchar(255) default NULL,
-            PRIMARY KEY (nid)
-          );");
-        db_query("CREATE INDEX {project_release_nodes}_pid_idx ON {project_release_nodes} (pid)");
-      }
-      if (!db_table_exists('project_release_projects')) {
-        db_query("CREATE TABLE {project_release_projects} (
-            nid int NOT NULL default '0',
-            releases smallint NOT NULL default '1',
-            version_format varchar(255) NOT NULL default '',
-            PRIMARY KEY (nid)
-          );");
-        db_query("CREATE INDEX {project_release_projects}_releases_idx ON {project_release_projects} (releases)");
-      }
-      if (!db_table_exists('project_release_supported_versions')) {
-        db_query("CREATE TABLE {project_release_supported_versions} (
-            nid int NOT NULL default '0',
-            tid int NOT NULL default '0',
-            major int NOT NULL default '0',
-            supported smallint NOT NULL default '1',
-            recommended smallint NOT NULL default '0',
-            snapshot smallint NOT NULL default '0',
-            PRIMARY KEY (nid, tid, major)
-          );");
-      }
-      if (!db_table_exists('project_release_package_errors')) {
-        db_query("CREATE TABLE {project_release_package_errors} (
-          nid int NOT NULL default '0',
-          messages text,
-          PRIMARY KEY (nid)
-        )");
-      }
-      if (!db_table_exists('cache_project_release')) {
-        db_query("CREATE TABLE {cache_project_release} (
-          cid varchar(255) NOT NULL default '',
-          data bytea,
-          expire int NOT NULL default '0',
-          created int NOT NULL default '0',
-          headers text,
-          PRIMARY KEY (cid)
-        )");
-        db_query("CREATE INDEX {cache_project_release}_expire_idx ON {cache_project_release} (expire)");
-      }
-      break;
-  }
+  // Make this module heavier than the default module weight.
   db_query("UPDATE {system} SET weight = 2 WHERE name = 'project_release'");
-  db_query("DELETE FROM {variable} WHERE name = 'project_browse_releases'");
 }
 
 /**
  * Implementation of hook_uninstall().
  */
 function project_release_uninstall() {
-  $tables = array(
-    'project_release_nodes',
-    'project_release_projects',
-    'project_release_default_versions',
-    'cache_project_release',
-  );
-  foreach ($tables as $table) {
-    if (db_table_exists($table)) {
-      db_query("DROP TABLE {$table}");
-    }
-  }
-
+  // Drop database tables.
+  drupal_uninstall_schema('project_release');
+  
   $variables = array(
     'project_release_active_compatibility_tids',
     'project_release_api_vocabulary',
@@ -149,207 +33,245 @@ function project_release_uninstall() {
 }
 
 /**
- * Adds the {project_release_default_versions} table for branch-aware
- * default versions and populates it the best it can.
+ * Implementation of hook_schema().
  */
-function project_release_update_1() {
-  $ret = array();
-
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql(
-        "CREATE TABLE IF NOT EXISTS {project_release_default_versions} (
-          nid int unsigned NOT NULL default '0',
-          tid int unsigned NOT NULL default '0',
-          major int unsigned NOT NULL default '0',
-          PRIMARY KEY (nid, tid)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-    case 'pgsql':
-      if (!db_table_exists('project_release_default_versions')) {
-        $ret[] = update_sql(
-          "CREATE TABLE {project_release_default_versions} (
-            nid int NOT NULL default '0',
-            tid int NOT NULL default '0',
-            major int NOT NULL default '0',
-            PRIMARY KEY (nid, tid)
-          );");
-      }
-      break;
-  }
-
-  // Initially populate based on the existing default release, if that
-  // release is a real release with a valid compatibility taxonomy.
-  $ret[] = update_sql("INSERT INTO {project_release_default_versions} (nid, tid, major) SELECT pp.nid, tn.tid, prn.version_major FROM {project_projects} pp INNER JOIN {project_release_nodes} prn ON pp.version = prn.nid INNER JOIN {term_node} tn ON tn.nid = prn.nid");
-
-  // Now, add in values for any other distinct branches we know about
-  // for each project, for all active compatibility terms.
-  $tids = variable_get('project_release_active_compatibility_tids', '');
-  if (!empty($tids)) {
-    $where_tid = 'AND tn.tid IN (' . implode(',', array_filter($tids)) . ') ';
-  }
-  $ret[] = update_sql("INSERT INTO {project_release_default_versions} (nid, tid, major) SELECT prn.pid, tn.tid, MIN(prn.version_major) FROM {project_release_nodes} prn INNER JOIN {term_node} tn ON prn.nid = tn.nid LEFT JOIN {project_release_default_versions} prdv ON prdv.nid = prn.pid AND prdv.tid = tn.tid WHERE prn.version_major IS NOT NULL AND prdv.nid IS NULL AND prdv.tid IS NULL $where_tid GROUP BY prn.pid, tn.tid");
-
-  return $ret;
-}
-
-/**
- * Add a new column to {project_release_projects} that determines if
- * the development snapshot table should be shown on project nodes.
- */
-function project_release_update_2() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("ALTER TABLE {project_release_projects} ADD snapshot_table tinyint unsigned default '1' NOT NULL");
-      break;
-    case 'pgsql':
-      db_add_column($ret, 'project_release_projects', 'snapshot_table', 'smallint', array('default' => 1, 'not null' => TRUE));
-      break;
-  }
-  return $ret;
-}
-
-/**
- * Add a cache table {cache_project_release}.
- */
-function project_release_update_5000() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("CREATE TABLE IF NOT EXISTS {cache_project_release} (
-        cid varchar(255) BINARY NOT NULL default '',
-        data longblob,
-        expire int NOT NULL default '0',
-        created int NOT NULL default '0',
-        headers text,
-        PRIMARY KEY (cid),
-        INDEX expire (expire)
-      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
-      break;
-    case 'pgsql':
-      if (!db_table_exists('cache_project_release')) {
-        $ret[] = update_sql("CREATE TABLE {cache_project_release} (
-          cid varchar(255) NOT NULL default '',
-          data bytea,
-          expire int NOT NULL default '0',
-          created int NOT NULL default '0',
-          headers text,
-          PRIMARY KEY (cid)
-        )");
-        $ret[] = update_sql("CREATE INDEX {cache_project_release}_expire_idx ON {cache_project_release} (expire)");
-      }
-      break;
-  }
-  return $ret;
-}
-
-/**
- * Remove variables from dead code for serving XML history files, which is
- * now handled by project-release-serve-history.php instead.
- */
-function project_release_update_5001() {
-  $ret = array();
-  $variables = array(
-    'project_release_history_xml',
-    'project_release_history_directory',
+function project_release_schema() {
+  $schema['project_release_nodes'] = array(
+    'description' => t('The base table for project_project nodes.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Primary Key: The {node}.nid of the project_release node.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'pid' => array(
+        'description' => t('The {project_projects}.nid of the project_project node with which the project_release node is associated.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'version' => array(
+        'description' => t('A string containing the full version of a release. The format of this string for a given project is dictated by {project_release_projects}.version_format.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'tag' => array(
+        'description' => t('The name of a CVS branch or tag on which a release is based.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'file_path' => array(
+        'description' => t('The path to the downloadable file for the release.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'file_date' => array(
+        'description' => t('A Unix timestamp indicating when the file was created.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'file_hash' => array(
+        'description' => t('An MD5 hash of the file.'),
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'rebuild' => array(
+        'description' => t('A flag indicating whether or not the file associated with a release should be rebuilt periodically. For official releases this should be 0, for development snapshots it should be 1.'),
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => FALSE,
+        'not null' => FALSE,
+        'default' => 0,
+      ),
+      'version_major' => array(
+        'description' => t('The major version number of a release.'),
+        'type' => 'int',
+        'unsigned' => FALSE,
+        'not null' => FALSE,
+        'default' => NULL,
+      ),
+      'version_minor' => array(
+        'description' => t('The minor version number of a release.'),
+        'type' => 'int',
+        'unsigned' => FALSE,
+        'not null' => FALSE,
+        'default' => NULL,
+      ),
+      'version_patch' => array(
+        'description' => t('The patch level version number of a release.'),
+        'type' => 'int',
+        'unsigned' => FALSE,
+        'not null' => FALSE,
+        'default' => NULL,
+      ),
+      'version_extra' => array(
+        'description' => t('A text string that can be used to provide additional information about a release.  Ex: BETA'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'default' => NULL,
+      ),
+    ),
+    'primary key' => array('nid'),
+    'indexes' => array(
+      'project_releases_pid' => array('pid')
+    ),
   );
-  foreach ($variables as $variable) {
-    variable_del($variable);
-    $ret[] = array('success' => TRUE, 'query' => "variable_del($variable)");
-  }
-  return $ret;
-}
-
-/**
- * Remove a dead variable from before project_release.module existed.
- */
-function project_release_update_5002() {
-  $ret = array();
-  variable_del('project_release_unmoderate');
-  $ret[] = array('success' => TRUE, 'query' => "variable_del('project_release_unmoderate')");
-  return $ret;
-}
-
-/**
- * Add {project_release_package_errors} table to track packaging errors.
- */
-function project_release_update_5003() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("CREATE TABLE IF NOT EXISTS {project_release_package_errors} (
-          nid int unsigned NOT NULL default '0',
-          messages text NOT NULL,
-          PRIMARY KEY (nid)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-    case 'pgsql':
-      if (!db_table_exists('project_release_package_errors')) {
-        $ret[] = update_sql("CREATE TABLE {project_release_package_errors} (
-          nid int NOT NULL default '0',
-          messages text,
-          PRIMARY KEY (nid)
-        )");
-      }
-      break;
-  }
-  return $ret;
-}
 
-/**
- * Add the new {project_release_supported_versions} table, transfer data
- * from {project_release_default_versions} and {project_release_projects},
- * and drop the stale table and columns.
- */
-function project_release_update_5200() {
-  $ret = array();
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      $ret[] = update_sql("CREATE TABLE IF NOT EXISTS {project_release_supported_versions} (
-          nid int unsigned NOT NULL default '0',
-          tid int unsigned NOT NULL default '0',
-          major int unsigned NOT NULL default '0',
-          supported tinyint unsigned NOT NULL default '1',
-          recommended tinyint unsigned NOT NULL default '0',
-          snapshot tinyint unsigned NOT NULL default '0',
-          PRIMARY KEY (nid, tid, major)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-    case 'pgsql':
-      if (!db_table_exists('project_release_supported_versions')) {
-        $ret[] = update_sql("CREATE TABLE {project_release_supported_versions} (
-            nid int NOT NULL default '0',
-            tid int NOT NULL default '0',
-            major int NOT NULL default '0',
-            supported smallint NOT NULL default '1',
-            recommended smallint NOT NULL default '0',
-            snapshot smallint NOT NULL default '0',
-            PRIMARY KEY (nid, tid, major)
-          );");
-      }
-      break;
-  }
-  // Now, populate the table with the existing data. First, populate all the
-  // recommended majors versions from {project_release_default_versions}.
-  $ret[] = update_sql("INSERT INTO {project_release_supported_versions} (nid, tid, major, supported, recommended, snapshot) SELECT prdv.nid, prdv.tid, prdv.major, 1, 1, prp.snapshot_table FROM {project_release_default_versions} prdv INNER JOIN {project_release_projects} prp ON prdv.nid = prp.nid");
+  $schema['project_release_projects'] = array(
+    'description' => t('Table used to store release specific information about projects.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Primary Key: The {project_projects}.nid of the project_project node.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'releases' => array(
+        'description' => t('A flag indicating whether or not releases are enabled for a project.'),
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => FALSE,
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'version_format' => array(
+        'description' => t('A string used to designate the format of the {project_release_nodes}.version field for releases of a project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('nid'),
+    'indexes' => array(
+      'project_release_projects_releases' => array('releases')
+    ),
+  );
 
-  // Now, fill in all the non-recommended versions. For the migration path, we
-  // assume that if it's not recommended, it's also not supported. Project
-  // maintainers will have to manually visit the new UI if they want to
-  // specify multiple supported versions.
-  $vid = _project_release_get_api_vid();
-  $ret[] = update_sql("INSERT INTO {project_release_supported_versions} (nid, tid, major, supported, recommended, snapshot) SELECT DISTINCT prn.pid, tn.tid, prn.version_major, 0, 0, 0 FROM {project_release_nodes} prn INNER JOIN {term_node} tn ON prn.nid = tn.nid INNER JOIN {term_data} td ON tn.tid = td.tid INNER JOIN {node} n ON prn.nid = n.nid LEFT JOIN {project_release_default_versions} prdv ON prdv.nid = prn.pid AND prdv.tid = tn.tid AND prdv.major = prn.version_major WHERE n.status = 1 AND td.vid = $vid AND prn.version_major IS NOT NULL AND prdv.major IS NULL");
+  $schema['project_release_supported_versions'] = array(
+    'description' => t('Table used to store information about which major versions of a project are supported and/or recommended.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Primary Key: The {project_projects}.nid of the project_project node.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'tid' => array(
+        'description' => t('Primary Key: The {term_data}.tid of the API compatability version associated with a major version of a project.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'major' => array(
+        'description' => t('Primary Key: The {project_release_nodes}.version_major of a release node.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'supported' => array(
+        'description' => t('A flag to indicate whether or not a given major version of a project is supported.'),
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'recommended' => array(
+        'description' => t('A flag to indicate whether or not a given major version of a project is recommended.'),
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'snapshot' => array(
+        'description' => t('A flag to indicate whether or not snapshot releases of a major version of a project should be shown in the release download table.'),
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('nid', 'tid', 'major'),
+  );
 
-  // Finally, drop the stale table and column.
-  // While testing the upgrade path, these are both commented out for now:
-  //$ret[] = update_sql('DROP TABLE {project_release_default_versions}');
-  //$ret[] = update_sql("ALTER TABLE {project_release_projects} DROP snapshot_table");
+  $schema['project_release_package_errors'] = array(
+    'description' => t('Table used to store error messages generated by the scripts that package project_release nodes into tarballs.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Primary Key: The {node}.nid of the project_release node.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'messages' => array(
+        'description' => t('The text of any error messages created by the packaging scripts.'),
+        'type' => 'text',
+        'not null' => FALSE,
+      )
+    ),
+    'primary key' => array('nid'),
+  );
 
-  return $ret;
+  $schema['cache_project_release'] = array(
+    'description' => t('Cache table used to store the project release download tables.'),
+    'fields' => array(
+      'cid' => array(
+        'description' => t('Primary Key: Unique cache ID.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'data' => array(
+        'description' => t('A collection of data to cache.'),
+        'type' => 'blob',
+        'not null' => FALSE,
+        'size' => 'big',
+      ),
+      'expire' => array(
+        'description' => t('A Unix timestamp indicating when the cache entry should expire, or 0 for never.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'created' => array(
+        'description' => t('A Unix timestamp indicating when the cache entry was created.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'headers' => array(
+        'description' => t('Any custom HTTP headers to be added to cached data.'),
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
+    ),
+    'primary key' => array('cid'),
+    'indexes' => array(
+      'expire' => array('expire')
+    ),
+  );
+  return $schema;
 }
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/release/project_release.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/release/project_release.module,v
retrieving revision 1.68
diff -u -p -r1.68 project_release.module
--- release/project_release.module	14 Apr 2008 00:31:02 -0000	1.68
+++ release/project_release.module	27 Apr 2008 16:49:49 -0000
@@ -11,81 +11,86 @@ define('PROJECT_RELEASE_VERSION_FORMAT_H
  */
 
 /**
+ * Implementation of hook_init().
+ */
+function project_release_init() {
+  drupal_add_css(drupal_get_path('module', 'project_release') .'/project_release.css');
+  project_release_get_api_taxonomy();
+}
+
+/**
+ * Menu loader callback.  Load a project_project node if the given
+ * nid is a project_project node.
+ */
+function project_release_project_load($nid) {
+  if (!is_numeric($nid)) {
+    return FALSE;
+  }
+  $node = node_load($nid);
+  if (!isset($node->type) || $node->type != 'project_project') {
+    return FALSE;
+  }
+  return $node;
+}
+
+/**
  * Implementation of hook_menu()
  * @ingroup project_release_core
  */
 function project_release_menu($may_cache) {
   $items = array();
-  global $user;
-
-  $access_create = node_access('create', 'project_release');
 
-  if (!$may_cache) {
-    if (arg(0) == 'node' && is_numeric(arg(1))) {
-      $node = node_load(arg(1));
-      if ($node->type == 'project_project') {
-        $items[] = array(
-          'path' => 'node/'. arg(1) .'/release',
-          'title' => t('Releases'),
-          'callback' => 'project_release_project_releases',
-          'access' => node_access('view', $node),
-          'type' => MENU_CALLBACK,
-        );
-        if (node_access('update', $node)) {
-          $items[] = array(
-            'path' => 'node/'. arg(1) .'/release/overview',
-            'title' => t('Overview'),
-            'callback' => 'project_release_project_releases',
-            'access' => node_access('view', $node),
-            'type' => MENU_CALLBACK,
-          );
-          $items[] = array(
-            'path' => 'node/'. arg(1) .'/edit/releases',
-            'title' => t('Releases'),
-            'callback' => 'project_release_project_edit_releases',
-            'type' => MENU_LOCAL_TASK,
-          );
-        }
-      }
-    }
-    if (arg(0) == 'node' && arg(1) == 'add' && arg(2) == 'project-release' && is_numeric(arg(3))) {
-      $items[] = array(
-        'path' => 'node/add/project-release/'. arg(3),
-        'callback' => 'node_add',
-        'callback arguments' => array('project-release'),
-        'access' => $access_create,
-        'type' => MENU_CALLBACK,
-      );
-    }
-
-    drupal_add_css(drupal_get_path('module', 'project_release') .'/project_release.css');
-    project_release_get_api_taxonomy();
-  }
-  else {    // $may_cache
-    $items[] = array(
-      'path' => 'admin/project/project-release-settings',
-      'description' => t('Configure the default version string for releases and other settings for the Project release module.'),
-      'title' => t('Project release settings'),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => 'project_release_settings_form',
-      'access' => user_access('administer projects'),
-      'weight' => 1,
-      'type' => MENU_NORMAL_ITEM,
-    );
-    // Special menu item for the "first page" of submitting a new release.
-    // Instead of the treachery of a true multipage form, we just have
-    // a simple form at node/add/project-release that provides a project
-    // selector which redirects to node/add/project-release/[project-nid].
-    $types = node_get_types();
-    $items[] = array(
-      'path' => 'node/add/project-release',
-      'title' => t('Submit @name', array('@name' => $types['project_release']->name)),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => array('project_release_pick_project_form'),
-      'access' => $access_create,
-      'type' => MENU_NORMAL_ITEM,
-    );
-  }
+  $items['node/%project_release_project/release'] = array(
+    'title' => 'Releases',
+    'page callback' => 'project_release_project_releases',
+    'page arguments' => array(1),
+    'access callback' => 'node_access',
+    'access arguments' => array('view', 1),
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['node/%project_release_project/edit/releases'] = array(
+    'title' => 'Releases',
+    'page callback' => 'project_release_project_edit_releases',
+    'page arguments' => array(1),
+    'access callback' => 'node_access',
+    'access arguments' => array('update', 1),
+    'type' => MENU_LOCAL_TASK,
+  );
+// TODO:  One or both of the two menu items below probably needs to be done
+// via hook_menu_alter() instead of from here.
+  // Special menu item for the "first page" of submitting a new release.
+  // Instead of the treachery of a true multipage form, we just have
+  // a simple form at node/add/project-release that provides a project
+  // selector which redirects to node/add/project-release/[project-nid].
+  $types = node_get_types();
+  $items['node/add/project-release'] = array(
+    'title' => 'Submit @name',
+    'title arguments' => array('@name' => $types['project_release']->name),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('project_release_pick_project_form'),
+    'access callback' => 'node_access',
+    'access arguments' => array('create', 'project_release'),
+    'type' => MENU_NORMAL_ITEM,
+  );
+
+  $items['node/add/project-release/%project_release_project'] = array(
+    'page callback' => 'node_add',
+    'page arguments' => array('project-release'),
+    'access callback' => 'node_access',
+    'access arguments' => array('create', 'project_release'),
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['admin/project/project-release-settings'] = array(
+    'description' => 'Configure the default version string for releases and other settings for the Project release module.',
+    'title' => 'Project release settings',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => 'project_release_settings_form',
+    'access arguments' => array('administer projects'),
+    'weight' => 1,
+    'type' => MENU_NORMAL_ITEM,
+  );
   return $items;
 }
 
@@ -117,7 +122,7 @@ function project_release_settings_form()
     foreach ($tree as $term) {
       $terms[$term->tid] = check_plain($term->name);
     }
-    $vocab = taxonomy_get_vocabulary(_project_release_get_api_vid());
+    $vocab = taxonomy_vocabulary_load(_project_release_get_api_vid());
     $tids = variable_get('project_release_active_compatibility_tids', '');
     $form['project_release_active_compatibility_tids'] = array(
       '#type' => 'checkboxes',
@@ -155,23 +160,23 @@ function project_release_settings_form()
   return system_settings_form($form);
 }
 
-function project_release_settings_form_validate($form_id, $form_values, $form) {
-  if (!empty($form_values['project_release_directory'])) {
+function project_release_settings_form_validate($form, &$form_state) {
+  if (!empty($form_state['values']['project_release_directory'])) {
     form_set_error('project_release_directory', t('Release directory setting has been deprecated.'));
   }
-  $tids = $form_values['project_release_active_compatibility_tids'];
-  $default_tid = $form_values['project_release_overview'];
+  $tids = $form_state['values']['project_release_active_compatibility_tids'];
+  $default_tid = $form_state['values']['project_release_overview'];
   if ($default_tid != -1 && !$tids[$default_tid]) {
-    $vocab = taxonomy_get_vocabulary(_project_release_get_api_vid());
+    $vocab = taxonomy_vocabulary_load(_project_release_get_api_vid());
     form_set_error('project_release_overview', t('Project release overview must be one of the active @vocab terms', array('@vocab' => $vocab->name)));
   }
 
   // Make sure the default version format has no bad characters.
-  _project_release_validate_format_string($form_values, 'project_release_default_version_format');
+  _project_release_validate_format_string($form_state['values'], 'project_release_default_version_format');
 
   // If set, the project_release_download_base must end with a '/'
-  if (!empty($form_values['project_release_download_base'])) {
-    if (substr($form_values['project_release_download_base'], -1) != '/') {
+  if (!empty($form_state['values']['project_release_download_base'])) {
+    if (substr($form_state['values']['project_release_download_base'], -1) != '/') {
        form_set_error('project_release_download_base', t('The %download_base_setting should end with a slash.', array('%download_base_setting' => t('Download link base URL'))));
     }
   }
@@ -188,13 +193,12 @@ function project_release_settings_form_v
  * TODO: Maybe we should add new permissions for accessing release
  * nodes, but for now, we're just using the existing project perms.
  */
-function project_release_access($op, $node) {
-  global $user;
+function project_release_access($op, $node, $account) {
   switch ($op) {
     case 'view':
       // We want to use the identical logic for viewing projects,
       // so we call that method directly.
-      return project_project_access($op, $node);
+      return project_project_access($op, $node, $account);
     case 'create':
       // Due to how node_menu() works, we have to allow anyone with
       // permission to maintain a project to be able to create a
@@ -204,7 +208,7 @@ function project_release_access($op, $no
       // enforce more closely in project_release_form(). As with the
       // 'view' case above, we want the identical logic as project
       // nodes, so we call that hook, instead of duplicating code.
-      return project_project_access($op, $node);
+      return project_project_access($op, $node, $account);
     case 'update':
       // We can't just use project_project_access() here, since we
       // need to check access to the project itself, not the release
@@ -315,11 +319,11 @@ function project_release_form($release) 
     '#collapsible' => TRUE,
   );
   if (empty($release->file_path)) {
-    $file = file_check_upload('file');
+    $file = file_save_upload('file');
     $form['file']['file'] = array(
       '#title' => t('File'),
       '#type' => 'file',
-      '#description' => ($file ? t('A file named %filename has already been uploaded. If you upload another file %filename will be replaced.', array('%filename' => $file->filename)) : t('Choose the file that will be associated with this release.')),
+      '#description' => (!empty($file) ? t('A file named %filename has already been uploaded. If you upload another file %filename will be replaced.', array('%filename' => $file->filename)) : t('Choose the file that will be associated with this release.')),
     );
   }
 
@@ -449,7 +453,7 @@ function _project_release_form_add_text_
  */
 function project_release_validate(&$edit, $form) {
   global $form_values;
-
+// TODO:  get $form_state from somewhere.  I'm also probably not doing all the conversions correctly.
   if ($_POST['validate_version']) {
     if (!isset($edit->version_major) && !isset($edit->version_minor) &&
         !isset($edit->version_patch) &&
@@ -469,17 +473,17 @@ function project_release_validate(&$edit
     }
   }
 
-  if ($file = file_check_upload('file')) {
-    if ($file = file_save_upload($file)) {
+  if ($file = file_save_upload('file')) {
+    if (!empty($file)) {
       // Using $form_values here is an ugly hack, but the caching mechanism
       // in file_check_upload() causes problems if we can't pass this object
       // to the file_save_upload() call in the submit function which actually
       // saves the file.
-      $form_values['release_file'] = $file;
+      $form['release_file'] = $file;
       $filepath = file_create_path($file->filepath);
-      form_set_value($form['file']['file_path'], $file->filepath);
-      form_set_value($form['file']['file_date'], filemtime($filepath));
-      form_set_value($form['file']['file_hash'], md5_file($filepath));
+      form_set_value($form['file']['file_path'], $file->filepath, $form_state);
+      form_set_value($form['file']['file_date'], filemtime($filepath), $form_state);
+      form_set_value($form['file']['file_hash'], md5_file($filepath), $form_state);
     }
     else {
       form_set_error('file', t('There was a problem uploading the specified file.'));
@@ -519,13 +523,13 @@ function project_release_validate(&$edit
     // TODO: Magic re-setting to "%project_name %version" ??
   }
   elseif (isset($edit->version) && $edit->version !== '') {
-    form_set_value($form['title'], "$project_name $edit->version");
+    form_set_value($form['title'], "$project_name $edit->version", $form_state);
   }
   elseif (isset($edit->project)) {
     $version = project_release_get_version((object)$edit, $edit->project);
-    form_set_value(array('#parents' => array('version')), $version);
+    form_set_value(array('#parents' => array('version')), $version, $form_state);
     $title = $edit->project->title;
-    form_set_value($form['title'], "$title $version");
+    form_set_value($form['title'], "$title $version", $form_state);
   }
 }
 
@@ -875,9 +879,7 @@ function project_release_view($node, $te
  * Display a list of releases for a given project
  * @ingroup project_release_api
  */
-function project_release_project_releases() {
-  $node = node_load(arg(1));
-
+function project_release_project_releases($node) {
   // Breadcrumb navigation
   $breadcrumb[] = l($node->title, 'node/'. $node->nid);
   project_project_set_breadcrumb($node, $breadcrumb);
@@ -1025,32 +1027,32 @@ function project_release_version_filter_
       );
       $register = '';
       if (variable_get('user_register', 1)) {
-        $register = ' or '. l(t('register'), 'user/register', array(), $destination) .' ';
+        $register = ' or '. l(t('register'), 'user/register', array('query' => $destination)) .' ';
       }
-      $form['version_login'] = array('#value' => l(t('Login'), 'user/login', array(), $destination) . $register . t('to modify the filter.'));
+      $form['version_login'] = array('#value' => l(t('Login'), 'user/login', array('query' => $destination)) . $register . t('to modify the filter.'));
     }
     $form['#redirect'] = FALSE;
   }
   return isset($form) ? $form : '';
 }
 
-function project_release_version_filter_form_submit($form_id, $form_values) {
-  if (isset($form_values['version_tid'])) {
-    $_SESSION['project_version'] = $form_values['version_tid'];
+function project_release_version_filter_form_submit($form, &$form_state) {
+  if (isset($form_state['values']['version_tid'])) {
+    $_SESSION['project_version'] = $form_state['values']['version_tid'];
   }
 }
 
-function project_release_version_filter_form_validate($form_id, $form_values, $form) {
+function project_release_version_filter_form_validate($form, &$form_state) {
   global $user;
-  if (!$user->uid && $form_values['version_tid'] != variable_get('project_release_overview', -1)) {
-    $vocab = taxonomy_get_vocabulary(_project_release_get_api_vid());
+  if (!$user->uid && $form_state['values']['version_tid'] != variable_get('project_release_overview', -1)) {
+    $vocab = taxonomy_vocabulary_load(_project_release_get_api_vid());
     form_set_error('version_tid', t('You must login or register to modify the @vocab filter.', array('@vocab' => $vocab->name)));
   }
 }
 
 function theme_project_release_version_filter_form($form) {
   if (project_release_get_api_taxonomy()) {
-    $vocab = taxonomy_get_vocabulary(_project_release_get_api_vid());
+    $vocab = taxonomy_vocabulary_load(_project_release_get_api_vid());
     $label = check_plain($vocab->name);
   }
   else {
@@ -1069,7 +1071,7 @@ function theme_project_release_version_f
  * Implementation of hook_form_alter().
  * @ingroup project_release_fapi
  */
-function project_release_form_alter($form_id, &$form) {
+function project_release_form_alter(&$form, &$form_state, $form_id) {
   if ($form_id == 'project_project_node_form') {
     return project_release_alter_project_form($form);
   }
@@ -1090,8 +1092,7 @@ function project_release_alter_project_f
 /**
  * Releases subtab for the project edit tab.
  */
-function project_release_project_edit_releases() {
-  $node = node_load(arg(1));
+function project_release_project_edit_releases($node) {
   project_project_set_breadcrumb($node);
   drupal_set_title(check_plain($node->title));
   return drupal_get_form('project_release_project_edit_form', $node);
@@ -1110,7 +1111,7 @@ function project_release_project_edit_fo
     '#value' => t('Supported versions'),
   );
 
-  $vocab = taxonomy_get_vocabulary(_project_release_get_api_vid());
+  $vocab = taxonomy_vocabulary_load(_project_release_get_api_vid());
   $form['help'] = array(
     '#type' => 'markup',
     '#value' => t('For each term in the %api_vocabulary_name vocabulary, the following tables allow you to define which major versions are supported. If there are releases from more than one major version number, you can select which major version should be recommended for new users to download. You can also control if the development snapshot releases should be displayed on the front page of the project. Finally, for each term in the %api_vocabulary_name vocabulary, the current recommended release is shown. If no official releases have been made, the development snapshot from the corresponding branch will be listed. Otherwise, the most recent official release will be listed.', array('%api_vocabulary_name' => $vocab->name)),
@@ -1310,12 +1311,12 @@ function theme_project_release_project_e
  * @ingroup project_release_fapi
  * @see project_release_project_edit_releases
  */
-function project_release_project_edit_form_validate($form_id, $form_values, $form) {
-  if (!empty($form_values['version_format'])) {
-    _project_release_validate_format_string($form_values, 'version_format');
+function project_release_project_edit_form_validate($form, &$form_state) {
+  if (!empty($form_state['values']['version_format'])) {
+    _project_release_validate_format_string($form_state['values'], 'version_format');
   }
-  if (isset($form_values['api'])) {
-    foreach ($form_values['api'] as $tid => $api_info) {
+  if (isset($form_state['values']['api'])) {
+    foreach ($form_state['values']['api'] as $tid => $api_info) {
       $supported = FALSE;
       // First, we just iterate through to see if *any* majors are supported.
       foreach ($api_info['major'] as $major => $flags) {
@@ -1329,15 +1330,15 @@ function project_release_project_edit_fo
         foreach ($api_info['major'] as $major => $flags) {
           if (empty($flags['supported']) && !empty($flags['snapshot'])) {
             $element = 'api]['. $tid .'][major]['. $major .'][snapshot';
-            form_set_error($element, t('You can not show a snapshot release for a major version that is not supported for %api_term_name.', array('%api_term_name' => $form['api'][$tid]['#api_term_name'])));
+            form_set_error($element, t('You can not show a snapshot release for a major version that is not supported for %api_term_name.', array('%api_term_name' => $form_state['values']['api'][$tid]['#api_term_name'])));
           }
         }
         $recommended = $api_info['recommended'];
         if ($recommended < 0) {
-          form_set_error("api][$tid][recommended", t('You must select a recommended major version for %api_term_name.', array('%api_term_name' => $form['api'][$tid]['#api_term_name'])));
+          form_set_error("api][$tid][recommended", t('You must select a recommended major version for %api_term_name.', array('%api_term_name' => $form_state['values']['api'][$tid]['#api_term_name'])));
         }
         elseif (empty($api_info['major'][$recommended]['supported'])) {
-          form_set_error("api][$tid][recommended", t('You can not recommend a major version that is not supported for %api_term_name.', array('%api_term_name' => $form['api'][$tid]['#api_term_name'])));
+          form_set_error("api][$tid][recommended", t('You can not recommend a major version that is not supported for %api_term_name.', array('%api_term_name' => $form_state['values']['api'][$tid]['#api_term_name'])));
         }
       }
     }
@@ -1349,12 +1350,12 @@ function project_release_project_edit_fo
  * @ingroup project_release_fapi
  * @see project_release_project_edit_releases
  */
-function project_release_project_edit_form_submit($form_id, $form_values) {
-  $nid = $form_values['nid'];
-  db_query("UPDATE {project_release_projects} SET releases = %d, version_format = '%s' WHERE nid = %d", $form_values['releases'], $form_values['version_format'], $nid);
+function project_release_project_edit_form_submit($form, &$form_state) {
+  $nid = $form_state['values']['nid'];
+  db_query("UPDATE {project_release_projects} SET releases = %d, version_format = '%s' WHERE nid = %d", $form_state['values']['releases'], $form_state['values']['version_format'], $nid);
 
-  if (!empty($form_values['api'])) {
-    foreach ($form_values['api'] as $tid => $values) {
+  if (!empty($form_state['values']['api'])) {
+    foreach ($form_state['values']['api'] as $tid => $values) {
       if (isset($values['recommended'])) {
         $recommended_major = $values['recommended'];
       }
@@ -1376,9 +1377,9 @@ function project_release_project_edit_fo
       }
     }
   }
-  db_query("UPDATE {node} SET changed = %d WHERE nid = %d", time(), $form_values['nid']);
+  db_query("UPDATE {node} SET changed = %d WHERE nid = %d", time(), $form_state['values']['nid']);
 
-  $cid = 'table:'. $form_values['nid'] .':';
+  $cid = 'table:'. $form_state['values']['nid'] .':';
   cache_clear_all($cid, 'cache_project_release', TRUE);
 
   drupal_set_message(t('Release settings have been saved.'));
@@ -1616,7 +1617,7 @@ function theme_project_release_project_d
 /**
  * Implemenation of hook_project_page_link_alter().
  */
-function project_release_project_page_link_alter($node, &$all_links) {
+function project_release_project_page_link_alter(&$all_links, $node) {
   $all_links['project_release'] = array(
     // NOTE:  The 'name' element of this array is not defined here because
     // it's actually printed as part of the output of the
@@ -1825,7 +1826,7 @@ function project_release_table($project,
     $output = theme('table', $header, $rows, array('class' => 'releases'));
   }
   // Default cache time is 12 hours - will be cleared by the packaging script
-  cache_set($cid, 'cache_project_release', $output, time() + 43200);
+  cache_set($cid, $output, time() + 43200, 'cache_project_release');
   return $output;
 }
 
@@ -2053,14 +2054,14 @@ function project_release_exists($version
     $tid = $version->version_api_tid;
   }
 
-  $sql = 'SELECT * FROM {project_release_nodes} p'. $taxo_join .' WHERE p.pid = %d';
+  $sql = 'SELECT COUNT(*) FROM {project_release_nodes} p'. $taxo_join .' WHERE p.pid = %d';
   foreach ($types as $field => $type) {
     $sql .= " AND p.$field = $type";
   }
   $sql .= $taxo_where;
   // we put pid as the first WHERE, so stick it on the front
   $values = array_merge(array('pid' => $version->pid), $values);
-  return db_num_rows(db_query($sql, $values));
+  return db_result(db_query($sql, $values));
 }
 
 /**
@@ -2158,16 +2159,92 @@ function project_release_pick_project_fo
   return $form;
 }
 
-function project_release_pick_project_form_validate($form_id, $form_values) {
-  if (empty($form_values['pid'])) {
+function project_release_pick_project_form_validate($form, &$form_state) {
+  if (empty($form_state['values']['pid'])) {
     form_set_error('pid', t('You must select a project.'));
   }
-  $node = node_load($form_values['pid']);
+  $node = node_load($form_state['values']['pid']);
   if (empty($node) || $node->type != 'project_project') {
     form_set_error('pid', t('Invalid project selected.'));
   }
 }
 
-function project_release_pick_project_form_submit($form_id, $form_values) {
-  return 'node/add/project-release/'. $form_values['pid'];
+function project_release_pick_project_form_submit($form, &$form_state) {
+  return 'node/add/project-release/'. $form_state['values']['pid'];
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function project_release_theme() {
+  return array(
+    'project_release_download_link' => array(
+      'arguments' => array(
+        'file_path' => NULL,
+        'link_text' => NULL,
+        'as_array' => FALSE,
+      ),
+    ),
+    'project_release_download_table_row' => array(
+      'arguments' => array(
+        'release' => NULL,
+        'recommended' => FALSE,
+        'can_edit' => FALSE,
+        'print_size' => TRUE,
+      ),
+    ),
+    'project_release_download_text_recommended' => array(
+      'arguments' => array(
+        'release' => NULL,
+        'text_type' => NULL,
+      ),
+    ),
+    'project_release_download_text_snapshot' => array(
+      'arguments' => array(
+        'release' => NULL,
+        'text_type' => NULL,
+      ),
+    ),
+    'project_release_download_text_supported' => array(
+      'arguments' => array(
+        'release' => NULL,
+        'text_type' => NULL,
+      ),
+    ),
+    'project_release_download_text_unsupported' => array(
+      'arguments' => array(
+        'release' => NULL,
+        'text_type' => NULL,
+      ),
+    ),
+    'project_release_form_value' => array(
+      'arguments' => array(
+        'element' => NULL,
+      ),
+    ),
+    'project_release_project_download_table' => array(
+      'arguments' => array(
+        'node' => NULL,
+      ),
+    ),
+    'project_release_project_edit_form' => array(
+      'arguments' => array(
+        'form' => NULL,
+      ),
+    ),
+    'project_release_table_overview' => array(
+      'arguments' => array(
+        'project' => NULL,
+        'table_type' => NULL,
+        'release_type' => NULL,
+        'title' => NULL,
+        'print_size' => NULL,
+      ),
+    ),
+    'project_release_version_filter_form' => array(
+      'arguments' => array(
+        'form' => NULL,
+      ),
+    ),
+  );
 }
Index: /Applications/MAMP/htdocs/port/drupal/sites/all/modules/project/usage/project_usage.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/usage/project_usage.install,v
retrieving revision 1.3
diff -u -p -r1.3 project_usage.install
--- usage/project_usage.install	14 Sep 2007 16:17:55 -0000	1.3
+++ usage/project_usage.install	27 Apr 2008 16:49:49 -0000
@@ -3,57 +3,13 @@
 // $Name:  $
 
 function project_usage_install() {
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      db_query("CREATE TABLE IF NOT EXISTS {project_usage_raw} (
-          project_uri varchar(50) NOT NULL default '',
-          timestamp int unsigned NOT NULL default '0',
-          site_key varchar(32) NOT NULL default '',
-          api_version varchar(32) NOT NULL default '',
-          project_version varchar(255) NOT NULL default '',
-          pid int unsigned NOT NULL default '0',
-          nid int unsigned NOT NULL default '0',
-          tid int unsigned NOT NULL default '0',
-          PRIMARY KEY (timestamp, project_uri, site_key)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE IF NOT EXISTS {project_usage_day} (
-          timestamp int unsigned NOT NULL default '0',
-          site_key varchar(32) NOT NULL default '',
-          pid int unsigned NOT NULL default '0',
-          nid int unsigned NOT NULL default '0',
-          tid int unsigned NOT NULL default '0',
-          PRIMARY KEY (timestamp, site_key, pid)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE IF NOT EXISTS {project_usage_week_project} (
-          nid int unsigned NOT NULL default '0',
-          timestamp int unsigned NOT NULL default '0',
-          tid int unsigned NOT NULL default '0',
-          count int unsigned NOT NULL default '0',
-          PRIMARY KEY (nid, timestamp, tid)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE IF NOT EXISTS {project_usage_week_release} (
-          nid int unsigned NOT NULL default '0',
-          timestamp int unsigned NOT NULL default '0',
-          count int unsigned NOT NULL default '0',
-          PRIMARY KEY (nid, timestamp)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-  }
+  // Create the database tables.
+  drupal_install_schema('project_usage');
 }
 
 function project_usage_uninstall() {
-  $tables = array(
-    'project_usage_raw',
-    'project_usage_day',
-    'project_usage_week_project',
-    'project_usage_week_release',
-  );
-  foreach ($tables as $table) {
-    if (db_table_exists($table)) {
-      db_query("DROP TABLE {$table}");
-    }
-  }
+  // Drop database tables.
+  drupal_uninstall_schema('project_usage');
 
   $variables = array(
     'project_usage_last_daily',
@@ -68,34 +24,175 @@ function project_usage_uninstall() {
 }
 
 /**
- * Make sure that all the timestamps in the tables are GMT.
+ * Implementation of hook_schema().
  */
-function project_usage_update_5000() {
-  $ret = array();
+function project_usage_schema() {
+  $schema['project_usage_raw'] = array(
+    'description' => t('Table used to store raw usage information.'),
+    'fields' => array(
+      'project_uri' => array(
+        'description' => t('Primary Key: The {project_projects}.uri short name of the project.'),
+        'type' => 'varchar',
+        'length' => 50,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'timestamp' => array(
+        'description' => t('Primary Key: The Unix timestamp of when the request was made.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'site_key' => array(
+        'description' => t('Primary Key: An MD5 hash that identifies the site from which the request was made.'),
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'api_version' => array(
+        'description' => t('The {term_data}.name of the API version requested.'),
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'project_version' => array(
+        'description' => t('The {project_release_nodes}.version of the requested project.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'pid' => array(
+        'description' => t('The {node}.nid of the requested project.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'nid' => array(
+        'description' => t('The {node}.nid of the requested release.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'tid' => array(
+        'description' => t('The {term_data}.tid of the API compatability version of the requested release.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('timestamp', 'project_uri', 'site_key'),
+  );
 
-  // Since this might take a long time, if we're not in 'safe mode', increase
-  // the maximum execution time.
-  if (!ini_get('safe_mode')) {
-    set_time_limit(240);
-  }
+  $schema['project_usage_day'] = array(
+    'description' => t('Table used to store daily usage information.'),
+    'fields' => array(
+      'timestamp' => array(
+        'description' => t('Primary Key: The Unix timestamp of when the request was made.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'site_key' => array(
+        'description' => t('Primary Key: An MD5 hash that identifies the site from which the request was made.'),
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'pid' => array(
+        'description' => t('Primary Key: The {node}.nid of the requested project.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'nid' => array(
+        'description' => t('The {node}.nid of the requested release.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'tid' => array(
+        'description' => t('The {term_data}.tid of the API compatability version of the requested release.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('timestamp', 'site_key', 'pid'),
+  );
 
-  // Key is table name, value is function used to round the timestamp.
-  $tables = array(
-    'project_usage_week_project' => 'project_usage_weekly_timestamp',
-    'project_usage_week_release' => 'project_usage_weekly_timestamp',
-    'project_usage_raw' => 'project_usage_daily_timestamp',
-    'project_usage_day' => 'project_usage_daily_timestamp',
+  $schema['project_usage_week_project'] = array(
+    'description' => t('Table used to store weekly usage information by project and {term_data}.tid.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Primary Key: The {node}.nid of the project.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'timestamp' => array(
+        'description' => t('Primary Key: A Unix timestamp.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'tid' => array(
+        'description' => t('Primary Key: The {term_data}.tid of the API compatability version of the release.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'count' => array(
+        'description' => t('The number of requests.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('nid', 'timestamp', 'tid'),
   );
-  foreach ($tables as $table => $rounding_function) {
-    $query = db_query("SELECT DISTINCT timestamp FROM {$table} ORDER BY timestamp ASC");
-    while ($row = db_fetch_object($query)) {
-      $old = (int) $row->timestamp;
-      $new = (int) $rounding_function($old);
-      if ($old != $new) {
-        $ret[] = update_sql("UPDATE {$table} SET timestamp = $new WHERE timestamp = $old");
-      }
-    }
-  }
 
-  return $ret;
+  $schema['project_usage_week_release'] = array(
+    'description' => t('Table used to store weekly usage information by project and {term_data}.tid.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Primary Key: The {node}.nid of the project.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'timestamp' => array(
+        'description' => t('Primary Key: A Unix timestamp.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'count' => array(
+        'description' => t('The number of requests.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('nid', 'timestamp'),
+  );
+  return $schema;
 }
