File Source: ClientInfo.java

         /* 
    P/P   *  Method: com.dmdirc.parser.irc.ClientInfo__static_init
          */
     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.parser.irc;
    24  
    25  import java.util.ArrayList;
    26  import java.util.List;
    27  import java.util.LinkedList;
    28  import java.util.Hashtable;
    29  import java.util.HashMap;
    30  import java.util.Map;
    31  
    32  /**
    33   * Contains information about known users.
    34   * 
    35   * @author Shane Mc Cormack
    36   * @author Chris Smith
    37   * @see IRCParser
    38   */
    39  public final class ClientInfo {
    40  	/** Known nickname of client. */
    41  	private String sNickname = "";
    42  	/** Known ident of client. */
    43  	private String sIdent = "";	
    44  	/** Known host of client. */
    45  	private String sHost = "";
    46  	/** Known user modes of client. */
    47  	private long nModes;
    48  	/** Known Away Reason of client. */
    49  	private String myAwayReason = "";
    50  	/** Known RealName of client. */
    51  	private String sRealName = "";
    52  	/** Known away state for client. */
    53  	private boolean bIsAway;
    54  	/** Is this a fake client created just for a callback? */
    55  	private boolean bIsFake;
    56  	/** Reference to the parser object that owns this channel, Used for modes. */
    57  	private final IRCParser myParser;
    58  	/** A Map to allow applications to attach misc data to this object */
    59  	private Map myMap;
    60  	/** List of ChannelClientInfos that point to this */
    61  	private final Map<String, ChannelClientInfo> myChannelClientInfos = new Hashtable<String, ChannelClientInfo>();
    62  	/** Modes waiting to be sent to the server. */
    63  	private final List<String> lModeQueue = new LinkedList<String>();
    64  
    65  	/**
    66  	 * Create a new client object from a hostmask.
    67  	 *
    68   	 * @param tParser Refernce to parser that owns this channelclient (used for modes)	 
    69  	 * @param sHostmask Hostmask parsed by parseHost to get nickname
    70  	 * @see ClientInfo#parseHost
    71  	 */
        	 /* 
    P/P 	  *  Method: void com.dmdirc.parser.irc.ClientInfo(IRCParser, String)
        	  * 
        	  *  Preconditions:
        	  *    sHostmask != null
        	  * 
        	  *  Postconditions:
        	  *    this.lModeQueue == &amp;new LinkedList(ClientInfo#2)
        	  *    this.myAwayReason == &amp;""
        	  *    this.sRealName == &amp;""
        	  *    this.myChannelClientInfos == &amp;new Hashtable(ClientInfo#1)
        	  *    this.myMap == &amp;new HashMap(ClientInfo#3)
        	  *    this.myParser == tParser
        	  *    init'ed(this.myParser)
        	  *    this.sHost == One-of{this.myAwayReason, undefined}
        	  *    this.sHost in Addr_Set{null,&amp;""}
        	  *    this.sIdent == One-of{this.myAwayReason, undefined}
        	  *    ...
        	  */
    72  	public ClientInfo(final IRCParser tParser, final String sHostmask) { 
    73  		myMap = new HashMap<Object, Object>();
    74  		setUserBits(sHostmask, true);
    75  		myParser = tParser;
    76  	}
    77  
    78  	/**
    79  	 * Set the Map object attatched to this object.
    80  	 *
    81  	 * @param newMap New Map to attatch.
    82  	 */
    83  	public void setMap(final Map newMap) {
        		 /* 
    P/P 		  *  Method: void setMap(Map)
        		  * 
        		  *  Postconditions:
        		  *    this.myMap == newMap
        		  *    init'ed(this.myMap)
        		  */
    84  		myMap = newMap;
    85  	}
    86  	
    87  	/**
    88  	 * Get the Map object attatched to this object.
    89  	 *
    90  	 * @return Map to attatched to this.
    91  	 */
    92  	public Map getMap() {
        		 /* 
    P/P 		  *  Method: Map getMap()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.myMap)
        		  * 
        		  *  Postconditions:
        		  *    return_value == this.myMap
        		  *    init'ed(return_value)
        		  */
    93  		return myMap;
    94  	}
    95  
    96  	/**
    97  	 * Check if this is a fake client.
    98  	 *
    99  	 * @return True if this is a fake client, else false
   100  	 */
        	 /* 
    P/P 	  *  Method: bool isFake()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.bIsFake)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.bIsFake
        	  *    init'ed(return_value)
        	  */
   101  	public boolean isFake() { return bIsFake; }
   102  	/**
   103  	 * Check if this client is actually a server.
   104  	 *
   105  	 * @return True if this client is actually a server.
   106  	 */
        	 /* 
    P/P 	  *  Method: bool isServer()
        	  * 
        	  *  Preconditions:
        	  *    this.sNickname != null
        	  * 
        	  *  Postconditions:
        	  *    init'ed(return_value)
        	  */
   107  	public boolean isServer() { return !(sNickname.indexOf(':') == -1); }
   108  	/**
   109  	 * Set if this is a fake client.
   110  	 * This returns "this" and thus can be used in the construction line.
   111  	 *
   112  	 * @param newValue new value for isFake - True if this is a fake client, else false
   113  	 * @return this Object
   114  	 */
        	 /* 
    P/P 	  *  Method: ClientInfo setFake(bool)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this
        	  *    return_value != null
        	  *    this.bIsFake == newValue
        	  *    init'ed(this.bIsFake)
        	  */
   115  	public ClientInfo setFake(final boolean newValue) { bIsFake = newValue; return this; }
   116  
   117  	/**
   118  	 * Get a nickname of a user from a hostmask.
   119  	 * Hostmask must match (?:)nick(?!ident)(?@host)
   120  	 *
   121  	 * @param sWho Hostname to parse
   122  	 * @return nickname of user
   123  	 */
   124  	public static String parseHost(final String sWho) {
   125  		// Get the nickname from the string.
        		 /* 
    P/P 		  *  Method: String parseHost(String)
        		  * 
        		  *  Preconditions:
        		  *    sWho != null
        		  * 
        		  *  Postconditions:
        		  *    return_value == undefined
        		  *    return_value == null
        		  */
   126  		return parseHostFull(sWho)[0];
   127  	}
   128  	
   129  	/**
   130  	 * Get a nick ident and host of a user from a hostmask.
   131  	 * Hostmask must match (?:)nick(?!ident)(?@host)
   132  	 *
   133  	 * @param sWho Hostname to parse
   134  	 * @return Array containing details. (result[0] -> Nick | result[1] -> Ident | result[2] -> Host)
   135  	 */
   136  	public static String[] parseHostFull(String sWho) {
        		 /* 
    P/P 		  *  Method: String[] parseHostFull(String)
        		  *    parseHostFull fails for all possible inputs
        		  * 
        		  *  Preconditions:
        		  *    sWho != null
        		  * 
        		  *  Postconditions:
        		  *    return_value == &amp;new String[](parseHostFull#1)
        		  *    new String[](parseHostFull#1) num objects == 1
        		  *    return_value.length == 3
        		  *    return_value[0] == undefined
        		  *    return_value[0] == null
        		  *    return_value[1] == null
        		  *    return_value[2] == null
        		  * 
        		  *  Test Vectors:
        		  *    java.lang.String:charAt(...)@139: {0..57, 59..216-1}, {58}
        		  *    java.lang.String:isEmpty(...)@139: {1}, {0}
        		  */
   137  		String[] sTemp = null;
   138  		final String[] result = new String[3];
   139  		if (!sWho.isEmpty() && sWho.charAt(0) == ':') { sWho = sWho.substring(1); }
   140  		sTemp = sWho.split("@", 2);
   141  		if (sTemp.length == 1) { result[2] = ""; } else { result[2] = sTemp[1]; }
   142  		sTemp = sTemp[0].split("!", 2);
   143  		if (sTemp.length == 1) { result[1] = ""; } else { result[1] = sTemp[1]; }
   144  		result[0] = sTemp[0];
   145  		
   146  		return result;
   147  	}
   148  
   149  	/**
   150  	 * Set the nick/ident/host of this client.
   151  	 *
   152  	 * @param sHostmask takes a host (?:)nick(?!ident)(?@host) and sets nick/host/ident variables
   153  	 * @param bUpdateNick if this is false, only host/ident will be updated.
   154  	 */	
   155  	public void setUserBits(final String sHostmask, final boolean bUpdateNick) {
        		 /* 
    P/P 		  *  Method: void setUserBits(String, bool)
        		  * 
        		  *  Preconditions:
        		  *    sHostmask != null
        		  * 
        		  *  Postconditions:
        		  *    this.sHost == One-of{old this.sHost, &amp;"", undefined}
        		  *    this.sIdent == One-of{old this.sIdent, &amp;"", undefined}
        		  *    this.sNickname == One-of{old this.sNickname, undefined}
        		  */
   156  		setUserBits(sHostmask, bUpdateNick, false);
   157  	}
   158  	
   159  	/**
   160  	 * Set the nick/ident/host of this client.
   161  	 *
   162  	 * @param sHostmask takes a host (?:)nick(?!ident)(?@host) and sets nick/host/ident variables
   163  	 * @param bUpdateNick if this is false, only host/ident will be updated.
   164  	 * @param allowBlank if this is true, ident/host will be set even if
   165  	 *                   parseHostFull returns empty values for them
   166  	 */	
   167  	public void setUserBits(final String sHostmask, final boolean bUpdateNick, final boolean allowBlank) {
        		 /* 
    P/P 		  *  Method: void setUserBits(String, bool, bool)
        		  *    setUserBits fails for all possible inputs
        		  * 
        		  *  Preconditions:
        		  *    sHostmask != null
        		  * 
        		  *  Postconditions:
        		  *    this.sHost == One-of{old this.sHost, &amp;"", undefined}
        		  *    this.sIdent == One-of{old this.sIdent, &amp;"", undefined}
        		  *    this.sNickname == One-of{old this.sNickname, undefined}
        		  * 
        		  *  Test Vectors:
        		  *    allowBlank: {0}, {1}
        		  *    bUpdateNick: {0}, {1}
        		  */
   168  		final String[] sTemp = parseHostFull(sHostmask);
   169  		if (!sTemp[2].isEmpty() || allowBlank) { sHost = sTemp[2]; }
   170  		if (!sTemp[1].isEmpty() || allowBlank) { sIdent = sTemp[1]; }
   171  		if (bUpdateNick) { sNickname = sTemp[0]; }
   172  	}
   173  	
   174  	/**
   175  	 * Get a string representation of the user.
   176  	 *
   177  	 * @return String representation of the user.
   178  	 */
   179  	@Override
        	 /* 
    P/P 	  *  Method: String toString()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.sHost)
        	  *    init'ed(this.sIdent)
        	  *    init'ed(this.sNickname)
        	  * 
        	  *  Postconditions:
        	  *    java.lang.StringBuilder:toString(...)._tainted == this.sHost._tainted | this.sNickname._tainted | this.sIdent._tainted
        	  *    init'ed(java.lang.StringBuilder:toString(...)._tainted)
        	  *    return_value == &amp;java.lang.StringBuilder:toString(...)
        	  */
   180  	public String toString() { return sNickname + "!" + sIdent + "@" + sHost; }
   181  	
   182  	/**
   183  	 * Get the nickname for this user.
   184  	 *
   185  	 * @return Known nickname for user.
   186  	 */
        	 /* 
    P/P 	  *  Method: String getNickname()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.sNickname)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.sNickname
        	  *    init'ed(return_value)
        	  */
   187  	public String getNickname() { return sNickname; }
   188  	
   189  	/**
   190  	 * Get the ident for this user.
   191  	 *
   192  	 * @return Known ident for user. (May be "")
   193  	 */		
        	 /* 
    P/P 	  *  Method: String getIdent()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.sIdent)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.sIdent
        	  *    init'ed(return_value)
        	  */
   194  	public String getIdent() { return sIdent; }
   195  	
   196  	/**
   197  	 * Get the hostname for this user.
   198  	 *
   199  	 * @return Known host for user. (May be "")
   200  	 */		
        	 /* 
    P/P 	  *  Method: String getHost()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.sHost)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.sHost
        	  *    init'ed(return_value)
        	  */
   201  	public String getHost() { return sHost; }
   202  	
   203  	/**
   204  	 * Set the away state of a user.
   205  	 * Automatically sets away reason to "" if set to false
   206  	 *
   207  	 * @param bNewState Boolean representing state. true = away, false = here
   208  	 */	
   209  	protected void setAwayState(final boolean bNewState) {
        		 /* 
    P/P 		  *  Method: void setAwayState(bool)
        		  * 
        		  *  Postconditions:
        		  *    this.bIsAway == bNewState
        		  *    init'ed(this.bIsAway)
        		  *    this.myAwayReason == One-of{old this.myAwayReason, &amp;""}
        		  * 
        		  *  Test Vectors:
        		  *    bNewState: {1}, {0}
        		  */
   210  		bIsAway = bNewState;
   211  		if (!bIsAway) { myAwayReason = ""; }
   212  	}
   213  	
   214  	/**
   215  	 * Get the away state of a user.
   216  	 *
   217  	 * @return Boolean representing state. true = away, false = here
   218  	 */	
        	 /* 
    P/P 	  *  Method: bool getAwayState()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.bIsAway)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.bIsAway
        	  *    init'ed(return_value)
        	  */
   219  	public boolean getAwayState() { return bIsAway; }
   220  	
   221  	/**
   222  	 * Get the Away Reason for this user.
   223  	 *
   224  	 * @return Known away reason for user.
   225  	 */
        	 /* 
    P/P 	  *  Method: String getAwayReason()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.myAwayReason)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.myAwayReason
        	  *    init'ed(return_value)
        	  */
   226  	public String getAwayReason() { return myAwayReason; }
   227  	
   228  	/**
   229  	 * Set the Away Reason for this user.
   230  	 * Automatically set to "" if awaystate is set to false
   231  	 *
   232  	 * @param newValue new away reason for user.
   233  	 */
        	 /* 
    P/P 	  *  Method: void setAwayReason(String)
        	  * 
        	  *  Postconditions:
        	  *    this.myAwayReason == newValue
        	  *    init'ed(this.myAwayReason)
        	  */
   234  	protected void setAwayReason(final String newValue) { myAwayReason = newValue; }
   235  	
   236  	/**
   237  	 * Get the RealName for this user.
   238  	 *
   239  	 * @return Known RealName for user.
   240  	 */
        	 /* 
    P/P 	  *  Method: String getRealName()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.sRealName)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.sRealName
        	  *    init'ed(return_value)
        	  */
   241  	public String getRealName() { return sRealName; }
   242  	
   243  	/**
   244  	 * Set the RealName for this user.
   245  	 *
   246  	 * @param newValue new RealName for user.
   247  	 */
        	 /* 
    P/P 	  *  Method: void setRealName(String)
        	  * 
        	  *  Postconditions:
        	  *    this.sRealName == newValue
        	  *    init'ed(this.sRealName)
        	  */
   248  	protected void setRealName(final String newValue) { sRealName = newValue; }
   249  	
   250  	/**
   251  	 * Set the user modes (as an integer).
   252  	 *
   253  	 * @param nNewMode new long representing channel modes. (Boolean only)
   254  	 */	
        	 /* 
    P/P 	  *  Method: void setUserMode(long)
        	  * 
        	  *  Postconditions:
        	  *    this.nModes == nNewMode
        	  *    init'ed(this.nModes)
        	  */
   255  	protected void setUserMode(final long nNewMode) { nModes = nNewMode; }
   256  	
   257  	/**
   258  	 * Get the user modes (as an integer).
   259  	 *
   260  	 * @return long representing channel modes. (Boolean only)
   261  	 */	
        	 /* 
    P/P 	  *  Method: long getUserMode()
        	  * 
        	  *  Preconditions:
        	  *    init'ed(this.nModes)
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.nModes
        	  *    init'ed(return_value)
        	  */
   262  	public long getUserMode() { return nModes; }	
   263  	
   264  	/**
   265  	 * Get the user modes (as a string representation).
   266  	 *
   267  	 * @return string representing modes. (boolean and non-list)
   268  	 */	
   269  	public String getUserModeStr() { 
        		 /* 
    P/P 		  *  Method: String getUserModeStr()
        		  * 
        		  *  Preconditions:
        		  *    this.myParser != null
        		  *    this.myParser.hUserModes != null
        		  *    init'ed(this.nModes)
        		  * 
        		  *  Presumptions:
        		  *    java.util.Iterator:next(...)@274 != null
        		  *    java.util.Map:get(...)@275 != null
        		  *    java.util.Map:keySet(...)@274 != null
        		  * 
        		  *  Postconditions:
        		  *    java.lang.StringBuilder:toString(...)._tainted == 0
        		  *    return_value == &amp;java.lang.StringBuilder:toString(...)
        		  * 
        		  *  Test Vectors:
        		  *    java.util.Iterator:hasNext(...)@274: {0}, {1}
        		  */
   270  		final StringBuilder sModes = new StringBuilder("+");
   271  		long nTemp = 0;
   272  		final long nChanModes = this.getUserMode();
   273  		
   274  		for (char cTemp : myParser.hUserModes.keySet()) {
   275  			nTemp = myParser.hUserModes.get(cTemp);
   276  			if ((nChanModes & nTemp) == nTemp) { sModes.append(cTemp); }
   277  		}
   278  		
   279  		return sModes.toString();
   280  	}
   281  	
   282  	/**
   283  	 * Is this client an oper?
   284  	 * This is a guess currently based on user-modes and thus only works on the
   285  	 * parsers own client.
   286  	 *
   287  	 * @return True/False if this client appears to be an oper
   288  	 */
   289  	public boolean isOper() {
        		 /* 
    P/P 		  *  Method: bool isOper()
        		  * 
        		  *  Preconditions:
        		  *    this.myParser != null
        		  *    this.myParser.hUserModes != null
        		  *    init'ed(this.nModes)
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  */
   290  		final String modestr = getUserModeStr();
   291  		return (modestr.indexOf('o') > -1) || (modestr.indexOf('O') > -1);
   292  	}
   293  	
   294  	/**
   295  	 * Add a ChannelClientInfo as a known reference to this client.
   296  	 *
   297  	 * @param cci ChannelClientInfo to add as a known reference
   298  	 */	
   299  	public void addChannelClientInfo(final ChannelClientInfo cci) {
        		 /* 
    P/P 		  *  Method: void addChannelClientInfo(ChannelClientInfo)
        		  * 
        		  *  Preconditions:
        		  *    cci != null
        		  *    cci.myChannel != null
        		  *    cci.myChannel.sName != null
        		  *    init'ed(this.myParser.stringConverter)
        		  *    this.myChannelClientInfos != null
        		  *    this.myParser != null
        		  *    (soft) this.myParser.stringConverter.lowercase != null
        		  *    (soft) init'ed(this.myParser.stringConverter.lowercase[...])
        		  * 
        		  *  Postconditions:
        		  *    this.myParser.stringConverter == One-of{old this.myParser.stringConverter, &amp;new IRCStringConverter(getIRCStringConverter#1)}
        		  *    this.myParser.stringConverter != null
        		  *    new IRCStringConverter(getIRCStringConverter#1) num objects <= 1
        		  *    new char[](IRCStringConverter#1) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
        		  *    new char[](IRCStringConverter#2) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
        		  *    new IRCStringConverter(getIRCStringConverter#1).limit == 4
        		  *    new IRCStringConverter(getIRCStringConverter#1).lowercase == &amp;new char[](IRCStringConverter#1)
        		  *    new IRCStringConverter(getIRCStringConverter#1).uppercase == &amp;new char[](IRCStringConverter#2)
        		  *    new char[](IRCStringConverter#1).length == 127
        		  *    new char[](IRCStringConverter#2).length == 127
        		  *    ...
        		  * 
        		  *  Test Vectors:
        		  *    java.util.Map:containsKey(...)@301: {1}, {0}
        		  */
   300  		final String key = myParser.getIRCStringConverter().toLowerCase(cci.getChannel().getName());
   301  		if (!myChannelClientInfos.containsKey(key)) {
   302  			myChannelClientInfos.put(key, cci);
   303  		}
   304  	}
   305  	
   306  	/**
   307  	 * Remove a ChannelClientInfo as a known reference to this client.
   308  	 *
   309  	 * @param cci ChannelClientInfo to remove as a known reference
   310  	 */	
   311  	public void delChannelClientInfo(final ChannelClientInfo cci) {
        		 /* 
    P/P 		  *  Method: void delChannelClientInfo(ChannelClientInfo)
        		  * 
        		  *  Preconditions:
        		  *    cci != null
        		  *    cci.myChannel != null
        		  *    cci.myChannel.sName != null
        		  *    init'ed(this.myParser.stringConverter)
        		  *    this.myChannelClientInfos != null
        		  *    this.myParser != null
        		  *    (soft) this.myParser.stringConverter.lowercase != null
        		  *    (soft) init'ed(this.myParser.stringConverter.lowercase[...])
        		  * 
        		  *  Postconditions:
        		  *    this.myParser.stringConverter == One-of{old this.myParser.stringConverter, &amp;new IRCStringConverter(getIRCStringConverter#1)}
        		  *    this.myParser.stringConverter != null
        		  *    new IRCStringConverter(getIRCStringConverter#1) num objects <= 1
        		  *    new char[](IRCStringConverter#1) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
        		  *    new char[](IRCStringConverter#2) num objects == new IRCStringConverter(getIRCStringConverter#1) num objects
        		  *    new IRCStringConverter(getIRCStringConverter#1).limit == 4
        		  *    new IRCStringConverter(getIRCStringConverter#1).lowercase == &amp;new char[](IRCStringConverter#1)
        		  *    new IRCStringConverter(getIRCStringConverter#1).uppercase == &amp;new char[](IRCStringConverter#2)
        		  *    new char[](IRCStringConverter#1).length == 127
        		  *    new char[](IRCStringConverter#2).length == 127
        		  *    ...
        		  * 
        		  *  Test Vectors:
        		  *    java.util.Map:containsKey(...)@313: {0}, {1}
        		  */
   312  		final String key = myParser.getIRCStringConverter().toLowerCase(cci.getChannel().getName());
   313  		if (myChannelClientInfos.containsKey(key)) {
   314  			myChannelClientInfos.remove(key);
   315  		}
   316  	}
   317  	
   318  	/**
   319  	 * Check to see if a client is still known on any of the channels we are on.
   320  	 *
   321  	 * @return Boolean to see if client is still visable.
   322  	 */
   323  	public boolean checkVisibility() {
        		 /* 
    P/P 		  *  Method: bool checkVisibility()
        		  * 
        		  *  Preconditions:
        		  *    this.myChannelClientInfos != null
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  */
   324  		return !myChannelClientInfos.isEmpty();
   325  	}
   326  	
   327  	/**
   328  	 * Check how many channels this client is known on.
   329  	 *
   330  	 * @return int with the count of known channels
   331  	 */	
   332  	public int channelCount() {
        		 /* 
    P/P 		  *  Method: int channelCount()
        		  * 
        		  *  Preconditions:
        		  *    this.myChannelClientInfos != null
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  */
   333  		return myChannelClientInfos.size();
   334  	}
   335  	
   336  	/**
   337  	 * Get a list of channelClients that point to this object.
   338  	 *
   339  	 * @return int with the count of known channels
   340  	 */	
   341  	public List<ChannelClientInfo> getChannelClients() {
        		 /* 
    P/P 		  *  Method: List getChannelClients()
        		  * 
        		  *  Preconditions:
        		  *    this.myChannelClientInfos != null
        		  * 
        		  *  Presumptions:
        		  *    java.util.Map:values(...)@343 != null
        		  * 
        		  *  Postconditions:
        		  *    return_value == &amp;new ArrayList(getChannelClients#1)
        		  *    new ArrayList(getChannelClients#1) num objects == 1
        		  * 
        		  *  Test Vectors:
        		  *    java.util.Iterator:hasNext(...)@343: {0}, {1}
        		  */
   342  		final List<ChannelClientInfo> result = new ArrayList<ChannelClientInfo>();
   343  		for (ChannelClientInfo cci : myChannelClientInfos.values()) {
   344  			result.add(cci);
   345  		}
   346  		return result;
   347  	}
   348  	
   349  	/**
   350  	 * Adjust the channel modes on a channel.
   351  	 * This function will queue modes up to be sent in one go, according to 005 params.
   352  	 * If less modes are altered than the queue accepts, sendModes() must be called.<br><br>
   353  	 * sendModes is automatically called if you attempt to add more modes than is allowed
   354  	 * to be queued
   355  	 *
   356  	 * @param positive Is this a positive mode change, or a negative mode change
   357  	 * @param mode Character representing the mode to change
   358  	 */
   359  	public void alterMode(final boolean positive, final Character mode) {
        		 /* 
    P/P 		  *  Method: void alterMode(bool, Character)
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.bIsFake)
        		  *    (soft) init'ed(this.myParser.stringConverter)
        		  *    (soft) this.lModeQueue != null
        		  *    (soft) this.myParser != null
        		  *    (soft) this.myParser.cMyself != null
        		  *    (soft) init'ed(this.myParser.currentSocketState)
        		  *    (soft) this.myParser.h005Info != null
        		  *    (soft) this.myParser.hChanModesOther != null
        		  *    (soft) this.myParser.hChannelList != null
        		  *    (soft) this.myParser.hUserModes != null
        		  *    ...
        		  * 
        		  *  Postconditions:
        		  *    init'ed(java.lang.String:substring(...)._tainted)
        		  *    possibly_updated(this...myAwayReason)
        		  *    this.myParser.stringConverter == One-of{old this.myParser.stringConverter, &amp;new IRCStringConverter(getIRCStringConverter#1)}
        		  *    init'ed(this.myParser.stringConverter)
        		  *    new IRCStringConverter(getIRCStringConverter#1) num objects <= 1
        		  *    init'ed(new IRCStringConverter(getIRCStringConverter#1).limit)
        		  *    init'ed(new IRCStringConverter(getIRCStringConverter#1).lowercase)
        		  *    init'ed(new IRCStringConverter(getIRCStringConverter#1).uppercase)
        		  *    new char[](IRCStringConverter#1) num objects <= 1
        		  *    init'ed(new char[](IRCStringConverter#1).length)
        		  *    ...
        		  * 
        		  *  Test Vectors:
        		  *    this.bIsFake: {0}, {1}
        		  *    java.util.List:contains(...)@373: {0}, {1}
        		  *    java.util.List:contains(...)@376: {0}, {1}
        		  *    java.util.Map:containsKey(...)@363: {0}, {1}
        		  *    java.util.Map:containsKey(...)@371: {1}, {0}
        		  */
   360  		if (isFake()) { return; }
   361  		int modecount = 1;
   362  		String modestr = "";
   363  		if (myParser.h005Info.containsKey("MODES")) {
   364  			try { 
   365  				modecount = Integer.parseInt(myParser.h005Info.get("MODES")); 
   366  			} catch (NumberFormatException e) { 
   367  				modecount = 1;
   368  			}
   369  		}
   370  		modestr = ((positive) ? "+" : "-") + mode;
   371  		if (!myParser.hUserModes.containsKey(mode)) { return; }
   372  		final String teststr = ((positive) ? "-" : "+") + mode;
   373  		if (lModeQueue.contains(teststr)) {
   374  			lModeQueue.remove(teststr);
   375  			return;
   376  		} else if (lModeQueue.contains(modestr)) {
   377  			return;
   378  		}
   379  		myParser.callDebugInfo(myParser.DEBUG_INFO, "Queueing user mode: %s", modestr);
   380  		lModeQueue.add(modestr);
   381  		if (lModeQueue.size() == modecount) { sendModes(); }
   382  	}
   383  	
   384  	/**
   385  	 * This function will send modes that are currently queued up to send.
   386  	 * This assumes that the queue only contains the amount that are alowed to be sent
   387  	 * and thus will try to send the entire queue in one go.<br><br>
   388  	 * Modes are always sent negative then positive and not mixed.
   389  	 */
   390  	public void sendModes() {
        		 /* 
    P/P 		  *  Method: void sendModes()
        		  * 
        		  *  Preconditions:
        		  *    this.lModeQueue != null
        		  *    (soft) init'ed(this.myParser.stringConverter)
        		  *    (soft) this.myParser != null
        		  *    (soft) this.myParser.cMyself != null
        		  *    (soft) init'ed(this.myParser.currentSocketState)
        		  *    (soft) this.myParser.hChanModesOther != null
        		  *    (soft) this.myParser.hChannelList != null
        		  *    (soft) this.myParser.myCallbackManager != null
        		  *    (soft) this.myParser.myCallbackManager.callbackHash != null
        		  *    (soft) init'ed(this.myParser.out)
        		  *    ...
        		  * 
        		  *  Presumptions:
        		  *    java.util.List:get(...)@398 != null
        		  * 
        		  *  Postconditions:
        		  *    init'ed(java.lang.String:substring(...)._tainted)
        		  *    possibly_updated(this...myAwayReason)
        		  *    this.myParser.stringConverter == One-of{old this.myParser.stringConverter, &amp;new IRCStringConverter(getIRCStringConverter#1)}
        		  *    init'ed(this.myParser.stringConverter)
        		  *    new IRCStringConverter(getIRCStringConverter#1) num objects <= 1
        		  *    init'ed(new IRCStringConverter(getIRCStringConverter#1).limit)
        		  *    init'ed(new IRCStringConverter(getIRCStringConverter#1).lowercase)
        		  *    init'ed(new IRCStringConverter(getIRCStringConverter#1).uppercase)
        		  *    new char[](IRCStringConverter#1) num objects <= 1
        		  *    init'ed(new char[](IRCStringConverter#1).length)
        		  *    ...
        		  * 
        		  *  Test Vectors:
        		  *    java.lang.String:charAt(...)@399: {0..42, 44..216-1}, {43}
        		  *    java.lang.StringBuilder:length(...)@406: {-231..0}, {1..232-1}
        		  *    java.lang.StringBuilder:length(...)@407: {-231..0}, {1..232-1}
        		  *    java.util.List:isEmpty(...)@391: {0}, {1}
        		  */
   391  		if (lModeQueue.isEmpty()) { return; }
   392  		final StringBuilder positivemode = new StringBuilder();
   393  		final StringBuilder negativemode = new StringBuilder();
   394  		final StringBuilder sendModeStr = new StringBuilder();
   395  		String modestr;
   396  		boolean positive;
   397  		for (int i = 0; i < lModeQueue.size(); ++i) {
   398  			modestr = lModeQueue.get(i);
   399  			positive = modestr.charAt(0) == '+';
   400  			if (positive) {
   401  				positivemode.append(modestr.charAt(1));
   402  			} else {
   403  				negativemode.append(modestr.charAt(1));
   404  			}
   405  		}
   406  		if (negativemode.length() > 0) { sendModeStr.append("-").append(negativemode); }
   407  		if (positivemode.length() > 0) { sendModeStr.append("+").append(positivemode); }
   408  		myParser.callDebugInfo(IRCParser.DEBUG_INFO, "Sending mode: %s", sendModeStr.toString());
   409  		myParser.sendLine("MODE " + sNickname + " " + sendModeStr.toString());
   410  		clearModeQueue();
   411  	}
   412  	
   413  	/**
   414  	 * This function will clear the mode queue (WITHOUT Sending).
   415  	 */
   416  	public void clearModeQueue() { 
        		 /* 
    P/P 		  *  Method: void clearModeQueue()
        		  * 
        		  *  Preconditions:
        		  *    this.lModeQueue != null
        		  */
   417  		lModeQueue.clear();
   418  	}
   419  	
   420  	/**
   421  	 * Get the parser object that owns this client.
   422  	 *
   423  	 * @return The parser object that owns this client
   424  	 */
        	 /* 
    P/P 	  *  Method: IRCParser getParser()
        	  * 
        	  *  Postconditions:
        	  *    return_value == this.myParser
        	  *    init'ed(return_value)
        	  */
   425  	public IRCParser getParser() { return myParser; }
   426  
   427  }








SofCheck Inspector Build Version : 2.17854
ClientInfo.java 2009-Jun-25 01:54:24
ClientInfo.class 2009-Sep-02 17:04:12