Index: tracker2.admin.inc
===================================================================
RCS file: tracker2.admin.inc
diff -N tracker2.admin.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tracker2.admin.inc	11 Jan 2009 18:24:04 -0000
@@ -0,0 +1,55 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Admin page callbacks for the tracker2 module.
+ */
+
+/**
+ * Menu callback argument. Creates the tracker2 administration form.
+ */
+function tracker2_admin() {
+  $max_nid = variable_get('tracker2_index_nid', 0);
+  $form['max_nid'] = array(
+    '#value' => $max_nid ? t('Max node ID for indexing on the next cron run: @max', array('@max' => $max_nid)) : t('Existing nodes have finished tracker indexing.'),
+  );
+
+  $form['tracker2_batch_size'] = array(
+    '#title' => t('Batch size'),
+    '#description' => t('Number of nodes to index during each cron run.'),
+    '#type' => 'textfield',
+    '#size' => 6,
+    '#maxlength' => 7,
+    '#default_value' => variable_get('tracker2_batch_size', 1000),
+    '#required' => TRUE,
+  );
+
+	$form['tracker2_pager'] = array(
+    '#title' => t('Nodes per page'),
+    '#description' => t('Number of nodes to show per page of the tracker listing.'),
+    '#type' => 'textfield',
+    '#size' => 6,
+    '#maxlength' => 7,
+    '#default_value' => variable_get('tracker2_pager', 25),
+    '#required' => TRUE,
+  );
+
+  return system_settings_form($form);
+}
+
+/**
+ * Validate callback.
+ */
+function tracker2_admin_validate($form, &$form_state) {
+	// Max_nid is just a markup field and should not cause a variable to be set.
+	unset($form_state['values']['max_nid']);
+	
+	// The variables must be non-negative and numeric.
+  if (!is_numeric($form_state['values']['tracker2_batch_size']) || $form_state['values']['tracker2_batch_size'] <= 0) {
+	  form_set_error('tracker2_batch_size', t('The batch size must be a number and greater than zero.'));
+  }
+  if (!is_numeric($form_state['values']['tracker2_pager']) || $form_state['values']['tracker2_pager'] <= 0) {
+	  form_set_error('tracker2_pager', t('The nodes per page must be a number and greater than zero.'));
+  }
+}
\ No newline at end of file
Index: tracker2.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/tracker2/tracker2.info,v
retrieving revision 1.9
diff -u -p -r1.9 tracker2.info
--- tracker2.info	1 Apr 2008 15:56:29 -0000	1.9
+++ tracker2.info	11 Jan 2009 18:24:04 -0000
@@ -1,4 +1,5 @@
 ; $Id: tracker2.info,v 1.9 2008/04/01 15:56:29 straussd Exp $
 name = Tracker 2
 description = Enables tracking of recent posts for users.
-dependencies = comment
+dependencies[] = comment
+core = 6.x
Index: tracker2.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/tracker2/tracker2.install,v
retrieving revision 1.8
diff -u -p -r1.8 tracker2.install
--- tracker2.install	1 Apr 2008 15:56:29 -0000	1.8
+++ tracker2.install	11 Jan 2009 18:24:04 -0000
@@ -2,83 +2,101 @@
 
 // $Id: tracker2.install,v 1.8 2008/04/01 15:56:29 straussd Exp $
 
-function tracker2_install() {
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      db_query("CREATE TABLE IF NOT EXISTS {tracker2_node} (
-        nid int(10) unsigned NOT NULL,
-        published tinyint(1) NOT NULL,
-        changed int(10) unsigned NOT NULL,
-        PRIMARY KEY  (nid),
-        KEY tracker (published,changed)
-      )");
-        
-      db_query("CREATE TABLE IF NOT EXISTS {tracker2_user} (
-        nid int(10) unsigned NOT NULL,
-        published tinyint(1) NOT NULL,
-        uid int(10) unsigned NOT NULL,
-        changed int(10) unsigned NOT NULL,
-        PRIMARY KEY  (nid,uid),
-        KEY tracker (uid,published,changed)
-      )");
-    
-      db_query('ALTER TABLE {comments} ADD INDEX tracker_changed (nid, status, timestamp)');
-      db_query('ALTER TABLE {comments} ADD INDEX tracker_subscription (uid, nid, status)');
-      break;
-    case 'pgsql':
-      db_query("CREATE TABLE {tracker2_node} (
-        nid int_unsigned NOT NULL,
-        published smallint NOT NULL,
-        changed int_unsigned NOT NULL,
-        PRIMARY KEY  (nid)
-      )");
-      db_query('CREATE INDEX {tracker2_node}_tracker_idx ON {tracker2_node} (published, changed)');
-    
-      db_query("CREATE TABLE {tracker2_user} (
-        nid int_unsigned NOT NULL,
-        published smallint NOT NULL,
-        uid int_unsigned NOT NULL,
-        changed int_unsigned NOT NULL,
-        PRIMARY KEY  (nid, uid)
-      )");
-      db_query('CREATE INDEX {tracker2_user}_tracker_idx ON {tracker2_user} (uid, published, changed)');
+/**
+ * @file
+ * The (un)install and update code for the tracker2 module.
+ *
+ * @ingroup tracker2
+ */
 
-      db_query('CREATE INDEX {comments}_tracker_changed_idx ON {comments} (nid, status, timestamp)');
-      db_query('CREATE INDEX {comments}_tracker_subscription_idx ON {comments} (uid, nid, status)');
-      break;
-  }
+function tracker2_install() {
+  drupal_install_schema('tracker2');
+  tracker2_update_6001();
 }
 
 function tracker2_uninstall() {
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      db_query('DROP TABLE IF EXISTS {tracker2_node}');
-      db_query('DROP TABLE IF EXISTS {tracker2_user}');
-      db_query('ALTER TABLE {comments} DROP INDEX tracker_changed');
-      db_query('ALTER TABLE {comments} DROP INDEX tracker_subscription');
-      break;
-    case 'pgsql':
-      db_query('DROP TABLE {tracker2_node}');
-      db_query('DROP TABLE {tracker2_user}');
-      db_query('DROP INDEX {comments}_tracker_changed_idx');
-      db_query('DROP INDEX {comments}_tracker_subscription_idx');
-      break;
-  }
+  drupal_uninstall_schema('tracker2');
   variable_del('tracker2_index_nid');
