Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

ProcessMode.java 17KB

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