Revert broken rewrite of login system; totally broken.
authorBrion Vibber <brion@users.mediawiki.org>
Sat, 26 Sep 2009 00:49:32 +0000 (00:49 +0000)
committerBrion Vibber <brion@users.mediawiki.org>
Sat, 26 Sep 2009 00:49:32 +0000 (00:49 +0000)
* Login doesn't attach to session properly, so can't stay logged in!
* Password field shown in plaintext!

If it just DOESN'T WORK please keep it on a work branch, don't put it in trunk!

Reverted:
r56682
r56683
r56684
r56686
r56688
r56696
r56699
r56702
r56703
r56704
r56782
r56896

19 files changed:
RELEASE-NOTES
docs/hooks.txt
includes/AuthPlugin.php
includes/AutoLoader.php
includes/ExternalUser.php
includes/HTMLForm.php
includes/Login.php [deleted file]
includes/SpecialPage.php
includes/api/ApiLogin.php
includes/parser/Parser.php
includes/specials/SpecialCreateAccount.php [deleted file]
includes/specials/SpecialResetpass.php
includes/specials/SpecialUserlogin.php
includes/templates/Userlogin.php [new file with mode: 0644]
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messages.inc
skins/common/shared.css
skins/monobook/main.css

index 5acf13d..f2935ec 100644 (file)
@@ -87,11 +87,6 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
   correctly (img_auth only)
 * $wgUploadMaintenance added to disable file deletions and restorations during
   maintenance
-* UserLoginForm and UserCreateForm hooks, and AuthPlugin::modifyUITemplate, now receive a
-  SpecialPage subclass instead of a QuickTemplate subclass.  Hence there is no
-  $template->set(), etc.  The hook has access to most of the stuff that will go into the
-  Login/Create form; see the documentation on HTMLForm for syntax for extra fields.
-  LoginForm class is deprecated, its state constants are now in the Login class.
 * New hook AbortNewAccountAuto, called before account creation from AuthPlugin-
   or ExtUser-driven requests.
 
@@ -240,7 +235,6 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * A new permission, 'root', is created.  Analogous to root users on Unix systems,
   the root permission effectively grants all other permissions on a wiki.  Useful
   for debugging and administration.
-* (bug 16979) Tracking categories for __INDEX__ and __NOINDEX__
 * New configuration variable $wgShowPageOnRedlink that can be set to show the page
   instead of an edit interface when visiting a red link. The value can be specified
   for specific usergroups and namespaces.
index 4bfa457..0ed4b0f 100644 (file)
@@ -244,8 +244,8 @@ $block: The block from which the autoblock is coming.
 'AbortLogin': Return false to cancel account login.
 $user: the User object being authenticated against
 $password: the password being submitted, not yet checked for validity
-&$retval: a Login class constant to return from authenticateUserData();
-          default is Login::ABORTED. Note that the client may be using
+&$retval: a LoginForm class constant to return from authenticateUserData();
+          default is LoginForm::ABORTED. Note that the client may be using
           a machine API rather than the HTML user interface.
 
 'AbortMove': allows to abort moving an article (title)
@@ -950,7 +950,7 @@ $code: language code
 succeeded or failed. No return data is accepted; this hook is for auditing only.
 $user: the User object being authenticated against
 $password: the password being submitted and found wanting
-$retval: a Login class constant with authenticateUserData() return
+$retval: a LoginForm class constant with authenticateUserData() return
        value (SUCCESS, WRONG_PASS, etc)
 
 'LogLine': Processes a single log entry on Special:Log
@@ -1532,7 +1532,7 @@ override the default password checks
        determine if the password was valid
 
 'UserCreateForm': change to manipulate the login form
-$sp: SpecialCreateAccount instance
+$template: SimpleTemplate instance for the form
 
 'UserCryptPassword': called when hashing a password, return false to implement
 your own hashing method
@@ -1602,7 +1602,7 @@ $user: the user object that was created on login
 $inject_html: Any HTML to inject after the "logged in" message.
 
 'UserLoginForm': change to manipulate the login form
-$sp: SpecialCreateAccount instance
+$template: SimpleTemplate instance for the form
 
 'UserLoginMailPassword': Block users from emailing passwords
 $name: the username to email the password of.
