Index: modules/tracker/tracker.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/tracker/tracker.module,v
retrieving revision 1.143.2.2
diff -u -r1.143.2.2 tracker.module
--- modules/tracker/tracker.module	26 Jul 2007 19:16:50 -0000	1.143.2.2
+++ modules/tracker/tracker.module	27 Jul 2007 13:51:30 -0000
@@ -101,7 +101,7 @@
 
       if ($new = comment_num_new($node->nid)) {
         $comments .= '<br />';
-        $comments .= l(format_plural($new, '1 new', '@count new'), "node/$node->nid", NULL, NULL, 'new');
+        $comments .= l(format_plural($new, '1 new', '@count new'), "node/$node->nid", NULL, comment_page_new_query($node->nid), 'new');
       }
     }
 
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.375.2.5
diff -u -r1.375.2.5 forum.module
--- modules/forum/forum.module	31 May 2007 05:58:17 -0000	1.375.2.5
+++ modules/forum/forum.module	27 Jul 2007 13:51:30 -0000
@@ -1001,7 +1001,7 @@
         $rows[] = array(
           array('data' => theme('forum_icon', $topic->new, $topic->num_comments, $topic->comment_mode, $topic->sticky), 'class' => 'icon'),
           array('data' => l($topic->title, "node/$topic->nid"), 'class' => 'topic'),
-          array('data' => $topic->num_comments . ($topic->new_replies ? '<br />'. l(format_plural($topic->new_replies, '1 new', '@count new'), "node/$topic->nid", NULL, NULL, 'new') : ''), 'class' => 'replies'),
+          array('data' => $topic->num_comments . ($topic->new_replies ? '<br />'. l(format_plural($topic->new_replies, '1 new', '@count new'), "node/$topic->nid", NULL, comment_page_new_query($topic->nid), 'new') : ''), 'class' => 'replies'),
           array('data' => _forum_format($topic), 'class' => 'created'),
           array('data' => _forum_format(isset($topic->last_reply) ? $topic->last_reply : NULL), 'class' => 'last-reply')
         );
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.520.2.6
diff -u -r1.520.2.6 comment.module
--- modules/comment/comment.module	26 Jul 2007 19:16:45 -0000	1.520.2.6
+++ modules/comment/comment.module	27 Jul 2007 13:51:25 -0000
@@ -249,19 +249,22 @@
   // Select the $number nodes (visible to the current user) with the most
   // recent comments. This is efficient due to the index on
   // last_comment_timestamp.
-  $result = db_query_range(db_rewrite_sql("SELECT nc.nid FROM {node_comment_statistics} nc WHERE nc.comment_count > 0 ORDER BY nc.last_comment_timestamp DESC", 'nc'), 0, $number);
+  $result = db_query_range(db_rewrite_sql("SELECT nc.nid, nc.comment_count FROM {node_comment_statistics} nc WHERE nc.comment_count > 0 ORDER BY nc.last_comment_timestamp DESC", 'nc'), 0, $number);
 
   $nids = array();
+  $comment_counts = array();
   while ($row = db_fetch_object($result)) {
     $nids[] = $row->nid;
+    $comment_counts[$row->nid] = $row->comment_count;
   }
 
   $comments = array();
   if (!empty($nids)) {
     // From among the comments on the nodes selected in the first query,
     // find the $number most recent comments.
-    $result = db_query_range('SELECT c.nid, c.subject, c.cid, c.timestamp FROM {comments} c INNER JOIN {node} n ON n.nid = c.nid WHERE c.nid IN ('. implode(',', $nids) .') AND n.status = 1 AND c.status = %d ORDER BY c.timestamp DESC', COMMENT_PUBLISHED, 0, $number);
+    $result = db_query_range('SELECT c.nid, c.subject, c.cid, c.timestamp, c.thread FROM {comments} c INNER JOIN {node} n ON n.nid = c.nid WHERE c.nid IN ('. implode(',', $nids) .') AND n.status = 1 AND c.status = %d ORDER BY c.timestamp DESC', COMMENT_PUBLISHED, 0, $number);
     while ($comment = db_fetch_object($result)) {
+      $comment->comment_count = $comment_counts[$comment->nid];
       $comments[] = $comment;
     }
   }
