Index: User.php
===================================================================
--- User.php	(revision 76210)
+++ User.php	(working copy)
@@ -2219,8 +2219,8 @@
 			return true; // In the spirit of DWIM
 		# Patrolling may not be enabled
 		if( $action === 'patrol' || $action === 'autopatrol' ) {
-			global $wgUseRCPatrol, $wgUseNPPatrol;
-			if( !$wgUseRCPatrol && !$wgUseNPPatrol )
+			global $wgUseRCPatrol, $wgUseNPPatrol, $wgUseUploadPatrol;
+			if( !$wgUseRCPatrol && !$wgUseNPPatrol && !$wgUseUploadPatrol )
 				return false;
 		}
 		# Use strict parameter to avoid matching numeric 0 accidentally inserted
Index: RecentChange.php
===================================================================
--- RecentChange.php	(revision 76210)
+++ RecentChange.php	(working copy)
@@ -483,7 +483,7 @@
 	}
 
 	public static function notifyLog( $timestamp, &$title, &$user, $actionComment, $ip='', $type, 
-		$action, $target, $logComment, $params, $newId=0 )
+		$action, $target, $logComment, $params, $newId=0, $patrolled=true )
 	{
 		global $wgLogRestrictions;
 		# Don't add private logs to RC!
@@ -491,13 +491,20 @@
 			return false;
 		}
 		$rc = self::newLogEntry( $timestamp, $title, $user, $actionComment, $ip, $type, $action,
-			$target, $logComment, $params, $newId );
+			$target, $logComment, $params, $newId, $patrolled );
 		$rc->save();