index 97cb11f..eacabd4 100644 (file)
@@ -62,13 +62,12 @@ class AuthPlugin {
        /**
         * Modify options in the login template.
         *
-        * @param $sp SpecialUserlogin or SpecialCreateAccount object.
-        * @param $type String 'signup' or 'login'. Redundant because
-        *    you can just use instanceof to tell the two cases apart.
+        * @param $template UserLoginTemplate object.
+        * @param $type String 'signup' or 'login'.
         */
-       public function modifyUITemplate( &$sp, $type=null ) {
+       public function modifyUITemplate( &$template, &$type ) {
                # Override this!
-               $sp->mDomains = false;
+               $template->set( 'usedomain', false );
        }
 
        /**
index 3f4ecf4..7b7303d 100644 (file)
@@ -134,8 +134,6 @@ $wgAutoloadLocalClasses = array(
        'LinksUpdate' => 'includes/LinksUpdate.php',
        'LocalisationCache' => 'includes/LocalisationCache.php',
        'LocalisationCache_BulkLoad' => 'includes/LocalisationCache.php',
-       'LoginForm' => 'includes/Login.php', # For B/C
-       'Login' => 'includes/Login.php',
        'LogPage' => 'includes/LogPage.php',
        'LogPager' => 'includes/LogEventsList.php',
        'LogEventsList' => 'includes/LogEventsList.php',
@@ -495,7 +493,6 @@ $wgAutoloadLocalClasses = array(
        'AncientPagesPage' => 'includes/specials/SpecialAncientpages.php',
        'BrokenRedirectsPage' => 'includes/specials/SpecialBrokenRedirects.php',
        'ContribsPager' => 'includes/specials/SpecialContributions.php',
-       'SpecialCreateAccount' => 'includes/specials/SpecialCreateAccount.php',
        'DBLockForm' => 'includes/specials/SpecialLockdb.php',
        'DBUnlockForm' => 'includes/specials/SpecialUnlockdb.php',
        'DeadendPagesPage' => 'includes/specials/SpecialDeadendpages.php',
@@ -516,6 +513,7 @@ $wgAutoloadLocalClasses = array(
        'ImportStringSource' => 'includes/Import.php',
        'LinkSearchPage' => 'includes/specials/SpecialLinkSearch.php',
        'ListredirectsPage' => 'includes/specials/SpecialListredirects.php',
+       'LoginForm' => 'includes/specials/SpecialUserlogin.php',
        'LonelyPagesPage' => 'includes/specials/SpecialLonelypages.php',
        'LongPagesPage' => 'includes/specials/SpecialLongpages.php',
        'MIMEsearchPage' => 'includes/specials/SpecialMIMEsearch.php',
@@ -564,7 +562,6 @@ $wgAutoloadLocalClasses = array(
        'UnwatchedpagesPage' => 'includes/specials/SpecialUnwatchedpages.php',
        'UploadForm' => 'includes/specials/SpecialUpload.php',
        'UploadFormMogile' => 'includes/specials/SpecialUploadMogile.php',
-       'SpecialUserLogin' => 'includes/specials/SpecialUserlogin.php',
        'UserrightsPage' => 'includes/specials/SpecialUserrights.php',
        'UsersPager' => 'includes/specials/SpecialListusers.php',
        'WantedCategoriesPage' => 'includes/specials/SpecialWantedcategories.php',
index 334ec17..a5f9322 100644 (file)
@@ -285,22 +285,4 @@ abstract class ExternalUser {
                               'eu_external_id' => $this->getId() ),
                    __METHOD__ );
        }
-       
-       /**
-        * Check whether this external user id is already linked with
-        * a local user.
-        * @return Mixed User if the account is linked, Null otherwise.
-        */
-       public final function getLocalUser(){
-               $dbr = wfGetDb( DB_SLAVE );
-               $row = $dbr->selectRow(
-                       'external_user',
-                       '*',
-                       array( 'eu_external_id' => $this->getId() )
-               );
-               return $row
-                       ? User::newFromId( $row->eu_wiki_id )
-                       : null;
-       }
-       
 }
index 50683a4..ca5121e 100644 (file)
@@ -1,54 +1,16 @@
 <?php
 
-/**
- * Object handling generic submission, CSRF protection, layout and 
- * other logic for UI forms. in a reusable manner. 
- *
- * In order to generate the form, the HTMLForm object takes an array 
- * structure detailing the form fields available. Each element of the 
- * array is a basic property-list, including the type of field, the 
- * label it is to be given in the form, callbacks for validation and
- * 'filtering', and other pertinent information. 
- *
- * Field types are implemented as subclasses of the generic HTMLFormField
- * object, and typically implement at least getInputHTML, which generates 
- * the HTML for the input field to be placed in the table.
- * 
- * The constructor input is an associative array of $fieldname => $info,
- * where $info is an Associative Array with any of the following:
- * 
- *     'class'    -- the subclass of HTMLFormField that will be used
- *                   to create the object.  *NOT* the CSS class!
- *     'type'     -- roughly translates into the <select> type attribute.
- *                   if 'class' is not specified, this is used as a map
- *                   through HTMLForm::$typeMappings to get the class name.
- *     'default'  -- default value when the form is displayed
- *     'id'       -- HTML id attribute
- *     'options'  -- varies according to the specific object.
- *     'label-message' -- message key for a message to use as the label.
- *                   can be an array of msg key and then parameters to 
- *                   the message.
- *     'label'    -- alternatively, a raw text message. Overridden by
- *                   label-message
- *     'help-message'  -- message key for a message to use as a help text.
- *                   can be an array of msg key and then parameters to 
- *                   the message.
- *     'required' -- passed through to the object, indicating that it
- *                   is a required field.
- *     'size'     -- the length of text fields
- *     'filter-callback -- a function name to give you the chance to 
- *                   massage the inputted value before it's processed.
- *                   @see HTMLForm::filter()
- *     'validation-callback' -- a function name to give you the chance
- *                   to impose extra validation on the field input.
- *                   @see HTMLForm::validate()
- *                   
- * TODO: Document 'section' / 'subsection' stuff
- */
 class HTMLForm {
        static $jsAdded = false;
 
-       # A mapping of 'type' inputs onto standard HTMLFormField subclasses
+       /* The descriptor is an array of arrays.
+               i.e. array(
+                       'fieldname' => array( 'section' => 'section/subsection',
+                                                               properties... ),
+                       ...
+               )
+        */
+
        static $typeMappings = array(
                'text' => 'HTMLTextField',
                'select' => 'HTMLSelectField',
@@ -60,44 +22,14 @@ class HTMLForm {
                'float' => 'HTMLFloatField',
                'info' => 'HTMLInfoField',
                'selectorother' => 'HTMLSelectOrOtherField',
-               'submit' => 'HTMLSubmitField',
-               'hidden' => 'HTMLHiddenField',
-       
                # HTMLTextField will output the correct type="" attribute automagically.
                # There are about four zillion other HTML 5 input types, like url, but
                # we don't use those at the moment, so no point in adding all of them.
                'email' => 'HTMLTextField',
                'password' => 'HTMLTextField',
        );
-       
-       protected $mMessagePrefix;
-       protected $mFlatFields;
-       protected $mFieldTree;
-       protected $mShowReset = false;
-       public $mFieldData;
-       
-       protected $mSubmitCallback;
-       protected $mValidationErrorMessage;
-       
-       protected $mPre = '';
-       protected $mHeader = '';
-       protected $mPost = '';
-       
-       protected $mSubmitID;
-       protected $mSubmitText;
-       protected $mTitle;
-       
-       protected $mHiddenFields = array();
-       protected $mButtons = array();
-       
-       protected $mWrapperLegend = false;
 
-       /**
-        * Build a new HTMLForm from an array of field attributes
-        * @param $descriptor Array of Field constructs, as described above
-        * @param $messagePrefix String a prefix to go in front of default messages
-        */
-       public function __construct( $descriptor, $messagePrefix='' ) {
+       function __construct( $descriptor, $messagePrefix ) {
                $this->mMessagePrefix = $messagePrefix;
 
                // Expand out into a tree.
@@ -111,7 +43,7 @@ class HTMLForm {
 
                        $info['name'] = $fieldname;
 
-                       $field = self::loadInputFromParameters( $info );
+                       $field = $this->loadInputFromParameters( $info );
                        $field->mParent = $this;
 
                        $setSection =& $loadedDescriptor;
@@ -134,12 +66,10 @@ class HTMLForm {
                }
 
                $this->mFieldTree = $loadedDescriptor;
+
+               $this->mShowReset = true;
        }
 
-       /**
-        * Add the HTMLForm-specific JavaScript, if it hasn't been 
-        * done already.
-        */
        static function addJS() {
                if( self::$jsAdded ) return;
 
@@ -148,11 +78,6 @@ class HTMLForm {
                $wgOut->addScriptClass( 'htmlform' );
        }
 
-       /**
-        * Initialise a new Object for the field
-        * @param $descriptor input Descriptor, as described above
-        * @return HTMLFormField subclass
-        */
        static function loadInputFromParameters( $descriptor ) {
                if ( isset( $descriptor['class'] ) ) {
                        $class = $descriptor['class'];
@@ -170,21 +95,15 @@ class HTMLForm {
                return $obj;
        }
 
-       /**
-        * The here's-one-I-made-earlier option: do the submission if 
-        * posted, or display the form with or without funky valiation 
-        * errors
-        * @return Bool whether submission was successful.
-        */
        function show() {
                $html = '';
 
                self::addJS();
 
-               # Load data from the request.
+               // Load data from the request.
                $this->loadData();
 
-               # Try a submission
+               // Try a submission
                global $wgUser, $wgRequest;
                $editToken = $wgRequest->getVal( 'wpEditToken' );
 
@@ -195,31 +114,23 @@ class HTMLForm {
                if( $result === true )
                        return $result;
 
-               # Display form.
+               // Display form.
                $this->displayForm( $result );
-               return false;
        }
 
-       /**
-        * Validate all the fields, and call the submision callback
-        * function if everything is kosher.
-        * @return Mixed Bool true == Successful submission, Bool false
-        *     == No submission attempted, anything else == Error to 
-        *     display.
-        */
+       /** Return values:
+         * TRUE == Successful submission
+         * FALSE == No submission attempted
+         * Anything else == Error to display.
+         */
        function trySubmit() {
-               # Check for validation
+               // Check for validation
                foreach( $this->mFlatFields as $fieldname => $field ) {
-                       if ( !empty( $field->mParams['nodata'] ) )
-                               continue;
-                       if ( $field->validate( 
-                                       $this->mFieldData[$fieldname],
-                                       $this->mFieldData ) 
-                               !== true )
-                       {
-                               return isset( $this->mValidationErrorMessage )
-                                       ? $this->mValidationErrorMessage
-                                       : array( 'htmlform-invalid-input' );
+                       if ( !empty( $field->mParams['nodata'] ) ) continue;
+                       if ( $field->validate( $this->mFieldData[$fieldname],
+                                       $this->mFieldData ) !== true ) {
+                               return isset( $this->mValidationErrorMessage ) ?
+                                               $this->mValidationErrorMessage : array( 'htmlform-invalid-input' );
                        }
                }
 
@@ -232,69 +143,18 @@ class HTMLForm {
                return $res;
        }
 
-       /**
-        * Set a callback to a function to do something with the form
-        * once it's been successfully validated.
-        * @param $cb String function name.  The function will be passed
-        *     the output from HTMLForm::filterDataForSubmit, and must
-        *     return Bool true on success, Bool false if no submission
-        *     was attempted, or String HTML output to display on error.
-        */
        function setSubmitCallback( $cb ) {
                $this->mSubmitCallback = $cb;
        }
 
-       /**
-        * Set a message to display on a validation error.  
-        * @param $msg Mixed String or Array of valid inputs to wfMsgExt()
-        *     (so each entry can be either a String or Array)
-        */
        function setValidationErrorMessage( $msg ) {
                $this->mValidationErrorMessage = $msg;
        }
-       
-       /**
-        * Set the introductory message, overwriting any existing message.
-        * @param $msg String complete text of message to display
-        */
-       function setIntro( $msg ) { $this->mPre = $msg; }
 
-       /**
-        * Add introductory text.
-        * @param $msg String complete text of message to display
-        */
-       function addPreText( $msg ) { $this->mPre .= $msg; }
-       
-       /**
-        * Add header text, inside the form.
-        * @param $msg String complete text of message to display
-        */
-       function addHeaderText( $msg ) { $this->mHeader .= $msg; }
-       
-       /**
-        * Add text to the end of the display.
-        * @param $msg String complete text of message to display
-        */
-       function addPostText( $msg ) { $this->mPost .= $msg; }
-       
-       /**
-        * Add a hidden field to the output
-        * @param $name String field name
-        * @param $value String field value
-        */
-       public function addHiddenField( $name, $value ){
-               $this->mHiddenFields[ $name ] = $value;
-       }
-       
-       public function addButton( $name, $value, $id=null ){
-               $this->mButtons[] = compact( 'name', 'value', 'id' );
+       function setIntro( $msg ) {
+               $this->mIntro = $msg;
        }
 
-       /**
-        * Display the form (sending to wgOut), with an appropriate error 
-        * message or stack of messages, and any validation errors, etc.
-        * @param $submitResult Mixed output from HTMLForm::trySubmit()
-        */
        function displayForm( $submitResult ) {
                global $wgOut;
 
@@ -302,67 +162,44 @@ class HTMLForm {
                        $this->displayErrors( $submitResult );
                }
 
-               $html = ''
-                       . $this->mHeader
-                       . $this->getBody()
-                       . $this->getHiddenFields()
-                       . $this->getButtons()
-               ;
+               if ( isset( $this->mIntro ) ) {
+                       $wgOut->addHTML( $this->mIntro );
+               }
+
+               $html = $this->getBody();
+
+               // Hidden fields
+               $html .= $this->getHiddenFields();
+
+               // Buttons
+               $html .= $this->getButtons();
 
                $html = $this->wrapForm( $html );
 
-               $wgOut->addHTML( ''
-                       . $this->mPre
-                       . $html
-                       . $this->mPost
-               );
+               $wgOut->addHTML( $html );
        }
 
-       /**
-        * Wrap the form innards in an actual <form> element
-        * @param $html String HTML contents to wrap.
-        * @return String wrapped HTML.
-        */
        function wrapForm( $html ) {
-               
-               # Include a <fieldset> wrapper for style, if requested.
-               if( $this->mWrapperLegend !== false ){
-                       $html = Xml::fieldset( $this->mWrapperLegend, $html );
-               }
-               
                return Html::rawElement(
                        'form',
                        array(
                                'action' => $this->getTitle()->getFullURL(),
                                'method' => 'post',
-                               'class'  => 'visualClear',
                        ),
                        $html
                );
        }
 
-       /**
-        * Get the hidden fields that should go inside the form.
-        * @return String HTML.
-        */
        function getHiddenFields() {
                global $wgUser;
                $html = '';
 
                $html .= Html::hidden( 'wpEditToken', $wgUser->editToken() ) . "\n";
                $html .= Html::hidden( 'title', $this->getTitle() ) . "\n";
-               
-               foreach( $this->mHiddenFields as $name => $value ){
-                       $html .= Html::hidden( $name, $value ) . "\n";
-               }
 
                return $html;
        }
 
-       /**
-        * Get the submit and (potentially) reset buttons.
-        * @return String HTML.
-        */
        function getButtons() {
                $html = '';
 
@@ -385,31 +222,13 @@ class HTMLForm {
                        ) . "\n";
                }
                
-               foreach( $this->mButtons as $button ){
-                       $attrs = array(
-                               'type'  => 'submit',
-                               'name'  => $button['name'],
-                               'value' => $button['value']
-                       );
-                       if( isset( $button['id'] ) )
-                               $attrs['id'] = $button['id'];
-                       $html .= Html::element( 'input', $attrs );
-               }
-               
                return $html;
        }
 
-       /**
-        * Get the whole body of the form.
-        */
        function getBody() {
                return $this->displaySection( $this->mFieldTree );
        }
 
-       /**
-        * Format and display an error message stack.
-        * @param $errors Mixed String or Array of message keys
-        */
        function displayErrors( $errors ) {
                if ( is_array( $errors ) ) {
                        $errorstr = $this->formatErrors( $errors );
@@ -423,11 +242,6 @@ class HTMLForm {
                $wgOut->addHTML( $errorstr );
        }
 
-       /**
-        * Format a stack of error messages into a single HTML string
-        * @param $errors Array of message keys/values
-        * @return String HTML, a <ul> list of errors
-        */
        static function formatErrors( $errors ) {
                $errorstr = '';
                foreach ( $errors as $error ) {
@@ -449,70 +263,30 @@ class HTMLForm {
                return $errorstr;
        }
 
-       /**
-        * Set the text for the submit button
-        * @param $t String plaintext.
-        */
        function setSubmitText( $t ) {
                $this->mSubmitText = $t;
        }
 
-       /**
-        * Get the text for the submit button, either customised or a default.
-        * @return unknown_type
-        */
        function getSubmitText() {
-               return $this->mSubmitText
-                       ? $this->mSubmitText 
-                       : wfMsg( 'htmlform-submit' );
+               return isset( $this->mSubmitText ) ? $this->mSubmitText : wfMsg( 'htmlform-submit' );
        }
 
-       /**
-        * Set the id for the submit button. 
-        * @param $t String.  FIXME: Integrity is *not* validated
-        */
        function setSubmitID( $t ) {
                $this->mSubmitID = $t;
        }
-       
-       /**
-        * Prompt the whole form to be wrapped in a <fieldset>, with
-        * this text as its <legend> element.
-        * @param $legend String HTML to go inside the <legend> element.
-        *     Will be escaped
-        */
-       public function setWrapperLegend( $legend ){ $this->mWrapperLegend = $legend; }
 
-       /**
-        * Set the prefix for various default messages
-        * TODO: currently only used for the <fieldset> legend on forms 
-        * with multiple sections; should be used elsewhre?
-        * @param $p String
-        */
        function setMessagePrefix( $p ) {
                $this->mMessagePrefix = $p;
        }
 
-       /**
-        * Set the title for form submission
-        * @param $t Title of page the form is on/should be posted to
-        */
        function setTitle( $t ) {
                $this->mTitle = $t;
        }
 
-       /**
-        * Get the title
-        * @return Title
-        */
        function getTitle() {
                return $this->mTitle;
        }
 
-       /**
-        * TODO: Document
-        * @param $fields
-        */
        function displaySection( $fields ) {
                $tableHtml = '';
                $subsectionHtml = '';
@@ -521,8 +295,8 @@ class HTMLForm {
                foreach( $fields as $key => $value ) {
                        if ( is_object( $value ) ) {
                                $v = empty( $value->mParams['nodata'] )
-                                       ? $this->mFieldData[$key]
-                                       : $value->getDefault();
+                                                       ? $this->mFieldData[$key]
+                                                       : $value->getDefault();
                                $tableHtml .= $value->getTableRow( $v );
 
                                if( $value->getLabel() != '&nbsp;' )
@@ -545,9 +319,6 @@ class HTMLForm {
                return $subsectionHtml . "\n" . $tableHtml;
        }
 
-       /**
-        * Construct the form fields from the Descriptor array
-        */
        function loadData() {
                global $wgRequest;
 
@@ -562,7 +333,7 @@ class HTMLForm {
                        }
                }
 
-               # Filter data.
+               // Filter data.
                foreach( $fieldData as $name => &$value ) {
                        $field = $this->mFlatFields[$name];
                        $value = $field->filter( $value, $this->mFlatFields );
@@ -571,60 +342,33 @@ class HTMLForm {
                $this->mFieldData = $fieldData;
        }
 
-       /**
-        * Stop a reset button being shown for this form
-        * @param $suppressReset Bool set to false to re-enable the 
-        *     button again
-        */
+       function importData( $fieldData ) {
+               // Filter data.
+               foreach( $fieldData as $name => &$value ) {
+                       $field = $this->mFlatFields[$name];
+                       $value = $field->filter( $value, $this->mFlatFields );
+               }
+
+               foreach( $this->mFlatFields as $fieldname => $field ) {
+                       if ( !isset( $fieldData[$fieldname] ) )
+                               $fieldData[$fieldname] = $field->getDefault();
+               }
+
+               $this->mFieldData = $fieldData;
+       }
+
        function suppressReset( $suppressReset = true ) {
                $this->mShowReset = !$suppressReset;
        }
 
-       /**
-        * Overload this if you want to apply special filtration routines
-        * to the form as a whole, after it's submitted but before it's 
-        * processed.
-        * @param $data 
-        * @return unknown_type
-        */
        function filterDataForSubmit( $data ) {
                return $data;
        }
 }
 
-/**
- * The parent class to generate form fields.  Any field type should 
- * be a subclass of this.
- */
 abstract class HTMLFormField {
-       
-       protected $mValidationCallback;
-       protected $mFilterCallback;
-       protected $mName;
-       public $mParams;
-       protected $mLabel;    # String label.  Set on construction
-       protected $mID;
-       protected $mDefault;
-       public $mParent;
-       
-       /**
-        * This function must be implemented to return the HTML to generate
-        * the input object itself.  It should not implement the surrounding
-        * table cells/rows, or labels/help messages.
-        * @param $value String the value to set the input to; eg a default
-        *     text for a text input. 
-        * @return String valid HTML.
-        */
        abstract function getInputHTML( $value );
 
-       /**
-        * Override this function to add specific validation checks on the 
-        * field input.  Don't forget to call parent::validate() to ensure
-        * that the user-defined callback mValidationCallback is still run
-        * @param $value String the value the field was submitted with
-        * @param $alldata $all the data collected from the form
-        * @return Mixed Bool true on success, or String error to display.
-        */
        function validate( $value, $alldata ) {
                if ( isset( $this->mValidationCallback ) ) {
                        return call_user_func( $this->mValidationCallback, $value, $alldata );
@@ -651,12 +395,6 @@ abstract class HTMLFormField {
                return true;
        }
 
-       /**
-        * Get the value that this input has been set to from a posted form,
-        * or the input's default value if it has not been set.
-        * @param $request WebRequest
-        * @return String the value
-        */
        function loadDataFromRequest( $request ) {
                if( $request->getCheck( $this->mName ) ) {
                        return $request->getText( $this->mName );
@@ -665,14 +403,9 @@ abstract class HTMLFormField {
                }
        }
 
-       /**
-        * Initialise the object
-        * @param $params Associative Array. See HTMLForm doc for syntax.
-        */
        function __construct( $params ) {
                $this->mParams = $params;
 
-               # Generate the label from a message, if possible
                if( isset( $params['label-message'] ) ) {
                        $msgInfo = $params['label-message'];
 
@@ -720,14 +453,8 @@ abstract class HTMLFormField {
                }
        }
 
-       /**
-        * Get the complete table row for the input, including help text,
-        * labels, and whatever.
-        * @param $value String the value to set the input to.
-        * @return String complete HTML table row.
-        */
        function getTableRow( $value ) {
-               # Check for invalid data.
+               // Check for invalid data.
                global $wgRequest;
 
                $errors = $this->validate( $value, $this->mParent->mFieldData );
@@ -790,14 +517,7 @@ abstract class HTMLFormField {
                }
        }
 
-       /**
-        * flatten an array of options to a single array, for instance,
-        * a set of <options> inside <optgroups>.  
-        * @param $options Associative Array with values either Strings
-        *     or Arrays
-        * @return Array flattened input
-        */
-       public static function flattenOptions( $options ) {
+       static function flattenOptions( $options ) {
                $flatOpts = array();
 
                foreach( $options as $key => $value ) {
@@ -813,11 +533,11 @@ abstract class HTMLFormField {
 }
 
 class HTMLTextField extends HTMLFormField {
+       # Override in derived classes to use other Xml::... functions
+       protected $mFunction = 'input';
        
        function getSize() {
-               return isset( $this->mParams['size'] ) 
-                       ? $this->mParams['size'] 
-                       : 45;
+               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
        }
 
        function getInputHTML( $value ) {
@@ -852,25 +572,21 @@ class HTMLTextField extends HTMLFormField {
                                        $attribs[$param] = '';
                                }
                        }
-                       
-                       # Implement tiny differences between some field variants
-                       # here, rather than creating a new class for each one which
-                       # is essentially just a clone of this one.
                        if ( isset( $this->mParams['type'] ) ) {
                                switch ( $this->mParams['type'] ) {
-                                       case 'email':
-                                               $attribs['type'] = 'email';
-                                               break;
-                                       case 'int':
-                                               $attribs['type'] = 'number';
-                                               break;
-                                       case 'float':
-                                               $attribs['type'] = 'number';
-                                               $attribs['step'] = 'any';
-                                               break;
-                                       case 'password':
-                                               $attribs['type'] = 'password';
-                                               break;
+                               case 'email':
+                                       $attribs['type'] = 'email';
+                                       break;
+                               case 'int':
+                                       $attribs['type'] = 'number';
+                                       break;
+                               case 'float':
+                                       $attribs['type'] = 'number';
+                                       $attribs['step'] = 'any';
+                                       break;
+                               case 'password':
+                                       $attribs['type'] = 'password';
+                                       break;
                                }
                        }
                }
@@ -879,15 +595,9 @@ class HTMLTextField extends HTMLFormField {
        }
 }
 
-/**
- * A field that will contain a numeric value
- */
 class HTMLFloatField extends HTMLTextField {
-       
        function getSize() {
-               return isset( $this->mParams['size'] ) 
-                       ? $this->mParams['size'] 
-                       : 20;
+               return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 20;
        }
 
        function validate( $value, $alldata ) {
@@ -901,8 +611,8 @@ class HTMLFloatField extends HTMLTextField {
 
                $in_range = true;
 
-               # The "int" part of these message names is rather confusing. 
-               # They make equal sense for all numbers.
+               # The "int" part of these message names is rather confusing.  They make
+               # equal sense for all numbers.
                if ( isset( $this->mParams['min'] ) ) {
                        $min = $this->mParams['min'];
                        if ( $min > $value )
@@ -919,9 +629,6 @@ class HTMLFloatField extends HTMLTextField {
        }
 }
 
-/**
- * A field that must contain a number
- */
 class HTMLIntField extends HTMLFloatField {
        function validate( $value, $alldata ) {
                $p = parent::validate( $value, $alldata );
@@ -936,9 +643,6 @@ class HTMLIntField extends HTMLFloatField {
        }
 }
 
-/**
- * A checkbox field
- */
 class HTMLCheckField extends HTMLFormField {
        function getInputHTML( $value ) {
                if ( !empty( $this->mParams['invert'] ) )
@@ -953,12 +657,8 @@ class HTMLCheckField extends HTMLFormField {
                                Html::rawElement( 'label', array( 'for' => $this->mID ), $this->mLabel );
        }
 
-       /**
-        * For a checkbox, the label goes on the right hand side, and is
-        * added in getInputHTML(), rather than HTMLFormField::getRow()
-        */
        function getLabel() {
-               return '&nbsp;';
+               return '&nbsp;'; // In the right-hand column.
        }
 
        function loadDataFromRequest( $request ) {
@@ -982,9 +682,6 @@ class HTMLCheckField extends HTMLFormField {
        }
 }
 
-/**
- * A select dropdown field.  Basically a wrapper for Xmlselect class
- */
 class HTMLSelectField extends HTMLFormField {
 
        function validate( $value, $alldata ) {
@@ -1001,9 +698,9 @@ class HTMLSelectField extends HTMLFormField {
        function getInputHTML( $value ) {
                $select = new XmlSelect( $this->mName, $this->mID, strval( $value ) );
 
-               # If one of the options' 'name' is int(0), it is automatically selected.
-               # because PHP sucks and things int(0) == 'some string'.
-               # Working around this by forcing all of them to strings.
+               // If one of the options' 'name' is int(0), it is automatically selected.
+               //  because PHP sucks and things int(0) == 'some string'.
+               //  Working around this by forcing all of them to strings.
                $options = array_map( 'strval', $this->mParams['options'] );
 
                if( !empty( $this->mParams['disabled'] ) ) {
@@ -1016,9 +713,6 @@ class HTMLSelectField extends HTMLFormField {
        }
 }
 
-/**
- * Select dropdown field, with an additional "other" textbox.
- */
 class HTMLSelectOrOtherField extends HTMLTextField {
        static $jsAdded = false;
 
@@ -1089,19 +783,15 @@ class HTMLSelectOrOtherField extends HTMLTextField {
        }
 }
 
-/**
- * Multi-select field
- */
 class HTMLMultiSelectField extends HTMLFormField {
-       
        function validate( $value, $alldata ) {
                $p = parent::validate( $value, $alldata );
                if( $p !== true ) return $p;
 
                if( !is_array( $value ) ) return false;
 
-               # If all options are valid, array_intersect of the valid options 
-               # and the provided options will return the provided options.
+               // If all options are valid, array_intersect of the valid options and the provided
+               //  options will return the provided options.
                $validOptions = HTMLFormField::flattenOptions( $this->mParams['options'] );
 
                $validValues = array_intersect( $value, $validOptions );
@@ -1144,7 +834,7 @@ class HTMLMultiSelectField extends HTMLFormField {
        }
 
        function loadDataFromRequest( $request ) {
-               # won't work with getCheck
+               // won't work with getCheck
                if( $request->getCheck( 'wpEditToken' ) ) {
                        $arr = $request->getArray( $this->mName );
 
@@ -1170,9 +860,6 @@ class HTMLMultiSelectField extends HTMLFormField {
        }
 }
 
-/**
- * Radio checkbox fields.
- */
 class HTMLRadioField extends HTMLFormField {
        function validate( $value, $alldata ) {
                $p = parent::validate( $value, $alldata );
@@ -1189,10 +876,6 @@ class HTMLRadioField extends HTMLFormField {
                        return wfMsgExt( 'htmlform-select-badoption', 'parseinline' );
        }
 
-       /**
-        * This returns a block of all the radio options, in one cell.
-        * @see includes/HTMLFormField#getInputHTML()
-        */
        function getInputHTML( $value ) {
                $html = $this->formatOptions( $this->mParams['options'], $value );
 
@@ -1207,7 +890,6 @@ class HTMLRadioField extends HTMLFormField {
                        $attribs['disabled'] = 'disabled';
                }
 
-               # TODO: should this produce an unordered list perhaps?
                foreach( $options as $label => $info ) {
                        if( is_array( $info ) ) {
                                $html .= Html::rawElement( 'h1', array(), $label ) . "\n";
@@ -1231,9 +913,6 @@ class HTMLRadioField extends HTMLFormField {
        }
 }
 
-/**
- * An information field (text blob), not a proper input.
- */
 class HTMLInfoField extends HTMLFormField {
        function __construct( $info ) {
                $info['nodata'] = true;
@@ -1257,30 +936,3 @@ class HTMLInfoField extends HTMLFormField {
                return false;
        }
 }
-
-class HTMLHiddenField extends HTMLFormField {
-       
-       public function getTableRow( $value ){
-               $this->mParent->addHiddenField( 
-                       $this->mParams['name'],
-                       $this->mParams['default']
-               );
-               return '';
-       }
-
-       public function getInputHTML( $value ){ return ''; }
-}
-
-class HTMLSubmitField extends HTMLFormField {
-       
-       public function getTableRow( $value ){
-               $this->mParent->addButton(
-                       $this->mParams['name'],
-                       $this->mParams['default'],
-                       isset($this->mParams['id']) ? $this->mParams['id'] : null 
-               );
-       }
-       
-       public function getInputHTML( $value ){ return ''; }
-}
-
diff --git a/includes/Login.php b/includes/Login.php
deleted file mode 100644 (file)
index 42a0e76..0000000
+++ /dev/null
@@ -1,596 +0,0 @@
-<?php
-
-/**
- * Encapsulates the backend activities of logging a user into the wiki.
- */
-class Login {
-
-       const SUCCESS = 0;
-       const NO_NAME = 1;
-       const ILLEGAL = 2;
-       const WRONG_PLUGIN_PASS = 3;
-       const NOT_EXISTS = 4;
-       const WRONG_PASS = 5;
-       const EMPTY_PASS = 6;
-       const RESET_PASS = 7;
-       const ABORTED = 8;
-       const THROTTLED = 10;
-       const FAILED = 11;
-       const READ_ONLY = 12;
-       
-       const MAIL_PASSCHANGE_FORBIDDEN = 21;
-       const MAIL_BLOCKED = 22;
-       const MAIL_PING_THROTTLED = 23;
-       const MAIL_PASS_THROTTLED = 24;
-       const MAIL_EMPTY_EMAIL = 25;
-       const MAIL_BAD_IP = 26;
-       const MAIL_ERROR = 27;
-       
-       const CREATE_BLOCKED = 40;
-       const CREATE_EXISTS = 41;
-       const CREATE_SORBS = 42;
-       const CREATE_BADDOMAIN = 43;
-       const CREATE_BADNAME = 44;
-       const CREATE_BADPASS = 45;
-       const CREATE_NEEDEMAIL = 46;
-       const CREATE_BADEMAIL = 47;
-
-       protected $mName;
-       protected $mPassword;
-       public $mRemember; # 0 or 1
-       public $mEmail;
-       public $mDomain;
-       public $mRealname;
-
-       private $mExtUser = null;
-       
-       public $mUser;
-       
-       public $mLoginResult = '';
-       public $mMailResult = '';
-       public $mCreateResult = '';
-
-       /**
-        * Constructor
-        * @param WebRequest $request A WebRequest object passed by reference.
-        *     uses $wgRequest if not given.
-        */
-       public function __construct( &$request=null ) {
-               global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
-               if( !$request ) $request = &$wgRequest;
-
-               $this->mName = $request->getText( 'wpName' );
-               $this->mPassword = $request->getText( 'wpPassword' );
-               $this->mDomain = $request->getText( 'wpDomain' );
-               $this->mRemember = $request->getCheck( 'wpRemember' ) ? 1 : 0;
-
-               if( $wgEnableEmail ) {
-                       $this->mEmail = $request->getText( 'wpEmail' );
-               } else {
-                       $this->mEmail = '';
-               }
-               if( !in_array( 'realname', $wgHiddenPrefs ) ) {
-                   $this->mRealName = $request->getText( 'wpRealName' );
-               } else {
-                   $this->mRealName = '';
-               }
-
-               if( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       $this->mDomain = 'invaliddomain';
-               }
-               $wgAuth->setDomain( $this->mDomain );
-
-               # Load the user, if they exist in the local database.
-               $this->mUser = User::newFromName( trim( $this->mName ), 'usable' );
-       }
-       
-       /**
-        * Having initialised the Login object with (at least) the wpName
-        * and wpPassword pair, attempt to authenticate the user and log
-        * them into the wiki.  Authentication may come from the local 
-        * user database, or from an AuthPlugin- or ExternalUser-based
-        * foreign database; in the latter case, a local user record may
-        * or may not be created and initialised.  
-        * @return a Login class constant representing the status.
-        */
-       public function attemptLogin(){
-               global $wgUser;
-               
-               $code = $this->authenticateUserData();
-               if( $code != self::SUCCESS ){
-                       return $code;
-               }
-               
-               # Log the user in and remember them if they asked for that.
-               if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
-                       $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
-                       $wgUser->saveSettings();
-               } else {
-                       $wgUser->invalidateCache();
-               }
-               $wgUser->setCookies();
-
-               # Reset the password throttle
-               $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
-               global $wgMemc;
-               $wgMemc->delete( $key );
-               
-               wfRunHooks( 'UserLoginComplete', array( &$wgUser, &$this->mLoginResult ) );
-               
-               return self::SUCCESS;
-       }
-
-       /**
-        * Check whether there is an external authentication mechanism from
-        * which we can automatically authenticate the user and create a 
-        * local account for them. 
-        * @return integer Status code.  Login::SUCCESS == clear to proceed
-        *    with user creation.
-        */
-       protected function canAutoCreate() {
-               global $wgAuth, $wgUser, $wgAutocreatePolicy;
-
-               if( $wgUser->isBlockedFromCreateAccount() ) {
-                       wfDebug( __METHOD__.": user is blocked from account creation\n" );
-                       return self::CREATE_BLOCKED;
-               }
-
-               # If the external authentication plugin allows it, automatically 
-               # create a new account for users that are externally defined but 
-               # have not yet logged in.
-               if( $this->mExtUser ) {
-                       # mExtUser is neither null nor false, so use the new 
-                       # ExternalAuth system.
-                       if( $wgAutocreatePolicy == 'never' ) {
-                               return self::NOT_EXISTS;
-                       }
-                       if( !$this->mExtUser->authenticate( $this->mPassword ) ) {
-                               return self::WRONG_PLUGIN_PASS;
-                       }
-               } else {
-                       # Old AuthPlugin.
-                       if( !$wgAuth->autoCreate() ) {
-                               return self::NOT_EXISTS;
-                       }
-                       if( !$wgAuth->userExists( $this->mUser->getName() ) ) {
-                               wfDebug( __METHOD__.": user does not exist\n" );
-                               return self::NOT_EXISTS;
-                       }
-                       if( !$wgAuth->authenticate( $this->mUser->getName(), $this->mPassword ) ) {
-                               wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
-                               return self::WRONG_PLUGIN_PASS;
-                       }
-               }
-
-               return self::SUCCESS;
-       }
-
-       /**
-        * Internally authenticate the login request.
-        *
-        * This may create a local account as a side effect if the
-        * authentication plugin allows transparent local account
-        * creation.
-        */
-       protected function authenticateUserData() {
-               global $wgUser, $wgAuth;
-               
-               if ( '' == $this->mName ) {
-                       $this->mLoginResult = 'noname';
-                       return self::NO_NAME;
-               }
-               
-               global $wgPasswordAttemptThrottle;
-               $throttleCount = 0;
-               if ( is_array( $wgPasswordAttemptThrottle ) ) {
-                       $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
-                       $count = $wgPasswordAttemptThrottle['count'];
-                       $period = $wgPasswordAttemptThrottle['seconds'];
-                       
-                       global $wgMemc;
-                       $throttleCount = $wgMemc->get( $throttleKey );
-                       if ( !$throttleCount ) {
-                               $wgMemc->add( $throttleKey, 1, $period ); # Start counter
-                       } else if ( $throttleCount < $count ) {
-                               $wgMemc->incr($throttleKey);
-                       } else if ( $throttleCount >= $count ) {
-                               $this->mLoginResult = 'login-throttled';
-                               return self::THROTTLED;
-                       }
-               }
-
-               # Unstub $wgUser now, and check to see if we're logging in as the same
-               # name. As well as the obvious, unstubbing $wgUser (say by calling
-               # getName()) calls the UserLoadFromSession hook, which potentially
-               # creates the user in the database. Until we load $wgUser, checking
-               # for user existence using User::newFromName($name)->getId() below
-               # will effectively be using stale data.
-               if ( $wgUser->getName() === $this->mName ) {
-                       wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
-                       return self::SUCCESS;
-               }
-
-               $this->mExtUser = ExternalUser::newFromName( $this->mName );
-               
-               # If the given username produces a valid ExternalUser, which is 
-               # linked to an existing local user, use that, regardless of 
-               # whether the username matches up.
-               if( $this->mExtUser ){
-                       $user = $this->mExtUser->getLocalUser();
-                       if( $user instanceof User ){
-                               $this->mUser = $user;
-                       }
-               }
-
-               # TODO: Allow some magic here for invalid external names, e.g., let the
-               # user choose a different wiki name.
-               if( is_null( $this->mUser ) || !User::isUsableName( $this->mUser->getName() ) ) {
-                       return self::ILLEGAL;
-               }
-
-               # If the user doesn't exist in the local database, our only chance 
-               # is for an external auth plugin to autocreate the local user first.
-               if ( $this->mUser->getID() == 0 ) {
-                       if ( $this->canAutoCreate() == self::SUCCESS ) {
-                               
-                               $isAutoCreated = true;
-                               wfDebug( __METHOD__.": creating account\n" );
-                               
-                               if( !wfRunHooks( 'AbortNewAccountAuto', array( $this->mUser, &$this->mCreateResult ) ) ) {
-                                       wfDebug( __METHOD__ . ": a hook blocked creation\n" );
-                                       return self::ABORTED;
-                               }
-                               
-                               $result = $this->initUser( true );
-                               if( $result !== self::SUCCESS ){
-                                       return $result;
-                               }
-                               
-                       } else {
-                               return $this->canAutoCreate();
-                       }
-               } else {
-                       $isAutoCreated = false;
-                       $this->mUser->load();
-               }
-
-               # Give general extensions, such as a captcha, a chance to abort logins
-               if( !wfRunHooks( 'AbortLogin', array( $this->mUser, $this->mPassword, &$this->mLoginResult ) ) ) {
-                       return self::ABORTED;
-               }
-
-               if( !$this->mUser->checkPassword( $this->mPassword ) ) {
-                       if( $this->mUser->checkTemporaryPassword( $this->mPassword ) ) {
-                               # The e-mailed temporary password should not be used for actual
-                               # logins; that's a very sloppy habit, and insecure if an
-                               # attacker has a few seconds to click "search" on someone's 
-                               # open mail reader.
-                               #
-                               # Allow it to be used only to reset the password a single time
-                               # to a new value, which won't be in the user's e-mail archives
-                               #
-                               # For backwards compatibility, we'll still recognize it at the
-                               # login form to minimize surprises for people who have been
-                               # logging in with a temporary password for some time.
-                               #
-                               # As a side-effect, we can authenticate the user's e-mail ad-
-                               # dress if it's not already done, since the temporary password
-                               # was sent via e-mail.
-                               if( !$this->mUser->isEmailConfirmed() ) {
-                                       $this->mUser->confirmEmail();
-                                       $this->mUser->saveSettings();
-                               }
-
-                               # At this point we just return an appropriate code/ indicating
-                               # that the UI should show a password reset form; bot interfaces
-                               # etc will probably just fail cleanly here.
-                               $retval = self::RESET_PASS;
-                       } else {
-                               if( $this->mPassword === '' ){
-                                       $retval = self::EMPTY_PASS;
-                                       $this->mLoginResult = 'wrongpasswordempty';
-                               } else {
-                                       $retval = self::WRONG_PASS;
-                                       $this->mLoginResult = 'wrongpassword';
-                               }
-                       }
-               } else {
-                       $wgAuth->updateUser( $this->mUser );
-                       $wgUser = $this->mUser;
-
-                       # Reset throttle after a successful login
-                       if( $throttleCount ) {
-                               $wgMemc->delete( $throttleKey );
-                       }
-
-                       if( $isAutoCreated ) {
-                               # Must be run after $wgUser is set, for correct new user log
-                               wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
-                       }
-
-                       $retval = self::SUCCESS;
-               }
-               wfRunHooks( 'LoginAuthenticateAudit', array( $this->mUser, $this->mPassword, $retval ) );
-               return $retval;
-       }
-
-       /**
-        * Actually add a user to the database.
-        * Give it a User object that has been initialised with a name.
-        *
-        * @param $autocreate Bool is this is an autocreation from an external
-        *   authentication database?
-        * @param $byEmail Bool is this request going to be handled by sending
-        *   the password by email?
-        * @return Bool whether creation was successful (should only fail for
-        *   Db errors etc).
-        */
-       protected function initUser( $autocreate=false, $byEmail=false ) {
-               global $wgAuth, $wgUser;
-
-               $fields = array(
-                       'name' => User::getCanonicalName( $this->mName ),
-                       'password' => $byEmail ? null : User::crypt( $this->mPassword ),
-                       'email' => $this->mEmail,
-                       'options' => array(
-                               'rememberpassword' => $this->mRemember ? 1 : 0,
-                       ),
-               );
-               
-               $this->mUser = User::createNew( $this->mName, $fields );
-               
-               if( $this->mUser === null ){
-                       return null;
-               }
-
-               # Let old AuthPlugins play with the user
-               $wgAuth->initUser( $this->mUser, $autocreate );
-
-               # Or new ExternalUser plugins
-               if( $this->mExtUser ) {
-                       $this->mExtUser->link( $this->mUser->getId() );
-                       $email = $this->mExtUser->getPref( 'emailaddress' );
-                       if( $email && !$this->mEmail ) {
-                               $this->mUser->setEmail( $email );
-                       }
-               }
-
-               # Update user count and newuser logs
-               $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
-               $ssUpdate->doUpdate();
-               if( $autocreate )
-                       $this->mUser->addNewUserLogEntryAutoCreate();
-               elseif( $wgUser->isAnon() )
-                       # Avoid spamming IP addresses all over the newuser log
-                       $this->mUser->addNewUserLogEntry( $this->mUser, $byEmail );
-               else
-                       $this->mUser->addNewUserLogEntry( $wgUser, $byEmail );
-               
-               # Run hooks
-               wfRunHooks( 'AddNewAccount', array( $this->mUser ) );
-
-               return true;
-       }
-
-       /**
-        * Entry point to create a new local account from user-supplied
-        * data loaded from the WebRequest.  We handle initialising the 
-        * email here because it's needed for some backend things; frontend
-        * interfaces calling this should handle recording things like 
-        * preference options
-        * @param $byEmail Bool whether to email the user their new password
-        * @return Status code; Login::SUCCESS == the user was successfully created
-        */
-       public function attemptCreation( $byEmail=false ) {
-               global $wgUser, $wgOut;
-               global $wgEnableSorbs, $wgProxyWhitelist;
-               global $wgMemc, $wgAccountCreationThrottle;
-               global $wgAuth;
-               global $wgEmailAuthentication, $wgEmailConfirmToEdit;
-
-               if( wfReadOnly() ) 
-                       return self::READ_ONLY;
-                       
-               # If the user passes an invalid domain, something is fishy
-               if( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       $this->mCreateResult = 'wrongpassword';
-                       return self::CREATE_BADDOMAIN;
-               }
-
-               # If we are not allowing users to login locally, we should be checking
-               # to see if the user is actually able to authenticate to the authenti-
-               # cation server before they create an account (otherwise, they can
-               # create a local account and login as any domain user). We only need
-               # to check this for domains that aren't local.
-               if(    !in_array( $this->mDomain, array( 'local', '' ) ) 
-                       && !$wgAuth->canCreateAccounts() 
-                       && ( !$wgAuth->userExists( $this->mUsername ) 
-                               || !$wgAuth->authenticate( $this->mUsername, $this->mPassword ) 
-                       ) ) 
-               {
-                       $this->mCreateResult = 'wrongpassword';
-                       return self::WRONG_PLUGIN_PASS;
-               }
-
-               $ip = wfGetIP();
-               if ( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
-                 $wgUser->inSorbsBlacklist( $ip ) )
-               {
-                       $this->mCreateResult = 'sorbs_create_account_reason';
-                       return self::CREATE_SORBS;
-               }
-
-               # Now create a dummy user ($user) and check if it is valid
-               $name = trim( $this->mName );
-               $user = User::newFromName( $name, 'creatable' );
-               if ( is_null( $user ) ) {
-                       $this->mCreateResult = 'noname';
-                       return self::CREATE_BADNAME;
-               }
-
-               if ( $this->mUser->idForName() != 0 ) {
-                       $this->mCreateResult = 'userexists';
-                       return self::CREATE_EXISTS;
-               }
-
-               # Check that the password is acceptable, if we're actually
-               # going to use it
-               if( !$byEmail ){
-                       $valid = $this->mUser->isValidPassword( $this->mPassword );
-                       if ( $valid !== true ) {
-                               $this->mCreateResult = $valid;
-                               return self::CREATE_BADPASS;
-                       }
-               }
-
-               # if you need a confirmed email address to edit, then obviously you
-               # need an email address. Equally if we're going to send the password to it.
-               if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) || $byEmail ) {
-                       $this->mCreateResult = 'noemailcreate';
-                       return self::CREATE_NEEDEMAIL;
-               }
-
-               if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
-                       $this->mCreateResult = 'invalidemailaddress';
-                       return self::CREATE_BADEMAIL;
-               }
-
-               # Set some additional data so the AbortNewAccount hook can be used for
-               # more than just username validation
-               $this->mUser->setEmail( $this->mEmail );
-               $this->mUser->setRealName( $this->mRealName );
-
-               if( !wfRunHooks( 'AbortNewAccount', array( $this->mUser, &$this->mCreateResult ) ) ) {
-                       # Hook point to add extra creation throttles and blocks
-                       wfDebug( __METHOD__ . ": a hook blocked creation\n" );
-                       return self::ABORTED;
-               }
-
-               if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
-                       $key = wfMemcKey( 'acctcreate', 'ip', $ip );
-                       $value = $wgMemc->get( $key );
-                       if ( !$value ) {
-                               $wgMemc->set( $key, 0, 86400 );
-                       }
-                       if ( $value >= $wgAccountCreationThrottle ) {
-                               return self::THROTTLED;
-                       }
-                       $wgMemc->incr( $key );
-               }
-
-               # Since we're creating a new local user, give the external 
-               # database a chance to synchronise.
-               if( !$wgAuth->addUser( $this->mUser, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
-                       $this->mCreateResult = 'externaldberror';
-                       return self::ABORTED;
-               }
-
-               $result = $this->initUser( false, $byEmail );
-               if( $result === null )
-                       # It's unlikely we'd get here without some exception 
-                       # being thrown, but it's probably possible...
-                       return self::FAILED;
-                       
-       
-               # Send out an email message if needed
-               if( $byEmail ){
-                       $this->mailPassword( 'createaccount-title', 'createaccount-text' );
-                       if( WikiError::isError( $this->mMailResult ) ){
-                               # FIXME: If the password email hasn't gone out, 
-                               # then the account is inaccessible :(
-                               return self::MAIL_ERROR;
-                       } else {
-                               return self::SUCCESS;
-                       }
-               } else {
-                       if( $wgEmailAuthentication && User::isValidEmailAddr( $this->mUser->getEmail() ) ) 
-                       {
-                               $this->mMailResult = $this->mUser->sendConfirmationMail();
-                               return WikiError::isError( $this->mMailResult ) 
-                                       ? self::MAIL_ERROR 
-                                       : self::SUCCESS;
-                       }
-               }
-               return true;
-       }
-
-       /**
-        * Email the user a new password, if appropriate to do so.
-        * @param $text String message key
-        * @param $title String message key
-        * @return Status code
-        */
-       public function mailPassword( $text='passwordremindertext', $title='passwordremindertitle' ) {
-               global $wgUser, $wgOut, $wgAuth, $wgServer, $wgScript, $wgNewPasswordExpiry;
-
-               if( wfReadOnly() ) 
-                       return self::READ_ONLY;
-
-               # If we let the email go out, it will take users to a form where
-               # they are forced to change their password, so don't let us go 
-               # there if we don't want passwords changed.
-               if( !$wgAuth->allowPasswordChange() ) 
-                       return self::MAIL_PASSCHANGE_FORBIDDEN;
-
-               # Check against blocked IPs
-               # FIXME: -- should we not?
-               if( $wgUser->isBlocked() )
-                       return self::MAIL_BLOCKED;
-
-               # Check for hooks
-               if( !wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$this->mMailResult ) ) )
-                       return self::ABORTED;
-
-               # Check against the rate limiter
-               if( $wgUser->pingLimiter( 'mailpassword' ) )
-                       return self::MAIL_PING_THROTTLED;
-
-               # Check for a valid name
-               if ($this->mName === '' )
-                       return self::NO_NAME;
-               $this->mUser = User::newFromName( $this->mName );
-               if( is_null( $this->mUser ) )
-                       return self::NO_NAME;
-
-               # And that the resulting user actually exists
-               if ( $this->mUser->getId() === 0 )
-                       return self::NOT_EXISTS;
-
-               # Check against password throttle
-               if ( $this->mUser->isPasswordReminderThrottled() )
-                       return self::MAIL_PASS_THROTTLED;
-               
-               # User doesn't have email address set
-               if ( $this->mUser->getEmail() === '' )
-                       return self::MAIL_EMPTY_EMAIL;
-
-               # Don't send to people who are acting fishily by hiding their IP
-               $ip = wfGetIP();
-               if( !$ip )
-                       return self::MAIL_BAD_IP;
-
-               # Let hooks do things with the data
-               wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$this->mUser) );
-
-               $newpass = $this->mUser->randomPassword();
-               $this->mUser->setNewpassword( $newpass, true );
-               $this->mUser->saveSettings();
-
-               $message = wfMsgExt( $text, array( 'parsemag' ), $ip, $this->mUser->getName(), $newpass,
-                               $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
-               $this->mMailResult = $this->mUser->sendMail( wfMsg( $title ), $message );
-               
-               if( WikiError::isError( $this->mMailResult ) ) {
-                       return self::MAIL_ERROR;
-               } else {
-                       return self::SUCCESS;
-               }
-       }
-}
-
-/**
- * For backwards compatibility, mainly with the state constants, which
- * could be referred to in old extensions with the old class name.
- * @deprecated
- */
-class LoginForm extends Login {}
\ No newline at end of file
index 228d3f9..dbf0974 100644 (file)
@@ -112,8 +112,8 @@ class SpecialPage {
                'Listredirects'             => array( 'SpecialPage', 'Listredirects' ), 
 
                # Login/create account
-               'Userlogin'                 => 'SpecialUserLogin',              
-               'CreateAccount'             => 'SpecialCreateAccount',
+               'Userlogin'                 => array( 'SpecialPage', 'Userlogin' ),             
+               'CreateAccount'             => array( 'SpecialRedirectToSpecial', 'CreateAccount', 'Userlogin', 'signup', array( 'uselang' ) ),
 
                # Users and rights
                'Blockip'                   => array( 'SpecialPage', 'Blockip', 'block' ),
index 45b3604..66ff8df 100644 (file)
@@ -60,7 +60,7 @@ class ApiLogin extends ApiBase {
                        'wpName' => $params['name'],
                        'wpPassword' => $params['password'],
                        'wpDomain' => $params['domain'],
-                       'wpRemember' => '1'
+                       'wpRemember' => ''
                ));
 
                // Init session if necessary
@@ -68,11 +68,19 @@ class ApiLogin extends ApiBase {
                        wfSetupSession();
                }
 
-               $login = new Login( $req );
-               switch ( $authRes = $login->attemptLogin() ) {
-                       case Login::SUCCESS :
+               $loginForm = new LoginForm($req);
+               switch ($authRes = $loginForm->authenticateUserData()) {
+                       case LoginForm :: SUCCESS :
                                global $wgUser, $wgCookiePrefix;
 
+                               $wgUser->setOption('rememberpassword', 1);
+                               $wgUser->setCookies();
+
+                               // Run hooks. FIXME: split back and frontend from this hook.
+                               // FIXME: This hook should be placed in the backend
+                               $injected_html = '';
+                               wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
+
                                $result['result'] = 'Success';
                                $result['lguserid'] = intval($wgUser->getId());
                                $result['lgusername'] = $wgUser->getName();
@@ -81,35 +89,35 @@ class ApiLogin extends ApiBase {
                                $result['sessionid'] = session_id();
                                break;
 
-                       case Login::NO_NAME :
+                       case LoginForm :: NO_NAME :
                                $result['result'] = 'NoName';
                                break;
-                       case Login::ILLEGAL :
+                       case LoginForm :: ILLEGAL :
                                $result['result'] = 'Illegal';
                                break;
-                       case Login::WRONG_PLUGIN_PASS :
+                       case LoginForm :: WRONG_PLUGIN_PASS :
                                $result['result'] = 'WrongPluginPass';
                                break;
-                       case Login::NOT_EXISTS :
+                       case LoginForm :: NOT_EXISTS :
                                $result['result'] = 'NotExists';
                                break;
-                       case Login::WRONG_PASS :
+                       case LoginForm :: WRONG_PASS :
                                $result['result'] = 'WrongPass';
                                break;
-                       case Login::EMPTY_PASS :
+                       case LoginForm :: EMPTY_PASS :
                                $result['result'] = 'EmptyPass';
                                break;
-                       case Login::CREATE_BLOCKED :
+                       case LoginForm :: CREATE_BLOCKED :
                                $result['result'] = 'CreateBlocked';
                                $result['details'] = 'Your IP address is blocked from account creation';
                                break;
-                       case Login::THROTTLED :
+                       case LoginForm :: THROTTLED :
                                global $wgPasswordAttemptThrottle;
                                $result['result'] = 'Throttled';
-                               $result['wait'] = intval( $wgPasswordAttemptThrottle['seconds'] );
+                               $result['wait'] = intval($wgPasswordAttemptThrottle['seconds']);
                                break;
                        default :
-                               ApiBase::dieDebug( __METHOD__, "Unhandled case value: {$authRes}" );
+                               ApiBase :: dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
                }
 
                $this->getResult()->addValue(null, 'login', $result);
index 9c8cae1..20af1c6 100644 (file)
@@ -3332,39 +3332,25 @@ class Parser
                }
                if ( isset( $this->mDoubleUnderscores['hiddencat'] ) && $this->mTitle->getNamespace() == NS_CATEGORY ) {
                        $this->mOutput->setProperty( 'hiddencat', 'y' );
-                       $this->addTrackingCategory( 'hidden-category-category' );
+
+                       $containerCategory = Title::makeTitleSafe( NS_CATEGORY, wfMsgForContent( 'hidden-category-category' ) );
+                       if ( $containerCategory ) {
+                               $this->mOutput->addCategory( $containerCategory->getDBkey(), $this->getDefaultSort() );
+                       } else {
+                               wfDebug( __METHOD__.": [[MediaWiki:hidden-category-category]] is not a valid title!\n" );
+                       }
                }
                # (bug 8068) Allow control over whether robots index a page.
                #
                # FIXME (bug 14899): __INDEX__ always overrides __NOINDEX__ here!  This
                # is not desirable, the last one on the page should win.
-               if( isset( $this->mDoubleUnderscores['noindex'] ) && $this->mTitle->canUseNoindex() ) {
+               if( isset( $this->mDoubleUnderscores['noindex'] ) ) {
                        $this->mOutput->setIndexPolicy( 'noindex' );
-                       $this->addTrackingCategory( 'noindex-category' );
-               }
-               if( isset( $this->mDoubleUnderscores['index'] ) && $this->mTitle->canUseNoindex() ){
+               } elseif( isset( $this->mDoubleUnderscores['index'] ) ) {
                        $this->mOutput->setIndexPolicy( 'index' );
-                       $this->addTrackingCategory( 'index-category' );
                }
                wfProfileOut( __METHOD__ );
                return $text;
-       }       
-       
-       /**
-        * Add a tracking category, getting the title from a system message,
-        * or print a debug message if the title is invalid.
-        * @param $msg String message key
-        * @return Bool whether the addition was successful
-        */
-       protected function addTrackingCategory( $msg ){
-               $containerCategory = Title::makeTitleSafe( NS_CATEGORY, wfMsgForContent( $msg ) );
-               if ( $containerCategory ) {
-                       $this->mOutput->addCategory( $containerCategory->getDBkey(), $this->getDefaultSort() );
-                       return true;
-               } else {
-                       wfDebug( __METHOD__.": [[MediaWiki:$msg]] is not a valid title!\n" );
-                       return false;
-               }
        }
 
        /**
diff --git a/includes/specials/SpecialCreateAccount.php b/includes/specials/SpecialCreateAccount.php
deleted file mode 100644 (file)
index e449d0e..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-<?php
-/**
- * Special page for creating/registering new user accounts.
- * @ingroup SpecialPage
- */
-class SpecialCreateAccount extends SpecialPage {
-
-       var $mUsername, $mPassword, $mRetype, $mReturnTo, $mPosted;
-       var $mCreateaccountMail, $mRemember, $mEmail, $mDomain, $mLanguage;
-       var $mReturnToQuery;
-       
-       protected $mLogin;
-
-       public $mDomains = array();
-       
-       public $mUseEmail = true; # Can be switched off by AuthPlugins etc
-       public $mUseRealname = true;
-       public $mUseRemember = true;
-       
-       public $mFormHeader = '';
-       public $mFormFields = array(
-               'Name' => array(
-                       'type'          => 'text',
-                       'label-message' => 'yourname',
-                       'id'            => 'wpName2',
-                       'tabindex'      => '1',
-                       'size'          => '20',
-                       'required'      => '1',
-                       'autofocus'     => '',
-               ),
-               'Password' => array(
-                       'type'          => 'password',
-                       'label-message' => 'yourpassword',
-                       'size'          => '20',
-                       'id'            => 'wpPassword2',
-                       'required'      => '',
-               ),
-               'Retype' => array(
-                       'type'          => 'password',
-                       'label-message' => 'yourpasswordagain',
-                       'size'          => '20',
-                       'id'            => 'wpRetype',
-                       'required'      => '',
-               ),
-               'Email' => array(
-                       'type'          => 'email',
-                       'label-message' => 'youremail',
-                       'size'          => '20',
-                       'id'            => 'wpEmail',
-               ),
-               'RealName' => array(
-                       'type'          => 'text',
-                       'label-message' => 'yourrealname',
-                       'id'            => 'wpRealName',
-                       'tabindex'      => '1',
-                       'size'          => '20',
-               ),
-               'Remember' => array(
-                       'type'          => 'check',
-                       'label-message' => 'remembermypassword',
-                       'id'            => 'wpRemember',
-               ),
-               'Domain' => array(
-                       'type'          => 'select',
-                       'id'            => 'wpDomain',
-                       'label-message' => 'yourdomainname',
-                       'options'       => null,
-                       'default'       => null, 
-               ),
-       );
-       
-       public function __construct(){
-               parent::__construct( 'CreateAccount', 'createaccount' );
-               $this->mLogin = new Login();
-               $this->mFormFields['RealName']['label-help'] = 'prefs-help-realname';
-       }
-       
-       public function execute( $par ){
-               global $wgUser, $wgOut;
-               
-               $this->setHeaders();
-               $this->loadQuery();
-               
-               # Block signup here if in readonly. Keeps user from 
-               # going through the process (filling out data, etc) 
-               # and being informed later.
-               if ( wfReadOnly() ) {
-                       $wgOut->readOnlyPage();
-                       return;
-               } 
-               # Bail out straightaway on permissions errors
-               if ( !$this->userCanExecute( $wgUser ) ) {
-                       $this->displayRestrictionError();
-                       return;
-               } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
-                       $this->userBlockedMessage();
-                       return;
-               } elseif ( count( $permErrors = $this->getTitle()->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
-                       $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
-                       return;
-               }       
-               
-               if( $this->mPosted ) {
-                       $this->addNewAccount( $this->mCreateaccountMail );
-               } else {
-                       $this->showMainForm('');
-               }
-       }
-       
-       /**
-        * Load the member variables from the request parameters
-        */
-       protected function loadQuery(){
-               global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
-               $this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
-                                           && $wgEnableEmail;
-               
-               $this->mUsername = $wgRequest->getText( 'wpName' );
-               $this->mPassword = $wgRequest->getText( 'wpPassword' );
-               $this->mRetype = $wgRequest->getText( 'wpRetype' );
-               $this->mDomain = $wgRequest->getText( 'wpDomain' );
-               $this->mReturnTo = $wgRequest->getVal( 'returnto' );
-               $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
-               $this->mPosted = $wgRequest->wasPosted();
-               $this->mCreateaccountMail = $wgRequest->getCheck( 'wpCreateaccountMail' )
-                                           && $wgEnableEmail;
-               $this->mRemember = $wgRequest->getCheck( 'wpRemember' );
-               $this->mLanguage = $wgRequest->getText( 'uselang' );
-               
-               if ( $wgRedirectOnLogin ) {
-                       $this->mReturnTo = $wgRedirectOnLogin;
-                       $this->mReturnToQuery = '';
-               }
-
-               if( $wgEnableEmail ) {
-                       $this->mEmail = $wgRequest->getText( 'wpEmail' );
-               } else {
-                       $this->mEmail = '';
-               }
-               if( !in_array( 'realname', $wgHiddenPrefs ) ) {
-                   $this->mRealName = $wgRequest->getText( 'wpRealName' );
-               } else {
-                   $this->mRealName = '';
-               }
-
-               if( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       $this->mDomain = 'invaliddomain';
-               }
-               $wgAuth->setDomain( $this->mDomain );
-
-               # When switching accounts, it sucks to get automatically logged out
-               $returnToTitle = Title::newFromText( $this->mReturnTo );
-               if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
-                       $this->mReturnTo = '';
-                       $this->mReturnToQuery = '';
-               }
-       }
-
-       /**
-        * Create a new user account from the provided data
-        */
-       protected function addNewAccount( $byEmail=false ) {
-               global $wgUser, $wgEmailAuthentication;
-       
-               # Do a quick check that the user actually managed to type
-               # the password in the same both times
-               if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
-                       return $this->showMainForm( wfMsgExt( 'badretype', 'parseinline' ) );
-               }
-               
-               # Create the account and abort if there's a problem doing so
-               $status = $this->mLogin->attemptCreation( $byEmail );
-               switch( $status ){
-                       case Login::SUCCESS: 
-                       case Login::MAIL_ERROR: 
-                               break;
-                               
-                       case Login::CREATE_BADDOMAIN: 
-                       case Login::CREATE_EXISTS: 
-                       case Login::NO_NAME:
-                       case Login::CREATE_NEEDEMAIL: 
-                       case Login::CREATE_BADEMAIL: 
-                       case Login::CREATE_BADNAME:
-                       case Login::WRONG_PLUGIN_PASS:
-                       case Login::ABORTED:
-                               return $this->showMainForm( wfMsgExt( $this->mLogin->mCreateResult, 'parseinline' ) );
-                       
-                       case Login::CREATE_SORBS: 
-                               return $this->showMainForm( wfMsgExt( 'sorbs_create_account_reason', 'parseinline' ) . ' (' . wfGetIP() . ')' );
-                               
-                       case Login::CREATE_BLOCKED:
-                               return $this->userBlockedMessage();
-                               
-                       case Login::CREATE_BADPASS:
-                               global $wgMinimalPasswordLength;
-                               return $this->showMainForm( wfMsgExt( $this->mLogin->mCreateResult, array( 'parsemag' ), $wgMinimalPasswordLength ) );
-                               
-                       case Login::THROTTLED: 
-                               global $wgAccountCreationThrottle;
-                               return $this->showMainForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $wgAccountCreationThrottle ) ); 
-                       
-                       default: 
-                               throw new MWException( "Unhandled status code $status in " . __METHOD__ );
-               }
-
-               # If we showed up language selection links, and one was in use, be
-               # smart (and sensible) and save that language as the user's preference
-               global $wgLoginLanguageSelector;
-               if( $wgLoginLanguageSelector && $this->mLanguage )
-                       $this->mLogin->mUser->setOption( 'language', $this->mLanguage );
-               $this->mLogin->mUser->saveSettings();
-       
-               if( $byEmail ) {
-                       if( $result == Login::MAIL_ERROR ){
-                               # FIXME: we are totally screwed if we end up here...
-                               $this->showMainForm( wfMsgExt( 'mailerror', 'parseinline', $this->mLogin->mMailResult->getMessage() ) );
-                       } else {
-                               $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
-                               $wgOut->addWikiMsg( 'accmailtext', $this->mLogin->mUser->getName(), $this->mLogin->mUser->getEmail() );
-                               $wgOut->returnToMain( false );
-                       }
-                       
-               } else {
-
-                       # There might be a message stored from the confirmation mail
-                       # send, which we can display.
-                       if( $wgEmailAuthentication && $this->mLogin->mMailResult ) {
-                               global $wgOut;
-                               if( WikiError::isError( $this->mLogin->mMailResult ) ) {
-                                       $wgOut->addWikiMsg( 'confirmemail_sendfailed', $this->mLogin->mMailResult->getMessage() );
-                               } else {
-                                       $wgOut->addWikiMsg( 'confirmemail_oncreate' );
-                               }
-                       }
-                       
-                       # If not logged in, assume the new account as the current 
-                       # one and set session cookies then show a "welcome" message 
-                       # or a "need cookies" message as needed
-                       if( $wgUser->isAnon() ) {
-                               $wgUser = $this->mLogin->mUser;
-                               $wgUser->setCookies();
-                               if( $this->hasSessionCookie() ) {
-                                       return $this->successfulCreation();
-                               } else {
-                                       return $this->cookieRedirectCheck();
-                               }
-                       } else {
-                               # Show confirmation that the account was created
-                               global $wgOut;
-                               $self = SpecialPage::getTitleFor( 'Userlogin' );
-                               $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
-                               $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $this->mLogin->mUser->getName() ) );
-                               $wgOut->returnToMain( false, $self );
-                               return true;
-                       }
-               }
-       }
-
-       /**
-        * Run any hooks registered for logins, then 
-        * display a message welcoming the user.
-        */
-       protected function successfulCreation(){
-               global $wgUser, $wgOut;
-
-               # Run any hooks; display injected HTML
-               $injected_html = '';
-               wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
-
-               SpecialUserLogin::displaySuccessfulLogin( 
-                       'welcomecreation', 
-                       $injected_html,
-                       $this->mReturnTo,
-                       $this->mReturnToQuery );
-       }
-
-       /**
-        * Display a message indicating that account creation from their IP has 
-        * been blocked by a (range)block with 'block account creation' enabled. 
-        * It's likely that this feature will be used for blocking large numbers 
-        * of innocent people, e.g. range blocks on schools. Don't blame it on 
-        * the user. There's a small chance that it really is the user's fault, 
-        * i.e. the username is blocked and they haven't bothered to log out 
-        * before trying to create an account to evade it, but we'll leave that 
-        * to their guilty conscience to figure out...
-        */
-       protected function userBlockedMessage() {
-               global $wgOut, $wgUser;
-
-               $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
-               $wgOut->setRobotPolicy( 'noindex,nofollow' );
-               $wgOut->setArticleRelated( false );
-
-               $ip = wfGetIP();
-               $blocker = User::whoIs( $wgUser->mBlock->mBy );
-               $block_reason = $wgUser->mBlock->mReason;
-
-               if ( strval( $block_reason ) === '' ) {
-                       $block_reason = wfMsgExt( 'blockednoreason', 'parseinline' );
-               }
-               $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
-               $wgOut->returnToMain( false );
-       }
-
-       /**
-        * Show the main input form, with an appropriate error message
-        * from a previous iteration, if necessary
-        * @param $msg String HTML of message received previously
-        * @param $msgtype String type of message, usually 'error'
-        */
-       protected function showMainForm( $msg, $msgtype = 'error' ) {
-               global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
-               global $wgCookiePrefix, $wgLoginLanguageSelector;
-               global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
-               
-               # Parse the error message if we got one
-               if( $msg ){
-                       if( $msgtype == 'error' ){
-                               $msg = wfMsgExt( 'createaccounterror', array( 'parseinline', 'replaceafter' ), $msg );
-                       }
-                       $msg = Html::rawElement(
-                               'div',
-                               array( 'class' => $msgtype . 'box' ),
-                               $msg
-                       );
-               } else {
-                       $msg = '';
-               }
-
-               # Make sure the returnTo strings don't get lost if the
-               # user changes language, etc
-               $linkq = array();
-               if ( !empty( $this->mReturnTo ) ) {
-                       $linkq['returnto'] = wfUrlencode( $this->mReturnTo );
-                       if ( !empty( $this->mReturnToQuery ) )
-                               $linkq['returntoquery'] = wfUrlencode( $this->mReturnToQuery );
-               }
-
-               # Pass any language selection on to the mode switch link
-               if( $wgLoginLanguageSelector && $this->mLanguage )
-                       $linkq['uselang'] = $this->mLanguage;
-
-               $skin = $wgUser->getSkin();
-               $link = $skin->link( 
-                       SpecialPage::getTitleFor( 'Userlogin' ),
-                       wfMsgHtml( 'gotaccountlink' ),
-                       array(),
-                       $linkq );
-               $link = $wgUser->isLoggedIn()
-                       ? ''
-                       : wfMsgWikiHtml( 'gotaccount', $link );
-               
-               # Prepare language selection links as needed
-               $langSelector = $wgLoginLanguageSelector 
-                       ? Html::rawElement( 
-                               'div',
-                               array( 'id' => 'languagelinks' ),
-                               SpecialUserLogin::makeLanguageSelector( $this->getTitle(), $this->mReturnTo ) )
-                       : '';
-                               
-               # Give authentication and captcha plugins a chance to 
-               # modify the form, by hook or by using $wgAuth
-               $wgAuth->modifyUITemplate( $this, 'new' );
-               wfRunHooks( 'UserCreateForm', array( &$this ) );
-               
-               # The most likely use of the hook is to enable domains;
-               # check that now, and add fields if necessary
-               if( $this->mDomains ){
-                       $this->mFormFields['Domain']['options'] = $this->mDomains;
-                       $this->mFormFields['Domain']['default'] = $this->mDomain;
-               } else {
-                       unset( $this->mFormFields['Domain'] );
-               }
-               
-               # Or to switch email on or off
-               if( !$wgEnableEmail || !$this->mUseEmail ){
-                       unset( $this->mFormFields['Email'] );
-               } else {
-                       if( $wgEmailConfirmToEdit ){
-                               $this->mFormFields['Email']['help-message'] = 'prefs-help-email-required';
-                               $this->mFormFields['Email']['required'] = '';
-                       } else {
-                               $this->mFormFields['Email']['help-message'] = 'prefs-help-email';
-                       }
-               }
-               
-               # Or to play with realname
-               if( in_array( 'realname', $wgHiddenPrefs ) || !$this->mUseRealname ){
-                       unset( $this->mFormFields['Realname'] );
-               }
-               
-               # Or to tweak the 'remember my password' checkbox
-               if( !($wgCookieExpiration > 0) || !$this->mUseRemember ){
-                       # Remove it altogether
-                       unset( $this->mFormFields['Remember'] );
-               } elseif( $wgUser->getOption( 'rememberpassword' ) || $this->mRemember ){
-                       # Or check it by default
-                       # FIXME: this doesn't always work?
-                       $this->mFormFields['Remember']['checked'] = '1';
-               }
-               
-               $form = new HTMLForm( $this->mFormFields );
-               
-               $form->setTitle( $this->getTitle() );
-               $form->setSubmitText( wfMsg( 'createaccount' ) );
-               $form->setSubmitId( 'wpCreateaccount' );
-               $form->suppressReset();
-               $form->setWrapperLegend( wfMsg( 'createaccount' ) );
-               
-               $form->addHiddenField( 'returnto', $this->mReturnTo );
-               $form->addHiddenField( 'returntoquery', $this->mReturnToQuery );
-               
-               $form->addHeaderText( ''
-                       . Html::rawElement( 'p', array( 'id' => 'userloginlink' ),
-                               $link )
-                       . $this->mFormHeader
-                       . $langSelector
-               );
-               $form->addPreText( ''
-                       . $msg
-                       . Html::rawElement( 
-                               'div', 
-                               array( 'id' => 'signupstart' ), 
-                               wfMsgExt( 'loginstart', array( 'parseinline' ) )
-                       )
-               );
-               $form->addPostText(
-                       Html::rawElement( 
-                               'div', 
-                               array( 'id' => 'signupend' ), 
-                               wfMsgExt( 'loginend', array( 'parseinline' ) )
-                       )
-               );
-               
-               # Add a  'send password by email' button if available
-               if( $wgEnableEmail && $wgUser->isLoggedIn() ){
-                       $form->addButton(
-                               'wpCreateaccountMail',
-                               wfMsg( 'createaccountmail' ),
-                               'wpCreateaccountMail'
-                       );
-               }
-               
-               $form->loadData();
-
-               $wgOut->setPageTitle( wfMsg( 'createaccount' ) );
-               $wgOut->setRobotPolicy( 'noindex,nofollow' );
-               $wgOut->setArticleRelated( false );
-               $wgOut->disallowUserJs();  # Stop malicious userscripts sniffing passwords
-
-               
-               $form->displayForm( false );
-               
-       }
-
-       /**
-        * Check if a session cookie is present.
-        *
-        * This will not pick up a cookie set during _this_ request, but is meant
-        * to ensure that the client is returning the cookie which was set on a
-        * previous pass through the system.
-        *
-        * @private
-        */
-       protected function hasSessionCookie() {
-               global $wgDisableCookieCheck, $wgRequest;
-               return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
-       }
-
-       /**
-        * Do a redirect back to the same page, so we can check any
-        * new session cookies.
-        */
-       protected function cookieRedirectCheck() {
-               global $wgOut;
-
-               $query = array( 'wpCookieCheck' => '1' );
-               if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
-               $check = $this->getTitle()->getFullURL( $query );
-
-               return $wgOut->redirect( $check );
-       }
-
-       /**
-        * Check the cookies and show errors if they're not enabled.
-        * @param $type String action being performed
-        */
-       protected function onCookieRedirectCheck() {
-               if ( !$this->hasSessionCookie() ) {
-                       return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
-               } else {
-                       return SpecialUserlogin::successfulLogin( 
-                               array( 'welcomecreate' ), 
-                               $this->mReturnTo, 
-                               $this->mReturnToQuery
-                       );
-               }
-       }
-       
-       /**
-        * Add text to the header.  Only write to $mFormHeader directly  
-        * if you're determined to overwrite anything that other 
-        * extensions might have added.
-        * @param $text String HTML
-        */
-       public function addFormHeader( $text ){
-               $this->mFormHeader .= $text;
-       }
-       
-       /**
-        * Since the UserCreateForm hook was changed to pass a SpecialPage
-        * instead of a QuickTemplate derivative, old extensions might
-        * easily try calling these methods expecing them to exist.  Tempting
-        * though it is to let them have the fatal error, let's at least
-        * fail gracefully...
-        * @deprecated
-        */
-       public function set(){
-               wfDeprecated( __METHOD__ );
-       }
-       public function addInputItem(){
-               wfDeprecated( __METHOD__ );
-       }
-}
index df0969e..3e49354 100644 (file)
@@ -12,48 +12,6 @@ class SpecialResetpass extends SpecialPage {
        public function __construct() {
                parent::__construct( 'Resetpass' );
        }
-       
-       public $mFormFields = array(
-               'Name' => array(
-                       'type'          => 'info',
-                       'label-message' => 'yourname',
-                       'default'       => '',
-               ),
-               'Password' => array(
-                       'type'          => 'password',
-                       'label-message' => 'oldpassword',
-                       'size'          => '20',
-                       'id'            => 'wpPassword',
-                       'required'      => '',
-               ),
-               'NewPassword' => array(
-                       'type'          => 'password',
-                       'label-message' => 'newpassword',
-                       'size'          => '20',
-                       'id'            => 'wpNewPassword',
-                       'required'      => '',
-               ),
-               'Retype' => array(
-                       'type'          => 'password',
-                       'label-message' => 'retypenew',
-                       'size'          => '20',
-                       'id'            => 'wpRetype',
-                       'required'      => '',
-               ),
-               'Remember' => array(
-                       'type'          => 'check',
-                       'label-message' => 'remembermypassword',
-                       'id'            => 'wpRemember',
-               ),
-       );
-       public $mSubmitMsg = 'resetpass-submit-loggedin';
-       public $mHeaderMsg = '';
-       public $mHeaderMsgType = 'error';
-       
-       protected $mUsername;
-       protected $mOldpass;
-       protected $mNewpass;
-       protected $mRetype;
 
        /**
         * Main execution point
@@ -61,142 +19,176 @@ class SpecialResetpass extends SpecialPage {
        function execute( $par ) {
                global $wgUser, $wgAuth, $wgOut, $wgRequest;
 
-               $this->mUsername = $wgRequest->getVal( 'wpName', $wgUser->getName() );
+               $this->mUserName = $wgRequest->getVal( 'wpName' );
                $this->mOldpass = $wgRequest->getVal( 'wpPassword' );
                $this->mNewpass = $wgRequest->getVal( 'wpNewPassword' );
                $this->mRetype = $wgRequest->getVal( 'wpRetype' );
-               $this->mRemember = $wgRequest->getVal( 'wpRemember' );
-               $this->mReturnTo = $wgRequest->getVal( 'returnto' );
-               $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
                
                $this->setHeaders();
                $this->outputHeader();
 
                if( !$wgAuth->allowPasswordChange() ) {
-                       $wgOut->showErrorPage( 'errorpagetitle', 'resetpass_forbidden' );
-                       return false;
+                       $this->error( wfMsg( 'resetpass_forbidden' ) );
+                       return;
                }
 
                if( !$wgRequest->wasPosted() && !$wgUser->isLoggedIn() ) {
-                       $wgOut->showErrorPage( 'errorpagetitle', 'resetpass-no-info' );
-                       return false;
+                       $this->error( wfMsg( 'resetpass-no-info' ) );
+                       return;
                }
 
-               if( $wgRequest->wasPosted() 
-                   && $wgUser->matchEditToken( $wgRequest->getVal('wpEditToken') )
-                       && $this->attemptReset() )
-               {
-                       # Log the user in if they're not already (ie we're 
-                       # coming from the e-mail-password-reset route
-                       if( !$wgUser->isLoggedIn() ) {
-                               $data = array(
-                                       'wpName'     => $this->mUsername,
-                                       'wpPassword' => $this->mNewpass,
-                                       'returnto'   => $this->mReturnTo,
-                               );
-                               if( $this->mRemember ) {
-                                       $data['wpRemember'] = 1;
+               if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal('token') ) ) {
+                       try {
+                               $this->attemptReset( $this->mNewpass, $this->mRetype );
+                               $wgOut->addWikiMsg( 'resetpass_success' );
+                               if( !$wgUser->isLoggedIn() ) {
+                                       $data = array(
+                                               'action'     => 'submitlogin',
+                                               'wpName'     => $this->mUserName,
+                                               'wpPassword' => $this->mNewpass,
+                                               'returnto'   => $wgRequest->getVal( 'returnto' ),
+                                       );
+                                       if( $wgRequest->getCheck( 'wpRemember' ) ) {
+                                               $data['wpRemember'] = 1;
+                                       }
+                                       $login = new LoginForm( new FauxRequest( $data, true ) );
+                                       $login->execute();
                                }
-                               $login = new Login( new FauxRequest( $data, true ) );
-                               $login->attemptLogin();
-                       
-                               # Redirect out to the appropriate target.
-                               SpecialUserlogin::successfulLogin( 
-                                       'resetpass_success', 
-                                       $this->mReturnTo, 
-                                       $this->mReturnToQuery,
-                                       $login->mLoginResult
-                               );
-                       } else {
-                               # Redirect out to the appropriate target.
-                               SpecialUserlogin::successfulLogin( 
-                                       'resetpass_success', 
-                                       $this->mReturnTo, 
-                                       $this->mReturnToQuery
-                               );
+                               $titleObj = Title::newFromText( $wgRequest->getVal( 'returnto' ) );
+                               if ( !$titleObj instanceof Title ) {
+                                       $titleObj = Title::newMainPage();
+                               }
+                               $wgOut->redirect( $titleObj->getFullURL() );
+                       } catch( PasswordError $e ) {
+                               $this->error( $e->getMessage() );
                        }
-               } else {
-                       $this->showForm();
                }
+               $this->showForm();
+       }
+
+       function error( $msg ) {
+               global $wgOut;
+               $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $msg ) );
        }
 
        function showForm() {
-               global $wgOut, $wgUser;
+               global $wgOut, $wgUser, $wgRequest;
 
                $wgOut->disallowUserJs();
-               
-               if( $wgUser->isLoggedIn() ){
-                       unset( $this->mFormFields['Remember'] );
+
+               $self = SpecialPage::getTitleFor( 'Resetpass' );
+               if ( !$this->mUserName ) {
+                       $this->mUserName = $wgUser->getName();
+               }
+               $rememberMe = '';
+               if ( !$wgUser->isLoggedIn() ) {
+                       $rememberMe = '<tr>' .
+                               '<td></td>' .
+                               '<td class="mw-input">' .
+                                       Xml::checkLabel( wfMsg( 'remembermypassword' ),
+                                               'wpRemember', 'wpRemember',
+                                               $wgRequest->getCheck( 'wpRemember' ) ) .
+                               '</td>' .
+                       '</tr>';
+                       $submitMsg = 'resetpass_submit';
+                       $oldpassMsg = 'resetpass-temp-password';
                } else {
-                       # Request is coming from Special:UserLogin after it
-                       # authenticated someone with a temporary password.
-                       $this->mFormFields['Password']['label-message'] = 'resetpass-temp-password';
-                       $this->mSubmitMsg = 'resetpass_submit';
+                       $oldpassMsg = 'oldpassword';
+                       $submitMsg = 'resetpass-submit-loggedin';
                }
-               $this->mFormFields['Name']['default'] = $this->mUsername;
-               
-               $header = $this->mHeaderMsg
-                       ? Xml::element( 'div', array( 'class' => "{$this->mHeaderMsgType}box" ), wfMsg( $this->mHeaderMsg ) )
-                       : '';
-                               
-               $form = new HTMLForm( $this->mFormFields, '' );
-               $form->suppressReset();
-               $form->setSubmitText( wfMsg( $this->mSubmitMsg ) );
-               $form->setTitle( $this->getTitle() );
-               $form->loadData();
-               
-               $formContents = '' 
-                       . $form->getBody()
-                       . $form->getButtons()
-                       . $form->getHiddenFields()
-                       . Html::hidden( 'wpName', $this->mUsername )
-                       . Html::hidden( 'returnto', $this->mReturnTo )
-                       ;
-               $formOutput = $form->wrapForm( $formContents );
-               
                $wgOut->addHTML(
-                       $header
-                       . Html::rawElement( 'fieldset', array( 'class' => 'visualClear' ), ''
-                               . Html::element( 'legend', array(), wfMsg( 'resetpass_header' ) )
-                               . $formOutput
-                       )
+                       Xml::fieldset( wfMsg( 'resetpass_header' ) ) .
+                       Xml::openElement( 'form',
+                               array(
+                                       'method' => 'post',
+                                       'action' => $self->getLocalUrl(),
+                                       'id' => 'mw-resetpass-form' ) ) . "\n" .
+                       Xml::hidden( 'token', $wgUser->editToken() ) . "\n" .
+                       Xml::hidden( 'wpName', $this->mUserName ) . "\n" .
+                       Xml::hidden( 'returnto', $wgRequest->getVal( 'returnto' ) ) . "\n" .
+                       wfMsgExt( 'resetpass_text', array( 'parse' ) ) . "\n" .
+                       Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) . "\n" .
+                       $this->pretty( array(
+                               array( 'wpName', 'username', 'text', $this->mUserName ),
+                               array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass ),
+                               array( 'wpNewPassword', 'newpassword', 'password', null ),
+                               array( 'wpRetype', 'retypenew', 'password', null ),
+                       ) ) . "\n" .
+                       $rememberMe .
+                       "<tr>\n" .
+                               "<td></td>\n" .
+                               '<td class="mw-input">' .
+                                       Xml::submitButton( wfMsg( $submitMsg ) ) .
+                               "</td>\n" .
+                       "</tr>\n" .
+                       Xml::closeElement( 'table' ) .
+                       Xml::closeElement( 'form' ) .
+                       Xml::closeElement( 'fieldset' ) . "\n"
                );
        }
 
+       function pretty( $fields ) {
+               $out = '';
+               foreach ( $fields as $list ) {
+                       list( $name, $label, $type, $value ) = $list;
+                       if( $type == 'text' ) {
+                               $field = htmlspecialchars( $value );
+                       } else {
+                               $attribs = array( 'id' => $name );
+                               if ( $name == 'wpNewPassword' || $name == 'wpRetype' ) {
+                                       $attribs = array_merge( $attribs,
+                                               User::passwordChangeInputAttribs() );
+                               }
+                               if ( $name == 'wpPassword' ) {
+                                       $attribs[] = 'autofocus';
+                               }
+                               $field = Html::input( $name, $value, $type, $attribs );
+                       }
+                       $out .= "<tr>\n";
+                       $out .= "\t<td class='mw-label'>";
+                       if ( $type != 'text' )
+                               $out .= Xml::label( wfMsg( $label ), $name );
+                       else 
+                               $out .=  wfMsgHtml( $label );
+                       $out .= "</td>\n";
+                       $out .= "\t<td class='mw-input'>";
+                       $out .= $field;
+                       $out .= "</td>\n";
+                       $out .= "</tr>";
+               }
+               return $out;
+       }
+
        /**
-        * Try to reset the user's password 
+        * @throws PasswordError when cannot set the new password because requirements not met.
         */
-       protected function attemptReset() {
-               $user = User::newFromName( $this->mUsername );
+       protected function attemptReset( $newpass, $retype ) {
+               $user = User::newFromName( $this->mUserName );
                if( !$user || $user->isAnon() ) {
-                       $this->mHeaderMsg = 'no such user';
-                       return false;
+                       throw new PasswordError( 'no such user' );
                }
                
-               if( $this->mNewpass !== $this->mRetype ) {
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'badretype' ) );
-                       $this->mHeaderMsg = 'badretype';
-                       return false;
+               if( $newpass !== $retype ) {
+                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
+                       throw new PasswordError( wfMsg( 'badretype' ) );
                }
 
                if( !$user->checkTemporaryPassword($this->mOldpass) && !$user->checkPassword($this->mOldpass) ) {
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'wrongpassword' ) );
-                       $this->mHeaderMsg = 'resetpass-wrong-oldpass';
-                       return false;
+                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
+                       throw new PasswordError( wfMsg( 'resetpass-wrong-oldpass' ) );
                }
                
                try {
                        $user->setPassword( $this->mNewpass );
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'success' ) );
+                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
                        $this->mNewpass = $this->mOldpass = $this->mRetypePass = '';
                } catch( PasswordError $e ) {
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $this->mNewpass, 'error' ) );
-                       $this->mHeaderMsg = $e->getMessage();
-                       return false;
+                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
+                       throw new PasswordError( $e->getMessage() );
+                       return;
                }
                
                $user->setCookies();
                $user->saveSettings();
-               return true;
        }
 }
index dd98c1b..da06df0 100644 (file)
 <?php
 /**
- * SpecialPage for logging users into the wiki
+ * @file
  * @ingroup SpecialPage
  */
 
-class SpecialUserLogin extends SpecialPage {
+/**
+ * constructor
+ */
+function wfSpecialUserlogin( $par = '' ) {
+       global $wgRequest;
+       if( session_id() == '' ) {
+               wfSetupSession();
+       }
+
+       $form = new LoginForm( $wgRequest, $par );
+       $form->execute();
+}
 
-       var $mUsername, $mPassword, $mReturnTo, $mCookieCheck, $mPosted;
-       var $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
-       var $mRemember, $mDomain, $mLanguage;
+/**
+ * implements Special:Login
+ * @ingroup SpecialPage
+ */
+class LoginForm {
+
+       const SUCCESS = 0;
+       const NO_NAME = 1;
+       const ILLEGAL = 2;
+       const WRONG_PLUGIN_PASS = 3;
+       const NOT_EXISTS = 4;
+       const WRONG_PASS = 5;
+       const EMPTY_PASS = 6;
+       const RESET_PASS = 7;
+       const ABORTED = 8;
+       const CREATE_BLOCKED = 9;
+       const THROTTLED = 10;
+
+       var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
+       var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
+       var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage;
        var $mSkipCookieCheck, $mReturnToQuery;
 
-       public $mDomains = array();
-
-       public $mFormHeader = ''; # Can be filled by hooks etc
-       public $mFormFields = array(
-               'Name' => array(
-                       'type'          => 'text',
-                       'label-message' => 'yourname',
-                       'id'            => 'wpName1',
-                       'tabindex'      => '1',
-                       'size'          => '20',
-                       'required'      => '1',
-               ),
-               'Password' => array(
-                       'type'          => 'password',
-                       'label-message' => 'yourpassword',
-                       'size'          => '20',
-                       'id'            => 'wpPassword1',
-               ),
-               'Domain' => array(
-                       'type'          => 'select',
-                       'id'            => 'wpDomain',
-                       'label-message' => 'yourdomainname',
-                       'options'       => null,
-                       'default'       => null, 
-               ),
-               'Remember' => array(
-                       'type'          => 'check',
-                       'label-message' => 'remembermypassword',
-                       'id'            => 'wpRemember',
-               )
-       );
-
-       protected $mLogin; # Login object
-
-       public function __construct(){
-               parent::__construct( 'Userlogin' );
+       private $mExtUser = null;
+
+       /**
+        * Constructor
+        * @param WebRequest $request A WebRequest object passed by reference
+        */
+       function LoginForm( &$request, $par = '' ) {
+               global $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
+
+               $this->mType = ( $par == 'signup' ) ? $par : $request->getText( 'type' ); # Check for [[Special:Userlogin/signup]]
+               $this->mName = $request->getText( 'wpName' );
+               $this->mPassword = $request->getText( 'wpPassword' );
+               $this->mRetype = $request->getText( 'wpRetype' );
+               $this->mDomain = $request->getText( 'wpDomain' );
+               $this->mReturnTo = $request->getVal( 'returnto' );
+               $this->mReturnToQuery = $request->getVal( 'returntoquery' );
+               $this->mCookieCheck = $request->getVal( 'wpCookieCheck' );
+               $this->mPosted = $request->wasPosted();
+               $this->mCreateaccount = $request->getCheck( 'wpCreateaccount' );
+               $this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
+                                           && $wgEnableEmail;
+               $this->mMailmypassword = $request->getCheck( 'wpMailmypassword' )
+                                        && $wgEnableEmail;
+               $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
+               $this->mAction = $request->getVal( 'action' );
+               $this->mRemember = $request->getCheck( 'wpRemember' );
+               $this->mLanguage = $request->getText( 'uselang' );
+               $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' );
+
+               if ( $wgRedirectOnLogin ) {
+                       $this->mReturnTo = $wgRedirectOnLogin;
+                       $this->mReturnToQuery = '';
+               }
+
+               if( $wgEnableEmail ) {
+                       $this->mEmail = $request->getText( 'wpEmail' );
+               } else {
+                       $this->mEmail = '';
+               }
+               if( !in_array( 'realname', $wgHiddenPrefs ) ) {
+                   $this->mRealName = $request->getText( 'wpRealName' );
+               } else {
+                   $this->mRealName = '';
+               }
+
+               if( !$wgAuth->validDomain( $this->mDomain ) ) {
+                       $this->mDomain = 'invaliddomain';
+               }
+               $wgAuth->setDomain( $this->mDomain );
+
+               # When switching accounts, it sucks to get automatically logged out
+               $returnToTitle = Title::newFromText( $this->mReturnTo );
+               if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
+                       $this->mReturnTo = '';
+                       $this->mReturnToQuery = '';
+               }
+       }
+
+       function execute() {
+               if ( !is_null( $this->mCookieCheck ) ) {
+                       $this->onCookieRedirectCheck( $this->mCookieCheck );
+                       return;
+               } else if( $this->mPosted ) {
+                       if( $this->mCreateaccount ) {
+                               return $this->addNewAccount();
+                       } else if ( $this->mCreateaccountMail ) {
+                               return $this->addNewAccountMailPassword();
+                       } else if ( $this->mMailmypassword ) {
+                               return $this->mailPassword();
+                       } else if ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
+                               return $this->processLogin();
+                       }
+               }
+               $this->mainLoginForm( '' );
        }
 
-       function execute( $par ) {
-               global $wgRequest;
+       /**
+        * @private
+        */
+       function addNewAccountMailPassword() {
+               global $wgOut;
 
-               # Redirect out for account creation, for B/C
-               $type = ( $par == 'signup' ) ? $par : $wgRequest->getText( 'type' );
-               if( $type == 'signup' ){
-                       $sp = new SpecialCreateAccount();
-                       $sp->execute( $par );
+               if ('' == $this->mEmail) {
+                       $this->mainLoginForm( wfMsg( 'noemail', htmlspecialchars( $this->mName ) ) );
                        return;
                }
-               
-               # Because we're transitioning from logged-out, who might not
-               # have a session, to logged-in, who always do, we need to make
-               # sure that we *always* have a session...
-               if( session_id() == '' ) {
-                       wfSetupSession();
+
+               $u = $this->addNewaccountInternal();
+
+               if ($u == NULL) {
+                       return;
                }
-               
-               $this->loadQuery();
-               $this->mLogin = new Login();
 
-               if ( $wgRequest->getCheck( 'wpCookieCheck' ) ) {
-                       $this->onCookieRedirectCheck();
+               // Wipe the initial password and mail a temporary one
+               $u->setPassword( null );
+               $u->saveSettings();
+               $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
+
+               wfRunHooks( 'AddNewAccount', array( $u, true ) );
+               $u->addNewUserLogEntry();
+
+               $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
+               $wgOut->setRobotPolicy( 'noindex,nofollow' );
+               $wgOut->setArticleRelated( false );
+
+               if( WikiError::isError( $result ) ) {
+                       $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
+               } else {
+                       $wgOut->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() );
+                       $wgOut->returnToMain( false );
+               }
+               $u = 0;
+       }
+
+
+       /**
+        * @private
+        */
+       function addNewAccount() {
+               global $wgUser, $wgEmailAuthentication;
+
+               # Create the account and abort if there's a problem doing so
+               $u = $this->addNewAccountInternal();
+               if( $u == NULL )
                        return;
-               } else if( $wgRequest->wasPosted() ) {
-                       if ( $this->mMailmypassword ) {
-                               return $this->showMailPage();
+
+               # If we showed up language selection links, and one was in use, be
+               # smart (and sensible) and save that language as the user's preference
+               global $wgLoginLanguageSelector;
+               if( $wgLoginLanguageSelector && $this->mLanguage )
+                       $u->setOption( 'language', $this->mLanguage );
+
+               # Send out an email authentication message if needed
+               if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) {
+                       global $wgOut;
+                       $error = $u->sendConfirmationMail();
+                       if( WikiError::isError( $error ) ) {
+                               $wgOut->addWikiMsg( 'confirmemail_sendfailed', $error->getMessage() );
                        } else {
-                               return $this->processLogin();
+                               $wgOut->addWikiMsg( 'confirmemail_oncreate' );
+                       }
+               }
+
+               # Save settings (including confirmation token)
+               $u->saveSettings();
+
+               # If not logged in, assume the new account as the current one and set
+               # session cookies then show a "welcome" message or a "need cookies"
+               # message as needed
+               if( $wgUser->isAnon() ) {
+                       $wgUser = $u;
+                       $wgUser->setCookies();
+                       wfRunHooks( 'AddNewAccount', array( $wgUser ) );
+                       $wgUser->addNewUserLogEntry();
+                       if( $this->hasSessionCookie() ) {
+                               return $this->successfulCreation();
+                       } else {
+                               return $this->cookieRedirectCheck( 'new' );
                        }
                } else {
-                       $this->mainLoginForm( '' );
+                       # Confirm that the account was created
+                       global $wgOut;
+                       $self = SpecialPage::getTitleFor( 'Userlogin' );
+                       $wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
+                       $wgOut->setArticleRelated( false );
+                       $wgOut->setRobotPolicy( 'noindex,nofollow' );
+                       $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
+                       $wgOut->returnToMain( false, $self );
+                       wfRunHooks( 'AddNewAccount', array( $u ) );
+                       $u->addNewUserLogEntry();
+                       return true;
                }
        }
 
        /**
-        * Load member variables from the HTTP request data
-        * @param $par String the fragment passed to execute()
+        * @private
         */
-       protected function loadQuery(){
-               global $wgRequest, $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
+       function addNewAccountInternal() {
+               global $wgUser, $wgOut;
+               global $wgEnableSorbs, $wgProxyWhitelist;
+               global $wgMemc, $wgAccountCreationThrottle;
+               global $wgAuth, $wgMinimalPasswordLength;
+               global $wgEmailConfirmToEdit;
 
-               $this->mUsername = $wgRequest->getText( 'wpName' );
-               $this->mPassword = $wgRequest->getText( 'wpPassword' );
-               $this->mDomain = $wgRequest->getText( 'wpDomain' );
-               $this->mLanguage = $wgRequest->getText( 'uselang' );
+               // If the user passes an invalid domain, something is fishy
+               if( !$wgAuth->validDomain( $this->mDomain ) ) {
+                       $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
+                       return false;
+               }
 
-               $this->mReturnTo = $wgRequest->getVal( 'returnto' );
-               $this->mReturnToQuery = $wgRequest->getVal( 'returntoquery' );
+               // If we are not allowing users to login locally, we should be checking
+               // to see if the user is actually able to authenticate to the authenti-
+               // cation server before they create an account (otherwise, they can
+               // create a local account and login as any domain user). We only need
+               // to check this for domains that aren't local.
+               if( 'local' != $this->mDomain && '' != $this->mDomain ) {
+                       if( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mName ) || !$wgAuth->authenticate( $this->mName, $this->mPassword ) ) ) {
+                               $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
+                               return false;
+                       }
+               }
 
-               $this->mMailmypassword = $wgRequest->getCheck( 'wpMailmypassword' )
-                                        && $wgEnableEmail;
-               $this->mRemember = $wgRequest->getCheck( 'wpRemember' );
-               $this->mSkipCookieCheck = $wgRequest->getCheck( 'wpSkipCookieCheck' );
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return false;
+               }
 
-               if( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       $this->mDomain = 'invaliddomain';
+               # Check permissions
+               if ( !$wgUser->isAllowed( 'createaccount' ) ) {
+                       $this->userNotPrivilegedMessage();
+                       return false;
+               } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
+                       $this->userBlockedMessage();
+                       return false;
                }
-               $wgAuth->setDomain( $this->mDomain );
-       
-               if ( $wgRedirectOnLogin ) {
-                       $this->mReturnTo = $wgRedirectOnLogin;
-                       $this->mReturnToQuery = '';
+
+               $ip = wfGetIP();
+               if ( $wgEnableSorbs && !in_array( $ip, $wgProxyWhitelist ) &&
+                 $wgUser->inSorbsBlacklist( $ip ) )
+               {
+                       $this->mainLoginForm( wfMsg( 'sorbs_create_account_reason' ) . ' (' . htmlspecialchars( $ip ) . ')' );
+                       return;
                }
-               # When switching accounts, it sucks to get automatically logged out
-               $returnToTitle = Title::newFromText( $this->mReturnTo );
-               if( is_object( $returnToTitle ) && $returnToTitle->isSpecial( 'Userlogout' ) ) {
-                       $this->mReturnTo = '';
-                       $this->mReturnToQuery = '';
+
+               # Now create a dummy user ($u) and check if it is valid
+               $name = trim( $this->mName );
+               $u = User::newFromName( $name, 'creatable' );
+               if ( is_null( $u ) ) {
+                       $this->mainLoginForm( wfMsg( 'noname' ) );
+                       return false;
+               }
+
+               if ( 0 != $u->idForName() ) {
+                       $this->mainLoginForm( wfMsg( 'userexists' ) );
+                       return false;
+               }
+
+               if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
+                       $this->mainLoginForm( wfMsg( 'badretype' ) );
+                       return false;
+               }
+
+               # check for minimal password length
+               $valid = $u->isValidPassword( $this->mPassword );
+               if ( $valid !== true ) {
+                       if ( !$this->mCreateaccountMail ) {
+                               $this->mainLoginForm( wfMsgExt( $valid, array( 'parsemag' ), $wgMinimalPasswordLength ) );
+                               return false;
+                       } else {
+                               # do not force a password for account creation by email
+                               # set invalid password, it will be replaced later by a random generated password
+                               $this->mPassword = null;
+                       }
+               }
+
+               # if you need a confirmed email address to edit, then obviously you
+               # need an email address.
+               if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) ) {
+                       $this->mainLoginForm( wfMsg( 'noemailtitle' ) );
+                       return false;
+               }
+
+               if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
+                       $this->mainLoginForm( wfMsg( 'invalidemailaddress' ) );
+                       return false;
+               }
+
+               # Set some additional data so the AbortNewAccount hook can be used for
+               # more than just username validation
+               $u->setEmail( $this->mEmail );
+               $u->setRealName( $this->mRealName );
+
+               $abortError = '';
+               if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
+                       // Hook point to add extra creation throttles and blocks
+                       wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
+                       $this->mainLoginForm( $abortError );
+                       return false;
+               }
+
+               if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
+                       $key = wfMemcKey( 'acctcreate', 'ip', $ip );
+                       $value = $wgMemc->get( $key );
+                       if ( !$value ) {
+                               $wgMemc->set( $key, 0, 86400 );
+                       }
+                       if ( $value >= $wgAccountCreationThrottle ) {
+                               $this->throttleHit( $wgAccountCreationThrottle );
+                               return false;
+                       }
+                       $wgMemc->incr( $key );
+               }
+
+               if( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
+                       $this->mainLoginForm( wfMsg( 'externaldberror' ) );
+                       return false;
                }
+
+               return $this->initUser( $u, false );
        }
 
        /**
-        * Show the main login form
-        * @param $msg String a message key for a warning/error message
-        * that may have been generated on a previous iteration
+        * Actually add a user to the database.
+        * Give it a User object that has been initialised with a name.
+        *
+        * @param $u User object.
+        * @param $autocreate boolean -- true if this is an autocreation via auth plugin
+        * @return User object.
+        * @private
         */
-       protected function mainLoginForm( $msg, $msgtype = 'error' ) {
-               global $wgUser, $wgOut, $wgEnableEmail;
-               global $wgCookiePrefix, $wgLoginLanguageSelector;
-               global $wgAuth, $wgCookieExpiration;
+       function initUser( $u, $autocreate ) {
+               global $wgAuth;
 
-               # Preload the name field with something if we can
-               if ( '' == $this->mUsername ) {
-                       if ( $wgUser->isLoggedIn() ) {
-                               $this->mUsername = $wgUser->getName();
-                       } elseif( isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ) {
-                               $this->mUsername = $_COOKIE[$wgCookiePrefix.'UserName'];
+               $u->addToDatabase();
+
+               if ( $wgAuth->allowPasswordChange() ) {
+                       $u->setPassword( $this->mPassword );
+               }
+
+               $u->setEmail( $this->mEmail );
+               $u->setRealName( $this->mRealName );
+               $u->setToken();
+
+               $wgAuth->initUser( $u, $autocreate );
+
+               if ( $this->mExtUser ) {
+                       $this->mExtUser->link( $u->getId() );
+                       $email = $this->mExtUser->getPref( 'emailaddress' );
+                       if ( $email && !$this->mEmail ) {
+                               $u->setEmail( $email );
                        }
                }
-               if( $this->mUsername ){
-                       $this->mFormFields['Name']['default'] = $this->mUsername;
-                       $this->mFormFields['Password']['autofocus'] = '1';
-               } else {
-                       $this->mFormFields['Name']['autofocus'] = '1';
+
+               $u->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
+               $u->saveSettings();
+
+               # Update user count
+               $ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
+               $ssUpdate->doUpdate();
+
+               return $u;
+       }
+
+       /**
+        * Internally authenticate the login request.
+        *
+        * This may create a local account as a side effect if the
+        * authentication plugin allows transparent local account
+        * creation.
+        *
+        * @public
+        */
+       function authenticateUserData() {
+               global $wgUser, $wgAuth;
+               if ( '' == $this->mName ) {
+                       return self::NO_NAME;
                }
+               
+               global $wgPasswordAttemptThrottle;
 
-               # Parse the error message if we got one
-               if( $msg ){
-                       if( $msgtype == 'error' ){
-                               $msg = wfMsgExt( 'loginerror', 'parseinline' ) . ' ' . $msg;
+               $throttleCount = 0;
+               if ( is_array( $wgPasswordAttemptThrottle ) ) {
+                       $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
+                       $count = $wgPasswordAttemptThrottle['count'];
+                       $period = $wgPasswordAttemptThrottle['seconds'];
+                       
+                       global $wgMemc;
+                       $throttleCount = $wgMemc->get( $throttleKey );
+                       if ( !$throttleCount ) {
+                               $wgMemc->add( $throttleKey, 1, $period ); // start counter
+                       } else if ( $throttleCount < $count ) {
+                               $wgMemc->incr($throttleKey);
+                       } else if ( $throttleCount >= $count ) {
+                               return self::THROTTLED;
+                       }
+               }
+
+               // Load $wgUser now, and check to see if we're logging in as the same
+               // name. This is necessary because loading $wgUser (say by calling
+               // getName()) calls the UserLoadFromSession hook, which potentially
+               // creates the user in the database. Until we load $wgUser, checking
+               // for user existence using User::newFromName($name)->getId() below
+               // will effectively be using stale data.
+               if ( $wgUser->getName() === $this->mName ) {
+                       wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
+                       return self::SUCCESS;
+               }
+
+               $this->mExtUser = ExternalUser::newFromName( $this->mName );
+
+               # TODO: Allow some magic here for invalid external names, e.g., let the
+               # user choose a different wiki name.
+               $u = User::newFromName( $this->mName );
+               if( is_null( $u ) || !User::isUsableName( $u->getName() ) ) {
+                       return self::ILLEGAL;
+               }
+
+               $isAutoCreated = false;
+               if ( 0 == $u->getID() ) {
+                       $status = $this->attemptAutoCreate( $u );
+                       if ( $status !== self::SUCCESS ) {
+                               return $status;
+                       } else {
+                               $isAutoCreated = true;
                        }
-                       $msg = Html::rawElement(
-                               'div',
-                               array( 'class' => $msgtype . 'box' ),
-                               $msg
-                       );
                } else {
-                       $msg = '';
+                       $u->load();
                }
 
-               # Make sure the returnTo strings don't get lost if the
-               # user changes language, etc
-               $linkq = array();
-               if ( !empty( $this->mReturnTo ) ) {
-                       $linkq['returnto'] = wfUrlencode( $this->mReturnTo );
-                       if ( !empty( $this->mReturnToQuery ) )
-                               $linkq['returntoquery'] = wfUrlencode( $this->mReturnToQuery );
+               // Give general extensions, such as a captcha, a chance to abort logins
+               $abort = self::ABORTED;
+               if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort ) ) ) {
+                       return $abort;
                }
 
-               # Pass any language selection on to the mode switch link
-               if( $wgLoginLanguageSelector && $this->mLanguage )
-                       $linkq['uselang'] = $this->mLanguage;
+               if (!$u->checkPassword( $this->mPassword )) {
+                       if( $u->checkTemporaryPassword( $this->mPassword ) ) {
+                               // The e-mailed temporary password should not be used for actu-
+                               // al logins; that's a very sloppy habit, and insecure if an
+                               // attacker has a few seconds to click "search" on someone's o-
+                               // pen mail reader.
+                               //
+                               // Allow it to be used only to reset the password a single time
+                               // to a new value, which won't be in the user's e-mail ar-
+                               // chives.
+                               //
+                               // For backwards compatibility, we'll still recognize it at the
+                               // login form to minimize surprises for people who have been
+                               // logging in with a temporary password for some time.
+                               //
+                               // As a side-effect, we can authenticate the user's e-mail ad-
+                               // dress if it's not already done, since the temporary password
+                               // was sent via e-mail.
+                               if( !$u->isEmailConfirmed() ) {
+                                       $u->confirmEmail();
+                                       $u->saveSettings();
+                               }
 
-               $skin = $wgUser->getSkin();
-               $link = $skin->link( 
-                       SpecialPage::getTitleFor( 'CreateAccount' ),
-                       wfMsgHtml( 'nologinlink' ),
-                       array(),
-                       $linkq );
+                               // At this point we just return an appropriate code/ indicating
+                               // that the UI should show a password reset form; bot inter-
+                               // faces etc will probably just fail cleanly here.
+                               $retval = self::RESET_PASS;
+                       } else {
+                               $retval = '' == $this->mPassword ? self::EMPTY_PASS : self::WRONG_PASS;
+                       }
+               } else {
+                       $wgAuth->updateUser( $u );
+                       $wgUser = $u;
 
-               # Don't show a "create account" link if the user can't
-               $link = $wgUser->isAllowed( 'createaccount' ) && !$wgUser->isLoggedIn()
-                       ? wfMsgWikiHtml( 'nologin', $link )
-                       : '';
+                       // Please reset throttle for successful logins, thanks!
+                       if($throttleCount) {
+                               $wgMemc->delete($throttleKey);
+                       }
 
-               # Prepare language selection links as needed
-               $langSelector = $wgLoginLanguageSelector 
-                       ? Html::rawElement( 
-                               'div',
-                               array( 'id' => 'languagelinks' ),
-                               self::makeLanguageSelector( $this->getTitle(), $this->mReturnTo ) )
-                       : '';
-
-               # Give authentication and captcha plugins a chance to 
-               # modify the form, by hook or by using $wgAuth
-               $wgAuth->modifyUITemplate( $this, 'login' );
-               wfRunHooks( 'UserLoginForm', array( &$this ) );
-       
-               # The most likely use of the hook is to enable domains;
-               # check that now, and add fields if necessary
-               if( $this->mDomains ){
-                       $this->mFormFields['Domain']['options'] = $this->mDomains;
-                       $this->mFormFields['Domain']['default'] = $this->mDomain;
+                       if ( $isAutoCreated ) {
+                               // Must be run after $wgUser is set, for correct new user log
+                               wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
+                       }
+
+                       $retval = self::SUCCESS;
+               }
+               wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
+               return $retval;
+       }
+
+       /**
+        * Attempt to automatically create a user on login. Only succeeds if there
+        * is an external authentication method which allows it.
+        * @return integer Status code
+        */
+       function attemptAutoCreate( $user ) {
+               global $wgAuth, $wgUser, $wgAutocreatePolicy;
+
+               if ( $wgUser->isBlockedFromCreateAccount() ) {
+                       wfDebug( __METHOD__.": user is blocked from account creation\n" );
+                       return self::CREATE_BLOCKED;
+               }
+
+               /**
+                * If the external authentication plugin allows it, automatically cre-
+                * ate a new account for users that are externally defined but have not
+                * yet logged in.
+                */
+               if ( $this->mExtUser ) {
+                       # mExtUser is neither null nor false, so use the new ExternalAuth
+                       # system.
+                       if ( $wgAutocreatePolicy == 'never' ) {
+                               return self::NOT_EXISTS;
+                       }
+                       if ( !$this->mExtUser->authenticate( $this->mPassword ) ) {
+                               return self::WRONG_PLUGIN_PASS;
+                       }
                } else {
-                       unset( $this->mFormFields['Domain'] );
+                       # Old AuthPlugin.
+                       if ( !$wgAuth->autoCreate() ) {
+                               return self::NOT_EXISTS;
+                       }
+                       if ( !$wgAuth->userExists( $user->getName() ) ) {
+                               wfDebug( __METHOD__.": user does not exist\n" );
+                               return self::NOT_EXISTS;
+                       }
+                       if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) {
+                               wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" );
+                               return self::WRONG_PLUGIN_PASS;
+                       }
                }
-               
-               # Or to tweak the 'remember my password' checkbox
-               if( !($wgCookieExpiration > 0) ){
-                       # Remove it altogether
-                       unset( $this->mFormFields['Remember'] );
-               } elseif( $wgUser->getOption( 'rememberpassword' ) || $this->mRemember ){
-                       # Or check it by default
-                       # FIXME: this doesn't always work?
-                       $this->mFormFields['Remember']['checked'] = '1';
+
+               wfDebug( __METHOD__.": creating account\n" );
+               $user = $this->initUser( $user, true );
+               return self::SUCCESS;
+       }
+
+       function processLogin() {
+               global $wgUser, $wgAuth;
+
+               switch ( $this->authenticateUserData() ) {
+                       case self::SUCCESS:
+                               # We've verified now, update the real record
+                               if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) {
+                                       $wgUser->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 );
+                                       $wgUser->saveSettings();
+                               } else {
+                                       $wgUser->invalidateCache();
+                               }
+                               $wgUser->setCookies();
+
+                               // Reset the throttle
+                               $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
+                               global $wgMemc;
+                               $wgMemc->delete( $key );
+
+                               if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
+                                       /* Replace the language object to provide user interface in
+                                        * correct language immediately on this first page load.
+                                        */
+                                       global $wgLang, $wgRequest;
+                                       $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
+                                       $wgLang = Language::factory( $code );
+                                       return $this->successfulLogin();
+                               } else {
+                                       return $this->cookieRedirectCheck( 'login' );
+                               }
+                               break;
+
+                       case self::NO_NAME:
+                       case self::ILLEGAL:
+                               $this->mainLoginForm( wfMsg( 'noname' ) );
+                               break;
+                       case self::WRONG_PLUGIN_PASS:
+                               $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
+                               break;
+                       case self::NOT_EXISTS:
+                               if( $wgUser->isAllowed( 'createaccount' ) ){
+                                       $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
+                               } else {
+                                       $this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
+                               }
+                               break;
+                       case self::WRONG_PASS:
+                               $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
+                               break;
+                       case self::EMPTY_PASS:
+                               $this->mainLoginForm( wfMsg( 'wrongpasswordempty' ) );
+                               break;
+                       case self::RESET_PASS:
+                               $this->resetLoginForm( wfMsg( 'resetpass_announce' ) );
+                               break;
+                       case self::CREATE_BLOCKED:
+                               $this->userBlockedMessage();
+                               break;
+                       case self::THROTTLED:
+                               $this->mainLoginForm( wfMsg( 'login-throttled' ) );
+                               break;
+                       default:
+                               throw new MWException( "Unhandled case value" );
                }
+       }
+
+       function resetLoginForm( $error ) {
+               global $wgOut;
+               $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
+               $reset = new SpecialResetpass();
+               $reset->execute( null );
+       }
+
+       /**
+        * @private
+        */
+       function mailPassword() {
+               global $wgUser, $wgOut, $wgAuth;
                
-               $form = new HTMLForm( $this->mFormFields, '' );
-               $form->setTitle( $this->getTitle() );
-               $form->setSubmitText( wfMsg( 'login' ) );
-               $form->setSubmitId( 'wpLoginAttempt' );
-               $form->suppressReset();
-               $form->setWrapperLegend( wfMsg( 'userlogin' ) );
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return false;
+               }
                
-               $form->addHiddenField( 'returnto', $this->mReturnTo );
-               $form->addHiddenField( 'returntoquery', $this->mReturnToQuery );
+               if( !$wgAuth->allowPasswordChange() ) {
+                       $this->mainLoginForm( wfMsg( 'resetpass_forbidden' ) );
+                       return;
+               }
+
+               # Check against blocked IPs
+               # fixme -- should we not?
+               if( $wgUser->isBlocked() ) {
+                       $this->mainLoginForm( wfMsg( 'blocked-mailpassword' ) );
+                       return;
+               }
                
-               $form->addHeaderText( ''
-                       . Html::rawElement( 'p', array( 'id' => 'userloginlink' ),
-                               $link )
-                       . Html::rawElement( 'div', array( 'id' => 'userloginprompt' ),
-                               wfMsgExt( 'loginprompt', array( 'parseinline' ) ) )
-                       . $this->mFormHeader
-                       . $langSelector
-               );
-               $form->addPreText( ''
-                       . $msg
-                       . Html::rawElement( 
-                               'div', 
-                               array( 'id' => 'loginstart' ), 
-                               wfMsgExt( 'loginstart', array( 'parseinline' ) )
-                       )
-               );
-               $form->addPostText(
-                       Html::rawElement( 
-                               'div', 
-                               array( 'id' => 'loginend' ), 
-                               wfMsgExt( 'loginend', array( 'parseinline' ) )
-                       )
-               );
+               // Check for hooks
+               $error = null;
+               if ( ! wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$error ) ) ) {
+                       $this->mainLoginForm( $error );
+                       return;
+               }
+
+               # Check against the rate limiter
+               if( $wgUser->pingLimiter( 'mailpassword' ) ) {
+                       $wgOut->rateLimited();
+                       return;
+               }
+
+               if ( '' == $this->mName ) {
+                       $this->mainLoginForm( wfMsg( 'noname' ) );
+                       return;
+               }
+               $u = User::newFromName( $this->mName );
+               if( is_null( $u ) ) {
+                       $this->mainLoginForm( wfMsg( 'noname' ) );
+                       return;
+               }
+               if ( 0 == $u->getID() ) {
+                       $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $u->getName() ) ) );
+                       return;
+               }
+
+               # Check against password throttle
+               if ( $u->isPasswordReminderThrottled() ) {
+                       global $wgPasswordReminderResendTime;
+                       # Round the time in hours to 3 d.p., in case someone is specifying
+                       # minutes or seconds.
+                       $this->mainLoginForm( wfMsgExt( 'throttled-mailpassword', array( 'parsemag' ),
+                               round( $wgPasswordReminderResendTime, 3 ) ) );
+                       return;
+               }
+
+               $result = $this->mailPasswordInternal( $u, true, 'passwordremindertitle', 'passwordremindertext' );
+               if( WikiError::isError( $result ) ) {
+                       $this->mainLoginForm( wfMsg( 'mailerror', $result->getMessage() ) );
+               } else {
+                       $this->mainLoginForm( wfMsg( 'passwordsent', $u->getName() ), 'success' );
+               }
+       }
+
+
+       /**
+        * @param object user
+        * @param bool throttle
+        * @param string message name of email title
+        * @param string message name of email text
+        * @return mixed true on success, WikiError on failure
+        * @private
+        */
+       function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext' ) {
+               global $wgServer, $wgScript, $wgUser, $wgNewPasswordExpiry;
+
+               if ( '' == $u->getEmail() ) {
+                       return new WikiError( wfMsg( 'noemail', $u->getName() ) );
+               }
+               $ip = wfGetIP();
+               if( !$ip ) {
+                       return new WikiError( wfMsg( 'badipaddress' ) );
+               }
                
-               # Add a  'mail reset' button if available
-               $buttons = '';
-               if( $wgEnableEmail && $wgAuth->allowPasswordChange() ){
-                       $form->addButton(
-                               'wpMailmypassword',
-                               wfMsg( 'mailmypassword' ),
-                               'wpMailmypassword'
-                       );
+               wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$u) );
+
+               $np = $u->randomPassword();
+               $u->setNewpassword( $np, $throttle );
+               $u->saveSettings();
+
+               $m = wfMsgExt( $emailText, array( 'parsemag' ), $ip, $u->getName(), $np,
+                               $wgServer . $wgScript, round( $wgNewPasswordExpiry / 86400 ) );
+               $result = $u->sendMail( wfMsg( $emailTitle ), $m );
+
+               return $result;
+       }
+
+
+       /**
+        * Run any hooks registered for logins, then HTTP redirect to
+        * $this->mReturnTo (or Main Page if that's undefined).  Formerly we had a
+        * nice message here, but that's really not as useful as just being sent to
+        * wherever you logged in from.  It should be clear that the action was
+        * successful, given the lack of error messages plus the appearance of your
+        * name in the upper right.
+        *
+        * @private
+        */
+       function successfulLogin() {
+               global $wgUser, $wgOut;
+
+               # Run any hooks; display injected HTML if any, else redirect
+               $injected_html = '';
+               wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
+
+               if( $injected_html !== '' ) {
+                       $this->displaySuccessfulLogin( 'loginsuccess', $injected_html );
+               } else {
+                       $titleObj = Title::newFromText( $this->mReturnTo );
+                       if ( !$titleObj instanceof Title ) {
+                               $titleObj = Title::newMainPage();
+                       }
+                       $wgOut->redirect( $titleObj->getFullURL( $this->mReturnToQuery ) );
                }
+       }
+
+       /**
+        * Run any hooks registered for logins, then display a message welcoming
+        * the user.
+        *
+        * @private
+        */
+       function successfulCreation() {
+               global $wgUser, $wgOut;
+
+               # Run any hooks; display injected HTML
+               $injected_html = '';
+               wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
+
+               $this->displaySuccessfulLogin( 'welcomecreation', $injected_html );
+       }
+
+       /**
+        * Display a "login successful" page.
+        */
+       private function displaySuccessfulLogin( $msgname, $injected_html ) {
+               global $wgOut, $wgUser;
+
+               $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
+               $wgOut->setRobotPolicy( 'noindex,nofollow' );
+               $wgOut->setArticleRelated( false );
+               $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
+               $wgOut->addHTML( $injected_html );
+
+               if ( !empty( $this->mReturnTo ) ) {
+                       $wgOut->returnToMain( null, $this->mReturnTo, $this->mReturnToQuery );
+               } else {
+                       $wgOut->returnToMain( null );
+               }
+       }
+
+       /** */
+       function userNotPrivilegedMessage($errors) {
+               global $wgOut;
+
+               $wgOut->setPageTitle( wfMsg( 'permissionserrors' ) );
+               $wgOut->setRobotPolicy( 'noindex,nofollow' );
+               $wgOut->setArticleRelated( false );
+
+               $wgOut->addWikitext( $wgOut->formatPermissionsErrorMessage( $errors, 'createaccount' ) );
+               // Stuff that might want to be added at the end. For example, instruc-
+               // tions if blocked.
+               $wgOut->addWikiMsg( 'cantcreateaccount-nonblock-text' );
+
+               $wgOut->returnToMain( false );
+       }
+
+       /** */
+       function userBlockedMessage() {
+               global $wgOut, $wgUser;
+
+               # Let's be nice about this, it's likely that this feature will be used
+               # for blocking large numbers of innocent people, e.g. range blocks on
+               # schools. Don't blame it on the user. There's a small chance that it
+               # really is the user's fault, i.e. the username is blocked and they
+               # haven't bothered to log out before trying to create an account to
+               # evade it, but we'll leave that to their guilty conscience to figure
+               # out.
+
+               $wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
+               $wgOut->setRobotPolicy( 'noindex,nofollow' );
+               $wgOut->setArticleRelated( false );
+
+               $ip = wfGetIP();
+               $blocker = User::whoIs( $wgUser->mBlock->mBy );
+               $block_reason = $wgUser->mBlock->mReason;
+
+               if ( strval( $block_reason ) === '' ) {
+                       $block_reason = wfMsg( 'blockednoreason' );
+               }
+               $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
+               $wgOut->returnToMain( false );
+       }
+
+       /**
+        * @private
+        */
+       function mainLoginForm( $msg, $msgtype = 'error' ) {
+               global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
+               global $wgCookiePrefix, $wgLoginLanguageSelector;
+               global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
+               
+               $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
                
-               $form->loadData();
+               if ( $this->mType == 'signup' ) {
+                       // Block signup here if in readonly. Keeps user from 
+                       // going through the process (filling out data, etc) 
+                       // and being informed later.
+                       if ( wfReadOnly() ) {
+                               $wgOut->readOnlyPage();
+                               return;
+                       } elseif ( $wgUser->isBlockedFromCreateAccount() ) {
+                               $this->userBlockedMessage();
+                               return;
+                       } elseif ( count( $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
+                               $wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
+                               return;
+                       }
+               }
+
+               if ( '' == $this->mName ) {
+                       if ( $wgUser->isLoggedIn() ) {
+                               $this->mName = $wgUser->getName();
+                       } else {
+                               $this->mName = isset( $_COOKIE[$wgCookiePrefix.'UserName'] ) ? $_COOKIE[$wgCookiePrefix.'UserName'] : null;
+                       }
+               }
 
-               $wgOut->setPageTitle( wfMsg( 'login' ) );
+               $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
+
+               if ( $this->mType == 'signup' ) {
+                       $template = new UsercreateTemplate();
+                       $q = 'action=submitlogin&type=signup';
+                       $linkq = 'type=login';
+                       $linkmsg = 'gotaccount';
+               } else {
+                       $template = new UserloginTemplate();
+                       $q = 'action=submitlogin&type=login';
+                       $linkq = 'type=signup';
+                       $linkmsg = 'nologin';
+               }
+
+               if ( !empty( $this->mReturnTo ) ) {
+                       $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
+                       if ( !empty( $this->mReturnToQuery ) )
+                               $returnto .= '&returntoquery=' .
+                                       wfUrlencode( $this->mReturnToQuery );
+                       $q .= $returnto;
+                       $linkq .= $returnto;
+               }
+
+               # Pass any language selection on to the mode switch link
+               if( $wgLoginLanguageSelector && $this->mLanguage )
+                       $linkq .= '&uselang=' . $this->mLanguage;
+
+               $link = '<a href="' . htmlspecialchars ( $titleObj->getLocalUrl( $linkq ) ) . '">';
+               $link .= wfMsgHtml( $linkmsg . 'link' ); # Calling either 'gotaccountlink' or 'nologinlink'
+               $link .= '</a>';
+
+               # Don't show a "create account" link if the user can't
+               if( $this->showCreateOrLoginLink( $wgUser ) )
+                       $template->set( 'link', wfMsgWikiHtml( $linkmsg, $link ) );
+               else
+                       $template->set( 'link', '' );
+
+               $template->set( 'header', '' );
+               $template->set( 'name', $this->mName );
+               $template->set( 'password', $this->mPassword );
+               $template->set( 'retype', $this->mRetype );
+               $template->set( 'email', $this->mEmail );
+               $template->set( 'realname', $this->mRealName );
+               $template->set( 'domain', $this->mDomain );
+
+               $template->set( 'action', $titleObj->getLocalUrl( $q ) );
+               $template->set( 'message', $msg );
+               $template->set( 'messagetype', $msgtype );
+               $template->set( 'createemail', $wgEnableEmail && $wgUser->isLoggedIn() );
+               $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
+               $template->set( 'useemail', $wgEnableEmail );
+               $template->set( 'emailrequired', $wgEmailConfirmToEdit );
+               $template->set( 'canreset', $wgAuth->allowPasswordChange() );
+               $template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
+               $template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) or $this->mRemember  );
+
+               # Prepare language selection links as needed
+               if( $wgLoginLanguageSelector ) {
+                       $template->set( 'languages', $this->makeLanguageSelector() );
+                       if( $this->mLanguage )
+                               $template->set( 'uselang', $this->mLanguage );
+               }
+
+               // Give authentication and captcha plugins a chance to modify the form
+               $wgAuth->modifyUITemplate( $template, $this->mType );
+               if ( $this->mType == 'signup' ) {
+                       wfRunHooks( 'UserCreateForm', array( &$template ) );
+               } else {
+                       wfRunHooks( 'UserLoginForm', array( &$template ) );
+               }
+
+               $wgOut->setPageTitle( wfMsg( 'userlogin' ) );
                $wgOut->setRobotPolicy( 'noindex,nofollow' );
                $wgOut->setArticleRelated( false );
-               $wgOut->disallowUserJs();  # Stop malicious userscripts sniffing passwords
+               $wgOut->disallowUserJs();  // just in case...
+               $wgOut->addTemplate( $template );
+       }
 
-               $form->displayForm( '' );
-       }       
+       /**
+        * @private
+        */
+       function showCreateOrLoginLink( &$user ) {
+               if( $this->mType == 'signup' ) {
+                       return( true );
+               } elseif( $user->isAllowed( 'createaccount' ) ) {
+                       return( true );
+               } else {
+                       return( false );
+               }
+       }
 
        /**
         * Check if a session cookie is present.
@@ -280,49 +967,57 @@ class SpecialUserLogin extends SpecialPage {
         *
         * @private
         */
-       protected function hasSessionCookie() {
+       function hasSessionCookie() {
                global $wgDisableCookieCheck, $wgRequest;
-               return $wgDisableCookieCheck || $wgRequest->checkSessionCookie();
+               return $wgDisableCookieCheck ? true : $wgRequest->checkSessionCookie();
        }
 
        /**
-        * Do a redirect back to the same page, so we can check any
-        * new session cookies.
+        * @private
         */
-       protected function cookieRedirectCheck() {
+       function cookieRedirectCheck( $type ) {
                global $wgOut;
 
-               $query = array( 'wpCookieCheck' => '1');
+               $titleObj = SpecialPage::getTitleFor( 'Userlogin' );
+               $query = array( 'wpCookieCheck' => $type );
                if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
-               $check = $this->getTitle()->getFullURL( $query );
+               $check = $titleObj->getFullURL( $query );
 
                return $wgOut->redirect( $check );
        }
 
        /**
-        * Check the cookies and show errors if they're not enabled.
-        * @param $type String action being performed
+        * @private
         */
-       protected function onCookieRedirectCheck() {
-               if ( $this->hasSessionCookie() ) {
-                       return self::successfulLogin( 
-                               'loginsuccess', 
-                               $this->mReturnTo, 
-                               $this->mReturnToQuery
-                       );
+       function onCookieRedirectCheck( $type ) {
+               if ( !$this->hasSessionCookie() ) {
+                       if ( $type == 'new' ) {
+                               return $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
+                       } else if ( $type == 'login' ) {
+                               return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
+                       } else {
+                               # shouldn't happen
+                               return $this->mainLoginForm( wfMsg( 'error' ) );
+                       }
                } else {
-                       return $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
+                       return $this->successfulLogin();
                }
        }
 
+       /**
+        * @private
+        */
+       function throttleHit( $limit ) {
+               $this->mainLoginForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $limit ) );
+       }
+
        /**
         * Produce a bar of links which allow the user to select another language
         * during login/registration but retain "returnto"
-        * @param $title Title to use in the link
-        * @param $returnTo query string to append
-        * @return String HTML for bar
+        *
+        * @return string
         */
-       public static function makeLanguageSelector( $title, $returnTo=false ) {
+       function makeLanguageSelector() {
                global $wgLang;
 
                $msg = wfMsgForContent( 'loginlanguagelinks' );
@@ -333,8 +1028,7 @@ class SpecialUserLogin extends SpecialPage {
                                $lang = trim( $lang, '* ' );
                                $parts = explode( '|', $lang );
                                if (count($parts) >= 2) {
-                                       $links[] = SpecialUserLogin::makeLanguageSelectorLink( 
-                                                       $parts[0], $parts[1], $title, $returnTo );
+                                       $links[] = $this->makeLanguageSelectorLink( $parts[0], $parts[1] );
                                }
                        }
                        return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
@@ -346,214 +1040,24 @@ class SpecialUserLogin extends SpecialPage {
        /**
         * Create a language selector link for a particular language
         * Links back to this page preserving type and returnto
+        *
         * @param $text Link text
         * @param $lang Language code
-        * @param $title Title to link to
-        * @param $returnTo String returnto query
         */
-       public static function makeLanguageSelectorLink( $text, $lang, $title, $returnTo=false ) {
+       function makeLanguageSelectorLink( $text, $lang ) {
                global $wgUser;
+               $self = SpecialPage::getTitleFor( 'Userlogin' );
                $attr = array( 'uselang' => $lang );
-               if( $returnTo )
-                       $attr['returnto'] = $returnTo;
+               if( $this->mType == 'signup' )
+                       $attr['type'] = 'signup';
+               if( $this->mReturnTo )
+                       $attr['returnto'] = $this->mReturnTo;
                $skin = $wgUser->getSkin();
                return $skin->linkKnown(
-                       $title,
+                       $self,
                        htmlspecialchars( $text ),
                        array(),
                        $attr
                );
        }
-
-       /**
-        * Display a "login successful" page.
-        * @param $message String message key of main message to display
-        * @param $html String HTML to optionally add
-        * @param $returnto Title to returnto
-        * @param $returntoQuery String query string for returnto link
-        */
-       public static function displaySuccessfulLogin( $message, $html='', $returnTo=false, $returnToQuery=false ) {
-               global $wgOut, $wgUser;
-               
-               $wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
-               $wgOut->setRobotPolicy( 'noindex,nofollow' );
-               $wgOut->setArticleRelated( false );
-               $wgOut->addWikiMsg( $message, $wgUser->getName() );
-               $wgOut->addHTML( $html );
-
-               if ( $returnTo ) {
-                       $wgOut->returnToMain( null, $returnTo, $returnToQuery );
-               } else {
-                       $wgOut->returnToMain( null );
-               }
-       }
-
-       /**
-        * Display any messages generated by hooks, or HTTP redirect to
-        * $this->mReturnTo (or Main Page if that's undefined).  Formerly we had a
-        * nice message here, but that's not as useful as just being sent to
-        * wherever you logged in from.  It should be clear that the action was
-        * successful, given the lack of error messages plus the appearance of your
-        * name in the upper right.
-        * 
-        * Remember that this function can be accessed from a variety of 
-        * places, such as Special:ResetPass, or Special:CreateAccount.
-        * @param $message String message key of a message to display if
-        *   we don't redirect
-        * @param $returnTo String title of page to redirect to
-        * @param $returnToQuery String query string to add to the redirect.
-        * @param $html String empty string to go straight 
-        *   to the redirect, or valid HTML to add underneath the text.
-        */
-       public static function successfulLogin( $message, $returnTo='', $returnToQuery='', $html='' ) {
-               global $wgUser, $wgOut;
-
-               if( $html === '' ) {
-                       $titleObj = Title::newFromText( $returnTo );
-                       if ( !$titleObj instanceof Title ) {
-                               $titleObj = Title::newMainPage();
-                       }
-                       $wgOut->redirect( $titleObj->getFullURL( $returnToQuery ) );
-               } else {
-                       SpecialUserLogin::displaySuccessfulLogin( $message, $html, $returnTo, $returnToQuery );
-               }
-       }
-       
-
-       protected function processLogin(){
-               global $wgUser, $wgAuth;
-               $result = $this->mLogin->attemptLogin();
-               switch ( $result ) {
-                       case Login::SUCCESS:
-                               if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
-                                       # Replace the language object to provide user interface in
-                                       # correct language immediately on this first page load.
-                                       global $wgLang, $wgRequest;
-                                       $code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
-                                       $wgLang = Language::factory( $code );
-                                       return self::successfulLogin( 
-                                               'loginsuccess', 
-                                               $this->mReturnTo, 
-                                               $this->mReturnToQuery,
-                                               $this->mLogin->mLoginResult );
-                               } else {
-                                       # Do a redirect check to ensure that the cookies are 
-                                       # being retained by the user's browser.
-                                       return $this->cookieRedirectCheck();
-                               }
-                               break;
-
-                       case Login::NO_NAME:
-                       case Login::ILLEGAL:
-                       case Login::WRONG_PLUGIN_PASS:
-                       case Login::WRONG_PASS:
-                       case Login::EMPTY_PASS:
-                       case Login::THROTTLED:
-                               $this->mainLoginForm( wfMsgExt( $this->mLogin->mLoginResult, 'parseinline' ) );
-                               break;
-                               
-                       case Login::NOT_EXISTS:
-                               if( $wgUser->isAllowed( 'createaccount' ) ){
-                                       $this->mainLoginForm( wfMsgExt( 'nosuchuser', 'parseinline', htmlspecialchars( $this->mUsername ) ) );
-                               } else {
-                                       $this->mainLoginForm( wfMsgExt( 'nosuchusershort', 'parseinline', htmlspecialchars( $this->mUsername ) ) );
-                               }
-                               break;
-                               
-                       case Login::RESET_PASS:
-                               # 'Shell out' to Special:ResetPass to get the user to 
-                               # set a new permanent password from a temporary one.
-                               $reset = new SpecialResetpass();
-                               $reset->mHeaderMsg = 'resetpass_announce';
-                               $reset->mHeaderMsgType = 'success';
-                               $reset->execute( null );
-                               break;
-                               
-                       case Login::CREATE_BLOCKED:
-                               $this->userBlockedMessage();
-                               break;
-                               
-                       case Login::ABORTED: 
-                               $msg = $this->mLogin->mLoginResult ? $this->mLogin->mLoginResult : $this->mLogin->mCreateResult;
-                               $this->mainLoginForm( wfMsgExt( $msg, 'parseinline' ) );
-                               break;
-                               
-                       default:
-                               throw new MWException( "Unhandled case value: $result" );
-               }
-       }
-
-       /**
-        * Attempt to send the user a password-reset mail, and display
-        * the results (good, bad or ugly).
-        */
-       protected function showMailPage(){
-               global $wgOut;
-               $result = $this->mLogin->mailPassword();
-
-               switch( $result ){
-                       case Login::READ_ONLY : 
-                               $wgOut->readOnlyPage();
-                               return;
-                       case Login::MAIL_PASSCHANGE_FORBIDDEN:
-                               $this->mainLoginForm( wfMsgExt( 'resetpass_forbidden', 'parseinline' ) );
-                               return;
-                       case Login::MAIL_BLOCKED: 
-                               $this->mainLoginForm( wfMsgExt( 'blocked-mailpassword', 'parseinline' ) );
-                               return;
-                       case Login::MAIL_PING_THROTTLED: 
-                               $wgOut->rateLimited();
-                               return;
-                       case Login::MAIL_PASS_THROTTLED: 
-                               global $wgPasswordReminderResendTime;
-                               # Round the time in hours to 3 d.p., in case someone 
-                               # is specifying minutes or seconds.
-                               $this->mainLoginForm( wfMsgExt( 
-                                       'throttled-mailpassword', 
-                                       array( 'parsemag' ),
-                                       round( $wgPasswordReminderResendTime, 3 )
-                               ) );
-                               return;
-                       case Login::NO_NAME: 
-                               $this->mainLoginForm( wfMsgExt( 'noname', 'parseinline' ) );
-                               return;
-                       case Login::NOT_EXISTS: 
-                               $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mLogin->mUser->getName() ) ) );
-                               return;
-                       case Login::MAIL_EMPTY_EMAIL: 
-                               $this->mainLoginForm( wfMsgExt( 'noemail', 'parseinline', $this->mLogin->mUser->getName() ) );
-                               return;
-                       case Login::MAIL_BAD_IP: 
-                               $this->mainLoginForm( wfMsgExt( 'badipaddress', 'parseinline' ) );
-                               return;
-                       case Login::MAIL_ERROR: 
-                               $this->mainLoginForm( wfMsgExt( 'mailerror', 'parseinline', $this->mLogin->mMailResult->getMessage() ) );
-                               return;
-                       case Login::SUCCESS:
-                               $this->mainLoginForm( wfMsgExt( 'passwordsent', 'parseinline', $this->mLogin->mUser->getName() ), 'success' );
-                               return;
-               }
-       }
-       
-       /**
-        * Add text to the header.  Only write to $mFormHeader directly  
-        * if you're determined to overwrite anything that other 
-        * extensions might have added.
-        * @param $text String HTML
-        */
-       public function addFormHeader( $text ){
-               $this->mFormHeader .= $text;
-       }
-
-       /**
-        * Since the UserLoginForm hook was changed to pass a SpecialPage
-        * instead of a QuickTemplate derivative, old extensions might
-        * easily try calling this method expecing it to exist.  Tempting
-        * though it is to let them have the fatal error, let's at least
-        * fail gracefully...
-        * @deprecated
-        */
-       public function set(){
-               wfDeprecated( __METHOD__ );
-       }
 }
diff --git a/includes/templates/Userlogin.php b/includes/templates/Userlogin.php
new file mode 100644 (file)
index 0000000..96713ff
--- /dev/null
@@ -0,0 +1,323 @@
+<?php
+/**
+ * @defgroup Templates Templates
+ * @file
+ * @ingroup Templates
+ */
+if( !defined( 'MEDIAWIKI' ) ) die( -1 );
+
+/**
+ * HTML template for Special:Userlogin form
+ * @ingroup Templates
+ */
+class UserloginTemplate extends QuickTemplate {
+       function execute() {
+               if( $this->data['message'] ) {
+?>
+       <div class="<?php $this->text('messagetype') ?>box">
+               <?php if ( $this->data['messagetype'] == 'error' ) { ?>
+                       <h2><?php $this->msg('loginerror') ?></h2>
+               <?php } ?>
+               <?php $this->html('message') ?>
+       </div>
+       <div class="visualClear"></div>
+<?php } ?>
+
+<div id="loginstart"><?php $this->msgWiki( 'loginstart' ); ?></div>
+<div id="userloginForm">
+<form name="userlogin" method="post" action="<?php $this->text('action') ?>">
+       <h2><?php $this->msg('login') ?></h2>
+       <p id="userloginlink"><?php $this->html('link') ?></p>
+       <?php $this->html('header'); /* pre-table point for form plugins... */ ?>
+       <div id="userloginprompt"><?php  $this->msgWiki('loginprompt') ?></div>
+       <?php if( @$this->haveData( 'languages' ) ) { ?><div id="languagelinks"><p><?php $this->html( 'languages' ); ?></p></div><?php } ?>
+       <table>
+               <tr>
+                       <td class="mw-label"><label for='wpName1'><?php $this->msg('yourname') ?></label></td>
+                       <td class="mw-input">
+                               <?php
+                       echo Html::input( 'wpName', $this->data['name'], 'text', array(
+                               'class' => 'loginText',
+                               'id' => 'wpName1',
+                               'tabindex' => '1',
+                               'size' => '20',
+                               'required'
+                               # Can't do + array( 'autofocus' ) because + for arrays in PHP
+                               # only works right for associative arrays!  Thanks, PHP.
+                       ) + ( $this->data['name'] ? array() : array( 'autofocus' => '' ) ) ); ?>
+
+                       </td>
+               </tr>
+               <tr>
+                       <td class="mw-label"><label for='wpPassword1'><?php $this->msg('yourpassword') ?></label></td>
+                       <td class="mw-input">
+                               <?php
+                       echo Html::input( 'wpPassword', null, 'password', array(
+                               'class' => 'loginPassword',
+                               'id' => 'wpPassword1',
+                               'tabindex' => '2',
+                               'size' => '20'
+                       ) + ( $this->data['name'] ? array( 'autofocus' ) : array() ) ); ?>
+
+                       </td>
+               </tr>
+       <?php if( $this->data['usedomain'] ) {
+               $doms = "";
+               foreach( $this->data['domainnames'] as $dom ) {
+                       $doms .= "<option>" . htmlspecialchars( $dom ) . "</option>";
+               }
+       ?>
+               <tr id="mw-user-domain-section">
+                       <td class="mw-label"><?php $this->msg( 'yourdomainname' ) ?></td>
+                       <td class="mw-input">
+                               <select name="wpDomain" value="<?php $this->text( 'domain' ) ?>"
+                                       tabindex="3">
+                                       <?php echo $doms ?>
+                               </select>
+                       </td>
+               </tr>
+       <?php }
+       if( $this->data['canremember'] ) { ?>
+               <tr>
+                       <td></td>
+                       <td class="mw-input">
+                               <?php
+               echo Html::input( 'wpRemember', '1', 'checkbox', array(
+                       'tabindex' => '4',
+                       'id' => 'wpRemember'
+               ) + ( $this->data['remember'] ? array( 'checked' ) : array() ) ); ?>
+
+                               <label for="wpRemember"><?php $this->msg('remembermypassword') ?></label>
+                       </td>
+               </tr>
+<?php } ?>
+               <tr>
+                       <td></td>
+                       <td class="mw-submit">
+                               <?php
+               echo Html::input( 'wpLoginAttempt', wfMsg( 'login' ), 'submit', array(
+                       'id' => 'wpLoginAttempt',
+                       'tabindex' => '5'
+               ) );
+               if ( $this->data['useemail'] && $this->data['canreset'] ) {
+                       echo '&nbsp;';
+                       echo Html::input( 'wpMailmypassword', wfMsg( 'mailmypassword' ), 'submit', array(
+                               'id' => 'wpMailmypassword',
+                               'tabindex' => '6'
+                       ) );
+               } ?>
+
+                       </td>
+               </tr>
+       </table>
+<?php if( @$this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
+</form>
+</div>
+<div id="loginend"><?php $this->msgWiki( 'loginend' ); ?></div>
+<?php
+
+       }
+}
+
+/**
+ * @ingroup Templates
+ */
+class UsercreateTemplate extends QuickTemplate {
+       function addInputItem( $name, $value, $type, $msg, $helptext = false ) {
+               $this->data['extraInput'][] = array(
+                       'name' => $name,
+                       'value' => $value,
+                       'type' => $type,
+                       'msg' => $msg,
+                       'helptext' => $helptext,
+               );
+       }
+       
+       function execute() {
+               if( $this->data['message'] ) {
+?>
+       <div class="<?php $this->text('messagetype') ?>box">
+               <?php if ( $this->data['messagetype'] == 'error' ) { ?>
+                       <h2><?php $this->msg('loginerror') ?></h2>
+               <?php } ?>
+               <?php $this->html('message') ?>
+       </div>
+       <div class="visualClear"></div>
+<?php } ?>
+<div id="userlogin">
+
+<form name="userlogin2" id="userlogin2" method="post" action="<?php $this->text('action') ?>">
+       <h2><?php $this->msg('createaccount') ?></h2>
+       <p id="userloginlink"><?php $this->html('link') ?></p>
+       <?php $this->html('header'); /* pre-table point for form plugins... */ ?>
+       <?php if( @$this->haveData( 'languages' ) ) { ?><div id="languagelinks"><p><?php $this->html( 'languages' ); ?></p></div><?php } ?>
+       <table>
+               <tr>
+                       <td class="mw-label"><label for='wpName2'><?php $this->msg('yourname') ?></label></td>
+                       <td class="mw-input">
+                               <?php
+                       echo Html::input( 'wpName', $this->data['name'], 'text', array(
+                               'class' => 'loginText',
+                               'id' => 'wpName2',
+                               'tabindex' => '1',
+                               'size' => '20',
+                               'required',
+                               'autofocus'
+                       ) ); ?>
+                       </td>
+               </tr>
+               <tr>
+                       <td class="mw-label"><label for='wpPassword2'><?php $this->msg('yourpassword') ?></label></td>
+                       <td class="mw-input">
+<?php
+                       echo Html::input( 'wpPassword', null, 'password', array(
+                               'class' => 'loginPassword',
+                               'id' => 'wpPassword2',
+                               'tabindex' => '2',
+                               'size' => '20'
+                       ) + User::passwordChangeInputAttribs() ); ?>
+                       </td>
+               </tr>
+       <?php if( $this->data['usedomain'] ) {
+               $doms = "";
+               foreach( $this->data['domainnames'] as $dom ) {
+                       $doms .= "<option>" . htmlspecialchars( $dom ) . "</option>";
+               }
+       ?>
+               <tr>
+                       <td class="mw-label"><?php $this->msg( 'yourdomainname' ) ?></td>
+                       <td class="mw-input">
+                               <select name="wpDomain" value="<?php $this->text( 'domain' ) ?>"
+                                       tabindex="3">
+                                       <?php echo $doms ?>
+                               </select>
+                       </td>
+               </tr>
+       <?php } ?>
+               <tr>
+                       <td class="mw-label"><label for='wpRetype'><?php $this->msg('yourpasswordagain') ?></label></td>
+                       <td class="mw-input">
+                               <?php
+               echo Html::input( 'wpRetype', null, 'password', array(
+                       'class' => 'loginPassword',
+                       'id' => 'wpRetype',
+                       'tabindex' => '4',
+                       'size' => '20'
+               ) + User::passwordChangeInputAttribs() ); ?>
+                       </td>
+               </tr>
+               <tr>
+                       <?php if( $this->data['useemail'] ) { ?>
+                               <td class="mw-label"><label for='wpEmail'><?php $this->msg('youremail') ?></label></td>
+                               <td class="mw-input">
+                                       <?php
+               echo Html::input( 'wpEmail', $this->data['email'], 'email', array(
+                       'class' => 'loginText',
+                       'id' => 'wpEmail',
+                       'tabindex' => '5',
+                       'size' => '20'
+               ) ); ?>
+                                       <div class="prefsectiontip">
+                                               <?php if( $this->data['emailrequired'] ) {
+                                                                       $this->msgWiki('prefs-help-email-required');
+                                                     } else {
+                                                                       $this->msgWiki('prefs-help-email');
+                                                     } ?>
+                                       </div>
+                               </td>
+                       <?php } ?>
+                       <?php if( $this->data['userealname'] ) { ?>
+                               </tr>
+                               <tr>
+                                       <td class="mw-label"><label for='wpRealName'><?php $this->msg('yourrealname') ?></label></td>
+                                       <td class="mw-input">
+                                               <input type='text' class='loginText' name="wpRealName" id="wpRealName"
+                                                       tabindex="6"
+                                                       value="<?php $this->text('realname') ?>" size='20' />
+                                               <div class="prefsectiontip">
+                                                       <?php $this->msgWiki('prefs-help-realname'); ?>
+                                               </div>
+                                       </td>
+                       <?php } ?>
+               </tr>
+               <?php if( $this->data['canremember'] ) { ?>
+               <tr>
+                       <td></td>
+                       <td class="mw-input">
+                               <input type='checkbox' name="wpRemember"
+                                       tabindex="7"
+                                       value="1" id="wpRemember"
+                                       <?php if( $this->data['remember'] ) { ?>checked="checked"<?php } ?>
+                                       /> <label for="wpRemember"><?php $this->msg('remembermypassword') ?></label>
+                       </td>
+               </tr>
+<?php   }
+
+               $tabIndex = 8;
+               if ( isset( $this->data['extraInput'] ) && is_array( $this->data['extraInput'] ) ) {
+                       foreach ( $this->data['extraInput'] as $inputItem ) { ?>
+               <tr>
+                       <?php 
+                               if ( !empty( $inputItem['msg'] ) && $inputItem['type'] != 'checkbox' ) {
+                                       ?><td class="mw-label"><label for="<?php 
+                                       echo htmlspecialchars( $inputItem['name'] ); ?>"><?php
+                                       $this->msgWiki( $inputItem['msg'] ) ?></label><?php
+                               } else {
+                                       ?><td><?php
+                               }
+                       ?></td>
+                       <td class="mw-input">
+                               <input type="<?php echo htmlspecialchars( $inputItem['type'] ) ?>" name="<?php
+                               echo htmlspecialchars( $inputItem['name'] ); ?>"
+                                       tabindex="<?php echo $tabIndex++; ?>"
+                                       value="<?php 
+                               if ( $inputItem['type'] != 'checkbox' ) {
+                                       echo htmlspecialchars( $inputItem['value'] );
+                               } else {
+                                       echo '1';
+                               }                                       
+                                       ?>" id="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"
+                                       <?php 
+                               if ( $inputItem['type'] == 'checkbox' && !empty( $inputItem['value'] ) )
+                                       echo 'checked="checked"'; 
+                                       ?> /> <?php 
+                                       if ( $inputItem['type'] == 'checkbox' && !empty( $inputItem['msg'] ) ) {
+                                               ?>
+                               <label for="<?php echo htmlspecialchars( $inputItem['name'] ); ?>"><?php
+                                       $this->msgHtml( $inputItem['msg'] ) ?></label><?php
+                                       }
+                               if( $inputItem['helptext'] !== false ) {
+                               ?>
+                               <div class="prefsectiontip">
+                                       <?php $this->msgWiki( $inputItem['helptext'] ); ?>
+                               </div>
+                               <?php } ?>
+                       </td>
+               </tr>
+<?php                          
+                               
+                       }
+               }
+?>
+               <tr>
+                       <td></td>
+                       <td class="mw-submit">
+                               <input type='submit' name="wpCreateaccount" id="wpCreateaccount"
+                                       tabindex="<?php echo $tabIndex++; ?>"
+                                       value="<?php $this->msg('createaccount') ?>" />
+                               <?php if( $this->data['createemail'] ) { ?>
+                               <input type='submit' name="wpCreateaccountMail" id="wpCreateaccountMail"
+                                       tabindex="<?php echo $tabIndex++; ?>"
+                                       value="<?php $this->msg('createaccountmail') ?>" />
+                               <?php } ?>
+                       </td>
+               </tr>
+       </table>
+<?php if( @$this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
+</form>
+</div>
+<div id="signupend"><?php $this->msgWiki( 'signupend' ); ?></div>
+<?php
+
+       }
+}
index 42e0d93..d69784a 100644 (file)
@@ -735,8 +735,6 @@ XHTML id names.
 'category-file-count'            => '{{PLURAL:$2|This category contains only the following file.|The following {{PLURAL:$1|file is|$1 files are}} in this category, out of $2 total.}}',
 'category-file-count-limited'    => 'The following {{PLURAL:$1|file is|$1 files are}} in the current category.',
 'listingcontinuesabbrev'         => 'cont.',
-'index-category'                 => 'Indexed pages',
-'noindex-category'               => 'Noindexed pages',
 
 'linkprefix'        => '/^(.*?)([a-zA-Z\\x80-\\xff]+)$/sD', # only translate this message to other languages if you have to change it
 'mainpagetext'      => "<big>'''MediaWiki has been successfully installed.'''</big>",
@@ -1044,14 +1042,14 @@ Do not forget to change your [[Special:Preferences|{{SITENAME}} preferences]].',
 'login'                      => 'Log in',
 'nav-login-createaccount'    => 'Log in / create account',
 'loginprompt'                => 'You must have cookies enabled to log in to {{SITENAME}}.',
-'userlogin'                  => 'Log in',
+'userlogin'                  => 'Log in / create account',
 'logout'                     => 'Log out',
 'userlogout'                 => 'Log out',
 'notloggedin'                => 'Not logged in',
-'nologin'                    => "Don't have an account? '''$1'''.",
+'nologin'                    => "Don't have an account? $1.",
 'nologinlink'                => 'Create an account',
 'createaccount'              => 'Create account',
-'gotaccount'                 => "Already have an account? '''$1'''.",
+'gotaccount'                 => 'Already have an account? $1.',
 'gotaccountlink'             => 'Log in',
 'createaccountmail'          => 'by e-mail',
 'badretype'                  => 'The passwords you entered do not match.',
index 04081a8..b9aebac 100644 (file)
@@ -236,8 +236,6 @@ This is the toolbar: [[Image:Toolbar.png]]",
 * $1: number of files shown',
 'listingcontinuesabbrev'         => 'Shown in contiuation of each first letter group.
 See http://test.wikipedia.org/wiki/Category:Test_ko?uselang={{SUBPAGENAME}}, for example.',
-'index-category'                 => 'Name of the category where pages with the <nowiki>__INDEX__</nowiki> behaviour switch are listed',
-'noindex-category'               => 'Name of the category where pages with the <nowiki>__NOINDEX__</nowiki> behaviour switch are listed',
 
 'linkprefix'        => '{{optional}}',
 'mainpagetext'      => 'Along with {{msg|mainpagedocfooter}}, the text you will see on the Main Page when your wiki is installed.',
@@ -598,7 +596,7 @@ HTML markup cannot be used.",
 {{Identical|Log in}}",
 'nav-login-createaccount'    => "Shown to anonymous users in the upper right corner of the page. When you can't create an account, the message {{msg|login}} is shown.",
 'loginprompt'                => 'A small notice in the log in form.',
-'userlogin'                  => 'Name of special page [[Special:UserLogin]] where a user can log in.',
+'userlogin'                  => 'Name of special page [[Special:UserLogin]] where a user can log in or click to create a user account.',
 'logout'                     => '{{Identical|Log out}}',
 'userlogout'                 => '{{Identical|Log out}}',
 'notloggedin'                => 'This message is displayed in the standard skin when not logged in. The message is placed above the login link in the top right corner of pages.
index 13aca82..86aa8d4 100644 (file)
@@ -141,8 +141,6 @@ $wgMessageStructure = array(
                'category-file-count',
                'category-file-count-limited',
                'listingcontinuesabbrev',
-               'index-category',
-               'noindex-category',
        ),
        'mainpage' => array(
                'linkprefix',
index b7acae9..8f46c5c 100644 (file)
@@ -802,5 +802,3 @@ td.mw-enhanced-rc {
        position: relative;
        top: -16px;
 }
-
-#wpLoginAttempt, #wpCreateaccount { margin-right:0; }
index e7f2009..727355b 100644 (file)
@@ -1015,10 +1015,59 @@ td.htmlform-tip {
        margin-top: 2em;
 }
 
+div#userloginForm form,
+div#userlogin form#userlogin2 {
+       margin: 0 3em 1em 0;
+       border: 1px solid #aaa;
+       clear: both;
+       padding: 1.5em 2em;
+       background-color: #f9f9f9;
+       float: left;
+}
+.rtl div#userloginForm form,
+.rtl div#userlogin form#userlogin2 {
+       float: right;
+}
+
+div#userloginForm table,
+div#userlogin form#userlogin2 table {
+       background-color: #f9f9f9;
+}
+
+div#userloginForm h2,
+div#userlogin form#userlogin2 h2 {
+       padding-top: 0;
+}
+
+div#userlogin .captcha,
+div#userloginForm .captcha {
+       border: 1px solid #bbb;
+       padding: 1.5em 2em;
+       background-color: white;
+}
+
+#loginend, #signupend {
+       clear: both;
+}
+
 #userloginprompt, #languagelinks {
        font-size: 85%;
 }
 
+#login-sectiontip {
+       font-size: 85%;
+       line-height: 1.2;
+       padding-top: 2em;
+}
+
+#userlogin .loginText, #userlogin .loginPassword {
+       width: 12em;
+}
+
+#userloginlink a, #wpLoginattempt, #wpCreateaccount {
+       font-weight: bold;
+}
+
 /*
 ** IE/Mac fixes, hope to find a validating way to move this
 ** to a separate stylesheet. This would work but doesn't validate: