From f6da12ca19f5dff391a025b33889b34e42b692c3 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Wed, 15 Jan 2003 23:01:42 +0000
Subject: [PATCH] Patch by Marco:

- forum: fixed link to new topic
- forum: new topic shows default forum correctly
- forum: first_new is back; the anchor didn't consider multiple pages
- forum: use standard pager, needed some changes/fixes to pager.inc
- forum: some cleanup
- forum: taxonomy hook
- renamed first_new to simply new
- added an optional parameter to pager_query for the count query
- used the optional count param for paging forum topics
- internal change: moving a topic doesn't duplicate the node anymore but just
  changes the forum (term); no change in functionality, and shadow still
  works (suggested by Dries).  This probably also made some queries somewhat
  lighter.
- bug fixed: anonymous users always saw "n (n new)" in the replies column
- updated pager help and moved from _help to phpdoc
---
 includes/pager.inc         |  55 +++++----
 modules/forum.module       | 226 ++++++++++++++++---------------------
 modules/forum/forum.module | 226 ++++++++++++++++---------------------
 update.php                 |  12 +-
 4 files changed, 236 insertions(+), 283 deletions(-)

diff --git a/includes/pager.inc b/includes/pager.inc
index 28d96c743099..626f0ca2e126 100644
--- a/includes/pager.inc
+++ b/includes/pager.inc
@@ -1,14 +1,6 @@
 <?php
 // $Id$
 
-function pager_help() {
-  ?>
-  <h3>Implementation note: making queries pagable</h3>
-  <p>The pager uses <code>LIMIT</code>-based queries to fetch only the records required to render a certain page.  However, it has to learn the total number of records returned by the query to (among others) compute the number of pages (= number of all records / number of records per page). This is done by inserting <code>COUNT(*)</code> in the original query, ie. by rewriting the original query <pre>SELECT nid, type FROM node WHERE status = '1' ORDER BY static DESC, created DESC</pre> to read <pre>SELECT COUNT(*) FROM node WHERE status = '1' ORDER BY static DESC, created DESC</pre>Rewriting the query is accomplished using a regular expression; <code>preg_replace("/SELECT.*FROM/i", "SELECT COUNT(*) FROM", $query)</code>.</p>
-  <p>Unfortunately, the call to <code>preg_replace()</code> does not work as intended for queries that already have a <code>COUNT()</code> clause; the original <code>COUNT()</code> will be removed from the query, possibly making the remainder of the query fail (eg. when the use of <code>HAVING</code> or <code>ORDER</code> depends on the value returned by <code>COUNT()</code>).  In practice, for queries to be <code>pager_query()</code>-able, they shold be reformulated not to use <code>COUNT()</code>.</p>
- <?php
-}
-
 /* ***************************************************
  *            external functions (API)
  * ***************************************************/
