├── README.md
├── build.xml
├── ivy.xml
└── src
└── org
└── jibble
└── pircbot
├── Colors.java
├── ConfigurablePircBot.java
├── ConnectionSettings.java
├── DccChat.java
├── DccFileTransfer.java
├── DccManager.java
├── IdentServer.java
├── InputThread.java
├── IrcException.java
├── NickAlreadyInUseException.java
├── OutputThread.java
├── PircBot.java
├── Queue.java
├── ReplyConstants.java
├── UnverifiedSSL.java
└── User.java
/README.md:
--------------------------------------------------------------------------------
1 | # PircBot'
2 |
3 | PircBot' (pronounced "PircBot prime") is a framework for writing IRC bots in
4 | Java. This is a fork of jibble.org's [PircBot](http://www.jibble.org/pircbot.php)
5 | (version 1.5.0) that adds the following features:
6 |
7 | * SSL support
8 | * The `ConfigurablePircBot` class, allowing IRC bots to be configured easily
9 | * A build system using Apache Ant and Apache Ivy
10 | * Other minor improvements
11 |
12 | # Usage
13 |
14 | PircBot' can be installed by typing:
15 |
16 | $ ant
17 |
18 | This makes the PircBot' library available to projects that depend on it
19 | through Ivy. The library can also be used via the resulting
20 | `build/artifacts/pircbot.jar` file.
21 |
22 | For general documentation on using PircBot' once it's installed, see the
23 | [jibble.org PircBot website](http://www.jibble.org/pircbot.php). See
24 | [ReminderBot'](https://github.com/davidlazar/ReminderBot) for an example of
25 | how to use the new features provided by PircBot'.
26 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
21 | * This class contains constants that are useful for formatting lines 22 | * sent to IRC servers. These constants allow you to apply various 23 | * formatting to the lines, such as colours, boldness, underlining 24 | * and reverse text. 25 | *
26 | * The class contains static methods to remove colours and formatting 27 | * from lines of IRC text. 28 | *
29 | * Here are some examples of how to use the contants from within a 30 | * class that extends PircBot and imports org.jibble.pircbot.*; 31 | * 32 | *
sendMessage("#cs", Colors.BOLD + "A bold hello!"); 33 | * A bold hello! 34 | * sendMessage("#cs", Colors.RED + "Red" + Colors.NORMAL + " text"); 35 | * Red text 36 | * sendMessage("#cs", Colors.BOLD + Colors.RED + "Bold and red"); 37 | * Bold and red38 | * 39 | * Please note that some IRC channels may be configured to reject any 40 | * messages that use colours. Also note that older IRC clients may be 41 | * unable to correctly display lines that contain colours and other 42 | * control characters. 43 | *
44 | * Note that this class name has been spelt in the American style in 45 | * order to remain consistent with the rest of the Java API. 46 | * 47 | * 48 | * @since 0.9.12 49 | * @author Paul James Mutton, 50 | * http://www.jibble.org/ 51 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 52 | */ 53 | public class Colors { 54 | 55 | 56 | /** 57 | * Removes all previously applied color and formatting attributes. 58 | */ 59 | public static final String NORMAL = "\u000f"; 60 | 61 | 62 | /** 63 | * Bold text. 64 | */ 65 | public static final String BOLD = "\u0002"; 66 | 67 | 68 | /** 69 | * Underlined text. 70 | */ 71 | public static final String UNDERLINE = "\u001f"; 72 | 73 | 74 | /** 75 | * Reversed text (may be rendered as italic text in some clients). 76 | */ 77 | public static final String REVERSE = "\u0016"; 78 | 79 | 80 | /** 81 | * White coloured text. 82 | */ 83 | public static final String WHITE = "\u000300"; 84 | 85 | 86 | /** 87 | * Black coloured text. 88 | */ 89 | public static final String BLACK = "\u000301"; 90 | 91 | 92 | /** 93 | * Dark blue coloured text. 94 | */ 95 | public static final String DARK_BLUE = "\u000302"; 96 | 97 | 98 | /** 99 | * Dark green coloured text. 100 | */ 101 | public static final String DARK_GREEN = "\u000303"; 102 | 103 | 104 | /** 105 | * Red coloured text. 106 | */ 107 | public static final String RED = "\u000304"; 108 | 109 | 110 | /** 111 | * Brown coloured text. 112 | */ 113 | public static final String BROWN = "\u000305"; 114 | 115 | 116 | /** 117 | * Purple coloured text. 118 | */ 119 | public static final String PURPLE = "\u000306"; 120 | 121 | 122 | /** 123 | * Olive coloured text. 124 | */ 125 | public static final String OLIVE = "\u000307"; 126 | 127 | 128 | /** 129 | * Yellow coloured text. 130 | */ 131 | public static final String YELLOW = "\u000308"; 132 | 133 | 134 | /** 135 | * Green coloured text. 136 | */ 137 | public static final String GREEN = "\u000309"; 138 | 139 | 140 | /** 141 | * Teal coloured text. 142 | */ 143 | public static final String TEAL = "\u000310"; 144 | 145 | 146 | /** 147 | * Cyan coloured text. 148 | */ 149 | public static final String CYAN = "\u000311"; 150 | 151 | 152 | /** 153 | * Blue coloured text. 154 | */ 155 | public static final String BLUE = "\u000312"; 156 | 157 | 158 | /** 159 | * Magenta coloured text. 160 | */ 161 | public static final String MAGENTA = "\u000313"; 162 | 163 | 164 | /** 165 | * Dark gray coloured text. 166 | */ 167 | public static final String DARK_GRAY = "\u000314"; 168 | 169 | 170 | /** 171 | * Light gray coloured text. 172 | */ 173 | public static final String LIGHT_GRAY = "\u000315"; 174 | 175 | 176 | /** 177 | * This class should not be constructed. 178 | */ 179 | private Colors() { 180 | 181 | } 182 | 183 | 184 | /** 185 | * Removes all colours from a line of IRC text. 186 | * 187 | * @since PircBot 1.2.0 188 | * 189 | * @param line the input text. 190 | * 191 | * @return the same text, but with all colours removed. 192 | */ 193 | public static String removeColors(String line) { 194 | int length = line.length(); 195 | StringBuffer buffer = new StringBuffer(); 196 | int i = 0; 197 | while (i < length) { 198 | char ch = line.charAt(i); 199 | if (ch == '\u0003') { 200 | i++; 201 | // Skip "x" or "xy" (foreground color). 202 | if (i < length) { 203 | ch = line.charAt(i); 204 | if (Character.isDigit(ch)) { 205 | i++; 206 | if (i < length) { 207 | ch = line.charAt(i); 208 | if (Character.isDigit(ch)) { 209 | i++; 210 | } 211 | } 212 | // Now skip ",x" or ",xy" (background color). 213 | if (i < length) { 214 | ch = line.charAt(i); 215 | if (ch == ',') { 216 | i++; 217 | if (i < length) { 218 | ch = line.charAt(i); 219 | if (Character.isDigit(ch)) { 220 | i++; 221 | if (i < length) { 222 | ch = line.charAt(i); 223 | if (Character.isDigit(ch)) { 224 | i++; 225 | } 226 | } 227 | } 228 | else { 229 | // Keep the comma. 230 | i--; 231 | } 232 | } 233 | else { 234 | // Keep the comma. 235 | i--; 236 | } 237 | } 238 | } 239 | } 240 | } 241 | } 242 | else if (ch == '\u000f') { 243 | i++; 244 | } 245 | else { 246 | buffer.append(ch); 247 | i++; 248 | } 249 | } 250 | return buffer.toString(); 251 | } 252 | 253 | 254 | /** 255 | * Remove formatting from a line of IRC text. 256 | * 257 | * @since PircBot 1.2.0 258 | * 259 | * @param line the input text. 260 | * 261 | * @return the same text, but without any bold, underlining, reverse, etc. 262 | */ 263 | public static String removeFormatting(String line) { 264 | int length = line.length(); 265 | StringBuffer buffer = new StringBuffer(); 266 | for (int i = 0; i < length; i++) { 267 | char ch = line.charAt(i); 268 | if (ch == '\u000f' || ch == '\u0002' || ch == '\u001f' || ch == '\u0016') { 269 | // Don't add this character. 270 | } 271 | else { 272 | buffer.append(ch); 273 | } 274 | } 275 | return buffer.toString(); 276 | } 277 | 278 | 279 | /** 280 | * Removes all formatting and colours from a line of IRC text. 281 | * 282 | * @since PircBot 1.2.0 283 | * 284 | * @param line the input text. 285 | * 286 | * @return the same text, but without formatting and colour characters. 287 | * 288 | */ 289 | public static String removeFormattingAndColors(String line) { 290 | return removeFormatting(removeColors(line)); 291 | } 292 | 293 | } 294 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/ConfigurablePircBot.java: -------------------------------------------------------------------------------- 1 | /* 2 | Author: David Lazar 3 | */ 4 | package org.jibble.pircbot; 5 | 6 | import java.io.*; 7 | import org.apache.commons.configuration.*; 8 | 9 | public abstract class ConfigurablePircBot extends PircBot { 10 | private Configuration configuration; 11 | 12 | public Configuration getConfiguration() { 13 | return configuration; 14 | } 15 | 16 | public void initBot(String fileName) throws Exception { 17 | initBot(new File(fileName)); 18 | } 19 | 20 | public void initBot(File file) throws Exception { 21 | PropertiesConfiguration c = new PropertiesConfiguration(); 22 | c.setDelimiterParsingDisabled(true); 23 | c.load(file); 24 | initBot(c); 25 | } 26 | 27 | public void initBot(Configuration c) throws Exception { 28 | this.configuration = c; 29 | 30 | if (c.containsKey("Verbose")) { 31 | setVerbose(c.getBoolean("Verbose")); 32 | } 33 | 34 | if (c.containsKey("Nick")) { 35 | setName(c.getString("Nick")); 36 | } 37 | 38 | if (c.containsKey("UserName")) { 39 | setUserName(c.getString("UserName")); 40 | } 41 | 42 | if (c.containsKey("RealName")) { 43 | setRealName(c.getString("RealName")); 44 | } 45 | 46 | if (c.containsKey("Version")) { 47 | setVersion(c.getString("Version")); 48 | } 49 | 50 | if (c.containsKey("Finger")) { 51 | setFinger(c.getString("Finger")); 52 | } 53 | 54 | if (c.containsKey("Server")) { 55 | ConnectionSettings cs = new ConnectionSettings(c.getString("Server")); 56 | 57 | if (c.containsKey("Port")) { 58 | cs.port = c.getInt("Port"); 59 | } 60 | 61 | if (c.containsKey("SSL")) { 62 | cs.useSSL = c.getBoolean("SSL"); 63 | } 64 | 65 | if (c.containsKey("VerifySSL")) { 66 | cs.verifySSL = c.getBoolean("VerifySSL"); 67 | } 68 | 69 | if (c.containsKey("Password")) { 70 | cs.password = c.getString("Password"); 71 | } 72 | 73 | connect(cs); 74 | 75 | if (c.containsKey("Channels")) { 76 | joinChannel(c.getString("Channels")); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/ConnectionSettings.java: -------------------------------------------------------------------------------- 1 | /* 2 | Author: David Lazar 3 | */ 4 | package org.jibble.pircbot; 5 | 6 | public class ConnectionSettings { 7 | public String server = null; 8 | public int port = 6667; 9 | public boolean useSSL = false; 10 | public boolean verifySSL = false; 11 | public String password = null; 12 | 13 | public ConnectionSettings(String server) { 14 | this.server = server; 15 | } 16 | 17 | public ConnectionSettings clone() { 18 | ConnectionSettings cs = new ConnectionSettings(server); 19 | cs.port = port; 20 | cs.useSSL = useSSL; 21 | cs.verifySSL = verifySSL; 22 | cs.password = password; 23 | return cs; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/DccChat.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | 20 | /** 21 | * This class is used to allow the bot to interact with a DCC Chat session. 22 | * 23 | * @since 0.9c 24 | * @author Paul James Mutton, 25 | * http://www.jibble.org/ 26 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 27 | */ 28 | public class DccChat { 29 | 30 | 31 | /** 32 | * This constructor is used when we are accepting a DCC CHAT request 33 | * from somebody. It attempts to connect to the client that issued the 34 | * request. 35 | * 36 | * @param bot An instance of the underlying PircBot. 37 | * @param sourceNick The nick of the sender. 38 | * @param address The address to connect to. 39 | * @param port The port number to connect to. 40 | * 41 | * @throws IOException If the connection cannot be made. 42 | */ 43 | DccChat(PircBot bot, String nick, String login, String hostname, long address, int port) { 44 | _bot = bot; 45 | _address = address; 46 | _port = port; 47 | _nick = nick; 48 | _login = login; 49 | _hostname = hostname; 50 | _acceptable = true; 51 | } 52 | 53 | 54 | /** 55 | * This constructor is used after we have issued a DCC CHAT request to 56 | * somebody. If the client accepts the chat request, then the socket we 57 | * obtain is passed to this constructor. 58 | * 59 | * @param bot An instance of the underlying PircBot. 60 | * @param sourceNick The nick of the user we are sending the request to. 61 | * @param socket The socket which will be used for the DCC CHAT session. 62 | * 63 | * @throws IOException If the socket cannot be read from. 64 | */ 65 | DccChat(PircBot bot, String nick, Socket socket) throws IOException { 66 | _bot = bot; 67 | _nick = nick; 68 | _socket = socket; 69 | _reader = new BufferedReader(new InputStreamReader(_socket.getInputStream())); 70 | _writer = new BufferedWriter(new OutputStreamWriter(_socket.getOutputStream())); 71 | _acceptable = false; 72 | } 73 | 74 | 75 | /** 76 | * Accept this DccChat connection. 77 | * 78 | * @since 1.2.0 79 | * 80 | */ 81 | public synchronized void accept() throws IOException { 82 | if (_acceptable) { 83 | _acceptable = false; 84 | int[] ip = _bot.longToIp(_address); 85 | String ipStr = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3]; 86 | _socket = new Socket(ipStr, _port); 87 | _reader = new BufferedReader(new InputStreamReader(_socket.getInputStream())); 88 | _writer = new BufferedWriter(new OutputStreamWriter(_socket.getOutputStream())); 89 | } 90 | } 91 | 92 | 93 | /** 94 | * Reads the next line of text from the client at the other end of our DCC Chat 95 | * connection. This method blocks until something can be returned. 96 | * If the connection has closed, null is returned. 97 | * 98 | * @return The next line of text from the client. Returns null if the 99 | * connection has closed normally. 100 | * 101 | * @throws IOException If an I/O error occurs. 102 | */ 103 | public String readLine() throws IOException { 104 | if (_acceptable) { 105 | throw new IOException("You must call the accept() method of the DccChat request before you can use it."); 106 | } 107 | return _reader.readLine(); 108 | } 109 | 110 | 111 | /** 112 | * Sends a line of text to the client at the other end of our DCC Chat 113 | * connection. 114 | * 115 | * @param line The line of text to be sent. This should not include 116 | * linefeed characters. 117 | * 118 | * @throws IOException If an I/O error occurs. 119 | */ 120 | public void sendLine(String line) throws IOException { 121 | if (_acceptable) { 122 | throw new IOException("You must call the accept() method of the DccChat request before you can use it."); 123 | } 124 | // No need for synchronization here really... 125 | _writer.write(line + "\r\n"); 126 | _writer.flush(); 127 | } 128 | 129 | 130 | /** 131 | * Closes the DCC Chat connection. 132 | * 133 | * @throws IOException If an I/O error occurs. 134 | */ 135 | public void close() throws IOException { 136 | if (_acceptable) { 137 | throw new IOException("You must call the accept() method of the DccChat request before you can use it."); 138 | } 139 | _socket.close(); 140 | } 141 | 142 | 143 | /** 144 | * Returns the nick of the other user taking part in this file transfer. 145 | * 146 | * @return the nick of the other user. 147 | * 148 | */ 149 | public String getNick() { 150 | return _nick; 151 | } 152 | 153 | 154 | /** 155 | * Returns the login of the DCC Chat initiator. 156 | * 157 | * @return the login of the DCC Chat initiator. null if we sent it. 158 | * 159 | */ 160 | public String getLogin() { 161 | return _login; 162 | } 163 | 164 | 165 | /** 166 | * Returns the hostname of the DCC Chat initiator. 167 | * 168 | * @return the hostname of the DCC Chat initiator. null if we sent it. 169 | * 170 | */ 171 | public String getHostname() { 172 | return _hostname; 173 | } 174 | 175 | 176 | /** 177 | * Returns the BufferedReader used by this DCC Chat. 178 | * 179 | * @return the BufferedReader used by this DCC Chat. 180 | */ 181 | public BufferedReader getBufferedReader() { 182 | return _reader; 183 | } 184 | 185 | 186 | /** 187 | * Returns the BufferedReader used by this DCC Chat. 188 | * 189 | * @return the BufferedReader used by this DCC Chat. 190 | */ 191 | public BufferedWriter getBufferedWriter() { 192 | return _writer; 193 | } 194 | 195 | 196 | /** 197 | * Returns the raw Socket used by this DCC Chat. 198 | * 199 | * @return the raw Socket used by this DCC Chat. 200 | */ 201 | public Socket getSocket() { 202 | return _socket; 203 | } 204 | 205 | 206 | /** 207 | * Returns the address of the sender as a long. 208 | * 209 | * @return the address of the sender as a long. 210 | */ 211 | public long getNumericalAddress() { 212 | return _address; 213 | } 214 | 215 | 216 | private PircBot _bot; 217 | private String _nick; 218 | private String _login = null; 219 | private String _hostname = null; 220 | private BufferedReader _reader; 221 | private BufferedWriter _writer; 222 | private Socket _socket; 223 | private boolean _acceptable; 224 | private long _address = 0; 225 | private int _port = 0; 226 | 227 | } 228 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/DccFileTransfer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | 20 | /** 21 | * This class is used to administer a DCC file transfer. 22 | * 23 | * @since 1.2.0 24 | * @author Paul James Mutton, 25 | * http://www.jibble.org/ 26 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 27 | */ 28 | public class DccFileTransfer { 29 | 30 | /** 31 | * The default buffer size to use when sending and receiving files. 32 | */ 33 | public static final int BUFFER_SIZE = 1024; 34 | 35 | 36 | /** 37 | * Constructor used for receiving files. 38 | */ 39 | DccFileTransfer(PircBot bot, DccManager manager, String nick, String login, String hostname, String type, String filename, long address, int port, long size) { 40 | _bot = bot; 41 | _manager = manager; 42 | _nick = nick; 43 | _login = login; 44 | _hostname = hostname; 45 | _type = type; 46 | _file = new File(filename); 47 | _address = address; 48 | _port = port; 49 | _size = size; 50 | _received = false; 51 | 52 | _incoming = true; 53 | } 54 | 55 | 56 | /** 57 | * Constructor used for sending files. 58 | */ 59 | DccFileTransfer(PircBot bot, DccManager manager, File file, String nick, int timeout) { 60 | _bot = bot; 61 | _manager = manager; 62 | _nick = nick; 63 | _file = file; 64 | _size = file.length(); 65 | _timeout = timeout; 66 | _received = true; 67 | 68 | _incoming = false; 69 | } 70 | 71 | 72 | /** 73 | * Receives a DccFileTransfer and writes it to the specified file. 74 | * Resuming allows a partial download to be continue from the end of 75 | * the current file contents. 76 | * 77 | * @param file The file to write to. 78 | * @param resume True if you wish to try and resume the download instead 79 | * of overwriting an existing file. 80 | * 81 | */ 82 | public synchronized void receive(File file, boolean resume) { 83 | if (!_received) { 84 | _received = true; 85 | _file = file; 86 | 87 | if (_type.equals("SEND") && resume) { 88 | _progress = file.length(); 89 | if (_progress == 0) { 90 | doReceive(file, false); 91 | } 92 | else { 93 | _bot.sendCTCPCommand(_nick, "DCC RESUME file.ext " + _port + " " + _progress); 94 | _manager.addAwaitingResume(this); 95 | } 96 | } 97 | else { 98 | _progress = file.length(); 99 | doReceive(file, resume); 100 | } 101 | } 102 | } 103 | 104 | 105 | /** 106 | * Receive the file in a new thread. 107 | */ 108 | void doReceive(final File file, final boolean resume) { 109 | new Thread() { 110 | public void run() { 111 | 112 | BufferedOutputStream foutput = null; 113 | Exception exception = null; 114 | 115 | try { 116 | 117 | // Convert the integer address to a proper IP address. 118 | int[] ip = _bot.longToIp(_address); 119 | String ipStr = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3]; 120 | 121 | // Connect the socket and set a timeout. 122 | _socket = new Socket(ipStr, _port); 123 | _socket.setSoTimeout(30*1000); 124 | _startTime = System.currentTimeMillis(); 125 | 126 | // No longer possible to resume this transfer once it's underway. 127 | _manager.removeAwaitingResume(DccFileTransfer.this); 128 | 129 | BufferedInputStream input = new BufferedInputStream(_socket.getInputStream()); 130 | BufferedOutputStream output = new BufferedOutputStream(_socket.getOutputStream()); 131 | 132 | // Following line fixed for jdk 1.1 compatibility. 133 | foutput = new BufferedOutputStream(new FileOutputStream(file.getCanonicalPath(), resume)); 134 | 135 | byte[] inBuffer = new byte[BUFFER_SIZE]; 136 | byte[] outBuffer = new byte[4]; 137 | int bytesRead = 0; 138 | while ((bytesRead = input.read(inBuffer, 0, inBuffer.length)) != -1) { 139 | foutput.write(inBuffer, 0, bytesRead); 140 | _progress += bytesRead; 141 | // Send back an acknowledgement of how many bytes we have got so far. 142 | outBuffer[0] = (byte) ((_progress >> 24) & 0xff); 143 | outBuffer[1] = (byte) ((_progress >> 16) & 0xff); 144 | outBuffer[2] = (byte) ((_progress >> 8) & 0xff); 145 | outBuffer[3] = (byte) ((_progress >> 0) & 0xff); 146 | output.write(outBuffer); 147 | output.flush(); 148 | delay(); 149 | } 150 | foutput.flush(); 151 | } 152 | catch (Exception e) { 153 | exception = e; 154 | } 155 | finally { 156 | try { 157 | foutput.close(); 158 | _socket.close(); 159 | } 160 | catch (Exception anye) { 161 | // Do nothing. 162 | } 163 | } 164 | 165 | _bot.onFileTransferFinished(DccFileTransfer.this, exception); 166 | } 167 | }.start(); 168 | } 169 | 170 | 171 | /** 172 | * Method to send the file inside a new thread. 173 | */ 174 | void doSend(final boolean allowResume) { 175 | new Thread() { 176 | public void run() { 177 | 178 | BufferedInputStream finput = null; 179 | Exception exception = null; 180 | 181 | try { 182 | 183 | ServerSocket ss = null; 184 | 185 | int[] ports = _bot.getDccPorts(); 186 | if (ports == null) { 187 | // Use any free port. 188 | ss = new ServerSocket(0); 189 | } 190 | else { 191 | for (int i = 0; i < ports.length; i++) { 192 | try { 193 | ss = new ServerSocket(ports[i]); 194 | // Found a port number we could use. 195 | break; 196 | } 197 | catch (Exception e) { 198 | // Do nothing; go round and try another port. 199 | } 200 | } 201 | if (ss == null) { 202 | // No ports could be used. 203 | throw new IOException("All ports returned by getDccPorts() are in use."); 204 | } 205 | } 206 | 207 | ss.setSoTimeout(_timeout); 208 | _port = ss.getLocalPort(); 209 | InetAddress inetAddress = _bot.getDccInetAddress(); 210 | if (inetAddress == null) { 211 | inetAddress = _bot.getInetAddress(); 212 | } 213 | byte[] ip = inetAddress.getAddress(); 214 | long ipNum = _bot.ipToLong(ip); 215 | 216 | // Rename the filename so it has no whitespace in it when we send it. 217 | // .... I really should do this a bit more nicely at some point .... 218 | String safeFilename = _file.getName().replace(' ', '_'); 219 | safeFilename = safeFilename.replace('\t', '_'); 220 | 221 | if (allowResume) { 222 | _manager.addAwaitingResume(DccFileTransfer.this); 223 | } 224 | 225 | // Send the message to the user, telling them where to connect to in order to get the file. 226 | _bot.sendCTCPCommand(_nick, "DCC SEND " + safeFilename + " " + ipNum + " " + _port + " " + _file.length()); 227 | 228 | // The client may now connect to us and download the file. 229 | _socket = ss.accept(); 230 | _socket.setSoTimeout(30000); 231 | _startTime = System.currentTimeMillis(); 232 | 233 | // No longer possible to resume this transfer once it's underway. 234 | if (allowResume) { 235 | _manager.removeAwaitingResume(DccFileTransfer.this); 236 | } 237 | 238 | // Might as well close the server socket now; it's finished with. 239 | ss.close(); 240 | 241 | BufferedOutputStream output = new BufferedOutputStream(_socket.getOutputStream()); 242 | BufferedInputStream input = new BufferedInputStream(_socket.getInputStream()); 243 | finput = new BufferedInputStream(new FileInputStream(_file)); 244 | 245 | // Check for resuming. 246 | if (_progress > 0) { 247 | long bytesSkipped = 0; 248 | while (bytesSkipped < _progress) { 249 | bytesSkipped += finput.skip(_progress - bytesSkipped); 250 | } 251 | } 252 | 253 | byte[] outBuffer = new byte[BUFFER_SIZE]; 254 | byte[] inBuffer = new byte[4]; 255 | int bytesRead = 0; 256 | while ((bytesRead = finput.read(outBuffer, 0, outBuffer.length)) != -1) { 257 | output.write(outBuffer, 0, bytesRead); 258 | output.flush(); 259 | input.read(inBuffer, 0, inBuffer.length); 260 | _progress += bytesRead; 261 | delay(); 262 | } 263 | } 264 | catch (Exception e) { 265 | exception = e; 266 | } 267 | finally { 268 | try { 269 | finput.close(); 270 | _socket.close(); 271 | } 272 | catch (Exception e) { 273 | // Do nothing. 274 | } 275 | } 276 | 277 | _bot.onFileTransferFinished(DccFileTransfer.this, exception); 278 | } 279 | }.start(); 280 | } 281 | 282 | 283 | /** 284 | * Package mutator for setting the progress of the file transfer. 285 | */ 286 | void setProgress(long progress) { 287 | _progress = progress; 288 | } 289 | 290 | 291 | /** 292 | * Delay between packets. 293 | */ 294 | private void delay() { 295 | if (_packetDelay > 0) { 296 | try { 297 | Thread.sleep(_packetDelay); 298 | } 299 | catch (InterruptedException e) { 300 | // Do nothing. 301 | } 302 | } 303 | } 304 | 305 | 306 | /** 307 | * Returns the nick of the other user taking part in this file transfer. 308 | * 309 | * @return the nick of the other user. 310 | * 311 | */ 312 | public String getNick() { 313 | return _nick; 314 | } 315 | 316 | 317 | /** 318 | * Returns the login of the file sender. 319 | * 320 | * @return the login of the file sender. null if we are sending. 321 | * 322 | */ 323 | public String getLogin() { 324 | return _login; 325 | } 326 | 327 | 328 | /** 329 | * Returns the hostname of the file sender. 330 | * 331 | * @return the hostname of the file sender. null if we are sending. 332 | * 333 | */ 334 | public String getHostname() { 335 | return _hostname; 336 | } 337 | 338 | 339 | /** 340 | * Returns the suggested file to be used for this transfer. 341 | * 342 | * @return the suggested file to be used. 343 | * 344 | */ 345 | public File getFile() { 346 | return _file; 347 | } 348 | 349 | 350 | /** 351 | * Returns the port number to be used when making the connection. 352 | * 353 | * @return the port number. 354 | * 355 | */ 356 | public int getPort() { 357 | return _port; 358 | } 359 | 360 | 361 | /** 362 | * Returns true if the file transfer is incoming (somebody is sending 363 | * the file to us). 364 | * 365 | * @return true if the file transfer is incoming. 366 | * 367 | */ 368 | public boolean isIncoming() { 369 | return _incoming; 370 | } 371 | 372 | 373 | /** 374 | * Returns true if the file transfer is outgoing (we are sending the 375 | * file to someone). 376 | * 377 | * @return true if the file transfer is outgoing. 378 | * 379 | */ 380 | public boolean isOutgoing() { 381 | return !isIncoming(); 382 | } 383 | 384 | 385 | /** 386 | * Sets the delay time between sending or receiving each packet. 387 | * Default is 0. 388 | * This is useful for throttling the speed of file transfers to maintain 389 | * a good quality of service for other things on the machine or network. 390 | * 391 | * @param millis The number of milliseconds to wait between packets. 392 | * 393 | */ 394 | public void setPacketDelay(long millis) { 395 | _packetDelay = millis; 396 | } 397 | 398 | 399 | /** 400 | * returns the delay time between each packet that is send or received. 401 | * 402 | * @return the delay between each packet. 403 | * 404 | */ 405 | public long getPacketDelay() { 406 | return _packetDelay; 407 | } 408 | 409 | 410 | /** 411 | * Returns the size (in bytes) of the file being transfered. 412 | * 413 | * @return the size of the file. Returns -1 if the sender did not 414 | * specify this value. 415 | */ 416 | public long getSize() { 417 | return _size; 418 | } 419 | 420 | 421 | /** 422 | * Returns the progress (in bytes) of the current file transfer. 423 | * When resuming, this represents the total number of bytes in the 424 | * file, which may be greater than the amount of bytes resumed in 425 | * just this transfer. 426 | * 427 | * @return the progress of the transfer. 428 | */ 429 | public long getProgress() { 430 | return _progress; 431 | } 432 | 433 | 434 | /** 435 | * Returns the progress of the file transfer as a percentage. 436 | * Note that this should never be negative, but could become 437 | * greater than 100% if you attempt to resume a larger file 438 | * onto a partially downloaded file that was smaller. 439 | * 440 | * @return the progress of the transfer as a percentage. 441 | */ 442 | public double getProgressPercentage() { 443 | return 100 * (getProgress() / (double) getSize()); 444 | } 445 | 446 | 447 | /** 448 | * Stops the DCC file transfer by closing the connection. 449 | */ 450 | public void close() { 451 | try { 452 | _socket.close(); 453 | } 454 | catch (Exception e) { 455 | // Let the DCC manager worry about anything that may go wrong. 456 | } 457 | } 458 | 459 | 460 | /** 461 | * Returns the rate of data transfer in bytes per second. 462 | * This value is an estimate based on the number of bytes 463 | * transfered since the connection was established. 464 | * 465 | * @return data transfer rate in bytes per second. 466 | */ 467 | public long getTransferRate() { 468 | long time = (System.currentTimeMillis() - _startTime) / 1000; 469 | if (time <= 0) { 470 | return 0; 471 | } 472 | return getProgress() / time; 473 | } 474 | 475 | /** 476 | * Returns the address of the sender as a long. 477 | * 478 | * @return the address of the sender as a long. 479 | */ 480 | public long getNumericalAddress() { 481 | return _address; 482 | } 483 | 484 | 485 | private PircBot _bot; 486 | private DccManager _manager; 487 | private String _nick; 488 | private String _login = null; 489 | private String _hostname = null; 490 | private String _type; 491 | private long _address; 492 | private int _port; 493 | private long _size; 494 | private boolean _received; 495 | 496 | private Socket _socket = null; 497 | private long _progress = 0; 498 | private File _file = null; 499 | private int _timeout = 0; 500 | private boolean _incoming; 501 | private long _packetDelay = 0; 502 | 503 | private long _startTime = 0; 504 | 505 | } 506 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/DccManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | import java.util.*; 18 | 19 | /** 20 | * This class is used to process DCC events from the server. 21 | * 22 | * @since 1.2.0 23 | * @author Paul James Mutton, 24 | * http://www.jibble.org/ 25 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 26 | */ 27 | public class DccManager { 28 | 29 | 30 | /** 31 | * Constructs a DccManager to look after all DCC SEND and CHAT events. 32 | * 33 | * @param bot The PircBot whose DCC events this class will handle. 34 | */ 35 | DccManager(PircBot bot) { 36 | _bot = bot; 37 | } 38 | 39 | 40 | /** 41 | * Processes a DCC request. 42 | * 43 | * @return True if the type of request was handled successfully. 44 | */ 45 | boolean processRequest(String nick, String login, String hostname, String request) { 46 | StringTokenizer tokenizer = new StringTokenizer(request); 47 | tokenizer.nextToken(); 48 | String type = tokenizer.nextToken(); 49 | String filename = tokenizer.nextToken(); 50 | 51 | if (type.equals("SEND")) { 52 | long address = Long.parseLong(tokenizer.nextToken()); 53 | int port = Integer.parseInt(tokenizer.nextToken()); 54 | long size = -1; 55 | try { 56 | size = Long.parseLong(tokenizer.nextToken()); 57 | } 58 | catch (Exception e) { 59 | // Stick with the old value. 60 | } 61 | 62 | DccFileTransfer transfer = new DccFileTransfer(_bot, this, nick, login, hostname, type, filename, address, port, size); 63 | _bot.onIncomingFileTransfer(transfer); 64 | 65 | } 66 | else if (type.equals("RESUME")) { 67 | int port = Integer.parseInt(tokenizer.nextToken()); 68 | long progress = Long.parseLong(tokenizer.nextToken()); 69 | 70 | DccFileTransfer transfer = null; 71 | synchronized (_awaitingResume) { 72 | for (int i = 0; i < _awaitingResume.size(); i++) { 73 | transfer = (DccFileTransfer) _awaitingResume.elementAt(i); 74 | if (transfer.getNick().equals(nick) && transfer.getPort() == port) { 75 | _awaitingResume.removeElementAt(i); 76 | break; 77 | } 78 | } 79 | } 80 | 81 | if (transfer != null) { 82 | transfer.setProgress(progress); 83 | _bot.sendCTCPCommand(nick, "DCC ACCEPT file.ext " + port + " " + progress); 84 | } 85 | 86 | } 87 | else if (type.equals("ACCEPT")) { 88 | int port = Integer.parseInt(tokenizer.nextToken()); 89 | long progress = Long.parseLong(tokenizer.nextToken()); 90 | 91 | DccFileTransfer transfer = null; 92 | synchronized (_awaitingResume) { 93 | for (int i = 0; i < _awaitingResume.size(); i++) { 94 | transfer = (DccFileTransfer) _awaitingResume.elementAt(i); 95 | if (transfer.getNick().equals(nick) && transfer.getPort() == port) { 96 | _awaitingResume.removeElementAt(i); 97 | break; 98 | } 99 | } 100 | } 101 | 102 | if (transfer != null) { 103 | transfer.doReceive(transfer.getFile(), true); 104 | } 105 | 106 | } 107 | else if (type.equals("CHAT")) { 108 | long address = Long.parseLong(tokenizer.nextToken()); 109 | int port = Integer.parseInt(tokenizer.nextToken()); 110 | 111 | final DccChat chat = new DccChat(_bot, nick, login, hostname, address, port); 112 | 113 | new Thread() { 114 | public void run() { 115 | _bot.onIncomingChatRequest(chat); 116 | } 117 | }.start(); 118 | } 119 | else { 120 | return false; 121 | } 122 | 123 | return true; 124 | } 125 | 126 | 127 | /** 128 | * Add this DccFileTransfer to the list of those awaiting possible 129 | * resuming. 130 | * 131 | * @param transfer the DccFileTransfer that may be resumed. 132 | */ 133 | void addAwaitingResume(DccFileTransfer transfer) { 134 | synchronized (_awaitingResume) { 135 | _awaitingResume.addElement(transfer); 136 | } 137 | } 138 | 139 | 140 | /** 141 | * Remove this transfer from the list of those awaiting resuming. 142 | */ 143 | void removeAwaitingResume(DccFileTransfer transfer) { 144 | _awaitingResume.removeElement(transfer); 145 | } 146 | 147 | 148 | private PircBot _bot; 149 | private Vector _awaitingResume = new Vector(); 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/IdentServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | 20 | /** 21 | * A simple IdentServer (also know as "The Identification Protocol"). 22 | * An ident server provides a means to determine the identity of a 23 | * user of a particular TCP connection. 24 | *
25 | * Most IRC servers attempt to contact the ident server on connecting 26 | * hosts in order to determine the user's identity. A few IRC servers 27 | * will not allow you to connect unless this information is provided. 28 | *
29 | * So when a PircBot is run on a machine that does not run an ident server, 30 | * it may be necessary to provide a "faked" response by starting up its 31 | * own ident server and sending out apparently correct responses. 32 | *
33 | * An instance of this class can be used to start up an ident server 34 | * only if it is possible to do so. Reasons for not being able to do 35 | * so are if there is already an ident server running on port 113, or 36 | * if you are running as an unprivileged user who is unable to create 37 | * a server socket on that port number. 38 | * 39 | * @since 0.9c 40 | * @author Paul James Mutton, 41 | * http://www.jibble.org/ 42 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 43 | */ 44 | public class IdentServer extends Thread { 45 | 46 | /** 47 | * Constructs and starts an instance of an IdentServer that will 48 | * respond to a client with the provided login. Rather than calling 49 | * this constructor explicitly from your code, it is recommended that 50 | * you use the startIdentServer method in the PircBot class. 51 | *
52 | * The ident server will wait for up to 60 seconds before shutting 53 | * down. Otherwise, it will shut down as soon as it has responded 54 | * to an ident request. 55 | * 56 | * @param bot The PircBot instance that will be used to log to. 57 | * @param login The login that the ident server will respond with. 58 | */ 59 | IdentServer(PircBot bot, String login) { 60 | _bot = bot; 61 | _login = login; 62 | 63 | try { 64 | _ss = new ServerSocket(113); 65 | _ss.setSoTimeout(60000); 66 | } 67 | catch (Exception e) { 68 | _bot.log("*** Could not start the ident server on port 113."); 69 | return; 70 | } 71 | 72 | _bot.log("*** Ident server running on port 113 for the next 60 seconds..."); 73 | this.setName(this.getClass() + "-Thread"); 74 | this.start(); 75 | } 76 | 77 | 78 | /** 79 | * Waits for a client to connect to the ident server before making an 80 | * appropriate response. Note that this method is started by the class 81 | * constructor. 82 | */ 83 | public void run() { 84 | try { 85 | Socket socket = _ss.accept(); 86 | socket.setSoTimeout(60000); 87 | 88 | BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 89 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 90 | 91 | String line = reader.readLine(); 92 | if (line != null) { 93 | _bot.log("*** Ident request received: " + line); 94 | line = line + " : USERID : UNIX : " + _login; 95 | writer.write(line + "\r\n"); 96 | writer.flush(); 97 | _bot.log("*** Ident reply sent: " + line); 98 | writer.close(); 99 | } 100 | } 101 | catch (Exception e) { 102 | // We're not really concerned with what went wrong, are we? 103 | } 104 | 105 | try { 106 | _ss.close(); 107 | } 108 | catch (Exception e) { 109 | // Doesn't really matter... 110 | } 111 | 112 | _bot.log("*** The Ident server has been shut down."); 113 | } 114 | 115 | private PircBot _bot; 116 | private String _login; 117 | private ServerSocket _ss = null; 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/InputThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | import java.io.*; 18 | import java.net.*; 19 | import java.util.*; 20 | 21 | /** 22 | * A Thread which reads lines from the IRC server. It then 23 | * passes these lines to the PircBot without changing them. 24 | * This running Thread also detects disconnection from the server 25 | * and is thus used by the OutputThread to send lines to the server. 26 | * 27 | * @author Paul James Mutton, 28 | * http://www.jibble.org/ 29 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 30 | */ 31 | public class InputThread extends Thread { 32 | 33 | /** 34 | * The InputThread reads lines from the IRC server and allows the 35 | * PircBot to handle them. 36 | * 37 | * @param bot An instance of the underlying PircBot. 38 | * @param breader The BufferedReader that reads lines from the server. 39 | * @param bwriter The BufferedWriter that sends lines to the server. 40 | */ 41 | InputThread(PircBot bot, Socket socket, BufferedReader breader, BufferedWriter bwriter) { 42 | _bot = bot; 43 | _socket = socket; 44 | _breader = breader; 45 | _bwriter = bwriter; 46 | this.setName(this.getClass() + "-Thread"); 47 | } 48 | 49 | 50 | /** 51 | * Sends a raw line to the IRC server as soon as possible, bypassing the 52 | * outgoing message queue. 53 | * 54 | * @param line The raw line to send to the IRC server. 55 | */ 56 | void sendRawLine(String line) { 57 | OutputThread.sendRawLine(_bot, _bwriter, line); 58 | } 59 | 60 | 61 | /** 62 | * Returns true if this InputThread is connected to an IRC server. 63 | * The result of this method should only act as a rough guide, 64 | * as the result may not be valid by the time you act upon it. 65 | * 66 | * @return True if still connected. 67 | */ 68 | boolean isConnected() { 69 | return _isConnected; 70 | } 71 | 72 | 73 | /** 74 | * Called to start this Thread reading lines from the IRC server. 75 | * When a line is read, this method calls the handleLine method 76 | * in the PircBot, which may subsequently call an 'onXxx' method 77 | * in the PircBot subclass. If any subclass of Throwable (i.e. 78 | * any Exception or Error) is thrown by your method, then this 79 | * method will print the stack trace to the standard output. It 80 | * is probable that the PircBot may still be functioning normally 81 | * after such a problem, but the existance of any uncaught exceptions 82 | * in your code is something you should really fix. 83 | */ 84 | public void run() { 85 | try { 86 | boolean running = true; 87 | while (running) { 88 | try { 89 | String line = null; 90 | while ((line = _breader.readLine()) != null) { 91 | try { 92 | _bot.handleLine(line); 93 | } 94 | catch (Throwable t) { 95 | // Stick the whole stack trace into a String so we can output it nicely. 96 | StringWriter sw = new StringWriter(); 97 | PrintWriter pw = new PrintWriter(sw); 98 | t.printStackTrace(pw); 99 | pw.flush(); 100 | StringTokenizer tokenizer = new StringTokenizer(sw.toString(), "\r\n"); 101 | synchronized (_bot) { 102 | _bot.log("### Your implementation of PircBot is faulty and you have"); 103 | _bot.log("### allowed an uncaught Exception or Error to propagate in your"); 104 | _bot.log("### code. It may be possible for PircBot to continue operating"); 105 | _bot.log("### normally. Here is the stack trace that was produced: -"); 106 | _bot.log("### "); 107 | while (tokenizer.hasMoreTokens()) { 108 | _bot.log("### " + tokenizer.nextToken()); 109 | } 110 | } 111 | } 112 | } 113 | if (line == null) { 114 | // The server must have disconnected us. 115 | running = false; 116 | } 117 | } 118 | catch (InterruptedIOException iioe) { 119 | // This will happen if we haven't received anything from the server for a while. 120 | // So we shall send it a ping to check that we are still connected. 121 | this.sendRawLine("PING " + (System.currentTimeMillis() / 1000)); 122 | // Now we go back to listening for stuff from the server... 123 | } 124 | } 125 | } 126 | catch (Exception e) { 127 | // Do nothing. 128 | } 129 | 130 | // If we reach this point, then we must have disconnected. 131 | try { 132 | _socket.close(); 133 | } 134 | catch (Exception e) { 135 | // Just assume the socket was already closed. 136 | } 137 | 138 | if (!_disposed) { 139 | _bot.log("*** Disconnected."); 140 | _isConnected = false; 141 | _bot.onDisconnect(); 142 | } 143 | 144 | } 145 | 146 | 147 | /** 148 | * Closes the socket without onDisconnect being called subsequently. 149 | */ 150 | public void dispose () { 151 | try { 152 | _disposed = true; 153 | _socket.close(); 154 | } 155 | catch (Exception e) { 156 | // Do nothing. 157 | } 158 | } 159 | 160 | private PircBot _bot = null; 161 | private Socket _socket = null; 162 | private BufferedReader _breader = null; 163 | private BufferedWriter _bwriter = null; 164 | private boolean _isConnected = true; 165 | private boolean _disposed = false; 166 | 167 | public static final int MAX_LINE_LENGTH = 512; 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/IrcException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | package org.jibble.pircbot; 15 | 16 | /** 17 | * An IrcException class. 18 | * 19 | * @since 0.9 20 | * @author Paul James Mutton, 21 | * http://www.jibble.org/ 22 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 23 | */ 24 | public class IrcException extends Exception { 25 | 26 | /** 27 | * Constructs a new IrcException. 28 | * 29 | * @param e The error message to report. 30 | */ 31 | public IrcException(String e) { 32 | super(e); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/NickAlreadyInUseException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | /** 18 | * A NickAlreadyInUseException class. This exception is 19 | * thrown when the PircBot attempts to join an IRC server 20 | * with a user name that is already in use. 21 | * 22 | * @since 0.9 23 | * @author Paul James Mutton, 24 | * http://www.jibble.org/ 25 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 26 | */ 27 | public class NickAlreadyInUseException extends IrcException { 28 | 29 | /** 30 | * Constructs a new IrcException. 31 | * 32 | * @param e The error message to report. 33 | */ 34 | public NickAlreadyInUseException(String e) { 35 | super(e); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/OutputThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | import java.io.*; 18 | import java.net.*; 19 | 20 | /** 21 | * A Thread which is responsible for sending messages to the IRC server. 22 | * Messages are obtained from the outgoing message queue and sent 23 | * immediately if possible. If there is a flood of messages, then to 24 | * avoid getting kicked from a channel, we put a small delay between 25 | * each one. 26 | * 27 | * @author Paul James Mutton, 28 | * http://www.jibble.org/ 29 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 30 | */ 31 | public class OutputThread extends Thread { 32 | 33 | 34 | /** 35 | * Constructs an OutputThread for the underlying PircBot. All messages 36 | * sent to the IRC server are sent by this OutputThread to avoid hammering 37 | * the server. Messages are sent immediately if possible. If there are 38 | * multiple messages queued, then there is a delay imposed. 39 | * 40 | * @param bot The underlying PircBot instance. 41 | * @param outQueue The Queue from which we will obtain our messages. 42 | */ 43 | OutputThread(PircBot bot, Queue outQueue) { 44 | _bot = bot; 45 | _outQueue = outQueue; 46 | this.setName(this.getClass() + "-Thread"); 47 | } 48 | 49 | 50 | /** 51 | * A static method to write a line to a BufferedOutputStream and then pass 52 | * the line to the log method of the supplied PircBot instance. 53 | * 54 | * @param bot The underlying PircBot instance. 55 | * @param out The BufferedOutputStream to write to. 56 | * @param line The line to be written. "\r\n" is appended to the end. 57 | * @param encoding The charset to use when encoing this string into a 58 | * byte array. 59 | */ 60 | static void sendRawLine(PircBot bot, BufferedWriter bwriter, String line) { 61 | if (line.length() > bot.getMaxLineLength() - 2) { 62 | line = line.substring(0, bot.getMaxLineLength() - 2); 63 | } 64 | synchronized(bwriter) { 65 | try { 66 | bwriter.write(line + "\r\n"); 67 | bwriter.flush(); 68 | bot.log(">>>" + line); 69 | } 70 | catch (Exception e) { 71 | // Silent response - just lose the line. 72 | } 73 | } 74 | } 75 | 76 | 77 | /** 78 | * This method starts the Thread consuming from the outgoing message 79 | * Queue and sending lines to the server. 80 | */ 81 | public void run() { 82 | try { 83 | boolean running = true; 84 | while (running) { 85 | // Small delay to prevent spamming of the channel 86 | Thread.sleep(_bot.getMessageDelay()); 87 | 88 | String line = (String) _outQueue.next(); 89 | if (line != null) { 90 | _bot.sendRawLine(line); 91 | } 92 | else { 93 | running = false; 94 | } 95 | } 96 | } 97 | catch (InterruptedException e) { 98 | // Just let the method return naturally... 99 | } 100 | } 101 | 102 | private PircBot _bot = null; 103 | private Queue _outQueue = null; 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/PircBot.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | Modifications from PircBot 1.5 by David Lazar. 13 | */ 14 | 15 | 16 | package org.jibble.pircbot; 17 | 18 | import java.io.*; 19 | import java.net.*; 20 | import java.util.*; 21 | import javax.net.*; 22 | import javax.net.ssl.*; 23 | 24 | /** 25 | * PircBot is a Java framework for writing IRC bots quickly and easily. 26 | *
27 | * It provides an event-driven architecture to handle common IRC 28 | * events, flood protection, DCC support, ident support, and more. 29 | * The comprehensive logfile format is suitable for use with pisg to generate 30 | * channel statistics. 31 | *
32 | * Methods of the PircBot class can be called to send events to the IRC server 33 | * that it connects to. For example, calling the sendMessage method will 34 | * send a message to a channel or user on the IRC server. Multiple servers 35 | * can be supported using multiple instances of PircBot. 36 | *
37 | * To perform an action when the PircBot receives a normal message from the IRC 38 | * server, you would override the onMessage method defined in the PircBot 39 | * class. All onXYZ methods in the PircBot class are automatically called 40 | * when the event XYZ happens, so you would override these if you wish 41 | * to do something when it does happen. 42 | *
43 | * Some event methods, such as onPing, should only really perform a specific 44 | * function (i.e. respond to a PING from the server). For your convenience, such 45 | * methods are already correctly implemented in the PircBot and should not 46 | * normally need to be overridden. Please read the full documentation for each 47 | * method to see which ones are already implemented by the PircBot class. 48 | *
49 | * Please visit the PircBot homepage at 50 | * http://www.jibble.org/pircbot.php 51 | * for full revision history, a beginners guide to creating your first PircBot 52 | * and a list of some existing Java IRC bots and clients that use the PircBot 53 | * framework. 54 | * 55 | * @author Paul James Mutton, 56 | * http://www.jibble.org/ 57 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 58 | */ 59 | public abstract class PircBot implements ReplyConstants { 60 | 61 | 62 | /** 63 | * The definitive version number of this release of PircBot. 64 | * (Note: Change this before automatically building releases) 65 | */ 66 | public static final String VERSION = "1.5.0"; 67 | 68 | 69 | private static final int OP_ADD = 1; 70 | private static final int OP_REMOVE = 2; 71 | private static final int VOICE_ADD = 3; 72 | private static final int VOICE_REMOVE = 4; 73 | 74 | 75 | /** 76 | * Constructs a PircBot with the default settings. Your own constructors 77 | * in classes which extend the PircBot abstract class should be responsible 78 | * for changing the default settings if required. 79 | */ 80 | public PircBot() {} 81 | 82 | 83 | /** 84 | * Attempt to connect to the specified IRC server. 85 | * The onConnect method is called upon success. 86 | * 87 | * @param hostname The hostname of the server to connect to. 88 | * 89 | * @throws IOException if it was not possible to connect to the server. 90 | * @throws IrcException if the server would not let us join it. 91 | * @throws NickAlreadyInUseException if our nick is already in use on the server. 92 | */ 93 | public final synchronized void connect(String hostname) throws IOException, IrcException, NickAlreadyInUseException { 94 | ConnectionSettings cs = new ConnectionSettings(hostname); 95 | this.connect(cs); 96 | } 97 | 98 | 99 | /** 100 | * Attempt to connect to the specified IRC server and port number. 101 | * The onConnect method is called upon success. 102 | * 103 | * @param hostname The hostname of the server to connect to. 104 | * @param port The port number to connect to on the server. 105 | * 106 | * @throws IOException if it was not possible to connect to the server. 107 | * @throws IrcException if the server would not let us join it. 108 | * @throws NickAlreadyInUseException if our nick is already in use on the server. 109 | */ 110 | public final synchronized void connect(String hostname, int port) throws IOException, IrcException, NickAlreadyInUseException { 111 | ConnectionSettings cs = new ConnectionSettings(hostname); 112 | cs.port = port; 113 | this.connect(cs); 114 | } 115 | 116 | 117 | /** 118 | * Attempt to connect to the specified IRC server using the supplied 119 | * password. 120 | * The onConnect method is called upon success. 121 | * 122 | * @param hostname The hostname of the server to connect to. 123 | * @param port The port number to connect to on the server. 124 | * @param password The password to use to join the server. 125 | * 126 | * @throws IOException if it was not possible to connect to the server. 127 | * @throws IrcException if the server would not let us join it. 128 | * @throws NickAlreadyInUseException if our nick is already in use on the server. 129 | */ 130 | public final synchronized void connect(String hostname, int port, String password) throws IOException, IrcException, NickAlreadyInUseException { 131 | ConnectionSettings cs = new ConnectionSettings(hostname); 132 | cs.port = port; 133 | cs.password = password; 134 | this.connect(cs); 135 | } 136 | 137 | 138 | /** 139 | * Attempt to connect to an IRC server using the supplied 140 | * connection settings. 141 | * The onConnect method is called upon success. 142 | * 143 | * @param cs The connection settings to use. 144 | * 145 | * @throws IOException if it was not possible to connect to the server. 146 | * @throws IrcException if the server would not let us join it. 147 | * @throws NickAlreadyInUseException if our nick is already in use on the server. 148 | */ 149 | public final synchronized void connect(ConnectionSettings cs) throws IOException, IrcException, NickAlreadyInUseException { 150 | 151 | ConnectionSettings _cs = cs.clone(); 152 | _connectionSettings = _cs; 153 | 154 | if (isConnected()) { 155 | throw new IOException("The PircBot is already connected to an IRC server. Disconnect first."); 156 | } 157 | 158 | // Don't clear the outqueue - there might be something important in it! 159 | 160 | // Clear everything we may have know about channels. 161 | this.removeAllChannels(); 162 | 163 | // Connect to the server. 164 | Socket socket; 165 | if (_cs.useSSL) { 166 | try { 167 | SocketFactory factory; 168 | if (_cs.verifySSL) { 169 | factory = SSLSocketFactory.getDefault(); 170 | } else { 171 | SSLContext sc = UnverifiedSSL.getUnverifiedSSLContext(); 172 | factory = sc.getSocketFactory(); 173 | } 174 | socket = factory.createSocket(_cs.server, _cs.port); 175 | } catch (Exception e) { 176 | throw new IOException("SSL failure"); 177 | } 178 | } else { 179 | socket = new Socket(_cs.server, _cs.port); 180 | } 181 | 182 | this.log("*** Connected to server."); 183 | 184 | _inetAddress = socket.getLocalAddress(); 185 | 186 | InputStreamReader inputStreamReader = null; 187 | OutputStreamWriter outputStreamWriter = null; 188 | if (getEncoding() != null) { 189 | // Assume the specified encoding is valid for this JVM. 190 | inputStreamReader = new InputStreamReader(socket.getInputStream(), getEncoding()); 191 | outputStreamWriter = new OutputStreamWriter(socket.getOutputStream(), getEncoding()); 192 | } 193 | else { 194 | // Otherwise, just use the JVM's default encoding. 195 | inputStreamReader = new InputStreamReader(socket.getInputStream()); 196 | outputStreamWriter = new OutputStreamWriter(socket.getOutputStream()); 197 | } 198 | 199 | BufferedReader breader = new BufferedReader(inputStreamReader); 200 | BufferedWriter bwriter = new BufferedWriter(outputStreamWriter); 201 | 202 | // Attempt to join the server. 203 | if (_cs.password != null && !_cs.password.equals("")) { 204 | OutputThread.sendRawLine(this, bwriter, "PASS " + _cs.password); 205 | } 206 | String nick = this.getName(); 207 | OutputThread.sendRawLine(this, bwriter, "NICK " + nick); 208 | // http://tools.ietf.org/html/rfc2812#section-3.1.3 209 | OutputThread.sendRawLine(this, bwriter, "USER " + this.getUserName() + " 8 * :" + this.getRealName()); 210 | 211 | _inputThread = new InputThread(this, socket, breader, bwriter); 212 | 213 | // Read stuff back from the server to see if we connected. 214 | String line = null; 215 | int tries = 1; 216 | while ((line = breader.readLine()) != null) { 217 | 218 | this.handleLine(line); 219 | 220 | int firstSpace = line.indexOf(" "); 221 | int secondSpace = line.indexOf(" ", firstSpace + 1); 222 | if (secondSpace >= 0) { 223 | String code = line.substring(firstSpace + 1, secondSpace); 224 | 225 | if (code.equals("004")) { 226 | // We're connected to the server. 227 | break; 228 | } 229 | else if (code.equals("433")) { 230 | if (_autoNickChange) { 231 | tries++; 232 | nick = getName() + tries; 233 | OutputThread.sendRawLine(this, bwriter, "NICK " + nick); 234 | } 235 | else { 236 | socket.close(); 237 | _inputThread = null; 238 | throw new NickAlreadyInUseException(line); 239 | } 240 | } 241 | else if (code.equals("439")) { 242 | // No action required. 243 | } 244 | else if (code.startsWith("5") || code.startsWith("4")) { 245 | socket.close(); 246 | _inputThread = null; 247 | throw new IrcException("Could not log into the IRC server: " + line); 248 | } 249 | } 250 | this.setNick(nick); 251 | 252 | } 253 | 254 | this.log("*** Logged onto server."); 255 | 256 | // This makes the socket timeout on read operations after 5 minutes. 257 | // Maybe in some future version I will let the user change this at runtime. 258 | socket.setSoTimeout(5 * 60 * 1000); 259 | 260 | // Now start the InputThread to read all other lines from the server. 261 | _inputThread.start(); 262 | 263 | // Now start the outputThread that will be used to send all messages. 264 | if (_outputThread == null) { 265 | _outputThread = new OutputThread(this, _outQueue); 266 | _outputThread.start(); 267 | } 268 | 269 | this.onConnect(); 270 | 271 | } 272 | 273 | 274 | /** 275 | * Reconnects to the IRC server that we were previously connected to. 276 | * If necessary, the appropriate port number and password will be used. 277 | * This method will throw an IrcException if we have never connected 278 | * to an IRC server previously. 279 | * 280 | * @since PircBot 0.9.9 281 | * 282 | * @throws IOException if it was not possible to connect to the server. 283 | * @throws IrcException if the server would not let us join it. 284 | * @throws NickAlreadyInUseException if our nick is already in use on the server. 285 | */ 286 | public final synchronized void reconnect() throws IOException, IrcException, NickAlreadyInUseException{ 287 | if (getServer() == null) { 288 | throw new IrcException("Cannot reconnect to an IRC server because we were never connected to one previously!"); 289 | } 290 | connect(_connectionSettings); 291 | } 292 | 293 | 294 | /** 295 | * This method disconnects from the server cleanly by calling the 296 | * quitServer() method. Providing the PircBot was connected to an 297 | * IRC server, the onDisconnect() will be called as soon as the 298 | * disconnection is made by the server. 299 | * 300 | * @see #quitServer() quitServer 301 | * @see #quitServer(String) quitServer 302 | */ 303 | public final synchronized void disconnect() { 304 | this.quitServer(); 305 | } 306 | 307 | 308 | /** 309 | * When you connect to a server and your nick is already in use and 310 | * this is set to true, a new nick will be automatically chosen. 311 | * This is done by adding numbers to the end of the nick until an 312 | * available nick is found. 313 | * 314 | * @param autoNickChange Set to true if you want automatic nick changes 315 | * during connection. 316 | */ 317 | public void setAutoNickChange(boolean autoNickChange) { 318 | _autoNickChange = autoNickChange; 319 | } 320 | 321 | 322 | /** 323 | * Starts an ident server (Identification Protocol Server, RFC 1413). 324 | *
325 | * Most IRC servers attempt to contact the ident server on connecting 326 | * hosts in order to determine the user's identity. A few IRC servers 327 | * will not allow you to connect unless this information is provided. 328 | *
329 | * So when a PircBot is run on a machine that does not run an ident server, 330 | * it may be necessary to call this method to start one up. 331 | *
332 | * Calling this method starts up an ident server which will respond with 333 | * the login provided by calling getLogin() and then shut down immediately. 334 | * It will also be shut down if it has not been contacted within 60 seconds 335 | * of creation. 336 | *
337 | * If you require an ident response, then the correct procedure is to start 338 | * the ident server and then connect to the IRC server. The IRC server may 339 | * then contact the ident server to get the information it needs. 340 | *
341 | * The ident server will fail to start if there is already an ident server 342 | * running on port 113, or if you are running as an unprivileged user who 343 | * is unable to create a server socket on that port number. 344 | *
345 | * If it is essential for you to use an ident server when connecting to an 346 | * IRC server, then make sure that port 113 on your machine is visible to 347 | * the IRC server so that it may contact the ident server. 348 | * 349 | * @since PircBot 0.9c 350 | */ 351 | public final void startIdentServer() { 352 | new IdentServer(this, getLogin()); 353 | } 354 | 355 | 356 | /** 357 | * Joins a channel. 358 | * 359 | * @param channel The name of the channel to join (eg "#cs"). 360 | */ 361 | public final void joinChannel(String channel) { 362 | this.sendRawLine("JOIN " + channel); 363 | } 364 | 365 | 366 | /** 367 | * Joins a channel with a key. 368 | * 369 | * @param channel The name of the channel to join (eg "#cs"). 370 | * @param key The key that will be used to join the channel. 371 | */ 372 | public final void joinChannel(String channel, String key) { 373 | this.joinChannel(channel + " " + key); 374 | } 375 | 376 | 377 | /** 378 | * Parts a channel. 379 | * 380 | * @param channel The name of the channel to leave. 381 | */ 382 | public final void partChannel(String channel) { 383 | this.sendRawLine("PART " + channel); 384 | } 385 | 386 | 387 | /** 388 | * Parts a channel, giving a reason. 389 | * 390 | * @param channel The name of the channel to leave. 391 | * @param reason The reason for parting the channel. 392 | */ 393 | public final void partChannel(String channel, String reason) { 394 | this.sendRawLine("PART " + channel + " :" + reason); 395 | } 396 | 397 | 398 | /** 399 | * Quits from the IRC server. 400 | * Providing we are actually connected to an IRC server, the 401 | * onDisconnect() method will be called as soon as the IRC server 402 | * disconnects us. 403 | */ 404 | public final void quitServer() { 405 | this.quitServer(""); 406 | } 407 | 408 | 409 | /** 410 | * Quits from the IRC server with a reason. 411 | * Providing we are actually connected to an IRC server, the 412 | * onDisconnect() method will be called as soon as the IRC server 413 | * disconnects us. 414 | * 415 | * @param reason The reason for quitting the server. 416 | */ 417 | public final void quitServer(String reason) { 418 | this.sendRawLine("QUIT :" + reason); 419 | } 420 | 421 | 422 | /** 423 | * Sends a raw line to the IRC server as soon as possible, bypassing the 424 | * outgoing message queue. 425 | * 426 | * @param line The raw line to send to the IRC server. 427 | */ 428 | public final synchronized void sendRawLine(String line) { 429 | if (isConnected()) { 430 | _inputThread.sendRawLine(line); 431 | } 432 | } 433 | 434 | /** 435 | * Sends a raw line through the outgoing message queue. 436 | * 437 | * @param line The raw line to send to the IRC server. 438 | */ 439 | public final synchronized void sendRawLineViaQueue(String line) { 440 | if (line == null) { 441 | throw new NullPointerException("Cannot send null messages to server"); 442 | } 443 | if (isConnected()) { 444 | _outQueue.add(line); 445 | } 446 | } 447 | 448 | 449 | /** 450 | * Sends a message to a channel or a private message to a user. These 451 | * messages are added to the outgoing message queue and sent at the 452 | * earliest possible opportunity. 453 | *
454 | * Some examples: - 455 | *
// Send the message "Hello!" to the channel #cs. 456 | * sendMessage("#cs", "Hello!"); 457 | * 458 | * // Send a private message to Paul that says "Hi". 459 | * sendMessage("Paul", "Hi");460 | * 461 | * You may optionally apply colours, boldness, underlining, etc to 462 | * the message by using the
Colors
class.
463 | *
464 | * @param target The name of the channel or user nick to send to.
465 | * @param message The message to send.
466 | *
467 | * @see Colors
468 | */
469 | public final void sendMessage(String target, String message) {
470 | _outQueue.add("PRIVMSG " + target + " :" + message);
471 | }
472 |
473 |
474 | /**
475 | * Sends an action to the channel or to a user.
476 | *
477 | * @param target The name of the channel or user nick to send to.
478 | * @param action The action to send.
479 | *
480 | * @see Colors
481 | */
482 | public final void sendAction(String target, String action) {
483 | sendCTCPCommand(target, "ACTION " + action);
484 | }
485 |
486 |
487 | /**
488 | * Sends a notice to the channel or to a user.
489 | *
490 | * @param target The name of the channel or user nick to send to.
491 | * @param notice The notice to send.
492 | */
493 | public final void sendNotice(String target, String notice) {
494 | _outQueue.add("NOTICE " + target + " :" + notice);
495 | }
496 |
497 |
498 | /**
499 | * Sends a CTCP command to a channel or user. (Client to client protocol).
500 | * Examples of such commands are "PING sendCTCPCommand("Dave", "VERSION");
.
503 | * The type of response to such commands is largely dependant on the target
504 | * client software.
505 | *
506 | * @since PircBot 0.9.5
507 | *
508 | * @param target The name of the channel or user to send the CTCP message to.
509 | * @param command The CTCP command to send.
510 | */
511 | public final void sendCTCPCommand(String target, String command) {
512 | _outQueue.add("PRIVMSG " + target + " :\u0001" + command + "\u0001");
513 | }
514 |
515 |
516 | /**
517 | * Attempt to change the current nick (nickname) of the bot when it
518 | * is connected to an IRC server.
519 | * After confirmation of a successful nick change, the getNick method
520 | * will return the new nick.
521 | *
522 | * @param newNick The new nick to use.
523 | */
524 | public final void changeNick(String newNick) {
525 | this.sendRawLine("NICK " + newNick);
526 | }
527 |
528 |
529 | /**
530 | * Identify the bot with NickServ, supplying the appropriate password.
531 | * Some IRC Networks (such as freenode) require users to register and
532 | * identify with NickServ before they are able to send private messages
533 | * to other users, thus reducing the amount of spam. If you are using
534 | * an IRC network where this kind of policy is enforced, you will need
535 | * to make your bot identify itself to NickServ before you can send
536 | * private messages. Assuming you have already registered your bot's
537 | * nick with NickServ, this method can be used to identify with
538 | * the supplied password. It usually makes sense to identify with NickServ
539 | * immediately after connecting to a server.
540 | * 541 | * This method issues a raw NICKSERV command to the server, and is therefore 542 | * safer than the alternative approach of sending a private message to 543 | * NickServ. The latter approach is considered dangerous, as it may cause 544 | * you to inadvertently transmit your password to an untrusted party if you 545 | * connect to a network which does not run a NickServ service and where the 546 | * untrusted party has assumed the nick "NickServ". However, if your IRC 547 | * network is only compatible with the private message approach, you may 548 | * typically identify like so: 549 | *
sendMessage("NickServ", "identify PASSWORD");550 | * 551 | * @param password The password which will be used to identify with NickServ. 552 | */ 553 | public final void identify(String password) { 554 | this.sendRawLine("NICKSERV IDENTIFY " + password); 555 | } 556 | 557 | 558 | /** 559 | * Set the mode of a channel. 560 | * This method attempts to set the mode of a channel. This 561 | * may require the bot to have operator status on the channel. 562 | * For example, if the bot has operator status, we can grant 563 | * operator status to "Dave" on the #cs channel 564 | * by calling setMode("#cs", "+o Dave"); 565 | * An alternative way of doing this would be to use the op method. 566 | * 567 | * @param channel The channel on which to perform the mode change. 568 | * @param mode The new mode to apply to the channel. This may include 569 | * zero or more arguments if necessary. 570 | * 571 | * @see #op(String,String) op 572 | */ 573 | public final void setMode(String channel, String mode) { 574 | this.sendRawLine("MODE " + channel + " " + mode); 575 | } 576 | 577 | 578 | /** 579 | * Sends an invitation to join a channel. Some channels can be marked 580 | * as "invite-only", so it may be useful to allow a bot to invite people 581 | * into it. 582 | * 583 | * @param nick The nick of the user to invite 584 | * @param channel The channel you are inviting the user to join. 585 | * 586 | */ 587 | public final void sendInvite(String nick, String channel) { 588 | this.sendRawLine("INVITE " + nick + " :" + channel); 589 | } 590 | 591 | 592 | /** 593 | * Bans a user from a channel. An example of a valid hostmask is 594 | * "*!*compu@*.18hp.net". This may be used in conjunction with the 595 | * kick method to permanently remove a user from a channel. 596 | * Successful use of this method may require the bot to have operator 597 | * status itself. 598 | * 599 | * @param channel The channel to ban the user from. 600 | * @param hostmask A hostmask representing the user we're banning. 601 | */ 602 | public final void ban(String channel, String hostmask) { 603 | this.sendRawLine("MODE " + channel + " +b " + hostmask); 604 | } 605 | 606 | 607 | /** 608 | * Unbans a user from a channel. An example of a valid hostmask is 609 | * "*!*compu@*.18hp.net". 610 | * Successful use of this method may require the bot to have operator 611 | * status itself. 612 | * 613 | * @param channel The channel to unban the user from. 614 | * @param hostmask A hostmask representing the user we're unbanning. 615 | */ 616 | public final void unBan(String channel, String hostmask) { 617 | this.sendRawLine("MODE " + channel + " -b " + hostmask); 618 | } 619 | 620 | 621 | /** 622 | * Grants operator privilidges to a user on a channel. 623 | * Successful use of this method may require the bot to have operator 624 | * status itself. 625 | * 626 | * @param channel The channel we're opping the user on. 627 | * @param nick The nick of the user we are opping. 628 | */ 629 | public final void op(String channel, String nick) { 630 | this.setMode(channel, "+o " + nick); 631 | } 632 | 633 | 634 | /** 635 | * Removes operator privilidges from a user on a channel. 636 | * Successful use of this method may require the bot to have operator 637 | * status itself. 638 | * 639 | * @param channel The channel we're deopping the user on. 640 | * @param nick The nick of the user we are deopping. 641 | */ 642 | public final void deOp(String channel, String nick) { 643 | this.setMode(channel, "-o " + nick); 644 | } 645 | 646 | 647 | /** 648 | * Grants voice privilidges to a user on a channel. 649 | * Successful use of this method may require the bot to have operator 650 | * status itself. 651 | * 652 | * @param channel The channel we're voicing the user on. 653 | * @param nick The nick of the user we are voicing. 654 | */ 655 | public final void voice(String channel, String nick) { 656 | this.setMode(channel, "+v " + nick); 657 | } 658 | 659 | 660 | /** 661 | * Removes voice privilidges from a user on a channel. 662 | * Successful use of this method may require the bot to have operator 663 | * status itself. 664 | * 665 | * @param channel The channel we're devoicing the user on. 666 | * @param nick The nick of the user we are devoicing. 667 | */ 668 | public final void deVoice(String channel, String nick) { 669 | this.setMode(channel, "-v " + nick); 670 | } 671 | 672 | 673 | /** 674 | * Set the topic for a channel. 675 | * This method attempts to set the topic of a channel. This 676 | * may require the bot to have operator status if the topic 677 | * is protected. 678 | * 679 | * @param channel The channel on which to perform the mode change. 680 | * @param topic The new topic for the channel. 681 | * 682 | */ 683 | public final void setTopic(String channel, String topic) { 684 | this.sendRawLine("TOPIC " + channel + " :" + topic); 685 | } 686 | 687 | 688 | /** 689 | * Kicks a user from a channel. 690 | * This method attempts to kick a user from a channel and 691 | * may require the bot to have operator status in the channel. 692 | * 693 | * @param channel The channel to kick the user from. 694 | * @param nick The nick of the user to kick. 695 | */ 696 | public final void kick(String channel, String nick) { 697 | this.kick(channel, nick, ""); 698 | } 699 | 700 | 701 | /** 702 | * Kicks a user from a channel, giving a reason. 703 | * This method attempts to kick a user from a channel and 704 | * may require the bot to have operator status in the channel. 705 | * 706 | * @param channel The channel to kick the user from. 707 | * @param nick The nick of the user to kick. 708 | * @param reason A description of the reason for kicking a user. 709 | */ 710 | public final void kick(String channel, String nick, String reason) { 711 | this.sendRawLine("KICK " + channel + " " + nick + " :" + reason); 712 | } 713 | 714 | 715 | /** 716 | * Issues a request for a list of all channels on the IRC server. 717 | * When the PircBot receives information for each channel, it will 718 | * call the onChannelInfo method, which you will need to override 719 | * if you want it to do anything useful. 720 | * 721 | * @see #onChannelInfo(String,int,String) onChannelInfo 722 | */ 723 | public final void listChannels() { 724 | this.listChannels(null); 725 | } 726 | 727 | 728 | /** 729 | * Issues a request for a list of all channels on the IRC server. 730 | * When the PircBot receives information for each channel, it will 731 | * call the onChannelInfo method, which you will need to override 732 | * if you want it to do anything useful. 733 | *
734 | * Some IRC servers support certain parameters for LIST requests. 735 | * One example is a parameter of ">10" to list only those channels 736 | * that have more than 10 users in them. Whether these parameters 737 | * are supported or not will depend on the IRC server software. 738 | * 739 | * @param parameters The parameters to supply when requesting the 740 | * list. 741 | * 742 | * @see #onChannelInfo(String,int,String) onChannelInfo 743 | */ 744 | public final void listChannels(String parameters) { 745 | if (parameters == null) { 746 | this.sendRawLine("LIST"); 747 | } 748 | else { 749 | this.sendRawLine("LIST " + parameters); 750 | } 751 | } 752 | 753 | 754 | /** 755 | * Sends a file to another user. Resuming is supported. 756 | * The other user must be able to connect directly to your bot to be 757 | * able to receive the file. 758 | *
759 | * You may throttle the speed of this file transfer by calling the 760 | * setPacketDelay method on the DccFileTransfer that is returned. 761 | *
762 | * This method may not be overridden. 763 | * 764 | * @since 0.9c 765 | * 766 | * @param file The file to send. 767 | * @param nick The user to whom the file is to be sent. 768 | * @param timeout The number of milliseconds to wait for the recipient to 769 | * acccept the file (we recommend about 120000). 770 | * 771 | * @return The DccFileTransfer that can be used to monitor this transfer. 772 | * 773 | * @see DccFileTransfer 774 | * 775 | */ 776 | public final DccFileTransfer dccSendFile(File file, String nick, int timeout) { 777 | DccFileTransfer transfer = new DccFileTransfer(this, _dccManager, file, nick, timeout); 778 | transfer.doSend(true); 779 | return transfer; 780 | } 781 | 782 | 783 | /** 784 | * Receives a file that is being sent to us by a DCC SEND request. 785 | * Please use the onIncomingFileTransfer method to receive files. 786 | * 787 | * @deprecated As of PircBot 1.2.0, use {@link #onIncomingFileTransfer(DccFileTransfer)} 788 | */ 789 | protected final void dccReceiveFile(File file, long address, int port, int size) { 790 | throw new RuntimeException("dccReceiveFile is deprecated, please use sendFile"); 791 | } 792 | 793 | 794 | /** 795 | * Attempts to establish a DCC CHAT session with a client. This method 796 | * issues the connection request to the client and then waits for the 797 | * client to respond. If the connection is successfully made, then a 798 | * DccChat object is returned by this method. If the connection is not 799 | * made within the time limit specified by the timeout value, then null 800 | * is returned. 801 | *
802 | * It is strongly recommended that you call this method within a new 803 | * Thread, as it may take a long time to return. 804 | *
805 | * This method may not be overridden. 806 | * 807 | * @since PircBot 0.9.8 808 | * 809 | * @param nick The nick of the user we are trying to establish a chat with. 810 | * @param timeout The number of milliseconds to wait for the recipient to 811 | * accept the chat connection (we recommend about 120000). 812 | * 813 | * @return a DccChat object that can be used to send and recieve lines of 814 | * text. Returns null if the connection could not be made. 815 | * 816 | * @see DccChat 817 | */ 818 | public final DccChat dccSendChatRequest(String nick, int timeout) { 819 | DccChat chat = null; 820 | try { 821 | ServerSocket ss = null; 822 | 823 | int[] ports = getDccPorts(); 824 | if (ports == null) { 825 | // Use any free port. 826 | ss = new ServerSocket(0); 827 | } 828 | else { 829 | for (int i = 0; i < ports.length; i++) { 830 | try { 831 | ss = new ServerSocket(ports[i]); 832 | // Found a port number we could use. 833 | break; 834 | } 835 | catch (Exception e) { 836 | // Do nothing; go round and try another port. 837 | } 838 | } 839 | if (ss == null) { 840 | // No ports could be used. 841 | throw new IOException("All ports returned by getDccPorts() are in use."); 842 | } 843 | } 844 | 845 | ss.setSoTimeout(timeout); 846 | int port = ss.getLocalPort(); 847 | 848 | InetAddress inetAddress = getDccInetAddress(); 849 | if (inetAddress == null) { 850 | inetAddress = getInetAddress(); 851 | } 852 | byte[] ip = inetAddress.getAddress(); 853 | long ipNum = ipToLong(ip); 854 | 855 | sendCTCPCommand(nick, "DCC CHAT chat " + ipNum + " " + port); 856 | 857 | // The client may now connect to us to chat. 858 | Socket socket = ss.accept(); 859 | 860 | // Close the server socket now that we've finished with it. 861 | ss.close(); 862 | 863 | chat = new DccChat(this, nick, socket); 864 | } 865 | catch (Exception e) { 866 | // Do nothing. 867 | } 868 | return chat; 869 | } 870 | 871 | 872 | /** 873 | * Attempts to accept a DCC CHAT request by a client. 874 | * Please use the onIncomingChatRequest method to receive files. 875 | * 876 | * @deprecated As of PircBot 1.2.0, use {@link #onIncomingChatRequest(DccChat)} 877 | */ 878 | protected final DccChat dccAcceptChatRequest(String sourceNick, long address, int port) { 879 | throw new RuntimeException("dccAcceptChatRequest is deprecated, please use onIncomingChatRequest"); 880 | } 881 | 882 | 883 | /** 884 | * Adds a line to the log. This log is currently output to the standard 885 | * output and is in the correct format for use by tools such as pisg, the 886 | * Perl IRC Statistics Generator. You may override this method if you wish 887 | * to do something else with log entries. 888 | * Each line in the log begins with a number which 889 | * represents the logging time (as the number of milliseconds since the 890 | * epoch). This timestamp and the following log entry are separated by 891 | * a single space character, " ". Outgoing messages are distinguishable 892 | * by a log entry that has ">>>" immediately following the space character 893 | * after the timestamp. DCC events use "+++" and warnings about unhandled 894 | * Exceptions and Errors use "###". 895 | *
896 | * This implementation of the method will only cause log entries to be 897 | * output if the PircBot has had its verbose mode turned on by calling 898 | * setVerbose(true); 899 | * 900 | * @param line The line to add to the log. 901 | */ 902 | public void log(String line) { 903 | if (_verbose) { 904 | System.out.println(System.currentTimeMillis() + " " + line); 905 | } 906 | } 907 | 908 | 909 | /** 910 | * This method handles events when any line of text arrives from the server, 911 | * then calling the appropriate method in the PircBot. This method is 912 | * protected and only called by the InputThread for this instance. 913 | *
914 | * This method may not be overridden! 915 | * 916 | * @param line The raw line of text from the server. 917 | */ 918 | protected void handleLine(String line) { 919 | this.log(line); 920 | 921 | // Check for server pings. 922 | if (line.startsWith("PING ")) { 923 | // Respond to the ping and return immediately. 924 | this.onServerPing(line.substring(5)); 925 | return; 926 | } 927 | 928 | String sourceNick = ""; 929 | String sourceLogin = ""; 930 | String sourceHostname = ""; 931 | 932 | StringTokenizer tokenizer = new StringTokenizer(line); 933 | String senderInfo = tokenizer.nextToken(); 934 | String command = tokenizer.nextToken(); 935 | String target = null; 936 | 937 | int exclamation = senderInfo.indexOf("!"); 938 | int at = senderInfo.indexOf("@"); 939 | if (senderInfo.startsWith(":")) { 940 | if (exclamation > 0 && at > 0 && exclamation < at) { 941 | sourceNick = senderInfo.substring(1, exclamation); 942 | sourceLogin = senderInfo.substring(exclamation + 1, at); 943 | sourceHostname = senderInfo.substring(at + 1); 944 | } 945 | else { 946 | 947 | if (tokenizer.hasMoreTokens()) { 948 | String token = command; 949 | 950 | int code = -1; 951 | try { 952 | code = Integer.parseInt(token); 953 | } 954 | catch (NumberFormatException e) { 955 | // Keep the existing value. 956 | } 957 | 958 | if (code != -1) { 959 | String errorStr = token; 960 | String response = line.substring(line.indexOf(errorStr, senderInfo.length()) + 4, line.length()); 961 | this.processServerResponse(code, response); 962 | // Return from the method. 963 | return; 964 | } 965 | else { 966 | // This is not a server response. 967 | // It must be a nick without login and hostname. 968 | // (or maybe a NOTICE or suchlike from the server) 969 | sourceNick = senderInfo; 970 | target = token; 971 | } 972 | } 973 | else { 974 | // We don't know what this line means. 975 | this.onUnknown(line); 976 | // Return from the method; 977 | return; 978 | } 979 | 980 | } 981 | } 982 | 983 | command = command.toUpperCase(); 984 | if (sourceNick.startsWith(":")) { 985 | sourceNick = sourceNick.substring(1); 986 | } 987 | if (target == null) { 988 | target = tokenizer.nextToken(); 989 | } 990 | if (target.startsWith(":")) { 991 | target = target.substring(1); 992 | } 993 | 994 | // Check for CTCP requests. 995 | if (command.equals("PRIVMSG") && line.indexOf(":\u0001") > 0 && line.endsWith("\u0001")) { 996 | String request = line.substring(line.indexOf(":\u0001") + 2, line.length() - 1); 997 | if (request.equals("VERSION")) { 998 | // VERSION request 999 | this.onVersion(sourceNick, sourceLogin, sourceHostname, target); 1000 | } 1001 | else if (request.startsWith("ACTION ")) { 1002 | // ACTION request 1003 | this.onAction(sourceNick, sourceLogin, sourceHostname, target, request.substring(7)); 1004 | } 1005 | else if (request.startsWith("PING ")) { 1006 | // PING request 1007 | this.onPing(sourceNick, sourceLogin, sourceHostname, target, request.substring(5)); 1008 | } 1009 | else if (request.equals("TIME")) { 1010 | // TIME request 1011 | this.onTime(sourceNick, sourceLogin, sourceHostname, target); 1012 | } 1013 | else if (request.equals("FINGER")) { 1014 | // FINGER request 1015 | this.onFinger(sourceNick, sourceLogin, sourceHostname, target); 1016 | } 1017 | else if ((tokenizer = new StringTokenizer(request)).countTokens() >= 5 && tokenizer.nextToken().equals("DCC")) { 1018 | // This is a DCC request. 1019 | boolean success = _dccManager.processRequest(sourceNick, sourceLogin, sourceHostname, request); 1020 | if (!success) { 1021 | // The DccManager didn't know what to do with the line. 1022 | this.onUnknown(line); 1023 | } 1024 | } 1025 | else { 1026 | // An unknown CTCP message - ignore it. 1027 | this.onUnknown(line); 1028 | } 1029 | } 1030 | else if (command.equals("PRIVMSG") && _channelPrefixes.indexOf(target.charAt(0)) >= 0) { 1031 | // This is a normal message to a channel. 1032 | this.onMessage(target, sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); 1033 | } 1034 | else if (command.equals("PRIVMSG")) { 1035 | // This is a private message to us. 1036 | this.onPrivateMessage(sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); 1037 | } 1038 | else if (command.equals("JOIN")) { 1039 | // Someone is joining a channel. 1040 | String channel = target; 1041 | this.addUser(channel, new User("", sourceNick)); 1042 | this.onJoin(channel, sourceNick, sourceLogin, sourceHostname); 1043 | } 1044 | else if (command.equals("PART")) { 1045 | // Someone is parting from a channel. 1046 | this.removeUser(target, sourceNick); 1047 | if (sourceNick.equals(this.getNick())) { 1048 | this.removeChannel(target); 1049 | } 1050 | this.onPart(target, sourceNick, sourceLogin, sourceHostname); 1051 | } 1052 | else if (command.equals("NICK")) { 1053 | // Somebody is changing their nick. 1054 | String newNick = target; 1055 | this.renameUser(sourceNick, newNick); 1056 | if (sourceNick.equals(this.getNick())) { 1057 | // Update our nick if it was us that changed nick. 1058 | this.setNick(newNick); 1059 | } 1060 | this.onNickChange(sourceNick, sourceLogin, sourceHostname, newNick); 1061 | } 1062 | else if (command.equals("NOTICE")) { 1063 | // Someone is sending a notice. 1064 | this.onNotice(sourceNick, sourceLogin, sourceHostname, target, line.substring(line.indexOf(" :") + 2)); 1065 | } 1066 | else if (command.equals("QUIT")) { 1067 | // Someone has quit from the IRC server. 1068 | if (sourceNick.equals(this.getNick())) { 1069 | this.removeAllChannels(); 1070 | } 1071 | else { 1072 | this.removeUser(sourceNick); 1073 | } 1074 | this.onQuit(sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); 1075 | } 1076 | else if (command.equals("KICK")) { 1077 | // Somebody has been kicked from a channel. 1078 | String recipient = tokenizer.nextToken(); 1079 | if (recipient.equals(this.getNick())) { 1080 | this.removeChannel(target); 1081 | } 1082 | this.removeUser(target, recipient); 1083 | this.onKick(target, sourceNick, sourceLogin, sourceHostname, recipient, line.substring(line.indexOf(" :") + 2)); 1084 | } 1085 | else if (command.equals("MODE")) { 1086 | // Somebody is changing the mode on a channel or user. 1087 | String mode = line.substring(line.indexOf(target, 2) + target.length() + 1); 1088 | if (mode.startsWith(":")) { 1089 | mode = mode.substring(1); 1090 | } 1091 | this.processMode(target, sourceNick, sourceLogin, sourceHostname, mode); 1092 | } 1093 | else if (command.equals("TOPIC")) { 1094 | // Someone is changing the topic. 1095 | this.onTopic(target, line.substring(line.indexOf(" :") + 2), sourceNick, System.currentTimeMillis(), true); 1096 | } 1097 | else if (command.equals("INVITE")) { 1098 | // Somebody is inviting somebody else into a channel. 1099 | this.onInvite(target, sourceNick, sourceLogin, sourceHostname, line.substring(line.indexOf(" :") + 2)); 1100 | } 1101 | else { 1102 | // If we reach this point, then we've found something that the PircBot 1103 | // Doesn't currently deal with. 1104 | this.onUnknown(line); 1105 | } 1106 | 1107 | } 1108 | 1109 | 1110 | /** 1111 | * This method is called once the PircBot has successfully connected to 1112 | * the IRC server. 1113 | *
1114 | * The implementation of this method in the PircBot abstract class 1115 | * performs no actions and may be overridden as required. 1116 | * 1117 | * @since PircBot 0.9.6 1118 | */ 1119 | protected void onConnect() {} 1120 | 1121 | 1122 | /** 1123 | * This method carries out the actions to be performed when the PircBot 1124 | * gets disconnected. This may happen if the PircBot quits from the 1125 | * server, or if the connection is unexpectedly lost. 1126 | *
1127 | * Disconnection from the IRC server is detected immediately if either 1128 | * we or the server close the connection normally. If the connection to 1129 | * the server is lost, but neither we nor the server have explicitly closed 1130 | * the connection, then it may take a few minutes to detect (this is 1131 | * commonly referred to as a "ping timeout"). 1132 | *
1133 | * If you wish to get your IRC bot to automatically rejoin a server after 1134 | * the connection has been lost, then this is probably the ideal method to 1135 | * override to implement such functionality. 1136 | *
1137 | * The implementation of this method in the PircBot abstract class 1138 | * performs no actions and may be overridden as required. 1139 | */ 1140 | protected void onDisconnect() {} 1141 | 1142 | 1143 | /** 1144 | * This method is called by the PircBot when a numeric response 1145 | * is received from the IRC server. We use this method to 1146 | * allow PircBot to process various responses from the server 1147 | * before then passing them on to the onServerResponse method. 1148 | *
1149 | * Note that this method is private and should not appear in any 1150 | * of the javadoc generated documenation. 1151 | * 1152 | * @param code The three-digit numerical code for the response. 1153 | * @param response The full response from the IRC server. 1154 | */ 1155 | private final void processServerResponse(int code, String response) { 1156 | 1157 | if (code == RPL_LIST) { 1158 | // This is a bit of information about a channel. 1159 | int firstSpace = response.indexOf(' '); 1160 | int secondSpace = response.indexOf(' ', firstSpace + 1); 1161 | int thirdSpace = response.indexOf(' ', secondSpace + 1); 1162 | int colon = response.indexOf(':'); 1163 | String channel = response.substring(firstSpace + 1, secondSpace); 1164 | int userCount = 0; 1165 | try { 1166 | userCount = Integer.parseInt(response.substring(secondSpace + 1, thirdSpace)); 1167 | } 1168 | catch (NumberFormatException e) { 1169 | // Stick with the value of zero. 1170 | } 1171 | String topic = response.substring(colon + 1); 1172 | this.onChannelInfo(channel, userCount, topic); 1173 | } 1174 | else if (code == RPL_TOPIC) { 1175 | // This is topic information about a channel we've just joined. 1176 | int firstSpace = response.indexOf(' '); 1177 | int secondSpace = response.indexOf(' ', firstSpace + 1); 1178 | int colon = response.indexOf(':'); 1179 | String channel = response.substring(firstSpace + 1, secondSpace); 1180 | String topic = response.substring(colon + 1); 1181 | 1182 | _topics.put(channel, topic); 1183 | 1184 | // For backwards compatibility only - this onTopic method is deprecated. 1185 | this.onTopic(channel, topic); 1186 | } 1187 | else if (code == RPL_TOPICINFO) { 1188 | StringTokenizer tokenizer = new StringTokenizer(response); 1189 | tokenizer.nextToken(); 1190 | String channel = tokenizer.nextToken(); 1191 | String setBy = tokenizer.nextToken(); 1192 | long date = 0; 1193 | try { 1194 | date = Long.parseLong(tokenizer.nextToken()) * 1000; 1195 | } 1196 | catch (NumberFormatException e) { 1197 | // Stick with the default value of zero. 1198 | } 1199 | 1200 | String topic = (String) _topics.get(channel); 1201 | _topics.remove(channel); 1202 | 1203 | this.onTopic(channel, topic, setBy, date, false); 1204 | } 1205 | else if (code == RPL_NAMREPLY) { 1206 | // This is a list of nicks in a channel that we've just joined. 1207 | int channelEndIndex = response.indexOf(" :"); 1208 | String channel = response.substring(response.lastIndexOf(' ', channelEndIndex - 1) + 1, channelEndIndex); 1209 | 1210 | StringTokenizer tokenizer = new StringTokenizer(response.substring(response.indexOf(" :") + 2)); 1211 | while (tokenizer.hasMoreTokens()) { 1212 | String nick = tokenizer.nextToken(); 1213 | String prefix = ""; 1214 | if (nick.startsWith("@")) { 1215 | // User is an operator in this channel. 1216 | prefix = "@"; 1217 | } 1218 | else if (nick.startsWith("+")) { 1219 | // User is voiced in this channel. 1220 | prefix = "+"; 1221 | } 1222 | else if (nick.startsWith(".")) { 1223 | // Some wibbly status I've never seen before... 1224 | prefix = "."; 1225 | } 1226 | nick = nick.substring(prefix.length()); 1227 | this.addUser(channel, new User(prefix, nick)); 1228 | } 1229 | } 1230 | else if (code == RPL_ENDOFNAMES) { 1231 | // This is the end of a NAMES list, so we know that we've got 1232 | // the full list of users in the channel that we just joined. 1233 | String channel = response.substring(response.indexOf(' ') + 1, response.indexOf(" :")); 1234 | User[] users = this.getUsers(channel); 1235 | this.onUserList(channel, users); 1236 | } 1237 | 1238 | this.onServerResponse(code, response); 1239 | } 1240 | 1241 | 1242 | /** 1243 | * This method is called when we receive a numeric response from the 1244 | * IRC server. 1245 | *
1246 | * Numerics in the range from 001 to 099 are used for client-server 1247 | * connections only and should never travel between servers. Replies 1248 | * generated in response to commands are found in the range from 200 1249 | * to 399. Error replies are found in the range from 400 to 599. 1250 | *
1251 | * For example, we can use this method to discover the topic of a
1252 | * channel when we join it. If we join the channel #test which
1253 | * has a topic of "I am King of Test" then the response
1254 | * will be "PircBot #test :I Am King of Test
"
1255 | * with a code of 332 to signify that this is a topic.
1256 | * (This is just an example - note that overriding the
1257 | * onTopic
method is an easier way of finding the
1258 | * topic for a channel). Check the IRC RFC for the full list of other
1259 | * command response codes.
1260 | *
1261 | * PircBot implements the interface ReplyConstants, which contains 1262 | * contstants that you may find useful here. 1263 | *
1264 | * The implementation of this method in the PircBot abstract class 1265 | * performs no actions and may be overridden as required. 1266 | * 1267 | * @param code The three-digit numerical code for the response. 1268 | * @param response The full response from the IRC server. 1269 | * 1270 | * @see ReplyConstants 1271 | */ 1272 | protected void onServerResponse(int code, String response) {} 1273 | 1274 | 1275 | /** 1276 | * This method is called when we receive a user list from the server 1277 | * after joining a channel. 1278 | *
1279 | * Shortly after joining a channel, the IRC server sends a list of all 1280 | * users in that channel. The PircBot collects this information and 1281 | * calls this method as soon as it has the full list. 1282 | *
1283 | * To obtain the nick of each user in the channel, call the getNick() 1284 | * method on each User object in the array. 1285 | *
1286 | * At a later time, you may call the getUsers method to obtain an 1287 | * up to date list of the users in the channel. 1288 | *
1289 | * The implementation of this method in the PircBot abstract class 1290 | * performs no actions and may be overridden as required. 1291 | * 1292 | * @since PircBot 1.0.0 1293 | * 1294 | * @param channel The name of the channel. 1295 | * @param users An array of User objects belonging to this channel. 1296 | * 1297 | * @see User 1298 | */ 1299 | protected void onUserList(String channel, User[] users) {} 1300 | 1301 | 1302 | /** 1303 | * This method is called whenever a message is sent to a channel. 1304 | *
1305 | * The implementation of this method in the PircBot abstract class 1306 | * performs no actions and may be overridden as required. 1307 | * 1308 | * @param channel The channel to which the message was sent. 1309 | * @param sender The nick of the person who sent the message. 1310 | * @param login The login of the person who sent the message. 1311 | * @param hostname The hostname of the person who sent the message. 1312 | * @param message The actual message sent to the channel. 1313 | */ 1314 | protected void onMessage(String channel, String sender, String login, String hostname, String message) {} 1315 | 1316 | 1317 | /** 1318 | * This method is called whenever a private message is sent to the PircBot. 1319 | *
1320 | * The implementation of this method in the PircBot abstract class 1321 | * performs no actions and may be overridden as required. 1322 | * 1323 | * @param sender The nick of the person who sent the private message. 1324 | * @param login The login of the person who sent the private message. 1325 | * @param hostname The hostname of the person who sent the private message. 1326 | * @param message The actual message. 1327 | */ 1328 | protected void onPrivateMessage(String sender, String login, String hostname, String message) {} 1329 | 1330 | 1331 | /** 1332 | * This method is called whenever an ACTION is sent from a user. E.g. 1333 | * such events generated by typing "/me goes shopping" in most IRC clients. 1334 | *
1335 | * The implementation of this method in the PircBot abstract class 1336 | * performs no actions and may be overridden as required. 1337 | * 1338 | * @param sender The nick of the user that sent the action. 1339 | * @param login The login of the user that sent the action. 1340 | * @param hostname The hostname of the user that sent the action. 1341 | * @param target The target of the action, be it a channel or our nick. 1342 | * @param action The action carried out by the user. 1343 | */ 1344 | protected void onAction(String sender, String login, String hostname, String target, String action) {} 1345 | 1346 | 1347 | /** 1348 | * This method is called whenever we receive a notice. 1349 | *
1350 | * The implementation of this method in the PircBot abstract class 1351 | * performs no actions and may be overridden as required. 1352 | * 1353 | * @param sourceNick The nick of the user that sent the notice. 1354 | * @param sourceLogin The login of the user that sent the notice. 1355 | * @param sourceHostname The hostname of the user that sent the notice. 1356 | * @param target The target of the notice, be it our nick or a channel name. 1357 | * @param notice The notice message. 1358 | */ 1359 | protected void onNotice(String sourceNick, String sourceLogin, String sourceHostname, String target, String notice) {} 1360 | 1361 | 1362 | /** 1363 | * This method is called whenever someone (possibly us) joins a channel 1364 | * which we are on. 1365 | *
1366 | * The implementation of this method in the PircBot abstract class 1367 | * performs no actions and may be overridden as required. 1368 | * 1369 | * @param channel The channel which somebody joined. 1370 | * @param sender The nick of the user who joined the channel. 1371 | * @param login The login of the user who joined the channel. 1372 | * @param hostname The hostname of the user who joined the channel. 1373 | */ 1374 | protected void onJoin(String channel, String sender, String login, String hostname) {} 1375 | 1376 | 1377 | /** 1378 | * This method is called whenever someone (possibly us) parts a channel 1379 | * which we are on. 1380 | *
1381 | * The implementation of this method in the PircBot abstract class 1382 | * performs no actions and may be overridden as required. 1383 | * 1384 | * @param channel The channel which somebody parted from. 1385 | * @param sender The nick of the user who parted from the channel. 1386 | * @param login The login of the user who parted from the channel. 1387 | * @param hostname The hostname of the user who parted from the channel. 1388 | */ 1389 | protected void onPart(String channel, String sender, String login, String hostname) {} 1390 | 1391 | 1392 | /** 1393 | * This method is called whenever someone (possibly us) changes nick on any 1394 | * of the channels that we are on. 1395 | *
1396 | * The implementation of this method in the PircBot abstract class 1397 | * performs no actions and may be overridden as required. 1398 | * 1399 | * @param oldNick The old nick. 1400 | * @param login The login of the user. 1401 | * @param hostname The hostname of the user. 1402 | * @param newNick The new nick. 1403 | */ 1404 | protected void onNickChange(String oldNick, String login, String hostname, String newNick) {} 1405 | 1406 | 1407 | /** 1408 | * This method is called whenever someone (possibly us) is kicked from 1409 | * any of the channels that we are in. 1410 | *
1411 | * The implementation of this method in the PircBot abstract class 1412 | * performs no actions and may be overridden as required. 1413 | * 1414 | * @param channel The channel from which the recipient was kicked. 1415 | * @param kickerNick The nick of the user who performed the kick. 1416 | * @param kickerLogin The login of the user who performed the kick. 1417 | * @param kickerHostname The hostname of the user who performed the kick. 1418 | * @param recipientNick The unfortunate recipient of the kick. 1419 | * @param reason The reason given by the user who performed the kick. 1420 | */ 1421 | protected void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {} 1422 | 1423 | 1424 | /** 1425 | * This method is called whenever someone (possibly us) quits from the 1426 | * server. We will only observe this if the user was in one of the 1427 | * channels to which we are connected. 1428 | *
1429 | * The implementation of this method in the PircBot abstract class 1430 | * performs no actions and may be overridden as required. 1431 | * 1432 | * @param sourceNick The nick of the user that quit from the server. 1433 | * @param sourceLogin The login of the user that quit from the server. 1434 | * @param sourceHostname The hostname of the user that quit from the server. 1435 | * @param reason The reason given for quitting the server. 1436 | */ 1437 | protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {} 1438 | 1439 | 1440 | /** 1441 | * This method is called whenever a user sets the topic, or when 1442 | * PircBot joins a new channel and discovers its topic. 1443 | *
1444 | * The implementation of this method in the PircBot abstract class 1445 | * performs no actions and may be overridden as required. 1446 | * 1447 | * @param channel The channel that the topic belongs to. 1448 | * @param topic The topic for the channel. 1449 | * 1450 | * @deprecated As of 1.2.0, replaced by {@link #onTopic(String,String,String,long,boolean)} 1451 | */ 1452 | protected void onTopic(String channel, String topic) {} 1453 | 1454 | 1455 | /** 1456 | * This method is called whenever a user sets the topic, or when 1457 | * PircBot joins a new channel and discovers its topic. 1458 | *
1459 | * The implementation of this method in the PircBot abstract class 1460 | * performs no actions and may be overridden as required. 1461 | * 1462 | * @param channel The channel that the topic belongs to. 1463 | * @param topic The topic for the channel. 1464 | * @param setBy The nick of the user that set the topic. 1465 | * @param date When the topic was set (milliseconds since the epoch). 1466 | * @param changed True if the topic has just been changed, false if 1467 | * the topic was already there. 1468 | * 1469 | */ 1470 | protected void onTopic(String channel, String topic, String setBy, long date, boolean changed) {} 1471 | 1472 | 1473 | /** 1474 | * After calling the listChannels() method in PircBot, the server 1475 | * will start to send us information about each channel on the 1476 | * server. You may override this method in order to receive the 1477 | * information about each channel as soon as it is received. 1478 | *
1479 | * Note that certain channels, such as those marked as hidden, 1480 | * may not appear in channel listings. 1481 | *
1482 | * The implementation of this method in the PircBot abstract class 1483 | * performs no actions and may be overridden as required. 1484 | * 1485 | * @param channel The name of the channel. 1486 | * @param userCount The number of users visible in this channel. 1487 | * @param topic The topic for this channel. 1488 | * 1489 | * @see #listChannels() listChannels 1490 | */ 1491 | protected void onChannelInfo(String channel, int userCount, String topic) {} 1492 | 1493 | 1494 | /** 1495 | * Called when the mode of a channel is set. We process this in 1496 | * order to call the appropriate onOp, onDeop, etc method before 1497 | * finally calling the override-able onMode method. 1498 | *
1499 | * Note that this method is private and is not intended to appear 1500 | * in the javadoc generated documentation. 1501 | * 1502 | * @param target The channel or nick that the mode operation applies to. 1503 | * @param sourceNick The nick of the user that set the mode. 1504 | * @param sourceLogin The login of the user that set the mode. 1505 | * @param sourceHostname The hostname of the user that set the mode. 1506 | * @param mode The mode that has been set. 1507 | */ 1508 | private final void processMode(String target, String sourceNick, String sourceLogin, String sourceHostname, String mode) { 1509 | 1510 | if (_channelPrefixes.indexOf(target.charAt(0)) >= 0) { 1511 | // The mode of a channel is being changed. 1512 | String channel = target; 1513 | StringTokenizer tok = new StringTokenizer(mode); 1514 | String[] params = new String[tok.countTokens()]; 1515 | 1516 | int t = 0; 1517 | while (tok.hasMoreTokens()) { 1518 | params[t] = tok.nextToken(); 1519 | t++; 1520 | } 1521 | 1522 | char pn = ' '; 1523 | int p = 1; 1524 | 1525 | // All of this is very large and ugly, but it's the only way of providing 1526 | // what the users want :-/ 1527 | for (int i = 0; i < params[0].length(); i++) { 1528 | char atPos = params[0].charAt(i); 1529 | 1530 | if (atPos == '+' || atPos == '-') { 1531 | pn = atPos; 1532 | } 1533 | else if (atPos == 'o') { 1534 | if (pn == '+') { 1535 | this.updateUser(channel, OP_ADD, params[p]); 1536 | onOp(channel, sourceNick, sourceLogin, sourceHostname, params[p]); 1537 | } 1538 | else { 1539 | this.updateUser(channel, OP_REMOVE, params[p]); 1540 | onDeop(channel, sourceNick, sourceLogin, sourceHostname, params[p]); 1541 | } 1542 | p++; 1543 | } 1544 | else if (atPos == 'v') { 1545 | if (pn == '+') { 1546 | this.updateUser(channel, VOICE_ADD, params[p]); 1547 | onVoice(channel, sourceNick, sourceLogin, sourceHostname, params[p]); 1548 | } 1549 | else { 1550 | this.updateUser(channel, VOICE_REMOVE, params[p]); 1551 | onDeVoice(channel, sourceNick, sourceLogin, sourceHostname, params[p]); 1552 | } 1553 | p++; 1554 | } 1555 | else if (atPos == 'k') { 1556 | if (pn == '+') { 1557 | onSetChannelKey(channel, sourceNick, sourceLogin, sourceHostname, params[p]); 1558 | } 1559 | else { 1560 | onRemoveChannelKey(channel, sourceNick, sourceLogin, sourceHostname, params[p]); 1561 | } 1562 | p++; 1563 | } 1564 | else if (atPos == 'l') { 1565 | if (pn == '+') { 1566 | onSetChannelLimit(channel, sourceNick, sourceLogin, sourceHostname, Integer.parseInt(params[p])); 1567 | p++; 1568 | } 1569 | else { 1570 | onRemoveChannelLimit(channel, sourceNick, sourceLogin, sourceHostname); 1571 | } 1572 | } 1573 | else if (atPos == 'b') { 1574 | if (pn == '+') { 1575 | onSetChannelBan(channel, sourceNick, sourceLogin, sourceHostname,params[p]); 1576 | } 1577 | else { 1578 | onRemoveChannelBan(channel, sourceNick, sourceLogin, sourceHostname, params[p]); 1579 | } 1580 | p++; 1581 | } 1582 | else if (atPos == 't') { 1583 | if (pn == '+') { 1584 | onSetTopicProtection(channel, sourceNick, sourceLogin, sourceHostname); 1585 | } 1586 | else { 1587 | onRemoveTopicProtection(channel, sourceNick, sourceLogin, sourceHostname); 1588 | } 1589 | } 1590 | else if (atPos == 'n') { 1591 | if (pn == '+') { 1592 | onSetNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname); 1593 | } 1594 | else { 1595 | onRemoveNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname); 1596 | } 1597 | } 1598 | else if (atPos == 'i') { 1599 | if (pn == '+') { 1600 | onSetInviteOnly(channel, sourceNick, sourceLogin, sourceHostname); 1601 | } 1602 | else { 1603 | onRemoveInviteOnly(channel, sourceNick, sourceLogin, sourceHostname); 1604 | } 1605 | } 1606 | else if (atPos == 'm') { 1607 | if (pn == '+') { 1608 | onSetModerated(channel, sourceNick, sourceLogin, sourceHostname); 1609 | } 1610 | else { 1611 | onRemoveModerated(channel, sourceNick, sourceLogin, sourceHostname); 1612 | } 1613 | } 1614 | else if (atPos == 'p') { 1615 | if (pn == '+') { 1616 | onSetPrivate(channel, sourceNick, sourceLogin, sourceHostname); 1617 | } 1618 | else { 1619 | onRemovePrivate(channel, sourceNick, sourceLogin, sourceHostname); 1620 | } 1621 | } 1622 | else if (atPos == 's') { 1623 | if (pn == '+') { 1624 | onSetSecret(channel, sourceNick, sourceLogin, sourceHostname); 1625 | } 1626 | else { 1627 | onRemoveSecret(channel, sourceNick, sourceLogin, sourceHostname); 1628 | } 1629 | } 1630 | } 1631 | 1632 | this.onMode(channel, sourceNick, sourceLogin, sourceHostname, mode); 1633 | } 1634 | else { 1635 | // The mode of a user is being changed. 1636 | String nick = target; 1637 | this.onUserMode(nick, sourceNick, sourceLogin, sourceHostname, mode); 1638 | } 1639 | } 1640 | 1641 | 1642 | /** 1643 | * Called when the mode of a channel is set. 1644 | *
1645 | * You may find it more convenient to decode the meaning of the mode 1646 | * string by overriding the onOp, onDeOp, onVoice, onDeVoice, 1647 | * onChannelKey, onDeChannelKey, onChannelLimit, onDeChannelLimit, 1648 | * onChannelBan or onDeChannelBan methods as appropriate. 1649 | *
1650 | * The implementation of this method in the PircBot abstract class 1651 | * performs no actions and may be overridden as required. 1652 | * 1653 | * @param channel The channel that the mode operation applies to. 1654 | * @param sourceNick The nick of the user that set the mode. 1655 | * @param sourceLogin The login of the user that set the mode. 1656 | * @param sourceHostname The hostname of the user that set the mode. 1657 | * @param mode The mode that has been set. 1658 | * 1659 | */ 1660 | protected void onMode(String channel, String sourceNick, String sourceLogin, String sourceHostname, String mode) {} 1661 | 1662 | 1663 | /** 1664 | * Called when the mode of a user is set. 1665 | *
1666 | * The implementation of this method in the PircBot abstract class 1667 | * performs no actions and may be overridden as required. 1668 | * 1669 | * @since PircBot 1.2.0 1670 | * 1671 | * @param targetNick The nick that the mode operation applies to. 1672 | * @param sourceNick The nick of the user that set the mode. 1673 | * @param sourceLogin The login of the user that set the mode. 1674 | * @param sourceHostname The hostname of the user that set the mode. 1675 | * @param mode The mode that has been set. 1676 | * 1677 | */ 1678 | protected void onUserMode(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String mode) {} 1679 | 1680 | 1681 | 1682 | /** 1683 | * Called when a user (possibly us) gets granted operator status for a channel. 1684 | *
1685 | * This is a type of mode change and is also passed to the onMode 1686 | * method in the PircBot class. 1687 | *
1688 | * The implementation of this method in the PircBot abstract class 1689 | * performs no actions and may be overridden as required. 1690 | * 1691 | * @since PircBot 0.9.5 1692 | * 1693 | * @param channel The channel in which the mode change took place. 1694 | * @param sourceNick The nick of the user that performed the mode change. 1695 | * @param sourceLogin The login of the user that performed the mode change. 1696 | * @param sourceHostname The hostname of the user that performed the mode change. 1697 | * @param recipient The nick of the user that got 'opped'. 1698 | */ 1699 | protected void onOp(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} 1700 | 1701 | 1702 | /** 1703 | * Called when a user (possibly us) gets operator status taken away. 1704 | *
1705 | * This is a type of mode change and is also passed to the onMode 1706 | * method in the PircBot class. 1707 | *
1708 | * The implementation of this method in the PircBot abstract class 1709 | * performs no actions and may be overridden as required. 1710 | * 1711 | * @since PircBot 0.9.5 1712 | * 1713 | * @param channel The channel in which the mode change took place. 1714 | * @param sourceNick The nick of the user that performed the mode change. 1715 | * @param sourceLogin The login of the user that performed the mode change. 1716 | * @param sourceHostname The hostname of the user that performed the mode change. 1717 | * @param recipient The nick of the user that got 'deopped'. 1718 | */ 1719 | protected void onDeop(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} 1720 | 1721 | 1722 | /** 1723 | * Called when a user (possibly us) gets voice status granted in a channel. 1724 | *
1725 | * This is a type of mode change and is also passed to the onMode 1726 | * method in the PircBot class. 1727 | *
1728 | * The implementation of this method in the PircBot abstract class 1729 | * performs no actions and may be overridden as required. 1730 | * 1731 | * @since PircBot 0.9.5 1732 | * 1733 | * @param channel The channel in which the mode change took place. 1734 | * @param sourceNick The nick of the user that performed the mode change. 1735 | * @param sourceLogin The login of the user that performed the mode change. 1736 | * @param sourceHostname The hostname of the user that performed the mode change. 1737 | * @param recipient The nick of the user that got 'voiced'. 1738 | */ 1739 | protected void onVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} 1740 | 1741 | 1742 | /** 1743 | * Called when a user (possibly us) gets voice status removed. 1744 | *
1745 | * This is a type of mode change and is also passed to the onMode 1746 | * method in the PircBot class. 1747 | *
1748 | * The implementation of this method in the PircBot abstract class 1749 | * performs no actions and may be overridden as required. 1750 | * 1751 | * @since PircBot 0.9.5 1752 | * 1753 | * @param channel The channel in which the mode change took place. 1754 | * @param sourceNick The nick of the user that performed the mode change. 1755 | * @param sourceLogin The login of the user that performed the mode change. 1756 | * @param sourceHostname The hostname of the user that performed the mode change. 1757 | * @param recipient The nick of the user that got 'devoiced'. 1758 | */ 1759 | protected void onDeVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {} 1760 | 1761 | 1762 | /** 1763 | * Called when a channel key is set. When the channel key has been set, 1764 | * other users may only join that channel if they know the key. Channel keys 1765 | * are sometimes referred to as passwords. 1766 | *
1767 | * This is a type of mode change and is also passed to the onMode 1768 | * method in the PircBot class. 1769 | *
1770 | * The implementation of this method in the PircBot abstract class 1771 | * performs no actions and may be overridden as required. 1772 | * 1773 | * @since PircBot 0.9.5 1774 | * 1775 | * @param channel The channel in which the mode change took place. 1776 | * @param sourceNick The nick of the user that performed the mode change. 1777 | * @param sourceLogin The login of the user that performed the mode change. 1778 | * @param sourceHostname The hostname of the user that performed the mode change. 1779 | * @param key The new key for the channel. 1780 | */ 1781 | protected void onSetChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {} 1782 | 1783 | 1784 | /** 1785 | * Called when a channel key is removed. 1786 | *
1787 | * This is a type of mode change and is also passed to the onMode 1788 | * method in the PircBot class. 1789 | *
1790 | * The implementation of this method in the PircBot abstract class 1791 | * performs no actions and may be overridden as required. 1792 | * 1793 | * @since PircBot 0.9.5 1794 | * 1795 | * @param channel The channel in which the mode change took place. 1796 | * @param sourceNick The nick of the user that performed the mode change. 1797 | * @param sourceLogin The login of the user that performed the mode change. 1798 | * @param sourceHostname The hostname of the user that performed the mode change. 1799 | * @param key The key that was in use before the channel key was removed. 1800 | */ 1801 | protected void onRemoveChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {} 1802 | 1803 | 1804 | /** 1805 | * Called when a user limit is set for a channel. The number of users in 1806 | * the channel cannot exceed this limit. 1807 | *
1808 | * This is a type of mode change and is also passed to the onMode 1809 | * method in the PircBot class. 1810 | *
1811 | * The implementation of this method in the PircBot abstract class 1812 | * performs no actions and may be overridden as required. 1813 | * 1814 | * @since PircBot 0.9.5 1815 | * 1816 | * @param channel The channel in which the mode change took place. 1817 | * @param sourceNick The nick of the user that performed the mode change. 1818 | * @param sourceLogin The login of the user that performed the mode change. 1819 | * @param sourceHostname The hostname of the user that performed the mode change. 1820 | * @param limit The maximum number of users that may be in this channel at the same time. 1821 | */ 1822 | protected void onSetChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname, int limit) {} 1823 | 1824 | 1825 | /** 1826 | * Called when the user limit is removed for a channel. 1827 | *
1828 | * This is a type of mode change and is also passed to the onMode 1829 | * method in the PircBot class. 1830 | *
1831 | * The implementation of this method in the PircBot abstract class 1832 | * performs no actions and may be overridden as required. 1833 | * 1834 | * @since PircBot 0.9.5 1835 | * 1836 | * @param channel The channel in which the mode change took place. 1837 | * @param sourceNick The nick of the user that performed the mode change. 1838 | * @param sourceLogin The login of the user that performed the mode change. 1839 | * @param sourceHostname The hostname of the user that performed the mode change. 1840 | */ 1841 | protected void onRemoveChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 1842 | 1843 | 1844 | /** 1845 | * Called when a user (possibly us) gets banned from a channel. Being 1846 | * banned from a channel prevents any user with a matching hostmask from 1847 | * joining the channel. For this reason, most bans are usually directly 1848 | * followed by the user being kicked :-) 1849 | *
1850 | * This is a type of mode change and is also passed to the onMode 1851 | * method in the PircBot class. 1852 | *
1853 | * The implementation of this method in the PircBot abstract class 1854 | * performs no actions and may be overridden as required. 1855 | * 1856 | * @since PircBot 0.9.5 1857 | * 1858 | * @param channel The channel in which the mode change took place. 1859 | * @param sourceNick The nick of the user that performed the mode change. 1860 | * @param sourceLogin The login of the user that performed the mode change. 1861 | * @param sourceHostname The hostname of the user that performed the mode change. 1862 | * @param hostmask The hostmask of the user that has been banned. 1863 | */ 1864 | protected void onSetChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {} 1865 | 1866 | 1867 | /** 1868 | * Called when a hostmask ban is removed from a channel. 1869 | *
1870 | * This is a type of mode change and is also passed to the onMode 1871 | * method in the PircBot class. 1872 | *
1873 | * The implementation of this method in the PircBot abstract class 1874 | * performs no actions and may be overridden as required. 1875 | * 1876 | * @since PircBot 0.9.5 1877 | * 1878 | * @param channel The channel in which the mode change took place. 1879 | * @param sourceNick The nick of the user that performed the mode change. 1880 | * @param sourceLogin The login of the user that performed the mode change. 1881 | * @param sourceHostname The hostname of the user that performed the mode change. 1882 | * @param hostmask 1883 | */ 1884 | protected void onRemoveChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {} 1885 | 1886 | 1887 | /** 1888 | * Called when topic protection is enabled for a channel. Topic protection 1889 | * means that only operators in a channel may change the topic. 1890 | *
1891 | * This is a type of mode change and is also passed to the onMode 1892 | * method in the PircBot class. 1893 | *
1894 | * The implementation of this method in the PircBot abstract class 1895 | * performs no actions and may be overridden as required. 1896 | * 1897 | * @since PircBot 0.9.5 1898 | * 1899 | * @param channel The channel in which the mode change took place. 1900 | * @param sourceNick The nick of the user that performed the mode change. 1901 | * @param sourceLogin The login of the user that performed the mode change. 1902 | * @param sourceHostname The hostname of the user that performed the mode change. 1903 | */ 1904 | protected void onSetTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 1905 | 1906 | 1907 | /** 1908 | * Called when topic protection is removed for a channel. 1909 | *
1910 | * This is a type of mode change and is also passed to the onMode 1911 | * method in the PircBot class. 1912 | *
1913 | * The implementation of this method in the PircBot abstract class 1914 | * performs no actions and may be overridden as required. 1915 | * 1916 | * @since PircBot 0.9.5 1917 | * 1918 | * @param channel The channel in which the mode change took place. 1919 | * @param sourceNick The nick of the user that performed the mode change. 1920 | * @param sourceLogin The login of the user that performed the mode change. 1921 | * @param sourceHostname The hostname of the user that performed the mode change. 1922 | */ 1923 | protected void onRemoveTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 1924 | 1925 | 1926 | /** 1927 | * Called when a channel is set to only allow messages from users that 1928 | * are in the channel. 1929 | *
1930 | * This is a type of mode change and is also passed to the onMode 1931 | * method in the PircBot class. 1932 | *
1933 | * The implementation of this method in the PircBot abstract class 1934 | * performs no actions and may be overridden as required. 1935 | * 1936 | * @since PircBot 0.9.5 1937 | * 1938 | * @param channel The channel in which the mode change took place. 1939 | * @param sourceNick The nick of the user that performed the mode change. 1940 | * @param sourceLogin The login of the user that performed the mode change. 1941 | * @param sourceHostname The hostname of the user that performed the mode change. 1942 | */ 1943 | protected void onSetNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 1944 | 1945 | 1946 | /** 1947 | * Called when a channel is set to allow messages from any user, even 1948 | * if they are not actually in the channel. 1949 | *
1950 | * This is a type of mode change and is also passed to the onMode 1951 | * method in the PircBot class. 1952 | *
1953 | * The implementation of this method in the PircBot abstract class 1954 | * performs no actions and may be overridden as required. 1955 | * 1956 | * @since PircBot 0.9.5 1957 | * 1958 | * @param channel The channel in which the mode change took place. 1959 | * @param sourceNick The nick of the user that performed the mode change. 1960 | * @param sourceLogin The login of the user that performed the mode change. 1961 | * @param sourceHostname The hostname of the user that performed the mode change. 1962 | */ 1963 | protected void onRemoveNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 1964 | 1965 | 1966 | /** 1967 | * Called when a channel is set to 'invite only' mode. A user may only 1968 | * join the channel if they are invited by someone who is already in the 1969 | * channel. 1970 | *
1971 | * This is a type of mode change and is also passed to the onMode 1972 | * method in the PircBot class. 1973 | *
1974 | * The implementation of this method in the PircBot abstract class 1975 | * performs no actions and may be overridden as required. 1976 | * 1977 | * @since PircBot 0.9.5 1978 | * 1979 | * @param channel The channel in which the mode change took place. 1980 | * @param sourceNick The nick of the user that performed the mode change. 1981 | * @param sourceLogin The login of the user that performed the mode change. 1982 | * @param sourceHostname The hostname of the user that performed the mode change. 1983 | */ 1984 | protected void onSetInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 1985 | 1986 | 1987 | /** 1988 | * Called when a channel has 'invite only' removed. 1989 | *
1990 | * This is a type of mode change and is also passed to the onMode 1991 | * method in the PircBot class. 1992 | *
1993 | * The implementation of this method in the PircBot abstract class 1994 | * performs no actions and may be overridden as required. 1995 | * 1996 | * @since PircBot 0.9.5 1997 | * 1998 | * @param channel The channel in which the mode change took place. 1999 | * @param sourceNick The nick of the user that performed the mode change. 2000 | * @param sourceLogin The login of the user that performed the mode change. 2001 | * @param sourceHostname The hostname of the user that performed the mode change. 2002 | */ 2003 | protected void onRemoveInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 2004 | 2005 | 2006 | /** 2007 | * Called when a channel is set to 'moderated' mode. If a channel is 2008 | * moderated, then only users who have been 'voiced' or 'opped' may speak 2009 | * or change their nicks. 2010 | *
2011 | * This is a type of mode change and is also passed to the onMode 2012 | * method in the PircBot class. 2013 | *
2014 | * The implementation of this method in the PircBot abstract class 2015 | * performs no actions and may be overridden as required. 2016 | * 2017 | * @since PircBot 0.9.5 2018 | * 2019 | * @param channel The channel in which the mode change took place. 2020 | * @param sourceNick The nick of the user that performed the mode change. 2021 | * @param sourceLogin The login of the user that performed the mode change. 2022 | * @param sourceHostname The hostname of the user that performed the mode change. 2023 | */ 2024 | protected void onSetModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 2025 | 2026 | 2027 | /** 2028 | * Called when a channel has moderated mode removed. 2029 | *
2030 | * This is a type of mode change and is also passed to the onMode 2031 | * method in the PircBot class. 2032 | *
2033 | * The implementation of this method in the PircBot abstract class 2034 | * performs no actions and may be overridden as required. 2035 | * 2036 | * @since PircBot 0.9.5 2037 | * 2038 | * @param channel The channel in which the mode change took place. 2039 | * @param sourceNick The nick of the user that performed the mode change. 2040 | * @param sourceLogin The login of the user that performed the mode change. 2041 | * @param sourceHostname The hostname of the user that performed the mode change. 2042 | */ 2043 | protected void onRemoveModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 2044 | 2045 | 2046 | /** 2047 | * Called when a channel is marked as being in private mode. 2048 | *
2049 | * This is a type of mode change and is also passed to the onMode 2050 | * method in the PircBot class. 2051 | *
2052 | * The implementation of this method in the PircBot abstract class 2053 | * performs no actions and may be overridden as required. 2054 | * 2055 | * @since PircBot 0.9.5 2056 | * 2057 | * @param channel The channel in which the mode change took place. 2058 | * @param sourceNick The nick of the user that performed the mode change. 2059 | * @param sourceLogin The login of the user that performed the mode change. 2060 | * @param sourceHostname The hostname of the user that performed the mode change. 2061 | */ 2062 | protected void onSetPrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 2063 | 2064 | 2065 | /** 2066 | * Called when a channel is marked as not being in private mode. 2067 | *
2068 | * This is a type of mode change and is also passed to the onMode 2069 | * method in the PircBot class. 2070 | *
2071 | * The implementation of this method in the PircBot abstract class 2072 | * performs no actions and may be overridden as required. 2073 | * 2074 | * @since PircBot 0.9.5 2075 | * 2076 | * @param channel The channel in which the mode change took place. 2077 | * @param sourceNick The nick of the user that performed the mode change. 2078 | * @param sourceLogin The login of the user that performed the mode change. 2079 | * @param sourceHostname The hostname of the user that performed the mode change. 2080 | */ 2081 | protected void onRemovePrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 2082 | 2083 | 2084 | /** 2085 | * Called when a channel is set to be in 'secret' mode. Such channels 2086 | * typically do not appear on a server's channel listing. 2087 | *
2088 | * This is a type of mode change and is also passed to the onMode 2089 | * method in the PircBot class. 2090 | *
2091 | * The implementation of this method in the PircBot abstract class 2092 | * performs no actions and may be overridden as required. 2093 | * 2094 | * @since PircBot 0.9.5 2095 | * 2096 | * @param channel The channel in which the mode change took place. 2097 | * @param sourceNick The nick of the user that performed the mode change. 2098 | * @param sourceLogin The login of the user that performed the mode change. 2099 | * @param sourceHostname The hostname of the user that performed the mode change. 2100 | */ 2101 | protected void onSetSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 2102 | 2103 | 2104 | /** 2105 | * Called when a channel has 'secret' mode removed. 2106 | *
2107 | * This is a type of mode change and is also passed to the onMode 2108 | * method in the PircBot class. 2109 | *
2110 | * The implementation of this method in the PircBot abstract class 2111 | * performs no actions and may be overridden as required. 2112 | * 2113 | * @since PircBot 0.9.5 2114 | * 2115 | * @param channel The channel in which the mode change took place. 2116 | * @param sourceNick The nick of the user that performed the mode change. 2117 | * @param sourceLogin The login of the user that performed the mode change. 2118 | * @param sourceHostname The hostname of the user that performed the mode change. 2119 | */ 2120 | protected void onRemoveSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {} 2121 | 2122 | 2123 | /** 2124 | * Called when we are invited to a channel by a user. 2125 | *
2126 | * The implementation of this method in the PircBot abstract class 2127 | * performs no actions and may be overridden as required. 2128 | * 2129 | * @since PircBot 0.9.5 2130 | * 2131 | * @param targetNick The nick of the user being invited - should be us! 2132 | * @param sourceNick The nick of the user that sent the invitation. 2133 | * @param sourceLogin The login of the user that sent the invitation. 2134 | * @param sourceHostname The hostname of the user that sent the invitation. 2135 | * @param channel The channel that we're being invited to. 2136 | */ 2137 | protected void onInvite(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String channel) {} 2138 | 2139 | 2140 | /** 2141 | * This method used to be called when a DCC SEND request was sent to the PircBot. 2142 | * Please use the onIncomingFileTransfer method to receive files, as it 2143 | * has better functionality and supports resuming. 2144 | * 2145 | * @deprecated As of PircBot 1.2.0, use {@link #onIncomingFileTransfer(DccFileTransfer)} 2146 | */ 2147 | protected void onDccSendRequest(String sourceNick, String sourceLogin, String sourceHostname, String filename, long address, int port, int size) {} 2148 | 2149 | 2150 | /** 2151 | * This method used to be called when a DCC CHAT request was sent to the PircBot. 2152 | * Please use the onIncomingChatRequest method to accept chats, as it 2153 | * has better functionality. 2154 | * 2155 | * @deprecated As of PircBot 1.2.0, use {@link #onIncomingChatRequest(DccChat)} 2156 | */ 2157 | protected void onDccChatRequest(String sourceNick, String sourceLogin, String sourceHostname, long address, int port) {} 2158 | 2159 | 2160 | /** 2161 | * This method is called whenever a DCC SEND request is sent to the PircBot. 2162 | * This means that a client has requested to send a file to us. 2163 | * This abstract implementation performs no action, which means that all 2164 | * DCC SEND requests will be ignored by default. If you wish to receive 2165 | * the file, then you may override this method and call the receive method 2166 | * on the DccFileTransfer object, which connects to the sender and downloads 2167 | * the file. 2168 | *
2169 | * Example: 2170 | *
public void onIncomingFileTransfer(DccFileTransfer transfer) { 2171 | * // Use the suggested file name. 2172 | * File file = transfer.getFile(); 2173 | * // Receive the transfer and save it to the file, allowing resuming. 2174 | * transfer.receive(file, true); 2175 | * }2176 | *
2177 | * Warning: Receiving an incoming file transfer will cause a file 2178 | * to be written to disk. Please ensure that you make adequate security 2179 | * checks so that this file does not overwrite anything important! 2180 | *
2181 | * Each time a file is received, it happens within a new Thread 2182 | * in order to allow multiple files to be downloaded by the PircBot 2183 | * at the same time. 2184 | *
2185 | * If you allow resuming and the file already partly exists, it will 2186 | * be appended to instead of overwritten. If resuming is not enabled, 2187 | * the file will be overwritten if it already exists. 2188 | *
2189 | * You can throttle the speed of the transfer by calling the setPacketDelay 2190 | * method on the DccFileTransfer object, either before you receive the 2191 | * file or at any moment during the transfer. 2192 | *
2193 | * The implementation of this method in the PircBot abstract class 2194 | * performs no actions and may be overridden as required. 2195 | * 2196 | * @since PircBot 1.2.0 2197 | * 2198 | * @param transfer The DcccFileTransfer that you may accept. 2199 | * 2200 | * @see DccFileTransfer 2201 | * 2202 | */ 2203 | protected void onIncomingFileTransfer(DccFileTransfer transfer) {} 2204 | 2205 | 2206 | /** 2207 | * This method gets called when a DccFileTransfer has finished. 2208 | * If there was a problem, the Exception will say what went wrong. 2209 | * If the file was sent successfully, the Exception will be null. 2210 | *
2211 | * Both incoming and outgoing file transfers are passed to this method. 2212 | * You can determine the type by calling the isIncoming or isOutgoing 2213 | * methods on the DccFileTransfer object. 2214 | * 2215 | * @since PircBot 1.2.0 2216 | * 2217 | * @param transfer The DccFileTransfer that has finished. 2218 | * @param e null if the file was transfered successfully, otherwise this 2219 | * will report what went wrong. 2220 | * 2221 | * @see DccFileTransfer 2222 | * 2223 | */ 2224 | protected void onFileTransferFinished(DccFileTransfer transfer, Exception e) {} 2225 | 2226 | 2227 | /** 2228 | * This method will be called whenever a DCC Chat request is received. 2229 | * This means that a client has requested to chat to us directly rather 2230 | * than via the IRC server. This is useful for sending many lines of text 2231 | * to and from the bot without having to worry about flooding the server 2232 | * or any operators of the server being able to "spy" on what is being 2233 | * said. This abstract implementation performs no action, which means 2234 | * that all DCC CHAT requests will be ignored by default. 2235 | *
2236 | * If you wish to accept the connection, then you may override this 2237 | * method and call the accept() method on the DccChat object, which 2238 | * connects to the sender of the chat request and allows lines to be 2239 | * sent to and from the bot. 2240 | *
2241 | * Your bot must be able to connect directly to the user that sent the 2242 | * request. 2243 | *
2244 | * Example: 2245 | *
public void onIncomingChatRequest(DccChat chat) { 2246 | * try { 2247 | * // Accept all chat, whoever it's from. 2248 | * chat.accept(); 2249 | * chat.sendLine("Hello"); 2250 | * String response = chat.readLine(); 2251 | * chat.close(); 2252 | * } 2253 | * catch (IOException e) {} 2254 | * }2255 | * 2256 | * Each time this method is called, it is called from within a new Thread 2257 | * so that multiple DCC CHAT sessions can run concurrently. 2258 | *
2259 | * The implementation of this method in the PircBot abstract class 2260 | * performs no actions and may be overridden as required. 2261 | * 2262 | * @since PircBot 1.2.0 2263 | * 2264 | * @param chat A DccChat object that represents the incoming chat request. 2265 | * 2266 | * @see DccChat 2267 | * 2268 | */ 2269 | protected void onIncomingChatRequest(DccChat chat) {} 2270 | 2271 | 2272 | /** 2273 | * This method is called whenever we receive a VERSION request. 2274 | * This abstract implementation responds with the PircBot's _version string, 2275 | * so if you override this method, be sure to either mimic its functionality 2276 | * or to call super.onVersion(...); 2277 | * 2278 | * @param sourceNick The nick of the user that sent the VERSION request. 2279 | * @param sourceLogin The login of the user that sent the VERSION request. 2280 | * @param sourceHostname The hostname of the user that sent the VERSION request. 2281 | * @param target The target of the VERSION request, be it our nick or a channel name. 2282 | */ 2283 | protected void onVersion(String sourceNick, String sourceLogin, String sourceHostname, String target) { 2284 | this.sendRawLine("NOTICE " + sourceNick + " :\u0001VERSION " + _version + "\u0001"); 2285 | } 2286 | 2287 | 2288 | /** 2289 | * This method is called whenever we receive a PING request from another 2290 | * user. 2291 | *
2292 | * This abstract implementation responds correctly, so if you override this 2293 | * method, be sure to either mimic its functionality or to call 2294 | * super.onPing(...); 2295 | * 2296 | * @param sourceNick The nick of the user that sent the PING request. 2297 | * @param sourceLogin The login of the user that sent the PING request. 2298 | * @param sourceHostname The hostname of the user that sent the PING request. 2299 | * @param target The target of the PING request, be it our nick or a channel name. 2300 | * @param pingValue The value that was supplied as an argument to the PING command. 2301 | */ 2302 | protected void onPing(String sourceNick, String sourceLogin, String sourceHostname, String target, String pingValue) { 2303 | this.sendRawLine("NOTICE " + sourceNick + " :\u0001PING " + pingValue + "\u0001"); 2304 | } 2305 | 2306 | 2307 | /** 2308 | * The actions to perform when a PING request comes from the server. 2309 | *
2310 | * This sends back a correct response, so if you override this method, 2311 | * be sure to either mimic its functionality or to call 2312 | * super.onServerPing(response); 2313 | * 2314 | * @param response The response that should be given back in your PONG. 2315 | */ 2316 | protected void onServerPing(String response) { 2317 | this.sendRawLine("PONG " + response); 2318 | } 2319 | 2320 | 2321 | /** 2322 | * This method is called whenever we receive a TIME request. 2323 | *
2324 | * This abstract implementation responds correctly, so if you override this 2325 | * method, be sure to either mimic its functionality or to call 2326 | * super.onTime(...); 2327 | * 2328 | * @param sourceNick The nick of the user that sent the TIME request. 2329 | * @param sourceLogin The login of the user that sent the TIME request. 2330 | * @param sourceHostname The hostname of the user that sent the TIME request. 2331 | * @param target The target of the TIME request, be it our nick or a channel name. 2332 | */ 2333 | protected void onTime(String sourceNick, String sourceLogin, String sourceHostname, String target) { 2334 | this.sendRawLine("NOTICE " + sourceNick + " :\u0001TIME " + new Date().toString() + "\u0001"); 2335 | } 2336 | 2337 | 2338 | /** 2339 | * This method is called whenever we receive a FINGER request. 2340 | *
2341 | * This abstract implementation responds correctly, so if you override this 2342 | * method, be sure to either mimic its functionality or to call 2343 | * super.onFinger(...); 2344 | * 2345 | * @param sourceNick The nick of the user that sent the FINGER request. 2346 | * @param sourceLogin The login of the user that sent the FINGER request. 2347 | * @param sourceHostname The hostname of the user that sent the FINGER request. 2348 | * @param target The target of the FINGER request, be it our nick or a channel name. 2349 | */ 2350 | protected void onFinger(String sourceNick, String sourceLogin, String sourceHostname, String target) { 2351 | this.sendRawLine("NOTICE " + sourceNick + " :\u0001FINGER " + _finger + "\u0001"); 2352 | } 2353 | 2354 | 2355 | /** 2356 | * This method is called whenever we receive a line from the server that 2357 | * the PircBot has not been programmed to recognise. 2358 | *
2359 | * The implementation of this method in the PircBot abstract class 2360 | * performs no actions and may be overridden as required. 2361 | * 2362 | * @param line The raw line that was received from the server. 2363 | */ 2364 | protected void onUnknown(String line) { 2365 | // And then there were none :) 2366 | } 2367 | 2368 | 2369 | /** 2370 | * Sets the verbose mode. If verbose mode is set to true, then log entries 2371 | * will be printed to the standard output. The default value is false and 2372 | * will result in no output. For general development, we strongly recommend 2373 | * setting the verbose mode to true. 2374 | * 2375 | * @param verbose true if verbose mode is to be used. Default is false. 2376 | */ 2377 | public final void setVerbose(boolean verbose) { 2378 | _verbose = verbose; 2379 | } 2380 | 2381 | 2382 | /** 2383 | * Sets the name of the bot, which will be used as its nick when it 2384 | * tries to join an IRC server. This should be set before joining 2385 | * any servers, otherwise the default nick will be used. You would 2386 | * typically call this method from the constructor of the class that 2387 | * extends PircBot. 2388 | *
2389 | * The changeNick method should be used if you wish to change your nick 2390 | * when you are connected to a server. 2391 | * 2392 | * @param name The new name of the Bot. 2393 | */ 2394 | protected final void setName(String name) { 2395 | _name = name; 2396 | } 2397 | 2398 | 2399 | /** 2400 | * Sets the internal nick of the bot. This is only to be called by the 2401 | * PircBot class in response to notification of nick changes that apply 2402 | * to us. 2403 | * 2404 | * @param nick The new nick. 2405 | */ 2406 | private final void setNick(String nick) { 2407 | _nick = nick; 2408 | } 2409 | 2410 | 2411 | /** 2412 | * Sets the internal login of the Bot. This should be set before joining 2413 | * any servers. 2414 | * 2415 | * @param login The new login of the Bot. 2416 | * @deprecated As of version 1.6, replaced by {@link #setUserName} 2417 | */ 2418 | @Deprecated protected final void setLogin(String login) { 2419 | _username = login; 2420 | } 2421 | 2422 | 2423 | /** 2424 | * Sets the internal username of the Bot. This should be set before 2425 | * joining any servers. 2426 | * 2427 | * @param username The new username of the Bot. 2428 | */ 2429 | protected final void setUserName(String username) { 2430 | _username = username; 2431 | } 2432 | 2433 | 2434 | /** 2435 | * Sets the internal realname of the Bot. This should be set before 2436 | * joining any servers. 2437 | * 2438 | * @param realname The new realname of the Bot. 2439 | */ 2440 | protected final void setRealName(String realname) { 2441 | _realname = realname; 2442 | } 2443 | 2444 | 2445 | /** 2446 | * Sets the internal version of the Bot. This should be set before joining 2447 | * any servers. 2448 | * 2449 | * @param version The new version of the Bot. 2450 | */ 2451 | protected final void setVersion(String version) { 2452 | _version = version; 2453 | } 2454 | 2455 | 2456 | /** 2457 | * Sets the interal finger message. This should be set before joining 2458 | * any servers. 2459 | * 2460 | * @param finger The new finger message for the Bot. 2461 | */ 2462 | protected final void setFinger(String finger) { 2463 | _finger = finger; 2464 | } 2465 | 2466 | 2467 | /** 2468 | * Gets the name of the PircBot. This is the name that will be used as 2469 | * as a nick when we try to join servers. 2470 | * 2471 | * @return The name of the PircBot. 2472 | */ 2473 | public final String getName() { 2474 | return _name; 2475 | } 2476 | 2477 | 2478 | /** 2479 | * Returns the current nick of the bot. Note that if you have just changed 2480 | * your nick, this method will still return the old nick until confirmation 2481 | * of the nick change is received from the server. 2482 | *
2483 | * The nick returned by this method is maintained only by the PircBot
2484 | * class and is guaranteed to be correct in the context of the IRC server.
2485 | *
2486 | * @since PircBot 1.0.0
2487 | *
2488 | * @return The current nick of the bot.
2489 | */
2490 | public String getNick() {
2491 | return _nick;
2492 | }
2493 |
2494 |
2495 | /**
2496 | * Gets the internal login of the PircBot.
2497 | *
2498 | * @return The login of the PircBot.
2499 | * @deprecated As of version 1.6, replaced by {@link #getUserName()}
2500 | */
2501 | @Deprecated public final String getLogin() {
2502 | return _username;
2503 | }
2504 |
2505 |
2506 | /**
2507 | * Gets the internal username of the PircBot.
2508 | *
2509 | * @return The username of the PircBot.
2510 | */
2511 | public final String getUserName() {
2512 | return _username;
2513 | }
2514 |
2515 |
2516 | /**
2517 | * Gets the internal realname of the PircBot.
2518 | *
2519 | * @return The realname of the PircBot.
2520 | */
2521 | public final String getRealName() {
2522 | return _realname;
2523 | }
2524 |
2525 |
2526 | /**
2527 | * Gets the internal version of the PircBot.
2528 | *
2529 | * @return The version of the PircBot.
2530 | */
2531 | public final String getVersion() {
2532 | return _version;
2533 | }
2534 |
2535 |
2536 | /**
2537 | * Gets the internal finger message of the PircBot.
2538 | *
2539 | * @return The finger message of the PircBot.
2540 | */
2541 | public final String getFinger() {
2542 | return _finger;
2543 | }
2544 |
2545 |
2546 | /**
2547 | * Returns whether or not the PircBot is currently connected to a server.
2548 | * The result of this method should only act as a rough guide,
2549 | * as the result may not be valid by the time you act upon it.
2550 | *
2551 | * @return True if and only if the PircBot is currently connected to a server.
2552 | */
2553 | public final synchronized boolean isConnected() {
2554 | return _inputThread != null && _inputThread.isConnected();
2555 | }
2556 |
2557 |
2558 | /**
2559 | * Sets the number of milliseconds to delay between consecutive
2560 | * messages when there are multiple messages waiting in the
2561 | * outgoing message queue. This has a default value of 1000ms.
2562 | * It is a good idea to stick to this default value, as it will
2563 | * prevent your bot from spamming servers and facing the subsequent
2564 | * wrath! However, if you do need to change this delay value (not
2565 | * recommended), then this is the method to use.
2566 | *
2567 | * @param delay The number of milliseconds between each outgoing message.
2568 | *
2569 | */
2570 | public final void setMessageDelay(long delay) {
2571 | if (delay < 0) {
2572 | throw new IllegalArgumentException("Cannot have a negative time.");
2573 | }
2574 | _messageDelay = delay;
2575 | }
2576 |
2577 |
2578 | /**
2579 | * Returns the number of milliseconds that will be used to separate
2580 | * consecutive messages to the server from the outgoing message queue.
2581 | *
2582 | * @return Number of milliseconds.
2583 | */
2584 | public final long getMessageDelay() {
2585 | return _messageDelay;
2586 | }
2587 |
2588 |
2589 | /**
2590 | * Gets the maximum length of any line that is sent via the IRC protocol.
2591 | * The IRC RFC specifies that line lengths, including the trailing \r\n
2592 | * must not exceed 512 bytes. Hence, there is currently no option to
2593 | * change this value in PircBot. All lines greater than this length
2594 | * will be truncated before being sent to the IRC server.
2595 | *
2596 | * @return The maximum line length (currently fixed at 512)
2597 | */
2598 | public final int getMaxLineLength() {
2599 | return InputThread.MAX_LINE_LENGTH;
2600 | }
2601 |
2602 |
2603 | /**
2604 | * Gets the number of lines currently waiting in the outgoing message Queue.
2605 | * If this returns 0, then the Queue is empty and any new message is likely
2606 | * to be sent to the IRC server immediately.
2607 | *
2608 | * @since PircBot 0.9.9
2609 | *
2610 | * @return The number of lines in the outgoing message Queue.
2611 | */
2612 | public final int getOutgoingQueueSize() {
2613 | return _outQueue.size();
2614 | }
2615 |
2616 |
2617 | /**
2618 | * Returns the name of the last IRC server the PircBot tried to connect to.
2619 | * This does not imply that the connection attempt to the server was
2620 | * successful (we suggest you look at the onConnect method).
2621 | * A value of null is returned if the PircBot has never tried to connect
2622 | * to a server.
2623 | *
2624 | * @return The name of the last machine we tried to connect to. Returns
2625 | * null if no connection attempts have ever been made.
2626 | */
2627 | public final String getServer() {
2628 | if (_connectionSettings == null)
2629 | return null;
2630 | return _connectionSettings.server;
2631 | }
2632 |
2633 |
2634 | /**
2635 | * Returns the port number of the last IRC server that the PircBot tried
2636 | * to connect to.
2637 | * This does not imply that the connection attempt to the server was
2638 | * successful (we suggest you look at the onConnect method).
2639 | * A value of -1 is returned if the PircBot has never tried to connect
2640 | * to a server.
2641 | *
2642 | * @since PircBot 0.9.9
2643 | *
2644 | * @return The port number of the last IRC server we connected to.
2645 | * Returns -1 if no connection attempts have ever been made.
2646 | */
2647 | public final int getPort() {
2648 | if (_connectionSettings == null)
2649 | return -1;
2650 | return _connectionSettings.port;
2651 | }
2652 |
2653 | /**
2654 | * Returns whether PircBot used SSL with the last IRC server that
2655 | * it tried to connect to.
2656 | *
2657 | * @since PircBot 1.6
2658 | *
2659 | * @return Whether SSL was used in the last connection attempt.
2660 | * Returns false if no connection attempts have ever been made.
2661 | */
2662 | public final boolean useSSL() {
2663 | if (_connectionSettings == null)
2664 | return false;
2665 | return _connectionSettings.useSSL;
2666 | }
2667 |
2668 | /**
2669 | * Returns the last password that we used when connecting to an IRC server.
2670 | * This does not imply that the connection attempt to the server was
2671 | * successful (we suggest you look at the onConnect method).
2672 | * A value of null is returned if the PircBot has never tried to connect
2673 | * to a server using a password.
2674 | *
2675 | * @since PircBot 0.9.9
2676 | *
2677 | * @return The last password that we used when connecting to an IRC server.
2678 | * Returns null if we have not previously connected using a password.
2679 | */
2680 | public final String getPassword() {
2681 | if (_connectionSettings == null)
2682 | return null;
2683 | return _connectionSettings.password;
2684 | }
2685 |
2686 |
2687 | /**
2688 | * A convenient method that accepts an IP address represented as a
2689 | * long and returns an integer array of size 4 representing the same
2690 | * IP address.
2691 | *
2692 | * @since PircBot 0.9.4
2693 | *
2694 | * @param address the long value representing the IP address.
2695 | *
2696 | * @return An int[] of size 4.
2697 | */
2698 | public int[] longToIp(long address) {
2699 | int[] ip = new int[4];
2700 | for (int i = 3; i >= 0; i--) {
2701 | ip[i] = (int) (address % 256);
2702 | address = address / 256;
2703 | }
2704 | return ip;
2705 | }
2706 |
2707 |
2708 | /**
2709 | * A convenient method that accepts an IP address represented by a byte[]
2710 | * of size 4 and returns this as a long representation of the same IP
2711 | * address.
2712 | *
2713 | * @since PircBot 0.9.4
2714 | *
2715 | * @param address the byte[] of size 4 representing the IP address.
2716 | *
2717 | * @return a long representation of the IP address.
2718 | */
2719 | public long ipToLong(byte[] address) {
2720 | if (address.length != 4) {
2721 | throw new IllegalArgumentException("byte array must be of length 4");
2722 | }
2723 | long ipNum = 0;
2724 | long multiplier = 1;
2725 | for (int i = 3; i >= 0; i--) {
2726 | int byteVal = (address[i] + 256) % 256;
2727 | ipNum += byteVal*multiplier;
2728 | multiplier *= 256;
2729 | }
2730 | return ipNum;
2731 | }
2732 |
2733 |
2734 | /**
2735 | * Sets the encoding charset to be used when sending or receiving lines
2736 | * from the IRC server. If set to null, then the platform's default
2737 | * charset is used. You should only use this method if you are
2738 | * trying to send text to an IRC server in a different charset, e.g.
2739 | * "GB2312" for Chinese encoding. If a PircBot is currently connected
2740 | * to a server, then it must reconnect before this change takes effect.
2741 | *
2742 | * @since PircBot 1.0.4
2743 | *
2744 | * @param charset The new encoding charset to be used by PircBot.
2745 | *
2746 | * @throws UnsupportedEncodingException If the named charset is not
2747 | * supported.
2748 | */
2749 | public void setEncoding(String charset) throws UnsupportedEncodingException {
2750 | // Just try to see if the charset is supported first...
2751 | "".getBytes(charset);
2752 |
2753 | _charset = charset;
2754 | }
2755 |
2756 |
2757 | /**
2758 | * Returns the encoding used to send and receive lines from
2759 | * the IRC server, or null if not set. Use the setEncoding
2760 | * method to change the encoding charset.
2761 | *
2762 | * @since PircBot 1.0.4
2763 | *
2764 | * @return The encoding used to send outgoing messages, or
2765 | * null if not set.
2766 | */
2767 | public String getEncoding() {
2768 | return _charset;
2769 | }
2770 |
2771 | /**
2772 | * Returns the InetAddress used by the PircBot.
2773 | * This can be used to find the I.P. address from which the PircBot is
2774 | * connected to a server.
2775 | *
2776 | * @since PircBot 1.4.4
2777 | *
2778 | * @return The current local InetAddress, or null if never connected.
2779 | */
2780 | public InetAddress getInetAddress() {
2781 | return _inetAddress;
2782 | }
2783 |
2784 |
2785 | /**
2786 | * Sets the InetAddress to be used when sending DCC chat or file transfers.
2787 | * This can be very useful when you are running a bot on a machine which
2788 | * is behind a firewall and you need to tell receiving clients to connect
2789 | * to a NAT/router, which then forwards the connection.
2790 | *
2791 | * @since PircBot 1.4.4
2792 | *
2793 | * @param dccInetAddress The new InetAddress, or null to use the default.
2794 | */
2795 | public void setDccInetAddress(InetAddress dccInetAddress) {
2796 | _dccInetAddress = dccInetAddress;
2797 | }
2798 |
2799 |
2800 | /**
2801 | * Returns the InetAddress used when sending DCC chat or file transfers.
2802 | * If this is null, the default InetAddress will be used.
2803 | *
2804 | * @since PircBot 1.4.4
2805 | *
2806 | * @return The current DCC InetAddress, or null if left as default.
2807 | */
2808 | public InetAddress getDccInetAddress() {
2809 | return _dccInetAddress;
2810 | }
2811 |
2812 |
2813 | /**
2814 | * Returns the set of port numbers to be used when sending a DCC chat
2815 | * or file transfer. This is useful when you are behind a firewall and
2816 | * need to set up port forwarding. The array of port numbers is traversed
2817 | * in sequence until a free port is found to listen on. A DCC tranfer will
2818 | * fail if all ports are already in use.
2819 | * If set to null, any free port number will be used.
2820 | *
2821 | * @since PircBot 1.4.4
2822 | *
2823 | * @return An array of port numbers that PircBot can use to send DCC
2824 | * transfers, or null if any port is allowed.
2825 | */
2826 | public int[] getDccPorts() {
2827 | if (_dccPorts == null || _dccPorts.length == 0) {
2828 | return null;
2829 | }
2830 | // Clone the array to prevent external modification.
2831 | return (int[]) _dccPorts.clone();
2832 | }
2833 |
2834 |
2835 | /**
2836 | * Sets the choice of port numbers that can be used when sending a DCC chat
2837 | * or file transfer. This is useful when you are behind a firewall and
2838 | * need to set up port forwarding. The array of port numbers is traversed
2839 | * in sequence until a free port is found to listen on. A DCC tranfer will
2840 | * fail if all ports are already in use.
2841 | * If set to null, any free port number will be used.
2842 | *
2843 | * @since PircBot 1.4.4
2844 | *
2845 | * @param ports The set of port numbers that PircBot may use for DCC
2846 | * transfers, or null to let it use any free port (default).
2847 | *
2848 | */
2849 | public void setDccPorts(int[] ports) {
2850 | if (ports == null || ports.length == 0) {
2851 | _dccPorts = null;
2852 | }
2853 | else {
2854 | // Clone the array to prevent external modification.
2855 | _dccPorts = (int[]) ports.clone();
2856 | }
2857 | }
2858 |
2859 |
2860 | /**
2861 | * Returns true if and only if the object being compared is the exact
2862 | * same instance as this PircBot. This may be useful if you are writing
2863 | * a multiple server IRC bot that uses more than one instance of PircBot.
2864 | *
2865 | * @since PircBot 0.9.9
2866 | *
2867 | * @return true if and only if Object o is a PircBot and equal to this.
2868 | */
2869 | public boolean equals(Object o) {
2870 | // This probably has the same effect as Object.equals, but that may change...
2871 | if (o instanceof PircBot) {
2872 | PircBot other = (PircBot) o;
2873 | return other == this;
2874 | }
2875 | return false;
2876 | }
2877 |
2878 |
2879 | /**
2880 | * Returns the hashCode of this PircBot. This method can be called by hashed
2881 | * collection classes and is useful for managing multiple instances of
2882 | * PircBots in such collections.
2883 | *
2884 | * @since PircBot 0.9.9
2885 | *
2886 | * @return the hash code for this instance of PircBot.
2887 | */
2888 | public int hashCode() {
2889 | return super.hashCode();
2890 | }
2891 |
2892 |
2893 | /**
2894 | * Returns a String representation of this object.
2895 | * You may find this useful for debugging purposes, particularly
2896 | * if you are using more than one PircBot instance to achieve
2897 | * multiple server connectivity. The format of
2898 | * this String may change between different versions of PircBot
2899 | * but is currently something of the form
2900 | *
2901 | * Version{PircBot x.y.z Java IRC Bot - www.jibble.org}
2902 | * Connected{true}
2903 | * Server{irc.dal.net}
2904 | * Port{6667}
2905 | * Password{}
2906 | *
2907 | *
2908 | * @since PircBot 0.9.10
2909 | *
2910 | * @return a String representation of this object.
2911 | */
2912 | public String toString() {
2913 | return "Version{" + getVersion() + "}" +
2914 | " Connected{" + isConnected() + "}" +
2915 | " Server{" + getServer() + "}" +
2916 | " Port{" + getPort() + "}" +
2917 | " Password{" + getPassword() + "}";
2918 | }
2919 |
2920 |
2921 | /**
2922 | * Returns an array of all users in the specified channel.
2923 | *
2924 | * There are some important things to note about this method:- 2925 | *
3000 | * Each PircBot runs its own threads for dispatching messages from its 3001 | * outgoing message queue and receiving messages from the server. 3002 | * Calling dispose() ensures that these threads are 3003 | * stopped, thus freeing up system resources and allowing the PircBot 3004 | * object to be garbage collected if there are no other references to 3005 | * it. 3006 | *
3007 | * Once a PircBot object has been disposed, it should not be used again. 3008 | * Attempting to use a PircBot that has been disposed may result in 3009 | * unpredictable behaviour. 3010 | * 3011 | * @since 1.2.2 3012 | */ 3013 | public synchronized void dispose() { 3014 | //System.out.println("disposing..."); 3015 | _outputThread.interrupt(); 3016 | _inputThread.dispose(); 3017 | } 3018 | 3019 | 3020 | /** 3021 | * Add a user to the specified channel in our memory. 3022 | * Overwrite the existing entry if it exists. 3023 | */ 3024 | private final void addUser(String channel, User user) { 3025 | channel = channel.toLowerCase(); 3026 | synchronized (_channels) { 3027 | Hashtable users = (Hashtable) _channels.get(channel); 3028 | if (users == null) { 3029 | users = new Hashtable(); 3030 | _channels.put(channel, users); 3031 | } 3032 | users.put(user, user); 3033 | } 3034 | } 3035 | 3036 | 3037 | /** 3038 | * Remove a user from the specified channel in our memory. 3039 | */ 3040 | private final User removeUser(String channel, String nick) { 3041 | channel = channel.toLowerCase(); 3042 | User user = new User("", nick); 3043 | synchronized (_channels) { 3044 | Hashtable users = (Hashtable) _channels.get(channel); 3045 | if (users != null) { 3046 | return (User) users.remove(user); 3047 | } 3048 | } 3049 | return null; 3050 | } 3051 | 3052 | 3053 | /** 3054 | * Remove a user from all channels in our memory. 3055 | */ 3056 | private final void removeUser(String nick) { 3057 | synchronized (_channels) { 3058 | Enumeration enumeration = _channels.keys(); 3059 | while (enumeration.hasMoreElements()) { 3060 | String channel = (String) enumeration.nextElement(); 3061 | this.removeUser(channel, nick); 3062 | } 3063 | } 3064 | } 3065 | 3066 | 3067 | /** 3068 | * Rename a user if they appear in any of the channels we know about. 3069 | */ 3070 | private final void renameUser(String oldNick, String newNick) { 3071 | synchronized (_channels) { 3072 | Enumeration enumeration = _channels.keys(); 3073 | while (enumeration.hasMoreElements()) { 3074 | String channel = (String) enumeration.nextElement(); 3075 | User user = this.removeUser(channel, oldNick); 3076 | if (user != null) { 3077 | user = new User(user.getPrefix(), newNick); 3078 | this.addUser(channel, user); 3079 | } 3080 | } 3081 | } 3082 | } 3083 | 3084 | 3085 | /** 3086 | * Removes an entire channel from our memory of users. 3087 | */ 3088 | private final void removeChannel(String channel) { 3089 | channel = channel.toLowerCase(); 3090 | synchronized (_channels) { 3091 | _channels.remove(channel); 3092 | } 3093 | } 3094 | 3095 | 3096 | /** 3097 | * Removes all channels from our memory of users. 3098 | */ 3099 | private final void removeAllChannels() { 3100 | synchronized(_channels) { 3101 | _channels = new Hashtable(); 3102 | } 3103 | } 3104 | 3105 | 3106 | private final void updateUser(String channel, int userMode, String nick) { 3107 | channel = channel.toLowerCase(); 3108 | synchronized (_channels) { 3109 | Hashtable users = (Hashtable) _channels.get(channel); 3110 | User newUser = null; 3111 | if (users != null) { 3112 | Enumeration enumeration = users.elements(); 3113 | while(enumeration.hasMoreElements()) { 3114 | User userObj = (User) enumeration.nextElement(); 3115 | if (userObj.getNick().equalsIgnoreCase(nick)) { 3116 | if (userMode == OP_ADD) { 3117 | if (userObj.hasVoice()) { 3118 | newUser = new User("@+", nick); 3119 | } 3120 | else { 3121 | newUser = new User("@", nick); 3122 | } 3123 | } 3124 | else if (userMode == OP_REMOVE) { 3125 | if(userObj.hasVoice()) { 3126 | newUser = new User("+", nick); 3127 | } 3128 | else { 3129 | newUser = new User("", nick); 3130 | } 3131 | } 3132 | else if (userMode == VOICE_ADD) { 3133 | if(userObj.isOp()) { 3134 | newUser = new User("@+", nick); 3135 | } 3136 | else { 3137 | newUser = new User("+", nick); 3138 | } 3139 | } 3140 | else if (userMode == VOICE_REMOVE) { 3141 | if(userObj.isOp()) { 3142 | newUser = new User("@", nick); 3143 | } 3144 | else { 3145 | newUser = new User("", nick); 3146 | } 3147 | } 3148 | } 3149 | } 3150 | } 3151 | if (newUser != null) { 3152 | users.put(newUser, newUser); 3153 | } 3154 | else { 3155 | // just in case ... 3156 | newUser = new User("", nick); 3157 | users.put(newUser, newUser); 3158 | } 3159 | } 3160 | } 3161 | 3162 | 3163 | // Connection stuff. 3164 | private InputThread _inputThread = null; 3165 | private OutputThread _outputThread = null; 3166 | private String _charset = null; 3167 | private InetAddress _inetAddress = null; 3168 | 3169 | // Details about the last server that we connected to. 3170 | private ConnectionSettings _connectionSettings = null; 3171 | 3172 | // Outgoing message stuff. 3173 | private Queue _outQueue = new Queue(); 3174 | private long _messageDelay = 1000; 3175 | 3176 | // A Hashtable of channels that points to a selfreferential Hashtable of 3177 | // User objects (used to remember which users are in which channels). 3178 | private Hashtable _channels = new Hashtable(); 3179 | 3180 | // A Hashtable to temporarily store channel topics when we join them 3181 | // until we find out who set that topic. 3182 | private Hashtable _topics = new Hashtable(); 3183 | 3184 | // DccManager to process and handle all DCC events. 3185 | private DccManager _dccManager = new DccManager(this); 3186 | private int[] _dccPorts = null; 3187 | private InetAddress _dccInetAddress = null; 3188 | 3189 | // Default settings for the PircBot. 3190 | private boolean _autoNickChange = false; 3191 | private boolean _verbose = false; 3192 | private String _name = "PircBot"; 3193 | private String _nick = _name; 3194 | private String _username = "PircBot"; 3195 | private String _realname = "PircBot"; 3196 | private String _version = "PircBot " + VERSION + " Java IRC Bot - www.jibble.org"; 3197 | private String _finger = "You ought to be arrested for fingering a bot!"; 3198 | 3199 | private String _channelPrefixes = "#&+!"; 3200 | } 3201 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/Queue.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | import java.util.Vector; 18 | 19 | /** 20 | * Queue is a definition of a data structure that may 21 | * act as a queue - that is, data can be added to one end of the 22 | * queue and data can be requested from the head end of the queue. 23 | * This class is thread safe for multiple producers and a single 24 | * consumer. The next() method will block until there is data in 25 | * the queue. 26 | * 27 | * This has now been modified so that it is compatible with 28 | * the earlier JDK1.1 in order to be suitable for running on 29 | * mobile appliances. This means replacing the LinkedList with 30 | * a Vector, which is hardly ideal, but this Queue is typically 31 | * only polled every second before dispatching messages. 32 | * 33 | * @author Paul James Mutton, 34 | * http://www.jibble.org/ 35 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 36 | */ 37 | public class Queue { 38 | 39 | 40 | /** 41 | * Constructs a Queue object of unlimited size. 42 | */ 43 | public Queue() { 44 | 45 | } 46 | 47 | 48 | /** 49 | * Adds an Object to the end of the Queue. 50 | * 51 | * @param o The Object to be added to the Queue. 52 | */ 53 | public void add(Object o) { 54 | synchronized(_queue) { 55 | _queue.addElement(o); 56 | _queue.notify(); 57 | } 58 | } 59 | 60 | 61 | /** 62 | * Adds an Object to the front of the Queue. 63 | * 64 | * @param o The Object to be added to the Queue. 65 | */ 66 | public void addFront(Object o) { 67 | synchronized(_queue) { 68 | _queue.insertElementAt(o, 0); 69 | _queue.notify(); 70 | } 71 | } 72 | 73 | 74 | /** 75 | * Returns the Object at the front of the Queue. This 76 | * Object is then removed from the Queue. If the Queue 77 | * is empty, then this method shall block until there 78 | * is an Object in the Queue to return. 79 | * 80 | * @return The next item from the front of the queue. 81 | */ 82 | public Object next() { 83 | 84 | Object o = null; 85 | 86 | // Block if the Queue is empty. 87 | synchronized(_queue) { 88 | if (_queue.size() == 0) { 89 | try { 90 | _queue.wait(); 91 | } 92 | catch (InterruptedException e) { 93 | return null; 94 | } 95 | } 96 | 97 | // Return the Object. 98 | try { 99 | o = _queue.firstElement(); 100 | _queue.removeElementAt(0); 101 | } 102 | catch (ArrayIndexOutOfBoundsException e) { 103 | throw new InternalError("Race hazard in Queue object."); 104 | } 105 | } 106 | 107 | return o; 108 | } 109 | 110 | 111 | /** 112 | * Returns true if the Queue is not empty. If another 113 | * Thread empties the Queue before next() is 114 | * called, then the call to next() shall block 115 | * until the Queue has been populated again. 116 | * 117 | * @return True only if the Queue not empty. 118 | */ 119 | public boolean hasNext() { 120 | return (this.size() != 0); 121 | } 122 | 123 | 124 | /** 125 | * Clears the contents of the Queue. 126 | */ 127 | public void clear() { 128 | synchronized(_queue) { 129 | _queue.removeAllElements(); 130 | } 131 | } 132 | 133 | 134 | /** 135 | * Returns the size of the Queue. 136 | * 137 | * @return The current size of the queue. 138 | */ 139 | public int size() { 140 | return _queue.size(); 141 | } 142 | 143 | 144 | private Vector _queue = new Vector(); 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/ReplyConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | 15 | package org.jibble.pircbot; 16 | 17 | /** 18 | * This interface contains the values of all numeric replies specified 19 | * in section 6 of RFC 1459. Refer to RFC 1459 for further information. 20 | *
21 | * If you override the onServerResponse method in the PircBot class, 22 | * you may find these constants useful when comparing the numeric 23 | * value of a given code. 24 | * 25 | * @since 1.0.0 26 | * @author Paul James Mutton, 27 | * http://www.jibble.org/ 28 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 29 | */ 30 | public interface ReplyConstants { 31 | 32 | 33 | // Error Replies. 34 | public static final int ERR_NOSUCHNICK = 401; 35 | public static final int ERR_NOSUCHSERVER = 402; 36 | public static final int ERR_NOSUCHCHANNEL = 403; 37 | public static final int ERR_CANNOTSENDTOCHAN = 404; 38 | public static final int ERR_TOOMANYCHANNELS = 405; 39 | public static final int ERR_WASNOSUCHNICK = 406; 40 | public static final int ERR_TOOMANYTARGETS = 407; 41 | public static final int ERR_NOORIGIN = 409; 42 | public static final int ERR_NORECIPIENT = 411; 43 | public static final int ERR_NOTEXTTOSEND = 412; 44 | public static final int ERR_NOTOPLEVEL = 413; 45 | public static final int ERR_WILDTOPLEVEL = 414; 46 | public static final int ERR_UNKNOWNCOMMAND = 421; 47 | public static final int ERR_NOMOTD = 422; 48 | public static final int ERR_NOADMININFO = 423; 49 | public static final int ERR_FILEERROR = 424; 50 | public static final int ERR_NONICKNAMEGIVEN = 431; 51 | public static final int ERR_ERRONEUSNICKNAME = 432; 52 | public static final int ERR_NICKNAMEINUSE = 433; 53 | public static final int ERR_NICKCOLLISION = 436; 54 | public static final int ERR_USERNOTINCHANNEL = 441; 55 | public static final int ERR_NOTONCHANNEL = 442; 56 | public static final int ERR_USERONCHANNEL = 443; 57 | public static final int ERR_NOLOGIN = 444; 58 | public static final int ERR_SUMMONDISABLED = 445; 59 | public static final int ERR_USERSDISABLED = 446; 60 | public static final int ERR_NOTREGISTERED = 451; 61 | public static final int ERR_NEEDMOREPARAMS = 461; 62 | public static final int ERR_ALREADYREGISTRED = 462; 63 | public static final int ERR_NOPERMFORHOST = 463; 64 | public static final int ERR_PASSWDMISMATCH = 464; 65 | public static final int ERR_YOUREBANNEDCREEP = 465; 66 | public static final int ERR_KEYSET = 467; 67 | public static final int ERR_CHANNELISFULL = 471; 68 | public static final int ERR_UNKNOWNMODE = 472; 69 | public static final int ERR_INVITEONLYCHAN = 473; 70 | public static final int ERR_BANNEDFROMCHAN = 474; 71 | public static final int ERR_BADCHANNELKEY = 475; 72 | public static final int ERR_NOPRIVILEGES = 481; 73 | public static final int ERR_CHANOPRIVSNEEDED = 482; 74 | public static final int ERR_CANTKILLSERVER = 483; 75 | public static final int ERR_NOOPERHOST = 491; 76 | public static final int ERR_UMODEUNKNOWNFLAG = 501; 77 | public static final int ERR_USERSDONTMATCH = 502; 78 | 79 | 80 | // Command Responses. 81 | public static final int RPL_TRACELINK = 200; 82 | public static final int RPL_TRACECONNECTING = 201; 83 | public static final int RPL_TRACEHANDSHAKE = 202; 84 | public static final int RPL_TRACEUNKNOWN = 203; 85 | public static final int RPL_TRACEOPERATOR = 204; 86 | public static final int RPL_TRACEUSER = 205; 87 | public static final int RPL_TRACESERVER = 206; 88 | public static final int RPL_TRACENEWTYPE = 208; 89 | public static final int RPL_STATSLINKINFO = 211; 90 | public static final int RPL_STATSCOMMANDS = 212; 91 | public static final int RPL_STATSCLINE = 213; 92 | public static final int RPL_STATSNLINE = 214; 93 | public static final int RPL_STATSILINE = 215; 94 | public static final int RPL_STATSKLINE = 216; 95 | public static final int RPL_STATSYLINE = 218; 96 | public static final int RPL_ENDOFSTATS = 219; 97 | public static final int RPL_UMODEIS = 221; 98 | public static final int RPL_STATSLLINE = 241; 99 | public static final int RPL_STATSUPTIME = 242; 100 | public static final int RPL_STATSOLINE = 243; 101 | public static final int RPL_STATSHLINE = 244; 102 | public static final int RPL_LUSERCLIENT = 251; 103 | public static final int RPL_LUSEROP = 252; 104 | public static final int RPL_LUSERUNKNOWN = 253; 105 | public static final int RPL_LUSERCHANNELS = 254; 106 | public static final int RPL_LUSERME = 255; 107 | public static final int RPL_ADMINME = 256; 108 | public static final int RPL_ADMINLOC1 = 257; 109 | public static final int RPL_ADMINLOC2 = 258; 110 | public static final int RPL_ADMINEMAIL = 259; 111 | public static final int RPL_TRACELOG = 261; 112 | public static final int RPL_NONE = 300; 113 | public static final int RPL_AWAY = 301; 114 | public static final int RPL_USERHOST = 302; 115 | public static final int RPL_ISON = 303; 116 | public static final int RPL_UNAWAY = 305; 117 | public static final int RPL_NOWAWAY = 306; 118 | public static final int RPL_WHOISUSER = 311; 119 | public static final int RPL_WHOISSERVER = 312; 120 | public static final int RPL_WHOISOPERATOR = 313; 121 | public static final int RPL_WHOWASUSER = 314; 122 | public static final int RPL_ENDOFWHO = 315; 123 | public static final int RPL_WHOISIDLE = 317; 124 | public static final int RPL_ENDOFWHOIS = 318; 125 | public static final int RPL_WHOISCHANNELS = 319; 126 | public static final int RPL_LISTSTART = 321; 127 | public static final int RPL_LIST = 322; 128 | public static final int RPL_LISTEND = 323; 129 | public static final int RPL_CHANNELMODEIS = 324; 130 | public static final int RPL_NOTOPIC = 331; 131 | public static final int RPL_TOPIC = 332; 132 | public static final int RPL_TOPICINFO = 333; 133 | public static final int RPL_INVITING = 341; 134 | public static final int RPL_SUMMONING = 342; 135 | public static final int RPL_VERSION = 351; 136 | public static final int RPL_WHOREPLY = 352; 137 | public static final int RPL_NAMREPLY = 353; 138 | public static final int RPL_LINKS = 364; 139 | public static final int RPL_ENDOFLINKS = 365; 140 | public static final int RPL_ENDOFNAMES = 366; 141 | public static final int RPL_BANLIST = 367; 142 | public static final int RPL_ENDOFBANLIST = 368; 143 | public static final int RPL_ENDOFWHOWAS = 369; 144 | public static final int RPL_INFO = 371; 145 | public static final int RPL_MOTD = 372; 146 | public static final int RPL_ENDOFINFO = 374; 147 | public static final int RPL_MOTDSTART = 375; 148 | public static final int RPL_ENDOFMOTD = 376; 149 | public static final int RPL_YOUREOPER = 381; 150 | public static final int RPL_REHASHING = 382; 151 | public static final int RPL_TIME = 391; 152 | public static final int RPL_USERSSTART = 392; 153 | public static final int RPL_USERS = 393; 154 | public static final int RPL_ENDOFUSERS = 394; 155 | public static final int RPL_NOUSERS = 395; 156 | 157 | 158 | // Reserved Numerics. 159 | public static final int RPL_TRACECLASS = 209; 160 | public static final int RPL_STATSQLINE = 217; 161 | public static final int RPL_SERVICEINFO = 231; 162 | public static final int RPL_ENDOFSERVICES = 232; 163 | public static final int RPL_SERVICE = 233; 164 | public static final int RPL_SERVLIST = 234; 165 | public static final int RPL_SERVLISTEND = 235; 166 | public static final int RPL_WHOISCHANOP = 316; 167 | public static final int RPL_KILLDONE = 361; 168 | public static final int RPL_CLOSING = 362; 169 | public static final int RPL_CLOSEEND = 363; 170 | public static final int RPL_INFOSTART = 373; 171 | public static final int RPL_MYPORTIS = 384; 172 | public static final int ERR_YOUWILLBEBANNED = 466; 173 | public static final int ERR_BADCHANMASK = 476; 174 | public static final int ERR_NOSERVICEHOST = 492; 175 | 176 | } 177 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/UnverifiedSSL.java: -------------------------------------------------------------------------------- 1 | /* 2 | Author: David Lazar 3 | */ 4 | package org.jibble.pircbot; 5 | 6 | import javax.net.ssl.*; 7 | import java.security.cert.X509Certificate; 8 | 9 | public class UnverifiedSSL { 10 | public static SSLContext getUnverifiedSSLContext() throws Exception { 11 | TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { 12 | public java.security.cert.X509Certificate[] getAcceptedIssuers() { 13 | return null; 14 | } 15 | 16 | public void checkClientTrusted(X509Certificate[] certs, String authType) { 17 | } 18 | 19 | public void checkServerTrusted(X509Certificate[] certs, String authType) { 20 | } 21 | } 22 | }; 23 | 24 | HostnameVerifier allHostsValid = new HostnameVerifier() { 25 | public boolean verify(String hostname, SSLSession session) { 26 | return true; 27 | } 28 | }; 29 | 30 | SSLContext sc = SSLContext.getInstance("SSL"); 31 | sc.init(null, trustAllCerts, new java.security.SecureRandom()); 32 | return sc; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/jibble/pircbot/User.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Paul James Mutton, 2001-2009, http://www.jibble.org/ 3 | 4 | This file is part of PircBot. 5 | 6 | This software is dual-licensed, allowing you to choose between the GNU 7 | General Public License (GPL) and the www.jibble.org Commercial License. 8 | Since the GPL may be too restrictive for use in a proprietary application, 9 | a commercial license is also provided. Full license information can be 10 | found at http://www.jibble.org/licenses/ 11 | 12 | */ 13 | 14 | package org.jibble.pircbot; 15 | 16 | /** 17 | * This class is used to represent a user on an IRC server. 18 | * Instances of this class are returned by the getUsers method 19 | * in the PircBot class. 20 | *
21 | * Note that this class no longer implements the Comparable interface 22 | * for Java 1.1 compatibility reasons. 23 | * 24 | * @since 1.0.0 25 | * @author Paul James Mutton, 26 | * http://www.jibble.org/ 27 | * @version 1.5.0 (Build time: Mon Dec 14 20:07:17 2009) 28 | */ 29 | public class User { 30 | 31 | 32 | /** 33 | * Constructs a User object with a known prefix and nick. 34 | * 35 | * @param prefix The status of the user, for example, "@". 36 | * @param nick The nick of the user. 37 | */ 38 | User(String prefix, String nick) { 39 | _prefix = prefix; 40 | _nick = nick; 41 | _lowerNick = nick.toLowerCase(); 42 | } 43 | 44 | 45 | /** 46 | * Returns the prefix of the user. If the User object has been obtained 47 | * from a list of users in a channel, then this will reflect the user's 48 | * status in that channel. 49 | * 50 | * @return The prefix of the user. If there is no prefix, then an empty 51 | * String is returned. 52 | */ 53 | public String getPrefix() { 54 | return _prefix; 55 | } 56 | 57 | 58 | /** 59 | * Returns whether or not the user represented by this object is an 60 | * operator. If the User object has been obtained from a list of users 61 | * in a channel, then this will reflect the user's operator status in 62 | * that channel. 63 | * 64 | * @return true if the user is an operator in the channel. 65 | */ 66 | public boolean isOp() { 67 | return _prefix.indexOf('@') >= 0; 68 | } 69 | 70 | 71 | /** 72 | * Returns whether or not the user represented by this object has 73 | * voice. If the User object has been obtained from a list of users 74 | * in a channel, then this will reflect the user's voice status in 75 | * that channel. 76 | * 77 | * @return true if the user has voice in the channel. 78 | */ 79 | public boolean hasVoice() { 80 | return _prefix.indexOf('+') >= 0; 81 | } 82 | 83 | 84 | /** 85 | * Returns the nick of the user. 86 | * 87 | * @return The user's nick. 88 | */ 89 | public String getNick() { 90 | return _nick; 91 | } 92 | 93 | 94 | /** 95 | * Returns the nick of the user complete with their prefix if they 96 | * have one, e.g. "@Dave". 97 | * 98 | * @return The user's prefix and nick. 99 | */ 100 | public String toString() { 101 | return this.getPrefix() + this.getNick(); 102 | } 103 | 104 | 105 | /** 106 | * Returns true if the nick represented by this User object is the same 107 | * as the argument. A case insensitive comparison is made. 108 | * 109 | * @return true if the nicks are identical (case insensitive). 110 | */ 111 | public boolean equals(String nick) { 112 | return nick.toLowerCase().equals(_lowerNick); 113 | } 114 | 115 | 116 | /** 117 | * Returns true if the nick represented by this User object is the same 118 | * as the nick of the User object given as an argument. 119 | * A case insensitive comparison is made. 120 | * 121 | * @return true if o is a User object with a matching lowercase nick. 122 | */ 123 | public boolean equals(Object o) { 124 | if (o instanceof User) { 125 | User other = (User) o; 126 | return other._lowerNick.equals(_lowerNick); 127 | } 128 | return false; 129 | } 130 | 131 | 132 | /** 133 | * Returns the hash code of this User object. 134 | * 135 | * @return the hash code of the User object. 136 | */ 137 | public int hashCode() { 138 | return _lowerNick.hashCode(); 139 | } 140 | 141 | 142 | /** 143 | * Returns the result of calling the compareTo method on lowercased 144 | * nicks. This is useful for sorting lists of User objects. 145 | * 146 | * @return the result of calling compareTo on lowercased nicks. 147 | */ 148 | public int compareTo(Object o) { 149 | if (o instanceof User) { 150 | User other = (User) o; 151 | return other._lowerNick.compareTo(_lowerNick); 152 | } 153 | return -1; 154 | } 155 | 156 | 157 | private String _prefix; 158 | private String _nick; 159 | private String _lowerNick; 160 | 161 | } 162 | --------------------------------------------------------------------------------