package pl.shockah.shocky;
import java.io.File;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.*;
import org.pircbotx.*;
import org.pircbotx.hooks.events.*;
import pl.shockah.Reflection;
import pl.shockah.shocky.cmds.AuthorizationException;
import pl.shockah.shocky.cmds.Parameters;
import pl.shockah.shocky.cmds.Command;
import pl.shockah.shocky.cmds.Command.EType;
import pl.shockah.shocky.cmds.CommandCallback;
import pl.shockah.shocky.sql.SQL;
import pl.shockah.shocky.threads.SandboxSecurityManager;
public class Shocky extends ListenerAdapter {
private static final ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
private static final RunnableSave saver = new RunnableSave();
private static ScheduledFuture<?> futureSave = null;
private static MultiBotManager multiBot;
private static boolean isClosing = false;
private static SandboxSecurityManager secure;
public static void main(String[] args) {
System.setProperty("http.keepAlive", "false");
Data.load();
SQL.init();
multiBot = new ShockyMultiBotManager(Data.config.getString("main-botname"));
try {
multiBot.setName(Data.config.getString("main-botname"));
multiBot.setLogin(Data.config.getString("main-botname"));
multiBot.setAutoNickChange(true);
multiBot.setMessageDelay(Data.config.getInt("main-messagedelay"));
multiBot.setEncoding("UTF8");
multiBot.setVerbose(Data.config.getBoolean("main-verbose"));
multiBot.setListenerManager(new ShockyListenerManager<PircBotX>());
} catch (Exception e) {e.printStackTrace();}
multiBot.getListenerManager().addListener(new Shocky());
Module.loadNewModules();
Utils.initPasteServices();
System.out.println("--- Shocky, the IRC bot, up and running! ---");
System.out.println("--- type \"help\" to list all available commands ---");
try {
MultiChannel.join(Data.channels.toArray(new String[0]));
} catch (Exception e) {e.printStackTrace();}
int delay = Data.config.getInt("main-saveinterval");
if (delay <= 0)
delay = 300;
futureSave = timer.scheduleAtFixedRate(saver, delay, delay, TimeUnit.MINUTES);
new ThreadConsoleInput().start();
List<File> files = new ArrayList<File>();
for (Module module : Module.getModules())
{
File[] fileArray = module.getReadableFiles();
for (int i = 0; i < fileArray.length; ++i)
files.add(fileArray[i]);
}
secure = new SandboxSecurityManager(files.toArray(new File[0]));
System.setSecurityManager(secure);
}
public static void dataSave() {
saver.run();
}
public static long nextSave(TimeUnit unit) {
if (futureSave == null)
return -1;
return futureSave.getDelay(unit);
}
public static void die() {die(null);}
public static void die(String reason) {
timer.shutdown();
isClosing = true;
Set<PircBotX> bots = getBots();
for (Module module : Module.getModules(false)) for (PircBotX bot : bots) module.onDie(bot);
if (reason == null) {
multiBot.disconnectAll();
killMe();
return;
}
reason = reason.replace("\n"," | ");
for (PircBotX bot : bots) {
bot.quitServer(reason);
}
killMe();
}
private static void killMe() {
WebServer.stop();
while (true) {
for (PircBotX bot : multiBot.getBots()) if (bot.isConnected()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();}
continue;
}
break;
}
dataSave();
System.exit(0);
}
public static MultiBotManager getBotManager() {
return multiBot;
}
public static Set<PircBotX> getBots() {
return multiBot.getBots();
}
public static void send(PircBotX bot, Command.EType type, Command.EType msgChannel, Command.EType msgPrivate, Command.EType msgNotice, Command.EType msgConsole, Channel channel, User user, String message) {
Command.EType t = null;
switch (type) {
case Action:
case Channel: t = msgChannel; break;
case Private: t = msgPrivate; break;
case Notice: t = msgNotice; break;
case Console: t = msgConsole; break;
}
send(bot,t,channel,user,message);
}
public static void send(PircBotX bot, Command.EType type, Channel channel, User user, String message) {
switch (type) {
case Action: message = "\1ACTION" + message + '\1';
case Channel: sendChannel(bot,channel,message); break;
case Private: sendPrivate(bot,user,message); break;
case Notice: sendNotice(bot,user,message); break;
case Console: sendConsole(message); break;
}
}
public static void sendChannel(PircBotX bot, Channel channel, String message) {
for (String line : message.split("\n")) bot.sendMessage(channel,line);
}
public static void sendPrivate(PircBotX bot, User user, String message) {
for (String line : message.split("\n")) bot.sendMessage(user,line);
}
public static void sendNotice(PircBotX bot, User user, String message) {
for (String line : message.split("\n")) bot.sendNotice(user,line);
}
public static void sendConsole(String message) {
for (String line : message.split("\n")) System.out.println(Colors.removeFormattingAndColors(line));
}
public static void sendAction(PircBotX bot, Channel channel, String message) {
for (String line : message.split("\n")) bot.sendAction(channel,line);
}
public static void sendAction(PircBotX bot, User user, String message) {
for (String line : message.split("\n")) bot.sendAction(user,line);
}
public static User getUser(String user) {
if (user == null) return null;
for (PircBotX bot : getBots()) if (getUser(bot,user) != null) return getUser(bot,user);
return null;
}
public static User getUser(PircBotX bot, String user) {
if (user == null) return null;
User u = bot.getUser(user);
if (u.getHostmask().isEmpty()) return null;
return u;
}
public static String getLogin(User user) {
if (user == null) return null;
return Whois.getWhoisLogin(user);
}
public static PircBotX getBotForChannel(String channel) {
for (PircBotX bot : getBots()) for (Channel c : bot.getChannels()) if (c.getName().equals(channel)) return bot;
return null;
}
public static Channel getChannel(String channel) {
for (PircBotX bot : getBots()) for (Channel c : bot.getChannels()) if (c.getName().equals(channel)) return c;
return null;
}
public static boolean isChannel(String channame) {
for (int i = 0; i < MultiChannel.channelPrefixes.length(); i++) if (channame.charAt(0) == MultiChannel.channelPrefixes.charAt(i)) return true;
return false;
}
public static boolean isClosing() {
return isClosing;
}
@Override
public void onConnect(ConnectEvent<ShockyBot> event) throws Exception {
PircBotX bot = event.getBot();
bot.sendRawLine("CAP LS");
bot.sendRawLine("CAP REQ account-notify");
bot.sendRawLine("CAP END");
}
/*public void onNickChange(NickChangeEvent<PircBotX> event) {
Whois.renameWhois(event);
}*/
public void onQuit(QuitEvent<ShockyBot> event) {
if (event.getUser().getNick().equals(event.getBot().getNick())) return;
Whois.clearWhois(event.getUser());
}
public void onPart(PartEvent<ShockyBot> event) {
if (event.getUser().getNick().equals(event.getBot().getNick())) return;
Whois.clearWhois(event.getUser());
}
public void onMessage(MessageEvent<ShockyBot> event) {
if (Data.isBlacklisted(event.getUser())) return;
String message = event.getMessage().trim();
if (message.length()<=1) return;
String[] args = null;
Command cmd = null;
CommandCallback callback = null;
if (Data.forChannel(event.getChannel()).getString("main-cmdchar").contains(message.substring(0, 1))) {
callback = new CommandCallback();
callback.targetUser = event.getUser();
callback.targetChannel = event.getChannel();
args = message.split("\\s+", 2);
cmd = Command.getCommand(event.getBot(),event.getUser(),event.getChannel(),Command.EType.Channel,callback,args[0].substring(1));
}
if (cmd == null)
URLDispatcher.findURLs(event.getBot(), event.getChannel(), event.getUser(), message);
else if (callback != null) {
String s = (args.length == 1) ? "" : args[1];
Parameters params = new Parameters(event.getBot(),Command.EType.Channel,event.getChannel(),event.getUser(),s);
try {
cmd.doCommand(params,callback);
} catch (AuthorizationException e) {
sendNotice(event.getBot(),event.getUser(),e.getMessage());
return;
}
}
if (callback != null && callback.length()>0) {
if (callback.type == EType.Channel) {
callback.insert(0,": ");
callback.insert(0,event.getUser().getNick());
}
send(event.getBot(),callback.type==EType.Notice?EType.Notice:Command.EType.Channel,callback.targetChannel,callback.targetUser,callback.toString());
}
}
public void onPrivateMessage(PrivateMessageEvent<ShockyBot> event) {
if (Data.isBlacklisted(event.getUser())) return;
CommandCallback callback = new CommandCallback();
String[] args = event.getMessage().split("\\s+", 2);
Command cmd = Command.getCommand(event.getBot(),event.getUser(),null,Command.EType.Private,callback,args[0]);
if (cmd != null) {
String s = (args.length == 1) ? "" : args[1];
Parameters params = new Parameters(event.getBot(),Command.EType.Private,null,event.getUser(),s);
try {
cmd.doCommand(params,callback);
} catch (AuthorizationException e) {
sendPrivate(event.getBot(),event.getUser(),e.getMessage());
return;
}
} else {
URLDispatcher.findURLs(event.getBot(), null, event.getUser(), event.getMessage());
}
if (callback.length()>0)
send(event.getBot(),Command.EType.Private,null,event.getUser(),callback.toString());
}
public void onNotice(NoticeEvent<ShockyBot> event) {
if (event.getUser().getNick().equals("NickServ")) return;
if (Data.isBlacklisted(event.getUser())) return;
CommandCallback callback = new CommandCallback();
String[] args = event.getMessage().split("\\s+", 2);
Command cmd = Command.getCommand(event.getBot(),event.getUser(),null,Command.EType.Notice,callback,args[0]);
if (cmd != null) {
String s = (args.length == 1) ? "" : args[1];
Parameters params = new Parameters(event.getBot(),Command.EType.Notice,null,event.getUser(),s);
try {
cmd.doCommand(params,callback);
} catch (AuthorizationException e) {
sendNotice(event.getBot(),event.getUser(),e.getMessage());
return;
}
}
if (callback.length()>0)
send(event.getBot(),Command.EType.Notice,event.getChannel(),event.getUser(),callback.toString());
}
public void onKick(KickEvent<ShockyBot> event) {
if (event.getRecipient().equals(event.getBot().getUserBot())) try {
MultiChannel.lostChannel(event.getChannel().getName());
} catch (Exception e) {e.printStackTrace();}
}
@Override
public void onUserList(UserListEvent<ShockyBot> event) throws Exception {
PircBotX bot = event.getBot();
if (event.getChannel()==null || !event.getChannel().getName().startsWith("#")) {
return;
}
Set<User> users = event.getUsers();
if (users.isEmpty() || (users.size()==1 && users.contains(bot.getUserBot()))) {
try {
MultiChannel.lostChannel(event.getChannel().getName());
bot.partChannel(event.getChannel());
} catch (Exception e) {e.printStackTrace();}
}
}
@Override
public void onServerResponse(ServerResponseEvent<ShockyBot> event)
throws Exception {
switch(event.getCode()) {
case 5:
String[] s = event.getResponse().split(" :", 2);
serverInfo(event.getBot(),s[0].split(" "));
case ReplyConstants.ERR_CHANNELISFULL://Cannot join channel (+l)
case ReplyConstants.ERR_INVITEONLYCHAN://Cannot join channel (+i)
case ReplyConstants.ERR_BANNEDFROMCHAN://Cannot join channel (+b)
case ReplyConstants.ERR_BADCHANNELKEY://Cannot join channel (+k)
case 477://You need a registered nick to join that channel.
case 485://Cannot join channel (reason)
MultiChannel.lostChannel(event.getResponse().split(" ")[1]);
break;
}
}
private void serverInfo (PircBotX bot, String[] args) {
for (int i = 1; i < args.length; ++i) {
String s = args[i];
if (s.contentEquals("WHOX")) {
Method m = Reflection.getPrivateMethod(ServerInfo.class, "setWhoX", boolean.class);
Reflection.invokeMethod(m, bot.getServerInfo(), true);
}
}
}
@SuppressWarnings("unused")
@Override
public void onUnknown(UnknownEvent<ShockyBot> event) throws Exception {
ShockyBot bot = event.getBot();
String line = event.getLine();
String sourceNick = "";
String sourceLogin = "";
String sourceHostname = "";
StringTokenizer tokenizer = new StringTokenizer(line);
String senderInfo = tokenizer.nextToken();
String command = tokenizer.nextToken();
String target = null;
int exclamation = senderInfo.indexOf("!");
int at = senderInfo.indexOf("@");
if (senderInfo.startsWith(":")) {
if ((exclamation > 0) && (at > 0) && (exclamation < at)) {
sourceNick = senderInfo.substring(1, exclamation);
sourceLogin = senderInfo.substring(exclamation + 1, at);
sourceHostname = senderInfo.substring(at + 1);
}
}
command = command.toUpperCase();
if (sourceNick.startsWith(":"))
sourceNick = sourceNick.substring(1);
if (target == null)
target = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : "";
if (target.startsWith(":")) {
target = target.substring(1);
}
User source = bot.getUser(sourceNick);
Channel channel = (target.length() != 0) && (bot.getChannelPrefixes().indexOf(target.charAt(0)) >= 0) ? bot.getChannel(target) : null;
String message = line.contains(" :") ? line.substring(line.indexOf(" :") + 2) : "";
System.out.append(source != null ? source.toString() : "No Source").append(',').
append(channel != null ? channel.toString() : "No Channel").append(',').
append(command != null ? command.toString() : "No Command?").append(',').
append(target != null ? target.toString() : "No Target?").append(',').
append(message).println();
if (command.equals("ACCOUNT")) {
if (target.contentEquals("*"))
Whois.clearWhois(source);
else
Whois.setWhois(source, target);
}
}
}