Skizzerz has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/386711 )

Change subject: Update extension for AuthManager
......................................................................

Update extension for AuthManager

In addition to AuthManager compatibility, this brings it up to modern
coding standards regarding array syntax and the like, and converts the
extension to use extension registration. Compatibility shims have been
removed.

Bug: T110293
Change-Id: Ia0caae13109affe6a441f087e31dc83e9856f309
Co-Authored-By: Isarra <zhoris...@gmail.com>
---
A ExternalWikiPrimaryAuthenticationProvider.php
D MediaWikiAuth.i18n.php
D MediaWikiAuth.php
D MediaWikiAuthPlugin.class.php
A PopulateImportedWatchlistJob.php
D README
D Snoopy.class.php
A extension.json
M i18n/en.json
M i18n/qqq.json
D patches/SpecialUserlogin.php-1.17alpha.r67921.patch
D patches/SpecialUserlogin.php-1.20.0.patch
D patches/SpecialUserlogin.php-1.21.2.patch
D patches/SpecialUserlogin.php-1.23.3.patch
14 files changed, 456 insertions(+), 2,116 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MediaWikiAuth 
refs/changes/11/386711/1

diff --git a/ExternalWikiPrimaryAuthenticationProvider.php 
b/ExternalWikiPrimaryAuthenticationProvider.php
new file mode 100644
index 0000000..3d24e68
--- /dev/null
+++ b/ExternalWikiPrimaryAuthenticationProvider.php
@@ -0,0 +1,364 @@
+<?php
+
+namespace MediaWikiAuth;
+
+use MediaWiki\Auth\AuthenticationRequest;
+use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Auth\PasswordAuthenticationRequest;
+use Status;
+use User;
+
+class ExternalWikiPrimaryAuthenticationProvider
+       extends \MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProvider
+{
+       protected $cookieJar;
+       private $userCache = [];
+
+       public function __construct( array $params = [] ) {
+               parent::__construct( $params );
+
+               $this->cookieJar = new \CookieJar();
+       }
+
+       /**
+        * Attempt to authenticate against a remote wiki's API
+        *
+        * We first check to see if the given user exists in the remote wiki; 
if they do not
+        * then we abstain from this auth provider (as the username may be 
handled by a different
+        * provider). If they exist, we attempt to auth against that username 
with our provided
+        * password, and return the result (PASS/FAIL).
+        *
+        * Once the user successfully authenticates, we import their 
Preferences and Watchlist from
+        * the remote wiki and prompt them to change their password.
+        */
+       public function beginPrimaryAuthentication( array $reqs ) {
+               $req = AuthenticationRequest::getRequestByClass( $reqs, 
PasswordAuthenticationRequest::class );
+               if ( !$req ) {
+                       return AuthenticationResponse::newAbstain();
+               }
+
+               if ( $req->username === null || $req->password === null ) {
+                       return AuthenticationResponse::newAbstain();
+               }
+
+               // Check if the user exists on the local wiki. If so, do not 
attempt to auth against the remote one.
+               // if $existingUser is false, that means username validation 
failed so we won't be able to auth with
+               // this name anyway once the account does exist.
+               $existingUser = User::newFromName( $req->username, 'usable' );
+               if ( $existingUser === false || $existingUser->getId() !== 0 ) {
+                       return AuthenticationResponse::newAbstain();
+               }
+
+               $username = $existingUser->getName();
+
+               // Check for username existence on other wiki
+               if ( !$this->testUserExists( $username ) ) {
+                       return AuthenticationResponse::newAbstain();
+               }
+
+               // Grab remote MediaWiki version; our auth flow depends on what 
we get back
+               $resp = $this->apiRequest( 'GET', [
+                       'action' => 'query',
+                       'meta' => 'siteinfo',
+                       'siprop' => 'general'
+               ], [], __METHOD__ );
+               // generator is of the form 'MediaWiki X.X.X'; strip MediaWiki 
from out front
+               $remoteVersion = substr( $resp->query->general->generator, 10 );
+
+               if ( version_compare( $remoteVersion, '1.27', '<' ) ) {
+                       // use old login API
+                       $resp = $this->apiRequest( 'POST', [
+                               'action' => 'login'
+                       ], [
+                               'lgname' => $username,
+                               'lgpassword' => $req->password
+                       ], __METHOD__ );
+
+                       if ( $resp->login->result === 'NeedToken' ) {
+                               $loginToken = $resp->login->token;
+
+                               $resp = $this->apiRequest( 'POST', [
+                                       'action' => 'login'
+                               ], [
+                                       'lgname' => $username,
+                                       'lgpassword' => $req->password,
+                                       'lgtoken' => $loginToken
+                               ], __METHOD__ );
+                       }
+
+                       if ( $resp->login->result !== 'Success' ) {
+                               $this->logger->info( 'Authentication against 
legacy remote API failed for reason ' . $resp->login->result,
+                                       [ 'remoteVersion' => $remoteVersion, 
'caller' => __METHOD__, 'username' => $username ] );
+                               return AuthenticationResponse::newFail( 
wfMessage( 'mwa-authfail' ) );
+                       }
+               } else {
+                       // use new clientlogin API.
+                       // TODO: We do not currently support things that inject 
into the auth flow,
+                       // such as if the remote wiki uses OAuth, two-factor 
authentication,
+                       // or has CAPTCHAs on login.
+
+                       // Step 1. Grab a login token
+                       $resp = $this->apiRequest( 'GET', [
+                               'action' => 'query',
+                               'meta' => 'tokens',
+                               'type' => 'login'
+                       ], [], __METHOD__ );
+                       $loginToken = $resp->query->tokens->logintoken;
+
+                       $resp = $this->apiRequest( 'POST', [
+                               'action' => 'clientlogin'
+                       ], [
+                               'loginreturnurl' => $this->config->get( 
'Server' ),
+                               'logintoken' => $loginToken,
+                               'username' => $username,
+                               'password' => $req->password
+                       ], __METHOD__ );
+
+                       if ( $resp->clientlogin->status !== 'PASS' ) {
+                               $this->logger->info( 'Authentication against 
modern remote API failed for reason ' . $resp->clientlogin->status,
+                                       [ 'remoteVersion' => $remoteVersion, 
'caller' => __METHOD__, 'username' => $username ] );
+                               return AuthenticationResponse::newFail( 
wfMessage( 'mwa-authfail' ) );
+                       }
+               }
+
+               // Remote login was successful, an account will be 
automatically created for the user by the system
+               // Mark them as (maybe) needing to reset their password as a 
secondary auth step.
+               $this->setPasswordResetFlag( $username, Status::newGood() );
+
+               return AuthenticationResponse::newPass( $username );
+       }
+
+       /**
+        * Callback for when an account is created automatically upon login 
(not necessarily by us).
+        *
+        * @param User $user
+        * @param string $source
+        * @return void
+        */
+       public function autoCreatedAccount( $user, $source ) {
+               $this->logger->debug( "Automatically created account created by 
$source." );
+               if ( $source !== __CLASS__ ) {
+                       // this account wasn't created by us, so we have 
nothing to contribute to it
+                       return;
+               }
+
+               // $user->saveChanges() is called automatically after this runs,
+               // so calling it ourselves is not necessary.
+               // This is where we fetch user preferences and watchlist to 
save locally.
+               $userInfo = $this->apiRequest( 'GET', [
+                       'action' => 'query',
+                       'meta' => 'userinfo',
+                       'uiprop' => 
'blockinfo|hasmsg|editcount|groups|groupmemberships|options|email|realname|registrationdate'
+               ], [], __METHOD__ );
+
+               $wrquery = [
+                       'action' => 'query',
+                       'list' => 'watchlistraw',
+                       'wrprop' => 'changed',
+                       'wrlimit' => 'max'
+               ];
+
+               $watchlist = [];
+
+               while ( true ) {
+                       $resp = $this->apiRequest( 'GET', $wrquery, [], 
__METHOD__ );
+                       $watchlist = array_merge( $watchlist, 
$resp->watchlistraw );
+
+                       if ( !isset( $resp->{'query-continue'} ) ) {
+                               break;
+                       }
+
+                       $wrquery['wrcontinue'] = 
$resp->{'query-continue'}->watchlistraw->wrcontinue;
+               }
+
+               // enqueue jobs to actually add the watchlist pages to the 
user, since there might be a lot of them
+               $pagesPerJob = (int)$this->config->get( 'UpdateRowsPerJob' );
+               if ( $pagesPerJob <= 0 ) {
+                       $this->logger->warning( '$wgUpdateRowsPerJob is set to 
0 or a negative value; importing watchlist in batches of 300 instead.' );
+                       $pagesPerJob = 300;
+               }
+
+               $jobs = [];
+               $title = $user->getUserPage(); // not used by us, but Job 
constructor needs a valid Title
+               while ( $watchlist ) {
+                       // array_splice reduces the size of $watchlist and 
returns the removed elements.
+                       // This avoids memory bloat so that we only keep the 
watchlist resident in memory one time.
+                       $slice = array_splice( $watchlist, 0, $pagesPerJob );
+                       $jobs[] = new PopulateImportedWatchlistJob( $title, [ 
'username' => $user->getName(), 'pages' => $slice ] );
+               }
+
+               \JobQueueGroup::singleton()->push( $jobs );
+
+               // groupmemberships contains groups and expiries, but is only 
present in recent versions of MW. Fall back to groups if it doesn't exist.
+               $validGroups = array_diff( array_keys( $this->config->get( 
'GroupPermissions' ) ), $this->config->get( 'ImplicitGroups' ) );
+
+               if ( isset( $userInfo->query->userinfo->groupmemberships ) ) {
+                       foreach ( $userInfo->query->userinfo->groupmemberships 
as $group ) {
+                               if ( !in_array( $group->group, $validGroups ) ) 
{
+                                       continue;
+                               }
+
+                               $user->addGroup( $group->group, $group->expiry 
);
+                       }
+               } else {
+                       foreach ( $userInfo->query->userinfo->groups as $group 
) {
+                               if ( !in_array( $group, $validGroups ) ) {
+                                       continue;
+                               }
+
+                               $user->addGroup( $group );
+                       }
+               }
+
+               if ( isset( $userInfo->query->userinfo->emailauthenticated ) ) {
+                       $user->setEmail( $userInfo->query->userinfo->email );
+                       $user->setEmailAuthenticationTimestamp( wfTimestamp( 
TS_MW, $userInfo->query->userinfo->emailauthenticated ) );
+               } elseif ( isset( $userInfo->query->userinfo->email ) ) {
+                       $user->setEmailWithConfirmation( 
$userInfo->query->userinfo->email );
+               }
+
+               $validOptions = $user->getOptions();
+               $validSkins = array_keys( \Skin::getAllowedSkins() );
+               $optionBlacklist = [ 'watchlisttoken' ];
+
+               foreach ( $userInfo->query->userinfo->options as $option => 
$value ) {
+                       if ( !in_array( $option, $optionBlacklist )
+                               && ( $option !== 'skin' || in_array( $value, 
$validSkins ) )
+                               && array_key_exists( $option, $validOptions )
+                               && $validOptions[$option] !== $value
+                       ) {
+                               $user->setOption( $option, $value );
+                       }
+               }
+
+               if ( isset( $userInfo->query->userinfo->messages ) ) {
+                       $user->setNewtalk( true );
+               }
+
+               // editcount and registrationdate cannot be set via methods on 
User
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->update(
+                       'user',
+                       [
+                               'user_editcount' => 
$userInfo->query->userinfo->editcount,
+                               'user_registration' => $dbw->timestamp( 
$userInfo->query->userinfo->registrationdate )
+                       ],
+                       [ 'user_id' => $user->getId() ],
+                       __METHOD__
+               );
+       }
+
+       public function beginPrimaryAccountCreation( $user, $creator, array 
$reqs ) {
+               throw new \BadMethodCallException( 'This provider cannot be 
used for explicit account creation.' );
+       }
+
+       public function finishAccountCreation( $user, $creator, 
AuthenticationResponse $response ) {
+               throw new \BadMethodCallException( 'This provider cannot be 
used for explicit account creation.' );
+       }
+
+       public function testUserExists( $username, $flags = User::READ_NORMAL ) 
{
+               if ( !isset( $this->userCache[$username] ) ) {
+                       $resp = $this->apiRequest( 'GET', [
+                               'action' => 'query',
+                               'list' => 'allusers',
+                               'aufrom' => $username,
+                               'auto' => $username,
+                               'aulimit' => 1,
+                       ], [], __METHOD__ );
+
+                       $this->userCache[$username] = count( 
$resp->query->allusers ) === 1;
+               }
+
+               return $this->userCache[$username];
+       }
+
+       /**
+        * Performs an API request to the external wiki.
+        *
+        * @param string $method GET or POST
+        * @param array $params GET parameters to add to the API URL
+        * @param array $postData POST data
+        * @param string $caller Caller of this method for logging purposes
+        * @return object The parsed JSON result of the request
+        */
+       protected function apiRequest( $method, array $params, array $postData 
= [], $caller = __METHOD__ ) {
+               $baseUrl = $this->config->get( 'MediaWikiAuthApiUrl' );
+
+               if ( !$baseUrl ) {
+                       throw new \ErrorPageError( 'mwa-unconfiguredtitle', 
'mwa-unconfiguredtext' );
+               }
+
+               $params['format'] = 'json';
+               $options = [ 'method' => $method ];
+               $apiUrl = wfAppendQuery( $baseUrl, $params );
+
+               if ( $method === 'POST' ) {
+                       $options['postData'] = $postData;
+               }
+
+               \MWDebug::log( "API Request: $method $apiUrl" );
+               if ( $method === 'POST' ) {
+                       \MWDebug::log( 'POST data: ' . json_encode( $postData ) 
);
+               }
+
+               $req = \MWHttpRequest::factory( $apiUrl, $options, __METHOD__ );
+               $req->setCookieJar( $this->cookieJar );
+               $status = $req->execute();
+
+               if ( $status->isOK() ) {
+                       $content = json_decode( $req->getContent() );
+
+                       if ( $content === null ) {
+                               // invalid JSON response, which means this 
isn't a valid API endpoint
+                               $logger = \LoggerFactory::getInstance( 'http' );
+                               $logger->error( 'Unable to parse JSON response 
from API endpoint: ' . json_last_error_msg(),
+                                       [ 'endpoint' => $apiUrl, 'caller' => 
__METHOD__, 'content' => $req->getContent()] );
+                               throw new \ErrorPageError( 
'mwa-unconfiguredtitle', 'mwa-unconfiguredtext' );
+                       }
+
+                       \MWDebug::log( 'API Response: ' . $req->getContent() );
+
+                       return $content;
+               } else {
+                       $errors = $status->getErrorsByType( 'error' );
+                       $logger = \LoggerFactory::getInstance( 'http' );
+                       $logger->error( \Status::wrap( $status )->getWikiText( 
false, false, 'en' ),
+                               [ 'error' => $errors, 'caller' => __METHOD__, 
'content' => $req->getContent() ] );
+
+                       // Might not be entirely accurate, as the error might 
be on the remote side...
+                       throw new \ErrorPageError( 'mwa-unconfiguredtitle', 
'mwa-unconfiguredtext' );
+               }
+       }
+
+       public function providerRevokeAccessForUser( $username ) {
+               // no-op; ExternalWiki authentication has no notion of revoking 
access, as it does not
+               // handle authentication once a local user account already 
exists.
+       }
+
+       public function providerAllowsPropertyChange( $property ) {
+               return false;
+       }
+
+       public function providerAllowsAuthenticationDataChange(
+               AuthenticationRequest $req, $checkData = true
+       )
+       {
+               return Status::newGood( 'ignored' );
+       }
+
+       public function providerChangeAuthenticationData( AuthenticationRequest 
$req ) {
+               // no-op
+       }
+
+       public function accountCreationType() {
+               // while this creates accounts, it does not do so via the 
Special:CreateAccount UI
+               return TYPE_NONE;
+       }
+
+       protected function getPasswordResetData( $username, $data ) {
+               return (object)[
+                       'msg' => wfMessage( 'mwa-finishcreate', wfMessage( 
'authprovider-resetpass-skip-label' )->text() ),
+                       'hard' => false
+               ];
+       }
+}
diff --git a/MediaWikiAuth.i18n.php b/MediaWikiAuth.i18n.php
deleted file mode 100644
index adbf928..0000000
--- a/MediaWikiAuth.i18n.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
- * This is a backwards-compatibility shim, generated by:
- * 
https://git.wikimedia.org/blob/mediawiki%2Fcore.git/HEAD/maintenance%2FgenerateJsonI18n.php
- *
- * Beginning with MediaWiki 1.23, translation strings are stored in json files,
- * and the EXTENSION.i18n.php file only exists to provide compatibility with
- * older releases of MediaWiki. For more information about this migration, see:
- * https://www.mediawiki.org/wiki/Requests_for_comment/Localisation_format
- *
- * This shim maintains compatibility back to MediaWiki 1.17.
- */
-$messages = array();
-if ( !function_exists( 'wfJsonI18nShimd1543230d7c05e05' ) ) {
-       function wfJsonI18nShimd1543230d7c05e05( $cache, $code, &$cachedData ) {
-               $codeSequence = array_merge( array( $code ), 
$cachedData['fallbackSequence'] );
-               foreach ( $codeSequence as $csCode ) {
-                       $fileName = dirname( __FILE__ ) . "/i18n/$csCode.json";
-                       if ( is_readable( $fileName ) ) {
-                               $data = FormatJson::decode( file_get_contents( 
$fileName ), true );
-                               foreach ( array_keys( $data ) as $key ) {
-                                       if ( $key === '' || $key[0] === '@' ) {
-                                               unset( $data[$key] );
-                                       }
-                               }
-                               $cachedData['messages'] = array_merge( $data, 
$cachedData['messages'] );
-                       }
-
-                       $cachedData['deps'][] = new FileDependency( $fileName );
-               }
-               return true;
-       }
-
-       $GLOBALS['wgHooks']['LocalisationCacheRecache'][] = 
'wfJsonI18nShimd1543230d7c05e05';
-}
diff --git a/MediaWikiAuth.php b/MediaWikiAuth.php
deleted file mode 100644
index 51b310e..0000000
--- a/MediaWikiAuth.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
- * MediaWikiAuth extension -- imports logins from an external MediaWiki 
instance
- * Requires Snoopy.class.php.
- *
- * @file
- * @ingroup Extensions
- * @version 0.8.1
- * @author Laurence "GreenReaper" Parry
- * @author Jack Phoenix <j...@countervandalism.net>
- * @author Kim Schoonover
- * @author Ryan Schmidt
- * @copyright © 2009-2010 Laurence "GreenReaper" Parry
- * @copyright © 2010-2015 Jack Phoenix, Ryan Schmidt
- * @copyright © 2012-2015 Kim Schoonover
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 
2.0 or later
- * @link https://www.mediawiki.org/wiki/Extension:MediaWikiAuth Documentation
- */
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
-if ( !defined( 'MEDIAWIKI' ) ) {
-       die( "This is not a valid entry point.\n" );
-}
-
-# Extension credits
-$wgExtensionCredits['other'][] = array(
-       'path' => __FILE__,
-       'name' => 'MediaWikiAuth',
-       'author' => array( 'Laurence Parry', 'Jack Phoenix', 'Kim Schoonover', 
'Ryan Schmidt' ),
-       'version' => '0.8.2',
-       'url' => 'https://www.mediawiki.org/wiki/Extension:MediaWikiAuth',
-       'descriptionmsg' => 'mwa-desc',
-);
-
-# Stuff
-$wgMessagesDirs['MediaWikiAuth'] = __DIR__ . '/i18n';
-$wgExtensionMessagesFiles['MediaWikiAuth'] = __DIR__ . 
'/MediaWikiAuth.i18n.php';
-
-$wgAutoloadClasses['MediaWikiAuthPlugin'] = __DIR__ . 
'/MediaWikiAuthPlugin.class.php';
\ No newline at end of file
diff --git a/MediaWikiAuthPlugin.class.php b/MediaWikiAuthPlugin.class.php
deleted file mode 100644
index 961ba3c..0000000
--- a/MediaWikiAuthPlugin.class.php
+++ /dev/null
@@ -1,412 +0,0 @@
-<?php
-
-class MediaWikiAuthPlugin extends AuthPlugin {
-       private $snoopy;
-       private $old_user_id;
-       private $old_user_name;
-       #private $old_user_rev_cnt;
-       #private $old_user_singlegroup;
-
-       function userExists( $username ) {
-               # Check against a table of existing names to import
-               $dbr = wfGetDB( DB_REPLICA );
-
-               # If this table doesn't exist, we can't check this way
-               if ( $dbr->tableExists( 'user' ) ) {
-                       $res = $dbr->select(
-                               'user',
-                               array( 'user_id' ),
-                               array( 'user_name' => $username ),
-                               __METHOD__
-                       );
-                       $row = $dbr->fetchObject( $res );
-                       if ( $row ) {
-                               $this->old_user_id = $row->user_id;
-                               return true;
-                       }
-               }
-               # Just say they exist for now, the authenticate() check will 
provide an appropriate
-               # error message if the user does not exist on the remote wiki
-               return true;
-       }
-
-       /**
-        * This will be called if the user did not exist locally and userExists 
returned true
-        * Using &$errormsg requires a patch, otherwise it'll always be "bad 
password"
-        * See Extension:MediaWikiAuth for this patch
-        *
-        * @param string $username Username
-        * @param string $password Password to the above username
-        * @param string|null $errormsg Error message, if any
-        */
-       function authenticate( $username, $password, &$errormsg = null ) {
-               global $wgMediaWikiAuthAPIURL;
-
-               $dbr = wfGetDB( DB_REPLICA );
-
-               # If the user exists locally, fall back to local auth
-               if ( $dbr->tableExists( 'user' ) ) {
-                       $res = $dbr->select(
-                               'user',
-                               array( 'user_id' ),
-                               array( 'user_name' => $username ),
-                               __METHOD__
-                       );
-                       $row = $dbr->fetchObject( $res );
-                       if ( $row ) {
-                               $this->old_user_id = $row->user_id;
-                               return false;
-                       }
-               }
-
-               # This is loaded here so it isn't loaded needlessly
-               if ( !class_exists( 'Snoopy', false ) ) {
-                       require_once( __DIR__ . '/Snoopy.class.php' );
-               }
-               $this->snoopy = new Snoopy();
-               $this->snoopy->agent = 'Mozilla/5.0 (compatible; MSIE 9.0; 
Windows NT 6.1; Trident/5.0)';
-
-               # The user should exist remotely. Let's try to login.
-               $login_vars = array(
-                       'action' => 'login',
-                       'lgname' => $username,
-                       'lgpassword' => $password,
-                       'format' => 'php'
-               );
-               do {
-                       $this->snoopy->submit( $wgMediaWikiAuthAPIURL, 
$login_vars );
-
-                       # Did we get in? Look for result: 'Success'
-                       $results = unserialize( $this->snoopy->results );
-                       wfDebugLog( 'MediaWikiAuth', 'Login result:' . print_r( 
$results, true ) );
-                       $errormsg = wfMessage( 'mwa-error-unknown' )->escaped();
-                       if ( isset( $results['login'] ) ) {
-                               $login = $results['login'];
-                               # This ignores the NoName option as it will be 
filtered out before now
-                               switch ( $login['result'] ) {
-                                       case 'Success':
-                                               # Set cookies from the 
successful login
-                                               $this->snoopy->setcookies();
-
-                                               # Did we not have an ID from 
earlier? Use the one we're given now
-                                               if ( !isset( $this->old_user_id 
) ) {
-                                                       $this->old_user_id = 
$login['lguserid'];
-                                                       # Check if ID already 
exists and handle
-                                                       $dbr = wfGetDB( 
DB_REPLICA );
-                                                       $localUser = 
$dbr->select(
-                                                               'user',
-                                                               'user_name',
-                                                               array( 
'user_id' => $this->old_user_id ),
-                                                               __METHOD__
-                                                       );
-                                                       if ( $dbr->fetchObject( 
$localUser ) ) {
-                                                               $resid = 
(int)$dbr->selectField(
-                                                                       'user',
-                                                                       
'user_id',
-                                                                       array(),
-                                                                       
__METHOD__,
-                                                                       array( 
'ORDER BY' => 'user_id desc' )
-                                                               );
-                                                               
$this->old_user_id = $resid + 1;
-                                                       }
-                                               }
-                                               $this->old_user_name = 
$login['lgusername'];
-                                               return true;
-
-                                       case 'NotExists':
-                                               global $wgUser;
-                                               if ( $wgUser->isAllowed( 
'createaccount' ) ) {
-                                                       $errormsg = wfMessage( 
'nosuchuser', htmlspecialchars( $username ) )->escaped();
-                                               } else {
-                                                       $errormsg = wfMessage( 
'nosuchusershort', htmlspecialchars( $username ) )->escaped();
-                                               }
-                                               break;
-
-                                       case 'NeedToken':
-                                               # Set cookies and break out to 
resubmit
-                                               $this->snoopy->setcookies();
-                                               $login_vars['lgtoken'] = 
$login['token'];
-                                               break;
-
-                                       case 'WrongToken':
-                                               $errormsg = wfMessage( 
'mwa-error-wrong-token' )->escaped();
-                                               break;
-
-                                       case 'EmptyPass':
-                                               $errormsg = wfMessage( 
'wrongpasswordempty' )->escaped();
-                                               break;
-
-                                       case 'WrongPass':
-                                       case 'WrongPluginPass':
-                                               $errormsg = wfMessage( 
'wrongpassword' )->escaped();
-                                               break;
-
-                                       case 'CreateBlocked':
-                                               $errormsg = wfMessage( 
'mwa-autocreate-blocked' )->escaped();
-                                               break;
-
-                                       case 'Throttled':
-                                               global $wgLang, 
$wgPasswordAttemptThrottle;
-                                               $errormsg = wfMessage( 
'login-throttled' )->params( $wgLang->formatDuration( 
$wgPasswordAttemptThrottle['seconds'] ) )->text();
-                                               break;
-
-                                       case 'ResetPass':
-                                               $errormsg = wfMessage( 
'mwa-resetpass' )->escaped();
-                                               break;
-                               }
-                               if ( isset( $login['wait'] ) ) {
-                                       $errormsg .= ' ' . wfMessage( 
'mwa-wait', $login['wait'] )->escaped();
-                               }
-                       }
-               } while ( isset( $results['login'] ) && $login['result'] == 
'NeedToken' );
-
-               # Login failed! Display a message
-               return false;
-       }
-
-       /**
-        * We do want to auto-create local accounts when a remote account 
exists.
-        */
-       function autoCreate() {
-               return true;
-       }
-
-       function initUser( &$user, $autocreate = false ) {
-               global $wgMediaWikiAuthAPIURL, $wgMediaWikiAuthPrefsURL;
-
-               # If autocreate is true (if it isn't, something's very wrong),
-               # import preferences, and remove from our local table of names 
to be imported
-               # $this->snoopy should still be active and logged in at this 
point
-               if ( $autocreate && !$user->isAnon() && $this->old_user_id ) {
-                       # Save user settings
-                       # $user->saveSettings();
-
-                       $dbw = wfGetDB( DB_MASTER );
-                       # Set old revisions with the old username to the new 
userID
-                       # (might have been imported with 0, or a temp ID)
-                       $dbw->update(
-                               'revision',
-                               array( 'rev_user' => $this->old_user_id ),
-                               array( 'rev_user_text' => $this->old_user_name 
),
-                               __METHOD__
-                       );
-                       $dbw->update(
-                               'logging',
-                               array( 'log_user' => $this->old_user_id ),
-                               array( 'log_user_text' => $this->old_user_name 
),
-                               __METHOD__
-                       );
-
-                       # Get correct edit count
-                       $dbr = wfGetDB( DB_REPLICA );
-                       $count = $dbr->selectField(
-                               'revision',
-                               'COUNT(rev_user)',
-                               array( 'rev_user' => $this->old_user_id ),
-                               __METHOD__
-                       );
-
-                       # Set real user editcount, email, and ID
-                       $dbw->update(
-                               'user',
-                               array(
-                                       'user_editcount' => $count,
-                                       'user_email' => $user->mEmail,
-                                       'user_id' => $this->old_user_id
-                               ),
-                               array( 'user_name' => $user->mName ),
-                               __METHOD__
-                       );
-                       $user->mId = $this->old_user_id;
-                       $user->mFrom = 'id';
-
-                       # Get account creation date
-                       $account_vars = array(
-                               'action' => 'query',
-                               'list' => 'users',
-                               'ususers' => $user->mName,
-                               'usprop' => 'registration',
-                               'format' => 'php'
-                       );
-                       $this->snoopy->submit( $wgMediaWikiAuthAPIURL, 
$account_vars );
-                       $unserializedResults = unserialize( 
$this->snoopy->results );
-                       # Remove formatting from API timestamp; database 
expects a plain number
-                       $results = str_replace(
-                               array( ':', 'T', 'Z', '-' ),
-                               '',
-                               
$unserializedResults['query']['users'][0]['registration']
-                       );
-                       # Bogus time? Missing dates default to the current 
timestamp; fall back to first edit
-                       if ( substr( $results, 0, 8 ) == gmdate( 'Ymd', time() 
) ) {
-                               $res = $dbr->select(
-                                       'revision',
-                                       array( 'rev_timestamp' ),
-                                       array( 'rev_user' => $this->old_user_id 
),
-                                       __METHOD__,
-                                       array( 'ORDER BY' => 'rev_timestamp 
ASC', 'LIMIT' => 1 )
-                               );
-                               if ( $res->numRows() ) {
-                                       $results = $dbr->fetchObject( $res 
)->rev_timestamp;
-                               }
-                       }
-                       if ( is_numeric( $results ) ) {
-                               $dbw->update(
-                                       'user',
-                                       array( 'user_registration' => $results 
),
-                                       array( 'user_id' => $this->old_user_id 
),
-                                       __METHOD__
-                               );
-                       }
-
-                       # Get watchlist
-                       # FIXME Bad things may happen with large watchlists. 
Also need option to not try.
-                       $watchlist_vars = array(
-                               'action' => 'query',
-                               'list' => 'watchlistraw',
-                               'wrlimit' => '500',
-                               'rawcontinue' => '1',
-                               'format' => 'php'
-                       );
-                       $more = true;
-                       $wrcontinue = null;
-                       do {
-                               if ( $wrcontinue === null ) {
-                                       unset( $watchlist_vars['wrcontinue'] );
-                               } else {
-                                       $watchlist_vars['wrcontinue'] = 
$wrcontinue;
-                               }
-                               $this->snoopy->submit( $wgMediaWikiAuthAPIURL, 
$watchlist_vars );
-                               $results = unserialize( $this->snoopy->results 
);
-
-                               if ( empty( $results['watchlistraw'] ) ) {
-                                       break;
-                               }
-                               foreach ( $results['watchlistraw'] as $wrEntry 
) {
-                                       # Insert the damn thing if it's not a 
talkpage
-                                       # For some reason the query returns 
talkpages too.
-                                       if ( $wrEntry['ns'] % 2 == 0 ) {
-                                               $watchTitle = 
Title::newFromText( $wrEntry['title'] );
-                                               if( $watchTitle instanceOf 
Title ) {
-                                                       $user->addWatch( 
$watchTitle );
-                                               } else {
-                                                       wfDebugLog( 
'MediaWikiAuth', 'Could not form Title object for ' . $wrEntry['title'] );
-                                               }
-                                       }
-                                       if ( isset( $results['query-continue'] 
) ) {
-                                               $wrcontinue = 
$results['query-continue']['watchlistraw']['wrcontinue'];
-                                       } else {
-                                               $wrcontinue = null;
-                                       }
-                                       $more = !( $wrcontinue === null );
-                               }
-                       } while ( $more );
-
-                       # Get user preferences
-                       $prefs_vars = array(
-                               'action' => 'query',
-                               'meta' => 'userinfo',
-                               'uiprop' => 'options|email|realname',
-                               'format' => 'php'
-                       );
-
-                       $this->snoopy->submit( $wgMediaWikiAuthAPIURL, 
$prefs_vars );
-                       $results = unserialize( $this->snoopy->results );
-                       if ( isset( $results['query'] ) && isset( 
$results['query']['userinfo'] ) ) {
-                               if ( isset( 
$results['query']['userinfo']['options'] ) ) {
-                                       $options = 
$results['query']['userinfo']['options'];
-                                       # Don't need some options
-                                       $ignoredOptions = array(
-                                               'widgets', 'showAds', 'theme',
-                                               'disableeditingtips', 
'edit-similar',
-                                               'skinoverwrite', 'htmlemails', 
'marketing',
-                                               'notifyhonorifics', 
'notifychallenge',
-                                               'notifygift', 
'notifyfriendsrequest',
-                                               'blackbirdenroll', 
'marketingallowed',
-                                               'disablecategorysuggest', 
'myhomedisableredirect',
-                                               'avatar', 
'widescreeneditingtips',
-                                               'disablelinksuggest', 
'watchlistdigestclear',
-                                               'hidefollowedpages', 
'enotiffollowedpages',
-                                               'enotiffollowedminoredits', 
'myhomedefaultview',
-                                               'disablecategoryselect'
-                                       );
-                                       foreach ( $ignoredOptions as $optName ) 
{
-                                               if ( isset( $options[$optName] 
) ) {
-                                                       unset( 
$options[$optName] );
-                                               }
-                                       }
-                                       $user->mOptions = array_merge( 
$user->mOptions, $options );
-                               }
-                               // Older wikis might not expose this in the API 
(1.15+)
-                               if ( isset( 
$results['query']['userinfo']['email'] ) ) {
-                                       $user->mEmail = 
$results['query']['userinfo']['email'];
-                                       Hooks::run( 'UserSetEmail', array( 
$this, &$this->mEmail ) );
-                                       if ( isset( 
$results['query']['userinfo']['emailauthenticated'] ) ) {
-                                               $user->confirmEmail();
-                                       } else {
-                                               $user->sendConfirmationMail();
-                                       }
-                               }
-
-                               // This is 1.18+
-                               if ( isset( 
$results['query']['userinfo']['realname'] ) ) {
-                                       $user->mRealName = 
$results['query']['userinfo']['realname'];
-                               }
-
-                       }
-
-                       if ( !$user->mRealName || !$user->mEmail ) {
-                               # Backwards-compat screenscraping...
-                               # Older versions had the user append 
?uselang=en; remove that since we'll do that ourselves here.
-                               $wgMediaWikiAuthPrefsURL = str_replace( array( 
'?uselang=en', '&uselang=en' ), '', $wgMediaWikiAuthPrefsURL );
-
-                               if ( strpos( $wgMediaWikiAuthPrefsURL, '?' ) ) {
-                                       $this->snoopy->fetch( 
$wgMediaWikiAuthPrefsURL . '&uselang=qqx' );
-                               } else {
-                                       $this->snoopy->fetch( 
$wgMediaWikiAuthPrefsURL . '?uselang=qqx' );
-                               }
-                               $result = $this->snoopy->results;
-
-                               # wpRealName = 1.15 and older, wprealname = 
1.16+
-                               if ( !$user->mRealName && preg_match( 
'^.*wp(R|r)eal(N|n)ame.*value="(.*?)".*^', $result, $matches ) ) {
-                                       $user->setRealName( stripslashes( 
html_entity_decode( $matches[3], ENT_QUOTES, 'UTF-8' ) ) );
-                               }
-                               # wpUserEmail = 1.15 and older, wpemailaddress 
= 1.16+
-                               if ( $user->mEmail == '' && preg_match( 
'^.*(wpUserEmail|wpemailaddress).*value="(.*?)".*^', $result, $matches ) ) {
-                                       $user->mEmail = stripslashes( 
html_entity_decode( $matches[2], ENT_QUOTES, 'UTF-8' ) );
-                                       Hooks::run( 'UserSetEmail', array( 
$this, &$this->mEmail ) );
-                                       # We assume the target server knows 
what it is doing.
-                                       if (
-                                               strpos( $result, 
'(emailauthenticated: ' ) ||
-                                               strpos( $result, 
'(usersignup-user-pref-emailauthenticated)' ) # Wikia
-                                       )
-                                       {
-                                               $user->confirmEmail();
-                                       } else {
-                                               $user->sendConfirmationMail();
-                                       }
-                               }
-                       }
-
-                       # Because updating the user object manually doesn't 
seem to work
-                       $dbw->update(
-                               'user',
-                               array(
-                                       'user_real_name' => $user->mRealName,
-                                       'user_email' => $user->mEmail,
-                                       'user_id' => $this->old_user_id
-                               ),
-                               array( 'user_id' => $user->mId ),
-                               __METHOD__
-                       );
-                       # May need to set last message date so they don't get 
old messages
-               }
-
-               if ( isset( $this->snoopy ) ) {
-                       # Logout once we're finished
-                       $logout_vars = array( 'action' => 'logout' );
-                       $this->snoopy->submit( $wgMediaWikiAuthAPIURL, 
$logout_vars );
-               }
-
-               return true;
-       }
-}
diff --git a/PopulateImportedWatchlistJob.php b/PopulateImportedWatchlistJob.php
new file mode 100644
index 0000000..05a8984
--- /dev/null
+++ b/PopulateImportedWatchlistJob.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace MediaWikiAuth;
+
+use Title;
+use User;
+
+class PopulateImportedWatchlistJob extends \Job {
+       /**
+        * Construct a new watchlist import job.
+        *
+        * @param $title Title unused
+        * @param $params Array of the format [
+        *     'username' => string username of the user whose watchlist is 
being modified
+        *     'pages' => array of objects to add to the watchlist. The objects 
have an 'ns', 'title', and sometimes 'changed'
+        *                (ns is an int, title is the prefixed page name, 
changed is a datetime string)
+        * ]
+        */
+       public function __construct( $title, $params ) {
+               parent::__construct( 'populateImportedWatchlist', $title, 
$params );
+       }
+
+       public function run() {
+               $user = User::newFromName( $this->params['username'] );
+               if ( $user === null || $user->getId() === 0 ) {
+                       throw new \BadMethodCallException( "Attempting to 
import watchlist pages for nonexistent user {$this->params['username']}." );
+               }
+
+               foreach ( $this->params['pages'] as $page ) {
+                       $title = Title::makeTitleSafe( $page->ns, $page->title 
);
+                       if ( $title === null ) {
+                               // do not error out import on invalid titles, 
as it could just mean that config
+                               // is different between our wiki and the 
external wiki such that this title isn't valid.
+                               continue;
+                       }
+
+                       $user->addWatch( $title, User::IGNORE_USER_RIGHTS );
+                       // TODO: we currently do nothing with $page->changed 
(i.e. the title is added as cleared instead of dirty in all cases).
+                       // we may wish to import changed as well (as 
wl_notificationtimestamp in the db). Note that $page->changed may not exists,
+                       // need to test with if ( isset( $page->changed ) ) 
before doing anything with it.
+               }
+       }
+}
diff --git a/README b/README
deleted file mode 100644
index d8ad8d7..0000000
--- a/README
+++ /dev/null
@@ -1,12 +0,0 @@
-If you're using this, you should know what to do. If not, talk to GreenReaper!
-
-* Apply patch to SpecialUserlogin.php in includes/specials
-
-* Add to LocalSettings.php or equivalent:
-
-$wgMediaWikiAuthAPIURL = 'http://www.example.com/w/api.php';
-$wgMediaWikiAuthPrefsURL = 'http://www.example.com/wiki/Special:Preferences';
-require_once("$IP/extensions/MediaWikiAuth/MediaWikiAuth.php");
-$wgAuth = new MediaWikiAuthPlugin();
-
-Users may now login and an account will be created for them. See the code for 
the potential of importing/matching up to previous edits.
diff --git a/Snoopy.class.php b/Snoopy.class.php
deleted file mode 100644
index 96ffb1e..0000000
--- a/Snoopy.class.php
+++ /dev/null
@@ -1,1203 +0,0 @@
-<?php
-
-/*************************************************
-
-Snoopy - the PHP net client
-Author: Monte Ohrt <mo...@ispi.net>
-Copyright (c): 1999-2008 New Digital Group, all rights reserved
-Version: 1.2.5-dev (revision 1.27)
-Note: some coding style changes by Jack Phoenix <j...@countervandalism.net>
-               var -> public, added some braces, double quotes -> single 
quotes, etc.
-
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-You may contact the author of Snoopy by e-mail at:
-mo...@ohrt.com
-
-The latest version of Snoopy can be obtained from:
-http://snoopy.sourceforge.net/
-
-*************************************************/
-
-class Snoopy {
-       /**** Public variables ****/
-
-       /* user definable vars */
-       public $host                    = 'www.php.net';                // host 
name we are connecting to
-       public $port                    = 80;                                   
// port we are connecting to
-       public $proxy_host              = '';                                   
// proxy host to use
-       public $proxy_port              = '';                                   
// proxy port to use
-       public $proxy_user              = '';                                   
// proxy user to use
-       public $proxy_pass              = '';                                   
// proxy password to use
-
-       public $agent                   = 'Snoopy v1.2.5-dev';  // agent we 
masquerade as
-       public $referer                 = '';                                   
// referer info to pass
-       public $cookies                 = array();                              
// array of cookies to pass
-                                                                               
                        // $cookies['username'] = 'joe';
-       public $rawheaders              = array();                              
// array of raw headers to send
-                                                                               
                        // $rawheaders['Content-type'] = 'text/html';
-
-       public $maxredirs               = 5;                                    
// http redirection depth maximum. 0 = disallow
-       public $lastredirectaddr        = '';                           // 
contains address of last redirected address
-       public $offsiteok               = true;                                 
// allows redirection off-site
-       public $maxframes               = 0;                                    
// frame content depth maximum. 0 = disallow
-       public $expandlinks     = true;                                         
// expand links to fully qualified URLs.
-                                                                               
                        // this only applies to fetchlinks()
-                                                                               
                        // submitlinks(), and submittext()
-       public $passcookies     = true;                                         
// pass set cookies back through redirects
-                                                                               
                        // NOTE: this currently does not respect
-                                                                               
                        // dates, domains or paths.
-
-       public $user                    = '';                                   
// user for http authentication
-       public $pass                    = '';                                   
// password for http authentication
-
-       // http accept types
-       public $accept                  = 'image/gif, image/x-xbitmap, 
image/jpeg, image/pjpeg, */*';
-
-       public $results                 = '';                                   
// where the content is put
-
-       public $error                   = '';                                   
// error messages sent here
-       public $response_code   = '';                                   // 
response code returned from server
-       public $headers                 = array();                              
// headers returned from server sent here
-       public $maxlength               = 500000;                               
// max return data length (body)
-       public $read_timeout    = 0;                                    // 
timeout on read operations, in seconds
-                                                                               
                        // supported only since PHP 4 Beta 4
-                                                                               
                        // set to 0 to disallow timeouts
-       public $timed_out               = false;                                
// if a read operation timed out
-       public $status                  = 0;                                    
// http request status
-
-       public $temp_dir                = '/tmp';                               
// temporary directory that the webserver
-                                                                               
                        // has permission to write to.
-                                                                               
                        // under Windows, this should be C:\temp
-
-       public $curl_path               = '/usr/local/bin/curl';
-                                                                               
                // Snoopy will use cURL for fetching
-                                                                               
                // SSL content if a full system path to
-                                                                               
                // the cURL binary is supplied here.
-                                                                               
                // set to false if you do not have
-                                                                               
                // cURL installed. See http://curl.haxx.se
-                                                                               
                // for details on installing cURL.
-                                                                               
                // Snoopy does *not* use the cURL
-                                                                               
                // library functions built into php,
-                                                                               
                // as these functions are not stable
-                                                                               
                // as of this Snoopy release.
-
-       /**** Private variables ****/
-       public  $_maxlinelen    = 4096;                                 // max 
line length (headers)
-
-       public $_httpmethod     = 'GET';                                // 
default http request method
-       public $_httpversion    = 'HTTP/1.0';                   // default http 
request version
-       public $_submit_method  = 'POST';                               // 
default submit method
-       public $_submit_type    = 'application/x-www-form-urlencoded'; // 
default submit type
-       public $_mime_boundary  = '';                                   // MIME 
boundary for multipart/form-data submit type
-       public $_redirectaddr   = false;                                // will 
be set if page fetched is a redirect
-       public $_redirectdepth  = 0;                                    // 
increments on an http redirect
-       public $_frameurls              = array();                              
// frame src urls
-       public $_framedepth     = 0;                                    // 
increments on frame depth
-
-       public $_isproxy                = false;                                
// set if using a proxy server
-       public $_fp_timeout     = 30;                                   // 
timeout for socket connection
-
-       
/*======================================================================*\
-       Function:       fetch
-       Purpose:        fetch the contents of a web page
-                               (and possibly other protocols in the
-                               future like ftp, nntp, gopher, etc.)
-       Input:          $URI    the location of the page to fetch
-       Output:         $this->results  the output text from the fetch
-       
\*======================================================================*/
-       function fetch( $URI ) {
-               //preg_match( "|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|", $URI, 
$URI_PARTS );
-               $URI_PARTS = parse_url( $URI );
-               if ( !empty( $URI_PARTS['user'] ) ) {
-                       $this->user = $URI_PARTS['user'];
-               }
-               if ( !empty( $URI_PARTS['pass'] ) ) {
-                       $this->pass = $URI_PARTS['pass'];
-               }
-               if ( empty( $URI_PARTS['query'] ) ) {
-                       $URI_PARTS['query'] = '';
-               }
-               if ( empty( $URI_PARTS['path'] ) ) {
-                       $URI_PARTS['path'] = '';
-               }
-
-               switch( strtolower( $URI_PARTS['scheme'] ) ) {
-                       case 'http':
-                               $this->host = $URI_PARTS['host'];
-                               if( !empty( $URI_PARTS['port'] ) ) {
-                                       $this->port = $URI_PARTS['port'];
-                               }
-                               if( $this->_connect( $fp ) ) {
-                                       if( $this->_isproxy ) {
-                                               // using proxy, send entire URI
-                                               $this->_httprequest( $URI, $fp, 
$URI, $this->_httpmethod );
-                                       } else {
-                                               $path = $URI_PARTS['path'] . ( 
$URI_PARTS['query'] ? '?' . $URI_PARTS['query'] : '' );
-                                               // no proxy, send only the path
-                                               $this->_httprequest( $path, 
$fp, $URI, $this->_httpmethod );
-                                       }
-
-                                       $this->_disconnect( $fp );
-
-                                       if( $this->_redirectaddr ) {
-                                               /* url was redirected, check if 
we've hit the max depth */
-                                               if( $this->maxredirs > 
$this->_redirectdepth ) {
-                                                       // only follow redirect 
if it's on this site, or offsiteok is true
-                                                       if( preg_match( 
"|^http://"; . preg_quote( $this->host ) . "|i", $this->_redirectaddr ) || 
$this->offsiteok )
-                                                       {
-                                                               /* follow the 
redirect */
-                                                               
$this->_redirectdepth++;
-                                                               
$this->lastredirectaddr = $this->_redirectaddr;
-                                                               $this->fetch( 
$this->_redirectaddr );
-                                                       }
-                                               }
-                                       }
-
-                                       if( $this->_framedepth < 
$this->maxframes && count( $this->_frameurls ) > 0 )
-                                       {
-                                               $frameurls = $this->_frameurls;
-                                               $this->_frameurls = array();
-
-                                               while( list( , $frameurl ) = 
each( $frameurls ) ) {
-                                                       if( $this->_framedepth 
< $this->maxframes ) {
-                                                               $this->fetch( 
$frameurl );
-                                                               
$this->_framedepth++;
-                                                       } else {
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                               } else {
-                                       return false;
-                               }
-                               return true;
-                               break;
-                       case 'https':
-                               if( !$this->curl_path ) {
-                                       return false;
-                               }
-                               if( function_exists( 'is_executable' ) ) {
-                                       if ( !is_executable( $this->curl_path ) 
) {
-                                               return false;
-                                       }
-                               }
-                               $this->host = $URI_PARTS['host'];
-                               if( !empty( $URI_PARTS['port'] ) ) {
-                                       $this->port = $URI_PARTS['port'];
-                               }
-                               if( $this->_isproxy ) {
-                                       // using proxy, send entire URI
-                                       $this->_httpsrequest( $URI, $URI, 
$this->_httpmethod );
-                               } else {
-                                       $path = $URI_PARTS['path'] . ( 
$URI_PARTS['query'] ? '?' . $URI_PARTS['query'] : '' );
-                                       // no proxy, send only the path
-                                       $this->_httpsrequest( $path, $URI, 
$this->_httpmethod );
-                               }
-
-                               if( $this->_redirectaddr ) {
-                                       /* url was redirected, check if we've 
hit the max depth */
-                                       if( $this->maxredirs > 
$this->_redirectdepth ) {
-                                               // only follow redirect if it's 
on this site, or offsiteok is true
-                                               if( preg_match( "|^http://"; . 
preg_quote( $this->host ) . "|i", $this->_redirectaddr ) || $this->offsiteok )
-                                               {
-                                                       /* follow the redirect 
*/
-                                                       $this->_redirectdepth++;
-                                                       $this->lastredirectaddr 
= $this->_redirectaddr;
-                                                       $this->fetch( 
$this->_redirectaddr );
-                                               }
-                                       }
-                               }
-
-                               if( $this->_framedepth < $this->maxframes && 
count( $this->_frameurls ) > 0 )
-                               {
-                                       $frameurls = $this->_frameurls;
-                                       $this->_frameurls = array();
-
-                                       while( list( , $frameurl ) = each( 
$frameurls ) ) {
-                                               if( $this->_framedepth < 
$this->maxframes ) {
-                                                       $this->fetch( $frameurl 
);
-                                                       $this->_framedepth++;
-                                               } else {
-                                                       break;
-                                               }
-                                       }
-                               }
-                               return true;
-                               break;
-                       default:
-                               // not a valid protocol
-                               $this->error = 'Invalid protocol "' . 
$URI_PARTS['scheme'] . '"\n';
-                               return false;
-                               break;
-               }
-               return true;
-       }
-
-       
/*======================================================================*\
-       Function:       submit
-       Purpose:        submit an HTTP form
-       Input:          $URI    the location to post the data
-                               $formvars       the formvars to use.
-                                       format: $formvars['var'] = 'val';
-                               $formfiles  an array of files to submit
-                                       format: $formfiles['var'] = 
'/dir/filename.ext';
-       Output:         $this->results  the text output from the post
-       
\*======================================================================*/
-       function submit( $URI, $formvars = '', $formfiles = '' ) {
-               unset( $postdata );
-
-               $postdata = $this->_prepare_post_body( $formvars, $formfiles );
-
-               $URI_PARTS = parse_url( $URI );
-               if ( !empty( $URI_PARTS['user'] ) ) {
-                       $this->user = $URI_PARTS['user'];
-               }
-               if ( !empty( $URI_PARTS['pass'] ) ) {
-                       $this->pass = $URI_PARTS['pass'];
-               }
-               if ( empty( $URI_PARTS['query'] ) ) {
-                       $URI_PARTS['query'] = '';
-               }
-               if ( empty( $URI_PARTS['path'] ) ) {
-                       $URI_PARTS['path'] = '';
-               }
-
-               switch( strtolower( $URI_PARTS['scheme'] ) ) {
-                       case 'http':
-                               $this->host = $URI_PARTS['host'];
-                               if( !empty( $URI_PARTS['port'] ) ) {
-                                       $this->port = $URI_PARTS['port'];
-                               }
-                               if( $this->_connect( $fp ) ) {
-                                       if( $this->_isproxy ) {
-                                               // using proxy, send entire URI
-                                               $this->_httprequest( $URI, $fp, 
$URI, $this->_submit_method, $this->_submit_type, $postdata );
-                                       } else {
-                                               $path = $URI_PARTS['path'] . ( 
$URI_PARTS['query'] ? '?' . $URI_PARTS['query'] : '' );
-                                               // no proxy, send only the path
-                                               $this->_httprequest(
-                                                       $path, $fp, $URI,
-                                                       $this->_submit_method,
-                                                       $this->_submit_type,
-                                                       $postdata
-                                               );
-                                       }
-
-                                       $this->_disconnect( $fp );
-
-                                       if( $this->_redirectaddr ) {
-                                               /* url was redirected, check if 
we've hit the max depth */
-                                               if( $this->maxredirs > 
$this->_redirectdepth ) {
-                                                       if( !preg_match( "|^" . 
$URI_PARTS['scheme'] . "://|", $this->_redirectaddr ) ) {
-                                                               
$this->_redirectaddr = $this->_expandlinks( $this->_redirectaddr, 
$URI_PARTS['scheme'] . '://' . $URI_PARTS['host'] );
-                                                       }
-
-                                                       // only follow redirect 
if it's on this site, or offsiteok is true
-                                                       if( preg_match( 
"|^http://"; . preg_quote( $this->host ) . "|i", $this->_redirectaddr ) || 
$this->offsiteok )
-                                                       {
-                                                               /* follow the 
redirect */
-                                                               
$this->_redirectdepth++;
-                                                               
$this->lastredirectaddr = $this->_redirectaddr;
-                                                               if( strpos( 
$this->_redirectaddr, '?' ) > 0 ) {
-                                                                       
$this->fetch( $this->_redirectaddr ); // the redirect has changed the request 
method from post to get
-                                                               } else {
-                                                                       
$this->submit( $this->_redirectaddr, $formvars, $formfiles );
-                                                               }
-                                                       }
-                                               }
-                                       }
-
-                                       if( $this->_framedepth < 
$this->maxframes && count( $this->_frameurls ) > 0 )
-                                       {
-                                               $frameurls = $this->_frameurls;
-                                               $this->_frameurls = array();
-
-                                               while( list( , $frameurl ) = 
each( $frameurls ) ) {
-                                                       if( $this->_framedepth 
< $this->maxframes ) {
-                                                               $this->fetch( 
$frameurl );
-                                                               
$this->_framedepth++;
-                                                       } else {
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                               } else {
-                                       return false;
-                               }
-                               return true;
-                               break;
-                       case 'https':
-                               if( !$this->curl_path ) {
-                                       return false;
-                               }
-                               if( function_exists( 'is_executable' ) ) {
-                                       if ( !is_executable( $this->curl_path ) 
) {
-                                               return false;
-                                       }
-                               }
-                               $this->host = $URI_PARTS['host'];
-                               if( !empty( $URI_PARTS['port'] ) ) {
-                                       $this->port = $URI_PARTS['port'];
-                               }
-                               if( $this->_isproxy ) {
-                                       // using proxy, send entire URI
-                                       $this->_httpsrequest(
-                                               $URI,
-                                               $URI,
-                                               $this->_submit_method,
-                                               $this->_submit_type,
-                                               $postdata
-                                       );
-                               } else {
-                                       $path = $URI_PARTS['path'] . ( 
$URI_PARTS['query'] ? '?' . $URI_PARTS['query'] : '' );
-                                       // no proxy, send only the path
-                                       $this->_httpsrequest(
-                                               $path,
-                                               $URI,
-                                               $this->_submit_method,
-                                               $this->_submit_type,
-                                               $postdata
-                                       );
-                               }
-
-                               if( $this->_redirectaddr ) {
-                                       /* url was redirected, check if we've 
hit the max depth */
-                                       if( $this->maxredirs > 
$this->_redirectdepth ) {
-                                               if( !preg_match( "|^" . 
$URI_PARTS['scheme'] . "://|", $this->_redirectaddr ) ) {
-                                                       $this->_redirectaddr = 
$this->_expandlinks(
-                                                               
$this->_redirectaddr,
-                                                               
$URI_PARTS['scheme'] . '://' . $URI_PARTS['host']
-                                                       );
-                                               }
-
-                                               // only follow redirect if it's 
on this site, or offsiteok is true
-                                               if( preg_match( "|^http://"; . 
preg_quote( $this->host ) . "|i", $this->_redirectaddr ) || $this->offsiteok )
-                                               {
-                                                       /* follow the redirect 
*/
-                                                       $this->_redirectdepth++;
-                                                       $this->lastredirectaddr 
= $this->_redirectaddr;
-                                                       if( strpos( 
$this->_redirectaddr, '?' ) > 0 ) {
-                                                               $this->fetch( 
$this->_redirectaddr ); // the redirect has changed the request method from 
post to get
-                                                       } else {
-                                                               $this->submit( 
$this->_redirectaddr, $formvars, $formfiles );
-                                                       }
-                                               }
-                                       }
-                               }
-
-                               if( $this->_framedepth < $this->maxframes && 
count( $this->_frameurls ) > 0 )
-                               {
-                                       $frameurls = $this->_frameurls;
-                                       $this->_frameurls = array();
-
-                                       while( list( , $frameurl ) = each( 
$frameurls ) ) {
-                                               if( $this->_framedepth < 
$this->maxframes ) {
-                                                       $this->fetch( $frameurl 
);
-                                                       $this->_framedepth++;
-                                               } else {
-                                                       break;
-                                               }
-                                       }
-                               }
-                               return true;
-                               break;
-
-                       default:
-                               // not a valid protocol
-                               $this->error = 'Invalid protocol "' . 
$URI_PARTS['scheme'] . '"\n';
-                               return false;
-                               break;
-               }
-               return true;
-       }
-
-       
/*======================================================================*\
-       Function:       fetchlinks
-       Purpose:        fetch the links from a web page
-       Input:          $URI    where you are fetching from
-       Output:         $this->results  an array of the URLs
-       
\*======================================================================*/
-       function fetchlinks( $URI ) {
-               if ( $this->fetch( $URI ) ) {
-                       if( $this->lastredirectaddr ) {
-                               $URI = $this->lastredirectaddr;
-                       }
-                       if( is_array( $this->results ) ) {
-                               for( $x = 0; $x < count( $this->results ); $x++ 
) {
-                                       $this->results[$x] = 
$this->_striplinks( $this->results[$x] );
-                               }
-                       } else {
-                               $this->results = $this->_striplinks( 
$this->results );
-                       }
-
-                       if( $this->expandlinks ) {
-                               $this->results = $this->_expandlinks( 
$this->results, $URI );
-                       }
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       
/*======================================================================*\
-       Function:       fetchform
-       Purpose:        fetch the form elements from a web page
-       Input:          $URI    where you are fetching from
-       Output:         $this->results  the resulting html form
-       
\*======================================================================*/
-       function fetchform( $URI ) {
-               if ( $this->fetch( $URI ) ) {
-                       if( is_array( $this->results ) ) {
-                               for( $x = 0; $x < count( $this->results ); $x++ 
) {
-                                       $this->results[$x] = $this->_stripform( 
$this->results[$x] );
-                               }
-                       } else {
-                               $this->results = $this->_stripform( 
$this->results );
-                       }
-
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-
-       
/*======================================================================*\
-       Function:       fetchtext
-       Purpose:        fetch the text from a web page, stripping the links
-       Input:          $URI    where you are fetching from
-       Output:         $this->results  the text from the web page
-       
\*======================================================================*/
-       function fetchtext( $URI ) {
-               if( $this->fetch( $URI ) ) {
-                       if( is_array( $this->results ) ) {
-                               for( $x = 0; $x < count( $this->results ); $x++ 
) {
-                                       $this->results[$x] = $this->_striptext( 
$this->results[$x] );
-                               }
-                       } else {
-                               $this->results = $this->_striptext( 
$this->results );
-                       }
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       
/*======================================================================*\
-       Function:       submitlinks
-       Purpose:        grab links from a form submission
-       Input:          $URI    where you are submitting from
-       Output:         $this->results  an array of the links from the post
-       
\*======================================================================*/
-       function submitlinks( $URI, $formvars = '', $formfiles = '' ) {
-               if( $this->submit( $URI, $formvars, $formfiles ) ) {
-                       if( $this->lastredirectaddr ) {
-                               $URI = $this->lastredirectaddr;
-                       }
-                       if( is_array( $this->results ) ) {
-                               for( $x = 0; $x < count( $this->results ); $x++ 
) {
-                                       $this->results[$x] = 
$this->_striplinks( $this->results[$x] );
-                                       if( $this->expandlinks ) {
-                                               $this->results[$x] = 
$this->_expandlinks( $this->results[$x], $URI );
-                                       }
-                               }
-                       } else {
-                               $this->results = $this->_striplinks( 
$this->results );
-                               if( $this->expandlinks ) {
-                                       $this->results = $this->_expandlinks( 
$this->results, $URI );
-                               }
-                       }
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       
/*======================================================================*\
-       Function:       submittext
-       Purpose:        grab text from a form submission
-       Input:          $URI    where you are submitting from
-       Output:         $this->results  the text from the web page
-       
\*======================================================================*/
-       function submittext( $URI, $formvars = '', $formfiles = '' ) {
-               if( $this->submit( $URI, $formvars, $formfiles ) ) {
-                       if( $this->lastredirectaddr ) {
-                               $URI = $this->lastredirectaddr;
-                       }
-                       if( is_array( $this->results ) ) {
-                               for( $x = 0; $x < count( $this->results ); $x++ 
) {
-                                       $this->results[$x] = $this->_striptext( 
$this->results[$x] );
-                                       if( $this->expandlinks ) {
-                                               $this->results[$x] = 
$this->_expandlinks( $this->results[$x], $URI );
-                                       }
-                               }
-                       } else {
-                               $this->results = $this->_striptext( 
$this->results );
-                               if( $this->expandlinks ) {
-                                       $this->results = $this->_expandlinks( 
$this->results, $URI );
-                               }
-                       }
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       
/*======================================================================*\
-       Function:       set_submit_multipart
-       Purpose:        Set the form submission content type to
-                               multipart/form-data
-       
\*======================================================================*/
-       function set_submit_multipart() {
-               $this->_submit_type = 'multipart/form-data';
-       }
-
-       
/*======================================================================*\
-       Function:       set_submit_normal
-       Purpose:        Set the form submission content type to
-                               application/x-www-form-urlencoded
-       
\*======================================================================*/
-       function set_submit_normal() {
-               $this->_submit_type = 'application/x-www-form-urlencoded';
-       }
-
-       
/*======================================================================*\
-       Private functions
-       
\*======================================================================*/
-
-       
/*======================================================================*\
-       Function:       _striplinks
-       Purpose:        strip the hyperlinks from an html document
-       Input:          $document       document to strip.
-       Output:         $match          an array of the links
-       
\*======================================================================*/
-       function _striplinks( $document ) {
-               preg_match_all("'<\s*a\s.*?href\s*=\s*                  # find 
<a href=
-                                               ([\"\'])?                       
                # find single or double quote
-                                               (?(1) (.*?)\\1 | ([^\s\>]+))    
        # if quote found, match up to next matching
-                                                                               
                        # quote, otherwise match up to next space
-                                               'isx", $document, $links
-               );
-
-               // catenate the non-empty matches from the conditional 
subpattern
-               while( list( $key, $val ) = each( $links[2] ) ) {
-                       if( !empty( $val ) ) {
-                               $match[] = $val;
-                       }
-               }
-
-               while( list( $key, $val ) = each( $links[3] ) ) {
-                       if( !empty( $val ) ) {
-                               $match[] = $val;
-                       }
-               }
-
-               // return the links
-               return $match;
-       }
-
-       
/*======================================================================*\
-       Function:       _stripform
-       Purpose:        strip the form elements from an HTML document
-       Input:          $document       document to strip.
-       Output:         $match          an array of the links
-       
\*======================================================================*/
-       function _stripform( $document ) {
-               preg_match_all(
-                       
"'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",
-                       $document,
-                       $elements
-               );
-
-               // catenate the matches
-               $match = implode( "\r\n", $elements[0] );
-
-               // return the links
-               return $match;
-       }
-
-       
/*======================================================================*\
-       Function:       _striptext
-       Purpose:        strip the text from an html document
-       Input:          $document       document to strip.
-       Output:         $text           the resulting text
-       
\*======================================================================*/
-       function _striptext( $document ) {
-               // I didn't use preg eval (//e) since that is only available in 
PHP 4.0.
-               // so, list your entities one by one here. I included some of 
the
-               // more common ones.
-               $search = array(
-                       "'<script[^>]*?>.*?</script>'si",       // strip out 
JavaScript
-                       "'<[\/\!]*?[^<>]*?>'si",                        // 
strip out HTML tags
-                       "'([\r\n])[\s]+'",                                      
// strip out white space
-                       "'&(quot|#34|#034|#x22);'i",            // replace HTML 
entities
-                       "'&(amp|#38|#038|#x26);'i",                     // 
added hexadecimal values
-                       "'&(lt|#60|#060|#x3c);'i",
-                       "'&(gt|#62|#062|#x3e);'i",
-                       "'&(nbsp|#160|#xa0);'i",
-                       "'&(iexcl|#161);'i",
-                       "'&(cent|#162);'i",
-                       "'&(pound|#163);'i",
-                       "'&(copy|#169);'i",
-                       "'&(reg|#174);'i",
-                       "'&(deg|#176);'i",
-                       "'&(#39|#039|#x27);'",
-                       "'&(euro|#8364);'i",                            // 
Europe
-                       "'&a(uml|UML);'",                                       
// German
-                       "'&o(uml|UML);'",
-                       "'&u(uml|UML);'",
-                       "'&A(uml|UML);'",
-                       "'&O(uml|UML);'",
-                       "'&U(uml|UML);'",
-                       "'&szlig;'i",
-               );
-               $replace = array(
-                       '',
-                       '',
-                       "\\1",
-                       "\"",
-                       '&',
-                       '<',
-                       '>',
-                       ' ',
-                       chr( 161 ),
-                       chr( 162 ),
-                       chr( 163 ),
-                       chr( 169 ),
-                       chr( 174 ),
-                       chr( 176 ),
-                       chr( 39 ),
-                       chr( 128 ),
-                       'ä',
-                       'ö',
-                       'ü',
-                       'Ä',
-                       'Ö',
-                       'Ü',
-                       'ß',
-               );
-
-               $text = preg_replace( $search, $replace, $document );
-
-               return $text;
-       }
-
-       
/*======================================================================*\
-       Function:       _expandlinks
-       Purpose:        expand each link into a fully qualified URL
-       Input:          $links                  the links to qualify
-                               $URI                    the full URI to get the 
base from
-       Output:         $expandedLinks  the expanded links
-       
\*======================================================================*/
-       function _expandlinks( $links, $URI ) {
-               preg_match( "/^[^\?]+/", $URI, $match );
-
-               $match = preg_replace( "|/[^\/\.]+\.[^\/\.]+$|", '', $match[0] 
);
-               $match = preg_replace( "|/$|", '', $match );
-               $match_part = parse_url( $match );
-               $match_root = $match_part['scheme'] . '://' . 
$match_part['host'];
-
-               $search = array(
-                       "|^http://"; . preg_quote( $this->host ) . "|i",
-                       "|^(\/)|i",
-                       "|^(?!http://)(?!mailto:)|i",
-                       "|/\./|",
-                       "|/[^\/]+/\.\./|"
-               );
-
-               $replace = array(
-                       '',
-                       $match_root . '/',
-                       $match . '/',
-                       '/',
-                       '/'
-               );
-
-               $expandedLinks = preg_replace( $search, $replace, $links );
-
-               return $expandedLinks;
-       }
-
-       
/*======================================================================*\
-       Function:       _httprequest
-       Purpose:        go get the http data from the server
-       Input:          $url            the url to fetch
-                               $fp                     the current open file 
pointer
-                               $URI            the full URI
-                               $body           body contents to send if any 
(POST)
-       Output:
-       
\*======================================================================*/
-       function _httprequest( $url, $fp, $URI, $http_method, $content_type = 
'', $body = '' ) {
-               $cookie_headers = '';
-               if( $this->passcookies && $this->_redirectaddr ) {
-                       $this->setcookies();
-               }
-
-               $URI_PARTS = parse_url( $URI );
-               if( empty( $url ) ) {
-                       $url = '/';
-               }
-               $headers = $http_method . ' ' . $url . ' ' . 
$this->_httpversion . "\r\n";
-               if( !empty( $this->agent ) ) {
-                       $headers .= 'User-Agent: ' . $this->agent . "\r\n";
-               }
-               if( !empty( $this->host ) && !isset( $this->rawheaders['Host'] 
) ) {
-                       $headers .= 'Host: ' . $this->host;
-                       if( !empty( $this->port ) ) {
-                               $headers .= ':' . $this->port;
-                       }
-                       $headers .= "\r\n";
-               }
-               if( !empty( $this->accept ) ) {
-                       $headers .= 'Accept: ' . $this->accept . "\r\n";
-               }
-               if( !empty( $this->referer ) ) {
-                       $headers .= 'Referer: ' . $this->referer . "\r\n";
-               }
-               if( !empty( $this->cookies ) ) {
-                       if( !is_array( $this->cookies ) ) {
-                               $this->cookies = (array)$this->cookies;
-                       }
-
-                       reset( $this->cookies );
-                       if ( count( $this->cookies ) > 0 ) {
-                               $cookie_headers .= 'Cookie: ';
-                               foreach ( $this->cookies as $cookieKey => 
$cookieVal ) {
-                                       $cookie_headers .= $cookieKey . '=' . 
urlencode( $cookieVal ) . '; ';
-                               }
-                               $headers .= substr( $cookie_headers, 0, -2 ) . 
"\r\n";
-                       }
-               }
-               if( !empty( $this->rawheaders ) ) {
-                       if( !is_array( $this->rawheaders ) ) {
-                               $this->rawheaders = (array)$this->rawheaders;
-                       }
-                       while( list( $headerKey, $headerVal ) = each( 
$this->rawheaders ) ) {
-                               $headers .= $headerKey . ': ' . $headerVal . 
"\r\n";
-                       }
-               }
-               if( !empty( $content_type ) ) {
-                       $headers .= "Content-type: $content_type";
-                       if ( $content_type == 'multipart/form-data' ) {
-                               $headers .= '; boundary=' . 
$this->_mime_boundary;
-                       }
-                       $headers .= "\r\n";
-               }
-               if( !empty( $body ) ) {
-                       $headers .= 'Content-length: ' . strlen( $body ) . 
"\r\n";
-               }
-               if( !empty( $this->user ) || !empty( $this->pass ) ) {
-                       $headers .= 'Authorization: Basic ' . base64_encode( 
$this->user . ':' . $this->pass ) . "\r\n";
-               }
-
-               // add proxy auth headers
-               if( !empty( $this->proxy_user ) ) {
-                       $headers .= 'Proxy-Authorization: ' . 'Basic ' . 
base64_encode( $this->proxy_user . ':' . $this->proxy_pass ) . "\r\n";
-               }
-
-               $headers .= "\r\n";
-
-               // set the read timeout if needed
-               if ( $this->read_timeout > 0 ) {
-                       socket_set_timeout( $fp, $this->read_timeout );
-               }
-               $this->timed_out = false;
-
-               fwrite( $fp, $headers . $body, strlen( $headers . $body ) );
-
-               $this->_redirectaddr = false;
-               unset( $this->headers );
-
-               while( $currentHeader = fgets( $fp, $this->_maxlinelen ) ) {
-                       if ( $this->read_timeout > 0 && $this->_check_timeout( 
$fp ) ) {
-                               $this->status = -100;
-                               return false;
-                       }
-
-                       if( $currentHeader == "\r\n" ) {
-                               break;
-                       }
-
-                       // if a header begins with Location: or URI:, set the 
redirect
-                       if( preg_match( "/^(Location:|URI:)/i", $currentHeader 
) ) {
-                               // get URL portion of the redirect
-                               preg_match( "/^(Location:|URI:)[ ]+(.*)/i", 
chop( $currentHeader ), $matches );
-                               // look for :// in the Location header to see 
if hostname is included
-                               if( !preg_match( "|\:\/\/|", $matches[2] ) ) {
-                                       // no host in the path, so prepend
-                                       $this->_redirectaddr = 
$URI_PARTS['scheme'] . '://' . $this->host . ':' . $this->port;
-                                       // eliminate double slash
-                                       if( !preg_match( "|^/|", $matches[2] ) 
) {
-                                               $this->_redirectaddr .= '/' . 
$matches[2];
-                                       } else {
-                                               $this->_redirectaddr .= 
$matches[2];
-                                       }
-                               } else {
-                                       $this->_redirectaddr = $matches[2];
-                               }
-                       }
-
-                       if( preg_match( "|^HTTP/|", $currentHeader ) ) {
-                               if( preg_match( "|^HTTP/[^\s]*\s(.*?)\s|", 
$currentHeader, $status ) ) {
-                                       $this->status = $status[1];
-                               }
-                               $this->response_code = $currentHeader;
-                       }
-
-                       $this->headers[] = $currentHeader;
-               }
-
-               $results = '';
-               do {
-                       $_data = fread( $fp, $this->maxlength );
-                       if ( strlen( $_data ) == 0 ) {
-                               break;
-                       }
-                       $results .= $_data;
-               } while( true );
-
-               if ( $this->read_timeout > 0 && $this->_check_timeout( $fp ) ) {
-                       $this->status = -100;
-                       return false;
-               }
-
-               // check if there is a a redirect meta tag
-               if( preg_match( 
"'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",
 $results, $match ) )
-               {
-                       $this->_redirectaddr = $this->_expandlinks( $match[1], 
$URI );
-               }
-
-               // have we hit our frame depth and is there frame src to fetch?
-               if( ( $this->_framedepth < $this->maxframes ) && 
preg_match_all( "'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i", $results, $match 
) )
-               {
-                       $this->results[] = $results;
-                       for( $x = 0; $x < count( $match[1] ); $x++ ) {
-                               $this->_frameurls[] = $this->_expandlinks( 
$match[1][$x], $URI_PARTS['scheme'] . '://' . $this->host );
-                       }
-               } elseif( is_array( $this->results ) ) { // have we already 
fetched framed content?
-                       $this->results[] = $results;
-               } else { // no framed content
-                       $this->results = $results;
-               }
-
-               return true;
-       }
-
-       
/*======================================================================*\
-       Function:       _httpsrequest
-       Purpose:        go get the https data from the server using curl
-       Input:          $url            the url to fetch
-                               $URI            the full URI
-                               $body           body contents to send if any 
(POST)
-       Output:
-       
\*======================================================================*/
-       function _httpsrequest( $url, $URI, $http_method, $content_type = '', 
$body = '' ) {
-               if( $this->passcookies && $this->_redirectaddr ) {
-                       $this->setcookies();
-               }
-
-               $headers = array();
-
-               $URI_PARTS = parse_url( $URI );
-               if( empty( $url ) ) {
-                       $url = '/';
-               }
-               // GET ... header not needed for curl
-               //$headers[] = $http_method." ".$url." ".$this->_httpversion;
-               if( !empty( $this->agent ) ) {
-                       $headers[] = 'User-Agent: ' . $this->agent;
-               }
-               if( !empty( $this->host ) ) {
-                       if( !empty( $this->port ) ) {
-                               $headers[] = 'Host: ' . $this->host . ':' . 
$this->port;
-                       } else {
-                               $headers[] = 'Host: ' . $this->host;
-                       }
-               }
-               if( !empty( $this->accept ) ) {
-                       $headers[] = 'Accept: ' . $this->accept;
-               }
-               if( !empty( $this->referer ) ) {
-                       $headers[] = 'Referer: ' . $this->referer;
-               }
-               if( !empty( $this->cookies ) ) {
-                       if( !is_array( $this->cookies ) ) {
-                               $this->cookies = (array)$this->cookies;
-                       }
-
-                       reset( $this->cookies );
-                       if ( count( $this->cookies ) > 0 ) {
-                               $cookie_str = 'Cookie: ';
-                               foreach ( $this->cookies as $cookieKey => 
$cookieVal ) {
-                                       $cookie_str .= $cookieKey . '=' . 
urlencode( $cookieVal ) . '; ';
-                               }
-                               $headers[] = substr( $cookie_str, 0, -2 );
-                       }
-               }
-               if( !empty( $this->rawheaders ) ) {
-                       if( !is_array( $this->rawheaders ) ) {
-                               $this->rawheaders = (array)$this->rawheaders;
-                       }
-                       while( list( $headerKey, $headerVal ) = each( 
$this->rawheaders ) ) {
-                               $headers[] = $headerKey . ': ' . $headerVal;
-                       }
-               }
-               if( !empty( $content_type ) ) {
-                       if ( $content_type == 'multipart/form-data' ) {
-                               $headers[] = "Content-type: $content_type; 
boundary=" . $this->_mime_boundary;
-                       } else {
-                               $headers[] = "Content-type: $content_type";
-                       }
-               }
-               if( !empty( $body ) ) {
-                       $headers[] = 'Content-length: ' . strlen( $body );
-               }
-               if( !empty( $this->user ) || !empty( $this->pass ) ) {
-                       $headers[] = 'Authorization: BASIC ' . base64_encode( 
$this->user . ':' . $this->pass );
-               }
-
-               for( $curr_header = 0; $curr_header < count( $headers ); 
$curr_header++ ) {
-                       $cmdline_params .= " -H \"" . escapeshellcmd( 
$headers[$curr_header] ) . "\"";
-               }
-
-               if( !empty( $body ) ) {
-                       $cmdline_params .= " -d \"" . escapeshellcmd( $body ) . 
"\"";
-               }
-
-               if( $this->read_timeout > 0 ) {
-                       $cmdline_params .= ' -m ' . $this->read_timeout;
-               }
-
-               $headerfile = tempnam( $temp_dir, 'sno' );
-
-               exec(
-                       $this->curl_path . " -k -D \"$headerfile\"" . 
$cmdline_params . " \"" . escapeshellcmd( $URI ) . "\"",
-                       $results,
-                       $return
-               );
-
-               if( $return ) {
-                       $this->error = "Error: cURL could not retrieve the 
document, error $return.";
-                       return false;
-               }
-
-               $results = implode( "\r\n", $results );
-
-               $result_headers = file( "$headerfile" );
-
-               $this->_redirectaddr = false;
-               unset( $this->headers );
-
-               for( $currentHeader = 0; $currentHeader < count( 
$result_headers ); $currentHeader++ ) {
-                       // if a header begins with Location: or URI:, set the 
redirect
-                       if( preg_match( "/^(Location: |URI: )/i", 
$result_headers[$currentHeader] ) ) {
-                               // get URL portion of the redirect
-                               preg_match( "/^(Location: |URI:)\s+(.*)/", 
chop( $result_headers[$currentHeader] ), $matches );
-                               // look for :// in the Location header to see 
if hostname is included
-                               if( !preg_match( "|\:\/\/|", $matches[2] ) ) {
-                                       // no host in the path, so prepend
-                                       $this->_redirectaddr = 
$URI_PARTS['scheme'] . '://' . $this->host . ':' . $this->port;
-                                       // eliminate double slash
-                                       if( !preg_match( "|^/|", $matches[2] ) 
) {
-                                               $this->_redirectaddr .= '/' . 
$matches[2];
-                                       } else {
-                                               $this->_redirectaddr .= 
$matches[2];
-                                       }
-                               } else {
-                                       $this->_redirectaddr = $matches[2];
-                               }
-                       }
-
-                       if( preg_match( "|^HTTP/|", 
$result_headers[$currentHeader] ) ) {
-                               $this->response_code = 
$result_headers[$currentHeader];
-                       }
-
-                       $this->headers[] = $result_headers[$currentHeader];
-               }
-
-               // check if there is a a redirect meta tag
-               if( preg_match( 
"'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",
 $results, $match ) )
-               {
-                       $this->_redirectaddr = $this->_expandlinks( $match[1], 
$URI );
-               }
-
-               // have we hit our frame depth and is there frame src to fetch?
-               if( ( $this->_framedepth < $this->maxframes ) && 
preg_match_all( "'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i", $results, $match 
) )
-               {
-                       $this->results[] = $results;
-                       for( $x = 0; $x < count( $match[1] ); $x++ ) {
-                               $this->_frameurls[] = $this->_expandlinks( 
$match[1][$x], $URI_PARTS['scheme'] . '://' . $this->host );
-                       }
-               } elseif( is_array( $this->results ) ) { // have we already 
fetched framed content?
-                       $this->results[] = $results;
-               } else { // no framed content
-                       $this->results = $results;
-               }
-
-               unlink( "$headerfile" );
-
-               return true;
-       }
-
-       
/*======================================================================*\
-       Function:       setcookies()
-       Purpose:        set cookies for a redirection
-       
\*======================================================================*/
-       function setcookies() {
-               for( $x = 0; $x < count( $this->headers ); $x++ ) {
-                       if( preg_match( '/^set-cookie:[\s]+([^=]+)=([^;]+)/i', 
$this->headers[$x], $match ) ) {
-                               $this->cookies[$match[1]] = urldecode( 
$match[2] );
-                       }
-               }
-       }
-
-       
/*======================================================================*\
-       Function:       _check_timeout
-       Purpose:        checks whether timeout has occurred
-       Input:          $fp     file pointer
-       
\*======================================================================*/
-       function _check_timeout( $fp ) {
-               if ( $this->read_timeout > 0 ) {
-                       $fp_status = socket_get_status( $fp );
-                       if ( $fp_status['timed_out'] ) {
-                               $this->timed_out = true;
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       
/*======================================================================*\
-       Function:       _connect
-       Purpose:        make a socket connection
-       Input:          $fp     file pointer
-       
\*======================================================================*/
-       function _connect( &$fp ) {
-               if( !empty( $this->proxy_host ) && !empty( $this->proxy_port ) 
) {
-                       $this->_isproxy = true;
-                       $host = $this->proxy_host;
-                       $port = $this->proxy_port;
-               } else {
-                       $host = $this->host;
-                       $port = $this->port;
-               }
-
-               $this->status = 0;
-
-               $fp = fsockopen( $host, $port, $errno, $errstr, 
$this->_fp_timeout );
-
-               if ( $fp ) {
-                       // socket connection succeeded
-                       return true;
-               } else {
-                       // socket connection failed
-                       $this->status = $errno;
-                       switch( $errno ) {
-                               case -3:
-                                       $this->error = 'socket creation failed 
(-3)';
-                               case -4:
-                                       $this->error = 'dns lookup failure 
(-4)';
-                               case -5:
-                                       $this->error = 'connection refused or 
timed out (-5)';
-                               default:
-                                       $this->error = 'connection failed (' . 
$errno . ')';
-                       }
-                       return false;
-               }
-       }
-
-       
/*======================================================================*\
-       Function:       _disconnect
-       Purpose:        disconnect a socket connection
-       Input:          $fp     file pointer
-       
\*======================================================================*/
-       function _disconnect( $fp ) {
-               return( fclose( $fp ) );
-       }
-
-       
/*======================================================================*\
-       Function:       _prepare_post_body
-       Purpose:        Prepare post body according to encoding type
-       Input:          $formvars  - form variables
-                               $formfiles - form upload files
-       Output:         post body
-       
\*======================================================================*/
-       function _prepare_post_body( $formvars, $formfiles ) {
-               settype( $formvars, 'array' );
-               settype( $formfiles, 'array' );
-               $postdata = '';
-
-               if ( count( $formvars ) == 0 && count( $formfiles ) == 0 ) {
-                       return;
-               }
-
-               switch ( $this->_submit_type ) {
-                       case 'application/x-www-form-urlencoded':
-                               reset( $formvars );
-                               while( list( $key, $val ) = each( $formvars ) ) 
{
-                                       if ( is_array( $val ) || is_object( 
$val ) ) {
-                                               while ( list( $cur_key, 
$cur_val ) = each( $val ) ) {
-                                                       $postdata .= urlencode( 
$key ) . '[]=' . urlencode( $cur_val ) . '&';
-                                               }
-                                       } else {
-                                               $postdata .= urlencode( $key ) 
. '=' . urlencode( $val ) . '&';
-                                       }
-                               }
-                               break;
-
-                       case 'multipart/form-data':
-                               $this->_mime_boundary = 'Snoopy' . md5( uniqid( 
microtime() ) );
-
-                               reset( $formvars );
-                               while( list( $key, $val ) = each( $formvars ) ) 
{
-                                       if ( is_array( $val ) || is_object( 
$val ) ) {
-                                               while ( list( $cur_key, 
$cur_val ) = each( $val ) ) {
-                                                       $postdata .= '--' . 
$this->_mime_boundary . "\r\n";
-                                                       $postdata .= 
"Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n";
-                                                       $postdata .= 
"$cur_val\r\n";
-                                               }
-                                       } else {
-                                               $postdata .= '--' . 
$this->_mime_boundary . "\r\n";
-                                               $postdata .= 
"Content-Disposition: form-data; name=\"$key\"\r\n\r\n";
-                                               $postdata .= "$val\r\n";
-                                       }
-                               }
-
-                               reset( $formfiles );
-                               while ( list( $field_name, $file_names ) = 
each( $formfiles ) ) {
-                                       settype( $file_names, 'array' );
-                                       while ( list( , $file_name ) = each( 
$file_names ) ) {
-                                               if ( !is_readable( $file_name ) 
) {
-                                                       continue;
-                                               }
-
-                                               $fp = fopen( $file_name, 'r' );
-                                               $file_content = fread( $fp, 
filesize( $file_name ) );
-                                               fclose( $fp );
-                                               $base_name = basename( 
$file_name );
-
-                                               $postdata .= '--' . 
$this->_mime_boundary . "\r\n";
-                                               $postdata .= 
"Content-Disposition: form-data; name=\"$field_name\"; 
filename=\"$base_name\"\r\n\r\n";
-                                               $postdata .= 
"$file_content\r\n";
-                                       }
-                               }
-                               $postdata .= '--' . $this->_mime_boundary . 
"--\r\n";
-                               break;
-               }
-
-               return $postdata;
-       }
-}
\ No newline at end of file
diff --git a/extension.json b/extension.json
new file mode 100644
index 0000000..c576116
--- /dev/null
+++ b/extension.json
@@ -0,0 +1,39 @@
+{
+       "name": "MediaWikiAuth",
+       "version": "0.9.0",
+       "author": [
+               "Laurence Parry",
+               "Jack Phoenix",
+               "Kim Schoonover",
+               "Ryan Schmidt"
+       ],
+       "url": "https://www.mediawiki.org/wiki/Extension:MediaWikiAuth";,
+       "descriptionmsg": "mwa-desc",
+       "license-name": "GPL-2.0+",
+       "type": "other",
+       "config": {
+               "MediaWikiAuthApiUrl": ""
+       },
+       "MessagesDirs": {
+               "MediaWikiAuth": [
+                       "i18n"
+               ]
+       },
+       "AutoloadClasses": {
+               "MediaWikiAuth\\ExternalWikiPrimaryAuthenticationProvider": 
"ExternalWikiPrimaryAuthenticationProvider.php",
+               "MediaWikiAuth\\PopulateImportedWatchlistJob": 
"PopulateImportedWatchlistJob.php"
+       },
+       "JobClasses": {
+               "populateImportedWatchlist": 
"MediaWikiAuth\\PopulateImportedWatchlistJob"
+       },
+       "AuthManagerAutoConfig": {
+               "primaryauth": {
+                       "ExternalWikiPrimaryAuthenticationProvider": {
+                               "class": 
"MediaWikiAuth\\ExternalWikiPrimaryAuthenticationProvider",
+                               "args": [ { "authoritative": false } ],
+                               "sort": 50
+                       }
+               }
+       },
+       "manifest_version": 1
+}
diff --git a/i18n/en.json b/i18n/en.json
index ca69c7f..930b5c7 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1,14 +1,14 @@
 {
        "@metadata": {
                "authors": [
-                       "Laurence \"GreenReaper\" Parry"
+                       "Laurence \"GreenReaper\" Parry",
+                       "Ryan Schmidt"
                ]
        },
        "mwa-desc": "Authenticates against and imports logins from an external 
MediaWiki instance",
-       "mwa-autocreate-blocked": "Automatic account creation is blocked for 
this IP on the remote wiki.",
        "mwa-error-unknown": "Unknown error when logging in to the remote 
wiki.",
-       "mwa-error-wrong-token": "A login token submission error occurred. 
Please retry, and contact an administrator if this fails.",
-       "mwa-must-be-imported": "Your account must be imported.\nPlease <a 
target=\"_new\" href=\"http://www.wikia.com/wiki/Special:UserLogin\";>reset your 
password at Wikia</a>, then use the new password here.<br /><br 
/>\n<b>Note:</b> You must use the password Wikia emails you to login there. You 
will then be asked to set a new password, which can be used here.",
-       "mwa-resetpass": "You cannot login with a temporary password. Please 
use it on the remote wiki to create a new permanent password.",
-       "mwa-wait": "Please wait $1 seconds before trying again."
-}
\ No newline at end of file
+       "mwa-authfail": "Unable to log into the remote wiki to import your 
account. Ensure you are using the correct password.",
+       "mwa-finishcreate": "Your account has been successfully imported. You 
may set a new password now or choose \"$1\" to keep your current password.",
+       "mwa-unconfiguredtitle": "Extension not configured.",
+       "mwa-unconfiguredtext": "The MediaWikiAuth extension is not configured 
properly. Ensure that $wgMediaWikiAuthApiUrl is set in your LocalSettings.php 
to the API URL of the remote wiki."
+}
diff --git a/i18n/qqq.json b/i18n/qqq.json
index cba58ad..10b4a89 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -6,5 +6,7 @@
        "mwa-error-wrong-token": "Used as error message for wrong token on 
account creation",
        "mwa-must-be-imported": "Used as message on account creation",
        "mwa-resetpass": "Used as error message for resetting password",
-       "mwa-wait": "Used as message to wait on account creation"
+       "mwa-wait": "Used as message to wait on account creation",
+       "mwa-unconfiguredtitle": "Used as the page title on the error page when 
the extension is not configured",
+       "mwa-unconfiguredtext": "Used as the page text on the error page when 
the extension is not configured. $wgMediaWikiAuthApiUrl is a PHP variable name 
and must be preserved as-is; do not translate or modify it."
 }
diff --git a/patches/SpecialUserlogin.php-1.17alpha.r67921.patch 
b/patches/SpecialUserlogin.php-1.17alpha.r67921.patch
deleted file mode 100644
index acd0106..0000000
--- a/patches/SpecialUserlogin.php-1.17alpha.r67921.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-Index: SpecialUserlogin.php
-===================================================================
---- SpecialUserlogin.php       (revision 67921)
-+++ SpecialUserlogin.php       (working copy)
-@@ -234,6 +234,13 @@
-                       return false;
-               }
- 
-+              // Patch for MediaWikiAuth extension
-+              if ( $this->checkImportableUser( $this->mName ) ) {
-+                      $this->mainLoginForm( wfMsg( 'userexists' ) );
-+                      return false;
-+              }
-+              // Patch ends here
-+
-               // 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
-@@ -594,8 +601,15 @@
-                               wfDebug( __METHOD__.": user does not exist\n" );
-                               return self::NOT_EXISTS;
-                       }
--                      if ( !$wgAuth->authenticate( $user->getName(), 
$this->mPassword ) ) {
-+                      // Patch for MediaWikiAuth extension
-+                      $errormsg = null;
-+                      if ( !$wgAuth->authenticate( $user->getName(), 
$this->mPassword, $errormsg ) ) {
-                               wfDebug( __METHOD__.": \$wgAuth->authenticate() 
returned false, aborting\n" );
-+
-+                              # The AuthPlugin may have set a custom error 
message
-+                              $this->mainLoginForm( isset( $errormsg ) ? 
$errormsg : wfMsg( 'wrongpassword' ) );
-+                              // Patch ends here
-+
-                               return self::WRONG_PLUGIN_PASS;
-                       }
-               }
-@@ -647,7 +661,7 @@
-                               $this->mainLoginForm( wfMsg( 'noname' ) );
-                               break;
-                       case self::WRONG_PLUGIN_PASS:
--                              $this->mainLoginForm( wfMsg( 'wrongpassword' ) 
);
-+                              # Message is handled in the authentication code
-                               break;
-                       case self::NOT_EXISTS:
-                               if( $wgUser->isAllowed( 'createaccount' ) ){
-@@ -688,6 +702,51 @@
-       }
- 
-       /**
-+       * New function for MediaWikiAuth extension
-+       *
-+       * @param $username Mixed: username to check
-+       * @return Boolean
-+       */
-+      private function checkImportableUser( $username ) {
-+              # Check against a table of existing names to import
-+              $dbr = wfGetDB( DB_SLAVE );
-+
-+              # If this table exists, there's users to import
-+              if ( $dbr->tableExists( 'user' ) ) {
-+                      $res = $dbr->select(
-+                              'user',
-+                              array( 'user_id' ),
-+                              array( 'user_name' => $username ),
-+                              __METHOD__
-+                      );
-+                      $row = $dbr->fetchObject( $res );
-+                      if ( $row ) {
-+                              $dbr->freeResult( $res );
-+                              return true;
-+                      }
-+                      $dbr->freeResult( $res );
-+
-+                      # Because some people have ' in their usernames
-+                      $username = $dbr->strencode( $username );
-+
-+                      # Let's see if the count of revisions by their name is 
greater than 1
-+                      # This is not 100% correct as it is possible to have a 
username
-+                      # like greenReaper, enter greenreaper, and match
-+                      # However, we're just checking to see if we should even 
try, here
-+                      $revisions = $dbr->selectField(
-+                              'revision',
-+                              'COUNT(1)',
-+                              'rev_user_text = \'' . $username . '\'',
-+                              __METHOD__
-+                      );
-+                      if ( $revisions ) {
-+                              return true;
-+                      }
-+              }
-+              return false;
-+      }
-+
-+      /**
-        * @private
-        */
-       function mailPassword() {
-@@ -746,7 +805,14 @@
-                       return;
-               }
-               if ( 0 == $u->getID() ) {
--                      $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', 
htmlspecialchars( $u->getName() ) ) );
-+                      // Patch for MediaWikiAuth extension
-+                      # Try and get this to work for users that might be 
imported
-+                      if ( $this->checkImportableUser( $u->getName() ) ) {
-+                              $this->mainLoginForm( wfMsg( 
'mwa-must-be-imported' ) );
-+                      } else {
-+                              $this->mainLoginForm( wfMsgWikiHtml( 
'nosuchuser', htmlspecialchars( $u->getName() ) ) );
-+                      }
-+                      // Patch ends here
-                       return;
-               }
- 
diff --git a/patches/SpecialUserlogin.php-1.20.0.patch 
b/patches/SpecialUserlogin.php-1.20.0.patch
deleted file mode 100644
index a9ed26f..0000000
--- a/patches/SpecialUserlogin.php-1.20.0.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-diff --git a/includes/specials/SpecialUserlogin.php 
b/includes/specials/SpecialUserlogin.php
-index c101897..4c972a2 100644
---- a/includes/specials/SpecialUserlogin.php
-+++ b/includes/specials/SpecialUserlogin.php
-@@ -281,6 +281,13 @@ class LoginForm extends SpecialPage {
-                       return false;
-               }
- 
-+              // Patch for MediaWikiAuth extension
-+              if ( self::checkImportableUser( $this->mUsername ) ) {
-+                      $this->mainLoginForm( wfMsg( 'userexists' ) );
-+                      return false;
-+              }
-+              // Patch ends here
-+
-               // 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
-@@ -698,8 +705,13 @@ class LoginForm extends SpecialPage {
-                               wfDebug( __METHOD__ . ": user does not exist\n" 
);
-                               return self::NOT_EXISTS;
-                       }
--                      if ( !$wgAuth->authenticate( $user->getName(), 
$this->mPassword ) ) {
-+                      // Patch for MediaWikiAuth extension
-+                      $errormsg = null;
-+                      if ( !$wgAuth->authenticate( $user->getName(), 
$this->mPassword, $errormsg ) ) {
-                               wfDebug( __METHOD__ . ": 
\$wgAuth->authenticate() returned false, aborting\n" );
-+                              # The AuthPlugin may have set a custom error 
message
-+                              $this->mainLoginForm( isset( $errormsg ) ? 
$errormsg : wfMsg( 'wrongpassword' ) );
-+                              // Patch ends here
-                               return self::WRONG_PLUGIN_PASS;
-                       }
-               }
-@@ -763,7 +775,7 @@ class LoginForm extends SpecialPage {
-                               $this->mainLoginForm( $this->msg( 'noname' 
)->text() );
-                               break;
-                       case self::WRONG_PLUGIN_PASS:
--                              $this->mainLoginForm( $this->msg( 
'wrongpassword' )->text() );
-+                              # Message is handled in the authentication code
-                               break;
-                       case self::NOT_EXISTS:
-                               if( $this->getUser()->isAllowed( 
'createaccount' ) ) {
-@@ -1124,6 +1136,47 @@ class LoginForm extends SpecialPage {
-       }
- 
-       /**
-+       * New function for MediaWikiAuth extension
-+       *
-+       * @param $username Mixed: username to check
-+       * @return Boolean
-+       */
-+      public static function checkImportableUser( $username ) {
-+              $dbr = wfGetDB( DB_SLAVE );
-+ 
-+              # Check against existing users
-+              if ( $dbr->tableExists( 'user' ) ) {
-+                      $res = $dbr->select(
-+                              'user',
-+                              array( 'user_id' ),
-+                              array( 'user_name' => $username ),
-+                              __METHOD__
-+                      );
-+                      $row = $dbr->fetchObject( $res );
-+                      # Check for valid id to see if user already exists; 
stop if it does
-+                      # In theory, anyway. 
-+                      if ( $row > 0 ) {
-+                              return false;
-+                      }
-+ 
-+                      # Let's see if the count of revisions by their name is 
greater than 1
-+                      # This is not 100% correct as it is possible to have a 
username
-+                      # like greenReaper, enter greenreaper, and match
-+                      # However, we're just checking to see if we should even 
try, here
-+                      $revisions = $dbr->selectField(
-+                              'revision',
-+                              'COUNT(1)',
-+                              array( 'rev_user_text' => $username ),
-+                              __METHOD__
-+                      );
-+                      if ( $revisions ) {
-+                              return true;
-+                      }
-+              }
-+              return false;
-+      }
-+
-+      /**
-        * @private
-        *
-        * @param $user User
diff --git a/patches/SpecialUserlogin.php-1.21.2.patch 
b/patches/SpecialUserlogin.php-1.21.2.patch
deleted file mode 100644
index dd14aa5..0000000
--- a/patches/SpecialUserlogin.php-1.21.2.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-diff --git a/includes/specials/SpecialUserlogin.php 
b/includes/specials/SpecialUserlogin.php
-index eef6691..7f18d7b 100644
---- a/includes/specials/SpecialUserlogin.php
-+++ b/includes/specials/SpecialUserlogin.php
-@@ -318,6 +318,12 @@ class LoginForm extends SpecialPage {
-                       return Status::newFatal( 'wrongpassword' );
-               }
- 
-+              // Patch for MediaWikiAuth extension
-+              if ( self::checkImportableUser( $this->mUsername ) ) {
-+                      return Status::newFatal( 'userexists' );
-+              }
-+              // Patch ends here
-+
-               // 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
-@@ -726,8 +732,13 @@ class LoginForm extends SpecialPage {
-                               wfDebug( __METHOD__ . ": user does not exist\n" 
);
-                               return self::NOT_EXISTS;
-                       }
--                      if ( !$wgAuth->authenticate( $user->getName(), 
$this->mPassword ) ) {
-+                      // Patch for MediaWikiAuth extension
-+                      $errormsg = null;
-+                      if ( !$wgAuth->authenticate( $user->getName(), 
$this->mPassword, $errormsg ) ) {
-                               wfDebug( __METHOD__ . ": 
\$wgAuth->authenticate() returned false, aborting\n" );
-+                              // The AuthPlugin may have set a custom error 
message
-+                              $this->mainLoginForm( isset( $errormsg ) ? 
$errormsg : wfMessage( 'wrongpassword' )->text() );
-+                              // Patch ends here
-                               return self::WRONG_PLUGIN_PASS;
-                       }
-               }
-@@ -805,7 +816,7 @@ class LoginForm extends SpecialPage {
-                               $this->mainLoginForm( $this->msg( 'noname' 
)->text() );
-                               break;
-                       case self::WRONG_PLUGIN_PASS:
--                              $this->mainLoginForm( $this->msg( 
'wrongpassword' )->text() );
-+                              # Message is handled in the authentication code
-                               break;
-                       case self::NOT_EXISTS:
-                               if( $this->getUser()->isAllowed( 
'createaccount' ) ) {
-@@ -1181,6 +1192,47 @@ class LoginForm extends SpecialPage {
-       }
- 
-       /**
-+       * New function for MediaWikiAuth extension
-+       *
-+       * @param $username mixed username to check
-+       * @return bool
-+       */
-+      public static function checkImportableUser( $username ) {
-+              $dbr = wfGetDB( DB_SLAVE );
-+
-+              # Check against existing users
-+              if ( $dbr->tableExists( 'user' ) ) {
-+                      $res = $dbr->select(
-+                              'user',
-+                              array( 'user_id' ),
-+                              array( 'user_name' => $username ),
-+                              __METHOD__
-+                      );
-+                      $row = $dbr->fetchObject( $res );
-+                      # Check for valid id to see if user already exists; 
stop if it does
-+                      # In theory, anyway.
-+                      if ( $row > 0 ) {
-+                              return false;
-+                      }
-+
-+                      # Let's see if the count of revisiosn by their name is 
greater than 1
-+                      # This is not 100% correct as it possible to have a 
username
-+                      # like greenReaper, enter greenreaper and match
-+                      # However, we're just checking to see if we should even 
try, here
-+                      $revisions = $dbr->selectField(
-+                              'revision',
-+                              'COUNT(1)',
-+                              array( 'rev_user_text' => $username ),
-+                              __METHOD__
-+                      );
-+                      if ( $revisions ) {
-+                              return true;
-+                      }
-+              }
-+              return false;
-+      }
-+
-+      /**
-        * @private
-        *
-        * @param $user User
diff --git a/patches/SpecialUserlogin.php-1.23.3.patch 
b/patches/SpecialUserlogin.php-1.23.3.patch
deleted file mode 100644
index 1f4425f..0000000
--- a/patches/SpecialUserlogin.php-1.23.3.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-diff --git a/includes/specials/SpecialUserlogin.php 
b/includes/specials/SpecialUserlogin.php
-old mode 100644
-new mode 100755
-index 9a2e194..c0b62d9
---- a/includes/specials/SpecialUserlogin.php
-+++ b/includes/specials/SpecialUserlogin.php
-@@ -359,13 +359,19 @@ class LoginForm extends SpecialPage {
-        */
-       public function addNewAccountInternal() {
-               global $wgAuth, $wgMemc, $wgAccountCreationThrottle,
--                      $wgMinimalPasswordLength, $wgEmailConfirmToEdit;
-+                      $wgMinimalPasswordLength, $wgEmailConfirmToEdit, 
$wgMediaWikiAuthAPIURL;
- 
-               // If the user passes an invalid domain, something is fishy
-               if ( !$wgAuth->validDomain( $this->mDomain ) ) {
-                       return Status::newFatal( 'wrongpassword' );
-               }
- 
-+              // Patch for MediaWikiAuth extension
-+              if ( isset( $wgMediaWikiAuthAPIURL ) && 
self::checkImportableUser( $this->mUsername ) ) {
-+                      return Status::newFatal( 'userexists' );
-+              }
-+              // Patch ends here
-+
-               // 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
-@@ -785,9 +791,13 @@ class LoginForm extends SpecialPage {
-                       return self::NOT_EXISTS;
-               }
- 
--              if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword 
) ) {
-+              // Patch for MediaWikiAuth extension
-+              $errormsg = null;
-+              if ( !$wgAuth->authenticate( $user->getName(), 
$this->mPassword, $errormsg ) ) {
-                       wfDebug( __METHOD__ . ": \$wgAuth->authenticate() 
returned false, aborting\n" );
--
-+                      // The AuthPlugin may have set a custom error message
-+                      $this->mainLoginForm( isset( $errormsg ) ? $errormsg : 
wfMessage( 'wrongpassword' )->text() );
-+                      // Patch ends here
-                       return self::WRONG_PLUGIN_PASS;
-               }
- 
-@@ -880,8 +890,11 @@ class LoginForm extends SpecialPage {
-                               $this->mainLoginForm( $this->msg( $error 
)->text() );
-                               break;
-                       case self::WRONG_PLUGIN_PASS:
-+                              /* Patch for MediaWikiAuth extension
-+                               * Message is handled in the authentication code
-                               $error = $this->mAbortLoginErrorMsg ?: 
'wrongpassword';
-                               $this->mainLoginForm( $this->msg( $error 
)->text() );
-+                               */
-                               break;
-                       case self::NOT_EXISTS:
-                               if ( $this->getUser()->isAllowed( 
'createaccount' ) ) {
-@@ -1156,6 +1169,47 @@ class LoginForm extends SpecialPage {
-       }
- 
-       /**
-+       * New function for MediaWikiAuth extension
-+       *
-+       * @param $username mixed username to check
-+       * @return bool
-+       */
-+      public static function checkImportableUser( $username ) {
-+              $dbr = wfGetDB( DB_SLAVE );
-+
-+              # Check against existing users
-+              if ( $dbr->tableExists( 'user' ) ) {
-+                      $res = $dbr->select(
-+                              'user',
-+                              array( 'user_id' ),
-+                              array( 'user_name' => $username ),
-+                              __METHOD__
-+                      );
-+                      $row = $dbr->fetchObject( $res );
-+                      # Check for valid id to see if user already exists; 
stop if it does
-+                      # In theory, anyway.
-+                      if ( $row > 0 ) {
-+                              return false;
-+                      }
-+
-+                      # Let's see if the count of revisiosn by their name is 
greater than 1
-+                      # This is not 100% correct as it possible to have a 
username
-+                      # like greenReaper, enter greenreaper and match
-+                      # However, we're just checking to see if we should even 
try, here
-+                      $revisions = $dbr->selectField(
-+                              'revision',
-+                              'COUNT(1)',
-+                              array( 'rev_user_text' => $username ),
-+                              __METHOD__
-+                      );
-+                      if ( $revisions ) {
-+                              return true;
-+                      }
-+              }
-+              return false;
-+      }
-+
-+      /**
-        * @private
-        */
-       function mainLoginForm( $msg, $msgtype = 'error' ) {

-- 
To view, visit https://gerrit.wikimedia.org/r/386711
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia0caae13109affe6a441f087e31dc83e9856f309
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MediaWikiAuth
Gerrit-Branch: master
Gerrit-Owner: Skizzerz <skizz...@skizzerz.net>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to