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", true);
        int a = blah.indexOf("wpLoginToken") + 21;
        int b = blah.indexOf('\"', a);
        String wpLoginToken = blah.substring(a, b);

        // sanitize
        username = URLEncoder.encode(username, "UTF-8");

        // start
        String url = query + "action=login";
        URLConnection connection = new URL(url).openConnection();
        logurl(url, "login");
        setCookies(connection, cookies2);
        connection.setDoOutput(true);
        connection.connect();

        // send
        OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
        out.write("lgname=");
        out.write(username);
        out.write("&lgpassword=");
        out.write(password);
        out.write("&lgtoken=");
        out.write(URLEncoder.encode(wpLoginToken, "UTF-8"));
        out.close();

        // get the cookies. Note: no post() here because of this line!
        grabCookies(connection, cookies);

        // determine success
        BufferedReader in = new BufferedReader(new InputStreamReader(
            zipped ? new GZIPInputStream(connection.getInputStream()) : connection.getInputStream(), "UTF-8"));String line = in.readLine();
        boolean success = line.contains("result=\"Success\"");
        in.close();
        if (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(20000); // 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.");
        }
    }