public synchronized void login(String username, char[] password) throws IOException, FailedLoginException
    {
        // @revised 0.11 to remove screen scraping
        // @revised 0.23 readded screen scraping

        // Scrape a login token from Special:Userlogin. Login tokens should be
        // available through prop=info !
        String blah = fetch(base + "Special:Userlogin", "login");
        int a = blah.indexOf("wpLoginToken") + 21;
        int b = blah.indexOf('\"', a);
        String wpLoginToken = blah.substring(a, b);

        // post login request
        username = normalize(username);
        StringBuilder buffer = new StringBuilder(500);
        buffer.append("lgname=");
        buffer.append(URLEncoder.encode(username, "UTF-8"));
        buffer.append("&lgpassword=");
        buffer.append(URLEncoder.encode(new String(password), "UTF-8"));
        buffer.append("&lgtoken=");
        buffer.append(URLEncoder.encode(wpLoginToken, "UTF-8"));
        String line = post(apiUrl + "action=login", buffer.toString(), "login");
        buffer = null;
        
        // check for success
        if (line.contains("result=\"Success\""))
        {
            user = new User(username);
            boolean apihighlimit = user.isAllowedTo("apihighlimits");
            max = apihighlimit ? 5000 : 500;
            log(Level.INFO, "Successfully logged in as " + username + ", highLimit = " + apihighlimit, "login");
        }
        else
        {
            log(Level.WARNING, "Failed to log in as " + username, "login");
            try
            {
                Thread.sleep(200); // to prevent brute force
            }
            catch (InterruptedException e)
            {
                // nobody cares
            }
            // test for some common failure reasons
            if (line.contains("WrongPass") || line.contains("WrongPluginPass"))
                throw new FailedLoginException("Login failed: incorrect password.");
            else if (line.contains("NotExists"))
                throw new FailedLoginException("Login failed: user does not exist.");
            throw new FailedLoginException("Login failed: unknown reason.");
        }
    }