PageRenderTime 57ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/fullmetalgalaxy/server/forum/ConectorImpl.java

https://code.google.com/p/fullmetalgalaxy/
Java | 1002 lines | 711 code | 144 blank | 147 comment | 88 complexity | 0372955a2d564b64e290069b5067c368 MD5 | raw file
Possible License(s): AGPL-3.0, GPL-3.0, Apache-2.0, CC-BY-3.0
  1. /* *********************************************************************
  2. *
  3. * This file is part of Full Metal Galaxy.
  4. * http://www.fullmetalgalaxy.com
  5. *
  6. * Full Metal Galaxy is free software: you can redistribute it and/or
  7. * modify it under the terms of the GNU Affero General Public License
  8. * as published by the Free Software Foundation, either version 3 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * Full Metal Galaxy is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public
  17. * License along with Full Metal Galaxy.
  18. * If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. * Copyright 2010, 2011, 2012, 2013 Vincent Legendre
  21. *
  22. * *********************************************************************/
  23. package com.fullmetalgalaxy.server.forum;
  24. import java.io.BufferedReader;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.io.InputStreamReader;
  28. import java.io.StringWriter;
  29. import java.io.UnsupportedEncodingException;
  30. import java.io.Writer;
  31. import java.net.URL;
  32. import java.net.URLConnection;
  33. import java.net.URLDecoder;
  34. import java.net.URLEncoder;
  35. import java.util.HashMap;
  36. import java.util.Map;
  37. import java.util.Map.Entry;
  38. import java.util.Properties;
  39. import java.util.logging.Logger;
  40. import java.util.regex.Matcher;
  41. import java.util.regex.Pattern;
  42. import com.fullmetalgalaxy.model.constant.FmpConstant;
  43. import com.fullmetalgalaxy.server.EbAccount;
  44. import com.fullmetalgalaxy.server.EbAccount.NotificationQty;
  45. import com.fullmetalgalaxy.server.FmgCookieStore;
  46. import com.fullmetalgalaxy.server.ServerUtil;
  47. import com.google.appengine.api.urlfetch.FetchOptions;
  48. import com.google.appengine.api.urlfetch.HTTPHeader;
  49. import com.google.appengine.api.urlfetch.HTTPMethod;
  50. import com.google.appengine.api.urlfetch.HTTPRequest;
  51. import com.google.appengine.api.urlfetch.HTTPResponse;
  52. import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
  53. import com.myjavatools.web.ClientHttpRequest;
  54. /**
  55. *
  56. * I used firefox livehttpheaders extension to help constructing this.
  57. *
  58. * As google infrastructure change his IP address every request, we arn't able to connect to forum.
  59. * To bypass this limitation, I usea web proxy located on another server.
  60. */
  61. public class ConectorImpl implements ForumConector, NewsConector
  62. {
  63. public static String FORUM_NEWS_THREAD_ID = "40";
  64. public static String FORUM_GAMES_THREAD_ID = "41";
  65. public static Logger logger = Logger.getLogger( "Conector" );
  66. private static String COOKIE_SID = "fa_" + FmpConstant.getForumHost().replace( '.', '_' )
  67. + "_sid";
  68. private static String FORUM_USERNAME = "";
  69. private static String FORUM_PASS = "";
  70. private static String PROXY_KEY = "";
  71. // various pattern on forum pages
  72. private static Pattern s_confirmPassPattern = Pattern.compile(
  73. ".*<input type=\"hidden\" name=\"confirm_pass\" value=\"(.+)\" />.*", Pattern.DOTALL );
  74. private static Pattern s_addHiddenFieldsPattern = Pattern
  75. .compile(
  76. ".*addHiddenFields\\('.+', \\{'auth\\[\\]':\\[\\['(.+)',(.+)\\],\\['(.+)',(.+)\\]\\]\\}\\);\\}.*",
  77. Pattern.DOTALL );
  78. // profil field
  79. private static final String FIELD_USERNAME = "username_edit";
  80. private static final String FIELD_EMAIL = "email";
  81. private static final String FIELD_LEVEL = "profile_field_10_2";
  82. private static final String FIELD_GRADICON = "profile_field_6_3[]";
  83. private static final String FIELD_JABBER = "profile_field_3_1";
  84. private static final String FIELD_FMG_NOTIF_MODE = "profile_field_7_4";
  85. private static final String FIELD_FMG_NOTIF_QTY = "profile_field_7_5";
  86. // field pattern for profil forum page
  87. private static final Pattern s_usernamePattern = fieldTextPattern( FIELD_USERNAME );
  88. private static final Pattern s_emailPattern = fieldTextPattern( FIELD_EMAIL );
  89. private static final Pattern s_jabberPattern = fieldTextPattern( FIELD_JABBER );
  90. private static final Pattern s_avatarUrlPattern = Pattern.compile(
  91. ".*Image Actuelle</span><br /><img src=\"([^\"]*)\".*", Pattern.DOTALL );
  92. private static final Pattern s_notifModePattern = fieldSelectPattern( FIELD_FMG_NOTIF_MODE );
  93. private static final Pattern s_notifQtyPattern = fieldSelectPattern( FIELD_FMG_NOTIF_QTY );
  94. private static final Pattern s_sendEmailPattern = fieldRadioPattern( "viewemail" );
  95. // field pattern for profil page that we need to backup to avoid override
  96. private static Map<String, Pattern> s_fieldPatternMap = new HashMap<String, Pattern>();
  97. static
  98. {
  99. s_fieldPatternMap.put( "viewemail", fieldRadioPattern( "viewemail" ) );
  100. s_fieldPatternMap.put( "newsletter", fieldRadioPattern( "newsletter" ) );
  101. s_fieldPatternMap.put( "hideonline", fieldRadioPattern( "hideonline" ) );
  102. s_fieldPatternMap.put( "notifyreply", fieldRadioPattern( "notifyreply" ) );
  103. s_fieldPatternMap.put( "notifypm", fieldRadioPattern( "notifypm" ) );
  104. s_fieldPatternMap.put( "popup_pm", fieldRadioPattern( "popup_pm" ) );
  105. s_fieldPatternMap.put( "post_prevent", fieldRadioPattern( "post_prevent" ) );
  106. //s_fieldPatternMap.put( "no_report_popup", fieldRadioPattern( "no_report_popup" ) );
  107. //s_fieldPatternMap.put( "no_report_mail", fieldRadioPattern( "no_report_mail" ) );
  108. s_fieldPatternMap.put( "attachsig", fieldRadioPattern( "attachsig" ) );
  109. s_fieldPatternMap.put( "language", fieldSelectPattern( "language" ) );
  110. // s_fieldPatternMap.put( "timezone", fieldSelectPattern( "timezone" ) );
  111. s_fieldPatternMap.put( "dateformat", fieldSelectPattern( "dateformat" ) );
  112. s_fieldPatternMap.put( "next_birthday_greeting", fieldTextPattern( "next_birthday_greeting" ) );
  113. s_fieldPatternMap.put( "user_status", fieldRadioPattern( "user_status" ) );
  114. s_fieldPatternMap.put( "user_allowpm", fieldRadioPattern( "user_allowpm" ) );
  115. s_fieldPatternMap.put( "user_allowavatar", fieldRadioPattern( "user_allowavatar" ) );
  116. s_fieldPatternMap.put( "user_allow_att", fieldRadioPattern( "user_allow_att" ) );
  117. // s_fieldPatternMap.put( "user_rank", fieldSelectPattern( "user_rank" ) );
  118. s_fieldPatternMap.put( "user_rank", Pattern.compile(
  119. ".*<select name=\"user_rank\">.*<option value=\"([^\"]*)\" selected=\"selected\">.*",
  120. Pattern.DOTALL ) );
  121. }
  122. private FmgCookieStore m_cookieStore = new FmgCookieStore();
  123. private static final String DEFAULT_ADMIN_URL = "http://" + FmpConstant.getForumHost()
  124. + "/admin/index.forum?part=admin";
  125. private String m_adminUrl = DEFAULT_ADMIN_URL;
  126. private static Properties s_forumConfig = new Properties();
  127. static
  128. {
  129. // try retrieve data from file
  130. try
  131. {
  132. s_forumConfig.load( ConectorImpl.class.getResourceAsStream( "forumaccount.properties" ) );
  133. FORUM_USERNAME = s_forumConfig.getProperty( "username" );
  134. FORUM_PASS = s_forumConfig.getProperty( "password" );
  135. PROXY_KEY = s_forumConfig.getProperty( "proxykey" );
  136. } catch( Exception e )
  137. {
  138. logger.severe( e.getMessage() );
  139. }
  140. }
  141. private static Pattern fieldTextPattern(String p_field)
  142. {
  143. return Pattern.compile( ".*<input[^>]*type=\"text\"[^>]*name=\"" + p_field
  144. + "\"[^>]*value=\"([^\"]*)\" />.*", Pattern.DOTALL );
  145. }
  146. private static Pattern fieldRadioPattern(String p_field)
  147. {
  148. return Pattern.compile( ".*<input type=\"radio\"[^>]*name=\"" + p_field
  149. + "\"[^>]*value=\"([^\"]*)\" checked=\"checked\".*",
  150. Pattern.DOTALL );
  151. }
  152. private static Pattern fieldSelectPattern(String p_field)
  153. {
  154. return Pattern.compile( ".*<select[^>]*name=\"" + p_field
  155. + "\"(?:[^<]*|</?o){0,20}<option value=\"([^\"]*)\" selected.*",
  156. Pattern.DOTALL );
  157. }
  158. private static final String PROXY_HOST = "www.fullmetalgalaxy.web-address.fr";
  159. private static String proxyfyUrl(String p_url)
  160. {
  161. if( !p_url.startsWith( "http://" ) )
  162. {
  163. p_url = "http://" + p_url;
  164. }
  165. try
  166. {
  167. return "http://" + PROXY_HOST + "/browse.php?url="
  168. + URLEncoder.encode( p_url, "UTF-8" ) + "&b=12";
  169. } catch( UnsupportedEncodingException e )
  170. {
  171. e.printStackTrace( System.err );
  172. }
  173. return "http://" + PROXY_HOST + "/browse.php?url=" + p_url;
  174. }
  175. private static Pattern s_deproxyfyPattern = Pattern.compile( ".*url=([^&]*)($|&.*)" );
  176. private static String deproxyfyUrl(String p_url)
  177. {
  178. Matcher matcher = s_deproxyfyPattern.matcher( p_url );
  179. if( !matcher.matches() )
  180. {
  181. return p_url;
  182. }
  183. p_url = matcher.group( 1 );
  184. try
  185. {
  186. p_url = URLDecoder.decode( p_url, "UTF-8" );
  187. } catch( UnsupportedEncodingException e )
  188. {
  189. logger.severe( e.getMessage() );
  190. }
  191. return p_url;
  192. }
  193. protected boolean isConnected()
  194. {
  195. return (m_cookieStore.getCookie( COOKIE_SID ) != null)
  196. || (!m_adminUrl.equals( DEFAULT_ADMIN_URL ));
  197. }
  198. protected void disconnect()
  199. {
  200. m_cookieStore = new FmgCookieStore();
  201. m_adminUrl = DEFAULT_ADMIN_URL;
  202. }
  203. /**
  204. *
  205. */
  206. protected void connect()
  207. {
  208. if( isConnected() )
  209. {
  210. // done already !
  211. return;
  212. }
  213. URL url = null;
  214. try
  215. {
  216. // post login to get cookies
  217. // =========================
  218. url = new URL( proxyfyUrl( "http://" + FmpConstant.getForumHost() + "/login" ) );
  219. HTTPRequest request = new HTTPRequest( url, HTTPMethod.POST, FetchOptions.Builder
  220. .withDefaults().doNotFollowRedirects() );
  221. request
  222. .setPayload( ("username=" + FORUM_USERNAME + "&password=" + FORUM_PASS + "&redirect=&query=&login=Connexion")
  223. .getBytes( "UTF-8" ) );
  224. request.addHeader( new HTTPHeader( "Host", PROXY_HOST ) );
  225. // request.addHeader( new HTTPHeader( "User-Agent",
  226. // "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9) Gecko/2008052906 (CK-Ifremer) Firefox/3.0 ( .NET CLR 3.5.30729; .NET4.0E)"
  227. // ) );
  228. // request.addHeader( new HTTPHeader( "Accept",
  229. // "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ) );
  230. // request.addHeader( new HTTPHeader( "Accept-Language",
  231. // "fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3" ) );
  232. // /request.addHeader( new HTTPHeader( "Accept-Encoding", "gzip,deflate" )
  233. // );
  234. request.addHeader( new HTTPHeader( "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" ) );
  235. // request.addHeader( new HTTPHeader( "Keep-Alive", "300" ) );
  236. // request.addHeader( new HTTPHeader( "Connection", "keep-alive" ) );
  237. request.addHeader( new HTTPHeader( "Referer", "http://" + FmpConstant.getForumHost()
  238. + "/login" ) );
  239. // request.addHeader( new HTTPHeader( "Cookie",
  240. // "extendedview=; __utma=197449400.1261798819.1301581035.1301581035.1301581035.1; __utmz=197449400.1301581035.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _csuid=X8b6019a8aa1ad"
  241. // ) );
  242. request.addHeader( new HTTPHeader( "Content-Type", "application/x-www-form-urlencoded" ) );
  243. HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch( request );
  244. System.out.println( "response code: " + response.getResponseCode() );
  245. System.out.println( "final url: " + response.getFinalUrl() );
  246. for( HTTPHeader header : response.getHeaders() )
  247. {
  248. System.out.println( header.getName() + ": " + header.getValue() );
  249. if( "Set-Cookie".equalsIgnoreCase( header.getName() ) )
  250. {
  251. m_cookieStore.add( header.getValue() );
  252. // System.out.println( "Set-Cookie: " + header.getValue() );
  253. }
  254. }
  255. // System.out.println( new String( response.getContent(), getCharset(
  256. // response ) ) );
  257. // get admin panel to read tid param
  258. // =================================
  259. url = new URL( proxyfyUrl( m_adminUrl ) );
  260. request = new HTTPRequest( url );
  261. request.addHeader( new HTTPHeader( "Host", PROXY_HOST ) );
  262. request.addHeader( new HTTPHeader( "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" ) );
  263. request.addHeader( new HTTPHeader( "Cookie", m_cookieStore.getCookies().toString() ) );
  264. response = URLFetchServiceFactory.getURLFetchService().fetch( request );
  265. if( m_cookieStore.getCookie( COOKIE_SID ) != null )
  266. {
  267. m_adminUrl += "&sid=" + m_cookieStore.getCookie( COOKIE_SID ).getValue();
  268. }
  269. if( response.getFinalUrl() != null )
  270. {
  271. m_adminUrl = response.getFinalUrl().toString();
  272. // m_adminUrl is now a proxyfied url: we need to deproxyfy it
  273. m_adminUrl = deproxyfyUrl( m_adminUrl );
  274. }
  275. } catch( IOException e )
  276. {
  277. logger.severe( e.getMessage() );
  278. disconnect();
  279. }
  280. }
  281. @Override
  282. public String getUserId(String p_pseudo)
  283. {
  284. // we don't need to be connected
  285. Pattern pattern = Pattern.compile(
  286. ".*href=\"[^\"]*(?:/|%2F)u([^\"&]*)[^\"]*\">(?:<span style=\"color:#......\">)?(?:<strong>)?"
  287. + Pattern.quote( p_pseudo ) + "<.*",
  288. Pattern.CASE_INSENSITIVE | Pattern.DOTALL );
  289. try
  290. {
  291. URL url = new URL(
  292. ("http://" + FmpConstant.getForumHost()
  293. + "/memberlist?username=" + URLEncoder.encode( p_pseudo, "UTF-8" ) ) );
  294. BufferedReader reader = new BufferedReader( new InputStreamReader( url.openStream() ) );
  295. StringBuffer page = new StringBuffer();
  296. String line;
  297. while( (line = reader.readLine()) != null )
  298. {
  299. page.append( line );
  300. }
  301. reader.close();
  302. // System.out.println( page.toString() );
  303. Matcher matcher = pattern.matcher( page );
  304. if( matcher.matches() )
  305. {
  306. // System.out.println( matcher.group( 1 ) );
  307. return matcher.group( 1 );
  308. }
  309. } catch( IOException e )
  310. {
  311. logger.severe( e.getMessage() );
  312. }
  313. return null;
  314. }
  315. /**
  316. * This method was reverse engineering from forum page.
  317. * <code>
  318. * (function(){document.write(unescape('%3C%73%63%72%69%70%74%20%74%79%70%65%3D%22%74%65%78%74%2F%6A%61%76%61%73%63%72%69%70%74%22%3E%0A%66%75%6E%63%74%69%6F%6E%20%64%46%28%73%2C%6E%29%7B%6E%3D%70%61%72%73%65%49%6E%74%28%6E%29%3B%76%61%72%20%73%31%3D%75%6E%65%73%63%61%70%65%28%73%2E%73%75%62%73%74%72%28%30%2C%6E%29%2B%73%2E%73%75%62%73%74%72%28%6E%2B%31%2C%73%2E%6C%65%6E%67%74%68%2D%6E%2D%31%29%29%3B%76%61%72%20%74%3D%27%27%3B%66%6F%72%28%69%3D%30%3B%69%3C%73%31%2E%6C%65%6E%67%74%68%3B%69%2B%2B%29%74%2B%3D%53%74%72%69%6E%67%2E%66%72%6F%6D%43%68%61%72%43%6F%64%65%28%73%31%2E%63%68%61%72%43%6F%64%65%41%74%28%69%29%2D%73%2E%73%75%62%73%74%72%28%6E%2C%31%29%29%3B%72%65%74%75%72%6E%28%75%6E%65%73%63%61%70%65%28%74%29%29%3B%7D%0A%64%6F%63%75%6D%65%6E%74%2E%77%72%69%74%65%28%64%46%28%27%2B%39%49%79%69%78%6F%76%7A%2B%38%36%7A%25%37%46%76%6B%2B%39%4A%2B%38%38%7A%6B%25%37%45%7A%35%70%67%25%37%43%67%79%69%78%6F%76%7A%2B%38%38%2B%39%4B%6C%25%37%42%74%69%7A%6F%75%74%2B%38%36%78%6B%76%72%67%69%6B%4C%75%78%73%47%69%7A%6F%75%74%2B%38%25%33%45%6F%6A%2B%38%49%2B%38%36%67%69%7A%6F%75%74%2B%38%25%33%46%2B%25%33%44%48%6A%75%69%25%37%42%73%6B%74%7A%34%6C%75%78%73%79%2B%25%33%42%48%6F%6A%2B%25%33%42%4A%34%79%6B%7A%47%7A%7A%78%6F%68%25%37%42%7A%6B%2B%38%25%33%45%2B%38%25%33%44%67%69%7A%6F%75%74%2B%38%25%33%44%2B%38%49%67%69%7A%6F%75%74%2B%38%25%33%46%2B%39%48%2B%25%33%44%4A%6C%25%37%42%74%69%7A%6F%75%74%2B%38%36%67%6A%6A%4E%6F%6A%6A%6B%74%4C%6F%6B%72%6A%79%2B%38%25%33%45%6F%6A%2B%38%49%2B%38%36%6C%6F%6B%72%6A%79%2B%38%25%33%46%2B%25%33%44%48%6C%2B%38%36%2B%39%4A%2B%38%36%6A%75%69%25%37%42%73%6B%74%7A%34%6C%75%78%73%79%2B%25%33%42%48%6F%6A%2B%25%33%42%4A%2B%39%48%6C%75%78%2B%38%36%2B%38%25%33%45%2B%38%36%6C%6F%6B%72%6A%74%67%73%6B%2B%38%36%6F%74%2B%38%36%6C%6F%6B%72%6A%79%2B%38%36%2B%38%25%33%46%2B%25%33%44%48%25%37%43%67%72%25%37%42%6B%2B%38%36%2B%39%4A%2B%38%36%6C%6F%6B%72%6A%79%2B%25%33%42%48%6C%6F%6B%72%6A%74%67%73%6B%2B%25%33%42%4A%2B%39%48%6F%6C%2B%38%36%2B%38%25%33%45%2B%38%36%7A%25%37%46%76%6B%75%6C%2B%38%25%33%45%25%37%43%67%72%25%37%42%6B%2B%38%25%33%46%2B%38%36%2B%39%4A%2B%39%4A%2B%38%36%2B%38%25%33%44%75%68%70%6B%69%7A%2B%38%25%33%44%2B%38%36%2B%38%25%33%46%2B%25%33%44%48%6C%75%78%2B%38%36%2B%38%25%33%45%2B%38%36%70%2B%38%36%6F%74%2B%38%36%25%37%43%67%72%25%37%42%6B%2B%38%36%2B%38%25%33%46%2B%38%36%2B%25%33%44%48%6B%72%2B%38%36%2B%39%4A%2B%38%36%6A%75%69%25%37%42%73%6B%74%7A%34%69%78%6B%67%7A%6B%4B%72%6B%73%6B%74%7A%2B%38%25%33%45%2B%38%25%33%44%6F%74%76%25%37%42%7A%2B%38%25%33%44%2B%38%25%33%46%2B%39%48%6B%72%34%7A%25%37%46%76%6B%2B%38%36%2B%39%4A%2B%38%36%2B%38%25%33%44%6E%6F%6A%6A%6B%74%2B%38%25%33%44%2B%39%48%6B%72%34%74%67%73%6B%2B%38%36%2B%39%4A%2B%38%36%6C%6F%6B%72%6A%74%67%73%6B%2B%39%48%6B%72%34%25%37%43%67%72%25%37%42%6B%2B%38%36%2B%39%4A%2B%38%36%6A%4C%2B%38%25%33%45%25%37%43%67%72%25%37%42%6B%2B%25%33%42%48%36%70%2B%25%33%42%4A%2B%25%33%42%48%36%2B%25%33%42%4A%2B%38%49%25%37%43%67%72%25%37%42%6B%2B%25%33%42%48%70%2B%25%33%42%4A%2B%25%33%42%48%37%2B%25%33%42%4A%2B%38%25%33%46%2B%39%48%6C%34%67%76%76%6B%74%6A%49%6E%6F%72%6A%2B%38%25%33%45%6B%72%2B%38%25%33%46%2B%39%48%2B%25%33%44%4A%2B%25%33%44%4A%6B%72%79%6B%2B%38%36%2B%25%33%44%48%6B%72%2B%38%36%2B%39%4A%2B%38%36%6A%75%69%25%37%42%73%6B%74%7A%34%69%78%6B%67%7A%6B%4B%72%6B%73%6B%74%7A%2B%38%25%33%45%2B%38%25%33%44%6F%74%76%25%37%42%7A%2B%38%25%33%44%2B%38%25%33%46%2B%39%48%6B%72%34%7A%25%37%46%76%6B%2B%38%36%2B%39%4A%2B%38%36%2B%38%25%33%44%6E%6F%6A%6A%6B%74%2B%38%25%33%44%2B%39%48%6B%72%34%74%67%73%6B%2B%38%36%2B%39%4A%2B%38%36%6F%2B%39%48%6B%72%34%25%37%43%67%72%25%37%42%6B%2B%38%36%2B%39%4A%2B%38%36%6A%4C%2B%38%25%33%45%6C%6F%6B%72%6A%79%2B%25%33%42%48%6F%2B%25%33%42%4A%2B%38%25%33%46%2B%39%48%6C%34%67%76%76%6B%74%6A%49%6E%6F%72%6A%2B%38%25%33%45%6B%72%2B%38%25%33%46%2B%39%48%2B%25%33%44%4A%2B%25%33%44%4A%2B%25%33%44%4A%2B%39%49%35%79%69%78%6F%76%7A%2B%39%4B%27%2C%36%38%39%29%29%3B%0A%3C%2F%73%63%72%69%70%74%3E'));}());
  319. * </code>
  320. * If this method change, this connector won't be able to create
  321. * new account.
  322. * @param s
  323. * @param n
  324. * @return
  325. */
  326. private static String decrypt(String s, int n)
  327. {
  328. String decrypted = "";
  329. try
  330. {
  331. char code = (char)Integer.parseInt( "" + s.charAt( n ) );
  332. // System.out.println( "code="+(int)code );
  333. String s1 = s.substring( 0, n );
  334. s1 += s.substring( n + 1, s.length() );
  335. // System.out.println( s );
  336. // System.out.println( s1 );
  337. s1 = URLDecoder.decode( s1, "UTF-8" );
  338. // not sure why this...
  339. // maybe javascript escape don't behave the same as URLDecoder
  340. s1 = s1.replace( ' ', (char)('%' + code) );
  341. // System.out.println( s1 );
  342. StringBuffer t = new StringBuffer();
  343. for( int i = 0; i < s1.length(); i++ )
  344. {
  345. t.append( (char)(s1.charAt( i ) - code) );
  346. }
  347. decrypted = URLDecoder.decode( t.toString(), "UTF-8" );
  348. // System.out.println( t.toString() );
  349. // System.out.println();
  350. // System.out.println("===========================");
  351. } catch( UnsupportedEncodingException e )
  352. {
  353. logger.severe( e.getMessage() );
  354. }
  355. return decrypted;
  356. }
  357. private static Pattern s_charsetPattern = Pattern.compile( ".*charset=(.+)[; $].*" );
  358. private static String getCharset(HTTPResponse p_response)
  359. {
  360. String responseCharset = "UTF-8";
  361. for( HTTPHeader header : p_response.getHeaders() )
  362. {
  363. if( "Content-Type".equalsIgnoreCase( header.getName() ) )
  364. {
  365. Matcher matcher = s_charsetPattern.matcher( header.getValue() );
  366. if( matcher.matches() )
  367. {
  368. responseCharset = matcher.group( 1 );
  369. }
  370. }
  371. }
  372. return responseCharset;
  373. }
  374. @Override
  375. public boolean createAccount(EbAccount p_account)
  376. {
  377. // we don't need to be connected
  378. // we need a password to create forum account
  379. if( p_account.getPassword() == null || p_account.getPassword().isEmpty() )
  380. {
  381. p_account.setPassword( ServerUtil.randomString( 8 ) );
  382. }
  383. // first request: send username, email and password
  384. // ================================================
  385. FmgCookieStore cookieStore = new FmgCookieStore();
  386. try
  387. {
  388. URL url = new URL( "http://" + FmpConstant.getForumHost() + "/register?agreed=true&step=2" );
  389. String payload = "username=" + URLEncoder.encode( p_account.getPseudo(), "UTF-8" )
  390. + "&email=" + URLEncoder.encode( p_account.getEmail(), "UTF-8" ) + "&password="
  391. + URLEncoder.encode( p_account.getPassword(), "UTF-8" ) + "&submit=Enregistrer";
  392. HTTPRequest request = new HTTPRequest( url, HTTPMethod.POST, FetchOptions.Builder
  393. .withDefaults().doNotFollowRedirects() );
  394. request.addHeader( new HTTPHeader( "Host", FmpConstant.getForumHost() ) );
  395. request.addHeader( new HTTPHeader( "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" ) );
  396. request.addHeader( new HTTPHeader( "Referer", "http://" + FmpConstant.getForumHost()
  397. + "/register?agreed=true&step=2" ) );
  398. request.addHeader( new HTTPHeader( "Content-Type", "application/x-www-form-urlencoded" ) );
  399. request.setPayload( payload.getBytes( "UTF-8" ) );
  400. HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch( request );
  401. // System.out.println( "response code: " + response.getResponseCode() );
  402. // System.out.println( "final url: " + response.getFinalUrl() );
  403. for( HTTPHeader header : response.getHeaders() )
  404. {
  405. // System.out.println( header.getName() + ": " + header.getValue() );
  406. if( "Set-Cookie".equalsIgnoreCase( header.getName() ) )
  407. {
  408. cookieStore.add( header.getValue() );
  409. }
  410. }
  411. // read auth variable used by forum for security
  412. // =============================================
  413. String confirm_pass = "";
  414. String auth1 = null;
  415. String auth2 = null;
  416. String page = new String( response.getContent(), getCharset( response ) );
  417. Matcher matcher = s_confirmPassPattern.matcher( page );
  418. if( matcher.matches() )
  419. {
  420. confirm_pass = matcher.group( 1 );
  421. }
  422. matcher = s_addHiddenFieldsPattern.matcher( page );
  423. if( matcher.matches() )
  424. {
  425. auth1 = decrypt( matcher.group( 1 ), Integer.parseInt( matcher.group( 2 ) ) );
  426. auth2 = decrypt( matcher.group( 3 ), Integer.parseInt( matcher.group( 4 ) ) );
  427. }
  428. // second request: confirm password
  429. // ================================
  430. payload = "";
  431. if( auth1 != null && auth2 != null )
  432. {
  433. payload += "auth[]=" + URLEncoder.encode( auth1, "UTF-8" ) + "&auth[]="
  434. + URLEncoder.encode( auth2, "UTF-8" );
  435. }
  436. payload += "&password_confirm=" + URLEncoder.encode( p_account.getPassword(), "UTF-8" )
  437. + "&username=" + URLEncoder.encode( p_account.getPseudo(), "UTF-8" ) + "&email="
  438. + URLEncoder.encode( p_account.getEmail(), "UTF-8" ) + "&password="
  439. + URLEncoder.encode( p_account.getPassword(), "UTF-8" ) + "&confirm_pass="
  440. + URLEncoder.encode( confirm_pass, "UTF-8" ) + "&submit=Enregistrer";
  441. // in theory we should parse response to get second url. but it's the
  442. // same.
  443. request = new HTTPRequest( url, HTTPMethod.POST, FetchOptions.Builder.withDefaults()
  444. .doNotFollowRedirects() );
  445. request.addHeader( new HTTPHeader( "Host", FmpConstant.getForumHost() ) );
  446. request.addHeader( new HTTPHeader( "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" ) );
  447. request.addHeader( new HTTPHeader( "Referer", "http://" + FmpConstant.getForumHost()
  448. + "/register?agreed=true&step=2" ) );
  449. request.addHeader( new HTTPHeader( "Content-Type", "application/x-www-form-urlencoded" ) );
  450. request.setPayload( payload.getBytes( "UTF-8" ) );
  451. response = URLFetchServiceFactory.getURLFetchService().fetch( request );
  452. page = new String( response.getContent(), getCharset( response ) );
  453. } catch( Exception e )
  454. {
  455. logger.severe( e.getMessage() );
  456. return false;
  457. }
  458. return true;
  459. }
  460. @Override
  461. public boolean pushAccount(EbAccount p_account)
  462. {
  463. // we need to be connected as admin
  464. connect();
  465. try
  466. {
  467. URL url = new URL( proxyfyUrl( m_adminUrl + "&part=users_groups&sub=users&mode=edit&u="
  468. + p_account.getForumId() + "&extended_admin=1" ) );
  469. ClientHttpRequest clientPostRequest = null;
  470. clientPostRequest = new ClientHttpRequest( url );
  471. clientPostRequest.setParameter( FIELD_USERNAME, p_account.getPseudo() );
  472. clientPostRequest.setParameter( FIELD_EMAIL, p_account.getEmail() );
  473. clientPostRequest.setParameter( "password", "" );
  474. clientPostRequest.setParameter( "password_confirm", "" );
  475. // a list of many parameters
  476. clientPostRequest.setParameter( FIELD_LEVEL, (int)p_account.getCurrentLevel() );
  477. clientPostRequest.setParameter( FIELD_GRADICON, p_account.getGradUrl() );
  478. Map<String,String> forumData = new HashMap<String,String>();
  479. if( p_account.getForumConnectorData() != null
  480. && p_account.getForumConnectorData() instanceof HashMap<?,?> )
  481. {
  482. forumData = (HashMap<String,String>)p_account.getForumConnectorData();
  483. }
  484. // for dateformat if == "D j M - G:i" set to "D j M Y - G:i"
  485. if( forumData.get( "dateformat" ) == null
  486. || forumData.get( "dateformat" ).equals( "D j M - G:i" ) )
  487. {
  488. forumData.put( "dateformat", "D j M Y - G:i" );
  489. }
  490. if( forumData.get( "user_status" ) == null )
  491. {
  492. forumData.put( "user_status", "1" );
  493. }
  494. if( forumData.get( "user_allowpm" ) == null )
  495. {
  496. forumData.put( "user_allowpm", "1" );
  497. }
  498. if( forumData.get( "user_allowavatar" ) == null )
  499. {
  500. forumData.put( "user_allowavatar", "1" );
  501. }
  502. if( forumData.get( "user_allow_att" ) == null )
  503. {
  504. forumData.put( "user_allow_att", "1" );
  505. }
  506. // put back saved field
  507. for( Entry<String, Pattern> entry : s_fieldPatternMap.entrySet() )
  508. {
  509. if( forumData.get( entry.getKey() ) != null )
  510. {
  511. clientPostRequest.setParameter( entry.getKey(), forumData.get( entry.getKey() ) );
  512. }
  513. }
  514. clientPostRequest.setParameter( "submit", "Enregistrer" );
  515. clientPostRequest.setParameter( "mode", "save" );
  516. clientPostRequest.setParameter( "agreed", "true" );
  517. clientPostRequest.setParameter( "id", p_account.getForumId() );
  518. clientPostRequest.setCookie( m_cookieStore.getCookies() );
  519. InputStream is = clientPostRequest.post();
  520. // look for "Le profil de l'utilisateur a été mis ŕ jour avec succčs"
  521. // read response
  522. if( is != null )
  523. {
  524. Writer writer = new StringWriter();
  525. char[] buffer = new char[1024];
  526. try
  527. {
  528. InputStreamReader reader = new InputStreamReader( is, "iso-8859-1" );
  529. int n;
  530. while( (n = reader.read( buffer )) != -1 )
  531. {
  532. writer.write( buffer, 0, n );
  533. }
  534. } finally
  535. {
  536. is.close();
  537. }
  538. // System.out.println( writer.toString() );
  539. if( !writer.toString().contains( "Le profil de l'utilisateur a été mis ŕ jour avec succčs" ) )
  540. {
  541. disconnect();
  542. return false;
  543. }
  544. }
  545. } catch( IOException e )
  546. {
  547. logger.severe( e.getMessage() );
  548. disconnect();
  549. return false;
  550. }
  551. return true;
  552. }
  553. @Override
  554. public boolean pullAccount(EbAccount p_account)
  555. {
  556. // we need to be connected as admin
  557. connect();
  558. try
  559. {
  560. // we should have all we want on this page
  561. //
  562. String urlStr = m_adminUrl + "&part=users_groups&sub=users&mode=edit&u="
  563. + p_account.getForumId() + "&extended_admin=1";
  564. URL url = new URL( proxyfyUrl( urlStr ) );
  565. HTTPRequest request = new HTTPRequest( url );
  566. request.addHeader( new HTTPHeader( "Host", PROXY_HOST ) );
  567. request.addHeader( new HTTPHeader( "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" ) );
  568. request.addHeader( new HTTPHeader( "Cookie", m_cookieStore.getCookies().toString() ) );
  569. HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch( request );
  570. String page = new String( response.getContent(), getCharset( response ) );
  571. Matcher matcher = s_usernamePattern.matcher( page );
  572. if( matcher.matches() )
  573. {
  574. p_account.setPseudo( matcher.group( 1 ) );
  575. }
  576. else
  577. {
  578. // if username isn't found, consider this method as failed
  579. disconnect();
  580. return false;
  581. }
  582. matcher = s_emailPattern.matcher( page );
  583. if( matcher.matches() )
  584. {
  585. p_account.setEmail( matcher.group( 1 ) );
  586. }
  587. else
  588. {
  589. logger.warning( "pattern 'email' failed" );
  590. }
  591. matcher = s_avatarUrlPattern.matcher( page );
  592. if( matcher.matches() )
  593. {
  594. p_account.setForumAvatarUrl( deproxyfyUrl( matcher.group( 1 ) ) );
  595. }
  596. else
  597. {
  598. logger.warning( "pattern 'avatar url' failed" );
  599. }
  600. matcher = s_jabberPattern.matcher( page );
  601. if( matcher.matches() )
  602. {
  603. String jabberId = matcher.group( 1 );
  604. if( jabberId != null && !jabberId.isEmpty() )
  605. {
  606. p_account.setJabberId( jabberId );
  607. }
  608. }
  609. else
  610. {
  611. logger.warning( "pattern 'jabber id' failed" );
  612. }
  613. matcher = s_notifQtyPattern.matcher( page );
  614. if( matcher.matches() )
  615. {
  616. String value = matcher.group( 1 );
  617. if( value != null )
  618. {
  619. // 0 : min
  620. // 1 : standard
  621. // 2 : max
  622. if( value.equalsIgnoreCase( "0" ) )
  623. {
  624. p_account.setNotificationQty( NotificationQty.Min );
  625. }
  626. else if( value.equalsIgnoreCase( "2" ) )
  627. {
  628. p_account.setNotificationQty( NotificationQty.Max );
  629. }
  630. else
  631. {
  632. p_account.setNotificationQty( NotificationQty.Std );
  633. }
  634. }
  635. }
  636. else
  637. {
  638. logger.warning( "pattern 'FIELD_FMG_NOTIF_QTY' failed" );
  639. }
  640. matcher = s_sendEmailPattern.matcher( page );
  641. if( matcher.matches() )
  642. {
  643. String value = matcher.group( 1 );
  644. if( value != null )
  645. {
  646. // 0 : no
  647. // 1 : by email client
  648. // 2 : by forms
  649. if( value.equalsIgnoreCase( "0" ) )
  650. {
  651. p_account.setAllowMsgFromPlayer( false );
  652. }
  653. else
  654. {
  655. p_account.setAllowMsgFromPlayer( true );
  656. }
  657. }
  658. }
  659. else
  660. {
  661. logger.warning( "pattern 'viewemail' failed" );
  662. }
  663. // backup some forum field to avoid override
  664. //
  665. Map<String,String> forumData = new HashMap<String,String>();
  666. if( p_account.getForumConnectorData() != null
  667. && p_account.getForumConnectorData() instanceof HashMap<?,?> )
  668. {
  669. forumData = (HashMap<String,String>)p_account.getForumConnectorData();
  670. }
  671. for( Entry<String, Pattern> entry : s_fieldPatternMap.entrySet() )
  672. {
  673. matcher = entry.getValue().matcher( page );
  674. if( matcher.matches() )
  675. {
  676. String data = matcher.group( 1 );
  677. if( data != null && !data.isEmpty() )
  678. {
  679. forumData.put( entry.getKey(), data );
  680. }
  681. }
  682. else
  683. {
  684. forumData.remove( entry.getKey() );
  685. if( entry.getKey().equals( "user_rank" ) )
  686. {
  687. logger.fine( "pattern '" + entry.getKey() + "' failed" );
  688. }
  689. else
  690. {
  691. logger.warning( "pattern '" + entry.getKey() + "' failed" );
  692. }
  693. }
  694. }
  695. p_account.setForumConnectorData( forumData );
  696. } catch( IOException e )
  697. {
  698. logger.severe( e.getMessage() );
  699. disconnect();
  700. return false;
  701. }
  702. return true;
  703. }
  704. @Override
  705. public boolean sendPMessage(String p_subject, String p_body, String... p_usernames)
  706. {
  707. // we need to be connected as admin
  708. connect();
  709. try
  710. {
  711. URL url = new URL( proxyfyUrl( "http://" + FmpConstant.getForumHost() + "/privmsg?" ) );
  712. ClientHttpRequest clientPostRequest = null;
  713. clientPostRequest = new ClientHttpRequest( url );
  714. for( String username : p_usernames )
  715. {
  716. if( username != null )
  717. {
  718. clientPostRequest.setParameter( "username[]", username );
  719. }
  720. }
  721. clientPostRequest.setParameter( "subject", p_subject );
  722. clientPostRequest.setParameter( "message", p_body );
  723. clientPostRequest.setParameter( "lt", "" );
  724. clientPostRequest.setParameter( "folder", "inbox" );
  725. clientPostRequest.setParameter( "mode", "post" );
  726. clientPostRequest.setParameter( "new_pm_time", "" + (System.currentTimeMillis() / 1000) );
  727. clientPostRequest.setParameter( "post", "Envoyer" );
  728. clientPostRequest.setCookie( m_cookieStore.getCookies() );
  729. clientPostRequest.post();
  730. } catch( IOException e )
  731. {
  732. logger.severe( e.getMessage() );
  733. disconnect();
  734. return false;
  735. }
  736. return true;
  737. }
  738. @Override
  739. public boolean postNews(String p_threadId, String p_subject, String p_body)
  740. {
  741. // we need to be connected as admin
  742. connect();
  743. try
  744. {
  745. // first request: simply ask for posting page
  746. // ==========================================
  747. URL url = new URL( proxyfyUrl( "http://" + FmpConstant.getForumHost() + "/post?f="
  748. + p_threadId + "&mode=newtopic" ) );
  749. HTTPRequest request = new HTTPRequest( url, HTTPMethod.GET, FetchOptions.Builder
  750. .withDefaults().doNotFollowRedirects() );
  751. request.addHeader( new HTTPHeader( "Host", PROXY_HOST ) );
  752. request.addHeader( new HTTPHeader( "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" ) );
  753. request.addHeader( new HTTPHeader( "Referer", "http://" + FmpConstant.getForumHost() ) );
  754. request.addHeader( new HTTPHeader( "Cookie", m_cookieStore.getCookies().toString() ) );
  755. HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch( request );
  756. // System.out.println( "response code: " + response.getResponseCode() );
  757. // System.out.println( "final url: " + response.getFinalUrl() );
  758. for( HTTPHeader header : response.getHeaders() )
  759. {
  760. // System.out.println( header.getName() + ": " + header.getValue() );
  761. if( "Set-Cookie".equalsIgnoreCase( header.getName() ) )
  762. {
  763. m_cookieStore.add( header.getValue() );
  764. }
  765. }
  766. // read auth variable used by forum for security
  767. // =============================================
  768. String auth1 = null;
  769. String auth2 = null;
  770. String page = new String( response.getContent(), getCharset( response ) );
  771. Matcher matcher = s_addHiddenFieldsPattern.matcher( page );
  772. if( matcher.matches() )
  773. {
  774. auth1 = decrypt( matcher.group( 1 ), Integer.parseInt( matcher.group( 2 ) ) );
  775. auth2 = decrypt( matcher.group( 3 ), Integer.parseInt( matcher.group( 4 ) ) );
  776. }
  777. // second request: post data
  778. // =========================
  779. url = new URL( proxyfyUrl( "http://" + FmpConstant.getForumHost() + "/post" ) );
  780. ClientHttpRequest clientPostRequest = null;
  781. //clientPostRequest = new ClientHttpRequest( url );
  782. // the following code was test and I didn't succeed to post a news on
  783. // forum
  784. URLConnection connection = url.openConnection();
  785. connection.setDoOutput( true );
  786. connection.setRequestProperty( "Host", "fullmetalplanete.forum2jeux.com" );
  787. connection
  788. .setRequestProperty( "User-Agent",
  789. "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB7.1" );
  790. connection.setRequestProperty( "Accept",
  791. "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" );
  792. connection.setRequestProperty( "Accept-Language", "fr-fr" );
  793. connection.setRequestProperty( "Keep-Alive", "300" );
  794. connection.setRequestProperty( "Connection", "keep-alive" );
  795. connection.setRequestProperty( "Referer", "http://fullmetalplanete.forum2jeux.com/post?f=41&mode=newtopic" );
  796. connection.setRequestProperty( "Cookie", m_cookieStore.toString() );
  797. clientPostRequest = new ClientHttpRequest( connection );
  798. // clientPostRequest.setCookie( m_cookieStore.getCookies() );
  799. // clientPostRequest.postCookies();
  800. clientPostRequest.setParameter( "subject", p_subject );
  801. clientPostRequest.setParameter( "post_icon", "0" );
  802. clientPostRequest.setParameter( "message", p_body );
  803. clientPostRequest.setParameter( "lt", "0" );
  804. clientPostRequest.setParameter( "mode", "newtopic" );
  805. clientPostRequest.setParameter( "f", p_threadId );
  806. clientPostRequest.setParameter( "post", "Envoyer" );
  807. clientPostRequest.setParameter( "notify", "off" );
  808. clientPostRequest.setParameter( "topictype", "0" );
  809. // clientPostRequest.setParameter( "topic_calendar_day", "0" );
  810. // clientPostRequest.setParameter( "topic_calendar_month", "0" );
  811. // clientPostRequest.setParameter( "topic_calendar_year", "0" );
  812. // clientPostRequest.setParameter( "topic_calendar_hour", "" );
  813. // clientPostRequest.setParameter( "topic_calendar_min", "" );
  814. // clientPostRequest.setParameter( "topic_calendar_duration_day", "" );
  815. // clientPostRequest.setParameter( "topic_calendar_duration_hour", "" );
  816. // clientPostRequest.setParameter( "topic_calendar_duration_min", "" );
  817. // clientPostRequest.setParameter( "create_event", "0" );
  818. // clientPostRequest.setParameter( "calendar_d", "0" );
  819. clientPostRequest.setParameter( "poll_title", "" );
  820. clientPostRequest.setParameter( "poll_option_text", "" );
  821. clientPostRequest.setParameter( "poll_length", "" );
  822. clientPostRequest.setParameter( "poll_multiple", "0" );
  823. clientPostRequest.setParameter( "poll_cancel_vote", "0" );
  824. if( auth1 != null )
  825. {
  826. clientPostRequest.setParameter( "auth[]", auth1 );
  827. }
  828. if( auth2 != null )
  829. {
  830. clientPostRequest.setParameter( "auth[]", auth2 );
  831. }
  832. // clientPostRequest.setCookie( m_cookieStore.getCookies() );
  833. InputStream is = clientPostRequest.post();
  834. // read response
  835. if( is != null )
  836. {
  837. char[] buffer = new char[1024];
  838. InputStreamReader reader = new InputStreamReader( is, "iso-8859-1" );
  839. int n;
  840. while( (n = reader.read( buffer )) != -1 )
  841. {
  842. System.out.print( buffer/*, 0, n*/);
  843. }
  844. }
  845. } catch( IOException e )
  846. {
  847. logger.severe( e.getMessage() );
  848. disconnect();
  849. return false;
  850. }
  851. return true;
  852. }
  853. @Override
  854. public String getNewsRssUrl(String p_threadId)
  855. {
  856. return "http://" + FmpConstant.getForumHost() + "/feed?f=" + p_threadId;
  857. }
  858. }