+  variable_del('tracker2_batch_size');
+  variable_del('tracker2_pager');
+  db_drop_index($ret, 'comments', 'tracker_changed');
+  db_drop_index($ret, 'comments', 'tracker_subscription');
 }
 
 function tracker2_enable() {
   $max_nid = db_result(db_query('SELECT MAX(nid) FROM {node}'));
   variable_set('tracker2_index_nid', $max_nid);
-  drupal_set_message(t('Tracker will index from node %nid downward.', array('%nid' => $max_nid)));
+  if ($max_nid) {
+    drupal_set_message(t('Tracker will index from node %nid downward.', array('%nid' => $max_nid)));
+  }
 }
 
-function tracker2_update_1() {
+function tracker2_update_6001() {
   $ret = array();
-  $ret[] = update_sql('ALTER TABLE {comments} DROP INDEX tracker');
-  $ret[] = update_sql('ALTER TABLE {comments} ADD INDEX tracker_changed (nid, status, timestamp)');
-  $ret[] = update_sql('ALTER TABLE {comments} ADD INDEX tracker_subscription (uid, nid, status)');
+  db_add_index($ret, 'comments', 'tracker_changed', array('nid', 'status', 'timestamp'));
+  db_add_index($ret, 'comments', 'tracker_subscription', array('uid', 'nid', 'status'));
   return $ret;
 }
+
+function tracker2_schema() {
+  $schema['tracker2_node'] = array(
+    'description' => 'Track changes to content',
+    'fields' => array(
+      'nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => "{node}.nid",
+      ),
+      'published' => array(
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'description' => "True if {node}.status == 1",
+      ),
+      'changed' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => "{node}.changed",
+      ),
+    ),
+    'primary key' => array('nid'),
+    'indexes' => array(
+      'tracker' => array('published', 'changed'),
+    ),
+  );
+  $schema['tracker2_user'] = array(
+    'fields' => array(
+      'nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => "{node}.nid"
+      ),
+     'uid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => "{user}.uid",
+      ),
+      'published' => array(
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'description' => "True if {node}.status == 1",
+      ),
+      'changed' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => "{node}.changed",
+      ),
+    ),
+    'primary key' => array('nid', 'uid'),
+    'indexes' => array(
+      'tracker' => array('uid', 'published', 'changed'),
+    ),
+  );
+  return $schema;
+}
Index: tracker2.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/tracker2/tracker2.module,v
retrieving revision 1.13
diff -u -p -r1.13 tracker2.module
--- tracker2.module	2 Jun 2008 04:06:49 -0000	1.13
+++ tracker2.module	11 Jan 2009 18:24:05 -0000
@@ -1,14 +1,26 @@
 <?php
-
 // $Id: tracker2.module,v 1.13 2008/06/02 04:06:49 straussd Exp $
 
 /**
- * Implementation of hook_menu().
+ * @file
+ * Enables tracking of recent posts for users.
+ */
+
+/**
+ * Implementation of hook_help().
  */
-function tracker2_menu($may_cache) {
-  global $user;
-  $items = array();
+function tracker2_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#tracker2':
+      return '<p>'. t('The Tracker2 module is a much more efficient tracker that maintains seperate database tables of updated items.') .'</p>';
+  }
+}
 
