1 package net.sourceforge.phpeclipse.wiki.actions.mediawiki.connect;
2 //Parts of this sources are copied and modified from the jEdit Wikipedia plugin:
3 //http://www.djini.de/software/wikipedia/index.html
5 //The modified sources are available under the "Common Public License"
6 //with permission from the original author: Daniel Wunsch
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.UnsupportedEncodingException;
11 import java.net.URLDecoder;
12 import java.util.regex.Matcher;
13 import java.util.regex.Pattern;
15 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.config.IWikipedia;
16 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.MethodException;
17 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.PageNotEditableException;
18 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.UnexpectedAnswerException;
19 import net.sourceforge.phpeclipse.wiki.editor.WikiEditorPlugin;
21 import org.apache.commons.httpclient.ConnectMethod;
22 import org.apache.commons.httpclient.HttpClient;
23 import org.apache.commons.httpclient.HttpConnection;
24 import org.apache.commons.httpclient.HttpException;
25 import org.apache.commons.httpclient.HttpMethod;
26 import org.apache.commons.httpclient.HttpState;
27 import org.apache.commons.httpclient.HttpStatus;
28 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
29 import org.apache.commons.httpclient.NameValuePair;
30 import org.apache.commons.httpclient.URI;
31 import org.apache.commons.httpclient.UsernamePasswordCredentials;
32 import org.apache.commons.httpclient.methods.GetMethod;
33 import org.apache.commons.httpclient.methods.PostMethod;
34 import org.apache.commons.httpclient.protocol.Protocol;
35 import org.apache.commons.httpclient.util.EncodingUtil;
38 * This class gets the wikitext from a wikipedia edit page
40 * The basic coding was copied from the commons-httpclient example <code>MediaWikiConnector.java</code>
42 public class MediaWikiConnector {
43 //pattern used to scarp an edit page
44 private static final Pattern BODY_PATTERN = Pattern.compile(
46 * action=".*?title=(.*?)(&|\") <form id="editform" name="editform" method="post"
47 * action="/w/wiki.phtml?title=Ammersee&action=submit" locked pages: <textarea cols='80' rows='25' readonly>
49 ".*<form[^>]*\\sid=\"editform\"[^>]*title=(.*?)&[^>]*>" + ".*<textarea[^>]*\\sname=\"wpTextbox1\"[^>]*>(.*?)</textarea>"
50 + ".*<input[^>]*\\svalue=\"(\\d*)\"[^>]*\\sname=\"wpEdittime\"[^>]*>" + ".*", Pattern.DOTALL);
52 //setup default user agent
53 final static public String userAgent = "PHPeclipse.de/0.0";
55 // create a ConnectionManager
56 private MultiThreadedHttpConnectionManager manager;
58 private HttpClient client;
61 * Delay a new store to 1 second
63 private Throttle storeThrottle = new Throttle(1000);
66 private long nextTime = 0;
68 private final long minimumDelay;
70 public Throttle(long minimumDelay) {
71 this.minimumDelay = minimumDelay;
74 /** this is called from the client */
75 public synchronized void delay() throws InterruptedException {
76 long delay = nextTime - System.currentTimeMillis();
79 nextTime = System.currentTimeMillis() + minimumDelay;
83 public MediaWikiConnector() {
84 // <a href="javascript:window.location.href='http://127.0.0.1:8009/open/?' + window.location.href">bookmarklet</a>
85 manager = new MultiThreadedHttpConnectionManager();
86 manager.setMaxConnectionsPerHost(6);
87 manager.setMaxTotalConnections(18);
88 manager.setConnectionStaleCheckingEnabled(true);
89 // open the conversation
90 client = new HttpClient(manager);
91 //client.State.CookiePolicy = CookiePolicy.COMPATIBILITY;
92 //client.HostConfiguration.setHost(LOGON_SITE, LOGON_PORT, "http");
95 /** destructor freeing all resources. the Connection is not usable any more after calling this method */
96 public void destroy() {
100 /** log in - returns success */
101 public boolean login(IWikipedia config, String actionUrl, String user, String password, boolean remember)
102 throws UnexpectedAnswerException, MethodException {
103 PostMethod method = new PostMethod(actionUrl);
104 method.setFollowRedirects(false);
105 method.addRequestHeader("User-Agent", userAgent);
106 NameValuePair[] params = new NameValuePair[] { new NameValuePair("title", config.getLoginTitle()), new NameValuePair("action", "submit"),
107 new NameValuePair("wpName", user), new NameValuePair("wpPassword", password),
108 new NameValuePair("wpRemember", remember ? "1" : "0"), new NameValuePair("wpLoginattempt", "submit") };
109 method.addParameters(params);
113 int responseCode = client.executeMethod(method);
114 String responseBody = method.getResponseBodyAsString();
120 if (responseCode == 302 && responseBody.length() == 0 || responseCode == 200
121 && responseBody.matches(config.getLoginSuccess())) {
123 } else if (responseCode == 200 && responseBody.matches(config.getLoginWrongPw()) || responseCode == 200
124 && responseBody.matches(config.getLoginNoUser())) {
127 throw new UnexpectedAnswerException("login not successful: " + method.getStatusLine());
129 } catch (HttpException e) {
130 throw new MethodException("method failed", e);
131 } catch (IOException e) {
132 throw new MethodException("method failed", e);
134 method.releaseConnection();
137 * // display cookies System.err.println("login: " + result); for (var cookie : client.State.Cookies) {
138 * System.err.println("cookie: " + cookie); }
142 SiteState state = SiteState.siteState(config);
143 state.loggedIn = result;
144 state.userName = user;
149 /** log out - return success */
150 public boolean logout(IWikipedia config,String actionUrl) throws UnexpectedAnswerException, MethodException {
151 GetMethod method = new GetMethod(actionUrl);
152 method.setFollowRedirects(false);
153 method.addRequestHeader("User-Agent", userAgent);
154 NameValuePair[] params = new NameValuePair[] { new NameValuePair("title", config.getLogoutTitle()),
155 new NameValuePair("action", "submit") };
156 method.setQueryString(EncodingUtil.formUrlEncode(params, config.getCharSet()));
160 int responseCode = client.executeMethod(method);
161 String responseBody = method.getResponseBodyAsString();
164 if (responseCode == 302 && responseBody.length() == 0 || responseCode == 200
165 && responseBody.matches(config.getLoginSuccess())) {
166 // config.getloggedIn = false;
168 } else if (responseCode == 200) {
169 //### should check for a failure message
172 throw new UnexpectedAnswerException("logout not successful: " + method.getStatusLine());
174 } catch (HttpException e) {
175 throw new MethodException("method failed", e);
176 } catch (IOException e) {
177 throw new MethodException("method failed", e);
179 method.releaseConnection();
183 SiteState state = SiteState.siteState(config);
184 state.loggedIn = false;
189 /** parses a returned editform into a Content object with UNIX-EOLs ("\n") */
190 private Parsed parseBody(String charSet, String responseBody) throws PageNotEditableException, UnsupportedEncodingException {
191 Matcher matcher = BODY_PATTERN.matcher(responseBody);
192 if (!matcher.matches())
193 throw new PageNotEditableException("cannot find editform form");
195 String title = matcher.group(1);
196 String body = matcher.group(2);
197 String timestamp = matcher.group(3);
199 title = URLDecoder.decode(title, charSet);
200 body = body.replaceAll(""", "\"").replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">").replaceAll(
201 "&", "&").replaceAll("\r\n", "\n").replace('\r', '\n');
203 return new Parsed(timestamp, title, body);
206 /** load a Page Version - returns a Loaded Object */
207 public Loaded load(String actionURL, String charSet, String title) throws UnexpectedAnswerException, MethodException,
208 PageNotEditableException {
209 GetMethod method = new GetMethod(actionURL);
210 method.setFollowRedirects(false);
211 method.addRequestHeader("User-Agent", userAgent);
212 NameValuePair[] params = new NameValuePair[] { new NameValuePair("title", title), new NameValuePair("action", "edit") };
213 method.setQueryString(EncodingUtil.formUrlEncode(params, charSet));
217 int responseCode = client.executeMethod(method);
218 String responseBody = method.getResponseBodyAsString();
221 if (responseCode == 200) {
222 Parsed parsed = parseBody(charSet, responseBody);
223 Content content = new Content(parsed.timestamp, parsed.body);
224 result = new Loaded(actionURL, charSet, parsed.title, content);
226 throw new UnexpectedAnswerException("load not successful: expected 200 OK, got " + method.getStatusLine());
228 } catch (HttpException e) {
229 throw new MethodException("method failed", e);
230 } catch (IOException e) {
231 throw new MethodException("method failed", e);
233 method.releaseConnection();
239 * store a Page Version - returns a Stored object
241 * @param config - WiKipedia predefined properties
249 * @throws UnexpectedAnswerException
250 * @throws MethodException
251 * @throws PageNotEditableException
252 * @throws InterruptedException
254 public Stored store(IWikipedia config, String actionUrl, String title, Content content, String summary, boolean minorEdit,
255 boolean watchThis) throws UnexpectedAnswerException, MethodException, PageNotEditableException, InterruptedException {
256 //### workaround: prevent too many stores at a time
257 storeThrottle.delay();
259 PostMethod method = new PostMethod(actionUrl);
260 method.setFollowRedirects(false);
261 method.addRequestHeader("User-Agent", userAgent);
262 method.addRequestHeader("Content-Type", PostMethod.FORM_URL_ENCODED_CONTENT_TYPE + "; charset=" + config.getCharSet());
263 NameValuePair[] params = new NameValuePair[] {
264 // new NameValuePair("wpSection", ""),
265 // new NameValuePair("wpPreview", "Vorschau zeigen"),
266 // new NameValuePair("wpSave", "Artikel speichern"),
267 new NameValuePair("title", title), new NameValuePair("wpTextbox1", content.body),
268 new NameValuePair("wpEdittime", content.timestamp), new NameValuePair("wpSummary", summary),
269 new NameValuePair("wpSave", "yes"), new NameValuePair("action", "submit") };
270 method.addParameters(params);
272 method.addParameter("wpMinoredit", "1");
274 method.addParameter("wpWatchthis", "1");
278 int responseCode = client.executeMethod(method);
279 String responseBody = method.getResponseBodyAsString();
282 // since 11dec04 there is a single linefeed instead of an empty page.. trim() helps.
283 if (responseCode == 302 && responseBody.trim().length() == 0) {
284 // log("store successful, reloading");
285 Loaded loaded = load(actionUrl, config.getCharSet(), title);
286 result = new Stored(actionUrl, config.getCharSet(), loaded.title, loaded.content, false);
287 } else if (responseCode == 200) {
288 // log("store not successful, conflict detected");
289 Parsed parsed = parseBody(config.getCharSet(), responseBody);
290 Content cont = new Content(parsed.timestamp, parsed.body);
291 result = new Stored(actionUrl, config.getCharSet(), parsed.title, cont, true);
293 throw new UnexpectedAnswerException("store not successful: expected 200 OK, got " + method.getStatusLine());
295 } catch (HttpException e) {
296 throw new MethodException("method failed", e);
297 } catch (IOException e) {
298 throw new MethodException("method failed", e);
300 method.releaseConnection();
306 * Get the text of a wikimedia article
309 public static String getWikiRawText(String wikiname, String urlStr) {
311 // http://en.wikipedia.org/w/wiki.phtml?title=Main_Page&action=raw
312 // http://en.wikibooks.org/w/index.php?title=Programming:PHP:SQL_Injection&action=raw
313 // http://en.wikipedia.org/w/wiki.phtml?title=Talk:Division_by_zero&action=raw
314 HttpMethod method = null;
316 if (urlStr == null) {
317 WikiEditorPlugin.getDefault().reportError("No Wikipedia URL configured", "URL-String == null");
318 // urlStr = "http://en.wikipedia.org/w/wiki.phtml?title=" + wikiname + "&action=raw";
320 URI uri = new URI(urlStr.toCharArray());
322 String schema = uri.getScheme();
323 if ((schema == null) || (schema.equals(""))) {
326 Protocol protocol = Protocol.getProtocol(schema);
328 HttpState state = new HttpState();
330 method = new GetMethod(uri.toString());
331 String host = uri.getHost();
332 int port = uri.getPort();
334 HttpConnection connection = new HttpConnection(host, port, protocol);
335 // timeout after 30 seconds
336 connection.setConnectionTimeout(30000);
337 connection.setProxyHost(System.getProperty("http.proxyHost"));
338 connection.setProxyPort(Integer.parseInt(System.getProperty("http.proxyPort", "80")));
340 if (System.getProperty("http.proxyUserName") != null) {
341 state.setProxyCredentials(null, null, new UsernamePasswordCredentials(System.getProperty("http.proxyUserName"), System
342 .getProperty("http.proxyPassword")));
345 if (connection.isProxied() && connection.isSecure()) {
346 method = new ConnectMethod(method);
349 method.execute(state, connection);
351 if (method.getStatusCode() == HttpStatus.SC_OK) {
352 // get the wiki text now:
353 String wikiText = method.getResponseBodyAsString();
355 // wrong text not always complete
356 // InputStream stream = method.getResponseBodyAsStream();
357 // int byteLen = stream.available();
359 // byte[] buffer = new byte[byteLen];
361 // stream.read(buffer, 0, byteLen);
362 // String wikiText = new String(buffer);
364 // System.out.println(wikiText);
366 } catch (Throwable e) {
367 WikiEditorPlugin.log(e);
368 WikiEditorPlugin.getDefault().reportError("Exception occured", e.getMessage() + "\nSee stacktrace in /.metadata/.log file.");
370 if (method != null) {
371 method.releaseConnection();
374 return null; // no success in getting wiki text
377 public static String getWikiEditTextarea(String wikiname, String urlStr) {
379 // http://en.wikipedia.org/w/wiki.phtml?title=Main_Page&action=edit
380 // http://en.wikibooks.org/w/wiki.phtml?title=Programming:PHP:SQL_Injection&action=edit
381 // http://en.wikipedia.org/w/wiki.phtml?title=Talk:Division_by_zero&action=edit
382 HttpMethod method = null;
384 if (urlStr == null) {
385 urlStr = "http://en.wikipedia.org/w/wiki.phtml?title=" + wikiname + "&action=edit";
388 // urlStr = urlStr + "?title=" + wikiname + "&action=edit";
390 URI uri = new URI(urlStr.toCharArray());
392 String schema = uri.getScheme();
393 if ((schema == null) || (schema.equals(""))) {
396 Protocol protocol = Protocol.getProtocol(schema);
398 HttpState state = new HttpState();
400 method = new GetMethod(uri.toString());
401 String host = uri.getHost();
402 int port = uri.getPort();
404 HttpConnection connection = new HttpConnection(host, port, protocol);
406 connection.setProxyHost(System.getProperty("http.proxyHost"));
407 connection.setProxyPort(Integer.parseInt(System.getProperty("http.proxyPort", "80")));
409 if (System.getProperty("http.proxyUserName") != null) {
410 state.setProxyCredentials(null, null, new UsernamePasswordCredentials(System.getProperty("http.proxyUserName"), System
411 .getProperty("http.proxyPassword")));
414 if (connection.isProxied() && connection.isSecure()) {
415 method = new ConnectMethod(method);
418 method.execute(state, connection);
420 if (method.getStatusCode() == HttpStatus.SC_OK) {
421 // get the textareas wiki text now:
422 InputStream stream = method.getResponseBodyAsStream();
423 int byteLen = stream.available();
425 byte[] buffer = new byte[byteLen];
426 stream.read(buffer, 0, byteLen);
427 String wikiText = new String(buffer);
428 // String wikiText = method.getResponseBodyAsString();
429 int start = wikiText.indexOf("<textarea");
431 start = wikiText.indexOf(">", start + 1);
433 int end = wikiText.indexOf("</textarea>");
434 wikiText = wikiText.substring(start + 1, end);
438 // System.out.println(wikiText);
441 } catch (Exception e) {
444 if (method != null) {
445 method.releaseConnection();
448 return null; // no success in getting wiki text