Upload/Download of multiple files now possible
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.wiki / src / net / sourceforge / phpeclipse / wiki / actions / mediawiki / connect / MediaWikiConnector.java
1 package net.sourceforge.phpeclipse.wiki.actions.mediawiki.connect;
2
3 //Parts of this sources are copied and modified from the jEdit Wikipedia plugin:
4 //http://www.djini.de/software/wikipedia/index.html
5 //
6 //The modified sources are available under the "Common Public License"
7 //with permission from the original author: Daniel Wunsch
8
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;
16
17 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.config.IWikipedia;
18 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.config.WikipediaDE;
19 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.MethodException;
20 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.PageNotEditableException;
21 import net.sourceforge.phpeclipse.wiki.actions.mediawiki.exceptions.UnexpectedAnswerException;
22 import net.sourceforge.phpeclipse.wiki.editor.WikiEditorPlugin;
23
24 import org.apache.commons.httpclient.ConnectMethod;
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
41 /**
42  * This class gets the wikitext from a wikipedia edit page
43  * 
44  * The basic coding was copied from the commons-httpclient example <code>MediaWikiConnector.java</code>
45  */
46 public class MediaWikiConnector {
47   //pattern used to scarp an edit page
48   private static final Pattern BODY_PATTERN = Pattern.compile(
49   /*
50    * action=".*?title=(.*?)(&amp;|\") <form id="editform" name="editform" method="post"
51    * action="/w/wiki.phtml?title=Ammersee&amp;action=submit" locked pages: <textarea cols='80' rows='25' readonly>
52    */
53   ".*<form[^>]*\\sid=\"editform\"[^>]*title=(.*?)&amp;[^>]*>" + ".*<textarea[^>]*\\sname=\"wpTextbox1\"[^>]*>(.*?)</textarea>"
54       + ".*<input[^>]*\\svalue=\"(\\d*)\"[^>]*\\sname=\"wpEdittime\"[^>]*>" + ".*", Pattern.DOTALL);
55
56   //setup default user agent
57   final static public String userAgent = "plog4u.org/0.0";
58
59   // create a ConnectionManager
60   private MultiThreadedHttpConnectionManager manager;
61
62   private HttpClient client;
63
64   /**
65    * Delay a new store to 1 second
66    */
67   private Throttle storeThrottle = new Throttle(1000);
68
69   class Throttle {
70     private long nextTime = 0;
71
72     private final long minimumDelay;
73
74     public Throttle(long minimumDelay) {
75       this.minimumDelay = minimumDelay;
76     }
77
78     /** this is called from the client */
79     public synchronized void delay() throws InterruptedException {
80       long delay = nextTime - System.currentTimeMillis();
81       if (delay > 0)
82         Thread.sleep(delay);
83       nextTime = System.currentTimeMillis() + minimumDelay;
84     }
85   }
86
87   public MediaWikiConnector() {
88     // <a href="javascript:window.location.href='http://127.0.0.1:8009/open/?' + window.location.href">bookmarklet</a>
89     manager = new MultiThreadedHttpConnectionManager();
90     manager.setMaxConnectionsPerHost(6);
91     manager.setMaxTotalConnections(18);
92     manager.setConnectionStaleCheckingEnabled(true);
93     // open the conversation
94     client = new HttpClient(manager);
95     //client.State.CookiePolicy = CookiePolicy.COMPATIBILITY;
96     //client.HostConfiguration.setHost(LOGON_SITE, LOGON_PORT, "http");
97   }
98
99   /** destructor freeing all resources. the Connection is not usable any more after calling this method */
100   public void destroy() {
101     manager.shutdown();
102   }
103
104   /** log in - returns success */
105   public boolean login(IWikipedia config, String actionUrl, String user, String password, boolean remember)
106       throws UnexpectedAnswerException, MethodException {
107     PostMethod method = new PostMethod(actionUrl);
108     method.setFollowRedirects(false);
109     method.addRequestHeader("User-Agent", userAgent);
110     NameValuePair[] params = new NameValuePair[] {
111         new NameValuePair("title", config.getLoginTitle()),
112         new NameValuePair("action", "submit"),
113         new NameValuePair("wpName", user),
114         new NameValuePair("wpPassword", password),
115         new NameValuePair("wpRemember", remember ? "1" : "0"),
116         new NameValuePair("wpLoginattempt", "submit") };
117     method.addParameters(params);
118
119     boolean result;
120     try {
121       int responseCode = client.executeMethod(method);
122       String responseBody = method.getResponseBodyAsString();
123
124       //### debugging
125       //log(responseBody);
126       //                        log(method);
127
128       if (responseCode == 302 && responseBody.length() == 0 || responseCode == 200
129           && responseBody.matches(config.getLoginSuccess())) {
130         result = true;
131       } else if (responseCode == 200 && responseBody.matches(config.getLoginWrongPw()) || responseCode == 200
132           && responseBody.matches(config.getLoginNoUser())) {
133         result = false;
134       } else {
135         throw new UnexpectedAnswerException("login not successful: " + method.getStatusLine());
136       }
137     } catch (HttpException e) {
138       throw new MethodException("method failed", e);
139     } catch (IOException e) {
140       throw new MethodException("method failed", e);
141     } finally {
142       method.releaseConnection();
143     }
144     /*
145      * // display cookies System.err.println("login: " + result); for (var cookie : client.State.Cookies) {
146      * System.err.println("cookie: " + cookie); }
147      */
148
149     // remember state
150     SiteState state = SiteState.siteState(config);
151     state.loggedIn = result;
152     state.userName = user;
153
154     return result;
155   }
156
157   /** log out - return success */
158   public boolean logout(IWikipedia config, String actionUrl) throws UnexpectedAnswerException, MethodException {
159     GetMethod method = new GetMethod(actionUrl);
160     method.setFollowRedirects(false);
161     method.addRequestHeader("User-Agent", userAgent);
162     NameValuePair[] params = new NameValuePair[] {
163         new NameValuePair("title", config.getLogoutTitle()),
164         new NameValuePair("action", "submit") };
165     method.setQueryString(EncodingUtil.formUrlEncode(params, config.getCharSet()));
166
167     boolean result;
168     try {
169       int responseCode = client.executeMethod(method);
170       String responseBody = method.getResponseBodyAsString();
171       //                        log(method);
172
173       if (responseCode == 302 && responseBody.length() == 0 || responseCode == 200
174           && responseBody.matches(config.getLoginSuccess())) {
175         //                              config.getloggedIn = false;
176         result = true;
177       } else if (responseCode == 200) {
178         //### should check for a failure message
179         result = false;
180       } else {
181         throw new UnexpectedAnswerException("logout not successful: " + method.getStatusLine());
182       }
183     } catch (HttpException e) {
184       throw new MethodException("method failed", e);
185     } catch (IOException e) {
186       throw new MethodException("method failed", e);
187     } finally {
188       method.releaseConnection();
189     }
190
191     // remember state
192     SiteState state = SiteState.siteState(config);
193     state.loggedIn = false;
194
195     return result;
196   }
197
198   /** parses a returned editform into a Content object with UNIX-EOLs ("\n") */
199   private Parsed parseBody(String charSet, String responseBody) throws PageNotEditableException, UnsupportedEncodingException {
200     Matcher matcher = BODY_PATTERN.matcher(responseBody);
201     if (!matcher.matches())
202       throw new PageNotEditableException("cannot find editform form");
203
204     String title = matcher.group(1);
205     String body = matcher.group(2);
206     String timestamp = matcher.group(3);
207
208     title = URLDecoder.decode(title, charSet);
209     body = body.replaceAll("&quot;", "\"").replaceAll("&apos;", "'").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll(
210         "&amp;", "&").replaceAll("\r\n", "\n").replace('\r', '\n');
211
212     return new Parsed(timestamp, title, body);
213   }
214
215   /** load a Page Version - returns a Loaded Object */
216   public Loaded load(String actionURL, String charSet, String title) throws UnexpectedAnswerException, MethodException,
217       PageNotEditableException {
218     GetMethod method = new GetMethod(actionURL);
219     method.setFollowRedirects(false);
220     method.addRequestHeader("User-Agent", userAgent);
221     NameValuePair[] params = new NameValuePair[] { new NameValuePair("title", title), new NameValuePair("action", "edit") };
222     method.setQueryString(EncodingUtil.formUrlEncode(params, charSet));
223
224     Loaded result;
225     try {
226       int responseCode = client.executeMethod(method);
227       String responseBody = method.getResponseBodyAsString();
228       //                        log(method);
229
230       if (responseCode == 200) {
231         Parsed parsed = parseBody(charSet, responseBody);
232         Content content = new Content(parsed.timestamp, parsed.body);
233         result = new Loaded(actionURL, charSet, parsed.title, content);
234       } else {
235         throw new UnexpectedAnswerException("load not successful: expected 200 OK, got " + method.getStatusLine());
236       }
237     } catch (HttpException e) {
238       throw new MethodException("method failed", e);
239     } catch (IOException e) {
240       throw new MethodException("method failed", e);
241     } finally {
242       method.releaseConnection();
243     }
244     return result;
245   }
246
247   public ArrayList loadXML(IWikipedia config, String actionURL, String pages) throws UnexpectedAnswerException, MethodException {
248     PostMethod method = new PostMethod(actionURL);
249     method.setFollowRedirects(false);
250     method.addRequestHeader("User-Agent", userAgent);
251     method.addRequestHeader("Content-Type", PostMethod.FORM_URL_ENCODED_CONTENT_TYPE + "; charset=" + config.getCharSet());
252     
253     NameValuePair[] params = new NameValuePair[] { 
254         new NameValuePair("pages", pages), 
255         new NameValuePair("curonly", "X"),
256         new NameValuePair("action", "submit") };
257     method.addParameters(params);
258     try {
259       int responseCode = client.executeMethod(method);
260       String responseBody = method.getResponseBodyAsString();
261
262       if (responseCode == 200) {
263         StringReader reader = new StringReader(responseBody);
264         return XMLReader.readFromStream(reader);
265       } else {
266         throw new UnexpectedAnswerException("XML load not successful: expected 200 OK, got " + method.getStatusLine());
267       }
268     } catch(CoreException e) {
269       throw new UnexpectedAnswerException("XML load method failed" + e.getMessage());
270     } catch (HttpException e) {
271       throw new MethodException("XML load method failed", e);
272     } catch (IOException e) {
273       throw new MethodException("XML load method failed", e);
274     } finally {
275       method.releaseConnection();
276     }
277   }
278
279   /**
280    * store a Page Version - returns a Stored object
281    * 
282    * @param config -
283    *          WiKipedia predefined properties
284    * @param actionURL
285    * @param title
286    * @param content
287    * @param summary
288    * @param minorEdit
289    * @param watchThis
290    * @return
291    * @throws UnexpectedAnswerException
292    * @throws MethodException
293    * @throws PageNotEditableException
294    * @throws InterruptedException
295    */
296   public Stored store(IWikipedia config, String actionUrl, String title, Content content, String summary, boolean minorEdit,
297       boolean watchThis) throws UnexpectedAnswerException, MethodException, PageNotEditableException, InterruptedException {
298     //### workaround: prevent too many stores at a time
299     storeThrottle.delay();
300
301     PostMethod method = new PostMethod(actionUrl);
302     method.setFollowRedirects(false);
303     method.addRequestHeader("User-Agent", userAgent);
304     method.addRequestHeader("Content-Type", PostMethod.FORM_URL_ENCODED_CONTENT_TYPE + "; charset=" + config.getCharSet());
305     NameValuePair[] params = new NameValuePair[] {
306         // new NameValuePair("wpSection", ""),
307         // new NameValuePair("wpPreview", "Vorschau zeigen"),
308         // new NameValuePair("wpSave", "Artikel speichern"),
309         new NameValuePair("title", title),
310         new NameValuePair("wpTextbox1", content.body),
311         new NameValuePair("wpEdittime", content.timestamp),
312         new NameValuePair("wpSummary", summary),
313         new NameValuePair("wpSave", "yes"),
314         new NameValuePair("action", "submit") };
315     method.addParameters(params);
316     if (minorEdit)
317       method.addParameter("wpMinoredit", "1");
318     if (watchThis)
319       method.addParameter("wpWatchthis", "1");
320
321     Stored result;
322     try {
323       int responseCode = client.executeMethod(method);
324       String responseBody = method.getResponseBodyAsString();
325       //                        log(method);
326
327       // since 11dec04 there is a single linefeed instead of an empty page.. trim() helps.
328       if (responseCode == 302 && responseBody.trim().length() == 0) {
329         //                              log("store successful, reloading");
330         Loaded loaded = load(actionUrl, config.getCharSet(), title);
331         result = new Stored(actionUrl, config.getCharSet(), loaded.title, loaded.content, false);
332       } else if (responseCode == 200) {
333         //        log("store not successful, conflict detected");
334         Parsed parsed = parseBody(config.getCharSet(), responseBody);
335         Content cont = new Content(parsed.timestamp, parsed.body);
336         result = new Stored(actionUrl, config.getCharSet(), parsed.title, cont, true);
337       } else {
338         throw new UnexpectedAnswerException("store not successful: expected 200 OK, got " + method.getStatusLine());
339       }
340     } catch (HttpException e) {
341       throw new MethodException("method failed", e);
342     } catch (IOException e) {
343       throw new MethodException("method failed", e);
344     } finally {
345       method.releaseConnection();
346     }
347     return result;
348   }
349
350   /**
351    * Get the text of a wikimedia article
352    *  
353    */
354   public String getWikiRawText(String wikiname, String urlStr) {
355     // examples
356     // http://en.wikipedia.org/w/wiki.phtml?title=Main_Page&action=raw
357     // http://en.wikibooks.org/w/index.php?title=Programming:PHP:SQL_Injection&action=raw
358     // http://en.wikipedia.org/w/wiki.phtml?title=Talk:Division_by_zero&action=raw
359     HttpMethod method = null;
360     try {
361       if (urlStr == null) {
362         WikiEditorPlugin.getDefault().reportError("No Wikipedia URL configured", "URL-String == null");
363         //        urlStr = "http://en.wikipedia.org/w/wiki.phtml?title=" + wikiname + "&action=raw";
364       }
365       URI uri = new URI(urlStr.toCharArray());
366
367       String schema = uri.getScheme();
368       if ((schema == null) || (schema.equals(""))) {
369         schema = "http";
370       }
371       Protocol protocol = Protocol.getProtocol(schema);
372
373       HttpState state = new HttpState();
374
375       method = new GetMethod(uri.toString());
376       String host = uri.getHost();
377       int port = uri.getPort();
378
379       HttpConnection connection = new HttpConnection(host, port, protocol);
380       // timeout after 30 seconds
381       connection.setConnectionTimeout(30000);
382       connection.setProxyHost(System.getProperty("http.proxyHost"));
383       connection.setProxyPort(Integer.parseInt(System.getProperty("http.proxyPort", "80")));
384
385       if (System.getProperty("http.proxyUserName") != null) {
386         state.setProxyCredentials(null, null, new UsernamePasswordCredentials(System.getProperty("http.proxyUserName"), System
387             .getProperty("http.proxyPassword")));
388       }
389
390       if (connection.isProxied() && connection.isSecure()) {
391         method = new ConnectMethod(method);
392       }
393
394       method.execute(state, connection);
395       //      client.executeMethod(method);
396
397       if (method.getStatusCode() == HttpStatus.SC_OK) {
398         // get the wiki text now:
399         String wikiText = method.getResponseBodyAsString();
400         return wikiText;
401       }
402     } catch (Throwable e) {
403       WikiEditorPlugin.log(e);
404       WikiEditorPlugin.getDefault().reportError("Exception occured", e.getMessage() + "\nSee stacktrace in /.metadata/.log file.");
405     } finally {
406       if (method != null) {
407         method.releaseConnection();
408       }
409     }
410     return null; // no success in getting wiki text
411   }
412
413   //  public static String getWikiEditTextarea(String wikiname, String urlStr) {
414   //    // examples
415   //    // http://en.wikipedia.org/w/wiki.phtml?title=Main_Page&action=edit
416   //    // http://en.wikibooks.org/w/wiki.phtml?title=Programming:PHP:SQL_Injection&action=edit
417   //    // http://en.wikipedia.org/w/wiki.phtml?title=Talk:Division_by_zero&action=edit
418   //    HttpMethod method = null;
419   //    try {
420   //      if (urlStr == null) {
421   //        urlStr = "http://en.wikipedia.org/w/wiki.phtml?title=" + wikiname + "&action=edit";
422   //      }
423   //      // else {
424   //      // urlStr = urlStr + "?title=" + wikiname + "&action=edit";
425   //      // }
426   //      URI uri = new URI(urlStr.toCharArray());
427   //
428   //      String schema = uri.getScheme();
429   //      if ((schema == null) || (schema.equals(""))) {
430   //        schema = "http";
431   //      }
432   //      Protocol protocol = Protocol.getProtocol(schema);
433   //
434   //      HttpState state = new HttpState();
435   //
436   //      method = new GetMethod(uri.toString());
437   //      String host = uri.getHost();
438   //      int port = uri.getPort();
439   //
440   //      HttpConnection connection = new HttpConnection(host, port, protocol);
441   //
442   //      connection.setProxyHost(System.getProperty("http.proxyHost"));
443   //      connection.setProxyPort(Integer.parseInt(System.getProperty("http.proxyPort", "80")));
444   //
445   //      if (System.getProperty("http.proxyUserName") != null) {
446   //        state.setProxyCredentials(null, null, new UsernamePasswordCredentials(System.getProperty("http.proxyUserName"), System
447   //            .getProperty("http.proxyPassword")));
448   //      }
449   //
450   //      if (connection.isProxied() && connection.isSecure()) {
451   //        method = new ConnectMethod(method);
452   //      }
453   //
454   //      method.execute(state, connection);
455   //
456   //      if (method.getStatusCode() == HttpStatus.SC_OK) {
457   //        // get the textareas wiki text now:
458   //        InputStream stream = method.getResponseBodyAsStream();
459   //        int byteLen = stream.available();
460   //        int count = 1;
461   //        byte[] buffer = new byte[byteLen];
462   //        stream.read(buffer, 0, byteLen);
463   //        String wikiText = new String(buffer);
464   //        // String wikiText = method.getResponseBodyAsString();
465   //        int start = wikiText.indexOf("<textarea");
466   //        if (start != (-1)) {
467   //          start = wikiText.indexOf(">", start + 1);
468   //          if (start != (-1)) {
469   //            int end = wikiText.indexOf("</textarea>");
470   //            wikiText = wikiText.substring(start + 1, end);
471   //          }
472   //        }
473   //        return wikiText;
474   //        // System.out.println(wikiText);
475   //
476   //      }
477   //    } catch (Exception e) {
478   //      e.printStackTrace();
479   //    } finally {
480   //      if (method != null) {
481   //        method.releaseConnection();
482   //      }
483   //    }
484   //    return null; // no success in getting wiki text
485   //  }
486   
487   public static void main(String[] args) {
488     MediaWikiConnector mwc = new MediaWikiConnector();
489     try {
490       IWikipedia wp = null; 
491       ArrayList list = mwc.loadXML(wp, "http://www.plog4u.de/wiki/index.php/Spezial:Export", "Mechanisches Fernsehen\nSynästhesie");
492       for (int i = 0; i < list.size(); i++) {
493         System.out.println(list.get(i).toString());
494       }
495     } catch (UnexpectedAnswerException e) {
496       // TODO Auto-generated catch block
497       e.printStackTrace();
498     } catch (MethodException e) {
499       // TODO Auto-generated catch block
500       e.printStackTrace();
501     } 
502   }
503 }
504