Commit 1fbab5fe authored by Christian Schudt's avatar Christian Schudt

Fix XEP-0012 logic.

If a query has no 'to' attribute it should be treated on behalf of the sender.
It should not be treated as if it were targeted to the server (and return the server uptime).

The former logic also threw an UserNotFoundException, if the user queried itself, because the user was not on his own roster.
 I've fixed that in the canProbePresence method.

 Fixes issue OF-982
parent 25d492d4
......@@ -98,7 +98,7 @@ public interface PresenceManager {
* Returns true if the the prober is allowed to see the presence of the probee.
*
* @param prober the user that is trying to probe the presence of another user.
* @param probee the username of the uset that is being probed.
* @param probee the username of the user that is being probed.
* @return true if the the prober is allowed to see the presence of the probee.
* @throws UserNotFoundException If the probee does not exist in the local server or the prober
* is not present in the roster of the probee.
......
......@@ -22,8 +22,6 @@ import org.jivesoftware.openfire.PresenceManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
......@@ -43,28 +41,29 @@ import java.util.Iterator;
*/
public class IQLastActivityHandler extends IQHandler implements ServerFeaturesProvider {
private IQHandlerInfo info;
private static final String NAMESPACE = "jabber:iq:last";
private final IQHandlerInfo info;
private PresenceManager presenceManager;
private RosterManager rosterManager;
public IQLastActivityHandler() {
super("XMPP Last Activity Handler");
info = new IQHandlerInfo("query", "jabber:iq:last");
info = new IQHandlerInfo("query", NAMESPACE);
}
@Override
public IQ handleIQ(IQ packet) throws UnauthorizedException {
IQ reply = IQ.createResultIQ(packet);
Element lastActivity = reply.setChildElement("query", "jabber:iq:last");
Element lastActivity = reply.setChildElement("query", NAMESPACE);
String sender = packet.getFrom().getNode();
String username = packet.getTo() == null ? null : packet.getTo().getNode();
// Check if any of the usernames is null
if (sender == null) {
reply.setError(PacketError.Condition.forbidden);
return reply;
}
if (username == null) {
if (packet.getTo() != null && packet.getTo().getNode() == null && XMPPServer.getInstance().isLocal(packet.getTo())) {
// http://xmpp.org/extensions/xep-0012.html#server
// When the last activity query is sent to a server or component (i.e., to a JID of the form <domain.tld>),
// the information contained in the IQ reply reflects the uptime of the JID sending the reply.
......@@ -75,34 +74,36 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
return reply;
}
// If the 'to' attribute is null, treat the IQ on behalf of the account from which received the stanza
// in accordance with RFC 6120 § 10.3.3.
String username = packet.getTo() == null ? packet.getFrom().getNode() : packet.getTo().getNode();
try {
RosterItem item = rosterManager.getRoster(username).getRosterItem(packet.getFrom());
// Check that the user requesting this information is subscribed to the user's presence
if (item.getSubStatus() == RosterItem.SUB_FROM ||
item.getSubStatus() == RosterItem.SUB_BOTH) {
if (sessionManager.getSessions(username).isEmpty()) {
User user = UserManager.getInstance().getUser(username);
// The user is offline so answer the user's "last available time and the
// status message of the last unavailable presence received from the user"
long lastActivityTime = presenceManager.getLastActivity(user);
if (lastActivityTime > -1) {
// Convert it to seconds
lastActivityTime = lastActivityTime / 1000;
if (username != null) {
// Check that the user requesting this information is subscribed to the user's presence
if (presenceManager.canProbePresence(packet.getFrom(), username)) {
if (sessionManager.getSessions(username).isEmpty()) {
User user = UserManager.getInstance().getUser(username);
// The user is offline so answer the user's "last available time and the
// status message of the last unavailable presence received from the user"
long lastActivityTime = presenceManager.getLastActivity(user);
if (lastActivityTime > -1) {
// Convert it to seconds
lastActivityTime = lastActivityTime / 1000;
}
lastActivity.addAttribute("seconds", String.valueOf(lastActivityTime));
String lastStatus = presenceManager.getLastPresenceStatus(user);
if (lastStatus != null && lastStatus.length() > 0) {
lastActivity.setText(lastStatus);
}
} else {
// The user is online so answer seconds=0
lastActivity.addAttribute("seconds", "0");
}
lastActivity.addAttribute("seconds", String.valueOf(lastActivityTime));
String lastStatus = presenceManager.getLastPresenceStatus(user);
if (lastStatus != null && lastStatus.length() > 0) {
lastActivity.setText(lastStatus);
}
}
else {
// The user is online so answer seconds=0
lastActivity.addAttribute("seconds", "0");
} else {
reply.setError(PacketError.Condition.forbidden);
}
}
else {
reply.setError(PacketError.Condition.forbidden);
}
}
catch (UserNotFoundException e) {
reply.setError(PacketError.Condition.forbidden);
......@@ -117,13 +118,12 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
@Override
public Iterator<String> getFeatures() {
return Collections.singleton("jabber:iq:last").iterator();
return Collections.singleton(NAMESPACE).iterator();
}
@Override
public void initialize(XMPPServer server) {
super.initialize(server);
presenceManager = server.getPresenceManager();
rosterManager = server.getRosterManager();
}
}
\ No newline at end of file
......@@ -337,6 +337,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager,
@Override
public boolean canProbePresence(JID prober, String probee) throws UserNotFoundException {
if (probee.equals(prober.getNode()) && XMPPServer.getInstance().isLocal(prober)) {
return true;
}
RosterItem item = rosterManager.getRoster(probee).getRosterItem(prober);
return item.getSubStatus() == RosterItem.SUB_FROM
|| item.getSubStatus() == RosterItem.SUB_BOTH;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment