package heufybot.modules; import heufybot.core.HeufyBot; import heufybot.core.IRCChannel; import heufybot.core.IRCUser; import heufybot.core.events.EventListenerAdapter; import heufybot.core.events.types.ActionEvent; import heufybot.core.events.types.MessageEvent; import heufybot.core.events.types.PMActionEvent; import heufybot.core.events.types.PMMessageEvent; import heufybot.modules.Module.TriggerType; import heufybot.utils.StringUtils; import java.io.File; import java.lang.reflect.Constructor; import java.net.URL; import java.net.URLClassLoader; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class ModuleInterface extends EventListenerAdapter { private ArrayList<Module> modules; private List<String> ignores; private HeufyBot bot; private String server; public ModuleInterface(HeufyBot bot, String server) { this.modules = new ArrayList<Module>(); this.setIgnores(new ArrayList<String>()); this.bot = bot; this.server = server; } public SimpleEntry<ModuleLoaderResponse, String> loadModule(String moduleName) { try { for (Module module : this.modules) { String toLoad = "heufybot.modules." + moduleName; if (module.getClass().getName().toLowerCase().equals(toLoad.toLowerCase())) { return new SimpleEntry<ModuleLoaderResponse, String>( ModuleLoaderResponse.AlreadyLoaded, ""); } } File[] folder = new File("modules").listFiles(); for (File element : folder) { if (element.getName().equalsIgnoreCase(moduleName + ".jar")) { String foundFileName = element.getName(); moduleName = foundFileName.substring(0, foundFileName.indexOf(".jar")); URL[] urls = { element.toURI().toURL() }; ClassLoader loader = URLClassLoader.newInstance(urls, this.getClass() .getClassLoader()); Class<?> moduleClass = Class.forName("heufybot.modules." + moduleName, true, loader); Class<?>[] argTypes = { String.class }; Constructor<?> ctor = moduleClass.getDeclaredConstructor(argTypes); Module module = (Module) ctor.newInstance(this.server); if (module.getAPIVersion() != HeufyBot.MODULE_API_VERSION) { return new SimpleEntry<ModuleLoaderResponse, String>( ModuleLoaderResponse.APIVersionDoesNotMatch, module.getAPIVersion() + " " + HeufyBot.MODULE_API_VERSION); } this.modules.add(module); module.onLoad(); return new SimpleEntry<ModuleLoaderResponse, String>( ModuleLoaderResponse.Success, moduleName); } } return new SimpleEntry<ModuleLoaderResponse, String>(ModuleLoaderResponse.DoesNotExist, ""); } catch (Exception e) { return new SimpleEntry<ModuleLoaderResponse, String>(ModuleLoaderResponse.DoesNotExist, ""); } } public SimpleEntry<ModuleLoaderResponse, String> unloadModule(String moduleName) { for (Iterator<Module> iter = this.modules.iterator(); iter.hasNext(); ) { Module module = iter.next(); if (module.toString().equalsIgnoreCase(moduleName)) { module.onUnload(); iter.remove(); return new SimpleEntry<ModuleLoaderResponse, String>(ModuleLoaderResponse.Success, module.toString()); } } return new SimpleEntry<ModuleLoaderResponse, String>(ModuleLoaderResponse.DoesNotExist, ""); } @Override public void onPMMessage(PMMessageEvent event) { this.handleMessage(event.getServerName(), event.getUser(), null, event.getMessage(), TriggerType.Message); } @Override public void onPMAction(PMActionEvent event) { this.handleMessage(event.getServerName(), event.getUser(), null, event.getMessage(), TriggerType.Action); } @Override public void onMessage(MessageEvent event) { this.handleMessage(event.getServerName(), event.getUser(), event.getChannel(), event.getMessage(), TriggerType.Message); } @Override public void onAction(ActionEvent event) { this.handleMessage(event.getServerName(), event.getUser(), event.getChannel(), event.getMessage(), TriggerType.Action); } private void handleMessage(final String serverName, final IRCUser user, final IRCChannel channel, final String message, TriggerType triggerType) { for (String ignore : this.ignores) { if (user.getFullHost().matches(ignore)) { return; } } Module[] listCopy = new Module[this.modules.size()]; listCopy = this.modules.toArray(listCopy); for (final Module module : listCopy) { if ((message.toLowerCase().matches(module.getTrigger()) || module .getTriggerOnEveryMessage()) && Arrays.asList(module.getTriggerTypes()).contains(triggerType)) { final String target; if (channel == null) { target = user.getNickname(); } else { target = channel.getName(); } if (this.isAuthorized(module, user)) { if (module.getTriggerOnEveryMessage()) { module.processEvent(target, message, user.getNickname(), StringUtils.parseStringtoList(message, " ")); } else if (Thread.activeCount() < this.bot.getServers().size() + 5) { // Thread limit might have to become a setting in the // future Thread thread = new Thread() { @Override public void run() { module.processEvent(target, message, user.getNickname(), StringUtils.parseStringtoList(message, " ")); } }; thread.start(); } else { this.bot.getServer(serverName).cmdPRIVMSG(target, "Calm down, " + user.getNickname() + "! Can't you see I'm busy?"); } } else { this.bot.getServer(serverName).cmdPRIVMSG( target, "You are not authorized to use the \"" + module.toString() + "\" module!"); } } } } public boolean isAuthorized(Module module, IRCUser user) { if (module.authType == Module.AuthType.Anyone) { return true; } else { ArrayList<String> botAdmins = this.bot.getServer(this.server).getConfig() .getSettingWithDefault("botAdmins", new ArrayList<String>()); for (String admin : botAdmins) { String regex = "^" + StringUtils.escapeRegex(admin).replaceAll("\\*", ".*") .replaceAll("\\?", ".").replaceAll("\\(", "(") .replaceAll("\\)", ")").replaceAll(",", "|").replaceAll("/", "|") + "$"; if (user.getFullHost().matches(regex)) { return true; } } } return false; } public boolean isModuleLoaded(String moduleName) { for (Module module : this.modules) { if (module.toString().equalsIgnoreCase(moduleName)) { return true; } } return false; } public String getModuleHelp(String message) { for (Module module : this.modules) { String moduleTrigger = module.getTrigger(); String commandPrefix = this.bot.getServer(this.server).getConfig() .getSettingWithDefault("commandPrefix", "~"); if (moduleTrigger.startsWith("^" + commandPrefix)) { moduleTrigger = moduleTrigger.substring(moduleTrigger.indexOf(commandPrefix) + commandPrefix.length()); } if (module.toString().equalsIgnoreCase(message) || message.toLowerCase().matches(moduleTrigger)) { return module.getHelp(message.toLowerCase()); } } return null; } public ArrayList<Module> getModuleList() { return this.modules; } public List<String> getIgnores() { return this.ignores; } public void setIgnores(List<String> ignores) { this.ignores = ignores; } public enum ModuleLoaderResponse { Success, DoesNotExist, AlreadyLoaded, APIVersionDoesNotMatch } }