You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IRCParser.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * Copyright (c) 2006-2007 Chris Smith, Shane Mc Cormack
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package dmdirc.parser;
  23. import java.io.BufferedReader;
  24. import java.io.IOException;
  25. import java.io.InputStreamReader;
  26. import java.io.PrintWriter;
  27. import java.net.Socket;
  28. import java.net.UnknownHostException;
  29. import java.util.ArrayList;
  30. public class IRCParser implements Runnable {
  31. public static final int ndInfo = 1;
  32. // public static final int ndSomething = 2;
  33. private Socket socket = null;
  34. private PrintWriter out = null;
  35. private BufferedReader in = null;
  36. public class MyInfo {
  37. public String sNickname = "IRCParser";
  38. public String sAltNickname = "IRC-Parser"; // Alternative nickname, if this fails, we start prepending _ to sNickname
  39. public String sRealname = "Java Test IRCParser";
  40. public String sUsername = "IRCParser";
  41. }
  42. public class ServerInfo {
  43. public String sHost = "uk.quakenet.org";
  44. public String sPassword = "";
  45. public int nPort = 6667;
  46. }
  47. public MyInfo me = new MyInfo(); // This is what the user wants, nickname here is *not* fact.
  48. public ServerInfo server = new ServerInfo(); // Server Info requested by user
  49. private String sThinkNickname; // This is what we want the nickname to be.
  50. private String sConfirmedNickname; // This is what the nickname actually is.
  51. private boolean TriedAlt = false;
  52. private boolean Got001 = false;
  53. private boolean Got005 = false;
  54. private boolean HasBegan = false;
  55. private boolean IsFirst = true;
  56. // Events
  57. public interface IDebugInfo { public void onDebug(IRCParser tParser, int nLevel, String sData); }
  58. ArrayList<IDebugInfo> cbDebugInfo = new ArrayList<IDebugInfo>();
  59. public interface IMOTDEnd { public void onMOTDEnd(IRCParser tParser); }
  60. ArrayList<IMOTDEnd> cbEndOfMOTD = new ArrayList<IMOTDEnd>();
  61. public interface IDataIn { public void onDataIn(IRCParser tParser, String sData); }
  62. ArrayList<IDataIn> cbDataIn = new ArrayList<IDataIn>();
  63. public interface IDataOut { public void onDataOut(IRCParser tParser, String sData, boolean FromParser); }
  64. ArrayList<IDataOut> cbDataOut = new ArrayList<IDataOut>();
  65. public interface INickInUse { public void onNickInUse(IRCParser tParser); }
  66. ArrayList<INickInUse> cbNickInUse = new ArrayList<INickInUse>();
  67. private void AddCallback (Object eMethod, ArrayList CallbackList) {
  68. for (int i = 0; i < CallbackList.size(); i++) {
  69. if (eMethod.equals(CallbackList.get(i))) { return; }
  70. }
  71. CallbackList.add(eMethod);
  72. }
  73. public void DelCallback (Object eMethod, ArrayList CallbackList) {
  74. for (int i = 0; i < CallbackList.size(); i++) {
  75. if (eMethod.equals(CallbackList.get(i))) { CallbackList.remove(i); break; }
  76. }
  77. }
  78. public void AddDebugInfo(Object eMethod) { AddCallback(eMethod, cbDebugInfo); }
  79. public void DelDebugInfo(Object eMethod) { DelCallback(eMethod, cbDebugInfo); }
  80. private boolean CallDebugInfo(int level, String data) {
  81. boolean bResult = false;
  82. for (int i = 0; i < cbDebugInfo.size(); i++) {
  83. cbDebugInfo.get(i).onDebug(this, level, data);
  84. bResult = true;
  85. }
  86. return bResult;
  87. }
  88. public void AddMOTDEnd(Object eMethod) { AddCallback(eMethod, cbEndOfMOTD); }
  89. public void DelMOTDEnd(Object eMethod) { DelCallback(eMethod, cbEndOfMOTD); }
  90. private boolean CallMOTDEnd() {
  91. boolean bResult = false;
  92. for (int i = 0; i < cbEndOfMOTD.size(); i++) {
  93. cbEndOfMOTD.get(i).onMOTDEnd(this);
  94. bResult = true;
  95. }
  96. return bResult;
  97. }
  98. public void AddDataIn(Object eMethod) { AddCallback((IDataIn)eMethod, cbDataIn); }
  99. public void DelDataIn(Object eMethod) { DelCallback((IDataIn)eMethod, cbDataIn); }
  100. private boolean CallDataIn(String data) {
  101. boolean bResult = false;
  102. for (int i = 0; i < cbDataIn.size(); i++) {
  103. cbDataIn.get(i).onDataIn(this, data);
  104. bResult = true;
  105. }
  106. return bResult;
  107. }
  108. public void AddDataOut(Object eMethod) { AddCallback((IDataOut)eMethod, cbDataOut); }
  109. public void DelDataOut(Object eMethod) { DelCallback((IDataOut)eMethod, cbDataOut); }
  110. private boolean CallDataOut(String data, boolean FromParser) {
  111. boolean bResult = false;
  112. for (int i = 0; i < cbDataOut.size(); i++) {
  113. cbDataOut.get(i).onDataOut(this, data, FromParser);
  114. bResult = true;
  115. }
  116. return bResult;
  117. }
  118. public void AddNickInUse(Object eMethod) { AddCallback(eMethod, cbNickInUse); }
  119. public void DelNickInUse(Object eMethod) { DelCallback(eMethod, cbNickInUse); }
  120. private boolean CallNickInUse() {
  121. boolean bResult = false;
  122. for (int i = 0; i < cbNickInUse.size(); i++) {
  123. cbNickInUse.get(i).onNickInUse(this);
  124. bResult = true;
  125. }
  126. return bResult;
  127. }
  128. // Constructors
  129. public IRCParser () { }
  130. public IRCParser (ServerInfo serverDetails) { this(null,serverDetails); }
  131. public IRCParser (MyInfo myDetails) { this(myDetails,null); }
  132. public IRCParser (MyInfo myDetails, ServerInfo serverDetails) {
  133. if (myDetails != null) { this.me = myDetails; }
  134. if (serverDetails != null) { this.server = serverDetails; }
  135. }
  136. private void ResetState() {
  137. TriedAlt = false;
  138. Got001 = false;
  139. Got005 = false;
  140. };
  141. private void connect() throws Exception {
  142. try {
  143. ResetState();
  144. socket = new Socket(server.sHost,server.nPort);
  145. out = new PrintWriter(socket.getOutputStream(), true);
  146. in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  147. } catch (Exception e) { throw e; }
  148. }
  149. public void run() /*throws Exception*/ {
  150. if (HasBegan) { return; } else { HasBegan = true; }
  151. try { connect(); } catch (Exception e) { /*throw e;*/ return; }
  152. // :HACK: While true loops really really suck.
  153. String line = "";
  154. while(true) {
  155. try {
  156. line = in.readLine(); // Blocking :/
  157. if (IsFirst) {
  158. SetNickname(me.sNickname);
  159. SendString("USER "+me.sUsername.toLowerCase()+" * * :"+me.sRealname);
  160. IsFirst = false;
  161. }
  162. ProcessLine(line);
  163. } catch (IOException e) {
  164. // Socket Closed.
  165. break;
  166. }
  167. }
  168. }
  169. protected void finalize(){
  170. try {
  171. socket.close();
  172. } catch (IOException e) {
  173. System.out.println("Could not close socket");
  174. System.exit(-1);
  175. }
  176. }
  177. private String GetParam(String line) {
  178. String[] params = null;
  179. params = line.split(" :",2);
  180. return params[params.length-1];
  181. }
  182. private String[] IRCTokenise(String line) {
  183. String[] params = null;
  184. String[] tokens = null;
  185. params = line.split(" :",2);
  186. tokens = params[0].split(" ");
  187. if (params.length == 2) {
  188. String[] temp = new String[tokens.length+1];
  189. System.arraycopy(tokens, 0, temp, 0, tokens.length);
  190. tokens = temp;
  191. tokens[tokens.length-1] = params[1];
  192. }
  193. return tokens;
  194. }
  195. public void SendLine(String line) { CallDataOut(line,false); out.printf("%s\r\n",line);} // This should do some checks on stuff, public event!
  196. // Our Method
  197. private void SendString(String line) {
  198. CallDataOut(line,true);
  199. out.printf("%s\r\n",line);
  200. }
  201. private void ProcessLine(String line) {
  202. String[] token = IRCTokenise(line);
  203. String sParam = token[token.length-1];
  204. int nParam;
  205. CallDataIn(line);
  206. try {nParam = Integer.parseInt(token[1]);} catch (Exception e) { nParam = -1;}
  207. if (token[0].equals("PING") || token[1].equals("PING")) { SendString("PONG :"+sParam); }
  208. else {
  209. if (token[0].substring(0,1).equals(":")) {
  210. // Post Connect
  211. switch (nParam) {
  212. case -1:
  213. ProcessStringParam(sParam,token);
  214. break;
  215. case 1: // 001
  216. break;
  217. case 422: // No MOTD
  218. case 376: // End of MOTD
  219. ProcessEndOfMOTD(sParam,token);
  220. break;
  221. case 433: // Nick In Use
  222. ProcessNickInUse(sParam,token);
  223. break;
  224. default: // Unknown
  225. break;
  226. }
  227. } else {
  228. // Pre Connect
  229. }
  230. }
  231. }
  232. private void ProcessStringParam(String sParam,String token[]) {
  233. // Process a line where the parameter is a string (IE PRIVMSG, NOTICE etc - Not including PING!)
  234. }
  235. private void ProcessEndOfMOTD(String sParam,String token[]) { CallMOTDEnd(); }
  236. private void ProcessNickInUse(String sParam,String token[]) {
  237. if (!CallNickInUse()) {
  238. // Manually handle nick in use.
  239. CallDebugInfo(ndInfo,"No Nick in use Handler.");
  240. if (!Got001) {
  241. CallDebugInfo(ndInfo,"Using inbuilt handler");
  242. // If this is before 001 we will try and get a nickname, else we will leave the nick as-is
  243. if (!TriedAlt) { SetNickname(me.sAltNickname); TriedAlt = true; }
  244. else {
  245. if (sThinkNickname.equalsIgnoreCase(me.sAltNickname)) { sThinkNickname = me.sNickname; }
  246. SetNickname('_'+sThinkNickname);
  247. }
  248. }
  249. }
  250. }
  251. public void JoinChannel(String sChannelName) {
  252. SendString("JOIN "+sChannelName);
  253. }
  254. public void SetNickname(String sNewNickName) {
  255. sThinkNickname = sNewNickName;
  256. SendString("NICK "+sNewNickName);
  257. }
  258. public void Quit(String sReason) { SendString("QUIT :"+sReason); }
  259. // Quit and force Disconnection
  260. public void Disconnect(String sReason) {
  261. Quit(sReason);
  262. try { socket.close(); } catch (Exception e) { /* Meh */ };
  263. }
  264. }