The Code
Now that you know how to request message
details via NNTP, you can encapsulate this into a separate class that
is responsible for getting these details. This class will use its
count field to keep track of the most recent
message on the newsgroup, so each time it receives a response to the
XOVER command, it can tell if new messages have
arrived. The getNewSubjects method will then be
responsible for returning an array of these new messages.
Create the file
NntpConnection.java:
import java.util.*;
import java.net.*;
import java.io.*;
public class NntpConnection {
private BufferedReader reader;
private BufferedWriter writer;
private Socket socket;
private int count = -1;
public NntpConnection(String server) throws IOException {
socket = new Socket(server, 119);
reader = new BufferedReader(
new InputStreamReader(socket.getInputStream( )));
writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream( )));
reader.readLine( );
writeLine("MODE READER");
reader.readLine( );
}
public void writeLine(String line) throws IOException {
writer.write(line + "\r\n");
writer.flush( );
}
public String[] getNewSubjects(String group) throws IOException {
String[] results = new String[0];
writeLine("GROUP " + group);
String[] replyParts = reader.readLine( ).split("\\s+");
if (replyParts[0].equals("211")) {
int newCount = Integer.parseInt(replyParts[3]);
int oldCount = count;
if (oldCount == -1) {
oldCount = newCount;
count = oldCount;
}
else if (oldCount < newCount) {
writeLine("XOVER " + (oldCount + 1) + "-" + newCount);
if (reader.readLine( ).startsWith("224")) {
LinkedList lines = new LinkedList( );
String line = null;
while (!(line = reader.readLine( )).equals(".")) {
lines.add(line);
}
results = (String[]) lines.toArray(results);
count = newCount;
}
}
}
return results;
}
}
The IRC bot will be written so that it spawns
a new Thread to continually poll the newsgroup server. Performing
this checking in a new Thread means that the bot is able to carry on
doing essential tasks like responding to server pings. This new
Thread is able to send messages to the IRC channel, as the
sendMessage method in the PircBot class is
thread-safe.
The bot will also store the time it last
found new articles and made an announcement. If it has been less than
10 minutes since the last announcement, the bot will not bother
saying anything. This is useful when lots of messages are arriving on
a moderated newsgroup, as these tend to arrive in large clusters in a
short time.
Create the bot in a file called NntpBot.java:
import org.jibble.pircbot.*;
public class NntpBot extends PircBot {
private NntpConnection conn;
private long updateInterval = 10000; // 10 seconds.
private long lastTime = 0;
public NntpBot(String ircServer, final String ircChannel, final String
newsServer, final String newsGroup) throws Exception {
setName("NntpBot");
setVerbose(true);
setMessageDelay(5000);
conn = new NntpConnection(newsServer);
connect(ircServer);
joinChannel(ircChannel);
new Thread( ) {
public void run( ) {
boolean running = true;
while (running) {
try {
String[] lines = conn.getNewSubjects(newsGroup);
if (lines.length > 0) {
long now = System.currentTimeMillis( );
if (now - lastTime > 600000) { // 10 minutes.
sendMessage(ircChannel, "New articles posted
to " + newsGroup);
}
lastTime = now;
}
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
String[] lineParts = line.split("\\t");
String count = lineParts[0];
String subject = lineParts[1];
String from = lineParts[2];
String date = lineParts[3];
String id = lineParts[4];
// Ignore the other fields.
sendMessage(ircChannel, Colors.BOLD +
"[" + newsGroup + "] " + subject +
Colors.NORMAL + " " + from + " " + id);
}
try {
Thread.sleep(updateInterval);
}
catch (InterruptedException ie) {
// Do nothing.
}
}
catch (Exception e) {
System.out.println("Disconnected from news server.");
}
}
}
}.start( );
}
}
Note that the Thread is started from the NntpBot constructor and no
PircBot methods are overridden—there is no need for this bot to
respond to user input, unless you want to modify it to do so.
The main method now just has to construct an instance of the bot, as
the constructor also tells the bot to connect to the IRC server.
Create the main method in NntpBotMain.java:
public class NntpBotMain {
public static void main(String[] args) throws Exception {
NntpBot bot = new NntpBot("irc.freenode.net", "#irchacks",
"news.kent.ac.uk", "ukc.misc");
}
}
Note that the constructor arguments specify which IRC server to
connect to, which channel to join, which newsgroup server to connect
to, and which newsgroup to monitor. If you want, you could make the
bot more flexible by using the command-line arguments
(args) to specify the name of the server, channel,
and so forth.