diff --git modules/node/node.module modules/node/node.module
index 0c31c5b..e4bcaae 100644
--- modules/node/node.module
+++ modules/node/node.module
@@ -1224,11 +1224,7 @@ function node_build($node, $teaser = FALSE) {
  * Apply filters and build the node's standard elements.
  */
 function node_prepare($node, $teaser = FALSE) {
-  // First we'll overwrite the existing node teaser and body with
-  // the filtered copies! Then, we'll stick those into the content
-  // array and set the read more flag if appropriate.
-  $node->readmore = (strlen($node->teaser) < strlen($node->body));
-
+  // We overwrite the existing node teaser and body with the filtered copies.
   if ($teaser == FALSE) {
     $node->body = check_markup($node->body, $node->format, $node->language, FALSE);
   }
@@ -1646,16 +1642,31 @@ function theme_node_search_admin($form) {
 }
 
 /**
- * Implementation of hook_link().
+ * Implementation of hook_node_view().
  */
-function node_link($type, $node = NULL, $teaser = FALSE) {
+function node_node_view($node, $teaser = FALSE) {
   $links = array();
 
-  if ($type == 'node') {
-    if ($teaser == 1 && $node->teaser && !empty($node->readmore)) {
-      $links['node_read_more'] = array(
+  // We add "Read more" when showing the node teaser in these 2 build modes.
+  if ($teaser && in_array($node->build_mode, array(NODE_BUILD_NORMAL, NODE_BUILD_RSS))) {
+    // We add a check to not override this if it was set by another module.
+    if (!isset($node->readmore)) {
+      // "Read more" is applicable only if the node body has more content than
+      // the node teaser.
+      $node->readmore = (strlen($node->teaser) < strlen($node->body));
+    }
+  
+    if ($node->readmore) { 
+      if ($node->build_mode == NODE_BUILD_RSS) {
+        // We use an absolute URL for RSS items.
+        $node_url = url("node/$node->nid", array('absolute' => TRUE, 'target' => '_blank'));
+      }
+      else {
+        $node_url = "node/$node->nid";
+      }
+      $links['read_more'] = array(
         'title' => t('Read more'),
-        'href' => "node/$node->nid",
+        'href' => $node_url,
         // The title attribute gets escaped when the links are processed, so
         // there is no need to escape here.
         'attributes' => array('title' => t('Read the rest of !title.', array('!title' => $node->title)))
@@ -1663,7 +1674,13 @@ function node_link($type, $node = NULL, $teaser = FALSE) {
     }
   }
 
-  return $links;
+  if (!empty($links)) {
+    $node->content['links']['node'] = array(
+      '#type' => 'node_links',
+      '#value' => $links,
+      '#weight' => -10,
+    );
+  }
 }
 
 function _node_revision_access($node, $op = 'view') {
diff --git modules/node/node.test modules/node/node.test
index 15921fa..a9c42c1 100644
--- modules/node/node.test
+++ modules/node/node.test
@@ -311,6 +311,108 @@ class NodeTeaserTestCase extends DrupalWebTestCase {
   }
 }
 
+class NodeLinksTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Node links'),
+      'description' => t('Test "Read more" link.'),
+      'group' => t('Node'),
+    );
+  }
+
+  function setUp() {
+    // Enable dummy module that sets 'readmore' flag.
+    parent::setUp('node_test');
+
+    $web_user = $this->drupalCreateUser(array('create page content', 'delete any page content'));
+    $this->drupalLogin($web_user);
+  }
+
+  /**
+   * Sets the response content to the <description> of the given item index.
+   */
+  function rssSetContentToDescription($index = 0) {
+    $description = $this->xpath('//item/description');
+    $this->drupalSetContent($description[$index]);
+  }
+
+  /**
+   * Test the correctness of the existence or absence of the "Read more" link
+   * in a variety of cases.
+   */
+  function testReadMore() {
+    $body = $this->randomName(200);
+    $teaser = drupal_substr($body, 0, 100);
+
+    // 1. For testing when node body is larger than teaser.
+    $node = array(
+      'title' => t('Test body larger than teaser'),
+      'body' => $body,
+      'teaser' => $teaser,
+      'promote' => 1,
+    );
+    $node = $this->drupalCreateNode($node);
+    $this->drupalGet('node');
+    $this->assertLink(t('Read more'), 0, t('Read more added to node teaser which is smaller than node body.'));
+    $this->drupalGet('rss.xml');
+    $this->rssSetContentToDescription();
+    $this->assertRaw(t('Read more'), t('Read more added to RSS node item teaser which is smaller than node body.'));
+    $this->drupalGet("node/$node->nid");
+    $this->assertNoLink(t('Read more'), 0, t('Read more not added when viewing full node.'));
+    node_delete($node->nid);
+
+    // 2. For testing when node body is equal to the teaser.
+    $node = array(
+      'title' => t('Test body same as teaser'),
+      'body' => $teaser,
+      'teaser' => $teaser,
+      'promote' => 1,
+    );
+    $node = $this->drupalCreateNode($node);
+    $this->drupalGet('node');
+    $this->assertNoLink(t('Read more'), t('Read more not added to node teaser which is equal to node body.'));
+    $this->drupalGet('rss.xml');
+    $this->rssSetContentToDescription();
+    $this->assertNoRaw(t('Read more'), t('Read more not added to RSS node item which is equal to node body.'));
+    node_delete($node->nid);
+
+    // 3. For testing when node body is larger than teaser, but read more is
+    //    forced off by a module.
+    // @see node_test_node_load()
+    $node = array(
+      'title' => t('Read more forced off'),
+      'body' => $body,
+      'teaser' => $teaser,
+      'promote' => 1,
+    );
+    $node = $this->drupalCreateNode($node);
+    $this->drupalGet('node');
+    $this->assertNoLink(t('Read more'), t('Read more not added when readmore flag is FALSE.'));
+    $this->drupalGet('rss.xml');
+    $this->rssSetContentToDescription();
+    $this->assertNoRaw(t('Read more'), t('Read more not added to RSS when readmore flag is FALSE.'));
+    node_delete($node->nid);
+
+    // 4. For testing when node body is equal to the teaser, but read more is
+    //    forced on by a module.
+    // @see node_test_node_load()
+    $node = array(
+      'title' => t('Read more forced on'),
+      'body' => $teaser,
+      'teaser' => $teaser,
+      'promote' => 1,
+    );
+    $node = $this->drupalCreateNode($node);
+    $this->drupalGet('node');
+    $this->assertLink(t('Read more'), 0, t('Read more added when readmore flag is TRUE.'));
+    $this->drupalGet('rss.xml');
+    $this->rssSetContentToDescription();
+    $this->assertRaw(t('Read more'), t('Read more added to RSS when readmore flag is TRUE.'));
+    $this->drupalGet("node/$node->nid");
+    $this->assertNoLink(t('Read more'), t('Read more not added when viewing full node and readmore flag is TRUE.'));
+  }
+}
+
 class PageEditTestCase extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
diff --git modules/node/tests/node_test.module modules/node/tests/node_test.module
index a54135c..8ee15ef 100644
--- modules/node/tests/node_test.module
+++ modules/node/tests/node_test.module
@@ -33,3 +33,19 @@ function node_test_node_view($node, $teaser) {
     );
   }
 }
+
+/**
+ * Implementation of hook_node_load().
+ */
+function node_test_node_load($nodes, $types) {
+  foreach ($nodes as &$node) {
+    if ($node->title == t('Read more forced off')) {
+      // Force readmore to not be displayed for this node.
+      $node->readmore = FALSE;
+    }
+    else if ($node->title == t('Read more forced on')) {
+      // Force readmore to be displayed for this node.
+      $node->readmore = TRUE;
+    }
+  }
+}
\ No newline at end of file
