mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-12-22 18:48:00 +01:00
Initial roster support.
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@1835 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
e08d37ac2e
commit
b2127ce982
7 changed files with 687 additions and 20 deletions
|
@ -72,6 +72,9 @@ import org.jivesoftware.smack.util.StringUtils;
|
|||
*/
|
||||
class PacketReader {
|
||||
|
||||
/**
|
||||
* Namespace used to store packet properties.
|
||||
*/
|
||||
private static final String PROPERTIES_NAMESPACE =
|
||||
"http://www.jivesoftware.com/xmlns/xmpp/properties";
|
||||
|
||||
|
@ -107,8 +110,21 @@ class PacketReader {
|
|||
listenerThread.setDaemon(true);
|
||||
|
||||
try {
|
||||
XmlPullParserFactory factory = XmlPullParserFactory.newInstance(
|
||||
System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
|
||||
final String defaultProviderName = "org.xmlpull.mxp1.MXParserFactory";
|
||||
XmlPullParserFactory factory = null;
|
||||
try {
|
||||
// Attempt to load a factory implementation using a system property
|
||||
// and a classloader context.
|
||||
factory = XmlPullParserFactory.newInstance(
|
||||
System.getProperty(XmlPullParserFactory.PROPERTY_NAME),
|
||||
Thread.currentThread().getContextClassLoader().getClass());
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (factory == null) {
|
||||
// Loading failed. Therefore, use the hardcoded default.
|
||||
factory = XmlPullParserFactory.newInstance(defaultProviderName, null);
|
||||
}
|
||||
}
|
||||
factory.setNamespaceAware(true);
|
||||
parser = factory.newPullParser();
|
||||
parser.setInput(connection.reader);
|
||||
|
@ -323,6 +339,9 @@ class PacketReader {
|
|||
if (namespace.equals("jabber:iq:auth")) {
|
||||
iqPacket = parseAuthentication(parser);
|
||||
}
|
||||
else if (namespace.equals("jabber:iq:roster")) {
|
||||
iqPacket = parseRoster(parser);
|
||||
}
|
||||
}
|
||||
else if (parser.getName().equals("error")) {
|
||||
error = parseError(parser);
|
||||
|
@ -387,6 +406,37 @@ class PacketReader {
|
|||
return authentication;
|
||||
}
|
||||
|
||||
private static RosterPacket parseRoster(XmlPullParser parser) throws Exception {
|
||||
RosterPacket roster = new RosterPacket();
|
||||
boolean done = false;
|
||||
RosterPacket.Item item = null;
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == parser.START_TAG) {
|
||||
if (parser.getName().equals("item")) {
|
||||
String jid = parser.getAttributeValue("", "jid");
|
||||
String name = parser.getAttributeValue("", "name");
|
||||
String subscription = parser.getAttributeValue("", "subscription");
|
||||
item = new RosterPacket.Item(jid, name);
|
||||
item.setItemType(RosterPacket.ItemType.fromString(subscription));
|
||||
}
|
||||
if (parser.getName().equals("group")) {
|
||||
String groupName = parser.nextText();
|
||||
item.addGroupName(groupName);
|
||||
}
|
||||
}
|
||||
else if (eventType == parser.END_TAG) {
|
||||
if (parser.getName().equals("item")) {
|
||||
roster.addRosterItem(item);
|
||||
}
|
||||
if (parser.getName().equals("query")) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return roster;
|
||||
}
|
||||
|
||||
private static Error parseError(XmlPullParser parser) throws Exception {
|
||||
String errorCode = null;
|
||||
for (int i=0; i<parser.getAttributeCount(); i++) {
|
||||
|
@ -542,7 +592,6 @@ class PacketReader {
|
|||
Map properties = new HashMap();
|
||||
while (true) {
|
||||
int eventType = parser.next();
|
||||
System.out.println("Start: " + parser.getName());
|
||||
if (eventType == parser.START_TAG) {
|
||||
String name = parser.nextText();
|
||||
parser.next();
|
||||
|
@ -615,10 +664,6 @@ class PacketReader {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void processPacket(Packet packet) {
|
||||
packetCollector.processPacket(packet);
|
||||
}
|
||||
|
||||
public boolean notifyListener() {
|
||||
Packet packet = packetCollector.pollResult();
|
||||
if (packet != null) {
|
||||
|
|
|
@ -52,21 +52,134 @@
|
|||
|
||||
package org.jivesoftware.smack;
|
||||
|
||||
import org.jivesoftware.smack.packet.*;
|
||||
import org.jivesoftware.smack.filter.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* NOTE: this class is not yet implemented.
|
||||
* Roster.
|
||||
*
|
||||
* @see XMPPConnection#getRoster()
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class Roster {
|
||||
|
||||
private Map presenceMap = new HashMap();
|
||||
|
||||
private XMPPConnection connection;
|
||||
private Map groups;
|
||||
|
||||
protected Roster(XMPPConnection connection) {
|
||||
|
||||
Roster(final XMPPConnection connection) {
|
||||
this.connection = connection;
|
||||
groups = new HashMap();
|
||||
// Listen for any roster packets.
|
||||
PacketFilter filter = new PacketTypeFilter(RosterPacket.class);
|
||||
PacketListener rosterListener = new RosterListener();
|
||||
connection.addPacketListener(rosterListener, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the entire roster from the server. This is an asynchronous operation,
|
||||
* which means the method will return immediately, and the roster will be
|
||||
* reloaded at a later point when the server responds to the reload request.
|
||||
*/
|
||||
public void reload() {
|
||||
connection.sendPacket(new RosterPacket());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new group.
|
||||
*
|
||||
* @param name the name of the group.
|
||||
* @return a new group.
|
||||
*/
|
||||
public RosterGroup createGroup(String name) {
|
||||
synchronized (groups) {
|
||||
if (groups.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Group with name " + name + " alread exists.");
|
||||
}
|
||||
RosterGroup group = new RosterGroup(name, connection);
|
||||
groups.put(name, group);
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the roster group with the specified name, or <tt>null</tt> if the
|
||||
* group doesn't exist.
|
||||
*
|
||||
* @param name the name of the group.
|
||||
* @return the roster group with the specified name.
|
||||
*/
|
||||
public RosterGroup getGroup(String name) {
|
||||
synchronized (groups) {
|
||||
return (RosterGroup)groups.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator the for all the roster groups.
|
||||
*
|
||||
* @return an iterator for all roster groups.
|
||||
*/
|
||||
public Iterator getGroups() {
|
||||
synchronized (groups) {
|
||||
List groupsList = Collections.unmodifiableList(new ArrayList(groups.values()));
|
||||
return groupsList.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for all roster packets and processes them.
|
||||
*/
|
||||
private class RosterListener implements PacketListener {
|
||||
|
||||
public void processPacket(Packet packet) {
|
||||
RosterPacket rosterPacket = (RosterPacket)packet;
|
||||
for (Iterator i=rosterPacket.getRosterItems(); i.hasNext(); ) {
|
||||
RosterPacket.Item item = (RosterPacket.Item)i.next();
|
||||
RosterEntry entry = new RosterEntry(item.getUser(), item.getName(),
|
||||
connection);
|
||||
// Find the list of groups that the user currently belongs to.
|
||||
List currentGroupNames = new ArrayList();
|
||||
for (Iterator j = entry.getGroups(); j.hasNext(); ) {
|
||||
RosterGroup group = (RosterGroup)j.next();
|
||||
currentGroupNames.add(group.getName());
|
||||
}
|
||||
|
||||
List newGroupNames = new ArrayList();
|
||||
for (Iterator k = item.getGroupNames(); k.hasNext(); ) {
|
||||
String groupName = (String)k.next();
|
||||
// Add the group name to the list.
|
||||
newGroupNames.add(groupName);
|
||||
|
||||
// Add the entry to the group.
|
||||
RosterGroup group = getGroup(groupName);
|
||||
if (group == null) {
|
||||
group = createGroup(groupName);
|
||||
groups.put(groupName, group);
|
||||
}
|
||||
// Add the entry.
|
||||
group.addEntryLocal(entry);
|
||||
}
|
||||
|
||||
// We have the list of old and new group names. We now need to
|
||||
// remove the entry from the all the groups it may no longer belong
|
||||
// to. We do this by subracting the new group set from the old.
|
||||
for (int m=0; m<newGroupNames.size(); m++) {
|
||||
currentGroupNames.remove(newGroupNames.get(m));
|
||||
}
|
||||
// Loop through any groups that remain and remove the entries.
|
||||
for (int n=0; n<currentGroupNames.size(); n++) {
|
||||
String groupName = (String)currentGroupNames.get(n);
|
||||
RosterGroup group = getGroup(groupName);
|
||||
group.removeEntryLocal(entry);
|
||||
if (group.getEntryCount() == 0) {
|
||||
synchronized (groups) {
|
||||
groups.remove(groupName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
93
source/org/jivesoftware/smack/RosterEntry.java
Normal file
93
source/org/jivesoftware/smack/RosterEntry.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
package org.jivesoftware.smack;
|
||||
|
||||
import org.jivesoftware.smack.packet.RosterPacket;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Each user in your roster is represented by a roster entry, which contains the user's
|
||||
* JID and a name or nickname you assign.
|
||||
*
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class RosterEntry {
|
||||
|
||||
private String user;
|
||||
private String name;
|
||||
private XMPPConnection connection;
|
||||
|
||||
RosterEntry(String user, String name, XMPPConnection connection) {
|
||||
this.user = user;
|
||||
this.name = name;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JID of the user associated with this entry.
|
||||
*
|
||||
* @return the user associated with this entry.
|
||||
*/
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name associated with this entry.
|
||||
*
|
||||
* @return the name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
RosterPacket packet = new RosterPacket();
|
||||
packet.setType(IQ.Type.SET);
|
||||
packet.addRosterItem(toRosterItem(this));
|
||||
connection.sendPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for all the roster groups that this entry belongs to.
|
||||
*
|
||||
* @return an iterator for the groups this entry belongs to.
|
||||
*/
|
||||
public Iterator getGroups() {
|
||||
Roster roster = connection.getRoster();
|
||||
List results = new ArrayList();
|
||||
// Loop through all roster groups and find the ones that contain this
|
||||
// entry. This algorithm should be fine
|
||||
for (Iterator i=roster.getGroups(); i.hasNext(); ) {
|
||||
RosterGroup group = (RosterGroup)i.next();
|
||||
if (group.contains(this)) {
|
||||
results.add(group);
|
||||
}
|
||||
}
|
||||
return results.iterator();
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (object != null && object instanceof RosterEntry) {
|
||||
return user.equals(((RosterEntry)object).getUser());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static RosterPacket.Item toRosterItem(RosterEntry entry) {
|
||||
RosterPacket.Item item = new RosterPacket.Item(entry.getUser(), entry.getName());
|
||||
item.setItemType(RosterPacket.ItemType.BOTH);
|
||||
// Set the correct group names for the item.
|
||||
for (Iterator j=entry.getGroups(); j.hasNext(); ) {
|
||||
RosterGroup group = (RosterGroup)j.next();
|
||||
item.addGroupName(group.getName());
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
167
source/org/jivesoftware/smack/RosterGroup.java
Normal file
167
source/org/jivesoftware/smack/RosterGroup.java
Normal file
|
@ -0,0 +1,167 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright (C) 2002-2003 Jive Software. All rights reserved.
|
||||
* ====================================================================
|
||||
* The Jive Software License (based on Apache Software License, Version 1.1)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution,
|
||||
* if any, must include the following acknowledgment:
|
||||
* "This product includes software developed by
|
||||
* Jive Software (http://www.jivesoftware.com)."
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "Smack" and "Jive Software" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please
|
||||
* contact webmaster@jivesoftware.com.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Smack",
|
||||
* nor may "Smack" appear in their name, without prior written
|
||||
* permission of Jive Software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
|
||||
package org.jivesoftware.smack;
|
||||
|
||||
import org.jivesoftware.smack.packet.RosterPacket;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @see Roster#getGroup(String)
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class RosterGroup {
|
||||
|
||||
private String name;
|
||||
private XMPPConnection connection;
|
||||
List entries;
|
||||
|
||||
/**
|
||||
* Creates a new roster group instance.
|
||||
*
|
||||
* @param name the name of the group.
|
||||
* @param connection the connection the group belongs to.
|
||||
*/
|
||||
RosterGroup(String name, XMPPConnection connection) {
|
||||
this.name = name;
|
||||
this.connection = connection;
|
||||
entries = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the group.
|
||||
*
|
||||
* @return the name of the group.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the group.
|
||||
*
|
||||
* @param name the name of the group.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
synchronized (entries) {
|
||||
for (int i=0; i<entries.size(); i++) {
|
||||
RosterPacket packet = new RosterPacket();
|
||||
packet.setType(IQ.Type.SET);
|
||||
RosterEntry entry = (RosterEntry)entries.get(i);
|
||||
packet.addRosterItem(RosterEntry.toRosterItem(entry));
|
||||
connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getEntryCount() {
|
||||
synchronized (entries) {
|
||||
return entries.size();
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator getEntries() {
|
||||
return Collections.unmodifiableList(entries).iterator();
|
||||
}
|
||||
|
||||
public boolean contains(RosterEntry entry) {
|
||||
return entries.contains(entry);
|
||||
}
|
||||
|
||||
public void addEntry(RosterEntry entry) {
|
||||
// Only add the entry if it isn't already in the list.
|
||||
synchronized (entries) {
|
||||
if (!entries.contains(entry)) {
|
||||
entries.add(entry);
|
||||
RosterPacket packet = new RosterPacket();
|
||||
packet.setType(IQ.Type.SET);
|
||||
packet.addRosterItem(RosterEntry.toRosterItem(entry));
|
||||
connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEntry(RosterEntry entry) {
|
||||
// Only remove the entry if it's in the entry list.
|
||||
synchronized (entries) {
|
||||
if (entries.contains(entry)) {
|
||||
entries.remove(entry);
|
||||
RosterPacket packet = new RosterPacket();
|
||||
packet.setType(IQ.Type.SET);
|
||||
packet.addRosterItem(RosterEntry.toRosterItem(entry));
|
||||
connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addEntryLocal(RosterEntry entry) {
|
||||
// Only add the entry if it isn't already in the list.
|
||||
synchronized (entries) {
|
||||
entries.remove(entry);
|
||||
entries.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void removeEntryLocal(RosterEntry entry) {
|
||||
// Only remove the entry if it's in the entry list.
|
||||
synchronized (entries) {
|
||||
if (entries.contains(entry)) {
|
||||
entries.remove(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,6 +109,8 @@ public class XMPPConnection {
|
|||
private PacketWriter packetWriter;
|
||||
private PacketReader packetReader;
|
||||
|
||||
private Roster roster;
|
||||
|
||||
Writer writer;
|
||||
Reader reader;
|
||||
|
||||
|
@ -274,6 +276,14 @@ public class XMPPConnection {
|
|||
collector.cancel();
|
||||
// Set presence to online.
|
||||
packetWriter.sendPacket(new Presence(Presence.Type.AVAILABLE));
|
||||
|
||||
// Finally, create the roster.
|
||||
this.roster = new Roster(this);
|
||||
roster.reload();
|
||||
}
|
||||
|
||||
public Roster getRoster() {
|
||||
return roster;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -389,8 +399,8 @@ public class XMPPConnection {
|
|||
*/
|
||||
void init() throws XMPPException {
|
||||
try {
|
||||
reader = new InputStreamReader(socket.getInputStream(), "UTF-8");
|
||||
writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
|
||||
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new XMPPException("Error establishing connection with server.", ioe);
|
||||
|
@ -496,11 +506,20 @@ public class XMPPConnection {
|
|||
int count = myReader.read(cbuf, off, len);
|
||||
if (count > 0) {
|
||||
String str = new String(cbuf, off, count);
|
||||
receivedText1.append(str);
|
||||
receivedText2.append(str);
|
||||
if (str.endsWith(">")) {
|
||||
int index = str.lastIndexOf(">");
|
||||
if (index != -1) {
|
||||
receivedText1.append(str.substring(0, index+1));
|
||||
receivedText2.append(str.substring(0, index+1));
|
||||
receivedText1.append(NEWLINE);
|
||||
receivedText2.append(NEWLINE);
|
||||
if (str.length() > index) {
|
||||
receivedText1.append(str.substring(index+1));
|
||||
receivedText2.append(str.substring(index+1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
receivedText1.append(str);
|
||||
receivedText2.append(str);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
|
|
@ -52,8 +52,6 @@
|
|||
|
||||
package org.jivesoftware.smack.packet;
|
||||
|
||||
import org.jivesoftware.smack.*;
|
||||
|
||||
/**
|
||||
* Represents XMPP presence packets. Every presence packet has a type, which is one of
|
||||
* the following values:
|
||||
|
@ -84,7 +82,7 @@ import org.jivesoftware.smack.*;
|
|||
* the clients current presence status. Second, they are used to subscribe and
|
||||
* unsubscribe users from the roster.
|
||||
*
|
||||
* @see Roster
|
||||
* @see RosterPacket
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class Presence extends Packet {
|
||||
|
|
232
source/org/jivesoftware/smack/packet/RosterPacket.java
Normal file
232
source/org/jivesoftware/smack/packet/RosterPacket.java
Normal file
|
@ -0,0 +1,232 @@
|
|||
/**
|
||||
* $RCSfile$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright (C) 2002-2003 Jive Software. All rights reserved.
|
||||
* ====================================================================
|
||||
* The Jive Software License (based on Apache Software License, Version 1.1)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution,
|
||||
* if any, must include the following acknowledgment:
|
||||
* "This product includes software developed by
|
||||
* Jive Software (http://www.jivesoftware.com)."
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "Smack" and "Jive Software" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please
|
||||
* contact webmaster@jivesoftware.com.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Smack",
|
||||
* nor may "Smack" appear in their name, without prior written
|
||||
* permission of Jive Software.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack.packet;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents XMPP roster packets.
|
||||
*
|
||||
* @author Matt Tucker
|
||||
*/
|
||||
public class RosterPacket extends IQ {
|
||||
|
||||
private List rosterItems = new ArrayList();
|
||||
|
||||
public void addRosterItem(Item entry) {
|
||||
synchronized (rosterItems) {
|
||||
rosterItems.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator getRosterItems() {
|
||||
synchronized (rosterItems) {
|
||||
List entries = Collections.unmodifiableList(new ArrayList(rosterItems));
|
||||
return entries.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
public String getQueryXML() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<query xmlns=\"jabber:iq:roster\">");
|
||||
synchronized (rosterItems) {
|
||||
for (int i=0; i<rosterItems.size(); i++) {
|
||||
Item entry = (Item)rosterItems.get(i);
|
||||
buf.append(entry.toXML());
|
||||
}
|
||||
}
|
||||
buf.append("</query>");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static class Item {
|
||||
|
||||
private String user;
|
||||
private String name;
|
||||
private ItemType itemType;
|
||||
private List groupNames;
|
||||
|
||||
public Item(String user, String name) {
|
||||
this.user = user;
|
||||
this.name = name;
|
||||
itemType = null;
|
||||
groupNames = new ArrayList();
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return itemType;
|
||||
}
|
||||
|
||||
public void setItemType(ItemType itemType) {
|
||||
this.itemType = itemType;
|
||||
}
|
||||
|
||||
public Iterator getGroupNames() {
|
||||
synchronized (groupNames) {
|
||||
return Collections.unmodifiableList(groupNames).iterator();
|
||||
}
|
||||
}
|
||||
|
||||
public void addGroupName(String groupName) {
|
||||
synchronized (groupNames) {
|
||||
if (!groupNames.contains(groupName)) {
|
||||
groupNames.add(groupName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeGroupName(String groupName) {
|
||||
synchronized (groupNames) {
|
||||
groupNames.remove(groupName);
|
||||
}
|
||||
}
|
||||
|
||||
public String toXML() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<item jid=\"").append(user).append("\"");
|
||||
if (name != null) {
|
||||
buf.append(" name=\"").append(name).append("\"");
|
||||
}
|
||||
if (itemType != null) {
|
||||
buf.append(" subscription=\"").append(itemType).append("\"");
|
||||
}
|
||||
buf.append(">");
|
||||
synchronized (groupNames) {
|
||||
for (int i=0; i<groupNames.size(); i++) {
|
||||
String groupName = (String)groupNames.get(i);
|
||||
buf.append("<group>").append(groupName).append("</group>");
|
||||
}
|
||||
}
|
||||
buf.append("</item>");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ItemStatus {
|
||||
|
||||
public static final ItemStatus SUBSCRIBED = new ItemStatus("subscribed");
|
||||
public static final ItemStatus SUBSCRIPTION_PENDING = new ItemStatus("subscribe");
|
||||
public static final ItemStatus UNSUBCRIPTION_PENDING = new ItemStatus("unsubscribe");
|
||||
|
||||
public static ItemStatus fromString(String value) {
|
||||
if ("subscribed".equals(value)) {
|
||||
return SUBSCRIBED;
|
||||
}
|
||||
else if ("subscribe".equals(value)) {
|
||||
return SUBSCRIPTION_PENDING;
|
||||
}
|
||||
else {
|
||||
return SUBSCRIBED;
|
||||
}
|
||||
}
|
||||
|
||||
private String value;
|
||||
|
||||
private ItemStatus (String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ItemType {
|
||||
|
||||
public static final ItemType NONE = new ItemType("none");
|
||||
public static final ItemType TO = new ItemType("to");
|
||||
public static final ItemType FROM = new ItemType("from");
|
||||
public static final ItemType BOTH = new ItemType("both");
|
||||
|
||||
public static ItemType fromString(String value) {
|
||||
if ("none".equals(value)) {
|
||||
return NONE;
|
||||
}
|
||||
else if ("to".equals(value)) {
|
||||
return TO;
|
||||
}
|
||||
else if ("from".equals(value)) {
|
||||
return FROM;
|
||||
}
|
||||
else if ("both".equals(value)) {
|
||||
return BOTH;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String value;
|
||||
|
||||
public ItemType (String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue