Java IRC bot
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.

ProcessMode.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
  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 com.dmdirc.parser.irc;
  23. import com.dmdirc.parser.irc.callbacks.CallbackObject;
  24. import java.util.Calendar;
  25. /**
  26. * Process a Mode line.
  27. */
  28. public class ProcessMode extends IRCProcessor {
  29. /**
  30. * Process a Mode Line.
  31. *
  32. * @param sParam Type of line to process ("MODE", "324")
  33. * @param token IRCTokenised line to process
  34. */
  35. @Override
  36. public void process(String sParam, String[] token) {
  37. String[] sModestr;
  38. String sChannelName;
  39. if (sParam.equals("324")) {
  40. sChannelName = token[3];
  41. sModestr = new String[token.length-4];
  42. System.arraycopy(token, 4, sModestr, 0, token.length-4);
  43. } else if (sParam.equals("221")) {
  44. processUserMode(sParam, token, new String[]{token[token.length-1]}, true);
  45. return;
  46. } else {
  47. sChannelName = token[2];
  48. sModestr = new String[token.length-3];
  49. System.arraycopy(token, 3, sModestr, 0, token.length-3);
  50. }
  51. if (!isValidChannelName(sChannelName)) { processUserMode(sParam, token, sModestr, false); }
  52. else { processChanMode(sParam, token, sModestr, sChannelName); }
  53. }
  54. /**
  55. * Method to trim spaces from strings
  56. *
  57. * @param str String to trim
  58. * @return String without spaces on the ends
  59. */
  60. private String trim(String str) { return str.trim(); }
  61. /**
  62. * Process Chan modes.
  63. *
  64. * @param sParam String representation of parameter to parse
  65. * @param token IRCTokenised Array of the incomming line
  66. * @param sModestr The modes and params
  67. * @param sChannelName Channel these modes are for
  68. */
  69. public void processChanMode(String sParam, String token[], String sModestr[], String sChannelName) {
  70. StringBuilder sFullModeStr = new StringBuilder();
  71. String sNonUserModeStr = "";
  72. String sNonUserModeStrParams = "";
  73. String sModeParam;
  74. String sTemp;
  75. int nParam = 1;
  76. long nTemp = 0, nValue = 0, nCurrent = 0;
  77. boolean bPositive = true, bBooleanMode = true;
  78. char cPositive = '+';
  79. ChannelInfo iChannel;
  80. ChannelClientInfo iChannelClientInfo;
  81. ClientInfo iClient;
  82. ChannelClientInfo setterCCI;
  83. CallbackObject cbSingle = null;
  84. CallbackObject cbNonUser = null;
  85. if (!sParam.equals("324")) {
  86. cbSingle = getCallbackManager().getCallbackType("OnChannelSingleModeChanged");
  87. cbNonUser = getCallbackManager().getCallbackType("OnChannelNonUserModeChanged");
  88. }
  89. iChannel = getChannelInfo(sChannelName);
  90. if (iChannel == null) {
  91. // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got modes for channel ("+sChannelName+") that I am not on.", myParser.getLastLine()));
  92. // iChannel = new ChannelInfo(myParser, sChannelName);
  93. // myParser.addChannel(iChannel);
  94. return;
  95. }
  96. // Get the current channel modes
  97. if (!sParam.equals("324")) { nCurrent = iChannel.getMode(); }
  98. setterCCI = iChannel.getUser(token[0]);
  99. if (IRCParser.ALWAYS_UPDATECLIENT && setterCCI != null) {
  100. // Facilitate dmdirc formatter
  101. if (setterCCI.getClient().getHost().isEmpty()) {setterCCI.getClient().setUserBits(token[0],false); }
  102. }
  103. // Loop through the mode string, and add/remove modes/params where they are needed
  104. for (int i = 0; i < sModestr[0].length(); ++i) {
  105. Character cMode = sModestr[0].charAt(i);
  106. if (cMode.equals(":".charAt(0))) { continue; }
  107. sNonUserModeStr = sNonUserModeStr+cMode;
  108. if (cMode.equals("+".charAt(0))) { cPositive = '+'; bPositive = true; }
  109. else if (cMode.equals("-".charAt(0))) { cPositive = '-'; bPositive = false; }
  110. else {
  111. if (myParser.hChanModesBool.containsKey(cMode)) { nValue = myParser.hChanModesBool.get(cMode); bBooleanMode = true; }
  112. else if (myParser.hChanModesOther.containsKey(cMode)) { nValue = myParser.hChanModesOther.get(cMode); bBooleanMode = false; }
  113. else if (myParser.hPrefixModes.containsKey(cMode)) {
  114. // (de) OP/Voice someone
  115. if (sModestr.length <= nParam) {
  116. myParser.callErrorInfo(new ParserError(ParserError.ERROR_FATAL + ParserError.ERROR_USER, "Broken Modes. Parameter required but not given.", myParser.getLastLine()));
  117. }
  118. sModeParam = sModestr[nParam++];
  119. nValue = myParser.hPrefixModes.get(cMode);
  120. callDebugInfo(IRCParser.DEBUG_INFO, "User Mode: %c / %d [%s] {Positive: %b}",cMode, nValue, sModeParam, bPositive);
  121. iChannelClientInfo = iChannel.getUser(sModeParam);
  122. if (iChannelClientInfo == null) {
  123. // Client not known?
  124. // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got mode for client not known on channel - Added", myParser.getLastLine()));
  125. iClient = getClientInfo(sModeParam);
  126. if (iClient == null) {
  127. // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got mode for client not known at all - Added", myParser.getLastLine()));
  128. iClient = new ClientInfo(myParser, sModeParam);
  129. myParser.addClient(iClient);
  130. }
  131. iChannelClientInfo = iChannel.addClient(iClient);
  132. }
  133. callDebugInfo(IRCParser.DEBUG_INFO, "\tOld Mode Value: %d",iChannelClientInfo.getChanMode());
  134. if (bPositive) { iChannelClientInfo.setChanMode(iChannelClientInfo.getChanMode() | nValue); sTemp = "+"; }
  135. else { iChannelClientInfo.setChanMode(iChannelClientInfo.getChanMode() ^ (iChannelClientInfo.getChanMode() & nValue)); sTemp = "-"; }
  136. sTemp = sTemp+cMode;
  137. callChannelUserModeChanged(iChannel, iChannelClientInfo, setterCCI, token[0], sTemp);
  138. continue;
  139. } else {
  140. // unknown mode - add as boolean
  141. // callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got unknown mode "+cMode+" - Added as boolean mode", myParser.getLastLine()));
  142. myParser.hChanModesBool.put(cMode,myParser.nNextKeyCMBool);
  143. nValue = myParser.nNextKeyCMBool;
  144. bBooleanMode = true;
  145. myParser.nNextKeyCMBool = myParser.nNextKeyCMBool*2;
  146. }
  147. if (bBooleanMode) {
  148. callDebugInfo(IRCParser.DEBUG_INFO, "Boolean Mode: %c [%d] {Positive: %b}",cMode, nValue, bPositive);
  149. if (bPositive) { nCurrent = nCurrent | nValue; }
  150. else { nCurrent = nCurrent ^ (nCurrent & nValue); }
  151. } else {
  152. if ((bPositive || nValue == IRCParser.MODE_LIST || ((nValue & IRCParser.MODE_UNSET) == IRCParser.MODE_UNSET)) && (sModestr.length <= nParam)) {
  153. myParser.callErrorInfo(new ParserError(ParserError.ERROR_FATAL + ParserError.ERROR_USER, "Broken Modes. Parameter required but not given.", myParser.getLastLine()));
  154. }
  155. if (nValue == IRCParser.MODE_LIST) {
  156. // List Mode
  157. sModeParam = sModestr[nParam++];
  158. sNonUserModeStrParams = sNonUserModeStrParams+" "+sModeParam;
  159. nTemp = (Calendar.getInstance().getTimeInMillis() / 1000);
  160. iChannel.setListModeParam(cMode, new ChannelListModeItem(sModeParam, token[0], nTemp ), bPositive);
  161. callDebugInfo(IRCParser.DEBUG_INFO, "List Mode: %c [%s] {Positive: %b}",cMode, sModeParam, bPositive);
  162. if (cbSingle != null) { cbSingle.call(iChannel, setterCCI, token[0], cPositive+cMode+" "+sModeParam ); }
  163. } else {
  164. // Mode with a parameter
  165. if (bPositive) {
  166. // +Mode - always needs a parameter to set
  167. sModeParam = sModestr[nParam++];
  168. sNonUserModeStrParams = sNonUserModeStrParams+" "+sModeParam;
  169. callDebugInfo(IRCParser.DEBUG_INFO, "Set Mode: %c [%s] {Positive: %b}",cMode, sModeParam, bPositive);
  170. iChannel.setModeParam(cMode,sModeParam);
  171. if (cbSingle != null) { cbSingle.call(iChannel, setterCCI, token[0], cPositive+cMode+" "+sModeParam ); }
  172. } else {
  173. // -Mode - parameter isn't always needed, we need to check
  174. if ((nValue & IRCParser.MODE_UNSET) == IRCParser.MODE_UNSET) {
  175. sModeParam = sModestr[nParam++];
  176. sNonUserModeStrParams = sNonUserModeStrParams+" "+sModeParam;
  177. } else {
  178. sModeParam = "";
  179. }
  180. callDebugInfo(IRCParser.DEBUG_INFO, "Unset Mode: %c [%s] {Positive: %b}",cMode, sModeParam, bPositive);
  181. iChannel.setModeParam(cMode,"");
  182. if (cbSingle != null) { cbSingle.call(iChannel, setterCCI, token[0], trim(cPositive+cMode+" "+sModeParam) ); }
  183. }
  184. }
  185. }
  186. }
  187. }
  188. // Call Callbacks
  189. for (int i = 0; i < sModestr.length; ++i) { sFullModeStr.append(sModestr[i]).append(" "); }
  190. iChannel.setMode(nCurrent);
  191. if (sParam.equals("324")) { callChannelModeChanged(iChannel, null, "", sFullModeStr.toString().trim()); }
  192. else { callChannelModeChanged(iChannel, setterCCI, token[0], sFullModeStr.toString().trim()); }
  193. if (cbNonUser != null) { cbNonUser.call(iChannel, setterCCI, token[0], trim(sNonUserModeStr+sNonUserModeStrParams)); }
  194. }
  195. /**
  196. * Process user modes.
  197. *
  198. * @param sParam String representation of parameter to parse
  199. * @param token IRCTokenised Array of the incomming line
  200. * @param clearOldModes Clear old modes before applying these modes (used by 221)
  201. */
  202. private void processUserMode(String sParam, String token[], String sModestr[], boolean clearOldModes) {
  203. long nCurrent = 0, nValue = 0;
  204. boolean bPositive = true;
  205. ClientInfo iClient;
  206. iClient = getClientInfo(token[2]);
  207. if (iClient == null) { return; }
  208. if (clearOldModes) {
  209. nCurrent = 0;
  210. } else {
  211. nCurrent = iClient.getUserMode();
  212. }
  213. for (int i = 0; i < sModestr[0].length(); ++i) {
  214. Character cMode = sModestr[0].charAt(i);
  215. if (cMode.equals("+".charAt(0))) { bPositive = true; }
  216. else if (cMode.equals("-".charAt(0))) { bPositive = false; }
  217. else if (cMode.equals(":".charAt(0))) { continue; }
  218. else {
  219. if (myParser.hUserModes.containsKey(cMode)) { nValue = myParser.hUserModes.get(cMode); }
  220. else {
  221. // Unknown mode
  222. callErrorInfo(new ParserError(ParserError.ERROR_WARNING, "Got unknown user mode "+cMode+" - Added", myParser.getLastLine()));
  223. myParser.hUserModes.put(cMode,myParser.nNextKeyUser);
  224. nValue = myParser.nNextKeyUser;
  225. myParser.nNextKeyUser = myParser.nNextKeyUser*2;
  226. }
  227. // Usermodes are always boolean
  228. callDebugInfo(IRCParser.DEBUG_INFO, "User Mode: %c [%d] {Positive: %b}",cMode, nValue, bPositive);
  229. if (bPositive) { nCurrent = nCurrent | nValue; }
  230. else { nCurrent = nCurrent ^ (nCurrent & nValue); }
  231. }
  232. }
  233. iClient.setUserMode(nCurrent);
  234. if (sParam.equals("221")) {
  235. callUserModeDiscovered(iClient, sModestr[0]);
  236. } else {
  237. callUserModeChanged(iClient, token[0], sModestr[0]);
  238. }
  239. }
  240. /**
  241. * Callback to all objects implementing the ChannelModeChanged Callback.
  242. *
  243. * @see IChannelModeChanged
  244. * @param cChannel Channel where modes were changed
  245. * @param cChannelClient Client chaning the modes (null if server)
  246. * @param sHost Host doing the mode changing (User host or server name)
  247. * @param sModes Exact String parsed
  248. * @return true if a method was called, false otherwise
  249. */
  250. protected boolean callChannelModeChanged(ChannelInfo cChannel, ChannelClientInfo cChannelClient, String sHost, String sModes) {
  251. return getCallbackManager().getCallbackType("OnChannelModeChanged").call(cChannel, cChannelClient, sHost, sModes);
  252. }
  253. /**
  254. * Callback to all objects implementing the ChannelUserModeChanged Callback.
  255. *
  256. * @see IChannelUserModeChanged
  257. * @param cChannel Channel where modes were changed
  258. * @param cChangedClient Client being changed
  259. * @param cSetByClient Client chaning the modes (null if server)
  260. * @param sMode String representing mode change (ie +o)
  261. * @param sHost Host doing the mode changing (User host or server name)
  262. * @return true if a method was called, false otherwise
  263. */
  264. protected boolean callChannelUserModeChanged(ChannelInfo cChannel, ChannelClientInfo cChangedClient, ChannelClientInfo cSetByClient, String sHost, String sMode) {
  265. return getCallbackManager().getCallbackType("OnChannelUserModeChanged").call(cChannel, cChangedClient, cSetByClient, sHost, sMode);
  266. }
  267. /**
  268. * Callback to all objects implementing the UserModeChanged Callback.
  269. *
  270. * @see IUserModeChanged
  271. * @param cClient Client that had the mode changed (almost always us)
  272. * @param sSetby Host that set the mode (us or servername)
  273. * @param sModes The modes set.
  274. * @return true if a method was called, false otherwise
  275. */
  276. protected boolean callUserModeChanged(ClientInfo cClient, String sSetby, String sModes) {
  277. return getCallbackManager().getCallbackType("OnUserModeChanged").call(cClient, sSetby, sModes);
  278. }
  279. /**
  280. * Callback to all objects implementing the UserModeDiscovered Callback.
  281. *
  282. * @see IUserModeDiscovered
  283. * @param cClient Client that had the mode changed (almost always us)
  284. * @param sModes The modes set.
  285. * @return true if a method was called, false otherwise
  286. */
  287. protected boolean callUserModeDiscovered(ClientInfo cClient, String sModes) {
  288. return getCallbackManager().getCallbackType("OnUserModeDiscovered").call(cClient, sModes);
  289. }
  290. /**
  291. * What does this IRCProcessor handle.
  292. *
  293. * @return String[] with the names of the tokens we handle.
  294. */
  295. @Override
  296. public String[] handles() {
  297. return new String[]{"MODE", "324", "221"};
  298. }
  299. /**
  300. * Create a new instance of the IRCProcessor Object.
  301. *
  302. * @param parser IRCParser That owns this IRCProcessor
  303. * @param manager ProcessingManager that is in charge of this IRCProcessor
  304. */
  305. protected ProcessMode (IRCParser parser, ProcessingManager manager) { super(parser, manager); }
  306. }