super("Presence subscription handler");
}
public void process(Presence presence) throws PacketException {
try {
JID senderJID = presence.getFrom();
JID recipientJID = presence.getTo();
Presence.Type type = presence.getType();
// Reject presence subscription requests sent to the local server itself.
if (recipientJID == null || recipientJID.toString().equals(serverName)) {
if (type == Presence.Type.subscribe) {
Presence reply = new Presence();
reply.setTo(senderJID);
reply.setFrom(recipientJID);
reply.setType(Presence.Type.unsubscribed);
deliverer.deliver(reply);
}
return;
}
try {
Roster senderRoster = getRoster(senderJID);
if (senderRoster != null) {
manageSub(recipientJID, true, type, senderRoster);
}
Roster recipientRoster = getRoster(recipientJID);
boolean recipientSubChanged = false;
if (recipientRoster != null) {
recipientSubChanged = manageSub(senderJID, false, type, recipientRoster);
}
// Do not forward the packet to the recipient if the presence is of type subscribed
// and the recipient user has not changed its subscription state.
if (!(type == Presence.Type.subscribed && recipientRoster != null && !recipientSubChanged)) {
// If the user is already subscribed to the *local* user's presence then do not
// forward the subscription request. Also, do not send an auto-reply on behalf
// of the user. This presence stanza is the user's server know that it MUST no
// longer send notification of the subscription state change to the user.
// See http://tools.ietf.org/html/rfc3921#section-7 and/or OF-38
if (type == Presence.Type.subscribe && recipientRoster != null && !recipientSubChanged) {
try {
RosterItem.SubType subType = recipientRoster.getRosterItem(senderJID)
.getSubStatus();
if (subType == RosterItem.SUB_FROM || subType == RosterItem.SUB_BOTH) {
return;
}
}
catch (UserNotFoundException e) {
// Weird case: Roster item does not exist. Should never happen
Log.error("User does not exist while trying to update roster item. " +
"This should never happen (this indicates a programming " +
"logic error). Processing stanza: " + presence.toString(), e);
}
}
// Try to obtain a handler for the packet based on the routes. If the handler is
// a module, the module will be able to handle the packet. If the handler is a
// Session the packet will be routed to the client. If a route cannot be found
// then the packet will be delivered based on its recipient and sender.
List<JID> jids = routingTable.getRoutes(recipientJID, null);
if (!jids.isEmpty()) {
for (JID jid : jids) {
Presence presenteToSend = presence.createCopy();
// Stamp the presence with the user's bare JID as the 'from' address,
// as required by section 8.2.5 of RFC 3921
presenteToSend.setFrom(senderJID.toBareJID());
routingTable.routePacket(jid, presenteToSend, false);
}
}
else {
deliverer.deliver(presence.createCopy());
}
if (type == Presence.Type.subscribed) {
// Send the presence of the local user to the remote user. The remote user
// subscribed to the presence of the local user and the local user accepted
JID prober = localServer.isLocal(recipientJID) ?
new JID(recipientJID.toBareJID()) : recipientJID;
presenceManager.probePresence(prober, senderJID);
PresenceEventDispatcher.subscribedToPresence(recipientJID, senderJID);
}
}
if (type == Presence.Type.unsubscribed) {
// Send unavailable presence from all of the local user's available resources
// to the remote user
presenceManager.sendUnavailableFromSessions(recipientJID, senderJID);
PresenceEventDispatcher.unsubscribedToPresence(senderJID, recipientJID);
}
}
catch (SharedGroupException e) {
Presence result = presence.createCopy();
JID sender = result.getFrom();
result.setFrom(presence.getTo());
result.setTo(sender);
result.setError(PacketError.Condition.not_acceptable);
deliverer.deliver(result);
}