Implementation of getServerChatRoomList.

Implemented getServerChatRoomList. There is no support for listing all
channels in the API, so a custom implementation is used with raw IRC
commands.
An attempt has been made to make this thread-safe, since the 'List'
button can be called multiple times, and whenever the search box
contents change, the original list is rerequested.
fix-message-formatting
Danny van Heumen 12 years ago
parent 5851e1b719
commit fd5f41d46f

@ -929,14 +929,14 @@ public void fireMemberPresenceEvent(ChatRoomMember member,
String eventID,
String eventReason)
{
// TODO Separate this from fireMemberPresenceEvent ... it does state modification not informing.
// First update local state w.r.t. member presence change
if (eventID == ChatRoomMemberPresenceChangeEvent.MEMBER_JOINED)
{
this.chatRoomMembers.put(member.getContactAddress(), member);
addChatRoomMember(member.getContactAddress(), member);
}
else
{
this.chatRoomMembers.remove(member.getContactAddress());
removeChatRoomMember(member.getContactAddress());
}
ChatRoomMemberPresenceChangeEvent evt;

@ -50,6 +50,15 @@ public class IrcStack
*/
private IIRCState connectionState;
/**
* The cached channel list.
*
* Contained inside a simple container object in order to lock the container
* while accessing the contents.
*/
private final Container<List<String>> channellist =
new Container<List<String>>(null);
/**
* Constructor
*
@ -278,8 +287,33 @@ public boolean isJoined(ChatRoomIrcImpl chatroom)
*/
public List<String> getServerChatRoomList()
{
// TODO Implement this. (Also probably cache the list, to prevent doing too many requests.)
return new ArrayList<String>();
// FIXME Currently, not using an API library method for listing
// channels, since it isn't available.
synchronized (this.channellist)
{
if (this.channellist.instance == null)
{
List<String> list = new ArrayList<String>();
synchronized (list)
{
try
{
this.irc.addListener(new ChannelListListener(this.irc,
list));
this.irc.rawMessage("LIST");
System.out.println("Started waiting for list ...");
list.wait();
System.out.println("Done waiting for list.");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
this.channellist.instance = list;
}
return Collections.unmodifiableList(this.channellist.instance);
}
}
/**
@ -806,6 +840,9 @@ public void onChannelMessage(ChannelPrivMsg msg)
private void processModeMessage(ChannelModeMessage msg)
{
// TODO Handle or ignore ban channel mode (MODE STRING: +b
// *!*@some-ip.dynamicIP.provider.net)
// TODO msg.getSource() can also be an IRCServer instance.
String sourceNick = ((IRCUser) msg.getSource()).getNick();
ChatRoomMemberIrcImpl sourceMember =
(ChatRoomMemberIrcImpl) this.chatroom
@ -984,6 +1021,95 @@ private boolean isMe(String name)
}
}
/**
* Special listener that processes LIST replies and signals once the list is
* completely filled.
*/
private static class ChannelListListener
extends VariousMessageListenerAdapter
{
/**
* Reference to the IRC API instance.
*/
private final IRCApi api;
/**
* Reference to the provided list instance.
*/
private List<String> channels;
private ChannelListListener(IRCApi api, List<String> list)
{
if (api == null)
throw new IllegalArgumentException("IRC api cannot be null");
this.api = api;
this.channels = list;
}
/**
* Act on LIST messages: 321 RPL_LISTSTART, 322 RPL_LIST, 323
* RPL_LISTEND
*
* Clears the list upon starting. All received channels are added to the
* list. Upon receiving RPL_LISTEND finalize the list and signal the
* waiting thread that it can continue processing the list.
*/
@Override
public void onServerNumericMessage(ServerNumericMessage msg)
{
if (this.channels == null)
return;
switch (msg.getNumericCode())
{
case 321:
synchronized (this.channels)
{
this.channels.clear();
}
break;
case 322:
String channel = parse(msg.getText());
if (channel != null)
{
synchronized (this.channels)
{
this.channels.add(channel);
}
}
break;
case 323:
synchronized (this.channels)
{
this.channels.notifyAll();
// Done collecting channels. Delete list reference and
// remove listener and then we're done.
this.channels = null;
this.api.deleteListener(this);
}
break;
default:
break;
}
}
/**
* Parse an IRC server response RPL_LIST. Extract the channel name.
*
* @param text raw server response
* @return returns the channel name
*/
private String parse(String text)
{
int endOfChannelName = text.indexOf(' ');
if (endOfChannelName == -1)
return null;
// Create a new string to make sure that the original (larger)
// strings can be GC'ed.
return new String(text.substring(0, endOfChannelName));
}
}
/**
* Container for storing server parameters.
*/
@ -1060,4 +1186,31 @@ public void setServer(IRCServer server)
this.server = server;
}
}
/**
* Simplest possible container that we can use for locking while we're
* checking/modifying the contents.
*
* FIXME I would love to get rid of this thing. Is there something similar
* in Java stdlib?
*
* @param <T> The type of instance to store in the container
*/
private static class Container<T>
{
/**
* The stored instance. (Can be null)
*/
public T instance;
/**
* Constructor that immediately sets the instance.
*
* @param instance the instance to set
*/
private Container(T instance)
{
this.instance = instance;
}
}
}

Loading…
Cancel
Save