+
+		# Log auto-patrolled log entries.
+		# Can be true (patolled, but not auto), false, or 'auto'.
+		if ( $patrolled === 'auto' ) {
+			PatrolLog::record( $rc, true );
+		}
+
 		return true;
 	}
 
 	public static function newLogEntry( $timestamp, &$title, &$user, $actionComment, $ip='',
-		$type, $action, $target, $logComment, $params, $newId=0 )
+		$type, $action, $target, $logComment, $params, $newId=0, $patrolled=true )
 	{
 		global $wgRequest;
 		if( !$ip ) {
@@ -523,7 +530,7 @@
 			'rc_moved_to_ns' => 0,
 			'rc_moved_to_title' => '',
 			'rc_ip'         => $ip,
-			'rc_patrolled'  => 1,
+			'rc_patrolled'  => $patrolled ? 1 : 0,
 			'rc_new'        => 0, # obsolete
 			'rc_old_len'    => null,
 			'rc_new_len'    => null,
Index: filerepo/LocalFile.php
===================================================================
--- filerepo/LocalFile.php	(revision 76210)
+++ filerepo/LocalFile.php	(working copy)
@@ -852,6 +852,7 @@
 	 */
 	function recordUpload2( $oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null )
 	{
+		global $wgUseUploadPatrol;
 		if ( is_null( $user ) ) {
 			global $wgUser;
 			$user = $wgUser;
@@ -971,8 +972,18 @@
 		# Add the log entry
 		$log = new LogPage( 'upload' );
 		$action = $reupload ? 'overwrite' : 'upload';
-		$log->addEntry( $action, $descTitle, $comment, array(), $user );
 
+		$patrolled = true;
+		if ( $wgUseUploadPatrol ) {
+			if ( $descTitle->userCan( 'autopatrol' ) ) {
+				$patrolled = 'auto';
+			} else {
+				$patrolled = false;
+			}
+		}
+
+		$log->addEntry( $action, $descTitle, $comment, array(), $user, $patrolled );
+
 		if ( $descTitle->exists() ) {
 			# Create a null revision
 			$latest = $descTitle->getLatestRevID();
Index: ChangesList.php
===================================================================
--- ChangesList.php	(revision 76210)
+++ ChangesList.php	(working copy)
@@ -345,13 +345,19 @@
 	}
 
 	/** insert a formatted action */
-	public function insertAction( &$s, &$rc ) {
+	public function insertAction( &$s, &$rc, $patrol_id = '' ) {
 		if( $rc->mAttribs['rc_type'] == RC_LOG ) {
+			$urlParams = array();
+			if ( $patrol_id ) {
+				$urlParams['rcid'] = $patrol_id;
+			}
+
 			if( $this->isDeleted( $rc, LogPage::DELETED_ACTION ) ) {
 				$s .= ' <span class="history-deleted">' . wfMsgHtml( 'rev-deleted-event' ) . '</span>';
 			} else {
 				$s .= ' '.LogPage::actionText( $rc->mAttribs['rc_log_type'], $rc->mAttribs['rc_log_action'],
-					$rc->getTitle(), $this->skin, LogPage::extractParams( $rc->mAttribs['rc_params'] ), true, true );
+					$rc->getTitle(), $this->skin, LogPage::extractParams( $rc->mAttribs['rc_params'] ),
+					true, $urlParams );
 			}
 		}
 	}
@@ -474,6 +480,10 @@
 		wfProfileIn( __METHOD__ );
 		# Should patrol-related stuff be shown?
 		$unpatrolled = $wgUser->useRCPatrol() && !$rc->mAttribs['rc_patrolled'];
+		$patrol_id = '';
+		if ( $unpatrolled ) {
+			$patrol_id = $rc->mAttribs['rc_id'];
+		}
 
 		$dateheader = ''; // $s now contains only <li>...</li>, for hooks' convenience.
 		$this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] );
@@ -497,6 +507,11 @@
 		} elseif( $rc->mAttribs['rc_log_type'] ) {
 			$logtitle = Title::newFromText( 'Log/'.$rc->mAttribs['rc_log_type'], NS_SPECIAL );
 			$this->insertLog( $s, $logtitle, $rc->mAttribs['rc_log_type'] );
+			// Unpatrolled and bot flags still make sense for log actions.
+			$flags = $this->recentChangesFlags( '', '', $unpatrolled, '', $rc->mAttribs['rc_bot'] );
+			if ( $flags !== '' ) {
+				$s .= ' . . ' . $flags;
+			}
 		// Log entries (old format) or log targets, and special pages
 		} elseif( $rc->mAttribs['rc_namespace'] == NS_SPECIAL ) {
 			list( $name, $subpage ) = SpecialPage::resolveAliasWithSubpage( $rc->mAttribs['rc_title'] );
@@ -523,7 +538,7 @@
 		# User tool links
 		$this->insertUserRelatedLinks( $s, $rc );
 		# Log action text (if any)
-		$this->insertAction( $s, $rc );
+		$this->insertAction( $s, $rc, $patrol_id );
 		# Edit or log comment
 		$this->insertComment( $s, $rc );
 		# Tags
Index: DefaultSettings.php
===================================================================
--- DefaultSettings.php	(revision 76210)
+++ DefaultSettings.php	(working copy)
@@ -4105,6 +4105,9 @@
 /** Use new page patrolling to check new pages on Special:Newpages */
 $wgUseNPPatrol = true;
 
+/** Use (experimental) upload patrolling */
+$wgUseUploadPatrol = false;
+
 /** Provide syndication feeds (RSS, Atom) for, e.g., Recentchanges, Newpages */
 $wgFeed = true;
 
Index: LogPage.php
===================================================================
--- LogPage.php	(revision 76210)
+++ LogPage.php	(working copy)
@@ -38,7 +38,7 @@
 	const SUPPRESSED_USER = 12;
 	const SUPPRESSED_ACTION = 9;
 	/* @access private */
-	var $type, $action, $comment, $params, $target, $doer;
+	var $type, $action, $comment, $params, $target, $doer, $patrolled;
 	/* @acess public */
 	var $updateRecentChanges, $sendToUDP;
 
@@ -85,7 +85,7 @@
 			RecentChange::notifyLog(
 				$now, $titleObj, $this->doer, $this->getRcComment(), '',
 				$this->type, $this->action, $this->target, $this->comment,
-				$this->params, $newId
+				$this->params, $newId, $this->patrolled
 			);
 		} elseif( $this->sendToUDP ) {
 			# Don't send private logs to UDP
@@ -186,11 +186,16 @@
 	 *              content language, since that will go to the IRC feed.
 	 * @param $params Array: parameters
 	 * @param $filterWikilinks Boolean: whether to filter wiki links
+	 * @param $urlParams Array: List of extra parameters for url (used for upload patrol)
 	 * @return HTML string
 	 */
 	public static function actionText( $type, $action, $title = null, $skin = null,
-		$params = array(), $filterWikilinks = false )
+		$params = array(), $filterWikilinks = false, $urlParams = array() )
 	{
+		if ( !is_array( $urlParams ) ) {
+			// Really really really old mediawiki had another argument.
+			$urlParams = array();
+		}
 		global $wgLang, $wgContLang, $wgLogActions;
 
 		$key = "$type/$action";
@@ -202,7 +207,7 @@
 			if( is_null( $title ) ) {
 				$rv = wfMsgHtml( $wgLogActions[$key] );
 			} else {
-				$titleLink = self::getTitleLink( $type, $skin, $title, $params );
+				$titleLink = self::getTitleLink( $type, $skin, $title, $params, $urlParams );
 				if( $key == 'rights/rights' ) {
 					if( $skin ) {
 						$rightsnone = wfMsg( 'rightsnone' );
@@ -318,7 +323,7 @@
 		return $rv;
 	}
 
-	protected static function getTitleLink( $type, $skin, $title, &$params ) {
+	protected static function getTitleLink( $type, $skin, $title, &$params, $urlParams = array() ) {
 		global $wgLang, $wgContLang, $wgUserrightsInterwikiDelimiter;
 		if( !$skin ) {
 			return $title->getPrefixedText();
@@ -329,7 +334,7 @@
 					$title,
 					htmlspecialchars( $title->getPrefixedText() ),
 					array(),
-					array( 'redirect' => 'no' )
+					array( 'redirect' => 'no' ) + $urlParams
 				);
 				$targetTitle = Title::newFromText( $params[0] );
 				if ( !$targetTitle ) {
@@ -338,7 +343,9 @@
 				} else {
 					$params[0] = $skin->link(
 						$targetTitle,
-						htmlspecialchars( $params[0] )
+						htmlspecialchars( $params[0] ),
+						array(),
+						$urlParams
 					);
 				}
 				break;
@@ -370,11 +377,13 @@
 					$title,
 					$title->getPrefixedText(),
 					array(),
-					array( 'redirect' => 'no' )
+					array( 'redirect' => 'no' ) + $urlParams
 				);
 				$params[0] = $skin->link(
 					Title::newFromText( $params[0] ),
-					htmlspecialchars( $params[0] )
+					htmlspecialchars( $params[0] ),
+					array(),
+					$urlParams
 				);
 				$params[1] = $wgLang->timeanddate( $params[1] );
 				break;
@@ -388,7 +397,12 @@
 						$titleLink = $skin->link( $title );
 					}
 				} else {
-					$titleLink = $skin->link( $title );
+					$titleLink = $skin->link(
+						$title,
+						null,
+						array(),
+						$urlParams
+					);
 				}
 		}
 		return $titleLink;
@@ -402,8 +416,10 @@
 	 * @param $comment String: description associated
 	 * @param $params Array: parameters passed later to wfMsg.* functions
 	 * @param $doer User object: the user doing the action
+	 * @param $patrolled Mixed: true for patrolled or patrol disabled (but not auto patrol),
+	 * false for not patrolled, 'auto' for auto.
 	 */
-	public function addEntry( $action, $target, $comment, $params = array(), $doer = null ) {
+	public function addEntry( $action, $target, $comment, $params = array(), $doer = null, $patrolled = true ) {
 		if ( !is_array( $params ) ) {
 			$params = array( $params );
 		}
@@ -415,6 +431,7 @@
 		$this->action = $action;
 		$this->target = $target;
 		$this->comment = $comment;
+		$this->patrolled = $patrolled;
 		$this->params = LogPage::makeParamBlob( $params );
 
 		if ( $doer === null ) {
