Commit 4e8859c4 authored by Matt Tucker's avatar Matt Tucker Committed by matt

Partial refactoring of moving to Whack packets. CVS will be broken until refactoring is complete.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@569 b35dd754-fafc-0310-a699-88a17e54d16e
parent 80ea3382
...@@ -233,6 +233,8 @@ ...@@ -233,6 +233,8 @@
<root url="jar://$PROJECT_DIR$/build/lib/merge/standard.jar!/" /> <root url="jar://$PROJECT_DIR$/build/lib/merge/standard.jar!/" />
<root url="jar://$PROJECT_DIR$/build/lib/merge/jstl.jar!/" /> <root url="jar://$PROJECT_DIR$/build/lib/merge/jstl.jar!/" />
<root url="jar://$PROJECT_DIR$/build/lib/whack.jar!/" /> <root url="jar://$PROJECT_DIR$/build/lib/whack.jar!/" />
<root url="jar://$PROJECT_DIR$/build/lib/merge/whack.jar!/" />
<root url="jar://$PROJECT_DIR$/build/lib/merge/jdic.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
......
...@@ -14,6 +14,7 @@ package org.jivesoftware.messenger; ...@@ -14,6 +14,7 @@ package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.xmpp.packet.Packet;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
...@@ -38,7 +39,7 @@ import java.util.concurrent.LinkedBlockingQueue; ...@@ -38,7 +39,7 @@ import java.util.concurrent.LinkedBlockingQueue;
* *
* @author Matt Tucker * @author Matt Tucker
*/ */
public class Channel<T extends XMPPPacket> { public class Channel<T extends Packet> {
private String name; private String name;
private ChannelHandler channelHandler; private ChannelHandler channelHandler;
...@@ -83,6 +84,7 @@ public class Channel<T extends XMPPPacket> { ...@@ -83,6 +84,7 @@ public class Channel<T extends XMPPPacket> {
catch (Exception e) { catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e); Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
try { try {
packet.getOriginatingSession().getConnection().close(); packet.getOriginatingSession().getConnection().close();
} }
catch (UnauthorizedException e1) { catch (UnauthorizedException e1) {
......
...@@ -12,13 +12,14 @@ ...@@ -12,13 +12,14 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
/** /**
* Interface to handle packets delivered by Channels. * Interface to handle packets delivered by Channels.
* *
* @author Matt Tucker * @author Matt Tucker
*/ */
public interface ChannelHandler<T extends XMPPPacket> { public interface ChannelHandler<T extends Packet> {
/** /**
* Process an XMPP packet. * Process an XMPP packet.
......
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.xmpp.packet.Packet;
public interface Component { public interface Component {
void processPacket(XMPPPacket packet); void processPacket(Packet packet);
} }
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import java.io.StringReader;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.ServiceLookupFactory; import org.jivesoftware.messenger.container.ServiceLookupFactory;
import org.jivesoftware.messenger.spi.PacketFactoryImpl;
import org.jivesoftware.messenger.spi.PacketRouterImpl; import org.jivesoftware.messenger.spi.PacketRouterImpl;
import org.jivesoftware.messenger.spi.PresenceImpl;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
/** /**
* <p>Manages the registration and delegation of Components.</p> * <p>Manages the registration and delegation of Components.</p>
...@@ -29,7 +23,7 @@ import org.xmpp.packet.Packet; ...@@ -29,7 +23,7 @@ import org.xmpp.packet.Packet;
public class ComponentManager { public class ComponentManager {
private Map<String, Component> components = new ConcurrentHashMap<String, Component>(); private Map<String, Component> components = new ConcurrentHashMap<String, Component>();
private Map<XMPPAddress, XMPPAddress> presenceMap = new ConcurrentHashMap<XMPPAddress, XMPPAddress>(); private Map<JID, JID> presenceMap = new ConcurrentHashMap<JID, JID>();
static private ComponentManager singleton; static private ComponentManager singleton;
private final static Object LOCK = new Object(); private final static Object LOCK = new Object();
...@@ -110,7 +104,7 @@ public class ComponentManager { ...@@ -110,7 +104,7 @@ public class ComponentManager {
* @param prober the jid probing. * @param prober the jid probing.
* @param probee the presence being probed. * @param probee the presence being probed.
*/ */
public void addPresenceRequest(XMPPAddress prober, XMPPAddress probee) { public void addPresenceRequest(JID prober, JID probee) {
presenceMap.put(prober, probee); presenceMap.put(prober, probee);
} }
...@@ -120,7 +114,7 @@ public class ComponentManager { ...@@ -120,7 +114,7 @@ public class ComponentManager {
* *
* @param packet the packet to send. * @param packet the packet to send.
*/ */
public void sendPacket(XMPPPacket packet) { public void sendPacket(Packet packet) {
PacketRouter router; PacketRouter router;
try { try {
router = (PacketRouterImpl)ServiceLookupFactory.getLookup().lookup(PacketRouterImpl.class); router = (PacketRouterImpl)ServiceLookupFactory.getLookup().lookup(PacketRouterImpl.class);
...@@ -133,44 +127,20 @@ public class ComponentManager { ...@@ -133,44 +127,20 @@ public class ComponentManager {
} }
} }
/**
* Send a packet to the specified recipient. Please note that this sends packets only
* to outgoing jids and does to the incoming server reader.
*
* @param packet the packet to send.
*/
public void sendPacket(Packet packet) {
PacketRouter router;
try {
router = (PacketRouterImpl)ServiceLookupFactory.getLookup().lookup(PacketRouterImpl.class);
if (router != null) {
String packetString = packet.toXML();
System.out.println(packetString + "\n");
XMPPPacket p = readStream(packetString);
router.route(p);
}
}
catch (Exception e) {
Log.error(e);
}
}
private String validateJID(String jid) { private String validateJID(String jid) {
jid = jid.trim().toLowerCase(); jid = jid.trim().toLowerCase();
return jid; return jid;
} }
private void checkPresences() { private void checkPresences() {
for (XMPPAddress prober : presenceMap.keySet()) { for (JID prober : presenceMap.keySet()) {
XMPPAddress probee = presenceMap.get(prober); JID probee = presenceMap.get(prober);
Component component = getComponent(probee.toBareStringPrep()); Component component = getComponent(probee.toBareJID());
if (component != null) { if (component != null) {
Presence presence = new PresenceImpl(); Presence presence = new Presence();
presence.setSender(prober); presence.setFrom(prober);
presence.setRecipient(probee); presence.setTo(probee);
component.processPacket(presence); component.processPacket(presence);
// No reason to hold onto prober reference. // No reason to hold onto prober reference.
...@@ -178,53 +148,4 @@ public class ComponentManager { ...@@ -178,53 +148,4 @@ public class ComponentManager {
} }
} }
} }
/**
* Read the incoming stream until it ends. Much of the reading
* will actually be done in the channel handlers as they run the
* XPP through the data. This method mostly handles the idle waiting
* for incoming data. To prevent clients from stalling channel handlers,
* a watch dog timer is used. Packets that take longer than the watch
* dog limit to read will cause the session to be closed.
*
* @throws javax.xml.stream.XMLStreamException
* if there is trouble reading from the socket
*/
private XMPPPacket readStream(String string) throws UnauthorizedException, XMLStreamException {
PacketFactoryImpl packetFactory = new PacketFactoryImpl();
XMLInputFactory x = packetFactory.getXMLFactory();
XMLStreamReader xpp = x.createXMLStreamReader(new StringReader(string));
XMPPPacket packet = null;
while (true) {
for (int eventType = xpp.next();
eventType != XMLStreamConstants.START_ELEMENT;
eventType = xpp.next()) {
if (eventType == XMLStreamConstants.CHARACTERS) {
if (!xpp.isWhiteSpace()) {
throw new XMLStreamException(LocaleUtils.getLocalizedString("admin.error.packet.text"));
}
}
else if (eventType == XMLStreamConstants.END_DOCUMENT) {
return null;
}
}
String tag = xpp.getLocalName();
if ("message".equals(tag)) {
packet = packetFactory.getMessage(xpp);
}
else if ("presence".equals(tag)) {
packet = packetFactory.getPresence(xpp);
}
else if ("iq".equals(tag)) {
packet = packetFactory.getIQ(xpp);
}
else {
throw new XMLStreamException(LocaleUtils.getLocalizedString("admin.error.packet.tag") + tag);
}
return packet;
}
}
} }
\ No newline at end of file
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
...@@ -128,5 +130,5 @@ public interface Connection { ...@@ -128,5 +130,5 @@ public interface Connection {
* @throws UnauthorizedException If caller doesn't have permission to access this resource * @throws UnauthorizedException If caller doesn't have permission to access this resource
* @throws XMLStreamException if there was a problem sending the packet * @throws XMLStreamException if there was a problem sending the packet
*/ */
void deliver(XMPPPacket packet) throws UnauthorizedException, XMLStreamException; void deliver(Packet packet) throws UnauthorizedException, XMLStreamException;
} }
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.dom4j.Element;
/**
* <p>Provides a common implementation of IQ packet creation, read, and update.</p>
* <p>Info-Query (iq) is used for practically all client-server interactions and drives
* all standard extension protocols. IQ itself is a generic envelope and protocol
* used to transport specific protocol XML fragments.</p>
* <h3>Warning</h3>
* <p>Because IQ relies on the sub-element for information regarding what IQ protocol
* is being handled, IQ packets start parsing with the parser pointed to either the end
* tag of the iq, or the start tag event of it's child element which ever is encountered
* first. This allows parser handlers to advance the xpp to the sub-element to know it's
* name and namespace but still defer to the packet for parsing.</p>
*
* @author Iain Shigeoka
*/
public interface IQ extends XMPPPacket {
Type GET = new Type("get");
Type SET = new Type("set");
Type RESULT = new Type("result");
/**
* <p>Obtain the namespace of the child element.</p>
* <p/>
* <p>IQ packets may only contain one child sub-element (other than the error sub-element).</p>
*
* @return The namespace of the child element
*/
String getChildNamespace();
/**
* <p>Set the namespace of the child element.</p>
* <p/>
* <p>IQ packets may only contain one child sub-element (other than the error sub-element).</p>
*
* @param namespace The namespace of the child element
*/
void setChildNamespace(String namespace);
/**
* <p>Obtain the name of the child element.</p>
* <p/>
* <p>IQ packets may only contain one child sub-element (other than the error sub-element).</p>
*
* @return The name of the child element
*/
String getChildName();
/**
* <p>Set the name of the child element.</p>
* <p/>
* <p>IQ packets may only contain one child sub-element (other than the error sub-element).</p>
*
* @param name The name of the child element
*/
void setChildName(String name);
/**
* <p>Returns the IQ packet's only child fragment (excluding the optional error
* sub packet).</p>
* <p>The XMPP spec limits IQ packets to having only one child fragment so this
* is a convenience method to return that fragment rather than having to grab it
* from the general fragments list.</p>
*
* @return The child fragment for this IQ or null if there is none.
*/
XMPPFragment getChildFragment();
/**
* <p>Set the child element for the IQ packet.</p>
* <p/>
* <p>IQ packets may only contain one child sub-element (other than the error sub-element).</p>
*
* @param fragment The fragment to be used as the iq child element
*/
void setChildFragment(XMPPFragment fragment);
/**
* <p>Obtain an IQ result packet for the current IQ using the given body.</p>
*
* @param body The new child element to use
* @return The created result
*/
IQ createResult(Element body);
/**
* <p>Obtain the IQ result packet for the current IQ.</p>
* <p/>
* <p>IQ packets may only contain one child sub-element (other than the error sub-element).</p>
*
* @return The namespace of the child element
*/
IQ createResult();
}
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.xmpp.packet.IQ;
/** /**
* <p>Route iq packets throughout the server.</p> * <p>Route iq packets throughout the server.</p>
* <p>Routing is based on the recipient and sender addresses. The typical * <p>Routing is based on the recipient and sender addresses. The typical
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
/**
* <p>Allows the simple creation, reading, and updating of message packets.<p>
* <p>The methods used are mainly convenience interfaces to the various parts
* of a typical message packet.</p>
*
* @author Iain Shigeoka
*/
public interface Message extends XMPPPacket {
/**
* Normal message displayed in an email like interface.
*/
Type NORMAL = new Type("normal");
/**
* Chat message displayed in a line-by-line chat interface.
*/
Type CHAT = new Type("chat");
/**
* Groupchat message displayed in chatroom line-by-line interface.
*/
Type GROUP_CHAT = new Type("groupchat");
/**
* Headline message displayed either as an alert, scrolling stock ticker, etc interface.
*/
Type HEADLINE = new Type("headline");
String getBody();
void setBody(String body);
String getSubject();
void setSubject(String subject);
String getThread();
void setThread(String thread);
}
\ No newline at end of file
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.xmpp.packet.Message;
/** /**
* <p>Route message packets throughout the server.</p> * <p>Route message packets throughout the server.</p>
* <p>Routing is based on the recipient and sender addresses. The typical * <p>Routing is based on the recipient and sender addresses. The typical
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.util.XPPWriter;
import java.util.*;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.*;
/**
* <p>Storage of generic meta-data.</p>
* <p>Meta-data is expected to be stored as XML. We use a simple
* naming convention of meta-data key names: data is stored
* heirarchically separated by dots. The last name may contain
* a colon ':' character that is read as name:attribute.
* For example setting X.Y.Z to someValue, would map to an XML snippet of:</p>
* <pre>
* &lt;X&gt;
* &lt;Y&gt;
* &lt;Z&gt;someValue&lt;/Z&gt;
* &lt;/Y&gt;
* &lt;/X&gt;
* </pre>
* And X.Y.Z:key to anotherValue as:</p>
* <pre>
* &lt;X&gt;
* &lt;Y&gt;
* &lt;Z key="anotherValue" /&gt;
* &lt;/Y&gt;
* &lt;/X&gt;
* </pre>
* <p>Some XML cannot be built or accessed using this naming
* convention (e.g. a typical Roster reset packet). More complex XML
* packet should be represented using the XMPPDOMFragment. The
* MetaDataFragment class is designed to provide 80% of XML
* manipulation capabilities with the simplest 20% of code and API size
* making it convenient for meta-data, simple IQ packets, etc.</p>
*
* @author Iain Shigeoka
* @see XMPPDOMFragment
*/
public class MetaDataFragment extends PayloadFragment {
Element root = DocumentHelper.createElement("root");
/**
* Parsing the XML DOM every time we need a property is slow. Therefore,
* we use a Map to cache property values that are accessed more than once.
*/
private Map propertyCache = new HashMap();
public void setName(String name) {
this.name = name;
((Element)root.elements().get(0)).setName(name);
}
public void setNamespace(String namespace) {
this.namespace = namespace;
QName qName = DocumentHelper.createQName(name, DocumentHelper.createNamespace("", namespace));
((Element)root.elements().get(0)).setQName(qName);
}
public void send(XMLStreamWriter xmlSerializer, int version) throws XMLStreamException {
Iterator fragIter = null;
if (fragments != null && !fragments.isEmpty()) {
fragIter = getFragments();
}
XPPWriter.write((Element)root.elements().get(0), xmlSerializer, fragIter, version);
}
public XMPPFragment createDeepCopy() {
MetaDataFragment meta = null;
Iterator metaElements = root.elementIterator();
if (metaElements.hasNext()) {
meta = new MetaDataFragment((Element)metaElements.next());
while (metaElements.hasNext()) {
meta.root.add((Element)metaElements.next());
}
}
else {
meta = new MetaDataFragment(namespace, name);
}
Iterator fragmentIter = getFragments();
while (fragmentIter.hasNext()) {
meta.addFragment(((XMPPFragment)fragmentIter.next()).createDeepCopy());
}
return meta;
}
/**
* Create an empty meta-data chunk.
*/
public MetaDataFragment(String namespace, String name) {
super(namespace, name);
QName qName = DocumentHelper.createQName(name, DocumentHelper.createNamespace("", namespace));
root.add(DocumentHelper.createElement(qName));
}
/**
* Create a meta-data chunk based on a DOM tree.
*/
public MetaDataFragment(Element root) {
super(root.getNamespaceURI(), root.getName());
this.root.add((Element)root.clone());
}
/**
* Returns the value of the specified property. A <tt>null</tt> answer does not necessarily mean
* that the property does not exist. Use {@link #includesProperty(String)} to find out whether
* the property exists or not.
*
* @param name the name of the property to get.
* @return the value of the specified property.
*/
public synchronized String getProperty(String name) {
String value = (String)propertyCache.get(name);
if (value == null) {
String[] propName = parsePropertyName(name);
// Grab the attribute if there is one
String lastName = propName[propName.length - 1];
String attName = null;
int attributeIndex = lastName.indexOf(':');
if (attributeIndex >= 0) {
propName[propName.length - 1] = lastName.substring(0, attributeIndex);
attName = lastName.substring(attributeIndex + 1);
}
// Search for this property by traversing down the XML hierarchy.
Element element = root;
for (int i = 0; i < propName.length; i++) {
element = element.element(propName[i]);
if (element == null) {
break;
}
}
if (element != null) {
if (attName == null) {
value = element.getTextTrim();
}
else {
value = element.attributeValue(attName);
}
// At this point, we found a matching property, so return its value.
// Empty strings are returned as null.
if ("".equals(value)) {
value = null;
}
else {
// Add to cache so that getting property next time is fast.
propertyCache.put(name, value);
}
}
}
return value;
}
/**
* Returns true if the specified property is included in the XML hierarchy. A property could
* have a value associated or not. If the property has an associated value then
* {@link #getProperty(String)} will return a String otherwise <tt>null</tt> will be answered.
*
* @param name the name of the property to find out.
* @return true if the specified property is included in the XML hierarchy.
*/
public synchronized boolean includesProperty(String name) {
String value = (String)propertyCache.get(name);
if (value == null) {
String[] propName = parsePropertyName(name);
// Grab the attribute if there is one
String lastName = propName[propName.length - 1];
String attName = null;
int attributeIndex = lastName.indexOf(':');
if (attributeIndex >= 0) {
propName[propName.length - 1] = lastName.substring(0, attributeIndex);
attName = lastName.substring(attributeIndex + 1);
}
// Search for this property by traversing down the XML hierarchy.
Element element = root;
for (int i = 0; i < propName.length; i++) {
element = element.element(propName[i]);
if (element == null) {
break;
}
}
if (element != null) {
if (attName == null){
// The property exists so return true
return true;
} else {
// The property exists if the attribute exists in the element
return element.attribute(attName) != null;
}
}
else {
// The property does not exist so return false
return false;
}
}
return true;
}
/**
* Return all values who's path matches the given property name as a String array,
* or an empty array if the if there are no children. You MAY NOT use the atttribute
* markup (using a ':' in the last element name) with this call.
* <p/>
* getProperties() allows you to retrieve several values with the same property name.
* For example, consider the XML file entry:
* <pre>
* &lt;foo&gt;
* &lt;bar&gt;
* &lt;prop&gt;some value&lt;/prop&gt;
* &lt;prop&gt;other value&lt;/prop&gt;
* &lt;prop&gt;last value&lt;/prop&gt;
* &lt;/bar&gt;
* &lt;/foo&gt;
* </pre>
* If you call getProperties("foo.bar.prop") will return a string array containing
* {"some value", "other value", "last value"}.
*
* @param name the name of the property to retrieve
* @return all child property values for the given node name.
*/
public String[] getProperties(String name) {
String[] propName = parsePropertyName(name);
// Search for this property by traversing down the XML heirarchy, stopping one short.
Element element = root;
for (int i = 0; i < propName.length - 1; i++) {
element = element.element(propName[i]);
if (element == null) {
// This node doesn't match this part of the property name which
// indicates this property doesn't exist so return empty array.
return new String[]{};
}
}
// We found matching property, return names of children.
Iterator iter = element.elementIterator(propName[propName.length - 1]);
ArrayList props = new ArrayList();
while (iter.hasNext()) {
Element e = (Element)iter.next();
props.add(e.getName());
}
String[] childrenNames = new String[props.size()];
return (String[])props.toArray(childrenNames);
}
/**
* Sets a property to an array of values. You MAY NOT use the atttribute
* markup (using a ':' in the last element name) with this call. Multiple values matching the
* same property is mapped to an XML file as multiple elements containing each value.
* For example, using the name "foo.bar.prop", and the value string array containing
* {"some value", "other value", "last value"} would produce the following XML:
* <pre>
* &lt;foo&gt;
* &lt;bar&gt;
* &lt;prop&gt;some value&lt;/prop&gt;
* &lt;prop&gt;other value&lt;/prop&gt;
* &lt;prop&gt;last value&lt;/prop&gt;
* &lt;/bar&gt;
* &lt;/foo&gt;
* </pre>
*
* @param name the name of the property.
* @param values The array of values for the property (can be empty but not null)
*/
public void setProperties(String name, String[] values) {
String[] propName = parsePropertyName(name);
setProperty(name, values[0]);
// Search for this property by traversing down the XML heirarchy, stopping one short.
Element element = root;
for (int i = 0; i < propName.length - 1; i++) {
element = element.element(propName[i]);
if (element == null) {
// This node doesn't match this part of the property name which
// indicates this property doesn't exist so return empty array.
return;
}
}
String childName = propName[propName.length - 1];
// We found matching property, clear all children.
List toRemove = new ArrayList();
Iterator iter = element.elementIterator(childName);
while (iter.hasNext()) {
toRemove.add(iter.next());
}
for (iter = toRemove.iterator(); iter.hasNext();) {
element.remove((Element)iter.next());
}
// Add the new children
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
element.addElement(childName).setText(values[i]);
}
}
}
/**
* Return all children property names of a parent property as a String array,
* or an empty array if the if there are no children. You MAY NOT use the atttribute
* markup (using a ':' in the last element name) with this call.
* For example, given the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and <tt>X.Y.C</tt>, then
* the child properties of <tt>X.Y</tt> are <tt>A</tt>, <tt>B</tt>, and
* <tt>C</tt>.
*
* @param parent the name of the parent property.
* @return all child property values for the given parent.
*/
public String[] getChildrenProperties(String parent) {
String[] propName = parsePropertyName(parent);
// Search for this property by traversing down the XML heirarchy.
Element element = root;
for (int i = 0; i < propName.length; i++) {
element = element.element(propName[i]);
if (element == null) {
// This node doesn't match this part of the property name which
// indicates this property doesn't exist so return empty array.
return new String[]{};
}
}
// We found matching property, return names of children.
List children = element.elements();
int childCount = children.size();
String[] childrenNames = new String[childCount];
for (int i = 0; i < childCount; i++) {
childrenNames[i] = ((Element)children.get(i)).getName();
}
return childrenNames;
}
/**
* Returns all recursive children of the given parent property or an empty string array
* if no children exist. The list of children is depth-first so the array is optimized
* for easy displaying.
*
* @param parent the parent property.
* @return all recursive children of the given property in depth-first order or an empty
* string array if no children exist.
*/
public String[] getRecursiveChildrenProperties(String parent) {
String[] properties = getChildrenProperties(parent);
if (properties.length == 0) {
return properties;
}
else {
List list = new ArrayList(15);
for (int i = 0; i < properties.length; i++) {
String propName = parent + "." + properties[i];
list.add(propName);
list.addAll(Arrays.asList(getRecursiveChildrenProperties(propName)));
}
return (String[])list.toArray(new String[]{});
}
}
/**
* Sets the value of the specified property. If the property doesn't
* currently exist, it will be automatically created.
*
* @param name the name of the property to set.
* @param value the new value for the property.
*/
public synchronized void setProperty(String name, String value) {
if (name == null) return;
if (value == null) value = "";
// Set cache correctly with prop name and value.
propertyCache.put(name, value);
String[] propName = parsePropertyName(name);
// Search for this property by traversing down the XML heirarchy.
Element element = root;
for (int i = 0; i < propName.length - 1; i++) {
// If we don't find this part of the property in the XML heirarchy
// we add it as a new node
if (element.element(propName[i]) == null) {
element.addElement(propName[i]);
}
element = element.element(propName[i]);
}
String lastName = propName[propName.length - 1];
int attributeIndex = lastName.indexOf(':');
if (attributeIndex >= 0) {
String eleName = lastName.substring(0, attributeIndex);
String attName = lastName.substring(attributeIndex + 1);
// If we don't find this part of the property in the XML heirarchy
// we add it as a new node
if (element.element(eleName) == null) {
element.addElement(eleName);
}
element.element(eleName).addAttribute(attName, value);
}
else {
// If we don't find this part of the property in the XML heirarchy
// we add it as a new node
if (element.element(lastName) == null) {
element.addElement(lastName);
}
// Set the value of the property in this node.
element.element(lastName).setText(value);
}
}
/**
* Deletes the specified property. You may use the atttribute markup (using a ':' in the last
* element name) with this call. This method removes both the containing text, and the
* element itself along with any attributes associated with that element.</p>
*
* @param name the property to delete.
*/
public synchronized void deleteProperty(String name) {
// Remove property from cache.
propertyCache.remove(name);
String[] propName = parsePropertyName(name);
// Search for this property by traversing down the XML heirarchy.
Element element = root;
for (int i = 0; i < propName.length - 1; i++) {
element = element.element(propName[i]);
// Can't find the property so return.
if (element == null) {
return;
}
}
String lastName = propName[propName.length - 1];
int attributeIndex = lastName.indexOf(':');
if (attributeIndex >= 0) {
String eleName = lastName.substring(0, attributeIndex);
String attName = lastName.substring(attributeIndex + 1);
Attribute attrib = element.element(eleName).attribute(attName);
if (attrib != null) {
element.element(eleName).remove(attrib);
}
}
else {
// Found the correct element to remove, so remove it...
element.remove(element.element(lastName));
}
}
/**
* Returns an array representation of the given Jive property. Jive
* properties are always in the format "prop.name.is.this" which would be
* represented as an array of four Strings.
*
* @param name the name of the Jive property.
* @return an array representation of the given Jive property.
*/
private String[] parsePropertyName(String name) {
List propName = new ArrayList(5);
// Use a StringTokenizer to tokenize the property name.
StringTokenizer tokenizer = new StringTokenizer(name, ".");
while (tokenizer.hasMoreTokens()) {
propName.add(tokenizer.nextToken());
}
return (String[])propName.toArray(new String[propName.size()]);
}
/**
* <p>Tries to convert any given fragment into a metadata fragment.</p>
*
* @param fragment The fragment to convert
* @return The converted fragment or null if the fragment could not be converted
*/
public static MetaDataFragment convertToMetaData(XMPPFragment fragment) {
MetaDataFragment meta = null;
if (fragment instanceof MetaDataFragment) {
meta = (MetaDataFragment)fragment;
}
else if (fragment instanceof XMPPDOMFragment) {
XMPPDOMFragment dom = (XMPPDOMFragment)fragment;
meta = new MetaDataFragment(dom.getRootElement());
Iterator frags = dom.getFragments();
while (frags.hasNext()) {
meta.addFragment((XMPPFragment)frags.next());
}
}
else {
// TODO: as a last resort, should read the fragment in using an empty serializer and rebuild the dom tree
throw new IllegalArgumentException();
}
return meta;
}
/**
* <p>Tries to convert this fragment into a metadata fragment.</p>
*
* @return The converted fragment
*/
public XMPPDOMFragment convertToDOMFragment() {
XMPPDOMFragment dom = new XMPPDOMFragment(((Element)root.elements().get(0)).createCopy());
return dom;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
/**
* <p>Implements the nameprep stringprep profile according to
* the XMPP specification.</p>
*
* @author Iain Shigeoka
*/
public class NamePrep {
/**
* <p>Returns the given domain name according to the resource
* prep profile. See the XMPP 1.0 specification for specifics.</p>
*
* @param name The domain name to prepare
* @return The prepared name
*/
public static String prep(String name) {
String prep = name.trim().toLowerCase();
return prep;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
/**
* <p>Implements the nodeprep stringprep profile according to
* the XMPP specification.</p>
*
* @author Iain Shigeoka
*/
public class NodePrep {
/**
* <p>Returns the given user name (node) according to the resource
* prep profile. See the XMPP 1.0 specification for specifics.</p>
*
* @param username The username to prepare
* @return The prepared name
*/
public static String prep(String username) {
String prep = username.trim().toLowerCase();
return prep;
}
}
...@@ -11,9 +11,16 @@ ...@@ -11,9 +11,16 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.database.DbConnectionManager;
import java.util.Iterator; import org.jivesoftware.util.*;
import org.xmpp.packet.Message;
import org.dom4j.io.SAXReader;
import org.dom4j.DocumentFactory;
import java.util.*;
import java.sql.*;
import java.sql.Connection;
/** /**
* Represents the user's offline message storage. A message store holds messages that were sent * Represents the user's offline message storage. A message store holds messages that were sent
...@@ -21,40 +28,154 @@ import java.util.Iterator; ...@@ -21,40 +28,154 @@ import java.util.Iterator;
* their presence to "available". The messages will then be delivered normally. * their presence to "available". The messages will then be delivered normally.
* Offline message storage is optional in which case, a null implementation is returned that * Offline message storage is optional in which case, a null implementation is returned that
* always throws UnauthorizedException adding messages to the store. * always throws UnauthorizedException adding messages to the store.
* <p/>
* A future version of the message store will support POP like message storage so that
* users may download offline messages on demand, inspect headers only, and continue to store
* offline messages even when available.
* *
* @author Iain Shigeoka * @author Iain Shigeoka
*/ */
public interface OfflineMessageStore { public class OfflineMessageStore {
private static final String INSERT_OFFLINE =
"INSERT INTO jiveOffline (username, messageID, creationDate, messageSize, message) " +
"VALUES (?, ?, ?, ?, ?)";
private static final String LOAD_OFFLINE =
"SELECT message FROM jiveOffline WHERE username=?";
private static final String SELECT_SIZE_OFFLINE =
"SELECT SUM(messageSize) FROM jiveOffline WHERE username=?";
private static final String DELETE_OFFLINE =
"DELETE FROM jiveOffline WHERE username=?";
private static OfflineMessageStore instance = new OfflineMessageStore();
/** /**
* Add a message to the message store. Messages will be stored and made available for * Returns a singleton instance of OfflineMessageStore.
* later delivery.
* *
* @param message The message to store (messages are standard XMPP message XML) * @return an instance.
* @throws UnauthorizedException If the user is not allowed to store messages, or they have exceeded their quota
*/ */
void addMessage(Message message) throws UnauthorizedException; public static OfflineMessageStore getInstance() {
return instance;
}
private SAXReader saxReader = new SAXReader();
private DocumentFactory docFactory = new DocumentFactory();
private OfflineMessageStore() {
}
/** /**
* <p>Obtain all messages in the store for a user.</p> * Adds a message to this message store. Messages will be stored and made
* <p>Remove messages using the iterator.remove() method. Otherwise * available for later delivery.
* messages stay in the message store and will be available to other *
* users of getMessages().</p> * @param message the message to store.
*/
public void addMessage(Message message) {
if (message == null) {
return;
}
String username = message.getFrom().getNode();
// If the username is null (such as when an anonymous user), don't store.
if (username == null) {
return;
}
long messageID = SequenceManager.nextID(JiveConstants.OFFLINE);
// Get the message in XML format. We add the element to a new document so
// that we can easily parse the message from the database later.
String msgXML = docFactory.createDocument(message.getElement()).asXML();
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(INSERT_OFFLINE);
pstmt.setString(1, username);
pstmt.setLong(2, messageID);
pstmt.setString(3, StringUtils.dateToMillis(new java.util.Date()));
pstmt.setInt(4, msgXML.length());
pstmt.setString(5, msgXML);
pstmt.executeUpdate();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
}
/**
* Returns a Collection of all messages in the store for a user.
* Messages are deleted after being selected from the database.
* *
* @param username the username of the user who's messages you'd like to receive * @param username the username of the user who's messages you'd like to receive
* @return An iterator of packets containing all offline messages * @return An iterator of packets containing all offline messages
* @throws UnauthorizedException If the user is not allowed to retrieve messages
*/ */
Iterator getMessages(String username) throws UnauthorizedException, UserNotFoundException; public Collection<Message> getMessages(String username) {
List<Message> messages = new ArrayList<Message>();
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_OFFLINE);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String msgXML = rs.getString(1);
messages.add(new Message(saxReader.read(msgXML).getRootElement()));
}
rs.close();
pstmt.close();
pstmt = con.prepareStatement(DELETE_OFFLINE);
pstmt.setString(1, username);
pstmt.executeUpdate();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
return messages;
}
/** /**
* <p>Obtain the approximate size of the XML messages stored for a particular user.</p> * Returns the approximate size (in bytes) of the XML messages stored for
* a particular user.
* *
* @param username the username of the user who's messages you'd like to receive * @param username the username of the user.
* @return The approximate size of messages stored in bytes * @return the approximate size of stored messages (in bytes).
*/ */
int getSize(String username) throws UnauthorizedException; public int getSize(String username) {
int size = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(SELECT_SIZE_OFFLINE);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
size = rs.getInt(1);
}
rs.close();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
return size;
}
} }
\ No newline at end of file
...@@ -13,6 +13,7 @@ package org.jivesoftware.messenger; ...@@ -13,6 +13,7 @@ package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.Message;
/** /**
* <p>Configures and controls the server's offline message storage strategy.</p> * <p>Configures and controls the server's offline message storage strategy.</p>
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
/** /**
...@@ -32,6 +34,6 @@ public interface PacketDeliverer { ...@@ -32,6 +34,6 @@ public interface PacketDeliverer {
* @param packet The packet to route * @param packet The packet to route
* @throws java.lang.NullPointerException If the packet is null or the packet could not be routed * @throws java.lang.NullPointerException If the packet is null or the packet could not be routed
*/ */
public void deliver(XMPPPacket packet) throws public void deliver(Packet packet) throws
UnauthorizedException, PacketException, XMLStreamException; UnauthorizedException, PacketException, XMLStreamException;
} }
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.xmpp.packet.Message;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Presence;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.xmpp.packet.Packet;
/** /**
* <p>An uber router that can handle any packet type.</p> * <p>An uber router that can handle any packet type.</p>
* <p>The interface is provided primarily as a convenience for services * <p>The interface is provided primarily as a convenience for services
...@@ -30,5 +32,5 @@ public interface PacketRouter extends IQRouter, MessageRouter, PresenceRouter { ...@@ -30,5 +32,5 @@ public interface PacketRouter extends IQRouter, MessageRouter, PresenceRouter {
* @throws NullPointerException If the packet is null * @throws NullPointerException If the packet is null
* @throws IllegalArgumentException If the packet is not one of the three XMPP packet types * @throws IllegalArgumentException If the packet is not one of the three XMPP packet types
*/ */
public void route(XMPPPacket packet) throws IllegalArgumentException, NullPointerException; public void route(Packet packet) throws IllegalArgumentException, NullPointerException;
} }
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.transport.TransportHandler;
import javax.xml.stream.XMLStreamException;
/**
* A service for transporting packets in/out of the current server domain.
*
* @author Iain Shigeoka
*/
public interface PacketTransporter {
/**
* Obtain the transport handler that this transporter uses for delivering
* transport packets.
*
* @return The transport handler instance used by this transporter
*/
public TransportHandler getTransportHandler();
/**
* Delivers the given packet based on packet recipient and sender. The
* deliverer defers actual routing decisions to other classes.
* <h2>Warning</h2>
* Be careful to enforce concurrency DbC of concurrent by synchronizing
* any accesses to class resources.
*
* @param packet The packet to route
* @throws NullPointerException If the packet is null or the packet could not be routed
*/
public void deliver(XMPPPacket packet) throws UnauthorizedException, PacketException, XMLStreamException;
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import java.util.Date;
/**
* <p>Allows the simple creation, reading, and updating of presence packets.<p>
* <p>The methods used are mainly convenience interfaces to the various parts
* of a typical presence packet.</p>
* <p>A Presence encapsulates information relating to the owning user such as login time, status and
* last update time.</p>
*
* @author Iain Shigeoka
*/
public interface Presence extends XMPPPacket {
/**
* <p>Sender is available for messaging.</p>
*/
Type AVAILABLE = new Type("");
/**
* <p>Sender is unavailable for messaging.</p>
*/
Type UNAVAILABLE = new Type("unavailable");
/**
* <p>Sender is available for message reciept but presence should not be broadcast to roster members.</p>
*/
Type INVISIBLE = new Type("invisible");
/**
* <p>Sender wishes to subscribe to recipient's roster.</p>
*/
Type SUBSCRIBE = new Type("subscribe");
/**
* <p>Indicates the sender should be unsubscribed from the recipient's roster.</p>
*/
Type UNSUBSCRIBE = new Type("unsubscribe");
/**
* <p>Sent to indicate a pending subcription request has been filled.</p>
*/
Type SUBSCRIBED = new Type("subscribed");
/**
* <p>Sent to indicate a pending subscription removal request has been filled.</p>
*/
Type UNSUBSCRIBED = new Type("unsubscribed");
/**
* <p>Used when the sender wants to know the recipient's presence.</p>
*/
Type PROBE = new Type("probe");
int NO_PRIORITY = -10;
public static final int STATUS_ONLINE = 0;
public static final int STATUS_IDLE = 1;
public static final int STATUS_OFFLINE = 4;
public static final int STATUS_PROBE = -1;
/**
* Available to chat show state
*/
public static final int SHOW_CHAT = 100;
/**
* No show state
*/
public static final int SHOW_NONE = 101;
/**
* Away show state
*/
public static final int SHOW_AWAY = 102;
/**
* "Extended away" show state
*/
public static final int SHOW_XA = 103;
/**
* Do not disturb show state
*/
public static final int SHOW_DND = 104;
/**
* The online/offline status of the user. Being available indicates that the node can be
* sent packets and does not imply how the presence is propogated or presented to users.
*
* @return True if the node is available for messaging
*/
public boolean isAvailable();
/**
* Sets the online/offline status of the user.
*
* @param online True if the node is available for messaging
*/
public void setAvailable(boolean online) throws UnauthorizedException;
/**
* Gets the visibility of the user. Invisible nodes can be sent packets, but don't
* automatically propagate presence to subscribers.
*
* @return True if the user is visible
* (presence should be automatically propagated to subscribers)
*/
public boolean isVisible();
/**
* Sets the visibility of the user. Invisible nodes can be sent packets, but don't
* automatically propagate presence to subscribers.
*
* @param visible True if the node is visible (presence is broadcast)
* @throws UnauthorizedException If the caller doesn't have permission
*/
public void setVisible(boolean visible) throws UnauthorizedException;
/**
* Returns the unique ID for this status. The ID in the default implmentation is the user's
* session ID, which is unique within a single JVM.
*
* @return the unique ID for the presence.
*/
public String getID();
/**
* Return the user owning the presence.
*
* @return the presence owner.
*/
public String getUsername();
/**
* Return the time when the presence was created.
*
* @return the time when the presence was created.
*/
public Date getLoginTime();
/**
* Return the time when the presence was last updated (when the user last visited).
*
* @return the time when the presence was last updated (when the user last visited).
*/
public Date getLastUpdateTime();
/**
* Set the time when the presence was last updated (when the user last visited).
*
* @param time the time of the last update.
* @throws UnauthorizedException If the caller doesn't have permissions to make this modification
*/
public void setLastUpdateTime(Date time) throws UnauthorizedException;
/**
* Returns the status of the presence.
*
* @return the status of the presence.
*/
public int getShow();
/**
* Sets the status of the user.
*
* @param status the status of the user.
* @throws UnauthorizedException If the caller doesn't have permissions to make this modification
*/
public void setShow(int status) throws UnauthorizedException;
/**
* Gets the free text status of the user. (e.g. "out to lunch").
*
* @return The status text for the user or null if none has been set
*/
public String getStatus();
/**
* Sets the free text status of the user. (e.g. "out to lunch").
*
* @param status The new status or null if none is set
* @throws UnauthorizedException
*/
public void setStatus(String status) throws UnauthorizedException;
/**
* Obtain the priority associated with this presence if any
*
* @return The priority of this presence or -1 to indicate none set
*/
public int getPriority();
/**
* Sets the new priority for this presence
*
* @param priority The new priority value
* @throws UnauthorizedException If the caller doesn't have the appropriate authorization
*/
public void setPriority(int priority) throws UnauthorizedException;
}
\ No newline at end of file
...@@ -13,6 +13,9 @@ package org.jivesoftware.messenger; ...@@ -13,6 +13,9 @@ package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.User; import org.jivesoftware.messenger.user.User;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import java.util.Collection; import java.util.Collection;
/** /**
...@@ -106,11 +109,10 @@ public interface PresenceManager { ...@@ -106,11 +109,10 @@ public interface PresenceManager {
* servlet session id. * servlet session id.
* *
* @param user the user to create a presence for. * @param user the user to create a presence for.
* @param uid a unique string.
* @return the presence for the user. * @return the presence for the user.
* @throws UnauthorizedException if not the user. * @throws UnauthorizedException if not the user.
*/ */
public Presence createPresence(User user, String uid) throws UnauthorizedException; public Presence createPresence(User user) throws UnauthorizedException;
/** /**
* Sets a presence to be offline which causes the presence to be removed from the system. * Sets a presence to be offline which causes the presence to be removed from the system.
...@@ -126,7 +128,7 @@ public interface PresenceManager { ...@@ -126,7 +128,7 @@ public interface PresenceManager {
* @param jid the user to set to be offline. * @param jid the user to set to be offline.
* @throws UnauthorizedException if not the user. * @throws UnauthorizedException if not the user.
*/ */
public void setOffline(XMPPAddress jid) throws UnauthorizedException; public void setOffline(JID jid) throws UnauthorizedException;
/** /**
* Probes the presence of the given XMPPAddress and attempts to send it to the given user. * Probes the presence of the given XMPPAddress and attempts to send it to the given user.
...@@ -134,7 +136,7 @@ public interface PresenceManager { ...@@ -134,7 +136,7 @@ public interface PresenceManager {
* @param prober The user requesting the probe * @param prober The user requesting the probe
* @param probee The XMPPAddress whos presence we would like sent have have probed * @param probee The XMPPAddress whos presence we would like sent have have probed
*/ */
public void probePresence(String prober, XMPPAddress probee) throws UnauthorizedException; public void probePresence(String prober, JID probee) throws UnauthorizedException;
/** /**
* Probes the presence of the given XMPPAddress and attempts to send it to the given user. * Probes the presence of the given XMPPAddress and attempts to send it to the given user.
...@@ -142,5 +144,5 @@ public interface PresenceManager { ...@@ -142,5 +144,5 @@ public interface PresenceManager {
* @param prober The user requesting the probe * @param prober The user requesting the probe
* @param probee The XMPPAddress whos presence we would like sent have have probed * @param probee The XMPPAddress whos presence we would like sent have have probed
*/ */
public void probePresence(XMPPAddress prober, XMPPAddress probee) throws UnauthorizedException; public void probePresence(JID prober, JID probee) throws UnauthorizedException;
} }
\ No newline at end of file
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
/**
* <p>Implements the resourceprep stringprep profile according to
* the XMPP specification.</p>
*
* @author Iain Shigeoka
*/
public class ResourcePrep {
/**
* <p>Returns the given resource name according to the resource
* prep profile. See the XMPP 1.0 specification for specifics.</p>
*
* @param resource The resource name to prepare
* @return The prepared name
*/
public static String prep(String resource) {
String prep = resource;
return prep;
}
}
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.xmpp.packet.JID;
/** /**
* *
* *
...@@ -26,5 +28,5 @@ public interface RoutableChannelHandler extends ChannelHandler { ...@@ -26,5 +28,5 @@ public interface RoutableChannelHandler extends ChannelHandler {
* *
* @return the XMPP address. * @return the XMPP address.
*/ */
public XMPPAddress getAddress(); public JID getAddress();
} }
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.xmpp.packet.JID;
import java.util.Iterator; import java.util.Iterator;
/** /**
...@@ -83,7 +85,7 @@ public interface RoutingTable { ...@@ -83,7 +85,7 @@ public interface RoutingTable {
* @param destination The destination object for this route * @param destination The destination object for this route
* @return The destination object previously registered under the given address, or null if none existed * @return The destination object previously registered under the given address, or null if none existed
*/ */
ChannelHandler addRoute(XMPPAddress node, RoutableChannelHandler destination); ChannelHandler addRoute(JID node, RoutableChannelHandler destination);
/** /**
* <p>Obtain a route to a packet handler for the given node.</p> * <p>Obtain a route to a packet handler for the given node.</p>
...@@ -93,7 +95,7 @@ public interface RoutingTable { ...@@ -93,7 +95,7 @@ public interface RoutingTable {
* @return The handler corresponding to the route, or null indicating no route exists * @return The handler corresponding to the route, or null indicating no route exists
* @throws NoSuchRouteException If the requested route does not exist * @throws NoSuchRouteException If the requested route does not exist
*/ */
RoutableChannelHandler getRoute(XMPPAddress node) throws NoSuchRouteException; RoutableChannelHandler getRoute(JID node) throws NoSuchRouteException;
/** /**
* <p>Obtain all child routes for the given node.</p> * <p>Obtain all child routes for the given node.</p>
...@@ -103,7 +105,7 @@ public interface RoutingTable { ...@@ -103,7 +105,7 @@ public interface RoutingTable {
* @param node The address we want a route to * @param node The address we want a route to
* @return An iterator over all applicable routes * @return An iterator over all applicable routes
*/ */
Iterator getRoutes(XMPPAddress node); Iterator getRoutes(JID node);
/** /**
* <p>Obtain a route to a handler at the given node falling back to a user branch if no resource leaf exists.</p> * <p>Obtain a route to a handler at the given node falling back to a user branch if no resource leaf exists.</p>
...@@ -136,7 +138,7 @@ public interface RoutingTable { ...@@ -136,7 +138,7 @@ public interface RoutingTable {
* @return The Session corresponding to the route, or null indicating no route exists * @return The Session corresponding to the route, or null indicating no route exists
* @throws NoSuchRouteException If the requested route does not exist * @throws NoSuchRouteException If the requested route does not exist
*/ */
ChannelHandler getBestRoute(XMPPAddress node) throws NoSuchRouteException; ChannelHandler getBestRoute(JID node) throws NoSuchRouteException;
/** /**
* <p>Remove a route from the routing table.</p> * <p>Remove a route from the routing table.</p>
...@@ -145,5 +147,5 @@ public interface RoutingTable { ...@@ -145,5 +147,5 @@ public interface RoutingTable {
* @param node The address we want a route to * @param node The address we want a route to
* @return The destination object previously registered under the given address, or null if none existed * @return The destination object previously registered under the given address, or null if none existed
*/ */
ChannelHandler removeRoute(XMPPAddress node); ChannelHandler removeRoute(JID node);
} }
...@@ -15,6 +15,10 @@ import org.jivesoftware.messenger.auth.AuthToken; ...@@ -15,6 +15,10 @@ import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager; import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Packet;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Date; import java.util.Date;
...@@ -24,11 +28,11 @@ import javax.xml.stream.XMLStreamWriter; ...@@ -24,11 +28,11 @@ import javax.xml.stream.XMLStreamWriter;
public class ServerSession implements Session { public class ServerSession implements Session {
private StreamID streamID; private StreamID streamID;
private XMPPAddress address; private JID address;
private Date creationDate; private Date creationDate;
private Connection connection = new ServerConnection(); private Connection connection = new ServerConnection();
public ServerSession(XMPPAddress address, StreamID streamID) { public ServerSession(JID address, StreamID streamID) {
this.address = address; this.address = address;
this.streamID = streamID; this.streamID = streamID;
creationDate = new Date(); creationDate = new Date();
...@@ -112,11 +116,11 @@ public class ServerSession implements Session { ...@@ -112,11 +116,11 @@ public class ServerSession implements Session {
public void incrementConflictCount() { public void incrementConflictCount() {
} }
public XMPPAddress getAddress() { public JID getAddress() {
return address; return address;
} }
public void process(XMPPPacket packet) { public void process(Packet packet) {
} }
private class ServerConnection implements Connection { private class ServerConnection implements Connection {
...@@ -159,7 +163,7 @@ public class ServerSession implements Session { ...@@ -159,7 +163,7 @@ public class ServerSession implements Session {
return null; return null;
} }
public void deliver(XMPPPacket packet) public void deliver(Packet packet)
throws UnauthorizedException { throws UnauthorizedException {
} }
......
...@@ -15,6 +15,9 @@ import org.jivesoftware.messenger.auth.AuthToken; ...@@ -15,6 +15,9 @@ import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager; import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import java.util.Date; import java.util.Date;
/** /**
...@@ -46,7 +49,7 @@ public interface Session extends RoutableChannelHandler { ...@@ -46,7 +49,7 @@ public interface Session extends RoutableChannelHandler {
* *
* @return the address of the packet handler. * @return the address of the packet handler.
*/ */
public XMPPAddress getAddress(); public JID getAddress();
/** /**
* Returns the connection associated with this Session. * Returns the connection associated with this Session.
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
/**
* Represents a single XMPP delivery node, identified by
* a XMPPAddress.<p>
*
* A normal full address is of the form: user@server/resource. However
* a 'bare address' is only composed of user@server and omits or ignores
* the resource. The bare address is useful for referring to a generic
* delivery node, without specifying the resource (allowing the normal
* resource priority routing to determine where it is being delivered).
*
* @author Iain Shigeoka
*/
public class XMPPAddress implements Cacheable {
private transient String cached;
private transient String cachedBare;
private transient String cachedPrep;
private transient String cachedBarePrep;
/**
* The user name associated with this address.
*/
private String name;
private transient String namePrep;
/**
* The name of the XMPP host domain (server host name).
*/
private String host;
private transient String hostPrep;
/**
* The address resource attribute typically identifying
* specific delivery points associated with a user account
*/
private String resource;
private transient String resourcePrep;
/**
* Dirty flag indicating that the cached address string must
* be regenerated because a set*() method
* was called.
*/
private transient boolean dirty = true;
/**
* Create a local XMPPAddress.
*
* @param username the user name for the id.
* @param resource the resource for the id.
*/
public XMPPAddress(String username, String host, String resource) {
setHost(host);
setName(username);
setResource(resource);
}
/**
* Create a XMPP ID by parsing the given address string.
*
* @param address the address string to parse.
*/
public static XMPPAddress parseJID(String address) {
String name;
String host;
String resource;
if (address == null) {
return null;
}
else {
address = address.trim();
int atPos = address.indexOf('@');
int slashPos = address.indexOf('/');
if (atPos != -1) {
name = address.substring(0, atPos);
}
else {
name = "";
}
if (slashPos == -1 || slashPos == address.length() - 1) {
slashPos = address.length();
resource = "";
}
else {
resource = address.substring(slashPos + 1);
}
host = address.substring(atPos + 1, slashPos);
}
return new XMPPAddress(name, host, resource);
}
/**
* Returns the XMPP address with any resource information removed. For example,
* for the address "matt@jivesoftware.com/Smack", "matt@jivesoftware.com" would
* be returned.
*
* @param XMPPAddress the XMPP address.
* @return the bare XMPP address without resource information.
*/
public static String parseBareAddress(String XMPPAddress) {
if (XMPPAddress == null) {
return null;
}
int slashIndex = XMPPAddress.indexOf("/");
if (slashIndex < 0) {
return XMPPAddress;
}
else if (slashIndex == 0) {
return "";
}
else {
return XMPPAddress.substring(0, slashIndex);
}
}
/**
* Obtain the XMPP name for this address.
*
* @return the name or null if no id has been set or no name is defined (server ID).
*/
public String getName() {
return name;
}
/**
* Obtain the XMPP nameprep name for this address.
*
* @return The name or null if no id has been set or no name is defined (server ID).
*/
public String getNamePrep() {
if (name != null) {
if (namePrep == null) {
namePrep = NodePrep.prep(name);
}
}
return namePrep;
}
/**
* Set the XMPP name for this address.
*
* @param name the name.
*/
public void setName(String name) {
dirty = true;
if (name == null) {
this.name = null;
}
else {
this.name = name.trim();
}
namePrep = null;
}
/**
* Obtain the XMPP host domain for this address.
*
* @return the name of the XMPP domain (server host name) or null if undefined.
*/
public String getHost() {
return host;
}
/**
* Obtain the XMPP host domain for this address.
*
* @return the name of the XMPP domain (server host name) or null if undefined
*/
public String getHostPrep() {
if (host != null) {
if (hostPrep == null) {
hostPrep = NamePrep.prep(host);
}
}
return hostPrep;
}
/**
* Set the XMPP host domain for this address.
*
* @param host the name of the XMPP domain (server host name) or null if undefined.
*/
public void setHost(String host) {
dirty = true;
if (host == null) {
this.host = null;
}
else {
this.host = host.trim();
}
hostPrep = null;
}
/**
* Obtain the resource identified by this address.
*
* @return The name of the resource or null if none defined.
*/
public String getResource() {
return resource;
}
/**
* Obtain the resource identified by this address.
*
* @return The name of the resource or null if none defined.
*/
public String getResourcePrep() {
if (resource != null) {
if (resourcePrep == null) {
resourcePrep = ResourcePrep.prep(resource);
}
}
return resourcePrep;
}
/**
* Set the resource identified by this address.
*
* @param resource the name of the resource or null if none defined.
*/
public void setResource(String resource) {
dirty = true;
if (resource == null) {
this.resource = null;
}
else {
this.resource = resource.trim();
}
resourcePrep = null;
}
private synchronized void generateCachedJID() {
dirty = false;
StringBuffer buf = new StringBuffer();
StringBuffer bufprep = new StringBuffer();
if (name != null && !"".equals(name)) {
bufprep.append(NodePrep.prep(name));
bufprep.append('@');
buf.append(name);
buf.append('@');
}
if (host != null) {
bufprep.append(NamePrep.prep(host));
buf.append(host);
}
if (resource != null && !"".equals(resource)) {
cachedBarePrep = bufprep.toString();
cachedBare = buf.toString();
buf.append('/');
buf.append(resource);
bufprep.append('/');
bufprep.append(ResourcePrep.prep(resource));
cached = buf.toString();
cachedPrep = bufprep.toString();
}
else {
if (buf.length() == 0) {
cached = Integer.toHexString(hashCode());
cachedBare = cached;
cachedPrep = cached;
cachedBarePrep = cached;
}
else {
cached = buf.toString();
cachedBare = cached;
cachedPrep = bufprep.toString();
cachedBarePrep = cachedPrep;
}
}
}
/**
* Obtain an easer to read string for this address.
*
* @return The XMPP ID as a URI or a simple "XMPPAddress" string if no URI has been set
*/
public String toString() {
if (dirty) {
generateCachedJID();
}
return cached;
}
/**
* Obtain the XMPP ID in normal XMPP format.
*/
public String toStringPrep() {
if (dirty) {
generateCachedJID();
}
return cachedPrep;
}
/**
* Obtain the XMPP ID in normal XMPP format excluding any resource information.
*
* @return the bare jid as a string (no resource)
*/
public String toBareString() {
if (dirty) {
generateCachedJID();
}
return cachedBare;
}
/**
* Obtain the XMPP ID in normal XMPP format excluding any resource information.
*
* @return the bare jid processed by stringprep and returned as a string (no resource)
*/
public String toBareStringPrep() {
if (dirty) {
generateCachedJID();
}
return cachedBarePrep;
}
public int getCachedSize() {
int size = CacheSizes.sizeOfString(name);
size += CacheSizes.sizeOfString(host);
size += CacheSizes.sizeOfString(resource);
return size;
}
public boolean equalsBare(XMPPAddress sender) {
return equal(getHostPrep(), sender.getHostPrep())
&& equal(getNamePrep(), sender.getNamePrep());
}
private boolean equal(String lhs, String rhs) {
boolean equals = true;
if (lhs == null) {
if (rhs != null) {
equals = false;
}
}
else {
if (!lhs.equals(rhs)) {
equals = false;
}
}
return equals;
}
public boolean equals(Object address) {
if (address instanceof XMPPAddress) {
XMPPAddress addr = (XMPPAddress)address;
if (equalsBare(addr) && equal(resource, addr.resource)) {
return true;
}
}
return false;
}
public int hashCode() {
if (dirty) {
generateCachedJID();
}
if (cachedPrep == null) {
return 0;
}
else {
return cachedPrep.hashCode();
}
}
/**
* Returns true if all the portions of the addresss are null.
*
* @return true if all the portions of the addresss are null.
*/
public boolean isEmpty() {
return name == null && host == null && resource == null;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.util.XPPWriter;
import org.jivesoftware.messenger.spi.AbstractFragment;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
/**
* Stores the fragment in a dom4j DOM model. Efficiency of the fragment is
* relatively low but is the most flexible way to store fragment information.
*
* @author Iain Shigeoka
*/
public class XMPPDOMFragment extends AbstractFragment implements XMPPFragment {
/**
* The document holding this fragment's data.
*/
private Element root;
/**
* Constructor using a given Document to represent the packet.
*/
public XMPPDOMFragment(Element root) {
this.root = root;
name = root.getName();
namespace = root.getNamespaceURI();
}
/**
* Obtain the root element of the DOM tree representing the data in this fragment.
*
* @return the root element of the DOM tree or null if none has been set
*/
public Element getRootElement() {
return root;
}
public void send(XMLStreamWriter xmlSerializer, int version) throws
XMLStreamException {
XPPWriter.write(root, xmlSerializer);
}
public XMPPFragment createDeepCopy() {
XMPPFragment frag = new XMPPDOMFragment((Element)root.clone());
Iterator frags = getFragments();
while (frags.hasNext()) {
frag.addFragment((XMPPFragment)frags.next());
}
return frag;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.spi.AbstractFragment;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
/**
* A error object representing an XMPP error. Error packets are tricky because
* Jabber (old style) and XMPP errors are completely different. This class does
* it's best to abstract the entire error generation process. The packet will
* serialize to XML according to the underlying session version (none indicating
* Jabber, v 1.0 indicating XMPP.</p>
*
* @author Iain Shigeoka
*/
public class XMPPError extends AbstractFragment {
/**
* The mandatory error message.
*/
private Code code;
/**
* Create an error with the given code.
*
* @param code The error code
*/
public XMPPError(Code code) {
this.code = code;
}
/**
* Returns the error code for this error. XMPP defines several standard error
* codes that MUST be included in the 'error' attribute of error packets.
*
* @return the error code.
*/
Code getCode() {
return code;
}
/**
* Set the error code for this error. XMPP defines several standard error codes
* that MUST be included in the 'error' attribute of error packets.
*
* @param code The error code
*/
void setCode(Code code) {
this.code = code;
}
public void send(XMLStreamWriter xmlSerializer, int version) throws XMLStreamException {
xmlSerializer.writeStartElement("jabber:client", "error");
xmlSerializer.writeAttribute("code", Integer.toString(code.getValue()));
xmlSerializer.writeEndElement();
}
public XMPPFragment createDeepCopy() {
XMPPError error = new XMPPError(code);
Iterator frags = getFragments();
while (frags.hasNext()) {
error.addFragment((XMPPFragment)frags.next());
}
return error;
}
/**
* Represents an error code.
*/
public enum Code {
NONE(-1),
REDIRECT(302),
BAD_REQUEST(400),
UNAUTHORIZED(401),
PAYMENT_REQUIRED(402),
FORBIDDEN(403),
NOT_FOUND(404),
NOT_ALLOWED(405),
NOT_ACCEPTABLE(406),
REGISTRATION_REQUIRED(407),
REQUEST_TIMEOUT(408),
CONFLICT(409),
INTERNAL_SERVER_ERROR(500),
NOT_IMPLEMENTED(501),
REMOTE_SERVER_ERROR(502),
SERVICE_UNAVAILABLE(503),
REMOTE_SERVER_TIMEOUT(504);
private int value;
/**
* Create a code with the given integer error code value.
*
* @param value the error value of the code
*/
private Code(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
/**
* <p>Represents an XML fragment with particular meaning in XMPP.</p>
* <p>XMPP systems will be dealing with many XML fragments and this class
* allows the system to generically handle fragments without particular knowledge
* of what they contain (and hiding optimizations in representing, storing,
* and sending these fragments). The most common fragments the system deals
* with are XMPP packets of the three cardinal types: Message, Presence,
* and IQ. However, these packets can contain protocol specific, or custom
* meta-data represented by additional fragments.</p>
* <p>Fragments allows parsers to breakdown XMPP packets into fragment object
* models. A higher abstraction level than XML DOM's that must create a node
* for every XML element. However, they also may be implemented as simple
* wrappers around raw XML DOM's if necessary.</p>
*
* @author Iain Shigeoka
*/
public interface XMPPFragment {
/**
* <p>Returns a namespace associated with this meta-data or null if none has been associated.</p>
*
* @return the namespace associated with this meta-data.
*/
public String getNamespace();
/**
* <p>Sets a namespace associated with this meta-data or null if none has been associated.</p>
*
* @param namespace the namespace associated with this meta-data.
*/
public void setNamespace(String namespace);
/**
* <p>Returns a name associated with this meta-data or null if none has been associated.</p>
*
* @return the name associated with this meta-data.
*/
public String getName();
/**
* Sets a namespace associated with this meta-data or null if none has been associated.
*
* @param name The namespace associated with this meta-data
*/
public void setName(String name);
/**
* <p>Sends the fragment as a string to the given writer.</p>
* <p>A fragment will always be written as a completely self
* contained, well-formed XML fragment.</p>
*
* @param xmlSerializer The serializer to send the jabber packet
* @param version The XMPP version for the stream (0 is old Jabber, 1 is XMPP 1.0)
* @throws XMLStreamException If there is a problem with the connection
*/
void send(XMLStreamWriter xmlSerializer, int version) throws XMLStreamException;
/**
* <p>Generates an independent, deep copy of this packet.</p>
*
* @return The deep copy of the packet
*/
XMPPFragment createDeepCopy();
/**
* <p>Adds another fragment as a child fragment of this one.</p>
* <p>Child fragments can be used to build a DOM like tree of fragments. However,
* the typical use case in Messenger packets is to store meta-data as child fragments
* and standard data as member fields accessed via standard setter/getters.</p>
*
* @param fragment the fragment to add to this packet.
*/
void addFragment(XMPPFragment fragment);
/**
* <p>Obtain an iterator of child fragments.</p>
*
* @return An iterator over all child fragments.
*/
Iterator getFragments();
/**
* Returns the fragment whose name and namespace matches the requested ones or <tt>null</tt> if
* none. It is assumed that there is at most one fragment per name and namespace.
*
* @param name the name of the fragment to search.
* @param namespace the namespace of the fragment to search.
* @return the fragment whose name and namespace matches the requested ones or <tt>null</tt> if
* none.
*/
XMPPFragment getFragment(String name, String namespace);
/**
* Remove any child fragments from this fragment.
*/
void clearFragments();
/**
* <p>Make a best guess estimate on size in bytes of an XML string representation of
* this fragment.</p>
* <p>There are several server operations that can be helped by hints on fragment sizes
* such as offline storage, auditing, caching, etc. To this end, this method provides
* a guess where speed of calculation and lowest resource impact are highest priorities
* (you should not generate the XML string and count the bytes).</p>
*
* @return an estimate in bytes of the size of this fragment as an XML string
* (assume UTF-8 encoding)
*/
int getSize();
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
/**
* A packet is a routeable XML fragment containing information on sender,
* recipient, and XMPP standard packet type.
*
* @author Iain Shigeoka
*/
public interface XMPPPacket extends XMPPFragment {
public static final Type ERROR = new Type("error");
/**
* <p>Obtain the flag indicating whether this packet is being
* sent (true) or received (false) by the server.</p>
* <p/>
* <p>The same packet may be received by the server at a c2s
* connection making isSending() false, then the server routes
* the packet and sets the isSending() to true for delivery
* out another c2s connection.</p>
*
* @return true if the packet is in the process of being sent.
*/
boolean isSending();
/**
* <p>Set a flag indicating whether this packet is being
* sent (true) or received (false) by the server.</p>
*
* @param isSending true if the packet is in the process of being sent.
*/
void setSending(boolean isSending);
/**
* <p>Returns the priority of the packet for routing and handling.</p>
* <p>Valid values are <tt>XMPPPacket.ROUTE_PRIORITY_HIGH</tt>,
* <tt>XMPPPacket.ROUTE_PRIORITY_NORMAL</tt> or
* <tt>XMPPPacket.ROUTE_PRIORITY_LOW</tt>. The
* priority determines how quickly a packet will be routed through
* a Channel, with higher priority packet being handled first. Any
* ChannelHandler can set the priority of a packet. Subsequently,
* that priority should apply for all future channels until a
* new priority setting is made.</p>
*
* @return the routing priority of the packet.
*/
RoutePriority getRoutePriority();
/**
* <p>Sets the priority of the packet for routing and handling.</p>
* <p>Valid values are <tt>XMPPPacket.ROUTE_PRIORITY_HIGH</tt>,
* <tt>XMPPPacket.ROUTE_PRIORITY_NORMAL</tt> or
* <tt>XMPPPacket.ROUTE_PRIORITY_LOW</tt>. The
* priority determines how quickly a packet will be routed
* through a Channel, with higher priority packet being
* handled first. Any ChannelHandler can set the priority
* of a packet. Subsequently, that priority should apply
* for all future channels until a new priority setting is made.</p>
*
* @param priority the routing priority of the packet.
*/
void setRoutePriority(RoutePriority priority);
/**
* <p>Makes this packet an error packet and sets it's error
* code to the given value.</p>
* <p/>
* <p>Errors are generically handled for XMPP 1.0 errors and
* old Jabber style errors.</p>
*
* @param errorCode The new error code for this packet
*/
void setError(XMPPError.Code errorCode);
/**
* <p>Get the error for this packet if the packet is of type 'error'.</p>
* <p>Packets of type 'error' MUST have an error payload. If the error
* packet is of type 'error' and no error object is currenly set, this method
* MUST return an unknown error (not null). Similarly, if the packet type is
* not 'error' this method will always return null.</p>
*
* @return error The error payload for this packet or null if none exists
*/
XMPPError getError();
/**
* <p>Obtain the id attribute of the packet.</p>
* <p/>
* <p>IDs are used to identify related packets. In IQ request-response
* pairs, the ID on the request is always set to the same value on
* the response to make matching of the two possible.</p>
*
* @return The ID of the packet or null if none is set
*/
String getID();
/**
* <p>Set the id attribute of the packet.</p>
*
* @param id The ID of the packet or null if none is set
* @see #getID
*/
void setID(String id);
/**
* Get the recipient JID for this packet. This taken from the "to" attribute
* of incoming packets or set if you want to force a destination.
*
* @return The recipient's JID
*/
XMPPAddress getRecipient();
/**
* <p>Set the recipient JID for this packet (will be used with the 'to'
* attribute of the packet).</p>
* <p/>
* <p>Setting the recipient to null leaves the 'to' attribute blank
* and eliminates the ability for the server to route the packet by
* recipient address. In other words, a packet with null recipient
* will not be routed automatically by the server.</p>
*
* @param recipient The address of the recipient of this packet or
* null to leave the field blank.
*/
void setRecipient(XMPPAddress recipient);
/**
* <p>Sets the sender JID for this packet (will be used with the 'from'
* attribute of the packet).</p>
* <p/>
* <p>The sender can be null, in which case the server will attempt to
* set the from field using the address associated with the originating
* session. If the originating session is null, or does not have an
* address, then the from attribute is not set on the packet.</p>
*
* @param sender The sender of this packet
*/
void setSender(XMPPAddress sender);
/**
* Get the sender's JID for this packet. This forced to be the originating
* sender on c2s packets or taken from the "from" attribute on
* of incoming s2s packets. The value of the "from" attribute is set
* to match the sender on outgoing packets regardless
* of the presence or value of the "from" attribute.
*
* @return the sender's JID.
*/
XMPPAddress getSender();
/**
* Gets the session that created this packet. The default is null
* which indicates that the packet was created by the server.
* The distinction between sender and originating session is needed
* for server and s2s generated packets.
*
* @return the session that created this packet.
*/
Session getOriginatingSession();
/**
* <p>Sets the session that created this packet.</p>
*
* @param session the session that created this packet or null if
* the server sent the packet
*/
void setOriginatingSession(Session session);
/**
* <p>Parse the packet from the given parser.</p>
* <p>The XPP parser MUST be set to the start tag of the packet's root element
* before calling this method and will always return with the xpp parser
* on the end tag token of the packet's root element.</p>
*
* @param xpp the XPP to pull the packet from.
*/
void parse(XMLStreamReader xpp) throws XMLStreamException;
/**
* <p>Obtain the type-safe type attribute from a string.</p>
*
* @param type the string type (may be null).
* @return the corrresponding type.
*/
Type typeFromString(String type);
/**
* Sets the type of packet. The type is used in the 'type'
* attribute of the packet and for determining output formatting
* such as whether to use an Error packet to decorate this packet.
*
* @param type the type of this packet.
*/
void setType(Type type);
/**
* Obtain the type of this packet.
*
* @return the type of this packet.
*/
Type getType();
/**
* Represents the type-safe 'type' attribute of a packet.
*/
class Type {
String value;
protected Type(String value) {
this.value = value;
}
public String toString() {
return value;
}
}
/**
* Routing priority of a packet.
*/
public enum RoutePriority {
high, normal, low;
}
}
\ No newline at end of file
...@@ -13,6 +13,7 @@ package org.jivesoftware.messenger; ...@@ -13,6 +13,7 @@ package org.jivesoftware.messenger;
import org.jivesoftware.messenger.container.Module; import org.jivesoftware.messenger.container.Module;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
/** /**
* The XMPP server definition. An interface allows us to implement the * The XMPP server definition. An interface allows us to implement the
...@@ -42,7 +43,7 @@ public interface XMPPServer extends XMPPServerMBean, Module { ...@@ -42,7 +43,7 @@ public interface XMPPServer extends XMPPServerMBean, Module {
* *
* @return true if the address is a local address to this server. * @return true if the address is a local address to this server.
*/ */
public boolean isLocal(XMPPAddress jid); public boolean isLocal(JID jid);
/** /**
* Creates an XMPPAddress local to this server. * Creates an XMPPAddress local to this server.
...@@ -51,7 +52,7 @@ public interface XMPPServer extends XMPPServerMBean, Module { ...@@ -51,7 +52,7 @@ public interface XMPPServer extends XMPPServerMBean, Module {
* @param resource the resource portion of the id or null to indicate none is needed. * @param resource the resource portion of the id or null to indicate none is needed.
* @return an XMPPAddress for the server. * @return an XMPPAddress for the server.
*/ */
public XMPPAddress createAddress(String username, String resource); public JID createJID(String username, String resource);
/** /**
* Obtain the session representing a packet stream originating from the server. * Obtain the session representing a packet stream originating from the server.
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
package org.jivesoftware.messenger.audit; package org.jivesoftware.messenger.audit;
import org.jivesoftware.messenger.XMPPPacket; import org.xmpp.packet.Packet;
/** /**
* <p>Use auditors to audit events and messages on the server.</p> * <p>Use auditors to audit events and messages on the server.</p>
...@@ -29,7 +29,7 @@ public interface Auditor { ...@@ -29,7 +29,7 @@ public interface Auditor {
* *
* @param packet the packet being audited * @param packet the packet being audited
*/ */
void audit(XMPPPacket packet); void audit(Packet packet);
/** /**
* Audit any packet that was dropped (undeliverables, etc). * Audit any packet that was dropped (undeliverables, etc).
......
...@@ -13,11 +13,12 @@ package org.jivesoftware.messenger.auth.spi; ...@@ -13,11 +13,12 @@ package org.jivesoftware.messenger.auth.spi;
import org.jivesoftware.database.DbConnectionManager; import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.NodePrep;
import org.jivesoftware.messenger.auth.AuthFactory; import org.jivesoftware.messenger.auth.AuthFactory;
import org.jivesoftware.messenger.auth.AuthProvider; import org.jivesoftware.messenger.auth.AuthProvider;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
...@@ -72,7 +73,12 @@ public class DbAuthProvider implements AuthProvider { ...@@ -72,7 +73,12 @@ public class DbAuthProvider implements AuthProvider {
if (username == null || password == null) { if (username == null || password == null) {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
username = NodePrep.prep(username); try {
username = Stringprep.nodeprep(username);
}
catch (StringprepException se) {
throw new UnauthorizedException("Illegal username: " + se.getMessage());
}
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
try { try {
...@@ -119,7 +125,12 @@ public class DbAuthProvider implements AuthProvider { ...@@ -119,7 +125,12 @@ public class DbAuthProvider implements AuthProvider {
if (username == null || token == null || digest == null) { if (username == null || token == null || digest == null) {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
username = NodePrep.prep(username); try {
username = Stringprep.nodeprep(username);
}
catch (StringprepException se) {
throw new UnauthorizedException("Illegal username: " + se.getMessage());
}
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
try { try {
...@@ -167,7 +178,12 @@ public class DbAuthProvider implements AuthProvider { ...@@ -167,7 +178,12 @@ public class DbAuthProvider implements AuthProvider {
if (username == null || password == null) { if (username == null || password == null) {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
username = NodePrep.prep(username); try {
username = Stringprep.nodeprep(username);
}
catch (StringprepException se) {
throw new UnauthorizedException("Illegal username: " + se.getMessage());
}
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
try { try {
......
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
package org.jivesoftware.messenger.disco; package org.jivesoftware.messenger.disco;
import org.jivesoftware.messenger.forms.XDataForm; import org.jivesoftware.messenger.forms.XDataForm;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
import java.util.Iterator; import java.util.Iterator;
/** /**
...@@ -38,7 +39,7 @@ public interface DiscoInfoProvider { ...@@ -38,7 +39,7 @@ public interface DiscoInfoProvider {
* @param senderJID the XMPPAddress of user that sent the disco info request. * @param senderJID the XMPPAddress of user that sent the disco info request.
* @return an Iterator (of Element) with the target entity's identities. * @return an Iterator (of Element) with the target entity's identities.
*/ */
public abstract Iterator getIdentities(String name, String node, XMPPAddress senderJID); public abstract Iterator getIdentities(String name, String node, JID senderJID);
/** /**
* Returns an Iterator (of String) with the supported features. The features to include are the * Returns an Iterator (of String) with the supported features. The features to include are the
...@@ -50,7 +51,7 @@ public interface DiscoInfoProvider { ...@@ -50,7 +51,7 @@ public interface DiscoInfoProvider {
* @param senderJID the XMPPAddress of user that sent the disco info request. * @param senderJID the XMPPAddress of user that sent the disco info request.
* @return an Iterator (of String) with the supported features. * @return an Iterator (of String) with the supported features.
*/ */
public abstract Iterator getFeatures(String name, String node, XMPPAddress senderJID); public abstract Iterator getFeatures(String name, String node, JID senderJID);
/** /**
* Returns an XDataForm with the extended information about the entity or null if none. Each bit * Returns an XDataForm with the extended information about the entity or null if none. Each bit
...@@ -61,7 +62,7 @@ public interface DiscoInfoProvider { ...@@ -61,7 +62,7 @@ public interface DiscoInfoProvider {
* @param senderJID the XMPPAddress of user that sent the disco info request. * @param senderJID the XMPPAddress of user that sent the disco info request.
* @return an XDataForm with the extended information about the entity or null if none. * @return an XDataForm with the extended information about the entity or null if none.
*/ */
public abstract XDataForm getExtendedInfo(String name, String node, XMPPAddress senderJID); public abstract XDataForm getExtendedInfo(String name, String node, JID senderJID);
/** /**
* Returns true if we can provide information related to the requested name and node. For * Returns true if we can provide information related to the requested name and node. For
...@@ -75,6 +76,6 @@ public interface DiscoInfoProvider { ...@@ -75,6 +76,6 @@ public interface DiscoInfoProvider {
* @return true if we can provide information related to the requested name and node. * @return true if we can provide information related to the requested name and node.
* @throws UnauthorizedException if the senderJID is not authorized to discover information. * @throws UnauthorizedException if the senderJID is not authorized to discover information.
*/ */
public abstract boolean hasInfo(String name, String node, XMPPAddress senderJID) public abstract boolean hasInfo(String name, String node, JID senderJID)
throws UnauthorizedException; throws UnauthorizedException;
} }
...@@ -11,8 +11,9 @@ ...@@ -11,8 +11,9 @@
package org.jivesoftware.messenger.disco; package org.jivesoftware.messenger.disco;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
import java.util.Iterator; import java.util.Iterator;
/** /**
...@@ -40,7 +41,7 @@ public interface DiscoItemsProvider { ...@@ -40,7 +41,7 @@ public interface DiscoItemsProvider {
* @return an Iterator (of Element) with the target entity's items or null if none. * @return an Iterator (of Element) with the target entity's items or null if none.
* @throws UnauthorizedException if the senderJID is not authorized to discover items. * @throws UnauthorizedException if the senderJID is not authorized to discover items.
*/ */
public abstract Iterator getItems(String name, String node, XMPPAddress senderJID) public abstract Iterator getItems(String name, String node, JID senderJID)
throws UnauthorizedException; throws UnauthorizedException;
} }
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.forms;
import org.jivesoftware.messenger.XMPPFragment;
import org.dom4j.Element;
/**
* The standard XMPP DataForm packet.
*
* @author Gaston Dombiak
*/
public interface XDataForm extends DataForm, XMPPFragment {
/**
* Obtain the data form as an XML DOM element.
*
* @return The data form as an XML DOM element.
*/
public Element asXMLElement();
}
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
package org.jivesoftware.messenger.forms.spi; package org.jivesoftware.messenger.forms.spi;
import org.jivesoftware.messenger.forms.FormField; import org.jivesoftware.messenger.forms.FormField;
import org.jivesoftware.messenger.forms.XDataForm;
import org.jivesoftware.messenger.XMPPFragment;
import org.jivesoftware.util.ConcurrentHashSet; import org.jivesoftware.util.ConcurrentHashSet;
import java.util.*; import java.util.*;
...@@ -48,7 +46,7 @@ import org.dom4j.QName; ...@@ -48,7 +46,7 @@ import org.dom4j.QName;
* *
* @author gdombiak * @author gdombiak
*/ */
public class XDataFormImpl implements XDataForm { public class XDataFormImpl {
private String type; private String type;
private String title; private String title;
......
...@@ -143,7 +143,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo { ...@@ -143,7 +143,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
Session session, Session session,
String digest) String digest)
throws UnauthorizedException, UserNotFoundException { throws UnauthorizedException, UserNotFoundException {
XMPPAddress jid = localServer.createAddress(username, iq.element("resource").getTextTrim()); XMPPAddress jid = localServer.createJID(username, iq.element("resource").getTextTrim());
// If a session already exists with the requested JID, then check to see // If a session already exists with the requested JID, then check to see
......
...@@ -17,6 +17,10 @@ import org.jivesoftware.util.LocaleUtils; ...@@ -17,6 +17,10 @@ import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
/** /**
...@@ -47,8 +51,8 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler { ...@@ -47,8 +51,8 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler {
this.router = router; this.router = router;
} }
public void process(XMPPPacket xmppPacket) throws UnauthorizedException, PacketException { public void process(Packet packet) throws UnauthorizedException, PacketException {
IQ iq = (IQ)xmppPacket; IQ iq = (IQ)packet;
try { try {
iq = handleIQ(iq); iq = handleIQ(iq);
if (iq != null) { if (iq != null) {
...@@ -58,8 +62,8 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler { ...@@ -58,8 +62,8 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler {
catch (org.jivesoftware.messenger.auth.UnauthorizedException e) { catch (org.jivesoftware.messenger.auth.UnauthorizedException e) {
if (iq != null) { if (iq != null) {
try { try {
XMPPPacket response = iq.createResult(); IQ response = IQ.createResultIQ(iq);
response.setError(XMPPError.Code.UNAUTHORIZED); response.setError(PacketError.Condition.not_authorized);
Session session = iq.getOriginatingSession(); Session session = iq.getOriginatingSession();
if (!session.getConnection().isClosed()) { if (!session.getConnection().isClosed()) {
session.getConnection().deliver(response); session.getConnection().deliver(response);
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
package org.jivesoftware.messenger.muc; package org.jivesoftware.messenger.muc;
import org.jivesoftware.messenger.IQ; import org.xmpp.packet.Message;
import org.jivesoftware.messenger.Message; import org.xmpp.packet.Presence;
import org.jivesoftware.messenger.Presence; import org.xmpp.packet.IQ;
/** /**
* Interface for any object that can accept chat messages and presence * Interface for any object that can accept chat messages and presence
...@@ -22,6 +22,7 @@ import org.jivesoftware.messenger.Presence; ...@@ -22,6 +22,7 @@ import org.jivesoftware.messenger.Presence;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public interface ChatDeliverer { public interface ChatDeliverer {
/** /**
* Sends a packet to the user. * Sends a packet to the user.
* *
......
...@@ -22,8 +22,6 @@ import java.util.TimeZone; ...@@ -22,8 +22,6 @@ import java.util.TimeZone;
import org.jivesoftware.messenger.muc.spi.MUCRoleImpl; import org.jivesoftware.messenger.muc.spi.MUCRoleImpl;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.MetaDataFragment;
/** /**
* Represents the amount of history requested by an occupant while joining a room. There are * Represents the amount of history requested by an occupant while joining a room. There are
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
package org.jivesoftware.messenger.muc; package org.jivesoftware.messenger.muc;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.JiveGlobals; import org.jivesoftware.messenger.JiveGlobals;
import org.xmpp.packet.Message;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
package org.jivesoftware.messenger.muc; package org.jivesoftware.messenger.muc;
import org.jivesoftware.messenger.MetaDataFragment; import org.xmpp.packet.JID;
import org.jivesoftware.messenger.Presence; import org.xmpp.packet.Presence;
import org.jivesoftware.messenger.XMPPAddress; import org.dom4j.Element;
/** /**
* Defines the permissions and actions that a MUCUser may use in * Defines the permissions and actions that a MUCUser may use in
...@@ -82,7 +82,7 @@ public interface MUCRole extends ChatDeliverer { ...@@ -82,7 +82,7 @@ public interface MUCRole extends ChatDeliverer {
* @return the extended presence information that includes information about roles, * @return the extended presence information that includes information about roles,
* affiliations. * affiliations.
*/ */
MetaDataFragment getExtendedPresenceInformation(); Element getExtendedPresenceInformation();
/** /**
* Set the current presence status of a user in a chatroom. * Set the current presence status of a user in a chatroom.
...@@ -183,5 +183,5 @@ public interface MUCRole extends ChatDeliverer { ...@@ -183,5 +183,5 @@ public interface MUCRole extends ChatDeliverer {
* *
* @return The Jabber ID that represents this role in the room. * @return The Jabber ID that represents this role in the room.
*/ */
XMPPAddress getRoleAddress(); JID getRoleAddress();
} }
...@@ -18,13 +18,12 @@ import java.util.Collection; ...@@ -18,13 +18,12 @@ import java.util.Collection;
import org.jivesoftware.messenger.muc.spi.IQAdminHandler; import org.jivesoftware.messenger.muc.spi.IQAdminHandler;
import org.jivesoftware.messenger.muc.spi.IQOwnerHandler; import org.jivesoftware.messenger.muc.spi.IQOwnerHandler;
import org.jivesoftware.util.NotFoundException; import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.Presence;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserAlreadyExistsException; import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Message;
import org.xmpp.packet.JID;
/** /**
...@@ -212,7 +211,7 @@ public interface MUCRoom extends ChatDeliverer { ...@@ -212,7 +211,7 @@ public interface MUCRoom extends ChatDeliverer {
* @return The new presence * @return The new presence
* @throws UnauthorizedException If the user doesn't have permission to leave the room * @throws UnauthorizedException If the user doesn't have permission to leave the room
*/ */
Presence createPresence(int presenceStatus) throws UnauthorizedException; Presence createPresence(Presence.Type type) throws UnauthorizedException;
/** /**
* Broadcast a given message to all members of this chat room. The sender is always set to * Broadcast a given message to all members of this chat room. The sender is always set to
...@@ -340,7 +339,7 @@ public interface MUCRoom extends ChatDeliverer { ...@@ -340,7 +339,7 @@ public interface MUCRoom extends ChatDeliverer {
* an existing occupant. * an existing occupant.
* @throws ForbiddenException If the user is not allowed to grant moderator privileges. * @throws ForbiddenException If the user is not allowed to grant moderator privileges.
*/ */
public Presence addModerator(String fullJID, MUCRole senderRole) throws ForbiddenException; public Presence addModerator(JID fullJID, MUCRole senderRole) throws ForbiddenException;
/** /**
* Changes the role of the user within the room to participant. A participant is allowed to send * Changes the role of the user within the room to participant. A participant is allowed to send
...@@ -355,7 +354,7 @@ public interface MUCRoom extends ChatDeliverer { ...@@ -355,7 +354,7 @@ public interface MUCRoom extends ChatDeliverer {
* @throws NotAllowedException If trying to change the moderator role to an owner or an admin. * @throws NotAllowedException If trying to change the moderator role to an owner or an admin.
* @throws ForbiddenException If the user is not allowed to grant participant privileges. * @throws ForbiddenException If the user is not allowed to grant participant privileges.
*/ */
public Presence addParticipant(String fullJID, String reason, MUCRole senderRole) public Presence addParticipant(JID fullJID, String reason, MUCRole senderRole)
throws NotAllowedException, ForbiddenException; throws NotAllowedException, ForbiddenException;
/** /**
...@@ -363,14 +362,14 @@ public interface MUCRoom extends ChatDeliverer { ...@@ -363,14 +362,14 @@ public interface MUCRoom extends ChatDeliverer {
* is not allowed to send messages to the room (i.e. does not has voice) and may invite others * is not allowed to send messages to the room (i.e. does not has voice) and may invite others
* to the room. * to the room.
* *
* @param fullJID The full JID of the occupant to change to visitor. * @param jid the full JID of the occupant to change to visitor.
* @param senderRole The role of the user that is changing the role to visitor. * @param senderRole the role of the user that is changing the role to visitor.
* @return the updated presence of the occupant or <tt>null</tt> if the JID does not belong to * @return the updated presence of the occupant or <tt>null</tt> if the JID does not belong to
* an existing occupant. * an existing occupant.
* @throws NotAllowedException If trying to change the moderator role to an owner or an admin. * @throws NotAllowedException if trying to change the moderator role to an owner or an admin.
* @throws ForbiddenException If the user is not a moderator. * @throws ForbiddenException if the user is not a moderator.
*/ */
public Presence addVisitor(String fullJID, MUCRole senderRole) throws NotAllowedException, public Presence addVisitor(JID jid, MUCRole senderRole) throws NotAllowedException,
ForbiddenException; ForbiddenException;
/** /**
...@@ -449,7 +448,7 @@ public interface MUCRoom extends ChatDeliverer { ...@@ -449,7 +448,7 @@ public interface MUCRoom extends ChatDeliverer {
* @return the updated presence of the kicked user or null if the user was not in the room. * @return the updated presence of the kicked user or null if the user was not in the room.
* @throws NotAllowedException Thrown if trying to ban an owner or an administrator. * @throws NotAllowedException Thrown if trying to ban an owner or an administrator.
*/ */
public Presence kickOccupant(String fullJID, String actorJID, String reason) public Presence kickOccupant(JID fullJID, JID actorJID, String reason)
throws NotAllowedException; throws NotAllowedException;
public IQOwnerHandler getIQOwnerHandler(); public IQOwnerHandler getIQOwnerHandler();
...@@ -785,13 +784,12 @@ public interface MUCRoom extends ChatDeliverer { ...@@ -785,13 +784,12 @@ public interface MUCRoom extends ChatDeliverer {
* need the originating session so that the offline strategy could potentially bounce the * need the originating session so that the offline strategy could potentially bounce the
* message with the invitation. * message with the invitation.
* *
* @param to the bare JID of the user that is being invited. * @param to the JID of the user that is being invited.
* @param reason the reason of the invitation or null if none. * @param reason the reason of the invitation or null if none.
* @param role the role of the occupant that sent the invitation. * @param role the role of the occupant that sent the invitation.
* @param session the originating session that the occupant used for sending the invitation.
* @throws ForbiddenException If the user is not allowed to send the invitation. * @throws ForbiddenException If the user is not allowed to send the invitation.
*/ */
public void sendInvitation(String to, String reason, MUCRole role, Session session) public void sendInvitation(JID to, String reason, MUCRole role)
throws ForbiddenException; throws ForbiddenException;
/** /**
...@@ -801,11 +799,9 @@ public interface MUCRoom extends ChatDeliverer { ...@@ -801,11 +799,9 @@ public interface MUCRoom extends ChatDeliverer {
* moment we need the originating session so that the offline strategy could potentially bounce * moment we need the originating session so that the offline strategy could potentially bounce
* the message with the rejection. * the message with the rejection.
* *
* @param to the bare JID of the user that is originated the invitation. * @param to the JID of the user that is originated the invitation.
* @param reason the reason for the rejection or null if none. * @param reason the reason for the rejection or null if none.
* @param sender the address of the invitee that is rejecting the invitation. * @param from the JID of the invitee that is rejecting the invitation.
* @param session the originating session that the invitee used for rejecting the invitation.
*/ */
public void sendInvitationRejection(String to, String reason, XMPPAddress sender, public void sendInvitationRejection(JID to, String reason, JID from);
Session session);
} }
\ No newline at end of file
...@@ -17,11 +17,10 @@ import java.util.Iterator; ...@@ -17,11 +17,10 @@ import java.util.Iterator;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.TimeZone; import java.util.TimeZone;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.MetaDataFragment;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.spi.MessageImpl;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.Message;
import org.xmpp.packet.JID;
import org.dom4j.Element;
/** /**
* Represent the data model for one <code>MUCRoom</code> history. Including chat transcript, * Represent the data model for one <code>MUCRoom</code> history. Including chat transcript,
...@@ -51,16 +50,12 @@ public final class MUCRoomHistory { ...@@ -51,16 +50,12 @@ public final class MUCRoomHistory {
public void addMessage(Message packet) { public void addMessage(Message packet) {
// Don't keep messages whose sender is the room itself (thus address without resource) // Don't keep messages whose sender is the room itself (thus address without resource)
// unless the message is changing the room's subject // unless the message is changing the room's subject
if ((packet.getSender().getResourcePrep() == null if ((packet.getFrom() == null
|| packet.getSender().getResourcePrep().length() == 0) && || packet.getFrom().toString().length() == 0) &&
packet.getSubject() == null) { packet.getSubject() == null) {
return; return;
} }
Message packetToAdd = (Message) packet.createDeepCopy(); Message packetToAdd = (Message) packet.createCopy();
// Clean the originating session of this message. We will need to deliver this message even
// after the user that sent it has logged off. Otherwise, it won't be delivered since
// messenger expects senders of messages to be authenticated when delivering their messages.
packetToAdd.setOriginatingSession(null);
// TODO Analyze concurrency (on the LinkList) when adding many messages simultaneously // TODO Analyze concurrency (on the LinkList) when adding many messages simultaneously
...@@ -69,47 +64,46 @@ public final class MUCRoomHistory { ...@@ -69,47 +64,46 @@ public final class MUCRoomHistory {
isNonAnonymousRoom = room.canAnyoneDiscoverJID(); isNonAnonymousRoom = room.canAnyoneDiscoverJID();
// Update the "from" attribute of the delay information in the history // Update the "from" attribute of the delay information in the history
Message message; Message message;
MetaDataFragment frag; Element delayElement;
// TODO Make this update in a separate thread // TODO Make this update in a separate thread
for (Iterator it = getMessageHistory(); it.hasNext();) { for (Iterator it = getMessageHistory(); it.hasNext();) {
message = (Message) it.next(); message = (Message) it.next();
frag = (MetaDataFragment) message.getFragment("x", "jabber:x:delay"); delayElement = message.getChildElement("x", "jabber:x:delay");
if (room.canAnyoneDiscoverJID()) { if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute // Set the Full JID as the "from" attribute
try { try {
MUCRole role = room.getOccupant(message.getSender().getResourcePrep()); MUCRole role = room.getOccupant(message.getFrom().getResource());
frag.setProperty("x:from", role.getChatUser().getAddress().toStringPrep()); delayElement.addAttribute("from", role.getChatUser().getAddress().toString());
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
} }
} }
else { else {
// Set the Room JID as the "from" attribute // Set the Room JID as the "from" attribute
frag.setProperty("x:from", message.getSender().toStringPrep()); delayElement.addAttribute("from", message.getFrom().toString());
} }
} }
} }
// Add the delay information to the message // Add the delay information to the message
MetaDataFragment delayInformation = new MetaDataFragment("jabber:x:delay", "x"); Element delayInformation = packetToAdd.addChildElement("x", "jabber:x:delay");
Date current = new Date(); Date current = new Date();
delayInformation.setProperty("x:stamp", UTC_FORMAT.format(current)); delayInformation.addAttribute("stamp", UTC_FORMAT.format(current));
if (room.canAnyoneDiscoverJID()) { if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute // Set the Full JID as the "from" attribute
try { try {
MUCRole role = room.getOccupant(packet.getSender().getResourcePrep()); MUCRole role = room.getOccupant(packet.getFrom().getResource());
delayInformation.setProperty("x:from", role.getChatUser().getAddress() delayInformation.addAttribute("from", role.getChatUser().getAddress()
.toStringPrep()); .toString());
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
} }
} }
else { else {
// Set the Room JID as the "from" attribute // Set the Room JID as the "from" attribute
delayInformation.setProperty("x:from", packet.getSender().toStringPrep()); delayInformation.addAttribute("from", packet.getFrom().toString());
} }
packetToAdd.addFragment(delayInformation);
historyStrategy.addMessage(packetToAdd); historyStrategy.addMessage(packetToAdd);
} }
...@@ -140,36 +134,36 @@ public final class MUCRoomHistory { ...@@ -140,36 +134,36 @@ public final class MUCRoomHistory {
* @param body the body of the message. * @param body the body of the message.
*/ */
public void addOldMessage(String senderJID, String nickname, Date sentDate, String subject, public void addOldMessage(String senderJID, String nickname, Date sentDate, String subject,
String body) { String body)
Message packetToAdd = new MessageImpl(); {
packetToAdd.setType(Message.GROUP_CHAT); Message message = new Message();
packetToAdd.setSubject(subject); message.setType(Message.Type.groupchat);
packetToAdd.setBody(body); message.setSubject(subject);
message.setBody(body);
// Set the sender of the message // Set the sender of the message
if (nickname != null && nickname.trim().length() > 0) { if (nickname != null && nickname.trim().length() > 0) {
XMPPAddress roomJID = room.getRole().getRoleAddress(); JID roomJID = room.getRole().getRoleAddress();
// Recreate the sender address based on the nickname and room's JID // Recreate the sender address based on the nickname and room's JID
packetToAdd.setSender(new XMPPAddress(roomJID.getNamePrep(), roomJID.getHostPrep(), message.setFrom(new JID(roomJID.getNode(), roomJID.getDomain(),
nickname)); nickname));
} }
else { else {
// Set the room as the sender of the message // Set the room as the sender of the message
packetToAdd.setSender(room.getRole().getRoleAddress()); message.setFrom(room.getRole().getRoleAddress());
} }
// Add the delay information to the message // Add the delay information to the message
MetaDataFragment delayInformation = new MetaDataFragment("jabber:x:delay", "x"); Element delayInformation = message.addChildElement("x", "jabber:x:deley");
delayInformation.setProperty("x:stamp", UTC_FORMAT.format(sentDate)); delayInformation.addAttribute("stamp", UTC_FORMAT.format(sentDate));
if (room.canAnyoneDiscoverJID()) { if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute // Set the Full JID as the "from" attribute
delayInformation.setProperty("x:from", senderJID); delayInformation.addAttribute("from", senderJID);
} }
else { else {
// Set the Room JID as the "from" attribute // Set the Room JID as the "from" attribute
delayInformation.setProperty("x:from", room.getRole().getRoleAddress().toStringPrep()); delayInformation.addAttribute("from", room.getRole().getRoleAddress().toString());
} }
packetToAdd.addFragment(delayInformation); historyStrategy.addMessage(message);
historyStrategy.addMessage(packetToAdd);
} }
/** /**
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
package org.jivesoftware.messenger.muc; package org.jivesoftware.messenger.muc;
import org.jivesoftware.util.NotFoundException; import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.ChannelHandler; import org.jivesoftware.messenger.ChannelHandler;
import org.xmpp.packet.JID;
import java.util.Iterator; import java.util.Iterator;
...@@ -47,7 +47,7 @@ public interface MUCUser extends ChannelHandler { ...@@ -47,7 +47,7 @@ public interface MUCUser extends ChannelHandler {
* *
* @return the address of the packet handler. * @return the address of the packet handler.
*/ */
public XMPPAddress getAddress(); public JID getAddress();
/** /**
* Obtain the role of the user in a particular room. * Obtain the role of the user in a particular room.
......
...@@ -16,7 +16,8 @@ import java.util.Collection; ...@@ -16,7 +16,8 @@ import java.util.Collection;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.messenger.*; import org.xmpp.packet.Message;
import org.xmpp.packet.JID;
/** /**
* Manages groupchat conversations, chatrooms, and users. This class is designed to operate * Manages groupchat conversations, chatrooms, and users. This class is designed to operate
...@@ -192,7 +193,7 @@ public interface MultiUserChatServer { ...@@ -192,7 +193,7 @@ public interface MultiUserChatServer {
* @return The chatroom for the given name. * @return The chatroom for the given name.
* @throws UnauthorizedException If the caller doesn't have permission to create a new room. * @throws UnauthorizedException If the caller doesn't have permission to create a new room.
*/ */
MUCRoom getChatRoom(String roomName, XMPPAddress userjid) throws UnauthorizedException; MUCRoom getChatRoom(String roomName, JID userjid) throws UnauthorizedException;
/** /**
* Obtains a chatroom by name. If the chatroom does not exists then null will be returned. * Obtains a chatroom by name. If the chatroom does not exists then null will be returned.
...@@ -230,7 +231,7 @@ public interface MultiUserChatServer { ...@@ -230,7 +231,7 @@ public interface MultiUserChatServer {
* *
* @param jabberID The user's normal jid, not the chat nickname jid. * @param jabberID The user's normal jid, not the chat nickname jid.
*/ */
void removeUser(XMPPAddress jabberID); void removeUser(JID jabberID);
/** /**
* Obtain a chat user by XMPPAddress. * Obtain a chat user by XMPPAddress.
...@@ -239,7 +240,7 @@ public interface MultiUserChatServer { ...@@ -239,7 +240,7 @@ public interface MultiUserChatServer {
* @return The chatuser corresponding to that XMPPAddress. * @return The chatuser corresponding to that XMPPAddress.
* @throws UserNotFoundException If the user is not found and can't be auto-created. * @throws UserNotFoundException If the user is not found and can't be auto-created.
*/ */
MUCUser getChatUser(XMPPAddress userjid) throws UserNotFoundException; MUCUser getChatUser(JID userjid) throws UserNotFoundException;
/** /**
* Broadcast a given message to all members of this chat room. The sender is always set to be * Broadcast a given message to all members of this chat room. The sender is always set to be
...@@ -271,5 +272,5 @@ public interface MultiUserChatServer { ...@@ -271,5 +272,5 @@ public interface MultiUserChatServer {
* @param message the message to log as part of the conversation in the room. * @param message the message to log as part of the conversation in the room.
* @param sender the real XMPPAddress of the sender (e.g. john@example.org). * @param sender the real XMPPAddress of the sender (e.g. john@example.org).
*/ */
void logConversation(MUCRoom room, Message message, XMPPAddress sender); void logConversation(MUCRoom room, Message message, JID sender);
} }
\ No newline at end of file
...@@ -14,8 +14,8 @@ package org.jivesoftware.messenger.muc.spi; ...@@ -14,8 +14,8 @@ package org.jivesoftware.messenger.muc.spi;
import java.util.Date; import java.util.Date;
import org.jivesoftware.messenger.muc.MUCRoom; import org.jivesoftware.messenger.muc.MUCRoom;
import org.jivesoftware.messenger.Message; import org.xmpp.packet.Message;
import org.jivesoftware.messenger.XMPPAddress; import org.xmpp.packet.JID;
/** /**
* Represents an entry in the conversation log of a room. An entry basically obtains the necessary * Represents an entry in the conversation log of a room. An entry basically obtains the necessary
...@@ -31,7 +31,7 @@ class ConversationLogEntry { ...@@ -31,7 +31,7 @@ class ConversationLogEntry {
private String body; private String body;
private XMPPAddress sender; private JID sender;
private String nickname; private String nickname;
...@@ -46,13 +46,13 @@ class ConversationLogEntry { ...@@ -46,13 +46,13 @@ class ConversationLogEntry {
* @param message the message to log as part of the conversation in the room. * @param message the message to log as part of the conversation in the room.
* @param sender the real XMPPAddress of the sender (e.g. john@example.org). * @param sender the real XMPPAddress of the sender (e.g. john@example.org).
*/ */
public ConversationLogEntry(Date date, MUCRoom room, Message message, XMPPAddress sender) { public ConversationLogEntry(Date date, MUCRoom room, Message message, JID sender) {
this.date = date; this.date = date;
this.subject = message.getSubject(); this.subject = message.getSubject();
this.body = message.getBody(); this.body = message.getBody();
this.sender = sender; this.sender = sender;
this.roomID = room.getID(); this.roomID = room.getID();
this.nickname = message.getSender().getResourcePrep(); this.nickname = message.getFrom().getResource();
} }
/** /**
...@@ -69,7 +69,7 @@ class ConversationLogEntry { ...@@ -69,7 +69,7 @@ class ConversationLogEntry {
* *
* @return the XMPP address of the logged message's sender. * @return the XMPP address of the logged message's sender.
*/ */
public XMPPAddress getSender() { public JID getSender() {
return sender; return sender;
} }
......
...@@ -12,15 +12,15 @@ ...@@ -12,15 +12,15 @@
package org.jivesoftware.messenger.muc.spi; package org.jivesoftware.messenger.muc.spi;
import org.jivesoftware.messenger.muc.*; import org.jivesoftware.messenger.muc.*;
import org.jivesoftware.messenger.IQ;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.MetaDataFragment;
import org.jivesoftware.messenger.PacketRouter; import org.jivesoftware.messenger.PacketRouter;
import org.jivesoftware.messenger.Presence;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.IQ;
import org.dom4j.Element;
/** /**
* Simple in-memory implementation of a role in a chatroom * Simple in-memory implementation of a role in a chatroom
...@@ -73,12 +73,12 @@ public class MUCRoleImpl implements MUCRole { ...@@ -73,12 +73,12 @@ public class MUCRoleImpl implements MUCRole {
/** /**
* The address of the person masquerading in this role. * The address of the person masquerading in this role.
*/ */
private XMPPAddress rJID; private JID rJID;
/** /**
* A fragment containing the x-extension for non-anonymous rooms. * A fragment containing the x-extension for non-anonymous rooms.
*/ */
private MetaDataFragment extendedInformation; private Element extendedInformation;
/** /**
* Create a new role. * Create a new role.
...@@ -93,13 +93,10 @@ public class MUCRoleImpl implements MUCRole { ...@@ -93,13 +93,10 @@ public class MUCRoleImpl implements MUCRole {
* @throws UnauthorizedException if the role could not be created due to security or permission * @throws UnauthorizedException if the role could not be created due to security or permission
* violations * violations
*/ */
public MUCRoleImpl(MultiUserChatServer chatserver, public MUCRoleImpl(MultiUserChatServer chatserver, MUCRoomImpl chatroom,
MUCRoomImpl chatroom, String nickname, int role, int affiliation, MUCUserImpl chatuser,
String nickname, PacketRouter packetRouter) throws UnauthorizedException
int role, {
int affiliation,
MUCUserImpl chatuser,
PacketRouter packetRouter) throws UnauthorizedException {
this.room = chatroom; this.room = chatroom;
this.nick = nickname; this.nick = nickname;
this.user = chatuser; this.user = chatuser;
...@@ -109,22 +106,22 @@ public class MUCRoleImpl implements MUCRole { ...@@ -109,22 +106,22 @@ public class MUCRoleImpl implements MUCRole {
this.affiliation = affiliation; this.affiliation = affiliation;
extendedInformation = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x"); extendedInformation = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x");
calculateExtendedInformation(); calculateExtendedInformation();
rJID = new XMPPAddress(room.getName(), server.getServiceName(), nick); rJID = new JID(room.getName(), server.getServiceName(), nick);
setPresence(room.createPresence(Presence.STATUS_ONLINE)); setPresence(room.createPresence(null));
} }
public Presence getPresence() { public Presence getPresence() {
return presence; return presence;
} }
public MetaDataFragment getExtendedPresenceInformation() { public Element getExtendedPresenceInformation() {
return extendedInformation; return extendedInformation;
} }
public void setPresence(Presence newPresence) { public void setPresence(Presence newPresence) {
this.presence = newPresence; this.presence = newPresence;
if (extendedInformation != null) { if (extendedInformation != null) {
presence.addFragment(extendedInformation); presence.getElement().add(extendedInformation.createCopy());
} }
} }
...@@ -144,13 +141,7 @@ public class MUCRoleImpl implements MUCRole { ...@@ -144,13 +141,7 @@ public class MUCRoleImpl implements MUCRole {
role = newRole; role = newRole;
if (MUCRole.NONE_ROLE == role) { if (MUCRole.NONE_ROLE == role) {
try { presence.setType(Presence.Type.unavailable);
presence.setAvailable(false);
presence.setVisible(false);
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
} }
calculateExtendedInformation(); calculateExtendedInformation();
} }
...@@ -214,7 +205,7 @@ public class MUCRoleImpl implements MUCRole { ...@@ -214,7 +205,7 @@ public class MUCRoleImpl implements MUCRole {
public void changeNickname(String nickname) { public void changeNickname(String nickname) {
this.nick = nickname; this.nick = nickname;
rJID = new XMPPAddress(room.getName(), server.getServiceName(), nick); rJID = new JID(room.getName(), server.getServiceName(), nick);
} }
public MUCUser getChatUser() { public MUCUser getChatUser() {
...@@ -225,30 +216,31 @@ public class MUCRoleImpl implements MUCRole { ...@@ -225,30 +216,31 @@ public class MUCRoleImpl implements MUCRole {
return room; return room;
} }
public XMPPAddress getRoleAddress() { public JID getRoleAddress() {
return rJID; return rJID;
} }
public void send(Presence packet) { public void send(Presence packet) {
packet.setRecipient(user.getAddress()); packet.setTo(user.getAddress());
router.route(packet); router.route(packet);
} }
public void send(Message packet) { public void send(Message packet) {
packet.setRecipient(user.getAddress()); packet.setTo(user.getAddress());
router.route(packet); router.route(packet);
} }
public void send(IQ packet) { public void send(IQ packet) {
packet.setRecipient(user.getAddress()); packet.setTo(user.getAddress());
router.route(packet); router.route(packet);
} }
/** /**
* Calculates and sets the extended presence information to add to the presence. The information * Calculates and sets the extended presence information to add to the presence.
* to add contains the user's jid, affiliation and role. * The information to add contains the user's jid, affiliation and role.
*/ */
private void calculateExtendedInformation() { private void calculateExtendedInformation() {
extendedInformation.setProperty("x.item:jid", user.getAddress().toString()); extendedInformation.setProperty("x.item:jid", user.getAddress().toString());
extendedInformation.setProperty("x.item:affiliation", getAffiliationAsString()); extendedInformation.setProperty("x.item:affiliation", getAffiliationAsString());
extendedInformation.setProperty("x.item:role", getRoleAsString()); extendedInformation.setProperty("x.item:role", getRoleAsString());
......
...@@ -22,10 +22,10 @@ import org.jivesoftware.messenger.muc.*; ...@@ -22,10 +22,10 @@ import org.jivesoftware.messenger.muc.*;
import org.jivesoftware.util.*; import org.jivesoftware.util.*;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.spi.MessageImpl;
import org.jivesoftware.messenger.spi.PresenceImpl;
import org.jivesoftware.messenger.user.UserAlreadyExistsException; import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.*;
import org.dom4j.Element;
/** /**
* Simple in-memory implementation of a chatroom. A MUCRoomImpl could represent a persistent room * Simple in-memory implementation of a chatroom. A MUCRoomImpl could represent a persistent room
...@@ -62,7 +62,7 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -62,7 +62,7 @@ public class MUCRoomImpl implements MUCRoom {
/** /**
* The occupants of the room accessible by the occupants full JID. * The occupants of the room accessible by the occupants full JID.
*/ */
private Map<String, MUCRole> occupantsByFullJID = new ConcurrentHashMap<String, MUCRole>(); private Map<JID, MUCRole> occupantsByFullJID = new ConcurrentHashMap<JID, MUCRole>();
/** /**
* The name of the room. * The name of the room.
...@@ -392,7 +392,7 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -392,7 +392,7 @@ public class MUCRoomImpl implements MUCRoom {
if (isDestroyed || (getMaxUsers() > 0 && getOccupantsCount() >= getMaxUsers())) { if (isDestroyed || (getMaxUsers() > 0 && getOccupantsCount() >= getMaxUsers())) {
throw new NotAllowedException(); throw new NotAllowedException();
} }
boolean isOwner = owners.contains(user.getAddress().toBareStringPrep()); boolean isOwner = owners.contains(user.getAddress().toBareJID());
// If the room is locked and this user is not an owner raise a RoomLocked exception // If the room is locked and this user is not an owner raise a RoomLocked exception
if (roomLocked) { if (roomLocked) {
if (!isOwner) { if (!isOwner) {
...@@ -413,7 +413,7 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -413,7 +413,7 @@ public class MUCRoomImpl implements MUCRoom {
// If another user attempts to join the room with a nickname reserved by the first user // If another user attempts to join the room with a nickname reserved by the first user
// raise a ConflictException // raise a ConflictException
if (members.containsValue(nickname)) { if (members.containsValue(nickname)) {
if (!nickname.equals(members.get(user.getAddress().toBareStringPrep()))) { if (!nickname.equals(members.get(user.getAddress().toBareJID()))) {
throw new ConflictException(); throw new ConflictException();
} }
} }
...@@ -426,23 +426,23 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -426,23 +426,23 @@ public class MUCRoomImpl implements MUCRoom {
role = MUCRole.MODERATOR; role = MUCRole.MODERATOR;
affiliation = MUCRole.OWNER; affiliation = MUCRole.OWNER;
} }
else if (server.getSysadmins().contains(user.getAddress().toBareStringPrep())) { else if (server.getSysadmins().contains(user.getAddress().toBareJID())) {
// The user is a system administrator of the MUC service. Treat him as an owner // The user is a system administrator of the MUC service. Treat him as an owner
// although he won't appear in the list of owners // although he won't appear in the list of owners
role = MUCRole.MODERATOR; role = MUCRole.MODERATOR;
affiliation = MUCRole.OWNER; affiliation = MUCRole.OWNER;
} }
else if (admins.contains(user.getAddress().toBareStringPrep())) { else if (admins.contains(user.getAddress().toBareJID())) {
// The user is an admin. Set the role and affiliation accordingly. // The user is an admin. Set the role and affiliation accordingly.
role = MUCRole.MODERATOR; role = MUCRole.MODERATOR;
affiliation = MUCRole.ADMINISTRATOR; affiliation = MUCRole.ADMINISTRATOR;
} }
else if (members.containsKey(user.getAddress().toBareStringPrep())) { else if (members.containsKey(user.getAddress().toBareJID())) {
// The user is a member. Set the role and affiliation accordingly. // The user is a member. Set the role and affiliation accordingly.
role = MUCRole.PARTICIPANT; role = MUCRole.PARTICIPANT;
affiliation = MUCRole.MEMBER; affiliation = MUCRole.MEMBER;
} }
else if (outcasts.contains(user.getAddress().toBareStringPrep())) { else if (outcasts.contains(user.getAddress().toBareJID())) {
// The user is an outcast. Raise a "Forbidden" exception. // The user is an outcast. Raise a "Forbidden" exception.
throw new ForbiddenException(); throw new ForbiddenException();
} }
...@@ -463,28 +463,28 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -463,28 +463,28 @@ public class MUCRoomImpl implements MUCRoom {
// Send presence of existing occupants to new occupant // Send presence of existing occupants to new occupant
for (MUCRole occupantsRole : occupants.values()) { for (MUCRole occupantsRole : occupants.values()) {
Presence occupantsPresence = (Presence) occupantsRole.getPresence() Presence occupantsPresence = (Presence) occupantsRole.getPresence()
.createDeepCopy(); .createCopy();
occupantsPresence.setSender(occupantsRole.getRoleAddress()); occupantsPresence.setFrom(occupantsRole.getRoleAddress());
// Don't include the occupant's JID if the room is semi-anon and the new occupant // Don't include the occupant's JID if the room is semi-anon and the new occupant
// is not a moderator // is not a moderator
if (!canAnyoneDiscoverJID() && MUCRole.MODERATOR != joinRole.getRole()) { if (!canAnyoneDiscoverJID() && MUCRole.MODERATOR != joinRole.getRole()) {
MetaDataFragment frag = (MetaDataFragment) occupantsPresence.getFragment( Element frag = occupantsPresence.getChildElement(
"x", "x",
"http://jabber.org/protocol/muc#user"); "http://jabber.org/protocol/muc#user");
frag.deleteProperty("x.item:jid"); frag.element("item").addAttribute("jid", null);
} }
joinRole.send(occupantsPresence); joinRole.send(occupantsPresence);
} }
// Add the new user as an occupant of this room // Add the new user as an occupant of this room
occupants.put(nickname.toLowerCase(), joinRole); occupants.put(nickname.toLowerCase(), joinRole);
// Update the tables of occupants based on the bare and full JID // Update the tables of occupants based on the bare and full JID
List<MUCRole> list = occupantsByBareJID.get(user.getAddress().toBareStringPrep()); List<MUCRole> list = occupantsByBareJID.get(user.getAddress().toBareJID());
if (list == null) { if (list == null) {
list = new ArrayList<MUCRole>(); list = new ArrayList<MUCRole>();
occupantsByBareJID.put(user.getAddress().toBareStringPrep(), list); occupantsByBareJID.put(user.getAddress().toBareJID(), list);
} }
list.add(joinRole); list.add(joinRole);
occupantsByFullJID.put(user.getAddress().toStringPrep(), joinRole); occupantsByFullJID.put(user.getAddress(), joinRole);
} }
finally { finally {
lock.writeLock().unlock(); lock.writeLock().unlock();
...@@ -497,14 +497,13 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -497,14 +497,13 @@ public class MUCRoomImpl implements MUCRoom {
params.add(nickname); params.add(nickname);
try { try {
// Send the presence of this new occupant to existing occupants // Send the presence of this new occupant to existing occupants
Presence joinPresence = (Presence) joinRole.getPresence().createDeepCopy(); Presence joinPresence = joinRole.getPresence().createCopy();
if (isRoomNew) { if (isRoomNew) {
MetaDataFragment frag = (MetaDataFragment) joinPresence.getFragment( Element frag = joinPresence.getChildElement(
"x", "x", "http://jabber.org/protocol/muc#user");
"http://jabber.org/protocol/muc#user"); frag.element("status").addAttribute("code", "201");
frag.setProperty("x.status:code", "201");
} }
joinPresence.setSender(joinRole.getRoleAddress()); joinPresence.setFrom(joinRole.getRoleAddress());
broadcastPresence(joinPresence); broadcastPresence(joinPresence);
} }
...@@ -518,25 +517,23 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -518,25 +517,23 @@ public class MUCRoomImpl implements MUCRoom {
// If the room has just been created send the "room locked until configuration is // If the room has just been created send the "room locked until configuration is
// confirmed" message // confirmed" message
if (isRoomNew) { if (isRoomNew) {
Message message = new MessageImpl(); Message message = new Message();
message.setType(Message.GROUP_CHAT); message.setType(Message.Type.groupchat);
message.setBody(LocaleUtils.getLocalizedString("muc.locked")); message.setBody(LocaleUtils.getLocalizedString("muc.locked"));
message.setSender(role.getRoleAddress()); message.setFrom(role.getRoleAddress());
message.setRecipient(user.getAddress()); message.setTo(user.getAddress());
router.route(message); router.route(message);
} }
else if (canAnyoneDiscoverJID()) { else if (canAnyoneDiscoverJID()) {
// Warn the new occupant that the room is non-anonymous (i.e. his JID will be // Warn the new occupant that the room is non-anonymous (i.e. his JID will be
// public) // public)
Message message = new MessageImpl(); Message message = new Message();
message.setType(Message.GROUP_CHAT); message.setType(Message.Type.groupchat);
message.setBody(LocaleUtils.getLocalizedString("muc.warnnonanonymous")); message.setBody(LocaleUtils.getLocalizedString("muc.warnnonanonymous"));
message.setSender(role.getRoleAddress()); message.setFrom(role.getRoleAddress());
message.setRecipient(user.getAddress()); message.setTo(user.getAddress());
MetaDataFragment frag = new MetaDataFragment("http://jabber.org/protocol/muc#user", Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
"x"); frag.addElement("status").addAttribute("code", "100");
frag.setProperty("x.status:code", "100");
message.addFragment(frag);
router.route(message); router.route(message);
} }
if (historyRequest == null) { if (historyRequest == null) {
...@@ -584,10 +581,10 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -584,10 +581,10 @@ public class MUCRoomImpl implements MUCRoom {
if (leaveRole != null) { if (leaveRole != null) {
try { try {
Presence presence = createPresence(Presence.STATUS_OFFLINE); Presence presence = createPresence(Presence.Type.unavailable);
presence.setSender(leaveRole.getRoleAddress()); presence.setFrom(leaveRole.getRoleAddress());
presence.addFragment(leaveRole.getExtendedPresenceInformation()); presence.getElement().add(leaveRole.getExtendedPresenceInformation().createCopy());
broadcastPresence((Presence) presence.createDeepCopy()); broadcastPresence(presence.createCopy());
leaveRole.kick(); leaveRole.kick();
List params = new ArrayList(); List params = new ArrayList();
params.add(nickname); params.add(nickname);
...@@ -610,14 +607,14 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -610,14 +607,14 @@ public class MUCRoomImpl implements MUCRoom {
MUCUser user = leaveRole.getChatUser(); MUCUser user = leaveRole.getChatUser();
// Update the tables of occupants based on the bare and full JID // Update the tables of occupants based on the bare and full JID
List list = occupantsByBareJID.get(user.getAddress().toBareStringPrep()); List list = occupantsByBareJID.get(user.getAddress().toBareJID());
if (list != null) { if (list != null) {
list.remove(leaveRole); list.remove(leaveRole);
if (list.isEmpty()) { if (list.isEmpty()) {
occupantsByBareJID.remove(user.getAddress().toBareStringPrep()); occupantsByBareJID.remove(user.getAddress().toBareJID());
} }
} }
occupantsByFullJID.remove(user.getAddress().toStringPrep()); occupantsByFullJID.remove(user.getAddress().toString());
} }
public void destroyRoom(String alternateJID, String reason) { public void destroyRoom(String alternateJID, String reason) {
...@@ -631,24 +628,32 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -631,24 +628,32 @@ public class MUCRoomImpl implements MUCRoom {
if (leaveRole != null) { if (leaveRole != null) {
try { try {
// Send a presence stanza of type "unavailable" to the occupant // Send a presence stanza of type "unavailable" to the occupant
Presence presence = createPresence(Presence.STATUS_OFFLINE); Presence presence = createPresence(Presence.Type.unavailable);
presence.setSender(leaveRole.getRoleAddress()); presence.setFrom(leaveRole.getRoleAddress());
presence.setRecipient(leaveRole.getChatUser().getAddress()); presence.setTo(leaveRole.getChatUser().getAddress());
// A fragment containing the x-extension for room destruction. // A fragment containing the x-extension for room destruction.
// TODO Analyze if we need/can reuse the same fragment instead of creating a // TODO Analyze if we need/can reuse the same fragment instead of creating a
// new one each time // new one each time
MetaDataFragment fragment; Element fragment;
fragment = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x"); fragment = presence.addChildElement("x", "http://jabber.org/protocol/muc#user");
fragment.setProperty("x.item:affiliation", "none"); Element item = fragment.addElement("item");
fragment.setProperty("x.item:role", "none"); item.addAttribute("affiliation", "none");
item.addAttribute("role", "none");
if (alternateJID != null && alternateJID.length() > 0) { if (alternateJID != null && alternateJID.length() > 0) {
fragment.setProperty("x.destroy:jid", alternateJID); fragment.addElement("destroy").addAttribute("jid", alternateJID);
} }
if (reason != null && reason.length() > 0) { if (reason != null && reason.length() > 0) {
fragment.setProperty("x.destroy.reason", reason); Element destroy = fragment.element("destroy");
if (destroy == null) {
destroy = fragment.addElement("destroy");
}
Element reasonEl = destroy.element("reason");
if (reasonEl == null) {
reasonEl = destroy.addElement("reason");
}
reasonEl.setText(reason);
} }
presence.addFragment(fragment);
router.route(presence); router.route(presence);
leaveRole.kick(); leaveRole.kick();
...@@ -670,28 +675,18 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -670,28 +675,18 @@ public class MUCRoomImpl implements MUCRoom {
} }
} }
public Presence createPresence(int presenceStatus) throws UnauthorizedException { public Presence createPresence(Presence.Type presenceType) throws UnauthorizedException {
Presence presence = new PresenceImpl(); Presence presence = new Presence();
presence.setSender(role.getRoleAddress()); presence.setType(presenceType);
switch (presenceStatus) { presence.setFrom(role.getRoleAddress());
case Presence.STATUS_ONLINE:
presence.setAvailable(true);
presence.setVisible(true);
break;
case Presence.STATUS_OFFLINE:
presence.setAvailable(false);
presence.setVisible(false);
break;
default:
}
return presence; return presence;
} }
public void serverBroadcast(String msg) { public void serverBroadcast(String msg) {
Message message = new MessageImpl(); Message message = new Message();
message.setType(Message.GROUP_CHAT); message.setType(Message.Type.groupchat);
message.setBody(msg); message.setBody(msg);
message.setSender(role.getRoleAddress()); message.setFrom(role.getRoleAddress());
roomHistory.addMessage(message); roomHistory.addMessage(message);
broadcast(message); broadcast(message);
} }
...@@ -702,16 +697,16 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -702,16 +697,16 @@ public class MUCRoomImpl implements MUCRoom {
throw new ForbiddenException(); throw new ForbiddenException();
} }
// Send the message to all occupants // Send the message to all occupants
message.setSender(senderRole.getRoleAddress()); message.setFrom(senderRole.getRoleAddress());
send(message); send(message);
} }
public void sendPrivateMessage(Message message, MUCRole senderRole) throws NotFoundException { public void sendPrivateMessage(Message message, MUCRole senderRole) throws NotFoundException {
String resource = message.getRecipient().getResource(); String resource = message.setTo().getResource();
MUCRole occupant = occupants.get(resource.toLowerCase()); MUCRole occupant = occupants.get(resource.toLowerCase());
if (occupant != null) { if (occupant != null) {
message.setSender(senderRole.getRoleAddress()); message.setFrom(senderRole.getRoleAddress());
message.setRecipient(occupant.getChatUser().getAddress()); message.setTo(occupant.getChatUser().getAddress());
router.route(message); router.route(message);
} }
else { else {
...@@ -730,10 +725,10 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -730,10 +725,10 @@ public class MUCRoomImpl implements MUCRoom {
} }
public void send(IQ packet) { public void send(IQ packet) {
packet = (IQ) packet.createDeepCopy(); packet = packet.createCopy();
packet.setError(XMPPError.Code.BAD_REQUEST); packet.setError(PacketError.Condition.bad_request);
packet.setRecipient(packet.getSender()); packet.setTo(packet.getFrom());
packet.setSender(role.getRoleAddress()); packet.setFrom(role.getRoleAddress());
router.route(packet); router.route(packet);
} }
...@@ -742,19 +737,17 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -742,19 +737,17 @@ public class MUCRoomImpl implements MUCRoom {
return; return;
} }
MetaDataFragment frag = null; Element frag = null;
String jid = null; String jid = null;
if (hasToCheckRoleToBroadcastPresence()) { if (hasToCheckRoleToBroadcastPresence()) {
frag = (MetaDataFragment) presence.getFragment( frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
"x",
"http://jabber.org/protocol/muc#user");
// Check if we can broadcast the presence for this role // Check if we can broadcast the presence for this role
if (!canBroadcastPresence(frag.getProperty("x.item:role"))) { if (!canBroadcastPresence(frag.element("item").attributeValue("role"))) {
// Just send the presence to the sender of the presence // Just send the presence to the sender of the presence
try { try {
MUCRole occupant = getOccupant(presence.getSender().getResourcePrep()); MUCRole occupant = getOccupant(presence.getFrom().getResource());
presence.setRecipient(occupant.getChatUser().getAddress()); presence.setTo(occupant.getChatUser().getAddress());
router.route(presence); router.route(presence);
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
...@@ -768,22 +761,20 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -768,22 +761,20 @@ public class MUCRoomImpl implements MUCRoom {
// is not a moderator // is not a moderator
if (!canAnyoneDiscoverJID()) { if (!canAnyoneDiscoverJID()) {
if (frag == null) { if (frag == null) {
frag = (MetaDataFragment) presence.getFragment( frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
"x",
"http://jabber.org/protocol/muc#user");
} }
jid = frag.getProperty("x.item:jid"); jid = frag.element("item").attributeValue("jid");
} }
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupants.values()) {
presence.setRecipient(occupant.getChatUser().getAddress()); presence.setTo(occupant.getChatUser().getAddress());
// Don't include the occupant's JID if the room is semi-anon and the new occupant // Don't include the occupant's JID if the room is semi-anon and the new occupant
// is not a moderator // is not a moderator
if (!canAnyoneDiscoverJID()) { if (!canAnyoneDiscoverJID()) {
if (MUCRole.MODERATOR == occupant.getRole()) { if (MUCRole.MODERATOR == occupant.getRole()) {
frag.setProperty("x.item:jid", jid); frag.element("item").addAttribute("jid", jid);
} }
else { else {
frag.deleteProperty("x.item:jid"); frag.element("item").addAttribute("jid", null);
} }
} }
router.route(presence); router.route(presence);
...@@ -794,13 +785,13 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -794,13 +785,13 @@ public class MUCRoomImpl implements MUCRoom {
lock.readLock().lock(); lock.readLock().lock();
try { try {
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupants.values()) {
message.setRecipient(occupant.getChatUser().getAddress()); message.setTo(occupant.getChatUser().getAddress());
router.route(message); router.route(message);
} }
if (isLogEnabled()) { if (isLogEnabled()) {
MUCRole senderRole; MUCRole senderRole;
XMPPAddress senderAddress; JID senderAddress;
senderRole = occupants.get(message.getSender().getResourcePrep()); senderRole = occupants.get(message.getTo().getResource());
if (senderRole == null) { if (senderRole == null) {
// The room itself is sending the message // The room itself is sending the message
senderAddress = getRole().getRoleAddress(); senderAddress = getRole().getRoleAddress();
...@@ -834,7 +825,7 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -834,7 +825,7 @@ public class MUCRoomImpl implements MUCRoom {
return null; return null;
} }
public MetaDataFragment getExtendedPresenceInformation() { public Element getExtendedPresenceInformation() {
return null; return null;
} }
...@@ -878,11 +869,11 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -878,11 +869,11 @@ public class MUCRoomImpl implements MUCRoom {
return room; return room;
} }
private XMPPAddress crJID = null; private JID crJID = null;
public XMPPAddress getRoleAddress() { public JID getRoleAddress() {
if (crJID == null) { if (crJID == null) {
crJID = new XMPPAddress(room.getName(), server.getServiceName(), ""); crJID = new JID(room.getName(), server.getServiceName(), "");
} }
return crJID; return crJID;
} }
...@@ -936,8 +927,8 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -936,8 +927,8 @@ public class MUCRoomImpl implements MUCRoom {
role.setAffiliation(newAffiliation); role.setAffiliation(newAffiliation);
role.setRole(newRole); role.setRole(newRole);
// Prepare a new presence to be sent to all the room occupants // Prepare a new presence to be sent to all the room occupants
Presence presence = (Presence) role.getPresence().createDeepCopy(); Presence presence = role.getPresence().createCopy();
presence.setSender(role.getRoleAddress()); presence.setFrom(role.getRoleAddress());
presences.add(presence); presences.add(presence);
} }
// Answer all the updated presences // Answer all the updated presences
...@@ -948,20 +939,20 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -948,20 +939,20 @@ public class MUCRoomImpl implements MUCRoom {
* Updates the presence of the given user with the new role information. Do nothing if the given * Updates the presence of the given user with the new role information. Do nothing if the given
* jid is not present in the room. * jid is not present in the room.
* *
* @param fullJID the full jid of the user to update his/her role. * @param jid the full jid of the user to update his/her role.
* @param newRole the new role for the JID. * @param newRole the new role for the JID.
* @return the updated presence of the user or null if none. * @return the updated presence of the user or null if none.
* @throws NotAllowedException If trying to change the moderator role to an owner or an admin. * @throws NotAllowedException If trying to change the moderator role to an owner or an admin.
*/ */
private Presence changeOccupantRole(String fullJID, int newRole) throws NotAllowedException { private Presence changeOccupantRole(JID jid, int newRole) throws NotAllowedException {
// Try looking the role in the bare JID list // Try looking the role in the bare JID list
MUCRole role = occupantsByFullJID.get(fullJID); MUCRole role = occupantsByFullJID.get(jid);
if (role != null) { if (role != null) {
// Update the presence with the new role // Update the presence with the new role
role.setRole(newRole); role.setRole(newRole);
// Prepare a new presence to be sent to all the room occupants // Prepare a new presence to be sent to all the room occupants
Presence presence = (Presence) role.getPresence().createDeepCopy(); Presence presence = role.getPresence().createCopy();
presence.setSender(role.getRoleAddress()); presence.setFrom(role.getRoleAddress());
return presence; return presence;
} }
return null; return null;
...@@ -1125,10 +1116,10 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1125,10 +1116,10 @@ public class MUCRoomImpl implements MUCRoom {
throw new ConflictException(); throw new ConflictException();
} }
// Update the presence with the new affiliation and inform all occupants // Update the presence with the new affiliation and inform all occupants
String actorJID = null; JID actorJID = null;
// actorJID will be null if the room itself (ie. via admin console) made the request // actorJID will be null if the room itself (ie. via admin console) made the request
if (senderRole.getChatUser() != null) { if (senderRole.getChatUser() != null) {
actorJID = senderRole.getChatUser().getAddress().toBareStringPrep(); actorJID = senderRole.getChatUser().getAddress();
} }
List<Presence> updatedPresences = changeOccupantAffiliation( List<Presence> updatedPresences = changeOccupantAffiliation(
bareJID, bareJID,
...@@ -1136,19 +1127,17 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1136,19 +1127,17 @@ public class MUCRoomImpl implements MUCRoom {
MUCRole.NONE_ROLE); MUCRole.NONE_ROLE);
if (!updatedPresences.isEmpty()) { if (!updatedPresences.isEmpty()) {
Presence presence; Presence presence;
MetaDataFragment frag; Element frag;
// Add the status code and reason why the user was banned to the presences that will // Add the status code and reason why the user was banned to the presences that will
// be sent to the room occupants (the banned user will not receive this presences) // be sent to the room occupants (the banned user will not receive this presences)
for (Iterator it = updatedPresences.iterator(); it.hasNext();) { for (Iterator it = updatedPresences.iterator(); it.hasNext();) {
presence = (Presence) it.next(); presence = (Presence) it.next();
frag = (MetaDataFragment) presence.getFragment( frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
"x",
"http://jabber.org/protocol/muc#user");
// Add the status code 301 that indicates that the user was banned // Add the status code 301 that indicates that the user was banned
frag.setProperty("x.status:code", "301"); frag.element("status").addAttribute("code", "301");
// Add the reason why the user was banned // Add the reason why the user was banned
if (reason != null && reason.trim().length() > 0) { if (reason != null && reason.trim().length() > 0) {
frag.setProperty("x.item.reason", reason); frag.element("item").element("reason").setText(reason);
} }
// Remove the banned users from the room. If a user has joined the room from // Remove the banned users from the room. If a user has joined the room from
...@@ -1228,31 +1217,24 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1228,31 +1217,24 @@ public class MUCRoomImpl implements MUCRoom {
// code of 321 to indicate that the user was removed because of an affiliation // code of 321 to indicate that the user was removed because of an affiliation
// change // change
Presence presence; Presence presence;
MetaDataFragment frag; Element frag;
// Add the status code to the presences that will be sent to the room occupants // Add the status code to the presences that will be sent to the room occupants
for (Iterator it = updatedPresences.iterator(); it.hasNext();) { for (Iterator it = updatedPresences.iterator(); it.hasNext();) {
presence = (Presence) it.next(); presence = (Presence) it.next();
// Set the presence as an unavailable presence // Set the presence as an unavailable presence
try { presence.setType(Presence.Type.unavailable);
presence.setAvailable(false); frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
presence.setVisible(false);
}
catch (UnauthorizedException e) {
}
frag = (MetaDataFragment) presence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
// Add the status code 321 that indicates that the user was removed because of // Add the status code 321 that indicates that the user was removed because of
// an affiliation change // an affiliation change
frag.setProperty("x.status:code", "321"); frag.element("status").addAttribute("code", "321");
// Remove the ex-member from the room. If a user has joined the room from // Remove the ex-member from the room. If a user has joined the room from
// different client resources, he/she will be kicked from all the client // different client resources, he/she will be kicked from all the client
// resources. // resources.
// Effectively kick the occupant from the room // Effectively kick the occupant from the room
MUCUser senderUser = senderRole.getChatUser(); MUCUser senderUser = senderRole.getChatUser();
String actorJID = (senderUser == null ? JID actorJID = (senderUser == null ?
null : senderUser.getAddress().toBareStringPrep()); null : senderUser.getAddress());
kickPresence(presence, actorJID); kickPresence(presence, actorJID);
} }
} }
...@@ -1289,7 +1271,7 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1289,7 +1271,7 @@ public class MUCRoomImpl implements MUCRoom {
subject = packet.getSubject(); subject = packet.getSubject();
MUCPersistenceManager.updateRoomSubject(this, subject); MUCPersistenceManager.updateRoomSubject(this, subject);
// Notify all the occupants that the subject has changed // Notify all the occupants that the subject has changed
packet.setSender(role.getRoleAddress()); packet.setFrom(role.getRoleAddress());
send(packet); send(packet);
} }
else { else {
...@@ -1305,35 +1287,36 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1305,35 +1287,36 @@ public class MUCRoomImpl implements MUCRoom {
this.subject = subject; this.subject = subject;
} }
public void sendInvitation(String to, String reason, MUCRole senderRole, Session session) public void sendInvitation(JID to, String reason, MUCRole senderRole)
throws ForbiddenException { throws ForbiddenException {
if (!isInvitationRequiredToEnter() || canOccupantsInvite() if (!isInvitationRequiredToEnter() || canOccupantsInvite()
|| MUCRole.ADMINISTRATOR == senderRole.getAffiliation() || MUCRole.ADMINISTRATOR == senderRole.getAffiliation()
|| MUCRole.OWNER == senderRole.getAffiliation()) { || MUCRole.OWNER == senderRole.getAffiliation()) {
// If the room is not members-only OR if the room is members-only and anyone can send // If the room is not members-only OR if the room is members-only and anyone can send
// invitations or the sender is an admin or an owner, then send the invitation // invitations or the sender is an admin or an owner, then send the invitation
Message message = new MessageImpl(); Message message = new Message();
message.setOriginatingSession(session); message.setFrom(role.getRoleAddress());
message.setSender(role.getRoleAddress()); message.setTo(to);
message.setRecipient(XMPPAddress.parseJID(to)); Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
MetaDataFragment frag = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x");
// ChatUser will be null if the room itself (ie. via admin console) made the request // ChatUser will be null if the room itself (ie. via admin console) made the request
if (senderRole.getChatUser() != null) { if (senderRole.getChatUser() != null) {
frag.setProperty("x.invite:from", senderRole.getChatUser().getAddress() frag.addElement("invite").addAttribute("from", senderRole.getChatUser().getAddress()
.toBareStringPrep()); .toBareJID());
} }
if (reason != null && reason.length() > 0) { if (reason != null && reason.length() > 0) {
frag.setProperty("x.invite.reason", reason); Element invite = frag.element("invite");
if (invite == null) {
invite.addElement("invite");
}
invite.addElement("reason").setText(reason);
} }
if (isPasswordProtected()) { if (isPasswordProtected()) {
frag.setProperty("x.password", getPassword()); frag.addElement("password").setText(getPassword());
} }
message.addFragment(frag);
// Include the jabber:x:conference information for backward compatibility // Include the jabber:x:conference information for backward compatibility
frag = new MetaDataFragment("jabber:x:conference", "x"); frag = message.addChildElement("x", "jabber:x:conference");
frag.setProperty("x:jid", role.getRoleAddress().toBareStringPrep()); frag.addAttribute("jid", role.getRoleAddress().toBareJID());
message.addFragment(frag);
// Send the message with the invitation // Send the message with the invitation
router.route(message); router.route(message);
...@@ -1343,18 +1326,15 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1343,18 +1326,15 @@ public class MUCRoomImpl implements MUCRoom {
} }
} }
public void sendInvitationRejection(String to, String reason, XMPPAddress sender, public void sendInvitationRejection(JID to, String reason, JID sender) {
Session session) { Message message = new Message();
Message message = new MessageImpl(); message.setFrom(role.getRoleAddress());
message.setOriginatingSession(session); message.setTo(to);
message.setSender(role.getRoleAddress()); Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
message.setRecipient(XMPPAddress.parseJID(to)); frag.addElement("decline").addAttribute("from", sender.toBareJID());
MetaDataFragment frag = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x");
frag.setProperty("x.decline:from", sender.toBareStringPrep());
if (reason != null && reason.length() > 0) { if (reason != null && reason.length() > 0) {
frag.setProperty("x.decline.reason", reason); frag.element("decline").addElement("reason").setText(reason);
} }
message.addFragment(frag);
// Send the message with the invitation // Send the message with the invitation
router.route(message); router.route(message);
...@@ -1408,14 +1388,14 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1408,14 +1388,14 @@ public class MUCRoomImpl implements MUCRoom {
return participants; return participants;
} }
public Presence addModerator(String fullJID, MUCRole senderRole) throws ForbiddenException { public Presence addModerator(JID jid, MUCRole senderRole) throws ForbiddenException {
if (MUCRole.ADMINISTRATOR != senderRole.getAffiliation() if (MUCRole.ADMINISTRATOR != senderRole.getAffiliation()
&& MUCRole.OWNER != senderRole.getAffiliation()) { && MUCRole.OWNER != senderRole.getAffiliation()) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
// Update the presence with the new role and inform all occupants // Update the presence with the new role and inform all occupants
try { try {
return changeOccupantRole(fullJID, MUCRole.MODERATOR); return changeOccupantRole(jid, MUCRole.MODERATOR);
} }
catch (NotAllowedException e) { catch (NotAllowedException e) {
// We should never receive this exception....in theory // We should never receive this exception....in theory
...@@ -1423,48 +1403,65 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1423,48 +1403,65 @@ public class MUCRoomImpl implements MUCRoom {
} }
} }
public Presence addParticipant(String fullJID, String reason, MUCRole senderRole) public Presence addParticipant(JID jid, String reason, MUCRole senderRole)
throws NotAllowedException, ForbiddenException { throws NotAllowedException, ForbiddenException {
if (MUCRole.MODERATOR != senderRole.getRole()) { if (MUCRole.MODERATOR != senderRole.getRole()) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
// Update the presence with the new role and inform all occupants // Update the presence with the new role and inform all occupants
Presence updatedPresence = changeOccupantRole(fullJID, MUCRole.PARTICIPANT); Presence updatedPresence = changeOccupantRole(jid, MUCRole.PARTICIPANT);
if (updatedPresence != null) { if (updatedPresence != null) {
MetaDataFragment frag = (MetaDataFragment) updatedPresence.getFragment( Element frag = updatedPresence.getChildElement(
"x", "x", "http://jabber.org/protocol/muc#user");
"http://jabber.org/protocol/muc#user");
// Add the reason why the user was granted voice // Add the reason why the user was granted voice
if (reason != null && reason.trim().length() > 0) { if (reason != null && reason.trim().length() > 0) {
frag.setProperty("x.item.reason", reason); Element item = frag.element("item");
if (item == null) {
item = frag.addElement("item");
}
Element reasonEl = item.element("reason");
if (reasonEl == null) {
reasonEl = item.addElement("reason");
}
reasonEl.setText(reason);
} }
} }
return updatedPresence; return updatedPresence;
} }
public Presence addVisitor(String fullJID, MUCRole senderRole) throws NotAllowedException, public Presence addVisitor(JID jid, MUCRole senderRole) throws NotAllowedException,
ForbiddenException { ForbiddenException {
if (MUCRole.MODERATOR != senderRole.getRole()) { if (MUCRole.MODERATOR != senderRole.getRole()) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
return changeOccupantRole(fullJID, MUCRole.VISITOR); return changeOccupantRole(jid, MUCRole.VISITOR);
} }
public Presence kickOccupant(String fullJID, String actorJID, String reason) public Presence kickOccupant(JID jid, JID actorJID, String reason)
throws NotAllowedException { throws NotAllowedException {
// Update the presence with the new role and inform all occupants // Update the presence with the new role and inform all occupants
Presence updatedPresence = changeOccupantRole(fullJID, MUCRole.NONE_ROLE); Presence updatedPresence = changeOccupantRole(jid, MUCRole.NONE_ROLE);
if (updatedPresence != null) { if (updatedPresence != null) {
MetaDataFragment frag = (MetaDataFragment) updatedPresence.getFragment( Element frag = updatedPresence.getChildElement(
"x", "x", "http://jabber.org/protocol/muc#user");
"http://jabber.org/protocol/muc#user");
// Add the status code 307 that indicates that the user was kicked // Add the status code 307 that indicates that the user was kicked
frag.setProperty("x.status:code", "307"); Element status = frag.element("status");
if (status == null) {
status = frag.addElement("status");
}
status.addAttribute("code", "307");
// Add the reason why the user was kicked // Add the reason why the user was kicked
if (reason != null && reason.trim().length() > 0) { if (reason != null && reason.trim().length() > 0) {
frag.setProperty("x.item.reason", reason); Element item = frag.element("item");
if (item == null) {
item = frag.addElement("item");
}
Element reasonEl = item.element("reason");
if (reasonEl == null) {
reasonEl = item.addElement("reason");
}
reasonEl.setText(reason);
} }
// Effectively kick the occupant from the room // Effectively kick the occupant from the room
...@@ -1482,18 +1479,25 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1482,18 +1479,25 @@ public class MUCRoomImpl implements MUCRoom {
* @param actorJID The JID of the actor that initiated the kick or <tt>null</tt> if the info * @param actorJID The JID of the actor that initiated the kick or <tt>null</tt> if the info
* was not provided. * was not provided.
*/ */
private void kickPresence(Presence kickPresence, String actorJID) { private void kickPresence(Presence kickPresence, JID actorJID) {
MUCRole kickedRole; MUCRole kickedRole;
// Get the role to kick // Get the role to kick
kickedRole = occupants.get(kickPresence.getSender().getResourcePrep()); kickedRole = occupants.get(kickPresence.getFrom().getResource());
if (kickedRole != null) { if (kickedRole != null) {
kickPresence = (Presence) kickPresence.createDeepCopy(); kickPresence = kickPresence.createCopy();
// Add the actor's JID that kicked this user from the room // Add the actor's JID that kicked this user from the room
if (actorJID != null && actorJID.trim().length() > 0) { if (actorJID != null && actorJID.toString().length() > 0) {
MetaDataFragment frag = (MetaDataFragment) kickPresence.getFragment( Element frag = kickPresence.getChildElement(
"x", "x", "http://jabber.org/protocol/muc#user");
"http://jabber.org/protocol/muc#user"); Element item = frag.element("item");
frag.setProperty("x.item.actor:jid", actorJID); if (item == null) {
frag.addElement("item");
}
Element actor = item.element("actor");
if (actor == null) {
actor = item.addElement("actor");
}
actor.addAttribute("jid", actorJID.toString());
} }
// Send the unavailable presence to the banned user // Send the unavailable presence to the banned user
kickedRole.send(kickPresence); kickedRole.send(kickPresence);
...@@ -1554,18 +1558,11 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1554,18 +1558,11 @@ public class MUCRoomImpl implements MUCRoom {
// of the room // of the room
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupants.values()) {
if (occupant.getAffiliation() > MUCRole.MEMBER) { if (occupant.getAffiliation() > MUCRole.MEMBER) {
try { presences.add(kickOccupant(jid, null,
presences.add(kickOccupant(occupant.getChatUser().getAddress()
.toStringPrep(), null,
LocaleUtils.getLocalizedString("muc.roomIsNowMembersOnly"))); LocaleUtils.getLocalizedString("muc.roomIsNowMembersOnly")));
} }
catch (NotAllowedException e) {
// Do Nothing
}
} }
} }
}
this.invitationRequiredToEnter = invitationRequiredToEnter; this.invitationRequiredToEnter = invitationRequiredToEnter;
return presences; return presences;
} }
...@@ -1667,11 +1664,11 @@ public class MUCRoomImpl implements MUCRoom { ...@@ -1667,11 +1664,11 @@ public class MUCRoomImpl implements MUCRoom {
this.lockedTime = 0; this.lockedTime = 0;
if (senderRole.getChatUser() != null) { if (senderRole.getChatUser() != null) {
// Send to the occupant that unlocked the room a message saying so // Send to the occupant that unlocked the room a message saying so
Message message = new MessageImpl(); Message message = new Message();
message.setType(Message.GROUP_CHAT); message.setType(Message.Type.groupchat);
message.setBody(LocaleUtils.getLocalizedString("muc.unlocked")); message.setBody(LocaleUtils.getLocalizedString("muc.unlocked"));
message.setSender(getRole().getRoleAddress()); message.setFrom(getRole().getRoleAddress());
message.setRecipient(senderRole.getChatUser().getAddress()); message.setTo(senderRole.getChatUser().getAddress());
router.route(message); router.route(message);
} }
} }
......
...@@ -22,6 +22,7 @@ import org.jivesoftware.messenger.*; ...@@ -22,6 +22,7 @@ import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserAlreadyExistsException; import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.*;
/** /**
* Implementation of MUCUser. There will be a MUCUser per user that is connected to one or more * Implementation of MUCUser. There will be a MUCUser per user that is connected to one or more
...@@ -35,7 +36,7 @@ public class MUCUserImpl implements MUCUser { ...@@ -35,7 +36,7 @@ public class MUCUserImpl implements MUCUser {
private MultiUserChatServer server; private MultiUserChatServer server;
/** Real system XMPPAddress for the user. */ /** Real system XMPPAddress for the user. */
private XMPPAddress realjid; private JID realjid;
/** Table: key roomName.toLowerCase(); value MUCRole. */ /** Table: key roomName.toLowerCase(); value MUCRole. */
private Map<String, MUCRole> roles = new ConcurrentHashMap<String, MUCRole>(); private Map<String, MUCRole> roles = new ConcurrentHashMap<String, MUCRole>();
...@@ -55,7 +56,7 @@ public class MUCUserImpl implements MUCUser { ...@@ -55,7 +56,7 @@ public class MUCUserImpl implements MUCUser {
* @param packetRouter the router for sending packets from this user. * @param packetRouter the router for sending packets from this user.
* @param jid the real address of the user * @param jid the real address of the user
*/ */
MUCUserImpl(MultiUserChatServerImpl chatserver, PacketRouter packetRouter, XMPPAddress jid) { MUCUserImpl(MultiUserChatServerImpl chatserver, PacketRouter packetRouter, JID jid) {
this.realjid = jid; this.realjid = jid;
this.router = packetRouter; this.router = packetRouter;
this.server = chatserver; this.server = chatserver;
...@@ -89,22 +90,21 @@ public class MUCUserImpl implements MUCUser { ...@@ -89,22 +90,21 @@ public class MUCUserImpl implements MUCUser {
* Generate a conflict packet to indicate that the nickname being requested/used is already in * Generate a conflict packet to indicate that the nickname being requested/used is already in
* use by another user. * use by another user.
* *
* @param packet The packet to be bounced. * @param packet the packet to be bounced.
*/ */
private void sendErrorPacket(XMPPPacket packet, XMPPError.Code errorCode) { private void sendErrorPacket(Packet packet, PacketError error) {
packet = (XMPPPacket) packet.createDeepCopy(); packet = packet.createCopy();
packet.setError(errorCode); packet.setError(error);
XMPPAddress sender = packet.getSender(); packet.setFrom(packet.getTo());
packet.setSender(packet.getRecipient()); packet.setTo(packet.getFrom());
packet.setRecipient(sender);
router.route(packet); router.route(packet);
} }
public XMPPAddress getAddress() { public JID getAddress() {
return realjid; return realjid;
} }
public void process(XMPPPacket packet) throws UnauthorizedException, PacketException { public void process(Packet packet) throws UnauthorizedException, PacketException {
if (packet instanceof IQ) { if (packet instanceof IQ) {
process((IQ)packet); process((IQ)packet);
} }
...@@ -132,8 +132,8 @@ public class MUCUserImpl implements MUCUser { ...@@ -132,8 +132,8 @@ public class MUCUserImpl implements MUCUser {
*/ */
public void process(Message packet) { public void process(Message packet) {
lastPacketTime = System.currentTimeMillis(); lastPacketTime = System.currentTimeMillis();
XMPPAddress recipient = packet.getRecipient(); JID recipient = packet.getTo();
String group = recipient.getName(); String group = recipient.getNode();
if (group == null) { if (group == null) {
// Ignore packets to the groupchat server // Ignore packets to the groupchat server
// In the future, we'll need to support TYPE_IQ queries to the server for MUC // In the future, we'll need to support TYPE_IQ queries to the server for MUC
...@@ -145,14 +145,13 @@ public class MUCUserImpl implements MUCUser { ...@@ -145,14 +145,13 @@ public class MUCUserImpl implements MUCUser {
if (role == null) { if (role == null) {
if (server.hasChatRoom(group)) { if (server.hasChatRoom(group)) {
boolean declinedInvitation = false; boolean declinedInvitation = false;
XMPPDOMFragment userInfo = null; Element userInfo = null;
if (Message.NORMAL == packet.getType()) { if (Message.Type.normal == packet.getType()) {
// An user that is not an occupant could be declining an invitation // An user that is not an occupant could be declining an invitation
userInfo = (XMPPDOMFragment) packet.getFragment( userInfo = packet.getChildElement(
"x", "x", "http://jabber.org/protocol/muc#user");
"http://jabber.org/protocol/muc#user");
if (userInfo != null if (userInfo != null
&& userInfo.getRootElement().element("decline") != null) { && userInfo.element("decline") != null) {
// A user has declined an invitation to a room // A user has declined an invitation to a room
// WARNING: Potential fraud if someone fakes the "from" of the // WARNING: Potential fraud if someone fakes the "from" of the
// message with the JID of a member and sends a "decline" // message with the JID of a member and sends a "decline"
...@@ -160,12 +159,11 @@ public class MUCUserImpl implements MUCUser { ...@@ -160,12 +159,11 @@ public class MUCUserImpl implements MUCUser {
} }
} }
if (declinedInvitation) { if (declinedInvitation) {
Element info = userInfo.getRootElement().element("decline"); Element info = userInfo.element("decline");
server.getChatRoom(group).sendInvitationRejection( server.getChatRoom(group).sendInvitationRejection(
info.attributeValue("to"), info.attributeValue("to"),
info.elementTextTrim("reason"), info.elementTextTrim("reason"),
packet.getSender(), packet.getFrom());
packet.getOriginatingSession());
} }
else { else {
// The sender is not an occupant of the room // The sender is not an occupant of the room
......
...@@ -34,6 +34,10 @@ import java.util.concurrent.CopyOnWriteArrayList; ...@@ -34,6 +34,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.dom4j.DocumentHelper; import org.dom4j.DocumentHelper;
import org.dom4j.Element; import org.dom4j.Element;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Message;
/** /**
* Implements the chat server as a cached memory resident chat server. The server is also * Implements the chat server as a cached memory resident chat server. The server is also
...@@ -92,7 +96,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -92,7 +96,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
* the chat service's hostname * the chat service's hostname
*/ */
private String chatServiceName = null; private String chatServiceName = null;
private XMPPAddress chatServiceAddress = null; private JID chatServiceAddress = null;
/** /**
* chatrooms managed by this manager, table: key room name (String); value ChatRoom * chatrooms managed by this manager, table: key room name (String); value ChatRoom
...@@ -102,7 +106,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -102,7 +106,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
/** /**
* chat users managed by this manager, table: key user jid (XMPPAddress); value ChatUser * chat users managed by this manager, table: key user jid (XMPPAddress); value ChatUser
*/ */
private Map<XMPPAddress, MUCUser> users = new ConcurrentHashMap<XMPPAddress, MUCUser>(); private Map<JID, MUCUser> users = new ConcurrentHashMap<JID, MUCUser>();
private HistoryStrategy historyStrategy; private HistoryStrategy historyStrategy;
private RoutingTable routingTable = null; private RoutingTable routingTable = null;
...@@ -196,7 +200,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -196,7 +200,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
room = role.getChatRoom(); room = role.getChatRoom();
try { try {
kickedPresence = kickedPresence =
room.kickOccupant(user.getAddress().toStringPrep(), null, null); room.kickOccupant(user.getAddress(), null, null);
// Send the updated presence to the room occupants // Send the updated presence to the room occupants
room.send(kickedPresence); room.send(kickedPresence);
} }
...@@ -254,7 +258,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -254,7 +258,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
} }
} }
public MUCRoom getChatRoom(String roomName, XMPPAddress userjid) throws UnauthorizedException { public MUCRoom getChatRoom(String roomName, JID userjid) throws UnauthorizedException {
MUCRoom room = null; MUCRoom room = null;
synchronized (rooms) { synchronized (rooms) {
room = rooms.get(roomName.toLowerCase()); room = rooms.get(roomName.toLowerCase());
...@@ -270,15 +274,15 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -270,15 +274,15 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
// The room does not exist so check for creation permissions // The room does not exist so check for creation permissions
// Room creation is always allowed for sysadmin // Room creation is always allowed for sysadmin
if (isRoomCreationRestricted() && if (isRoomCreationRestricted() &&
!sysadmins.contains(userjid.toBareStringPrep())) { !sysadmins.contains(userjid.toBareJID())) {
// The room creation is only allowed for certain JIDs // The room creation is only allowed for certain JIDs
if (!allowedToCreate.contains(userjid.toBareStringPrep())) { if (!allowedToCreate.contains(userjid.toBareJID())) {
// The user is not in the list of allowed JIDs to create a room so raise // The user is not in the list of allowed JIDs to create a room so raise
// an exception // an exception
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
} }
room.addFirstOwner(userjid.toBareStringPrep()); room.addFirstOwner(userjid.toBareJID());
} }
rooms.put(roomName.toLowerCase(), room); rooms.put(roomName.toLowerCase(), room);
} }
...@@ -314,7 +318,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -314,7 +318,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return historyStrategy; return historyStrategy;
} }
public void removeUser(XMPPAddress jabberID) { public void removeUser(JID jabberID) {
MUCUser user = users.remove(jabberID); MUCUser user = users.remove(jabberID);
if (user != null) { if (user != null) {
Iterator<MUCRole> roles = user.getRoles(); Iterator<MUCRole> roles = user.getRoles();
...@@ -330,7 +334,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -330,7 +334,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
} }
} }
public MUCUser getChatUser(XMPPAddress userjid) throws UserNotFoundException { public MUCUser getChatUser(JID userjid) throws UserNotFoundException {
if (router == null) { if (router == null) {
throw new IllegalStateException("Not initialized"); throw new IllegalStateException("Not initialized");
} }
...@@ -585,7 +589,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -585,7 +589,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
if (serverName != null) { if (serverName != null) {
chatServiceName += "." + serverName; chatServiceName += "." + serverName;
} }
chatServiceAddress = new XMPPAddress(null, chatServiceName, null); chatServiceAddress = new JID(null, chatServiceName, null);
// Run through the users every 5 minutes after a 5 minutes server startup delay (default // Run through the users every 5 minutes after a 5 minutes server startup delay (default
// values) // values)
userTimeoutTask = new UserTimeoutTask(); userTimeoutTask = new UserTimeoutTask();
...@@ -619,16 +623,16 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -619,16 +623,16 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
} }
} }
public XMPPAddress getAddress() { public JID getAddress() {
if (chatServiceAddress == null) { if (chatServiceAddress == null) {
throw new IllegalStateException("Not initialized"); throw new IllegalStateException("Not initialized");
} }
return chatServiceAddress; return chatServiceAddress;
} }
public void process(XMPPPacket packet) { public void process(Packet packet) {
try { try {
MUCUser user = getChatUser(packet.getSender()); MUCUser user = getChatUser(packet.getFrom());
user.process(packet); user.process(packet);
} }
catch (Exception e) { catch (Exception e) {
...@@ -640,7 +644,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -640,7 +644,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return totalChatTime; return totalChatTime;
} }
public void logConversation(MUCRoom room, Message message, XMPPAddress sender) { public void logConversation(MUCRoom room, Message message, JID sender) {
logQueue.add(new ConversationLogEntry(new Date(), room, message, sender)); logQueue.add(new ConversationLogEntry(new Date(), room, message, sender));
} }
...@@ -675,7 +679,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -675,7 +679,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return items.iterator(); return items.iterator();
} }
public Iterator getIdentities(String name, String node, XMPPAddress senderJID) { public Iterator getIdentities(String name, String node, JID senderJID) {
// TODO Improve performance by not creating objects each time // TODO Improve performance by not creating objects each time
ArrayList identities = new ArrayList(); ArrayList identities = new ArrayList();
if (name == null && node == null) { if (name == null && node == null) {
...@@ -703,7 +707,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -703,7 +707,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
// Answer reserved nickname for the sender of the disco request in the requested room // Answer reserved nickname for the sender of the disco request in the requested room
MUCRoom room = getChatRoom(name); MUCRoom room = getChatRoom(name);
if (room != null) { if (room != null) {
String reservedNick = room.getReservedNickname(senderJID.toBareStringPrep()); String reservedNick = room.getReservedNickname(senderJID.toBareJID());
if (reservedNick != null) { if (reservedNick != null) {
Element identity = DocumentHelper.createElement("identity"); Element identity = DocumentHelper.createElement("identity");
identity.addAttribute("category", "conference"); identity.addAttribute("category", "conference");
...@@ -717,7 +721,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -717,7 +721,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return identities.iterator(); return identities.iterator();
} }
public Iterator getFeatures(String name, String node, XMPPAddress senderJID) { public Iterator getFeatures(String name, String node, JID senderJID) {
ArrayList features = new ArrayList(); ArrayList features = new ArrayList();
if (name == null && node == null) { if (name == null && node == null) {
// Answer the features of the MUC service // Answer the features of the MUC service
...@@ -768,7 +772,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -768,7 +772,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return features.iterator(); return features.iterator();
} }
public XDataForm getExtendedInfo(String name, String node, XMPPAddress senderJID) { public XDataForm getExtendedInfo(String name, String node, JID senderJID) {
if (name != null && node == null) { if (name != null && node == null) {
// Answer the extended info of a given room // Answer the extended info of a given room
// TODO lock the room while gathering this info??? // TODO lock the room while gathering this info???
...@@ -808,7 +812,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -808,7 +812,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return null; return null;
} }
public boolean hasInfo(String name, String node, XMPPAddress senderJID) public boolean hasInfo(String name, String node, JID senderJID)
throws UnauthorizedException { throws UnauthorizedException {
if (name == null && node == node) { if (name == null && node == node) {
// We always have info about the MUC service // We always have info about the MUC service
...@@ -825,7 +829,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -825,7 +829,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return false; return false;
} }
public Iterator getItems(String name, String node, XMPPAddress senderJID) public Iterator getItems(String name, String node, JID senderJID)
throws UnauthorizedException { throws UnauthorizedException {
List answer = new ArrayList(); List answer = new ArrayList();
if (name == null && node == null) { if (name == null && node == null) {
...@@ -834,7 +838,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -834,7 +838,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
for (MUCRoom room : rooms.values()) { for (MUCRoom room : rooms.values()) {
if (room.isPublicRoom()) { if (room.isPublicRoom()) {
item = DocumentHelper.createElement("item"); item = DocumentHelper.createElement("item");
item.addAttribute("jid", room.getRole().getRoleAddress().toStringPrep()); item.addAttribute("jid", room.getRole().getRoleAddress().toString());
item.addAttribute("name", room.getNaturalLanguageName()); item.addAttribute("name", room.getNaturalLanguageName());
answer.add(item); answer.add(item);
...@@ -849,7 +853,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -849,7 +853,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
for (MUCRole role : room.getOccupants()) { for (MUCRole role : room.getOccupants()) {
// TODO Should we filter occupants that are invisible (presence is not broadcasted)? // TODO Should we filter occupants that are invisible (presence is not broadcasted)?
item = DocumentHelper.createElement("item"); item = DocumentHelper.createElement("item");
item.addAttribute("jid", role.getRoleAddress().toStringPrep()); item.addAttribute("jid", role.getRoleAddress().toString());
answer.add(item); answer.add(item);
} }
......
...@@ -16,6 +16,10 @@ import org.jivesoftware.util.Log; ...@@ -16,6 +16,10 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.audit.Auditor; import org.jivesoftware.messenger.audit.Auditor;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Message;
import org.xmpp.packet.IQ;
import java.io.EOFException; import java.io.EOFException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.Socket; import java.net.Socket;
...@@ -113,16 +117,10 @@ public class SocketReadThread extends Thread { ...@@ -113,16 +117,10 @@ public class SocketReadThread extends Thread {
Presence presence = session.getPresence(); Presence presence = session.getPresence();
if (presence != null) { if (presence != null) {
// Simulate an unavailable presence sent by the user. // Simulate an unavailable presence sent by the user.
Presence packet = (Presence) presence.createDeepCopy(); Presence packet = presence.createCopy();
packet.setType(Presence.UNAVAILABLE); packet.setType(Presence.Type.unavailable);
try { packet.setType(null);
packet.setAvailable(false); packet.setFrom(session.getAddress());
packet.setVisible(false);
}
catch (UnauthorizedException e) {}
packet.setOriginatingSession(session);
packet.setSender(session.getAddress());
packet.setSending(false);
router.route(packet); router.route(packet);
clearSignout = true; clearSignout = true;
} }
...@@ -190,29 +188,23 @@ public class SocketReadThread extends Thread { ...@@ -190,29 +188,23 @@ public class SocketReadThread extends Thread {
if ("message".equals(tag)) { if ("message".equals(tag)) {
Message packet = packetFactory.getMessage(xpp); Message packet = packetFactory.getMessage(xpp);
packet.setOriginatingSession(session); packet.setFrom(session.getAddress());
packet.setSender(session.getAddress());
packet.setSending(false);
auditor.audit(packet); auditor.audit(packet);
router.route(packet); router.route(packet);
session.incrementClientPacketCount(); session.incrementClientPacketCount();
} }
else if ("presence".equals(tag)) { else if ("presence".equals(tag)) {
Presence packet = packetFactory.getPresence(xpp); Presence packet = packetFactory.getPresence(xpp);
packet.setOriginatingSession(session); packet.setFrom(session.getAddress());
packet.setSender(session.getAddress());
packet.setSending(false);
auditor.audit(packet); auditor.audit(packet);
router.route(packet); router.route(packet);
session.incrementClientPacketCount(); session.incrementClientPacketCount();
// Update the flag that indicates if the user made a clean sign out // Update the flag that indicates if the user made a clean sign out
clearSignout = (Presence.UNAVAILABLE == packet.getType() ? true : false); clearSignout = (Presence.Type.unavailable == packet.getType() ? true : false);
} }
else if ("iq".equals(tag)) { else if ("iq".equals(tag)) {
IQ packet = packetFactory.getIQ(xpp); IQ packet = packetFactory.getIQ(xpp);
packet.setOriginatingSession(session); packet.setFrom(session.getAddress());
packet.setSender(session.getAddress());
packet.setSending(false);
auditor.audit(packet); auditor.audit(packet);
router.route(packet); router.route(packet);
session.incrementClientPacketCount(); session.incrementClientPacketCount();
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.XMPPFragment;
import java.util.*;
abstract public class AbstractFragment implements XMPPFragment {
protected LinkedList fragments;
protected String namespace = "";
protected String name = "";
/**
* <p>Returns a namespace associated with this meta-data or null if none has been associated.</p>
*
* @return The namespace associated with this meta-data
*/
public String getNamespace() {
return namespace;
}
/**
* <p>Sets a namespace associated with this meta-data or null if none has been associated.</p>
*
* @param namespace The namespace associated with this meta-data
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* <p>Returns a name associated with this meta-data or null if none has been associated.</p>
*
* @return The name associated with this meta-data
*/
public String getName() {
return name;
}
/**
* <p>Sets a namespace associated with this meta-data or null if none has been associated.</p>
*
* @param name The namespace associated with this meta-data
*/
public void setName(String name) {
this.name = name;
}
public int getSize() {
// estimate it to be something smaller than a packet
return 20;
}
public void addFragment(XMPPFragment fragment) {
if (fragments == null) {
fragments = new LinkedList();
}
else {
// inspect for circular parent-child relationship
if (fragment.equals(this)) {
throw new IllegalArgumentException("Circular parent-child relationship");
}
Iterator frags = fragment.getFragments();
while (frags.hasNext()) {
if (frags.next().equals(this)) {
throw new IllegalArgumentException("Circular parent-child relationship");
}
}
}
fragments.addLast(fragment);
}
public Iterator getFragments() {
if (fragments == null) {
return Collections.EMPTY_LIST.iterator();
}
else {
return fragments.iterator();
}
}
public XMPPFragment getFragment(String name, String namespace) {
if (fragments == null) {
return null;
}
XMPPFragment frag;
for (Iterator frags = fragments.iterator(); frags.hasNext();) {
frag = (XMPPFragment)frags.next();
if (name.equals(frag.getName()) && namespace.equals(frag.getNamespace())) {
return frag;
}
}
return null;
}
public void clearFragments() {
if (fragments != null) {
fragments.clear();
}
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.*;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
abstract public class AbstractPacket extends AbstractFragment implements XMPPPacket {
XMPPPacket.RoutePriority routePriority = XMPPPacket.RoutePriority.normal;
XMPPError error;
String id;
Session session;
XMPPAddress sender;
XMPPAddress recipient;
XMPPPacket.Type type;
protected boolean sending;
public boolean isSending() {
return sending;
}
public void setSending(boolean isSending) {
this.sending = isSending;
}
public XMPPPacket.RoutePriority getRoutePriority() {
return routePriority;
}
public void setRoutePriority(XMPPPacket.RoutePriority priority) {
routePriority = priority;
}
public void setError(XMPPError.Code errorCode) {
this.error = new XMPPError(errorCode);
type = ERROR;
}
public XMPPError getError() {
return error;
}
public String getID() {
return id;
}
public void setID(String id) {
this.id = id;
}
public void setOriginatingSession(Session session) {
this.session = session;
}
public Session getOriginatingSession() {
return session;
}
public void setSender(XMPPAddress sender) {
this.sender = sender;
}
public XMPPAddress getSender() {
return sender;
}
public void setRecipient(XMPPAddress recipient) {
this.recipient = recipient;
}
public XMPPAddress getRecipient() {
return recipient;
}
public XMPPPacket.Type typeFromString(String type) {
if (ERROR.toString().equals(type)) {
return ERROR;
}
return null;
}
public void setType(XMPPPacket.Type type) {
this.type = type;
}
public XMPPPacket.Type getType() {
return type;
}
protected void copyAttributes(AbstractPacket packet) {
packet.routePriority = routePriority;
packet.error = error;
packet.id = id;
packet.session = session;
packet.sender = sender;
packet.recipient = recipient;
packet.type = type;
}
protected void deepCopy(AbstractPacket packet) {
copyAttributes(packet);
Iterator frags = getFragments();
while (frags.hasNext()) {
packet.addFragment(((XMPPFragment)frags.next()).createDeepCopy());
}
}
/**
* <p>Sends the opening tag and the error sub-packet (if applicable).</p>
* <p>The serializer is left ready to send the next subpacket.</p>
*
* @param xmlSerializer the serializer to use.
* @param version the XMPP version to follow.
* @param elementName the element name of the packet (iq,message,presence).
* @param ignoreType the type (if any) to ignore (Message.NORMAL,Presence.AVAILABLE) or
* null to ignore
*/
public void sendRoot(XMLStreamWriter xmlSerializer, int version, String elementName,
XMPPPacket.Type ignoreType) throws XMLStreamException
{
xmlSerializer.writeStartElement("jabber:client", elementName);
if (sender != null && sender.getHost() != null) {
xmlSerializer.writeAttribute("from", sender.toString());
}
else {
if (session != null
&& session.getAddress() != null
&& session.getAddress().getHost() != null) {
xmlSerializer.writeAttribute("from", session.getAddress().toString());
}
}
if (recipient != null && recipient.getHost() != null) {
xmlSerializer.writeAttribute("to", recipient.toString());
}
if (id != null && !"".equals(id)) {
xmlSerializer.writeAttribute("id", id);
}
if (type != null && type != ignoreType) {
xmlSerializer.writeAttribute("type", type.toString());
if (type.equals(ERROR) && error != null) {
error.send(xmlSerializer, version);
}
}
}
public int getSize() {
// No sense even trying to calculate it, just provide a rough average packet size
return 50;
}
/**
* <p>Parses the standard root element attributes without moving
* the xpp position and sets the current packet up for the given
* packet type.</p>
*
* @param xpp The XML pull parser to obtain the root attributes
*/
protected void parseRootAttributes(XMLStreamReader xpp) {
setSender(XMPPAddress.parseJID(xpp.getAttributeValue("", "from")));
setRecipient(XMPPAddress.parseJID(xpp.getAttributeValue("", "to")));
setType(typeFromString(xpp.getAttributeValue("", "type")));
setID(xpp.getAttributeValue("", "id"));
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.XMPPError;
import org.jivesoftware.messenger.XMPPPacket;
import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.Permissions;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
abstract public class AbstractPacketProxy extends FragmentProxy implements XMPPPacket {
protected XMPPPacket packet;
public AbstractPacketProxy(XMPPPacket packet, AuthToken token, Permissions permissions) {
super(packet, token, permissions);
this.packet = packet;
}
public boolean isSending() {
return packet.isSending();
}
public void setSending(boolean isSending) {
packet.setSending(isSending);
}
public XMPPPacket.RoutePriority getRoutePriority() {
return packet.getRoutePriority();
}
public void setRoutePriority(XMPPPacket.RoutePriority priority) {
packet.setRoutePriority(priority);
}
public void setError(XMPPError.Code errorCode) {
packet.setError(errorCode);
}
public XMPPError getError() {
return packet.getError();
}
public String getID() {
return packet.getID();
}
public void setID(String id) {
packet.setID(id);
}
public void setOriginatingSession(Session session) {
packet.setOriginatingSession(session);
}
public XMPPAddress getRecipient() {
return packet.getRecipient();
}
public void setRecipient(XMPPAddress recipient) {
packet.setRecipient(recipient);
}
public void setSender(XMPPAddress sender) {
packet.setSender(sender);
}
public XMPPAddress getSender() {
return packet.getSender();
}
public Session getOriginatingSession() {
return packet.getOriginatingSession();
}
public void parse(XMLStreamReader xpp) throws XMLStreamException {
packet.parse(xpp);
}
public XMPPPacket.Type typeFromString(String type) {
return packet.typeFromString(type);
}
public void setType(XMPPPacket.Type type) {
packet.setType(type);
}
public XMPPPacket.Type getType() {
return packet.getType();
}
}
...@@ -19,6 +19,8 @@ import org.jivesoftware.util.Log; ...@@ -19,6 +19,8 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.util.Version; import org.jivesoftware.util.Version;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.*; import java.util.*;
...@@ -63,19 +65,19 @@ public class BasicServer extends BasicModule implements XMPPServer, BasicServerM ...@@ -63,19 +65,19 @@ public class BasicServer extends BasicModule implements XMPPServer, BasicServerM
return new XMPPServerInfoImpl(name, version, startDate, stopDate, ports); return new XMPPServerInfoImpl(name, version, startDate, stopDate, ports);
} }
public boolean isLocal(XMPPAddress jid) { public boolean isLocal(JID jid) {
boolean local = false; boolean local = false;
if (jid != null && name != null && name.equalsIgnoreCase(jid.getHost())) { if (jid != null && name != null && name.equalsIgnoreCase(jid.getDomain())) {
local = true; local = true;
} }
return local; return local;
} }
public XMPPAddress createAddress(String username, String resource) { public JID createJID(String username, String resource) {
return new XMPPAddress(username, name, resource); return new JID(username, name, resource);
} }
private Session serverSession = new ServerSession(new XMPPAddress(null, name, null), private Session serverSession = new ServerSession(new JID(null, name, null),
new BasicStreamIDFactory().createStreamID(name)); new BasicStreamIDFactory().createStreamID(name));
public Session getSession() { public Session getSession() {
...@@ -95,7 +97,7 @@ public class BasicServer extends BasicModule implements XMPPServer, BasicServerM ...@@ -95,7 +97,7 @@ public class BasicServer extends BasicModule implements XMPPServer, BasicServerM
name = "127.0.0.1"; name = "127.0.0.1";
} }
version = new Version(2, 0, 1, Version.ReleaseStatus.Release, -1); version = new Version(2, 1, 0, Version.ReleaseStatus.Beta, -1);
initialized = true; initialized = true;
} }
catch (UnauthorizedException e) { catch (UnauthorizedException e) {
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.util.XPPReader;
import org.jivesoftware.messenger.*;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
public class IQImpl extends AbstractPacket implements IQ {
String childNamespace = "";
String childName = "";
XMPPFragment childFragment;
public IQImpl() {
}
public String getChildNamespace() {
return childNamespace;
}
public IQ createResult(Element body) {
IQ result = createResult();
XMPPFragment fragment = new XMPPDOMFragment(body);
result.setChildFragment(fragment);
result.addFragment(fragment);
return result;
}
public IQ createResult() {
IQ result = (IQ)createDeepCopy();
result.setType(RESULT);
result.setChildFragment(null);
result.clearFragments();
result.setSender(recipient);
result.setRecipient(sender);
return result;
}
public XMPPPacket.Type typeFromString(String type) {
XMPPPacket.Type typeResult = super.typeFromString(type);
if (typeResult == null) {
if ("set".equals(type)) {
return SET;
}
else if ("get".equals(type)) {
return GET;
}
else if ("result".equals(type)) {
return RESULT;
}
}
return typeResult;
}
/**
* Quick hack to get around parsing for the short term
*
* @param doc The document holding the entire iq packet
*/
public void parse(Document doc) {
Element root = doc.getRootElement();
setRecipient(XMPPAddress.parseJID(root.attributeValue("to")));
setType(typeFromString(root.attributeValue("type")));
setID(root.attributeValue("id"));
Iterator elements = root.elements().iterator();
while (elements.hasNext()) {
Element element = (Element)elements.next();
setChildNamespace(element.getNamespaceURI());
setChildName(element.getName());
XMPPFragment fragment = new XMPPDOMFragment(element);
addFragment(fragment);
setChildFragment(fragment);
}
}
/**
* <p>The parsing occurs one past the root element start tag event.</p>
*
* @param xpp The parser to pull from (set to one past the root iq element).
* @throws XMLStreamException If there is trouble parsing
*/
public void parse(XMLStreamReader xpp) throws XMLStreamException {
// we're already one past the root iq-element
int event = xpp.getEventType();
Document doc = null;
if (event == XMLStreamConstants.START_ELEMENT) {
try {
doc = XPPReader.parseDocument(xpp);
setChildNamespace(doc.getRootElement().getNamespaceURI());
setChildName(doc.getRootElement().getName());
XMPPFragment fragment = new XMPPDOMFragment(doc.getRootElement());
addFragment(fragment);
setChildFragment(fragment);
}
catch (DocumentException e) {
throw new XMLStreamException();
}
}
while (event != XMLStreamConstants.END_ELEMENT) {
event = xpp.next();
}
}
public void setChildNamespace(String namespace) {
if (namespace == null) {
childNamespace = "";
}
else {
childNamespace = namespace;
}
}
public String getChildName() {
return childName;
}
public void setChildName(String name) {
if (name == null) {
childName = "";
}
else {
childName = name;
}
}
public XMPPFragment getChildFragment() {
return childFragment;
}
public void setChildFragment(XMPPFragment fragment) {
childFragment = fragment;
if (childFragment != null) {
childNamespace = childFragment.getNamespace();
childName = childFragment.getName();
}
}
public void send(XMLStreamWriter xmlSerializer, int version) throws
XMLStreamException {
super.sendRoot(xmlSerializer, version, "iq", null);
if (childFragment != null) {
childFragment.send(xmlSerializer, version);
}
xmlSerializer.writeEndElement();
}
public XMPPFragment createDeepCopy() {
IQImpl iq = new IQImpl();
copyAttributes(iq);
iq.childFragment = childFragment;
iq.childName = childName;
iq.childNamespace = childNamespace;
return iq;
}
public Iterator getFragments() {
Iterator frags;
if (childFragment == null) {
frags = Collections.EMPTY_LIST.iterator();
}
else {
List list = new ArrayList(1);
list.add(childFragment);
frags = list.iterator();
}
return frags;
}
public void clearFragments() {
childFragment = null;
}
public void addFragment(XMPPFragment fragment) {
if (fragment.equals(this)) {
throw new IllegalArgumentException("Circular parent-child relationship");
}
setChildFragment(fragment);
}
/* send
if (getSender() == null){
Attribute fromAttribute = document.getRootElement().attribute("from");
if (fromAttribute != null){
document.getRootElement().remove(fromAttribute);
}
} else {
document.getRootElement().addAttribute("from",getSender().toString());
}
XPPWriter.write(getDocument(),writer);
public XMPPDocumentPacket createResult(Element body) {
XMPPDocumentPacket resultPacket = createResult();
Element root = resultPacket.getDocument().getRootElement();
body.detach();
if ("query".equals(body.getName())){
root.add(body);
} else {
root.addElement("query",getIQNamespace()).add(body);
}
return resultPacket;
}
public XMPPDocumentPacket createQueryResult() {
XMPPDocumentPacket resultPacket = createResult();
resultPacket.getDocument().getRootElement().addElement("query",getIQNamespace());
return resultPacket;
}
public XMPPDocumentPacket createResult() {
XMPPDocumentPacket resultPacket = new XMPPDocumentPacket(DocumentHelper.createDocument(),localServerName);
tagType = TYPE_IQ;
Element root = DocumentHelper.createElement("iq");
resultPacket.getDocument().setRootElement(root);
if (getRecipient() != null){
root.addAttribute("from",getRecipient().toString());
resultPacket.setSender(getRecipient());
}
if (getSender() != null){
root.addAttribute("to",getSender().toString());
resultPacket.setRecipient(getSender());
}
root.addAttribute("type","result");
if (getID() != null){
root.addAttribute("id",getID());
}
resultPacket.setSender(null);
resultPacket.setRecipient(getSender());
resultPacket.setOriginatingSession(getOriginatingSession());
return resultPacket;
}
*/
public String toString() {
return "IQ " + Integer.toHexString(hashCode()) + " " + getChildName() + ">" + getChildNamespace() + " t: " + (type == null ? "no type" : type.toString()) + " S: " + sender + " R: " + recipient;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.IQ;
import org.jivesoftware.messenger.XMPPFragment;
import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.Permissions;
import org.dom4j.Element;
public class IQProxy extends AbstractPacketProxy implements IQ {
protected IQ iq;
public IQProxy(IQ iq, AuthToken authToken, Permissions permissions) {
super(iq, authToken, permissions);
this.iq = iq;
}
public String getChildNamespace() {
return iq.getChildNamespace();
}
public void setChildNamespace(String namespace) {
iq.setChildNamespace(namespace);
}
public String getChildName() {
return iq.getChildName();
}
public void setChildName(String name) {
iq.setChildName(name);
}
public XMPPFragment getChildFragment() {
return iq.getChildFragment();
}
public void setChildFragment(XMPPFragment fragment) {
iq.setChildFragment(fragment);
}
public IQ createResult(Element body) {
return iq.createResult(body);
}
public IQ createResult() {
return iq.createResult();
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.XPPReader;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.XMPPDOMFragment;
import org.jivesoftware.messenger.XMPPFragment;
import org.jivesoftware.messenger.XMPPPacket;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.Document;
import org.dom4j.Element;
public class MessageImpl extends AbstractPacket implements Message {
private String body;
private String subject;
private String thread;
public MessageImpl() {
type = Message.NORMAL;
}
public XMPPPacket.Type typeFromString(String type) {
XMPPPacket.Type typeObject = super.typeFromString(type);
if (typeObject == null) {
if (type == null || type.length() == 0) {
typeObject = Message.NORMAL;
}
else if (Message.GROUP_CHAT.toString().equals(type)) {
typeObject = Message.GROUP_CHAT;
}
else if (Message.CHAT.toString().equals(type)) {
typeObject = Message.CHAT;
}
else if (Message.HEADLINE.toString().equals(type)) {
typeObject = Message.HEADLINE;
}
else {
typeObject = Message.NORMAL;
}
}
return typeObject;
}
public int getSize() {
int size = super.getSize();
if (subject != null) {
size += subject.length();
}
if (body != null) {
size += body.length();
}
if (thread != null) {
size += thread.length();
}
return size;
}
public String toString() {
return "M " + hashCode() + " " + type + " S " + subject + " B " + body;
}
public void send(XMLStreamWriter xmlSerializer, int version) throws
XMLStreamException {
super.sendRoot(xmlSerializer, version, "message", Message.NORMAL);
if (subject != null && subject.length() > 0) {
xmlSerializer.writeStartElement("jabber:client", "subject");
xmlSerializer.writeCharacters(subject);
xmlSerializer.writeEndElement();
}
if (thread != null && thread.length() > 0) {
xmlSerializer.writeStartElement("jabber:client", "thread");
xmlSerializer.writeCharacters(thread);
xmlSerializer.writeEndElement();
}
if (body != null && body.length() > 0) {
xmlSerializer.writeStartElement("jabber:client", "body");
xmlSerializer.writeCharacters(body);
xmlSerializer.writeEndElement();
}
Iterator frags = getFragments();
while (frags.hasNext()) {
((XMPPFragment)frags.next()).send(xmlSerializer, version);
}
xmlSerializer.writeEndElement();
}
public XMPPFragment createDeepCopy() {
MessageImpl msg = new MessageImpl();
deepCopy(msg);
msg.body = body;
msg.subject = subject;
msg.thread = thread;
return msg;
}
public void parse(XMLStreamReader xpp) throws XMLStreamException {
// Super class AbstractPacket will not move the parser from it's start position.
parseRootAttributes(xpp);
Document doc = null;
try {
doc = XPPReader.parseDocument(xpp);
Element root = doc.getRootElement();
Iterator frags = root.elementIterator();
while (frags.hasNext()) {
Element element = (Element)frags.next();
String name = element.getName();
if ("body".equals(name)) {
body = element.getText();
}
else if ("thread".equals(name)) {
thread = element.getTextTrim();
}
else if ("subject".equals(name)) {
subject = element.getTextTrim();
}
else if ("error".equals(name)) {
setType(ERROR);
}
else {
addFragment(new XMPPDOMFragment(element));
}
}
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getThread() {
return thread;
}
public void setThread(String thread) {
this.thread = thread;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.OfflineMessageStore;
import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.Permissions;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException;
import java.util.Iterator;
/**
* Standard security proxy
*
* @author Iain Shigeoka
*/
public class OfflineMessageStoreProxy implements OfflineMessageStore {
private OfflineMessageStore store;
private org.jivesoftware.messenger.auth.AuthToken authToken;
private Permissions permissions;
public OfflineMessageStoreProxy(OfflineMessageStore store, AuthToken authToken, Permissions permissions) {
this.store = store;
this.authToken = authToken;
this.permissions = permissions;
}
public void addMessage(Message message) throws UnauthorizedException {
if (permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
store.addMessage(message);
}
else {
throw new org.jivesoftware.messenger.auth.UnauthorizedException();
}
}
public Iterator getMessages(String userName) throws UnauthorizedException, UserNotFoundException {
if (permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
return store.getMessages(userName);
}
else {
throw new org.jivesoftware.messenger.auth.UnauthorizedException();
}
}
public int getSize(String username) throws UnauthorizedException {
if (permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
return store.getSize(username);
}
else {
throw new org.jivesoftware.messenger.auth.UnauthorizedException();
}
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.*;
import org.jivesoftware.messenger.MetaDataFragment;
import org.jivesoftware.messenger.Presence;
import org.jivesoftware.messenger.XMPPFragment;
import org.jivesoftware.messenger.XMPPPacket;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.User;
import java.util.Date;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.Document;
import org.dom4j.Element;
/**
* Database implementation of the Presence interface.
*
* @author Iain Shigeoka
*/
public class PresenceImpl extends AbstractPacket implements Presence, Cacheable {
private String username;
private String uid = "";
private Date loginTime;
private Date updateTime;
private int show;
private int priority;
private boolean visible;
private String status;
public PresenceImpl(User user, String uid) {
this();
if (user != null) {
this.username = user.getUsername();
}
this.uid = uid;
}
public PresenceImpl() {
show = Presence.SHOW_NONE;
type = Presence.AVAILABLE;
visible = false;
loginTime = new Date();
updateTime = loginTime;
priority = NO_PRIORITY;
}
public boolean isAvailable() {
return type != Presence.UNAVAILABLE;
}
public void setAvailable(boolean online) throws UnauthorizedException {
if (online) {
type = Presence.AVAILABLE;
}
else {
type = Presence.UNAVAILABLE;
}
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) throws UnauthorizedException {
this.visible = visible;
}
public void parse(XMLStreamReader xpp) throws XMLStreamException {
// Super class AbstractPacket will not move the parser from it's start position.
parseRootAttributes(xpp);
Document doc = null;
try {
// Extremely inefficient to parse it into a DOM then toss it about like this
// but we'll optimize when we see it's a bottleneck
doc = XPPReader.parseDocument(xpp);
Element root = doc.getRootElement();
show = Presence.SHOW_NONE;
// Default priority is zero unless a value is provided
priority = 0;
Iterator subElements = root.elementIterator();
while (subElements.hasNext()) {
Element element = (Element)subElements.next();
String name = element.getName();
if ("show".equals(name)) {
String showText = root.element("show").getText();
if ("".equals(showText)) {
show = Presence.SHOW_NONE;
}
else if ("chat".equals(showText)) {
show = Presence.SHOW_CHAT;
}
else if ("dnd".equals(showText)) {
show = Presence.SHOW_DND;
}
else if ("away".equals(showText)) {
show = Presence.SHOW_AWAY;
}
else if ("xa".equals(showText)) {
show = Presence.SHOW_XA;
}
}
else if ("status".equals(name)) {
status = root.element("status").getTextTrim();
}
else if ("error".equals(name)) {
setType(ERROR);
}
else if ("priority".equals(name)) {
String priorityText = root.element("priority").getTextTrim();
if (priorityText != null && priorityText.length() > 0) {
priority = Integer.parseInt(priorityText);
}
}
else {
addFragment(new MetaDataFragment(element));
}
}
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
public String getUsername() {
return username;
}
public Date getLoginTime() {
return (Date)loginTime.clone();
}
public Date getLastUpdateTime() {
return (Date)updateTime.clone();
}
public void setLastUpdateTime(Date time) throws UnauthorizedException {
updateTime.setTime(time.getTime());
}
public int getShow() {
return show;
}
public void setShow(int show) throws UnauthorizedException {
this.show = show;
}
public String getStatus() {
return status;
}
public void setStatus(String status) throws UnauthorizedException {
this.status = status;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public int getCachedSize() {
// Approximate the size of the object in bytes by calculating the size of each field.
int size = 0;
size += CacheSizes.sizeOfObject(); // overhead of object
size += CacheSizes.sizeOfString(username); // username
size += CacheSizes.sizeOfString(uid); // uid
size += CacheSizes.sizeOfDate(); // login date
size += CacheSizes.sizeOfDate(); // last update date
size += CacheSizes.sizeOfInt(); // show
return size;
}
public String toString() {
return super.toString() + " " + type.toString() + " S: " + sender + " R: " + recipient;
}
public void send(XMLStreamWriter xmlSerializer, int version) throws
XMLStreamException {
super.sendRoot(xmlSerializer, version, "presence", Presence.AVAILABLE);
// if (show != Presence.SHOW_NONE)
switch (show) {
case Presence.SHOW_XA:
xmlSerializer.writeStartElement("jabber:client", "show");
xmlSerializer.writeCharacters("xa");
xmlSerializer.writeEndElement();
break;
case Presence.SHOW_AWAY:
xmlSerializer.writeStartElement("jabber:client", "show");
xmlSerializer.writeCharacters("away");
xmlSerializer.writeEndElement();
break;
case Presence.SHOW_CHAT:
xmlSerializer.writeStartElement("jabber:client", "show");
xmlSerializer.writeCharacters("chat");
xmlSerializer.writeEndElement();
break;
case Presence.SHOW_DND:
xmlSerializer.writeStartElement("jabber:client", "show");
xmlSerializer.writeCharacters("dnd");
xmlSerializer.writeEndElement();
break;
}
if (status != null && status.length() > 0) {
xmlSerializer.writeStartElement("jabber:client", "status");
xmlSerializer.writeCharacters(status);
xmlSerializer.writeEndElement();
}
if (priority != NO_PRIORITY) {
xmlSerializer.writeStartElement("jabber:client", "priority");
xmlSerializer.writeCharacters(Integer.toString(priority));
xmlSerializer.writeEndElement();
}
Iterator frags = getFragments();
while (frags.hasNext()) {
((XMPPFragment)frags.next()).send(xmlSerializer, version);
}
xmlSerializer.writeEndElement();
}
public XMPPFragment createDeepCopy() {
PresenceImpl presence = new PresenceImpl();
deepCopy(presence);
presence.username = username;
presence.uid = uid;
presence.loginTime = loginTime;
presence.updateTime = updateTime;
presence.show = show;
presence.priority = priority;
presence.visible = visible;
presence.status = status;
return presence;
}
public XMPPPacket.Type typeFromString(String type) {
XMPPPacket.Type typeObject = super.typeFromString(type);
if (typeObject == null) {
if (type == null || type.length() == 0) {
typeObject = Presence.AVAILABLE;
}
else if (Presence.UNAVAILABLE.toString().equals(type)) {
typeObject = Presence.UNAVAILABLE;
}
else if (Presence.SUBSCRIBE.toString().equals(type)) {
typeObject = Presence.SUBSCRIBE;
}
else if (Presence.SUBSCRIBED.toString().equals(type)) {
typeObject = Presence.SUBSCRIBED;
}
else if (Presence.UNSUBSCRIBE.toString().equals(type)) {
typeObject = Presence.UNSUBSCRIBE;
}
else if (Presence.INVISIBLE.toString().equals(type)) {
typeObject = Presence.INVISIBLE;
}
}
return typeObject;
}
}
\ No newline at end of file
...@@ -25,6 +25,8 @@ import org.jivesoftware.util.Cache; ...@@ -25,6 +25,8 @@ import org.jivesoftware.util.Cache;
import org.jivesoftware.util.JiveConstants; import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
/** /**
* Simple in memory implementation of the PresenceManager interface. * Simple in memory implementation of the PresenceManager interface.
...@@ -81,7 +83,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -81,7 +83,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
for (Presence presence : onlineUsers.values()) { for (Presence presence : onlineUsers.values()) {
if (presence.isAvailable()) { if (presence.isAvailable()) {
try { try {
users.add(userManager.getUser(presence.getUsername())); users.add(userManager.getUser(presence.getFrom().getNode()));
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e); Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
...@@ -134,9 +136,11 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -134,9 +136,11 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
String presenceUser2 = ""; String presenceUser2 = "";
try { try {
presenceUser1 = presenceUser1 =
userManager.getUser(presence1.getUsername()).getUsername(); userManager.getUser(presence1.getFrom().getNode()
).getUsername();
presenceUser2 = presenceUser2 =
userManager.getUser(presence2.getUsername()).getUsername(); userManager.getUser(presence2.getFrom().getNode()
).getUsername();
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e); Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
...@@ -162,7 +166,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -162,7 +166,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
for (int i = 0; i < presences.size(); i++) { for (int i = 0; i < presences.size(); i++) {
Presence presence = (Presence)presences.get(i); Presence presence = (Presence)presences.get(i);
try { try {
users.add(userManager.getUser(presence.getUsername())); users.add(userManager.getUser(presence.getFrom().getNode()));
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e); Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
...@@ -177,9 +181,10 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -177,9 +181,10 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
} }
public Presence createPresence(User user, String uid) { public Presence createPresence(User user) {
Presence presence = null; Presence presence = null;
presence = new PresenceImpl(user, uid); presence = new Presence();
presence.setFrom(server.createJID(user.getUsername(), null));
setOnline(presence); setOnline(presence);
return presence; return presence;
} }
...@@ -187,7 +192,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -187,7 +192,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
public void setOnline(Presence presence) { public void setOnline(Presence presence) {
User user = null; User user = null;
try { try {
user = userManager.getUser(presence.getUsername()); user = userManager.getUser(presence.getFrom().getNode());
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e); Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
...@@ -206,9 +211,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -206,9 +211,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
public void setOffline(Presence presence) { public void setOffline(Presence presence) {
if (presence.getUsername() != null) { if (presence.getFrom().getNode() != null) {
synchronized (onlineUsers) { synchronized (onlineUsers) {
onlineUsers.remove(presence.getUsername()); onlineUsers.remove(presence.getFrom().getNode());
} }
} }
else { else {
...@@ -218,7 +223,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -218,7 +223,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
} }
public void setOffline(XMPPAddress jid) throws UnauthorizedException { public void setOffline(JID jid) throws UnauthorizedException {
} }
public boolean isAvailable(User user) { public boolean isAvailable(User user) {
...@@ -239,7 +244,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -239,7 +244,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
if (presence == null) { if (presence == null) {
presence = session.getPresence(); presence = session.getPresence();
} }
else if (presence.getShow() > session.getPresence().getShow()) { else if (presence.getShow().ordinal() > session.getPresence().getShow().ordinal()) {
presence = session.getPresence(); presence = session.getPresence();
} }
} }
...@@ -286,17 +291,16 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -286,17 +291,16 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
return null; return null;
} }
public void probePresence(String prober, XMPPAddress probee) { public void probePresence(String prober, JID probee) {
try { try {
Component component = getPresenceComponent(probee); Component component = getPresenceComponent(probee);
if (server.isLocal(probee)) { if (server.isLocal(probee)) {
if (probee.getNamePrep() != null && !"".equals(probee.getNamePrep())) { if (probee.getNode() != null && !"".equals(probee.getNode())) {
Collection<Session> sessions = Collection<Session> sessions =
sessionManager.getSessions(probee.getNamePrep()); sessionManager.getSessions(probee.getNode());
for (Session session : sessions) { for (Session session : sessions) {
Presence presencePacket = Presence presencePacket = session.getPresence().createCopy();
(Presence)session.getPresence().createDeepCopy(); presencePacket.setFrom(session.getAddress());
presencePacket.setSender(session.getAddress());
try { try {
sessionManager.userBroadcast(prober, presencePacket); sessionManager.userBroadcast(prober, presencePacket);
} }
...@@ -307,17 +311,17 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -307,17 +311,17 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
} }
else if (component != null) { else if (component != null) {
Presence presence = new PresenceImpl(); Presence presence = new Presence();
presence.setType(Presence.PROBE); presence.setType(Presence.Type.probe);
presence.setSender(server.createAddress(prober, "")); presence.setFrom(server.createJID(prober, ""));
presence.setRecipient(probee); presence.setTo(probee);
component.processPacket(presence); component.processPacket(presence);
} }
else { else {
Presence presence = (Presence)foreignUserCache.get(probee.toBareStringPrep()); Presence presence = (Presence)foreignUserCache.get(probee.toBareJID());
if (presence != null) { if (presence != null) {
Presence presencePacket = (Presence)presence.createDeepCopy(); Presence presencePacket = presence.createCopy();
presencePacket.setSender(probee); presencePacket.setFrom(probee);
try { try {
sessionManager.userBroadcast(prober, presencePacket); sessionManager.userBroadcast(prober, presencePacket);
} }
...@@ -326,7 +330,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -326,7 +330,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
} }
else { else {
XMPPAddress proberAddress = server.createAddress(prober, ""); JID proberAddress = server.createJID(prober, "");
componentManager.addPresenceRequest(proberAddress, probee); componentManager.addPresenceRequest(proberAddress, probee);
} }
} }
...@@ -336,15 +340,14 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -336,15 +340,14 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
} }
public void probePresence(XMPPAddress prober, XMPPAddress probee) { public void probePresence(JID prober, JID probee) {
try { try {
if (server.isLocal(probee)) { if (server.isLocal(probee)) {
Collection<Session> sessions = Collection<Session> sessions =
sessionManager.getSessions(probee.getName().toLowerCase()); sessionManager.getSessions(probee.getNode());
for (Session session : sessions) { for (Session session : sessions) {
Presence presencePacket = Presence presencePacket = session.getPresence().createCopy();
(Presence)session.getPresence().createDeepCopy(); presencePacket.setFrom(session.getAddress());
presencePacket.setSender(session.getAddress());
try { try {
deliverer.deliver(presencePacket); deliverer.deliver(presencePacket);
} }
...@@ -355,10 +358,10 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -355,10 +358,10 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
else { else {
Presence presence = Presence presence =
(Presence)foreignUserCache.get(probee.toBareStringPrep()); (Presence)foreignUserCache.get(probee.toBareJID());
if (presence != null) { if (presence != null) {
Presence presencePacket = (Presence)presence.createDeepCopy(); Presence presencePacket = presence.createCopy();
presencePacket.setSender(probee); presencePacket.setFrom(probee);
try { try {
deliverer.deliver(presencePacket); deliverer.deliver(presencePacket);
} }
...@@ -392,9 +395,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -392,9 +395,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
return trackInfo; return trackInfo;
} }
public Component getPresenceComponent(XMPPAddress probee) { public Component getPresenceComponent(JID probee) {
// Check for registered components // Check for registered components
Component component = componentManager.getComponent(probee.toBareStringPrep()); Component component = componentManager.getComponent(probee.toBareJID());
if (component != null) { if (component != null) {
return component; return component;
} }
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.Permissions;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import java.util.Date;
/**
* Protection proxy for the Presence class.
*
* @author Iain Shigeoka
*/
public class PresenceProxy extends AbstractPacketProxy implements Presence {
private Presence presence;
public PresenceProxy(Presence presence, AuthToken authToken, Permissions permissions) {
super(presence, authToken, permissions);
this.presence = presence;
}
public boolean isAvailable() {
return presence.isAvailable();
}
public void setAvailable(boolean online) throws UnauthorizedException {
if (presence.getUsername().equals(authToken.getUsername()) ||
permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
presence.setAvailable(online);
}
else {
throw new org.jivesoftware.messenger.auth.UnauthorizedException();
}
}
public boolean isVisible() {
return presence.isVisible();
}
public void setVisible(boolean visible) throws UnauthorizedException {
if (presence.getUsername().equals(authToken.getUsername()) ||
permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
presence.setVisible(visible);
}
else {
throw new org.jivesoftware.messenger.auth.UnauthorizedException();
}
}
public String getID() {
return presence.getID();
}
public String getUsername() {
return presence.getUsername();
}
public Date getLoginTime() {
return presence.getLoginTime();
}
public Date getLastUpdateTime() {
return presence.getLastUpdateTime();
}
public void setLastUpdateTime(Date time) throws UnauthorizedException {
if (presence.getUsername().equals(authToken.getUsername()) ||
permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
presence.setLastUpdateTime(time);
}
else {
throw new UnauthorizedException();
}
}
public int getShow() {
return presence.getShow();
}
public void setShow(int status) throws UnauthorizedException {
if (presence.getUsername().equals(authToken.getUsername()) ||
permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
presence.setShow(status);
}
else {
throw new UnauthorizedException();
}
}
public String getStatus() {
return presence.getStatus();
}
public void setStatus(String status) throws UnauthorizedException {
if (presence.getUsername().equals(authToken.getUsername()) ||
permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
presence.setStatus(status);
}
else {
throw new UnauthorizedException();
}
}
public int getPriority() {
return presence.getPriority();
}
public void setPriority(int priority) throws UnauthorizedException {
if (presence.getUsername().equals(authToken.getUsername()) ||
permissions.hasPermission(Permissions.SYSTEM_ADMIN | Permissions.USER_ADMIN)) {
presence.setPriority(priority);
}
else {
throw new UnauthorizedException();
}
}
public RoutePriority getRoutePriority() {
return presence.getRoutePriority();
}
public void setRoutePriority(RoutePriority priority) {
presence.setRoutePriority(priority);
}
public XMPPError getError() {
return presence.getError();
}
public Type getType() {
return presence.getType();
}
public XMPPAddress getRecipient() {
return presence.getRecipient();
}
public XMPPAddress getSender() {
return presence.getSender();
}
public Session getOriginatingSession() {
return presence.getOriginatingSession();
}
public XMPPPacket.Type typeFromString(String type) {
return presence.typeFromString(type);
}
public XMPPFragment createDeepCopy() {
return presence.createDeepCopy();
}
}
...@@ -14,6 +14,7 @@ package org.jivesoftware.messenger.spi; ...@@ -14,6 +14,7 @@ package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule; import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import java.util.*; import java.util.*;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
...@@ -43,26 +44,26 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable { ...@@ -43,26 +44,26 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
super("Routing table"); super("Routing table");
} }
public ChannelHandler addRoute(XMPPAddress node, RoutableChannelHandler destination) { public ChannelHandler addRoute(JID node, RoutableChannelHandler destination) {
ChannelHandler route = null; ChannelHandler route = null;
routeLock.writeLock().lock(); routeLock.writeLock().lock();
try { try {
if (node.getName() == null) { if (node.getNode() == null) {
Object item = routes.put(node.getHostPrep(), destination); Object item = routes.put(node.getDomain(), destination);
if (item instanceof ChannelHandler) { if (item instanceof ChannelHandler) {
route = (ChannelHandler)item; route = (ChannelHandler)item;
} }
} }
else { else {
Object nameRoutes = routes.get(node.getHostPrep()); Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes == null || nameRoutes instanceof ChannelHandler) { if (nameRoutes == null || nameRoutes instanceof ChannelHandler) {
nameRoutes = new Hashtable(); nameRoutes = new Hashtable();
routes.put(node.getHostPrep(), nameRoutes); routes.put(node.getDomain(), nameRoutes);
} }
if (node.getResource() == null) { if (node.getResource() == null) {
Object item = ((Hashtable)nameRoutes).put(node.getNamePrep(), Object item = ((Hashtable)nameRoutes).put(node.getNode(),
destination); destination);
if (item instanceof ChannelHandler) { if (item instanceof ChannelHandler) {
route = (ChannelHandler)item; route = (ChannelHandler)item;
...@@ -70,18 +71,18 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable { ...@@ -70,18 +71,18 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
} }
else { else {
Object resourceRoutes = Object resourceRoutes =
((Hashtable)nameRoutes).get(node.getNamePrep()); ((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes == null if (resourceRoutes == null
|| resourceRoutes instanceof ChannelHandler) { || resourceRoutes instanceof ChannelHandler) {
resourceRoutes = new Hashtable(); resourceRoutes = new Hashtable();
Object item = ((Hashtable)nameRoutes).put(node.getNamePrep(), Object item = ((Hashtable)nameRoutes).put(node.getNode(),
resourceRoutes); resourceRoutes);
if (item instanceof ChannelHandler) { if (item instanceof ChannelHandler) {
route = (ChannelHandler)item; route = (ChannelHandler)item;
} }
} }
Object resourceRoute = Object resourceRoute =
((Hashtable)resourceRoutes).put(node.getResourcePrep(), ((Hashtable)resourceRoutes).put(node.getResource(),
destination); destination);
if (resourceRoute != null) { if (resourceRoute != null) {
if (resourceRoute instanceof ChannelHandler) { if (resourceRoute instanceof ChannelHandler) {
...@@ -99,22 +100,22 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable { ...@@ -99,22 +100,22 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
return route; return route;
} }
public RoutableChannelHandler getRoute(XMPPAddress node) throws NoSuchRouteException { public RoutableChannelHandler getRoute(JID node) throws NoSuchRouteException {
RoutableChannelHandler route = null; RoutableChannelHandler route = null;
routeLock.readLock().lock(); routeLock.readLock().lock();
try { try {
Object nameRoutes = routes.get(node.getHostPrep()); Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes instanceof ChannelHandler) { if (nameRoutes instanceof ChannelHandler) {
route = (RoutableChannelHandler)nameRoutes; route = (RoutableChannelHandler)nameRoutes;
} }
else { else {
Object resourceRoutes = ((Hashtable)nameRoutes).get(node.getNamePrep()); Object resourceRoutes = ((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes instanceof ChannelHandler) { if (resourceRoutes instanceof ChannelHandler) {
route = (RoutableChannelHandler)resourceRoutes; route = (RoutableChannelHandler)resourceRoutes;
} }
else if (resourceRoutes != null) { else if (resourceRoutes != null) {
route = (RoutableChannelHandler) route = (RoutableChannelHandler)
((Hashtable)resourceRoutes).get(node.getResourcePrep()); ((Hashtable)resourceRoutes).get(node.getResource());
} }
else { else {
//System.err.println(nameRoutes); //System.err.println(nameRoutes);
...@@ -135,28 +136,28 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable { ...@@ -135,28 +136,28 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
return route; return route;
} }
public Iterator getRoutes(XMPPAddress node) { public Iterator getRoutes(JID node) {
LinkedList list = null; LinkedList list = null;
routeLock.readLock().lock(); routeLock.readLock().lock();
try { try {
if (node == null || node.getHost() == null) { if (node == null || node.getDomain() == null) {
list = new LinkedList(); list = new LinkedList();
getRoutes(list, routes); getRoutes(list, routes);
} }
else { else {
Object nameRoutes = routes.get(node.getHostPrep()); Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes != null) { if (nameRoutes != null) {
if (nameRoutes instanceof ChannelHandler) { if (nameRoutes instanceof ChannelHandler) {
list = new LinkedList(); list = new LinkedList();
list.add(nameRoutes); list.add(nameRoutes);
} }
else if (node.getName() == null) { else if (node.getNode() == null) {
list = new LinkedList(); list = new LinkedList();
getRoutes(list, (Hashtable)nameRoutes); getRoutes(list, (Hashtable)nameRoutes);
} }
else { else {
Object resourceRoutes = Object resourceRoutes =
((Hashtable)nameRoutes).get(node.getNamePrep()); ((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes != null) { if (resourceRoutes != null) {
if (resourceRoutes instanceof ChannelHandler) { if (resourceRoutes instanceof ChannelHandler) {
list = new LinkedList(); list = new LinkedList();
...@@ -168,7 +169,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable { ...@@ -168,7 +169,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
} }
else { else {
Object entry = Object entry =
((Hashtable)resourceRoutes).get(node.getResourcePrep()); ((Hashtable)resourceRoutes).get(node.getResource());
if (entry != null) { if (entry != null) {
list = new LinkedList(); list = new LinkedList();
list.add(entry); list.add(entry);
...@@ -216,14 +217,14 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable { ...@@ -216,14 +217,14 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
} }
} }
public ChannelHandler getBestRoute(XMPPAddress node) throws NoSuchRouteException { public ChannelHandler getBestRoute(JID node) throws NoSuchRouteException {
ChannelHandler route = null; ChannelHandler route = null;
try { try {
route = getRoute(node); route = getRoute(node);
} }
catch (NoSuchRouteException e) { catch (NoSuchRouteException e) {
XMPPAddress defaultNode = new XMPPAddress(node.getName(), node.getHost(), ""); JID defaultNode = new JID(node.getNode(), node.getDomain(), "");
route = getRoute(defaultNode); route = getRoute(defaultNode);
} }
if (route == null) { if (route == null) {
...@@ -232,40 +233,40 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable { ...@@ -232,40 +233,40 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
return route; return route;
} }
public ChannelHandler removeRoute(XMPPAddress node) { public ChannelHandler removeRoute(JID node) {
ChannelHandler route = null; ChannelHandler route = null;
routeLock.writeLock().lock(); routeLock.writeLock().lock();
//System.err.println("Remove route " + node.toString()); //System.err.println("Remove route " + node.toString());
try { try {
if (node.getName() == null) { if (node.getNode() == null) {
// Chop off all hosted names for this domain // Chop off all hosted names for this domain
Object item = routes.remove(node.getHostPrep()); Object item = routes.remove(node.getDomain());
if (item instanceof ChannelHandler) { if (item instanceof ChannelHandler) {
route = (ChannelHandler)item; route = (ChannelHandler)item;
} }
} }
else { else {
Object nameRoutes = routes.get(node.getHostPrep()); Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes instanceof Hashtable) { if (nameRoutes instanceof Hashtable) {
if (node.getResource() == null || node.getResource().trim().length() == 0) { if (node.getResource() == null || node.getResource().trim().length() == 0) {
// Chop off all hosted resources for the given name // Chop off all hosted resources for the given name
Object item = ((Hashtable)nameRoutes).remove(node.getNamePrep()); Object item = ((Hashtable)nameRoutes).remove(node.getNode());
if (item instanceof ChannelHandler) { if (item instanceof ChannelHandler) {
route = (ChannelHandler)item; route = (ChannelHandler)item;
} }
} }
else { else {
Object resourceRoutes = Object resourceRoutes =
((Hashtable)nameRoutes).get(node.getNamePrep()); ((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes instanceof Hashtable) { if (resourceRoutes instanceof Hashtable) {
route = (ChannelHandler) route = (ChannelHandler)
((Hashtable)resourceRoutes).remove(node.getResourcePrep()); ((Hashtable)resourceRoutes).remove(node.getResource());
if (((Hashtable)resourceRoutes).isEmpty()) { if (((Hashtable)resourceRoutes).isEmpty()) {
((Hashtable)nameRoutes).remove(node.getNamePrep()); ((Hashtable)nameRoutes).remove(node.getNode());
if (((Hashtable)nameRoutes).isEmpty()) { if (((Hashtable)nameRoutes).isEmpty()) {
routes.remove(node.getHostPrep()); routes.remove(node.getDomain());
} }
} }
......
...@@ -56,8 +56,8 @@ public class XMPPServerProxy implements XMPPServer { ...@@ -56,8 +56,8 @@ public class XMPPServerProxy implements XMPPServer {
return server.isLocal(jid); return server.isLocal(jid);
} }
public XMPPAddress createAddress(String username, String resource) { public XMPPAddress createJID(String username, String resource) {
return server.createAddress(username, resource); return server.createJID(username, resource);
} }
public Session getSession() throws UnauthorizedException { public Session getSession() throws UnauthorizedException {
......
...@@ -206,7 +206,7 @@ public class CachedRosterImpl extends BasicRoster implements CachedRoster { ...@@ -206,7 +206,7 @@ public class CachedRosterImpl extends BasicRoster implements CachedRoster {
if (server == null) { if (server == null) {
server = (XMPPServer)ServiceLookupFactory.getLookup().lookup(XMPPServer.class); server = (XMPPServer)ServiceLookupFactory.getLookup().lookup(XMPPServer.class);
} }
XMPPAddress recipient = server.createAddress(username, null); XMPPAddress recipient = server.createJID(username, null);
roster.setRecipient(recipient); roster.setRecipient(recipient);
roster.setOriginatingSession(server.getSession()); roster.setOriginatingSession(server.getSession());
if (sessionManager == null) { if (sessionManager == null) {
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.user.spi;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.*;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.OfflineMessageStore;
import org.jivesoftware.messenger.PacketFactory;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Date;
import java.util.Iterator;
/**
* An empty implementation of a message store (drops message).
*
* @author Iain Shigeoka
*/
public class DbOfflineMessageStore extends BasicModule implements OfflineMessageStore {
private static final String INSERT_OFFLINE =
"INSERT INTO jiveOffline (username, messageID, creationDate, messageSize, message) " +
"VALUES (?, ?, ?, ?, ?)";
private static final String LOAD_OFFLINE =
"SELECT message FROM jiveOffline WHERE username=?";
private static final String SELECT_SIZE_OFFLINE =
"SELECT SUM(messageSize) FROM jiveOffline WHERE username=?";
private static final String DELETE_OFFLINE =
"DELETE FROM jiveOffline WHERE username=?";
public DbOfflineMessageStore() {
super("Offline Message Store");
}
public void addMessage(Message message) throws UnauthorizedException {
if (message != null) {
Connection con = null;
PreparedStatement pstmt = null;
long messageID = SequenceManager.nextID(JiveConstants.OFFLINE);
String username = message.getRecipient().getNamePrep();
try {
StringXMLStreamWriter serMsg = new StringXMLStreamWriter();
message.send(serMsg, 0);
String msg = serMsg.toString();
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(INSERT_OFFLINE);
pstmt.setString(1, username);
pstmt.setLong(2, messageID);
pstmt.setString(3, StringUtils.dateToMillis(new Date()));
pstmt.setInt(4, msg.length());
pstmt.setString(5, msg);
pstmt.executeUpdate();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
}
}
public Iterator getMessages(String username) throws UnauthorizedException {
java.util.LinkedList msgs = new java.util.LinkedList();
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_OFFLINE);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String msg = rs.getString(1);
msgs.add(packetFactory.getMessage(msg));
}
rs.close();
pstmt.close();
pstmt = con.prepareStatement(DELETE_OFFLINE);
pstmt.setString(1, username);
pstmt.executeUpdate();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
return msgs.iterator();
}
public int getSize(String username) {
int size = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(SELECT_SIZE_OFFLINE);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
size = rs.getInt(1);
}
rs.close();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
return size;
}
public PacketFactory packetFactory;
public UserManager userManager;
public TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(PacketFactory.class, "packetFactory");
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
return trackInfo;
}
}
...@@ -111,7 +111,7 @@ public class OfflineMessageStrategyImpl extends BasicModule implements OfflineMe ...@@ -111,7 +111,7 @@ public class OfflineMessageStrategyImpl extends BasicModule implements OfflineMe
Message response = packetFactory.getMessage(); Message response = packetFactory.getMessage();
response.setOriginatingSession(xmppServer.getSession()); response.setOriginatingSession(xmppServer.getSession());
response.setRecipient(message.getSender()); response.setRecipient(message.getSender());
response.setSender(xmppServer.createAddress(null, null)); response.setSender(xmppServer.createJID(null, null));
response.setBody("Message could not be delivered to " + message.getRecipient() + ". User is offline or unreachable."); response.setBody("Message could not be delivered to " + message.getRecipient() + ". User is offline or unreachable.");
message.getOriginatingSession().getConnection().deliver(response); message.getOriginatingSession().getConnection().deliver(response);
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
<%@ page import="java.io.*, <%@ page import="java.io.*,
org.jivesoftware.util.ParamUtils, org.jivesoftware.util.ParamUtils,
org.jivesoftware.util.Version,
org.jivesoftware.messenger.JiveGlobals, org.jivesoftware.messenger.JiveGlobals,
org.jivesoftware.messenger.auth.UnauthorizedException, org.jivesoftware.messenger.auth.UnauthorizedException,
org.jivesoftware.messenger.user.UserNotFoundException, org.jivesoftware.messenger.user.UserNotFoundException,
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
org.jivesoftware.messenger.container.ServiceLookupFactory, org.jivesoftware.messenger.container.ServiceLookupFactory,
org.jivesoftware.messenger.container.ServiceLookup, org.jivesoftware.messenger.container.ServiceLookup,
org.jivesoftware.messenger.JiveGlobals, org.jivesoftware.messenger.JiveGlobals,
org.jivesoftware.util.Version,
org.jivesoftware.util.Log, org.jivesoftware.util.Log,
org.jivesoftware.admin.AdminConsole" org.jivesoftware.admin.AdminConsole"
errorPage="error.jsp" errorPage="error.jsp"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment