If an item is stored in the Roster in mixed case (IE. syNIC@linuxhelp.HOMEUNIX.com) or if a user signs on with a mixed case JID, it is possible that RosterListener.presenceChanged() will never get fired.
If the item is stored in my Roster like this: SyNIC@linuxhelp.homeunix.com and that person signs on with synic@linuxhelp.homeunix.com then only the presence for synic@linuxhelp.homeunix.com will be recieved, and RosterListener.presenceChanged() will never be fired. This is because the PresencePacketListener inner class of org.jivesoftware.smack.Roster does not compensate for this.
This minor edit does fix it:
/**
* Listens for all presence packets and processes them.
*/
private class PresencePacketListener implements PacketListener {
public void processPacket(Packet packet) {
Presence presence = (Presence)packet;
String from = presence.getFrom();
String key = StringUtils.parseBareAddress(from);
// If an "available" packet, add it to the presence map. Each presence map will hold
// for a particular user a map with the presence packets saved for each resource.
if (presence.getType() == Presence.Type.AVAILABLE) {
Map userPresences;
// Get the user presence map
if (presenceMap.get(key) == null) {
userPresences = new HashMap();
presenceMap.put(key, userPresences);
} else {
userPresences = (Map) presenceMap.get(key);
}
// Add the new presence taking in consideration the presence�s resource
userPresences.put(StringUtils.parseResource(from), presence);
// If the user is in the roster, fire an event.
synchronized (entries) {
for (Iterator i = entries.iterator(); i.hasNext();) {
RosterEntry entry = (RosterEntry) i.next();
if (entry.getUser().toLowerCase().equals(key.toLowerCase())) {
fireRosterPresenceEvent(key);
}
}
}
}
// If an "unavailable" packet, remove any entries in the presence map.
else if (presence.getType() == Presence.Type.UNAVAILABLE) {
if (presenceMap.get(key) != null) {
Map userPresences = (Map) presenceMap.get(key);
userPresences.remove(StringUtils.parseResource(from));
if (userPresences.isEmpty()) {
presenceMap.remove(key);
}
}
// If the user is in the roster, fire an event.
synchronized (entries) {
for (Iterator i=entries.iterator(); i.hasNext(); ) {
RosterEntry entry = (RosterEntry)i.next();
if (entry.getUser().toLowerCase().equals(key.toLowerCase())) {
fireRosterPresenceEvent(key);
}
}
}
}
else if (presence.getType() == Presence.Type.SUBSCRIBE) {
if (subscriptionMode == SUBSCRIPTION_ACCEPT_ALL) {
// Accept all subscription requests.
Presence response = new Presence(Presence.Type.SUBSCRIBED);
response.setTo(presence.getFrom());
connection.sendPacket(response);
}
else if (subscriptionMode == SUBSCRIPTION_REJECT_ALL) {
// Reject all subscription requests.
Presence response = new Presence(Presence.Type.UNSUBSCRIBED);
response.setTo(presence.getFrom());
connection.sendPacket(response);
}
// Otherwise, in manual mode so ignore.
}
}
}
I just change the lines that say:
if(entry.getUser().equals(key))
to say:
if(entry.getUser().toLowerCase().equals(key.toLowerCase()))
What do you think?