Skip to content
This repository was archived by the owner on Nov 14, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 101 additions & 77 deletions src/fm/last/irccat/CatHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,85 +17,109 @@
*/
package fm.last.irccat;

import java.net.*;
import java.io.*;
import java.util.List;
import java.util.LinkedList;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;

// passes command to external program and returns results back to irc
class CatHandler extends Thread {

IRCCat bot;
Socket sock;
/**
* Utility class to handle IRC cat output text.
* 1) Handle parsing of initial line of the outgoing text
* which can contain metadata about the recipients of
* the message (channels or users) and whether its a /topic msg.
*
* 2) call the IRC cat bot the caller passes in, sending the text lines.
*/
class CatHandler implements Runnable {
public static final String TOPIC_TOKEN = "%TOPIC";
public static final String ALL_CHAN_TOKEN = "#*";

CatHandler(Socket s, IRCCat b){
sock = s;
bot = b;
}

public void run(){
try{
BufferedReader in = new BufferedReader(
new InputStreamReader(
sock.getInputStream(), "UTF-8"));
String inputLine = new String();
String recipients[] = null;
boolean all = false;
boolean topic = false;
int i = 0;
while ((inputLine = in.readLine()) != null) {
if(i++==0){
String[] words = inputLine.split(" ");
if(words[0].equals("%TOPIC")) {
topic = true;
inputLine = inputLine.substring(7);
String[] newwords = new String[words.length-1];
System.arraycopy(words, 1, newwords, 0, newwords.length);
words = newwords;
}
if(words[0].equals("#*")){
// send to all channels
all = true;
inputLine = inputLine.substring(3);
}else
if(words[0].startsWith("#") || words[0].startsWith("@")){
String addressees[] = words[0].split(",");
for(int j=0; j<addressees.length; ++j){
if(addressees[j].startsWith("@")){
// to a user, strip the @ for
// sendMessage()..
addressees[j] = addressees[j].substring(1);
}
}
recipients = addressees;
inputLine = inputLine.substring(words[0].length()+1);
}else{
// nothing specified. use default channel from
// config.
recipients = new String[1];
recipients[0] = bot.getDefaultChannel() ;
}
}

// now send it to the recipients:
if(all) {
if(topic) {
bot.catTopicToAll(inputLine);
}else {
bot.catStuffToAll(inputLine);
}
}else {
if(topic) {
bot.catTopic(inputLine, recipients);
}else {
bot.catStuff(inputLine, recipients);
}
}
}
in.close();
//System.out.println("Handler finished.");
}
catch(Exception e){ e.printStackTrace(); }
}
private final List<String> lines = new LinkedList<String>();
private final IRCCat bot;
private final Socket socket;

}
private boolean isBroadcastMessage;
private boolean isTopicMessage;
private String[] recipients = new String[0];

public CatHandler(Socket s, IRCCat b) {
this.socket = s;
this.bot = b;
}

@Override
public void run() {
try {
getLinesFromStream();
checkForTopicMessage();
populateRecipientList();
sendLines();
//System.out.println("Handler finished.");
} catch(Exception e) {
e.printStackTrace();
}
}

private void sendLines() {
for ( String line : lines ) {
if ( isBroadcastMessage && isTopicMessage ) {
bot.catTopicToAll(line);
} else if ( isTopicMessage ) {
bot.catTopic(line, recipients);
} else if ( isBroadcastMessage ) {
bot.catStuffToAll(line);
} else { // neither topic or broadcast
bot.catStuff(line, recipients);
}
}
}

private void getLinesFromStream() throws Exception {
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), "UTF-8")
);
String line;
while ( null != (line = in.readLine()) ) {
lines.add( line.trim() );
}
} finally {
if ( null != socket ) {
socket.close();
}
}
}

private void checkForTopicMessage() {
if ( lines.get(0).startsWith(TOPIC_TOKEN) ) {
isTopicMessage = true;
lines.set( 0, lines.get(0).substring(7) );
}
}

private void populateRecipientList() {
String firstLine = lines.get(0);
if( firstLine.startsWith(ALL_CHAN_TOKEN) ) {
isBroadcastMessage = true;
lines.set( 0, firstLine.substring(3) );
} else if ( firstLine.startsWith("#") || firstLine.startsWith("@") ) {
int length = 0, index = 0;
recipients = firstLine.split(",");
while ( index < recipients.length ) {
length += recipients[index].length(); // track size of text block
recipients[index] = recipients[index].trim();
if ( recipients[index].startsWith("@") ) {
// to a user, strip the @ for sendMessage()
recipients[index] = recipients[index].substring(1);
}
++index;
}
lines.set( 0, lines.get(0).substring(length + index) );
} else {
recipients = new String[1];
recipients[0] = bot.getDefaultChannel();
}
}
}

24 changes: 17 additions & 7 deletions src/fm/last/irccat/IRCCat.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,27 @@
import org.jibble.pircbot.*;
import java.net.*;
import java.io.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

public class IRCCat extends PircBot {

// we could use this for situations where an ordered sequence of tasks should
// be run on a single worker thread in serial order of task submission.
//static final ExecutorService threadPoolManager = Executors.newSingleThreadedExecutor();
// a thread pool manager to handle our thread lifecycles
static final ExecutorService threadPoolManager = Executors.newCachedThreadPool();

private String nick;
private String cmdScript;
private String defaultChannel = null;
private int maxCmdResponseLines = 26;
private XMLConfiguration config;


public static void main(String[] args) throws Exception {
try {
if (args.length == 0) {
Expand Down Expand Up @@ -79,16 +88,19 @@ public static void main(String[] args) throws Exception {
Socket clientSocket = serverSocket.accept();
// System.out.println("Connection on catport from: "
// + clientSocket.getInetAddress().toString());
CatHandler handler = new CatHandler(clientSocket, bot);
handler.start();
threadPoolManager.submit( new CatHandler(clientSocket, bot) );
} catch (Exception e) {
e.printStackTrace();
}
}

} catch (Exception e) {
e.printStackTrace();
}
} finally {
if (null != threadPoolManager) {
threadPoolManager.shutdown();
}
}

}

Expand All @@ -104,7 +116,6 @@ public IRCCat(XMLConfiguration c) throws Exception {
setFinger(config.getString("bot.finger",
"IRCCat - a development support bot, used by Last.fm"));


try {
// connect to server
int tries =0 ;
Expand Down Expand Up @@ -310,9 +321,8 @@ public void handleMessage(String channel_, String sender, String message) {

// now "cmd" contains the message, minus the address prefix (eg: ?)
// hand off msg to thread that executes shell script
System.out.println("Scripter: ["+respondTo+"] <"+sender+"> "+message);
Thread t = new Scripter(sender, channel_, respondTo, cmd, this);
t.run();
System.out.println("Scripter: ["+respondTo+"] <"+sender+"> "+message);
threadPoolManager.submit( new Scripter(sender, channel_, respondTo, cmd, this) );
}

/*
Expand Down
78 changes: 46 additions & 32 deletions src/fm/last/irccat/Scripter.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,55 @@
*/
package fm.last.irccat;

import java.io.*;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.util.List;
import java.util.LinkedList;

// hands off cmd to shell script and returns stdout to the requester
class Scripter extends Thread {
IRCCat bot;
String nick, channel, returnName, cmd;

Scripter(String nk, String ch, String r, String c, IRCCat b){
nick = nk;
channel = ch;
cmd = c;
returnName = r;
bot = b;
}
class Scripter implements Runnable {
private final IRCCat bot;
private final String nick, channel, returnName, cmd;

public Scripter( String nk, String ch, String r, String c, IRCCat b ) {
this.nick = nk;
this.channel = ch;
this.cmd = c;
this.returnName = r;
this.bot = b;
}

private Process startProcess() throws Exception {
String message = nick + " " + channel + " " + returnName + " " + " " + cmd;
return new ProcessBuilder(bot.getCmdScript(), message).start();
}

public void run(){
try{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(new String[]{bot.getCmdScript() ,nick + " " + channel + " " + returnName+" "+cmd});
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String line;
int i=0;
while ((line = br.readLine()) != null) {
bot.sendMsg(returnName, line);
if(++i==bot.getCmdMaxResponseLines()){
bot.sendMsg(returnName, "<truncated, too many lines>");
break;
}
}
}catch(Exception e){
e.printStackTrace();
}

@Override
public void run() {
BufferedReader reader = null;
Process process = null;
try {
process = startProcess();
reader = new BufferedReader( new InputStreamReader(process.getInputStream(), "UTF-8") );
String line;
int lineCount = 0;
while ( (line = reader.readLine()) != null) {
bot.sendMsg(returnName, line);
if ( ++lineCount == bot.getCmdMaxResponseLines() ) {
bot.sendMsg(returnName, "<truncated, too many lines>");
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if ( null != reader ) {
try { reader.close(); } catch (Exception ignored) { }
}
if ( null != process ) {
try { process.destroy(); } catch (Exception ignored) { }
}
}
}
}