package InnaIrcBot.Commanders; import InnaIrcBot.ProvidersConsumers.StreamProvider; import InnaIrcBot.config.ConfigurationChannel; import InnaIrcBot.config.ConfigurationManager; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.BlockingQueue; import java.util.regex.Pattern; //TODO: FLOOD public class ChanelCommander implements Runnable { private final BlockingQueue streamQueue; private final String server; private final String channel; //TODO: add timers private HashMap joinMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw private HashMap msgMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw private HashMap nickMap; // Mask(Pattern) ->, Action | Where Action[0] could be: raw private boolean joinFloodTrackNeed = false; private JoinFloodHandler jfh; private boolean joinCloneTrackNeed = false; // todo:fix private JoinCloneHandler jch; public ChanelCommander(BlockingQueue stream, String serverName, String channel) throws Exception{ this.streamQueue = stream; this.server = serverName; this.channel = channel; readConfing(); } @Override public void run() { System.out.println("["+LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))+"] ChanelCommander thread " +server+":"+this.channel +" started");// TODO:REMOVE DEBUG try { while (true) { String data = streamQueue.take(); String[] dataStrings = data.split(" ",3); switch (dataStrings[0]) { case "NICK": nickCame(dataStrings[2]+dataStrings[1].replaceAll("^.+?!","!")); break; // todo: need to track join flood case "JOIN": if (joinFloodTrackNeed) jfh.track(simplifyNick(dataStrings[1])); if (joinCloneTrackNeed) jch.track(dataStrings[1]); joinCame(dataStrings[1]); break; case "PRIVMSG": privmsgCame(dataStrings[1], dataStrings[2]); break; /* case "PART": // todo: need to track join flood? Fuck that. Track using JOIN case "QUIT": // todo: need this? case "TOPIC": // todo: need this? case "MODE": // todo: need this? case "KICK": // todo: need this? */ default: break; } } } catch (InterruptedException ie){ System.out.println("Internal issue: thread ChanelCommander->run() interrupted.\n\t"); // TODO: reconnect } System.out.println("Thread for ChanelCommander ended"); // TODO:REMOVE DEBUG } // Do we need old nick? private void nickCame(String newNick){ came(nickMap, newNick, newNick); } private void joinCame(String who){ came(joinMap, who, who); } private void privmsgCame(String who, String what){ if (what.indexOf(":")+1 < what.length()){ what = what.substring(what.indexOf(":")+1); came(msgMap, what, who); } } private void came(HashMap map, String arg1, String arg2){ for (String pattern : map.keySet()) if (Pattern.matches(pattern, arg1)){ // NOTE: validation based on new nick //TODO: parse here String[] cmdOrMsg = map.get(pattern); StringBuilder whatToSendStringBuilder; ArrayList whatToSendList; for (int i = 0; i(); for (i++; (i < cmdOrMsg.length) && !(cmdOrMsg[i].startsWith("\\")); i++) whatToSendList.add(cmdOrMsg[i]); msgAction(whatToSendList.toArray(new String[0]), arg2, false); break; case "\\privmsg": whatToSendList = new ArrayList<>(); for (i++; (i < cmdOrMsg.length) && !(cmdOrMsg[i].startsWith("\\")); i++) whatToSendList.add(cmdOrMsg[i]); msgAction(whatToSendList.toArray(new String[0]), arg2, true); break; case "\\ban": banAction(arg2); i++; break; case "\\voice": voiceAction(arg2); i++; break; case "\\kick": whatToSendList = new ArrayList<>(); for (i++; (i < cmdOrMsg.length) && !(cmdOrMsg[i].startsWith("\\")); i++) whatToSendList.add(cmdOrMsg[i]); kickAction(whatToSendList.toArray(new String[0]), arg2); break; case "\\kickban": whatToSendList = new ArrayList<>(); for (i++; (i < cmdOrMsg.length) && !(cmdOrMsg[i].startsWith("\\")); i++) whatToSendList.add(cmdOrMsg[i]); banAction(arg2); kickAction(whatToSendList.toArray(new String[0]), arg2); break; case "\\raw": whatToSendStringBuilder = new StringBuilder(); for (i++; (i < cmdOrMsg.length) && !(cmdOrMsg[i].startsWith("\\")); i++) whatToSendStringBuilder.append(cmdOrMsg[i]); StreamProvider.writeToStream(server, whatToSendStringBuilder.toString()); //TODO break; //todo: add script case "\\whois": // result will be noted in 'system' log whoisAction(arg2); i++; break; case "\\cclientinfo": // NOTE: All this handled by CTCPHelper instance case "\\cfinger": // C - publish request result to chan case "\\cping": case "\\csource": case "\\ctime": case "\\cuserinfo": case "\\cversion": case "\\pclientinfo": // P - reply to privmsg case "\\pfinger": case "\\pping": case "\\psource": case "\\ptime": case "\\puserinfo": case "\\pversion": String CTCPType = cmdOrMsg[i]; String objectRegexp = null; whatToSendStringBuilder = new StringBuilder(); for (i++; (i < cmdOrMsg.length) && !(cmdOrMsg[i].startsWith("\\")); i++){ if (objectRegexp == null && !cmdOrMsg[i].trim().isEmpty()) objectRegexp = cmdOrMsg[i].trim(); else whatToSendStringBuilder.append(cmdOrMsg[i]); } if (objectRegexp != null) { String objectToCtcp = arg1.trim().replaceAll(objectRegexp, ""); // note: trim() ? if (!objectToCtcp.isEmpty()){ if (CTCPType.startsWith("\\c")) CTCPHelper.getInstance().registerRequest(server, channel, CTCPType.substring(2).toUpperCase(), objectToCtcp, whatToSendStringBuilder.toString()); else CTCPHelper.getInstance().registerRequest(server, simplifyNick(arg2), CTCPType.substring(2).toUpperCase(), objectToCtcp, whatToSendStringBuilder.toString()); } } break; default: i++; } } } } ///////// ///////// private void whoisAction(String who){ // TODO: maybe we have to extend functionality to reuse received information. StreamProvider.writeToStream(server, "WHOIS "+simplifyNick(who)); } private void msgAction(String[] messages, String who, boolean sendToPrivate){ StringBuilder executiveStr = new StringBuilder(); executiveStr.append("PRIVMSG "); if(sendToPrivate) { executiveStr.append(simplifyNick(who)); executiveStr.append(" :"); } else { executiveStr.append(channel); executiveStr.append(" :"); executiveStr.append(simplifyNick(who)); executiveStr.append(": "); } for (String message : messages) { if (!message.startsWith("\\")) executiveStr.append(message); else if (message.equals("\\time")) // TODO: remove this shit executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))); } //System.out.println(executiveStr.toString()); //TODO: debug StreamProvider.writeToStream(server, executiveStr.toString()); } private void banAction(String whom){ StreamProvider.writeToStream(server, "MODE "+ channel +" +b "+simplifyNick(whom)+"*!*@*"); StreamProvider.writeToStream(server, "MODE "+ channel +" +b "+"*!*@"+whom.replaceAll("^.+@","")); } private void voiceAction(String whom){ StreamProvider.writeToStream(server, "MODE "+ channel +" +v "+simplifyNick(whom)); } private void kickAction(String[] messages, String whom){ StringBuilder executiveStr = new StringBuilder(); executiveStr.append("KICK "); executiveStr.append(channel); executiveStr.append(" "); executiveStr.append(simplifyNick(whom)); executiveStr.append(" :"); for (String message : messages) { if (!message.startsWith("\\")) executiveStr.append(message); else if (message.equals("\\time")) executiveStr.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))); } StreamProvider.writeToStream(server, executiveStr.toString()); } private String simplifyNick(String nick){ return nick.replaceAll("!.*$",""); } private void readConfing() throws Exception{ ConfigurationChannel configChannel = ConfigurationManager.getConfiguration(server).getChannelConfig(channel); joinMap = configChannel.getJoinMap(); msgMap = configChannel.getMsgMap(); nickMap = configChannel.getNickMap(); if (configChannel.isJoinFloodControl()) { jfh = new JoinFloodHandler(configChannel.getJoinFloodControlEvents(), configChannel.getJoinFloodControlTimeframe(), server, channel); joinFloodTrackNeed = true; } if (configChannel.isJoinCloneControl()) { jch = new JoinCloneHandler(configChannel.getJoinCloneControlPattern(), configChannel.getJoinCloneControlTimeframe(), server, channel); // TODO: REMOVE joinCloneTrackNeed = true; } } }