Implemented param tracking for hook users, feels a bit hackish
[lhc/web/wiklou.git] / includes / User.php
index de99114..5df021b 100644 (file)
@@ -4,6 +4,12 @@
  * @file
  */
 
+/**
+ * Int Number of characters in user_token field.
+ * @ingroup Constants
+ */
+define( 'USER_TOKEN_LENGTH', 32 );
+
 /**
  * Int Serialized record version.
  * @ingroup Constants
@@ -35,6 +41,13 @@ class PasswordError extends MWException {
  * of the database.
  */
 class User {
+       /**
+        * Global constants made accessible as class constants so that autoloader
+        * magic can be used.
+        */
+       const USER_TOKEN_LENGTH = USER_TOKEN_LENGTH;
+       const MW_USER_VERSION = MW_USER_VERSION;
+       const EDIT_TOKEN_SUFFIX = EDIT_TOKEN_SUFFIX;
 
        /**
         * Array of Strings List of member variables which are saved to the
@@ -160,10 +173,20 @@ class User {
        /**
         * Lazy-initialized variables, invalidated with clearInstanceCache
         */
-       var $mNewtalk, $mDatePreference, $mBlockedby, $mHash, $mSkin, $mRights,
-               $mBlockreason, $mBlock, $mEffectiveGroups, $mBlockedGlobally,
+       var $mNewtalk, $mDatePreference, $mBlockedby, $mHash, $mRights,
+               $mBlockreason, $mEffectiveGroups, $mBlockedGlobally,
                $mLocked, $mHideName, $mOptions;
 
+       /**
+        * @var Skin
+        */
+       var $mSkin;
+
+       /**
+        * @var Block
+        */
+       var $mBlock;
+
        static $idCacheByName = array();
 
        /**
@@ -180,6 +203,10 @@ class User {
                $this->clearInstanceCache( 'defaults' );
        }
 
+       function __toString(){
+               return $this->getName();
+       }
+
        /**
         * Load the user table data for this object from the source given by mFrom.
         */
@@ -364,7 +391,7 @@ class User {
        /**
         * Create a new user object from a user row.
         * The row should have all fields from the user table in it.
-        * @param $row array A row from the user table
+        * @param $row Array A row from the user table
         * @return User
         */
        static function newFromRow( $row ) {
@@ -614,7 +641,6 @@ class User {
                if( !wfRunHooks( 'isValidPassword', array( $password, &$result, $this ) ) )
                        return $result;
 
-
                if ( $result === false ) {
                        if( strlen( $password ) < $wgMinimalPasswordLength ) {
                                return 'passwordtooshort';
@@ -661,29 +687,10 @@ class User {
         *
         * @param $addr String E-mail address
         * @return Bool
+        * @deprecated since 1.18 call Sanitizer::isValidEmail() directly
         */
        public static function isValidEmailAddr( $addr ) {
-               $result = null;
-               if( !wfRunHooks( 'isValidEmailAddr', array( $addr, &$result ) ) ) {
-                       return $result;
-               }
-
-               // Please note strings below are enclosed in brackets [], this make the
-               // hyphen "-" a range indicator. Hence it is double backslashed below.
-               // See bug 26948
-               $rfc5322_atext   = "a-z0-9!#$%&'*+\\-\/=?^_`{|}~" ;
-               $rfc1034_ldh_str = "a-z0-9\\-" ;
-
-               $HTML5_email_regexp = "/
-               ^                      # start of string
-               [$rfc5322_atext\\.]+    # user part which is liberal :p
-               @                      # 'apostrophe'
-               [$rfc1034_ldh_str]+       # First domain part
-               (\\.[$rfc1034_ldh_str]+)*  # Following part prefixed with a dot
-               $                      # End of string
-               /ix" ; // case Insensitive, eXtended
-
-               return (bool) preg_match( $HTML5_email_regexp, $addr );
+               return Sanitizer::validateEmail( $addr );
        }
 
        /**
@@ -795,7 +802,7 @@ class User {
                $digit = mt_rand( 0, $pwlength - 1 );
                $np = '';
                for ( $i = 0; $i < $pwlength; $i++ ) {
-                       $np .= $i == $digit ? chr( mt_rand( 48, 57 ) ) : $pwchars{ mt_rand( 0, $l ) };
+                       $np .= $i == $digit ? chr( mt_rand( 48, 57 ) ) : $pwchars[ mt_rand( 0, $l ) ];
                }
                return $np;
        }
@@ -861,32 +868,30 @@ class User {
                        }
                }
 
-               if ( $wgRequest->getCookie( 'UserID' ) !== null ) {
-                       $sId = intval( $wgRequest->getCookie( 'UserID' ) );
-                       if( isset( $_SESSION['wsUserID'] ) && $sId != $_SESSION['wsUserID'] ) {
+               $cookieId = $wgRequest->getCookie( 'UserID' );
+               $sessId = $wgRequest->getSessionData( 'wsUserID' );
+
+               if ( $cookieId !== null ) {
+                       $sId = intval( $cookieId );
+                       if( $sessId !== null && $cookieId != $sessId ) {
                                $this->loadDefaults(); // Possible collision!
-                               wfDebugLog( 'loginSessions', "Session user ID ({$_SESSION['wsUserID']}) and
+                               wfDebugLog( 'loginSessions', "Session user ID ($sessId) and
                                        cookie user ID ($sId) don't match!" );
                                return false;
                        }
-                       $_SESSION['wsUserID'] = $sId;
-               } else if ( isset( $_SESSION['wsUserID'] ) ) {
-                       if ( $_SESSION['wsUserID'] != 0 ) {
-                               $sId = $_SESSION['wsUserID'];
-                       } else {
-                               $this->loadDefaults();
-                               return false;
-                       }
+                       $wgRequest->setSessionData( 'wsUserID', $sId );
+               } else if ( $sessId !== null && $sessId != 0 ) {
+                       $sId = $sessId;
                } else {
                        $this->loadDefaults();
                        return false;
                }
 
-               if ( isset( $_SESSION['wsUserName'] ) ) {
-                       $sName = $_SESSION['wsUserName'];
-               } else if ( $wgRequest->getCookie('UserName') !== null ) {
-                       $sName = $wgRequest->getCookie('UserName');
-                       $_SESSION['wsUserName'] = $sName;
+               if ( $wgRequest->getSessionData( 'wsUserName' ) !== null ) {
+                       $sName = $wgRequest->getSessionData( 'wsUserName' );
+               } else if ( $wgRequest->getCookie( 'UserName' ) !== null ) {
+                       $sName = $wgRequest->getCookie( 'UserName' );
+                       $wgRequest->setSessionData( 'wsUserName', $sName );
                } else {
                        $this->loadDefaults();
                        return false;
@@ -905,8 +910,8 @@ class User {
                        return false;
                }
 
-               if ( isset( $_SESSION['wsToken'] ) ) {
-                       $passwordCorrect = $_SESSION['wsToken'] == $this->mToken;
+               if ( $wgRequest->getSessionData( 'wsToken' ) !== null ) {
+                       $passwordCorrect = $this->mToken == $wgRequest->getSessionData( 'wsToken' );
                        $from = 'session';
                } else if ( $wgRequest->getCookie( 'Token' ) !== null ) {
                        $passwordCorrect = $this->mToken == $wgRequest->getCookie( 'Token' );
@@ -918,7 +923,7 @@ class User {
                }
 
                if ( ( $sName == $this->mName ) && $passwordCorrect ) {
-                       $_SESSION['wsToken'] = $this->mToken;
+                       $wgRequest->setSessionData( 'wsToken', $this->mToken );
                        wfDebug( "User: logged in from $from\n" );
                        return true;
                } else {
@@ -1105,44 +1110,26 @@ class User {
                $this->mHideName = 0;
                $this->mAllowUsertalk = 0;
 
-               # Check if we are looking at an IP or a logged-in user
-               if ( $this->isIP( $this->getName() ) ) {
-                       $ip = $this->getName();
+               # We only need to worry about passing the IP address to the Block generator if the
+               # user is not immune to autoblocks/hardblocks, and they are the current user so we
+               # know which IP address they're actually coming from
+               if ( !$this->isAllowed( 'ipblock-exempt' ) && $this->getID() == $wgUser->getID() ) {
+                       $ip = wfGetIP();
                } else {
-                       # Check if we are looking at the current user
-                       # If we don't, and the user is logged in, we don't know about
-                       # his IP / autoblock status, so ignore autoblock of current user's IP
-                       if ( $this->getID() != $wgUser->getID() ) {
-                               $ip = '';
-                       } else {
-                               # Get IP of current user
-                               $ip = wfGetIP();
-                       }
-               }
-
-               if ( $this->isAllowed( 'ipblock-exempt' ) ) {
-                       # Exempt from all types of IP-block
-                       $ip = '';
+                       $ip = null;
                }
 
                # User/IP blocking
-               $this->mBlock = new Block();
-               $this->mBlock->fromMaster( !$bFromSlave );
-               if ( $this->mBlock->load( $ip , $this->mId ) ) {
+               $this->mBlock = Block::newFromTarget( $this->getName(), $ip, !$bFromSlave );
+               if ( $this->mBlock instanceof Block ) {
                        wfDebug( __METHOD__ . ": Found block.\n" );
-                       $this->mBlockedby = $this->mBlock->mBy;
-                       if( $this->mBlockedby == 0 )
-                               $this->mBlockedby = $this->mBlock->mByName;
+                       $this->mBlockedby = $this->mBlock->getBlocker()->getName();
                        $this->mBlockreason = $this->mBlock->mReason;
                        $this->mHideName = $this->mBlock->mHideName;
-                       $this->mAllowUsertalk = $this->mBlock->mAllowUsertalk;
+                       $this->mAllowUsertalk = !$this->mBlock->prevents( 'editownusertalk' );
                        if ( $this->isLoggedIn() && $wgUser->getID() == $this->getID() ) {
                                $this->spreadBlock();
                        }
-               } else {
-                       // Bug 13611: don't remove mBlock here, to allow account creation blocks to
-                       // apply to users. Note that the existence of $this->mBlock is not used to
-                       // check for edit blocks, $this->mBlockedby is instead.
                }
 
                # Proxy blocking
@@ -1238,9 +1225,6 @@ class User {
                        // Deprecated, but kept for backwards-compatibility config
                        return false;
                }
-
-
-
                if( in_array( wfGetIP(), $wgRateLimitsExcludedIPs ) ) {
                        // No other good way currently to disable rate limits
                        // for specific IPs. :P
@@ -1330,7 +1314,7 @@ class User {
                                if( $count > $max ) {
                                        wfDebug( __METHOD__ . ": tripped! $key at $count $summary\n" );
                                        if( $wgRateLimitLog ) {
-                                               @error_log( wfTimestamp( TS_MW ) . ' ' . wfWikiID() . ': ' . $this->getName() . " tripped $key at $count $summary\n", 3, $wgRateLimitLog );
+                                               @file_put_contents( $wgRateLimitLog, wfTimestamp( TS_MW ) . ' ' . wfWikiID() . ': ' . $this->getName() . " tripped $key at $count $summary\n", FILE_APPEND );
                                        }
                                        $triggered = true;
                                } else {
@@ -1355,7 +1339,7 @@ class User {
         */
        function isBlocked( $bFromSlave = true ) { // hacked from false due to horrible probs on site
                $this->getBlockedStatus( $bFromSlave );
-               return $this->mBlockedby !== 0;
+               return $this->mBlock instanceof Block && $this->mBlock->prevents( 'edit' );
        }
 
        /**
@@ -1408,7 +1392,7 @@ class User {
         */
        function getBlockId() {
                $this->getBlockedStatus();
-               return ( $this->mBlock ? $this->mBlock->mId : false );
+               return ( $this->mBlock ? $this->mBlock->getId() : false );
        }
 
        /**
@@ -1473,8 +1457,8 @@ class User {
         * @return Int The user's ID; 0 if the user is anonymous or nonexistent
         */
        function getId() {
-               if( $this->mId === null and $this->mName !== null
-               and User::isIP( $this->mName ) ) {
+               if( $this->mId === null && $this->mName !== null
+               && User::isIP( $this->mName ) ) {
                        // Special case, we know the user is anonymous
                        return 0;
                } elseif( $this->mId === null ) {
@@ -1777,7 +1761,7 @@ class User {
                        }
 
                        if( !$this->isValidPassword( $str ) ) {
-                               global $wgMinimalPasswordLength;
+                               global $wgMinimalPasswordLength;
                                $valid = $this->getPasswordValidity( $str );
                                if ( is_array( $valid ) ) {
                                        $message = array_shift( $valid );
@@ -1787,7 +1771,7 @@ class User {
                                        $params = array( $wgMinimalPasswordLength );
                                }
                                throw new PasswordError( wfMsgExt( $message, array( 'parsemag' ), $params ) );
-                       }
+                       }
                }
 
                if( !$wgAuth->setPassword( $this, $str ) ) {
@@ -1944,11 +1928,13 @@ class User {
         *
         * @param $oname String The option to check
         * @param $defaultOverride String A default value returned if the option does not exist
+        * @param $ignoreHidden Bool = whether to ignore the effects of $wgHiddenPrefs
         * @return String User's current value for the option
         * @see getBoolOption()
         * @see getIntOption()
         */
-       function getOption( $oname, $defaultOverride = null ) {
+       function getOption( $oname, $defaultOverride = null, $ignoreHidden = false ) {
+               global $wgHiddenPrefs;
                $this->loadOptions();
 
                if ( is_null( $this->mOptions ) ) {
@@ -1958,6 +1944,15 @@ class User {
                        $this->mOptions = User::getDefaultOptions();
                }
 
+               # We want 'disabled' preferences to always behave as the default value for
+               # users, even if they have set the option explicitly in their settings (ie they
+               # set it, and then it was disabled removing their ability to change it).  But
+               # we don't want to erase the preferences in the database in case the preference
+               # is re-enabled again.  So don't touch $mOptions, just override the returned value
+               if( in_array( $oname, $wgHiddenPrefs ) && !$ignoreHidden ){
+                       return self::getDefaultOption( $oname );
+               }
+
                if ( array_key_exists( $oname, $this->mOptions ) ) {
                        return $this->mOptions[$oname];
                } else {
@@ -1971,8 +1966,23 @@ class User {
         * @return array
         */
        public function getOptions() {
+               global $wgHiddenPrefs;
                $this->loadOptions();
-               return $this->mOptions;
+               $options = $this->mOptions;
+
+               # We want 'disabled' preferences to always behave as the default value for
+               # users, even if they have set the option explicitly in their settings (ie they
+               # set it, and then it was disabled removing their ability to change it).  But
+               # we don't want to erase the preferences in the database in case the preference
+               # is re-enabled again.  So don't touch $mOptions, just override the returned value
+               foreach( $wgHiddenPrefs as $pref ){
+                       $default = self::getDefaultOption( $pref );
+                       if( $default !== null ){
+                               $options[$pref] = $default;
+                       }
+               }
+
+               return $options;
        }
 
        /**
@@ -2141,17 +2151,18 @@ class User {
         * @param $group String Name of the group to add
         */
        function addGroup( $group ) {
-               $dbw = wfGetDB( DB_MASTER );
-               if( $this->getId() ) {
-                       $dbw->insert( 'user_groups',
-                               array(
-                                       'ug_user'  => $this->getID(),
-                                       'ug_group' => $group,
-                               ),
-                               __METHOD__,
-                               array( 'IGNORE' ) );
+               if( wfRunHooks( 'UserAddGroup', array( &$this, &$group ) ) ) {
+                       $dbw = wfGetDB( DB_MASTER );
+                       if( $this->getId() ) {
+                               $dbw->insert( 'user_groups',
+                                       array(
+                                               'ug_user'  => $this->getID(),
+                                               'ug_group' => $group,
+                                       ),
+                                       __METHOD__,
+                                       array( 'IGNORE' ) );
+                       }
                }
-
                $this->loadGroups();
                $this->mGroups[] = $group;
                $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) );
@@ -2166,13 +2177,14 @@ class User {
         */
        function removeGroup( $group ) {
                $this->load();
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->delete( 'user_groups',
-                       array(
-                               'ug_user'  => $this->getID(),
-                               'ug_group' => $group,
-                       ), __METHOD__ );
-
+               if( wfRunHooks( 'UserRemoveGroup', array( &$this, &$group ) ) ) {
+                       $dbw = wfGetDB( DB_MASTER );
+                       $dbw->delete( 'user_groups',
+                               array(
+                                       'ug_user'  => $this->getID(),
+                                       'ug_group' => $group,
+                               ), __METHOD__ );
+               }
                $this->loadGroups();
                $this->mGroups = array_diff( $this->mGroups, array( $group ) );
                $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) );
@@ -2197,12 +2209,40 @@ class User {
        }
 
        /**
-
         * Check if user is allowed to access a feature / make an action
-        * @param $action String action to be checked
-        * @return Boolean: True if action is allowed, else false
+        * @param varargs String permissions to test
+        * @return Boolean: True if user is allowed to perform *any* of the given actions
+        */
+       public function isAllowedAny( /*...*/ ){
+               $permissions = func_get_args();
+               foreach( $permissions as $permission ){
+                       if( $this->isAllowed( $permission ) ){
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * @param varargs String
+        * @return bool True if the user is allowed to perform *all* of the given actions
         */
-       function isAllowed( $action = '' ) {
+       public function isAllowedAll( /*...*/ ){
+               $permissions = func_get_args();
+               foreach( $permissions as $permission ){
+                       if( !$this->isAllowed( $permission ) ){
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       /**
+        * Internal mechanics of testing a permission
+        * @param $action String
+        * @return bool
+        */
+       public function isAllowed( $action = '' ) {
                if ( $action === '' ) {
                        return true; // In the spirit of DWIM
                }
@@ -2223,7 +2263,7 @@ class User {
         */
        public function useRCPatrol() {
                global $wgUseRCPatrol;
-               return( $wgUseRCPatrol && ( $this->isAllowed( 'patrol' ) || $this->isAllowed( 'patrolmarks' ) ) );
+               return $wgUseRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
        }
 
        /**
@@ -2232,50 +2272,17 @@ class User {
         */
        public function useNPPatrol() {
                global $wgUseRCPatrol, $wgUseNPPatrol;
-               return( ( $wgUseRCPatrol || $wgUseNPPatrol ) && ( $this->isAllowed( 'patrol' ) || $this->isAllowed( 'patrolmarks' ) ) );
+               return( ( $wgUseRCPatrol || $wgUseNPPatrol ) && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) ) );
        }
 
        /**
-        * Get the current skin, loading it if required, and setting a title
-        * @param $t Title: the title to use in the skin
+        * Get the current skin, loading it if required
         * @return Skin The current skin
         * @todo: FIXME : need to check the old failback system [AV]
+        * @deprecated Use ->getSkin() in the most relevant outputting context you have
         */
-       function getSkin( $t = null ) {
-               if( !$this->mSkin ) {
-                       global $wgOut;
-                       $this->mSkin = $this->createSkinObject();
-                       $this->mSkin->setTitle( $wgOut->getTitle() );
-               }
-               if ( $t && ( !$this->mSkin->getTitle() || !$t->equals( $this->mSkin->getTitle() ) ) ) {
-                       $skin = $this->createSkinObject();
-                       $skin->setTitle( $t );
-                       return $skin;
-               } else {
-                       return $this->mSkin;
-               }
-       }
-
-       // Creates a Skin object, for getSkin()
-       private function createSkinObject() {
-               wfProfileIn( __METHOD__ );
-
-               global $wgHiddenPrefs;
-               if( !in_array( 'skin', $wgHiddenPrefs ) ) {
-                       global $wgRequest;
-                       # get the user skin
-                       $userSkin = $this->getOption( 'skin' );
-                       $userSkin = $wgRequest->getVal( 'useskin', $userSkin );
-               } else {
-                       # if we're not allowing users to override, then use the default
-                       global $wgDefaultSkin;
-                       $userSkin = $wgDefaultSkin;
-               }
-
-               $skin = Skin::newFromKey( $userSkin );
-               wfProfileOut( __METHOD__ );
-
-               return $skin;
+       function getSkin() {
+               return RequestContext::getMain()->getSkin();
        }
 
        /**
@@ -2443,8 +2450,16 @@ class User {
 
        /**
         * Set the default cookies for this session on the user's client.
+        *
+        * @param $request WebRequest object to use; $wgRequest will be used if null
+        *        is passed.
         */
-       function setCookies() {
+       function setCookies( $request = null ) {
+               if ( $request === null ) {
+                       global $wgRequest;
+                       $request = $wgRequest;
+               }
+
                $this->load();
                if ( 0 == $this->mId ) return;
                $session = array(
@@ -2463,9 +2478,9 @@ class User {
                }
 
                wfRunHooks( 'UserSetCookies', array( $this, &$session, &$cookies ) );
-               #check for null, since the hook could cause a null value
-               if ( !is_null( $session ) && isset( $_SESSION ) ){
-                       $_SESSION = $session + $_SESSION;
+
+               foreach ( $session as $name => $value ) {
+                       $request->setSessionData( $name, $value );
                }
                foreach ( $cookies as $name => $value ) {
                        if ( $value === false ) {
@@ -2491,9 +2506,11 @@ class User {
         * @see logout()
         */
        function doLogout() {
+               global $wgRequest;
+
                $this->clearInstanceCache( 'defaults' );
 
-               $_SESSION['wsUserID'] = 0;
+               $wgRequest->setSessionData( 'wsUserID', 0 );
 
                $this->clearCookie( 'UserID' );
                $this->clearCookie( 'Token' );
@@ -2521,8 +2538,8 @@ class User {
                                'user_newpassword' => $this->mNewpassword,
                                'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
                                'user_real_name' => $this->mRealName,
-                               'user_email' => $this->mEmail,
-                               'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
+                               'user_email' => $this->mEmail,
+                               'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
                                'user_options' => '',
                                'user_touched' => $dbw->timestamp( $this->mTouched ),
                                'user_token' => $this->mToken,
@@ -2560,9 +2577,9 @@ class User {
         * Add a user to the database, return the user object
         *
         * @param $name String Username to add
-        * @param $params Array of Strings Non-default parameters to save to the database:
-        *   - password             The user's password. Password logins will be disabled if this is omitted.
-        *   - newpassword          A temporary password mailed to the user
+        * @param $params Array of Strings Non-default parameters to save to the database as user_* fields:
+        *   - password             The user's password hash. Password logins will be disabled if this is omitted.
+        *   - newpassword          Hash for a temporary password that has been mailed to the user
         *   - email                The user's email address
         *   - email_authenticated  The email authentication timestamp
         *   - real_name            The user's real name
@@ -2581,6 +2598,7 @@ class User {
                }
                $dbw = wfGetDB( DB_MASTER );
                $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
+
                $fields = array(
                        'user_id' => $seqVal,
                        'user_name' => $name,
@@ -2649,7 +2667,7 @@ class User {
                        return;
                }
 
-               $userblock = Block::newFromDB( '', $this->mId );
+               $userblock = Block::newFromTarget( $this->getName() );
                if ( !$userblock ) {
                        return;
                }
@@ -2668,7 +2686,7 @@ class User {
         * which will give them a chance to modify this key based on their own
         * settings.
         *
-        * @deprecated @since 1.17 use the ParserOptions object to get the relevant options
+        * @deprecated since 1.17 use the ParserOptions object to get the relevant options
         * @return String Page rendering hash
         */
        function getPageRenderingHash() {
@@ -2711,11 +2729,24 @@ class User {
 
        /**
         * Get whether the user is explicitly blocked from account creation.
-        * @return Bool
+        * @return Bool|Block
         */
        function isBlockedFromCreateAccount() {
                $this->getBlockedStatus();
-               return $this->mBlock && $this->mBlock->mCreateAccount;
+               if( $this->mBlock && $this->mBlock->prevents( 'createaccount' ) ){
+                       return $this->mBlock;
+               }
+
+               # bug 13611: if the IP address the user is trying to create an account from is
+               # blocked with createaccount disabled, prevent new account creation there even
+               # when the user is logged in
+               static $accBlock = false;
+               if( $accBlock === false ){
+                       $accBlock = Block::newFromTarget( null, wfGetIP() );
+               }
+               return $accBlock instanceof Block && $accBlock->prevents( 'createaccount' )
+                       ? $accBlock
+                       : false;
        }
 
        /**
@@ -2724,7 +2755,7 @@ class User {
         */
        function isBlockedFromEmailuser() {
                $this->getBlockedStatus();
-               return $this->mBlock && $this->mBlock->mBlockEmail;
+               return $this->mBlock && $this->mBlock->prevents( 'sendemail' );
        }
 
        /**
@@ -2785,14 +2816,14 @@ class User {
         * @return Boolean: True if the given password is correct, otherwise False.
         */
        function checkPassword( $password ) {
-               global $wgAuth;
+               global $wgAuth, $wgLegacyEncoding;
                $this->load();
 
                // Even though we stop people from creating passwords that
                // are shorter than this, doesn't mean people wont be able
                // to. Certain authentication plugins do NOT want to save
                // domain passwords in a mysql database, so we should
-               // check this (incase $wgAuth->strict() is false).
+               // check this (in case $wgAuth->strict() is false).
                if( !$this->isValidPassword( $password ) ) {
                        return false;
                }
@@ -2808,11 +2839,13 @@ class User {
                }
                if ( self::comparePasswords( $this->mPassword, $password, $this->mId ) ) {
                        return true;
-               } elseif ( function_exists( 'iconv' ) ) {
+               } elseif ( $wgLegacyEncoding ) {
                        # Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
                        # Check for this with iconv
                        $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
-                       if ( self::comparePasswords( $this->mPassword, $cp1252Password, $this->mId ) ) {
+                       if ( $cp1252Password != $password &&
+                               self::comparePasswords( $this->mPassword, $cp1252Password, $this->mId ) )
+                       {
                                return true;
                        }
                }
@@ -2844,17 +2877,22 @@ class User {
         * submission.
         *
         * @param $salt String|Array of Strings Optional function-specific data for hashing
+        * @param $request WebRequest object to use or null to use $wgRequest
         * @return String The new edit token
         */
-       function editToken( $salt = '' ) {
+       function editToken( $salt = '', $request = null ) {
+               if ( $request == null ) {
+                       global $wgRequest;
+                       $request = $wgRequest;
+               }
+
                if ( $this->isAnon() ) {
                        return EDIT_TOKEN_SUFFIX;
                } else {
-                       if( !isset( $_SESSION['wsEditToken'] ) ) {
-                               $token = $this->generateToken();
-                               $_SESSION['wsEditToken'] = $token;
-                       } else {
-                               $token = $_SESSION['wsEditToken'];
+                       $token = $request->getSessionData( 'wsEditToken' );
+                       if ( $token === null ) {
+                               $token = self::generateToken();
+                               $request->setSessionData( 'wsEditToken', $token );
                        }
                        if( is_array( $salt ) ) {
                                $salt = implode( '|', $salt );
@@ -2869,7 +2907,7 @@ class User {
         * @param $salt String Optional salt value
         * @return String The new random token
         */
-       function generateToken( $salt = '' ) {
+       public static function generateToken( $salt = '' ) {
                $token = dechex( mt_rand() ) . dechex( mt_rand() );
                return md5( $token . $salt );
        }
@@ -2882,10 +2920,11 @@ class User {
         *
         * @param $val String Input value to compare
         * @param $salt String Optional function-specific data for hashing
+        * @param $request WebRequest object to use or null to use $wgRequest
         * @return Boolean: Whether the token matches
         */
-       function matchEditToken( $val, $salt = '' ) {
-               $sessionToken = $this->editToken( $salt );
+       function matchEditToken( $val, $salt = '', $request = null ) {
+               $sessionToken = $this->editToken( $salt, $request );
                if ( $val != $sessionToken ) {
                        wfDebug( "User::matchEditToken: broken session data\n" );
                }
@@ -2898,10 +2937,11 @@ class User {
         *
         * @param $val String Input value to compare
         * @param $salt String Optional function-specific data for hashing
+        * @param $request WebRequest object to use or null to use $wgRequest
         * @return Boolean: Whether the token matches
         */
-       function matchEditTokenNoSuffix( $val, $salt = '' ) {
-               $sessionToken = $this->editToken( $salt );
+       function matchEditTokenNoSuffix( $val, $salt = '', $request = null ) {
+               $sessionToken = $this->editToken( $salt, $request );
                return substr( $sessionToken, 0, 32 ) == substr( $val, 0, 32 );
        }
 
@@ -2977,7 +3017,7 @@ class User {
                $now = time();
                $expires = $now + $wgUserEmailConfirmationTokenExpiry;
                $expiration = wfTimestamp( TS_MW, $expires );
-               $token = wfGenerateToken( $this->mId . $this->mEmail . $expires );
+               $token = self::generateToken( $this->mId . $this->mEmail . $expires );
                $hash = md5( $token );
                $this->load();
                $this->mEmailToken = $hash;
@@ -3131,7 +3171,7 @@ class User {
         * Get the timestamp of account creation.
         *
         * @return String|Bool Timestamp of account creation, or false for
-        *                                non-existent/anonymous user accounts.
+        *     non-existent/anonymous user accounts.
         */
        public function getRegistration() {
                return $this->getId() > 0
@@ -3143,7 +3183,7 @@ class User {
         * Get the timestamp of the first edit
         *
         * @return String|Bool Timestamp of first edit, or false for
-        *                                non-existent/anonymous user accounts.
+        *     non-existent/anonymous user accounts.
         */
        public function getFirstEditTimestamp() {
                if( $this->getId() == 0 ) {
@@ -3333,9 +3373,9 @@ class User {
         *
         * @param $group String: the group to check for whether it can add/remove
         * @return Array array( 'add' => array( addablegroups ),
-        *  'remove' => array( removablegroups ),
-        *  'add-self' => array( addablegroups to self),
-        *  'remove-self' => array( removable groups from self) )
+        *     'remove' => array( removablegroups ),
+        *     'add-self' => array( addablegroups to self),
+        *     'remove-self' => array( removable groups from self) )
         */
        static function changeableByGroup( $group ) {
                global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
@@ -3490,7 +3530,7 @@ class User {
        static function getRightDescription( $right ) {
                $key = "right-$right";
                $name = wfMsg( $key );
-               return $name == '' || wfEmptyMsg( $key, $name )
+               return $name == '' || wfEmptyMsg( $key )
                        ? $right
                        : $name;
        }
@@ -3573,27 +3613,31 @@ class User {
         * @param $byEmail Boolean: account made by email?
         * @param $reason String: user supplied reason
         */
-       public function addNewUserLogEntry( $creator, $byEmail = false ) {
-               global $wgUser, $wgNewUserLog;
+       public function addNewUserLogEntry( $byEmail = false, $reason = '' ) {
+               global $wgUser, $wgContLang, $wgNewUserLog;
                if( empty( $wgNewUserLog ) ) {
                        return true; // disabled
                }
 
-               $action = ( $creator == $wgUser )
-                       ? 'create2' # Safe to publish the creator
-                       : 'create'; # Creator is an IP, don't splash it all over Special:Log
-
-               $message = $byEmail
-                       ? wfMsgForContent( 'newuserlog-byemail' )
-                       : '';
-
+               if( $this->getName() == $wgUser->getName() ) {
+                       $action = 'create';
+               } else {
+                       $action = 'create2';
+                       if ( $byEmail ) {
+                               if ( $reason === '' ) {
+                                       $reason = wfMsgForContent( 'newuserlog-byemail' );
+                               } else {
+                                       $reason = $wgContLang->commaList( array(
+                                               $reason, wfMsgForContent( 'newuserlog-byemail' ) ) );
+                               }
+                       }
+               }
                $log = new LogPage( 'newusers' );
                $log->addEntry(
                        $action,
                        $this->getUserPage(),
-                       $message,
-                       array( $this->getId() ),
-                       $creator
+                       $reason,
+                       array( $this->getId() )
                );
                return true;
        }
@@ -3604,17 +3648,11 @@ class User {
         */
        public function addNewUserLogEntryAutoCreate() {
                global $wgNewUserLog;
-               if( empty( $wgNewUserLog ) ) {
+               if( !$wgNewUserLog ) {
                        return true; // disabled
                }
                $log = new LogPage( 'newusers', false );
-               $log->addEntry(
-                       'autocreate',
-                       $this->getUserPage(),
-                       '',
-                       array( $this->getId() ),
-                       $this->getId()
-                       );
+               $log->addEntry( 'autocreate', $this->getUserPage(), '', array( $this->getId() ) );
                return true;
        }
 
@@ -3758,8 +3796,4 @@ class User {
 
                return $ret;
        }
-
-
-
-
 }