User:TheFearow/Wiki.java
Info
This is a wiki interface, based on MER-C's version at User:MER-C/Wiki.java.
I have added several functions and renamed some, more functions are on the way. Enjoy!
Code
/**
* @(#)Wiki.java 0.03 10/06/2007
* Copyright (C) 2007 MER-C
* Modified by TheFearow
*
* 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.03
*/
public class Wiki
{
/**
* Denotes the namespace of images and media, such that there is no description page.
* Uses the "Media:" prefix.
* @see IMAGE_NAMESPACE
* @since 0.03
*/
public static final int MEDIA_NAMESPACE = -2;
/**
* Denotes the namespace of pages with the "Special:" prefix. Note that many methods
* dealing with special pages may spew due to raw content not being available.
* @since 0.03
*/
public static final int SPECIAL_NAMESPACE = -1;
/**
* Denotes the main namespace, with no prefix.
* @since 0.03
*/
public static final int MAIN_NAMESPACE = 0;
/**
* Denotes the namespace for talk pages relating to the main namespace, denoted by the
* prefix "Talk:".
* @since 0.03
*/
public static final int TALK_NAMESPACE = 1;
/**
* Denotes the namespace for user pages, given the prefix "User:".
* @since 0.03
*/
public static final int USER_NAMESPACE = 2;
/**
* Denotes the namespace for user talk pages, given the prefix "User talk:".
* @since 0.03
*/
public static final int USER_TALK_NAMESPACE = 3;
/**
* Denotes the namespace for pages relating to the project, with prefix "Project:". It
* also goes by the name of whatever the project name was.
* @since 0.03
*/
public static final int PROJECT_NAMESPACE = 4;
/**
* Denotes the namespace for talk pages relating to project pages, with prefix "Project
* talk:". It also goes by the name of whatever the project name was, + "talk:".
* @since 0.03
*/
public static final int PROJECT_TALK_NAMESPACE = 5;
/**
* Denotes the namespace for image description pages. Has the prefix "Image:". Do not
* create these directly, use upload() instead.
* @see MEDIA_NAMESPACE
* @since 0.03
*/
public static final int IMAGE_NAMESPACE = 6;
/**
* Denotes talk pages for image description pages. Has the prefix "Image talk:".
* @since 0.03
*/
public static final int IMAGE_TALK_NAMESPACE = 7;
/**
* Denotes the namespace for (wiki) system messages, given the prefix "MediaWiki:".
* @since 0.03
*/
public static final int MEDIAWIKI_NAMESPACE = 8;
/**
* Denotes the namespace for talk pages relating to system messages, given the prefix
* "MediaWiki talk:".
* @since 0.03
*/
public static final int MEDIAWIKI_TALK_NAMESPACE = 9;
/**
* Denotes the namespace for templates, given the prefix "Template:".
* @since 0.03
*/
public static final int TEMPLATE_NAMESPACE = 10;
/**
* Denotes the namespace for talk pages regarding templates, given the prefix
* "Template talk:".
* @since 0.03
*/
public static final int TEMPLATE_TALK_NAMESPACE = 11;
/**
* Denotes the namespace for help pages, given the prefix "Help:".
* @since 0.03
*/
public static final int HELP_NAMESPACE = 12;
/**
* Denotes the namespace for talk pages regarding help pages, given the prefix "Help
* talk:".
* @since 0.03
*/
public static final int HELP_TALK_NAMESPACE = 13;
/**
* Denotes the namespace for category description pages. Has the prefix "Category:".
* @since 0.03
*/
public static final int CATEGORY_NAMESPACE = 14;
/**
* Denotes the namespace for talk pages regarding categories. Has the prefix "Category
* talk:".
* @since 0.03
*/
public static final int CATEGORY_TALK_NAMESPACE = 15;
/**
* Denotes all namespaces.
* @since 0.03
*/
public static final int ALL_NAMESPACES = 0x09f91102;
// the domain of the wiki
private String domain;
private String query;
// something to handle cookies
private Map cookies = new HashMap(10);
// internal data storage
private Map namespaces = null;
/**
* Creates a new connection to the English Wikipedia.
* @since 0.02
*/
public Wiki()
{
this("");
}
/**
* 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";
query = "http://" + domain + "/w/query.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()
{
cookies.clear();
}
/**
* Gets the raw wikicode for a page. WARNING: does not support special pages.
* @param title the title of the page.
* @throws IOException if something stuffs up the connection between here and wiki
* @return the raw wikicode of a page
* @throws IllegalArgumentException if you try to retrieve the text of a Special: page or a Media: page
*/
public String getPageText(String title) throws IOException
{
// pitfall check
if (namespace(title) < 0)
throw new IllegalArgumentException("Cannot retrieve Special: or Media: pages!");
// 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+"\n");
return text.toString();
}
/**
* Gets the rendered HTML for a page. WARNING: does not support special pages.
* @param title the title of the page.
* @throws IOException if something stuffs up the connection between here and wiki
* @return the rendered HTML of a page
* @throws IllegalArgumentException if you try to retrieve the text of a Special: page or a Media: page
*/
public String getPageTextRendered(String title) throws IOException
{
// pitfall check
if (namespace(title) < 0)
throw new IllegalArgumentException("Cannot retrieve Special: or Media: pages!");
// sanitise the title
title = URLEncoder.encode(title);
// go for it
String URL = domain + "?title=" + title + "&action=render";
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+"\n");
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
* @throws IllegalArgumentException if you try to edit a Special: page or a Media: page
*/
public void editPage(String title, String text, String summary, boolean minor) throws IOException
{
// pitfall check
if (namespace(title) < 0)
throw new IllegalArgumentException("Cannot edit Special: or Media: pages!");
// 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, watchRetrieved = false;
boolean watched = 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 (line.indexOf("name=\"wpWatchthis\"") != -1)
{
watched = (line.indexOf("checked=\"") != -1);
watchRetrieved = true;
}
else if (editRetrieved && summaryRetrieved && startRetrieved && timeRetrieved && watchRetrieved)
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");
if (watched)
out.print("&wpWatchthis=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 addPagePrefix(String title, String stuff, boolean minor) throws IOException
{
StringBuffer text = new StringBuffer();
text.append(stuff);
text.append(getPageText(title));
editPage(title, text.toString(), "Added prefix +" + stuff, minor);
}
/**
* Adds something to the end of the given page. A convenience method for adding various
* things, 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 add 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 addPageSuffix(String title, String stuff, boolean minor) throws IOException
{
StringBuffer text = new StringBuffer();
text.append(getPageText(title));
text.append(stuff);
editPage(title, text.toString(), "Added suffix +" + stuff, minor);
}
/**
* Gets the members of a category.
* @param name the name of the category (e.g. Candidates for speedy deletion, not
* Category:Candidates for speedy deletion)
* @return a String[] containing page titles of members of the category
* @throws IOException if something goes wrong
* @since 0.02
*/
public String[] getCategoryMembers(String name) throws IOException
{
return getCategoryMembers(name, ALL_NAMESPACES);
}
/**
* Gets the members of a category.
* @param name the name of the category (e.g. Candidates for speedy deletion, not
* Category:Candidates for speedy deletion)
* @param namespace filters by namespace, returns empty if namespace does not exist
* @return a String[] containing page titles of members of the category
* @throws IOException if something goes wrong
* @since 0.03
*/
public String[] getCategoryMembers(String name, int namespace) throws IOException
{
String url;
if (namespace == ALL_NAMESPACES)
url = query + "?what=category&format=xml&cptitle=" + URLEncoder.encode(name);
else
url = query + "?what=category&format=xml&cptitle=" + URLEncoder.encode(name) + "&cpnamespace=" + namespace;
URLConnection connection = new URL(url).openConnection();
connection.connect();
// read the first line, as it is the only thing worth paying attention to
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = in.readLine();
// parse
ArrayList<String> members = new ArrayList<String>(10000); // enough for most cats
while (line.indexOf("<title>") != -1)
{
int x = line.indexOf("<title>");
int y = line.indexOf("</title");
members.add(line.substring(x + 7, y));
line = line.substring(y + 8, line.length());
}
return members.toArray(new String[0]);
}
/**
* Returns the namespace the page is in. Uses /w/query.php?what=namespaces to fetch
* list of namespaces.
* @since 0.03
* @return one of namespace types above, or a number for custom namespaces or ALL_NAMESPACES
* if we can't make sense of it
* @throws IOException if something goes wrong
*/
public int namespace(String title) throws IOException
{
// sanitise
title = title.replace('_', ' ');
if (title.indexOf(':') == -1)
return MAIN_NAMESPACE;
String namespace = title.substring(0, title.indexOf(':'));
// all wiki namespace test
if (namespace.equals("Project talk"))
return PROJECT_TALK_NAMESPACE;
if (namespace.equals("Project"))
return PROJECT_NAMESPACE;
if (namespaces == null)
{
URLConnection connection = new URL(query + "?what=namespaces&format=xml").openConnection();
connection.connect();
// read the first line, as it is the only thing worth paying attention to
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = in.readLine();
namespaces = new HashMap(20);
while (line.indexOf("<ns") != -1)
{
int x = line.indexOf("<ns id=");
if (line.charAt(x + 8) == '0')
{
line = line.substring(13, line.length());
continue;
}
int y = line.indexOf("</ns>");
String working = line.substring(x + 8, y);
int ns = Integer.parseInt(working.substring(0, working.indexOf('"')));
String name = working.substring(working.indexOf(">") + 1, working.length());
namespaces.put(name, new Integer(ns));
line = line.substring(y + 5, line.length());
}
}
if (!namespaces.containsKey(namespace))
return MAIN_NAMESPACE; // For titles like UN:NRV
Iterator i = namespaces.entrySet().iterator();
while (i.hasNext())
{
Map.Entry entry = (Map.Entry)i.next();
if (entry.getKey().equals(namespace))
return ((Integer)entry.getValue()).intValue();
}
return ALL_NAMESPACES; // unintelligble title
}
/**
* 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());
}
}
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.