Index: includes/DefaultSettings.php
===================================================================
RCS file: /cvsroot/wikipedia/phase3/includes/DefaultSettings.php,v
retrieving revision 1.391
diff -u -r1.391 DefaultSettings.php
--- includes/DefaultSettings.php	28 Nov 2005 21:38:09 -0000	1.391
+++ includes/DefaultSettings.php	3 Dec 2005 02:51:18 -0000
@@ -1407,6 +1407,14 @@
  * pages larger than this size. */
 $wgFeedDiffCutoff = 32768;
 
+/** Whether the Recentchanges feeds should be page-centric or change-centric.
+ * In the "page" mode, an item represents a page, its link points to the page,
+ * and its ID is the same as the IDs of all other items representing that page.
+ * In the "change" mode, an item represents a change, its link points to the
+ * change, and its ID is different from the IDs of all other items representing
+ * changes to that page.
+ */
+$wgFeedChangesMode = "page";
 
 /**
  * Additional namespaces. If the namespaces defined in Language.php and
Index: includes/SpecialRecentchanges.php
===================================================================
RCS file: /cvsroot/wikipedia/phase3/includes/SpecialRecentchanges.php,v
retrieving revision 1.86
diff -u -r1.86 SpecialRecentchanges.php
--- includes/SpecialRecentchanges.php	18 Nov 2005 19:56:19 -0000	1.86
+++ includes/SpecialRecentchanges.php	3 Dec 2005 02:51:18 -0000
@@ -298,7 +298,8 @@
 }
 
 function rcDoOutputFeed( $rows, &$feed ) {
-	global $wgSitename, $wgFeedClasses, $wgContLanguageCode;
+	global $wgSitename, $wgFeedClasses, $wgContLanguageCode, $wgFeedChangesMode,
+				 $wgUseRCPatrol, $wgUser, $wgOnlySysopsCanPatrol;
 
 	$feed->outHeader();
 
@@ -321,10 +322,56 @@
 	foreach( $sorted as $obj ) {
 		$title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title );
 		$talkpage = $title->getTalkPage();
+
+		# Build a link to the feed item.
+		if ($wgFeedChangesMode == "page") {
+			# Use the URL of the page that was changed.
+			$link = $title->getFullURL();
+		} else if ($wgFeedChangesMode == "change") {
+			# Build a link to the diff itself.  If there isn't one (f.e. if the page
+			# is new), then fall back to the URL of the page that was changed.
+
+			$rc = RecentChange::newFromRow( $obj );
+
+			if ( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) {
+				$link = $title->getFullURL();
+			} else {
+				# Should patrol-related stuff be shown?
+				$unpatrolled = $wgUseRCPatrol && $wgUser->isLoggedIn() &&
+					( !$wgOnlySysopsCanPatrol || $wgUser->isAllowed('patrol') ) &&
+					$rc->mAttribs['rc_patrolled'] == 0;
+
+				$rcidparam = $unpatrolled ? array( 'rcid' => $rc->mAttribs['rc_id'] )
+																	: array();
+				$query = wfArrayToCGI( array( 'curid' => $rc->mAttribs['rc_cur_id'],
+																		  'diff'  => $rc->mAttribs['rc_this_oldid'],
+																		  'oldid' => $rc->mAttribs['rc_last_oldid'] ),
+															 $rcidparam );
+				$title = $rc->getTitle();
+				$link = $title->escapeLocalURL( $query );
+				if ( '' != $title->getFragment() ) {
+					if( $title->getPrefixedDbkey() == '' ) {
+						$link = '';
+					}
+					$anchor = urlencode( Sanitizer::decodeCharReferences( str_replace( ' ', '_', $title->getFragment() ) ) );
+					$replacearray = array(
+						'%3A' => ':',
+						'%' => '.'
+					);
+					$link .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
+				}
+			}
+		} else {
+			# wgFeedChangesMode should always be either page or change,
+			# but if it isn't for some reason, then assume it's "page" by default,
+			# and fall back to the URL of the page that was changed.
+			$link = $title->getFullURL();
+		}
+
 		$item = new FeedItem(
 			$title->getPrefixedText(),
 			rcFormatDiff( $obj ),
-			$title->getFullURL(),
+			$link,
 			$obj->rc_timestamp,
 			$obj->rc_user_text,
 			$talkpage->getFullURL()
