* (bug 11114) Fix regression in read-only mode error display during editing
[lhc/web/wiklou.git] / includes / Title.php
index d5e9d9f..80f298c 100644 (file)
@@ -279,10 +279,16 @@ class Title {
                $redir = MagicWord::get( 'redirect' );
                if( $redir->matchStart( $text ) ) {
                        // Extract the first link and see if it's usable
+                       $m = array();
                        if( preg_match( '!\[{2}(.*?)(?:\||\]{2})!', $text, $m ) ) {
                                // Strip preceding colon used to "escape" categories, etc.
                                // and URL-decode links
-                               $m[1] = urldecode( ltrim( $m[1], ':' ) );
+                               if( strpos( $m[1], '%' ) !== false ) {
+                                       // Match behavior of inline link parsing here;
+                                       // don't interpret + as " " most of the time!
+                                       // It might be safe to just use rawurldecode instead, though.
+                                       $m[1] = urldecode( ltrim( $m[1], ':' ) );
+                               }
                                $title = Title::newFromText( $m[1] );
                                // Redirects to Special:Userlogout are not permitted
                                if( $title instanceof Title && !$title->isSpecial( 'Userlogout' ) )
@@ -1006,7 +1012,7 @@ class Title {
                }
                return false;
        }
-       
+
        /**
         * Can $wgUser perform $action on this page?
         * @param string $action action that permission needs to be checked for
@@ -1014,42 +1020,124 @@ class Title {
         * @return boolean
         */
        public function userCan( $action, $doExpensiveQueries = true ) {
+               global $wgUser;
+               return ( $this->getUserPermissionsErrorsInternal( $action, $wgUser, $doExpensiveQueries ) === array());
+       }
+
+        /**
+        * Can $user perform $action on this page?
+        * @param string $action action that permission needs to be checked for
+        * @param bool $doExpensiveQueries Set this to false to avoid doing unnecessary queries.
+        * @return array Array of arrays of the arguments to wfMsg to explain permissions problems.
+       */
+       public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true ) {
+               $errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries );
+
+               global $wgContLang;
+               global $wgLang;
+
+               if ( wfReadOnly() && $action != 'read' ) {
+                       global $wgReadOnly;
+                       $errors[] = array( 'readonlytext', $wgReadOnly );
+               }
+
+               global $wgEmailConfirmToEdit, $wgUser;
+
+               if ( $wgEmailConfirmToEdit && !$wgUser->isEmailConfirmed() )
+               {
+                       $errors[] = array( 'confirmedittext' );
+               }
+
+               if ( $user->isBlockedFrom( $this ) ) {
+                       $block = $user->mBlock;
+
+                       // This is from OutputPage::blockedPage
+                       // Copied at r23888 by werdna
+
+                       $id = $user->blockedBy();
+                       $reason = $user->blockedFor();
+                       $ip = wfGetIP();
+
+                       if ( is_numeric( $id ) ) {
+                               $name = User::whoIs( $id );
+                       } else {
+                               $name = $id;
+                       }
+
+                       $link = '[[' . $wgContLang->getNsText( NS_USER ) . ":{$name}|{$name}]]";
+                       $blockid = $block->mId;
+                       $blockExpiry = $user->mBlock->mExpiry;
+                       $blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $wgUser->mBlock->mTimestamp ), true );
+
+                       if ( $blockExpiry == 'infinity' ) {
+                               // Entry in database (table ipblocks) is 'infinity' but 'ipboptions' uses 'infinite' or 'indefinite'
+                               $scBlockExpiryOptions = wfMsg( 'ipboptions' );
+
+                               foreach ( explode( ',', $scBlockExpiryOptions ) as $option ) {
+                                       if ( strpos( $option, ':' ) == false )
+                                               continue;
+
+                                       list ($show, $value) = explode( ":", $option );
+
+                                       if ( $value == 'infinite' || $value == 'indefinite' ) {
+                                               $blockExpiry = $show;
+                                               break;
+                                       }
+                               }
+                       } else {
+                               $blockExpiry = $wgLang->timeanddate( wfTimestamp( TS_MW, $blockExpiry ), true );
+                       }
+
+                       $intended = $user->mBlock->mAddress;
+
+                       $errors[] = array ( ($block->mAuto ? 'autoblockedtext' : 'blockedtext'), $link, $reason, $ip, $name, $blockid, $blockExpiry, $intended, $blockTimestamp );
+               }
+
+               return $errors;
+       }
+
+       /**
+        * Can $user perform $action on this page?
+        * This is an internal function, which checks ONLY that previously checked by userCan (i.e. it leaves out checks on wfReadOnly() and blocks)
+        * @param string $action action that permission needs to be checked for
+        * @param bool $doExpensiveQueries Set this to false to avoid doing unnecessary queries.
+        * @return array Array of arrays of the arguments to wfMsg to explain permissions problems.
+        */
+       private function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true ) {
                $fname = 'Title::userCan';
                wfProfileIn( $fname );
 
-               global $wgUser;
+               $errors = array();
 
-               $result = null;
-               wfRunHooks( 'userCan', array( &$this, &$wgUser, $action, &$result ) );
-               if ( $result !== null ) {
-                       wfProfileOut( $fname );
-                       return $result;
+               if ( !wfRunHooks( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
+                       return $result ? array() : array( array( 'badaccess-group0' ) );
                }
 
                if( NS_SPECIAL == $this->mNamespace ) {
-                       wfProfileOut( $fname );
-                       return false;
+                       $errors[] = array('ns-specialprotected');
                }
                
                if ( $this->isNamespaceProtected() ) {
-                       wfProfileOut( $fname );
-                       return false;
+                       $ns = $this->getNamespace() == NS_MAIN
+                               ? wfMsg( 'nstab-main' )
+                               : $this->getNsText();
+                       $errors[] = (NS_MEDIAWIKI == $this->mNamespace 
+                               ? array('protectedinterface') 
+                               : array( 'namespaceprotected',  $ns ) );
                }
 
                if( $this->mDbkeyform == '_' ) {
                        # FIXME: Is this necessary? Shouldn't be allowed anyway...
-                       wfProfileOut( $fname );
-                       return false;
+                       $errors[] = array('badaccess-group0');
                }
 
                # protect css/js subpages of user pages
                # XXX: this might be better using restrictions
                # XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working
                if( $this->isCssJsSubpage()
-                       && !$wgUser->isAllowed('editinterface')
-                       && !preg_match('/^'.preg_quote($wgUser->getName(), '/').'\//', $this->mTextform) ) {
-                       wfProfileOut( $fname );
-                       return false;
+                       && !$user->isAllowed('editinterface')
+                       && !preg_match('/^'.preg_quote($user->getName(), '/').'\//', $this->mTextform) ) {
+                       $errors[] = array('customcssjsprotected');
                }
                
                if ( $doExpensiveQueries && !$this->isCssJsSubpage() ) {
@@ -1065,9 +1153,11 @@ class Title {
                        if( $cascadingSources > 0 && isset($restrictions[$action]) ) {
                                foreach( $restrictions[$action] as $right ) {
                                        $right = ( $right == 'sysop' ) ? 'protect' : $right;
-                                       if( '' != $right && !$wgUser->isAllowed( $right ) ) {
-                                               wfProfileOut( $fname );
-                                               return false;
+                                       if( '' != $right && !$user->isAllowed( $right ) ) {
+                                               $pages = '';
+                                               foreach( $cascadingSources as $page )
+                                                       $pages .= '* [[:' . $page->getPrefixedText() . "]]\n";
+                                               $errors[] = array( 'cascadeprotected', count( $cascadingSources ), $pages );
                                        }
                                }
                        }
@@ -1078,33 +1168,51 @@ class Title {
                        if ( $right == 'sysop' ) {
                                $right = 'protect';
                        }
-                       if( '' != $right && !$wgUser->isAllowed( $right ) ) {
-                               wfProfileOut( $fname );
-                               return false;
+                       if( '' != $right && !$user->isAllowed( $right ) ) {
+                               $errors[] = array( 'protectedpagetext' );
                        }
                }
 
-               if( $action == 'move' &&
-                       !( $this->isMovable() && $wgUser->isAllowed( 'move' ) ) ) {
-                       wfProfileOut( $fname );
-                       return false;
-               }
-
                if( $action == 'create' ) {
-                       if( (  $this->isTalkPage() && !$wgUser->isAllowed( 'createtalk' ) ) ||
-                               ( !$this->isTalkPage() && !$wgUser->isAllowed( 'createpage' ) ) ) {
-                               wfProfileOut( $fname );
-                               return false;
+                       if( (  $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) ||
+                               ( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) ) ) {
+                               $errors[] = $user->isAnon() ? array ('nocreatetext') : array ('nocreate-loggedin');
                        }
-               }
-
-               if( $action == 'edit' && !$wgUser->isAllowed( 'edit' ) ) {
-                       wfProfileOut( $fname );
-                       return false;
+               } elseif( $action == 'move' &&
+                       !( $this->isMovable() && $user->isAllowed( 'move' ) ) ) {
+                       $errors[] = $user->isAnon() ? array ( 'movenologintext' ) : array ('movenotallowed');
+                } else if ( !$user->isAllowed( $action ) ) {
+                       $return = null;
+                       $groups = array();
+                       global $wgGroupPermissions;
+                       foreach( $wgGroupPermissions as $key => $value ) {
+                           if( isset( $value[$action] ) && $value[$action] == true ) {
+                               $groupName = User::getGroupName( $key );
+                               $groupPage = User::getGroupPage( $key );
+                               if( $groupPage ) {
+                                   $skin = $user->getSkin();
+                                   $groups[] = $skin->makeLinkObj( $groupPage, $groupName );
+                               } else {
+                                   $groups[] = $groupName;
+                               }
+                           }
+                       }
+                       $n = count( $groups );
+                       $groups = implode( ', ', $groups );
+                       switch( $n ) {
+                           case 0:
+                           case 1:
+                           case 2:
+                               $return = array( "badaccess-group$n", $groups );
+                               break;
+                           default:
+                               $return = array( 'badaccess-groups', $groups );
+                       }
+                       $errors[] = $return;
                }
 
                wfProfileOut( $fname );
-               return true;
+               return $errors;
        }
 
        /**
@@ -1194,7 +1302,7 @@ class Title {
                         */
                        if( $this->getNamespace() == NS_SPECIAL ) {
                                $name = $this->getText();
-                               list( $name, $subpage ) = SpecialPage::resolveAliasWithSubpage( $name );
+                               list( $name, /* $subpage */) = SpecialPage::resolveAliasWithSubpage( $name );
                                $pure = SpecialPage::getTitleFor( $name )->getPrefixedText();
                                if( in_array( $pure, $wgWhitelistRead, true ) )
                                        return true;
@@ -1296,7 +1404,7 @@ class Title {
         * @return bool If the page is subject to cascading restrictions.
         */
        public function isCascadeProtected() {
-               list( $sources, $restrictions ) = $this->getCascadeProtectionSources( false );
+               list( $sources, /* $restrictions */ ) = $this->getCascadeProtectionSources( false );
                return ( $sources > 0 );
        }