use of org.jivesoftware.openfire.roster.Roster in project Openfire by igniterealtime.
the class BaseTransport method addOrUpdateRosterItem.
/**
* Either updates or adds a JID to a user's roster.
*
* Tries to only edit the roster if it has to.
*
* @param userjid JID of user to have item added to their roster.
* @param contactjid JID to add to roster.
* @param nickname Nickname of item. (can be null)
* @param groups List of group the item is to be placed in. (can be null)
* @param subtype Specific subscription setting.
* @param asktype Specific ask setting.
* @throws UserNotFoundException if userjid not found.
*/
public void addOrUpdateRosterItem(JID userjid, JID contactjid, String nickname, Collection<String> groups, RosterItem.SubType subtype, RosterItem.AskType asktype) throws UserNotFoundException {
Log.debug("add or update roster item " + contactjid + " for: " + userjid);
try {
final Roster roster = rosterManager.getRoster(userjid.getNode());
try {
RosterItem gwitem = roster.getRosterItem(contactjid);
Log.debug("Found existing roster item " + contactjid + " for: " + userjid + ". We will update if required.");
boolean changed = false;
if (gwitem.getSubStatus() != subtype) {
gwitem.setSubStatus(subtype);
changed = true;
}
if (gwitem.getAskStatus() != asktype) {
gwitem.setAskStatus(asktype);
changed = true;
}
// gnickname is not null, nickname is not null, if different, set gnickname to nickname
if ((gwitem.getNickname() != null && nickname == null) || (gwitem.getNickname() == null && nickname != null) || (gwitem.getNickname() != null && nickname != null && !gwitem.getNickname().equals(nickname))) {
gwitem.setNickname(nickname);
changed = true;
}
List<String> curgroups = gwitem.getGroups();
// curgroups is not null, groups is not null, if their sizes are different or curgroups does not contain all of groups, set curgroups to groups
if (((curgroups != null && curgroups.size() > 0) && (groups == null || groups.size() == 0)) || ((curgroups == null || curgroups.size() == 0) && (groups != null && groups.size() > 0)) || (curgroups != null && groups != null && ((curgroups.size() != groups.size()) || !curgroups.containsAll(groups)))) {
try {
gwitem.setGroups((List<String>) (groups != null ? groups : new ArrayList<String>()));
changed = true;
} catch (Exception ee) {
Log.debug("Exception while setting groups for roster item:", ee);
}
}
if (changed) {
Log.debug("Updating existing roster item " + contactjid + " for: " + userjid);
roster.updateRosterItem(gwitem);
} else {
Log.debug("Update of existing roster item " + contactjid + " for: " + userjid + " can be skipped - nothing changed.");
}
} catch (UserNotFoundException e) {
try {
// Create new roster item for the gateway service or legacy contact. Only
// roster items related to the gateway service will be persistent. Roster
// items of legacy users are never persisted in the DB. (unless tweak enabled)
Log.debug("Creating new roster item " + contactjid + " for: " + userjid + ". No existing item was found.");
final RosterItem gwitem = roster.createRosterItem(contactjid, false, contactjid.getNode() == null || JiveGlobals.getBooleanProperty("plugin.gateway.tweak.persistentroster", false));
gwitem.setSubStatus(subtype);
gwitem.setAskStatus(asktype);
gwitem.setNickname(nickname);
try {
gwitem.setGroups((List<String>) groups);
} catch (Exception ee) {
Log.debug("Exception while setting groups for gateway item:", ee);
}
roster.updateRosterItem(gwitem);
} catch (UserAlreadyExistsException ee) {
Log.debug("getRosterItem claims user exists, but couldn't find via getRosterItem?", ee);
} catch (Exception ee) {
Log.debug("Exception while creating roster item:", ee);
}
}
} catch (UserNotFoundException e) {
throw new UserNotFoundException("Could not find roster for " + userjid.toString());
}
}
use of org.jivesoftware.openfire.roster.Roster in project Openfire by igniterealtime.
the class PresenceManagerImpl method handleProbe.
@Override
public void handleProbe(Presence packet) throws UnauthorizedException {
String username = packet.getTo().getNode();
try {
Roster roster = rosterManager.getRoster(username);
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);
}
}
use of org.jivesoftware.openfire.roster.Roster in project Openfire by igniterealtime.
the class IQRosterHandler method manageRoster.
/**
* The packet is a typical 'set' or 'get' update targeted at the server.
* Notice that the set could be a roster removal in which case we have to
* generate a local roster removal update as well as a new roster removal
* to send to the the roster item's owner.
*
* @param packet The packet that triggered this update
* @return Either a response to the roster update or null if the packet is corrupt and the session was closed down
*/
private IQ manageRoster(org.xmpp.packet.Roster packet) throws UnauthorizedException, UserAlreadyExistsException, SharedGroupException {
IQ returnPacket = null;
JID sender = packet.getFrom();
IQ.Type type = packet.getType();
try {
if ((sender.getNode() == null || !RosterManager.isRosterServiceEnabled() || !userManager.isRegisteredUser(sender, false)) && IQ.Type.get == type) {
// If anonymous user asks for his roster or roster service is disabled then
// return an empty roster
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement("query", "jabber:iq:roster");
return reply;
}
if (!localServer.isLocal(sender)) {
// Sender belongs to a remote server so discard this IQ request
Log.warn("Discarding IQ roster packet of remote user: " + packet);
return null;
}
Roster cachedRoster = userManager.getUser(sender.getNode()).getRoster();
if (IQ.Type.get == type) {
if (RosterManager.isRosterVersioningEnabled()) {
String clientVersion = packet.getChildElement().attributeValue("ver");
String latestVersion = String.valueOf(cachedRoster.hashCode());
// Whether or not the roster has been modified since the version ID enumerated by the client, ...
if (!latestVersion.equals(clientVersion)) {
// ... the server MUST either return the complete roster
// (including a 'ver' attribute that signals the latest version)
returnPacket = cachedRoster.getReset();
returnPacket.getChildElement().addAttribute("ver", latestVersion);
} else {
// ... or return an empty IQ-result
returnPacket = new org.xmpp.packet.IQ();
}
} else {
returnPacket = cachedRoster.getReset();
}
returnPacket.setType(IQ.Type.result);
returnPacket.setTo(sender);
returnPacket.setID(packet.getID());
// Force delivery of the response because we need to trigger
// a presence probe from all contacts
deliverer.deliver(returnPacket);
returnPacket = null;
} else if (IQ.Type.set == type) {
returnPacket = IQ.createResultIQ(packet);
// The <query/> element contains more than one <item/> child element.
if (packet.getItems().size() > 1) {
returnPacket.setError(new PacketError(PacketError.Condition.bad_request, PacketError.Type.modify, "Query contains more than one item"));
} else {
for (org.xmpp.packet.Roster.Item item : packet.getItems()) {
if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.remove) {
if (removeItem(cachedRoster, packet.getFrom(), item) == null) {
// RFC 6121 2.5.3. Error Cases: If the value of the 'jid' attribute specifies an item that is not in the roster, then the server MUST return an <item-not-found/> stanza error.
returnPacket.setError(PacketError.Condition.item_not_found);
}
} else {
PacketError error = checkGroups(item.getGroups());
if (error != null) {
returnPacket.setError(error);
} else {
if (cachedRoster.isRosterItem(item.getJID())) {
// existing item
RosterItem cachedItem = cachedRoster.getRosterItem(item.getJID());
cachedItem.setAsCopyOf(item);
cachedRoster.updateRosterItem(cachedItem);
} else {
// new item
cachedRoster.createRosterItem(item);
}
}
}
}
}
}
} catch (UserNotFoundException e) {
throw new UnauthorizedException(e);
}
return returnPacket;
}
use of org.jivesoftware.openfire.roster.Roster in project Openfire by igniterealtime.
the class PresenceUpdateHandler method directedPresenceSent.
/**
* Notification method sent to this handler when a user has sent a directed
* presence to an entity. If the sender of the presence is local (to this server)
* and the target entity does not belong to the user's roster then update the
* registry of sent directed presences by the user.
*
* @param update the directed Presence sent by the user to an entity.
* @param handlerJID the JID of the handler that will receive/handle/process the sent packet.
* @param jid the receipient specified in the packet to handle.
*/
public void directedPresenceSent(Presence update, JID handlerJID, String jid) {
if (update.getFrom() == null) {
return;
}
if (localServer.isLocal(update.getFrom())) {
boolean keepTrack = false;
String name = update.getFrom().getNode();
if (name != null && !"".equals(name)) {
// Keep track of all directed presences if roster service is disabled
if (!RosterManager.isRosterServiceEnabled()) {
keepTrack = true;
} else {
try {
Roster roster = rosterManager.getRoster(name);
// If the directed presence was sent to an entity that is not in the user's
// roster, keep a registry of this so that when the user goes offline we
// will be able to send the unavailable presence to the entity
RosterItem rosterItem = null;
try {
rosterItem = roster.getRosterItem(update.getTo());
} catch (UserNotFoundException e) {
// Ignore
}
if (rosterItem == null || RosterItem.SUB_NONE == rosterItem.getSubStatus() || RosterItem.SUB_TO == rosterItem.getSubStatus()) {
keepTrack = true;
}
} catch (UserNotFoundException e) {
Log.warn("Presence being sent from unknown user " + name, e);
} catch (PacketException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
} else if (update.getFrom().getResource() != null) {
// Keep always track of anonymous users directed presences
keepTrack = true;
}
if (keepTrack) {
String sender = update.getFrom().toString();
Lock lock = directedPresencesCache.getLock(sender);
lock.lock();
try {
ConcurrentLinkedQueue<DirectedPresence> directedPresences = directedPresencesCache.get(sender);
if (Presence.Type.unavailable.equals(update.getType())) {
if (directedPresences != null) {
// It's a directed unavailable presence
if (routingTable.hasClientRoute(handlerJID)) {
// address of the session) so remove the handler from the map
for (DirectedPresence directedPresence : directedPresences) {
if (directedPresence.getHandler().equals(handlerJID)) {
directedPresences.remove(directedPresence);
break;
}
}
} else {
// unavailable presence
for (DirectedPresence directedPresence : directedPresences) {
if (directedPresence.getHandler().equals(handlerJID)) {
directedPresence.removeReceiver(jid);
if (directedPresence.isEmpty()) {
directedPresences.remove(directedPresence);
}
break;
}
}
}
if (directedPresences.isEmpty()) {
// Remove the user from the registry since the list of directed
// presences is empty
directedPresencesCache.remove(sender);
localDirectedPresences.remove(sender);
} else {
directedPresencesCache.put(sender, directedPresences);
localDirectedPresences.put(sender, directedPresences);
}
}
} else {
if (directedPresences == null) {
// We are using a set to avoid duplicate jids in case the user
// sends several directed presences to the same handler. The Map also
// ensures that if the user sends several presences to the same handler
// we will have only one entry in the Map
directedPresences = new ConcurrentLinkedQueue<>();
}
// Add the handler to the list of handler that processed the directed
// presence sent by the user. This handler will be used to send
// the unavailable presence when the user goes offline
DirectedPresence affectedDirectedPresence = null;
for (DirectedPresence directedPresence : directedPresences) {
if (directedPresence.getHandler().equals(handlerJID)) {
affectedDirectedPresence = directedPresence;
break;
}
}
if (affectedDirectedPresence == null) {
affectedDirectedPresence = new DirectedPresence(handlerJID);
directedPresences.add(affectedDirectedPresence);
}
affectedDirectedPresence.addReceiver(jid);
directedPresencesCache.put(sender, directedPresences);
localDirectedPresences.put(sender, directedPresences);
}
} finally {
lock.unlock();
}
}
}
}
use of org.jivesoftware.openfire.roster.Roster in project Openfire by igniterealtime.
the class PresenceUpdateHandler method broadcastUpdate.
/**
* Broadcast the given update to all subscribers. We need to:
* <ul>
* <li>Query the roster table for subscribers</li>
* <li>Iterate through the list and send the update to each subscriber</li>
* </ul>
* <p/>
* Is there a safe way to cache the query results while maintaining
* integrity with roster changes?
*
* @param update The update to broadcast
*/
private void broadcastUpdate(Presence update) {
if (update.getFrom() == null) {
return;
}
if (localServer.isLocal(update.getFrom())) {
// Do nothing if roster service is disabled
if (!RosterManager.isRosterServiceEnabled()) {
return;
}
// Local updates can simply run through the roster of the local user
String name = update.getFrom().getNode();
try {
if (name != null && !"".equals(name)) {
Roster roster = rosterManager.getRoster(name);
roster.broadcastPresence(update);
}
} catch (UserNotFoundException e) {
Log.warn("Presence being sent from unknown user " + name, e);
} catch (PacketException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
} else {
// Foreign updates will do a reverse lookup of entries in rosters
// on the server
Log.warn("Presence requested from server " + localServer.getServerInfo().getXMPPDomain() + " by unknown user: " + update.getFrom());
}
}
Aggregations