PresenceManagerImpl.java 17.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/**
 * $RCSfile: PresenceManagerImpl.java,v $
 * $Revision: 3128 $
 * $Date: 2005-11-30 15:31:54 -0300 (Wed, 30 Nov 2005) $
 *
 * Copyright (C) 2004 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
 */

package org.jivesoftware.wildfire.spi;

import org.dom4j.Document;
import org.dom4j.DocumentException;
16 17 18
import org.dom4j.DocumentHelper;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
19 20
import org.jivesoftware.wildfire.*;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
21
import org.jivesoftware.wildfire.component.InternalComponentManager;
22
import org.jivesoftware.wildfire.container.BasicModule;
23 24 25
import org.jivesoftware.wildfire.handler.PresenceUpdateHandler;
import org.jivesoftware.wildfire.privacy.PrivacyList;
import org.jivesoftware.wildfire.privacy.PrivacyListManager;
26 27
import org.jivesoftware.wildfire.roster.Roster;
import org.jivesoftware.wildfire.roster.RosterItem;
28
import org.jivesoftware.wildfire.roster.RosterManager;
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.xmpp.component.Component;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * Simple in memory implementation of the PresenceManager interface.
 *
 * @author Iain Shigeoka
 */
public class PresenceManagerImpl extends BasicModule implements PresenceManager {

    private static final String LAST_PRESENCE_PROP = "lastUnavailablePresence";
    private static final String LAST_ACTIVITY_PROP = "lastActivity";

    private SessionManager sessionManager;
53
    private UserManager userManager;
54
    private RosterManager rosterManager;
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    private XMPPServer server;
    private PacketDeliverer deliverer;
    private PresenceUpdateHandler presenceUpdateHandler;

    private InternalComponentManager componentManager;

    public PresenceManagerImpl() {
        super("Presence manager");

        // Use component manager for Presence Updates.
        componentManager = InternalComponentManager.getInstance();
    }

    public boolean isAvailable(User user) {
        return sessionManager.getSessionCount(user.getUsername()) > 0;
    }

    public Presence getPresence(User user) {
        if (user == null) {
            return null;
        }
        Presence presence = null;

        for (ClientSession session : sessionManager.getSessions(user.getUsername())) {
            if (presence == null) {
                presence = session.getPresence();
            }
            else {
                // Get the ordinals of the presences to compare. If no ordinal is available then
                // assume a value of -1
                int o1 = presence.getShow() != null ? presence.getShow().ordinal() : -1;
                int o2 = session.getPresence().getShow() != null ?
                        session.getPresence().getShow().ordinal() : -1;
                // Compare the presences' show ordinals
                if (o1 > o2) {
                    presence = session.getPresence();
                }
            }
        }
        return presence;
    }

    public Collection<Presence> getPresences(String username) {
        if (username == null) {
            return null;
        }
        List<Presence> presences = new ArrayList<Presence>();

        for (ClientSession session : sessionManager.getSessions(username)) {
            presences.add(session.getPresence());
        }
        return Collections.unmodifiableCollection(presences);
    }

    public String getLastPresenceStatus(User user) {
        String answer = null;
        String presenceXML = user.getProperties().get(LAST_PRESENCE_PROP);
        if (presenceXML != null) {
            try {
                // Parse the element
                Document element = DocumentHelper.parseText(presenceXML);
                answer = element.getRootElement().elementTextTrim("status");
            }
            catch (DocumentException e) {
                Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
            }
        }
        return answer;
    }

    public long getLastActivity(User user) {
        long answer = -1;
        String offline = user.getProperties().get(LAST_ACTIVITY_PROP);
        if (offline != null) {
            try {
                answer = (System.currentTimeMillis() - Long.parseLong(offline)) / 1000;
            }
            catch (NumberFormatException e) {
                Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
            }
        }
        return answer;
    }

    public void userAvailable(Presence presence) {
        // Delete the last unavailable presence of this user since the user is now
        // available. Only perform this operation if this is an available presence sent to
        // THE SERVER and the presence belongs to a local user.
        if (presence.getTo() == null && server.isLocal(presence.getFrom())) {
            String username = presence.getFrom().getNode();
145
            if (username == null || !userManager.isRegisteredUser(username)) {
146 147 148 149
                // Ignore anonymous users
                return;
            }
            try {
150
                User probeeUser = userManager.getUser(username);
151 152 153 154 155 156 157 158 159 160 161 162 163
                probeeUser.getProperties().remove(LAST_PRESENCE_PROP);
            }
            catch (UserNotFoundException e) {
            }
        }
    }

