1 package net.sourceforge.phpeclipse.wiki.actions.mediawiki.connect;
3 //Parts of this sources are copied and modified from the jEdit Wikipedia plugin:
4 //http://www.djini.de/software/wikipedia/index.html
6 //The modified sources are available under the "Common Public License"
7 //with permission from the original author: Daniel Wunsch
9 import java.io.IOException;
10 import java.io.StringReader;
11 import java.io.UnsupportedEncodingException;
12 import java.net.URLDecoder;
13 import java.util.ArrayList;
14 import java.util.regex.Matcher;
15 import java.util.regex.Pattern;
17 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.config.IWikipedia;
18 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.MethodException;
19 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.PageNotEditableException;
20 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.UnexpectedAnswerException;
21 import net.sourceforge.phpeclipse.wiki.editor.WikiEditorPlugin;
23 import org.apache.commons.httpclient.ConnectMethod;
24 import org.apache.commons.httpclient.HostConfiguration;
25 import org.apache.commons.httpclient.HttpClient;
26 import org.apache.commons.httpclient.HttpConnection;
27 import org.apache.commons.httpclient.HttpException;
28 import org.apache.commons.httpclient.HttpMethod;
29 import org.apache.commons.httpclient.HttpState;
30 import org.apache.commons.httpclient.HttpStatus;
31 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
32 import org.apache.commons.httpclient.NameValuePair;
33 import org.apache.commons.httpclient.URI;
34 import org.apache.commons.httpclient.UsernamePasswordCredentials;
35 import org.apache.commons.httpclient.methods.GetMethod;
36 import org.apache.commons.httpclient.methods.PostMethod;
37 import org.apache.commons.httpclient.protocol.Protocol;
38 import org.apache.commons.httpclient.util.EncodingUtil;
39 import org.eclipse.core.runtime.CoreException;
40 import org.eclipse.core.runtime.Preferences;
43 * This class gets the wikitext from a wikipedia edit page
45 * The basic coding was copied from the commons-httpclient example <code>MediaWikiConnector.java</code>
47 public class MediaWikiConnector {
48 //pattern used to scarp an edit page
49 private static final Pattern BODY_PATTERN = Pattern.compile(
51 * action=".*?title=(.*?)(&|\") <form id="editform" name="editform" method="post"
52 * action="/w/wiki.phtml?title=Ammersee&action=submit" locked pages: <textarea cols='80' rows='25' readonly>
54 ".*<form[^>]*\\sid=\"editform\"[^>]*title=(.*?)&[^>]*>" + ".*<textarea[^>]*\\sname=\"wpTextbox1\"[^>]*>(.*?)</textarea>"
55 + ".*<input[^>]*\\svalue=\"(\\d*)\"[^>]*\\sname=\"wpEdittime\"[^>]*>" + ".*", Pattern.DOTALL);
57 // <input type='hidden' value="53ee6d8b42ff9b7d" name="wpEditToken" />
58 private static final Pattern EDIT_TOKEN = Pattern.compile(
59 ".*<input\\stype='hidden'\\svalue=\"(.*?)\"\\sname=\"wpEditToken\"\\s/>.*", Pattern.DOTALL);
61 //setup default user agent
62 final static public String userAgent = "plog4u.org/0.0";
64 // create a ConnectionManager
65 private MultiThreadedHttpConnectionManager manager;
67 private HttpClient client;
70 * Delay a new store to 1 second
72 private Throttle storeThrottle = new Throttle(1000);
75 private long nextTime = 0;
77 private final long minimumDelay;
79 public Throttle(long minimumDelay) {
80 this.minimumDelay = minimumDelay;
83 /** this is called from the client */
84 public synchronized void delay() throws InterruptedException {
85 long delay = nextTime - System.currentTimeMillis();
88 nextTime = System.currentTimeMillis() + minimumDelay;
92 public MediaWikiConnector() {
93 // <a href="javascript:window.location.href='http://127.0.0.1:8009/open/?' + window.location.href">bookmarklet</a>
94 manager = new MultiThreadedHttpConnectionManager();
95 manager.setMaxConnectionsPerHost(6);
96 manager.setMaxTotalConnections(18);
97 manager.setConnectionStaleCheckingEnabled(true);
98 // open the conversation
99 client = new HttpClient(manager);
100 setHTTPClientParameters(client);
101 //client.State.CookiePolicy = CookiePolicy.COMPATIBILITY;
102 //client.HostConfiguration.setHost(LOGON_SITE, LOGON_PORT, "http");
105 /** destructor freeing all resources. the Connection is not usable any more after calling this method */
106 public void destroy() {
110 /** log in - returns success */
111 public boolean login(IWikipedia config, String actionUrl, String user, String password, boolean remember)
112 throws UnexpectedAnswerException, MethodException {
113 PostMethod method = new PostMethod(actionUrl);
114 method.setFollowRedirects(false);
115 method.addRequestHeader("User-Agent", userAgent);
116 NameValuePair[] params = new NameValuePair[] {
117 new NameValuePair("title", config.getLoginTitle()),
118 new NameValuePair("action", "submit"),
119 new NameValuePair("wpName", user),
120 new NameValuePair("wpPassword", password),
121 new NameValuePair("wpRemember", remember ? "1" : "0"),
122 new NameValuePair("wpLoginattempt", "submit") };
123 method.addParameters(params);
127 int responseCode = client.executeMethod(method);
128 String responseBody = method.getResponseBodyAsString();
134 if (responseCode == 302 && responseBody.length() == 0 || responseCode == 200
135 && responseBody.matches(config.getLoginSuccess())) {
137 } else if (responseCode == 200 && responseBody.matches(config.getLoginWrongPw()) || responseCode == 200
138 && responseBody.matches(config.getLoginNoUser())) {
140 if (responseBody.matches(config.getLoginNoUser())) {
141 throw new UnexpectedAnswerException("login not successful: wrong user name: " + user);
142 } else if (responseBody.matches(config.getLoginWrongPw())) {
143 throw new UnexpectedAnswerException("login not successful: wrong password for user: " + user);
145 throw new UnexpectedAnswerException("logout not successful: responseCode == 200");
148 throw new UnexpectedAnswerException("login not successful: " + method.getStatusLine());
150 } catch (HttpException e) {
151 throw new MethodException("method failed", e);
152 } catch (IOException e) {
153 throw new MethodException("method failed", e);
155 method.releaseConnection();
158 * // display cookies System.err.println("login: " + result); for (var cookie : client.State.Cookies) {
159 * System.err.println("cookie: " + cookie); }
163 SiteState state = SiteState.siteState(config);
164 state.loggedIn = result;
165 state.userName = user;
170 /** log out - return success */
171 public boolean logout(IWikipedia config, String actionUrl) throws UnexpectedAnswerException, MethodException {
172 GetMethod method = new GetMethod(actionUrl);
173 method.setFollowRedirects(false);
174 method.addRequestHeader("User-Agent", userAgent);
175 NameValuePair[] params = new NameValuePair[] {
176 new NameValuePair("title", config.getLogoutTitle()),
177 new NameValuePair("action", "submit") };
178 method.setQueryString(EncodingUtil.formUrlEncode(params, config.getCharSet()));
182 int responseCode = client.executeMethod(method);
183 String responseBody = method.getResponseBodyAsString();
186 if (responseCode == 302 && responseBody.length() == 0 || responseCode == 200
187 && responseBody.matches(config.getLogoutSuccess())) {
188 // config.getloggedIn = false;
190 } else if (responseCode == 200) {
191 //### should check for a failure message
193 throw new UnexpectedAnswerException("logout not successful: responseCode == 200");
195 throw new UnexpectedAnswerException("logout not successful: " + method.getStatusLine());
197 } catch (HttpException e) {
198 throw new MethodException("method failed", e);
199 } catch (IOException e) {
200 throw new MethodException("method failed", e);
202 method.releaseConnection();
206 SiteState state = SiteState.siteState(config);
207 state.loggedIn = false;
212 /** parses a returned editform for the sessions wpEditToken */
213 private String parseEditToken(String charSet, String responseBody) throws PageNotEditableException {
214 Matcher matcher = EDIT_TOKEN.matcher(responseBody);
215 if (!matcher.matches()) {
219 return matcher.group(1);
223 * returns the edit token or <code>null</code> if no token is available
229 * @throws UnexpectedAnswerException
230 * @throws MethodException
231 * @throws PageNotEditableException
233 public String loadEditToken(String actionURL, String charSet, String title) throws UnexpectedAnswerException, MethodException,
234 PageNotEditableException {
235 GetMethod method = new GetMethod(actionURL);
236 method.setFollowRedirects(false);
237 method.addRequestHeader("User-Agent", userAgent);
238 NameValuePair[] params = new NameValuePair[] { new NameValuePair("title", title), new NameValuePair("action", "edit") };
239 method.setQueryString(EncodingUtil.formUrlEncode(params, charSet));
242 int responseCode = client.executeMethod(method);
243 String responseBody = method.getResponseBodyAsString();
246 if (responseCode == 200) {
247 String parsed = parseEditToken(charSet, responseBody);
248 if (parsed != null && parsed.length() == 0) {
253 throw new UnexpectedAnswerException("load not successful: expected 200 OK, got " + method.getStatusLine());
255 } catch (HttpException e) {
256 throw new MethodException("method failed", e);
257 } catch (IOException e) {
258 throw new MethodException("method failed", e);
260 method.releaseConnection();
264 /** parses a returned editform into a Content object with UNIX-EOLs ("\n") */
265 private Parsed parseBody(String charSet, String responseBody) throws PageNotEditableException, UnsupportedEncodingException {
266 Matcher matcher = BODY_PATTERN.matcher(responseBody);
267 if (!matcher.matches())
268 throw new PageNotEditableException("cannot find editform form");
270 String title = matcher.group(1);
271 String body = matcher.group(2);
272 String timestamp = matcher.group(3);
273 String tokenEdit = null;
274 // String tokenEdit = matcher.group(4);
275 title = URLDecoder.decode(title, charSet);
276 body = body.replaceAll(""", "\"").replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">").replaceAll(
277 "&", "&").replaceAll("\r\n", "\n").replace('\r', '\n');
279 return new Parsed(timestamp, title, body, tokenEdit);
282 /** load a Page Version - returns a Loaded Object */
283 public Loaded load(String actionURL, String charSet, String title) throws UnexpectedAnswerException, MethodException,
284 PageNotEditableException {
285 GetMethod method = new GetMethod(actionURL);
286 method.setFollowRedirects(false);
287 method.addRequestHeader("User-Agent", userAgent);
288 NameValuePair[] params = new NameValuePair[] { new NameValuePair("title", title), new NameValuePair("action", "edit") };
289 method.setQueryString(EncodingUtil.formUrlEncode(params, charSet));
293 int responseCode = client.executeMethod(method);
294 String responseBody = method.getResponseBodyAsString();
297 if (responseCode == 200) {
298 Parsed parsed = parseBody(charSet, responseBody);
299 Content content = new Content(parsed.timestamp, parsed.body);
300 result = new Loaded(actionURL, charSet, parsed.title, content);
302 throw new UnexpectedAnswerException("load not successful: expected 200 OK, got " + method.getStatusLine());
304 } catch (HttpException e) {
305 throw new MethodException("method failed", e);
306 } catch (IOException e) {
307 throw new MethodException("method failed", e);
309 method.releaseConnection();
314 public Loaded loadCategory(String actionURL, String charSet, String title) throws UnexpectedAnswerException, MethodException,
315 PageNotEditableException {
316 GetMethod method = new GetMethod(actionURL);
317 method.setFollowRedirects(false);
318 method.addRequestHeader("User-Agent", userAgent);
319 NameValuePair[] params = new NameValuePair[] { new NameValuePair("title", title) };
320 method.setQueryString(EncodingUtil.formUrlEncode(params, charSet));
324 int responseCode = client.executeMethod(method);
325 String responseBody = method.getResponseBodyAsString();
328 if (responseCode == 200) {
329 Parsed parsed = parseBody(charSet, responseBody);
330 Content content = new Content(parsed.timestamp, parsed.body);
331 result = new Loaded(actionURL, charSet, parsed.title, content);
333 throw new UnexpectedAnswerException("load not successful: expected 200 OK, got " + method.getStatusLine());
335 } catch (HttpException e) {
336 throw new MethodException("method failed", e);
337 } catch (IOException e) {
338 throw new MethodException("method failed", e);
340 method.releaseConnection();
345 public ArrayList loadXML(IWikipedia config, String actionURL, String pages) throws UnexpectedAnswerException, MethodException,
346 InterruptedException {
347 storeThrottle.delay();
348 PostMethod method = new PostMethod(actionURL);
349 method.setFollowRedirects(false);
350 method.addRequestHeader("User-Agent", userAgent);
351 method.addRequestHeader("Content-Type", PostMethod.FORM_URL_ENCODED_CONTENT_TYPE + "; charset=" + config.getCharSet());
353 NameValuePair[] params = new NameValuePair[] {
354 new NameValuePair("pages", pages),
355 new NameValuePair("curonly", "X"),
356 new NameValuePair("action", "submit") };
357 method.addParameters(params);
359 int responseCode = client.executeMethod(method);
360 String responseBody = method.getResponseBodyAsString();
362 if (responseCode == 200) {
363 StringReader reader = new StringReader(responseBody);
364 return XMLReader.readFromStream(reader);
366 throw new UnexpectedAnswerException("XML load not successful: expected 200 OK, got " + method.getStatusLine());
368 } catch (CoreException e) {
369 throw new UnexpectedAnswerException("XML load method failed" + e.getMessage());
370 } catch (HttpException e) {
371 throw new MethodException("XML load method failed", e);
372 } catch (IOException e) {
373 throw new MethodException("XML load method failed", e);
375 method.releaseConnection();
380 * store a Page Version - returns a Stored object
383 * WiKipedia predefined properties
391 * @throws UnexpectedAnswerException
392 * @throws MethodException
393 * @throws PageNotEditableException
394 * @throws InterruptedException
396 public Stored store(IWikipedia config, String editToken, String actionUrl, String title, Content content, String summary,
397 boolean minorEdit, boolean watchThis) throws UnexpectedAnswerException, MethodException, PageNotEditableException,
398 InterruptedException {
399 //### workaround: prevent too many stores at a time
400 storeThrottle.delay();
402 PostMethod method = new PostMethod(actionUrl);
404 method.setFollowRedirects(false);
405 method.addRequestHeader("User-Agent", userAgent);
406 method.addRequestHeader("Content-Type", PostMethod.FORM_URL_ENCODED_CONTENT_TYPE + "; charset=" + config.getCharSet());
407 if (editToken == null) {
408 // in some versions editToken isn't supported
411 NameValuePair[] params = new NameValuePair[] {
412 // new NameValuePair("wpSection", ""),
413 // new NameValuePair("wpPreview", "Vorschau zeigen"),
414 // new NameValuePair("wpSave", "Artikel speichern"),
415 new NameValuePair("title", title),
416 new NameValuePair("wpTextbox1", content.body),
417 new NameValuePair("wpEdittime", content.timestamp),
418 new NameValuePair("wpSummary", summary),
419 new NameValuePair("wpEditToken", editToken),
420 new NameValuePair("wpSave", "yes"),
421 new NameValuePair("action", "submit") };
422 method.addParameters(params);
424 method.addParameter("wpMinoredit", "1");
426 method.addParameter("wpWatchthis", "1");
430 int responseCode = client.executeMethod(method);
431 String responseBody = method.getResponseBodyAsString();
434 // since 11dec04 there is a single linefeed instead of an empty page.. trim() helps.
435 if (responseCode == 302 && responseBody.trim().length() == 0) {
436 // log("store successful, reloading");
437 Loaded loaded = load(actionUrl, config.getCharSet(), title);
438 result = new Stored(actionUrl, config.getCharSet(), loaded.title, loaded.content, false);
439 } else if (responseCode == 200) {
440 // log("store not successful, conflict detected");
441 Parsed parsed = parseBody(config.getCharSet(), responseBody);
442 Content cont = new Content(parsed.timestamp, parsed.body);
443 result = new Stored(actionUrl, config.getCharSet(), parsed.title, cont, true);
445 throw new UnexpectedAnswerException("store not successful: expected 200 OK, got " + method.getStatusLine());
447 } catch (HttpException e) {
448 throw new MethodException("method failed", e);
449 } catch (IOException e) {
450 throw new MethodException("method failed", e);
452 method.releaseConnection();
458 * Get the text of a wikimedia article
461 public String getWikiRawText(String wikiname, String urlStr) {
463 // http://en.wikipedia.org/w/wiki.phtml?title=Main_Page&action=raw
464 // http://en.wikibooks.org/w/index.php?title=Programming:PHP:SQL_Injection&action=raw
465 // http://en.wikipedia.org/w/wiki.phtml?title=Talk:Division_by_zero&action=raw
466 HttpMethod method = null;
468 if (urlStr == null) {
469 WikiEditorPlugin.getDefault().reportError("No Wikipedia URL configured", "URL-String == null");
470 // urlStr = "http://en.wikipedia.org/w/wiki.phtml?title=" + wikiname + "&action=raw";
472 URI uri = new URI(urlStr.toCharArray());
474 String schema = uri.getScheme();
475 if ((schema == null) || (schema.equals(""))) {
478 Protocol protocol = Protocol.getProtocol(schema);
480 method = new GetMethod(uri.toString());
481 String host = uri.getHost();
482 int port = uri.getPort();
484 HttpConnection connection = new HttpConnection(host, port, protocol);
485 HttpState state = setHTTPParameters(connection);
487 if (connection.isProxied() && connection.isSecure()) {
488 method = new ConnectMethod(method);
491 method.execute(state, connection);
492 // client.executeMethod(method);
494 if (method.getStatusCode() == HttpStatus.SC_OK) {
495 // get the wiki text now:
496 String wikiText = method.getResponseBodyAsString();
499 } catch (Throwable e) {
500 WikiEditorPlugin.log(e);
501 WikiEditorPlugin.getDefault().reportError("Exception occured", e.getMessage() + "\nSee stacktrace in /.metadata/.log file.");
503 if (method != null) {
504 method.releaseConnection();
507 return null; // no success in getting wiki text
510 // public static String getWikiEditTextarea(String wikiname, String urlStr) {
512 // // http://en.wikipedia.org/w/wiki.phtml?title=Main_Page&action=edit
513 // // http://en.wikibooks.org/w/wiki.phtml?title=Programming:PHP:SQL_Injection&action=edit
514 // // http://en.wikipedia.org/w/wiki.phtml?title=Talk:Division_by_zero&action=edit
515 // HttpMethod method = null;
517 // if (urlStr == null) {
518 // urlStr = "http://en.wikipedia.org/w/wiki.phtml?title=" + wikiname + "&action=edit";
521 // // urlStr = urlStr + "?title=" + wikiname + "&action=edit";
523 // URI uri = new URI(urlStr.toCharArray());
525 // String schema = uri.getScheme();
526 // if ((schema == null) || (schema.equals(""))) {
529 // Protocol protocol = Protocol.getProtocol(schema);
531 // HttpState state = new HttpState();
533 // method = new GetMethod(uri.toString());
534 // String host = uri.getHost();
535 // int port = uri.getPort();
537 // HttpConnection connection = new HttpConnection(host, port, protocol);
539 // connection.setProxyHost(System.getProperty("http.proxyHost"));
540 // connection.setProxyPort(Integer.parseInt(System.getProperty("http.proxyPort", "80")));
542 // if (System.getProperty("http.proxyUserName") != null) {
543 // state.setProxyCredentials(null, null, new UsernamePasswordCredentials(System.getProperty("http.proxyUserName"), System
544 // .getProperty("http.proxyPassword")));
547 // if (connection.isProxied() && connection.isSecure()) {
548 // method = new ConnectMethod(method);
551 // method.execute(state, connection);
553 // if (method.getStatusCode() == HttpStatus.SC_OK) {
554 // // get the textareas wiki text now:
555 // InputStream stream = method.getResponseBodyAsStream();
556 // int byteLen = stream.available();
558 // byte[] buffer = new byte[byteLen];
559 // stream.read(buffer, 0, byteLen);
560 // String wikiText = new String(buffer);
561 // // String wikiText = method.getResponseBodyAsString();
562 // int start = wikiText.indexOf("<textarea");
563 // if (start != (-1)) {
564 // start = wikiText.indexOf(">", start + 1);
565 // if (start != (-1)) {
566 // int end = wikiText.indexOf("</textarea>");
567 // wikiText = wikiText.substring(start + 1, end);
571 // // System.out.println(wikiText);
574 // } catch (Exception e) {
575 // e.printStackTrace();
577 // if (method != null) {
578 // method.releaseConnection();
581 // return null; // no success in getting wiki text
588 private HttpState setHTTPParameters(HttpConnection connection) {
589 HttpState state = new HttpState();
590 Preferences prefs = WikiEditorPlugin.getDefault().getPluginPreferences();
591 String timeout = prefs.getString(WikiEditorPlugin.HTTP_TIMEOUT);
592 String proxyHost = prefs.getString(WikiEditorPlugin.HTTP_PROXYHOST);
595 // timeout after xx seconds
596 connection.setConnectionTimeout(Integer.parseInt(timeout));
598 if (proxyHost.length() > 0) {
599 String proxyPort = prefs.getString(WikiEditorPlugin.HTTP_PROXYPORT);
600 connection.setProxyHost(proxyHost);
601 connection.setProxyPort(Integer.parseInt(proxyPort));
603 String proxyUserName = prefs.getString(WikiEditorPlugin.HTTP_PROXYUSERNAME);
604 if (proxyUserName.length() > 0) {
605 String proxyPassWord = prefs.getString(WikiEditorPlugin.HTTP_PROXYPASSWORD);
606 state.setProxyCredentials(null, null, new UsernamePasswordCredentials(proxyUserName, proxyPassWord));
610 } catch (Exception e) {
616 private void setHTTPClientParameters(HttpClient client) {
618 Preferences prefs = WikiEditorPlugin.getDefault().getPluginPreferences();
619 String timeout = prefs.getString(WikiEditorPlugin.HTTP_TIMEOUT);
620 String proxyHost = prefs.getString(WikiEditorPlugin.HTTP_PROXYHOST);
623 // timeout after xx seconds
624 client.setConnectionTimeout(Integer.parseInt(timeout));
626 if (proxyHost.length() > 0) {
627 String proxyPort = prefs.getString(WikiEditorPlugin.HTTP_PROXYPORT);
628 HostConfiguration conf = new HostConfiguration();
629 client.setHostConfiguration(conf);
630 conf.setProxy(proxyHost, Integer.parseInt(proxyPort));
632 String proxyUserName = prefs.getString(WikiEditorPlugin.HTTP_PROXYUSERNAME);
633 if (proxyUserName.length() > 0) {
634 HttpState state = new HttpState();
635 String proxyPassWord = prefs.getString(WikiEditorPlugin.HTTP_PROXYPASSWORD);
636 state.setProxyCredentials(null, null, new UsernamePasswordCredentials(proxyUserName, proxyPassWord));
637 client.setState(state);
641 } catch (Exception e) {
647 public static void main(String[] args) {
648 MediaWikiConnector mwc = new MediaWikiConnector();
650 IWikipedia wp = null;
651 ArrayList list = mwc.loadXML(wp, "http://www.plog4u.de/wiki/index.php/Spezial:Export", "Mechanisches Fernsehen\nSynästhesie");
652 for (int i = 0; i < list.size(); i++) {
653 System.out.println(list.get(i).toString());
655 } catch (UnexpectedAnswerException e) {
656 // TODO Auto-generated catch block
658 } catch (Exception e) {
659 // TODO Auto-generated catch block