Browse Source

add .irclib

Andrew Dolgov 4 years ago
parent
commit
06fb4066fb

File diff suppressed because it is too large
+ 1194 - 0
daemon/src/org/fox/ttirc/irclib/IRCConnection.java


File diff suppressed because it is too large
+ 1402 - 0
daemon/src/org/fox/ttirc/irclib/IRCConstants.java


+ 301 - 0
daemon/src/org/fox/ttirc/irclib/IRCEventAdapter.java

@@ -0,0 +1,301 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class IRCEventAdapter
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+/**
+ * Adapts the events of the <code>IRCEventListener</code> interface.
+ * <p>
+ * Supported events:
+ * <ul>
+ * <li>Connect</li>
+ * <li>Disconnect</li>
+ * <li>Error</li>
+ * <li>Invite</li>
+ * <li>Join</li>
+ * <li>Kick</li>
+ * <li>Private Message</li>
+ * <li>Mode (Chan)</li>
+ * <li>Mode (User)</li>
+ * <li>Nick</li>
+ * <li>Notice</li>
+ * <li>Numeric Reply</li>
+ * <li>Numeric Error</li>
+ * <li>Part</li>
+ * <li>Ping</li>
+ * <li>Quit</li>
+ * <li>Topic</li>
+ * </ul>
+ * <p>
+ * For other, unkown events there's the <code>unknown</code>-method.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @version 1.63
+ * @see IRCEventListener
+ */
+public class IRCEventAdapter implements IRCEventListener {
+	
+	/** 
+	 * The default and only constructor does nothing. 
+	 */
+	public IRCEventAdapter() {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when the own connection is successfully established. 
+	 * This is the case when the first PING? is received. <br />
+	 * This happens between the connection is opened with a socket and the 
+	 * connection is registered: The client sends his information to the server 
+	 * (nickname, username). The server says hello to you by sending you 
+	 * some <code>NOTICE</code>s. And if your nickname is invalid or in use or 
+	 * anything else is wrong with your nickname, it asks you for a new one.
+	 */
+	public void onRegistered() {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when the own connection is broken.
+	 */
+	public void onDisconnected() {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when an <code>ERROR</code> command is received.
+	 * @param msg The message of the error.
+	 */
+	public void onError(String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a numeric error is received.
+	 * The server often sends numeric errors (wrong nickname etc.). 
+	 * The <code>msg</code>'s format is different for every reply. All replies'
+	 * formats are described in the {@link IRCUtil}.
+	 * @param num The identifier (usually a 3-digit number).
+	 * @param msg The message of the error.
+	 */
+	public void onError(int num, String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody is invited to a channel.
+	 * @param chan The channel the user is invited to.
+	 * @param user The user who invites another. Contains nick, username and host.
+	 * @param passiveNick The nickname of the user who is invited by another user 
+	 *                    (passive).
+	 */
+	public void onInvite(String chan, IRCUser user, String passiveNick) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody joins a channel.
+	 * @param chan The channel the person joins.
+	 * @param user The user who joins. Contains nick, username and host.
+	 */
+	public void onJoin(String chan, IRCUser user) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody is kicked from a channel.
+	 * @param chan The channel somebody is kicked from.
+	 * @param user The user who kicks another user from a channel. 
+	 *             Contains nick, username and host.
+	 * @param passiveNick The nickname of the user who is kicked from a channel 
+	 *                    (passive).
+	 * @param msg The message the active user has set. This is <code>""</code> if 
+	 *            no message was set.
+	 */
+	public void onKick(String chan, IRCUser user, String passiveNick, 
+			String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when an operator changes the modes of a channel. 
+	 * For example, he can set somebody as an operator, too, or take him the 
+	 * oper-status. 
+	 * Also keys, moderated and other channelmodes are fired here.
+	 * @param chan The channel in which the modes are changed. 
+	 * @param user The user who changes the modes. 
+	 *             Contains nick, username and host.
+	 * @param modeParser The <code>IRCModeParser</code> object which contains the 
+	 *                   parsed information about the modes which are changed. 
+	 */
+	public void onMode(String chan, IRCUser user, IRCModeParser modeParser) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody changes somebody's usermodes. 
+	 * Note that this event is not fired when a channel-mode is set, for example
+	 * when someone sets another user as operator or the mode moderated.
+	 * @param user The user who changes the modes of another user or himself. 
+	 *             Contains nick, username and host.
+	 * @param passiveNick The nickname of the person whose modes are changed by 
+	 *                    another user or himself. 
+	 * @param mode The changed modes which are set.
+	 */
+	public void onMode(IRCUser user, String passiveNick, String mode) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody changes his nickname successfully.
+	 * @param user The user who changes his nickname. 
+	 *             Contains nick, username and host.
+	 * @param newNick The new nickname of the user who changes his nickname.
+	 */
+	public void onNick(IRCUser user, String newNick) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody sends a <code>NOTICE</code> to a user or a group. 
+	 * @param target The channel or nickname the user sent a <code>NOTICE</code> 
+	 *               to.
+	 * @param user The user who notices another person or a group. 
+	 *             Contains nick, username and host.
+	 * @param msg The message.
+	 */
+	public void onNotice(String target, IRCUser user, String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody parts from a channel.
+	 * @param chan The channel somebody parts from.
+	 * @param user The user who parts from a channel. 
+	 *             Contains nick, username and host.
+	 * @param msg The part-message which is optionally. 
+	 *            If it's empty, msg is <code>""</code>.
+	 */
+	public void onPart(String chan, IRCUser user, String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a <code>PING</code> comes in. 
+	 * The IRC server tests in different periods if the client is still there by 
+	 * sending PING &lt;ping&gt;. The client must response PONG &lt;ping&gt;.
+	 * @param ping The ping which is received from the server.
+	 */
+	public void onPing(String ping) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a user sends a <code>PRIVMSG</code> to a user or to a
+	 * group.
+	 * @param target The channel or nickname the user sent a <code>PRIVMSG</code> 
+	 *               to.
+	 * @param user The user who sent the <code>PRIVMSG</code>. 
+	 *             Contains nick, username and host.
+	 * @param msg The message the user transmits.
+	 */
+	public void onPrivmsg(String target, IRCUser user, String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody quits from the network.
+	 * @param user The user who quits. Contains nick, username and host.
+	 * @param msg The optional message. <code>""</code> if no message is set by 
+	 *            the user.
+	 */
+	public void onQuit(IRCUser user, String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a numeric reply is received. 
+	 * For example, <code>WHOIS</code> queries are answered by the server with 
+	 * numeric replies. 
+	 * The <code>msg</code>'s format is different for every reply. All replies'
+	 * formats are described in the {@link IRCUtil}.
+	 * The first word in the <code>value</code> is always your own nickname! 
+	 * @param num The numeric reply. 
+	 * @param value The first part of the message.
+	 * @param msg The main part of the message.
+	 */
+	public void onReply(int num, String value, String msg) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when the topic is changed by operators. 
+	 * Note that the topic is given as a numeric reply fired in 
+	 * <code>onReply</code> when you join a channel.
+	 * @param chan The channel where the topic is changed. 
+	 * @param user The user who changes the topic. 
+	 *             Contains nick, username and host.
+	 * @param topic The new topic.
+	 */
+	public void onTopic(String chan, IRCUser user, String topic) {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * This event is fired when the incoming line can not be identified as a known
+	 * event.
+	 * @param prefix The prefix of the incoming line.
+	 * @param command The command of the incoming line.
+	 * @param middle The part until the colon (<code>:</code>).
+	 * @param trailing The part behind the colon (<code>:</code>).
+	 */
+	public void unknown(String prefix, String command, String middle,
+			String trailing) {
+		// nothing
+	}
+}

+ 264 - 0
daemon/src/org/fox/ttirc/irclib/IRCEventListener.java

@@ -0,0 +1,264 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class IRCEventListener
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+import java.util.EventListener;
+
+/**
+ * Used as listener for incoming events like messages.
+ * <p>
+ * The <code>IRCEventListener</code> is used by the 
+ * <code>IRCConnection.addEventListener(IRCEventListener)</code> method to add
+ * a listener which listens to the connection for incoming IRC events like 
+ * <code>PRIVMSG</code>s or numeric replies.
+ * <p>
+ * Supported events:
+ * <ul>
+ * <li>Connect</li>
+ * <li>Disconnect</li>
+ * <li>Error</li>
+ * <li>Invite</li>
+ * <li>Join</li>
+ * <li>Kick</li>
+ * <li>Private Message</li>
+ * <li>Mode (Chan)</li>
+ * <li>Mode (User)</li>
+ * <li>Nick</li>
+ * <li>Notice</li>
+ * <li>Numeric Reply</li>
+ * <li>Numeric Error</li>
+ * <li>Part</li>
+ * <li>Ping</li>
+ * <li>Quit</li>
+ * <li>Topic</li>
+ * </ul>
+ * <p>
+ * For other, unkown events there's the <code>unknown</code>-method.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @version 1.64
+ * @see IRCEventAdapter
+ * @see IRCConnection
+ */
+public interface IRCEventListener extends EventListener, IRCConstants {
+	
+	/** 
+	 * Fired when the own connection is successfully established. 
+	 * This is the case when the first PING? is received. <br />
+	 * This happens between the connection is opened with a socket and the 
+	 * connection is registered: The client sends his information to the server 
+	 * (nickname, username). The server says hello to you by sending you 
+	 * some <code>NOTICE</code>s. And if your nickname is invalid or in use or 
+	 * anything else is wrong with your nickname, it asks you for a new one.
+	 */
+	public void onRegistered();
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when the own connection is broken.
+	 */
+	public void onDisconnected();
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when an <code>ERROR</code> command is received.
+	 * @param msg The message of the error.
+	 */
+	public void onError(String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a numeric error is received.
+	 * The server often sends numeric errors (wrong nickname etc.). 
+	 * The <code>msg</code>'s format is different for every reply. All replies'
+	 * formats are described in the {@link IRCUtil}.
+	 * @param num The identifier (usually a 3-digit number).
+	 * @param msg The message of the error. 
+	 */
+	public void onError(int num, String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody is invited to a channel.
+	 * @param chan The channel the user is invited to.
+	 * @param user The user who invites another. Contains nick, username and host.
+	 * @param passiveNick The nickname of the user who is invited by another user 
+	 *                    (passive).
+	 */
+	public void onInvite(String chan, IRCUser user, String passiveNick);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody joins a channel.
+	 * @param chan The channel the person joins.
+	 * @param user The user who joins. Contains nick, username and host.
+	 */
+	public void onJoin(String chan, IRCUser user);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody is kicked from a channel.
+	 * @param chan The channel somebody is kicked from.
+	 * @param user The user who kicks another user from a channel. 
+	 *             Contains nick, username and host.
+	 * @param passiveNick The nickname of the user who is kicked from a channel 
+	 *                    (passive).
+	 * @param msg The message the active user has set. This is <code>""</code> if 
+	 *            no message was set.
+	 */
+	public void onKick(String chan, IRCUser user, String passiveNick, String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when an operator changes the modes of a channel. 
+	 * For example, he can set somebody as an operator, too, or take him the 
+	 * oper-status. 
+	 * Also keys, moderated and other channelmodes are fired here.
+	 * @param chan The channel in which the modes are changed. 
+	 * @param user The user who changes the modes. 
+	 *             Contains nick, username and host.
+	 * @param modeParser The <code>IRCModeParser</code> object which contains the 
+	 *                   parsed information about the modes which are changed. 
+	 */
+	public void onMode(String chan, IRCUser user, IRCModeParser modeParser);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody changes somebody's usermodes. 
+	 * Note that this event is not fired when a channel-mode is set, for example
+	 * when someone sets another user as operator or the mode moderated.
+	 * @param user The user who changes the modes of another user or himself. 
+	 *             Contains nick, username and host.
+	 * @param passiveNick The nickname of the person whose modes are changed by 
+	 *                    another user or himself. 
+	 * @param mode The changed modes which are set.
+	 */
+	public void onMode(IRCUser user, String passiveNick, String mode);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody changes his nickname successfully.
+	 * @param user The user who changes his nickname. 
+	 *             Contains nick, username and host.
+	 * @param newNick The new nickname of the user who changes his nickname.
+	 */
+	public void onNick(IRCUser user, String newNick);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody sends a <code>NOTICE</code> to a user or a group. 
+	 * @param target The channel or nickname the user sent a <code>NOTICE</code> 
+	 *               to.
+	 * @param user The user who notices another person or a group. 
+	 *             Contains nick, username and host.
+	 * @param msg The message.
+	 */
+	public void onNotice(String target, IRCUser user, String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody parts from a channel.
+	 * @param chan The channel somebody parts from.
+	 * @param user The user who parts from a channel. 
+	 *             Contains nick, username and host.
+	 * @param msg The part-message which is optionally. 
+	 *            If it's empty, msg is <code>""</code>.
+	 */
+	public void onPart(String chan, IRCUser user, String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a <code>PING</code> comes in. 
+	 * The IRC server tests in different periods if the client is still there by 
+	 * sending PING &lt;ping&gt;. The client must response PONG &lt;ping&gt;.
+	 * @param ping The ping which is received from the server.
+	 */
+	public void onPing(String ping);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a user sends a <code>PRIVMSG</code> to a user or to a
+	 * group.
+	 * @param target The channel or nickname the user sent a <code>PRIVMSG</code> 
+	 *               to.
+	 * @param user The user who sent the <code>PRIVMSG</code>. 
+	 *             Contains nick, username and host.
+	 * @param msg The message the user transmits.
+	 */
+	public void onPrivmsg(String target, IRCUser user, String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when somebody quits from the network.
+	 * @param user The user who quits. Contains nick, username and host.
+	 * @param msg The optional message. <code>""</code> if no message is set by 
+	 *            the user.
+	 */
+	public void onQuit(IRCUser user, String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when a numeric reply is received. 
+	 * For example, <code>WHOIS</code> queries are answered by the server with 
+	 * numeric replies. 
+	 * The <code>msg</code>'s format is different for every reply. All replies'
+	 * formats are described in the {@link IRCUtil}.
+	 * The first word in the <code>value</code> is always your own nickname! 
+	 * @param num The numeric reply. 
+	 * @param value The first part of the message.
+	 * @param msg The main part of the message.
+	 */
+	public void onReply(int num, String value, String msg);
+	
+// ------------------------------
+	
+	/** 
+	 * Fired when the topic is changed by operators. 
+	 * Note that the topic is given as a numeric reply fired in 
+	 * <code>onReply</code> when you join a channel.
+	 * @param chan The channel where the topic is changed. 
+	 * @param user The user who changes the topic. 
+	 *             Contains nick, username and host.
+	 * @param topic The new topic.
+	 */
+	public void onTopic(String chan, IRCUser user, String topic);
+	
+// ------------------------------
+	
+	/** 
+	 * This event is fired when the incoming line can not be identified as a known
+	 * event.
+	 * @param prefix The prefix of the incoming line.
+	 * @param command The command of the incoming line.
+	 * @param middle The part until the colon (<code>:</code>).
+	 * @param trailing The part behind the colon (<code>:</code>).
+	 */
+	public void unknown(String prefix, String command, String middle,
+			String trailing);
+	
+}

+ 257 - 0
daemon/src/org/fox/ttirc/irclib/IRCModeParser.java

@@ -0,0 +1,257 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class IRCModeParser
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+/**
+ * Parses channel-modes.
+ * <p>
+ * An instance of this class is an argument of the <code>{@link 
+ * IRCEventListener#onMode(String chan, IRCUser user,
+ * IRCModeParser modeParser)}</code>.
+ * It's intended to help the programmer to work with the modes.
+ * <p>
+ * Channelmodes are:
+ * <ul>
+ * <li> +/- o nick </li>
+ * <li> +/- v nick </li>
+ * <li> +/- b banmask </li>
+ * <li> +/- l limit </li>
+ * <li> +/- k key </li>
+ * <li> +/- p </li>
+ * <li> +/- s </li>
+ * <li> +/- i </li>
+ * <li> +/- t </li>
+ * <li> +/- n </li>
+ * <li> +/- m </li>
+ * </ul>
+ * <p>
+ * These are all channel-modes defined in RFC1459. Nevertheless, most 
+ * networks provide more channel-modes. This class can handle all modes; it's 
+ * not restricted to the rights defined in RFC1459.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @version 1.22
+ * @see IRCEventListener
+ */
+public class IRCModeParser {
+	
+	/** 
+	 * Represents the operators, modes and nicks as they were sent from the IRC 
+	 * server. 
+	 */
+	private String line;
+	
+	/** 
+	 * Contains pluses (<code>+</code>) and minuses (<code>-</code>) which show 
+	 * if the mode is taken or given. 
+	 */
+	private char[] operatorsArr;
+	
+	/** 
+	 * This array contains the modes that are set with the operator of the 
+	 * <code>operatorsArr</code>-array. *
+	 */
+	private char[] modesArr;
+	
+	/** 
+	 * Represents the parsed nicks, hostnames, limits or keys in an array of 
+	 * Strings. 
+	 */
+	private String[] argsArr;
+	
+// ------------------------------
+	
+	/** 
+	 * Analyzes the modes and parses them into the parts operators (<code>+</code>
+	 * or <code>-</code>), modes (one character) and optional arguments (one 
+	 * word or number).
+	 * @param line The modes and the arguments; nothing more.
+	 */
+	public IRCModeParser(String line) {
+		line = line.trim();
+		this.line = line;
+		int index = line.indexOf(' ');
+		if (index >= 2) { // with arguments
+			String modes = line.substring(0, index);
+			String args  = line.substring(index + 1);
+			parse(modes, args); // call real constructor. 
+		} else if (line.length() >= 2) { // no arguments
+			String modes = line;
+			String args = "";
+			parse(modes, args);
+		} else { // nothing
+			argsArr = new String[0];
+			operatorsArr = new char[0];
+			modesArr = new char[0];
+		}
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Analyzes the modes and parses them into the parts operators (<code>+</code>
+	 * or <code>-</code>), modes (one character) and optional arguments (one 
+	 * word or number).
+	 * @param modes The modes (for example <code>+oo+m-v</code>).
+	 * @param args The modes' arguments (for example <code>Heinz Hans 
+	 *             Thomas</code>).
+	 */
+	public IRCModeParser(String modes, String args) {
+		line = modes +" "+ args;
+		parse(modes, args);
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Parses the modes into two <code>char</code>-arrays and one 
+	 * <code>String</code>-array. <br />
+	 * The first one contains the operator of the mode (<code>+</code> or 
+	 * </code>-</code>) and the second one the mode (<code>w</code>, 
+	 * <code>i</code>, <code>s</code>, <code>o</code> or any other mode). 
+	 * The <code>String[]</code> contains the nicknames. 
+	 * @param modes The modes (for example <code>+oo+m-v</code>).
+	 * @param args The modes' arguments (for example <code>Heinz Hans 
+	 *             Thomas</code>).
+	 */
+	private void parse(String modes, String args) {
+		String[] argsTmp = IRCUtil.split(args, ' ');
+		int modesLen = modes.length();
+		int modesCount = getModesCount(modes);
+		char c;
+		char operator = '+'; // any value cause it must be initialized
+		operatorsArr = new char[modesCount];
+		modesArr = new char[modesCount];
+		argsArr = new String[modesCount];
+		// parse and fill the arrays
+		for (int i = 0, j = 0, n = 0; i < modesLen; i++) {
+			c = modes.charAt(i);
+			if (c == '+' || c == '-') {
+				operator = c;
+			} else {
+				// add the operator (which was found earlier in the loop)
+				operatorsArr[n] = operator; 
+				modesArr[n] = c; // add the mode
+				if ((c == 'o' || c == 'v' || c == 'b' || c == 'k') // come with arg
+						|| (c == 'l' && operator == '+')) { // key comes with arg if '+'
+					argsArr[n] = (j < argsTmp.length) ? argsTmp[j++] : "";
+				} else {
+					argsArr[n] = ""; // null if mode has no argument (for example m, p, s)
+				}
+				n++; // increase n, not i. n is used to fill the arrays
+			}
+		}
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the amount of modes in the string. This is done by counting all 
+	 * chars which are not <code>+</code> or <code>-</code>.
+	 * @param modes The modes which are to analyze.
+	 * @return The count of modes without operators.
+	 */
+	private int getModesCount(String modes) {
+		int count = 0;
+		for (int i = 0, c, len = modes.length(); i < len; i++)
+			if ((c = modes.charAt(i)) != '+' && c != '-')
+				count++;
+		return count;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns count of modes. 
+	 * @return The count of modes.
+	 * @see #getOperatorAt(int)
+	 * @see #getModeAt(int)
+	 * @see #getArgAt(int)
+	 */
+	public int getCount() {
+		return operatorsArr.length;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the operator (<code>+</code> or <code>-</code>) of a given index.
+	 * @param i The index of the operator you want to get. The index starts 
+	 *          with <code>1</code> and not with <code>0</code>.
+	 * @return The operator at the given index (<code>+</code> or <code>-</code>).
+	 * @see #getCount()
+	 * @see #getModeAt(int)
+	 * @see #getArgAt(int)
+	 */
+	public char getOperatorAt(int i) {
+		return operatorsArr[i - 1];
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the mode (for example <code>o</code>, <code>v</code>, 
+	 * <code>m</code>, <code>i</code>) of a given index. 
+	 * @param i The index of the mode you want to get. The index starts with 
+	 *          <code>1</code> and not with <code>0</code>.
+	 * @return The mode of the given index (for example <code>o</code>, 
+	 *         <code>v</code>, <code>m</code>, <code>i</code>)
+	 * @see #getCount()
+	 * @see #getOperatorAt(int)
+	 * @see #getArgAt(int)
+	 */
+	public char getModeAt(int i) {
+		return modesArr[i - 1];
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the nick of a given index. 
+	 * @param i The index of the argument you want to get. The index starts with 
+	 *          <code>1</code> and not with <code>0</code>.
+	 * @return The argument you requested. It's <code>""</code> if there's no 
+	 *         argument at this index (for example <code>+m</code> for moderated 
+	 *         has never an argument).
+	 * @see #getCount()
+	 * @see #getOperatorAt(int)
+	 * @see #getModeAt(int)
+	 */
+	public String getArgAt(int i) {
+		return argsArr[i - 1];
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the line as it was sent from the IRC server.
+	 * The line contains the the operators, the modes and the nicknames, but not 
+	 * the channel or the nickname who executed the MODE command! 
+	 * @return The line which was set as argument when the parser was initialized.
+	 */
+	public String getLine() {
+		return line;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Generates a <code>String</code> with some information about the instance of
+	 * <code>IRCModeParser</code>.
+	 * Its format is: <code>classname[line]</code>.
+	 * @return A <code>String</code> with information about the instance.
+	 */
+	public String toString() {
+		return getClass().getName() +"["+ getLine() +"]";
+	}
+}

+ 558 - 0
daemon/src/org/fox/ttirc/irclib/IRCParser.java

@@ -0,0 +1,558 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class IRCParser
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+/**
+ * Parses a line sent from the IRC server.
+ * <p>
+ * Note: Probably this class is unimportant for you. It's used by the
+ * <code>IRCConnection</code> to parse incoming lines. Nevertheless I declared
+ * it as <code>public</code> because you might want to use it to parse IRC 
+ * command-shortcuts like <code>MSG</code> instead of <code>PRIVMSG</code> in 
+ * your client.<br />
+ * The following text goes on with the description of the class and what it
+ * does.
+ * <p>
+ * According with RFC1459 it divides the line into a prefix, a command and 
+ * its parameters.
+ * <p>
+ * The prefix is only given if a line starts with a <code>:</code> (colon) 
+ * and is used to indicate from where the line is send.
+ * <p>
+ * The next word in the line (if no prefix exists it is the first, else the 
+ * second word) is the command.
+ * The command is eiter a valid IRC command or a three-digit number which 
+ * represents a numeric reply or a numeric error.
+ * <p>
+ * The parameters are divided into a middle and a trailing part. 
+ * In the middle part one word means one parameter while the trailing part is 
+ * just one parameter independent from the amount of words in it. 
+ * If there is a  "<code>&nbsp;:</code>" (space+colon) in the line, this point 
+ * means the beginning of the trailing.
+ * If there is no such space+colon, the trailing is just the last word. 
+ * All words behind the space+colon mean just one parameter.
+ * If there is only one parameter given (the parameter is the first, the last 
+ * and the only one), the parameter is available as trailing (with 
+ * <code>getTrailing</code>), not as middle!
+ * <p>
+ * One line may have up to 15 parameters. Therefore up to 14 are middle and 
+ * one is the trailing.
+ * <p>
+ * The line may have up to 510 characters plus the CR-LF (carriage return - 
+ * line feed) which trails the incoming line. 
+ * <p>
+ * The following extract of the RFC1459 shows the message format in BNF:
+ * <blockquote cite="RFC1459"><code>
+ * &lt;message&gt;&nbsp;&nbsp;::=
+ * [':' &lt;prefix&gt; &lt;SPACE&gt; ] &lt;command&gt; &lt;params&gt; 
+ * &lt;crlf&gt; <br />
+ * &lt;prefix&gt;&nbsp;&nbsp;&nbsp;::=
+ * &lt;servername&gt; | &lt;nick&gt; 
+ * [ '!' &lt;username&gt; ] [ '@' &lt;host&gt; ]
+ * <br />
+ * &lt;command&gt;&nbsp;&nbsp;::=
+ * &lt;letter&gt; { &lt;letter&gt; } | &lt;number&gt; &lt;number&gt; 
+ * &lt;number&gt; <br />
+ * &lt;SPACE&gt;&nbsp;&nbsp;&nbsp;&nbsp;::=
+ * ' ' { ' ' }<br />
+ * &lt;params&gt;&nbsp;&nbsp;&nbsp;::=
+ * &lt;SPACE&gt; [ ':' &lt;trailing&gt; | &lt;middle&gt; &lt;params&gt; ] <br />
+ * &lt;middle&gt;&nbsp;&nbsp;&nbsp;::=
+ * &lt;Any *non-empty* sequence of octets not including SPACE or NUL or CR or 
+ * LF, the first of which may not be ':'&gt; <br />
+ * &lt;trailing&gt;&nbsp;::=
+ * &lt;Any, possibly *empty*, sequence of octets not including NUL or CR or 
+ * LF&gt; <br />
+ * &lt;crlf&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;::=
+ * CR LF<br />
+ * </code></blockquote>
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @version 3.22
+ * @see IRCConnection
+ */
+public class IRCParser {
+	
+	/** 
+	 * The <code>StringBuffer</code> contains the line which was analyzed. 
+	 */
+	private StringBuffer buf;
+	
+	/**
+	 * The length of the line. 
+	 */
+	private int len;
+	
+	/**
+	 * The prefix, which is parsed out in the constructor. 
+	 */
+	private String prefix;
+	
+	/**
+	 * The command, which is parsed out in the constructor. 
+	 */
+	private String command;
+	
+	/**
+	 * The middle, which is parsed out in the constructor. 
+	 */
+	private String middle;
+	
+	/**
+	 * The trailing, which is parsed out in the constructor. The trailing is the 
+	 * part behind the colon (<code>:</code>) or the last parameter. 
+	 */
+	private String trailing;
+	
+	/**
+	 * The parameters' array. It's not initialized in the constructor because of 
+	 * rare access. The methods which use and need this parameter-array 
+	 * (getParametersCount, getParameter, getParameterFrom etc.) initialize this 
+	 * array by calling initParameters, if the array isn't initialized yet.
+	 */
+	private String[] parameters;
+	
+// ------------------------------
+	
+	/**
+	 * Parses the line after erasing all mIRC color codes.
+	 * This constructor is a shorthand for <code>IRCParser(line, false)</code>.
+	 * @param line The line which will be parsed. 
+	 */
+	public IRCParser(String line) {
+		this(line, false);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * The main constructor. 
+	 * Parses prefix, command, middle and trailing.
+	 * @param line The line which will be parsed. 
+	 * @param colorsEnabled If <code>false</code>, mIRC color codes are parsed out
+	 *                      by using <code>IRCUtil.parseColors</code> method. 
+	 */
+	public IRCParser(String line, boolean colorsEnabled) {
+		int index = 0;
+		int trail;
+		
+		buf = new StringBuffer(line);
+		if (!colorsEnabled)
+			buf = IRCUtil.parseColors(buf);
+		len = buf.length();
+		
+		// prefix
+		if (buf.charAt(0) == ':') {
+			prefix = buf.substring(1, (index = indexOf(' ', index)));
+			index++;
+		}
+		
+		while (buf.charAt(index) == ' ')
+			index++;
+		
+		// command
+		command = buf.substring(index, ((index = indexOf(' ', index)) != -1) 
+				? index : (index = len));
+		
+		while (index < len && buf.charAt(index) == ' ')
+			index++;
+		index--;
+		
+		// middle & trailing
+		if ((trail = indexOf(" :", index)) != -1)
+			trailing = buf.substring(trail + 2, len);
+		else if ((trail = lastIndexOf(' ')) != -1 && trail >= index) 
+			trailing = buf.substring(trail + 1, len);
+		middle = (index < trail) ? buf.substring(index + 1, trail) : "";
+		
+		// save
+		this.prefix = (prefix != null) ?  prefix : "";
+		this.command = (command != null) ?  command : "";
+		this.middle = (middle != null) ?  middle : "";
+		this.trailing = (trailing != null) ?  trailing : "";
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Searches for a char in the <code>StringBuffer buf</code> from a given index
+	 * and returns its index.
+	 * @param c The char to search.
+	 * @param i The index the method will start searching at.
+	 * @return The index of the searched char. 
+	 */
+	private int indexOf(int c, int i) {
+		while (i < len)
+			if (buf.charAt(i++) == c)
+				return --i;
+		return -1;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Searches for a string in the <code>StringBuffer buf</code> from a given 
+	 * index and returns its beginning index.
+	 * @param str The string to search.
+	 * @param i The index the method will start searching at.
+	 * @return The index of the searched string.
+	 */
+	private int indexOf(String str, int i) {
+		int sublen = str.length();
+		int index = -1;
+		int j;
+		for ( ; i < len; i++) 
+			for (index = i, j = 0; i < len && j < sublen; i++, j++)
+				if (buf.charAt(i) != str.charAt(j))
+					break;
+				else if (j + 1 == sublen) 
+					return index;
+		return -1;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Searches for a given char in the <code>StringBuffer buf</code>. <br />
+	 * It starts at the end. <br />
+	 * Note: The method expects a character which is not <code>c</code> before
+	 * it can return an index. Thus in a string like "<code>nick moor&nbsp;&nbsp;
+	 * &nbsp;&nbsp;</code>" with four trailing spaces 
+	 * <code>lastIndexOf(' ')</code> does not return the the index of the last 
+	 * space. It first waits for characters which are not a space (r, o, o, m) and
+	 * then returns the index of the next space: the space between 
+	 * <code>nick</code> and <code>moor</code>. By this, also in lines with 
+	 * trailing whitespace the trailing-part is correctly recognized.
+	 * @param c The char to search.
+	 * @return The last index of the searched char.
+	 */
+	private int lastIndexOf(int c) {
+		int i = len;
+		boolean ok = false;
+		while (i > 0)
+			if (buf.charAt(--i) != c)
+				ok = true;
+			else if (ok)
+				return i;
+		return -1;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Initializes the <code>parameters[]</code>. 
+	 * This method is called by <code>getParam</code>, <code>getParamFrom</code> 
+	 * and <code>getParamTo</code>, if the <code>parameters[]</code> aren't 
+	 * initialized yet.<br />
+	 * The method splits the <code>middle</code> into all words using and appends 
+	 * the trailing as last parameter. It uses the <code>IRCUtil.split</code>
+	 * method.
+	 */
+	private void initParameters() {
+		parameters = IRCUtil.split(middle, ' ', trailing);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the line's prefix. A prefix is the part which contains information
+	 * about the sender of the line. If no prefix is set, <code>""</code> is 
+	 * returned; but in fact there's always a prefix.
+	 * @return The line's prefix.
+	 */
+	public String getPrefix() {
+		return prefix;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the line's command.
+	 * @return The line's command.
+	 */
+	public String getCommand() {
+		return command;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the line's middle.
+	 * @return The line's middle.
+	 */
+	public String getMiddle() {
+		return middle;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the line's trailing.
+	 * @return The line's trailing.
+	 */
+	public String getTrailing() {
+		return trailing;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the unparsed line. It looks exacttly as the server sent it, but
+	 * if colors are disabled and therefore already parsed out by 
+	 * IRCUtil.parseColors, the colors are not included in here.
+	 * @return The line.
+	 */
+	public String getLine() {
+		return buf.toString();
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the line's parameters which consists of the middle and the 
+	 * trailing.
+	 * @return The line's parameters.
+	 */
+	public String getParameters() {
+		return middle + 
+		((middle.length() != 0 && trailing.length() != 0) ? " " : "") + 
+		trailing;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the nickname of the person who sent the line 
+	 * or the servername of the server which sent the line. <br />
+	 * It is found in the prefix which always looks like that:<br />
+	 * <code>
+	 * &lt;servername&gt; | &lt;nick&gt; 
+	 * [ '!' &lt;username&gt; ] [ '@' &lt;host&gt; ]
+	 * </code><br /><br />
+	 * If no prefix is given in the whole line, <code>null</code> is returned.
+	 * <br /><br />
+	 * <b>Note:</b> This method is totally equal to <code>getServername</code>!
+	 * <br />
+	 * <b>Note:</b> There is also the method <code>getUser</code> which returns
+	 * an <code>IRCUser</code> object which holds the nickname, username and host.
+	 * By the way, the <code>getUser</code> uses the <code>getNick</code>, 
+	 * <code>getUsername</code> and <code>getHost</code> methods to create this
+	 * object.
+	 * @return The nickname or the servername of the line. If no prefix is given,
+	 *         <code>null</code> is returned.
+	 * @see #getServername()
+	 * @see #getUsername()
+	 * @see #getHost()
+	 * @see #getUser()
+	 */
+	public String getNick() {
+		int i = prefix.indexOf('!');
+		if (i != -1 || (i = prefix.indexOf('@')) != -1)
+			return prefix.substring(0, i); 
+		return (prefix.length() != 0) ? prefix : null;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the servername of the server which sent the line 
+	 * or the nickname of the person who sent the line. <br />
+	 * It is found in the prefix which always looks like that:<br />
+	 * <code>
+	 * &lt;servername&gt; | &lt;nick&gt; 
+	 * [ '!' &lt;username&gt; ] [ '@' &lt;host&gt; ]
+	 * </code><br /><br />
+	 * If no prefix is given in the whole line, <code>null</code> is returned.
+	 * <br /><br />
+	 * <b>Note:</b> This method is totally equal to <code>getNick</code>!
+	 * <br />
+	 * <b>Note:</b> There is also the method <code>getUser</code> which returns
+	 * an <code>IRCUser</code> object which holds the nickname, username and host.
+	 * By the way, the <code>getUser</code> uses the <code>getNick</code>, 
+	 * <code>getUsername</code> and <code>getHost</code> methods to create this
+	 * object.
+	 * @return The servername or the nickname of the line. If no prefix is given,
+	 *         <code>null</code> is returned.
+	 * @see #getNick()
+	 * @see #getUser()
+	 */
+	public String getServername() {
+		return getNick();
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the username of the person who sent the line.<br />
+	 * It is found in the prefix which always looks like that:<br />
+	 * <code>
+	 * &lt;servername&gt; | &lt;nick&gt; 
+	 * [ '!' &lt;username&gt; ] [ '@' &lt;host&gt; ]
+	 * </code><br /><br />
+	 * If the username is not specified, this method returns <code>null</code>.
+	 * <br />
+	 * <b>Note:</b> There is also the method <code>getUser</code> which returns
+	 * an <code>IRCUser</code> object which holds the nickname, username and host.
+	 * By the way, the <code>getUser</code> uses the <code>getNick</code>, 
+	 * <code>getUsername</code> and <code>getHost</code> methods to create this
+	 * object.
+	 * @return The username of the line; <code>null</code> if it's not given.
+	 * @see #getNick()
+	 * @see #getHost()
+	 * @see #getUser()
+	 */
+	public String getUsername() {
+		int i = prefix.indexOf('!') + 1;
+		if (i != 0) {
+			int j = prefix.indexOf('@', i); 
+			return prefix.substring(i, (j != -1) ? j : prefix.length()); 
+		}
+		return null;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the host of the person who sent the line.<br />
+	 * It is found in the prefix which always looks like that:<br />
+	 * <code>
+	 * &lt;servername&gt; | &lt;nick&gt; 
+	 * [ '!' &lt;username&gt; ] [ '@' &lt;host&gt; ]
+	 * </code><br /><br />
+	 * If the host is not specified, this method returns <code>null</code>.
+	 * <br />
+	 * <b>Note:</b> There is also the method <code>getUser</code> which returns
+	 * an <code>IRCUser</code> object which holds the nickname, username and host.
+	 * By the way, the <code>getUser</code> uses the <code>getNick</code>, 
+	 * <code>getUsername</code> and <code>getHost</code> methods to create this
+	 * object.
+	 * @return The host of the line; <code>null</code> if it's not given.
+	 * @see #getNick()
+	 * @see #getUsername()
+	 * @see #getUser()
+	 */
+	public String getHost() {
+		int i = prefix.indexOf('@') + 1;
+		if (i != 0)
+			return prefix.substring(i, prefix.length()); 
+		return null;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns a new <code>IRCUser</code> object.
+	 * This method is equal to <code>new IRCUser(IRCParser.getNick(), 
+	 * IRCParser.getUsername(), IRCParser.getHost())</code>. See those methods to
+	 * learn which value they return if they are not set. 
+	 * @return A new <code>IRCUser</code> object with exactly those values which
+	 *         are returned by the <code>getNick</code>, <code>getUsername</code> 
+	 *         and <code>getHost</code> methods.
+	 * @see #getNick()
+	 * @see #getUsername()
+	 * @see #getHost()
+	 */
+	public IRCUser getUser() {
+		return new IRCUser(getNick(), getUsername(), getHost());
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Gets count of parameters.
+	 * If <code>parameters</code> isn't initialized yet, it calls 
+	 * <code>initParameters</code> to do that.
+	 * @return The number of parameters. 
+	 */
+	public int getParameterCount() {
+		if (parameters == null) 
+			initParameters();
+		return parameters.length;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Get one parameter of the line.
+	 * If <code>parameters</code> isn't initialized yet, it calls 
+	 * <code>initParameters</code> to do that.
+	 * @param i The index of the parameter you want to get. The index starts with 
+	 *          1 and not with 0.
+	 * @return The <code>i</code>th parameter. If <code>i</code> is out of bounds,
+	 *         <code>""</code> is returned. 
+	 */
+	public String getParameter(int i) {
+		if (parameters == null) 
+			initParameters();
+		--i;
+		if (i >= 0 && i < parameters.length)
+			return parameters[i];
+		else
+			return "";
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Grabs the line's parameters from the <code>i</code>th to the last 
+	 * parameter (including the <code>i</code>th).
+	 * If <code>parameters</code> isn't initialized yet, it calls 
+	 * <code>initParameters</code> to do that.
+	 * @param i The index of the first parameter you want to get. 
+	 * @return All parameters behind another beginning at the <code>i</code>th. 
+	 *         If <code>i</code> is out of bounds, <code>""</code> is returned. 
+	 */
+	public String getParametersFrom(int i) {
+		if (parameters == null) 
+			initParameters();
+		StringBuffer params = new StringBuffer();
+		for (i--; i < parameters.length; i++)
+			params.append(parameters[i] +" ");
+		return params.toString();
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Grabs the line's parameters from the first to the <code>i</code>th 
+	 * parameters (including the <code>i</code>th).
+	 * If <code>parameters</code> isn't initialized yet, it calls 
+	 * <code>initParameters</code> to do that.
+	 * @param i The index of the last parameter you want to get. 
+	 * @return All parameters beginning at the first and ending at the 
+	 *         <code>i</code>th.  If <code>i</code> is out of bounds, 
+	 *         <code>""</code> is returned. 
+	 */
+	public String getParametersTo(int i) {
+		if (parameters == null) 
+			initParameters();
+		StringBuffer params = new StringBuffer();
+		int max = (i < parameters.length) ? i : parameters.length;
+		for (i = 0; i < max; i++)
+			params.append(parameters[i] +" ");
+		return params.toString();
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Generates a <code>String</code> with some information about the instance of
+	 * <code>IRCParser</code>.<br />
+	 * Its format is: <code>classname[prefix,command,middle,trailing]</code>.
+	 * @return A <code>String</code> with information about the instance.
+	 */
+	public String toString() {
+		return getClass().getName() +"["+ prefix +","+ command +","+ middle +","+ 
+		trailing +"]";
+	}
+}

+ 125 - 0
daemon/src/org/fox/ttirc/irclib/IRCUser.java

@@ -0,0 +1,125 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class IRCUser
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+/**
+ * Holds variables for the nick, username and host of a user.
+ * <p>
+ * It's used to pack these information in one object.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @version 1.02
+ * @see IRCEventListener
+ * @see IRCParser
+ */
+public class IRCUser {
+	
+	/** 
+	 * The user's nickname.
+	 */
+	private String nick;
+	
+	/**
+	 * The user's username.
+	 */
+	private String username;
+	
+	/**
+	 * The user's host.
+	 */
+	private String host;
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new <code>IRCUser</code> object.
+	 * @param nick The user's nickname.
+	 * @param username The user's username.
+	 * @param host The user's host.
+	 */
+	public IRCUser(String nick, String username, String host) {
+		this.nick = nick;
+		this.username = username;
+		this.host = host;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the nickname of the person who sent the line 
+	 * or the servername of the server which sent the line. <br />
+	 * If no nickname is given, <code>null</code> is returned.
+	 * <br /><br />
+	 * <b>Note:</b> This method is totally equal to <code>getServername</code>!
+	 * @return The nickname or the servername of the line. If no nick is given,
+	 *         <code>null</code> is returned.
+	 * @see #getServername()
+	 * @see #getUsername()
+	 * @see #getHost()
+	 */
+	public String getNick() {
+		return nick;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the servername of the server which sent the line or the nickname of
+	 * the person who sent the line. <br />
+	 * If no nickname is given, <code>null</code> is returned.
+	 * <br /><br />
+	 * <b>Note:</b> This method is totally equal to <code>getNick</code>!
+	 * @return The servername or the nickname of the line. If no server is given,
+	 *         <code>null</code> is returned.
+	 * @see #getNick()
+	 */
+	public String getServername() {
+		return getNick();
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the username of the person who sent the line. <br />
+	 * If the username is not specified, this method returns <code>null</code>.
+	 * @return The username of the line; <code>null</code> if it's not given.
+	 * @see #getNick()
+	 * @see #getHost()
+	 */
+	public String getUsername() {
+		return username;
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Returns the host of the person who sent the line. <br />
+	 * If the host is not specified, this method returns <code>null</code>.
+	 * @return The host of the line; <code>null</code> if it's not given.
+	 * @see #getNick()
+	 * @see #getUsername()
+	 */
+	public String getHost() {
+		return host;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the nickname.
+	 * @return The nickname.
+	 */
+	public String toString() {
+		return getNick();
+	}
+}

+ 248 - 0
daemon/src/org/fox/ttirc/irclib/IRCUtil.java

@@ -0,0 +1,248 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class IRCUtil
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+import java.util.Vector;
+
+/**
+ * Contains some utilities like numeric error and reply numbers.
+ * <p>
+ * The most description of the numeric errors and numeric replies are copied
+ * from RFC1459.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @author Normton &lt;[email protected]&gt;
+ * @version 2.03
+ * @see IRCConnection
+ * @see IRCEventListener#onError(int, String)
+ * @see IRCEventListener#onReply(int, String, String)
+ */
+public class IRCUtil implements IRCConstants {
+	/** 
+	 * This is part of the mIRC code and shows that a color-code starts / ends. 
+	 * Here it is as the ASCII decimal int 3. 
+	 * @deprecated Moved to <code>IRCConstants</code>.
+	 */
+	public static char colorIndicator = 3; // ASCII code
+	
+	/** 
+	 * This is part of the mIRC code and shows that bold starts / ends.
+	 * Here it is as the ASCII decimal int 32. 
+	 * @deprecated Moved to <code>IRCConstants</code>.
+	 */
+	public static char boldIndicator = 31; // ASCII code
+	
+	/**
+	 * This is part of the mIRC code and shows that bold starts / ends.
+	 * Here it is as the ASCII decimal int 2. 
+	 * @deprecated Moved to <code>IRCConstants</code>.
+	 */ 
+	public static char underlinedIndicator = 2; // ASCII code
+	
+	/**
+	 * This is part of the mIRC code and shows that bold, underline and colors 
+	 * end. 
+	 * Here it is as the ASCII decimal int 15. 
+	 * @deprecated Moved to <code>IRCConstants</code>.
+	 */
+	public static char colorEndIndicator = 15; // ASCII code
+	
+	/**
+	 * This is part of the mIRC code and indicates that the client's colors are 
+	 * reversed (background -&gt; foreground and foreground -&gt; background).
+	 * Here it is as the ASCII decimal int 1. 
+	 * @deprecated Moved to <code>IRCConstants</code>.
+	 */ 
+	public static char colorReverseIndicator = 22; // ASCII code
+	
+	/**
+	 * This is part of the mIRC code and shows that a PRIVMSG is an ACTION 
+	 * (<code>/me</code>).
+	 * Here it is as the ASCII decimal int 22. 
+	 * @deprecated Moved to <code>IRCConstants</code>.
+	 */ 
+	public static char actionIndicator = 1; // ASCII code
+	
+// ------------------------------
+	
+	/** 
+	 * This is an empty constructor, it does nothing. Nobody may instantiate this
+	 * class.
+	 */
+	private IRCUtil() {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * According to RFC2812 the channel's name may and must start with one of the
+	 * following characters.
+	 * <ul>
+	 * <li>! == 33 (ASCII)</li>
+	 * <li># == 35</li>
+	 * <li>&amp; == 38</li>
+	 * <li>+ == 43</li>
+	 * </ul>. 
+	 * @param str The name to check if it's a channel. 
+	 * @return <code>true</code> if the argument starts with one of the characters
+	 *         mentioned above.
+	 */
+	public static boolean isChan(String str) {
+		int c;
+		return (str.length() >= 2) 
+		&& ((c = str.charAt(0)) == 35 || c == 38 || c == 33 || c == 43);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Parses a <code>String</code> to an <code>int</code> via
+	 * <code>Integer.parseInt</code> but avoids the
+	 * <code>NumberFormatException</code>.
+	 * @param str The <code>String</code> to parse.
+	 * @return The parsed new <code>int</code>. <code>-1</code> if
+	 *         <code>NumberFormatException</code> was thrown. 
+	 */
+	public static int parseInt(String str) {
+		try {
+			return Integer.parseInt(str);
+		} catch (NumberFormatException exc) {
+			return -1;
+		}
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Erases the mIRC colorcodes from a String. 
+	 * The documentation of the evil color codes is available on
+	 * <a href="http://www.mirc.co.uk/help/color.txt" 
+	 * target="_blank">http://www.mirc.co.uk/help/color.txt</a>. 
+	 * This method links to the <code>parseColors(StringBuffer)</code> method.
+	 * @param str The line which should be parsed. 
+	 * @return A line cleaned from any mIRC colorcodes.
+	 * @see #parseColors(StringBuffer)
+	 */
+	public static String parseColors(String str) {
+		return parseColors(new StringBuffer(str)).toString();
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Erases the mIRC colorcodes from a String. 
+	 * The documentation of the evil color codes is available on 
+	 * <a href="http://www.mirc.co.uk/help/color.txt" 
+	 * target="_blank">http://www.mirc.co.uk/help/color.txt</a>. 
+	 * @param buf The line which should be parsed. 
+	 * @return A line as <code>StringBuffer</code> object which is cleaned from 
+	 *         any mIRC colorcodes.
+	 * @see #parseColors(String)
+	 */
+	public static StringBuffer parseColors(StringBuffer buf) {
+		int len = buf.length();
+		
+		for (int i = 0, j = 0, c; i < len; i++, j = i) {
+			c = buf.charAt(i);
+			try {
+				// COLORS Beginning 
+				// (format: <colorIndicator><int>[<int>][[,<int>[<int>]]
+				if (c == COLOR_INDICATOR) { 
+					c = buf.charAt(++j);
+					if ('0' <= c && c <= '9') { // first int
+						c = buf.charAt(++j);
+						if ('0' <= c && c <= '9') 
+							c = buf.charAt(++j); // second int
+					}
+					if (c == ',') 
+						c = buf.charAt(++j); // comma 
+					if ('0' <= c && c <= '9') { // first int
+						c = buf.charAt(++j); 
+						if ('0' <= c && c <= '9') 
+							c = buf.charAt(++j); // second int
+					}
+					// ACTION / BOLD / UNDERLINE / COLOR END 
+					// (format: <actionIndicator> / <boldIndicator> etc.)
+				} else if (c == ACTION_INDICATOR || c == BOLD_INDICATOR || 
+						c == UNDERLINE_INDICATOR || c == COLOR_END_INDICATOR ||
+						c == COLOR_REVERSE_INDICATOR) {
+					j++;
+				}
+			} catch(StringIndexOutOfBoundsException exc) {
+				// we got the end of the string with a call to charAt(++iIndexEnd)
+				// nothing
+			}
+			
+			if (j > i) {
+				buf = buf.delete(i, j); // remove the cars
+				len -= (j - i);
+				i -= (j - i);
+			}
+		}
+		return buf;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Splits a string into substrings. 
+	 * @param str The string which is to split.
+	 * @param delim The delimiter character, for example a space <code>' '</code>.
+	 * @param trailing The ending which is added as a substring though it wasn't 
+	 *                 in the <code>str</code>. This parameter is just for the 
+	 *                 <code>IRCParser</code> class which uses this method to 
+	 *                 split the <code>middle</code> part into the parameters. 
+	 *                 But as last parameter always the <code>trailing</code> is 
+	 *                 added. This is done here because it's the fastest way to 
+	 *                 do it here. <br />
+	 *                 If the <code>end</code> is <code>null</code> or 
+	 *                 <code>""</code>, nothing is appended.
+	 * @return An array with all substrings.
+	 * @see #split(String, int)
+	 */
+	public static String[] split(String str, int delim, String trailing) {
+		Vector items = new Vector(15);
+		int last = 0;
+		int index = 0; 
+		int len = str.length(); 
+		while (index < len) {
+			if (str.charAt(index) == delim) {
+				items.add(str.substring(last, index));
+				last = index + 1;
+			}
+			index++;
+		}
+		if (last != len)
+			items.add(str.substring(last));
+		if (trailing != null && trailing.length() != 0)
+			items.add(trailing);
+		String[] result = new String[items.size()];
+		items.copyInto(result);
+		return result;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Splits a string into substrings. This method is totally equal to 
+	 * <code>split(str, delim, null)</code>.
+	 * @param str The string which is to split.
+	 * @param delim The delimiter character, for example a space <code>' '</code>.
+	 * @return An array with all substrings.
+	 * @see #split(String, int, String)
+	 */
+	public static String[] split(String str, int delim) {
+		return split(str, delim, null);
+	}
+}

+ 97 - 0
daemon/src/org/fox/ttirc/irclib/SSLDefaultTrustManager.java

@@ -0,0 +1,97 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class SSLDefaultTrustManager
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+import com.sun.net.ssl.X509TrustManager;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * The default <code>TrustManager</code> of the 
+ * <code>SSLIRCConnection</code>.
+ * <p>
+ * Note that this class is <b>deprecated</b>. The SSL supporting classes moved 
+ * to <code>org.schwering.irc.lib.ssl</code> since IRClib 1.10.
+ * <p>
+ * It automatically accepts the X509 certificate.
+ * <p>
+ * In many cases you should change the <code>SSLIRCConnection</code>'s 
+ * <code>TrustManager</code>. For examle if you write an IRC client for human
+ * users, you may want to ask the user whether he accepts the server's 
+ * certificate or not. You could do this by a new class which extends the
+ * <code>SSLDefaultTrustManager</code> class and overrides the 
+ * <code>checkServerTrusted</code> method and asks the user whether he wants to
+ * accept the certification or not.
+ * @deprecated This class has been replaced with 
+ * <code>SSLDefaultTrustManager</code>.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @version 1.13
+ * @see SSLIRCConnection
+ * @see com.sun.net.ssl.TrustManager
+ */
+public class SSLDefaultTrustManager implements X509TrustManager {
+	
+	/**
+	 * The <code>X509Certificate</code>s which are accepted.
+	 */
+	protected X509Certificate[] accepted = new X509Certificate[0];
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new instance of the <code>SSLDefaultTrustManager</code> class.
+	 */
+	public SSLDefaultTrustManager() {
+		// nothing
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Does nothing. This method would check whether we (the server) trust the 
+	 * client. But we are the client and not the server. <br />
+	 * It's final so that nobody can override it; it would make no sense.
+	 * @param chain The peer certificate chain.
+	 * @return Always <code>false</code>.
+	 */
+	public final boolean isClientTrusted(X509Certificate chain[]) {
+		return false;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Invoked when the client should check whether he trusts the server or not.
+	 * This method trusts the server. But this method can be overriden and then
+	 * ask the user whether he truts the client or not.
+	 * @param chain The peer certificate chain.
+	 * @return Always <code>true</code>.
+	 */
+	public boolean isServerTrusted(X509Certificate chain[]) {
+		accepted = chain;
+		return true;
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the accepted certificates. They are set in the 
+	 * <code>checkServerTrusted</code> method.
+	 * @return A non-null (possibly empty) array of acceptable CA issuer 
+	 *         certificates.
+	 */
+	public X509Certificate[] getAcceptedIssuers() {
+		return accepted;
+	}
+}

+ 326 - 0
daemon/src/org/fox/ttirc/irclib/SSLIRCConnection.java

@@ -0,0 +1,326 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class SSLIRCConnection
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib;
+
+import com.sun.net.ssl.SSLContext;
+import com.sun.net.ssl.TrustManager;
+import com.sun.net.ssl.internal.ssl.Provider;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.SocketException;
+import java.security.Security;
+import java.util.Vector;
+
+/**
+ * The SSL extension of the <code>IRCConnection</code> class.
+ * <p>
+ * Note that this class is <b>deprecated</b>. The SSL supporting classes moved 
+ * to <code>org.schwering.irc.lib.ssl</code> since IRClib 1.10.
+ * <p>
+ * The IRC server you want to connect to must accept SSL connections. 
+ * Otherwise you cannot connect to it with an instance of 
+ * <code>SSLIRCConnection</code>. IRC servers which accept SSL connections are 
+ * really very rare, because SSL means a high load for the server.
+ * <p>
+ * The following sample code tries to establish an IRC connection to an
+ * IRC server which must support SSL. Differences to the code which 
+ * demonstrates the use of of the {@link IRCConnection}
+ * class are printed in bold font:
+ * <p>
+ * <hr /><pre>
+ * /&#42; 
+ *  &#42; The following code of a class which imports org.schwering.irc.lib.*
+ *  &#42; prepares an SSL IRC connection and then tries to establish the 
+ *  &#42; connection. The server is "irc.somenetwork.com", the ports are 
+ *  &#42; the default SSL port (443) and the port used on most SSL IRC servers
+ *  &#42; (994). No password is used (null). The nickname is "Foo" and 
+ *  &#42; the realname is "Mr. Foobar". The username "foobar".
+ *  &#42; Because of setDaemon(true), the JVM exits even if this thread is 
+ *  &#42; running.
+ *  &#42; By setting an instance of SSLDefaultTrustManager as TrustManager
+ *  &#42; (which is also done implicitely by the SSLIRCConnection class if no
+ *  &#42; TrustManager is set until the connect method is invoked), the
+ *  &#42; X509Certificate is accepted automatically. Of course, you can write
+ *  &#42; your own TrustManager. For example, you could write a class which
+ *  &#42; extends SSLDefaultTrustManager and overrides its checkServerTrusted
+ *  &#42; method. In the new checkServerTrusted method, you could ask the user
+ *  &#42; to accept or reject the certificate.
+ *  &#42; An instance of the class MyListener which must implement 
+ *  &#42; IRCActionListener is set as event-listener for the connection. 
+ *  &#42; The connection is told to parse out mIRC color codes and to enable
+ *  &#42; automatic PING? PONG! replies.
+ *  &#42;/
+ * <b>SSL</b>IRCConnection conn = new <b>SSL</b>IRCConnection(
+ *                               "irc.somenetwork.com", 
+ *                               new int[] { 443, 994 },  
+ *                               null, 
+ *                               "Foo", 
+ *                               "Mr. Foobar", 
+ *                               "[email protected]" 
+ *                             ); 
+ * 
+ * conn.addIRCEventListener(new MyListener()); 
+ * <b>conn.addTrustManager(new SSLDefaultTrustManager());</b>
+ * conn.setDaemon(true);
+ * conn.setColors(false); 
+ * conn.setPong(true); 
+ *   
+ * try {
+ *   conn.connect(); // Try to connect!!! Don't forget this!!!
+ * } catch (IOException ioexc) {
+ *   ioexc.printStackTrace(); 
+ * }
+ * </pre><hr />
+ * <p>
+ * The serverpassword isn't needed in most cases. You can give 
+ * <code>null</code> or <code>""</code> instead as done in this example.
+ * <p>
+ * <code>TrustManager</code>s can be added and removed until the 
+ * <code>connect</code> method is invoked. If no <code>TrustManager</code>s are
+ * set until then, an {@link SSLDefaultTrustManager} is
+ * set automatically. It accepts all X509 certificates.
+ * @deprecated This class has been replaced with 
+ * <code>SSLDefaultTrustManager</code>.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @version 1.33
+ * @see IRCConnection
+ * @see SSLDefaultTrustManager
+ * @see com.sun.net.ssl.TrustManager
+ */
+public class SSLIRCConnection extends IRCConnection {
+	
+	/**
+	 * The list of <code>TrustManager</code>s. <code>TrustManager</code>s can be
+	 * added with the <code>addTrustManager</code> method and removed with the
+	 * <code>removeTrustManager</code> method. If no <code>TrustManager</code>
+	 * is included, the <code>getTrustManagers</code> method sets an instance of
+	 * <code>SSLDefaultTrustManager</code> as only <code>TrustManager</code>.
+	 */
+	private Vector trustManagers = new Vector(1);
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new IRC connection with secure sockets (SSL).<br />
+	 * The difference to the other constructor is, that it transmits the ports in
+	 * an <code>int[]</code>. Thus, also ports like 994, 6000 and 6697 can be 
+	 * selected.<br /><br />
+	 * The constructor prepares a new IRC connection with secure sockets which 
+	 * can be really started by invoking the <code>connect</code> method. Before 
+	 * invoking it, you should set the <code>IRCEventListener</code>, optionally
+	 * the <code>TrustManager</code>, if you don't want to use the 
+	 * <code>SSLDefaultTrustManager</code> which accepts the X509 certificate 
+	 * automatically, and other settings.<br />
+	 * Note that you do not need to set a password to connect to the large public
+	 * IRC networks like QuakeNet, EFNet etc. To use no password in your IRC
+	 * connection, use <code>""</code> or <code>null</code> for the password
+	 * argument in the constructor.
+	 * @param host The hostname of the server we want to connect to.
+	 * @param ports The portrange to which we want to connect.
+	 * @param pass The password of the IRC server. If your server isn't 
+	 *             secured by a password (that's normal), use 
+	 *             <code>null</code> or <code>""</code>.
+	 * @param nick The nickname for the connection. Is used to register the 
+	 *             connection. 
+	 * @param username The username. Is used to register the connection. 
+	 * @param realname The realname. Is used to register the connection. 
+	 * @throws IllegalArgumentException If the <code>host</code> or 
+	 *                                  <code>ports</code> is <code>null</code> or
+	 *                                  <code>ports</code>' length is 
+	 *                                  <code>0</code>.
+	 * @see #connect()
+	 */
+	public SSLIRCConnection(String host, int[] ports, String pass, String nick, 
+			String username, String realname) {
+		super(host, ports, pass, nick, username, realname);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new IRC connection with secure sockets (SSL).<br />
+	 * The difference to the other constructor is, that it transmits the ports as
+	 * two <code>int</code>s. Thus, only a portrange from port <code>x</code> to
+	 * port <code>y</code> like from port 6000 to 6010 can be selected.<br />
+	 * <br />
+	 * The constructor prepares a new IRC connection with secure sockets which 
+	 * can be really started by invoking the <code>connect</code> method. Before 
+	 * invoking it, you should set the <code>IRCEventListener</code>, optionally
+	 * the <code>TrustManager</code>, if you don't want to use the 
+	 * <code>SSLDefaultTrustManager</code> which accepts the X509 certificate 
+	 * automatically, and other settings.<br />
+	 * Note that you do not need to set a password to connect to the large public
+	 * IRC networks like QuakeNet, EFNet etc. To use no password in your IRC
+	 * connection, use <code>""</code> or <code>null</code> for the password
+	 * argument in the constructor.
+	 * @param host The hostname of the server we want to connect to.
+	 * @param portMin The beginning of the port range we are going to connect 
+	 *                to.
+	 * @param portMax The ending of the port range we are going to connect to.
+	 * @param pass The password of the IRC server. If your server isn't 
+	 *             secured by a password (that's normal), use 
+	 *             <code>null</code> or <code>""</code>.
+	 * @param nick The nickname for the connection. Is used to register the 
+	 *             connection. 
+	 * @param username The username. Is used to register the connection. 
+	 * @param realname The realname. Is used to register the connection. 
+	 * @throws IllegalArgumentException If the <code>host</code> is 
+	 *                                  <code>null</code>.
+	 * @see #connect()
+	 */
+	public SSLIRCConnection(String host, int portMin, int portMax, String pass, 
+			String nick, String username, String realname) {
+		super(host, portMin, portMax, pass, nick, username, realname);
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Establish a connection to the server.<br />
+	 * This method must be invoked to start a connection; the constructor doesn't 
+	 * do that!<br />
+	 * It tries all set ports until one is open. If all ports fail it throws an 
+	 * <code>IOException</code>. If anything SSL related fails (for example 
+	 * conflicts with the algorithms or during the handshaking), a 
+	 * <code>SSLException</code> is thrown. <br />
+	 * You can invoke <code>connect</code> only one time.
+	 * @throws IOException If an I/O error occurs. 
+	 * @throws SSLException If anything with the secure sockets fails. 
+	 * @throws SocketException If the <code>connect</code> method was already
+	 *                         invoked.
+	 * @see #isConnected()
+	 * @see #doQuit()
+	 * @see #doQuit(String)
+	 * @see #close()
+	 */
+	public void connect() throws IOException {
+		if (level != 0) // otherwise disconnected or connect
+			throw new SocketException("Socket closed or already open ("+ level +")");
+		IOException exception = null;
+		SSLSocketFactory sf = null;
+		SSLSocket s = null;
+		for (int i = 0; i < ports.length && s == null; i++) {
+			try {
+				if (sf == null)
+					sf = getSocketFactory();
+				s = (SSLSocket)sf.createSocket(host, ports[i]);
+				s.startHandshake();
+				exception = null; 
+			} catch (IOException exc) {
+				if (s != null)
+					s.close();
+				s = null;
+				exception = exc; 
+			}
+		}
+		if (exception != null)
+			throw exception; // connection wasn't successful at any port
+		
+		prepare(s);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new <code>SSLSocketFactory</code> on whose base a new 
+	 * <code>SSLSocket</code> can be created. This method is used by the 
+	 * <code>connect</code> method. If a <code>NoSuchAlgorithmException</code>,
+	 * <code>KeyManagementException</code>, or any other exception is thrown,
+	 * it's catched a <code>SSLException</code> is thrown. This 
+	 * <code>SSLException</code> contains all information about the exception
+	 * which was really thrown.<br /><br />
+	 * If there are now <code>TrustManager</code>s set at the moment, an instance 
+	 * of <code>SSLDefultTrustManager</code> is set automatically.
+	 * @throws SSLException If any exception is thrown. It contains all the thrown
+	 *                      exception's information.
+	 * @return A new <code>SSLSocketFactory on which base a new 
+	 *         <code>SSLSocket</code> can be created.
+	 */
+	private SSLSocketFactory getSocketFactory() throws SSLException {
+		if (trustManagers.size() == 0)
+			addTrustManager(new SSLDefaultTrustManager());
+		try {
+			Security.addProvider(new Provider());
+			SSLContext context = SSLContext.getInstance("SSL");
+			context.init(null, getTrustManagers(), null);
+			SSLSocketFactory socketFactory = context.getSocketFactory();
+			return socketFactory;
+		} catch (Exception exc) {
+			StringWriter sw = new StringWriter();
+			PrintWriter pw = new PrintWriter(sw);
+			exc.printStackTrace(pw);
+			pw.close();
+			throw new SSLException("Exception while preparing "+
+					"the SSLSocket:\n---\n"+ sw.toString() + "---");
+		}
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Adds a new <code>TrustManager</code>. <br />
+	 * Please remind that we're talking here about 
+	 * <code>com.sun.net.ssl.TrustManager</code>s of the JSSE API and not the 
+	 * <code>javax.net.ssl.TrustManager</code>s of the Java 1.4 API!
+	 * @param trustManager The <code>TrustManager</code> object which is to add.
+	 * @see #removeTrustManager(TrustManager)
+	 * @see #getTrustManagers()
+	 */
+	public void addTrustManager(TrustManager trustManager) {
+		trustManagers.add(trustManager);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Removes one <code>TrustManager</code>.<br />
+	 * Please remind that we're talking here about 
+	 * <code>com.sun.net.ssl.TrustManager</code>s of the JSSE API and not the 
+	 * <code>javax.net.ssl.TrustManager</code>s of the Java 1.4 API!
+	 * @param trustManager The <code>TrustManager</code> object which is to 
+	 *                     remove.
+	 * @return <code>true</code> if a <code>TrustManager</code> was removed.
+	 * @see #addTrustManager(TrustManager)
+	 * @see #getTrustManagers()
+	 */
+	public boolean removeTrustManager(TrustManager trustManager) {
+		return trustManagers.remove(trustManager);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the set <code>TrustManager</code>s. The default 
+	 * <code>TrustManager</code> is an instance of 
+	 * <code>SSLDefaultTrustManager</code>, which is set when you invoke the
+	 * <code>connect</code> method without having set another 
+	 * <code>TrustManager</code>.<br />
+	 * Please remind that we're talking here about 
+	 * <code>com.sun.net.ssl.TrustManager</code>s of the JSSE API and not the 
+	 * <code>javax.net.ssl.TrustManager</code>s of the Java 1.4 API!
+	 * @return The set <code>TrustManager</code>s.
+	 * @see #addTrustManager(TrustManager)
+	 * @see #removeTrustManager(TrustManager)
+	 */
+	public TrustManager[] getTrustManagers() {
+		TrustManager[] tm = new TrustManager[trustManagers.size()];
+		trustManagers.copyInto(tm);
+		return tm;
+	}
+}

+ 27 - 0
daemon/src/org/fox/ttirc/irclib/package.html

@@ -0,0 +1,27 @@
+<body>
+IRClib is a library for the client-side of IRC (Internet Relay Chat) 
+connections.
+<p>
+IRClib is RFC1459 and RFC2812 compliant. It's licensed under the GNU Lesser 
+General Public License, the Apache License 2.0 and the Eclipse Public License
+so that you can use and modify it for your purposes for free.
+<p>
+By instantiating the <code>{@link org.schwering.irc.lib.IRCConnection}</code> 
+class you can establish a new connection to an IRC server. The 
+<code>{@link org.schwering.irc.lib.IRCEventListener}</code> informs your class 
+about lines coming from the server which are parsed by the 
+<code>{@link org.schwering.irc.lib.IRCParser}</code>. The 
+<code>{@link org.schwering.irc.lib.IRCModeParser}</code> is especially made for 
+channel-modes.<br />
+To create a secure connection with SSL, instantiate the 
+<code>{@link org.schwering.irc.lib.ssl.SSLIRCConnection}</code>.
+<p>
+This project's home page is available at <a href="http://moepii.sourceforge.net" 
+target="_blank">http://moepii.sourceforge.net</a>.
+<p>
+If you're using IRClib, write a <a href="mailto:[email protected]">mail to me</a>
+so that I can put you on the using-IRClib-list!
+
[email protected] 1.10
[email protected] Christoph Schwering &lt;[email protected]&gt;
+</body>

+ 64 - 0
daemon/src/org/fox/ttirc/irclib/ssl/SSLDefaultTrustManager.java

@@ -0,0 +1,64 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class SSLDefaultTrustManager
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib.ssl;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * The default <code>TrustManager</code> of the 
+ * <code>SSLIRCConnection</code>.
+ * <p>
+ * It automatically accepts the X509 certificate.
+ * <p>
+ * In many cases you should change the <code>SSLIRCConnection</code>'s 
+ * <code>SSLTrustManager</code>. For examle if you write an IRC client for human
+ * users, you may want to ask the user whether he accepts the server's 
+ * certificate or not.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @since 1.10
+ * @version 2.00
+ * @see SSLIRCConnection
+ * @see SSLTrustManager
+ */
+public class SSLDefaultTrustManager implements SSLTrustManager {
+	
+	/**
+	 * The <code>X509Certificate</code>s which are accepted.
+	 */
+	protected X509Certificate[] accepted = new X509Certificate[0];
+	
+// ------------------------------
+	
+	/**
+	 * Trusts the complete certificate chain and returns <code>true</code>.
+	 * @param chain The peer certificate chain.
+	 * @return <code>true</code>.
+	 */
+	public boolean isTrusted(X509Certificate[] chain) {
+		accepted = chain;
+		return true;
+	}
+
+// ------------------------------
+	
+	/**
+	 * Returns the accepted certificates. They are set in the 
+	 * <code>checkServerTrusted</code> method.
+	 * @return A non-null (possibly empty) array of acceptable CA issuer 
+	 *         certificates.
+	 */
+	public X509Certificate[] getAcceptedIssuers() {
+		return accepted;
+	}
+}

+ 290 - 0
daemon/src/org/fox/ttirc/irclib/ssl/SSLIRCConnection.java

@@ -0,0 +1,290 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class SSLIRCConnection
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib.ssl;
+
+import org.fox.ttirc.irclib.IRCConnection;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.SocketException;
+import java.util.Vector;
+
+/**
+ * The SSL extension of the <code>IRCConnection</code> class.
+ * <p>
+ * The IRC server you want to connect to must accept SSL connections. 
+ * Otherwise you cannot connect to it with an instance of 
+ * <code>SSLIRCConnection</code>. IRC servers which accept SSL connections are 
+ * really very rare, because SSL means a high load for the server.
+ * <p>
+ * The following sample code tries to establish an IRC connection to an
+ * IRC server which must support SSL. Differences to the code which 
+ * demonstrates the use of of the {@link IRCConnection}
+ * class are printed in bold font:
+ * <p>
+ * <hr /><pre>
+ * /&#42; 
+ *  &#42; The following code of a class which imports org.schwering.irc.lib.*
+ *  &#42; prepares an SSL IRC connection and then tries to establish the 
+ *  &#42; connection. The server is "irc.somenetwork.com", the ports are 
+ *  &#42; the default SSL port (443) and the port used on most SSL IRC servers
+ *  &#42; (994). No password is used (null). The nickname is "Foo" and 
+ *  &#42; the realname is "Mr. Foobar". The username "foobar".
+ *  &#42; Because of setDaemon(true), the JVM exits even if this thread is 
+ *  &#42; running.
+ *  &#42; By setting an instance of SSLDefaultTrustManager as TrustManager
+ *  &#42; (which is also done implicitely by the SSLIRCConnection class if no
+ *  &#42; TrustManager is set until the connect method is invoked), the
+ *  &#42; X509Certificate is accepted automatically. Of course, you can write
+ *  &#42; your own TrustManager. For example, you could write a class which
+ *  &#42; extends SSLDefaultTrustManager and overrides its checkServerTrusted
+ *  &#42; method. In the new checkServerTrusted method, you could ask the user
+ *  &#42; to accept or reject the certificate.
+ *  &#42; An instance of the class MyListener which must implement 
+ *  &#42; IRCActionListener is set as event-listener for the connection. 
+ *  &#42; The connection is told to parse out mIRC color codes and to enable
+ *  &#42; automatic PING? PONG! replies.
+ *  &#42;/
+ * <b>SSL</b>IRCConnection conn = new <b>SSL</b>IRCConnection(
+ *                               "irc.somenetwork.com", 
+ *                               new int[] { 443, 994 },  
+ *                               null, 
+ *                               "Foo", 
+ *                               "Mr. Foobar", 
+ *                               "[email protected]" 
+ *                             ); 
+ * 
+ * conn.addIRCEventListener(new MyListener()); 
+ * <b>conn.addTrustManager(new SSLDefaultTrustManager());</b>
+ * conn.setDaemon(true);
+ * conn.setColors(false); 
+ * conn.setPong(true); 
+ *   
+ * try {
+ *   conn.connect(); // Try to connect!!! Don't forget this!!!
+ * } catch (IOException ioexc) {
+ *   ioexc.printStackTrace(); 
+ * }
+ * </pre><hr />
+ * <p>
+ * The serverpassword isn't needed in most cases. You can give 
+ * <code>null</code> or <code>""</code> instead as done in this example.
+ * <p>
+ * <code>SSLTrustManager</code>s can be added and removed until the 
+ * <code>connect</code> method is invoked. If no <code>SSLTrustManager</code>s 
+ * are set until then, an 
+ * {@link SSLDefaultTrustManager} is set
+ * automatically. It accepts all X509 certificates.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @since 1.10
+ * @version 2.00
+ * @see IRCConnection
+ * @see SSLTrustManager
+ */
+public class SSLIRCConnection extends IRCConnection {
+	
+	/**
+	 * The SSL protocol of choice. Values can be "TLS", "SSLv3" or "SSL".
+	 * "SSL" is the default value.
+	 */
+	public static String protocol = "SSL";
+	
+	/**
+	 * The list of <code>SSLTrustManager</code>s. 
+	 */
+	private Vector trustManagers = new Vector(1);
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new IRC connection with secure sockets (SSL). <br />
+	 * The difference to the other constructor is, that it transmits the ports in
+	 * an <code>int[]</code>. Thus, also ports like 994, 6000 and 6697 can be 
+	 * selected.<br /><br />
+	 * The constructor prepares a new IRC connection with secure sockets which 
+	 * can be really started by invoking the <code>connect</code> method. Before 
+	 * invoking it, you should set the <code>IRCEventListener</code>, optionally
+	 * the <code>SSLTrustManager</code>, if you don't want to use the 
+	 * <code>SSLDefaultTrustManager</code> which accepts the X509 certificate 
+	 * automatically, and other settings.<br />
+	 * Note that you do not need to set a password to connect to the large public
+	 * IRC networks like QuakeNet, EFNet etc. To use no password in your IRC
+	 * connection, use <code>""</code> or <code>null</code> for the password
+	 * argument in the constructor.
+	 * @param host The hostname of the server we want to connect to.
+	 * @param ports The portrange to which we want to connect.
+	 * @param pass The password of the IRC server. If your server isn't 
+	 *             secured by a password (that's normal), use 
+	 *             <code>null</code> or <code>""</code>.
+	 * @param nick The nickname for the connection. Is used to register the 
+	 *             connection. 
+	 * @param username The username. Is used to register the connection. 
+	 * @param realname The realname. Is used to register the connection. 
+	 * @throws IllegalArgumentException If the <code>host</code> or 
+	 *                                  <code>ports</code> is <code>null</code> or
+	 *                                  <code>ports</code>' length is 
+	 *                                  <code>0</code>.
+	 * @see #connect()
+	 */
+	public SSLIRCConnection(String host, int[] ports, String pass, String nick, 
+			String username, String realname) {
+		super(host, ports, pass, nick, username, realname);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new IRC connection with secure sockets (SSL). <br />
+	 * The difference to the other constructor is, that it transmits the ports as
+	 * two <code>int</code>s. Thus, only a portrange from port <code>x</code> to
+	 * port <code>y</code> like from port 6000 to 6010 can be selected.<br />
+	 * <br />
+	 * The constructor prepares a new IRC connection with secure sockets which 
+	 * can be really started by invoking the <code>connect</code> method. Before 
+	 * invoking it, you should set the <code>IRCEventListener</code>, optionally
+	 * the <code>SSLTrustManager</code>, if you don't want to use the 
+	 * <code>SSLDefaultTrustManager</code> which accepts the X509 certificate 
+	 * automatically, and other settings.<br />
+	 * Note that you do not need to set a password to connect to the large public
+	 * IRC networks like QuakeNet, EFNet etc. To use no password in your IRC
+	 * connection, use <code>""</code> or <code>null</code> for the password
+	 * argument in the constructor.
+	 * @param host The hostname of the server we want to connect to.
+	 * @param portMin The beginning of the port range we are going to connect 
+	 *                to.
+	 * @param portMax The ending of the port range we are going to connect to.
+	 * @param pass The password of the IRC server. If your server isn't 
+	 *             secured by a password (that's normal), use 
+	 *             <code>null</code> or <code>""</code>.
+	 * @param nick The nickname for the connection. Is used to register the 
+	 *             connection. 
+	 * @param username The username. Is used to register the connection. 
+	 * @param realname The realname. Is used to register the connection. 
+	 * @throws IllegalArgumentException If the <code>host</code> is 
+	 *                                  <code>null</code>.
+	 * @see #connect()
+	 */
+	public SSLIRCConnection(String host, int portMin, int portMax, String pass, 
+			String nick, String username, String realname) {
+		super(host, portMin, portMax, pass, nick, username, realname);
+	}
+	
+// ------------------------------
+	
+	/** 
+	 * Establish a connection to the server. <br />
+	 * This method must be invoked to start a connection; the constructor doesn't 
+	 * do that!<br />
+	 * It tries all set ports until one is open. If all ports fail it throws an 
+	 * <code>IOException</code>. If anything SSL related fails (for example 
+	 * conflicts with the algorithms or during the handshaking), a 
+	 * <code>SSLException</code> is thrown. <br />
+	 * You can invoke <code>connect</code> only one time.
+	 * @throws NoClassDefFoundError If SSL is not supported. This is the case
+	 *                              if neither JSSE nor J2SE 1.4 or later is 
+	 *                              installed.
+	 * @throws SSLNotSupportedException If SSL is not supported. This is the 
+	 *                                  case if neither JSSE nor J2SE 1.4 or 
+	 *                                  later is installed. This exception is 
+	 *                                  thrown if no NoClassDefFoundError is 
+	 *                                  thrown.
+	 * @throws IOException If an I/O error occurs. 
+	 * @throws SSLException If anything with the secure sockets fails. 
+	 * @throws SocketException If the <code>connect</code> method was already
+	 *                         invoked.
+	 * @see #isConnected()
+	 * @see #doQuit()
+	 * @see #doQuit(String)
+	 * @see #close()
+	 */
+	public void connect() throws IOException {
+		if (level != 0) // otherwise disconnected or connect
+			throw new SocketException("Socket closed or already open ("+ level +")");
+		IOException exception = null;
+		if (trustManagers.size() == 0)
+			addTrustManager(new SSLDefaultTrustManager());
+		SSLSocketFactory sf = null;
+		SSLSocket s = null;
+		for (int i = 0; i < ports.length && s == null; i++) {
+			try {
+				if (sf == null)
+					sf = SSLSocketFactoryFactory.createSSLSocketFactory(getTrustManagers());
+				s = (SSLSocket)sf.createSocket(host, ports[i]);
+				s.startHandshake();
+				exception = null;
+			} catch (SSLNotSupportedException exc) {
+				if (s != null)
+					s.close();
+				s = null;
+				throw exc;
+			} catch (IOException exc) {
+				if (s != null)
+					s.close();
+				s = null;
+				exception = exc; 
+			}
+		}
+		if (exception != null)
+			throw exception; // connection wasn't successful at any port
+		
+		prepare(s);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Adds a new <code>SSLTrustManager</code>.
+	 * @param trustManager The <code>SSLTrustManager</code> object which is to 
+	 * add.
+	 * @see #removeTrustManager(SSLTrustManager)
+	 * @see #getTrustManagers()
+	 */
+	public void addTrustManager(SSLTrustManager trustManager) {
+		trustManagers.add(trustManager);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Removes one <code>SSLTrustManager</code>.
+	 * @param trustManager The <code>SSLTrustManager</code> object which is to 
+	 *                     remove.
+	 * @return <code>true</code> if a <code>SSLTrustManager</code> was removed.
+	 * @see #addTrustManager(SSLTrustManager)
+	 * @see #getTrustManagers()
+	 */
+	public boolean removeTrustManager(SSLTrustManager trustManager) {
+		return trustManagers.remove(trustManager);
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Returns the set <code>SSLTrustManager</code>s. The default 
+	 * <code>SSLTrustManager</code> is an instance of 
+	 * <code>SSLDefaultTrustManager</code>, which is set when you invoke the
+	 * <code>connect</code> method without having set another 
+	 * <code>SSLTrustManager</code>.
+	 * @return The set <code>SSLTrustManager</code>s.
+	 * @see #addTrustManager(SSLTrustManager)
+	 * @see #removeTrustManager(SSLTrustManager)
+	 */
+	public SSLTrustManager[] getTrustManagers() {
+		SSLTrustManager[] tm = new SSLTrustManager[trustManagers.size()];
+		trustManagers.copyInto(tm);
+		return tm;
+	}
+}

+ 45 - 0
daemon/src/org/fox/ttirc/irclib/ssl/SSLNotSupportedException.java

@@ -0,0 +1,45 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class SSLNotSupportedException
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib.ssl;
+
+/**
+ * Indicates that SSL is not supported. However, a 
+ * <code>NoClassDefFoundError</code> is probably thrown before a
+ * <code>SSLNotSupportedException</code> can be thrown, because the 
+ * <code>javax.net.SocketFactory</code> will not be found (among others).
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @since 1.10
+ * @version 1.00
+ * @see SSLIRCConnection
+ */
+public class SSLNotSupportedException extends RuntimeException {
+	private static final long serialVersionUID = -5108810948951810903L;
+	
+	/**
+	 * Empty exception.
+	 */
+	public SSLNotSupportedException() {
+		super();
+	}
+	
+// ------------------------------
+
+	/**
+	 * Creates an exception with description.
+	 * @param s The description.
+	 */
+	public SSLNotSupportedException(String s) {
+		super(s);
+	}
+}

+ 220 - 0
daemon/src/org/fox/ttirc/irclib/ssl/SSLSocketFactoryFactory.java

@@ -0,0 +1,220 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class SSLSocketFactoryFactory
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib.ssl;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Factory for <code>javax.net.ssl.SSLSocketFactory</code>. Firstly tries to 
+ * creates this object using exclusively the <code>javax.net.ssl.*</code> 
+ * classes and then tries to do so using the <code>javax.net.ssl.*</code> 
+ * classes plus the <code>com.sun.net.ssl.*</code> classes.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @since 1.10
+ * @version 1.00
+ * @see SSLIRCConnection
+ * @see SSLIRCConnection#connect()
+ */
+class SSLSocketFactoryFactory {
+	/**
+	 * Disallow instances.
+	 */
+	private SSLSocketFactoryFactory() {
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new <code>SSLSocketFactory</code>. This method first tries to 
+	 * create it using <code>javax.net.ssl.*</code> classes. If this fails, it 
+	 * tries to access the old JSSE classes in <code>com.sun.net.ssl.*</code>.
+	 * @throws SSLNotSupportedException If neither JSSE nor J2SE >= 1.4 are 
+	 *                                  installed.
+	 * @throws SSLException If any exception is thrown. It contains all the 
+	 *                      thrown exception's information.
+	 * @return A new <code>SSLSocketFactory</code>.
+	 */
+	public static SSLSocketFactory createSSLSocketFactory(SSLTrustManager[] tm) 
+	throws SSLException, SSLNotSupportedException {
+		boolean sslNotSupported = false;
+		Exception exception = null;
+		
+		try {
+			return createJava14SSLSocketFactory(tm);
+		} catch (ClassNotFoundException cnfe) {
+			// try JSSE after try/catch block
+		} catch (NoSuchMethodException nsme) {
+			// try JSSE after try/catch block
+		} catch (InvocationTargetException ite) {
+			// try JSSE after try/catch block
+		} catch (IllegalAccessException eae) {
+			// try JSSE after try/catch block
+		} catch (Exception exc) {
+			// try JSSE after try/catch block
+		}
+		
+		try {
+			return createJsseSSLSocketFactory(tm);
+		} catch (ClassNotFoundException cnfe) {
+			exception = cnfe;
+			sslNotSupported = true;
+		} catch (NoSuchMethodException nsme) {
+			exception = nsme;
+			sslNotSupported = true;
+		} catch (InstantiationException ie) {
+			exception = ie;
+			sslNotSupported = true;
+		} catch (InvocationTargetException ite) {
+			exception = ite;
+			sslNotSupported = true;
+		} catch (IllegalAccessException eae) {
+			exception = eae;
+			sslNotSupported = true;
+		} catch (Exception exc) {
+			exception = exc;
+		}
+		
+		StringWriter sw = new StringWriter();
+		PrintWriter pw = new PrintWriter(sw);
+		exception.printStackTrace(pw);
+		pw.close();
+		
+		if (sslNotSupported) {
+			throw new SSLNotSupportedException("Neither JSSE nor J2SE " +
+					">= 1.4 installed:\n---\n"+
+			sw.toString() +"---");
+		} else {
+			throw new SSLException("Exception while creating "+
+					"the SSLSocketFactory with JSSE:\n---\n"+ 
+					sw.toString() + "---");
+		}
+	}
+	
+// ------------------------------
+	
+	/**
+	 * Creates a new <code>SSLSocketFactory</code> using the 
+	 * <code>javax.net.ssl.*</code> classes.
+	 * @param tm The trustmanagers.
+	 * @return A <code>javax.net.ssl.SSLSocketFactory</code>.
+	 * @throws ClassNotFoundException If the classes could not be loaded and 
+	 * accessed properly
+	 * @throws NoSuchMethodException If the classes could not be loaded and 
+	 * accessed properly
+	 * @throws InvocationTargetException If the classes could not be loaded and 
+	 * accessed properly
+	 * @throws IllegalAccessException If the classes could not be loaded and 
+	 * accessed properly
+	 */
+	private static SSLSocketFactory createJava14SSLSocketFactory(SSLTrustManager[] tm) 
+	throws ClassNotFoundException, NoSuchMethodException, 
+	InvocationTargetException, IllegalAccessException {
+		/*
+		 * The code below does the following:
+		 * TrustManagerJava14Wrapper[] tmWrappers = TrustManagerJava14Wrapper.wrap(tm);
+		 * javax.net.ssl.SSLContext context = javax.net.ssl.SSLContext.getInstance("SSL");
+		 * context.init(null, tmWrappers, null);
+		 * SSLSocketFactory socketFactory = context.getSocketFactory();
+		 */
+		
+		Class stringClass = String.class;
+		Class contextClass = Class.forName("javax.net.ssl.SSLContext");
+		Class keyManagerClass = Class.forName("javax.net.ssl.KeyManager");
+		Class keyManagerArrayClass = java.lang.reflect.Array.newInstance(keyManagerClass, 0).getClass();
+		Class trustManagerClass = Class.forName("javax.net.ssl.TrustManager");
+		Class trustManagerArrayClass = java.lang.reflect.Array.newInstance(trustManagerClass, 0).getClass();
+		Class secureRandomClass = java.security.SecureRandom.class;
+
+		Method getInstanceMethod = contextClass.getMethod("getInstance", new Class[] { stringClass });
+		Method initMethod = contextClass.getMethod("init", new Class[] { keyManagerArrayClass, trustManagerArrayClass, secureRandomClass });
+		Method getSocketFactoryMethod = contextClass.getMethod("getSocketFactory", null);
+		
+		Class.forName("javax.net.ssl.X509TrustManager"); // check for availability
+		TrustManagerJava14Wrapper[] tmWrappers = TrustManagerJava14Wrapper.wrap(tm);
+		
+		String protocol = SSLIRCConnection.protocol;
+		Object context = getInstanceMethod.invoke(null, new Object[] { protocol });
+		initMethod.invoke(context, new Object[] { null, tmWrappers, null });
+		Object socketFactory = getSocketFactoryMethod.invoke(context, null);
+
+		return (SSLSocketFactory)socketFactory;
+	}
+	
+// ------------------------------
+
+	/**
+	 * Creates a new <code>SSLSocketFactory</code> using the 
+	 * <code>com.sun.net.ssl.*</code> and <code>javax.net.ssl.*</code> classes.
+	 * @param tm The trustmanagers.
+	 * @return A <code>javax.net.ssl.SSLSocketFactory</code>.
+	 * @throws ClassNotFoundException If the classes could not be loaded and 
+	 * accessed properly
+	 * @throws NoSuchMethodException If the classes could not be loaded and 
+	 * accessed properly
+	 * @throws InvocationTargetException If the classes could not be loaded and 
+	 * accessed properly
+	 * @throws IllegalAccessException If the classes could not be loaded and 
+	 * accessed properly
+	 */
+	private static SSLSocketFactory createJsseSSLSocketFactory(SSLTrustManager[] tm) 
+	throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
+	InvocationTargetException, IllegalAccessException {
+		/*
+		 * The code below does the following:
+		 * java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
+		 * 
+		 * TrustManagerJsseWrapper[] tmWrappers = TrustManagerJsseWrapper.wrap(tm);
+		 * com.sun.net.ssl.SSLContext context = com.sun.net.ssl.SSLContext.getInstance("SSL");
+		 * context.init(null, tmWrappers, null);
+		 * SSLSocketFactory socketFactory = context.getSocketFactory();
+		 */
+		
+		Class securityClass = Class.forName("java.security.Security");
+		Class providerClass = Class.forName("java.security.Provider");
+		Class sslProviderClass = Class.forName("com.sun.net.ssl.internal.ssl.Provider");
+		
+		Method addProvider = securityClass.getMethod("addProvider", new Class[] { providerClass });
+		
+		Object provider = sslProviderClass.newInstance();
+		addProvider.invoke(null, new Object[] { provider });
+		
+		
+		Class stringClass = String.class;
+		Class contextClass = Class.forName("com.sun.net.ssl.SSLContext");
+		Class keyManagerClass = Class.forName("com.sun.net.ssl.KeyManager");
+		Class keyManagerArrayClass = java.lang.reflect.Array.newInstance(keyManagerClass, 0).getClass();
+		Class trustManagerClass = Class.forName("com.sun.net.ssl.TrustManager");
+		Class trustManagerArrayClass = java.lang.reflect.Array.newInstance(trustManagerClass, 0).getClass();
+		Class secureRandomClass = java.security.SecureRandom.class;
+
+		Method getInstanceMethod = contextClass.getMethod("getInstance", new Class[] { stringClass });
+		Method initMethod = contextClass.getMethod("init", new Class[] { keyManagerArrayClass, trustManagerArrayClass, secureRandomClass });
+		Method getSocketFactoryMethod = contextClass.getMethod("getSocketFactory", null);
+		
+		Class.forName("com.sun.net.ssl.X509TrustManager"); // check for availability
+		TrustManagerJsseWrapper[] tmWrappers = TrustManagerJsseWrapper.wrap(tm);
+		
+		String protocol = SSLIRCConnection.protocol;
+		Object context = getInstanceMethod.invoke(null, new Object[] { protocol });
+		initMethod.invoke(context, new Object[] { null, tmWrappers, null });
+		Object socketFactory = getSocketFactoryMethod.invoke(context, null);
+
+		return (SSLSocketFactory)socketFactory;
+	}
+}

+ 47 - 0
daemon/src/org/fox/ttirc/irclib/ssl/SSLTrustManager.java

@@ -0,0 +1,47 @@
+/*
+ * IRClib -- A Java Internet Relay Chat library -- class SSLTrustManager
+ * Copyright (C) 2002 - 2006 Christoph Schwering <[email protected]>
+ * 
+ * This library and the accompanying materials are made available under the
+ * terms of the
+ * 	- GNU Lesser General Public License,
+ * 	- Apache License, Version 2.0 and
+ * 	- Eclipse Public License v1.0.
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY.
+ */
+
+package org.fox.ttirc.irclib.ssl;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * A trust manager decides whether the server is trusted or not.
+ * @author Christoph Schwering &lt;[email protected]&gt;
+ * @since 1.10
+ * @version 1.00
+ * @see SSLIRCConnection
+ * @see SSLDefaultTrustManager
+ */
+public interface SSLTrustManager {
+	/**
+	 * Checks whether the server is trusted or not. <br />
+	 * Given the partial or complete certificate chain provided by the peer,
+	 * build a certificate path to a trusted root and return true if it can 
+	 * be validated and is trusted for server SSL authentication.
+	 * @param chain The peer certificate chain.
+	 * @return <code>true</code> if the server is trusted, <code>false</code>
+	 * if the server is not trusted.
+	 */
+	public boolean isTrusted(X509Certificate[] chain);
+	
+// ------------------------------
+	
+	/**
+	 * Return an array of certificate authority certificates which are trusted 
+	 * for authenticating peers.
+	 * @return A non-null (possibly empty) array of acceptable CA issuer 
+	 * certificates.