    public void userUnavailable(Presence presence) {
        // Only save the last presence status and keep track of the time when the user went
        // offline if this is an unavailable presence sent to THE SERVER and the presence belongs
        // to a local user.
        if (presence.getTo() == null && server.isLocal(presence.getFrom())) {
            String username = presence.getFrom().getNode();
164
            if (username == null || !userManager.isRegisteredUser(username)) {
165 166 167 168
                // Ignore anonymous users
                return;
            }
            try {
169
                User probeeUser = userManager.getUser(username);
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
                if (!presence.getElement().elements().isEmpty()) {
                    // Save the last unavailable presence of this user if the presence contains any
                    // child element such as <status>
                    probeeUser.getProperties().put(LAST_PRESENCE_PROP, presence.toXML());
                }
                // Keep track of the time when the user went offline
                probeeUser.getProperties().put(LAST_ACTIVITY_PROP,
                        String.valueOf(System.currentTimeMillis()));
            }
            catch (UserNotFoundException e) {
            }
        }
    }

    public void handleProbe(Presence packet) throws UnauthorizedException {
        String username = packet.getTo().getNode();
        try {
187
            Roster roster = rosterManager.getRoster(username);
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
            RosterItem item = roster.getRosterItem(packet.getFrom());
            if (item.getSubStatus() == RosterItem.SUB_FROM
                    || item.getSubStatus() == RosterItem.SUB_BOTH) {
                probePresence(packet.getFrom(),  packet.getTo());
            }
            else {
                PacketError.Condition error = PacketError.Condition.not_authorized;
                if ((item.getSubStatus() == RosterItem.SUB_NONE &&
                        item.getRecvStatus() != RosterItem.RECV_SUBSCRIBE) ||
                        (item.getSubStatus() == RosterItem.SUB_TO &&
                        item.getRecvStatus() != RosterItem.RECV_SUBSCRIBE)) {
                    error = PacketError.Condition.forbidden;
                }
                Presence presenceToSend = new Presence();
                presenceToSend.setError(error);
                presenceToSend.setTo(packet.getFrom());
                presenceToSend.setFrom(packet.getTo());
                deliverer.deliver(presenceToSend);
            }
        }
        catch (UserNotFoundException e) {
            Presence presenceToSend = new Presence();
            presenceToSend.setError(PacketError.Condition.forbidden);
            presenceToSend.setTo(packet.getFrom());
            presenceToSend.setFrom(packet.getTo());
            deliverer.deliver(presenceToSend);
        }
    }

    public boolean canProbePresence(JID prober, String probee) throws UserNotFoundException {
218
        RosterItem item = rosterManager.getRoster(probee).getRosterItem(prober);
219 220 221 222 223 224 225 226 227 228
        if (item.getSubStatus() == RosterItem.SUB_FROM
                || item.getSubStatus() == RosterItem.SUB_BOTH) {
            return true;
        }
        return false;
    }

    public void probePresence(JID prober, JID probee) {
        try {
            if (server.isLocal(probee)) {
229 230 231 232 233 234 235 236 237 238
                // Local probers should receive presences of probee in all connected resources
                Collection<JID> proberFullJIDs = new ArrayList<JID>();
                if (prober.getResource() == null && server.isLocal(prober)) {
                    for (ClientSession session : sessionManager.getSessions(prober.getNode())) {
                        proberFullJIDs.add(session.getAddress());
                    }
                }
                else {
                    proberFullJIDs.add(prober);
                }
239 240
                // If the probee is a local user then don't send a probe to the contact's server.
                // But instead just send the contact's presence to the prober
241 242 243 244 245 246 247 248
                Collection<ClientSession> sessions = sessionManager.getSessions(probee.getNode());
                if (sessions.isEmpty()) {
                    // If the probee is not online then try to retrieve his last unavailable
                    // presence which may contain particular information and send it to the
                    // prober
                    String presenceXML =
                            userManager.getUserProperty(probee.getNode(), LAST_PRESENCE_PROP);
                    if (presenceXML != null) {
249
                        try {
250 251 252 253 254 255 256 257 258
                            // Parse the element
                            Document element = DocumentHelper.parseText(presenceXML);
                            // Create the presence from the parsed element
                            Presence presencePacket = new Presence(element.getRootElement());
                            presencePacket.setFrom(probee.toBareJID());
                            // Check if default privacy list of the probee blocks the
                            // outgoing presence
                            PrivacyList list = PrivacyListManager.getInstance()
                                    .getDefaultPrivacyList(probee.getNode());
259 260 261 262 263 264 265
                            // Send presence to all prober's resources
                            for (JID receipient : proberFullJIDs) {
                                presencePacket.setTo(receipient);
                                if (list == null || !list.shouldBlockPacket(presencePacket)) {
                                    // Send the presence to the prober
                                    deliverer.deliver(presencePacket);
                                }
266 267
                            }
                        }
268 269
                        catch (Exception e) {
                            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
270 271
                        }
                    }
272 273 274 275 276 277 278 279 280 281 282
                }
                else {
                    // The contact is online so send to the prober all the resources where the
                    // probee is connected
                    for (ClientSession session : sessions) {
                        // Create presence to send from probee to prober
                        Presence presencePacket = session.getPresence().createCopy();
                        presencePacket.setFrom(session.getAddress());
                        // Check if a privacy list of the probee blocks the outgoing presence
                        PrivacyList list = session.getActiveList();
                        list = list == null ? session.getDefaultList() : list;
283 284 285 286 287 288 289 290 291 292 293 294 295 296
                        // Send presence to all prober's resources
                        for (JID receipient : proberFullJIDs) {
                            presencePacket.setTo(receipient);
                            if (list != null) {
                                if (list.shouldBlockPacket(presencePacket)) {
                                    // Default list blocked outgoing presence so skip this session
                                    continue;
                                }
                            }
                            try {
                                deliverer.deliver(presencePacket);
                            }
                            catch (Exception e) {
                                Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
297
                            }
298
                        }
299 300 301 302
                    }
                }
            }
            else {
Gaston Dombiak's avatar
Gaston Dombiak committed
303
                Component component = getComponent(probee);
304 305 306 307 308 309 310 311
                if (component != null) {
                    // If the probee belongs to a component then ask the component to process the
                    // probe presence
                    Presence presence = new Presence();
                    presence.setType(Presence.Type.probe);
                    presence.setFrom(prober);
                    presence.setTo(probee);
                    component.processPacket(presence);
312 313
                }
                else {
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
                    // Check if the probee may be hosted by this server
                    /*String serverDomain = server.getServerInfo().getName();
                    if (!probee.getDomain().contains(serverDomain)) {*/
                    if (server.isRemote(probee)) {
                        // Send the probe presence to the remote server
                        Presence probePresence = new Presence();
                        probePresence.setType(Presence.Type.probe);
                        probePresence.setFrom(prober);
                        probePresence.setTo(probee.toBareJID());
                        // Send the probe presence
                        deliverer.deliver(probePresence);
                    }
                    else {
                        // The probee may be related to a component that has not yet been connected so
                        // we will keep a registry of this presence probe. The component will answer
                        // this presence probe when he becomes online
                        componentManager.addPresenceRequest(prober, probee);
                    }
332 333 334 335 336 337 338 339 340
                }
            }
        }
        catch (Exception e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        }
    }

    public void sendUnavailableFromSessions(JID recipientJID, JID userJID) {
341
        if (userManager.isRegisteredUser(userJID.getNode())) {
342 343 344 345 346 347 348 349
            for (ClientSession session : sessionManager.getSessions(userJID.getNode())) {
                // Do not send an unavailable presence if the user sent a direct available presence
                if (presenceUpdateHandler.hasDirectPresence(session, recipientJID)) {
                    continue;
                }
                Presence presencePacket = new Presence();
                presencePacket.setType(Presence.Type.unavailable);
                presencePacket.setFrom(session.getAddress());
350 351 352 353 354 355 356
                // Ensure that unavailable presence is sent to all receipient's resources
                Collection<JID> recipientFullJIDs = new ArrayList<JID>();
                if (server.isLocal(recipientJID)) {
                    for (ClientSession targetSession : sessionManager
                            .getSessions(recipientJID.getNode())) {
                        recipientFullJIDs.add(targetSession.getAddress());
                    }
357
                }
358 359 360 361 362 363 364 365 366 367 368
                else {
                    recipientFullJIDs.add(recipientJID);
                }
                for (JID jid : recipientFullJIDs) {
                    presencePacket.setTo(jid);
                    try {
                        deliverer.deliver(presencePacket);
                    }
                    catch (Exception e) {
                        Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
                    }
369 370 371 372 373 374 375 376 377 378 379 380 381 382
                }
            }
        }
    }

    // #####################################################################
    // Module management
    // #####################################################################

    public void initialize(XMPPServer server) {
        super.initialize(server);
        this.server = server;
        deliverer = server.getPacketDeliverer();
        sessionManager = server.getSessionManager();
383
        userManager = server.getUserManager();
384
        presenceUpdateHandler = server.getPresenceUpdateHandler();
385
        rosterManager = server.getRosterManager();
386 387
    }

Gaston Dombiak's avatar
Gaston Dombiak committed
388
    private Component getComponent(JID probee) {
389
        // Check for registered components
390
        Component component = componentManager.getComponent(probee);
391 392 393 394 395 396
        if (component != null) {
            return component;
        }
        return null;
    }
}