Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

ProcessMode.java 17KB

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