package net.rizon.bncbot;\r
\r
import java.io.BufferedInputStream;\r
+import java.io.BufferedReader;\r
import java.io.File;\r
import java.io.FileInputStream;\r
import java.io.FileNotFoundException;\r
import java.io.FileOutputStream;\r
import java.io.IOException;\r
import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
import java.io.OutputStream;\r
import java.io.PrintWriter;\r
import java.net.Socket;\r
import java.text.DateFormat;\r
import java.text.SimpleDateFormat;\r
import java.util.Date;\r
+import java.util.HashSet;\r
import java.util.Hashtable;\r
import java.util.Iterator;\r
import java.util.Properties;\r
-import java.util.Scanner;\r
import java.util.Timer;\r
import java.util.TimerTask;\r
import java.util.regex.Matcher;\r
private OutputStream netOutStream;\r
private PrintWriter netOut;\r
private InputStream netInStream;\r
- private Scanner netIn;\r
+ private BufferedReader netIn;\r
\r
private Timer bgTasks;\r
\r
private Hashtable<String, Boolean> identifiedLookup = new Hashtable<String, Boolean>();\r
private Hashtable<String, Boolean> operLookup = new Hashtable<String, Boolean>();\r
\r
+ private HashSet<String> serverPing = new HashSet<String>();\r
+\r
public UserDB database;\r
public BncManager bncManager;\r
public LookupService geoip;\r
\r
// Grab and load GeoIP database.\r
this.getGeoIP();\r
- this.geoip = new LookupService("GeoIP.dat", LookupService.GEOIP_INDEX_CACHE);\r
+ //this.geoip = new LookupService("GeoIP.dat", LookupService.GEOIP_INDEX_CACHE);\r
}\r
\r
// Entry point.\r
if (cmdconf == null) {\r
System.exit(1); // FAILURE.\r
} else {\r
- try {\r
- // Instantiate.\r
- BncBot.instance = new BncBot(cmdconf);\r
- DatabaseConnection.setProps(instance.config);\r
+ boolean allControllingBoolean = true;\r
+\r
+ while (allControllingBoolean)\r
+ try {\r
+ // Instantiate.\r
+ BncBot.instance = new BncBot(cmdconf);\r
+ DatabaseConnection.setProps(instance.config);\r
+\r
+ instance.stdPrintln("Initialization completed...spawning main loop thread.");\r
+\r
+ // Add shutdown handler.\r
+ Runtime.getRuntime().addShutdownHook(new Thread() {\r
+ public void run() {\r
+ try {\r
+ System.err.println("Caught signal...halting.");\r
+\r
+ BncBot.instance.running = false;\r
+ BncBot.instance.socket.close();\r
+ BncBot.instanceThread.interrupt();\r
+\r
+ BncBot.instance.cleanUp();\r
+ } catch (Exception e) {\r
+ System.err.println("Unable to interrupt main thread: " + e.getMessage());\r
+ }\r
+ }\r
+ });\r
\r
- instance.stdPrintln("Initialization completed...spawning main loop thread.");\r
+ // Set the thread running the loop to this thread...\r
+ BncBot.instanceThread = Thread.currentThread();\r
\r
- // Add shutdown handler.\r
- Runtime.getRuntime().addShutdownHook(new Thread() {\r
- public void run() {\r
- try {\r
- System.err.println("Caught signal...halting.");\r
+ // ...then run the loop.\r
+ BncBot.instance.botLoop();\r
\r
- BncBot.instance.running = false;\r
- BncBot.instance.netIn.close();\r
- BncBot.instanceThread.interrupt();\r
+ // If we returned then there's a mess. Clean this mess up.\r
+ BncBot.instance.cleanUp();\r
\r
- BncBot.instance.cleanUp();\r
- } catch (Exception e) {\r
- System.err.println("Unable to interrupt main thread: " + e.getMessage());\r
- }\r
+ if (!BncBot.instance.running) {\r
+ allControllingBoolean = false;\r
}\r
- });\r
-\r
- // Set the thread running the loop to this thread...\r
- BncBot.instanceThread = Thread.currentThread();\r
-\r
- // ...then run the loop.\r
- BncBot.instance.botLoop();\r
-\r
- // If we returned then there's a mess. Clean this mess up.\r
- BncBot.instance.cleanUp();\r
-\r
- // Exit cleanly.\r
- System.exit(0);\r
- } catch (FileNotFoundException fnfe) {\r
- System.err.println("Error loading config: " + fnfe.getMessage());\r
- fnfe.printStackTrace();\r
- } catch (IOException ioe) {\r
- System.err.println("Error loading config: " + ioe.getMessage());\r
- ioe.printStackTrace();\r
- } catch (RuntimeException re) {\r
- re.printStackTrace();\r
- }\r
+ \r
+ System.err.println("Main loop halted...waiting 5 seconds.");\r
+ Thread.sleep(5000);\r
+ } catch (FileNotFoundException fnfe) {\r
+ System.err.println("Error loading config: " + fnfe.getMessage());\r
+ fnfe.printStackTrace();\r
+ } catch (IOException ioe) {\r
+ System.err.println("Error loading config: " + ioe.getMessage());\r
+ ioe.printStackTrace();\r
+ } catch (RuntimeException re) {\r
+ re.printStackTrace();\r
+ } catch (InterruptedException ie) {\r
+ ie.printStackTrace();\r
+ }\r
+\r
+ System.exit(0);\r
}\r
} catch (JSAPException e) {\r
System.err.println("Error parsing command-line arguments: " + e.getMessage());\r
if (!retVal.success()) {\r
System.err.println();\r
\r
- for (@SuppressWarnings("rawtypes")\r
+ for (@SuppressWarnings("unchecked")\r
Iterator iter = retVal.getErrorMessageIterator(); iter.hasNext();) {\r
System.err.println("Error: " + iter.next());\r
}\r
bgTasks = new Timer();\r
bgTasks.scheduleAtFixedRate(new DatabaseDaemon(), 300000, 300000);\r
bgTasks.scheduleAtFixedRate(new UnsuspendTimer(), 10000, 300000);\r
- \r
+ bgTasks.schedule(new PingTimer(), 60000, 60000);\r
+\r
// Connect to BNC.\r
bncManager.init();\r
\r
// Set up main input loop.\r
this.netInStream = this.socket.getInputStream();\r
- this.netIn = new Scanner(this.netInStream);\r
+ this.netIn = new BufferedReader(new InputStreamReader(this.netInStream));\r
String line, words[], userlookup = null;\r
Pattern ccStripper = Pattern.compile("[\u0002\u001F\u000F]");\r
Pattern colorStripper = Pattern.compile("\u0003[0-9]{1,2}(,[0-9]{1,2})?");\r
\r
// TODO - Fix exiting.\r
// Right now, nextLine() must return before the program exits (i.e. shutdown via command)\r
- while (running && !Thread.interrupted() && netIn.hasNextLine()) {\r
- line = netIn.nextLine();\r
+ while (running && !Thread.interrupted() && this.socket.isConnected()) {\r
+ line = netIn.readLine();\r
+ if (line == null)\r
+ break;\r
+\r
line = ccStripper.matcher(line).replaceAll("");\r
line = colorStripper.matcher(line).replaceAll("");\r
line = line.replace("\u0003", "");\r
if (line.startsWith("PING ") && words.length > 1)\r
this.send("PONG " + words[1]);\r
\r
+ // Handle pong messages.\r
+ if (words.length == 4 && words[1].equals("PONG")) {\r
+ String id = words[3].substring(1);\r
+\r
+ if (serverPing.contains(id))\r
+ serverPing.remove(id);\r
+ }\r
+\r
// Look for end of MOTD.\r
else if (words[1].equals("376")) {\r
new Thread() {\r
}\r
send("JOIN " + config.getProperty("adminChannel"));\r
send("JOIN " + config.getProperty("whyChannel"));\r
- \r
+\r
send("MODE " + config.getProperty("nick") + " +Gp");\r
\r
// Do the autojoin stuff.\r
\r
// ===========================================\r
\r
+ private class PingTimer extends TimerTask {\r
+ @Override\r
+ public void run() {\r
+ if (serverPing.size() > 0) {\r
+ errPrintln("IRC server ping timeout. Attempting reconnect.");\r
+\r
+ try {\r
+ netIn.close();\r
+ netInStream.close();\r
+ } catch (Exception e) {\r
+ }\r
+ }\r
+\r
+ String pingId = "" + System.currentTimeMillis() / 1000;\r
+\r
+ serverPing.add(pingId);\r
+ send("PING " + pingId);\r
+ }\r
+ }\r
+\r
private class DatabaseDaemon extends TimerTask {\r
@Override\r
public void run() {\r
Connection conn = DatabaseConnection.getConnection();\r
PreparedStatement ps = conn.prepareStatement("SELECT * FROM `bncbot_suspension` WHERE `suspend_expiry` < CURRENT_TIMESTAMP;");\r
ResultSet rs = ps.executeQuery();\r
- while(rs.next()) {\r
+ while (rs.next()) {\r
UserEntry ue = database.findUser(rs.getInt("user_id"));\r
- if(ue == null)\r
+ if (ue == null)\r
throw new RuntimeException("Bug? No user entry found for suspension in database.");\r
- \r
+\r
privmsg(getAdminChannel(), getString("adminExpire", ue.getNick(), ue.getId(), ue.getActionReason()));\r
database.unsuspendUser(ue, "Automatic!Unsuspension@Timer");\r
bncManager.getUserServer(ue).unblockUser(ue.getNick());\r
import java.util.ArrayList;\r
import java.util.Date;\r
import java.util.Hashtable;\r
-import java.util.Scanner;\r
import java.util.Stack;\r
import java.util.Timer;\r
import java.util.TimerTask;\r
private Thread connectionThread;\r
\r
private Socket socket;\r
- private Scanner netIn;\r
+ private BufferedReader netIn;\r
private PrintWriter netOut;\r
\r
private ArrayList<String> hostsResults;\r
private ArrayList<Pair<String, String>> searchResults;\r
private Hashtable<String, Integer> statsResults;\r
- \r
+\r
private int adminReplyRequests;\r
private Stack<String> adminReplyStack;\r
\r
searchResults = new ArrayList<Pair<String, String>>();\r
statsResults = new Hashtable<String, Integer>();\r
lastSeen = new Hashtable<String, Date>();\r
- \r
+\r
adminReplyRequests = 0;\r
adminReplyStack = new Stack<String>();\r
\r
\r
public void disable() {\r
this.enabled = false;\r
- \r
+\r
this.failureCount = 0;\r
}\r
\r
privmsg("*admin", String.format("adduser %s %s 127.0.0.1 +6697", user, password));\r
\r
// Set options.\r
- privmsg("*admin", String.format("set BounceDCCs %s false", user));\r
- privmsg("*admin", String.format("set DenySetVHost %s true", user));\r
+ privmsg("*admin", String.format("set DCCBindHost %s false", user));\r
+ privmsg("*admin", String.format("set DenySetBindHost %s true", user));\r
privmsg("*admin", String.format("set DenyLoadMod %s true", user));\r
- privmsg("*admin", String.format("set VHost %s 127.0.0.1", user));\r
+ privmsg("*admin", String.format("set BindHost %s 127.0.0.1", user));\r
\r
// Load modules.\r
privmsg("*admin", String.format("LoadModule %s away ThisIsSecure123", user));\r
privmsg("*admin", String.format("LoadModule %s nickserv", user));\r
privmsg("*admin", String.format("LoadModule %s perform", user));\r
privmsg("*admin", String.format("LoadModule %s simple_away", user));\r
- \r
+\r
this.userCount++;\r
}\r
\r
public void changePass(String user, String pass) {\r
privmsg("*admin", String.format("set password %s %s", user, pass));\r
}\r
- \r
+\r
public String loadModule(String user, String modArgStr) {\r
adminReplyRequests++;\r
- \r
+\r
privmsg("*admin", String.format("LoadModule %s %s", user, modArgStr));\r
- \r
+\r
long end = System.currentTimeMillis() + 2000;\r
while (System.currentTimeMillis() < end && adminReplyStack.empty())\r
try {\r
Thread.sleep(50);\r
} catch (InterruptedException e) {\r
}\r
- \r
- if(adminReplyStack.empty()) return "nothing. Server timeout?";\r
- else return adminReplyStack.pop();\r
+\r
+ if (adminReplyStack.empty())\r
+ return "nothing. Server timeout?";\r
+ else\r
+ return adminReplyStack.pop();\r
}\r
- \r
+\r
public String unloadModule(String user, String mod) {\r
adminReplyRequests++;\r
- \r
+\r
privmsg("*admin", String.format("UnloadModule %s %s", user, mod));\r
- \r
+\r
long end = System.currentTimeMillis() + 2000;\r
while (System.currentTimeMillis() < end && adminReplyStack.empty())\r
try {\r
Thread.sleep(50);\r
} catch (InterruptedException e) {\r
}\r
- \r
- if(adminReplyStack.empty()) return "nothing. Server timeout?";\r
- else return adminReplyStack.pop();\r
+\r
+ if (adminReplyStack.empty())\r
+ return "nothing. Server timeout?";\r
+ else\r
+ return adminReplyStack.pop();\r
}\r
\r
public void refreshLastSeen() {\r
return (ArrayList<Pair<String, String>>) this.searchResults.clone();\r
}\r
}\r
- \r
+\r
public int getUserCount() {\r
return this.userCount;\r
}\r
\r
public int[] getStats() {\r
- synchronized(this.statsResults) {\r
+ synchronized (this.statsResults) {\r
this.statsResults = new Hashtable<String, Integer>();\r
}\r
- \r
- synchronized(this.statsResults) {\r
+\r
+ synchronized (this.statsResults) {\r
privmsg("*status", "userstats");\r
- \r
+\r
try {\r
this.statsResults.wait(3000);\r
} catch (Exception e) {\r
e.printStackTrace();\r
}\r
- \r
+\r
if (this.statsResults.size() == 0)\r
return null;\r
else\r
stdPrintln("Connecting to BNC server...");\r
\r
if (BncServer.this.ssl) {\r
- socket = TrustingSSLSocketFactory.getInstance().createSocket(BncServer.this.hostname, BncServer.this.port, 1024 * 128);\r
+ socket = TrustingSSLSocketFactory.getInstance().createSocket(BncServer.this.hostname, BncServer.this.port, 1024 * 512);\r
} else {\r
socket = SocketFactory.getDefault().createSocket();\r
- socket.setReceiveBufferSize(1024 * 128);\r
+ socket.setReceiveBufferSize(1024 * 512);\r
socket.connect(new InetSocketAddress(BncServer.this.hostname, BncServer.this.port));\r
}\r
\r
}, 300000);\r
\r
stdPrintln("BNC connection established.");\r
- \r
+\r
BncServer.this.privmsg("*status", "userstats");\r
\r
// TODO - Fix so that scan.nextLine() does not have to return for thread to exit.\r
- netIn = new Scanner(new BufferedReader(new InputStreamReader(socket.getInputStream()), 1024 * 128));\r
+ netIn = new BufferedReader(new InputStreamReader(socket.getInputStream()), 1024 * 512);\r
Pattern ccStripper = Pattern.compile("[\u0002\u001F\u000F]");\r
Pattern colorStripper = Pattern.compile("\u0003[0-9]{1,2}(,[0-9]{1,2})?");\r
Pattern hostsStartParse = Pattern.compile("^:\\*status!.*@.* PRIVMSG .* :\\| Host *\\|");\r
Pattern hostsParse = Pattern.compile("^:\\*status!.*@.* PRIVMSG .* :\\| ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) \\|");\r
Pattern adminReply = Pattern.compile("^:\\*admin!.*@.* PRIVMSG .* :(.*)$");\r
String line, words[];\r
- while (BncBot.get().running && netIn.hasNextLine() && !Thread.interrupted()) {\r
- line = netIn.nextLine();\r
+ while (BncBot.get().running && socket.isConnected() && !Thread.interrupted()) {\r
+ line = netIn.readLine();\r
+ if (line == null)\r
+ break;\r
+\r
line = ccStripper.matcher(line).replaceAll("");\r
line = colorStripper.matcher(line).replaceAll("");\r
line = line.replace("\u0003", "");\r
// Handle JSON stuff.\r
int jsonPos = line.indexOf("JSON:");\r
if (jsonPos > -1 || line.contains("userstats")) {\r
- //if (jsonPos > -1) {\r
+ //if (jsonPos > -1) {\r
try {\r
//JSONObject jo = new JSONObject(line.substring(jsonPos + 5));\r
JSONObject jo = new JSONObject(line.substring((jsonPos > -1 ? jsonPos + 5 : line.indexOf("{"))));\r
stdPrintln("Error while parsing JSON data from the BNC server: " + jsone.getMessage());\r
}\r
}\r
- \r
+\r
// Catch admin module output if we want it.\r
- if(adminReplyRequests > 0) {\r
+ if (adminReplyRequests > 0) {\r
Matcher adminReplyM = adminReply.matcher(line);\r
- \r
- if(adminReplyM.matches()) {\r
+\r
+ if (adminReplyM.matches()) {\r
adminReplyRequests--;\r
adminReplyStack.push(adminReplyM.group(1));\r
}\r
// Parse hosts output.\r
Matcher hostsStartM = hostsStartParse.matcher(line);\r
if (hostsStartM.matches()) {\r
- formatIn(netIn.nextLine()); // Skip the divider.\r
+ formatIn(netIn.readLine()); // Skip the divider.\r
\r
- while (netIn.hasNextLine()) {\r
- String line2 = netIn.nextLine();\r
+ String line2;\r
+ while ((line2 = netIn.readLine()) != null) {\r
formatIn(line2);\r
\r
// Match for a host and also the end.\r