From 860d446d28776ec842fa53e8e08538d4e093d6e9 Mon Sep 17 00:00:00 2001 From: snowleo Date: Wed, 12 Oct 2011 03:14:07 +0200 Subject: EssentialsUpdate WIP --- .../net/irc/martyr/commands/AbstractCommand.java | 32 +++ .../net/irc/martyr/commands/AbstractInCommand.java | 174 +++++++++++++++ .../f00f/net/irc/martyr/commands/ActionCtcp.java | 12 ++ .../irc/martyr/commands/ChannelModeCommand.java | 189 ++++++++++++++++ .../f00f/net/irc/martyr/commands/CtcpMessage.java | 129 +++++++++++ .../f00f/net/irc/martyr/commands/CtcpNotice.java | 131 ++++++++++++ .../net/irc/martyr/commands/InviteCommand.java | 90 ++++++++ .../f00f/net/irc/martyr/commands/IsonCommand.java | 144 +++++++++++++ .../f00f/net/irc/martyr/commands/JoinCommand.java | 131 ++++++++++++ .../f00f/net/irc/martyr/commands/KickCommand.java | 110 ++++++++++ .../net/irc/martyr/commands/MessageCommand.java | 127 +++++++++++ .../f00f/net/irc/martyr/commands/ModeCommand.java | 237 +++++++++++++++++++++ .../f00f/net/irc/martyr/commands/NamesCommand.java | 77 +++++++ .../f00f/net/irc/martyr/commands/NickCommand.java | 97 +++++++++ .../net/irc/martyr/commands/NoticeCommand.java | 129 +++++++++++ .../f00f/net/irc/martyr/commands/PartCommand.java | 126 +++++++++++ .../f00f/net/irc/martyr/commands/PassCommand.java | 33 +++ .../f00f/net/irc/martyr/commands/PingCommand.java | 67 ++++++ .../f00f/net/irc/martyr/commands/PongCommand.java | 39 ++++ .../f00f/net/irc/martyr/commands/QuitCommand.java | 132 ++++++++++++ .../f00f/net/irc/martyr/commands/RawCommand.java | 58 +++++ .../f00f/net/irc/martyr/commands/TopicCommand.java | 80 +++++++ .../net/irc/martyr/commands/UnknownCommand.java | 38 ++++ .../f00f/net/irc/martyr/commands/UserCommand.java | 46 ++++ .../net/irc/martyr/commands/UserModeCommand.java | 99 +++++++++ .../net/irc/martyr/commands/WelcomeCommand.java | 125 +++++++++++ .../f00f/net/irc/martyr/commands/WhoisCommand.java | 40 ++++ 27 files changed, 2692 insertions(+) create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractInCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/ActionCtcp.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/ChannelModeCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpMessage.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/CtcpNotice.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/InviteCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/IsonCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/JoinCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/KickCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/MessageCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/ModeCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/NamesCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/NickCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/NoticeCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/PartCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/PassCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/PingCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/PongCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/QuitCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/RawCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/TopicCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/UnknownCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/UserModeCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/WelcomeCommand.java create mode 100644 EssentialsUpdate/src/f00f/net/irc/martyr/commands/WhoisCommand.java (limited to 'EssentialsUpdate/src/f00f/net/irc/martyr/commands') 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 attributes = new HashMap(); + + 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 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(); + + 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 Morgan Christiansson + */ +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 nicks = new ArrayList(); + + /* 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 nicks) + { + this.nicks.addAll(nicks); + } + + public IsonCommand(String dest, List 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 nicks = Arrays.asList(nickParam.split(" ")); + return new IsonCommand(getParameter(params, 0), nicks); + } + else { + String nickParam = getParameter(params, 0); + List 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 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 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 + //
:repp_!bdamm@dammfine.com MODE #bytesex +oo z * repp_telnet
+ 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 parseModes( Map modes, StringTokenizer tokens ) + { + LinkedList results = new LinkedList(); + + 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 modes, StringTokenizer tokens, List results ) + { + // A list of modes that we have. + LinkedList localModes = new LinkedList(); + + 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 channels = new ArrayList(); + + /** + * 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 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 + * 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; + +/** + *

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; + +/** + *

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.

+ * + *

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).

+ */ +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 identifier + " " + + * parameters. This constructure simply allows a correct + * response to the getIrcIdentifier 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 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(); + + // 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; + } +} + + -- cgit v1.2.3