+/**
+ * Implementation of hook_menu().
+ */
+ //TODO: test paths still work after file changes.
+function tracker2_menu() {
   $base = 'tracker2';
   $user_base = 'track2';
   if (!module_exists('tracker')) {
@@ -16,159 +28,135 @@ function tracker2_menu($may_cache) {
     $user_base = 'track';
   }
 
-  if ($may_cache) {
-    $items[] = array(
-      'path' => $base,
-      'title' => t('Recent posts'),
-      'callback' => 'tracker2_page',
-      'access' => user_access('access content'),
-      'weight' => 1,
-    );
-
-    if ($user->uid) {
-      $items[] = array(
-        'path' => $base . '/all',
-        'title' => t('All recent posts'),
-        'type' => MENU_DEFAULT_LOCAL_TASK,
-      );
-      $items[] = array(
-        'path' => $base . '/'. $user->uid,
-        'title' => t('My recent posts'),
-        'type' => MENU_LOCAL_TASK,
-      );
-    }
-    
-    $items[] = array(
-      'path' => 'admin/settings/tracker2',
-      'title' => 'Tracker 2',
-      'description' => t('High-performance reimplementation of the Tracker module.'),
-      'callback' => 'drupal_get_form',
-      'access' => user_access('administer tracker'),
-      'callback arguments' => array('tracker2_admin_settings')
-    );
-  }
-  else {
-    if (arg(0) == 'user' && is_numeric(arg(1))) {
-      $items[] = array(
-        'path' => 'user/'. arg(1) .'/' . $user_base,
-        'title' => t('Track'),
-        'callback' => 'tracker2_track_user',
-        'access' => user_access('access content'),
-        'type' => MENU_IS_LOCAL_TASK
-      );
-      $items[] = array(
-        'path' => 'user/'. arg(1) .'/' . $user_base . '/posts',
-        'title' => t('Track posts'),
-        'type' => MENU_DEFAULT_LOCAL_TASK,
-      );
-    }
-  }
+  $items[$base] = array(
+    'title' => 'Recent posts',
+    'page callback' => 'tracker2_page',
+    'access arguments' => array('access content'),
+    'weight' => 1,
+    'file' => 'tracker2.pages.inc',
+  );
+
+  $items[$base .'/all'] = array(
+    'title' => 'All recent posts',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  $items[$base .'/%user'] = array(
+    'title' => 'My recent posts',
+    'access callback' => '_tracker2_myrecent_access',
+    'access arguments' => array(1),
+    'page arguments' => array(1),
+    'type' => MENU_LOCAL_TASK,
+  );
+  
+  $items['admin/settings/tracker2'] = array(
+    'title' => 'Tracker 2',
+    'description' => 'High-performance reimplementation of the Tracker module.',
+    'page callback' => 'drupal_get_form',
+    'access arguments' => array('administer tracker'),
+    'page arguments' => array('tracker2_admin'),
+    'file' => 'tracker2.admin.inc',
+  );
+
+  $items['user/%user/'. $user_base] = array(
+    'title' => 'Track',
+    'page callback' => 'tracker2_track_user',
+    'access arguments' => array('access content'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'tracker2.pages.inc',
+  );
+  $items['user/%user/'. $user_base .'/posts'] = array(
+    'title' => 'Track posts',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
 
   return $items;
 }
 
 /**
- * Implementation of hook_perm().
+ * Access callback for tracker/%user.
  */
-function tracker2_perm() {
-  return array('administer tracker');
+function _tracker2_myrecent_access($account) {
+  // This path is only allowed for authenticated users looking at their own posts.
+  return $account->uid && ($GLOBALS['user']->uid == $account->uid) && user_access('access content');
 }
 
 /**
- * Menu callback argument. Prints a listing of active nodes on the site.
+ * Access callback for user account tracker tab.
  */
-function tracker2_admin_settings() {
-  $form = array();
-  
-  $max_nid = variable_get('tracker2_index_nid', 0);
-  
-  if ($max_nid) {
-    $form['max_nid'] = array(
-      '#value' => t('Max node ID for indexing on the next cron run: @max', array('@max' => $max_nid)),
-    );
-  }
-  else {
-    $form['max_nid'] = array(
-      '#value' => t('Existing nodes have finished tracker indexing.'),
-    );
-  }
-  
-  $form['tracker2_batch_size'] = array(
-    '#title' => t('Batch size'),
-    '#description' => t('Number of nodes to index during each cron run.'),
-    '#type' => 'textfield',
-    '#size' => 6,
-    '#maxlength' => 7,
-    '#default_value' => variable_get('tracker2_batch_size', 1000),
-  );
-  return system_settings_form($form);
+function _tracker2_user_access($account) {
+  return user_view_access($account) && user_access('access content');
+}
+
+
+/**
+ * Implementation of hook_perm().
+ */
+function tracker2_perm() {
+  return array('administer tracker');
 }
 
 /**
  * Implementation of hook_cron().
  */
+ //TODO: needs testing
 function tracker2_cron() {
   $max_nid = variable_get('tracker2_index_nid', 0);
   $batch_size = variable_get('tracker2_batch_size', 1000);
-  if ($max_nid > 0) {
+  if ($max_nid) {
     $last_nid = FALSE;
-    $res = db_query_range('SELECT nid, uid, status FROM {node} WHERE nid <= %d ORDER BY nid DESC', $max_nid, 0, $batch_size);
-    
+    $res = db_query_range("SELECT nid, uid, status FROM {node} WHERE nid <= %d ORDER BY nid DESC", $max_nid, 0, $batch_size);
     $count = 0;
-    
+
     while ($row = db_fetch_object($res)) {
-      //echo 'Indexing node ' . $row->nid . '<br />';
-      
       // Calculate the changed timestamp for this node.
       $changed = _tracker2_calculate_changed($row->nid);
-      
+
       // Remove existing data for this node.
-      db_query('DELETE FROM {tracker2_node} WHERE nid = %d', $row->nid);
-      db_query('DELETE FROM {tracker2_user} WHERE nid = %d', $row->nid);
-      
+      db_query("DELETE FROM {tracker2_node} WHERE nid = %d", $row->nid);
+      db_query("DELETE FROM {tracker2_user} WHERE nid = %d", $row->nid);
+
       // Insert the node-level data.
-      db_query('INSERT INTO {tracker2_node} (nid, published, changed) VALUES (%d, %d, %d)', $row->nid, $row->status, $changed);
-      
+      db_query("INSERT INTO {tracker2_node} (nid, published, changed) VALUES (%d, %d, %d)", $row->nid, $row->status, $changed);
+
       // Insert the user-level data for the node's author.
-      db_query('INSERT INTO {tracker2_user} (nid, published, uid, changed) VALUES (%d, %d, %d, %d)', $row->nid, $row->status, $row->uid, $changed);
-      
+      db_query("INSERT INTO {tracker2_user} (nid, published, uid, changed) VALUES (%d, %d, %d, %d)", $row->nid, $row->status, $row->uid, $changed);
+
       // Insert the user-level data for the commenters (except if a commenter is the node's author).
-      db_query('INSERT INTO {tracker2_user} (nid, published, uid, changed) SELECT DISTINCT %d AS nid, %d AS published, uid, %d AS changed FROM {comments} WHERE nid = %d AND uid <> %d AND status = %d', $row->nid, $row->status, $changed, $row->nid, $row->uid, COMMENT_PUBLISHED);
+      db_query("INSERT INTO {tracker2_user} (nid, published, uid, changed) SELECT DISTINCT %d AS nid, %d AS published, uid, %d AS changed FROM {comments} WHERE nid = %d AND uid <> %d AND status = %d", $row->nid, $row->status, $changed, $row->nid, $row->uid, COMMENT_PUBLISHED);
 
       // Note that we have indexed at least one node.
       $last_nid = $row->nid;
-      
-      ++$count;
+
+      $count++;
     }
     
     if ($last_nid !== FALSE) {
-      // Prepare a starting point for the next run
+      // Prepare a starting point for the next run.
       variable_set('tracker2_index_nid', $last_nid - 1);
-      
-      watchdog('tracker2', t('Indexed %count nodes for tracking.', array('%count' => $count)));
+
+      watchdog('tracker2', 'Indexed %count nodes for tracking.', array('%count' => $count));
     }
     else {
-      // If all nodes have been indexed, set to zero to skip future cron runs
-      variable_set('tracker2_index_nid', 0);    
+      // If all nodes have been indexed, set to zero to skip future cron runs.
+      variable_set('tracker2_index_nid', 0);
     }
   }
 }
-
+// TODO: combine the next two functions into the hook_nodeapi because this is not robust enough.
 /**
  * Implementation of hook_form_alter().
  */
-function tracker2_form_alter($form_id, &$form) {
+function tracker2_form_alter(&$form, $form_state, $form_id) {
   if ($form_id == 'node_admin_nodes') {
-    $form['#submit']['tracker2_batch_node_alter'] = array();
+    $form['#submit'][] = 'tracker2_batch_node_alter';
   }
 }
 
-function tracker2_batch_node_alter($form_id, $form_values) {
-  //drupal_set_message('<pre>' . print_r($form_values, TRUE) . '</pre>');
+function tracker2_batch_node_alter($form, &$form_state) {
 
-  $op = $form_values['operation'];
-  foreach($form_values['nodes'] as $nid => $selected) {
-    if ($selected) {      
+  $op = $form_state['values']['operation'];
+  foreach ($form_values['nodes'] as $nid => $selected) {
+    if ($selected) {
       if ($op == 'publish') {
         db_query('UPDATE {tracker2_node} SET published = 1 WHERE nid = %d', $nid);
         db_query('UPDATE {tracker2_user} SET published = 1 WHERE nid = %d', $nid);
@@ -184,88 +172,105 @@ function tracker2_batch_node_alter($form
   }
 }
 
-function _tracker2_add($nid, $uid, $changed) {  
-  $node = db_fetch_object(db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = %d', $nid));
+/**
+ * Create or update the tracker2 records.
+ */
+function _tracker2_add($nid, $uid, $changed) {
+  $node = db_fetch_object(db_query("SELECT nid, status, uid, changed FROM {node} WHERE nid = %d", $nid));
 
+  $insert = new stdClass();
+  $insert->nid = $nid;
   // Adding a comment can only increase the changed timestamp, so our calculation here is easy.
-  $changed = max($node->changed, $changed);
-
-  // Update the node-level data
-  $exists = db_result(db_query('SELECT COUNT(*) FROM {tracker2_node} WHERE nid = %d', $nid));
+  $insert->changed = max($node->changed, $changed);
+  $insert->published = $node->status;
+  
+  // Create or update the node-level data.
+  $exists = db_result(db_query("SELECT COUNT(*) FROM {tracker2_node} WHERE nid = %d", $nid));
   if ($exists) {
-    db_query('UPDATE {tracker2_node} SET changed = %d, published = %d WHERE nid = %d', $changed, $node->status, $nid);
+    drupal_write_record('tracker2_node', $insert, 'nid');
   }
   else {
-    db_query('INSERT INTO {tracker2_node} (changed, published, nid) VALUES (%d, %d, %d)', $changed, $node->status, $nid);
+    drupal_write_record('tracker2_node', $insert);
   }
-  
-  // Create or update the user-level data
-  db_query('UPDATE {tracker2_user} SET changed = %d, published = %d WHERE nid = %d', $changed, $node->status, $nid);
-  $exists = db_result(db_query('SELECT COUNT(*) FROM {tracker2_user} WHERE nid = %d AND uid = %d', $nid, $uid));
-  if (!$exists) {
-    db_query('INSERT INTO {tracker2_user} (changed, published, nid, uid) VALUES (%d, %d, %d, %d)', $changed, $node->status, $nid, $uid);
+
+  // Create or update the user-level data.
+  $exists = db_result(db_query("SELECT COUNT(*) FROM {tracker2_user} WHERE nid = %d AND uid = %d", $nid, $uid));
+  $insert->uid = $uid;
+  if ($exists) {
+    drupal_write_record('tracker2_user', $insert, 'nid');
+  }
+  else {
+    drupal_write_record('tracker2_user', $insert);
   }
 }
 
+/**
+ * Calculate the last time the node was changed or commented upon.
+ */
 function _tracker2_calculate_changed($nid) {
-  $changed = db_result(db_query('SELECT changed FROM {node} WHERE nid = %d', $nid));
-  $latest_comment = db_fetch_object(db_query_range('SELECT cid, timestamp FROM {comments} WHERE nid = %d AND status = %d ORDER BY timestamp DESC', $nid, COMMENT_PUBLISHED, 0, 1));
-  if ($latest_comment && $latest_comment->timestamp > $changed) {
-    $changed = $latest_comment->timestamp;
-  }
-  return $changed;
+  $changed = db_result(db_query("SELECT changed FROM {node} WHERE nid = %d", $nid));
+  $comment_changed = db_result(db_query_range("SELECT timestamp FROM {comments} WHERE nid = %d AND status = %d ORDER BY timestamp DESC", $nid, COMMENT_PUBLISHED, 0, 1));
+  return max($comment_changed, $changed);
 }
 
+/**
+ * Delete from the tracker2 records.
+ */
 function _tracker2_remove($nid, $uid = NULL, $changed = NULL) {
-  $node = db_fetch_object(db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = %d', $nid));
-
-  // The user only keeps his or her subscription if both of the following are true:
-  // (1) The node exists.
-  // (2) The user is either the node author or has commented on the node.
-  $keep_subscription = FALSE;
+  $node = db_fetch_object(db_query("SELECT nid, status, uid, changed FROM {node} WHERE nid = %d", $nid));
   
   if ($node) {
+    $keep_subscription = FALSE;
+    
+    // The user only keeps his or her subscription if both of the following are true:
+    // (1) The node exists.
+    // (2) The user is either the node author or has commented on the node.
+    
     // Self-authorship is one reason to keep the user's subscription.
     $keep_subscription = ($node->uid == $uid);
-    
+
     // Comments are a second reason to keep the user's subscription.
     if (!$keep_subscription) {
-      // Check if the user has commented at least once on the given nid
-      $keep_subscription = db_result(db_query_range('SELECT COUNT(*) FROM {comments} WHERE nid = %d AND uid = %d AND status = 0', $nid, $uid, 0, 1));
+      // Check if the user has a published comment at least once on the given nid.
+      $keep_subscription = db_result(db_query_range("SELECT COUNT(*) FROM {comments} WHERE nid = %d AND uid = %d AND status = 0", $nid, $uid, 0, 1));
     }
 
-    // If we haven't found a reason to keep the user's subscription, delete it.  
+    // If we haven't found a reason to keep the user's subscription, delete it.
     if (!$keep_subscription) {
-      db_query('DELETE FROM {tracker2_user} WHERE nid = %d AND uid = %d', $nid, $uid);
+      db_query("DELETE FROM {tracker2_user} WHERE nid = %d AND uid = %d", $nid, $uid);
     }
-      
+
     // Now we need to update the (possibly) changed timestamps for other users and the node itself.
-    
+
     // We only need to do this if the removed item has a timestamp that equals
-    // or exceeds the listed changed timestamp for the node
-    $tracker_node = db_fetch_object(db_query('SELECT nid, changed FROM {tracker2_node} WHERE nid = %d', $nid));
+    // or exceeds the listed changed timestamp for the node.
+    $tracker_node = db_fetch_object(db_query("SELECT nid, changed FROM {tracker2_node} WHERE nid = %d", $nid));
     if ($tracker_node && $changed >= $tracker_node->changed) {
       // If we're here, the item being removed is *possibly* the item that established the node's changed timestamp.
       
+      $insert = new stdClass();
+      $insert->nid = $nid;
+      $insert->published = $node->status;
+
       // We just have to recalculate things from scratch.
-      $changed = _tracker2_calculate_changed($nid);
-      
+      $insert->changed = _tracker2_calculate_changed($nid);
+
       // And then we push the out the new changed timestamp to our denormalized tables.
-      db_query('UPDATE {tracker2_node} SET changed = %d, published = %d WHERE nid = %d', $changed, $node->status, $nid);
-      db_query('UPDATE {tracker2_user} SET changed = %d, published = %d WHERE nid = %d', $changed, $node->status, $nid);
+      drupal_write_record('tracker2_node', $insert, 'nid');
+      drupal_write_record('tracker2_user', $insert, 'nid');
     }
   }
   else {
-    // If the node doesn't exist, remove everything
-    db_query('DELETE FROM {tracker2_node} WHERE nid = %d', $nid);
-    db_query('DELETE FROM {tracker2_user} WHERE nid = %d', $nid);
+    // If the node doesn't exist, remove everything.
+    db_query("DELETE FROM {tracker2_node} WHERE nid = %d", $nid);
+    db_query("DELETE FROM {tracker2_user} WHERE nid = %d", $nid);
   }
 }
 
 /**
  * Implementation of hook_nodeapi().
  */
-function tracker2_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
+function tracker2_nodeapi(&$node, $op) {
   if ($op == 'insert' || $op == 'update') {
     _tracker2_add($node->nid, $node->uid, $node->changed);
   }
@@ -278,110 +283,33 @@ function tracker2_nodeapi(&$node, $op, $
  * Implementation of hook_comment().
  */
 function tracker2_comment($a1, $op) {
-  //drupal_set_message($op . '<pre>' . print_r($a1, TRUE) . '</pre>');  
   $comment = (array) $a1;
-  if ($op == 'insert' || $op == 'update' || $op == 'publish') {
-    if ($comment['status'] == COMMENT_PUBLISHED) {
-      _tracker2_add($comment['nid'], $comment['uid'], $comment['timestamp']);
-    }
-    else {
-      _tracker2_remove($comment['nid'], $comment['uid'], $comment['timestamp']);
-    }
-  }
-  else if ($op == 'delete' || $op == 'unpublish') {
-    _tracker2_remove($comment['nid'], $comment['uid'], $comment['timestamp']);
-  }
-}
-
-/**
- * Menu callback. Prints a listing of active nodes on the site.
- */
-function tracker2_page($uid = 0) {
-  drupal_add_css(drupal_get_path('module', 'tracker2') .'/tracker2.css', 'module', 'all', FALSE);
-
-  if ($uid) {
-    $sql = 'SELECT t2u.nid, t2u.changed AS last_activity FROM {tracker2_user} t2u WHERE t2u.published = 1 AND t2u.uid = %d ORDER BY t2u.changed DESC';
-    $sql = db_rewrite_sql($sql, 't2u');
-    $sql_count = 'SELECT COUNT(t2u.nid) FROM {tracker2_user} t2u WHERE t2u.published = 1 AND t2u.uid = %d';
-    $sql_count = db_rewrite_sql($sql_count, 't2u');
-    $result = pager_query($sql, 25, 0, $sql_count, $uid);
-  }
-  else {
-    $sql = 'SELECT t2n.nid, t2n.changed AS last_activity FROM {tracker2_node} t2n WHERE t2n.published = 1 ORDER BY t2n.changed DESC';
-    $sql = db_rewrite_sql($sql, 't2n');
-    $sql_count = 'SELECT COUNT(n.nid) FROM {node} n WHERE n.status = 1';
-    $sql_count = db_rewrite_sql($sql_count);
-    $result = pager_query($sql, 25, 0, $sql_count);
-  }
-
-  // This array acts as a placeholder for the data selected later
-  // while keeping the correct order.
-  $nodes = array();
-  while ($node = db_fetch_object($result)) {
-    $nodes[$node->nid] = $node;
-  }
-
-  if (!empty($nodes)) {
-    // Now, get the data and put into the placeholder array
-    $placeholders = implode(',', array_fill(0, count($nodes), '%d'));
-    $result = db_query("SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, l.comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {users} u ON n.uid = u.uid WHERE n.nid IN ($placeholders)", array_keys($nodes));
-    while ($node = db_fetch_object($result)) {
-      $node->last_activity = $nodes[$node->nid]->last_activity;
-      $nodes[$node->nid] = $node;
-    }
-  
-    // Finally display the data
-    $rows = array();
-    foreach ($nodes as $node) {
-      // Determine the number of comments:
-      $comments = 0;
-      if ($node->comment_count) {
-        $comments = $node->comment_count;
-  
-        if ($new = comment_num_new($node->nid)) {
-          $comments .= '<br />';
-          $comments .= l(format_plural($new, '1 new', '@count new'), 'node/'. $node->nid, NULL, NULL, 'new');
-        }
+  switch ($op) {
+    case 'insert':
+    case 'update':
+    case 'publish':
+      if ($comment['status'] == COMMENT_PUBLISHED) {
+        _tracker2_add($comment['nid'], $comment['uid'], $comment['timestamp']);
       }
-  
-      $rows[] = array(
-        check_plain(node_get_types('name', $node->type)),
-        l($node->title, "node/$node->nid") .' '. theme('mark', node_mark($node->nid, $node->changed)),
-        theme('username', $node),
-        array('class' => 'replies', 'data' => $comments),
-        t('!time ago', array('!time' => format_interval(time() - $node->last_activity)))
-      );
-    }
-  }
-  else {
-    $rows[] = array(array('data' => t('No posts available.'), 'colspan' => '5'));
+      else {
+        _tracker2_remove($comment['nid'], $comment['uid'], $comment['timestamp']);
+      }
+      break;    
+    case 'delete':
+    case 'unpublish':
+       _tracker2_remove($comment['nid'], $comment['uid'], $comment['timestamp']);
+      break;
   }
-
-  $header = array(t('Type'), t('Post'), t('Author'), t('Replies'), t('Last updated'));
-
-  $output = '<div id="tracker">';
-  $output .= theme('table', $header, $rows);
-  $output .= theme('pager', NULL, 25, 0);
-  $output .= '</div>';
-
-  return $output;
 }
 
-
 /**
- * Menu callback. Prints a listing of active nodes on the site.
+ * Implementation of hook_theme().
  */
-function tracker2_track_user() {
-  if ($account = user_load(array('uid' => arg(1)))) {
-    if ($account->status || user_access('administer users')) {
-      drupal_set_title(check_plain($account->name));
-      return tracker2_page($account->uid);
-    }
-    else {
-      drupal_access_denied();
-    }
-  }
-  else {
-    drupal_not_found();
-  }
+function tracker2_theme() {
+  return array(
+    'tracker2_page' => array(
+      'arguments' => array('nodes' => array()),
+      'file' => 'tracker2.pages.inc',
+    ),
+  );
 }
\ No newline at end of file
Index: tracker2.pages.inc
===================================================================
RCS file: tracker2.pages.inc
diff -N tracker2.pages.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tracker2.pages.inc	11 Jan 2009 18:24:05 -0000
@@ -0,0 +1,108 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * User page callbacks for the tracker2 module.
+ */
+
+/**
+ * Menu callback. Prints a listing of active nodes on the site.
+ */
+function tracker2_page($account = NULL) {
+  drupal_add_css(drupal_get_path('module', 'tracker2') .'/tracker2.css', 'module', 'all', FALSE);
+  $nodes_per_page = variable_get('tracker2_pager', 25);
+ 
+  if ($account) {
+    $sql = "SELECT t2u.nid, t2u.changed AS last_activity FROM {tracker2_user} t2u WHERE t2u.published = 1 AND t2u.uid = %d ORDER BY t2u.changed DESC";
+    $sql = db_rewrite_sql($sql, 't2u');
+    $sql_count = "SELECT COUNT(t2u.nid) FROM {tracker2_user} t2u WHERE t2u.published = 1 AND t2u.uid = %d";
+    $sql_count = db_rewrite_sql($sql_count, 't2u');
+    $result = pager_query($sql, $nodes_per_page, 0, $sql_count, $account->uid);
+  }
+  else {
+    $sql = "SELECT t2n.nid, t2n.changed AS last_activity FROM {tracker2_node} t2n WHERE t2n.published = 1 ORDER BY t2n.changed DESC";
+    $sql = db_rewrite_sql($sql, 't2n');
+    $sql_count = "SELECT COUNT(n.nid) FROM {node} n WHERE n.status = 1";
+    $sql_count = db_rewrite_sql($sql_count);
+    $result = pager_query($sql, $nodes_per_page, 0, $sql_count);
+  }
+
+  // This array acts as a placeholder for the data selected later
+  // while keeping the correct order.
+  $nodes = array();
+  while ($node = db_fetch_object($result)) {
+    $nodes[$node->nid] = $node;
+  }
+  return theme('tracker2_page', $nodes);
+}
+
+/**
+ * Override-able output of the tracker2 listings.
+ */
+function theme_tracker2_page($nodes = array()) {
+	if (!empty($nodes)) {
+    // Now, get the data and put into the placeholder array
+    $placeholders = array_fill(0, count($nodes), '%d');
+
+    $result = db_query("SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, l.comment_count FROM {node} n 
+      INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {users} u ON n.uid = u.uid 
+      WHERE n.nid IN (". implode(',', $placeholders) .")", array_keys($nodes));
+    while ($node = db_fetch_object($result)) {
+      $node->last_activity = $nodes[$node->nid]->last_activity;
+      $nodes[$node->nid] = $node;
+    }
+
+    // Finally display the data
+    $rows = array();
+    foreach ($nodes as $node) {
+      // Determine the number of comments:
+      $comments = 0;
+      if ($node->comment_count) {
+        $comments = $node->comment_count;
+
+        if ($new = comment_num_new($node->nid)) {
+          $comments .= '<br />';
+          $comments .= l(format_plural($new, '1 new', '@count new'), 'node/'. $node->nid, array('fragment' => 'new'));
+        }
+      }
+
+      $rows[] = array(
+        check_plain(node_get_types('name', $node->type)),
+        l($node->title, "node/$node->nid") .' '. theme('mark', node_mark($node->nid, $node->changed)),
+        theme('username', $node),
+        array('class' => 'replies', 'data' => $comments),
+        t('!time ago', array('!time' => format_interval(time() - $node->last_activity)))
+      );
+    }
+  }
+  else {
+    $rows[] = array(array('data' => t('No posts available.'), 'colspan' => '5'));
+  }
+
+  $header = array(t('Type'), t('Post'), t('Author'), t('Replies'), t('Last updated'));
+
+  $output = '<div id="tracker">';
+  $output .= theme('table', $header, $rows);
+  $output .= theme('pager', NULL, variable_get('tracker2_pager', 25), 0);
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Menu callback. Prints a listing of active nodes on the site per user.
+ */
+function tracker2_track_user() {
+  if ($account = user_load(array('uid' => arg(1)))) {
+    if ($account->status || user_access('administer users')) {
+      drupal_set_title(check_plain($account->name));
+      return tracker2_page($account);
+    }
+    else {
+      drupal_access_denied();
+    }
+  }
+  else {
+    drupal_not_found();
+  }
+}
\ No newline at end of file
Index: tracker2.test
===================================================================
RCS file: tracker2.test
diff -N tracker2.test
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tracker2.test	11 Jan 2009 18:24:05 -0000
@@ -0,0 +1,45 @@
+<?php
+// $Id$
+
+class Tracker2TestCase extends DrupalWebTestCase {
+  function getInfo() {
+    return array(
+      'name' => t('Tracker 2'),
+      'description' => t('tests the tracker2 module'),
+      'group' => t('tracker2'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('tracker2');
+  }
+
+  function testTracker2TrackUser() {
+    $base = 'tracker2';
+    $user_base = 'track2';
+    if (!module_exists('tracker')) {
+      $base = 'tracker';
+      $user_base = 'track';
+    }
+
+    // call tracker2_track_user -> there is not arg(1)
+    $this->drupalGet('user');
+    tracker2_track_user();
+    $this->assertResponse(404, t('take sure that the function returns 404, if there is no arg(1)'));
+
+    // create user
+    $web_user_1 = $this->drupalCreateUser();
+    $web_user_2 = $this->drupalCreateUser();
+    $web_user_1->status = 0;
+    user_save($web_user_1);
+    $admin_user = $this->drupalCreateUser(array('administer users'));
+
+    $this->drupalLogin($web_user_2);
+    $this->drupalGet('user/'. $web_user_1->uid .'/'. $user_base);
+    $this->assertResponse(403, t('take sure that it is pot possible to look at users with status 0 for normal users'));
+
+    $this->drupalLogin($admin_user);
+    $this->drupalGet('user/'. $web_user_1->uid .'/'. $user_base);
+    $this->assertTitle(check_plain($web_user_1->name), t('take sure that the title is set right'));
+  }
+}
