Don't duplicate code, use wfAppendQuery
[lhc/web/wiklou.git] / includes / User.php
index 99b0dd6..f7d7880 100644 (file)
@@ -43,7 +43,7 @@ class PasswordError extends MWException {
 class User {
 
        /**
-        * \arrayof{\string} A list of default user toggles, i.e., boolean user 
+        * \type{\arrayof{\string}} A list of default user toggles, i.e., boolean user 
          * preferences that are displayed by Special:Preferences as checkboxes.
         * This list can be extended via the UserToggles hook or by
         * $wgContLang::getExtraUserToggles().
@@ -82,16 +82,19 @@ class User {
                'showjumplinks',
                'uselivepreview',
                'forceeditsummary',
-               'watchlisthideown',
-               'watchlisthidebots',
                'watchlisthideminor',
+               'watchlisthidebots',
+               'watchlisthideown',
+               'watchlisthideanons',
+               'watchlisthideliu',
                'ccmeonemails',
                'diffonly',
                'showhiddencats',
+               'noconvertlink',
        );
 
        /**
-        * \arrayof{\string} List of member variables which are saved to the 
+        * \type{\arrayof{\string}} List of member variables which are saved to the 
         * shared cache (memcached). Any operation which changes the 
         * corresponding database fields must call a cache-clearing function.
         * @showinitializer
@@ -118,7 +121,7 @@ class User {
        );
 
        /**
-        * \arrayof{\string} Core rights.
+        * \type{\arrayof{\string}} Core rights.
         * Each of these should have a corresponding message of the form 
         * "right-$right".
         * @showinitializer
@@ -156,6 +159,7 @@ class User {
                'reupload',
                'reupload-shared',
                'rollback',
+               'siteadmin',
                'suppressredirect',
                'trackback',
                'undelete',
@@ -461,8 +465,8 @@ class User {
         * addresses like this, if we allowed accounts like this to be created
         * new users could get the old edits of these anonymous users.
         *
-        * @param $name \type{\string}
-        * @return \type{\bool}
+        * @param $name \type{\string} String to match
+        * @return \type{\bool} True or false
         */
        static function isIP( $name ) {
                return preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/',$name) || IP::isIPv6($name);
@@ -476,8 +480,8 @@ class User {
         * is longer than the maximum allowed username size or doesn't begin with
         * a capital letter.
         *
-        * @param $name \type{\string}
-        * @return \type{\bool}
+        * @param $name \type{\string} String to match
+        * @return \type{\bool} True or false
         */
        static function isValidUserName( $name ) {
                global $wgContLang, $wgMaxNameChars;
@@ -530,8 +534,8 @@ class User {
         * If an account already exists in this form, login will be blocked
         * by a failure to pass this function.
         *
-        * @param $name \type{\string}
-        * @return \type{\bool}
+        * @param $name \type{\string} String to match
+        * @return \type{\bool} True or false
         */
        static function isUsableName( $name ) {
                global $wgReservedUsernames;
@@ -568,8 +572,8 @@ class User {
         * rather than in isValidUserName() to avoid disrupting
         * existing accounts.
         *
-        * @param $name \type{\string}
-        * @return \type{\bool}
+        * @param $name \type{\string} String to match
+        * @return \type{\bool} True or false
         */
        static function isCreatableName( $name ) {
                return
@@ -583,7 +587,7 @@ class User {
         * Is the input a valid password for this user?
         *
         * @param $password \type{\string} Desired password
-        * @return \type{\bool}
+        * @return \type{\bool} True or false
         */
        function isValidPassword( $password ) {
                global $wgMinimalPasswordLength, $wgContLang;
@@ -609,7 +613,7 @@ class User {
         * @todo Check for RFC 2822 compilance (bug 959)
         *
         * @param $addr \type{\string} E-mail address
-        * @return \type{\bool}
+        * @return \type{\bool} True or false
         */
        public static function isValidEmailAddr( $addr ) {
                $result = null;
@@ -642,7 +646,9 @@ class User {
                        return false;
 
                # Clean up name according to title rules
-               $t = Title::newFromText( $name );
+               $t = ($validate === 'valid') ? 
+                       Title::newFromText( $name ) : Title::makeTitle( NS_USER, $name );
+               # Check for invalid titles
                if( is_null( $t ) ) {
                        return false;
                }
@@ -717,7 +723,7 @@ class User {
         * Return a random password. Sourced from mt_rand, so it's not particularly secure.
         * @todo hash random numbers to improve security, like generateToken()
         *
-        * @return \type{\string}
+        * @return \type{\string} New random password
         */
        static function randomPassword() {
                global $wgMinimalPasswordLength;
@@ -885,7 +891,7 @@ class User {
        /**
         * Initialize this object from a row from the user table.
         *
-        * @param $row \arrayof{\mixed} Row from the user table to load.
+        * @param $row \type{\arrayof{\mixed}} Row from the user table to load.
         */
        function loadFromRow( $row ) {
                $this->mDataLoaded = true;
@@ -952,7 +958,7 @@ class User {
         * Combine the language default options with any site-specific options
         * and add the default language variants.
         *
-        * @return \arrayof{\string} Array of options
+        * @return \type{\arrayof{\string}} Array of options
         */
        static function getDefaultOptions() {
                global $wgNamespacesToBeSearchedDefault;
@@ -979,7 +985,7 @@ class User {
         * Get a given default option value.
         *
         * @param $opt \type{\string} Name of option to retrieve
-        * @return \type{\string}
+        * @return \type{\string} Default option value
         */
        public static function getDefaultOption( $opt ) {
                $defOpts = self::getDefaultOptions();
@@ -992,7 +998,7 @@ class User {
 
        /**
         * Get a list of user toggle names
-        * @return \arrayof{\string}
+        * @return \type{\arrayof{\string}} Array of user toggle names
         */
        static function getToggles() {
                global $wgContLang;
@@ -1030,6 +1036,7 @@ class User {
                
                $this->mBlockedby = 0;
                $this->mHideName = 0;
+               $this->mAllowUsertalk = 0;
                $ip = wfGetIP();
 
                if ($this->isAllowed( 'ipblock-exempt' ) ) {
@@ -1045,12 +1052,14 @@ class User {
                        $this->mBlockedby = $this->mBlock->mBy;
                        $this->mBlockreason = $this->mBlock->mReason;
                        $this->mHideName = $this->mBlock->mHideName;
+                       $this->mAllowUsertalk = $this->mBlock->mAllowUsertalk;
                        if ( $this->isLoggedIn() ) {
                                $this->spreadBlock();
                        }
                } else {
-                       $this->mBlock = null;
-                       wfDebug( __METHOD__.": No block.\n" );
+                       // 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
@@ -1080,7 +1089,7 @@ class User {
         * Whether the given IP is in the SORBS blacklist.
         *
         * @param $ip \type{\string} IP to check
-        * @return \type{\bool}
+        * @return \type{\bool} True if blacklisted
         */
        function inSorbsBlacklist( $ip ) {
                global $wgEnableSorbs, $wgSorbsUrl;
@@ -1094,26 +1103,22 @@ class User {
         *
         * @param $ip \type{\string} IP to check
         * @param $base \type{\string} URL of the DNS blacklist
-        * @return \type{\bool}
+        * @return \type{\bool} True if blacklisted
         */
        function inDnsBlacklist( $ip, $base ) {
                wfProfileIn( __METHOD__ );
 
                $found = false;
                $host = '';
-               // FIXME: IPv6 ???
-               $m = array();
-               if ( preg_match( '/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip, $m ) ) {
+               // FIXME: IPv6 ???  (http://bugs.php.net/bug.php?id=33170)
+               if( IP::isIPv4($ip) ) {
                        # Make hostname
-                       for ( $i=4; $i>=1; $i-- ) {
-                               $host .= $m[$i] . '.';
-                       }
-                       $host .= $base;
+                       $host = "$ip.$base";
 
                        # Send query
                        $ipList = gethostbynamel( $host );
 
-                       if ( $ipList ) {
+                       if( $ipList ) {
                                wfDebug( "Hostname $host is {$ipList[0]}, it's a proxy says $base!\n" );
                                $found = true;
                        } else {
@@ -1128,7 +1133,7 @@ class User {
        /**
         * Is this user subject to rate limiting?
         *
-        * @return \type{\bool}
+        * @return \type{\bool} True if rate limited
         */
        public function isPingLimitable() {
                global $wgRateLimitsExcludedGroups;
@@ -1263,7 +1268,7 @@ class User {
                wfDebug( __METHOD__.": asking isBlocked()\n" );
                $blocked = $this->isBlocked( $bFromSlave );
                # If a user's name is suppressed, they cannot make edits anywhere
-               if ( !$this->mHideName && $wgBlockAllowsUTEdit && $title->getText() === $this->getName() &&
+               if ( !$this->mHideName && $this->mAllowUsertalk && $title->getText() === $this->getName() &&
                  $title->getNamespace() == NS_USER_TALK ) {
                        $blocked = false;
                        wfDebug( __METHOD__.": self-talk page, ignoring any blocks\n" );
@@ -1317,7 +1322,7 @@ class User {
 
        /**
         * Get the user name, or the IP of an anonymous user
-        * @return \type{\string}
+        * @return \type{\string} User's name or IP address
         */
        function getName() {
                if ( !$this->mDataLoaded && $this->mFrom == 'name' ) {
@@ -1353,7 +1358,7 @@ class User {
 
        /**
         * Get the user's name escaped by underscores.
-        * @return \type{\string}
+        * @return \type{\string} Username escaped by underscores
         */
        function getTitleKey() {
                return str_replace( ' ', '_', $this->getName() );
@@ -1394,7 +1399,7 @@ class User {
 
        /**
         * Return the talk page(s) this user has new messages on.
-        * @return \arrayof{\string} Array of page URLs
+        * @return \type{\arrayof{\string}} Array of page URLs
         */
        function getNewMessageLinks() {
                $talks = array();
@@ -1564,6 +1569,14 @@ class User {
                return ($timestamp >= $this->mTouched);
        }
 
+       /**
+        * Get the user touched timestamp
+        */
+       function getTouched() {
+               $this->load();
+               return $this->mTouched;
+       }
+
        /**
         * Set the password and reset the random token.
         * Calls through to authentication plugin if necessary;
@@ -1623,7 +1636,7 @@ class User {
        
        /**
         * Get the user's current token.
-        * @return \type{\string}
+        * @return \type{\string} Token
         */
        function getToken() {
                $this->load();
@@ -1682,7 +1695,7 @@ class User {
        /**
         * Has password reminder email been sent within the last 
         * $wgPasswordReminderResendTime hours?
-        * @return \type{\bool}
+        * @return \type{\bool} True or false
         */
        function isPasswordReminderThrottled() {
                global $wgPasswordReminderResendTime;
@@ -1696,7 +1709,7 @@ class User {
 
        /**
         * Get the user's e-mail address
-        * @return \type{\string}
+        * @return \type{\string} User's e-mail address
         */
        function getEmail() {
                $this->load();
@@ -1726,7 +1739,7 @@ class User {
 
        /**
         * Get the user's real name
-        * @return \type{\string}
+        * @return \type{\string} User's real name
         */
        function getRealName() {
                $this->load();
@@ -1828,7 +1841,7 @@ class User {
 
        /**
         * Get the user's preferred date format.
-        * @return \type{\string}
+        * @return \type{\string} User's preferred date format
         */
        function getDatePreference() {
                // Important migration for old data rows
@@ -1846,7 +1859,7 @@ class User {
 
        /**
         * Get the permissions this user has.
-        * @return \arrayof{\string}
+        * @return \type{\arrayof{\string}} Array of permission names
         */
        function getRights() {
                if ( is_null( $this->mRights ) ) {
@@ -1861,7 +1874,7 @@ class User {
        /**
         * Get the list of explicit group memberships this user has.
         * The implicit * and user groups are not included.
-        * @return \arrayof{\string}
+        * @return \type{\arrayof{\string}} Array of internal group names
         */
        function getGroups() {
                $this->load();
@@ -1872,8 +1885,9 @@ class User {
         * Get the list of implicit group memberships this user has.
         * This includes all explicit groups, plus 'user' if logged in,
         * '*' for all accounts and autopromoted groups
+        *
         * @param $recache \type{\bool} Whether to avoid the cache
-        * @return \arrayof{\string}
+        * @return \type{\arrayof{\string}} Array of internal group names
         */
        function getEffectiveGroups( $recache = false ) {
                if ( $recache || is_null( $this->mEffectiveGroups ) ) {
@@ -1896,7 +1910,7 @@ class User {
 
        /**
         * Get the user's edit count.
-        * @return \type{\int}
+        * @return \type{\int} User's edit count
         */
        function getEditCount() {
                if ($this->mId) {
@@ -1960,7 +1974,7 @@ class User {
 
        /**
         * Get whether the user is logged in
-        * @return \type{\bool}
+        * @return \type{\bool} True or false
         */
        function isLoggedIn() {
                return $this->getID() != 0;
@@ -1968,7 +1982,7 @@ class User {
 
        /**
         * Get whether the user is anonymous
-        * @return \type{\bool}
+        * @return \type{\bool} True or false
         */
        function isAnon() {
                return !$this->isLoggedIn();
@@ -1976,7 +1990,7 @@ class User {
 
        /**
         * Get whether the user is a bot
-        * @return \type{\bool}
+        * @return \type{\bool} True or false
         * @deprecated
         */
        function isBot() {
@@ -1994,12 +2008,14 @@ class User {
                        // In the spirit of DWIM
                        return true;
 
-               return in_array( $action, $this->getRights() );
+               # Use strict parameter to avoid matching numeric 0 accidentally inserted 
+               # by misconfiguration: 0 == 'foo'
+               return in_array( $action, $this->getRights(), true );
        }
 
        /**
        * Check whether to enable recent changes patrol features for this user
-       * @return \type{\bool}
+       * @return \type{\bool} True or false
        */
        public function useRCPatrol() {
                global $wgUseRCPatrol;
@@ -2008,7 +2024,7 @@ class User {
 
        /**
        * Check whether to enable new pages patrol features for this user
-       * @return \type{\bool}
+       * @return \type{\bool} True or false
        */
        public function useNPPatrol() {
                global $wgUseRCPatrol, $wgUseNPPatrol;
@@ -2017,7 +2033,7 @@ class User {
 
        /**
         * Get the current skin, loading it if required
-        * @return \type{Skin}
+        * @return \type{Skin} Current skin
         * @todo FIXME : need to check the old failback system [AV]
         */
        function &getSkin() {
@@ -2187,46 +2203,12 @@ class User {
        }
        
        /**
-        * Set a cookie on the user's client
-        * @param $name \type{\string} Name of the cookie to set
-        * @param $name \type{\string} Value to set
-        * @param $name \type{\int} Expiration time, as a UNIX time value; 
-        *                   if 0 or not specified, use the default $wgCookieExpiration
+        * Set a cookie on the user's client. Wrapper for 
+        * WebResponse::setCookie
         */
        protected function setCookie( $name, $value, $exp=0 ) {
-               global $wgCookiePrefix,$wgCookieDomain,$wgCookieSecure,$wgCookieExpiration, $wgCookieHttpOnly;
-               if( $exp == 0 ) {
-                       $exp = time() + $wgCookieExpiration;
-               }
-               $httpOnlySafe = wfHttpOnlySafe();
-               wfDebugLog( 'cookie',
-                       'setcookie: "' . implode( '", "',
-                               array(
-                                       $wgCookiePrefix . $name,
-                                       $value,
-                                       $exp,
-                                       '/',
-                                       $wgCookieDomain,
-                                       $wgCookieSecure,
-                                       $httpOnlySafe && $wgCookieHttpOnly ) ) . '"' );
-               if( $httpOnlySafe && isset( $wgCookieHttpOnly ) ) {
-                       setcookie( $wgCookiePrefix . $name,
-                               $value,
-                               $exp,
-                               '/',
-                               $wgCookieDomain,
-                               $wgCookieSecure,
-                               $wgCookieHttpOnly );
-               } else {
-                       // setcookie() fails on PHP 5.1 if you give it future-compat paramters.
-                       // stab stab!
-                       setcookie( $wgCookiePrefix . $name,
-                               $value,
-                               $exp,
-                               '/',
-                               $wgCookieDomain,
-                               $wgCookieSecure );
-               }
+               global $wgRequest;
+               $wgRequest->response()->setcookie( $name, $value, $exp );
        }
        
        /**
@@ -2349,7 +2331,7 @@ class User {
         * Add a user to the database, return the user object
         *
         * @param $name \type{\string} Username to add
-        * @param $params \arrayof{\string} Non-default parameters to save to the database:
+        * @param $params \type{\arrayof{\string}} 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
         *   - email                The user's email address
@@ -2456,10 +2438,10 @@ class User {
         * which will give them a chance to modify this key based on their own
         * settings.
         *
-        * @return \type{\string}
+        * @return \type{\string} Page rendering hash
         */
        function getPageRenderingHash() {
-               global $wgContLang, $wgUseDynamicDates, $wgLang;
+               global $wgUseDynamicDates, $wgRenderHashAppend, $wgLang, $wgContLang;
                if( $this->mHash ){
                        return $this->mHash;
                }
@@ -2479,6 +2461,8 @@ class User {
                $extra = $wgContLang->getExtraHashOptions();
                $confstr .= $extra;
 
+               $confstr .= $wgRenderHashAppend;
+
                // Give a chance for extensions to modify the hash, if they have
                // extra options or other effects on the parser cache.
                wfRunHooks( 'PageRenderingHash', array( &$confstr ) );
@@ -2491,7 +2475,7 @@ class User {
 
        /**
         * Get whether the user is explicitly blocked from account creation.
-        * @return \type{\bool}
+        * @return \type{\bool} True if blocked
         */
        function isBlockedFromCreateAccount() {
                $this->getBlockedStatus();
@@ -2500,7 +2484,7 @@ class User {
 
        /**
         * Get whether the user is blocked from using Special:Emailuser.
-        * @return \type{\bool}
+        * @return \type{\bool} True if blocked
         */
        function isBlockedFromEmailuser() {
                $this->getBlockedStatus();
@@ -2509,7 +2493,7 @@ class User {
 
        /**
         * Get whether the user is allowed to create an account.
-        * @return \type{\bool}
+        * @return \type{\bool} True if allowed
         */
        function isAllowedToCreateAccount() {
                return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount();
@@ -2525,7 +2509,7 @@ class User {
        /**
         * Get this user's personal page title.
         *
-        * @return \type{Title}
+        * @return \type{Title} User's personal page title
         */
        function getUserPage() {
                return Title::makeTitle( NS_USER, $this->getName() );
@@ -2534,7 +2518,7 @@ class User {
        /**
         * Get this user's talk page title.
         *
-        * @return \type{Title}
+        * @return \type{Title} User's talk page title
         */
        function getTalkPage() {
                $title = $this->getUserPage();
@@ -2543,7 +2527,7 @@ class User {
 
        /**
         * Get the maximum valid user ID.
-        * @return \type{\int}
+        * @return \type{\int} %User ID
         * @static
         */
        function getMaxID() {
@@ -2635,7 +2619,7 @@ class User {
        /**
         * Check if the given clear-text password matches the temporary password
         * sent by e-mail for password reset operations.
-        * @return \type{\bool}
+        * @return \type{\bool} True if matches, false otherwise
         */
        function checkTemporaryPassword( $plaintext ) {
                return self::comparePasswords( $this->mNewpassword, $plaintext, $this->getId() );
@@ -2739,7 +2723,7 @@ class User {
         * @param $subject \type{\string} Message subject
         * @param $body \type{\string} Message body
         * @param $from \type{\string} Optional From address; if unspecified, default $wgPasswordSender will be used
-        * @param $replyto \type{\string}
+        * @param $replyto \type{\string} Reply-to address
         * @return \twotypes{\bool,WikiError} True on success, a WikiError object on failure
         */
        function sendMail( $subject, $body, $from = null, $replyto = null ) {
@@ -2761,7 +2745,7 @@ class User {
         * this change to the database.
         *
         * @param[out] &$expiration \type{\mixed} Accepts the expiration time
-        * @return \type{\string}
+        * @return \type{\string} New token
         * @private
         */
        function confirmationToken( &$expiration ) {
@@ -2779,7 +2763,7 @@ class User {
        /**
        * Return a URL the user can use to confirm their email address.
         * @param $token \type{\string} Accepts the email confirmation token
-        * @return \type{\string}
+        * @return \type{\string} New token URL
         * @private
         */
        function confirmationTokenUrl( $token ) {
@@ -2787,8 +2771,9 @@ class User {
        }
        /**
         * Return a URL the user can use to invalidate their email address.
+        *
         * @param $token \type{\string} Accepts the email confirmation token
-        * @return \type{\string}
+        * @return \type{\string} New token URL
         * @private
         */
        function invalidationTokenUrl( $token ) {
@@ -2855,7 +2840,7 @@ class User {
        /**
         * Is this user allowed to send e-mails within limits of current
         * site configuration?
-        * @return \type{\bool}
+        * @return \type{\bool} True if allowed
         */
        function canSendEmail() {
                $canSend = $this->isEmailConfirmed();
@@ -2866,7 +2851,7 @@ class User {
        /**
         * Is this user allowed to receive e-mails within limits of current
         * site configuration?
-        * @return \type{\bool}
+        * @return \type{\bool} True if allowed
         */
        function canReceiveEmail() {
                return $this->isEmailConfirmed() && !$this->getOption( 'disablemail' );
@@ -2880,7 +2865,7 @@ class User {
         * confirmed their address by returning a code or using a password
         * sent to the address from the wiki.
         *
-        * @return \type{\bool}
+        * @return \type{\bool} True if confirmed
         */
        function isEmailConfirmed() {
                global $wgEmailAuthentication;
@@ -2901,7 +2886,7 @@ class User {
 
        /**
         * Check whether there is an outstanding request for e-mail confirmation.
-        * @return \type{\bool}
+        * @return \type{\bool} True if pending
         */
        function isEmailConfirmationPending() {
                global $wgEmailAuthentication;
@@ -2926,8 +2911,8 @@ class User {
        /**
         * Get the permissions associated with a given list of groups
         *
-        * @param $groups \arrayof{\string} List of internal group names
-        * @return \arrayof{\string} List of permission key names for given groups combined
+        * @param $groups \type{\arrayof{\string}} List of internal group names
+        * @return \type{\arrayof{\string}} List of permission key names for given groups combined
         */
        static function getGroupPermissions( $groups ) {
                global $wgGroupPermissions;
@@ -2945,7 +2930,7 @@ class User {
         * Get all the groups who have a given permission
         * 
         * @param $role \type{\string} Role to check
-        * @return \arrayof{\string} List of internal group names with the given permission
+        * @return \type{\arrayof{\string}} List of internal group names with the given permission
         */
        static function getGroupsWithPermission( $role ) {
                global $wgGroupPermissions;
@@ -2962,7 +2947,7 @@ class User {
         * Get the localized descriptive name for a group, if it exists
         *
         * @param $group \type{\string} Internal group name
-        * @return \type{\string}
+        * @return \type{\string} Localized descriptive group name
         */
        static function getGroupName( $group ) {
                global $wgMessageCache;
@@ -2978,7 +2963,7 @@ class User {
         * Get the localized descriptive name for a member of a group, if it exists
         *
         * @param $group \type{\string} Internal group name
-        * @return \type{\string}
+        * @return \type{\string} Localized name for group member
         */
        static function getGroupMember( $group ) {
                global $wgMessageCache;
@@ -2994,7 +2979,7 @@ class User {
         * Return the set of defined explicit groups.
         * The implicit groups (by default *, 'user' and 'autoconfirmed')
         * are not included, as they are defined automatically, not in the database.
-        * @return \arrayof{\string}
+        * @return \type{\arrayof{\string}} Array of internal group names
         */
        static function getAllGroups() {
                global $wgGroupPermissions;
@@ -3006,7 +2991,7 @@ class User {
 
        /**
         * Get a list of all available permissions.
-        * @return \arrayof{\string}
+        * @return \type{\arrayof{\string}} Array of permission names
         */
        static function getAllRights() {
                if ( self::$mAllRights === false ) {
@@ -3023,7 +3008,7 @@ class User {
 
        /**
         * Get a list of implicit groups
-        * @return \arrayof{\string}
+        * @return \type{\arrayof{\string}} Array of internal group names
         */
        public static function getImplicitGroups() {
                global $wgImplicitGroups;
@@ -3141,7 +3126,7 @@ class User {
         * Get the description of a given right
         *
         * @param $right \type{\string} Right to query
-        * @return \type{\string}
+        * @return \type{\string} Localized description of the right
         */
        static function getRightDescription( $right ) {
                global $wgMessageCache;
@@ -3197,7 +3182,7 @@ class User {
         * @param $hash \type{\string} Password hash
         * @param $password \type{\string} Plain-text password to compare
         * @param $userId \type{\string} %User ID for old-style password salt
-        * @return \type{\bool}
+        * @return \type{\bool} True if matches, false otherwise
         */
        static function comparePasswords( $hash, $password, $userId = false ) {
                $m = false;
@@ -3214,4 +3199,41 @@ class User {
                        return self::oldCrypt( $password, $userId ) === $hash;
                }
        }
+       
+       /**
+        * Add a newuser log entry for this user
+        * @param bool $byEmail, account made by email?
+        */
+       public function addNewUserLogEntry( $byEmail = false ) {
+               global $wgUser, $wgContLang, $wgNewUserLog;
+               if( empty($wgNewUserLog) ) {
+                       return true; // disabled
+               }
+               $talk = $wgContLang->getFormattedNsText( NS_TALK );
+               if( $this->getName() == $wgUser->getName() ) {
+                       $action = 'create';
+                       $message = '';
+               } else {
+                       $action = 'create2';
+                       $message = $byEmail ? wfMsgForContent( 'newuserlog-byemail' ) : '';
+               }
+               $log = new LogPage( 'newusers' );
+               $log->addEntry( $action, $this->getUserPage(), $message, array( $this->getId() ) );
+               return true;
+       }
+
+       /**
+        * Add an autocreate newuser log entry for this user
+        * Used by things like CentralAuth and perhaps other authplugins.
+        */
+       public function addNewUserLogEntryAutoCreate() {
+               global $wgNewUserLog;
+               if( empty($wgNewUserLog) ) {
+                       return true; // disabled
+               }
+               $log = new LogPage( 'newusers', false );
+               $log->addEntry( 'autocreate', $this->getUserPage(), '', array( $this->getId() ) );
+               return true;
+       }
+
 }