diff --git a/src/org/jibble/pircbot/Colors.java b/src/org/jibble/pircbot/Colors.java index 29286a1..b8f7a60 100644 --- a/src/org/jibble/pircbot/Colors.java +++ b/src/org/jibble/pircbot/Colors.java @@ -1,293 +1,293 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -/** - * The Colors class provides several static fields and methods that you may - * find useful when writing an IRC Bot. - *

- * This class contains constants that are useful for formatting lines - * sent to IRC servers. These constants allow you to apply various - * formatting to the lines, such as colours, boldness, underlining - * and reverse text. - *

- * The class contains static methods to remove colours and formatting - * from lines of IRC text. - *

- * Here are some examples of how to use the contants from within a - * class that extends PircBot and imports org.jibble.pircbot.*; - * - *

 sendMessage("#cs", Colors.BOLD + "A bold hello!");
- *     A bold hello!
- * sendMessage("#cs", Colors.RED + "Red" + Colors.NORMAL + " text");
- *     Red text
- * sendMessage("#cs", Colors.BOLD + Colors.RED + "Bold and red");
- *     Bold and red
- * - * Please note that some IRC channels may be configured to reject any - * messages that use colours. Also note that older IRC clients may be - * unable to correctly display lines that contain colours and other - * control characters. - *

- * Note that this class name has been spelt in the American style in - * order to remain consistent with the rest of the Java API. - * - * - * @since 0.9.12 - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class Colors { - - - /** - * Removes all previously applied color and formatting attributes. - */ - public static final String NORMAL = "\u000f"; - - - /** - * Bold text. - */ - public static final String BOLD = "\u0002"; - - - /** - * Underlined text. - */ - public static final String UNDERLINE = "\u001f"; - - - /** - * Reversed text (may be rendered as italic text in some clients). - */ - public static final String REVERSE = "\u0016"; - - - /** - * White coloured text. - */ - public static final String WHITE = "\u000300"; - - - /** - * Black coloured text. - */ - public static final String BLACK = "\u000301"; - - - /** - * Dark blue coloured text. - */ - public static final String DARK_BLUE = "\u000302"; - - - /** - * Dark green coloured text. - */ - public static final String DARK_GREEN = "\u000303"; - - - /** - * Red coloured text. - */ - public static final String RED = "\u000304"; - - - /** - * Brown coloured text. - */ - public static final String BROWN = "\u000305"; - - - /** - * Purple coloured text. - */ - public static final String PURPLE = "\u000306"; - - - /** - * Olive coloured text. - */ - public static final String OLIVE = "\u000307"; - - - /** - * Yellow coloured text. - */ - public static final String YELLOW = "\u000308"; - - - /** - * Green coloured text. - */ - public static final String GREEN = "\u000309"; - - - /** - * Teal coloured text. - */ - public static final String TEAL = "\u000310"; - - - /** - * Cyan coloured text. - */ - public static final String CYAN = "\u000311"; - - - /** - * Blue coloured text. - */ - public static final String BLUE = "\u000312"; - - - /** - * Magenta coloured text. - */ - public static final String MAGENTA = "\u000313"; - - - /** - * Dark gray coloured text. - */ - public static final String DARK_GRAY = "\u000314"; - - - /** - * Light gray coloured text. - */ - public static final String LIGHT_GRAY = "\u000315"; - - - /** - * This class should not be constructed. - */ - private Colors() { - - } - - - /** - * Removes all colours from a line of IRC text. - * - * @since PircBot 1.2.0 - * - * @param line the input text. - * - * @return the same text, but with all colours removed. - */ - public static String removeColors(String line) { - int length = line.length(); - StringBuffer buffer = new StringBuffer(); - int i = 0; - while (i < length) { - char ch = line.charAt(i); - if (ch == '\u0003') { - i++; - // Skip "x" or "xy" (foreground color). - if (i < length) { - ch = line.charAt(i); - if (Character.isDigit(ch)) { - i++; - if (i < length) { - ch = line.charAt(i); - if (Character.isDigit(ch)) { - i++; - } - } - // Now skip ",x" or ",xy" (background color). - if (i < length) { - ch = line.charAt(i); - if (ch == ',') { - i++; - if (i < length) { - ch = line.charAt(i); - if (Character.isDigit(ch)) { - i++; - if (i < length) { - ch = line.charAt(i); - if (Character.isDigit(ch)) { - i++; - } - } - } - else { - // Keep the comma. - i--; - } - } - else { - // Keep the comma. - i--; - } - } - } - } - } - } - else if (ch == '\u000f') { - i++; - } - else { - buffer.append(ch); - i++; - } - } - return buffer.toString(); - } - - - /** - * Remove formatting from a line of IRC text. - * - * @since PircBot 1.2.0 - * - * @param line the input text. - * - * @return the same text, but without any bold, underlining, reverse, etc. - */ - public static String removeFormatting(String line) { - int length = line.length(); - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - char ch = line.charAt(i); - if (ch == '\u000f' || ch == '\u0002' || ch == '\u001f' || ch == '\u0016') { - // Don't add this character. - } - else { - buffer.append(ch); - } - } - return buffer.toString(); - } - - - /** - * Removes all formatting and colours from a line of IRC text. - * - * @since PircBot 1.2.0 - * - * @param line the input text. - * - * @return the same text, but without formatting and colour characters. - * - */ - public static String removeFormattingAndColors(String line) { - return removeFormatting(removeColors(line)); - } - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +/** + * The Colors class provides several static fields and methods that you may + * find useful when writing an IRC Bot. + *

+ * This class contains constants that are useful for formatting lines + * sent to IRC servers. These constants allow you to apply various + * formatting to the lines, such as colours, boldness, underlining + * and reverse text. + *

+ * The class contains static methods to remove colours and formatting + * from lines of IRC text. + *

+ * Here are some examples of how to use the contants from within a + * class that extends PircBot and imports org.jibble.pircbot.*; + * + *

 sendMessage("#cs", Colors.BOLD + "A bold hello!");
+ *     A bold hello!
+ * sendMessage("#cs", Colors.RED + "Red" + Colors.NORMAL + " text");
+ *     Red text
+ * sendMessage("#cs", Colors.BOLD + Colors.RED + "Bold and red");
+ *     Bold and red
+ * + * Please note that some IRC channels may be configured to reject any + * messages that use colours. Also note that older IRC clients may be + * unable to correctly display lines that contain colours and other + * control characters. + *

+ * Note that this class name has been spelt in the American style in + * order to remain consistent with the rest of the Java API. + * + * + * @since 0.9.12 + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class Colors { + + + /** + * Removes all previously applied color and formatting attributes. + */ + public static final String NORMAL = "\u000f"; + + + /** + * Bold text. + */ + public static final String BOLD = "\u0002"; + + + /** + * Underlined text. + */ + public static final String UNDERLINE = "\u001f"; + + + /** + * Reversed text (may be rendered as italic text in some clients). + */ + public static final String REVERSE = "\u0016"; + + + /** + * White coloured text. + */ + public static final String WHITE = "\u000300"; + + + /** + * Black coloured text. + */ + public static final String BLACK = "\u000301"; + + + /** + * Dark blue coloured text. + */ + public static final String DARK_BLUE = "\u000302"; + + + /** + * Dark green coloured text. + */ + public static final String DARK_GREEN = "\u000303"; + + + /** + * Red coloured text. + */ + public static final String RED = "\u000304"; + + + /** + * Brown coloured text. + */ + public static final String BROWN = "\u000305"; + + + /** + * Purple coloured text. + */ + public static final String PURPLE = "\u000306"; + + + /** + * Olive coloured text. + */ + public static final String OLIVE = "\u000307"; + + + /** + * Yellow coloured text. + */ + public static final String YELLOW = "\u000308"; + + + /** + * Green coloured text. + */ + public static final String GREEN = "\u000309"; + + + /** + * Teal coloured text. + */ + public static final String TEAL = "\u000310"; + + + /** + * Cyan coloured text. + */ + public static final String CYAN = "\u000311"; + + + /** + * Blue coloured text. + */ + public static final String BLUE = "\u000312"; + + + /** + * Magenta coloured text. + */ + public static final String MAGENTA = "\u000313"; + + + /** + * Dark gray coloured text. + */ + public static final String DARK_GRAY = "\u000314"; + + + /** + * Light gray coloured text. + */ + public static final String LIGHT_GRAY = "\u000315"; + + + /** + * This class should not be constructed. + */ + private Colors() { + + } + + + /** + * Removes all colours from a line of IRC text. + * + * @since PircBot 1.2.0 + * + * @param line the input text. + * + * @return the same text, but with all colours removed. + */ + public static String removeColors(String line) { + int length = line.length(); + StringBuffer buffer = new StringBuffer(); + int i = 0; + while (i < length) { + char ch = line.charAt(i); + if (ch == '\u0003') { + i++; + // Skip "x" or "xy" (foreground color). + if (i < length) { + ch = line.charAt(i); + if (Character.isDigit(ch)) { + i++; + if (i < length) { + ch = line.charAt(i); + if (Character.isDigit(ch)) { + i++; + } + } + // Now skip ",x" or ",xy" (background color). + if (i < length) { + ch = line.charAt(i); + if (ch == ',') { + i++; + if (i < length) { + ch = line.charAt(i); + if (Character.isDigit(ch)) { + i++; + if (i < length) { + ch = line.charAt(i); + if (Character.isDigit(ch)) { + i++; + } + } + } + else { + // Keep the comma. + i--; + } + } + else { + // Keep the comma. + i--; + } + } + } + } + } + } + else if (ch == '\u000f') { + i++; + } + else { + buffer.append(ch); + i++; + } + } + return buffer.toString(); + } + + + /** + * Remove formatting from a line of IRC text. + * + * @since PircBot 1.2.0 + * + * @param line the input text. + * + * @return the same text, but without any bold, underlining, reverse, etc. + */ + public static String removeFormatting(String line) { + int length = line.length(); + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + char ch = line.charAt(i); + if (ch == '\u000f' || ch == '\u0002' || ch == '\u001f' || ch == '\u0016') { + // Don't add this character. + } + else { + buffer.append(ch); + } + } + return buffer.toString(); + } + + + /** + * Removes all formatting and colours from a line of IRC text. + * + * @since PircBot 1.2.0 + * + * @param line the input text. + * + * @return the same text, but without formatting and colour characters. + * + */ + public static String removeFormattingAndColors(String line) { + return removeFormatting(removeColors(line)); + } + +} diff --git a/src/org/jibble/pircbot/DccChat.java b/src/org/jibble/pircbot/DccChat.java index 2119d2e..78ce9cf 100644 --- a/src/org/jibble/pircbot/DccChat.java +++ b/src/org/jibble/pircbot/DccChat.java @@ -1,227 +1,227 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -import java.net.*; -import java.io.*; - -/** - * This class is used to allow the bot to interact with a DCC Chat session. - * - * @since 0.9c - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class DccChat { - - - /** - * This constructor is used when we are accepting a DCC CHAT request - * from somebody. It attempts to connect to the client that issued the - * request. - * - * @param bot An instance of the underlying PircBot. - * @param sourceNick The nick of the sender. - * @param address The address to connect to. - * @param port The port number to connect to. - * - * @throws IOException If the connection cannot be made. - */ - DccChat(PircBot bot, String nick, String login, String hostname, long address, int port) { - _bot = bot; - _address = address; - _port = port; - _nick = nick; - _login = login; - _hostname = hostname; - _acceptable = true; - } - - - /** - * This constructor is used after we have issued a DCC CHAT request to - * somebody. If the client accepts the chat request, then the socket we - * obtain is passed to this constructor. - * - * @param bot An instance of the underlying PircBot. - * @param sourceNick The nick of the user we are sending the request to. - * @param socket The socket which will be used for the DCC CHAT session. - * - * @throws IOException If the socket cannot be read from. - */ - DccChat(PircBot bot, String nick, Socket socket) throws IOException { - _bot = bot; - _nick = nick; - _socket = socket; - _reader = new BufferedReader(new InputStreamReader(_socket.getInputStream())); - _writer = new BufferedWriter(new OutputStreamWriter(_socket.getOutputStream())); - _acceptable = false; - } - - - /** - * Accept this DccChat connection. - * - * @since 1.2.0 - * - */ - public synchronized void accept() throws IOException { - if (_acceptable) { - _acceptable = false; - int[] ip = _bot.longToIp(_address); - String ipStr = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3]; - _socket = new Socket(ipStr, _port); - _reader = new BufferedReader(new InputStreamReader(_socket.getInputStream())); - _writer = new BufferedWriter(new OutputStreamWriter(_socket.getOutputStream())); - } - } - - - /** - * Reads the next line of text from the client at the other end of our DCC Chat - * connection. This method blocks until something can be returned. - * If the connection has closed, null is returned. - * - * @return The next line of text from the client. Returns null if the - * connection has closed normally. - * - * @throws IOException If an I/O error occurs. - */ - public String readLine() throws IOException { - if (_acceptable) { - throw new IOException("You must call the accept() method of the DccChat request before you can use it."); - } - return _reader.readLine(); - } - - - /** - * Sends a line of text to the client at the other end of our DCC Chat - * connection. - * - * @param line The line of text to be sent. This should not include - * linefeed characters. - * - * @throws IOException If an I/O error occurs. - */ - public void sendLine(String line) throws IOException { - if (_acceptable) { - throw new IOException("You must call the accept() method of the DccChat request before you can use it."); - } - // No need for synchronization here really... - _writer.write(line + "\r\n"); - _writer.flush(); - } - - - /** - * Closes the DCC Chat connection. - * - * @throws IOException If an I/O error occurs. - */ - public void close() throws IOException { - if (_acceptable) { - throw new IOException("You must call the accept() method of the DccChat request before you can use it."); - } - _socket.close(); - } - - - /** - * Returns the nick of the other user taking part in this file transfer. - * - * @return the nick of the other user. - * - */ - public String getNick() { - return _nick; - } - - - /** - * Returns the login of the DCC Chat initiator. - * - * @return the login of the DCC Chat initiator. null if we sent it. - * - */ - public String getLogin() { - return _login; - } - - - /** - * Returns the hostname of the DCC Chat initiator. - * - * @return the hostname of the DCC Chat initiator. null if we sent it. - * - */ - public String getHostname() { - return _hostname; - } - - - /** - * Returns the BufferedReader used by this DCC Chat. - * - * @return the BufferedReader used by this DCC Chat. - */ - public BufferedReader getBufferedReader() { - return _reader; - } - - - /** - * Returns the BufferedReader used by this DCC Chat. - * - * @return the BufferedReader used by this DCC Chat. - */ - public BufferedWriter getBufferedWriter() { - return _writer; - } - - - /** - * Returns the raw Socket used by this DCC Chat. - * - * @return the raw Socket used by this DCC Chat. - */ - public Socket getSocket() { - return _socket; - } - - - /** - * Returns the address of the sender as a long. - * - * @return the address of the sender as a long. - */ - public long getNumericalAddress() { - return _address; - } - - - private PircBot _bot; - private String _nick; - private String _login = null; - private String _hostname = null; - private BufferedReader _reader; - private BufferedWriter _writer; - private Socket _socket; - private boolean _acceptable; - private long _address = 0; - private int _port = 0; - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +import java.net.*; +import java.io.*; + +/** + * This class is used to allow the bot to interact with a DCC Chat session. + * + * @since 0.9c + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class DccChat { + + + /** + * This constructor is used when we are accepting a DCC CHAT request + * from somebody. It attempts to connect to the client that issued the + * request. + * + * @param bot An instance of the underlying PircBot. + * @param sourceNick The nick of the sender. + * @param address The address to connect to. + * @param port The port number to connect to. + * + * @throws IOException If the connection cannot be made. + */ + DccChat(PircBot bot, String nick, String login, String hostname, long address, int port) { + _bot = bot; + _address = address; + _port = port; + _nick = nick; + _login = login; + _hostname = hostname; + _acceptable = true; + } + + + /** + * This constructor is used after we have issued a DCC CHAT request to + * somebody. If the client accepts the chat request, then the socket we + * obtain is passed to this constructor. + * + * @param bot An instance of the underlying PircBot. + * @param sourceNick The nick of the user we are sending the request to. + * @param socket The socket which will be used for the DCC CHAT session. + * + * @throws IOException If the socket cannot be read from. + */ + DccChat(PircBot bot, String nick, Socket socket) throws IOException { + _bot = bot; + _nick = nick; + _socket = socket; + _reader = new BufferedReader(new InputStreamReader(_socket.getInputStream())); + _writer = new BufferedWriter(new OutputStreamWriter(_socket.getOutputStream())); + _acceptable = false; + } + + + /** + * Accept this DccChat connection. + * + * @since 1.2.0 + * + */ + public synchronized void accept() throws IOException { + if (_acceptable) { + _acceptable = false; + int[] ip = _bot.longToIp(_address); + String ipStr = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3]; + _socket = new Socket(ipStr, _port); + _reader = new BufferedReader(new InputStreamReader(_socket.getInputStream())); + _writer = new BufferedWriter(new OutputStreamWriter(_socket.getOutputStream())); + } + } + + + /** + * Reads the next line of text from the client at the other end of our DCC Chat + * connection. This method blocks until something can be returned. + * If the connection has closed, null is returned. + * + * @return The next line of text from the client. Returns null if the + * connection has closed normally. + * + * @throws IOException If an I/O error occurs. + */ + public String readLine() throws IOException { + if (_acceptable) { + throw new IOException("You must call the accept() method of the DccChat request before you can use it."); + } + return _reader.readLine(); + } + + + /** + * Sends a line of text to the client at the other end of our DCC Chat + * connection. + * + * @param line The line of text to be sent. This should not include + * linefeed characters. + * + * @throws IOException If an I/O error occurs. + */ + public void sendLine(String line) throws IOException { + if (_acceptable) { + throw new IOException("You must call the accept() method of the DccChat request before you can use it."); + } + // No need for synchronization here really... + _writer.write(line + "\r\n"); + _writer.flush(); + } + + + /** + * Closes the DCC Chat connection. + * + * @throws IOException If an I/O error occurs. + */ + public void close() throws IOException { + if (_acceptable) { + throw new IOException("You must call the accept() method of the DccChat request before you can use it."); + } + _socket.close(); + } + + + /** + * Returns the nick of the other user taking part in this file transfer. + * + * @return the nick of the other user. + * + */ + public String getNick() { + return _nick; + } + + + /** + * Returns the login of the DCC Chat initiator. + * + * @return the login of the DCC Chat initiator. null if we sent it. + * + */ + public String getLogin() { + return _login; + } + + + /** + * Returns the hostname of the DCC Chat initiator. + * + * @return the hostname of the DCC Chat initiator. null if we sent it. + * + */ + public String getHostname() { + return _hostname; + } + + + /** + * Returns the BufferedReader used by this DCC Chat. + * + * @return the BufferedReader used by this DCC Chat. + */ + public BufferedReader getBufferedReader() { + return _reader; + } + + + /** + * Returns the BufferedReader used by this DCC Chat. + * + * @return the BufferedReader used by this DCC Chat. + */ + public BufferedWriter getBufferedWriter() { + return _writer; + } + + + /** + * Returns the raw Socket used by this DCC Chat. + * + * @return the raw Socket used by this DCC Chat. + */ + public Socket getSocket() { + return _socket; + } + + + /** + * Returns the address of the sender as a long. + * + * @return the address of the sender as a long. + */ + public long getNumericalAddress() { + return _address; + } + + + private PircBot _bot; + private String _nick; + private String _login = null; + private String _hostname = null; + private BufferedReader _reader; + private BufferedWriter _writer; + private Socket _socket; + private boolean _acceptable; + private long _address = 0; + private int _port = 0; + +} diff --git a/src/org/jibble/pircbot/DccFileTransfer.java b/src/org/jibble/pircbot/DccFileTransfer.java index dd8b2cc..bad4b7d 100644 --- a/src/org/jibble/pircbot/DccFileTransfer.java +++ b/src/org/jibble/pircbot/DccFileTransfer.java @@ -1,505 +1,505 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -import java.net.*; -import java.io.*; - -/** - * This class is used to administer a DCC file transfer. - * - * @since 1.2.0 - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class DccFileTransfer { - - /** - * The default buffer size to use when sending and receiving files. - */ - public static final int BUFFER_SIZE = 1024; - - - /** - * Constructor used for receiving files. - */ - DccFileTransfer(PircBot bot, DccManager manager, String nick, String login, String hostname, String type, String filename, long address, int port, long size) { - _bot = bot; - _manager = manager; - _nick = nick; - _login = login; - _hostname = hostname; - _type = type; - _file = new File(filename); - _address = address; - _port = port; - _size = size; - _received = false; - - _incoming = true; - } - - - /** - * Constructor used for sending files. - */ - DccFileTransfer(PircBot bot, DccManager manager, File file, String nick, int timeout) { - _bot = bot; - _manager = manager; - _nick = nick; - _file = file; - _size = file.length(); - _timeout = timeout; - _received = true; - - _incoming = false; - } - - - /** - * Receives a DccFileTransfer and writes it to the specified file. - * Resuming allows a partial download to be continue from the end of - * the current file contents. - * - * @param file The file to write to. - * @param resume True if you wish to try and resume the download instead - * of overwriting an existing file. - * - */ - public synchronized void receive(File file, boolean resume) { - if (!_received) { - _received = true; - _file = file; - - if (_type.equals("SEND") && resume) { - _progress = file.length(); - if (_progress == 0) { - doReceive(file, false); - } - else { - _bot.sendCTCPCommand(_nick, "DCC RESUME file.ext " + _port + " " + _progress); - _manager.addAwaitingResume(this); - } - } - else { - _progress = file.length(); - doReceive(file, resume); - } - } - } - - - /** - * Receive the file in a new thread. - */ - void doReceive(final File file, final boolean resume) { - new Thread() { - public void run() { - - BufferedOutputStream foutput = null; - Exception exception = null; - - try { - - // Convert the integer address to a proper IP address. - int[] ip = _bot.longToIp(_address); - String ipStr = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3]; - - // Connect the socket and set a timeout. - _socket = new Socket(ipStr, _port); - _socket.setSoTimeout(30*1000); - _startTime = System.currentTimeMillis(); - - // No longer possible to resume this transfer once it's underway. - _manager.removeAwaitingResume(DccFileTransfer.this); - - BufferedInputStream input = new BufferedInputStream(_socket.getInputStream()); - BufferedOutputStream output = new BufferedOutputStream(_socket.getOutputStream()); - - // Following line fixed for jdk 1.1 compatibility. - foutput = new BufferedOutputStream(new FileOutputStream(file.getCanonicalPath(), resume)); - - byte[] inBuffer = new byte[BUFFER_SIZE]; - byte[] outBuffer = new byte[4]; - int bytesRead = 0; - while ((bytesRead = input.read(inBuffer, 0, inBuffer.length)) != -1) { - foutput.write(inBuffer, 0, bytesRead); - _progress += bytesRead; - // Send back an acknowledgement of how many bytes we have got so far. - outBuffer[0] = (byte) ((_progress >> 24) & 0xff); - outBuffer[1] = (byte) ((_progress >> 16) & 0xff); - outBuffer[2] = (byte) ((_progress >> 8) & 0xff); - outBuffer[3] = (byte) ((_progress >> 0) & 0xff); - output.write(outBuffer); - output.flush(); - delay(); - } - foutput.flush(); - } - catch (Exception e) { - exception = e; - } - finally { - try { - foutput.close(); - _socket.close(); - } - catch (Exception anye) { - // Do nothing. - } - } - - _bot.onFileTransferFinished(DccFileTransfer.this, exception); - } - }.start(); - } - - - /** - * Method to send the file inside a new thread. - */ - void doSend(final boolean allowResume) { - new Thread() { - public void run() { - - BufferedInputStream finput = null; - Exception exception = null; - - try { - - ServerSocket ss = null; - - int[] ports = _bot.getDccPorts(); - if (ports == null) { - // Use any free port. - ss = new ServerSocket(0); - } - else { - for (int i = 0; i < ports.length; i++) { - try { - ss = new ServerSocket(ports[i]); - // Found a port number we could use. - break; - } - catch (Exception e) { - // Do nothing; go round and try another port. - } - } - if (ss == null) { - // No ports could be used. - throw new IOException("All ports returned by getDccPorts() are in use."); - } - } - - ss.setSoTimeout(_timeout); - _port = ss.getLocalPort(); - InetAddress inetAddress = _bot.getDccInetAddress(); - if (inetAddress == null) { - inetAddress = _bot.getInetAddress(); - } - byte[] ip = inetAddress.getAddress(); - long ipNum = _bot.ipToLong(ip); - - // Rename the filename so it has no whitespace in it when we send it. - // .... I really should do this a bit more nicely at some point .... - String safeFilename = _file.getName().replace(' ', '_'); - safeFilename = safeFilename.replace('\t', '_'); - - if (allowResume) { - _manager.addAwaitingResume(DccFileTransfer.this); - } - - // Send the message to the user, telling them where to connect to in order to get the file. - _bot.sendCTCPCommand(_nick, "DCC SEND " + safeFilename + " " + ipNum + " " + _port + " " + _file.length()); - - // The client may now connect to us and download the file. - _socket = ss.accept(); - _socket.setSoTimeout(30000); - _startTime = System.currentTimeMillis(); - - // No longer possible to resume this transfer once it's underway. - if (allowResume) { - _manager.removeAwaitingResume(DccFileTransfer.this); - } - - // Might as well close the server socket now; it's finished with. - ss.close(); - - BufferedOutputStream output = new BufferedOutputStream(_socket.getOutputStream()); - BufferedInputStream input = new BufferedInputStream(_socket.getInputStream()); - finput = new BufferedInputStream(new FileInputStream(_file)); - - // Check for resuming. - if (_progress > 0) { - long bytesSkipped = 0; - while (bytesSkipped < _progress) { - bytesSkipped += finput.skip(_progress - bytesSkipped); - } - } - - byte[] outBuffer = new byte[BUFFER_SIZE]; - byte[] inBuffer = new byte[4]; - int bytesRead = 0; - while ((bytesRead = finput.read(outBuffer, 0, outBuffer.length)) != -1) { - output.write(outBuffer, 0, bytesRead); - output.flush(); - input.read(inBuffer, 0, inBuffer.length); - _progress += bytesRead; - delay(); - } - } - catch (Exception e) { - exception = e; - } - finally { - try { - finput.close(); - _socket.close(); - } - catch (Exception e) { - // Do nothing. - } - } - - _bot.onFileTransferFinished(DccFileTransfer.this, exception); - } - }.start(); - } - - - /** - * Package mutator for setting the progress of the file transfer. - */ - void setProgress(long progress) { - _progress = progress; - } - - - /** - * Delay between packets. - */ - private void delay() { - if (_packetDelay > 0) { - try { - Thread.sleep(_packetDelay); - } - catch (InterruptedException e) { - // Do nothing. - } - } - } - - - /** - * Returns the nick of the other user taking part in this file transfer. - * - * @return the nick of the other user. - * - */ - public String getNick() { - return _nick; - } - - - /** - * Returns the login of the file sender. - * - * @return the login of the file sender. null if we are sending. - * - */ - public String getLogin() { - return _login; - } - - - /** - * Returns the hostname of the file sender. - * - * @return the hostname of the file sender. null if we are sending. - * - */ - public String getHostname() { - return _hostname; - } - - - /** - * Returns the suggested file to be used for this transfer. - * - * @return the suggested file to be used. - * - */ - public File getFile() { - return _file; - } - - - /** - * Returns the port number to be used when making the connection. - * - * @return the port number. - * - */ - public int getPort() { - return _port; - } - - - /** - * Returns true if the file transfer is incoming (somebody is sending - * the file to us). - * - * @return true if the file transfer is incoming. - * - */ - public boolean isIncoming() { - return _incoming; - } - - - /** - * Returns true if the file transfer is outgoing (we are sending the - * file to someone). - * - * @return true if the file transfer is outgoing. - * - */ - public boolean isOutgoing() { - return !isIncoming(); - } - - - /** - * Sets the delay time between sending or receiving each packet. - * Default is 0. - * This is useful for throttling the speed of file transfers to maintain - * a good quality of service for other things on the machine or network. - * - * @param millis The number of milliseconds to wait between packets. - * - */ - public void setPacketDelay(long millis) { - _packetDelay = millis; - } - - - /** - * returns the delay time between each packet that is send or received. - * - * @return the delay between each packet. - * - */ - public long getPacketDelay() { - return _packetDelay; - } - - - /** - * Returns the size (in bytes) of the file being transfered. - * - * @return the size of the file. Returns -1 if the sender did not - * specify this value. - */ - public long getSize() { - return _size; - } - - - /** - * Returns the progress (in bytes) of the current file transfer. - * When resuming, this represents the total number of bytes in the - * file, which may be greater than the amount of bytes resumed in - * just this transfer. - * - * @return the progress of the transfer. - */ - public long getProgress() { - return _progress; - } - - - /** - * Returns the progress of the file transfer as a percentage. - * Note that this should never be negative, but could become - * greater than 100% if you attempt to resume a larger file - * onto a partially downloaded file that was smaller. - * - * @return the progress of the transfer as a percentage. - */ - public double getProgressPercentage() { - return 100 * (getProgress() / (double) getSize()); - } - - - /** - * Stops the DCC file transfer by closing the connection. - */ - public void close() { - try { - _socket.close(); - } - catch (Exception e) { - // Let the DCC manager worry about anything that may go wrong. - } - } - - - /** - * Returns the rate of data transfer in bytes per second. - * This value is an estimate based on the number of bytes - * transfered since the connection was established. - * - * @return data transfer rate in bytes per second. - */ - public long getTransferRate() { - long time = (System.currentTimeMillis() - _startTime) / 1000; - if (time <= 0) { - return 0; - } - return getProgress() / time; - } - - /** - * Returns the address of the sender as a long. - * - * @return the address of the sender as a long. - */ - public long getNumericalAddress() { - return _address; - } - - - private PircBot _bot; - private DccManager _manager; - private String _nick; - private String _login = null; - private String _hostname = null; - private String _type; - private long _address; - private int _port; - private long _size; - private boolean _received; - - private Socket _socket = null; - private long _progress = 0; - private File _file = null; - private int _timeout = 0; - private boolean _incoming; - private long _packetDelay = 0; - - private long _startTime = 0; - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +import java.net.*; +import java.io.*; + +/** + * This class is used to administer a DCC file transfer. + * + * @since 1.2.0 + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class DccFileTransfer { + + /** + * The default buffer size to use when sending and receiving files. + */ + public static final int BUFFER_SIZE = 1024; + + + /** + * Constructor used for receiving files. + */ + DccFileTransfer(PircBot bot, DccManager manager, String nick, String login, String hostname, String type, String filename, long address, int port, long size) { + _bot = bot; + _manager = manager; + _nick = nick; + _login = login; + _hostname = hostname; + _type = type; + _file = new File(filename); + _address = address; + _port = port; + _size = size; + _received = false; + + _incoming = true; + } + + + /** + * Constructor used for sending files. + */ + DccFileTransfer(PircBot bot, DccManager manager, File file, String nick, int timeout) { + _bot = bot; + _manager = manager; + _nick = nick; + _file = file; + _size = file.length(); + _timeout = timeout; + _received = true; + + _incoming = false; + } + + + /** + * Receives a DccFileTransfer and writes it to the specified file. + * Resuming allows a partial download to be continue from the end of + * the current file contents. + * + * @param file The file to write to. + * @param resume True if you wish to try and resume the download instead + * of overwriting an existing file. + * + */ + public synchronized void receive(File file, boolean resume) { + if (!_received) { + _received = true; + _file = file; + + if (_type.equals("SEND") && resume) { + _progress = file.length(); + if (_progress == 0) { + doReceive(file, false); + } + else { + _bot.sendCTCPCommand(_nick, "DCC RESUME file.ext " + _port + " " + _progress); + _manager.addAwaitingResume(this); + } + } + else { + _progress = file.length(); + doReceive(file, resume); + } + } + } + + + /** + * Receive the file in a new thread. + */ + void doReceive(final File file, final boolean resume) { + new Thread() { + public void run() { + + BufferedOutputStream foutput = null; + Exception exception = null; + + try { + + // Convert the integer address to a proper IP address. + int[] ip = _bot.longToIp(_address); + String ipStr = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3]; + + // Connect the socket and set a timeout. + _socket = new Socket(ipStr, _port); + _socket.setSoTimeout(30*1000); + _startTime = System.currentTimeMillis(); + + // No longer possible to resume this transfer once it's underway. + _manager.removeAwaitingResume(DccFileTransfer.this); + + BufferedInputStream input = new BufferedInputStream(_socket.getInputStream()); + BufferedOutputStream output = new BufferedOutputStream(_socket.getOutputStream()); + + // Following line fixed for jdk 1.1 compatibility. + foutput = new BufferedOutputStream(new FileOutputStream(file.getCanonicalPath(), resume)); + + byte[] inBuffer = new byte[BUFFER_SIZE]; + byte[] outBuffer = new byte[4]; + int bytesRead = 0; + while ((bytesRead = input.read(inBuffer, 0, inBuffer.length)) != -1) { + foutput.write(inBuffer, 0, bytesRead); + _progress += bytesRead; + // Send back an acknowledgement of how many bytes we have got so far. + outBuffer[0] = (byte) ((_progress >> 24) & 0xff); + outBuffer[1] = (byte) ((_progress >> 16) & 0xff); + outBuffer[2] = (byte) ((_progress >> 8) & 0xff); + outBuffer[3] = (byte) ((_progress >> 0) & 0xff); + output.write(outBuffer); + output.flush(); + delay(); + } + foutput.flush(); + } + catch (Exception e) { + exception = e; + } + finally { + try { + foutput.close(); + _socket.close(); + } + catch (Exception anye) { + // Do nothing. + } + } + + _bot.onFileTransferFinished(DccFileTransfer.this, exception); + } + }.start(); + } + + + /** + * Method to send the file inside a new thread. + */ + void doSend(final boolean allowResume) { + new Thread() { + public void run() { + + BufferedInputStream finput = null; + Exception exception = null; + + try { + + ServerSocket ss = null; + + int[] ports = _bot.getDccPorts(); + if (ports == null) { + // Use any free port. + ss = new ServerSocket(0); + } + else { + for (int i = 0; i < ports.length; i++) { + try { + ss = new ServerSocket(ports[i]); + // Found a port number we could use. + break; + } + catch (Exception e) { + // Do nothing; go round and try another port. + } + } + if (ss == null) { + // No ports could be used. + throw new IOException("All ports returned by getDccPorts() are in use."); + } + } + + ss.setSoTimeout(_timeout); + _port = ss.getLocalPort(); + InetAddress inetAddress = _bot.getDccInetAddress(); + if (inetAddress == null) { + inetAddress = _bot.getInetAddress(); + } + byte[] ip = inetAddress.getAddress(); + long ipNum = _bot.ipToLong(ip); + + // Rename the filename so it has no whitespace in it when we send it. + // .... I really should do this a bit more nicely at some point .... + String safeFilename = _file.getName().replace(' ', '_'); + safeFilename = safeFilename.replace('\t', '_'); + + if (allowResume) { + _manager.addAwaitingResume(DccFileTransfer.this); + } + + // Send the message to the user, telling them where to connect to in order to get the file. + _bot.sendCTCPCommand(_nick, "DCC SEND " + safeFilename + " " + ipNum + " " + _port + " " + _file.length()); + + // The client may now connect to us and download the file. + _socket = ss.accept(); + _socket.setSoTimeout(30000); + _startTime = System.currentTimeMillis(); + + // No longer possible to resume this transfer once it's underway. + if (allowResume) { + _manager.removeAwaitingResume(DccFileTransfer.this); + } + + // Might as well close the server socket now; it's finished with. + ss.close(); + + BufferedOutputStream output = new BufferedOutputStream(_socket.getOutputStream()); + BufferedInputStream input = new BufferedInputStream(_socket.getInputStream()); + finput = new BufferedInputStream(new FileInputStream(_file)); + + // Check for resuming. + if (_progress > 0) { + long bytesSkipped = 0; + while (bytesSkipped < _progress) { + bytesSkipped += finput.skip(_progress - bytesSkipped); + } + } + + byte[] outBuffer = new byte[BUFFER_SIZE]; + byte[] inBuffer = new byte[4]; + int bytesRead = 0; + while ((bytesRead = finput.read(outBuffer, 0, outBuffer.length)) != -1) { + output.write(outBuffer, 0, bytesRead); + output.flush(); + input.read(inBuffer, 0, inBuffer.length); + _progress += bytesRead; + delay(); + } + } + catch (Exception e) { + exception = e; + } + finally { + try { + finput.close(); + _socket.close(); + } + catch (Exception e) { + // Do nothing. + } + } + + _bot.onFileTransferFinished(DccFileTransfer.this, exception); + } + }.start(); + } + + + /** + * Package mutator for setting the progress of the file transfer. + */ + void setProgress(long progress) { + _progress = progress; + } + + + /** + * Delay between packets. + */ + private void delay() { + if (_packetDelay > 0) { + try { + Thread.sleep(_packetDelay); + } + catch (InterruptedException e) { + // Do nothing. + } + } + } + + + /** + * Returns the nick of the other user taking part in this file transfer. + * + * @return the nick of the other user. + * + */ + public String getNick() { + return _nick; + } + + + /** + * Returns the login of the file sender. + * + * @return the login of the file sender. null if we are sending. + * + */ + public String getLogin() { + return _login; + } + + + /** + * Returns the hostname of the file sender. + * + * @return the hostname of the file sender. null if we are sending. + * + */ + public String getHostname() { + return _hostname; + } + + + /** + * Returns the suggested file to be used for this transfer. + * + * @return the suggested file to be used. + * + */ + public File getFile() { + return _file; + } + + + /** + * Returns the port number to be used when making the connection. + * + * @return the port number. + * + */ + public int getPort() { + return _port; + } + + + /** + * Returns true if the file transfer is incoming (somebody is sending + * the file to us). + * + * @return true if the file transfer is incoming. + * + */ + public boolean isIncoming() { + return _incoming; + } + + + /** + * Returns true if the file transfer is outgoing (we are sending the + * file to someone). + * + * @return true if the file transfer is outgoing. + * + */ + public boolean isOutgoing() { + return !isIncoming(); + } + + + /** + * Sets the delay time between sending or receiving each packet. + * Default is 0. + * This is useful for throttling the speed of file transfers to maintain + * a good quality of service for other things on the machine or network. + * + * @param millis The number of milliseconds to wait between packets. + * + */ + public void setPacketDelay(long millis) { + _packetDelay = millis; + } + + + /** + * returns the delay time between each packet that is send or received. + * + * @return the delay between each packet. + * + */ + public long getPacketDelay() { + return _packetDelay; + } + + + /** + * Returns the size (in bytes) of the file being transfered. + * + * @return the size of the file. Returns -1 if the sender did not + * specify this value. + */ + public long getSize() { + return _size; + } + + + /** + * Returns the progress (in bytes) of the current file transfer. + * When resuming, this represents the total number of bytes in the + * file, which may be greater than the amount of bytes resumed in + * just this transfer. + * + * @return the progress of the transfer. + */ + public long getProgress() { + return _progress; + } + + + /** + * Returns the progress of the file transfer as a percentage. + * Note that this should never be negative, but could become + * greater than 100% if you attempt to resume a larger file + * onto a partially downloaded file that was smaller. + * + * @return the progress of the transfer as a percentage. + */ + public double getProgressPercentage() { + return 100 * (getProgress() / (double) getSize()); + } + + + /** + * Stops the DCC file transfer by closing the connection. + */ + public void close() { + try { + _socket.close(); + } + catch (Exception e) { + // Let the DCC manager worry about anything that may go wrong. + } + } + + + /** + * Returns the rate of data transfer in bytes per second. + * This value is an estimate based on the number of bytes + * transfered since the connection was established. + * + * @return data transfer rate in bytes per second. + */ + public long getTransferRate() { + long time = (System.currentTimeMillis() - _startTime) / 1000; + if (time <= 0) { + return 0; + } + return getProgress() / time; + } + + /** + * Returns the address of the sender as a long. + * + * @return the address of the sender as a long. + */ + public long getNumericalAddress() { + return _address; + } + + + private PircBot _bot; + private DccManager _manager; + private String _nick; + private String _login = null; + private String _hostname = null; + private String _type; + private long _address; + private int _port; + private long _size; + private boolean _received; + + private Socket _socket = null; + private long _progress = 0; + private File _file = null; + private int _timeout = 0; + private boolean _incoming; + private long _packetDelay = 0; + + private long _startTime = 0; + +} diff --git a/src/org/jibble/pircbot/DccManager.java b/src/org/jibble/pircbot/DccManager.java index 1fbd06d..f981bca 100644 --- a/src/org/jibble/pircbot/DccManager.java +++ b/src/org/jibble/pircbot/DccManager.java @@ -1,152 +1,152 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -import java.util.*; - -/** - * This class is used to process DCC events from the server. - * - * @since 1.2.0 - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class DccManager { - - - /** - * Constructs a DccManager to look after all DCC SEND and CHAT events. - * - * @param bot The PircBot whose DCC events this class will handle. - */ - DccManager(PircBot bot) { - _bot = bot; - } - - - /** - * Processes a DCC request. - * - * @return True if the type of request was handled successfully. - */ - boolean processRequest(String nick, String login, String hostname, String request) { - StringTokenizer tokenizer = new StringTokenizer(request); - tokenizer.nextToken(); - String type = tokenizer.nextToken(); - String filename = tokenizer.nextToken(); - - if (type.equals("SEND")) { - long address = Long.parseLong(tokenizer.nextToken()); - int port = Integer.parseInt(tokenizer.nextToken()); - long size = -1; - try { - size = Long.parseLong(tokenizer.nextToken()); - } - catch (Exception e) { - // Stick with the old value. - } - - DccFileTransfer transfer = new DccFileTransfer(_bot, this, nick, login, hostname, type, filename, address, port, size); - _bot.onIncomingFileTransfer(transfer); - - } - else if (type.equals("RESUME")) { - int port = Integer.parseInt(tokenizer.nextToken()); - long progress = Long.parseLong(tokenizer.nextToken()); - - DccFileTransfer transfer = null; - synchronized (_awaitingResume) { - for (int i = 0; i < _awaitingResume.size(); i++) { - transfer = (DccFileTransfer) _awaitingResume.elementAt(i); - if (transfer.getNick().equals(nick) && transfer.getPort() == port) { - _awaitingResume.removeElementAt(i); - break; - } - } - } - - if (transfer != null) { - transfer.setProgress(progress); - _bot.sendCTCPCommand(nick, "DCC ACCEPT file.ext " + port + " " + progress); - } - - } - else if (type.equals("ACCEPT")) { - int port = Integer.parseInt(tokenizer.nextToken()); - // XXX: progress is not used? - //long progress = Long.parseLong(tokenizer.nextToken()); - - DccFileTransfer transfer = null; - synchronized (_awaitingResume) { - for (int i = 0; i < _awaitingResume.size(); i++) { - transfer = (DccFileTransfer) _awaitingResume.elementAt(i); - if (transfer.getNick().equals(nick) && transfer.getPort() == port) { - _awaitingResume.removeElementAt(i); - break; - } - } - } - - if (transfer != null) { - transfer.doReceive(transfer.getFile(), true); - } - - } - else if (type.equals("CHAT")) { - long address = Long.parseLong(tokenizer.nextToken()); - int port = Integer.parseInt(tokenizer.nextToken()); - - final DccChat chat = new DccChat(_bot, nick, login, hostname, address, port); - - new Thread() { - public void run() { - _bot.onIncomingChatRequest(chat); - } - }.start(); - } - else { - return false; - } - - return true; - } - - - /** - * Add this DccFileTransfer to the list of those awaiting possible - * resuming. - * - * @param transfer the DccFileTransfer that may be resumed. - */ - void addAwaitingResume(DccFileTransfer transfer) { - synchronized (_awaitingResume) { - _awaitingResume.addElement(transfer); - } - } - - - /** - * Remove this transfer from the list of those awaiting resuming. - */ - void removeAwaitingResume(DccFileTransfer transfer) { - _awaitingResume.removeElement(transfer); - } - - - private PircBot _bot; - private Vector _awaitingResume = new Vector(); - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +import java.util.*; + +/** + * This class is used to process DCC events from the server. + * + * @since 1.2.0 + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class DccManager { + + + /** + * Constructs a DccManager to look after all DCC SEND and CHAT events. + * + * @param bot The PircBot whose DCC events this class will handle. + */ + DccManager(PircBot bot) { + _bot = bot; + } + + + /** + * Processes a DCC request. + * + * @return True if the type of request was handled successfully. + */ + boolean processRequest(String nick, String login, String hostname, String request) { + StringTokenizer tokenizer = new StringTokenizer(request); + tokenizer.nextToken(); + String type = tokenizer.nextToken(); + String filename = tokenizer.nextToken(); + + if (type.equals("SEND")) { + long address = Long.parseLong(tokenizer.nextToken()); + int port = Integer.parseInt(tokenizer.nextToken()); + long size = -1; + try { + size = Long.parseLong(tokenizer.nextToken()); + } + catch (Exception e) { + // Stick with the old value. + } + + DccFileTransfer transfer = new DccFileTransfer(_bot, this, nick, login, hostname, type, filename, address, port, size); + _bot.onIncomingFileTransfer(transfer); + + } + else if (type.equals("RESUME")) { + int port = Integer.parseInt(tokenizer.nextToken()); + long progress = Long.parseLong(tokenizer.nextToken()); + + DccFileTransfer transfer = null; + synchronized (_awaitingResume) { + for (int i = 0; i < _awaitingResume.size(); i++) { + transfer = (DccFileTransfer) _awaitingResume.elementAt(i); + if (transfer.getNick().equals(nick) && transfer.getPort() == port) { + _awaitingResume.removeElementAt(i); + break; + } + } + } + + if (transfer != null) { + transfer.setProgress(progress); + _bot.sendCTCPCommand(nick, "DCC ACCEPT file.ext " + port + " " + progress); + } + + } + else if (type.equals("ACCEPT")) { + int port = Integer.parseInt(tokenizer.nextToken()); + // XXX: progress is not used? + //long progress = Long.parseLong(tokenizer.nextToken()); + + DccFileTransfer transfer = null; + synchronized (_awaitingResume) { + for (int i = 0; i < _awaitingResume.size(); i++) { + transfer = (DccFileTransfer) _awaitingResume.elementAt(i); + if (transfer.getNick().equals(nick) && transfer.getPort() == port) { + _awaitingResume.removeElementAt(i); + break; + } + } + } + + if (transfer != null) { + transfer.doReceive(transfer.getFile(), true); + } + + } + else if (type.equals("CHAT")) { + long address = Long.parseLong(tokenizer.nextToken()); + int port = Integer.parseInt(tokenizer.nextToken()); + + final DccChat chat = new DccChat(_bot, nick, login, hostname, address, port); + + new Thread() { + public void run() { + _bot.onIncomingChatRequest(chat); + } + }.start(); + } + else { + return false; + } + + return true; + } + + + /** + * Add this DccFileTransfer to the list of those awaiting possible + * resuming. + * + * @param transfer the DccFileTransfer that may be resumed. + */ + void addAwaitingResume(DccFileTransfer transfer) { + synchronized (_awaitingResume) { + _awaitingResume.addElement(transfer); + } + } + + + /** + * Remove this transfer from the list of those awaiting resuming. + */ + void removeAwaitingResume(DccFileTransfer transfer) { + _awaitingResume.removeElement(transfer); + } + + + private PircBot _bot; + private Vector _awaitingResume = new Vector(); + +} diff --git a/src/org/jibble/pircbot/IdentServer.java b/src/org/jibble/pircbot/IdentServer.java index 936202a..98b0c13 100644 --- a/src/org/jibble/pircbot/IdentServer.java +++ b/src/org/jibble/pircbot/IdentServer.java @@ -1,119 +1,119 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -import java.net.*; -import java.io.*; - -/** - * A simple IdentServer (also know as "The Identification Protocol"). - * An ident server provides a means to determine the identity of a - * user of a particular TCP connection. - *

- * Most IRC servers attempt to contact the ident server on connecting - * hosts in order to determine the user's identity. A few IRC servers - * will not allow you to connect unless this information is provided. - *

- * So when a PircBot is run on a machine that does not run an ident server, - * it may be necessary to provide a "faked" response by starting up its - * own ident server and sending out apparently correct responses. - *

- * An instance of this class can be used to start up an ident server - * only if it is possible to do so. Reasons for not being able to do - * so are if there is already an ident server running on port 113, or - * if you are running as an unprivileged user who is unable to create - * a server socket on that port number. - * - * @since 0.9c - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class IdentServer extends Thread { - - /** - * Constructs and starts an instance of an IdentServer that will - * respond to a client with the provided login. Rather than calling - * this constructor explicitly from your code, it is recommended that - * you use the startIdentServer method in the PircBot class. - *

- * The ident server will wait for up to 60 seconds before shutting - * down. Otherwise, it will shut down as soon as it has responded - * to an ident request. - * - * @param bot The PircBot instance that will be used to log to. - * @param login The login that the ident server will respond with. - */ - IdentServer(PircBot bot, String login) { - _bot = bot; - _login = login; - - try { - _ss = new ServerSocket(113); - _ss.setSoTimeout(60000); - } - catch (Exception e) { - _bot.log("*** Could not start the ident server on port 113."); - return; - } - - _bot.log("*** Ident server running on port 113 for the next 60 seconds..."); - this.setName(this.getClass() + "-Thread"); - this.start(); - } - - - /** - * Waits for a client to connect to the ident server before making an - * appropriate response. Note that this method is started by the class - * constructor. - */ - public void run() { - try { - Socket socket = _ss.accept(); - socket.setSoTimeout(60000); - - BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); - - String line = reader.readLine(); - if (line != null) { - _bot.log("*** Ident request received: " + line); - line = line + " : USERID : UNIX : " + _login; - writer.write(line + "\r\n"); - writer.flush(); - _bot.log("*** Ident reply sent: " + line); - writer.close(); - } - } - catch (Exception e) { - // We're not really concerned with what went wrong, are we? - } - - try { - _ss.close(); - } - catch (Exception e) { - // Doesn't really matter... - } - - _bot.log("*** The Ident server has been shut down."); - } - - private PircBot _bot; - private String _login; - private ServerSocket _ss = null; - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +import java.net.*; +import java.io.*; + +/** + * A simple IdentServer (also know as "The Identification Protocol"). + * An ident server provides a means to determine the identity of a + * user of a particular TCP connection. + *

+ * Most IRC servers attempt to contact the ident server on connecting + * hosts in order to determine the user's identity. A few IRC servers + * will not allow you to connect unless this information is provided. + *

+ * So when a PircBot is run on a machine that does not run an ident server, + * it may be necessary to provide a "faked" response by starting up its + * own ident server and sending out apparently correct responses. + *

+ * An instance of this class can be used to start up an ident server + * only if it is possible to do so. Reasons for not being able to do + * so are if there is already an ident server running on port 113, or + * if you are running as an unprivileged user who is unable to create + * a server socket on that port number. + * + * @since 0.9c + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class IdentServer extends Thread { + + /** + * Constructs and starts an instance of an IdentServer that will + * respond to a client with the provided login. Rather than calling + * this constructor explicitly from your code, it is recommended that + * you use the startIdentServer method in the PircBot class. + *

+ * The ident server will wait for up to 60 seconds before shutting + * down. Otherwise, it will shut down as soon as it has responded + * to an ident request. + * + * @param bot The PircBot instance that will be used to log to. + * @param login The login that the ident server will respond with. + */ + IdentServer(PircBot bot, String login) { + _bot = bot; + _login = login; + + try { + _ss = new ServerSocket(113); + _ss.setSoTimeout(60000); + } + catch (Exception e) { + _bot.log("*** Could not start the ident server on port 113."); + return; + } + + _bot.log("*** Ident server running on port 113 for the next 60 seconds..."); + this.setName(this.getClass() + "-Thread"); + this.start(); + } + + + /** + * Waits for a client to connect to the ident server before making an + * appropriate response. Note that this method is started by the class + * constructor. + */ + public void run() { + try { + Socket socket = _ss.accept(); + socket.setSoTimeout(60000); + + BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); + + String line = reader.readLine(); + if (line != null) { + _bot.log("*** Ident request received: " + line); + line = line + " : USERID : UNIX : " + _login; + writer.write(line + "\r\n"); + writer.flush(); + _bot.log("*** Ident reply sent: " + line); + writer.close(); + } + } + catch (Exception e) { + // We're not really concerned with what went wrong, are we? + } + + try { + _ss.close(); + } + catch (Exception e) { + // Doesn't really matter... + } + + _bot.log("*** The Ident server has been shut down."); + } + + private PircBot _bot; + private String _login; + private ServerSocket _ss = null; + +} diff --git a/src/org/jibble/pircbot/InputThread.java b/src/org/jibble/pircbot/InputThread.java index a470eca..0dcfc7e 100644 --- a/src/org/jibble/pircbot/InputThread.java +++ b/src/org/jibble/pircbot/InputThread.java @@ -1,169 +1,169 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -import java.io.*; -import java.net.*; -import java.util.*; - -/** - * A Thread which reads lines from the IRC server. It then - * passes these lines to the PircBot without changing them. - * This running Thread also detects disconnection from the server - * and is thus used by the OutputThread to send lines to the server. - * - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class InputThread extends Thread { - - /** - * The InputThread reads lines from the IRC server and allows the - * PircBot to handle them. - * - * @param bot An instance of the underlying PircBot. - * @param breader The BufferedReader that reads lines from the server. - * @param bwriter The BufferedWriter that sends lines to the server. - */ - InputThread(PircBot bot, Socket socket, BufferedReader breader, BufferedWriter bwriter) { - _bot = bot; - _socket = socket; - _breader = breader; - _bwriter = bwriter; - this.setName(this.getClass() + "-Thread"); - } - - - /** - * Sends a raw line to the IRC server as soon as possible, bypassing the - * outgoing message queue. - * - * @param line The raw line to send to the IRC server. - */ - void sendRawLine(String line) { - OutputThread.sendRawLine(_bot, _bwriter, line); - } - - - /** - * Returns true if this InputThread is connected to an IRC server. - * The result of this method should only act as a rough guide, - * as the result may not be valid by the time you act upon it. - * - * @return True if still connected. - */ - boolean isConnected() { - return _isConnected; - } - - - /** - * Called to start this Thread reading lines from the IRC server. - * When a line is read, this method calls the handleLine method - * in the PircBot, which may subsequently call an 'onXxx' method - * in the PircBot subclass. If any subclass of Throwable (i.e. - * any Exception or Error) is thrown by your method, then this - * method will print the stack trace to the standard output. It - * is probable that the PircBot may still be functioning normally - * after such a problem, but the existance of any uncaught exceptions - * in your code is something you should really fix. - */ - public void run() { - try { - boolean running = true; - while (running) { - try { - String line = null; - while ((line = _breader.readLine()) != null) { - try { - _bot.handleLine(line); - } - catch (Throwable t) { - // Stick the whole stack trace into a String so we can output it nicely. - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - t.printStackTrace(pw); - pw.flush(); - StringTokenizer tokenizer = new StringTokenizer(sw.toString(), "\r\n"); - synchronized (_bot) { - _bot.log("### Your implementation of PircBot is faulty and you have"); - _bot.log("### allowed an uncaught Exception or Error to propagate in your"); - _bot.log("### code. It may be possible for PircBot to continue operating"); - _bot.log("### normally. Here is the stack trace that was produced: -"); - _bot.log("### "); - while (tokenizer.hasMoreTokens()) { - _bot.log("### " + tokenizer.nextToken()); - } - } - } - } - if (line == null) { - // The server must have disconnected us. - running = false; - } - } - catch (InterruptedIOException iioe) { - // This will happen if we haven't received anything from the server for a while. - // So we shall send it a ping to check that we are still connected. - this.sendRawLine("PING " + (System.currentTimeMillis() / 1000)); - // Now we go back to listening for stuff from the server... - } - } - } - catch (Exception e) { - // Do nothing. - } - - // If we reach this point, then we must have disconnected. - try { - _socket.close(); - } - catch (Exception e) { - // Just assume the socket was already closed. - } - - if (!_disposed) { - _bot.log("*** Disconnected."); - _isConnected = false; - _bot.onDisconnect(); - } - - } - - - /** - * Closes the socket without onDisconnect being called subsequently. - */ - public void dispose () { - try { - _disposed = true; - _socket.close(); - } - catch (Exception e) { - // Do nothing. - } - } - - private PircBot _bot = null; - private Socket _socket = null; - private BufferedReader _breader = null; - private BufferedWriter _bwriter = null; - private boolean _isConnected = true; - private boolean _disposed = false; - - public static final int MAX_LINE_LENGTH = 512; - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +import java.io.*; +import java.net.*; +import java.util.*; + +/** + * A Thread which reads lines from the IRC server. It then + * passes these lines to the PircBot without changing them. + * This running Thread also detects disconnection from the server + * and is thus used by the OutputThread to send lines to the server. + * + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class InputThread extends Thread { + + /** + * The InputThread reads lines from the IRC server and allows the + * PircBot to handle them. + * + * @param bot An instance of the underlying PircBot. + * @param breader The BufferedReader that reads lines from the server. + * @param bwriter The BufferedWriter that sends lines to the server. + */ + InputThread(PircBot bot, Socket socket, BufferedReader breader, BufferedWriter bwriter) { + _bot = bot; + _socket = socket; + _breader = breader; + _bwriter = bwriter; + this.setName(this.getClass() + "-Thread"); + } + + + /** + * Sends a raw line to the IRC server as soon as possible, bypassing the + * outgoing message queue. + * + * @param line The raw line to send to the IRC server. + */ + void sendRawLine(String line) { + OutputThread.sendRawLine(_bot, _bwriter, line); + } + + + /** + * Returns true if this InputThread is connected to an IRC server. + * The result of this method should only act as a rough guide, + * as the result may not be valid by the time you act upon it. + * + * @return True if still connected. + */ + boolean isConnected() { + return _isConnected; + } + + + /** + * Called to start this Thread reading lines from the IRC server. + * When a line is read, this method calls the handleLine method + * in the PircBot, which may subsequently call an 'onXxx' method + * in the PircBot subclass. If any subclass of Throwable (i.e. + * any Exception or Error) is thrown by your method, then this + * method will print the stack trace to the standard output. It + * is probable that the PircBot may still be functioning normally + * after such a problem, but the existance of any uncaught exceptions + * in your code is something you should really fix. + */ + public void run() { + try { + boolean running = true; + while (running) { + try { + String line = null; + while ((line = _breader.readLine()) != null) { + try { + _bot.handleLine(line); + } + catch (Throwable t) { + // Stick the whole stack trace into a String so we can output it nicely. + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + t.printStackTrace(pw); + pw.flush(); + StringTokenizer tokenizer = new StringTokenizer(sw.toString(), "\r\n"); + synchronized (_bot) { + _bot.log("### Your implementation of PircBot is faulty and you have"); + _bot.log("### allowed an uncaught Exception or Error to propagate in your"); + _bot.log("### code. It may be possible for PircBot to continue operating"); + _bot.log("### normally. Here is the stack trace that was produced: -"); + _bot.log("### "); + while (tokenizer.hasMoreTokens()) { + _bot.log("### " + tokenizer.nextToken()); + } + } + } + } + if (line == null) { + // The server must have disconnected us. + running = false; + } + } + catch (InterruptedIOException iioe) { + // This will happen if we haven't received anything from the server for a while. + // So we shall send it a ping to check that we are still connected. + this.sendRawLine("PING " + (System.currentTimeMillis() / 1000)); + // Now we go back to listening for stuff from the server... + } + } + } + catch (Exception e) { + // Do nothing. + } + + // If we reach this point, then we must have disconnected. + try { + _socket.close(); + } + catch (Exception e) { + // Just assume the socket was already closed. + } + + if (!_disposed) { + _bot.log("*** Disconnected."); + _isConnected = false; + _bot.onDisconnect(); + } + + } + + + /** + * Closes the socket without onDisconnect being called subsequently. + */ + public void dispose () { + try { + _disposed = true; + _socket.close(); + } + catch (Exception e) { + // Do nothing. + } + } + + private PircBot _bot = null; + private Socket _socket = null; + private BufferedReader _breader = null; + private BufferedWriter _bwriter = null; + private boolean _isConnected = true; + private boolean _disposed = false; + + public static final int MAX_LINE_LENGTH = 512; + +} diff --git a/src/org/jibble/pircbot/IrcException.java b/src/org/jibble/pircbot/IrcException.java index c34e9a1..a0dbcf7 100644 --- a/src/org/jibble/pircbot/IrcException.java +++ b/src/org/jibble/pircbot/IrcException.java @@ -1,36 +1,36 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - -package org.jibble.pircbot; - -/** - * An IrcException class. - * - * @since 0.9 - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class IrcException extends Exception { - private static final long serialVersionUID = -3705541066912475928L; - - /** - * Constructs a new IrcException. - * - * @param e The error message to report. - */ - public IrcException(String e) { - super(e); - } - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + +package org.jibble.pircbot; + +/** + * An IrcException class. + * + * @since 0.9 + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class IrcException extends Exception { + private static final long serialVersionUID = -3705541066912475928L; + + /** + * Constructs a new IrcException. + * + * @param e The error message to report. + */ + public IrcException(String e) { + super(e); + } + +} diff --git a/src/org/jibble/pircbot/NickAlreadyInUseException.java b/src/org/jibble/pircbot/NickAlreadyInUseException.java index 6e950ff..10343d2 100644 --- a/src/org/jibble/pircbot/NickAlreadyInUseException.java +++ b/src/org/jibble/pircbot/NickAlreadyInUseException.java @@ -1,39 +1,39 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -/** - * A NickAlreadyInUseException class. This exception is - * thrown when the PircBot attempts to join an IRC server - * with a user name that is already in use. - * - * @since 0.9 - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class NickAlreadyInUseException extends IrcException { - private static final long serialVersionUID = -4724325464519465479L; - - /** - * Constructs a new IrcException. - * - * @param e The error message to report. - */ - public NickAlreadyInUseException(String e) { - super(e); - } - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +/** + * A NickAlreadyInUseException class. This exception is + * thrown when the PircBot attempts to join an IRC server + * with a user name that is already in use. + * + * @since 0.9 + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class NickAlreadyInUseException extends IrcException { + private static final long serialVersionUID = -4724325464519465479L; + + /** + * Constructs a new IrcException. + * + * @param e The error message to report. + */ + public NickAlreadyInUseException(String e) { + super(e); + } + +} diff --git a/src/org/jibble/pircbot/OutputThread.java b/src/org/jibble/pircbot/OutputThread.java index e1e33bb..ffb4c5d 100644 --- a/src/org/jibble/pircbot/OutputThread.java +++ b/src/org/jibble/pircbot/OutputThread.java @@ -1,104 +1,104 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -import java.io.*; - -/** - * A Thread which is responsible for sending messages to the IRC server. - * Messages are obtained from the outgoing message queue and sent - * immediately if possible. If there is a flood of messages, then to - * avoid getting kicked from a channel, we put a small delay between - * each one. - * - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class OutputThread extends Thread { - - - /** - * Constructs an OutputThread for the underlying PircBot. All messages - * sent to the IRC server are sent by this OutputThread to avoid hammering - * the server. Messages are sent immediately if possible. If there are - * multiple messages queued, then there is a delay imposed. - * - * @param bot The underlying PircBot instance. - * @param outQueue The Queue from which we will obtain our messages. - */ - OutputThread(PircBot bot, Queue outQueue) { - _bot = bot; - _outQueue = outQueue; - this.setName(this.getClass() + "-Thread"); - } - - - /** - * A static method to write a line to a BufferedOutputStream and then pass - * the line to the log method of the supplied PircBot instance. - * - * @param bot The underlying PircBot instance. - * @param out The BufferedOutputStream to write to. - * @param line The line to be written. "\r\n" is appended to the end. - * @param encoding The charset to use when encoing this string into a - * byte array. - */ - static void sendRawLine(PircBot bot, BufferedWriter bwriter, String line) { - if (line.length() > bot.getMaxLineLength() - 2) { - line = line.substring(0, bot.getMaxLineLength() - 2); - } - synchronized(bwriter) { - try { - bwriter.write(line + "\r\n"); - bwriter.flush(); - bot.log(">>>" + line); - } - catch (Exception e) { - // Silent response - just lose the line. - } - } - } - - - /** - * This method starts the Thread consuming from the outgoing message - * Queue and sending lines to the server. - */ - public void run() { - try { - boolean running = true; - while (running) { - // Small delay to prevent spamming of the channel - Thread.sleep(_bot.getMessageDelay()); - - String line = (String) _outQueue.next(); - if (line != null) { - _bot.sendRawLine(line); - } - else { - running = false; - } - } - } - catch (InterruptedException e) { - // Just let the method return naturally... - } - } - - private PircBot _bot = null; - private Queue _outQueue = null; - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +import java.io.*; + +/** + * A Thread which is responsible for sending messages to the IRC server. + * Messages are obtained from the outgoing message queue and sent + * immediately if possible. If there is a flood of messages, then to + * avoid getting kicked from a channel, we put a small delay between + * each one. + * + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class OutputThread extends Thread { + + + /** + * Constructs an OutputThread for the underlying PircBot. All messages + * sent to the IRC server are sent by this OutputThread to avoid hammering + * the server. Messages are sent immediately if possible. If there are + * multiple messages queued, then there is a delay imposed. + * + * @param bot The underlying PircBot instance. + * @param outQueue The Queue from which we will obtain our messages. + */ + OutputThread(PircBot bot, Queue outQueue) { + _bot = bot; + _outQueue = outQueue; + this.setName(this.getClass() + "-Thread"); + } + + + /** + * A static method to write a line to a BufferedOutputStream and then pass + * the line to the log method of the supplied PircBot instance. + * + * @param bot The underlying PircBot instance. + * @param out The BufferedOutputStream to write to. + * @param line The line to be written. "\r\n" is appended to the end. + * @param encoding The charset to use when encoing this string into a + * byte array. + */ + static void sendRawLine(PircBot bot, BufferedWriter bwriter, String line) { + if (line.length() > bot.getMaxLineLength() - 2) { + line = line.substring(0, bot.getMaxLineLength() - 2); + } + synchronized(bwriter) { + try { + bwriter.write(line + "\r\n"); + bwriter.flush(); + bot.log(">>>" + line); + } + catch (Exception e) { + // Silent response - just lose the line. + } + } + } + + + /** + * This method starts the Thread consuming from the outgoing message + * Queue and sending lines to the server. + */ + public void run() { + try { + boolean running = true; + while (running) { + // Small delay to prevent spamming of the channel + Thread.sleep(_bot.getMessageDelay()); + + String line = (String) _outQueue.next(); + if (line != null) { + _bot.sendRawLine(line); + } + else { + running = false; + } + } + } + catch (InterruptedException e) { + // Just let the method return naturally... + } + } + + private PircBot _bot = null; + private Queue _outQueue = null; + +} diff --git a/src/org/jibble/pircbot/PircBot.java b/src/org/jibble/pircbot/PircBot.java index 95bb4cb..c059bab 100644 --- a/src/org/jibble/pircbot/PircBot.java +++ b/src/org/jibble/pircbot/PircBot.java @@ -1,3107 +1,3107 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -Modified by: Sebastian Kaspari - -*/ -package org.jibble.pircbot; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.StringTokenizer; - -import android.util.Log; - -/** - * PircBot is a Java framework for writing IRC bots quickly and easily. - *

- * It provides an event-driven architecture to handle common IRC - * events, flood protection, DCC support, ident support, and more. - * The comprehensive logfile format is suitable for use with pisg to generate - * channel statistics. - *

- * Methods of the PircBot class can be called to send events to the IRC server - * that it connects to. For example, calling the sendMessage method will - * send a message to a channel or user on the IRC server. Multiple servers - * can be supported using multiple instances of PircBot. - *

- * To perform an action when the PircBot receives a normal message from the IRC - * server, you would override the onMessage method defined in the PircBot - * class. All onXYZ methods in the PircBot class are automatically called - * when the event XYZ happens, so you would override these if you wish - * to do something when it does happen. - *

- * Some event methods, such as onPing, should only really perform a specific - * function (i.e. respond to a PING from the server). For your convenience, such - * methods are already correctly implemented in the PircBot and should not - * normally need to be overridden. Please read the full documentation for each - * method to see which ones are already implemented by the PircBot class. - *

- * Please visit the PircBot homepage at - * http://www.jibble.org/pircbot.php - * for full revision history, a beginners guide to creating your first PircBot - * and a list of some existing Java IRC bots and clients that use the PircBot - * framework. - * - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public abstract class PircBot implements ReplyConstants { - public static final String TAG = "Yaaic/PircBot"; - /** - * The definitive version number of this release of PircBot. - * (Note: Change this before automatically building releases) - */ - public static final String VERSION = "1.4.6"; - - private static final int OP_ADD = 1; - private static final int OP_REMOVE = 2; - private static final int VOICE_ADD = 3; - private static final int VOICE_REMOVE = 4; - - /** - * Constructs a PircBot with the default settings. Your own constructors - * in classes which extend the PircBot abstract class should be responsible - * for changing the default settings if required. - */ - public PircBot() {} - - /** - * Attempt to connect to the specified IRC server. - * The onConnect method is called upon success. - * - * @param hostname The hostname of the server to connect to. - * - * @throws IOException if it was not possible to connect to the server. - * @throws IrcException if the server would not let us join it. - * @throws NickAlreadyInUseException if our nick is already in use on the server. - */ - public final synchronized void connect(String hostname) throws IOException, IrcException, NickAlreadyInUseException { - this.connect(hostname, 6667, null); - } - - - /** - * Attempt to connect to the specified IRC server and port number. - * The onConnect method is called upon success. - * - * @param hostname The hostname of the server to connect to. - * @param port The port number to connect to on the server. - * - * @throws IOException if it was not possible to connect to the server. - * @throws IrcException if the server would not let us join it. - * @throws NickAlreadyInUseException if our nick is already in use on the server. - */ - public final synchronized void connect(String hostname, int port) throws IOException, IrcException, NickAlreadyInUseException { - this.connect(hostname, port, null); - } - - - /** - * Attempt to connect to the specified IRC server using the supplied - * password. - * The onConnect method is called upon success. - * - * @param hostname The hostname of the server to connect to. - * @param port The port number to connect to on the server. - * @param password The password to use to join the server. - * - * @throws IOException if it was not possible to connect to the server. - * @throws IrcException if the server would not let us join it. - * @throws NickAlreadyInUseException if our nick is already in use on the server. - */ - public final synchronized void connect(String hostname, int port, String password) throws IOException, IrcException, NickAlreadyInUseException { - - _server = hostname; - _port = port; - _password = password; - - if (isConnected()) { - throw new IOException("The PircBot is already connected to an IRC server. Disconnect first."); - } - - // Don't clear the outqueue - there might be something important in it! - - // Clear everything we may have know about channels. - this.removeAllChannels(); - - // Connect to the server. - Socket socket = new Socket(hostname, port); - this.log("*** Connected to server."); - - _inetAddress = socket.getLocalAddress(); - - InputStreamReader inputStreamReader = null; - OutputStreamWriter outputStreamWriter = null; - if (getEncoding() != null) { - // Assume the specified encoding is valid for this JVM. - inputStreamReader = new InputStreamReader(socket.getInputStream(), getEncoding()); - outputStreamWriter = new OutputStreamWriter(socket.getOutputStream(), getEncoding()); - } - else { - // Otherwise, just use the JVM's default encoding. - inputStreamReader = new InputStreamReader(socket.getInputStream()); - outputStreamWriter = new OutputStreamWriter(socket.getOutputStream()); - } - - BufferedReader breader = new BufferedReader(inputStreamReader); - BufferedWriter bwriter = new BufferedWriter(outputStreamWriter); - - // Attempt to join the server. - if (password != null && !password.equals("")) { - OutputThread.sendRawLine(this, bwriter, "PASS " + password); - } - String nick = this.getName(); - OutputThread.sendRawLine(this, bwriter, "NICK " + nick); - OutputThread.sendRawLine(this, bwriter, "USER " + this.getLogin() + " 8 * :" + this.getVersion()); - - _inputThread = new InputThread(this, socket, breader, bwriter); - - // Read stuff back from the server to see if we connected. - String line = null; - int tries = 1; - while ((line = breader.readLine()) != null) { - - this.handleLine(line); - - int firstSpace = line.indexOf(" "); - int secondSpace = line.indexOf(" ", firstSpace + 1); - if (secondSpace >= 0) { - String code = line.substring(firstSpace + 1, secondSpace); - - if (code.equals("004")) { - // We're connected to the server. - break; - } - else if (code.equals("433")) { - if (_autoNickChange) { - tries++; - nick = getName() + tries; - OutputThread.sendRawLine(this, bwriter, "NICK " + nick); - } - else { - socket.close(); - _inputThread = null; - throw new NickAlreadyInUseException(line); - } - } - else if (code.startsWith("5") || code.startsWith("4")) { - socket.close(); - _inputThread = null; - throw new IrcException("Could not log into the IRC server: " + line); - } - } - this.setNick(nick); - - } - - this.log("*** Logged onto server."); - - // This makes the socket timeout on read operations after 5 minutes. - // Maybe in some future version I will let the user change this at runtime. - socket.setSoTimeout(5 * 60 * 1000); - - // Now start the InputThread to read all other lines from the server. - _inputThread.start(); - - // Now start the outputThread that will be used to send all messages. - if (_outputThread == null) { - _outputThread = new OutputThread(this, _outQueue); - _outputThread.start(); - } - - this.onConnect(); - - } - - - /** - * Reconnects to the IRC server that we were previously connected to. - * If necessary, the appropriate port number and password will be used. - * This method will throw an IrcException if we have never connected - * to an IRC server previously. - * - * @since PircBot 0.9.9 - * - * @throws IOException if it was not possible to connect to the server. - * @throws IrcException if the server would not let us join it. - * @throws NickAlreadyInUseException if our nick is already in use on the server. - */ - public final synchronized void reconnect() throws IOException, IrcException, NickAlreadyInUseException{ - if (getServer() == null) { - throw new IrcException("Cannot reconnect to an IRC server because we were never connected to one previously!"); - } - connect(getServer(), getPort(), getPassword()); - } - - - /** - * This method disconnects from the server cleanly by calling the - * quitServer() method. Providing the PircBot was connected to an - * IRC server, the onDisconnect() will be called as soon as the - * disconnection is made by the server. - * - * @see #quitServer() quitServer - * @see #quitServer(String) quitServer - */ - public final synchronized void disconnect() { - this.quitServer(); - } - - - /** - * When you connect to a server and your nick is already in use and - * this is set to true, a new nick will be automatically chosen. - * This is done by adding numbers to the end of the nick until an - * available nick is found. - * - * @param autoNickChange Set to true if you want automatic nick changes - * during connection. - */ - public void setAutoNickChange(boolean autoNickChange) { - _autoNickChange = autoNickChange; - } - - - /** - * Starts an ident server (Identification Protocol Server, RFC 1413). - *

- * Most IRC servers attempt to contact the ident server on connecting - * hosts in order to determine the user's identity. A few IRC servers - * will not allow you to connect unless this information is provided. - *

- * So when a PircBot is run on a machine that does not run an ident server, - * it may be necessary to call this method to start one up. - *

- * Calling this method starts up an ident server which will respond with - * the login provided by calling getLogin() and then shut down immediately. - * It will also be shut down if it has not been contacted within 60 seconds - * of creation. - *

- * If you require an ident response, then the correct procedure is to start - * the ident server and then connect to the IRC server. The IRC server may - * then contact the ident server to get the information it needs. - *

- * The ident server will fail to start if there is already an ident server - * running on port 113, or if you are running as an unprivileged user who - * is unable to create a server socket on that port number. - *

- * If it is essential for you to use an ident server when connecting to an - * IRC server, then make sure that port 113 on your machine is visible to - * the IRC server so that it may contact the ident server. - * - * @since PircBot 0.9c - */ - public final void startIdentServer() { - new IdentServer(this, getLogin()); - } - - - /** - * Joins a channel. - * - * @param channel The name of the channel to join (eg "#cs"). - */ - public final void joinChannel(String channel) { - this.sendRawLine("JOIN " + channel); - } - - - /** - * Joins a channel with a key. - * - * @param channel The name of the channel to join (eg "#cs"). - * @param key The key that will be used to join the channel. - */ - public final void joinChannel(String channel, String key) { - this.joinChannel(channel + " " + key); - } - - - /** - * Parts a channel. - * - * @param channel The name of the channel to leave. - */ - public final void partChannel(String channel) { - this.sendRawLine("PART " + channel); - } - - - /** - * Parts a channel, giving a reason. - * - * @param channel The name of the channel to leave. - * @param reason The reason for parting the channel. - */ - public final void partChannel(String channel, String reason) { - this.sendRawLine("PART " + channel + " :" + reason); - } - - - /** - * Quits from the IRC server. - * Providing we are actually connected to an IRC server, the - * onDisconnect() method will be called as soon as the IRC server - * disconnects us. - */ - public void quitServer() { - this.quitServer(""); - } - - - /** - * Quits from the IRC server with a reason. - * Providing we are actually connected to an IRC server, the - * onDisconnect() method will be called as soon as the IRC server - * disconnects us. - * - * @param reason The reason for quitting the server. - */ - public final void quitServer(String reason) { - this.sendRawLine("QUIT :" + reason); - } - - - /** - * Sends a raw line to the IRC server as soon as possible, bypassing the - * outgoing message queue. - * - * @param line The raw line to send to the IRC server. - */ - public final synchronized void sendRawLine(String line) { - if (isConnected()) { - _inputThread.sendRawLine(line); - } - } - - /** - * Sends a raw line through the outgoing message queue. - * - * @param line The raw line to send to the IRC server. - */ - public final synchronized void sendRawLineViaQueue(String line) { - if (line == null) { - throw new NullPointerException("Cannot send null messages to server"); - } - if (isConnected()) { - _outQueue.add(line); - } - } - - - /** - * Sends a message to a channel or a private message to a user. These - * messages are added to the outgoing message queue and sent at the - * earliest possible opportunity. - *

- * Some examples: - - *

    // Send the message "Hello!" to the channel #cs.
-     *    sendMessage("#cs", "Hello!");
-     *    
-     *    // Send a private message to Paul that says "Hi".
-     *    sendMessage("Paul", "Hi");
- * - * You may optionally apply colours, boldness, underlining, etc to - * the message by using the Colors class. - * - * @param target The name of the channel or user nick to send to. - * @param message The message to send. - * - * @see Colors - */ - public final void sendMessage(String target, String message) { - _outQueue.add("PRIVMSG " + target + " :" + message); - } - - - /** - * Sends an action to the channel or to a user. - * - * @param target The name of the channel or user nick to send to. - * @param action The action to send. - * - * @see Colors - */ - public final void sendAction(String target, String action) { - sendCTCPCommand(target, "ACTION " + action); - } - - - /** - * Sends a notice to the channel or to a user. - * - * @param target The name of the channel or user nick to send to. - * @param notice The notice to send. - */ - public final void sendNotice(String target, String notice) { - _outQueue.add("NOTICE " + target + " :" + notice); - } - - - /** - * Sends a CTCP command to a channel or user. (Client to client protocol). - * Examples of such commands are "PING ", "FINGER", "VERSION", etc. - * For example, if you wish to request the version of a user called "Dave", - * then you would call sendCTCPCommand("Dave", "VERSION");. - * The type of response to such commands is largely dependant on the target - * client software. - * - * @since PircBot 0.9.5 - * - * @param target The name of the channel or user to send the CTCP message to. - * @param command The CTCP command to send. - */ - public final void sendCTCPCommand(String target, String command) { - _outQueue.add("PRIVMSG " + target + " :\u0001" + command + "\u0001"); - } - - - /** - * Attempt to change the current nick (nickname) of the bot when it - * is connected to an IRC server. - * After confirmation of a successful nick change, the getNick method - * will return the new nick. - * - * @param newNick The new nick to use. - */ - public final void changeNick(String newNick) { - this.sendRawLine("NICK " + newNick); - } - - - /** - * Identify the bot with NickServ, supplying the appropriate password. - * Some IRC Networks (such as freenode) require users to register and - * identify with NickServ before they are able to send private messages - * to other users, thus reducing the amount of spam. If you are using - * an IRC network where this kind of policy is enforced, you will need - * to make your bot identify itself to NickServ before you can send - * private messages. Assuming you have already registered your bot's - * nick with NickServ, this method can be used to identify with - * the supplied password. It usually makes sense to identify with NickServ - * immediately after connecting to a server. - *

- * This method issues a raw NICKSERV command to the server, and is therefore - * safer than the alternative approach of sending a private message to - * NickServ. The latter approach is considered dangerous, as it may cause - * you to inadvertently transmit your password to an untrusted party if you - * connect to a network which does not run a NickServ service and where the - * untrusted party has assumed the nick "NickServ". However, if your IRC - * network is only compatible with the private message approach, you may - * typically identify like so: - *

sendMessage("NickServ", "identify PASSWORD");
- * - * @param password The password which will be used to identify with NickServ. - */ - public final void identify(String password) { - this.sendRawLine("NICKSERV IDENTIFY " + password); - } - - - /** - * Set the mode of a channel. - * This method attempts to set the mode of a channel. This - * may require the bot to have operator status on the channel. - * For example, if the bot has operator status, we can grant - * operator status to "Dave" on the #cs channel - * by calling setMode("#cs", "+o Dave"); - * An alternative way of doing this would be to use the op method. - * - * @param channel The channel on which to perform the mode change. - * @param mode The new mode to apply to the channel. This may include - * zero or more arguments if necessary. - * - * @see #op(String,String) op - */ - public final void setMode(String channel, String mode) { - this.sendRawLine("MODE " + channel + " " + mode); - } - - - /** - * Sends an invitation to join a channel. Some channels can be marked - * as "invite-only", so it may be useful to allow a bot to invite people - * into it. - * - * @param nick The nick of the user to invite - * @param channel The channel you are inviting the user to join. - * - */ - public final void sendInvite(String nick, String channel) { - this.sendRawLine("INVITE " + nick + " :" + channel); - } - - - /** - * Bans a user from a channel. An example of a valid hostmask is - * "*!*compu@*.18hp.net". This may be used in conjunction with the - * kick method to permanently remove a user from a channel. - * Successful use of this method may require the bot to have operator - * status itself. - * - * @param channel The channel to ban the user from. - * @param hostmask A hostmask representing the user we're banning. - */ - public final void ban(String channel, String hostmask) { - this.sendRawLine("MODE " + channel + " +b " + hostmask); - } - - - /** - * Unbans a user from a channel. An example of a valid hostmask is - * "*!*compu@*.18hp.net". - * Successful use of this method may require the bot to have operator - * status itself. - * - * @param channel The channel to unban the user from. - * @param hostmask A hostmask representing the user we're unbanning. - */ - public final void unBan(String channel, String hostmask) { - this.sendRawLine("MODE " + channel + " -b " + hostmask); - } - - - /** - * Grants operator privilidges to a user on a channel. - * Successful use of this method may require the bot to have operator - * status itself. - * - * @param channel The channel we're opping the user on. - * @param nick The nick of the user we are opping. - */ - public final void op(String channel, String nick) { - this.setMode(channel, "+o " + nick); - } - - - /** - * Removes operator privilidges from a user on a channel. - * Successful use of this method may require the bot to have operator - * status itself. - * - * @param channel The channel we're deopping the user on. - * @param nick The nick of the user we are deopping. - */ - public final void deOp(String channel, String nick) { - this.setMode(channel, "-o " + nick); - } - - - /** - * Grants voice privilidges to a user on a channel. - * Successful use of this method may require the bot to have operator - * status itself. - * - * @param channel The channel we're voicing the user on. - * @param nick The nick of the user we are voicing. - */ - public final void voice(String channel, String nick) { - this.setMode(channel, "+v " + nick); - } - - - /** - * Removes voice privilidges from a user on a channel. - * Successful use of this method may require the bot to have operator - * status itself. - * - * @param channel The channel we're devoicing the user on. - * @param nick The nick of the user we are devoicing. - */ - public final void deVoice(String channel, String nick) { - this.setMode(channel, "-v " + nick); - } - - - /** - * Set the topic for a channel. - * This method attempts to set the topic of a channel. This - * may require the bot to have operator status if the topic - * is protected. - * - * @param channel The channel on which to perform the mode change. - * @param topic The new topic for the channel. - * - */ - public final void setTopic(String channel, String topic) { - this.sendRawLine("TOPIC " + channel + " :" + topic); - } - - - /** - * Kicks a user from a channel. - * This method attempts to kick a user from a channel and - * may require the bot to have operator status in the channel. - * - * @param channel The channel to kick the user from. - * @param nick The nick of the user to kick. - */ - public final void kick(String channel, String nick) { - this.kick(channel, nick, ""); - } - - - /** - * Kicks a user from a channel, giving a reason. - * This method attempts to kick a user from a channel and - * may require the bot to have operator status in the channel. - * - * @param channel The channel to kick the user from. - * @param nick The nick of the user to kick. - * @param reason A description of the reason for kicking a user. - */ - public final void kick(String channel, String nick, String reason) { - this.sendRawLine("KICK " + channel + " " + nick + " :" + reason); - } - - - /** - * Issues a request for a list of all channels on the IRC server. - * When the PircBot receives information for each channel, it will - * call the onChannelInfo method, which you will need to override - * if you want it to do anything useful. - * - * @see #onChannelInfo(String,int,String) onChannelInfo - */ - public final void listChannels() { - this.listChannels(null); - } - - - /** - * Issues a request for a list of all channels on the IRC server. - * When the PircBot receives information for each channel, it will - * call the onChannelInfo method, which you will need to override - * if you want it to do anything useful. - *

- * Some IRC servers support certain parameters for LIST requests. - * One example is a parameter of ">10" to list only those channels - * that have more than 10 users in them. Whether these parameters - * are supported or not will depend on the IRC server software. - * - * @param parameters The parameters to supply when requesting the - * list. - * - * @see #onChannelInfo(String,int,String) onChannelInfo - */ - public final void listChannels(String parameters) { - if (parameters == null) { - this.sendRawLine("LIST"); - } - else { - this.sendRawLine("LIST " + parameters); - } - } - - - /** - * Sends a file to another user. Resuming is supported. - * The other user must be able to connect directly to your bot to be - * able to receive the file. - *

- * You may throttle the speed of this file transfer by calling the - * setPacketDelay method on the DccFileTransfer that is returned. - *

- * This method may not be overridden. - * - * @since 0.9c - * - * @param file The file to send. - * @param nick The user to whom the file is to be sent. - * @param timeout The number of milliseconds to wait for the recipient to - * acccept the file (we recommend about 120000). - * - * @return The DccFileTransfer that can be used to monitor this transfer. - * - * @see DccFileTransfer - * - */ - public final DccFileTransfer dccSendFile(File file, String nick, int timeout) { - DccFileTransfer transfer = new DccFileTransfer(this, _dccManager, file, nick, timeout); - transfer.doSend(true); - return transfer; - } - - - /** - * Receives a file that is being sent to us by a DCC SEND request. - * Please use the onIncomingFileTransfer method to receive files. - * - * @deprecated As of PircBot 1.2.0, use {@link #onIncomingFileTransfer(DccFileTransfer)} - */ - protected final void dccReceiveFile(File file, long address, int port, int size) { - throw new RuntimeException("dccReceiveFile is deprecated, please use sendFile"); - } - - - /** - * Attempts to establish a DCC CHAT session with a client. This method - * issues the connection request to the client and then waits for the - * client to respond. If the connection is successfully made, then a - * DccChat object is returned by this method. If the connection is not - * made within the time limit specified by the timeout value, then null - * is returned. - *

- * It is strongly recommended that you call this method within a new - * Thread, as it may take a long time to return. - *

- * This method may not be overridden. - * - * @since PircBot 0.9.8 - * - * @param nick The nick of the user we are trying to establish a chat with. - * @param timeout The number of milliseconds to wait for the recipient to - * accept the chat connection (we recommend about 120000). - * - * @return a DccChat object that can be used to send and recieve lines of - * text. Returns null if the connection could not be made. - * - * @see DccChat - */ - public final DccChat dccSendChatRequest(String nick, int timeout) { - DccChat chat = null; - try { - ServerSocket ss = null; - - int[] ports = getDccPorts(); - if (ports == null) { - // Use any free port. - ss = new ServerSocket(0); - } - else { - for (int i = 0; i < ports.length; i++) { - try { - ss = new ServerSocket(ports[i]); - // Found a port number we could use. - break; - } - catch (Exception e) { - // Do nothing; go round and try another port. - } - } - if (ss == null) { - // No ports could be used. - throw new IOException("All ports returned by getDccPorts() are in use."); - } - } - - ss.setSoTimeout(timeout); - int port = ss.getLocalPort(); - - InetAddress inetAddress = getDccInetAddress(); - if (inetAddress == null) { - inetAddress = getInetAddress(); - } - byte[] ip = inetAddress.getAddress(); - long ipNum = ipToLong(ip); - - sendCTCPCommand(nick, "DCC CHAT chat " + ipNum + " " + port); - - // The client may now connect to us to chat. - Socket socket = ss.accept(); - - // Close the server socket now that we've finished with it. - ss.close(); - - chat = new DccChat(this, nick, socket); - } - catch (Exception e) { - // Do nothing. - } - return chat; - } - - - /** - * Attempts to accept a DCC CHAT request by a client. - * Please use the onIncomingChatRequest method to receive files. - * - * @deprecated As of PircBot 1.2.0, use {@link #onIncomingChatRequest(DccChat)} - */ - protected final DccChat dccAcceptChatRequest(String sourceNick, long address, int port) { - throw new RuntimeException("dccAcceptChatRequest is deprecated, please use onIncomingChatRequest"); - } - - - /** - * Adds a line to the log. This log is currently output to the standard - * output and is in the correct format for use by tools such as pisg, the - * Perl IRC Statistics Generator. You may override this method if you wish - * to do something else with log entries. - * Each line in the log begins with a number which - * represents the logging time (as the number of milliseconds since the - * epoch). This timestamp and the following log entry are separated by - * a single space character, " ". Outgoing messages are distinguishable - * by a log entry that has ">>>" immediately following the space character - * after the timestamp. DCC events use "+++" and warnings about unhandled - * Exceptions and Errors use "###". - *

- * This implementation of the method will only cause log entries to be - * output if the PircBot has had its verbose mode turned on by calling - * setVerbose(true); - * - * @param line The line to add to the log. - */ - public void log(String line) { - if (_verbose) { - // XXX: PircBot Patch: Log to debug log instead of standard output - Log.d(TAG, line); - //System.out.println(System.currentTimeMillis() + " " + line); - } - } - - - /** - * This method handles events when any line of text arrives from the server, - * then calling the appropriate method in the PircBot. This method is - * protected and only called by the InputThread for this instance. - *

- * This method may not be overridden! - * - * @param line The raw line of text from the server. - */ - protected void handleLine(String line) { - this.log(line); - - // Check for server pings. - if (line.startsWith("PING ")) { - // Respond to the ping and return immediately. - this.onServerPing(line.substring(5)); - return; - } - - 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); - } - else { - - if (tokenizer.hasMoreTokens()) { - String token = command; - - int code = -1; - try { - code = Integer.parseInt(token); - } - catch (NumberFormatException e) { - // Keep the existing value. - } - - if (code != -1) { - String errorStr = token; - String response = line.substring(line.indexOf(errorStr, senderInfo.length()) + 4, line.length()); - this.processServerResponse(code, response); - // Return from the method. - return; - } - else { - // This is not a server response. - // It must be a nick without login and hostname. - // (or maybe a NOTICE or suchlike from the server) - sourceNick = senderInfo; - target = token; - } - } - else { - // We don't know what this line means. - this.onUnknown(line); - // Return from the method; - return; - } - - } - } - - command = command.toUpperCase(); - if (sourceNick.startsWith(":")) { - sourceNick = sourceNick.substring(1); - } - if (target == null) { - target = tokenizer.nextToken(); - } - if (target.startsWith(":")) { - target = target.substring(1); - } - - // Check for CTCP requests. - if (command.equals("PRIVMSG") && line.indexOf(":\u0001") > 0 && line.endsWith("\u0001")) { - String request = line.substring(line.indexOf(":\u0001") + 2, line.length() - 1); - if (request.equals("VERSION")) { - // VERSION request - this.onVersion(sourceNick, sourceLogin, sourceHostname, target); - } - else if (request.startsWith("ACTION ")) { - // ACTION request - this.onAction(sourceNick, sourceLogin, sourceHostname, target, request.substring(7)); - } - else if (request.startsWith("PING ")) { - // PING request - this.onPing(sourceNick, sourceLogin, sourceHostname, target, request.substring(5)); - } - else if (request.equals("TIME")) { - // TIME request - this.onTime(sourceNick, sourceLogin, sourceHostname, target); - } - else if (request.equals("FINGER")) { - // FINGER request - this.onFinger(sourceNick, sourceLogin, sourceHostname, target); - } - else if ((tokenizer = new StringTokenizer(request)).countTokens() >= 5 && tokenizer.nextToken().equals("DCC")) { - // This is a DCC request. - boolean success = _dccManager.processRequest(sourceNick, sourceLogin, sourceHostname, request); - if (!success) { - // The DccManager didn't know what to do with the line. - this.onUnknown(line); - } - } - else { - // An unknown CTCP message - ignore it. - this.onUnknown(line); - } - } - else if (command.equals("PRIVMSG") && _channelPrefixes.indexOf(target.charAt(0)) >= 0) { - // This is a normal message to a channel. - this.onMessage(target, sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); - } - else if (command.equals("PRIVMSG")) { - // This is a private message to us. - this.onPrivateMessage(sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); - } - else if (command.equals("JOIN")) { - // Someone is joining a channel. - String channel = target; - this.addUser(channel, new User("", sourceNick)); - this.onJoin(channel, sourceNick, sourceLogin, sourceHostname); - } - else if (command.equals("PART")) { - // Someone is parting from a channel. - this.removeUser(target, sourceNick); - if (sourceNick.equals(this.getNick())) { - this.removeChannel(target); - } - this.onPart(target, sourceNick, sourceLogin, sourceHostname); - } - else if (command.equals("NICK")) { - // Somebody is changing their nick. - String newNick = target; - this.renameUser(sourceNick, newNick); - if (sourceNick.equals(this.getNick())) { - // Update our nick if it was us that changed nick. - this.setNick(newNick); - } - this.onNickChange(sourceNick, sourceLogin, sourceHostname, newNick); - } - else if (command.equals("NOTICE")) { - // Someone is sending a notice. - this.onNotice(sourceNick, sourceLogin, sourceHostname, target, line.substring(line.indexOf(" :") + 2)); - } - else if (command.equals("QUIT")) { - // Someone has quit from the IRC server. - - // XXX: Pircbot Patch - Call onQuit before removing the user. This way we - // are able to know which channels the user was on. - this.onQuit(sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); - - if (sourceNick.equals(this.getNick())) { - this.removeAllChannels(); - } - else { - this.removeUser(sourceNick); - } - } - else if (command.equals("KICK")) { - // Somebody has been kicked from a channel. - String recipient = tokenizer.nextToken(); - if (recipient.equals(this.getNick())) { - this.removeChannel(target); - } - this.removeUser(target, recipient); - this.onKick(target, sourceNick, sourceLogin, sourceHostname, recipient, line.substring(line.indexOf(" :") + 2)); - } - else if (command.equals("MODE")) { - // Somebody is changing the mode on a channel or user. - String mode = line.substring(line.indexOf(target, 2) + target.length() + 1); - if (mode.startsWith(":")) { - mode = mode.substring(1); - } - this.processMode(target, sourceNick, sourceLogin, sourceHostname, mode); - } - else if (command.equals("TOPIC")) { - // Someone is changing the topic. - this.onTopic(target, line.substring(line.indexOf(" :") + 2), sourceNick, System.currentTimeMillis(), true); - } - else if (command.equals("INVITE")) { - // Somebody is inviting somebody else into a channel. - this.onInvite(target, sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); - } - else { - // If we reach this point, then we've found something that the PircBot - // Doesn't currently deal with. - this.onUnknown(line); - } - - } - - - /** - * This method is called once the PircBot has successfully connected to - * the IRC server. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.6 - */ - protected void onConnect() {} - - - /** - * This method carries out the actions to be performed when the PircBot - * gets disconnected. This may happen if the PircBot quits from the - * server, or if the connection is unexpectedly lost. - *

- * Disconnection from the IRC server is detected immediately if either - * we or the server close the connection normally. If the connection to - * the server is lost, but neither we nor the server have explicitly closed - * the connection, then it may take a few minutes to detect (this is - * commonly referred to as a "ping timeout"). - *

- * If you wish to get your IRC bot to automatically rejoin a server after - * the connection has been lost, then this is probably the ideal method to - * override to implement such functionality. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - */ - protected void onDisconnect() {} - - - /** - * This method is called by the PircBot when a numeric response - * is received from the IRC server. We use this method to - * allow PircBot to process various responses from the server - * before then passing them on to the onServerResponse method. - *

- * Note that this method is private and should not appear in any - * of the javadoc generated documenation. - * - * @param code The three-digit numerical code for the response. - * @param response The full response from the IRC server. - */ - private final void processServerResponse(int code, String response) { - - if (code == RPL_LIST) { - // This is a bit of information about a channel. - int firstSpace = response.indexOf(' '); - int secondSpace = response.indexOf(' ', firstSpace + 1); - int thirdSpace = response.indexOf(' ', secondSpace + 1); - int colon = response.indexOf(':'); - String channel = response.substring(firstSpace + 1, secondSpace); - int userCount = 0; - try { - userCount = Integer.parseInt(response.substring(secondSpace + 1, thirdSpace)); - } - catch (NumberFormatException e) { - // Stick with the value of zero. - } - String topic = response.substring(colon + 1); - this.onChannelInfo(channel, userCount, topic); - } - else if (code == RPL_TOPIC) { - // This is topic information about a channel we've just joined. - int firstSpace = response.indexOf(' '); - int secondSpace = response.indexOf(' ', firstSpace + 1); - int colon = response.indexOf(':'); - String channel = response.substring(firstSpace + 1, secondSpace); - String topic = response.substring(colon + 1); - - _topics.put(channel, topic); - - // For backwards compatibility only - this onTopic method is deprecated. - this.onTopic(channel, topic); - } - else if (code == RPL_TOPICINFO) { - StringTokenizer tokenizer = new StringTokenizer(response); - tokenizer.nextToken(); - String channel = tokenizer.nextToken(); - String setBy = tokenizer.nextToken(); - long date = 0; - try { - date = Long.parseLong(tokenizer.nextToken()) * 1000; - } - catch (NumberFormatException e) { - // Stick with the default value of zero. - } - - String topic = (String) _topics.get(channel); - _topics.remove(channel); - - this.onTopic(channel, topic, setBy, date, false); - } - else if (code == RPL_NAMREPLY) { - // This is a list of nicks in a channel that we've just joined. - int channelEndIndex = response.indexOf(" :"); - String channel = response.substring(response.lastIndexOf(' ', channelEndIndex - 1) + 1, channelEndIndex); - - StringTokenizer tokenizer = new StringTokenizer(response.substring(response.indexOf(" :") + 2)); - while (tokenizer.hasMoreTokens()) { - String nick = tokenizer.nextToken(); - String prefix = ""; - if (nick.startsWith("@")) { - // User is an operator in this channel. - prefix = "@"; - } - else if (nick.startsWith("+")) { - // User is voiced in this channel. - prefix = "+"; - } - else if (nick.startsWith(".")) { - // Some wibbly status I've never seen before... - prefix = "."; - } - nick = nick.substring(prefix.length()); - this.addUser(channel, new User(prefix, nick)); - } - } - else if (code == RPL_ENDOFNAMES) { - // This is the end of a NAMES list, so we know that we've got - // the full list of users in the channel that we just joined. - String channel = response.substring(response.indexOf(' ') + 1, response.indexOf(" :")); - User[] users = this.getUsers(channel); - this.onUserList(channel, users); - } - - this.onServerResponse(code, response); - } - - - /** - * This method is called when we receive a numeric response from the - * IRC server. - *

- * Numerics in the range from 001 to 099 are used for client-server - * connections only and should never travel between servers. Replies - * generated in response to commands are found in the range from 200 - * to 399. Error replies are found in the range from 400 to 599. - *

- * For example, we can use this method to discover the topic of a - * channel when we join it. If we join the channel #test which - * has a topic of "I am King of Test" then the response - * will be "PircBot #test :I Am King of Test" - * with a code of 332 to signify that this is a topic. - * (This is just an example - note that overriding the - * onTopic method is an easier way of finding the - * topic for a channel). Check the IRC RFC for the full list of other - * command response codes. - *

- * PircBot implements the interface ReplyConstants, which contains - * contstants that you may find useful here. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param code The three-digit numerical code for the response. - * @param response The full response from the IRC server. - * - * @see ReplyConstants - */ - protected void onServerResponse(int code, String response) {} - - - /** - * This method is called when we receive a user list from the server - * after joining a channel. - *

- * Shortly after joining a channel, the IRC server sends a list of all - * users in that channel. The PircBot collects this information and - * calls this method as soon as it has the full list. - *

- * To obtain the nick of each user in the channel, call the getNick() - * method on each User object in the array. - *

- * At a later time, you may call the getUsers method to obtain an - * up to date list of the users in the channel. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 1.0.0 - * - * @param channel The name of the channel. - * @param users An array of User objects belonging to this channel. - * - * @see User - */ - protected void onUserList(String channel, User[] users) {} - - - /** - * This method is called whenever a message is sent to a channel. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The channel to which the message was sent. - * @param sender The nick of the person who sent the message. - * @param login The login of the person who sent the message. - * @param hostname The hostname of the person who sent the message. - * @param message The actual message sent to the channel. - */ - protected void onMessage(String channel, String sender, String login, String hostname, String message) {} - - - /** - * This method is called whenever a private message is sent to the PircBot. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param sender The nick of the person who sent the private message. - * @param login The login of the person who sent the private message. - * @param hostname The hostname of the person who sent the private message. - * @param message The actual message. - */ - protected void onPrivateMessage(String sender, String login, String hostname, String message) {} - - - /** - * This method is called whenever an ACTION is sent from a user. E.g. - * such events generated by typing "/me goes shopping" in most IRC clients. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param sender The nick of the user that sent the action. - * @param login The login of the user that sent the action. - * @param hostname The hostname of the user that sent the action. - * @param target The target of the action, be it a channel or our nick. - * @param action The action carried out by the user. - */ - protected void onAction(String sender, String login, String hostname, String target, String action) {} - - - /** - * This method is called whenever we receive a notice. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param sourceNick The nick of the user that sent the notice. - * @param sourceLogin The login of the user that sent the notice. - * @param sourceHostname The hostname of the user that sent the notice. - * @param target The target of the notice, be it our nick or a channel name. - * @param notice The notice message. - */ - protected void onNotice(String sourceNick, String sourceLogin, String sourceHostname, String target, String notice) {} - - - /** - * This method is called whenever someone (possibly us) joins a channel - * which we are on. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The channel which somebody joined. - * @param sender The nick of the user who joined the channel. - * @param login The login of the user who joined the channel. - * @param hostname The hostname of the user who joined the channel. - */ - protected void onJoin(String channel, String sender, String login, String hostname) {} - - - /** - * This method is called whenever someone (possibly us) parts a channel - * which we are on. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The channel which somebody parted from. - * @param sender The nick of the user who parted from the channel. - * @param login The login of the user who parted from the channel. - * @param hostname The hostname of the user who parted from the channel. - */ - protected void onPart(String channel, String sender, String login, String hostname) {} - - - /** - * This method is called whenever someone (possibly us) changes nick on any - * of the channels that we are on. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param oldNick The old nick. - * @param login The login of the user. - * @param hostname The hostname of the user. - * @param newNick The new nick. - */ - protected void onNickChange(String oldNick, String login, String hostname, String newNick) {} - - - /** - * This method is called whenever someone (possibly us) is kicked from - * any of the channels that we are in. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The channel from which the recipient was kicked. - * @param kickerNick The nick of the user who performed the kick. - * @param kickerLogin The login of the user who performed the kick. - * @param kickerHostname The hostname of the user who performed the kick. - * @param recipientNick The unfortunate recipient of the kick. - * @param reason The reason given by the user who performed the kick. - */ - protected void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {} - - - /** - * This method is called whenever someone (possibly us) quits from the - * server. We will only observe this if the user was in one of the - * channels to which we are connected. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param sourceNick The nick of the user that quit from the server. - * @param sourceLogin The login of the user that quit from the server. - * @param sourceHostname The hostname of the user that quit from the server. - * @param reason The reason given for quitting the server. - */ - protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {} - - - /** - * This method is called whenever a user sets the topic, or when - * PircBot joins a new channel and discovers its topic. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The channel that the topic belongs to. - * @param topic The topic for the channel. - * - * @deprecated As of 1.2.0, replaced by {@link #onTopic(String,String,String,long,boolean)} - */ - protected void onTopic(String channel, String topic) {} - - - /** - * This method is called whenever a user sets the topic, or when - * PircBot joins a new channel and discovers its topic. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The channel that the topic belongs to. - * @param topic The topic for the channel. - * @param setBy The nick of the user that set the topic. - * @param date When the topic was set (milliseconds since the epoch). - * @param changed True if the topic has just been changed, false if - * the topic was already there. - * - */ - protected void onTopic(String channel, String topic, String setBy, long date, boolean changed) {} - - - /** - * After calling the listChannels() method in PircBot, the server - * will start to send us information about each channel on the - * server. You may override this method in order to receive the - * information about each channel as soon as it is received. - *

- * Note that certain channels, such as those marked as hidden, - * may not appear in channel listings. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The name of the channel. - * @param userCount The number of users visible in this channel. - * @param topic The topic for this channel. - * - * @see #listChannels() listChannels - */ - protected void onChannelInfo(String channel, int userCount, String topic) {} - - - /** - * Called when the mode of a channel is set. We process this in - * order to call the appropriate onOp, onDeop, etc method before - * finally calling the override-able onMode method. - *

- * Note that this method is private and is not intended to appear - * in the javadoc generated documentation. - * - * @param target The channel or nick that the mode operation applies to. - * @param sourceNick The nick of the user that set the mode. - * @param sourceLogin The login of the user that set the mode. - * @param sourceHostname The hostname of the user that set the mode. - * @param mode The mode that has been set. - */ - private final void processMode(String target, String sourceNick, String sourceLogin, String sourceHostname, String mode) { - - if (_channelPrefixes.indexOf(target.charAt(0)) >= 0) { - // The mode of a channel is being changed. - String channel = target; - StringTokenizer tok = new StringTokenizer(mode); - String[] params = new String[tok.countTokens()]; - - int t = 0; - while (tok.hasMoreTokens()) { - params[t] = tok.nextToken(); - t++; - } - - char pn = ' '; - int p = 1; - - // All of this is very large and ugly, but it's the only way of providing - // what the users want :-/ - for (int i = 0; i < params[0].length(); i++) { - char atPos = params[0].charAt(i); - - if (atPos == '+' || atPos == '-') { - pn = atPos; - } - else if (atPos == 'o') { - if (pn == '+') { - this.updateUser(channel, OP_ADD, params[p]); - onOp(channel, sourceNick, sourceLogin, sourceHostname, params[p]); - } - else { - this.updateUser(channel, OP_REMOVE, params[p]); - onDeop(channel, sourceNick, sourceLogin, sourceHostname, params[p]); - } - p++; - } - else if (atPos == 'v') { - if (pn == '+') { - this.updateUser(channel, VOICE_ADD, params[p]); - onVoice(channel, sourceNick, sourceLogin, sourceHostname, params[p]); - } - else { - this.updateUser(channel, VOICE_REMOVE, params[p]); - onDeVoice(channel, sourceNick, sourceLogin, sourceHostname, params[p]); - } - p++; - } - else if (atPos == 'k') { - if (pn == '+') { - onSetChannelKey(channel, sourceNick, sourceLogin, sourceHostname, params[p]); - } - else { - onRemoveChannelKey(channel, sourceNick, sourceLogin, sourceHostname, params[p]); - } - p++; - } - else if (atPos == 'l') { - if (pn == '+') { - onSetChannelLimit(channel, sourceNick, sourceLogin, sourceHostname, Integer.parseInt(params[p])); - p++; - } - else { - onRemoveChannelLimit(channel, sourceNick, sourceLogin, sourceHostname); - } - } - else if (atPos == 'b') { - if (pn == '+') { - onSetChannelBan(channel, sourceNick, sourceLogin, sourceHostname,params[p]); - } - else { - onRemoveChannelBan(channel, sourceNick, sourceLogin, sourceHostname, params[p]); - } - p++; - } - else if (atPos == 't') { - if (pn == '+') { - onSetTopicProtection(channel, sourceNick, sourceLogin, sourceHostname); - } - else { - onRemoveTopicProtection(channel, sourceNick, sourceLogin, sourceHostname); - } - } - else if (atPos == 'n') { - if (pn == '+') { - onSetNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname); - } - else { - onRemoveNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname); - } - } - else if (atPos == 'i') { - if (pn == '+') { - onSetInviteOnly(channel, sourceNick, sourceLogin, sourceHostname); - } - else { - onRemoveInviteOnly(channel, sourceNick, sourceLogin, sourceHostname); - } - } - else if (atPos == 'm') { - if (pn == '+') { - onSetModerated(channel, sourceNick, sourceLogin, sourceHostname); - } - else { - onRemoveModerated(channel, sourceNick, sourceLogin, sourceHostname); - } - } - else if (atPos == 'p') { - if (pn == '+') { - onSetPrivate(channel, sourceNick, sourceLogin, sourceHostname); - } - else { - onRemovePrivate(channel, sourceNick, sourceLogin, sourceHostname); - } - } - else if (atPos == 's') { - if (pn == '+') { - onSetSecret(channel, sourceNick, sourceLogin, sourceHostname); - } - else { - onRemoveSecret(channel, sourceNick, sourceLogin, sourceHostname); - } - } - } - - this.onMode(channel, sourceNick, sourceLogin, sourceHostname, mode); - } - else { - // The mode of a user is being changed. - String nick = target; - this.onUserMode(nick, sourceNick, sourceLogin, sourceHostname, mode); - } - } - - - /** - * Called when the mode of a channel is set. - *

- * You may find it more convenient to decode the meaning of the mode - * string by overriding the onOp, onDeOp, onVoice, onDeVoice, - * onChannelKey, onDeChannelKey, onChannelLimit, onDeChannelLimit, - * onChannelBan or onDeChannelBan methods as appropriate. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param channel The channel that the mode operation applies to. - * @param sourceNick The nick of the user that set the mode. - * @param sourceLogin The login of the user that set the mode. - * @param sourceHostname The hostname of the user that set the mode. - * @param mode The mode that has been set. - * - */ - protected void onMode(String channel, String sourceNick, String sourceLogin, String sourceHostname, String mode) {} - - - /** - * Called when the mode of a user is set. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 1.2.0 - * - * @param targetNick The nick that the mode operation applies to. - * @param sourceNick The nick of the user that set the mode. - * @param sourceLogin The login of the user that set the mode. - * @param sourceHostname The hostname of the user that set the mode. - * @param mode The mode that has been set. - * - */ - protected void onUserMode(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String mode) {} - - - - /** - * Called when a user (possibly us) gets granted operator status for a channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param recipient The nick of the user that got 'opped'. - */ - protected void onOp(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} - - - /** - * Called when a user (possibly us) gets operator status taken away. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param recipient The nick of the user that got 'deopped'. - */ - protected void onDeop(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} - - - /** - * Called when a user (possibly us) gets voice status granted in a channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param recipient The nick of the user that got 'voiced'. - */ - protected void onVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} - - - /** - * Called when a user (possibly us) gets voice status removed. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param recipient The nick of the user that got 'devoiced'. - */ - protected void onDeVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} - - - /** - * Called when a channel key is set. When the channel key has been set, - * other users may only join that channel if they know the key. Channel keys - * are sometimes referred to as passwords. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param key The new key for the channel. - */ - protected void onSetChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {} - - - /** - * Called when a channel key is removed. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param key The key that was in use before the channel key was removed. - */ - protected void onRemoveChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {} - - - /** - * Called when a user limit is set for a channel. The number of users in - * the channel cannot exceed this limit. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param limit The maximum number of users that may be in this channel at the same time. - */ - protected void onSetChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname, int limit) {} - - - /** - * Called when the user limit is removed for a channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onRemoveChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a user (possibly us) gets banned from a channel. Being - * banned from a channel prevents any user with a matching hostmask from - * joining the channel. For this reason, most bans are usually directly - * followed by the user being kicked :-) - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param hostmask The hostmask of the user that has been banned. - */ - protected void onSetChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {} - - - /** - * Called when a hostmask ban is removed from a channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - * @param hostmask - */ - protected void onRemoveChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {} - - - /** - * Called when topic protection is enabled for a channel. Topic protection - * means that only operators in a channel may change the topic. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onSetTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when topic protection is removed for a channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onRemoveTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel is set to only allow messages from users that - * are in the channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onSetNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel is set to allow messages from any user, even - * if they are not actually in the channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onRemoveNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel is set to 'invite only' mode. A user may only - * join the channel if they are invited by someone who is already in the - * channel. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onSetInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel has 'invite only' removed. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onRemoveInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel is set to 'moderated' mode. If a channel is - * moderated, then only users who have been 'voiced' or 'opped' may speak - * or change their nicks. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onSetModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel has moderated mode removed. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onRemoveModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel is marked as being in private mode. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onSetPrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel is marked as not being in private mode. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onRemovePrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel is set to be in 'secret' mode. Such channels - * typically do not appear on a server's channel listing. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onSetSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when a channel has 'secret' mode removed. - *

- * This is a type of mode change and is also passed to the onMode - * method in the PircBot class. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param channel The channel in which the mode change took place. - * @param sourceNick The nick of the user that performed the mode change. - * @param sourceLogin The login of the user that performed the mode change. - * @param sourceHostname The hostname of the user that performed the mode change. - */ - protected void onRemoveSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} - - - /** - * Called when we are invited to a channel by a user. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 0.9.5 - * - * @param targetNick The nick of the user being invited - should be us! - * @param sourceNick The nick of the user that sent the invitation. - * @param sourceLogin The login of the user that sent the invitation. - * @param sourceHostname The hostname of the user that sent the invitation. - * @param channel The channel that we're being invited to. - */ - protected void onInvite(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String channel) {} - - - /** - * This method used to be called when a DCC SEND request was sent to the PircBot. - * Please use the onIncomingFileTransfer method to receive files, as it - * has better functionality and supports resuming. - * - * @deprecated As of PircBot 1.2.0, use {@link #onIncomingFileTransfer(DccFileTransfer)} - */ - protected void onDccSendRequest(String sourceNick, String sourceLogin, String sourceHostname, String filename, long address, int port, int size) {} - - - /** - * This method used to be called when a DCC CHAT request was sent to the PircBot. - * Please use the onIncomingChatRequest method to accept chats, as it - * has better functionality. - * - * @deprecated As of PircBot 1.2.0, use {@link #onIncomingChatRequest(DccChat)} - */ - protected void onDccChatRequest(String sourceNick, String sourceLogin, String sourceHostname, long address, int port) {} - - - /** - * This method is called whenever a DCC SEND request is sent to the PircBot. - * This means that a client has requested to send a file to us. - * This abstract implementation performs no action, which means that all - * DCC SEND requests will be ignored by default. If you wish to receive - * the file, then you may override this method and call the receive method - * on the DccFileTransfer object, which connects to the sender and downloads - * the file. - *

- * Example: - *

 public void onIncomingFileTransfer(DccFileTransfer transfer) {
-     *     // Use the suggested file name.
-     *     File file = transfer.getFile();
-     *     // Receive the transfer and save it to the file, allowing resuming.
-     *     transfer.receive(file, true);
-     * }
- *

- * Warning: Receiving an incoming file transfer will cause a file - * to be written to disk. Please ensure that you make adequate security - * checks so that this file does not overwrite anything important! - *

- * Each time a file is received, it happens within a new Thread - * in order to allow multiple files to be downloaded by the PircBot - * at the same time. - *

- * If you allow resuming and the file already partly exists, it will - * be appended to instead of overwritten. If resuming is not enabled, - * the file will be overwritten if it already exists. - *

- * You can throttle the speed of the transfer by calling the setPacketDelay - * method on the DccFileTransfer object, either before you receive the - * file or at any moment during the transfer. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 1.2.0 - * - * @param transfer The DcccFileTransfer that you may accept. - * - * @see DccFileTransfer - * - */ - protected void onIncomingFileTransfer(DccFileTransfer transfer) {} - - - /** - * This method gets called when a DccFileTransfer has finished. - * If there was a problem, the Exception will say what went wrong. - * If the file was sent successfully, the Exception will be null. - *

- * Both incoming and outgoing file transfers are passed to this method. - * You can determine the type by calling the isIncoming or isOutgoing - * methods on the DccFileTransfer object. - * - * @since PircBot 1.2.0 - * - * @param transfer The DccFileTransfer that has finished. - * @param e null if the file was transfered successfully, otherwise this - * will report what went wrong. - * - * @see DccFileTransfer - * - */ - protected void onFileTransferFinished(DccFileTransfer transfer, Exception e) {} - - - /** - * This method will be called whenever a DCC Chat request is received. - * This means that a client has requested to chat to us directly rather - * than via the IRC server. This is useful for sending many lines of text - * to and from the bot without having to worry about flooding the server - * or any operators of the server being able to "spy" on what is being - * said. This abstract implementation performs no action, which means - * that all DCC CHAT requests will be ignored by default. - *

- * If you wish to accept the connection, then you may override this - * method and call the accept() method on the DccChat object, which - * connects to the sender of the chat request and allows lines to be - * sent to and from the bot. - *

- * Your bot must be able to connect directly to the user that sent the - * request. - *

- * Example: - *

 public void onIncomingChatRequest(DccChat chat) {
-     *     try {
-     *         // Accept all chat, whoever it's from.
-     *         chat.accept();
-     *         chat.sendLine("Hello");
-     *         String response = chat.readLine();
-     *         chat.close();
-     *     }
-     *     catch (IOException e) {}
-     * }
- * - * Each time this method is called, it is called from within a new Thread - * so that multiple DCC CHAT sessions can run concurrently. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @since PircBot 1.2.0 - * - * @param chat A DccChat object that represents the incoming chat request. - * - * @see DccChat - * - */ - protected void onIncomingChatRequest(DccChat chat) {} - - - /** - * This method is called whenever we receive a VERSION request. - * This abstract implementation responds with the PircBot's _version string, - * so if you override this method, be sure to either mimic its functionality - * or to call super.onVersion(...); - * - * @param sourceNick The nick of the user that sent the VERSION request. - * @param sourceLogin The login of the user that sent the VERSION request. - * @param sourceHostname The hostname of the user that sent the VERSION request. - * @param target The target of the VERSION request, be it our nick or a channel name. - */ - protected void onVersion(String sourceNick, String sourceLogin, String sourceHostname, String target) { - this.sendRawLine("NOTICE " + sourceNick + " :\u0001VERSION " + _version + "\u0001"); - } - - - /** - * This method is called whenever we receive a PING request from another - * user. - *

- * This abstract implementation responds correctly, so if you override this - * method, be sure to either mimic its functionality or to call - * super.onPing(...); - * - * @param sourceNick The nick of the user that sent the PING request. - * @param sourceLogin The login of the user that sent the PING request. - * @param sourceHostname The hostname of the user that sent the PING request. - * @param target The target of the PING request, be it our nick or a channel name. - * @param pingValue The value that was supplied as an argument to the PING command. - */ - protected void onPing(String sourceNick, String sourceLogin, String sourceHostname, String target, String pingValue) { - this.sendRawLine("NOTICE " + sourceNick + " :\u0001PING " + pingValue + "\u0001"); - } - - - /** - * The actions to perform when a PING request comes from the server. - *

- * This sends back a correct response, so if you override this method, - * be sure to either mimic its functionality or to call - * super.onServerPing(response); - * - * @param response The response that should be given back in your PONG. - */ - protected void onServerPing(String response) { - this.sendRawLine("PONG " + response); - } - - - /** - * This method is called whenever we receive a TIME request. - *

- * This abstract implementation responds correctly, so if you override this - * method, be sure to either mimic its functionality or to call - * super.onTime(...); - * - * @param sourceNick The nick of the user that sent the TIME request. - * @param sourceLogin The login of the user that sent the TIME request. - * @param sourceHostname The hostname of the user that sent the TIME request. - * @param target The target of the TIME request, be it our nick or a channel name. - */ - protected void onTime(String sourceNick, String sourceLogin, String sourceHostname, String target) { - this.sendRawLine("NOTICE " + sourceNick + " :\u0001TIME " + new Date().toString() + "\u0001"); - } - - - /** - * This method is called whenever we receive a FINGER request. - *

- * This abstract implementation responds correctly, so if you override this - * method, be sure to either mimic its functionality or to call - * super.onFinger(...); - * - * @param sourceNick The nick of the user that sent the FINGER request. - * @param sourceLogin The login of the user that sent the FINGER request. - * @param sourceHostname The hostname of the user that sent the FINGER request. - * @param target The target of the FINGER request, be it our nick or a channel name. - */ - protected void onFinger(String sourceNick, String sourceLogin, String sourceHostname, String target) { - this.sendRawLine("NOTICE " + sourceNick + " :\u0001FINGER " + _finger + "\u0001"); - } - - - /** - * This method is called whenever we receive a line from the server that - * the PircBot has not been programmed to recognise. - *

- * The implementation of this method in the PircBot abstract class - * performs no actions and may be overridden as required. - * - * @param line The raw line that was received from the server. - */ - protected void onUnknown(String line) { - // And then there were none :) - } - - - /** - * Sets the verbose mode. If verbose mode is set to true, then log entries - * will be printed to the standard output. The default value is false and - * will result in no output. For general development, we strongly recommend - * setting the verbose mode to true. - * - * @param verbose true if verbose mode is to be used. Default is false. - */ - public final void setVerbose(boolean verbose) { - _verbose = verbose; - } - - - /** - * Sets the name of the bot, which will be used as its nick when it - * tries to join an IRC server. This should be set before joining - * any servers, otherwise the default nick will be used. You would - * typically call this method from the constructor of the class that - * extends PircBot. - *

- * The changeNick method should be used if you wish to change your nick - * when you are connected to a server. - * - * @param name The new name of the Bot. - */ - protected final void setName(String name) { - _name = name; - } - - - /** - * Sets the internal nick of the bot. This is only to be called by the - * PircBot class in response to notification of nick changes that apply - * to us. - * - * @param nick The new nick. - */ - private final void setNick(String nick) { - _nick = nick; - } - - - /** - * Sets the internal login of the Bot. This should be set before joining - * any servers. - * - * @param login The new login of the Bot. - */ - protected final void setLogin(String login) { - _login = login; - } - - - /** - * Sets the internal version of the Bot. This should be set before joining - * any servers. - * - * @param version The new version of the Bot. - */ - protected final void setVersion(String version) { - _version = version; - } - - - /** - * Sets the interal finger message. This should be set before joining - * any servers. - * - * @param finger The new finger message for the Bot. - */ - protected final void setFinger(String finger) { - _finger = finger; - } - - - /** - * Gets the name of the PircBot. This is the name that will be used as - * as a nick when we try to join servers. - * - * @return The name of the PircBot. - */ - public final String getName() { - return _name; - } - - - /** - * Returns the current nick of the bot. Note that if you have just changed - * your nick, this method will still return the old nick until confirmation - * of the nick change is received from the server. - *

- * The nick returned by this method is maintained only by the PircBot - * class and is guaranteed to be correct in the context of the IRC server. - * - * @since PircBot 1.0.0 - * - * @return The current nick of the bot. - */ - public String getNick() { - return _nick; - } - - - /** - * Gets the internal login of the PircBot. - * - * @return The login of the PircBot. - */ - public final String getLogin() { - return _login; - } - - - /** - * Gets the internal version of the PircBot. - * - * @return The version of the PircBot. - */ - public final String getVersion() { - return _version; - } - - - /** - * Gets the internal finger message of the PircBot. - * - * @return The finger message of the PircBot. - */ - public final String getFinger() { - return _finger; - } - - - /** - * Returns whether or not the PircBot is currently connected to a server. - * The result of this method should only act as a rough guide, - * as the result may not be valid by the time you act upon it. - * - * @return True if and only if the PircBot is currently connected to a server. - */ - public final synchronized boolean isConnected() { - return _inputThread != null && _inputThread.isConnected(); - } - - - /** - * Sets the number of milliseconds to delay between consecutive - * messages when there are multiple messages waiting in the - * outgoing message queue. This has a default value of 1000ms. - * It is a good idea to stick to this default value, as it will - * prevent your bot from spamming servers and facing the subsequent - * wrath! However, if you do need to change this delay value (not - * recommended), then this is the method to use. - * - * @param delay The number of milliseconds between each outgoing message. - * - */ - public final void setMessageDelay(long delay) { - if (delay < 0) { - throw new IllegalArgumentException("Cannot have a negative time."); - } - _messageDelay = delay; - } - - - /** - * Returns the number of milliseconds that will be used to separate - * consecutive messages to the server from the outgoing message queue. - * - * @return Number of milliseconds. - */ - public final long getMessageDelay() { - return _messageDelay; - } - - - /** - * Gets the maximum length of any line that is sent via the IRC protocol. - * The IRC RFC specifies that line lengths, including the trailing \r\n - * must not exceed 512 bytes. Hence, there is currently no option to - * change this value in PircBot. All lines greater than this length - * will be truncated before being sent to the IRC server. - * - * @return The maximum line length (currently fixed at 512) - */ - public final int getMaxLineLength() { - return InputThread.MAX_LINE_LENGTH; - } - - - /** - * Gets the number of lines currently waiting in the outgoing message Queue. - * If this returns 0, then the Queue is empty and any new message is likely - * to be sent to the IRC server immediately. - * - * @since PircBot 0.9.9 - * - * @return The number of lines in the outgoing message Queue. - */ - public final int getOutgoingQueueSize() { - return _outQueue.size(); - } - - - /** - * Returns the name of the last IRC server the PircBot tried to connect to. - * This does not imply that the connection attempt to the server was - * successful (we suggest you look at the onConnect method). - * A value of null is returned if the PircBot has never tried to connect - * to a server. - * - * @return The name of the last machine we tried to connect to. Returns - * null if no connection attempts have ever been made. - */ - public final String getServer() { - return _server; - } - - - /** - * Returns the port number of the last IRC server that the PircBot tried - * to connect to. - * This does not imply that the connection attempt to the server was - * successful (we suggest you look at the onConnect method). - * A value of -1 is returned if the PircBot has never tried to connect - * to a server. - * - * @since PircBot 0.9.9 - * - * @return The port number of the last IRC server we connected to. - * Returns -1 if no connection attempts have ever been made. - */ - public final int getPort() { - return _port; - } - - - /** - * Returns the last password that we used when connecting to an IRC server. - * This does not imply that the connection attempt to the server was - * successful (we suggest you look at the onConnect method). - * A value of null is returned if the PircBot has never tried to connect - * to a server using a password. - * - * @since PircBot 0.9.9 - * - * @return The last password that we used when connecting to an IRC server. - * Returns null if we have not previously connected using a password. - */ - public final String getPassword() { - return _password; - } - - - /** - * A convenient method that accepts an IP address represented as a - * long and returns an integer array of size 4 representing the same - * IP address. - * - * @since PircBot 0.9.4 - * - * @param address the long value representing the IP address. - * - * @return An int[] of size 4. - */ - public int[] longToIp(long address) { - int[] ip = new int[4]; - for (int i = 3; i >= 0; i--) { - ip[i] = (int) (address % 256); - address = address / 256; - } - return ip; - } - - - /** - * A convenient method that accepts an IP address represented by a byte[] - * of size 4 and returns this as a long representation of the same IP - * address. - * - * @since PircBot 0.9.4 - * - * @param address the byte[] of size 4 representing the IP address. - * - * @return a long representation of the IP address. - */ - public long ipToLong(byte[] address) { - if (address.length != 4) { - throw new IllegalArgumentException("byte array must be of length 4"); - } - long ipNum = 0; - long multiplier = 1; - for (int i = 3; i >= 0; i--) { - int byteVal = (address[i] + 256) % 256; - ipNum += byteVal*multiplier; - multiplier *= 256; - } - return ipNum; - } - - - /** - * Sets the encoding charset to be used when sending or receiving lines - * from the IRC server. If set to null, then the platform's default - * charset is used. You should only use this method if you are - * trying to send text to an IRC server in a different charset, e.g. - * "GB2312" for Chinese encoding. If a PircBot is currently connected - * to a server, then it must reconnect before this change takes effect. - * - * @since PircBot 1.0.4 - * - * @param charset The new encoding charset to be used by PircBot. - * - * @throws UnsupportedEncodingException If the named charset is not - * supported. - */ - public void setEncoding(String charset) throws UnsupportedEncodingException { - // Just try to see if the charset is supported first... - "".getBytes(charset); - - _charset = charset; - } - - - /** - * Returns the encoding used to send and receive lines from - * the IRC server, or null if not set. Use the setEncoding - * method to change the encoding charset. - * - * @since PircBot 1.0.4 - * - * @return The encoding used to send outgoing messages, or - * null if not set. - */ - public String getEncoding() { - return _charset; - } - - /** - * Returns the InetAddress used by the PircBot. - * This can be used to find the I.P. address from which the PircBot is - * connected to a server. - * - * @since PircBot 1.4.4 - * - * @return The current local InetAddress, or null if never connected. - */ - public InetAddress getInetAddress() { - return _inetAddress; - } - - - /** - * Sets the InetAddress to be used when sending DCC chat or file transfers. - * This can be very useful when you are running a bot on a machine which - * is behind a firewall and you need to tell receiving clients to connect - * to a NAT/router, which then forwards the connection. - * - * @since PircBot 1.4.4 - * - * @param dccInetAddress The new InetAddress, or null to use the default. - */ - public void setDccInetAddress(InetAddress dccInetAddress) { - _dccInetAddress = dccInetAddress; - } - - - /** - * Returns the InetAddress used when sending DCC chat or file transfers. - * If this is null, the default InetAddress will be used. - * - * @since PircBot 1.4.4 - * - * @return The current DCC InetAddress, or null if left as default. - */ - public InetAddress getDccInetAddress() { - return _dccInetAddress; - } - - - /** - * Returns the set of port numbers to be used when sending a DCC chat - * or file transfer. This is useful when you are behind a firewall and - * need to set up port forwarding. The array of port numbers is traversed - * in sequence until a free port is found to listen on. A DCC tranfer will - * fail if all ports are already in use. - * If set to null, any free port number will be used. - * - * @since PircBot 1.4.4 - * - * @return An array of port numbers that PircBot can use to send DCC - * transfers, or null if any port is allowed. - */ - public int[] getDccPorts() { - if (_dccPorts == null || _dccPorts.length == 0) { - return null; - } - // Clone the array to prevent external modification. - return (int[]) _dccPorts.clone(); - } - - - /** - * Sets the choice of port numbers that can be used when sending a DCC chat - * or file transfer. This is useful when you are behind a firewall and - * need to set up port forwarding. The array of port numbers is traversed - * in sequence until a free port is found to listen on. A DCC tranfer will - * fail if all ports are already in use. - * If set to null, any free port number will be used. - * - * @since PircBot 1.4.4 - * - * @param ports The set of port numbers that PircBot may use for DCC - * transfers, or null to let it use any free port (default). - * - */ - public void setDccPorts(int[] ports) { - if (ports == null || ports.length == 0) { - _dccPorts = null; - } - else { - // Clone the array to prevent external modification. - _dccPorts = (int[]) ports.clone(); - } - } - - - /** - * Returns true if and only if the object being compared is the exact - * same instance as this PircBot. This may be useful if you are writing - * a multiple server IRC bot that uses more than one instance of PircBot. - * - * @since PircBot 0.9.9 - * - * @return true if and only if Object o is a PircBot and equal to this. - */ - public boolean equals(Object o) { - // This probably has the same effect as Object.equals, but that may change... - if (o instanceof PircBot) { - PircBot other = (PircBot) o; - return other == this; - } - return false; - } - - - /** - * Returns the hashCode of this PircBot. This method can be called by hashed - * collection classes and is useful for managing multiple instances of - * PircBots in such collections. - * - * @since PircBot 0.9.9 - * - * @return the hash code for this instance of PircBot. - */ - public int hashCode() { - return super.hashCode(); - } - - - /** - * Returns a String representation of this object. - * You may find this useful for debugging purposes, particularly - * if you are using more than one PircBot instance to achieve - * multiple server connectivity. The format of - * this String may change between different versions of PircBot - * but is currently something of the form - * - * Version{PircBot x.y.z Java IRC Bot - www.jibble.org} - * Connected{true} - * Server{irc.dal.net} - * Port{6667} - * Password{} - * - * - * @since PircBot 0.9.10 - * - * @return a String representation of this object. - */ - public String toString() { - return "Version{" + _version + "}" + - " Connected{" + isConnected() + "}" + - " Server{" + _server + "}" + - " Port{" + _port + "}" + - " Password{" + _password + "}"; - } - - - /** - * Returns an array of all users in the specified channel. - *

- * There are some important things to note about this method:- - *

- * - * @since PircBot 1.0.0 - * - * @param channel The name of the channel to list. - * - * @return An array of User objects. This array is empty if we are not - * in the channel. - * - * @see #onUserList(String,User[]) onUserList - */ - public final User[] getUsers(String channel) { - channel = channel.toLowerCase(); - User[] userArray = new User[0]; - synchronized (_channels) { - Hashtable users = _channels.get(channel); - if (users != null) { - userArray = new User[users.size()]; - Enumeration enumeration = users.elements(); - for (int i = 0; i < userArray.length; i++) { - User user = (User) enumeration.nextElement(); - userArray[i] = user; - } - } - } - return userArray; - } - - - /** - * Returns an array of all channels that we are in. Note that if you - * call this method immediately after joining a new channel, the new - * channel may not appear in this array as it is not possible to tell - * if the join was successful until a response is received from the - * IRC server. - * - * @since PircBot 1.0.0 - * - * @return A String array containing the names of all channels that we - * are in. - */ - public final String[] getChannels() { - String[] channels = new String[0]; - synchronized (_channels) { - channels = new String[_channels.size()]; - Enumeration enumeration = _channels.keys(); - for (int i = 0; i < channels.length; i++) { - channels[i] = (String) enumeration.nextElement(); - } - } - return channels; - } - - - /** - * Disposes of all thread resources used by this PircBot. This may be - * useful when writing bots or clients that use multiple servers (and - * therefore multiple PircBot instances) or when integrating a PircBot - * with an existing program. - *

- * Each PircBot runs its own threads for dispatching messages from its - * outgoing message queue and receiving messages from the server. - * Calling dispose() ensures that these threads are - * stopped, thus freeing up system resources and allowing the PircBot - * object to be garbage collected if there are no other references to - * it. - *

- * Once a PircBot object has been disposed, it should not be used again. - * Attempting to use a PircBot that has been disposed may result in - * unpredictable behaviour. - * - * @since 1.2.2 - */ - public synchronized void dispose() { - //System.out.println("disposing..."); - _outputThread.interrupt(); - _inputThread.dispose(); - } - - - /** - * Add a user to the specified channel in our memory. - * Overwrite the existing entry if it exists. - */ - private final void addUser(String channel, User user) { - channel = channel.toLowerCase(); - synchronized (_channels) { - Hashtable users = _channels.get(channel); - if (users == null) { - users = new Hashtable(); - _channels.put(channel, users); - } - users.put(user, user); - } - } - - - /** - * Remove a user from the specified channel in our memory. - */ - private final User removeUser(String channel, String nick) { - channel = channel.toLowerCase(); - User user = new User("", nick); - synchronized (_channels) { - Hashtable users = _channels.get(channel); - if (users != null) { - return (User) users.remove(user); - } - } - return null; - } - - - /** - * Remove a user from all channels in our memory. - */ - private final void removeUser(String nick) { - synchronized (_channels) { - Enumeration enumeration = _channels.keys(); - while (enumeration.hasMoreElements()) { - String channel = (String) enumeration.nextElement(); - this.removeUser(channel, nick); - } - } - } - - - /** - * Rename a user if they appear in any of the channels we know about. - */ - private final void renameUser(String oldNick, String newNick) { - synchronized (_channels) { - Enumeration enumeration = _channels.keys(); - while (enumeration.hasMoreElements()) { - String channel = (String) enumeration.nextElement(); - User user = this.removeUser(channel, oldNick); - if (user != null) { - user = new User(user.getPrefix(), newNick); - this.addUser(channel, user); - } - } - } - } - - - /** - * Removes an entire channel from our memory of users. - */ - private final void removeChannel(String channel) { - channel = channel.toLowerCase(); - synchronized (_channels) { - _channels.remove(channel); - } - } - - - /** - * Removes all channels from our memory of users. - */ - private final void removeAllChannels() { - synchronized(_channels) { - _channels = new Hashtable>(); - } - } - - - private final void updateUser(String channel, int userMode, String nick) { - channel = channel.toLowerCase(); - synchronized (_channels) { - Hashtable users = _channels.get(channel); - User newUser = null; - if (users != null) { - Enumeration enumeration = users.elements(); - while(enumeration.hasMoreElements()) { - User userObj = (User) enumeration.nextElement(); - if (userObj.getNick().equalsIgnoreCase(nick)) { - if (userMode == OP_ADD) { - if (userObj.hasVoice()) { - newUser = new User("@+", nick); - } - else { - newUser = new User("@", nick); - } - } - else if (userMode == OP_REMOVE) { - if(userObj.hasVoice()) { - newUser = new User("+", nick); - } - else { - newUser = new User("", nick); - } - } - else if (userMode == VOICE_ADD) { - if(userObj.isOp()) { - newUser = new User("@+", nick); - } - else { - newUser = new User("+", nick); - } - } - else if (userMode == VOICE_REMOVE) { - if(userObj.isOp()) { - newUser = new User("@", nick); - } - else { - newUser = new User("", nick); - } - } - } - } - } - if (newUser != null) { - users.put(newUser, newUser); - } - else { - // just in case ... - newUser = new User("", nick); - users.put(newUser, newUser); - } - } - } - - - // Connection stuff. - private InputThread _inputThread = null; - private OutputThread _outputThread = null; - private String _charset = null; - private InetAddress _inetAddress = null; - - // Details about the last server that we connected to. - private String _server = null; - private int _port = -1; - private String _password = null; - - // Outgoing message stuff. - private Queue _outQueue = new Queue(); - private long _messageDelay = 1000; - - // A Hashtable of channels that points to a selfreferential Hashtable of - // User objects (used to remember which users are in which channels). - private Hashtable> _channels = new Hashtable>(); - - // A Hashtable to temporarily store channel topics when we join them - // until we find out who set that topic. - private Hashtable _topics = new Hashtable(); - - // DccManager to process and handle all DCC events. - private DccManager _dccManager = new DccManager(this); - private int[] _dccPorts = null; - private InetAddress _dccInetAddress = null; - - // Default settings for the PircBot. - private boolean _autoNickChange = false; - private boolean _verbose = false; - private String _name = "PircBot"; - private String _nick = _name; - private String _login = "PircBot"; - private String _version = "PircBot " + VERSION + " Java IRC Bot - www.jibble.org"; - private String _finger = "You ought to be arrested for fingering a bot!"; - - private String _channelPrefixes = "#&+!"; -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +Modified by: Sebastian Kaspari + +*/ +package org.jibble.pircbot; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; + +import android.util.Log; + +/** + * PircBot is a Java framework for writing IRC bots quickly and easily. + *

+ * It provides an event-driven architecture to handle common IRC + * events, flood protection, DCC support, ident support, and more. + * The comprehensive logfile format is suitable for use with pisg to generate + * channel statistics. + *

+ * Methods of the PircBot class can be called to send events to the IRC server + * that it connects to. For example, calling the sendMessage method will + * send a message to a channel or user on the IRC server. Multiple servers + * can be supported using multiple instances of PircBot. + *

+ * To perform an action when the PircBot receives a normal message from the IRC + * server, you would override the onMessage method defined in the PircBot + * class. All onXYZ methods in the PircBot class are automatically called + * when the event XYZ happens, so you would override these if you wish + * to do something when it does happen. + *

+ * Some event methods, such as onPing, should only really perform a specific + * function (i.e. respond to a PING from the server). For your convenience, such + * methods are already correctly implemented in the PircBot and should not + * normally need to be overridden. Please read the full documentation for each + * method to see which ones are already implemented by the PircBot class. + *

+ * Please visit the PircBot homepage at + * http://www.jibble.org/pircbot.php + * for full revision history, a beginners guide to creating your first PircBot + * and a list of some existing Java IRC bots and clients that use the PircBot + * framework. + * + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public abstract class PircBot implements ReplyConstants { + public static final String TAG = "Yaaic/PircBot"; + /** + * The definitive version number of this release of PircBot. + * (Note: Change this before automatically building releases) + */ + public static final String VERSION = "1.4.6"; + + private static final int OP_ADD = 1; + private static final int OP_REMOVE = 2; + private static final int VOICE_ADD = 3; + private static final int VOICE_REMOVE = 4; + + /** + * Constructs a PircBot with the default settings. Your own constructors + * in classes which extend the PircBot abstract class should be responsible + * for changing the default settings if required. + */ + public PircBot() {} + + /** + * Attempt to connect to the specified IRC server. + * The onConnect method is called upon success. + * + * @param hostname The hostname of the server to connect to. + * + * @throws IOException if it was not possible to connect to the server. + * @throws IrcException if the server would not let us join it. + * @throws NickAlreadyInUseException if our nick is already in use on the server. + */ + public final synchronized void connect(String hostname) throws IOException, IrcException, NickAlreadyInUseException { + this.connect(hostname, 6667, null); + } + + + /** + * Attempt to connect to the specified IRC server and port number. + * The onConnect method is called upon success. + * + * @param hostname The hostname of the server to connect to. + * @param port The port number to connect to on the server. + * + * @throws IOException if it was not possible to connect to the server. + * @throws IrcException if the server would not let us join it. + * @throws NickAlreadyInUseException if our nick is already in use on the server. + */ + public final synchronized void connect(String hostname, int port) throws IOException, IrcException, NickAlreadyInUseException { + this.connect(hostname, port, null); + } + + + /** + * Attempt to connect to the specified IRC server using the supplied + * password. + * The onConnect method is called upon success. + * + * @param hostname The hostname of the server to connect to. + * @param port The port number to connect to on the server. + * @param password The password to use to join the server. + * + * @throws IOException if it was not possible to connect to the server. + * @throws IrcException if the server would not let us join it. + * @throws NickAlreadyInUseException if our nick is already in use on the server. + */ + public final synchronized void connect(String hostname, int port, String password) throws IOException, IrcException, NickAlreadyInUseException { + + _server = hostname; + _port = port; + _password = password; + + if (isConnected()) { + throw new IOException("The PircBot is already connected to an IRC server. Disconnect first."); + } + + // Don't clear the outqueue - there might be something important in it! + + // Clear everything we may have know about channels. + this.removeAllChannels(); + + // Connect to the server. + Socket socket = new Socket(hostname, port); + this.log("*** Connected to server."); + + _inetAddress = socket.getLocalAddress(); + + InputStreamReader inputStreamReader = null; + OutputStreamWriter outputStreamWriter = null; + if (getEncoding() != null) { + // Assume the specified encoding is valid for this JVM. + inputStreamReader = new InputStreamReader(socket.getInputStream(), getEncoding()); + outputStreamWriter = new OutputStreamWriter(socket.getOutputStream(), getEncoding()); + } + else { + // Otherwise, just use the JVM's default encoding. + inputStreamReader = new InputStreamReader(socket.getInputStream()); + outputStreamWriter = new OutputStreamWriter(socket.getOutputStream()); + } + + BufferedReader breader = new BufferedReader(inputStreamReader); + BufferedWriter bwriter = new BufferedWriter(outputStreamWriter); + + // Attempt to join the server. + if (password != null && !password.equals("")) { + OutputThread.sendRawLine(this, bwriter, "PASS " + password); + } + String nick = this.getName(); + OutputThread.sendRawLine(this, bwriter, "NICK " + nick); + OutputThread.sendRawLine(this, bwriter, "USER " + this.getLogin() + " 8 * :" + this.getVersion()); + + _inputThread = new InputThread(this, socket, breader, bwriter); + + // Read stuff back from the server to see if we connected. + String line = null; + int tries = 1; + while ((line = breader.readLine()) != null) { + + this.handleLine(line); + + int firstSpace = line.indexOf(" "); + int secondSpace = line.indexOf(" ", firstSpace + 1); + if (secondSpace >= 0) { + String code = line.substring(firstSpace + 1, secondSpace); + + if (code.equals("004")) { + // We're connected to the server. + break; + } + else if (code.equals("433")) { + if (_autoNickChange) { + tries++; + nick = getName() + tries; + OutputThread.sendRawLine(this, bwriter, "NICK " + nick); + } + else { + socket.close(); + _inputThread = null; + throw new NickAlreadyInUseException(line); + } + } + else if (code.startsWith("5") || code.startsWith("4")) { + socket.close(); + _inputThread = null; + throw new IrcException("Could not log into the IRC server: " + line); + } + } + this.setNick(nick); + + } + + this.log("*** Logged onto server."); + + // This makes the socket timeout on read operations after 5 minutes. + // Maybe in some future version I will let the user change this at runtime. + socket.setSoTimeout(5 * 60 * 1000); + + // Now start the InputThread to read all other lines from the server. + _inputThread.start(); + + // Now start the outputThread that will be used to send all messages. + if (_outputThread == null) { + _outputThread = new OutputThread(this, _outQueue); + _outputThread.start(); + } + + this.onConnect(); + + } + + + /** + * Reconnects to the IRC server that we were previously connected to. + * If necessary, the appropriate port number and password will be used. + * This method will throw an IrcException if we have never connected + * to an IRC server previously. + * + * @since PircBot 0.9.9 + * + * @throws IOException if it was not possible to connect to the server. + * @throws IrcException if the server would not let us join it. + * @throws NickAlreadyInUseException if our nick is already in use on the server. + */ + public final synchronized void reconnect() throws IOException, IrcException, NickAlreadyInUseException{ + if (getServer() == null) { + throw new IrcException("Cannot reconnect to an IRC server because we were never connected to one previously!"); + } + connect(getServer(), getPort(), getPassword()); + } + + + /** + * This method disconnects from the server cleanly by calling the + * quitServer() method. Providing the PircBot was connected to an + * IRC server, the onDisconnect() will be called as soon as the + * disconnection is made by the server. + * + * @see #quitServer() quitServer + * @see #quitServer(String) quitServer + */ + public final synchronized void disconnect() { + this.quitServer(); + } + + + /** + * When you connect to a server and your nick is already in use and + * this is set to true, a new nick will be automatically chosen. + * This is done by adding numbers to the end of the nick until an + * available nick is found. + * + * @param autoNickChange Set to true if you want automatic nick changes + * during connection. + */ + public void setAutoNickChange(boolean autoNickChange) { + _autoNickChange = autoNickChange; + } + + + /** + * Starts an ident server (Identification Protocol Server, RFC 1413). + *

+ * Most IRC servers attempt to contact the ident server on connecting + * hosts in order to determine the user's identity. A few IRC servers + * will not allow you to connect unless this information is provided. + *

+ * So when a PircBot is run on a machine that does not run an ident server, + * it may be necessary to call this method to start one up. + *

+ * Calling this method starts up an ident server which will respond with + * the login provided by calling getLogin() and then shut down immediately. + * It will also be shut down if it has not been contacted within 60 seconds + * of creation. + *

+ * If you require an ident response, then the correct procedure is to start + * the ident server and then connect to the IRC server. The IRC server may + * then contact the ident server to get the information it needs. + *

+ * The ident server will fail to start if there is already an ident server + * running on port 113, or if you are running as an unprivileged user who + * is unable to create a server socket on that port number. + *

+ * If it is essential for you to use an ident server when connecting to an + * IRC server, then make sure that port 113 on your machine is visible to + * the IRC server so that it may contact the ident server. + * + * @since PircBot 0.9c + */ + public final void startIdentServer() { + new IdentServer(this, getLogin()); + } + + + /** + * Joins a channel. + * + * @param channel The name of the channel to join (eg "#cs"). + */ + public final void joinChannel(String channel) { + this.sendRawLine("JOIN " + channel); + } + + + /** + * Joins a channel with a key. + * + * @param channel The name of the channel to join (eg "#cs"). + * @param key The key that will be used to join the channel. + */ + public final void joinChannel(String channel, String key) { + this.joinChannel(channel + " " + key); + } + + + /** + * Parts a channel. + * + * @param channel The name of the channel to leave. + */ + public final void partChannel(String channel) { + this.sendRawLine("PART " + channel); + } + + + /** + * Parts a channel, giving a reason. + * + * @param channel The name of the channel to leave. + * @param reason The reason for parting the channel. + */ + public final void partChannel(String channel, String reason) { + this.sendRawLine("PART " + channel + " :" + reason); + } + + + /** + * Quits from the IRC server. + * Providing we are actually connected to an IRC server, the + * onDisconnect() method will be called as soon as the IRC server + * disconnects us. + */ + public void quitServer() { + this.quitServer(""); + } + + + /** + * Quits from the IRC server with a reason. + * Providing we are actually connected to an IRC server, the + * onDisconnect() method will be called as soon as the IRC server + * disconnects us. + * + * @param reason The reason for quitting the server. + */ + public final void quitServer(String reason) { + this.sendRawLine("QUIT :" + reason); + } + + + /** + * Sends a raw line to the IRC server as soon as possible, bypassing the + * outgoing message queue. + * + * @param line The raw line to send to the IRC server. + */ + public final synchronized void sendRawLine(String line) { + if (isConnected()) { + _inputThread.sendRawLine(line); + } + } + + /** + * Sends a raw line through the outgoing message queue. + * + * @param line The raw line to send to the IRC server. + */ + public final synchronized void sendRawLineViaQueue(String line) { + if (line == null) { + throw new NullPointerException("Cannot send null messages to server"); + } + if (isConnected()) { + _outQueue.add(line); + } + } + + + /** + * Sends a message to a channel or a private message to a user. These + * messages are added to the outgoing message queue and sent at the + * earliest possible opportunity. + *

+ * Some examples: - + *

    // Send the message "Hello!" to the channel #cs.
+     *    sendMessage("#cs", "Hello!");
+     *    
+     *    // Send a private message to Paul that says "Hi".
+     *    sendMessage("Paul", "Hi");
+ * + * You may optionally apply colours, boldness, underlining, etc to + * the message by using the Colors class. + * + * @param target The name of the channel or user nick to send to. + * @param message The message to send. + * + * @see Colors + */ + public final void sendMessage(String target, String message) { + _outQueue.add("PRIVMSG " + target + " :" + message); + } + + + /** + * Sends an action to the channel or to a user. + * + * @param target The name of the channel or user nick to send to. + * @param action The action to send. + * + * @see Colors + */ + public final void sendAction(String target, String action) { + sendCTCPCommand(target, "ACTION " + action); + } + + + /** + * Sends a notice to the channel or to a user. + * + * @param target The name of the channel or user nick to send to. + * @param notice The notice to send. + */ + public final void sendNotice(String target, String notice) { + _outQueue.add("NOTICE " + target + " :" + notice); + } + + + /** + * Sends a CTCP command to a channel or user. (Client to client protocol). + * Examples of such commands are "PING ", "FINGER", "VERSION", etc. + * For example, if you wish to request the version of a user called "Dave", + * then you would call sendCTCPCommand("Dave", "VERSION");. + * The type of response to such commands is largely dependant on the target + * client software. + * + * @since PircBot 0.9.5 + * + * @param target The name of the channel or user to send the CTCP message to. + * @param command The CTCP command to send. + */ + public final void sendCTCPCommand(String target, String command) { + _outQueue.add("PRIVMSG " + target + " :\u0001" + command + "\u0001"); + } + + + /** + * Attempt to change the current nick (nickname) of the bot when it + * is connected to an IRC server. + * After confirmation of a successful nick change, the getNick method + * will return the new nick. + * + * @param newNick The new nick to use. + */ + public final void changeNick(String newNick) { + this.sendRawLine("NICK " + newNick); + } + + + /** + * Identify the bot with NickServ, supplying the appropriate password. + * Some IRC Networks (such as freenode) require users to register and + * identify with NickServ before they are able to send private messages + * to other users, thus reducing the amount of spam. If you are using + * an IRC network where this kind of policy is enforced, you will need + * to make your bot identify itself to NickServ before you can send + * private messages. Assuming you have already registered your bot's + * nick with NickServ, this method can be used to identify with + * the supplied password. It usually makes sense to identify with NickServ + * immediately after connecting to a server. + *

+ * This method issues a raw NICKSERV command to the server, and is therefore + * safer than the alternative approach of sending a private message to + * NickServ. The latter approach is considered dangerous, as it may cause + * you to inadvertently transmit your password to an untrusted party if you + * connect to a network which does not run a NickServ service and where the + * untrusted party has assumed the nick "NickServ". However, if your IRC + * network is only compatible with the private message approach, you may + * typically identify like so: + *

sendMessage("NickServ", "identify PASSWORD");
+ * + * @param password The password which will be used to identify with NickServ. + */ + public final void identify(String password) { + this.sendRawLine("NICKSERV IDENTIFY " + password); + } + + + /** + * Set the mode of a channel. + * This method attempts to set the mode of a channel. This + * may require the bot to have operator status on the channel. + * For example, if the bot has operator status, we can grant + * operator status to "Dave" on the #cs channel + * by calling setMode("#cs", "+o Dave"); + * An alternative way of doing this would be to use the op method. + * + * @param channel The channel on which to perform the mode change. + * @param mode The new mode to apply to the channel. This may include + * zero or more arguments if necessary. + * + * @see #op(String,String) op + */ + public final void setMode(String channel, String mode) { + this.sendRawLine("MODE " + channel + " " + mode); + } + + + /** + * Sends an invitation to join a channel. Some channels can be marked + * as "invite-only", so it may be useful to allow a bot to invite people + * into it. + * + * @param nick The nick of the user to invite + * @param channel The channel you are inviting the user to join. + * + */ + public final void sendInvite(String nick, String channel) { + this.sendRawLine("INVITE " + nick + " :" + channel); + } + + + /** + * Bans a user from a channel. An example of a valid hostmask is + * "*!*compu@*.18hp.net". This may be used in conjunction with the + * kick method to permanently remove a user from a channel. + * Successful use of this method may require the bot to have operator + * status itself. + * + * @param channel The channel to ban the user from. + * @param hostmask A hostmask representing the user we're banning. + */ + public final void ban(String channel, String hostmask) { + this.sendRawLine("MODE " + channel + " +b " + hostmask); + } + + + /** + * Unbans a user from a channel. An example of a valid hostmask is + * "*!*compu@*.18hp.net". + * Successful use of this method may require the bot to have operator + * status itself. + * + * @param channel The channel to unban the user from. + * @param hostmask A hostmask representing the user we're unbanning. + */ + public final void unBan(String channel, String hostmask) { + this.sendRawLine("MODE " + channel + " -b " + hostmask); + } + + + /** + * Grants operator privilidges to a user on a channel. + * Successful use of this method may require the bot to have operator + * status itself. + * + * @param channel The channel we're opping the user on. + * @param nick The nick of the user we are opping. + */ + public final void op(String channel, String nick) { + this.setMode(channel, "+o " + nick); + } + + + /** + * Removes operator privilidges from a user on a channel. + * Successful use of this method may require the bot to have operator + * status itself. + * + * @param channel The channel we're deopping the user on. + * @param nick The nick of the user we are deopping. + */ + public final void deOp(String channel, String nick) { + this.setMode(channel, "-o " + nick); + } + + + /** + * Grants voice privilidges to a user on a channel. + * Successful use of this method may require the bot to have operator + * status itself. + * + * @param channel The channel we're voicing the user on. + * @param nick The nick of the user we are voicing. + */ + public final void voice(String channel, String nick) { + this.setMode(channel, "+v " + nick); + } + + + /** + * Removes voice privilidges from a user on a channel. + * Successful use of this method may require the bot to have operator + * status itself. + * + * @param channel The channel we're devoicing the user on. + * @param nick The nick of the user we are devoicing. + */ + public final void deVoice(String channel, String nick) { + this.setMode(channel, "-v " + nick); + } + + + /** + * Set the topic for a channel. + * This method attempts to set the topic of a channel. This + * may require the bot to have operator status if the topic + * is protected. + * + * @param channel The channel on which to perform the mode change. + * @param topic The new topic for the channel. + * + */ + public final void setTopic(String channel, String topic) { + this.sendRawLine("TOPIC " + channel + " :" + topic); + } + + + /** + * Kicks a user from a channel. + * This method attempts to kick a user from a channel and + * may require the bot to have operator status in the channel. + * + * @param channel The channel to kick the user from. + * @param nick The nick of the user to kick. + */ + public final void kick(String channel, String nick) { + this.kick(channel, nick, ""); + } + + + /** + * Kicks a user from a channel, giving a reason. + * This method attempts to kick a user from a channel and + * may require the bot to have operator status in the channel. + * + * @param channel The channel to kick the user from. + * @param nick The nick of the user to kick. + * @param reason A description of the reason for kicking a user. + */ + public final void kick(String channel, String nick, String reason) { + this.sendRawLine("KICK " + channel + " " + nick + " :" + reason); + } + + + /** + * Issues a request for a list of all channels on the IRC server. + * When the PircBot receives information for each channel, it will + * call the onChannelInfo method, which you will need to override + * if you want it to do anything useful. + * + * @see #onChannelInfo(String,int,String) onChannelInfo + */ + public final void listChannels() { + this.listChannels(null); + } + + + /** + * Issues a request for a list of all channels on the IRC server. + * When the PircBot receives information for each channel, it will + * call the onChannelInfo method, which you will need to override + * if you want it to do anything useful. + *

+ * Some IRC servers support certain parameters for LIST requests. + * One example is a parameter of ">10" to list only those channels + * that have more than 10 users in them. Whether these parameters + * are supported or not will depend on the IRC server software. + * + * @param parameters The parameters to supply when requesting the + * list. + * + * @see #onChannelInfo(String,int,String) onChannelInfo + */ + public final void listChannels(String parameters) { + if (parameters == null) { + this.sendRawLine("LIST"); + } + else { + this.sendRawLine("LIST " + parameters); + } + } + + + /** + * Sends a file to another user. Resuming is supported. + * The other user must be able to connect directly to your bot to be + * able to receive the file. + *

+ * You may throttle the speed of this file transfer by calling the + * setPacketDelay method on the DccFileTransfer that is returned. + *

+ * This method may not be overridden. + * + * @since 0.9c + * + * @param file The file to send. + * @param nick The user to whom the file is to be sent. + * @param timeout The number of milliseconds to wait for the recipient to + * acccept the file (we recommend about 120000). + * + * @return The DccFileTransfer that can be used to monitor this transfer. + * + * @see DccFileTransfer + * + */ + public final DccFileTransfer dccSendFile(File file, String nick, int timeout) { + DccFileTransfer transfer = new DccFileTransfer(this, _dccManager, file, nick, timeout); + transfer.doSend(true); + return transfer; + } + + + /** + * Receives a file that is being sent to us by a DCC SEND request. + * Please use the onIncomingFileTransfer method to receive files. + * + * @deprecated As of PircBot 1.2.0, use {@link #onIncomingFileTransfer(DccFileTransfer)} + */ + protected final void dccReceiveFile(File file, long address, int port, int size) { + throw new RuntimeException("dccReceiveFile is deprecated, please use sendFile"); + } + + + /** + * Attempts to establish a DCC CHAT session with a client. This method + * issues the connection request to the client and then waits for the + * client to respond. If the connection is successfully made, then a + * DccChat object is returned by this method. If the connection is not + * made within the time limit specified by the timeout value, then null + * is returned. + *

+ * It is strongly recommended that you call this method within a new + * Thread, as it may take a long time to return. + *

+ * This method may not be overridden. + * + * @since PircBot 0.9.8 + * + * @param nick The nick of the user we are trying to establish a chat with. + * @param timeout The number of milliseconds to wait for the recipient to + * accept the chat connection (we recommend about 120000). + * + * @return a DccChat object that can be used to send and recieve lines of + * text. Returns null if the connection could not be made. + * + * @see DccChat + */ + public final DccChat dccSendChatRequest(String nick, int timeout) { + DccChat chat = null; + try { + ServerSocket ss = null; + + int[] ports = getDccPorts(); + if (ports == null) { + // Use any free port. + ss = new ServerSocket(0); + } + else { + for (int i = 0; i < ports.length; i++) { + try { + ss = new ServerSocket(ports[i]); + // Found a port number we could use. + break; + } + catch (Exception e) { + // Do nothing; go round and try another port. + } + } + if (ss == null) { + // No ports could be used. + throw new IOException("All ports returned by getDccPorts() are in use."); + } + } + + ss.setSoTimeout(timeout); + int port = ss.getLocalPort(); + + InetAddress inetAddress = getDccInetAddress(); + if (inetAddress == null) { + inetAddress = getInetAddress(); + } + byte[] ip = inetAddress.getAddress(); + long ipNum = ipToLong(ip); + + sendCTCPCommand(nick, "DCC CHAT chat " + ipNum + " " + port); + + // The client may now connect to us to chat. + Socket socket = ss.accept(); + + // Close the server socket now that we've finished with it. + ss.close(); + + chat = new DccChat(this, nick, socket); + } + catch (Exception e) { + // Do nothing. + } + return chat; + } + + + /** + * Attempts to accept a DCC CHAT request by a client. + * Please use the onIncomingChatRequest method to receive files. + * + * @deprecated As of PircBot 1.2.0, use {@link #onIncomingChatRequest(DccChat)} + */ + protected final DccChat dccAcceptChatRequest(String sourceNick, long address, int port) { + throw new RuntimeException("dccAcceptChatRequest is deprecated, please use onIncomingChatRequest"); + } + + + /** + * Adds a line to the log. This log is currently output to the standard + * output and is in the correct format for use by tools such as pisg, the + * Perl IRC Statistics Generator. You may override this method if you wish + * to do something else with log entries. + * Each line in the log begins with a number which + * represents the logging time (as the number of milliseconds since the + * epoch). This timestamp and the following log entry are separated by + * a single space character, " ". Outgoing messages are distinguishable + * by a log entry that has ">>>" immediately following the space character + * after the timestamp. DCC events use "+++" and warnings about unhandled + * Exceptions and Errors use "###". + *

+ * This implementation of the method will only cause log entries to be + * output if the PircBot has had its verbose mode turned on by calling + * setVerbose(true); + * + * @param line The line to add to the log. + */ + public void log(String line) { + if (_verbose) { + // XXX: PircBot Patch: Log to debug log instead of standard output + Log.d(TAG, line); + //System.out.println(System.currentTimeMillis() + " " + line); + } + } + + + /** + * This method handles events when any line of text arrives from the server, + * then calling the appropriate method in the PircBot. This method is + * protected and only called by the InputThread for this instance. + *

+ * This method may not be overridden! + * + * @param line The raw line of text from the server. + */ + protected void handleLine(String line) { + this.log(line); + + // Check for server pings. + if (line.startsWith("PING ")) { + // Respond to the ping and return immediately. + this.onServerPing(line.substring(5)); + return; + } + + 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); + } + else { + + if (tokenizer.hasMoreTokens()) { + String token = command; + + int code = -1; + try { + code = Integer.parseInt(token); + } + catch (NumberFormatException e) { + // Keep the existing value. + } + + if (code != -1) { + String errorStr = token; + String response = line.substring(line.indexOf(errorStr, senderInfo.length()) + 4, line.length()); + this.processServerResponse(code, response); + // Return from the method. + return; + } + else { + // This is not a server response. + // It must be a nick without login and hostname. + // (or maybe a NOTICE or suchlike from the server) + sourceNick = senderInfo; + target = token; + } + } + else { + // We don't know what this line means. + this.onUnknown(line); + // Return from the method; + return; + } + + } + } + + command = command.toUpperCase(); + if (sourceNick.startsWith(":")) { + sourceNick = sourceNick.substring(1); + } + if (target == null) { + target = tokenizer.nextToken(); + } + if (target.startsWith(":")) { + target = target.substring(1); + } + + // Check for CTCP requests. + if (command.equals("PRIVMSG") && line.indexOf(":\u0001") > 0 && line.endsWith("\u0001")) { + String request = line.substring(line.indexOf(":\u0001") + 2, line.length() - 1); + if (request.equals("VERSION")) { + // VERSION request + this.onVersion(sourceNick, sourceLogin, sourceHostname, target); + } + else if (request.startsWith("ACTION ")) { + // ACTION request + this.onAction(sourceNick, sourceLogin, sourceHostname, target, request.substring(7)); + } + else if (request.startsWith("PING ")) { + // PING request + this.onPing(sourceNick, sourceLogin, sourceHostname, target, request.substring(5)); + } + else if (request.equals("TIME")) { + // TIME request + this.onTime(sourceNick, sourceLogin, sourceHostname, target); + } + else if (request.equals("FINGER")) { + // FINGER request + this.onFinger(sourceNick, sourceLogin, sourceHostname, target); + } + else if ((tokenizer = new StringTokenizer(request)).countTokens() >= 5 && tokenizer.nextToken().equals("DCC")) { + // This is a DCC request. + boolean success = _dccManager.processRequest(sourceNick, sourceLogin, sourceHostname, request); + if (!success) { + // The DccManager didn't know what to do with the line. + this.onUnknown(line); + } + } + else { + // An unknown CTCP message - ignore it. + this.onUnknown(line); + } + } + else if (command.equals("PRIVMSG") && _channelPrefixes.indexOf(target.charAt(0)) >= 0) { + // This is a normal message to a channel. + this.onMessage(target, sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); + } + else if (command.equals("PRIVMSG")) { + // This is a private message to us. + this.onPrivateMessage(sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); + } + else if (command.equals("JOIN")) { + // Someone is joining a channel. + String channel = target; + this.addUser(channel, new User("", sourceNick)); + this.onJoin(channel, sourceNick, sourceLogin, sourceHostname); + } + else if (command.equals("PART")) { + // Someone is parting from a channel. + this.removeUser(target, sourceNick); + if (sourceNick.equals(this.getNick())) { + this.removeChannel(target); + } + this.onPart(target, sourceNick, sourceLogin, sourceHostname); + } + else if (command.equals("NICK")) { + // Somebody is changing their nick. + String newNick = target; + this.renameUser(sourceNick, newNick); + if (sourceNick.equals(this.getNick())) { + // Update our nick if it was us that changed nick. + this.setNick(newNick); + } + this.onNickChange(sourceNick, sourceLogin, sourceHostname, newNick); + } + else if (command.equals("NOTICE")) { + // Someone is sending a notice. + this.onNotice(sourceNick, sourceLogin, sourceHostname, target, line.substring(line.indexOf(" :") + 2)); + } + else if (command.equals("QUIT")) { + // Someone has quit from the IRC server. + + // XXX: Pircbot Patch - Call onQuit before removing the user. This way we + // are able to know which channels the user was on. + this.onQuit(sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); + + if (sourceNick.equals(this.getNick())) { + this.removeAllChannels(); + } + else { + this.removeUser(sourceNick); + } + } + else if (command.equals("KICK")) { + // Somebody has been kicked from a channel. + String recipient = tokenizer.nextToken(); + if (recipient.equals(this.getNick())) { + this.removeChannel(target); + } + this.removeUser(target, recipient); + this.onKick(target, sourceNick, sourceLogin, sourceHostname, recipient, line.substring(line.indexOf(" :") + 2)); + } + else if (command.equals("MODE")) { + // Somebody is changing the mode on a channel or user. + String mode = line.substring(line.indexOf(target, 2) + target.length() + 1); + if (mode.startsWith(":")) { + mode = mode.substring(1); + } + this.processMode(target, sourceNick, sourceLogin, sourceHostname, mode); + } + else if (command.equals("TOPIC")) { + // Someone is changing the topic. + this.onTopic(target, line.substring(line.indexOf(" :") + 2), sourceNick, System.currentTimeMillis(), true); + } + else if (command.equals("INVITE")) { + // Somebody is inviting somebody else into a channel. + this.onInvite(target, sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); + } + else { + // If we reach this point, then we've found something that the PircBot + // Doesn't currently deal with. + this.onUnknown(line); + } + + } + + + /** + * This method is called once the PircBot has successfully connected to + * the IRC server. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.6 + */ + protected void onConnect() {} + + + /** + * This method carries out the actions to be performed when the PircBot + * gets disconnected. This may happen if the PircBot quits from the + * server, or if the connection is unexpectedly lost. + *

+ * Disconnection from the IRC server is detected immediately if either + * we or the server close the connection normally. If the connection to + * the server is lost, but neither we nor the server have explicitly closed + * the connection, then it may take a few minutes to detect (this is + * commonly referred to as a "ping timeout"). + *

+ * If you wish to get your IRC bot to automatically rejoin a server after + * the connection has been lost, then this is probably the ideal method to + * override to implement such functionality. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + */ + protected void onDisconnect() {} + + + /** + * This method is called by the PircBot when a numeric response + * is received from the IRC server. We use this method to + * allow PircBot to process various responses from the server + * before then passing them on to the onServerResponse method. + *

+ * Note that this method is private and should not appear in any + * of the javadoc generated documenation. + * + * @param code The three-digit numerical code for the response. + * @param response The full response from the IRC server. + */ + private final void processServerResponse(int code, String response) { + + if (code == RPL_LIST) { + // This is a bit of information about a channel. + int firstSpace = response.indexOf(' '); + int secondSpace = response.indexOf(' ', firstSpace + 1); + int thirdSpace = response.indexOf(' ', secondSpace + 1); + int colon = response.indexOf(':'); + String channel = response.substring(firstSpace + 1, secondSpace); + int userCount = 0; + try { + userCount = Integer.parseInt(response.substring(secondSpace + 1, thirdSpace)); + } + catch (NumberFormatException e) { + // Stick with the value of zero. + } + String topic = response.substring(colon + 1); + this.onChannelInfo(channel, userCount, topic); + } + else if (code == RPL_TOPIC) { + // This is topic information about a channel we've just joined. + int firstSpace = response.indexOf(' '); + int secondSpace = response.indexOf(' ', firstSpace + 1); + int colon = response.indexOf(':'); + String channel = response.substring(firstSpace + 1, secondSpace); + String topic = response.substring(colon + 1); + + _topics.put(channel, topic); + + // For backwards compatibility only - this onTopic method is deprecated. + this.onTopic(channel, topic); + } + else if (code == RPL_TOPICINFO) { + StringTokenizer tokenizer = new StringTokenizer(response); + tokenizer.nextToken(); + String channel = tokenizer.nextToken(); + String setBy = tokenizer.nextToken(); + long date = 0; + try { + date = Long.parseLong(tokenizer.nextToken()) * 1000; + } + catch (NumberFormatException e) { + // Stick with the default value of zero. + } + + String topic = (String) _topics.get(channel); + _topics.remove(channel); + + this.onTopic(channel, topic, setBy, date, false); + } + else if (code == RPL_NAMREPLY) { + // This is a list of nicks in a channel that we've just joined. + int channelEndIndex = response.indexOf(" :"); + String channel = response.substring(response.lastIndexOf(' ', channelEndIndex - 1) + 1, channelEndIndex); + + StringTokenizer tokenizer = new StringTokenizer(response.substring(response.indexOf(" :") + 2)); + while (tokenizer.hasMoreTokens()) { + String nick = tokenizer.nextToken(); + String prefix = ""; + if (nick.startsWith("@")) { + // User is an operator in this channel. + prefix = "@"; + } + else if (nick.startsWith("+")) { + // User is voiced in this channel. + prefix = "+"; + } + else if (nick.startsWith(".")) { + // Some wibbly status I've never seen before... + prefix = "."; + } + nick = nick.substring(prefix.length()); + this.addUser(channel, new User(prefix, nick)); + } + } + else if (code == RPL_ENDOFNAMES) { + // This is the end of a NAMES list, so we know that we've got + // the full list of users in the channel that we just joined. + String channel = response.substring(response.indexOf(' ') + 1, response.indexOf(" :")); + User[] users = this.getUsers(channel); + this.onUserList(channel, users); + } + + this.onServerResponse(code, response); + } + + + /** + * This method is called when we receive a numeric response from the + * IRC server. + *

+ * Numerics in the range from 001 to 099 are used for client-server + * connections only and should never travel between servers. Replies + * generated in response to commands are found in the range from 200 + * to 399. Error replies are found in the range from 400 to 599. + *

+ * For example, we can use this method to discover the topic of a + * channel when we join it. If we join the channel #test which + * has a topic of "I am King of Test" then the response + * will be "PircBot #test :I Am King of Test" + * with a code of 332 to signify that this is a topic. + * (This is just an example - note that overriding the + * onTopic method is an easier way of finding the + * topic for a channel). Check the IRC RFC for the full list of other + * command response codes. + *

+ * PircBot implements the interface ReplyConstants, which contains + * contstants that you may find useful here. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param code The three-digit numerical code for the response. + * @param response The full response from the IRC server. + * + * @see ReplyConstants + */ + protected void onServerResponse(int code, String response) {} + + + /** + * This method is called when we receive a user list from the server + * after joining a channel. + *

+ * Shortly after joining a channel, the IRC server sends a list of all + * users in that channel. The PircBot collects this information and + * calls this method as soon as it has the full list. + *

+ * To obtain the nick of each user in the channel, call the getNick() + * method on each User object in the array. + *

+ * At a later time, you may call the getUsers method to obtain an + * up to date list of the users in the channel. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 1.0.0 + * + * @param channel The name of the channel. + * @param users An array of User objects belonging to this channel. + * + * @see User + */ + protected void onUserList(String channel, User[] users) {} + + + /** + * This method is called whenever a message is sent to a channel. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The channel to which the message was sent. + * @param sender The nick of the person who sent the message. + * @param login The login of the person who sent the message. + * @param hostname The hostname of the person who sent the message. + * @param message The actual message sent to the channel. + */ + protected void onMessage(String channel, String sender, String login, String hostname, String message) {} + + + /** + * This method is called whenever a private message is sent to the PircBot. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param sender The nick of the person who sent the private message. + * @param login The login of the person who sent the private message. + * @param hostname The hostname of the person who sent the private message. + * @param message The actual message. + */ + protected void onPrivateMessage(String sender, String login, String hostname, String message) {} + + + /** + * This method is called whenever an ACTION is sent from a user. E.g. + * such events generated by typing "/me goes shopping" in most IRC clients. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param sender The nick of the user that sent the action. + * @param login The login of the user that sent the action. + * @param hostname The hostname of the user that sent the action. + * @param target The target of the action, be it a channel or our nick. + * @param action The action carried out by the user. + */ + protected void onAction(String sender, String login, String hostname, String target, String action) {} + + + /** + * This method is called whenever we receive a notice. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param sourceNick The nick of the user that sent the notice. + * @param sourceLogin The login of the user that sent the notice. + * @param sourceHostname The hostname of the user that sent the notice. + * @param target The target of the notice, be it our nick or a channel name. + * @param notice The notice message. + */ + protected void onNotice(String sourceNick, String sourceLogin, String sourceHostname, String target, String notice) {} + + + /** + * This method is called whenever someone (possibly us) joins a channel + * which we are on. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The channel which somebody joined. + * @param sender The nick of the user who joined the channel. + * @param login The login of the user who joined the channel. + * @param hostname The hostname of the user who joined the channel. + */ + protected void onJoin(String channel, String sender, String login, String hostname) {} + + + /** + * This method is called whenever someone (possibly us) parts a channel + * which we are on. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The channel which somebody parted from. + * @param sender The nick of the user who parted from the channel. + * @param login The login of the user who parted from the channel. + * @param hostname The hostname of the user who parted from the channel. + */ + protected void onPart(String channel, String sender, String login, String hostname) {} + + + /** + * This method is called whenever someone (possibly us) changes nick on any + * of the channels that we are on. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param oldNick The old nick. + * @param login The login of the user. + * @param hostname The hostname of the user. + * @param newNick The new nick. + */ + protected void onNickChange(String oldNick, String login, String hostname, String newNick) {} + + + /** + * This method is called whenever someone (possibly us) is kicked from + * any of the channels that we are in. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The channel from which the recipient was kicked. + * @param kickerNick The nick of the user who performed the kick. + * @param kickerLogin The login of the user who performed the kick. + * @param kickerHostname The hostname of the user who performed the kick. + * @param recipientNick The unfortunate recipient of the kick. + * @param reason The reason given by the user who performed the kick. + */ + protected void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {} + + + /** + * This method is called whenever someone (possibly us) quits from the + * server. We will only observe this if the user was in one of the + * channels to which we are connected. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param sourceNick The nick of the user that quit from the server. + * @param sourceLogin The login of the user that quit from the server. + * @param sourceHostname The hostname of the user that quit from the server. + * @param reason The reason given for quitting the server. + */ + protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {} + + + /** + * This method is called whenever a user sets the topic, or when + * PircBot joins a new channel and discovers its topic. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The channel that the topic belongs to. + * @param topic The topic for the channel. + * + * @deprecated As of 1.2.0, replaced by {@link #onTopic(String,String,String,long,boolean)} + */ + protected void onTopic(String channel, String topic) {} + + + /** + * This method is called whenever a user sets the topic, or when + * PircBot joins a new channel and discovers its topic. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The channel that the topic belongs to. + * @param topic The topic for the channel. + * @param setBy The nick of the user that set the topic. + * @param date When the topic was set (milliseconds since the epoch). + * @param changed True if the topic has just been changed, false if + * the topic was already there. + * + */ + protected void onTopic(String channel, String topic, String setBy, long date, boolean changed) {} + + + /** + * After calling the listChannels() method in PircBot, the server + * will start to send us information about each channel on the + * server. You may override this method in order to receive the + * information about each channel as soon as it is received. + *

+ * Note that certain channels, such as those marked as hidden, + * may not appear in channel listings. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The name of the channel. + * @param userCount The number of users visible in this channel. + * @param topic The topic for this channel. + * + * @see #listChannels() listChannels + */ + protected void onChannelInfo(String channel, int userCount, String topic) {} + + + /** + * Called when the mode of a channel is set. We process this in + * order to call the appropriate onOp, onDeop, etc method before + * finally calling the override-able onMode method. + *

+ * Note that this method is private and is not intended to appear + * in the javadoc generated documentation. + * + * @param target The channel or nick that the mode operation applies to. + * @param sourceNick The nick of the user that set the mode. + * @param sourceLogin The login of the user that set the mode. + * @param sourceHostname The hostname of the user that set the mode. + * @param mode The mode that has been set. + */ + private final void processMode(String target, String sourceNick, String sourceLogin, String sourceHostname, String mode) { + + if (_channelPrefixes.indexOf(target.charAt(0)) >= 0) { + // The mode of a channel is being changed. + String channel = target; + StringTokenizer tok = new StringTokenizer(mode); + String[] params = new String[tok.countTokens()]; + + int t = 0; + while (tok.hasMoreTokens()) { + params[t] = tok.nextToken(); + t++; + } + + char pn = ' '; + int p = 1; + + // All of this is very large and ugly, but it's the only way of providing + // what the users want :-/ + for (int i = 0; i < params[0].length(); i++) { + char atPos = params[0].charAt(i); + + if (atPos == '+' || atPos == '-') { + pn = atPos; + } + else if (atPos == 'o') { + if (pn == '+') { + this.updateUser(channel, OP_ADD, params[p]); + onOp(channel, sourceNick, sourceLogin, sourceHostname, params[p]); + } + else { + this.updateUser(channel, OP_REMOVE, params[p]); + onDeop(channel, sourceNick, sourceLogin, sourceHostname, params[p]); + } + p++; + } + else if (atPos == 'v') { + if (pn == '+') { + this.updateUser(channel, VOICE_ADD, params[p]); + onVoice(channel, sourceNick, sourceLogin, sourceHostname, params[p]); + } + else { + this.updateUser(channel, VOICE_REMOVE, params[p]); + onDeVoice(channel, sourceNick, sourceLogin, sourceHostname, params[p]); + } + p++; + } + else if (atPos == 'k') { + if (pn == '+') { + onSetChannelKey(channel, sourceNick, sourceLogin, sourceHostname, params[p]); + } + else { + onRemoveChannelKey(channel, sourceNick, sourceLogin, sourceHostname, params[p]); + } + p++; + } + else if (atPos == 'l') { + if (pn == '+') { + onSetChannelLimit(channel, sourceNick, sourceLogin, sourceHostname, Integer.parseInt(params[p])); + p++; + } + else { + onRemoveChannelLimit(channel, sourceNick, sourceLogin, sourceHostname); + } + } + else if (atPos == 'b') { + if (pn == '+') { + onSetChannelBan(channel, sourceNick, sourceLogin, sourceHostname,params[p]); + } + else { + onRemoveChannelBan(channel, sourceNick, sourceLogin, sourceHostname, params[p]); + } + p++; + } + else if (atPos == 't') { + if (pn == '+') { + onSetTopicProtection(channel, sourceNick, sourceLogin, sourceHostname); + } + else { + onRemoveTopicProtection(channel, sourceNick, sourceLogin, sourceHostname); + } + } + else if (atPos == 'n') { + if (pn == '+') { + onSetNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname); + } + else { + onRemoveNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname); + } + } + else if (atPos == 'i') { + if (pn == '+') { + onSetInviteOnly(channel, sourceNick, sourceLogin, sourceHostname); + } + else { + onRemoveInviteOnly(channel, sourceNick, sourceLogin, sourceHostname); + } + } + else if (atPos == 'm') { + if (pn == '+') { + onSetModerated(channel, sourceNick, sourceLogin, sourceHostname); + } + else { + onRemoveModerated(channel, sourceNick, sourceLogin, sourceHostname); + } + } + else if (atPos == 'p') { + if (pn == '+') { + onSetPrivate(channel, sourceNick, sourceLogin, sourceHostname); + } + else { + onRemovePrivate(channel, sourceNick, sourceLogin, sourceHostname); + } + } + else if (atPos == 's') { + if (pn == '+') { + onSetSecret(channel, sourceNick, sourceLogin, sourceHostname); + } + else { + onRemoveSecret(channel, sourceNick, sourceLogin, sourceHostname); + } + } + } + + this.onMode(channel, sourceNick, sourceLogin, sourceHostname, mode); + } + else { + // The mode of a user is being changed. + String nick = target; + this.onUserMode(nick, sourceNick, sourceLogin, sourceHostname, mode); + } + } + + + /** + * Called when the mode of a channel is set. + *

+ * You may find it more convenient to decode the meaning of the mode + * string by overriding the onOp, onDeOp, onVoice, onDeVoice, + * onChannelKey, onDeChannelKey, onChannelLimit, onDeChannelLimit, + * onChannelBan or onDeChannelBan methods as appropriate. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param channel The channel that the mode operation applies to. + * @param sourceNick The nick of the user that set the mode. + * @param sourceLogin The login of the user that set the mode. + * @param sourceHostname The hostname of the user that set the mode. + * @param mode The mode that has been set. + * + */ + protected void onMode(String channel, String sourceNick, String sourceLogin, String sourceHostname, String mode) {} + + + /** + * Called when the mode of a user is set. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 1.2.0 + * + * @param targetNick The nick that the mode operation applies to. + * @param sourceNick The nick of the user that set the mode. + * @param sourceLogin The login of the user that set the mode. + * @param sourceHostname The hostname of the user that set the mode. + * @param mode The mode that has been set. + * + */ + protected void onUserMode(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String mode) {} + + + + /** + * Called when a user (possibly us) gets granted operator status for a channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param recipient The nick of the user that got 'opped'. + */ + protected void onOp(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} + + + /** + * Called when a user (possibly us) gets operator status taken away. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param recipient The nick of the user that got 'deopped'. + */ + protected void onDeop(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} + + + /** + * Called when a user (possibly us) gets voice status granted in a channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param recipient The nick of the user that got 'voiced'. + */ + protected void onVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} + + + /** + * Called when a user (possibly us) gets voice status removed. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param recipient The nick of the user that got 'devoiced'. + */ + protected void onDeVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} + + + /** + * Called when a channel key is set. When the channel key has been set, + * other users may only join that channel if they know the key. Channel keys + * are sometimes referred to as passwords. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param key The new key for the channel. + */ + protected void onSetChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {} + + + /** + * Called when a channel key is removed. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param key The key that was in use before the channel key was removed. + */ + protected void onRemoveChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {} + + + /** + * Called when a user limit is set for a channel. The number of users in + * the channel cannot exceed this limit. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param limit The maximum number of users that may be in this channel at the same time. + */ + protected void onSetChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname, int limit) {} + + + /** + * Called when the user limit is removed for a channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onRemoveChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a user (possibly us) gets banned from a channel. Being + * banned from a channel prevents any user with a matching hostmask from + * joining the channel. For this reason, most bans are usually directly + * followed by the user being kicked :-) + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param hostmask The hostmask of the user that has been banned. + */ + protected void onSetChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {} + + + /** + * Called when a hostmask ban is removed from a channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + * @param hostmask + */ + protected void onRemoveChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {} + + + /** + * Called when topic protection is enabled for a channel. Topic protection + * means that only operators in a channel may change the topic. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onSetTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when topic protection is removed for a channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onRemoveTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel is set to only allow messages from users that + * are in the channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onSetNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel is set to allow messages from any user, even + * if they are not actually in the channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onRemoveNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel is set to 'invite only' mode. A user may only + * join the channel if they are invited by someone who is already in the + * channel. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onSetInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel has 'invite only' removed. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onRemoveInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel is set to 'moderated' mode. If a channel is + * moderated, then only users who have been 'voiced' or 'opped' may speak + * or change their nicks. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onSetModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel has moderated mode removed. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onRemoveModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel is marked as being in private mode. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onSetPrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel is marked as not being in private mode. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onRemovePrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel is set to be in 'secret' mode. Such channels + * typically do not appear on a server's channel listing. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onSetSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when a channel has 'secret' mode removed. + *

+ * This is a type of mode change and is also passed to the onMode + * method in the PircBot class. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param channel The channel in which the mode change took place. + * @param sourceNick The nick of the user that performed the mode change. + * @param sourceLogin The login of the user that performed the mode change. + * @param sourceHostname The hostname of the user that performed the mode change. + */ + protected void onRemoveSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} + + + /** + * Called when we are invited to a channel by a user. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 0.9.5 + * + * @param targetNick The nick of the user being invited - should be us! + * @param sourceNick The nick of the user that sent the invitation. + * @param sourceLogin The login of the user that sent the invitation. + * @param sourceHostname The hostname of the user that sent the invitation. + * @param channel The channel that we're being invited to. + */ + protected void onInvite(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String channel) {} + + + /** + * This method used to be called when a DCC SEND request was sent to the PircBot. + * Please use the onIncomingFileTransfer method to receive files, as it + * has better functionality and supports resuming. + * + * @deprecated As of PircBot 1.2.0, use {@link #onIncomingFileTransfer(DccFileTransfer)} + */ + protected void onDccSendRequest(String sourceNick, String sourceLogin, String sourceHostname, String filename, long address, int port, int size) {} + + + /** + * This method used to be called when a DCC CHAT request was sent to the PircBot. + * Please use the onIncomingChatRequest method to accept chats, as it + * has better functionality. + * + * @deprecated As of PircBot 1.2.0, use {@link #onIncomingChatRequest(DccChat)} + */ + protected void onDccChatRequest(String sourceNick, String sourceLogin, String sourceHostname, long address, int port) {} + + + /** + * This method is called whenever a DCC SEND request is sent to the PircBot. + * This means that a client has requested to send a file to us. + * This abstract implementation performs no action, which means that all + * DCC SEND requests will be ignored by default. If you wish to receive + * the file, then you may override this method and call the receive method + * on the DccFileTransfer object, which connects to the sender and downloads + * the file. + *

+ * Example: + *

 public void onIncomingFileTransfer(DccFileTransfer transfer) {
+     *     // Use the suggested file name.
+     *     File file = transfer.getFile();
+     *     // Receive the transfer and save it to the file, allowing resuming.
+     *     transfer.receive(file, true);
+     * }
+ *

+ * Warning: Receiving an incoming file transfer will cause a file + * to be written to disk. Please ensure that you make adequate security + * checks so that this file does not overwrite anything important! + *

+ * Each time a file is received, it happens within a new Thread + * in order to allow multiple files to be downloaded by the PircBot + * at the same time. + *

+ * If you allow resuming and the file already partly exists, it will + * be appended to instead of overwritten. If resuming is not enabled, + * the file will be overwritten if it already exists. + *

+ * You can throttle the speed of the transfer by calling the setPacketDelay + * method on the DccFileTransfer object, either before you receive the + * file or at any moment during the transfer. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 1.2.0 + * + * @param transfer The DcccFileTransfer that you may accept. + * + * @see DccFileTransfer + * + */ + protected void onIncomingFileTransfer(DccFileTransfer transfer) {} + + + /** + * This method gets called when a DccFileTransfer has finished. + * If there was a problem, the Exception will say what went wrong. + * If the file was sent successfully, the Exception will be null. + *

+ * Both incoming and outgoing file transfers are passed to this method. + * You can determine the type by calling the isIncoming or isOutgoing + * methods on the DccFileTransfer object. + * + * @since PircBot 1.2.0 + * + * @param transfer The DccFileTransfer that has finished. + * @param e null if the file was transfered successfully, otherwise this + * will report what went wrong. + * + * @see DccFileTransfer + * + */ + protected void onFileTransferFinished(DccFileTransfer transfer, Exception e) {} + + + /** + * This method will be called whenever a DCC Chat request is received. + * This means that a client has requested to chat to us directly rather + * than via the IRC server. This is useful for sending many lines of text + * to and from the bot without having to worry about flooding the server + * or any operators of the server being able to "spy" on what is being + * said. This abstract implementation performs no action, which means + * that all DCC CHAT requests will be ignored by default. + *

+ * If you wish to accept the connection, then you may override this + * method and call the accept() method on the DccChat object, which + * connects to the sender of the chat request and allows lines to be + * sent to and from the bot. + *

+ * Your bot must be able to connect directly to the user that sent the + * request. + *

+ * Example: + *

 public void onIncomingChatRequest(DccChat chat) {
+     *     try {
+     *         // Accept all chat, whoever it's from.
+     *         chat.accept();
+     *         chat.sendLine("Hello");
+     *         String response = chat.readLine();
+     *         chat.close();
+     *     }
+     *     catch (IOException e) {}
+     * }
+ * + * Each time this method is called, it is called from within a new Thread + * so that multiple DCC CHAT sessions can run concurrently. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @since PircBot 1.2.0 + * + * @param chat A DccChat object that represents the incoming chat request. + * + * @see DccChat + * + */ + protected void onIncomingChatRequest(DccChat chat) {} + + + /** + * This method is called whenever we receive a VERSION request. + * This abstract implementation responds with the PircBot's _version string, + * so if you override this method, be sure to either mimic its functionality + * or to call super.onVersion(...); + * + * @param sourceNick The nick of the user that sent the VERSION request. + * @param sourceLogin The login of the user that sent the VERSION request. + * @param sourceHostname The hostname of the user that sent the VERSION request. + * @param target The target of the VERSION request, be it our nick or a channel name. + */ + protected void onVersion(String sourceNick, String sourceLogin, String sourceHostname, String target) { + this.sendRawLine("NOTICE " + sourceNick + " :\u0001VERSION " + _version + "\u0001"); + } + + + /** + * This method is called whenever we receive a PING request from another + * user. + *

+ * This abstract implementation responds correctly, so if you override this + * method, be sure to either mimic its functionality or to call + * super.onPing(...); + * + * @param sourceNick The nick of the user that sent the PING request. + * @param sourceLogin The login of the user that sent the PING request. + * @param sourceHostname The hostname of the user that sent the PING request. + * @param target The target of the PING request, be it our nick or a channel name. + * @param pingValue The value that was supplied as an argument to the PING command. + */ + protected void onPing(String sourceNick, String sourceLogin, String sourceHostname, String target, String pingValue) { + this.sendRawLine("NOTICE " + sourceNick + " :\u0001PING " + pingValue + "\u0001"); + } + + + /** + * The actions to perform when a PING request comes from the server. + *

+ * This sends back a correct response, so if you override this method, + * be sure to either mimic its functionality or to call + * super.onServerPing(response); + * + * @param response The response that should be given back in your PONG. + */ + protected void onServerPing(String response) { + this.sendRawLine("PONG " + response); + } + + + /** + * This method is called whenever we receive a TIME request. + *

+ * This abstract implementation responds correctly, so if you override this + * method, be sure to either mimic its functionality or to call + * super.onTime(...); + * + * @param sourceNick The nick of the user that sent the TIME request. + * @param sourceLogin The login of the user that sent the TIME request. + * @param sourceHostname The hostname of the user that sent the TIME request. + * @param target The target of the TIME request, be it our nick or a channel name. + */ + protected void onTime(String sourceNick, String sourceLogin, String sourceHostname, String target) { + this.sendRawLine("NOTICE " + sourceNick + " :\u0001TIME " + new Date().toString() + "\u0001"); + } + + + /** + * This method is called whenever we receive a FINGER request. + *

+ * This abstract implementation responds correctly, so if you override this + * method, be sure to either mimic its functionality or to call + * super.onFinger(...); + * + * @param sourceNick The nick of the user that sent the FINGER request. + * @param sourceLogin The login of the user that sent the FINGER request. + * @param sourceHostname The hostname of the user that sent the FINGER request. + * @param target The target of the FINGER request, be it our nick or a channel name. + */ + protected void onFinger(String sourceNick, String sourceLogin, String sourceHostname, String target) { + this.sendRawLine("NOTICE " + sourceNick + " :\u0001FINGER " + _finger + "\u0001"); + } + + + /** + * This method is called whenever we receive a line from the server that + * the PircBot has not been programmed to recognise. + *

+ * The implementation of this method in the PircBot abstract class + * performs no actions and may be overridden as required. + * + * @param line The raw line that was received from the server. + */ + protected void onUnknown(String line) { + // And then there were none :) + } + + + /** + * Sets the verbose mode. If verbose mode is set to true, then log entries + * will be printed to the standard output. The default value is false and + * will result in no output. For general development, we strongly recommend + * setting the verbose mode to true. + * + * @param verbose true if verbose mode is to be used. Default is false. + */ + public final void setVerbose(boolean verbose) { + _verbose = verbose; + } + + + /** + * Sets the name of the bot, which will be used as its nick when it + * tries to join an IRC server. This should be set before joining + * any servers, otherwise the default nick will be used. You would + * typically call this method from the constructor of the class that + * extends PircBot. + *

+ * The changeNick method should be used if you wish to change your nick + * when you are connected to a server. + * + * @param name The new name of the Bot. + */ + protected final void setName(String name) { + _name = name; + } + + + /** + * Sets the internal nick of the bot. This is only to be called by the + * PircBot class in response to notification of nick changes that apply + * to us. + * + * @param nick The new nick. + */ + private final void setNick(String nick) { + _nick = nick; + } + + + /** + * Sets the internal login of the Bot. This should be set before joining + * any servers. + * + * @param login The new login of the Bot. + */ + protected final void setLogin(String login) { + _login = login; + } + + + /** + * Sets the internal version of the Bot. This should be set before joining + * any servers. + * + * @param version The new version of the Bot. + */ + protected final void setVersion(String version) { + _version = version; + } + + + /** + * Sets the interal finger message. This should be set before joining + * any servers. + * + * @param finger The new finger message for the Bot. + */ + protected final void setFinger(String finger) { + _finger = finger; + } + + + /** + * Gets the name of the PircBot. This is the name that will be used as + * as a nick when we try to join servers. + * + * @return The name of the PircBot. + */ + public final String getName() { + return _name; + } + + + /** + * Returns the current nick of the bot. Note that if you have just changed + * your nick, this method will still return the old nick until confirmation + * of the nick change is received from the server. + *

+ * The nick returned by this method is maintained only by the PircBot + * class and is guaranteed to be correct in the context of the IRC server. + * + * @since PircBot 1.0.0 + * + * @return The current nick of the bot. + */ + public String getNick() { + return _nick; + } + + + /** + * Gets the internal login of the PircBot. + * + * @return The login of the PircBot. + */ + public final String getLogin() { + return _login; + } + + + /** + * Gets the internal version of the PircBot. + * + * @return The version of the PircBot. + */ + public final String getVersion() { + return _version; + } + + + /** + * Gets the internal finger message of the PircBot. + * + * @return The finger message of the PircBot. + */ + public final String getFinger() { + return _finger; + } + + + /** + * Returns whether or not the PircBot is currently connected to a server. + * The result of this method should only act as a rough guide, + * as the result may not be valid by the time you act upon it. + * + * @return True if and only if the PircBot is currently connected to a server. + */ + public final synchronized boolean isConnected() { + return _inputThread != null && _inputThread.isConnected(); + } + + + /** + * Sets the number of milliseconds to delay between consecutive + * messages when there are multiple messages waiting in the + * outgoing message queue. This has a default value of 1000ms. + * It is a good idea to stick to this default value, as it will + * prevent your bot from spamming servers and facing the subsequent + * wrath! However, if you do need to change this delay value (not + * recommended), then this is the method to use. + * + * @param delay The number of milliseconds between each outgoing message. + * + */ + public final void setMessageDelay(long delay) { + if (delay < 0) { + throw new IllegalArgumentException("Cannot have a negative time."); + } + _messageDelay = delay; + } + + + /** + * Returns the number of milliseconds that will be used to separate + * consecutive messages to the server from the outgoing message queue. + * + * @return Number of milliseconds. + */ + public final long getMessageDelay() { + return _messageDelay; + } + + + /** + * Gets the maximum length of any line that is sent via the IRC protocol. + * The IRC RFC specifies that line lengths, including the trailing \r\n + * must not exceed 512 bytes. Hence, there is currently no option to + * change this value in PircBot. All lines greater than this length + * will be truncated before being sent to the IRC server. + * + * @return The maximum line length (currently fixed at 512) + */ + public final int getMaxLineLength() { + return InputThread.MAX_LINE_LENGTH; + } + + + /** + * Gets the number of lines currently waiting in the outgoing message Queue. + * If this returns 0, then the Queue is empty and any new message is likely + * to be sent to the IRC server immediately. + * + * @since PircBot 0.9.9 + * + * @return The number of lines in the outgoing message Queue. + */ + public final int getOutgoingQueueSize() { + return _outQueue.size(); + } + + + /** + * Returns the name of the last IRC server the PircBot tried to connect to. + * This does not imply that the connection attempt to the server was + * successful (we suggest you look at the onConnect method). + * A value of null is returned if the PircBot has never tried to connect + * to a server. + * + * @return The name of the last machine we tried to connect to. Returns + * null if no connection attempts have ever been made. + */ + public final String getServer() { + return _server; + } + + + /** + * Returns the port number of the last IRC server that the PircBot tried + * to connect to. + * This does not imply that the connection attempt to the server was + * successful (we suggest you look at the onConnect method). + * A value of -1 is returned if the PircBot has never tried to connect + * to a server. + * + * @since PircBot 0.9.9 + * + * @return The port number of the last IRC server we connected to. + * Returns -1 if no connection attempts have ever been made. + */ + public final int getPort() { + return _port; + } + + + /** + * Returns the last password that we used when connecting to an IRC server. + * This does not imply that the connection attempt to the server was + * successful (we suggest you look at the onConnect method). + * A value of null is returned if the PircBot has never tried to connect + * to a server using a password. + * + * @since PircBot 0.9.9 + * + * @return The last password that we used when connecting to an IRC server. + * Returns null if we have not previously connected using a password. + */ + public final String getPassword() { + return _password; + } + + + /** + * A convenient method that accepts an IP address represented as a + * long and returns an integer array of size 4 representing the same + * IP address. + * + * @since PircBot 0.9.4 + * + * @param address the long value representing the IP address. + * + * @return An int[] of size 4. + */ + public int[] longToIp(long address) { + int[] ip = new int[4]; + for (int i = 3; i >= 0; i--) { + ip[i] = (int) (address % 256); + address = address / 256; + } + return ip; + } + + + /** + * A convenient method that accepts an IP address represented by a byte[] + * of size 4 and returns this as a long representation of the same IP + * address. + * + * @since PircBot 0.9.4 + * + * @param address the byte[] of size 4 representing the IP address. + * + * @return a long representation of the IP address. + */ + public long ipToLong(byte[] address) { + if (address.length != 4) { + throw new IllegalArgumentException("byte array must be of length 4"); + } + long ipNum = 0; + long multiplier = 1; + for (int i = 3; i >= 0; i--) { + int byteVal = (address[i] + 256) % 256; + ipNum += byteVal*multiplier; + multiplier *= 256; + } + return ipNum; + } + + + /** + * Sets the encoding charset to be used when sending or receiving lines + * from the IRC server. If set to null, then the platform's default + * charset is used. You should only use this method if you are + * trying to send text to an IRC server in a different charset, e.g. + * "GB2312" for Chinese encoding. If a PircBot is currently connected + * to a server, then it must reconnect before this change takes effect. + * + * @since PircBot 1.0.4 + * + * @param charset The new encoding charset to be used by PircBot. + * + * @throws UnsupportedEncodingException If the named charset is not + * supported. + */ + public void setEncoding(String charset) throws UnsupportedEncodingException { + // Just try to see if the charset is supported first... + "".getBytes(charset); + + _charset = charset; + } + + + /** + * Returns the encoding used to send and receive lines from + * the IRC server, or null if not set. Use the setEncoding + * method to change the encoding charset. + * + * @since PircBot 1.0.4 + * + * @return The encoding used to send outgoing messages, or + * null if not set. + */ + public String getEncoding() { + return _charset; + } + + /** + * Returns the InetAddress used by the PircBot. + * This can be used to find the I.P. address from which the PircBot is + * connected to a server. + * + * @since PircBot 1.4.4 + * + * @return The current local InetAddress, or null if never connected. + */ + public InetAddress getInetAddress() { + return _inetAddress; + } + + + /** + * Sets the InetAddress to be used when sending DCC chat or file transfers. + * This can be very useful when you are running a bot on a machine which + * is behind a firewall and you need to tell receiving clients to connect + * to a NAT/router, which then forwards the connection. + * + * @since PircBot 1.4.4 + * + * @param dccInetAddress The new InetAddress, or null to use the default. + */ + public void setDccInetAddress(InetAddress dccInetAddress) { + _dccInetAddress = dccInetAddress; + } + + + /** + * Returns the InetAddress used when sending DCC chat or file transfers. + * If this is null, the default InetAddress will be used. + * + * @since PircBot 1.4.4 + * + * @return The current DCC InetAddress, or null if left as default. + */ + public InetAddress getDccInetAddress() { + return _dccInetAddress; + } + + + /** + * Returns the set of port numbers to be used when sending a DCC chat + * or file transfer. This is useful when you are behind a firewall and + * need to set up port forwarding. The array of port numbers is traversed + * in sequence until a free port is found to listen on. A DCC tranfer will + * fail if all ports are already in use. + * If set to null, any free port number will be used. + * + * @since PircBot 1.4.4 + * + * @return An array of port numbers that PircBot can use to send DCC + * transfers, or null if any port is allowed. + */ + public int[] getDccPorts() { + if (_dccPorts == null || _dccPorts.length == 0) { + return null; + } + // Clone the array to prevent external modification. + return (int[]) _dccPorts.clone(); + } + + + /** + * Sets the choice of port numbers that can be used when sending a DCC chat + * or file transfer. This is useful when you are behind a firewall and + * need to set up port forwarding. The array of port numbers is traversed + * in sequence until a free port is found to listen on. A DCC tranfer will + * fail if all ports are already in use. + * If set to null, any free port number will be used. + * + * @since PircBot 1.4.4 + * + * @param ports The set of port numbers that PircBot may use for DCC + * transfers, or null to let it use any free port (default). + * + */ + public void setDccPorts(int[] ports) { + if (ports == null || ports.length == 0) { + _dccPorts = null; + } + else { + // Clone the array to prevent external modification. + _dccPorts = (int[]) ports.clone(); + } + } + + + /** + * Returns true if and only if the object being compared is the exact + * same instance as this PircBot. This may be useful if you are writing + * a multiple server IRC bot that uses more than one instance of PircBot. + * + * @since PircBot 0.9.9 + * + * @return true if and only if Object o is a PircBot and equal to this. + */ + public boolean equals(Object o) { + // This probably has the same effect as Object.equals, but that may change... + if (o instanceof PircBot) { + PircBot other = (PircBot) o; + return other == this; + } + return false; + } + + + /** + * Returns the hashCode of this PircBot. This method can be called by hashed + * collection classes and is useful for managing multiple instances of + * PircBots in such collections. + * + * @since PircBot 0.9.9 + * + * @return the hash code for this instance of PircBot. + */ + public int hashCode() { + return super.hashCode(); + } + + + /** + * Returns a String representation of this object. + * You may find this useful for debugging purposes, particularly + * if you are using more than one PircBot instance to achieve + * multiple server connectivity. The format of + * this String may change between different versions of PircBot + * but is currently something of the form + * + * Version{PircBot x.y.z Java IRC Bot - www.jibble.org} + * Connected{true} + * Server{irc.dal.net} + * Port{6667} + * Password{} + * + * + * @since PircBot 0.9.10 + * + * @return a String representation of this object. + */ + public String toString() { + return "Version{" + _version + "}" + + " Connected{" + isConnected() + "}" + + " Server{" + _server + "}" + + " Port{" + _port + "}" + + " Password{" + _password + "}"; + } + + + /** + * Returns an array of all users in the specified channel. + *

+ * There are some important things to note about this method:- + *

    + *
  • This method may not return a full list of users if you call it + * before the complete nick list has arrived from the IRC server. + *
  • + *
  • If you wish to find out which users are in a channel as soon + * as you join it, then you should override the onUserList method + * instead of calling this method, as the onUserList method is only + * called as soon as the full user list has been received. + *
  • + *
  • This method will return immediately, as it does not require any + * interaction with the IRC server. + *
  • + *
  • The bot must be in a channel to be able to know which users are + * in it. + *
  • + *
+ * + * @since PircBot 1.0.0 + * + * @param channel The name of the channel to list. + * + * @return An array of User objects. This array is empty if we are not + * in the channel. + * + * @see #onUserList(String,User[]) onUserList + */ + public final User[] getUsers(String channel) { + channel = channel.toLowerCase(); + User[] userArray = new User[0]; + synchronized (_channels) { + Hashtable users = _channels.get(channel); + if (users != null) { + userArray = new User[users.size()]; + Enumeration enumeration = users.elements(); + for (int i = 0; i < userArray.length; i++) { + User user = (User) enumeration.nextElement(); + userArray[i] = user; + } + } + } + return userArray; + } + + + /** + * Returns an array of all channels that we are in. Note that if you + * call this method immediately after joining a new channel, the new + * channel may not appear in this array as it is not possible to tell + * if the join was successful until a response is received from the + * IRC server. + * + * @since PircBot 1.0.0 + * + * @return A String array containing the names of all channels that we + * are in. + */ + public final String[] getChannels() { + String[] channels = new String[0]; + synchronized (_channels) { + channels = new String[_channels.size()]; + Enumeration enumeration = _channels.keys(); + for (int i = 0; i < channels.length; i++) { + channels[i] = (String) enumeration.nextElement(); + } + } + return channels; + } + + + /** + * Disposes of all thread resources used by this PircBot. This may be + * useful when writing bots or clients that use multiple servers (and + * therefore multiple PircBot instances) or when integrating a PircBot + * with an existing program. + *

+ * Each PircBot runs its own threads for dispatching messages from its + * outgoing message queue and receiving messages from the server. + * Calling dispose() ensures that these threads are + * stopped, thus freeing up system resources and allowing the PircBot + * object to be garbage collected if there are no other references to + * it. + *

+ * Once a PircBot object has been disposed, it should not be used again. + * Attempting to use a PircBot that has been disposed may result in + * unpredictable behaviour. + * + * @since 1.2.2 + */ + public synchronized void dispose() { + //System.out.println("disposing..."); + _outputThread.interrupt(); + _inputThread.dispose(); + } + + + /** + * Add a user to the specified channel in our memory. + * Overwrite the existing entry if it exists. + */ + private final void addUser(String channel, User user) { + channel = channel.toLowerCase(); + synchronized (_channels) { + Hashtable users = _channels.get(channel); + if (users == null) { + users = new Hashtable(); + _channels.put(channel, users); + } + users.put(user, user); + } + } + + + /** + * Remove a user from the specified channel in our memory. + */ + private final User removeUser(String channel, String nick) { + channel = channel.toLowerCase(); + User user = new User("", nick); + synchronized (_channels) { + Hashtable users = _channels.get(channel); + if (users != null) { + return (User) users.remove(user); + } + } + return null; + } + + + /** + * Remove a user from all channels in our memory. + */ + private final void removeUser(String nick) { + synchronized (_channels) { + Enumeration enumeration = _channels.keys(); + while (enumeration.hasMoreElements()) { + String channel = (String) enumeration.nextElement(); + this.removeUser(channel, nick); + } + } + } + + + /** + * Rename a user if they appear in any of the channels we know about. + */ + private final void renameUser(String oldNick, String newNick) { + synchronized (_channels) { + Enumeration enumeration = _channels.keys(); + while (enumeration.hasMoreElements()) { + String channel = (String) enumeration.nextElement(); + User user = this.removeUser(channel, oldNick); + if (user != null) { + user = new User(user.getPrefix(), newNick); + this.addUser(channel, user); + } + } + } + } + + + /** + * Removes an entire channel from our memory of users. + */ + private final void removeChannel(String channel) { + channel = channel.toLowerCase(); + synchronized (_channels) { + _channels.remove(channel); + } + } + + + /** + * Removes all channels from our memory of users. + */ + private final void removeAllChannels() { + synchronized(_channels) { + _channels = new Hashtable>(); + } + } + + + private final void updateUser(String channel, int userMode, String nick) { + channel = channel.toLowerCase(); + synchronized (_channels) { + Hashtable users = _channels.get(channel); + User newUser = null; + if (users != null) { + Enumeration enumeration = users.elements(); + while(enumeration.hasMoreElements()) { + User userObj = (User) enumeration.nextElement(); + if (userObj.getNick().equalsIgnoreCase(nick)) { + if (userMode == OP_ADD) { + if (userObj.hasVoice()) { + newUser = new User("@+", nick); + } + else { + newUser = new User("@", nick); + } + } + else if (userMode == OP_REMOVE) { + if(userObj.hasVoice()) { + newUser = new User("+", nick); + } + else { + newUser = new User("", nick); + } + } + else if (userMode == VOICE_ADD) { + if(userObj.isOp()) { + newUser = new User("@+", nick); + } + else { + newUser = new User("+", nick); + } + } + else if (userMode == VOICE_REMOVE) { + if(userObj.isOp()) { + newUser = new User("@", nick); + } + else { + newUser = new User("", nick); + } + } + } + } + } + if (newUser != null) { + users.put(newUser, newUser); + } + else { + // just in case ... + newUser = new User("", nick); + users.put(newUser, newUser); + } + } + } + + + // Connection stuff. + private InputThread _inputThread = null; + private OutputThread _outputThread = null; + private String _charset = null; + private InetAddress _inetAddress = null; + + // Details about the last server that we connected to. + private String _server = null; + private int _port = -1; + private String _password = null; + + // Outgoing message stuff. + private Queue _outQueue = new Queue(); + private long _messageDelay = 1000; + + // A Hashtable of channels that points to a selfreferential Hashtable of + // User objects (used to remember which users are in which channels). + private Hashtable> _channels = new Hashtable>(); + + // A Hashtable to temporarily store channel topics when we join them + // until we find out who set that topic. + private Hashtable _topics = new Hashtable(); + + // DccManager to process and handle all DCC events. + private DccManager _dccManager = new DccManager(this); + private int[] _dccPorts = null; + private InetAddress _dccInetAddress = null; + + // Default settings for the PircBot. + private boolean _autoNickChange = false; + private boolean _verbose = false; + private String _name = "PircBot"; + private String _nick = _name; + private String _login = "PircBot"; + private String _version = "PircBot " + VERSION + " Java IRC Bot - www.jibble.org"; + private String _finger = "You ought to be arrested for fingering a bot!"; + + private String _channelPrefixes = "#&+!"; +} diff --git a/src/org/jibble/pircbot/Queue.java b/src/org/jibble/pircbot/Queue.java index 37c899e..aa05e05 100644 --- a/src/org/jibble/pircbot/Queue.java +++ b/src/org/jibble/pircbot/Queue.java @@ -1,146 +1,146 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -import java.util.Vector; - -/** - * Queue is a definition of a data structure that may - * act as a queue - that is, data can be added to one end of the - * queue and data can be requested from the head end of the queue. - * This class is thread safe for multiple producers and a single - * consumer. The next() method will block until there is data in - * the queue. - * - * This has now been modified so that it is compatible with - * the earlier JDK1.1 in order to be suitable for running on - * mobile appliances. This means replacing the LinkedList with - * a Vector, which is hardly ideal, but this Queue is typically - * only polled every second before dispatching messages. - * - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class Queue { - - - /** - * Constructs a Queue object of unlimited size. - */ - public Queue() { - - } - - - /** - * Adds an Object to the end of the Queue. - * - * @param o The Object to be added to the Queue. - */ - public void add(Object o) { - synchronized(_queue) { - _queue.addElement(o); - _queue.notify(); - } - } - - - /** - * Adds an Object to the front of the Queue. - * - * @param o The Object to be added to the Queue. - */ - public void addFront(Object o) { - synchronized(_queue) { - _queue.insertElementAt(o, 0); - _queue.notify(); - } - } - - - /** - * Returns the Object at the front of the Queue. This - * Object is then removed from the Queue. If the Queue - * is empty, then this method shall block until there - * is an Object in the Queue to return. - * - * @return The next item from the front of the queue. - */ - public Object next() { - - Object o = null; - - // Block if the Queue is empty. - synchronized(_queue) { - if (_queue.size() == 0) { - try { - _queue.wait(); - } - catch (InterruptedException e) { - return null; - } - } - - // Return the Object. - try { - o = _queue.firstElement(); - _queue.removeElementAt(0); - } - catch (ArrayIndexOutOfBoundsException e) { - throw new InternalError("Race hazard in Queue object."); - } - } - - return o; - } - - - /** - * Returns true if the Queue is not empty. If another - * Thread empties the Queue before next() is - * called, then the call to next() shall block - * until the Queue has been populated again. - * - * @return True only if the Queue not empty. - */ - public boolean hasNext() { - return (this.size() != 0); - } - - - /** - * Clears the contents of the Queue. - */ - public void clear() { - synchronized(_queue) { - _queue.removeAllElements(); - } - } - - - /** - * Returns the size of the Queue. - * - * @return The current size of the queue. - */ - public int size() { - return _queue.size(); - } - - - private Vector _queue = new Vector(); - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +import java.util.Vector; + +/** + * Queue is a definition of a data structure that may + * act as a queue - that is, data can be added to one end of the + * queue and data can be requested from the head end of the queue. + * This class is thread safe for multiple producers and a single + * consumer. The next() method will block until there is data in + * the queue. + * + * This has now been modified so that it is compatible with + * the earlier JDK1.1 in order to be suitable for running on + * mobile appliances. This means replacing the LinkedList with + * a Vector, which is hardly ideal, but this Queue is typically + * only polled every second before dispatching messages. + * + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class Queue { + + + /** + * Constructs a Queue object of unlimited size. + */ + public Queue() { + + } + + + /** + * Adds an Object to the end of the Queue. + * + * @param o The Object to be added to the Queue. + */ + public void add(Object o) { + synchronized(_queue) { + _queue.addElement(o); + _queue.notify(); + } + } + + + /** + * Adds an Object to the front of the Queue. + * + * @param o The Object to be added to the Queue. + */ + public void addFront(Object o) { + synchronized(_queue) { + _queue.insertElementAt(o, 0); + _queue.notify(); + } + } + + + /** + * Returns the Object at the front of the Queue. This + * Object is then removed from the Queue. If the Queue + * is empty, then this method shall block until there + * is an Object in the Queue to return. + * + * @return The next item from the front of the queue. + */ + public Object next() { + + Object o = null; + + // Block if the Queue is empty. + synchronized(_queue) { + if (_queue.size() == 0) { + try { + _queue.wait(); + } + catch (InterruptedException e) { + return null; + } + } + + // Return the Object. + try { + o = _queue.firstElement(); + _queue.removeElementAt(0); + } + catch (ArrayIndexOutOfBoundsException e) { + throw new InternalError("Race hazard in Queue object."); + } + } + + return o; + } + + + /** + * Returns true if the Queue is not empty. If another + * Thread empties the Queue before next() is + * called, then the call to next() shall block + * until the Queue has been populated again. + * + * @return True only if the Queue not empty. + */ + public boolean hasNext() { + return (this.size() != 0); + } + + + /** + * Clears the contents of the Queue. + */ + public void clear() { + synchronized(_queue) { + _queue.removeAllElements(); + } + } + + + /** + * Returns the size of the Queue. + * + * @return The current size of the queue. + */ + public int size() { + return _queue.size(); + } + + + private Vector _queue = new Vector(); + +} diff --git a/src/org/jibble/pircbot/ReplyConstants.java b/src/org/jibble/pircbot/ReplyConstants.java index 4fabfe0..8d85f3f 100644 --- a/src/org/jibble/pircbot/ReplyConstants.java +++ b/src/org/jibble/pircbot/ReplyConstants.java @@ -1,176 +1,176 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - - -package org.jibble.pircbot; - -/** - * This interface contains the values of all numeric replies specified - * in section 6 of RFC 1459. Refer to RFC 1459 for further information. - *

- * If you override the onServerResponse method in the PircBot class, - * you may find these constants useful when comparing the numeric - * value of a given code. - * - * @since 1.0.0 - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public interface ReplyConstants { - - - // Error Replies. - public static final int ERR_NOSUCHNICK = 401; - public static final int ERR_NOSUCHSERVER = 402; - public static final int ERR_NOSUCHCHANNEL = 403; - public static final int ERR_CANNOTSENDTOCHAN = 404; - public static final int ERR_TOOMANYCHANNELS = 405; - public static final int ERR_WASNOSUCHNICK = 406; - public static final int ERR_TOOMANYTARGETS = 407; - public static final int ERR_NOORIGIN = 409; - public static final int ERR_NORECIPIENT = 411; - public static final int ERR_NOTEXTTOSEND = 412; - public static final int ERR_NOTOPLEVEL = 413; - public static final int ERR_WILDTOPLEVEL = 414; - public static final int ERR_UNKNOWNCOMMAND = 421; - public static final int ERR_NOMOTD = 422; - public static final int ERR_NOADMININFO = 423; - public static final int ERR_FILEERROR = 424; - public static final int ERR_NONICKNAMEGIVEN = 431; - public static final int ERR_ERRONEUSNICKNAME = 432; - public static final int ERR_NICKNAMEINUSE = 433; - public static final int ERR_NICKCOLLISION = 436; - public static final int ERR_USERNOTINCHANNEL = 441; - public static final int ERR_NOTONCHANNEL = 442; - public static final int ERR_USERONCHANNEL = 443; - public static final int ERR_NOLOGIN = 444; - public static final int ERR_SUMMONDISABLED = 445; - public static final int ERR_USERSDISABLED = 446; - public static final int ERR_NOTREGISTERED = 451; - public static final int ERR_NEEDMOREPARAMS = 461; - public static final int ERR_ALREADYREGISTRED = 462; - public static final int ERR_NOPERMFORHOST = 463; - public static final int ERR_PASSWDMISMATCH = 464; - public static final int ERR_YOUREBANNEDCREEP = 465; - public static final int ERR_KEYSET = 467; - public static final int ERR_CHANNELISFULL = 471; - public static final int ERR_UNKNOWNMODE = 472; - public static final int ERR_INVITEONLYCHAN = 473; - public static final int ERR_BANNEDFROMCHAN = 474; - public static final int ERR_BADCHANNELKEY = 475; - public static final int ERR_NOPRIVILEGES = 481; - public static final int ERR_CHANOPRIVSNEEDED = 482; - public static final int ERR_CANTKILLSERVER = 483; - public static final int ERR_NOOPERHOST = 491; - public static final int ERR_UMODEUNKNOWNFLAG = 501; - public static final int ERR_USERSDONTMATCH = 502; - - - // Command Responses. - public static final int RPL_TRACELINK = 200; - public static final int RPL_TRACECONNECTING = 201; - public static final int RPL_TRACEHANDSHAKE = 202; - public static final int RPL_TRACEUNKNOWN = 203; - public static final int RPL_TRACEOPERATOR = 204; - public static final int RPL_TRACEUSER = 205; - public static final int RPL_TRACESERVER = 206; - public static final int RPL_TRACENEWTYPE = 208; - public static final int RPL_STATSLINKINFO = 211; - public static final int RPL_STATSCOMMANDS = 212; - public static final int RPL_STATSCLINE = 213; - public static final int RPL_STATSNLINE = 214; - public static final int RPL_STATSILINE = 215; - public static final int RPL_STATSKLINE = 216; - public static final int RPL_STATSYLINE = 218; - public static final int RPL_ENDOFSTATS = 219; - public static final int RPL_UMODEIS = 221; - public static final int RPL_STATSLLINE = 241; - public static final int RPL_STATSUPTIME = 242; - public static final int RPL_STATSOLINE = 243; - public static final int RPL_STATSHLINE = 244; - public static final int RPL_LUSERCLIENT = 251; - public static final int RPL_LUSEROP = 252; - public static final int RPL_LUSERUNKNOWN = 253; - public static final int RPL_LUSERCHANNELS = 254; - public static final int RPL_LUSERME = 255; - public static final int RPL_ADMINME = 256; - public static final int RPL_ADMINLOC1 = 257; - public static final int RPL_ADMINLOC2 = 258; - public static final int RPL_ADMINEMAIL = 259; - public static final int RPL_TRACELOG = 261; - public static final int RPL_NONE = 300; - public static final int RPL_AWAY = 301; - public static final int RPL_USERHOST = 302; - public static final int RPL_ISON = 303; - public static final int RPL_UNAWAY = 305; - public static final int RPL_NOWAWAY = 306; - public static final int RPL_WHOISUSER = 311; - public static final int RPL_WHOISSERVER = 312; - public static final int RPL_WHOISOPERATOR = 313; - public static final int RPL_WHOWASUSER = 314; - public static final int RPL_ENDOFWHO = 315; - public static final int RPL_WHOISIDLE = 317; - public static final int RPL_ENDOFWHOIS = 318; - public static final int RPL_WHOISCHANNELS = 319; - public static final int RPL_LISTSTART = 321; - public static final int RPL_LIST = 322; - public static final int RPL_LISTEND = 323; - public static final int RPL_CHANNELMODEIS = 324; - public static final int RPL_NOTOPIC = 331; - public static final int RPL_TOPIC = 332; - public static final int RPL_TOPICINFO = 333; - public static final int RPL_INVITING = 341; - public static final int RPL_SUMMONING = 342; - public static final int RPL_VERSION = 351; - public static final int RPL_WHOREPLY = 352; - public static final int RPL_NAMREPLY = 353; - public static final int RPL_LINKS = 364; - public static final int RPL_ENDOFLINKS = 365; - public static final int RPL_ENDOFNAMES = 366; - public static final int RPL_BANLIST = 367; - public static final int RPL_ENDOFBANLIST = 368; - public static final int RPL_ENDOFWHOWAS = 369; - public static final int RPL_INFO = 371; - public static final int RPL_MOTD = 372; - public static final int RPL_ENDOFINFO = 374; - public static final int RPL_MOTDSTART = 375; - public static final int RPL_ENDOFMOTD = 376; - public static final int RPL_YOUREOPER = 381; - public static final int RPL_REHASHING = 382; - public static final int RPL_TIME = 391; - public static final int RPL_USERSSTART = 392; - public static final int RPL_USERS = 393; - public static final int RPL_ENDOFUSERS = 394; - public static final int RPL_NOUSERS = 395; - - - // Reserved Numerics. - public static final int RPL_TRACECLASS = 209; - public static final int RPL_STATSQLINE = 217; - public static final int RPL_SERVICEINFO = 231; - public static final int RPL_ENDOFSERVICES = 232; - public static final int RPL_SERVICE = 233; - public static final int RPL_SERVLIST = 234; - public static final int RPL_SERVLISTEND = 235; - public static final int RPL_WHOISCHANOP = 316; - public static final int RPL_KILLDONE = 361; - public static final int RPL_CLOSING = 362; - public static final int RPL_CLOSEEND = 363; - public static final int RPL_INFOSTART = 373; - public static final int RPL_MYPORTIS = 384; - public static final int ERR_YOUWILLBEBANNED = 466; - public static final int ERR_BADCHANMASK = 476; - public static final int ERR_NOSERVICEHOST = 492; - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + + +package org.jibble.pircbot; + +/** + * This interface contains the values of all numeric replies specified + * in section 6 of RFC 1459. Refer to RFC 1459 for further information. + *

+ * If you override the onServerResponse method in the PircBot class, + * you may find these constants useful when comparing the numeric + * value of a given code. + * + * @since 1.0.0 + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public interface ReplyConstants { + + + // Error Replies. + public static final int ERR_NOSUCHNICK = 401; + public static final int ERR_NOSUCHSERVER = 402; + public static final int ERR_NOSUCHCHANNEL = 403; + public static final int ERR_CANNOTSENDTOCHAN = 404; + public static final int ERR_TOOMANYCHANNELS = 405; + public static final int ERR_WASNOSUCHNICK = 406; + public static final int ERR_TOOMANYTARGETS = 407; + public static final int ERR_NOORIGIN = 409; + public static final int ERR_NORECIPIENT = 411; + public static final int ERR_NOTEXTTOSEND = 412; + public static final int ERR_NOTOPLEVEL = 413; + public static final int ERR_WILDTOPLEVEL = 414; + public static final int ERR_UNKNOWNCOMMAND = 421; + public static final int ERR_NOMOTD = 422; + public static final int ERR_NOADMININFO = 423; + public static final int ERR_FILEERROR = 424; + public static final int ERR_NONICKNAMEGIVEN = 431; + public static final int ERR_ERRONEUSNICKNAME = 432; + public static final int ERR_NICKNAMEINUSE = 433; + public static final int ERR_NICKCOLLISION = 436; + public static final int ERR_USERNOTINCHANNEL = 441; + public static final int ERR_NOTONCHANNEL = 442; + public static final int ERR_USERONCHANNEL = 443; + public static final int ERR_NOLOGIN = 444; + public static final int ERR_SUMMONDISABLED = 445; + public static final int ERR_USERSDISABLED = 446; + public static final int ERR_NOTREGISTERED = 451; + public static final int ERR_NEEDMOREPARAMS = 461; + public static final int ERR_ALREADYREGISTRED = 462; + public static final int ERR_NOPERMFORHOST = 463; + public static final int ERR_PASSWDMISMATCH = 464; + public static final int ERR_YOUREBANNEDCREEP = 465; + public static final int ERR_KEYSET = 467; + public static final int ERR_CHANNELISFULL = 471; + public static final int ERR_UNKNOWNMODE = 472; + public static final int ERR_INVITEONLYCHAN = 473; + public static final int ERR_BANNEDFROMCHAN = 474; + public static final int ERR_BADCHANNELKEY = 475; + public static final int ERR_NOPRIVILEGES = 481; + public static final int ERR_CHANOPRIVSNEEDED = 482; + public static final int ERR_CANTKILLSERVER = 483; + public static final int ERR_NOOPERHOST = 491; + public static final int ERR_UMODEUNKNOWNFLAG = 501; + public static final int ERR_USERSDONTMATCH = 502; + + + // Command Responses. + public static final int RPL_TRACELINK = 200; + public static final int RPL_TRACECONNECTING = 201; + public static final int RPL_TRACEHANDSHAKE = 202; + public static final int RPL_TRACEUNKNOWN = 203; + public static final int RPL_TRACEOPERATOR = 204; + public static final int RPL_TRACEUSER = 205; + public static final int RPL_TRACESERVER = 206; + public static final int RPL_TRACENEWTYPE = 208; + public static final int RPL_STATSLINKINFO = 211; + public static final int RPL_STATSCOMMANDS = 212; + public static final int RPL_STATSCLINE = 213; + public static final int RPL_STATSNLINE = 214; + public static final int RPL_STATSILINE = 215; + public static final int RPL_STATSKLINE = 216; + public static final int RPL_STATSYLINE = 218; + public static final int RPL_ENDOFSTATS = 219; + public static final int RPL_UMODEIS = 221; + public static final int RPL_STATSLLINE = 241; + public static final int RPL_STATSUPTIME = 242; + public static final int RPL_STATSOLINE = 243; + public static final int RPL_STATSHLINE = 244; + public static final int RPL_LUSERCLIENT = 251; + public static final int RPL_LUSEROP = 252; + public static final int RPL_LUSERUNKNOWN = 253; + public static final int RPL_LUSERCHANNELS = 254; + public static final int RPL_LUSERME = 255; + public static final int RPL_ADMINME = 256; + public static final int RPL_ADMINLOC1 = 257; + public static final int RPL_ADMINLOC2 = 258; + public static final int RPL_ADMINEMAIL = 259; + public static final int RPL_TRACELOG = 261; + public static final int RPL_NONE = 300; + public static final int RPL_AWAY = 301; + public static final int RPL_USERHOST = 302; + public static final int RPL_ISON = 303; + public static final int RPL_UNAWAY = 305; + public static final int RPL_NOWAWAY = 306; + public static final int RPL_WHOISUSER = 311; + public static final int RPL_WHOISSERVER = 312; + public static final int RPL_WHOISOPERATOR = 313; + public static final int RPL_WHOWASUSER = 314; + public static final int RPL_ENDOFWHO = 315; + public static final int RPL_WHOISIDLE = 317; + public static final int RPL_ENDOFWHOIS = 318; + public static final int RPL_WHOISCHANNELS = 319; + public static final int RPL_LISTSTART = 321; + public static final int RPL_LIST = 322; + public static final int RPL_LISTEND = 323; + public static final int RPL_CHANNELMODEIS = 324; + public static final int RPL_NOTOPIC = 331; + public static final int RPL_TOPIC = 332; + public static final int RPL_TOPICINFO = 333; + public static final int RPL_INVITING = 341; + public static final int RPL_SUMMONING = 342; + public static final int RPL_VERSION = 351; + public static final int RPL_WHOREPLY = 352; + public static final int RPL_NAMREPLY = 353; + public static final int RPL_LINKS = 364; + public static final int RPL_ENDOFLINKS = 365; + public static final int RPL_ENDOFNAMES = 366; + public static final int RPL_BANLIST = 367; + public static final int RPL_ENDOFBANLIST = 368; + public static final int RPL_ENDOFWHOWAS = 369; + public static final int RPL_INFO = 371; + public static final int RPL_MOTD = 372; + public static final int RPL_ENDOFINFO = 374; + public static final int RPL_MOTDSTART = 375; + public static final int RPL_ENDOFMOTD = 376; + public static final int RPL_YOUREOPER = 381; + public static final int RPL_REHASHING = 382; + public static final int RPL_TIME = 391; + public static final int RPL_USERSSTART = 392; + public static final int RPL_USERS = 393; + public static final int RPL_ENDOFUSERS = 394; + public static final int RPL_NOUSERS = 395; + + + // Reserved Numerics. + public static final int RPL_TRACECLASS = 209; + public static final int RPL_STATSQLINE = 217; + public static final int RPL_SERVICEINFO = 231; + public static final int RPL_ENDOFSERVICES = 232; + public static final int RPL_SERVICE = 233; + public static final int RPL_SERVLIST = 234; + public static final int RPL_SERVLISTEND = 235; + public static final int RPL_WHOISCHANOP = 316; + public static final int RPL_KILLDONE = 361; + public static final int RPL_CLOSING = 362; + public static final int RPL_CLOSEEND = 363; + public static final int RPL_INFOSTART = 373; + public static final int RPL_MYPORTIS = 384; + public static final int ERR_YOUWILLBEBANNED = 466; + public static final int ERR_BADCHANMASK = 476; + public static final int ERR_NOSERVICEHOST = 492; + +} diff --git a/src/org/jibble/pircbot/User.java b/src/org/jibble/pircbot/User.java index d4ce33a..ff74c18 100644 --- a/src/org/jibble/pircbot/User.java +++ b/src/org/jibble/pircbot/User.java @@ -1,161 +1,161 @@ -/* -Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ - -This file is part of PircBot. - -This software is dual-licensed, allowing you to choose between the GNU -General Public License (GPL) and the www.jibble.org Commercial License. -Since the GPL may be too restrictive for use in a proprietary application, -a commercial license is also provided. Full license information can be -found at http://www.jibble.org/licenses/ - -*/ - -package org.jibble.pircbot; - -/** - * This class is used to represent a user on an IRC server. - * Instances of this class are returned by the getUsers method - * in the PircBot class. - *

- * Note that this class no longer implements the Comparable interface - * for Java 1.1 compatibility reasons. - * - * @since 1.0.0 - * @author Paul James Mutton, - * http://www.jibble.org/ - * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) - */ -public class User { - - - /** - * Constructs a User object with a known prefix and nick. - * - * @param prefix The status of the user, for example, "@". - * @param nick The nick of the user. - */ - User(String prefix, String nick) { - _prefix = prefix; - _nick = nick; - _lowerNick = nick.toLowerCase(); - } - - - /** - * Returns the prefix of the user. If the User object has been obtained - * from a list of users in a channel, then this will reflect the user's - * status in that channel. - * - * @return The prefix of the user. If there is no prefix, then an empty - * String is returned. - */ - public String getPrefix() { - return _prefix; - } - - - /** - * Returns whether or not the user represented by this object is an - * operator. If the User object has been obtained from a list of users - * in a channel, then this will reflect the user's operator status in - * that channel. - * - * @return true if the user is an operator in the channel. - */ - public boolean isOp() { - return _prefix.indexOf('@') >= 0; - } - - - /** - * Returns whether or not the user represented by this object has - * voice. If the User object has been obtained from a list of users - * in a channel, then this will reflect the user's voice status in - * that channel. - * - * @return true if the user has voice in the channel. - */ - public boolean hasVoice() { - return _prefix.indexOf('+') >= 0; - } - - - /** - * Returns the nick of the user. - * - * @return The user's nick. - */ - public String getNick() { - return _nick; - } - - - /** - * Returns the nick of the user complete with their prefix if they - * have one, e.g. "@Dave". - * - * @return The user's prefix and nick. - */ - public String toString() { - return this.getPrefix() + this.getNick(); - } - - - /** - * Returns true if the nick represented by this User object is the same - * as the argument. A case insensitive comparison is made. - * - * @return true if the nicks are identical (case insensitive). - */ - public boolean equals(String nick) { - return nick.toLowerCase().equals(_lowerNick); - } - - - /** - * Returns true if the nick represented by this User object is the same - * as the nick of the User object given as an argument. - * A case insensitive comparison is made. - * - * @return true if o is a User object with a matching lowercase nick. - */ - public boolean equals(Object o) { - if (o instanceof User) { - User other = (User) o; - return other._lowerNick.equals(_lowerNick); - } - return false; - } - - - /** - * Returns the hash code of this User object. - * - * @return the hash code of the User object. - */ - public int hashCode() { - return _lowerNick.hashCode(); - } - - - /** - * Returns the result of calling the compareTo method on lowercased - * nicks. This is useful for sorting lists of User objects. - * - * @return the result of calling compareTo on lowercased nicks. - */ - public int compareTo(Object o) { - if (o instanceof User) { - User other = (User) o; - return other._lowerNick.compareTo(_lowerNick); - } - return -1; - } - - - private String _prefix; - private String _nick; - private String _lowerNick; - -} +/* +Copyright Paul James Mutton, 2001-2007, http://www.jibble.org/ + +This file is part of PircBot. + +This software is dual-licensed, allowing you to choose between the GNU +General Public License (GPL) and the www.jibble.org Commercial License. +Since the GPL may be too restrictive for use in a proprietary application, +a commercial license is also provided. Full license information can be +found at http://www.jibble.org/licenses/ + +*/ + +package org.jibble.pircbot; + +/** + * This class is used to represent a user on an IRC server. + * Instances of this class are returned by the getUsers method + * in the PircBot class. + *

+ * Note that this class no longer implements the Comparable interface + * for Java 1.1 compatibility reasons. + * + * @since 1.0.0 + * @author Paul James Mutton, + * http://www.jibble.org/ + * @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007) + */ +public class User { + + + /** + * Constructs a User object with a known prefix and nick. + * + * @param prefix The status of the user, for example, "@". + * @param nick The nick of the user. + */ + User(String prefix, String nick) { + _prefix = prefix; + _nick = nick; + _lowerNick = nick.toLowerCase(); + } + + + /** + * Returns the prefix of the user. If the User object has been obtained + * from a list of users in a channel, then this will reflect the user's + * status in that channel. + * + * @return The prefix of the user. If there is no prefix, then an empty + * String is returned. + */ + public String getPrefix() { + return _prefix; + } + + + /** + * Returns whether or not the user represented by this object is an + * operator. If the User object has been obtained from a list of users + * in a channel, then this will reflect the user's operator status in + * that channel. + * + * @return true if the user is an operator in the channel. + */ + public boolean isOp() { + return _prefix.indexOf('@') >= 0; + } + + + /** + * Returns whether or not the user represented by this object has + * voice. If the User object has been obtained from a list of users + * in a channel, then this will reflect the user's voice status in + * that channel. + * + * @return true if the user has voice in the channel. + */ + public boolean hasVoice() { + return _prefix.indexOf('+') >= 0; + } + + + /** + * Returns the nick of the user. + * + * @return The user's nick. + */ + public String getNick() { + return _nick; + } + + + /** + * Returns the nick of the user complete with their prefix if they + * have one, e.g. "@Dave". + * + * @return The user's prefix and nick. + */ + public String toString() { + return this.getPrefix() + this.getNick(); + } + + + /** + * Returns true if the nick represented by this User object is the same + * as the argument. A case insensitive comparison is made. + * + * @return true if the nicks are identical (case insensitive). + */ + public boolean equals(String nick) { + return nick.toLowerCase().equals(_lowerNick); + } + + + /** + * Returns true if the nick represented by this User object is the same + * as the nick of the User object given as an argument. + * A case insensitive comparison is made. + * + * @return true if o is a User object with a matching lowercase nick. + */ + public boolean equals(Object o) { + if (o instanceof User) { + User other = (User) o; + return other._lowerNick.equals(_lowerNick); + } + return false; + } + + + /** + * Returns the hash code of this User object. + * + * @return the hash code of the User object. + */ + public int hashCode() { + return _lowerNick.hashCode(); + } + + + /** + * Returns the result of calling the compareTo method on lowercased + * nicks. This is useful for sorting lists of User objects. + * + * @return the result of calling compareTo on lowercased nicks. + */ + public int compareTo(Object o) { + if (o instanceof User) { + User other = (User) o; + return other._lowerNick.compareTo(_lowerNick); + } + return -1; + } + + + private String _prefix; + private String _nick; + private String _lowerNick; + +} diff --git a/src/org/yaaic/command/BaseHandler.java b/src/org/yaaic/command/BaseHandler.java index e188380..66dfa5d 100644 --- a/src/org/yaaic/command/BaseHandler.java +++ b/src/org/yaaic/command/BaseHandler.java @@ -32,6 +32,7 @@ import org.yaaic.model.Server; */ public abstract class BaseHandler { + private String desc; /** * Execute the command * @@ -50,6 +51,13 @@ public abstract class BaseHandler */ public abstract String getUsage(); + /** + * Get the description for this command + * + * @return + */ + public abstract String getDescription(); + /** * Merge params to a string * diff --git a/src/org/yaaic/command/CommandParser.java b/src/org/yaaic/command/CommandParser.java index b326ce0..e74e8a4 100644 --- a/src/org/yaaic/command/CommandParser.java +++ b/src/org/yaaic/command/CommandParser.java @@ -21,6 +21,7 @@ along with Yaaic. If not, see . package org.yaaic.command; import java.util.HashMap; +import java.util.Set; import android.content.Intent; @@ -29,6 +30,7 @@ import org.yaaic.command.handler.DCCHandler; import org.yaaic.command.handler.DeopHandler; import org.yaaic.command.handler.DevoiceHandler; import org.yaaic.command.handler.EchoHandler; +import org.yaaic.command.handler.HelpHandler; import org.yaaic.command.handler.JoinHandler; import org.yaaic.command.handler.KickHandler; import org.yaaic.command.handler.MeHandler; @@ -95,6 +97,7 @@ public class CommandParser commands.put("notice", new NoticeHandler()); commands.put("dcc", new DCCHandler()); commands.put("mode", new ModeHandler()); + commands.put("help", new HelpHandler()); // Aliases commands.put("j", commands.get("join")); @@ -115,6 +118,16 @@ public class CommandParser return instance; } + /** + * Get the commands HashMap + * + * @return HashMap - command, commandHandler + */ + public HashMap getCommands() { + + return commands; + } + /** * Is the given command a valid client command? * diff --git a/src/org/yaaic/command/handler/CloseHandler.java b/src/org/yaaic/command/handler/CloseHandler.java index 323fee7..fabaafd 100644 --- a/src/org/yaaic/command/handler/CloseHandler.java +++ b/src/org/yaaic/command/handler/CloseHandler.java @@ -38,6 +38,8 @@ import android.content.Intent; */ public class CloseHandler extends BaseHandler { + private String desc ="Closes the current window"; + /** * Execute /close */ @@ -73,4 +75,12 @@ public class CloseHandler extends BaseHandler { return "/close"; } + + /** + * Description of /close + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/DCCHandler.java b/src/org/yaaic/command/handler/DCCHandler.java index 2228769..a96c1cf 100644 --- a/src/org/yaaic/command/handler/DCCHandler.java +++ b/src/org/yaaic/command/handler/DCCHandler.java @@ -39,6 +39,8 @@ import org.yaaic.model.Server; */ public class DCCHandler extends BaseHandler { + private String desc = "Send a file to a user"; + /** * Execute /dcc */ @@ -76,4 +78,13 @@ public class DCCHandler extends BaseHandler { return "/dcc SEND "; } + + + /** + * Description of /dcc + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/DeopHandler.java b/src/org/yaaic/command/handler/DeopHandler.java index 64a8813..fa9124c 100644 --- a/src/org/yaaic/command/handler/DeopHandler.java +++ b/src/org/yaaic/command/handler/DeopHandler.java @@ -33,6 +33,7 @@ import org.yaaic.model.Server; */ public class DeopHandler extends BaseHandler { + private String desc = ""; /** * Execute /voice */ @@ -58,4 +59,13 @@ public class DeopHandler extends BaseHandler { return "/voice "; } + + + /** + * Description of /voice + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/DevoiceHandler.java b/src/org/yaaic/command/handler/DevoiceHandler.java index e82532b..9d07e87 100644 --- a/src/org/yaaic/command/handler/DevoiceHandler.java +++ b/src/org/yaaic/command/handler/DevoiceHandler.java @@ -33,6 +33,7 @@ import org.yaaic.model.Server; */ public class DevoiceHandler extends BaseHandler { + private String desc = ""; /** * Execute /devoice */ @@ -58,4 +59,13 @@ public class DevoiceHandler extends BaseHandler { return "/devoice "; } + + + /** + * Description of /devoice + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/EchoHandler.java b/src/org/yaaic/command/handler/EchoHandler.java index 007a1c1..aa37875 100644 --- a/src/org/yaaic/command/handler/EchoHandler.java +++ b/src/org/yaaic/command/handler/EchoHandler.java @@ -37,6 +37,7 @@ import android.content.Intent; */ public class EchoHandler extends BaseHandler { + private String desc = ""; /** * Execute /echo */ @@ -66,4 +67,13 @@ public class EchoHandler extends BaseHandler { return "/echo "; } + + + /** + * Description of /echo + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/HelpHandler.java b/src/org/yaaic/command/handler/HelpHandler.java new file mode 100644 index 0000000..d0379e5 --- /dev/null +++ b/src/org/yaaic/command/handler/HelpHandler.java @@ -0,0 +1,75 @@ +package org.yaaic.command.handler; + +import java.util.HashMap; +import java.util.Set; + +import org.yaaic.command.BaseHandler; +import org.yaaic.command.CommandParser; +import org.yaaic.exception.CommandException; +import org.yaaic.irc.IRCService; +import org.yaaic.model.Broadcast; +import org.yaaic.model.Conversation; +import org.yaaic.model.Message; +import org.yaaic.model.Server; + +import android.content.Intent; + +/** + * Command: /help + * + * @author Karol Gliniecki + */ +public class HelpHandler extends BaseHandler { + + private String desc = "lists all available commands"; + + /** + * Execute /help + */ + @Override + public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException { + if (conversation.getType() != Conversation.TYPE_CHANNEL) { + throw new CommandException("Only usable from within a channel"); + } + + CommandParser cp = CommandParser.getInstance(); + + StringBuffer commandList = new StringBuffer("available commands: \n"); + HashMap commands = cp.getCommands(); + + Object[] commandKeys = commands.keySet().toArray(); + + for (Object command: commandKeys) { + commandList.append("/"+command.toString() + " - "+commands.get(command).getDescription()+"\n"); + } + + Message message = new Message(commandList.toString()); + message.setColor(Message.COLOR_YELLOW); + conversation.addMessage(message); + + Intent intent = Broadcast.createConversationIntent( + Broadcast.CONVERSATION_MESSAGE, + server.getId(), + conversation.getName() + ); + service.sendBroadcast(intent); + } + + /** + * + *Usage of /help + */ + @Override + public String getUsage() { + return "/help"; + } + + /** + * Description of /help + */ + @Override + public String getDescription() { + return desc; + } + +} diff --git a/src/org/yaaic/command/handler/JoinHandler.java b/src/org/yaaic/command/handler/JoinHandler.java index 8a3959d..d24590c 100644 --- a/src/org/yaaic/command/handler/JoinHandler.java +++ b/src/org/yaaic/command/handler/JoinHandler.java @@ -33,6 +33,7 @@ import org.yaaic.model.Server; */ public class JoinHandler extends BaseHandler { + private String desc = "join a channel"; /** * Execute /join */ @@ -56,4 +57,12 @@ public class JoinHandler extends BaseHandler { return "/join []"; } + + /** + * Description of /join + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/KickHandler.java b/src/org/yaaic/command/handler/KickHandler.java index 8ce2715..3ce9749 100644 --- a/src/org/yaaic/command/handler/KickHandler.java +++ b/src/org/yaaic/command/handler/KickHandler.java @@ -35,6 +35,8 @@ import org.yaaic.model.Server; */ public class KickHandler extends BaseHandler { + private String desc = "kicks a user"; + /** * Execute /kick */ @@ -60,4 +62,12 @@ public class KickHandler extends BaseHandler { return "/kick "; } + + /** + * Description of /kick + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/MeHandler.java b/src/org/yaaic/command/handler/MeHandler.java index 2f1f5b4..fb54e39 100644 --- a/src/org/yaaic/command/handler/MeHandler.java +++ b/src/org/yaaic/command/handler/MeHandler.java @@ -38,6 +38,8 @@ import android.content.Intent; */ public class MeHandler extends BaseHandler { + private String desc = ""; + /** * Execute /me */ @@ -77,4 +79,9 @@ public class MeHandler extends BaseHandler { return "/me "; } + + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/ModeHandler.java b/src/org/yaaic/command/handler/ModeHandler.java index c125a83..d3c51ee 100644 --- a/src/org/yaaic/command/handler/ModeHandler.java +++ b/src/org/yaaic/command/handler/ModeHandler.java @@ -35,6 +35,8 @@ import org.yaaic.model.Server; */ public class ModeHandler extends BaseHandler { + private String desc = ""; + /** * Execute /mode */ @@ -58,4 +60,9 @@ public class ModeHandler extends BaseHandler { return "/mode "; } + + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/NamesHandler.java b/src/org/yaaic/command/handler/NamesHandler.java index 4d546ba..bc7af8d 100644 --- a/src/org/yaaic/command/handler/NamesHandler.java +++ b/src/org/yaaic/command/handler/NamesHandler.java @@ -39,6 +39,8 @@ import android.content.Intent; */ public class NamesHandler extends BaseHandler { + private String desc = "lists all users in channel"; + /** * Execute /names */ @@ -76,4 +78,13 @@ public class NamesHandler extends BaseHandler { return "/names"; } + + + /** + * Description of /names + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/NickHandler.java b/src/org/yaaic/command/handler/NickHandler.java index bcfa321..408f570 100644 --- a/src/org/yaaic/command/handler/NickHandler.java +++ b/src/org/yaaic/command/handler/NickHandler.java @@ -33,6 +33,8 @@ import org.yaaic.model.Server; */ public class NickHandler extends BaseHandler { + private String desc = "change own nickname"; + /** * Execute /nick */ @@ -54,4 +56,13 @@ public class NickHandler extends BaseHandler { return "/nick "; } + + + /** + * Description of /nick + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/NoticeHandler.java b/src/org/yaaic/command/handler/NoticeHandler.java index 82a91fb..aae3c8f 100644 --- a/src/org/yaaic/command/handler/NoticeHandler.java +++ b/src/org/yaaic/command/handler/NoticeHandler.java @@ -40,6 +40,8 @@ import android.content.Intent; */ public class NoticeHandler extends BaseHandler { + private String desc = "Send a notice to an other user"; + /** * Execute /notice */ @@ -74,4 +76,13 @@ public class NoticeHandler extends BaseHandler { return "/notice "; } + + + /** + * Description of /notice + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/OpHandler.java b/src/org/yaaic/command/handler/OpHandler.java index 7b78f7d..b6984ec 100644 --- a/src/org/yaaic/command/handler/OpHandler.java +++ b/src/org/yaaic/command/handler/OpHandler.java @@ -33,6 +33,8 @@ import org.yaaic.model.Server; */ public class OpHandler extends BaseHandler { + private String desc = ""; + /** * Execute /deop */ @@ -58,4 +60,13 @@ public class OpHandler extends BaseHandler { return "/op "; } + + + /** + * Description of /deop + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/PartHandler.java b/src/org/yaaic/command/handler/PartHandler.java index 99eec8e..72e3b62 100644 --- a/src/org/yaaic/command/handler/PartHandler.java +++ b/src/org/yaaic/command/handler/PartHandler.java @@ -35,6 +35,8 @@ import org.yaaic.model.Server; */ public class PartHandler extends BaseHandler { + private String desc = "leave the current channel"; + /** * Execute /part */ @@ -62,4 +64,9 @@ public class PartHandler extends BaseHandler { return "/part []"; } + + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/QueryHandler.java b/src/org/yaaic/command/handler/QueryHandler.java index 96540ff..1d654df 100644 --- a/src/org/yaaic/command/handler/QueryHandler.java +++ b/src/org/yaaic/command/handler/QueryHandler.java @@ -39,6 +39,8 @@ import android.content.Intent; */ public class QueryHandler extends BaseHandler { + private String desc = "opens a private chat with a user"; + /** * Execute /query */ @@ -78,4 +80,9 @@ public class QueryHandler extends BaseHandler { return "/query "; } + + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/QuitHandler.java b/src/org/yaaic/command/handler/QuitHandler.java index 2c8b2bc..3a1477c 100644 --- a/src/org/yaaic/command/handler/QuitHandler.java +++ b/src/org/yaaic/command/handler/QuitHandler.java @@ -33,6 +33,8 @@ import org.yaaic.model.Server; */ public class QuitHandler extends BaseHandler { + private String desc = "leave current channel"; + /** * Execute /quit */ @@ -54,4 +56,13 @@ public class QuitHandler extends BaseHandler { return "/quit []"; } + + + /** + * Description of /quit + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/TopicHandler.java b/src/org/yaaic/command/handler/TopicHandler.java index f49d58c..6ec677d 100644 --- a/src/org/yaaic/command/handler/TopicHandler.java +++ b/src/org/yaaic/command/handler/TopicHandler.java @@ -36,6 +36,8 @@ import org.yaaic.model.Server; */ public class TopicHandler extends BaseHandler { + private String desc = "show or change the current topic"; + /** * Execute /topic */ @@ -65,4 +67,13 @@ public class TopicHandler extends BaseHandler { return "/topic []"; } + + + /** + * Description of /topic + */ + @Override + public String getDescription() { + return desc; + } } diff --git a/src/org/yaaic/command/handler/VoiceHandler.java b/src/org/yaaic/command/handler/VoiceHandler.java index b7f643e..2ab9638 100644 --- a/src/org/yaaic/command/handler/VoiceHandler.java +++ b/src/org/yaaic/command/handler/VoiceHandler.java @@ -33,6 +33,8 @@ import org.yaaic.model.Server; */ public class VoiceHandler extends BaseHandler { + private String desc = ""; + /** * Execute /voice */ @@ -58,4 +60,13 @@ public class VoiceHandler extends BaseHandler { return "/voice "; } + + + /** + * Description of /voice + */ + @Override + public String getDescription() { + return desc; + } }