@@ -257,23 +249,45 @@ function pager_list($limit, $element = 0, $quantity = 5, $text = "", $attributes
 
 /**
  * Use this function when doing select queries you wish to be able to page.
+ * The pager uses LIMIT-based queries to fetch only the records required
+ * to render a certain page.  However, it has to learn the total number
+ * of records returned by the query to (among others) compute the number
+ * of pages (= number of all records / number of records per page).  This
+ * is done by inserting "COUNT(*)" in the original query, ie. by rewriting
+ * the original query, say "SELECT nid, type FROM node WHERE status = '1'
+ * ORDER BY static DESC, created DESC" to read "SELECT COUNT(*) FROM node
+ * WHERE status = '1' ORDER BY static DESC, created DESC".  Rewriting the
+ * query is accomplished using a regular expression.
  *
- * TODO:
- * - examine a better solution for the "no COUNT in $query" requirement (see (output of) {@link pager_help()})
+ * Unfortunately, the rewrite rule does not always work as intended for
+ * queries that (already) have a "COUNT(*)" or a "GROUP BY" clause, and
+ * possibly for other complex queries.  In those cases, you can optionally
+ * pass a query that will be used to count the records.
  *
- * @param   string  $query    the database query *without* "LIMIT" in it. examples:<pre>
- *   "SELECT * FROM table"
- *   "SELECT field1,field2 FROM table WHERE nid = '1'"</pre>
- * @param   int     $limit    how many rows to return (per page)
- * @param   int     $element  adds support for multiple paged tables on one page
+ * For example, if you want to page this query: "SELECT COUNT(*), TYPE FROM
+ * node GROUP BY TYPE", pager_query() would invoke the wrong query, being:
+ * "SELECT COUNT(*) FROM node GROUP BY TYPE".  So instead, you should pass
+ * "SELECT COUNT(DISTINCT(TYPE)) FROM node" as the optional $count_query
+ * parameter.
  *
- * @return  resource  MySQL query result
+ * @param   string  $query        the SQL query that needs paging
+ * @param   int     $limit        the number of rows per page
+ * @param   int     $element      optional attribute to distringuish between multiple pagers on one page
+ * @param   string  $count_query  an optional SQL query used to count records when rewriting the query would fail
+ *
+ * @return  resource  SQL query result
  */
-function pager_query($query, $limit = 10, $element = 0) {
+
+function pager_query($query, $limit = 10, $element = 0, $count_query = "") {
   global $from, $pager_from_array, $db_type, $pager_total;
 
   // count the total number of records in this query:
-  $pager_total[$element] = db_result(db_query(preg_replace("/SELECT.*FROM/i", "SELECT COUNT(*) FROM", $query)));
+  if ($count_query == "") {
+    $pager_total[$element] = db_result(db_query(preg_replace(array("/SELECT.*FROM/i", "/ORDER BY .*/"), array("SELECT COUNT(*) FROM", ""), $query)));
+  }
+  else {
+    $pager_total[$element] = db_result(db_query($count_query));
+  }
 
   // convert comma separated $from to an array, used by other functions:
   $pager_from_array = explode(",", $from);
@@ -282,16 +296,17 @@ function pager_query($query, $limit = 10, $element = 0) {
 }
 
 function pager_link($from_new, $attributes = array()) {
+  global $q;
 
   foreach($attributes as $key => $value) {
     $query[] = "$key=$value";
   }
 
   if (count($attributes)) {
-    $url = url("", "from=". $from_new[0] ."&". implode("&", $query));
+    $url = url($q, "from=". $from_new[0] ."&". implode("&", $query));
   }
   else {
-    $url = url("", "from=". $from_new[0]);
+    $url = url($q, "from=". $from_new[0]);
   }
 
   return $url;
diff --git a/modules/forum.module b/modules/forum.module
index 605d8048ffb5..92d91f6bf27a 100644
--- a/modules/forum.module
+++ b/modules/forum.module
@@ -59,14 +59,22 @@ function forum_conf_options() {
   return $output;
 }
 
+function forum_taxonomy($op, $type, $object) {
+  if ($type == "vocabulary" && ($op == "insert" || $op == "update")) {
+    if (variable_get("forum_nav_vocabulary", "") == "" && in_array("forum", $object["types"])) {
+      // since none is already set, silently set this vocabulary as the navigation vocabulary
+      variable_set("forum_nav_vocabulary", $object["vid"]);
+    }
+  }
+}
+
 function forum_save($op, $node) {
   if ($op == "approve") {
     return array("status" => 1);
   }
 
   if ($op == "create") {
-    $moderation = array("body" => filter($node->body), "moderate" => 0, "status" => 1);
-    return array_merge($moderation, array("tid", "icon_num", "shadow"));
+    return array("body" => filter($node->body), "moderate" => 0, "status" => 1, "tid", "icon_num", "shadow" => 0);
   }
 
   if ($op == "decline") {
@@ -74,20 +82,12 @@ function forum_save($op, $node) {
   }
 
   if ($op == "update") {
-    // if she changed the term, we could have to leave a shadow
-    $old_terms = explode(",", $node->old_container);
-    foreach ($node->taxonomy as $term) {
-      if ($term && (!in_array($term, $old_terms)) && $node->shadow) {
-        $shadow = $term;
-        break;
-      }
-    }
-    return array("body" => filter($node->body), "tid", "icon_num", "shadow" => $shadow, "old_container");
+    return array("body" => filter($node->body), "tid", "icon_num", "shadow");
   }
 }
 
 function forum_load($node) {
-  $forum = db_fetch_object(db_query("SELECT * FROM forum WHERE nid = '%d' AND shadow = 0", $node->nid));
+  $forum = db_fetch_object(db_query("SELECT * FROM forum WHERE nid = '%d'", $node->nid));
 
   return $forum;
 }
@@ -102,7 +102,7 @@ function forum_block($op = "list", $delta = 0) {
 
       if (empty($cache)) {
         unset($items);
-        $content = node_title_list(db_query("SELECT n.nid, n.title, u.uid, u.name, GREATEST(n.created, MAX(c.timestamp)) AS sort FROM node n, forum f LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.type = 'forum' AND n.nid = f.nid AND f.shadow = 0 AND n.status = 1 GROUP BY n.nid ORDER BY sort DESC LIMIT ". variable_get("forum_block_num", "5")), t("Active forum topics:"));
+        $content = node_title_list(db_query("SELECT n.nid, n.title, u.uid, u.name, GREATEST(n.created, MAX(c.timestamp)) AS sort FROM node n, forum f LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.type = 'forum' AND n.nid = f.nid AND n.status = 1 GROUP BY n.nid ORDER BY sort DESC LIMIT ". variable_get("forum_block_num", "5")), t("Active forum topics:"));
         $content .= "<br />";
 
         unset ($items);
@@ -127,6 +127,7 @@ function forum_block($op = "list", $delta = 0) {
 }
 
 function forum_link($type, $node = 0, $main = 0) {
+  global $user;
 
   if ($type == "page" && user_access("access content")) {
     $links[] = l(t("forum"), "forum");
@@ -135,10 +136,7 @@ function forum_link($type, $node = 0, $main = 0) {
   if (!$main && $type == "node" && $node->type == "forum") {
     // get previous and next topic
 
-    $sql = "SELECT n.nid, title, body, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments FROM node n, term_node t, forum f LEFT JOIN comments c ON c.nid = n.nid WHERE n.nid = t.nid AND n.nid = f.nid AND t.tid = '%d' AND f.shadow = 0 AND n.status = 1 GROUP BY n.nid ORDER BY ". _forum_get_topic_order(isset($user->sortby) ? $user->sortby : variable_get("forum_order",1));
-
-    $terms = array_keys(taxonomy_node_get_terms_by_vocabulary($node->nid, variable_get("forum_nav_vocabulary", "")));
-    $result = db_query($sql, $terms[0]);
+    $result = db_query("SELECT n.nid, title, body, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments FROM node n, forum f LEFT JOIN comments c ON c.nid = n.nid WHERE n.nid = f.nid AND f.tid = '%d' AND n.status = 1 GROUP BY n.nid ORDER BY ". _forum_get_topic_order(isset($user->sortby) ? $user->sortby : variable_get("forum_order",1)), $node->tid);
 
     while ($topic = db_fetch_object($result)) {
       if ($stop == 1) {
@@ -179,16 +177,6 @@ function forum_view($node, $main = 0) {
   }
   $voc = taxonomy_get_vocabulary($term_data->vid);
 
-  /* TODO: find out what this code was ment to do and either use it or not.
-
-  $output .= "<p>". _forum_get_icon($node) ." ". l($voc->name, "forum") ." : ". l($term_data->name, "forum/$term_data->tid");
-
-  $output .= " / <b>$node->title</b><br>".t("%a by %b", array("%a" => format_date($node->created), "%b" => format_name($node)))."</p><p>". check_output($node->body) ."</p>";
-  $output .= "<p>". $theme->links(link_node($node, $main)) ."</p>";
-
-  #$theme->box(t("Discussion forum"), $output);
-  */
-
   if (!$main) {
     $node->title = _forum_get_icon($node) ." ". l($voc->name, "forum") ." : ". l($term_data->name, "forum/$term_data->tid") ." / <b>$node->title</b>";
   }
@@ -196,27 +184,31 @@ function forum_view($node, $main = 0) {
   $theme->node($node, $main);
 }
 
+function forum_validate($node) {
+  // we use the validate hook to remember the old taxonomy terms
+  $node->taxonomy = array_keys(taxonomy_node_get_terms($node->nid));
+  if (!in_array($node->tid[0], $node->taxonomy)) {
+    $node->taxonomy[] = $node->tid[0];
+  }
+  return $node;
+}
+
 function forum_form(&$node, &$help, &$error) {
-  global $tid;
-  if ($node->nid) {
-    if ($node->taxonomy) {
-      $tid = $node->taxonomy;
-    }
-    else {
-      // editing: load category from taxonomy
-      $tid = implode(",", array_keys(taxonomy_node_get_terms($node->nid)));
-    }
-    //$output .= implode("<p>", taxonomy_node_form("forum", $node));
-    $output .= "<input type=\"hidden\" name=\"edit[old_container]\" value=\"".implode(",", array_keys(taxonomy_node_get_terms($node->nid)))."\">";
-    $output .= form_checkbox(t("Leave shadow copy"), "shadow", 1, $node->shadow, t("If you move this topic, you can leave a link in the old forum to the new forum."));
+  if ($node->tid) {
+    // editing
+    $tid = $node->tid;
   }
   else {
-    if ($node->taxonomy) {
-      $tid = $node->taxonomy;
-    }
+    // new topic
+    $tid = arg(3);
   }
 
-  $output .= _taxonomy_term_select("Forum", "taxonomy", $tid, variable_get("forum_nav_vocabulary", ""), "", 0, "", variable_get("forum_containers", array()));
+  $output .= _taxonomy_term_select("Forum", "tid", $tid, variable_get("forum_nav_vocabulary", ""), "", 0, "", variable_get("forum_containers", array()));
+
+  if ($node->nid) {
+    // if editing, give option to leave shadows
+    $output .= form_checkbox(t("Leave shadow copy"), "shadow", 1, $node->shadow, t("If you move this topic, you can leave a link in the old forum to the new forum."));
+  }
 
   if ($icon_path = variable_get("forum_topic_icon_path", "")) {
     if ($node->icon) {
@@ -253,26 +245,12 @@ function forum_form(&$node, &$help, &$error) {
 
 function forum_insert($node) {
   $node->icon = _forum_decode_icon($node);
-  if (!$node->shadow) {
-    db_query("INSERT INTO forum (nid, icon) VALUES ('%d', '%s')", $node->nid, $node->icon);
-  }
-  else {
-    // we created a shadow, a link to a moved topic in a new forum
-    db_query("INSERT INTO forum (nid, icon, shadow) VALUES ('%d', '%s', '%d')", $node->nid, $node->icon, $node->shadow);
-  }
+  db_query("INSERT INTO forum (nid, icon, shadow, tid) VALUES ('%d', '%s', '%d', '%d')", $node->nid, $node->icon, $node->shadow, $node->tid);
 }
 
 function forum_update($node) {
   $node->icon = _forum_decode_icon($node);
-  db_query("UPDATE forum SET icon = '%s' WHERE nid = '%d'", $node->icon, $node->nid);
-  if ($node->shadow) {
-    // insert in old forum a new topic, with link to new forum
-    $node->nid = "";
-    $node->type = "forum";
-    $node->status = 1;
-    $node->taxonomy = array($node->old_container);
-    node_submit($node);
-  }
+  db_query("UPDATE forum SET icon = '%s', shadow = '%d', tid = '%d' WHERE nid = '%d'", $node->icon, $node->shadow, $node->tid[0], $node->nid);
 }
 
 function _forum_decode_icon($node) {
@@ -358,7 +336,6 @@ function forum_get_forums($tid = 0) {
       }
     }
   }
-
   return $forums;
 }
 
@@ -376,17 +353,17 @@ function forum_get_parents($tid) {
 }
 
 function _forum_num_topics($term) {
-  $value = db_fetch_object(db_query("SELECT COUNT(n.nid) AS count FROM node n, term_node r, forum f WHERE r.tid = '%d' AND n.nid = r.nid AND n.nid = f.nid AND n.status = 1 AND n.type = 'forum' AND f.shadow = 0", $term));
+  $value = db_fetch_object(db_query("SELECT COUNT(n.nid) AS count FROM node n, forum f WHERE f.tid = '%d' AND n.nid = f.nid AND n.status = 1 AND n.type = 'forum'", $term));
   return ($value) ? $value->count : 0;
 }
 
 function _forum_num_replies($term) {
-  $value = db_fetch_object(db_query("SELECT COUNT(*) AS count FROM comments c, term_node r, node n WHERE r.tid = '%d' AND n.nid = r.nid AND n.nid = c.nid AND n.status = 1 AND c.status = 0 AND n.type = 'forum'", $term));
+  $value = db_fetch_object(db_query("SELECT COUNT(*) AS count FROM comments c, node n, forum f WHERE f.tid = '%d' AND n.nid = f.nid AND n.nid = c.nid AND n.status = 1 AND c.status = 0 AND n.type = 'forum'", $term));
   return ($value) ? $value->count : 0;
 }
 
 function _forum_topics_read($uid) {
-  $result = db_query("SELECT tid, count(*) AS c FROM history h, term_node r, node n, forum f WHERE f.nid = r.nid AND r.nid = h.nid AND n.nid = h.nid AND f.shadow = 0 AND n.type = 'forum' AND n.status = 1 AND h.uid = '%d' GROUP BY tid", $uid);
+  $result = db_query("SELECT tid, count(*) AS c FROM history h, node n, forum f WHERE f.nid = n.nid AND n.nid = h.nid AND n.type = 'forum' AND n.status = 1 AND h.uid = '%d' GROUP BY tid", $uid);
 
   while ($obj = db_fetch_object($result)) {
     $topics_read[$obj->tid] = $obj->c;
@@ -396,16 +373,16 @@ function _forum_topics_read($uid) {
 }
 
 function _forum_last_post($term) {
-  $topic = db_fetch_object(db_query("SELECT n.nid, n.created AS timestamp, u.name AS name, u.uid AS uid FROM node n, term_node r LEFT JOIN users u ON n.uid = u.uid WHERE r.tid = '%d' AND n.nid = r.nid AND n.type = 'forum' AND n.status = 1 ORDER BY timestamp DESC LIMIT 1", $term));
+  $topic = db_fetch_object(db_query("SELECT n.nid, n.created AS timestamp, u.name AS name, u.uid AS uid FROM node n, forum f LEFT JOIN users u ON n.uid = u.uid WHERE f.tid = '%d' AND n.nid = f.nid AND n.type = 'forum' AND n.status = 1 ORDER BY timestamp DESC LIMIT 1", $term));
 
-  $reply = db_fetch_object(db_query("SELECT n.nid, c.timestamp, u.name AS name, u.uid AS uid FROM term_node r, node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON c.uid = u.uid WHERE r.tid = '%d' AND n.nid = r.nid AND n.type = 'forum' AND n.status = 1 AND c.status = 0 ORDER BY c.timestamp DESC LIMIT 1", $term));
+  $reply = db_fetch_object(db_query("SELECT n.nid, c.timestamp, u.name AS name, u.uid AS uid FROM forum f, node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON c.uid = u.uid WHERE f.tid = '%d' AND n.nid = f.nid AND n.type = 'forum' AND n.status = 1 AND c.status = 0 ORDER BY c.timestamp DESC LIMIT 1", $term));
 
   $value = ($topic->timestamp > $reply->timestamp) ? $topic : $reply;
 
   return $value;
 }
 
-function forum_get_topics($tid, $sortby, $forum_per_page, $offset) {
+function forum_get_topics($tid, $sortby, $forum_per_page) {
   global $user;
 
   $term = taxonomy_get_term($tid);
@@ -413,63 +390,61 @@ function forum_get_topics($tid, $sortby, $forum_per_page, $offset) {
 
   $sql_sortby = _forum_get_topic_order($sortby);
 
-  $sql = "SELECT n.nid, title, users.name AS name, users.uid AS uid, n.created AS timestamp, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments, icon, n.comment AS comment_mode, shadow FROM node n, term_node r LEFT JOIN users ON n.uid = users.uid LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN forum f ON n.nid = f.nid WHERE n.nid = r.nid AND r.tid = '%d' AND n.status = 1 AND n.type = 'forum' GROUP BY n.nid ORDER BY $sql_sortby";
+  // show topics with the correct tid, or in the forum but with shadow = 1
+  $sql = "SELECT n.nid, title, u.name AS name, u.uid AS uid, n.created AS timestamp, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments, icon, n.comment AS comment_mode, f.tid FROM node n, term_node r LEFT JOIN users u ON n.uid = u.uid LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN forum f ON n.nid = f.nid WHERE n.nid = r.nid AND ( (r.tid = '".check_query($tid)."' AND f.shadow = 1) OR f.tid = '".check_query($tid)."' ) AND n.status = 1 AND n.type = 'forum' GROUP BY n.nid ORDER BY $sql_sortby";
 
-  $result = db_query($sql, $tid);
+  $sql_count = "SELECT COUNT(DISTINCT(n.nid)) FROM node n, term_node r LEFT JOIN forum f ON n.nid = f.nid WHERE n.nid = r.nid AND ( (r.tid = '".check_query($tid)."' AND f.shadow = 1) OR f.tid = '".check_query($tid)."' ) AND n.status = 1 AND n.type = 'forum'";
+
+  $result = pager_query($sql, $forum_per_page, 0, $sql_count);
   $topic_num = db_num_rows($result);
 
   $n = 0;
   while ($topic = db_fetch_object($result)) {
-    if ($n < $offset) {
-      $n++;
-      continue;
-    }
-
-    $history = _forum_user_last_visit($topic->nid);
-    // folder is new if topic is new or there are new comments since last visit
-    if ($topic->shadow > 0) {
-      $topic->new = 0;
-    }
-    else {
-      if (!$history && $user->uid) {
-        $topic->new_replies = 0;
-        $topic->new = 1;
+    if ($user->uid) {
+      $history = _forum_user_last_visit($topic->nid);
+      // folder is new if topic is new or there are new comments since last visit
+      if ($topic->shadow > 0) {
+        $topic->new = 0;
       }
       else {
-        $comments = db_result(db_query("SELECT COUNT(c.nid) FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = '$topic->nid' AND n.status = 1 AND c.status = 0 AND timestamp > '$history' GROUP BY n.nid"));
-
-        $topic->new_replies = $comments ? $comments : 0;
-        if ($topic->new_replies) {
+        if (!$history && $user->uid) {
+          $topic->new_replies = 0;
           $topic->new = 1;
         }
         else {
-          $topic->new = 0;
+          $comments = db_result(db_query("SELECT COUNT(c.nid) FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = '$topic->nid' AND n.status = 1 AND c.status = 0 AND timestamp > '$history' GROUP BY n.nid"));
+
+          $topic->new_replies = $comments ? $comments : 0;
+          if ($topic->new_replies) {
+            $topic->new = 1;
+          }
+          else {
+            $topic->new = 0;
+          }
         }
       }
-    }
+     }
+     else {
+      // you're not logged in eh?
+      $topic->new_replies = 0;
+      $topic->new = 0;
+     }
 
     $topic->last_reply = _forum_last_reply($topic->nid);
     $topics[] = $topic;
-
-    $n++;
-    if ($n == ($forum_per_page + $offset)) {
-      break;
-    }
   }
 
-  return array($topics, $topic_num);
+  return $topics;
 }
 
-function _forum_first_new($tid) {
+function _forum_new($tid) {
   global $user;
-  $result = db_query("SELECT r.nid FROM node n, history h, term_node r WHERE n.type = 'forum' AND n.status = 1 AND h.nid = n.nid AND r.nid = h.nid AND r.tid = '%d' AND h.uid = '%d'   ", $tid, $user->uid);
+  $result = db_query("SELECT n.nid FROM node n, history h, forum f WHERE n.type = 'forum' AND n.status = 1 AND h.nid = n.nid AND f.nid = h.nid AND f.tid = '%d' AND h.uid = '%d'", $tid, $user->uid);
   while ($r = db_fetch_object($result)) {
     $read[] = $r->nid;
   }
 
-  if ($read) {
-    $nid = db_result(db_query("SELECT r.nid AS c FROM node n LEFT JOIN term_node r ON r.nid = n.nid WHERE n.type = 'forum' AND n.status = 1 AND r.tid = '%d' AND NOT (r.nid IN (".implode(",", $read).")) ORDER BY created LIMIT 1", $tid));
-  }
+  $nid = db_result(db_query("SELECT n.nid FROM node n, forum f WHERE n.type = 'forum' AND f.nid = n.nid AND n.status = 1 AND f.tid = '%d' ".($read ? "AND NOT (n.nid IN (".implode(",", $read).")) " : "") ."ORDER BY created LIMIT 1", $tid));
 
   return $nid ? $nid : 0;
 }
@@ -479,7 +454,7 @@ function _forum_message_taxonomy() {
 }
 
 function forum_page() {
-  global $theme, $sortby, $forum_per_page, $offset, $op, $user;
+  global $theme, $sortby, $forum_per_page, $from, $op, $user;
 
   if (user_access("access content")) {
     if (module_exist("taxonomy")) {
@@ -489,6 +464,12 @@ function forum_page() {
         $user = user_save($user, array("sortby" => $sortby, "forum_per_page" => $forum_per_page));
       }
 
+      if (arg(2) == "new") {
+        if ($nid = _forum_new($tid)) {
+          drupal_goto(url("node/view/$nid"));
+        }
+      }
+
       if (empty($sortby)) {
         $sortby = isset($user->sortby) ? $user->sortby : variable_get("forum_order",1);
       }
@@ -497,17 +478,15 @@ function forum_page() {
         $forum_per_page = isset($user->forum_per_page) ? $user->forum_per_page : variable_get("forum_per_page", 25);
       }
 
-      if (empty($offset)) {
-        $offset = 0;
-      }
+      $offset = ($from / $forum_per_page) + 1;
 
       $forums = forum_get_forums($tid);
       $parents = forum_get_parents($tid);
       if ($tid && !in_array($tid, variable_get("forum_containers", array()))) {
-        list($topics, $topic_num) = forum_get_topics($tid, $sortby, $forum_per_page, $offset);
+        $topics = forum_get_topics($tid, $sortby, $forum_per_page);
       }
 
-      theme_invoke("forum_render", $forums, $topics, $topic_num, $parents, $tid, $sortby, $forum_per_page, $offset);
+      theme_invoke("forum_render", $forums, $topics, $parents, $tid, $sortby, $forum_per_page, $offset);
     }
     else {
       $theme->header();
@@ -526,13 +505,13 @@ function forum_page() {
 ** Render functions.
 */
 
-function forum_render($forums, $topics, $topic_num, $parents, $tid, $sortby, $forum_per_page, $offset) {
+function forum_render($forums, $topics, $parents, $tid, $sortby, $forum_per_page, $offset) {
   // forum list, topics list, topic browser and "add new topic" link
   global $theme;
 
   $output .= theme_invoke("forum_forum_list", $forums, $parents, $tid);
   if ($tid && !in_array($tid, variable_get("forum_containers", array()))) {
-    $output .= theme_invoke("forum_topic_list", $topics, $topic_num, $sortby, $forum_per_page, $offset);
+    $output .= theme_invoke("forum_topic_list", $tid, $topics, $sortby, $forum_per_page, $offset);
   }
 
   $theme->header();
@@ -578,7 +557,7 @@ function forum_forum_list($forums, $parents, $tid) {
           $links[] = l(t("the most recent topic"), "node/view/". $forum->last_post->nid);
         }
         if ($new_topics) {
-          $links[] = l(t("the first new topic"), "forum/$forum->tid#new");
+          $links[] = l(t("the first new topic"), "forum/$forum->tid/new");
         }
 
         if ($links) {
@@ -624,10 +603,8 @@ function forum_topic_browser() {
   return form(form_item(t("Topic viewing options"), $output, t("Select your preferred way to display the topics and click 'Update settings'.")));
 }
 
-function forum_topic_list($topics, $num_topics, $sortby, $forum_per_page, $offset) {
-  global $theme, $id, $status, $tid, $user;
-
-  $output .= "<div style=\"margin-left: 20px; margin-top: 5px; margin-bottom: 10px;\">" .t("%a topics, %b topics per page, page %c of %d", array("%a" => $num_topics, "%b" => $forum_per_page, "%c" => ceil(($offset + 1)/$forum_per_page), "%d" => ceil($num_topics/$forum_per_page))) ."</div>";
+function forum_topic_list($tid, $topics, $sortby, $forum_per_page, $offset) {
+  global $theme, $id, $status, $user, $pager_total;
 
   if ($topics) {
     $output .= "<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\" width=\"100%\">\n";
@@ -635,13 +612,13 @@ function forum_topic_list($topics, $num_topics, $sortby, $forum_per_page, $offse
 
     foreach ($topics as $topic) {
       // folder is new if topic is new or there are new comments since last visit
-      if ($topic->shadow) {
+      if ($topic->tid != $tid) {
         $output .= "
           <tr>
             <td>"._forum_get_folder_icon($topic->new, $topic->num_comments, $topic->comment_mode)."</td>
             <td>"._forum_get_icon($topic)."</td>
             <td valign=\"top\">$topic->title</td>
-            <td align=\"center\" valign=\"top\" colspan=\"3\">". l(t("This topic has been moved"), "forum/$topic->shadow")."</td>
+            <td align=\"center\" valign=\"top\" colspan=\"3\">". l(t("This topic has been moved"), "forum/$topic->tid")."</td>
           </tr>";
       }
       else {
@@ -660,28 +637,15 @@ function forum_topic_list($topics, $num_topics, $sortby, $forum_per_page, $offse
     $output .= "</table></blockquote>\n";
   }
   $output .= "<hr />";
-  $output .= "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr>";
 
-  if ($offset > 0) {
-    $output .= "<td width=\"33%\"><div align=\"left\" style=\"font-style: bold;\">". l(t("previous topics"), array("mod" => "forum", "tid" => $tid, "offset" => ($offset-$forum_per_page))) ."</div></td>";
-  }
-  else {
-    $output .= "<td width=\"33%\">&nbsp;</td>";
-  }
+  $output .= "<div align=\"center\">" .t("%a topics, %b topics per page, page %c of %d", array("%a" => $pager_total[0], "%b" => $forum_per_page, "%c" => $offset, "%d" => ceil($pager_total[0]/$forum_per_page))) ."</div>";
 
-  if (user_access("create forum topics")) {
-    $output .= "<td width=\"33%\"><div align=\"center\" style=\"font-style: bold;\">". l(t("create new forum topic"), array("mod" => "node", "op" => "add", "type" => "forum", "tid" => $tid)) ."</div></td>";
-  }
+  $output .= (($pager = pager_display(NULL, $forum_per_page, 0, "default")) ? "$pager" : "");
 
-  if (count($topics) >= $forum_per_page) {
-    $output .= "<td width=\"33%\"><div align=\"right\" style=\"font-style: bold;\">". l(t("next topics"), array("mod" => "forum", "tid" => $tid, "offset" => ($offset+$forum_per_page))) ."</div></td>";
-  }
-  else {
-    $output .= "<td width=\"33%\">&nbsp;</td>";
+  if (user_access("create forum topics")) {
+    $output .= "<div align=\"center\" style=\"font-style: bold;\">". l(t("create new forum topic"), "node/add/forum/$tid") ."</div>";
   }
 
-  $output .= "</tr></table>";
-
   return $output;
 }
 
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index 605d8048ffb5..92d91f6bf27a 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -59,14 +59,22 @@ function forum_conf_options() {
   return $output;
 }
 
+function forum_taxonomy($op, $type, $object) {
+  if ($type == "vocabulary" && ($op == "insert" || $op == "update")) {
+    if (variable_get("forum_nav_vocabulary", "") == "" && in_array("forum", $object["types"])) {
+      // since none is already set, silently set this vocabulary as the navigation vocabulary
+      variable_set("forum_nav_vocabulary", $object["vid"]);
+    }
+  }
+}
+
 function forum_save($op, $node) {
   if ($op == "approve") {
     return array("status" => 1);
   }
 
   if ($op == "create") {
-    $moderation = array("body" => filter($node->body), "moderate" => 0, "status" => 1);
-    return array_merge($moderation, array("tid", "icon_num", "shadow"));
+    return array("body" => filter($node->body), "moderate" => 0, "status" => 1, "tid", "icon_num", "shadow" => 0);
   }
 
   if ($op == "decline") {
@@ -74,20 +82,12 @@ function forum_save($op, $node) {
   }
 
   if ($op == "update") {
-    // if she changed the term, we could have to leave a shadow
-    $old_terms = explode(",", $node->old_container);
-    foreach ($node->taxonomy as $term) {
-      if ($term && (!in_array($term, $old_terms)) && $node->shadow) {
-        $shadow = $term;
-        break;
-      }
-    }
-    return array("body" => filter($node->body), "tid", "icon_num", "shadow" => $shadow, "old_container");
+    return array("body" => filter($node->body), "tid", "icon_num", "shadow");
   }
 }
 
 function forum_load($node) {
-  $forum = db_fetch_object(db_query("SELECT * FROM forum WHERE nid = '%d' AND shadow = 0", $node->nid));
+  $forum = db_fetch_object(db_query("SELECT * FROM forum WHERE nid = '%d'", $node->nid));
 
   return $forum;
 }
@@ -102,7 +102,7 @@ function forum_block($op = "list", $delta = 0) {
 
       if (empty($cache)) {
         unset($items);
-        $content = node_title_list(db_query("SELECT n.nid, n.title, u.uid, u.name, GREATEST(n.created, MAX(c.timestamp)) AS sort FROM node n, forum f LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.type = 'forum' AND n.nid = f.nid AND f.shadow = 0 AND n.status = 1 GROUP BY n.nid ORDER BY sort DESC LIMIT ". variable_get("forum_block_num", "5")), t("Active forum topics:"));
+        $content = node_title_list(db_query("SELECT n.nid, n.title, u.uid, u.name, GREATEST(n.created, MAX(c.timestamp)) AS sort FROM node n, forum f LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.type = 'forum' AND n.nid = f.nid AND n.status = 1 GROUP BY n.nid ORDER BY sort DESC LIMIT ". variable_get("forum_block_num", "5")), t("Active forum topics:"));
         $content .= "<br />";
 
         unset ($items);
@@ -127,6 +127,7 @@ function forum_block($op = "list", $delta = 0) {
 }
 
 function forum_link($type, $node = 0, $main = 0) {
+  global $user;
 
   if ($type == "page" && user_access("access content")) {
     $links[] = l(t("forum"), "forum");
@@ -135,10 +136,7 @@ function forum_link($type, $node = 0, $main = 0) {
   if (!$main && $type == "node" && $node->type == "forum") {
     // get previous and next topic
 
-    $sql = "SELECT n.nid, title, body, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments FROM node n, term_node t, forum f LEFT JOIN comments c ON c.nid = n.nid WHERE n.nid = t.nid AND n.nid = f.nid AND t.tid = '%d' AND f.shadow = 0 AND n.status = 1 GROUP BY n.nid ORDER BY ". _forum_get_topic_order(isset($user->sortby) ? $user->sortby : variable_get("forum_order",1));
-
-    $terms = array_keys(taxonomy_node_get_terms_by_vocabulary($node->nid, variable_get("forum_nav_vocabulary", "")));
-    $result = db_query($sql, $terms[0]);
+    $result = db_query("SELECT n.nid, title, body, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments FROM node n, forum f LEFT JOIN comments c ON c.nid = n.nid WHERE n.nid = f.nid AND f.tid = '%d' AND n.status = 1 GROUP BY n.nid ORDER BY ". _forum_get_topic_order(isset($user->sortby) ? $user->sortby : variable_get("forum_order",1)), $node->tid);
 
     while ($topic = db_fetch_object($result)) {
       if ($stop == 1) {
@@ -179,16 +177,6 @@ function forum_view($node, $main = 0) {
   }
   $voc = taxonomy_get_vocabulary($term_data->vid);
 
-  /* TODO: find out what this code was ment to do and either use it or not.
-
-  $output .= "<p>". _forum_get_icon($node) ." ". l($voc->name, "forum") ." : ". l($term_data->name, "forum/$term_data->tid");
-
-  $output .= " / <b>$node->title</b><br>".t("%a by %b", array("%a" => format_date($node->created), "%b" => format_name($node)))."</p><p>". check_output($node->body) ."</p>";
-  $output .= "<p>". $theme->links(link_node($node, $main)) ."</p>";
-
-  #$theme->box(t("Discussion forum"), $output);
-  */
-
   if (!$main) {
     $node->title = _forum_get_icon($node) ." ". l($voc->name, "forum") ." : ". l($term_data->name, "forum/$term_data->tid") ." / <b>$node->title</b>";
   }
@@ -196,27 +184,31 @@ function forum_view($node, $main = 0) {
   $theme->node($node, $main);
 }
 
+function forum_validate($node) {
+  // we use the validate hook to remember the old taxonomy terms
+  $node->taxonomy = array_keys(taxonomy_node_get_terms($node->nid));
+  if (!in_array($node->tid[0], $node->taxonomy)) {
+    $node->taxonomy[] = $node->tid[0];
+  }
+  return $node;
+}
+
 function forum_form(&$node, &$help, &$error) {
-  global $tid;
-  if ($node->nid) {
-    if ($node->taxonomy) {
-      $tid = $node->taxonomy;
-    }
-    else {
-      // editing: load category from taxonomy
-      $tid = implode(",", array_keys(taxonomy_node_get_terms($node->nid)));
-    }
-    //$output .= implode("<p>", taxonomy_node_form("forum", $node));
-    $output .= "<input type=\"hidden\" name=\"edit[old_container]\" value=\"".implode(",", array_keys(taxonomy_node_get_terms($node->nid)))."\">";
-    $output .= form_checkbox(t("Leave shadow copy"), "shadow", 1, $node->shadow, t("If you move this topic, you can leave a link in the old forum to the new forum."));
+  if ($node->tid) {
+    // editing
+    $tid = $node->tid;
   }
   else {
-    if ($node->taxonomy) {
-      $tid = $node->taxonomy;
-    }
+    // new topic
+    $tid = arg(3);
   }
 
-  $output .= _taxonomy_term_select("Forum", "taxonomy", $tid, variable_get("forum_nav_vocabulary", ""), "", 0, "", variable_get("forum_containers", array()));
+  $output .= _taxonomy_term_select("Forum", "tid", $tid, variable_get("forum_nav_vocabulary", ""), "", 0, "", variable_get("forum_containers", array()));
+
+  if ($node->nid) {
+    // if editing, give option to leave shadows
+    $output .= form_checkbox(t("Leave shadow copy"), "shadow", 1, $node->shadow, t("If you move this topic, you can leave a link in the old forum to the new forum."));
+  }
 
   if ($icon_path = variable_get("forum_topic_icon_path", "")) {
     if ($node->icon) {
@@ -253,26 +245,12 @@ function forum_form(&$node, &$help, &$error) {
 
 function forum_insert($node) {
   $node->icon = _forum_decode_icon($node);
-  if (!$node->shadow) {
-    db_query("INSERT INTO forum (nid, icon) VALUES ('%d', '%s')", $node->nid, $node->icon);
-  }
-  else {
-    // we created a shadow, a link to a moved topic in a new forum
-    db_query("INSERT INTO forum (nid, icon, shadow) VALUES ('%d', '%s', '%d')", $node->nid, $node->icon, $node->shadow);
-  }
+  db_query("INSERT INTO forum (nid, icon, shadow, tid) VALUES ('%d', '%s', '%d', '%d')", $node->nid, $node->icon, $node->shadow, $node->tid);
 }
 
 function forum_update($node) {
   $node->icon = _forum_decode_icon($node);
-  db_query("UPDATE forum SET icon = '%s' WHERE nid = '%d'", $node->icon, $node->nid);
-  if ($node->shadow) {
-    // insert in old forum a new topic, with link to new forum
-    $node->nid = "";
-    $node->type = "forum";
-    $node->status = 1;
-    $node->taxonomy = array($node->old_container);
-    node_submit($node);
-  }
+  db_query("UPDATE forum SET icon = '%s', shadow = '%d', tid = '%d' WHERE nid = '%d'", $node->icon, $node->shadow, $node->tid[0], $node->nid);
 }
 
 function _forum_decode_icon($node) {
@@ -358,7 +336,6 @@ function forum_get_forums($tid = 0) {
       }
     }
   }
-
   return $forums;
 }
 
@@ -376,17 +353,17 @@ function forum_get_parents($tid) {
 }
 
 function _forum_num_topics($term) {
-  $value = db_fetch_object(db_query("SELECT COUNT(n.nid) AS count FROM node n, term_node r, forum f WHERE r.tid = '%d' AND n.nid = r.nid AND n.nid = f.nid AND n.status = 1 AND n.type = 'forum' AND f.shadow = 0", $term));
+  $value = db_fetch_object(db_query("SELECT COUNT(n.nid) AS count FROM node n, forum f WHERE f.tid = '%d' AND n.nid = f.nid AND n.status = 1 AND n.type = 'forum'", $term));
   return ($value) ? $value->count : 0;
 }
 
 function _forum_num_replies($term) {
-  $value = db_fetch_object(db_query("SELECT COUNT(*) AS count FROM comments c, term_node r, node n WHERE r.tid = '%d' AND n.nid = r.nid AND n.nid = c.nid AND n.status = 1 AND c.status = 0 AND n.type = 'forum'", $term));
+  $value = db_fetch_object(db_query("SELECT COUNT(*) AS count FROM comments c, node n, forum f WHERE f.tid = '%d' AND n.nid = f.nid AND n.nid = c.nid AND n.status = 1 AND c.status = 0 AND n.type = 'forum'", $term));
   return ($value) ? $value->count : 0;
 }
 
 function _forum_topics_read($uid) {
-  $result = db_query("SELECT tid, count(*) AS c FROM history h, term_node r, node n, forum f WHERE f.nid = r.nid AND r.nid = h.nid AND n.nid = h.nid AND f.shadow = 0 AND n.type = 'forum' AND n.status = 1 AND h.uid = '%d' GROUP BY tid", $uid);
+  $result = db_query("SELECT tid, count(*) AS c FROM history h, node n, forum f WHERE f.nid = n.nid AND n.nid = h.nid AND n.type = 'forum' AND n.status = 1 AND h.uid = '%d' GROUP BY tid", $uid);
 
   while ($obj = db_fetch_object($result)) {
     $topics_read[$obj->tid] = $obj->c;
@@ -396,16 +373,16 @@ function _forum_topics_read($uid) {
 }
 
 function _forum_last_post($term) {
-  $topic = db_fetch_object(db_query("SELECT n.nid, n.created AS timestamp, u.name AS name, u.uid AS uid FROM node n, term_node r LEFT JOIN users u ON n.uid = u.uid WHERE r.tid = '%d' AND n.nid = r.nid AND n.type = 'forum' AND n.status = 1 ORDER BY timestamp DESC LIMIT 1", $term));
+  $topic = db_fetch_object(db_query("SELECT n.nid, n.created AS timestamp, u.name AS name, u.uid AS uid FROM node n, forum f LEFT JOIN users u ON n.uid = u.uid WHERE f.tid = '%d' AND n.nid = f.nid AND n.type = 'forum' AND n.status = 1 ORDER BY timestamp DESC LIMIT 1", $term));
 
-  $reply = db_fetch_object(db_query("SELECT n.nid, c.timestamp, u.name AS name, u.uid AS uid FROM term_node r, node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON c.uid = u.uid WHERE r.tid = '%d' AND n.nid = r.nid AND n.type = 'forum' AND n.status = 1 AND c.status = 0 ORDER BY c.timestamp DESC LIMIT 1", $term));
+  $reply = db_fetch_object(db_query("SELECT n.nid, c.timestamp, u.name AS name, u.uid AS uid FROM forum f, node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON c.uid = u.uid WHERE f.tid = '%d' AND n.nid = f.nid AND n.type = 'forum' AND n.status = 1 AND c.status = 0 ORDER BY c.timestamp DESC LIMIT 1", $term));
 
   $value = ($topic->timestamp > $reply->timestamp) ? $topic : $reply;
 
   return $value;
 }
 
-function forum_get_topics($tid, $sortby, $forum_per_page, $offset) {
+function forum_get_topics($tid, $sortby, $forum_per_page) {
   global $user;
 
   $term = taxonomy_get_term($tid);
@@ -413,63 +390,61 @@ function forum_get_topics($tid, $sortby, $forum_per_page, $offset) {
 
   $sql_sortby = _forum_get_topic_order($sortby);
 
-  $sql = "SELECT n.nid, title, users.name AS name, users.uid AS uid, n.created AS timestamp, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments, icon, n.comment AS comment_mode, shadow FROM node n, term_node r LEFT JOIN users ON n.uid = users.uid LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN forum f ON n.nid = f.nid WHERE n.nid = r.nid AND r.tid = '%d' AND n.status = 1 AND n.type = 'forum' GROUP BY n.nid ORDER BY $sql_sortby";
+  // show topics with the correct tid, or in the forum but with shadow = 1
+  $sql = "SELECT n.nid, title, u.name AS name, u.uid AS uid, n.created AS timestamp, GREATEST(n.created, MAX(c.timestamp)) AS date_sort, COUNT(c.nid) AS num_comments, icon, n.comment AS comment_mode, f.tid FROM node n, term_node r LEFT JOIN users u ON n.uid = u.uid LEFT JOIN comments c ON c.nid = n.nid LEFT JOIN forum f ON n.nid = f.nid WHERE n.nid = r.nid AND ( (r.tid = '".check_query($tid)."' AND f.shadow = 1) OR f.tid = '".check_query($tid)."' ) AND n.status = 1 AND n.type = 'forum' GROUP BY n.nid ORDER BY $sql_sortby";
 
-  $result = db_query($sql, $tid);
+  $sql_count = "SELECT COUNT(DISTINCT(n.nid)) FROM node n, term_node r LEFT JOIN forum f ON n.nid = f.nid WHERE n.nid = r.nid AND ( (r.tid = '".check_query($tid)."' AND f.shadow = 1) OR f.tid = '".check_query($tid)."' ) AND n.status = 1 AND n.type = 'forum'";
+
+  $result = pager_query($sql, $forum_per_page, 0, $sql_count);
   $topic_num = db_num_rows($result);
 
   $n = 0;
   while ($topic = db_fetch_object($result)) {
-    if ($n < $offset) {
-      $n++;
-      continue;
-    }
-
-    $history = _forum_user_last_visit($topic->nid);
-    // folder is new if topic is new or there are new comments since last visit
-    if ($topic->shadow > 0) {
-      $topic->new = 0;
-    }
-    else {
-      if (!$history && $user->uid) {
-        $topic->new_replies = 0;
-        $topic->new = 1;
+    if ($user->uid) {
+      $history = _forum_user_last_visit($topic->nid);
+      // folder is new if topic is new or there are new comments since last visit
+      if ($topic->shadow > 0) {
+        $topic->new = 0;
       }
       else {
-        $comments = db_result(db_query("SELECT COUNT(c.nid) FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = '$topic->nid' AND n.status = 1 AND c.status = 0 AND timestamp > '$history' GROUP BY n.nid"));
-
-        $topic->new_replies = $comments ? $comments : 0;
-        if ($topic->new_replies) {
+        if (!$history && $user->uid) {
+          $topic->new_replies = 0;
           $topic->new = 1;
         }
         else {
-          $topic->new = 0;
+          $comments = db_result(db_query("SELECT COUNT(c.nid) FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = '$topic->nid' AND n.status = 1 AND c.status = 0 AND timestamp > '$history' GROUP BY n.nid"));
+
+          $topic->new_replies = $comments ? $comments : 0;
+          if ($topic->new_replies) {
+            $topic->new = 1;
+          }
+          else {
+            $topic->new = 0;
+          }
         }
       }
-    }
+     }
+     else {
+      // you're not logged in eh?
+      $topic->new_replies = 0;
+      $topic->new = 0;
+     }
 
     $topic->last_reply = _forum_last_reply($topic->nid);
     $topics[] = $topic;
-
-    $n++;
-    if ($n == ($forum_per_page + $offset)) {
-      break;
-    }
   }
 
-  return array($topics, $topic_num);
+  return $topics;
 }
 
-function _forum_first_new($tid) {
+function _forum_new($tid) {
   global $user;
-  $result = db_query("SELECT r.nid FROM node n, history h, term_node r WHERE n.type = 'forum' AND n.status = 1 AND h.nid = n.nid AND r.nid = h.nid AND r.tid = '%d' AND h.uid = '%d'   ", $tid, $user->uid);
+  $result = db_query("SELECT n.nid FROM node n, history h, forum f WHERE n.type = 'forum' AND n.status = 1 AND h.nid = n.nid AND f.nid = h.nid AND f.tid = '%d' AND h.uid = '%d'", $tid, $user->uid);
   while ($r = db_fetch_object($result)) {
     $read[] = $r->nid;
   }
 
-  if ($read) {
-    $nid = db_result(db_query("SELECT r.nid AS c FROM node n LEFT JOIN term_node r ON r.nid = n.nid WHERE n.type = 'forum' AND n.status = 1 AND r.tid = '%d' AND NOT (r.nid IN (".implode(",", $read).")) ORDER BY created LIMIT 1", $tid));
-  }
+  $nid = db_result(db_query("SELECT n.nid FROM node n, forum f WHERE n.type = 'forum' AND f.nid = n.nid AND n.status = 1 AND f.tid = '%d' ".($read ? "AND NOT (n.nid IN (".implode(",", $read).")) " : "") ."ORDER BY created LIMIT 1", $tid));
 
   return $nid ? $nid : 0;
 }
@@ -479,7 +454,7 @@ function _forum_message_taxonomy() {
 }
 
 function forum_page() {
-  global $theme, $sortby, $forum_per_page, $offset, $op, $user;
+  global $theme, $sortby, $forum_per_page, $from, $op, $user;
 
   if (user_access("access content")) {
     if (module_exist("taxonomy")) {
@@ -489,6 +464,12 @@ function forum_page() {
         $user = user_save($user, array("sortby" => $sortby, "forum_per_page" => $forum_per_page));
       }
 
+      if (arg(2) == "new") {
+        if ($nid = _forum_new($tid)) {
+          drupal_goto(url("node/view/$nid"));
+        }
+      }
+
       if (empty($sortby)) {
         $sortby = isset($user->sortby) ? $user->sortby : variable_get("forum_order",1);
       }
@@ -497,17 +478,15 @@ function forum_page() {
         $forum_per_page = isset($user->forum_per_page) ? $user->forum_per_page : variable_get("forum_per_page", 25);
       }
 
-      if (empty($offset)) {
-        $offset = 0;
-      }
+      $offset = ($from / $forum_per_page) + 1;
 
       $forums = forum_get_forums($tid);
       $parents = forum_get_parents($tid);
       if ($tid && !in_array($tid, variable_get("forum_containers", array()))) {
-        list($topics, $topic_num) = forum_get_topics($tid, $sortby, $forum_per_page, $offset);
+        $topics = forum_get_topics($tid, $sortby, $forum_per_page);
       }
 
-      theme_invoke("forum_render", $forums, $topics, $topic_num, $parents, $tid, $sortby, $forum_per_page, $offset);
+      theme_invoke("forum_render", $forums, $topics, $parents, $tid, $sortby, $forum_per_page, $offset);
     }
     else {
       $theme->header();
@@ -526,13 +505,13 @@ function forum_page() {
 ** Render functions.
 */
 
-function forum_render($forums, $topics, $topic_num, $parents, $tid, $sortby, $forum_per_page, $offset) {
+function forum_render($forums, $topics, $parents, $tid, $sortby, $forum_per_page, $offset) {
   // forum list, topics list, topic browser and "add new topic" link
   global $theme;
 
   $output .= theme_invoke("forum_forum_list", $forums, $parents, $tid);
   if ($tid && !in_array($tid, variable_get("forum_containers", array()))) {
-    $output .= theme_invoke("forum_topic_list", $topics, $topic_num, $sortby, $forum_per_page, $offset);
+    $output .= theme_invoke("forum_topic_list", $tid, $topics, $sortby, $forum_per_page, $offset);
   }
 
   $theme->header();
@@ -578,7 +557,7 @@ function forum_forum_list($forums, $parents, $tid) {
           $links[] = l(t("the most recent topic"), "node/view/". $forum->last_post->nid);
         }
         if ($new_topics) {
-          $links[] = l(t("the first new topic"), "forum/$forum->tid#new");
+          $links[] = l(t("the first new topic"), "forum/$forum->tid/new");
         }
 
         if ($links) {
@@ -624,10 +603,8 @@ function forum_topic_browser() {
   return form(form_item(t("Topic viewing options"), $output, t("Select your preferred way to display the topics and click 'Update settings'.")));
 }
 
-function forum_topic_list($topics, $num_topics, $sortby, $forum_per_page, $offset) {
-  global $theme, $id, $status, $tid, $user;
-
-  $output .= "<div style=\"margin-left: 20px; margin-top: 5px; margin-bottom: 10px;\">" .t("%a topics, %b topics per page, page %c of %d", array("%a" => $num_topics, "%b" => $forum_per_page, "%c" => ceil(($offset + 1)/$forum_per_page), "%d" => ceil($num_topics/$forum_per_page))) ."</div>";
+function forum_topic_list($tid, $topics, $sortby, $forum_per_page, $offset) {
+  global $theme, $id, $status, $user, $pager_total;
 
   if ($topics) {
     $output .= "<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\" width=\"100%\">\n";
@@ -635,13 +612,13 @@ function forum_topic_list($topics, $num_topics, $sortby, $forum_per_page, $offse
 
     foreach ($topics as $topic) {
       // folder is new if topic is new or there are new comments since last visit
-      if ($topic->shadow) {
+      if ($topic->tid != $tid) {
         $output .= "
           <tr>
             <td>"._forum_get_folder_icon($topic->new, $topic->num_comments, $topic->comment_mode)."</td>
             <td>"._forum_get_icon($topic)."</td>
             <td valign=\"top\">$topic->title</td>
-            <td align=\"center\" valign=\"top\" colspan=\"3\">". l(t("This topic has been moved"), "forum/$topic->shadow")."</td>
+            <td align=\"center\" valign=\"top\" colspan=\"3\">". l(t("This topic has been moved"), "forum/$topic->tid")."</td>
           </tr>";
       }
       else {
@@ -660,28 +637,15 @@ function forum_topic_list($topics, $num_topics, $sortby, $forum_per_page, $offse
     $output .= "</table></blockquote>\n";
   }
   $output .= "<hr />";
-  $output .= "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr>";
 
-  if ($offset > 0) {
-    $output .= "<td width=\"33%\"><div align=\"left\" style=\"font-style: bold;\">". l(t("previous topics"), array("mod" => "forum", "tid" => $tid, "offset" => ($offset-$forum_per_page))) ."</div></td>";
-  }
-  else {
-    $output .= "<td width=\"33%\">&nbsp;</td>";
-  }
+  $output .= "<div align=\"center\">" .t("%a topics, %b topics per page, page %c of %d", array("%a" => $pager_total[0], "%b" => $forum_per_page, "%c" => $offset, "%d" => ceil($pager_total[0]/$forum_per_page))) ."</div>";
 
-  if (user_access("create forum topics")) {
-    $output .= "<td width=\"33%\"><div align=\"center\" style=\"font-style: bold;\">". l(t("create new forum topic"), array("mod" => "node", "op" => "add", "type" => "forum", "tid" => $tid)) ."</div></td>";
-  }
+  $output .= (($pager = pager_display(NULL, $forum_per_page, 0, "default")) ? "$pager" : "");
 
-  if (count($topics) >= $forum_per_page) {
-    $output .= "<td width=\"33%\"><div align=\"right\" style=\"font-style: bold;\">". l(t("next topics"), array("mod" => "forum", "tid" => $tid, "offset" => ($offset+$forum_per_page))) ."</div></td>";
-  }
-  else {
-    $output .= "<td width=\"33%\">&nbsp;</td>";
+  if (user_access("create forum topics")) {
+    $output .= "<div align=\"center\" style=\"font-style: bold;\">". l(t("create new forum topic"), "node/add/forum/$tid") ."</div>";
   }
 
-  $output .= "</tr></table>";
-
   return $output;
 }
 
diff --git a/update.php b/update.php
index 6b7eb5712806..7918d7387296 100644
--- a/update.php
+++ b/update.php
@@ -62,7 +62,8 @@
   "2002-12-22" => "update_47",
   "2002-12-29" => "update_48",
   "2003-01-03" => "update_49",
-  "2003-01-05" => "update_50"
+  "2003-01-05" => "update_50",
+  "2003-01-15" => "update_51"
 );
 
 // Update functions
@@ -673,6 +674,15 @@ function update_50() {
   update_content("%node.php%");
 }
 
+function update_51() {
+  update_sql("ALTER TABLE form ADD tid INT UNSIGNED NOT NULL");
+  $result = db_queryd("SELECT n.nid, t.tid FROM node n, term_node t WHERE n.nid = t.nid AND type = 'forum'");
+  while ($node = db_fetch_object($result)) {
+    db_queryd("UPDATE forum SET tid = '%d' WHERE nid = '%d'", $node->tid, $node->nid);
+  }
+  update_sql("ALTER TABLE forum ADD INDEX (tid)");
+}
+
 function update_upgrade3() {
   update_sql("INSERT INTO system VALUES ('archive.module','archive','module','',1)");
   update_sql("INSERT INTO system VALUES ('block.module','block','module','',1)");
-- 
GitLab