/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.xmpp.impl.roster;
//~--- non-JDK imports --------------------------------------------------------
import tigase.db.TigaseDBException;
import tigase.db.UserRepository;
import tigase.server.Packet;
import tigase.util.Algorithms;
import tigase.xml.Element;
import tigase.xml.XMLUtils;
import tigase.xmpp.BareJID;
import tigase.xmpp.JID;
import tigase.xmpp.NoConnectionIdException;
import tigase.xmpp.NotAuthorizedException;
import tigase.xmpp.StanzaType;
import tigase.xmpp.XMPPResourceConnection;
//~--- JDK imports ------------------------------------------------------------
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
//~--- classes ----------------------------------------------------------------
/**
* Describe class RosterAbstract here.
*
*
* Created: Thu Sep 4 18:09:52 2008
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public abstract class RosterAbstract {
// Below StateTransition enum is implementation of all below tables
// coming from RFC-3921
// Table 1: Recommended handling of outbound "subscribed" stanzas
// +----------------------------------------------------------------+
// | EXISTING STATE | ROUTE? | NEW STATE |
// +----------------------------------------------------------------+
// | "None" | no | no state change |
// | "None + Pending Out" | no | no state change |
// | "None + Pending In" | yes | "From" |
// | "None + Pending Out/In" | yes | "From + Pending Out" |
// | "To" | no | no state change |
// | "To + Pending In" | yes | "Both" |
// | "From" | no | no state change |
// | "From + Pending Out" | no | no state change |
// | "Both" | no | no state change |
// +----------------------------------------------------------------+
// Table 2: Recommended handling of outbound "unsubscribed" stanzas
// +----------------------------------------------------------------+
// | EXISTING STATE | ROUTE? | NEW STATE |
// +----------------------------------------------------------------+
// | "None" | no | no state change |
// | "None + Pending Out" | no | no state change |
// | "None + Pending In" | yes | "None" |
// | "None + Pending Out/In" | yes | "None + Pending Out" |
// | "To" | no | no state change |
// | "To + Pending In" | yes | "To" |
// | "From" | yes | "None" |
// | "From + Pending Out" | yes | "None + Pending Out" |
// | "Both" | yes | "To" |
// +----------------------------------------------------------------+
// Table 3: Recommended handling of inbound "subscribe" stanzas
// +------------------------------------------------------------------+
// | EXISTING STATE | DELIVER? | NEW STATE |
// +------------------------------------------------------------------+
// | "None" | yes | "None + Pending In" |
// | "None + Pending Out" | yes | "None + Pending Out/In" |
// | "None + Pending In" | no | no state change |
// | "None + Pending Out/In" | no | no state change |
// | "To" | yes | "To + Pending In" |
// | "To + Pending In" | no | no state change |
// | "From" | no * | no state change |
// | "From + Pending Out" | no * | no state change |
// | "Both" | no * | no state change |
// +------------------------------------------------------------------+
// Table 4: Recommended handling of inbound "unsubscribe" stanzas
// +------------------------------------------------------------------+
// | EXISTING STATE | DELIVER? | NEW STATE |
// +------------------------------------------------------------------+
// | "None" | no | no state change |
// | "None + Pending Out" | no | no state change |
// | "None + Pending In" | yes * | "None" |
// | "None + Pending Out/In" | yes * | "None + Pending Out" |
// | "To" | no | no state change |
// | "To + Pending In" | yes * | "To" |
// | "From" | yes * | "None" |
// | "From + Pending Out" | yes * | "None + Pending Out" |
// | "Both" | yes * | "To" |
// +------------------------------------------------------------------+
// Table 5: Recommended handling of inbound "subscribed" stanzas
// +------------------------------------------------------------------+
// | EXISTING STATE | DELIVER? | NEW STATE |
// +------------------------------------------------------------------+
// | "None" | no | no state change |
// | "None + Pending Out" | yes | "To" |
// | "None + Pending In" | no | no state change |
// | "None + Pending Out/In" | yes | "To + Pending In" |
// | "To" | no | no state change |
// | "To + Pending In" | no | no state change |
// | "From" | no | no state change |
// | "From + Pending Out" | yes | "Both" |
// | "Both" | no | no state change |
// +------------------------------------------------------------------+
// Table 6: Recommended handling of inbound "unsubscribed" stanzas
// +------------------------------------------------------------------+
// | EXISTING STATE | DELIVER? | NEW STATE |
// +------------------------------------------------------------------+
// | "None" | no | no state change |
// | "None + Pending Out" | yes | "None" |
// | "None + Pending In" | no | no state change |
// | "None + Pending Out/In" | yes | "None + Pending In" |
// | "To" | yes | "None" |
// | "To + Pending In" | yes | "None + Pending In" |
// | "From" | no | no state change |
// | "From + Pending Out" | yes | "From" |
// | "Both" | yes | "From" |
// +------------------------------------------------------------------+
// There are 2 tables missing I think in RFC-3921:
// Table 7: Recommended handling of outbound "subscribe" stanzas
// +------------------------------------------------------------------+
// | EXISTING STATE | ROUTE? | NEW STATE |
// +------------------------------------------------------------------+
// | "None" | yes | "None + Pending Out" |
// | "None + Pending Out" | no | no state change |
// | "None + Pending In" | yes | "None + Pending Out/In" |
// | "None + Pending Out/In" | no | no state change |
// | "To" | no | no state change |
// | "To + Pending In" | no | no state change |
// | "From" | yes | "From + Pending Out" |
// | "From + Pending Out" | no | no state change |
// | "Both" | no | no state change |
// +------------------------------------------------------------------+
// Table 8: Recommended handling of outbound "unsubscribe" stanzas
// +------------------------------------------------------------------+
// | EXISTING STATE | ROUTE? | NEW STATE |
// +------------------------------------------------------------------+
// | "None" | no | no state change |
// | "None + Pending Out" | yes | "None" |
// | "None + Pending In" | no | no state change |
// | "None + Pending Out/In" | yes | "None + Pending In" |
// | "To" | yes | "None" |
// | "To + Pending In" | yes | "None + Pending In" |
// | "From" | no | no state change |
// | "From + Pending Out" | yes | "From" |
// | "Both" | yes | "From" |
// +------------------------------------------------------------------+
/**
* Enum description
*
*/
public enum StateTransition {
none(SubscriptionType.none, // Table 1.
SubscriptionType.none, // Table 2.
SubscriptionType.none_pending_in, // Table 3.
SubscriptionType.none, // Table 4.
SubscriptionType.none, // Table 5.
SubscriptionType.none, // Table 6.
SubscriptionType.none_pending_out, // Table 7.
SubscriptionType.none // Table 8.
), none_pending_out(SubscriptionType.none_pending_out, // Table 1.
SubscriptionType.none_pending_out, // Table 2.
SubscriptionType.none_pending_out_in, // Table 3.
SubscriptionType.none_pending_out, // Table 4.
SubscriptionType.to, // Table 5.
SubscriptionType.none, // Table 6.
SubscriptionType.none_pending_out, // Table 7.
SubscriptionType.none // Table 8.
), none_pending_in(SubscriptionType.from, // Table 1.
SubscriptionType.none, // Table 2.
SubscriptionType.none_pending_in, // Table 3.
SubscriptionType.none, // Table 4.
SubscriptionType.none_pending_in, // Table 5.
SubscriptionType.none_pending_in, // Table 6.
SubscriptionType.none_pending_out_in, // Table 7.
SubscriptionType.none_pending_in // Table 8.
), none_pending_out_in(SubscriptionType.from_pending_out, // Table 1.
SubscriptionType.none_pending_out, // Table 2.
SubscriptionType.none_pending_out_in, // Table 3.
SubscriptionType.none_pending_out, // Table 4.
SubscriptionType.to_pending_in, // Table 5.
SubscriptionType.none_pending_in, // Table 6.
SubscriptionType.none_pending_out_in, // Table 7.
SubscriptionType.none_pending_in // Table 8.
), to(SubscriptionType.to, // Table 1.
SubscriptionType.to, // Table 2.
SubscriptionType.to_pending_in, // Table 3.
SubscriptionType.to, // Table 4.
SubscriptionType.to, // Table 5.
SubscriptionType.none, // Table 6.
SubscriptionType.to, // Table 7.
SubscriptionType.none // Table 8.
), to_pending_in(SubscriptionType.both, // Table 1.
SubscriptionType.to, // Table 2.
SubscriptionType.to_pending_in, // Table 3.
SubscriptionType.to, // Table 4.
SubscriptionType.to_pending_in, // Table 5.
SubscriptionType.none_pending_in, // Table 6.
SubscriptionType.to_pending_in, // Table 7.
SubscriptionType.none_pending_in // Table 8.
), from(SubscriptionType.from, // Table 1.
SubscriptionType.none, // Table 2.
SubscriptionType.from, // Table 3.
SubscriptionType.none, // Table 4.
SubscriptionType.from, // Table 5.
SubscriptionType.from, // Table 6.
SubscriptionType.from_pending_out, // Table 7.
SubscriptionType.from // Table 8.
), from_pending_out(SubscriptionType.from_pending_out, // Table 1.
SubscriptionType.none_pending_out, // Table 2.
SubscriptionType.from_pending_out, // Table 3.
SubscriptionType.none_pending_out, // Table 4.
SubscriptionType.both, // Table 5.
SubscriptionType.from, // Table 6.
SubscriptionType.from_pending_out, // Table 7.
SubscriptionType.from // Table 8.
), both(SubscriptionType.both, // Table 1.
SubscriptionType.to, // Table 2.
SubscriptionType.both, // Table 3.
SubscriptionType.to, // Table 4.
SubscriptionType.both, // Table 5.
SubscriptionType.from, // Table 6.
SubscriptionType.both, // Table 7.
SubscriptionType.from // Table 8.
);
private EnumMap<PresenceType, SubscriptionType> stateTransition =
new EnumMap<PresenceType, SubscriptionType>(PresenceType.class);
// ~--- constructors -------------------------------------------------------
private StateTransition(SubscriptionType out_subscribed,
SubscriptionType out_unsubscribed, SubscriptionType in_subscribe,
SubscriptionType in_unsubscribe, SubscriptionType in_subscribed,
SubscriptionType in_unsubscribed, SubscriptionType out_subscribe,
SubscriptionType out_unsubscribe) {
stateTransition.put(PresenceType.out_subscribed, out_subscribed);
stateTransition.put(PresenceType.out_unsubscribed, out_unsubscribed);
stateTransition.put(PresenceType.in_subscribe, in_subscribe);
stateTransition.put(PresenceType.in_unsubscribe, in_unsubscribe);
stateTransition.put(PresenceType.in_subscribed, in_subscribed);
stateTransition.put(PresenceType.in_unsubscribed, in_unsubscribed);
stateTransition.put(PresenceType.out_subscribe, out_subscribe);
stateTransition.put(PresenceType.out_unsubscribe, out_unsubscribe);
}
// ~--- get methods --------------------------------------------------------
/**
* Method description
*
*
* @param pres_type
*
* @return
*/
public SubscriptionType getStateTransition(PresenceType pres_type) {
SubscriptionType res = stateTransition.get(pres_type);
if (log.isLoggable(Level.FINEST)) {
log.finest("this=" + this.toString() + ", pres_type=" + pres_type + ", res="
+ res);
}
return res;
}
}
/**
* Enum description
*
*/
public enum SubscriptionType {
none("none", null), none_pending_out("none", "subscribe"), none_pending_in("none",
null), none_pending_out_in("none", "subscribe"), to("to", null), to_pending_in(
"to", null), from("from", null), from_pending_out("from", "subscribe"), both(
"both", null), remove("remove", null);
private Map<String, String> attrs = new LinkedHashMap<String, String>(2, 1.0f);
// ~--- constructors -------------------------------------------------------
private SubscriptionType(String subscr, String ask) {
attrs.put("subscription", subscr);
if (ask != null) {
attrs.put("ask", ask);
} // end of if (ask != null)
}
// ~--- get methods --------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public Map<String, String> getSubscriptionAttr() {
return attrs;
}
}
// ~--- static fields --------------------------------------------------------
/**
* Private logger for class instances.
*/
private static Logger log = Logger.getLogger(RosterAbstract.class.getName());
public static final String CLIENT_XMLNS = "jabber:client";
/** Field description */
public static final String ROSTER_XMLNS = "jabber:iq:roster";
/** Field description */
public static final String ROSTER = "roster";
/** Field description */
public static final String GROUPS = "groups";
/** Field description */
public static final String GROUP = "group";
/** Field description */
public static final String NAME = "name";
/** Field description */
public static final String SUBSCRIPTION = "subscription";
/** Field description */
public static final String ROSTERHASH = "rosterhash";
/** Field description */
public static final String XMLNS = "jabber:iq:roster";
/** Field description */
public static final String XMLNS_DYNAMIC = "jabber:iq:roster-dynamic";
public static final String VER_ATT = "ver";
/** Field description */
public static final Element[] DISCO_FEATURES = {
new Element("feature", new String[] { "var" }, new String[] { XMLNS }),
new Element("feature", new String[] { "var" }, new String[] { XMLNS_DYNAMIC }) };
/** Field description */
public static final Element[] FEATURES = { new Element("ver", new String[] { "xmlns" },
new String[] { "urn:xmpp:features:rosterver" }) };
/** Field description */
public static final EnumSet<SubscriptionType> SUB_NONE = EnumSet.of(
SubscriptionType.none, SubscriptionType.none_pending_out,
SubscriptionType.none_pending_in, SubscriptionType.none_pending_out_in);
/** Field description */
public static final EnumSet<SubscriptionType> SUB_TO = EnumSet.of(SubscriptionType.to,
SubscriptionType.to_pending_in);
/** Field description */
public static final EnumSet<SubscriptionType> SUB_FROM = EnumSet.of(
SubscriptionType.from, SubscriptionType.from_pending_out);
/** Field description */
public static final EnumSet<SubscriptionType> SUB_BOTH = EnumSet
.of(SubscriptionType.both);
/** Field description */
public static final EnumSet<SubscriptionType> TO_SUBSCRIBED = EnumSet.of(
SubscriptionType.to, SubscriptionType.to_pending_in, SubscriptionType.both);
/** Field description */
public static final EnumSet<SubscriptionType> FROM_SUBSCRIBED = EnumSet.of(
SubscriptionType.from, SubscriptionType.from_pending_out, SubscriptionType.both);
/** Field description */
public static final EnumSet<StanzaType> INITIAL_PRESENCES = EnumSet.of(
StanzaType.available, StanzaType.unavailable);
/** Field description */
public static final EnumSet<SubscriptionType> PENDING_IN = EnumSet.of(
SubscriptionType.none_pending_in, SubscriptionType.none_pending_out_in,
SubscriptionType.to_pending_in);
/** Field description */
public static final EnumSet<SubscriptionType> PENDING_OUT = EnumSet.of(
SubscriptionType.none_pending_out, SubscriptionType.none_pending_out_in,
SubscriptionType.from_pending_out);
private static EnumMap<SubscriptionType, StateTransition> subsToStateMap =
new EnumMap<SubscriptionType, StateTransition>(SubscriptionType.class);
// ~--- constant enums -------------------------------------------------------
/**
* Enum description
*
*/
public enum PresenceType {
out_initial, out_subscribe, out_unsubscribe, out_subscribed, out_unsubscribed,
out_probe, in_initial, in_subscribe, in_unsubscribe, in_subscribed, in_unsubscribed,
in_probe, error;
}
// ~--- static initializers --------------------------------------------------
static {
subsToStateMap.put(SubscriptionType.none, StateTransition.none);
subsToStateMap.put(SubscriptionType.none_pending_out,
StateTransition.none_pending_out);
subsToStateMap.put(SubscriptionType.none_pending_in, StateTransition.none_pending_in);
subsToStateMap.put(SubscriptionType.none_pending_out_in,
StateTransition.none_pending_out_in);
subsToStateMap.put(SubscriptionType.to, StateTransition.to);
subsToStateMap.put(SubscriptionType.to_pending_in, StateTransition.to_pending_in);
subsToStateMap.put(SubscriptionType.from, StateTransition.from);
subsToStateMap.put(SubscriptionType.from_pending_out,
StateTransition.from_pending_out);
subsToStateMap.put(SubscriptionType.both, StateTransition.both);
}
// ~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param session
* @param jid
* @param name
* @param groups
* @param otherData
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract void addBuddy(XMPPResourceConnection session, JID jid, String name,
String[] groups, String otherData) throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param buddy
* @param groups
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract boolean addBuddyGroup(final XMPPResourceConnection session, JID buddy,
final String[] groups) throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param buddy
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract boolean containsBuddy(final XMPPResourceConnection session, JID buddy)
throws NotAuthorizedException, TigaseDBException;
// ~--- get methods ----------------------------------------------------------
// public abstract String[] getBuddies(final XMPPResourceConnection session,
// boolean onlineOnly)
// throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract JID[] getBuddies(final XMPPResourceConnection session)
throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param buddy
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract String[]
getBuddyGroups(final XMPPResourceConnection session, JID buddy)
throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param buddy
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract String getBuddyName(final XMPPResourceConnection session, JID buddy)
throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param buddy
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract SubscriptionType getBuddySubscription(
final XMPPResourceConnection session, JID buddy) throws NotAuthorizedException,
TigaseDBException;
/**
* Method description
*
*
* @param session
* @param jid
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract boolean isOnline(XMPPResourceConnection session, JID jid)
throws NotAuthorizedException, TigaseDBException;
// ~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param session
* @param jid
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract boolean presenceSent(XMPPResourceConnection session, JID jid)
throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param jid
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract boolean removeBuddy(final XMPPResourceConnection session, JID jid)
throws NotAuthorizedException, TigaseDBException;
// ~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param session
* @param buddy
* @param name
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract void setBuddyName(final XMPPResourceConnection session, JID buddy,
final String name) throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param subscription
* @param buddy
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract void setBuddySubscription(final XMPPResourceConnection session,
final SubscriptionType subscription, JID buddy) throws NotAuthorizedException,
TigaseDBException;
/**
* Method description
*
*
* @param session
* @param jid
* @param online
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract void setOnline(XMPPResourceConnection session, JID jid, boolean online)
throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param session
* @param jid
* @param sent
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public abstract void setPresenceSent(XMPPResourceConnection session, JID jid,
boolean sent) throws NotAuthorizedException, TigaseDBException;
public abstract RosterElementIfc getRosterElement(XMPPResourceConnection session,
JID jid) throws NotAuthorizedException, TigaseDBException;
// ~--- get methods ----------------------------------------------------------
// public String[] getBuddies(final XMPPResourceConnection session,
// final EnumSet<SubscriptionType> subscrs, boolean onlineOnly)
/**
* Method description
*
*
* @param session
* @param subscrs
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public JID[] getBuddies(final XMPPResourceConnection session,
final EnumSet<SubscriptionType> subscrs) throws NotAuthorizedException,
TigaseDBException {
// final String[] allBuddies = getBuddies(session, onlineOnly);
JID[] allBuddies = getBuddies(session);
if (allBuddies == null) {
return null;
} // end of if (allBuddies == null)
ArrayList<JID> list = new ArrayList<JID>();
for (JID buddy : allBuddies) {
final SubscriptionType subs = getBuddySubscription(session, buddy);
if (subscrs.contains(subs)) {
list.add(buddy);
} // end of if (subscrs.contains(subs))
} // end of for ()
return list.toArray(new JID[list.size()]);
}
/**
* Method description
*
*
* @param session
*
* @return
*/
public String getBuddiesHash(final XMPPResourceConnection session) {
String hash = (String) session.getCommonSessionData(ROSTERHASH);
return (hash != null ? hash : "");
}
/**
* Method description
*
*
* @param session
* @param buddy
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public Element getBuddyItem(final XMPPResourceConnection session, JID buddy)
throws NotAuthorizedException, TigaseDBException {
SubscriptionType subscr = getBuddySubscription(session, buddy);
if (subscr == null) {
subscr = SubscriptionType.none;
setBuddySubscription(session, subscr, buddy);
} // end of if
Element item = new Element("item");
item.setAttribute("jid", buddy.toString());
item.addAttributes(subscr.getSubscriptionAttr());
String name = getBuddyName(session, buddy);
if (name != null) {
item.setAttribute("name", XMLUtils.escape(name));
}
String[] groups = getBuddyGroups(session, buddy);
if (groups != null) {
for (String gr : groups) {
Element group = new Element("group");
group.setCData(XMLUtils.escape(gr));
item.addChild(group);
} // end of for ()
} // end of if-else
return item;
}
/**
* Method description
*
*
* @param session
* @param packet
*
* @return
*
* @throws NotAuthorizedException
*/
public PresenceType getPresenceType(final XMPPResourceConnection session,
final Packet packet) throws NotAuthorizedException {
BareJID to =
(packet.getStanzaTo() != null) ? packet.getStanzaTo().getBareJID() : null;
StanzaType type = packet.getType();
if (type == null) {
type = StanzaType.available;
} else {
if (type == StanzaType.error) {
return PresenceType.error;
}
}
if ((to == null) || !session.isUserId(to)) {
if (INITIAL_PRESENCES.contains(type)) {
return PresenceType.out_initial;
}
if (type == StanzaType.subscribe) {
return PresenceType.out_subscribe;
} // end of if (type == StanzaType.subscribe)
if (type == StanzaType.unsubscribe) {
return PresenceType.out_unsubscribe;
} // end of if (type == StanzaType.unsubscribe)
if (type == StanzaType.subscribed) {
return PresenceType.out_subscribed;
} // end of if (type == StanzaType.subscribed)
if (type == StanzaType.unsubscribed) {
return PresenceType.out_unsubscribed;
} // end of if (type == StanzaType.unsubscribed)
// StanzaType.probe is invalid here....
// if (type == StanzaType.probe) {
// return PresenceType.out_probe;
// } // if (type == StanzaType.probe)
} // end of if (to == null || to.equals(session.getUserId()))
if ((to != null) && session.isUserId(to)) {
if (INITIAL_PRESENCES.contains(type)) {
return PresenceType.in_initial;
}
if (type == StanzaType.subscribe) {
return PresenceType.in_subscribe;
} // end of if (type == StanzaType.subscribe)
if (type == StanzaType.unsubscribe) {
return PresenceType.in_unsubscribe;
} // end of if (type == StanzaType.unsubscribe)
if (type == StanzaType.subscribed) {
return PresenceType.in_subscribed;
} // end of if (type == StanzaType.subscribed)
if (type == StanzaType.unsubscribed) {
return PresenceType.in_unsubscribed;
} // end of if (type == StanzaType.unsubscribed)
if (type == StanzaType.probe) {
return PresenceType.in_probe;
} // end of if (type == StanzaType.probe)
} // end of if (to != null && !to.equals(session.getUserId()))
return null;
}
// public List<Element> getRosterItems(XMPPResourceConnection session, boolean
// online)
/**
* Method description
*
*
* @param session
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public List<Element> getRosterItems(XMPPResourceConnection session)
throws NotAuthorizedException, TigaseDBException {
LinkedList<Element> items = new LinkedList<Element>();
// String[] buddies = getBuddies(session, online);
JID[] buddies = getBuddies(session);
if (buddies != null) {
for (JID buddy : buddies) {
Element buddy_item = getBuddyItem(session, buddy);
// String item_group = buddy_item.getCData("/item/group");
items.add(buddy_item);
}
}
return items;
}
/**
* Method description
*
*
* @param subscription
* @param presence
*
* @return
*/
public SubscriptionType getStateTransition(final SubscriptionType subscription,
final PresenceType presence) {
return subsToStateMap.get(subscription).getStateTransition(presence);
}
// ~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param buddy
*
* @return
*/
public String groupNode(JID buddy) {
return ROSTER + "/" + buddy.getBareJID();
}
// public abstract void setBuddyOnline(final XMPPResourceConnection session,
// final String buddy, final boolean online)
// throws NotAuthorizedException, TigaseDBException;
//
// public abstract boolean isBuddyOnline(final XMPPResourceConnection session,
// final String buddy)
// throws NotAuthorizedException, TigaseDBException;
// public abstract void setBuddyGroups(XMPPResourceConnection session,
// String buddy, String[] groups)
// throws NotAuthorizedException, TigaseDBException;
/**
* Method description
*
*
* @param repo
*
* @throws TigaseDBException
* @throws TigaseDBException
*/
public void init(UserRepository repo) throws TigaseDBException, TigaseDBException {
}
// ~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param session
* @param jid
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public boolean isPendingIn(final XMPPResourceConnection session, JID jid)
throws NotAuthorizedException, TigaseDBException {
SubscriptionType subscr = getBuddySubscription(session, jid);
return PENDING_IN.contains(subscr);
}
/**
* Method description
*
*
* @param session
* @param jid
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public boolean isSubscribedFrom(final XMPPResourceConnection session, JID jid)
throws NotAuthorizedException, TigaseDBException {
SubscriptionType subscr = getBuddySubscription(session, jid);
return FROM_SUBSCRIBED.contains(subscr);
}
/**
* Method description
*
*
* @param subscr
*
* @return
*/
public boolean isSubscribedFrom(SubscriptionType subscr) {
return FROM_SUBSCRIBED.contains(subscr);
}
/**
* Method description
*
*
* @param session
* @param jid
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public boolean isSubscribedTo(final XMPPResourceConnection session, JID jid)
throws NotAuthorizedException, TigaseDBException {
SubscriptionType subscr = getBuddySubscription(session, jid);
return TO_SUBSCRIBED.contains(subscr);
}
// ~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param session
* @param results
* @param item
*
* @throws NotAuthorizedException
* @throws TigaseDBException
* @throws NoConnectionIdException
*/
public void updateBuddyChange(final XMPPResourceConnection session,
final Queue<Packet> results, final Element item) throws NotAuthorizedException,
TigaseDBException, NoConnectionIdException {
Element update = new Element("iq");
update.setXMLNS(CLIENT_XMLNS);
update.setAttribute("type", StanzaType.set.toString());
Element query = new Element("query");
query.setXMLNS(ROSTER_XMLNS);
query.addAttribute(VER_ATT, getBuddiesHash(session));
query.addChild(item);
update.addChild(query);
for (XMPPResourceConnection conn : session.getActiveSessions()) {
Element conn_update = update.clone();
conn_update.setAttribute("to", conn.getBareJID().toString());
conn_update.setAttribute("id", "rst" + session.nextStanzaId());
Packet pack_update = Packet.packetInstance(conn_update, null, conn.getJID());
pack_update.setPacketTo(conn.getConnectionId());
// pack_update.setPacketFrom(session.getJID());
results.offer(pack_update);
} // end of for (XMPPResourceConnection conn: sessions)
}
/**
* Method description
*
*
* @param session
* @param presence
* @param jid
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public boolean updateBuddySubscription(final XMPPResourceConnection session,
final PresenceType presence, JID jid) throws NotAuthorizedException,
TigaseDBException {
SubscriptionType current_subscription = getBuddySubscription(session, jid);
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "current_subscription={0} for jid={1}", new Object[] {
current_subscription, jid });
}
if (current_subscription == null) {
// don't create new roster item for incomming unsubscribe presence #219 /
// #210
if (presence != PresenceType.in_unsubscribe
&& presence != PresenceType.out_unsubscribe) {
addBuddy(session, jid, null, null, null);
}
current_subscription = SubscriptionType.none;
}
final SubscriptionType new_subscription =
getStateTransition(current_subscription, presence);
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "new_subscription={0} for presence={1}", new Object[] {
new_subscription, presence });
}
if ((current_subscription == SubscriptionType.none_pending_in)
&& (presence == PresenceType.out_unsubscribed)) {
removeBuddy(session, jid);
return false;
}
if (current_subscription != new_subscription) {
setBuddySubscription(session, new_subscription, jid);
return true;
} else {
return false;
}
// if ((SUB_NONE.contains(current_subscription)
// && SUB_NONE.contains(new_subscription))
// || (SUB_TO.contains(current_subscription)
// && SUB_TO.contains(new_subscription))
// || (SUB_FROM.contains(current_subscription)
// && SUB_FROM.contains(new_subscription))
// || (SUB_BOTH.contains(current_subscription)
// && SUB_BOTH.contains(new_subscription))) {
// return false;
// } else {
// setBuddySubscription(session, new_subscription, jid);
// return true;
// }
}
/**
* Method description
*
*
* @param roster_str
* @param session
*/
public void updateRosterHash(String roster_str, XMPPResourceConnection session) {
String roster_hash = null;
try {
roster_hash = Algorithms.hexDigest("", roster_str, "MD5");
} catch (Exception e) {
roster_hash = null;
}
session.putCommonSessionData(ROSTERHASH, roster_hash);
}
public abstract void logout(XMPPResourceConnection session);
/**
* @param session
* @param buddy
* @return
* @throws TigaseDBException
* @throws NotAuthorizedException
*/
public abstract String getCustomStatus(XMPPResourceConnection session, JID buddy)
throws NotAuthorizedException, TigaseDBException;
}