package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.QName;
import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.SharedGroupException;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
/**
* This class implements the XEP-xxx Remote Roster Management standard "2.3 Server or component requests user's roster".
* Part of command pattern used in {@link RemoteRosterInterceptor}
*
* Further information: <a href="http://jkaluza.fedorapeople.org/remote-roster.html#sect-id215516" >Here</a>
*
* @author Holger Bergunde
* @author axel.frederik.brand
*
*/
public class IQRosterPayloadProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager;
public IQRosterPayloadProcessor(RosterManager rosterMananger) {
Log.info("Created IQRosterPayloadProcessor");
_rosterManager = rosterMananger;
}
@Override
public void process(Packet packet, String subdomain, String to, String from) throws PacketRejectedException {
Log.debug("Processing packet in IQRosterPayloadProcessor for " + subdomain + " : " + packet.toString());
IQ myPacket = (IQ) packet;
String username = getUsernameFromJid(to);
if (myPacket.getType().equals(IQ.Type.get)) {
handleIQget(myPacket, subdomain, username);
} else if (myPacket.getType().equals(IQ.Type.set)) {
handleIQset(myPacket, subdomain, username);
}
}
private void handleIQget(IQ myPacket, String subdomain, String username) {
if (JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false)) {
Roster roster;
try {
roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems();
Log.debug("Sending contacts with subdomain " + subdomain + " from user " + username + " to external Component");
sendRosterToComponent(myPacket, items, subdomain);
} catch (UserNotFoundException e) {
e.printStackTrace();
}
} else {
Log.debug("Sending nonpersistant-RemoteRosterResponse to external Component for User: " + username);
sendEmptyRoster(myPacket, subdomain);
}
}
private void sendRosterToComponent(IQ requestPacket, Collection<RosterItem> items, String subdomain) {
IQ response = IQ.createResultIQ(requestPacket);
response.setTo(subdomain);
Element query = new DefaultElement( QName.get("query","jabber:iq:roster"));
for (RosterItem i : items) {
String jid = i.getJid().toString();
if (!jid.equals(subdomain) && jid.contains(subdomain)) {
Log.debug("Roster exchange for external component " + subdomain + ". Sending user " + i.getJid().toString());
Element item = new DefaultElement("item", null);
item.add(new DefaultAttribute("jid", i.getJid().toString()));
item.add(new DefaultAttribute("name", i.getNickname()));
item.add(new DefaultAttribute("subscription", "both"));
for (String s : i.getGroups()) {
Element group = new DefaultElement("group");
group.setText(s);
item.add(group);
}
query.add(item);
}
}
response.setChildElement(query);
dispatchPacket(response);
}
private void sendEmptyRoster(Packet requestPacket, String subdomain) {
IQ iq = (IQ) requestPacket;
IQ response = IQ.createResultIQ(iq);
response.setTo(subdomain);
Element query = new DefaultElement( QName.get("query","jabber:iq:roster") );
response.setChildElement(query);
dispatchPacket(response);
}
private void handleIQset(IQ myPacket, final String subdomain, final String username) throws PacketRejectedException {
IQ response = IQ.createResultIQ(myPacket);
List<Node> nodes = findNodesInDocument(myPacket.getElement().getDocument(), "//roster:item");
for (Node n : nodes) {
Roster roster;
String jid = n.valueOf("@jid");
String name = n.valueOf("@name");
String subvalue = n.valueOf("@subscription");
// We dont want to add or delete the subdomain itself, so we have to
// reject that packet, it seems openfire itself
// can interpret the iq:roster remove stanzas in some way, this was
// causing trouble on register:remove
if (JiveGlobals.getBooleanProperty("plugin.remoteroster.ignoreSubdomains", true) && jid.equals(subdomain)
&& subvalue.equals("both"))
throw new PacketRejectedException();
if (subvalue.equals("both")) {
try {
roster = _rosterManager.getRoster(username);
List<String> grouplist = new ArrayList<String>();
List<Node> groupnodes = findNodesInDocument(n.getDocument(), "//roster:group");
for (Node ne : groupnodes) {
String groupName = ne.getText();
grouplist.add(groupName);
}
boolean rosterPersistent = JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", true);
Log.debug("Adding/Updating Contact " + jid + " to roster of " + username);
try {
RosterItem item = roster.getRosterItem(new JID(jid));
item.setGroups(grouplist);
roster.updateRosterItem(item);
// dont send iq-result if just updating user
continue;
} catch (UserNotFoundException exc) {
// Then we should add him!
}
RosterItem item = roster.createRosterItem(new JID(jid), name, grouplist, false, rosterPersistent);
item.setSubStatus(RosterItem.SUB_BOTH);
roster.updateRosterItem(item);
} catch (Exception e) {
Log.info("Could not add user to Roster although no entry should exist..." + username, e);
}
dispatchPacket(response);
} else if (subvalue.equals("remove")) {
// check if its the right package to initiate unregister removal of contacts
// we dont need to do this when persistent = false because they will get deleted as soon as gateway is unavailable
if (JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false) && jid.equals(subdomain)) {
deleteSubdomainItemsFromRoster(username, subdomain);
}
// in ANY case, if its a roster:remove, we want to reject packet, as it causes errors if Openfire tries
// to handle it
throw new PacketRejectedException();
}
}
}
/**
* Searches the users roster for a specific subdomain and deletes all contacts that contain subdomain
*
* @param username
* @param subdomain
*/
private void deleteSubdomainItemsFromRoster(String username, String subdomain) {
try {
Roster roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems();
for (RosterItem item : items) {
String itemName = item.getJid().toString();
if (itemName.contains(subdomain)) {
Log.debug("Removing contact " + item.getJid().toString() + " from contact list because of Unregister.");
roster.deleteRosterItem(item.getJid(), false);
}
}
} catch (UserNotFoundException e) {
Log.debug("Couldnt find User!" + e.toString());
} catch (SharedGroupException e) {
e.printStackTrace();
}
}
}