mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-26 16:22:06 +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 {
|
class PacketReader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace used to store packet properties.
|
||||||
|
*/
|
||||||
private static final String PROPERTIES_NAMESPACE =
|
private static final String PROPERTIES_NAMESPACE =
|
||||||
"http://www.jivesoftware.com/xmlns/xmpp/properties";
|
"http://www.jivesoftware.com/xmlns/xmpp/properties";
|
||||||
|
|
||||||
|
@ -107,8 +110,21 @@ class PacketReader {
|
||||||
listenerThread.setDaemon(true);
|
listenerThread.setDaemon(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
XmlPullParserFactory factory = XmlPullParserFactory.newInstance(
|
final String defaultProviderName = "org.xmlpull.mxp1.MXParserFactory";
|
||||||
System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
|
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);
|
factory.setNamespaceAware(true);
|
||||||
parser = factory.newPullParser();
|
parser = factory.newPullParser();
|
||||||
parser.setInput(connection.reader);
|
parser.setInput(connection.reader);
|
||||||
|
@ -323,6 +339,9 @@ class PacketReader {
|
||||||
if (namespace.equals("jabber:iq:auth")) {
|
if (namespace.equals("jabber:iq:auth")) {
|
||||||
iqPacket = parseAuthentication(parser);
|
iqPacket = parseAuthentication(parser);
|
||||||
}
|
}
|
||||||
|
else if (namespace.equals("jabber:iq:roster")) {
|
||||||
|
iqPacket = parseRoster(parser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (parser.getName().equals("error")) {
|
else if (parser.getName().equals("error")) {
|
||||||
error = parseError(parser);
|
error = parseError(parser);
|
||||||
|
@ -387,6 +406,37 @@ class PacketReader {
|
||||||
return authentication;
|
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 {
|
private static Error parseError(XmlPullParser parser) throws Exception {
|
||||||
String errorCode = null;
|
String errorCode = null;
|
||||||
for (int i=0; i<parser.getAttributeCount(); i++) {
|
for (int i=0; i<parser.getAttributeCount(); i++) {
|
||||||
|
@ -542,7 +592,6 @@ class PacketReader {
|
||||||
Map properties = new HashMap();
|
Map properties = new HashMap();
|
||||||
while (true) {
|
while (true) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
System.out.println("Start: " + parser.getName());
|
|
||||||
if (eventType == parser.START_TAG) {
|
if (eventType == parser.START_TAG) {
|
||||||
String name = parser.nextText();
|
String name = parser.nextText();
|
||||||
parser.next();
|
parser.next();
|
||||||
|
@ -615,10 +664,6 @@ class PacketReader {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processPacket(Packet packet) {
|
|
||||||
packetCollector.processPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean notifyListener() {
|
public boolean notifyListener() {
|
||||||
Packet packet = packetCollector.pollResult();
|
Packet packet = packetCollector.pollResult();
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
|
|
|
@ -52,21 +52,134 @@
|
||||||
|
|
||||||
package org.jivesoftware.smack;
|
package org.jivesoftware.smack;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.*;
|
||||||
|
import org.jivesoftware.smack.filter.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: this class is not yet implemented.
|
* Roster.
|
||||||
*
|
*
|
||||||
|
* @see XMPPConnection#getRoster()
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public class Roster {
|
public class Roster {
|
||||||
|
|
||||||
private Map presenceMap = new HashMap();
|
|
||||||
|
|
||||||
private XMPPConnection connection;
|
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 PacketWriter packetWriter;
|
||||||
private PacketReader packetReader;
|
private PacketReader packetReader;
|
||||||
|
|
||||||
|
private Roster roster;
|
||||||
|
|
||||||
Writer writer;
|
Writer writer;
|
||||||
Reader reader;
|
Reader reader;
|
||||||
|
|
||||||
|
@ -274,6 +276,14 @@ public class XMPPConnection {
|
||||||
collector.cancel();
|
collector.cancel();
|
||||||
// Set presence to online.
|
// Set presence to online.
|
||||||
packetWriter.sendPacket(new Presence(Presence.Type.AVAILABLE));
|
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 {
|
void init() throws XMPPException {
|
||||||
try {
|
try {
|
||||||
reader = new InputStreamReader(socket.getInputStream(), "UTF-8");
|
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||||
writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
|
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
throw new XMPPException("Error establishing connection with server.", ioe);
|
throw new XMPPException("Error establishing connection with server.", ioe);
|
||||||
|
@ -496,11 +506,20 @@ public class XMPPConnection {
|
||||||
int count = myReader.read(cbuf, off, len);
|
int count = myReader.read(cbuf, off, len);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
String str = new String(cbuf, off, count);
|
String str = new String(cbuf, off, count);
|
||||||
receivedText1.append(str);
|
int index = str.lastIndexOf(">");
|
||||||
receivedText2.append(str);
|
if (index != -1) {
|
||||||
if (str.endsWith(">")) {
|
receivedText1.append(str.substring(0, index+1));
|
||||||
|
receivedText2.append(str.substring(0, index+1));
|
||||||
receivedText1.append(NEWLINE);
|
receivedText1.append(NEWLINE);
|
||||||
receivedText2.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;
|
return count;
|
||||||
|
|
|
@ -52,8 +52,6 @@
|
||||||
|
|
||||||
package org.jivesoftware.smack.packet;
|
package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import org.jivesoftware.smack.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents XMPP presence packets. Every presence packet has a type, which is one of
|
* Represents XMPP presence packets. Every presence packet has a type, which is one of
|
||||||
* the following values:
|
* the following values:
|
||||||
|
@ -84,7 +82,7 @@ import org.jivesoftware.smack.*;
|
||||||
* the clients current presence status. Second, they are used to subscribe and
|
* the clients current presence status. Second, they are used to subscribe and
|
||||||
* unsubscribe users from the roster.
|
* unsubscribe users from the roster.
|
||||||
*
|
*
|
||||||
* @see Roster
|
* @see RosterPacket
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public class Presence extends Packet {
|
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