@@ -278,7 +281,7 @@
 function theme_comment_block() {
   $items = array();
   foreach (comment_get_recent() as $comment) {
-    $items[] = l($comment->subject, 'node/'. $comment->nid, NULL, NULL, 'comment-'. $comment->cid) .'<br />'. t('@time ago', array('@time' => format_interval(time() - $comment->timestamp)));
+    $items[] = l($comment->subject, 'node/'. $comment->nid, NULL, comment_page_query($comment), 'comment-'. $comment->cid) .'<br />'. t('@time ago', array('@time' => format_interval(time() - $comment->timestamp)));
   }
   if ($items) {
     return theme('item_list', $items);
@@ -313,6 +316,7 @@
             $links['comment_new_comments'] = array(
               'title' => format_plural($new, '1 new comment', '@count new comments'),
               'href' => "node/$node->nid",
+              'query' => comment_page_new_query($node->nid),
               'attributes' => array('title' => t('Jump to the first new comment of this posting.')),
               'fragment' => 'new'
             );
@@ -1321,13 +1325,22 @@
   return db_fetch_object(db_query('SELECT * FROM {comments} WHERE cid = %d', $cid));
 }
 
-function comment_num_all($nid) {
+/**
+ * get number of comments for specified node
+ */
+function comment_num_all($nid, $include_not_published = FALSE) {
   static $cache;
-
-  if (!isset($cache[$nid])) {
-    $cache[$nid] = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $nid));
+  $key = $include_not_published ? 'published_unpublished' : 'published';
+  
+  if (!isset($cache[$nid][$key])) {
+    if ($include_not_published || user_access('administer comments')) {
+      $cache[$nid] = db_fetch_array(db_query('SELECT COUNT(*) AS published_unpublished, ncs.comment_count AS published FROM {comments} c INNER JOIN {node_comment_statistics} ncs ON ncs.nid = c.nid WHERE c.nid = %d GROUP BY c.nid, ncs.comment_count', $nid));
+    }
+    else {
+      $cache[$nid][$key] = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $nid));
+    }
   }
