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 == &new LinkedList(ClientInfo#2)
* this.myAwayReason == &""
* this.sRealName == &""
* this.myChannelClientInfos == &new Hashtable(ClientInfo#1)
* this.myMap == &new HashMap(ClientInfo#3)
* this.myParser == tParser
* init'ed(this.myParser)
* this.sHost == One-of{this.myAwayReason, undefined}
* this.sHost in Addr_Set{null,&""}
* 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 == &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, &"", undefined}
* this.sIdent == One-of{old this.sIdent, &"", 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, &"", undefined}
* this.sIdent == One-of{old this.sIdent, &"", 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 == &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, &""}
*
* 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 == &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, &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 == &new char[](IRCStringConverter#1)
* new IRCStringConverter(getIRCStringConverter#1).uppercase == &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, &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 == &new char[](IRCStringConverter#1)
* new IRCStringConverter(getIRCStringConverter#1).uppercase == &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 == &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, &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, &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 |