summaryrefslogtreecommitdiffstats
path: root/EssentialsUpdate/src/f00f/net/irc/martyr/commands
diff options
context:
space:
mode:
authorsnowleo <schneeleo@gmail.com>2011-10-12 03:14:07 +0200
committersnowleo <schneeleo@gmail.com>2011-10-12 03:14:26 +0200
commit860d446d28776ec842fa53e8e08538d4e093d6e9 (patch)
tree0c4598eae4eb8c59fd36e8312eab1b27a8018794 /EssentialsUpdate/src/f00f/net/irc/martyr/commands
parent9ec398b39b0f48392a9d635041b392c7dba2ca0c (diff)
downloadEssentials-860d446d28776ec842fa53e8e08538d4e093d6e9.tar
Essentials-860d446d28776ec842fa53e8e08538d4e093d6e9.tar.gz
Essentials-860d446d28776ec842fa53e8e08538d4e093d6e9.tar.lz
Essentials-860d446d28776ec842fa53e8e08538d4e093d6e9.tar.xz
Essentials-860d446d28776ec842fa53e8e08538d4e093d6e9.zip
EssentialsUpdate WIP
Diffstat (limited to 'EssentialsUpdate/src/f00f/net/irc/martyr/commands')
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractCommand.java32
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractInCommand.java174
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/ActionCtcp.java12
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/ChannelModeCommand.java189
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpMessage.java129
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpNotice.java131
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/InviteCommand.java90
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/IsonCommand.java144
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/JoinCommand.java131
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/KickCommand.java110
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/MessageCommand.java127
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/ModeCommand.java237
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/NamesCommand.java77
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/NickCommand.java97
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/NoticeCommand.java129
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/PartCommand.java126
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/PassCommand.java33
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/PingCommand.java67
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/PongCommand.java39
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/QuitCommand.java132
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/RawCommand.java58
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/TopicCommand.java80
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/UnknownCommand.java38
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserCommand.java46
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserModeCommand.java99
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/WelcomeCommand.java125
-rw-r--r--EssentialsUpdate/src/f00f/net/irc/martyr/commands/WhoisCommand.java40
27 files changed, 2692 insertions, 0 deletions
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractCommand.java
new file mode 100644
index 000000000..a3e3ef2c2
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractCommand.java
@@ -0,0 +1,32 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.OutCommand;
+
+/**
+ * Defines a generic command. Most commands will simply have to
+ * override the getIrcIdentifier method and implement the parse and
+ * render methods using convenience methods.
+ */
+public abstract class AbstractCommand extends AbstractInCommand implements OutCommand
+{
+
+ /**
+ * Forms a string appropriate to send to the server. All commands can
+ * be sent by the client.
+ */
+ public String render()
+ {
+ // no prefix, since we are sending as a client.
+ return getIrcIdentifier() + " " + renderParams();
+ }
+
+ /**
+ * Renders the parameters of this command.
+ *
+ * @return String of rendered parameters
+ */
+ public abstract String renderParams();
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractInCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractInCommand.java
new file mode 100644
index 000000000..97f305241
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractInCommand.java
@@ -0,0 +1,174 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import f00f.net.irc.martyr.CommandRegister;
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.State;
+import f00f.net.irc.martyr.clientstate.ClientState;
+
+/**
+ * Defines a generic command. Most commands will simply have to
+ * override the getIrcIdentifier method and implement the parse and
+ * render methods using convenience methods.
+ */
+public abstract class AbstractInCommand implements InCommand
+{
+
+ protected Map<String,String> attributes = new HashMap<String,String>();
+
+ protected AbstractInCommand()
+ {
+ }
+
+ protected AbstractInCommand( String[] attributeNames )
+ {
+ for (String attributeName : attributeNames) {
+ attributes.put(attributeName, null);
+ }
+ }
+
+ public String getAttribute( String key )
+ {
+ return attributes.get( key );
+ }
+
+ public Iterator getAttributeKeys()
+ {
+ return Collections.unmodifiableSet( attributes.keySet() ).iterator();
+ }
+
+ protected void setAttribute( String key, String value )
+ {
+ attributes.put( key, value );
+ }
+
+ private String sourceString;
+
+ /**
+ * Some commands, when received by the server, can only occur in one
+ * state. Thus, when this command is received, the protocol should
+ * assume that it is that state. A command can use the 'unknown'
+ * state to indicate it can be received in any state (for example,
+ * ping). Most commands will occur in the REGISTERED state, so for a
+ * few exeptions, commands can leave this alone.
+ */
+ public State getState()
+ {
+ return State.REGISTERED;
+ }
+
+ /**
+ * Every command should know how to register itself (or not) with the
+ * command parsing engine. If a command is available under mutiple
+ * identifiers, then this method can be overridden and the addCommand
+ * method can be called multiple times.
+ */
+ public void selfRegister( CommandRegister commandRegister )
+ {
+ commandRegister.addCommand( getIrcIdentifier(), this );
+ }
+
+ /**
+ * Parses a string and produces a formed command object, if it can.
+ * Should return null if it cannot form the command object.
+ */
+ public abstract InCommand parse( String prefix, String identifier, String params );
+
+ /**
+ * By default, commands do not update the client state.
+ */
+ public boolean updateClientState( ClientState state )
+ {
+ return false;
+ }
+
+ /**
+ * Utility method to make parsing easy. Provides parameter n, where
+ * n=0 is the first parameter. Parses out the : and considers
+ * anything after a : to be one string, the final parameter.
+ *
+ * If the index doesn't exist, returns null. Should it throw
+ * IndexOutOfBoundsException? No, some commands may have optional
+ * fields.
+ *
+ * @param params String with parameters in it
+ * @param num Position number of parameter to be requested
+ * @return Parameter specified by id in params string
+ */
+ public String getParameter( String params, int num )
+ {
+ int colonIndex = params.indexOf( " :" );
+ colonIndex++; // Skip the space, we just needed it to be sure it's really a "rest of line" colon
+ String textParam = null;
+ String spaceParams;
+
+ if( colonIndex < 0 )
+ {
+ spaceParams = params;
+ }
+ else if( colonIndex == 0 )
+ {
+ if( num == 0 )
+ return params.substring( 1, params.length() );
+ else
+ return null;
+ // throw exception?
+ }
+ else
+ {
+ // colon index > 0, so we have at least one parameter before
+ // the final parameter.
+ spaceParams = params.substring( 0, colonIndex ).trim();
+ textParam = params.substring( colonIndex + 1, params.length() );
+ }
+
+ StringTokenizer tokens = new StringTokenizer( spaceParams, " " );
+
+ while( tokens.hasMoreTokens() && num > 0 )
+ {
+ // strip off tokensi
+ --num;
+ tokens.nextToken();
+ }
+
+ if( num == 0 && tokens.hasMoreTokens() )
+ return tokens.nextToken();
+ if( num == 0 && !tokens.hasMoreTokens() )
+ return textParam;
+
+
+ return null;
+ // throw exception?
+ }
+
+ public int getIntParameter( String params, int paramnum, int defaultNum )
+ {
+ try
+ {
+ return Integer.parseInt( getParameter( params, paramnum ) );
+ }
+ catch( NumberFormatException nfe )
+ {
+ return defaultNum;
+ }
+
+ }
+
+ public void setSourceString( String source )
+ {
+ this.sourceString = source;
+ }
+
+ public String getSourceString()
+ {
+ return sourceString;
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ActionCtcp.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ActionCtcp.java
new file mode 100644
index 000000000..f599f16b7
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ActionCtcp.java
@@ -0,0 +1,12 @@
+package f00f.net.irc.martyr.commands;
+
+/**
+ * ActionCtcp allows the application to do a '/me'.
+ */
+public class ActionCtcp extends CtcpMessage
+{
+ public ActionCtcp( String dest, String message )
+ {
+ super( dest, "ACTION " + message );
+ }
+}
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ChannelModeCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ChannelModeCommand.java
new file mode 100644
index 000000000..f8305852b
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ChannelModeCommand.java
@@ -0,0 +1,189 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.Mode;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.modes.channel.AnonChannelMode;
+import f00f.net.irc.martyr.modes.channel.BanMode;
+import f00f.net.irc.martyr.modes.channel.ExceptionMode;
+import f00f.net.irc.martyr.modes.channel.InviteMaskMode;
+import f00f.net.irc.martyr.modes.channel.InviteOnlyMode;
+import f00f.net.irc.martyr.modes.channel.KeyMode;
+import f00f.net.irc.martyr.modes.channel.LimitMode;
+import f00f.net.irc.martyr.modes.channel.ModeratedMode;
+import f00f.net.irc.martyr.modes.channel.NoExtMsgMode;
+import f00f.net.irc.martyr.modes.channel.OperMode;
+import f00f.net.irc.martyr.modes.channel.PrivateMode;
+import f00f.net.irc.martyr.modes.channel.SecretMode;
+import f00f.net.irc.martyr.modes.channel.TopicLockMode;
+import f00f.net.irc.martyr.modes.channel.VoiceMode;
+import f00f.net.irc.martyr.util.FullNick;
+
+/**
+ * Defines the ChannelMode command. Can be used to send a Channel
+ * mode. For receiving, this defines which channel modes Martyr knows
+ * about and passes them on to the Channel object. Note that the
+ * actual logic of what happens when a mode arrives lies in the
+ * clientstate.Channel object.
+ */
+public class ChannelModeCommand extends ModeCommand
+{
+
+ private String prefix;
+ private String channelName;
+ private FullNick sender;
+
+ private List modes;
+
+ private static HashMap<Character,Mode> modeTypes;
+
+ /**
+ * For receiving a mode command.
+ * @param prefix Currently unused prefix string
+ * @param channelName Channel that the mode change is in reference to
+ * @param params List of params to be parsed
+ */
+ public ChannelModeCommand( String prefix, String channelName,
+ StringTokenizer params )
+ {
+ makeModes();
+
+ this.prefix = prefix;
+ this.channelName = channelName;
+
+ modes = parseModes( modeTypes, params );
+
+ // System.out.println( modes );
+ }
+
+ /**
+ * For sending a mode discovery.
+ *
+ * @param channelName Channel that the mode change is in reference to
+ */
+ public ChannelModeCommand( String channelName )
+ {
+ sender = null;
+ this.channelName = channelName;
+
+ // Empty list, no modes.
+ modes = new LinkedList();
+ }
+
+ public void makeModes()
+ {
+ if( modeTypes == null )
+ {
+ modeTypes = new HashMap<Character,Mode>();
+
+ registerMode( modeTypes, new BanMode() );
+ registerMode( modeTypes, new KeyMode() );
+ registerMode( modeTypes, new OperMode() );
+ registerMode( modeTypes, new VoiceMode() );
+ registerMode( modeTypes, new LimitMode() );
+ // registerMode( modeTypes, new QuietMode() );
+ registerMode( modeTypes, new SecretMode() );
+ registerMode( modeTypes, new PrivateMode() );
+ registerMode( modeTypes, new NoExtMsgMode() );
+ registerMode( modeTypes, new ExceptionMode() );
+ registerMode( modeTypes, new TopicLockMode() );
+ registerMode( modeTypes, new ModeratedMode() );
+ registerMode( modeTypes, new InviteMaskMode() );
+ registerMode( modeTypes, new InviteOnlyMode() );
+ registerMode( modeTypes, new AnonChannelMode() );
+ }
+ }
+
+ /**
+ * Shouldn't be called, as ModeCommand should be responsible for parsing
+ * and creating this class.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ throw new IllegalStateException( "Don't call this method!" );
+ }
+
+ public String render()
+ {
+ return "MODE " + channelName + renderParams();
+ }
+
+ public String renderParams()
+ {
+ Iterator modesI = modes.iterator();
+
+ String modes = "";
+ String params = "";
+
+ while( modesI.hasNext() )
+ {
+ Mode mode = (Mode)modesI.next();
+
+ if( mode.getSign() != Mode.Sign.NOSIGN )
+ {
+ modes += (mode.getSign() == Mode.Sign.POSITIVE ? "+" : "-" );
+ }
+ modes += mode.getChar();
+
+ if( mode.getParam() != null )
+ {
+ // Does the parameter list already have params?
+ // If so, stick in a space.
+ if( params.length() > 0 )
+ {
+ params += " ";
+ }
+ params += mode.getParam();
+ }
+ }
+
+ return modes + " " + params;
+ }
+
+ public String getChannel()
+ {
+ return channelName;
+ }
+
+ public FullNick getSender()
+ {
+ return sender;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ /**
+ * Passes the modes on to the clientstate.Channel object.
+ */
+ public boolean updateClientState( ClientState state )
+ {
+ boolean changed = false;
+
+ Iterator modesI = modes.iterator();
+ Channel channel = state.getChannel( channelName );
+
+ while( modesI.hasNext() )
+ {
+ Mode mode = (Mode)modesI.next();
+
+ channel.setMode( mode );
+
+ changed = true;
+ }
+
+ return changed;
+ }
+
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpMessage.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpMessage.java
new file mode 100644
index 000000000..6012aa0ab
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpMessage.java
@@ -0,0 +1,129 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.StringTokenizer;
+
+import f00f.net.irc.martyr.util.FullNick;
+
+/**
+ * This facilitates the sending and receiving of CTCP messages. Upon
+ * receiving a message, MessageCommand checks to see if it is a CTCP,
+ * and if it is, it instantiates this class instead of a
+ * MessageCommand. You can then use the getAction() and getMessage()
+ * methods to retreive the action and payload, respectively.
+ *
+ * @see MessageCommand
+ */
+public class CtcpMessage extends MessageCommand
+{
+ private String actionStr;
+
+ /**
+ * Use this to send a CTCP message. This simply wraps the string
+ * with the CTCP tags, \001.
+ *
+ * @param dest Target of CTCP message
+ * @param message Actual CTCP message
+ */
+ public CtcpMessage( String dest, String message )
+ {
+ super( dest, "\001" + message + "\001" );
+ }
+
+ public CtcpMessage( String dest, String action, String message )
+ {
+ this( dest, action + " " + message );
+ }
+
+ /**
+ * This is only to be called by MessageCommand, as a way of
+ * receiving a Ctcp message. It strips the \001's off and holds
+ * the message left over.
+ *
+ * @param from Nick that sent the message
+ * @param dest Target of the CTCP message
+ * @param message Actual CTCP message
+ */
+ protected CtcpMessage( FullNick from, String dest, String message )
+ {
+ super( from, dest, getMessageStr( stripCtcpWrapper( message ) ) );
+
+ actionStr = getActionStr( stripCtcpWrapper( message ) );
+ }
+
+ /**
+ * Returns the action of this CTCP. Use getMessage() to retreive
+ * the payload of the action.
+ *
+ * @return The action specified by the CTCP message
+ */
+ public String getAction()
+ {
+ return actionStr;
+ }
+
+ /**
+ * Given a stripped CTCP message, returns the ctcp action string.
+ *
+ * @param msg Message to be parsed into an action
+ * @return Action string from message
+ */
+ public static String getActionStr( String msg )
+ {
+ StringTokenizer tokens = new StringTokenizer( msg );
+ return tokens.nextToken();
+ }
+
+ public static String getMessageStr( String msg )
+ {
+ String acn = getActionStr( msg );
+ return msg.substring( acn.length() ).trim();
+ }
+
+ /**
+ * If the string is wrapped with CTCP signal chars (\001) returns
+ * true.
+ *
+ * @param msg String to check whether it's a CTCP message or not
+ * @return True or false if it's a CTCP message
+ */
+ public static boolean isCtcpString( String msg )
+ {
+ return msg.charAt(0) == '\001' && msg.charAt(msg.length()-1) == '\001';
+ }
+
+ /**
+ * Strips a CTCP wrapper, if there is one.
+ *
+ * @param msg String to be stripped
+ * @return Stripped string
+ */
+ public static String stripCtcpWrapper( String msg )
+ {
+ if( isCtcpString( msg ) )
+ {
+ return msg.substring( 1, msg.length()-1 );
+ }
+ else
+ {
+ return msg;
+ }
+ }
+
+ /**
+ * Dysfunctional. Returns dat immediatly.
+ */
+ /*public static byte[] escapeMsg( byte[] dat )
+ {
+ return dat;
+ }*/
+
+ /**
+ * Dysfunctional. Returns dat immediatly.
+ */
+ /*public static byte[] unEscapeMsg( byte[] dat )
+ {
+ return dat;
+ }*/
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpNotice.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpNotice.java
new file mode 100644
index 000000000..e40c0a01a
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpNotice.java
@@ -0,0 +1,131 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.StringTokenizer;
+
+import f00f.net.irc.martyr.util.FullNick;
+
+/**
+ * This facilitates the sending and receiving of CTCP messages. Upon
+ * receiving a message, MessageCommand checks to see if it is a CTCP,
+ * and if it is, it instantiates this class instead of a
+ * MessageCommand. You can then use the getAction() and getMessage()
+ * methods to retreive the action and payload, respectively.
+ *
+ * @see NoticeCommand
+ */
+public class CtcpNotice extends NoticeCommand
+{
+ private String actionStr;
+
+ /**
+ * Use this to send a CTCP message. This simply wraps the string
+ * with the CTCP tags, \001.
+ *
+ * @param dest Target of CTCP message
+ * @param message Actual CTCP message
+ */
+ public CtcpNotice( String dest, String message )
+ {
+ super( dest, "\001" + message + "\001" );
+ }
+
+ public CtcpNotice( String dest, String action, String message )
+ {
+ this( dest, action + " " + message );
+
+ actionStr = action;
+ }
+
+ /**
+ * This is only to be called by MessageCommand, as a way of
+ * receiving a Ctcp message. It strips the \001's off and holds
+ * the message left over.
+ *
+ * @param from Nick that sent the message
+ * @param dest Target of the CTCP message
+ * @param message Actual CTCP message
+ */
+ protected CtcpNotice( FullNick from, String dest, String message )
+ {
+ super( from, dest, getMessageStr( stripCtcpWrapper( message ) ) );
+
+ actionStr = getActionStr( stripCtcpWrapper( message ) );
+ }
+
+ /**
+ * Returns the action of this CTCP. Use getMessage() to retreive
+ * the payload of the action.
+ *
+ * @return The action specified by the CTCP message
+ */
+ public String getAction()
+ {
+ return actionStr;
+ }
+
+ /**
+ * Given a stripped CTCP message, returns the ctcp action string.
+ *
+ * @param msg Message to be parsed into an action
+ * @return Action string from message
+ */
+ public static String getActionStr( String msg )
+ {
+ StringTokenizer tokens = new StringTokenizer( msg );
+ return tokens.nextToken();
+ }
+
+ public static String getMessageStr( String msg )
+ {
+ String acn = getActionStr( msg );
+ return msg.substring( acn.length() ).trim();
+ }
+
+ /**
+ * If the string is wrapped with CTCP signal chars (\001) returns
+ * true.
+ *
+ * @param msg String to check whether it's a CTCP message or not
+ * @return True or false if it's a CTCP message
+ */
+ public static boolean isCtcpString( String msg )
+ {
+ return msg.charAt(0) == '\001' && msg.charAt(msg.length()-1) == '\001';
+ }
+
+ /**
+ * Strips a CTCP wrapper, if there is one.
+ *
+ * @param msg String to be stripped
+ * @return Stripped string
+ */
+ public static String stripCtcpWrapper( String msg )
+ {
+ if( isCtcpString( msg ) )
+ {
+ return msg.substring( 1, msg.length()-1 );
+ }
+ else
+ {
+ return msg;
+ }
+ }
+
+ /**
+ * Dysfunctional. Returns dat immediatly.
+ */
+ /*public static byte[] escapeMsg( byte[] dat )
+ {
+ return dat;
+ }*/
+
+ /**
+ * Dysfunctional. Returns dat immediatly.
+ */
+ /*public static byte[] unEscapeMsg( byte[] dat )
+ {
+ return dat;
+ }*/
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/InviteCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/InviteCommand.java
new file mode 100644
index 000000000..9010a4322
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/InviteCommand.java
@@ -0,0 +1,90 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.util.FullNick;
+import f00f.net.irc.martyr.util.ParameterIterator;
+
+/**
+ * @author <a href="mailto:martyr@mog.se">Morgan Christiansson</a>
+ */
+public class InviteCommand extends AbstractCommand {
+
+ private String _channel;
+ private String _nick;
+ private FullNick _user;
+
+ /** For use as a factory */
+ public InviteCommand()
+ {
+ _channel = null;
+ _nick = null;
+ _user = null;
+ }
+
+ private InviteCommand(FullNick user, String nick, String channel)
+ {
+ _user = user;
+ _nick = nick;
+ _channel = channel;
+ }
+
+ public InviteCommand(String nick, String channel)
+ {
+ _nick = nick;
+ _channel = channel;
+ }
+
+ public InviteCommand(FullNick nick, String channel)
+ {
+ this(nick.getNick(), channel);
+ }
+
+ /* (non-Javadoc)
+ * @see f00f.net.irc.martyr.Command#parse(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public InCommand parse(String prefix, String identifier, String params)
+ {
+ ParameterIterator iter = new ParameterIterator(params);
+ return new InviteCommand( new FullNick( prefix ), (String)iter.next(), (String)iter.next() );
+ }
+
+ /* (non-Javadoc)
+ * @see f00f.net.irc.martyr.commands.AbstractCommand#getIrcIdentifier()
+ */
+ public String getIrcIdentifier()
+ {
+ return "INVITE";
+ }
+
+ /* (non-Javadoc)
+ * @see f00f.net.irc.martyr.commands.AbstractCommand#renderParams()
+ */
+ public String renderParams()
+ {
+ return _nick+" "+_channel;
+ }
+
+ /**
+ * @return The channel invited to. */
+ public String getChannel()
+ {
+ return _channel;
+ }
+
+ /**
+ * @return The nick sending the invite.
+ */
+ public String getNick()
+ {
+ return _nick;
+ }
+
+ /**
+ * @return The user the invite is sent to.
+ */
+ public FullNick getUser()
+ {
+ return _user;
+ }
+}
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/IsonCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/IsonCommand.java
new file mode 100644
index 000000000..8df571a8e
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/IsonCommand.java
@@ -0,0 +1,144 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.CommandRegister;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Defines the ISON command, which is used to determine if a user or a list of users is online.
+ *
+ * @author Daniel Henninger
+ */
+public class IsonCommand extends AbstractCommand
+{
+
+ public static final String IDENTIFIER_PRIMARY = "ISON";
+ public static final String IDENTIFIER_SECONDARY = "303";
+
+ /* List of nicks that we will check for online status */
+ List<String> nicks = new ArrayList<String>();
+
+ /* Destination nick */
+ String dest = null;
+
+ /**
+ * No parameter passed to the ISON is not valid. This is used for factories.
+ */
+ public IsonCommand()
+ {
+ // Nothing to do
+ }
+
+ /**
+ * Check online status of a single nickname.
+ *
+ * @param nick Nick you want to check the online status of.
+ */
+ public IsonCommand(String nick)
+ {
+ this.nicks.add(nick);
+ }
+
+ public IsonCommand(String dest, String nick) {
+ this.dest = dest;
+ this.nicks.add(nick);
+ }
+
+ /**
+ * Check online status of a number of nicknames.
+ *
+ * @param nicks List of nicks you want to check the online status of.
+ */
+ public IsonCommand(List<String> nicks)
+ {
+ this.nicks.addAll(nicks);
+ }
+
+ public IsonCommand(String dest, List<String> nicks) {
+ this.dest = dest;
+ this.nicks.addAll(nicks);
+ }
+
+ /**
+ * @see AbstractCommand#parse(String, String, String)
+ */
+ public InCommand parse(String prefix, String identifier, String params)
+ {
+ // when the command is used as a reply, the nick is parameter 0 and the rest are parameter 1.
+ if ( identifier.equals( IDENTIFIER_SECONDARY ) ) {
+ String nickParam = getParameter(params, 1);
+ List<String> nicks = Arrays.asList(nickParam.split(" "));
+ return new IsonCommand(getParameter(params, 0), nicks);
+ }
+ else {
+ String nickParam = getParameter(params, 0);
+ List<String> nicks = Arrays.asList(nickParam.split(" "));
+ return new IsonCommand(nicks);
+ }
+ }
+
+ /**
+ * @see f00f.net.irc.martyr.commands.AbstractCommand#renderParams()
+ */
+ public String renderParams()
+ {
+ String ret = "";
+ if (nicks.size() > 0) {
+ Boolean isFirst = true;
+ for (String nick : nicks) {
+ if (isFirst) {
+ ret = ret + nick;
+ isFirst = false;
+ }
+ else {
+ ret = ret + " " + nick;
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * @see f00f.net.irc.martyr.Command#getIrcIdentifier()
+ */
+ public String getIrcIdentifier()
+ {
+ //
+ // This command uses "ISON" on outgoing, so that is why we use
+ // "ISON" here instead of "303".
+ //
+ return IDENTIFIER_PRIMARY;
+ }
+
+ /**
+ * @see AbstractCommand#selfRegister(f00f.net.irc.martyr.CommandRegister)
+ */
+ public void selfRegister(CommandRegister commandRegister)
+ {
+ commandRegister.addCommand( IDENTIFIER_PRIMARY, this );
+ commandRegister.addCommand( IDENTIFIER_SECONDARY, this );
+ }
+
+ /**
+ * Retrieves the target of the ISON command
+ *
+ * @return Target of command
+ */
+ public String getDest() {
+ return dest;
+ }
+
+ /**
+ * Retrieves the list of nicks that are online after an ISON command
+ *
+ * @return List of online nicks
+ */
+ public List<String> getNicks()
+ {
+ return nicks;
+ }
+
+}
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/JoinCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/JoinCommand.java
new file mode 100644
index 000000000..32f2d1e75
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/JoinCommand.java
@@ -0,0 +1,131 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.util.FullNick;
+import java.util.logging.Logger;
+
+
+/**
+ * Defines JOIN command.
+ */
+public class JoinCommand extends AbstractCommand
+{
+
+ static Logger log = Logger.getLogger(JoinCommand.class.getName());
+
+ private String channel;
+ private String secret;
+ private FullNick user;
+
+ /** For use as a factory */
+ public JoinCommand()
+ {
+ this.user = null;
+ this.channel = null;
+ this.secret = null;
+ }
+
+ /**
+ * This constructor is used with an incoming JOIN command from the server.
+ *
+ * @param user User that joined the channel
+ * @param channel Channel that was joined
+ */
+ private JoinCommand( FullNick user, String channel )
+ {
+ this.user = user;
+ this.channel = channel;
+ this.secret = null;
+ }
+
+ /**
+ * This constructor is used to make a request to join a channel that
+ * requires a secret key to join.
+ *
+ * @param channel The channel
+ * @param secret The secret key required to enter the channel, or null of
+ * none.
+ */
+ public JoinCommand( String channel, String secret )
+ {
+ this.secret = secret;
+ this.user = null;
+ this.channel = channel;
+ }
+
+ /**
+ * This constructor is used to make a request to join a channel.
+ *
+ * @param channel Channel that will be joined
+ */
+ public JoinCommand( String channel )
+ {
+ this.secret = null;
+ this.user = null;
+ this.channel = channel;
+ }
+
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ return new JoinCommand( new FullNick( prefix ), getParameter( params, 0 ) );
+ }
+
+ public String getIrcIdentifier()
+ {
+ return "JOIN";
+ }
+
+ public String renderParams()
+ {
+ if( secret == null )
+ return channel;
+ else
+ return channel + " " + secret;
+ }
+
+ public String getChannel()
+ {
+ return channel;
+ }
+
+ public String getSecret()
+ {
+ return secret;
+ }
+
+ public FullNick getUser()
+ {
+ return user;
+ }
+
+ public boolean weJoined( ClientState state )
+ {
+ return user.equals( state.getNick() );
+ }
+
+ public boolean updateClientState( ClientState state )
+ {
+ if( weJoined( state ) )
+ {
+ // We've joined a group.
+ //log.debug("JOIN: We've joined " + channel);
+ state.addChannel( channel );
+ return true;
+ }
+ else
+ {
+ // Someone else joined the group.
+ //log.debug("JOIN: " + user + " joined " + channel);
+ // 1) Grab group
+ Channel channelObj = state.getChannel( channel );
+ // 2) Add user
+ channelObj.addMember( user, this );
+ return true;
+ }
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/KickCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/KickCommand.java
new file mode 100644
index 000000000..96b2731e1
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/KickCommand.java
@@ -0,0 +1,110 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.util.FullNick;
+import java.util.logging.Logger;
+
+
+/**
+ * Defines KICK command.
+ */
+public class KickCommand extends AbstractCommand
+{
+
+ static Logger log = Logger.getLogger(KickCommand.class.getName());
+
+ private String channel;
+ private FullNick userKicker;
+ private FullNick userKicked;
+ private String comment;
+
+ /** For use as a factory */
+ public KickCommand()
+ {
+ this( null, null, null, null );
+ }
+
+ public KickCommand( FullNick userKicker, String channel,
+ String userKicked, String comment )
+ {
+ this.userKicker = userKicker;
+ this.channel = channel;
+ this.userKicked = new FullNick( userKicked );
+ this.comment = comment;
+ }
+
+ public KickCommand( String channel, String userToKick, String comment )
+ {
+ this( null, channel, userToKick, comment );
+ }
+
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ return new KickCommand(
+ new FullNick( prefix ),
+ getParameter( params, 0 ),
+ getParameter( params, 1 ),
+ getParameter( params, 2 )
+ );
+ }
+
+ public String getIrcIdentifier()
+ {
+ return "KICK";
+ }
+
+ public String renderParams()
+ {
+ return channel + " " + userKicked + " :" + comment;
+ }
+
+ public String getChannel()
+ {
+ return channel;
+ }
+
+ public FullNick getKicker()
+ {
+ return userKicker;
+ }
+
+ public FullNick getKicked()
+ {
+ return userKicked;
+ }
+
+ public String getComment()
+ {
+ return comment;
+ }
+
+ public boolean kickedUs( ClientState state )
+ {
+ return userKicked.equals( state.getNick() );
+ }
+
+ public boolean updateClientState( ClientState state )
+ {
+ if( kickedUs( state ) )
+ {
+ // We've been kicked.
+ //log.debug("KICK: We've been kicked " + channel);
+ state.removeChannel( channel );
+ return true;
+ }
+ else
+ {
+ // Someone else was kicked.
+ //log.debug("KICK: " + userKicked.getNick() + " kicked " + channel);
+ // 1) Grab group
+ Channel channelObj = state.getChannel( channel );
+ channelObj.removeMember( userKicked, this );
+ return true;
+ }
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/MessageCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/MessageCommand.java
new file mode 100644
index 000000000..3d66f7c21
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/MessageCommand.java
@@ -0,0 +1,127 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.util.FullNick;
+
+
+/**
+ * Defines the PRIVMSG command. Messages can be sent to groups or to users.
+ */
+public class MessageCommand extends AbstractCommand
+{
+
+ private FullNick from;
+ private String dest;
+ private String message;
+
+
+ /** Factory */
+ public MessageCommand()
+ {
+ from = null;
+ dest = null;
+ message = null;
+ }
+
+ /**
+ * Used to send a message.
+ *
+ * @param dest Target for message
+ * @param message Message to be sent
+ */
+ public MessageCommand( String dest, String message )
+ {
+ this( null, dest, message );
+ }
+
+ /**
+ * Used to send a message.
+ *
+ * @param dest Target for message
+ * @param message Message to be sent
+ */
+ public MessageCommand( FullNick dest, String message )
+ {
+ this( dest.getNick(), message );
+ }
+
+ public MessageCommand( FullNick source, String dest, String message )
+ {
+ this.from = source;
+ this.dest = dest;
+ this.message = message;
+ }
+
+ /**
+ * Parses a string and produces a formed command object, if it can.
+ * Should return null if it cannot form the command object.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ FullNick from;
+ if( prefix == null || prefix.trim().length() == 0 )
+ {
+ from = null;
+ }
+ else
+ {
+ from = new FullNick( prefix );
+ }
+ String dest = getParameter( params, 0 );
+ String msg = getParameter( params, 1 );
+
+ if( CtcpMessage.isCtcpString( msg ) )
+ {
+ return new CtcpMessage( from, dest, msg );
+ }
+
+ return new MessageCommand( from, dest, msg );
+ }
+
+ /**
+ * Returns the string IRC uses to identify this command. Examples:
+ * NICK, PING, KILL, 332
+ */
+ public String getIrcIdentifier()
+ {
+ return "PRIVMSG";
+ }
+
+ /**
+ * Renders the parameters of this command.
+ */
+ public String renderParams()
+ {
+ return dest + " :" + message;
+ }
+
+ public FullNick getSource()
+ {
+ return from;
+ }
+
+ public String getDest()
+ {
+ return dest;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Returns true if the message is both private and for us.
+ *
+ * @param state Client state to compare with
+ * @return True or false if this is a private message to us
+ */
+ public boolean isPrivateToUs( ClientState state )
+ {
+ return state.getNick().equals( dest );
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ModeCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ModeCommand.java
new file mode 100644
index 000000000..b3c3e19ef
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/ModeCommand.java
@@ -0,0 +1,237 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import f00f.net.irc.martyr.CommandRegister;
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.Mode;
+import f00f.net.irc.martyr.OutCommand;
+import f00f.net.irc.martyr.State;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import java.util.logging.Logger;
+
+/**
+ * Defines MODE command. Since the MODE command is of two distinct
+ * types, this class is really more of a command mini-factory. It
+ * determines which type of command it is, either a UserModeCommand or
+ * a ChannelModeCommand.
+ *
+ */
+public class ModeCommand implements InCommand, OutCommand
+{
+ static Logger log = Logger.getLogger(ModeCommand.class.getName());
+
+ public static final String IDENTIFIER = "MODE";
+ private String source;
+
+ /** For use as a factory */
+ public ModeCommand()
+ {
+ }
+
+ public Iterator getAttributeKeys()
+ {
+ return new LinkedList().iterator();
+ }
+
+ public String getAttribute( String key )
+ {
+ return null;
+ }
+
+ public static void registerMode( Map<Character,Mode> modes, Mode mode )
+ {
+ Character modeChar = mode.getChar();
+
+ if( modes.get( modeChar ) != null )
+ {
+ log.severe("ModeCommand: Warning: Two modes with same letter: " +
+ modes.get( modeChar ) + " and " + mode);
+ }
+
+ modes.put( modeChar, mode );
+ }
+
+ public State getState()
+ {
+ return State.REGISTERED;
+ }
+
+ public void selfRegister( CommandRegister reg )
+ {
+ reg.addCommand( IDENTIFIER, this );
+ }
+
+ public String getIrcIdentifier()
+ {
+ return IDENTIFIER;
+ }
+
+ // Example
+ // <pre>:repp_!bdamm@dammfine.com MODE #bytesex +oo z * repp_telnet</pre>
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ // there are two kinds of modes. Either a channel mode, or a user
+ // mode. We need to figure out which we are dealing with, and
+ // return that.
+
+ // TODO: Research: Should we specify delimiters other than whitespace?
+ StringTokenizer tokens = new StringTokenizer( params );
+
+ String str = tokens.nextToken();
+
+ //log.debug("ModeCommand: Prefix: " + prefix + " str: " + str
+ // + " total: " + params);
+
+ // Malformed command.
+ if( str == null )
+ return null;
+
+ // Should we check to see if the string is really a channel
+ // that we know about?
+ if( Channel.isChannel( str ) )
+ {
+ return new ChannelModeCommand( prefix, str, tokens );
+ }
+ else
+ {
+ return new UserModeCommand( prefix, str, tokens );
+ }
+ }
+
+ /**
+ * Should not be called, as ModeCommand doesn't actually represent a
+ * command. Use UserModeCommand or ChannelModeCommand instead.
+ */
+ public String render()
+ {
+ throw new IllegalStateException("Don't try to send ModeCommand!");
+ }
+
+ public void setSourceString( String source )
+ {
+ this.source = source;
+ }
+
+ public String getSourceString()
+ {
+ return source;
+ }
+
+ /**
+ * Does nothing, as this is a factory command.
+ */
+ public boolean updateClientState( ClientState cs )
+ {
+ // Nothing here, move on.
+ return false;
+ }
+
+ public String toString()
+ {
+ return "ModeCommand";
+ }
+
+ /** Takes a mode string, such as: '+ooo A B C' or '+o A +o B' or even
+ * '+o-o A B' and returns a List containing Mode objects that
+ * correspond to the modes specified.
+ *
+ * @param modes is a Map of Character to Mode objects.
+ * @param tokens is the sequence of tokens making up the parameters of
+ * the command.
+ * @return List of modes
+ */
+ public List<Mode> parseModes( Map<Character,Mode> modes, StringTokenizer tokens )
+ {
+ LinkedList<Mode> results = new LinkedList<Mode>();
+
+ while( true )
+ {
+ if( tokens.hasMoreTokens() )
+ {
+ parseOneModeSet( modes, tokens, results );
+ }
+ else
+ {
+ return results;
+ }
+ }
+ }
+
+ /**
+ * Parses one group of modes. '+ooo A B C' and not '+o A +o B'. It
+ * will parse the first group it finds and will ignore the rest.
+ *
+ * @param modes Map of character to Mode objects.
+ * @param tokens Sequence of tokens making up the parameters of the command.
+ * @param results List of Mode results to be filled in
+ */
+ private void parseOneModeSet( Map<Character,Mode> modes, StringTokenizer tokens, List<Mode> results )
+ {
+ // A list of modes that we have.
+ LinkedList<Mode> localModes = new LinkedList<Mode>();
+
+ Mode.Sign sign = Mode.Sign.NOSIGN;
+ String chars = tokens.nextToken();
+
+ int stop = chars.length();
+ for( int i = 0; i < stop; ++i )
+ {
+ char lookingAt = chars.charAt( i );
+ if( lookingAt == '+' )
+ sign = Mode.Sign.POSITIVE;
+ else if( lookingAt == '-' )
+ sign = Mode.Sign.NEGATIVE;
+ else if( lookingAt == ':' )
+ // This is to get around a bug in some ircds
+ continue;
+ else
+ {
+ // A real mode character!
+ Mode mode = modes.get( lookingAt );
+ if( mode == null )
+ {
+ //TODO: Is there some way we can figure out if the mode
+ // we don't know anything about needs a parameter?
+ // Things get messy if it does need a parameter, and we
+ // don't eat the string.
+ //log.severe("ModeCommand: Unknown mode: " + lookingAt);
+ }
+ else
+ {
+ mode = mode.newInstance();
+ mode.setSign( sign );
+ localModes.add( mode );
+ }
+ }
+ }
+
+ // Now we know what modes are specified, and whether they are
+ // positive or negative. Now we need to fill in the parameters for
+ // any that require parameters, and place the results in the result
+ // list.
+ for (Mode localMode : localModes) {
+ /*
+ * What we do if the server doesn't pass us a parameter
+ * for a mode is rather undefined - except that we don't
+ * want to run off the end of the tokens. So we just
+ * ignore it. The problem is that we don't always know
+ * when a server is going to send us a parameter or not.
+ * We can only hope that servers don't send ambiguous
+ * masks followed by more modes instead of a parameter.
+ */
+ if (localMode != null && localMode.requiresParam() && tokens.hasMoreTokens()) {
+ localMode.setParam(tokens.nextToken());
+ }
+
+ results.add(localMode);
+ }
+ }
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NamesCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NamesCommand.java
new file mode 100644
index 000000000..6f0a9ed5d
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NamesCommand.java
@@ -0,0 +1,77 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.OutCommand;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Defines the NAMES command, which is used to get the members of certain channels, or all of them.
+ *
+ * @author Daniel Henninger
+ */
+public class NamesCommand implements OutCommand
+{
+
+ /* List of channels we will request membership of. */
+ List<String> channels = new ArrayList<String>();
+
+ /**
+ * No parameter passed to the NAMES command represents a request for all channels.
+ */
+ public NamesCommand()
+ {
+ // Nothing to do
+ }
+
+ /**
+ * Request the membership of a single channel.
+ *
+ * @param channel Channel you want to request membership of.
+ */
+ public NamesCommand(String channel)
+ {
+ this.channels.add(channel);
+ }
+
+ /**
+ * Request the membership of multiple channels.
+ *
+ * @param channels List of channels you want to retrieve the membership list of.
+ */
+ public NamesCommand(List<String> channels)
+ {
+ this.channels.addAll(channels);
+ }
+
+ /**
+ * @see f00f.net.irc.martyr.OutCommand#render()
+ */
+ public String render()
+ {
+ String ret = getIrcIdentifier();
+ if (channels.size() > 0) {
+ ret = ret + " ";
+ Boolean isFirst = true;
+ for (String channel : channels) {
+ if (isFirst) {
+ ret = ret + channel;
+ isFirst = false;
+ }
+ else {
+ ret = ret + "," + channel;
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * @see f00f.net.irc.martyr.Command#getIrcIdentifier()
+ */
+ public String getIrcIdentifier()
+ {
+ return "NAMES";
+ }
+
+}
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NickCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NickCommand.java
new file mode 100644
index 000000000..6cdcb0224
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NickCommand.java
@@ -0,0 +1,97 @@
+/*
+ * Original version: Ben Damm <bdamm@dammfine.com>
+ * Changes by: Mog
+ * - added getOldNick
+ * */
+package f00f.net.irc.martyr.commands;
+
+import java.util.Enumeration;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.clientstate.Member;
+import f00f.net.irc.martyr.util.FullNick;
+
+/**
+ * Defines NICK command.
+ */
+public class NickCommand extends AbstractCommand
+{
+
+ private FullNick oldNick;
+ private FullNick newNick;
+
+ /** For use as a factory */
+ public NickCommand()
+ {
+ this( null, null );
+ }
+
+ public NickCommand( FullNick oldNick, FullNick newNick )
+ {
+ this.oldNick = oldNick;
+ this.newNick = newNick;
+ }
+
+ public NickCommand( String newNick )
+ {
+ this( null, new FullNick( newNick ) );
+ }
+
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ return new NickCommand( new FullNick( prefix ), new FullNick ( getParameter( params, 0 ) ) );
+ }
+
+ public String getIrcIdentifier()
+ {
+ return "NICK";
+ }
+
+ public String renderParams()
+ {
+ return getNick();
+ }
+
+ public String getNick()
+ {
+ return newNick.getNick();
+ }
+
+ public String getOldNick()
+ {
+ return oldNick.getNick();
+ }
+
+ public boolean updateClientState( ClientState state )
+ {
+ // Does this apply to us?
+ if( oldNick.equals( state.getNick() ) )
+ {
+ state.setNick( newNick );
+ return true;
+ }
+ else
+ {
+ // Ok, so we need to change someone's nick.
+ // This needs to occur for each member with that nick in each
+ // channel that we are in. Just use Member.setNick for each
+ // occurance.
+ // Note: I do not believe this code has received a vigorous
+ // test.
+ Enumeration channels = state.getChannels();
+ while( channels.hasMoreElements() )
+ {
+ Channel channel = (Channel)channels.nextElement();
+ Member member = channel.findMember( oldNick.getNick() );
+ if( member != null )
+ member.setNick( newNick );
+ }
+ }
+ return false;
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NoticeCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NoticeCommand.java
new file mode 100644
index 000000000..958dcc44f
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/NoticeCommand.java
@@ -0,0 +1,129 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.State;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.util.FullNick;
+
+
+/**
+ * Defines the NOTICE command.
+ */
+public class NoticeCommand extends AbstractCommand
+{
+
+ private FullNick from;
+ private String dest;
+ private String notice;
+
+ /** Factory */
+ public NoticeCommand()
+ {
+ from = null;
+ dest = null;
+ notice = null;
+ }
+
+ public NoticeCommand( String notice )
+ {
+ this.notice = notice;
+ }
+
+ public NoticeCommand( String dest, String notice )
+ {
+ this(null, dest, notice);
+ }
+
+ public NoticeCommand( FullNick dest, String notice )
+ {
+ this(dest.getNick(), notice);
+ }
+
+ public NoticeCommand( FullNick source, String dest, String notice ) {
+ this.from = source;
+ this.dest = dest;
+ this.notice = notice;
+ }
+
+ public State getState()
+ {
+ return State.UNKNOWN;
+ }
+
+ /**
+ * Parses a string and produces a formed command object, if it can.
+ * Should return null if it cannot form the command object.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ FullNick from;
+ if( prefix == null || prefix.trim().length() == 0 )
+ {
+ from = null;
+ }
+ else
+ {
+ from = new FullNick( prefix );
+ }
+ String dest = getParameter( params, 0 );
+ String msg = getParameter( params, 1 );
+
+ if( CtcpNotice.isCtcpString( msg ) )
+ {
+ return new CtcpNotice( from, dest, msg );
+ }
+
+ return new NoticeCommand( from, dest, msg );
+ }
+
+ /**
+ * Returns the string IRC uses to identify this command. Examples:
+ * NICK, PING, KILL, 332
+ */
+ public String getIrcIdentifier()
+ {
+ return "NOTICE";
+ }
+
+ /**
+ * Renders the parameters of this command.
+ */
+ public String renderParams()
+ {
+ if (dest != null) {
+ return dest + " :" + notice;
+ }
+ else {
+ return ":" + notice;
+ }
+ }
+
+ public FullNick getFrom()
+ {
+ return from;
+ }
+
+ public String getDest()
+ {
+ return dest;
+ }
+
+ public String getNotice()
+ {
+ return notice;
+ }
+
+ /**
+ * Returns true if the message is both private and for us.
+ *
+ * @param state Client state to compare with
+ * @return True or false if this is a private message to us
+ */
+ public boolean isPrivateToUs( ClientState state )
+ {
+ return state.getNick().equals( dest );
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PartCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PartCommand.java
new file mode 100644
index 000000000..b27ed6dd2
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PartCommand.java
@@ -0,0 +1,126 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.util.FullNick;
+
+/**
+ * <p>Defines PART command. If the part command is from us, we should
+ * remove that channel from the list of channels. If the part command
+ * is from someone else, we should remove that user from the list of
+ * users for that channel.
+ */
+
+public class PartCommand extends AbstractCommand
+{
+
+ private String reason;
+ private String channel;
+ private FullNick user;
+
+ /** For use as a factory */
+ public PartCommand()
+ {
+ this( null, null, null );
+ }
+
+ /**
+ * For use as an incoming command.
+ *
+ * @param user User that is parting
+ * @param channel Channel that the user is parting from
+ * @param reason Reason for part
+ */
+ public PartCommand( FullNick user, String channel, String reason )
+ {
+ this.user = user;
+ this.reason = reason;
+ this.channel = channel;
+ }
+
+ /**
+ * For use as an outgoing command.
+ *
+ * @param channel Channel that we are parting from
+ * @param reason Reason we are parting
+ */
+ public PartCommand( String channel, String reason )
+ {
+ this( null, channel, reason );
+ }
+
+ /**
+ * For use as an outgoing command. Part with no reason.
+ *
+ * @param channel Channel that we are parting from
+ */
+ public PartCommand( String channel )
+ {
+ this( null, channel, null );
+ }
+
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ return new PartCommand( new FullNick( prefix ), getParameter( params, 0 ), getParameter( params, 1 ) );
+ }
+
+ public String getIrcIdentifier()
+ {
+ return "PART";
+ }
+
+ public String renderParams()
+ {
+ if( reason != null )
+ return channel + " :" + reason;
+ else
+ return channel;
+ }
+
+ public String getReason()
+ {
+ return reason;
+ }
+
+ public String getChannel()
+ {
+ return channel;
+ }
+
+ public FullNick getUser()
+ {
+ return user;
+ }
+
+ /** Takes client state action. If we are parting, then remove that
+ * channel from our list of channels. If someone else is parting,
+ * remove them from the channel they are parting from.
+ */
+ public boolean updateClientState( ClientState state )
+ {
+ // We parted
+ if( user.equals( state.getNick() ) )
+ {
+ state.removeChannel( channel );
+ return true;
+ }
+ else
+ {
+ // Someone else parted.
+
+ // 1) Grab channel
+ Channel chanObj = state.getChannel( channel );
+
+ // 2) Remove user
+ chanObj.removeMember( user, this );
+ return true;
+ }
+
+ }
+
+}
+
+
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PassCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PassCommand.java
new file mode 100644
index 000000000..da1e63cd5
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PassCommand.java
@@ -0,0 +1,33 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.OutCommand;
+
+/**
+ * Defines PASS command, optional part of the handshake to register on the network.
+ * @author Daniel Henninger
+ */
+public class PassCommand implements OutCommand
+{
+ private String pass;
+
+ public static final String IDENTIFIER = "PASS";
+
+ /**
+ * @param pass the password for the user who is authenticating
+ * */
+ public PassCommand(String pass)
+ {
+ this.pass = pass;
+ }
+
+ public String render()
+ {
+ return IDENTIFIER + " " + pass;
+ }
+
+ public String getIrcIdentifier()
+ {
+ return IDENTIFIER;
+ }
+
+}
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PingCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PingCommand.java
new file mode 100644
index 000000000..01c68cb90
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PingCommand.java
@@ -0,0 +1,67 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.State;
+
+
+/**
+ * Defines the PING command. At this point, PINGs only come in from
+ * the server, so all we need to do is capture the parameters.
+ */
+public class PingCommand extends AbstractCommand
+{
+
+ private String pingSource;
+
+ /** Factory */
+ public PingCommand()
+ {
+ pingSource = null;
+ }
+
+ public PingCommand( String source )
+ {
+ pingSource = source;
+ }
+
+ public State getState()
+ {
+ return State.UNKNOWN;
+ }
+
+ /**
+ * Parses a string and produces a formed command object, if it can.
+ * Should return null if it cannot form the command object.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ String str = getParameter( params, 0 );
+ return new PingCommand( str );
+ }
+
+ /**
+ * Returns the string IRC uses to identify this command. Examples:
+ * NICK, PING, KILL, 332
+ */
+ public String getIrcIdentifier()
+ {
+ return "PING";
+ }
+
+ /**
+ * Renders the parameters of this command.
+ */
+ public String renderParams()
+ {
+ return ":" + pingSource;
+ }
+
+ // ===== Ping-specific methods =======================================
+ public String getPingSource()
+ {
+ return pingSource;
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PongCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PongCommand.java
new file mode 100644
index 000000000..bfd22531a
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/PongCommand.java
@@ -0,0 +1,39 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+
+
+/**
+ * Defines the PONG command. At this point, PONGs can only be sent to
+ * the server, so all we need to do is provide render().
+ */
+public class PongCommand extends PingCommand
+{
+
+ public PongCommand( String dest )
+ {
+ super( dest );
+ }
+
+ /**
+ * PONG shouldn't be sent to us.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ throw new UnsupportedOperationException("PONG is not an incommand.");
+ }
+
+ public String getIrcIdentifier()
+ {
+ return "PONG";
+ }
+
+ // ===== Pong-specific methods =======================================
+ public String getPongDest()
+ {
+ return getPingSource();
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/QuitCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/QuitCommand.java
new file mode 100644
index 000000000..e12a2520d
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/QuitCommand.java
@@ -0,0 +1,132 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.Enumeration;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.util.FullNick;
+
+/**
+ * <p>Defines QUIT command. The QUIT command asks the irc server to
+ * disconnect us, and we can optionally give a reason. The QUIT
+ * command is also received by us if someone on a channel we are on
+ * quits.</p>
+ *
+ * <p>What should be done to signal to the framework that the
+ * disconnection that should come from the server is legit, and we
+ * shouldn't try to re-connecet? For now it will be assumed that the
+ * user of the framework will signal all the appropriate classes that
+ * a legit disconnection will happen (ie AutoRegister which will try
+ * to re-connect otherwise).</p>
+ */
+public class QuitCommand extends AbstractCommand
+{
+ //static Logger log = Logger.getLogger(QuitCommand.class);
+
+ private String reason;
+ private FullNick user;
+
+ /** For use as a factory */
+ public QuitCommand()
+ {
+ this( null, null );
+ }
+
+ /**
+ * For use as an incoming command.
+ *
+ * @param user User that has quit
+ * @param reason Specified reason for quitting
+ */
+ public QuitCommand( FullNick user, String reason )
+ {
+ this.user = user;
+ this.reason = reason;
+ }
+
+ /**
+ * For use as an outgoing command.
+ *
+ * @param reason Specified reason for quitting
+ */
+ public QuitCommand( String reason )
+ {
+ this( null, reason );
+ }
+
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ return new QuitCommand( new FullNick( prefix ), getParameter( params, 0 ) );
+ }
+
+ public String getIrcIdentifier()
+ {
+ return "QUIT";
+ }
+
+ public String renderParams()
+ {
+ return ":" + reason;
+ }
+
+ public String getReason()
+ {
+ return reason;
+ }
+
+ public FullNick getUser()
+ {
+ return user;
+ }
+
+ /**
+ * Returns true if we are the ones quitting.
+ *
+ * @param state Client state we are checking against
+ * @return True or false if the quit is us quitting
+ */
+ public boolean isOurQuit( ClientState state )
+ {
+ return user.equals( state.getNick() );
+ }
+
+ /** If we are quitting, we won't be worrying about our client state.
+ * If someone else is leaving, then remove them from all the groups
+ * they are in.
+ */
+ public boolean updateClientState( ClientState state )
+ {
+ //log.debug( "Nick: " + state.getNick().toString() );
+ if( isOurQuit(state) )
+ {
+ // We've quit
+ //log.debug("QUIT: We've quit: " + reason);
+
+ // What should we do with the client state here?
+ return true;
+ }
+ else
+ {
+ // Someone else quit. We need to remove them from each group
+ // they are in.
+ //log.debug("QUIT: " + user + " quit: " + reason);
+
+ // 1) Grab channels
+ Enumeration channelNames = state.getChannelNames();
+ while( channelNames.hasMoreElements() )
+ {
+ String chanName = channelNames.nextElement().toString();
+
+ // 2) Remove from group.
+ Channel channelObj = state.getChannel( chanName);
+ channelObj.removeMember( user, this );
+ }
+
+ return true;
+ }
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/RawCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/RawCommand.java
new file mode 100644
index 000000000..b7375e92f
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/RawCommand.java
@@ -0,0 +1,58 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.StringTokenizer;
+
+import f00f.net.irc.martyr.OutCommand;
+
+public class RawCommand implements OutCommand
+{
+
+ private String sourceString;
+ private String ident;
+
+ /**
+ * Tries to use the first "word" in the command as the identifier.
+ * Using this constructor is not recommended.
+ *
+ * @param raw Raw command to send to server
+ */
+ public RawCommand( String raw )
+ {
+ sourceString = raw;
+ StringTokenizer tokens = new StringTokenizer( raw );
+ ident = tokens.nextToken();
+ }
+
+ /**
+ * The rendered command will be <code>identifier + " " +
+ * parameters</code>. This constructure simply allows a correct
+ * response to the <code>getIrcIdentifier</code> method.
+ *
+ * @param identifier Command identifier
+ * @param parameters Parameters to pass
+ */
+ public RawCommand( String identifier, String parameters )
+ {
+ ident = identifier;
+ sourceString = ident + " " + parameters;
+ }
+
+ /**
+ * Returns the identifier, if supplied, or null.
+ */
+ public String getIrcIdentifier()
+ {
+ return ident;
+ }
+
+ /**
+ * Simply returns the string given in the constructor.
+ */
+ public String render()
+ {
+ return sourceString;
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/TopicCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/TopicCommand.java
new file mode 100644
index 000000000..42e3d0421
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/TopicCommand.java
@@ -0,0 +1,80 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.Date;
+
+import f00f.net.irc.martyr.CommandRegister;
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.Channel;
+import f00f.net.irc.martyr.clientstate.ClientState;
+
+public class TopicCommand extends AbstractCommand
+{
+ //static Logger log = Logger.getLogger(TopicCommand.class);
+
+ private String channel;
+ private String topic;
+
+ public static final String IDENTIFIER_PRIMARY = "TOPIC";
+ public static final String IDENTIFIER_SECONDARY = "332";
+
+ public TopicCommand()
+ {
+ this( null, null );
+ }
+
+ public TopicCommand( String channel, String topic )
+ {
+ this.channel = channel;
+ this.topic = topic;
+ }
+
+ public String getIrcIdentifier()
+ {
+ //
+ // This command uses "TOPIC" on outgoing, so that is why we use
+ // "TOPIC" here instead of "332".
+ //
+ return IDENTIFIER_PRIMARY;
+ }
+
+ public void selfRegister( CommandRegister commandRegister )
+ {
+ commandRegister.addCommand( IDENTIFIER_PRIMARY, this );
+ commandRegister.addCommand( IDENTIFIER_SECONDARY, this );
+ }
+
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ // when the command is used as a reply, the nick is parameter 0.
+ if( identifier.equals( IDENTIFIER_SECONDARY ) )
+ return new TopicCommand( getParameter(params, 1), getParameter(params, 2) );
+ else
+ return new TopicCommand( getParameter(params, 0), getParameter(params, 1) );
+ }
+
+ public String renderParams()
+ {
+ return getChannel() + " :" + getTopic();
+ }
+
+ public String getTopic()
+ {
+ return topic;
+ }
+
+ public String getChannel()
+ {
+ return channel;
+ }
+
+ public boolean updateClientState( ClientState state )
+ {
+ //log.debug("Topic: Channel: " + channel);
+ Channel chan = state.getChannel( channel );
+ chan.setTopic( topic );
+ chan.setTopicDate( new Date() );
+ return true;
+ }
+
+}
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UnknownCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UnknownCommand.java
new file mode 100644
index 000000000..6ecd4bc4d
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UnknownCommand.java
@@ -0,0 +1,38 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.State;
+
+
+/**
+ * Some unknown command, for which there is no factory. This is a
+ * special case command, created by IRCConnection if it can't find a
+ * proper command object.
+ */
+public class UnknownCommand extends AbstractInCommand
+{
+
+ public State getState()
+ {
+ return State.UNKNOWN;
+ }
+
+ /**
+ * Never parsed.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ throw new UnsupportedOperationException("UnknownCommand does no parsing.");
+ }
+
+ /**
+ * Unknown, so we don't know what the identifier is ahead of time.
+ */
+ public String getIrcIdentifier()
+ {
+ return null;
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserCommand.java
new file mode 100644
index 000000000..ac7796f7c
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserCommand.java
@@ -0,0 +1,46 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.IRCConnection;
+import f00f.net.irc.martyr.OutCommand;
+/**
+ * Defines USER command, part of the handshake to register on the
+ * network.
+ */
+public class UserCommand implements OutCommand
+{
+
+ private String name;
+ private String user;
+ private String someA; // Might be a mode on some networks
+ private String someB; // might be ignored
+
+ public static final String IDENTIFIER = "USER";
+
+ /**
+ * @param user the login name on the computer the client is on
+ * @param name the purported full name of the user, can be anything.
+ * @param connection the connection the user command is affiliated with
+ * */
+ public UserCommand( String user, String name, IRCConnection connection )
+ {
+ this.name = name;
+ this.user = user;
+ //localhost = connection.getLocalhost();
+ //remotehost = connection.getRemotehost();
+ someA = "0"; // Can be 0|4|8, with 4=+w, 8=+i
+ someB = connection.getRemotehost(); // ignored, apparently
+ }
+
+ public String render()
+ {
+ return IDENTIFIER + " " + user + " " + someA + " " + someB + " :" + name;
+ }
+
+ public String getIrcIdentifier()
+ {
+ return IDENTIFIER;
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserModeCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserModeCommand.java
new file mode 100644
index 000000000..1190ed64a
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserModeCommand.java
@@ -0,0 +1,99 @@
+package f00f.net.irc.martyr.commands;
+
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.Mode;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.modes.user.InvisibleMode;
+import f00f.net.irc.martyr.util.FullNick;
+import java.util.logging.Logger;
+
+/**
+ * Defines a user MODE command.
+ */
+public class UserModeCommand extends ModeCommand
+{
+ static Logger log = Logger.getLogger(ModeCommand.class.getName());
+
+ private FullNick user;
+ private FullNick sender;
+ //private List modes;
+
+ private static HashMap<Character,Mode> modeTypes;
+
+ public UserModeCommand( String prefix, String userStr, StringTokenizer tokens )
+ {
+// System.out.println( prefix );
+ sender = new FullNick( prefix );
+ user = new FullNick( userStr );
+
+ if( !sender.equals( user ) )
+ {
+ log.severe("UserModeCommand: Odd: mode change for a user that isn't us.");
+ return;
+ }
+
+ makeModeTypes();
+
+ //modes = parseModes( modeTypes, tokens );
+
+// System.out.println( modes );
+ }
+
+ private void makeModeTypes()
+ {
+ if( modeTypes == null )
+ {
+ modeTypes = new HashMap<Character,Mode>();
+
+ // Add new mode types here
+ registerMode( modeTypes, new InvisibleMode() );
+ }
+ }
+
+
+ /**
+ * Should not be called, as ModeCommand does the parsing and instantiation
+ * of this class.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ throw new IllegalStateException( "Don't call this method!" );
+ }
+
+ public String render()
+ {
+ throw new UnsupportedOperationException("Can't send user modes, yet." );
+ }
+
+ public FullNick getUser()
+ {
+ return user;
+ }
+
+ public FullNick getSender() {
+ return sender;
+ }
+
+ {
+ //log.debug("TODO: UserModeCommand: Can't send");
+ //log.debug("TODO: UserModeCommand: Does not update client state");
+ }
+
+ public boolean updateClientState( ClientState state )
+ {
+ // TODO implement
+ return false;
+ }
+
+ public String toString()
+ {
+ return "UserModeCommand";
+ }
+
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/WelcomeCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/WelcomeCommand.java
new file mode 100644
index 000000000..ecbe9b1ac
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/WelcomeCommand.java
@@ -0,0 +1,125 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.CommandRegister;
+import f00f.net.irc.martyr.InCommand;
+import f00f.net.irc.martyr.clientstate.ClientState;
+import f00f.net.irc.martyr.util.FullNick;
+import f00f.net.irc.martyr.util.ParameterIterator;
+import java.util.logging.Logger;
+
+
+/**
+ * Defines the commands that a server issues to welcome us. These are
+ * identified with 001, 002... etc. These commands are only received
+ * after we register, unlike the NOTICE command.
+ */
+public class WelcomeCommand extends AbstractInCommand
+{
+ static Logger log = Logger.getLogger(WelcomeCommand.class.getName());
+
+ private String notice;
+ private String nick;
+
+ /** Factory */
+ public WelcomeCommand()
+ {
+ this( null, null );
+ }
+
+ /**
+ * Used by parse to create an instance of WelcomeCommand.
+ *
+ * @param nick Nick that send the welcome
+ * @param notice Notice that was sent
+ * */
+ public WelcomeCommand( String nick, String notice )
+ {
+ this.notice = notice;
+ this.nick = nick;
+ //log.debug("WelcomeCommand: Nick is: `" + nick + "'");
+ //log.debug("WelcomeCommand: Notice is: `"+notice+"'");
+ }
+
+ /**
+ * Parses a string and produces a formed command object, if it can.
+ * Should return null if it cannot form the command object.
+ */
+ public InCommand parse( String prefix, String identifier, String params )
+ {
+ ParameterIterator pi = new ParameterIterator( params );
+ String nick = pi.next().toString();
+ String notice;
+ if( pi.hasNext() )
+ {
+ // We are looking at a "nick :msg" pair
+ notice = pi.next().toString();
+ }
+ else
+ {
+ // There is only one parameter, a notice.
+ notice = nick;
+ nick = null;
+ }
+ if( pi.hasNext() )
+ {
+ //log.severe("WelcomeCommand: More than two parameters, confused.");
+ }
+
+
+ //String str = getParameter( params, 0 );
+ //
+ return new WelcomeCommand( nick, notice );
+ }
+
+ /**
+ * Sets the nick of the client state, if there is one included with
+ * this command.
+ */
+ public boolean updateClientState( ClientState state )
+ {
+ //log.debug("WelcomeCommand: updated client state with: " + new FullNick( nick ));
+ state.setNick( new FullNick( nick ) );
+
+ return true;
+ }
+
+ /**
+ * Returns the string IRC uses to identify this command. Examples:
+ * NICK, PING, KILL, 332. In our case, there is no one thing.
+ */
+ public String getIrcIdentifier()
+ {
+ return "001";
+ }
+
+ public void selfRegister( CommandRegister commandRegister )
+ {
+ commandRegister.addCommand( "001", this );
+ commandRegister.addCommand( "002", this );
+ commandRegister.addCommand( "003", this );
+ commandRegister.addCommand( "004", this );
+ commandRegister.addCommand( "005", this );
+ }
+
+ public String getNotice()
+ {
+ return notice;
+ }
+
+ /**
+ * @return the nick received with this command, or null if there isn't
+ * one.
+ * */
+ public String getNick()
+ {
+ return nick;
+ }
+
+ public String toString()
+ {
+ return "WelcomeCommand";
+ }
+
+}
+
+
diff --git a/EssentialsUpdate/src/f00f/net/irc/martyr/commands/WhoisCommand.java b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/WhoisCommand.java
new file mode 100644
index 000000000..1c5dea618
--- /dev/null
+++ b/EssentialsUpdate/src/f00f/net/irc/martyr/commands/WhoisCommand.java
@@ -0,0 +1,40 @@
+package f00f.net.irc.martyr.commands;
+
+import f00f.net.irc.martyr.OutCommand;
+
+/**
+ * Implements a WHOIS command, to query details about a user.
+ *
+ */
+public class WhoisCommand implements OutCommand
+{
+ private static final String WHOIS = "WHOIS";
+
+ private String target;
+
+ /**
+ * @param target the nick or mask that you wish to know about.
+ */
+ public WhoisCommand( String target )
+ {
+ this.target = target;
+ }
+
+ /**
+ * @return "WHOIS"
+ */
+ public String getIrcIdentifier()
+ {
+ return WHOIS;
+ }
+
+ /**
+ * Simply returns the string given in the constructor.
+ */
+ public String render()
+ {
+ return WHOIS + " " + target;
+ }
+}
+
+