-  return $cache[$nid];
+  return $cache[$nid][$key];
 }
 
 function comment_num_replies($pid) {
@@ -1348,25 +1361,7 @@
  *   to node)
  */
 function comment_num_new($nid, $timestamp = 0) {
-  global $user;
-
-  if ($user->uid) {
-    // Retrieve the timestamp at which the current user last viewed the
-    // specified node.
-    if (!$timestamp) {
-      $timestamp = node_last_viewed($nid);
-    }
-    $timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT);
-
-    // Use the timestamp to retrieve the number of new comments.
-    $result = db_result(db_query('SELECT COUNT(c.cid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d AND c.status = %d', $nid, $timestamp, COMMENT_PUBLISHED));
-
-    return $result;
-  }
-  else {
-    return 0;
-  }
-
+  return _comment_new_comments($nid, 'num', $timestamp);
 }
 
 function comment_validate($edit) {
@@ -1672,7 +1667,8 @@
 function comment_form_submit($form_id, $form_values) {
   $form_values = _comment_form_submit($form_values);
   if ($cid = comment_save($form_values)) {
-    return array('node/'. $form_values['nid'], NULL, "comment-$cid");
+    $comment = db_fetch_object(db_query('SELECT c.cid, c.nid, c.timestamp, c.thread, ncs.comment_count FROM {comments} c INNER JOIN {node_comment_statistics} ncs ON ncs.nid = c.nid WHERE cid = %d', $cid));
+    return array('node/'. $form_values['nid'], comment_page_query($comment), "comment-$cid");
   }
 }
 
@@ -1939,6 +1935,130 @@
 }
 
 /**
+ * Return an URL query string that points to the page the comment is on.
+ * Used in links to comments (e.g. 'recent comments' block). 
+ *
+ * @param $comment 
+ *   A comment object.
+ *   Required fields: 'nid', 'timestamp', 'thread'
+ *   Optional field: 'comment_count' (to save a db query get this field by
+ *     doing a JOIN of the node_comment_statistics on the comments table)
+ */
+function comment_page_query($comment) {
+  $page = _comment_page($comment);
+  return $page ? "page=$page" : NULL;
+}
+
+/**
+ * Return an URL query string that points to the page the node's first new
+ * comment is on. Used in links to new comments ('# new' links). 
+ *
+ * @param $nid
+ *   A node ID.
+ */
+function comment_page_new_query($nid) {
+  $comments_per_page = _comment_get_display_setting('comments_per_page');
+  $comments_num = comment_num_all($nid, user_access('administer comments'));
+  if ($comments_num <= $comments_per_page) {
+    // one page of comments only
+    return NULL;
+  }
+  else {
+    // get the node's first new comment
+    $cid = _comment_new_comments($nid, 'first');
+    $comment = db_fetch_object(db_query('SELECT nid, timestamp, thread FROM {comments} WHERE cid = %d', $cid));
+    return comment_page_query($comment);
+  }
+}
+
+/**
+ * Return the page a comment is on
+ */
+function _comment_page($comment) {
+  $comments_per_page = _comment_get_display_setting('comments_per_page');
+  if (user_access('administer comments')) {
+    // For users with 'administer comments' permission
+    // we have to count published and unpublished comments.
+    $comments_num = comment_num_all($comment->nid, TRUE);
+  }
+  else {
+    $comments_num = isset($comment->comment_count) ? $comment->comment_count : comment_num_all($comment->nid);
+  }
+  if ($comments_num <= $comments_per_page) {
+    // one page of comments only
+    return 0;
+  }
+  else {
+    // Build the database query that retrieves the comment's position
+    // This follows the same sheme as in comment_render().
+    // See comments there for an explanation.
+    $query = 'SELECT COUNT(*) FROM {comments} WHERE nid = %d';
+    $query_args = array($comment->nid);
+    
+    if (!user_access('administer comments')) {
+      $query .= ' AND status = %d';
+      $query_args[] = COMMENT_PUBLISHED;
+    }
+
+    $mode = _comment_get_display_setting('mode');
+    $order = _comment_get_display_setting('sort');
+    if ($order == COMMENT_ORDER_NEWEST_FIRST) {
+      if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) {
+        $query .= ' AND timestamp > %d';
+        $query_args[] = $comment->timestamp;
+      }
+      else {
+        $query .= " AND thread > '%s'";
+        $query_args[] = $comment->thread;
+      }
+    }
+    else if ($order == COMMENT_ORDER_OLDEST_FIRST) {
+      if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) {
+        $query .= ' AND timestamp < %d';
+        $query_args[] = $comment->timestamp;
+      }
+      else {
+        $query .= " AND SUBSTRING(thread, 1, (LENGTH(thread) - 1)) < '%s'";
+        $query_args[] = substr($comment->thread, 0, -1);
+      }
+    }
+    
+    $count = db_result(db_query($query, $query_args));
+    return floor($count / $comments_per_page);
+  } 
+}
+
+/**
+ * Return the specified node's number of new comments ($key = 'num')
+ * or the first new comment ($key = 'first') for the current user
+ */
+function _comment_new_comments($nid, $key, $timestamp = 0) {
+  global $user;
+  static $cache = array();
+
+  if ($user->uid) {
+    if (!isset($cache[$nid])) {
+      // Retrieve the timestamp at which the current user last viewed the
+      // specified node.
+      if (!$timestamp) {
+        $timestamp = node_last_viewed($nid);
+      }
+      $timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT);
+
+      // Use the timestamp to retrieve the number of new comments
+      // and the first new comment
+      $result = db_query('SELECT COUNT(cid) AS num, MIN(cid) AS first FROM {comments} WHERE nid = %d AND timestamp > %d AND status = %d', $nid, $timestamp, COMMENT_PUBLISHED);
+      $cache[$nid] = db_fetch_array($result);
+    }
+    return $cache[$nid][$key];
+  }
+  else {
+    return NULL;
+  }
+
+}
+
+/**
  * Updates the comment statistics for a given node. This should be called any
  * time a comment is added, deleted, or updated.
  *
