From Wikipedia, the free encyclopedia
/**
* @(#)Wiki.java 0.01 06/03/2007
* Copyright (C) 2007 MER-C
*
* 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.
*/
import java.io.*;
import java.util.*;
import java.net.*;
/**
* This is somewhat of a sketchy bot framework for editing MediaWiki wikis.
* @author MER-C
* @version 0.01
*/
public class Wiki
{
// the domain of the wiki
private String domain;
// something to handle cookies
private Map cookies = new HashMap(10);
/**
* Creates a new connection to a wiki.
* @param domain the wiki domain name e.g. en.wikipedia.org (defaults to en.wikipedia.org)
*/
public Wiki(String domain)
{
if (domain == null || domain == "")
domain = "en.wikipedia.org";
this.domain = "http://" + domain + "/w/index.php";
}
/**
* Logs in to the wiki
* @param username a username
* @param password a password (as a char[] due to JPasswordField)
* @return whether the login succeeded
* @throws IOException if something goes wrong
*/
public boolean login(String username, char[] password) throws IOException
{
// sanitize
String ps = new String(password);
username = URLEncoder.encode(username);
ps = URLEncoder.encode(ps);
// "enable" cookies
String URL = domain + "?title=Special:Userlogin";
URLConnection connection = new URL(URL).openConnection();
grabCookies(connection);
// find the target
URL = domain + "?title=Special:Userlogin&action=submitlogin&type=login";
connection = new URL(URL).openConnection();
setCookies(connection);
connection.setDoOutput(true);
PrintWriter out = new PrintWriter(connection.getOutputStream());
// now we send the data
out.print("wpName=");
out.print(username);
out.print("&wpPassword=");
out.print(ps);
out.print("&wpRemember=1&wpLoginattempt=Log+in");
out.close();
// make it stick by grabbing the cookie
grabCookies(connection);
BufferedReader in = null;
try
{
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
catch (IOException e)
{
if (!(connection instanceof HttpURLConnection))
throw e;
InputStream err = ((HttpURLConnection)connection).getInputStream();
if (err == null)
throw e;
in = new BufferedReader(new InputStreamReader(err));
}
in.readLine();
// test for success
String line;
while ((line = in.readLine()) != null)
if (line.indexOf("Login successful") != -1)
return true;
return false;
}
/**
* Logs out of the wiki.
*/
public void logout()
{
cookie = "";
}
/**
* Gets the raw wikicode for a page.
* @param title the title of the page.
* @throws IOException if something stuffs up the connection between here and wiki
*/
public String getPageText(String title) throws IOException
{
// sanitise the title
title = URLEncoder.encode(title);
// go for it
String URL = domain + "?title=" + title + "&action=raw";
URLConnection connection = new URL(URL).openConnection();
connection.connect();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// get the text
String line;
StringBuffer text = new StringBuffer();
while ((line = in.readLine()) != null)
text.append(line);
return text.toString();
}
/**
* Edits a page by setting its text to the supplied value.
* @param text the text of the page
* @param title the title of the page
* @param summary the edit summary
* @param minor whether the edit should be marked as minor
* @throws IOException if something stuffs up the connection between here and wiki
*/
public void editPage(String title, String text, String summary, boolean minor) throws IOException
{
// sanitise
title = URLEncoder.encode(title);
summary = URLEncoder.encode(summary);
text = URLEncoder.encode(text);
// what we need to do is get the edit page and fish out the wpEditToken, wpAutoSummary
// wpStartTime and wpEditTime values
String URL = domain + "?title=" + title + "&action=edit";
URLConnection connection = new URL(URL).openConnection();
setCookies(connection);
connection.connect();
grabCookies(connection);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// more specifically, we're looking for "name="wpEditToken"", "name="wpAutoSummary""
String line, wpEditToken = "", wpAutoSummary = "", wpStarttime = "", wpEdittime = "";
boolean editRetrieved = false, summaryRetrieved = false, startRetrieved = false, timeRetrieved = false;
while ((line = in.readLine()) != null)
{
if (line.indexOf("name=\"wpAutoSummary\"") != -1)
{
int x = line.indexOf("value=\"") + 7;
wpAutoSummary = line.substring(x, line.indexOf('\"', x));
summaryRetrieved = true;
}
else if (line.indexOf("name=\"wpEditToken\"") != -1)
{
int x = line.indexOf("value=\"") + 7;
wpEditToken = line.substring(x, line.indexOf('\"', x));
editRetrieved = true;
}
else if (line.indexOf("name=\"wpEdittime\"") != -1)
{
int x = line.indexOf("value=\"") + 7;
wpEdittime = line.substring(x, line.indexOf('\"', x));
timeRetrieved = true;
}
else if (line.indexOf("name=\"wpStarttime\"") != -1)
{
int x = line.indexOf("value=\"") + 7;
wpStarttime = line.substring(x, line.indexOf('\"', x));
startRetrieved = true;
}
else if (editRetrieved && summaryRetrieved && startRetrieved && timeRetrieved)
break; // bandwidth hack
}
// this is what accepts the text
URL = domain + "?title=" + title + "&action=submit";
connection = new URL(URL).openConnection();
setCookies(connection);
connection.setDoOutput(true);
PrintWriter out = new PrintWriter(connection.getOutputStream());
// now we send the data
out.print("wpTextbox1=");
out.print(text);
out.print("&wpSummary=");
out.print(summary);
if (minor)
out.print("&wpMinoredit=1");
out.print("&wpEdittime=");
out.print(wpEdittime);
out.print("&wpEditToken=");
out.print(wpEditToken);
out.print("&wpStarttime=");
out.print(wpStarttime);
out.print("&wpAutoSummary=");
out.print(wpAutoSummary);
//done, give the servers a rest
out.close();
try
{
Thread.sleep(2000);
// it's somewhat strange that the edit only sticks when you start reading the
// response...
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
catch (IOException e)
{
if (!(connection instanceof HttpURLConnection))
throw e;
InputStream err = ((HttpURLConnection)connection).getInputStream();
if (err == null)
throw e;
in = new BufferedReader(new InputStreamReader(err));
}
catch (InterruptedException e)
{
// nobody cares
}
in.readLine();
// for debugging and/or todo purposes
// String line;
// while ((line = in.readLine()) != null)
// {
// System.out.println(line);
// }
}
/**
* Prepends something to the given page. A convenience method for adding maintainance
* templates, rather than getting and setting the page yourself. Edit summary is
* automatic, being "+whatever".
* @param title the title of the page
* @param stuff what to prepend to the page
* @param minor whether the edit is minor (a prod compared to a simple tag)
* @throws IOException if something goes wrong
*/
public void prepend(String title, String stuff, boolean minor) throws IOException
{
StringBuffer text = new StringBuffer();
text.append(stuff);
text.append(getPageText(title));
editPage(title, text.toString(), "+" + stuff, minor);
}
/**
* Grabs cookies from the URL connection provided.
* @param u an unconnected URLConnection
*/
private void grabCookies(URLConnection u)
{
// reset the cookie store
cookies.clear();
String headerName = null;
for (int i = 1; (headerName = u.getHeaderFieldKey(i)) != null; i++)
{
if (headerName.equals("Set-Cookie"))
{
String cookie = u.getHeaderField(i);
cookie = cookie.substring(0, cookie.indexOf(";"));
String name = cookie.substring(0, cookie.indexOf("="));
String value = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
cookies.put(name, value);
}
}
}
/**
* Sets cookies to an unconnected URLConnection.
* @param u an unconnected URLConnection
*/
private void setCookies(URLConnection u)
{
Iterator i = cookies.entrySet().iterator();
StringBuffer cookie = new StringBuffer();
while (i.hasNext())
{
Map.Entry entry = (Map.Entry)i.next();
cookie.append(entry.getKey());
cookie.append("=");
cookie.append(entry.getValue());
cookie.append("; ");
}
u.setRequestProperty("Cookie", cookie.toString());
}
}