Index: permalink.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/permalink/permalink.install,v
retrieving revision 1.3
diff -u -p -r1.3 permalink.install
--- permalink.install	18 Mar 2009 01:54:50 -0000	1.3
+++ permalink.install	15 Sep 2009 18:08:23 -0000
@@ -2,15 +2,25 @@
 // $Id: permalink.install,v 1.3 2009/03/18 01:54:50 toddnienkerk Exp $
 
 /**
+ * @file
+ * Installs/uninstalls the permalink module.
+ *
+ */
+
+/**
  * Implementation of hook_uninstall().
  */
 function permalink_uninstall() {
-  $vars = db_query("select * from {variable} where name like 'permalink%'");
+  $vars = db_query("SELECT * FROM {variable} WHERE name LIKE 'permalink%'");
   while ($var = db_fetch_object($vars)) {
     variable_del($var->name);
   }
 }
-
+/**
+ * Implementation of hook_update_N().
+ *
+ * @return array of status => meessage values.
+ */
 function permalink_update_6000() {
   // Cycle through old var array
   // Change to the new method of storing vars
Index: permalink.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/permalink/permalink.module,v
retrieving revision 1.3.2.1
diff -u -p -r1.3.2.1 permalink.module
--- permalink.module	11 Apr 2009 21:34:02 -0000	1.3.2.1
+++ permalink.module	15 Sep 2009 18:08:24 -0000
@@ -1,6 +1,14 @@
 <?php
 // $Id: permalink.module,v 1.3.2.1 2009/04/11 21:34:02 toddnienkerk Exp $
 
+/**
+ * @file
+ * The permalink module, which adds permalink related features to Drupal.
+ *
+ * Adds permalinks to specific content and provides other features related
+ * to permalinks (like a comment permalink page).
+ */
+
 define('PERMALINK_NODE_TEXT_DEFAULT', t('Permalink'));
 define('PERMALINK_NODE_TITLE_TEXT_DEFAULT', t('Permanent link') .' |');
 define('PERMALINK_COMMENT_TEXT_DEFAULT', t('Permalink'));
@@ -27,17 +35,22 @@ function permalink_help($path, $arg) {
  */
 function permalink_menu() {
   $items['admin/settings/permalink'] = array(
-    'title' => t('Permalink'),
+    'title' => 'Permalink',
     'description' => t('Configures the permalink that appears in node links.'),
     'page callback' => 'drupal_get_form',
     'page arguments' => array('permalink_admin_settings'),
     'access arguments' => array('administer site configuration'),
     'type' => MENU_NORMAL_ITEM,
   );
+  $items['comment'] = array(
+    'title' => 'Comment permalink',
+    'page callback' => 'permalink_comment_permalink',
+    'access arguments' => array('access comments'),
+    'type' => MENU_NORMAL_ITEM,
+  );
   return $items;
 }
 
-
 /**
  * Displays the settings form.
  */
@@ -52,33 +65,33 @@ function permalink_admin_settings() {
     '#description' => t('Configure permalink dispaly options for nodes and node teasers.'),
   );
 
-    $form['permalink_node']['permalink_node_text'] = array(
-      '#type' => 'textfield',
-      '#title' =>  t('Node: Link text'),
-      '#default_value' => variable_get('permalink_node_text', PERMALINK_NODE_TEXT_DEFAULT),
-      '#description' => t('Enter the text you wish to display in the permalink. HTML is not allowed and will be stripped.'),
-      '#required' => TRUE,
-    );
+  $form['permalink_node']['permalink_node_text'] = array(
+    '#type' => 'textfield',
+    '#title' =>  t('Node: Link text'),
+    '#default_value' => variable_get('permalink_node_text', PERMALINK_NODE_TEXT_DEFAULT),
+    '#description' => t('Enter the text you wish to display in the permalink. HTML is not allowed and will be stripped.'),
+    '#required' => TRUE,
+  );
 
-    $form['permalink_node']['permalink_node_title'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Node: Link\'s %title attribute', array('%title' => 'title=""')),
-      '#collapsible' => FALSE,
-      '#description' => t('The %title attribute is used for accessibility and search engine optimization purposes and appears as a tooltip in some browsers.', array('%title' => 'title=""')),
-    );
-      $form['permalink_node']['permalink_node_title']['permalink_node_title_text'] = array(
-        '#type' => 'textfield',
-        '#title'=> t('Title text'),
-        '#default_value' => variable_get('permalink_node_title_text', PERMALINK_NODE_TITLE_TEXT_DEFAULT),
-        '#description' => t('Enter the text you wish to be used as the title for the permalink. HTML is not allowed and will be stripped. If you enable the option below, you should include a separator ("|" or ":").', array('%title' => 'title=""')),
-        '#required' => FALSE,
-      );
-      $form['permalink_node']['permalink_node_title']['permalink_node_title_text_append'] = array(
-        '#type' => 'checkbox',
-        '#title'=> t('Append the node title to the link\'s %title attribute.', array('%title' => 'title=""')),
-        '#default_value' => variable_get('permalink_node_title_text_append', TRUE),
-        '#description' => t('For example, if your title text (above) is <em>Permalink:</em> and the title of your node is <em>My Node</em>, enabling this option will display this link title: <em>Permalink: My Node</em>.'),
-      );
+  $form['permalink_node']['permalink_node_title'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Node: Link\'s %title attribute', array('%title' => 'title=""')),
+    '#collapsible' => FALSE,
+    '#description' => t('The %title attribute is used for accessibility and search engine optimization purposes and appears as a tooltip in some browsers.', array('%title' => 'title=""')),
+  );
+  $form['permalink_node']['permalink_node_title']['permalink_node_title_text'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Title text'),
+    '#default_value' => variable_get('permalink_node_title_text', PERMALINK_NODE_TITLE_TEXT_DEFAULT),
+    '#description' => t('Enter the text you wish to be used as the title for the permalink. HTML is not allowed and will be stripped. If you enable the option below, you should include a separator ("|" or ":").', array('%title' => 'title=""')),
+    '#required' => FALSE,
+  );
+  $form['permalink_node']['permalink_node_title']['permalink_node_title_text_append'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Append the node title to the link\'s %title attribute.', array('%title' => 'title=""')),
+    '#default_value' => variable_get('permalink_node_title_text_append', TRUE),
+    '#description' => t('For example, if your title text (above) is <em>Permalink:</em> and the title of your node is <em>My Node</em>, enabling this option will display this link title: <em>Permalink: My Node</em>.'),
+  );
 
   // Permalinks on comments
   $form['permalink_comment'] = array(
@@ -103,19 +116,19 @@ function permalink_admin_settings() {
       '#collapsible' => FALSE,
       '#description' => t('The %title attribute is used for accessibility and search engine optimization purposes and appears as a tooltip in some browsers.', array('%title' => 'title=""')),
     );
-      $form['permalink_comment']['permalink_comment_title']['permalink_comment_title_text'] = array(
-        '#type' => 'textfield',
-        '#title'=> t('Title text'),
-        '#default_value' => variable_get('permalink_comment_title_text', PERMALINK_COMMENT_TITLE_TEXT_DEFAULT),
-        '#description' => t('Enter the text you wish to be used as the title for the permalink. HTML is not allowed and will be stripped. If you enable the option below, you should include a separator ("|" or ":").', array('%title' => 'title=""')),
-        '#required' => FALSE,
-      );
-      $form['permalink_comment']['permalink_comment_title']['permalink_comment_title_text_append'] = array(
-        '#type' => 'checkbox',
-        '#title'=> t('Append the comment title to the link\'s %title attribute.', array('%title' => 'title=""')),
-        '#default_value' => variable_get('permalink_comment_title_text_append', TRUE),
-        '#description' => t('For example, if your title text (above) is <em>Permalink:</em> and the title of your comment is <em>My Comment</em>, enabling this option will display this link title: <em>Permalink: My Comment</em>.'),
-      );
+    $form['permalink_comment']['permalink_comment_title']['permalink_comment_title_text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Title text'),
+      '#default_value' => variable_get('permalink_comment_title_text', PERMALINK_COMMENT_TITLE_TEXT_DEFAULT),
+      '#description' => t('Enter the text you wish to be used as the title for the permalink. HTML is not allowed and will be stripped. If you enable the option below, you should include a separator ("|" or ":").', array('%title' => 'title=""')),
+      '#required' => FALSE,
+    );
+    $form['permalink_comment']['permalink_comment_title']['permalink_comment_title_text_append'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Append the comment title to the link\'s %title attribute.', array('%title' => 'title=""')),
+      '#default_value' => variable_get('permalink_comment_title_text_append', TRUE),
+      '#description' => t('For example, if your title text (above) is <em>Permalink:</em> and the title of your comment is <em>My Comment</em>, enabling this option will display this link title: <em>Permalink: My Comment</em>.'),
+    );
   }
   else {
     $form['permalink_comment'] = array(
@@ -126,7 +139,7 @@ function permalink_admin_settings() {
   // All permalinks
   $form['permalink_nofollow'] = array(
     '#type' => 'checkbox',
-    '#title'=> t('Make link nofollow'),
+    '#title' => t('Make link nofollow'),
     '#default_value' => variable_get('permalink_nofollow', TRUE),
     '#description' => t('Adds %nofollow to the permalink\'s attributes. Often used for search engine optimization purposes.', array('%nofollow' => 'rel="nofollow"')),
   );
@@ -212,7 +225,7 @@ function permalink_link($type, $object, 
 
 /**
  * Prepares the link for theming.
- * 
+ *
  * XSS checking and other safety measures are performed here to prevent
  * themers from omitting them.
  */
@@ -237,6 +250,8 @@ function permalink_link_render($type, $o
     $link_title_text = variable_get('permalink_comment_title_text', PERMALINK_COMMENT_TITLE_TEXT_DEFAULT);
     $show_object_title = variable_get('permalink_comment_title_text_append', TRUE);
     $object_title = $object->subject;
+    // Send the link to the custom comment page.
+    $link['href'] = 'comment/'. $object->cid;
   }
 
   // Strip HTML and filter for cross-site scripting (XSS)
@@ -312,7 +327,7 @@ function theme_permalink_copybox($node) 
   // Add stylesheet and JavaScript
   $path = drupal_get_path('module', 'permalink');
   drupal_add_css($path .'/permalink.css');
-  drupal_add_js($path .'/permalink.js'); 
+  drupal_add_js($path .'/permalink.js');
 
   // Generate URL text
   $link = url('node/'. $node->nid, array('absolute' => TRUE, 'alias' => TRUE));
@@ -326,3 +341,97 @@ function theme_permalink_copybox($node) 
 
   return $output;
 }
+
+/**
+ * Page callback for comment permalink page.
+ *
+ * Backported from Drupal 7 - may need to be removed eventually.
+ *
+ */
+function permalink_comment_permalink() {
+  $comment = _comment_load(arg(1));
+  $node = node_load($comment->nid);
+  if ($node && $comment) {
+
+    // Find the current display page for this comment.
+    $page = permalink_comment_get_display_page($comment->cid, $node->type);
+
+    // Set $_GET['q'] and $_GET['page'] ourselves so that the node callback
+    // behaves as it would when visiting the page directly.
+    $_GET['q'] = 'node/' . $node->nid;
+    $_GET['page'] = $page;
+
+    // Set the node path as the canonical URL to prevent duplicate content.
+    $options = array();
+    if ($page) {
+      $options = array('query' => 'page='. $page);
+    }
+    drupal_add_link(array('rel' => 'canonical', 'href' => url('node/' . $node->nid, $options)));
+
+    // Return the node view, this will show the correct comment in context.
+    return menu_execute_active_handler('node/' . $node->nid);
+  }
+  drupal_not_found();
+}
+
+/**
+ * Return the page number for a comment.
+ *
+ * Finds the correct page number for a comment taking into account display
+ * and paging settings.
+ *
+ * @param $cid
+ *   The comment ID.
+ * @param $node_type
+ *   The node type the comment is attached to.
+ * @return
+ *   The page number.
+ */
+function permalink_comment_get_display_page($cid, $node_type) {
+  $ordinal = permalink_comment_get_display_ordinal($cid, $node_type);
+  $comments_per_page = variable_get('comment_default_per_page_' . $node_type, 50);
+  return floor($ordinal / $comments_per_page);
+}
+
+/**
+ * Get the display ordinal for a comment, starting from 0.
+ *
+ * Count the number of comments which appear before the comment we want to
+ * display, taking into account display settings and threading.
+ *
+ * @param $cid
+ *   The comment ID.
+ * @param $node_type
+ *   The node type of the comment's parent.
+ * @return
+ *   The display ordinal for the comment.
+ * @see comment_get_display_page()
+ */
+function permalink_comment_get_display_ordinal($cid, $node_type) {
+  // Count how many comments (c1) are before $cid (c2) in display order. This is
+  // the 0-based display ordinal.
+  $sql = "SELECT COUNT(*) count FROM {comments} c1 INNER JOIN {comments} c2 ON c2.nid = c1.nid WHERE c2.cid = %d AND ";
+  $args[] = $cid;
+  if (!user_access('administer comments')) {
+    $sql .= 'c1.status ='. COMMENT_PUBLISHED .' AND ';
+  }
+
+  // 1 is COMMENT_MODE_THREADED
+  // 0 is COMMENT_MODE_FLAT
+  $mode = variable_get('comment_default_mode_' . $node_type, 1);
+  if ($mode == 0) {
+    // For flat comments, cid is used for ordering comments due to
+    // unpredicatable behavior with timestamp, so we make the same assumption
+    // here.
+    $sql .= ' c1.cid < %d ';
+    $args[] = $cid;
+  }
+  else {
+    // For threaded comments, the c.thread column is used for ordering. We can
+    // use the vancode for comparison, but must remove the trailing slash.
+    // @see comment_build_multiple().
+    $sql .= ' SUBSTRING(c1.thread, 1, (LENGTH(c1.thread) -1)) < SUBSTRING(c2.thread, 1, (LENGTH(c2.thread) -1)) ';
+  }
+  $data = db_result(db_query($sql, $args));
+  return db_result(db_query($sql, $args));
+}
\ No newline at end of file
