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 @@
<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/whack.jar!/" />
<root url="jar://$PROJECT_DIR$/build/lib/merge/whack.jar!/" />
<root url="jar://$PROJECT_DIR$/build/lib/merge/jdic.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
......
......@@ -14,6 +14,7 @@ package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.LocaleUtils;
import org.xmpp.packet.Packet;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
......@@ -38,7 +39,7 @@ import java.util.concurrent.LinkedBlockingQueue;
*
* @author Matt Tucker
*/
public class Channel<T extends XMPPPacket> {
public class Channel<T extends Packet> {
private String name;
private ChannelHandler channelHandler;
......@@ -83,6 +84,7 @@ public class Channel<T extends XMPPPacket> {
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
try {
packet.getOriginatingSession().getConnection().close();
}
catch (UnauthorizedException e1) {
......
......@@ -12,13 +12,14 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
/**
* Interface to handle packets delivered by Channels.
*
* @author Matt Tucker
*/
public interface ChannelHandler<T extends XMPPPacket> {
public interface ChannelHandler<T extends Packet> {
/**
* Process an XMPP packet.
......
package org.jivesoftware.messenger;
import org.xmpp.packet.Packet;
public interface Component {
void processPacket(XMPPPacket packet);
void processPacket(Packet packet);
}
package org.jivesoftware.messenger;
import java.io.StringReader;
import java.util.Map;
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.container.ServiceLookupFactory;
import org.jivesoftware.messenger.spi.PacketFactoryImpl;
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.StringUtils;
import org.xmpp.packet.Packet;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
/**
* <p>Manages the registration and delegation of Components.</p>
......@@ -29,7 +23,7 @@ import org.xmpp.packet.Packet;
public class ComponentManager {
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;
private final static Object LOCK = new Object();
......@@ -110,7 +104,7 @@ public class ComponentManager {
* @param prober the jid probing.
* @param probee the presence being probed.
*/
public void addPresenceRequest(XMPPAddress prober, XMPPAddress probee) {
public void addPresenceRequest(JID prober, JID probee) {
presenceMap.put(prober, probee);
}
......@@ -120,7 +114,7 @@ public class ComponentManager {
*
* @param packet the packet to send.
*/
public void sendPacket(XMPPPacket packet) {
public void sendPacket(Packet packet) {
PacketRouter router;
try {
router = (PacketRouterImpl)ServiceLookupFactory.getLookup().lookup(PacketRouterImpl.class);
......@@ -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) {
jid = jid.trim().toLowerCase();
return jid;
}
private void checkPresences() {
for (XMPPAddress prober : presenceMap.keySet()) {
XMPPAddress probee = presenceMap.get(prober);
for (JID prober : presenceMap.keySet()) {
JID probee = presenceMap.get(prober);
Component component = getComponent(probee.toBareStringPrep());
Component component = getComponent(probee.toBareJID());
if (component != null) {
Presence presence = new PresenceImpl();
presence.setSender(prober);
presence.setRecipient(probee);
Presence presence = new Presence();
presence.setFrom(prober);
presence.setTo(probee);
component.processPacket(presence);
// No reason to hold onto prober reference.
......@@ -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 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.xml.stream.XMLStreamException;
......@@ -128,5 +130,5 @@ public interface Connection {
* @throws UnauthorizedException If caller doesn't have permission to access this resource
* @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 @@
package org.jivesoftware.messenger;
import org.xmpp.packet.IQ;
/**
* <p>Route iq packets throughout the server.</p>
* <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 @@
package org.jivesoftware.messenger;
import org.xmpp.packet.Message;
/**
* <p>Route message packets throughout the server.</p>
* <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 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException;
import java.util.Iterator;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.database.DbConnectionManager;
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
......@@ -21,40 +28,154 @@ import java.util.Iterator;
* 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
* 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
*/
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();
/**
* Returns a singleton instance of OfflineMessageStore.
*
* @return an instance.
*/
public static OfflineMessageStore getInstance() {
return instance;
}
private SAXReader saxReader = new SAXReader();
private DocumentFactory docFactory = new DocumentFactory();
private OfflineMessageStore() {
}
/**
* Add a message to the message store. Messages will be stored and made available for
* later delivery.
* Adds a message to this message store. Messages will be stored and made
* available for later delivery.
*
* @param message The message to store (messages are standard XMPP message XML)
* @throws UnauthorizedException If the user is not allowed to store messages, or they have exceeded their quota
* @param message the message to store.
*/
void addMessage(Message message) throws UnauthorizedException;
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); }
}
}
/**
* <p>Obtain all messages in the store for a user.</p>
* <p>Remove messages using the iterator.remove() method. Otherwise
* messages stay in the message store and will be available to other
* users of getMessages().</p>
* 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
* @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
* @return The approximate size of messages stored in bytes
* @param username the username of the user.
* @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;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.Message;
/**
* <p>Configures and controls the server's offline message storage strategy.</p>
......
......@@ -12,6 +12,8 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
import javax.xml.stream.XMLStreamException;
/**
......@@ -32,6 +34,6 @@ public interface PacketDeliverer {
* @param packet The packet to route
* @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;
}
......@@ -11,6 +11,10 @@
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.XMLStreamReader;
......
......@@ -11,6 +11,8 @@
package org.jivesoftware.messenger;
import org.xmpp.packet.Packet;
/**
* <p>An uber router that can handle any packet type.</p>
* <p>The interface is provided primarily as a convenience for services
......@@ -30,5 +32,5 @@ public interface PacketRouter extends IQRouter, MessageRouter, PresenceRouter {
* @throws NullPointerException If the packet is null
* @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;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.User;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import java.util.Collection;
/**
......@@ -106,11 +109,10 @@ public interface PresenceManager {
* servlet session id.
*
* @param user the user to create a presence for.
* @param uid a unique string.
* @return the presence for 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.
......@@ -126,7 +128,7 @@ public interface PresenceManager {
* @param jid the user to set to be offline.
* @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.
......@@ -134,7 +136,7 @@ public interface PresenceManager {
* @param prober The user requesting the probe
* @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.
......@@ -142,5 +144,5 @@ public interface PresenceManager {
* @param prober The user requesting the probe
* @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 @@
package org.jivesoftware.messenger;
import org.xmpp.packet.JID;
/**
*
*
......@@ -26,5 +28,5 @@ public interface RoutableChannelHandler extends ChannelHandler {
*
* @return the XMPP address.
*/
public XMPPAddress getAddress();
public JID getAddress();
}
......@@ -11,6 +11,8 @@
package org.jivesoftware.messenger;
import org.xmpp.packet.JID;
import java.util.Iterator;
/**
......@@ -83,7 +85,7 @@ public interface RoutingTable {
* @param destination The destination object for this route
* @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>
......@@ -93,7 +95,7 @@ public interface RoutingTable {
* @return The handler corresponding to the route, or null indicating no route exists
* @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>
......@@ -103,7 +105,7 @@ public interface RoutingTable {
* @param node The address we want a route to
* @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>
......@@ -136,7 +138,7 @@ public interface RoutingTable {
* @return The Session corresponding to the route, or null indicating no route exists
* @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>
......@@ -145,5 +147,5 @@ public interface RoutingTable {
* @param node The address we want a route to
* @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;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager;
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.UnknownHostException;
import java.util.Date;
......@@ -24,11 +28,11 @@ import javax.xml.stream.XMLStreamWriter;
public class ServerSession implements Session {
private StreamID streamID;
private XMPPAddress address;
private JID address;
private Date creationDate;
private Connection connection = new ServerConnection();
public ServerSession(XMPPAddress address, StreamID streamID) {
public ServerSession(JID address, StreamID streamID) {
this.address = address;
this.streamID = streamID;
creationDate = new Date();
......@@ -112,11 +116,11 @@ public class ServerSession implements Session {
public void incrementConflictCount() {
}
public XMPPAddress getAddress() {
public JID getAddress() {
return address;
}
public void process(XMPPPacket packet) {
public void process(Packet packet) {
}
private class ServerConnection implements Connection {
......@@ -159,7 +163,7 @@ public class ServerSession implements Session {
return null;
}
public void deliver(XMPPPacket packet)
public void deliver(Packet packet)
throws UnauthorizedException {
}
......
......@@ -15,6 +15,9 @@ import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import java.util.Date;
/**
......@@ -46,7 +49,7 @@ public interface Session extends RoutableChannelHandler {
*
* @return the address of the packet handler.
*/
public XMPPAddress getAddress();
public JID getAddress();
/**
* 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;
import org.jivesoftware.messenger.container.Module;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
/**
* The XMPP server definition. An interface allows us to implement the
......@@ -42,7 +43,7 @@ public interface XMPPServer extends XMPPServerMBean, Module {
*
* @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.
......@@ -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.
* @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.
......
......@@ -11,7 +11,7 @@
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>
......@@ -29,7 +29,7 @@ public interface Auditor {
*
* @param packet the packet being audited
*/
void audit(XMPPPacket packet);
void audit(Packet packet);
/**
* Audit any packet that was dropped (undeliverables, etc).
......
......@@ -13,11 +13,12 @@ package org.jivesoftware.messenger.auth.spi;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.NodePrep;
import org.jivesoftware.messenger.auth.AuthFactory;
import org.jivesoftware.messenger.auth.AuthProvider;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import java.sql.Connection;
import java.sql.PreparedStatement;
......@@ -72,7 +73,12 @@ public class DbAuthProvider implements AuthProvider {
if (username == null || password == null) {
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;
PreparedStatement pstmt = null;
try {
......@@ -119,7 +125,12 @@ public class DbAuthProvider implements AuthProvider {
if (username == null || token == null || digest == null) {
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;
PreparedStatement pstmt = null;
try {
......@@ -167,7 +178,12 @@ public class DbAuthProvider implements AuthProvider {
if (username == null || password == null) {
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;
PreparedStatement pstmt = null;
try {
......
......@@ -12,8 +12,9 @@
package org.jivesoftware.messenger.disco;
import org.jivesoftware.messenger.forms.XDataForm;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
import java.util.Iterator;
/**
......@@ -38,7 +39,7 @@ public interface DiscoInfoProvider {
* @param senderJID the XMPPAddress of user that sent the disco info request.
* @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
......@@ -50,7 +51,7 @@ public interface DiscoInfoProvider {
* @param senderJID the XMPPAddress of user that sent the disco info request.
* @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
......@@ -61,7 +62,7 @@ public interface DiscoInfoProvider {
* @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.
*/
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
......@@ -75,6 +76,6 @@ public interface DiscoInfoProvider {
* @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.
*/
public abstract boolean hasInfo(String name, String node, XMPPAddress senderJID)
public abstract boolean hasInfo(String name, String node, JID senderJID)
throws UnauthorizedException;
}
......@@ -11,8 +11,9 @@
package org.jivesoftware.messenger.disco;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
import java.util.Iterator;
/**
......@@ -40,7 +41,7 @@ public interface DiscoItemsProvider {
* @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.
*/
public abstract Iterator getItems(String name, String node, XMPPAddress senderJID)
public abstract Iterator getItems(String name, String node, JID senderJID)
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 @@
package org.jivesoftware.messenger.forms.spi;
import org.jivesoftware.messenger.forms.FormField;
import org.jivesoftware.messenger.forms.XDataForm;
import org.jivesoftware.messenger.XMPPFragment;
import org.jivesoftware.util.ConcurrentHashSet;
import java.util.*;
......@@ -48,7 +46,7 @@ import org.dom4j.QName;
*
* @author gdombiak
*/
public class XDataFormImpl implements XDataForm {
public class XDataFormImpl {
private String type;
private String title;
......
......@@ -143,7 +143,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
Session session,
String digest)
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
......
......@@ -17,6 +17,10 @@ import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
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;
/**
......@@ -47,8 +51,8 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler {
this.router = router;
}
public void process(XMPPPacket xmppPacket) throws UnauthorizedException, PacketException {
IQ iq = (IQ)xmppPacket;
public void process(Packet packet) throws UnauthorizedException, PacketException {
IQ iq = (IQ)packet;
try {
iq = handleIQ(iq);
if (iq != null) {
......@@ -58,8 +62,8 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler {
catch (org.jivesoftware.messenger.auth.UnauthorizedException e) {
if (iq != null) {
try {
XMPPPacket response = iq.createResult();
response.setError(XMPPError.Code.UNAUTHORIZED);
IQ response = IQ.createResultIQ(iq);
response.setError(PacketError.Condition.not_authorized);
Session session = iq.getOriginatingSession();
if (!session.getConnection().isClosed()) {
session.getConnection().deliver(response);
......
......@@ -11,9 +11,9 @@
package org.jivesoftware.messenger.muc;
import org.jivesoftware.messenger.IQ;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.Presence;
import org.xmpp.packet.Message;
import org.xmpp.packet.Presence;
import org.xmpp.packet.IQ;
/**
* Interface for any object that can accept chat messages and presence
......@@ -22,6 +22,7 @@ import org.jivesoftware.messenger.Presence;
* @author Gaston Dombiak
*/
public interface ChatDeliverer {
/**
* Sends a packet to the user.
*
......
......@@ -22,8 +22,6 @@ import java.util.TimeZone;
import org.jivesoftware.messenger.muc.spi.MUCRoleImpl;
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
......
......@@ -12,8 +12,8 @@
package org.jivesoftware.messenger.muc;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.JiveGlobals;
import org.xmpp.packet.Message;
import java.util.Iterator;
import java.util.LinkedList;
......
......@@ -11,9 +11,9 @@
package org.jivesoftware.messenger.muc;
import org.jivesoftware.messenger.MetaDataFragment;
import org.jivesoftware.messenger.Presence;
import org.jivesoftware.messenger.XMPPAddress;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
import org.dom4j.Element;
/**
* Defines the permissions and actions that a MUCUser may use in
......@@ -82,7 +82,7 @@ public interface MUCRole extends ChatDeliverer {
* @return the extended presence information that includes information about roles,
* affiliations.
*/
MetaDataFragment getExtendedPresenceInformation();
Element getExtendedPresenceInformation();
/**
* Set the current presence status of a user in a chatroom.
......@@ -183,5 +183,5 @@ public interface MUCRole extends ChatDeliverer {
*
* @return The Jabber ID that represents this role in the room.
*/
XMPPAddress getRoleAddress();
JID getRoleAddress();
}
......@@ -18,13 +18,12 @@ import java.util.Collection;
import org.jivesoftware.messenger.muc.spi.IQAdminHandler;
import org.jivesoftware.messenger.muc.spi.IQOwnerHandler;
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.user.UserAlreadyExistsException;
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 {
* @return The new presence
* @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
......@@ -340,7 +339,7 @@ public interface MUCRoom extends ChatDeliverer {
* an existing occupant.
* @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
......@@ -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 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;
/**
......@@ -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
* to the room.
*
* @param fullJID 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 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.
* @return the updated presence of the occupant or <tt>null</tt> if the JID does not belong to
* an existing occupant.
* @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 NotAllowedException if trying to change the moderator role to an owner or an admin.
* @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;
/**
......@@ -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.
* @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;
public IQOwnerHandler getIQOwnerHandler();
......@@ -785,13 +784,12 @@ public interface MUCRoom extends ChatDeliverer {
* need the originating session so that the offline strategy could potentially bounce the
* 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 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.
*/
public void sendInvitation(String to, String reason, MUCRole role, Session session)
public void sendInvitation(JID to, String reason, MUCRole role)
throws ForbiddenException;
/**
......@@ -801,11 +799,9 @@ public interface MUCRoom extends ChatDeliverer {
* moment we need the originating session so that the offline strategy could potentially bounce
* 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 sender the address of the invitee that is rejecting the invitation.
* @param session the originating session that the invitee used for rejecting the invitation.
* @param from the JID of the invitee that is rejecting the invitation.
*/
public void sendInvitationRejection(String to, String reason, XMPPAddress sender,
Session session);
public void sendInvitationRejection(JID to, String reason, JID from);
}
\ No newline at end of file
......@@ -17,11 +17,10 @@ import java.util.Iterator;
import java.util.ListIterator;
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.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,
......@@ -51,16 +50,12 @@ public final class MUCRoomHistory {
public void addMessage(Message packet) {
// Don't keep messages whose sender is the room itself (thus address without resource)
// unless the message is changing the room's subject
if ((packet.getSender().getResourcePrep() == null
|| packet.getSender().getResourcePrep().length() == 0) &&
if ((packet.getFrom() == null
|| packet.getFrom().toString().length() == 0) &&
packet.getSubject() == null) {
return;
}
Message packetToAdd = (Message) packet.createDeepCopy();
// 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);
Message packetToAdd = (Message) packet.createCopy();
// TODO Analyze concurrency (on the LinkList) when adding many messages simultaneously
......@@ -69,47 +64,46 @@ public final class MUCRoomHistory {
isNonAnonymousRoom = room.canAnyoneDiscoverJID();
// Update the "from" attribute of the delay information in the history
Message message;
MetaDataFragment frag;
Element delayElement;
// TODO Make this update in a separate thread
for (Iterator it = getMessageHistory(); it.hasNext();) {
message = (Message) it.next();
frag = (MetaDataFragment) message.getFragment("x", "jabber:x:delay");
delayElement = message.getChildElement("x", "jabber:x:delay");
if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute
try {
MUCRole role = room.getOccupant(message.getSender().getResourcePrep());
frag.setProperty("x:from", role.getChatUser().getAddress().toStringPrep());
MUCRole role = room.getOccupant(message.getFrom().getResource());
delayElement.addAttribute("from", role.getChatUser().getAddress().toString());
}
catch (UserNotFoundException e) {
}
}
else {
// 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
MetaDataFragment delayInformation = new MetaDataFragment("jabber:x:delay", "x");
Element delayInformation = packetToAdd.addChildElement("x", "jabber:x:delay");
Date current = new Date();
delayInformation.setProperty("x:stamp", UTC_FORMAT.format(current));
delayInformation.addAttribute("stamp", UTC_FORMAT.format(current));
if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute
try {
MUCRole role = room.getOccupant(packet.getSender().getResourcePrep());
delayInformation.setProperty("x:from", role.getChatUser().getAddress()
.toStringPrep());
MUCRole role = room.getOccupant(packet.getFrom().getResource());
delayInformation.addAttribute("from", role.getChatUser().getAddress()
.toString());
}
catch (UserNotFoundException e) {
}
}
else {
// 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);
}
......@@ -140,36 +134,36 @@ public final class MUCRoomHistory {
* @param body the body of the message.
*/
public void addOldMessage(String senderJID, String nickname, Date sentDate, String subject,
String body) {
Message packetToAdd = new MessageImpl();
packetToAdd.setType(Message.GROUP_CHAT);
packetToAdd.setSubject(subject);
packetToAdd.setBody(body);
String body)
{
Message message = new Message();
message.setType(Message.Type.groupchat);
message.setSubject(subject);
message.setBody(body);
// Set the sender of the message
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
packetToAdd.setSender(new XMPPAddress(roomJID.getNamePrep(), roomJID.getHostPrep(),
message.setFrom(new JID(roomJID.getNode(), roomJID.getDomain(),
nickname));
}
else {
// 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
MetaDataFragment delayInformation = new MetaDataFragment("jabber:x:delay", "x");
delayInformation.setProperty("x:stamp", UTC_FORMAT.format(sentDate));
Element delayInformation = message.addChildElement("x", "jabber:x:deley");
delayInformation.addAttribute("stamp", UTC_FORMAT.format(sentDate));
if (room.canAnyoneDiscoverJID()) {
// Set the Full JID as the "from" attribute
delayInformation.setProperty("x:from", senderJID);
delayInformation.addAttribute("from", senderJID);
}
else {
// 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(packetToAdd);
historyStrategy.addMessage(message);
}
/**
......
......@@ -12,8 +12,8 @@
package org.jivesoftware.messenger.muc;
import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.ChannelHandler;
import org.xmpp.packet.JID;
import java.util.Iterator;
......@@ -47,7 +47,7 @@ public interface MUCUser extends ChannelHandler {
*
* @return the address of the packet handler.
*/
public XMPPAddress getAddress();
public JID getAddress();
/**
* Obtain the role of the user in a particular room.
......
......@@ -16,7 +16,8 @@ import java.util.Collection;
import org.jivesoftware.messenger.auth.UnauthorizedException;
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
......@@ -192,7 +193,7 @@ public interface MultiUserChatServer {
* @return The chatroom for the given name.
* @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.
......@@ -230,7 +231,7 @@ public interface MultiUserChatServer {
*
* @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.
......@@ -239,7 +240,7 @@ public interface MultiUserChatServer {
* @return The chatuser corresponding to that XMPPAddress.
* @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
......@@ -271,5 +272,5 @@ public interface MultiUserChatServer {
* @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).
*/
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;
import java.util.Date;
import org.jivesoftware.messenger.muc.MUCRoom;
import org.jivesoftware.messenger.Message;
import org.jivesoftware.messenger.XMPPAddress;
import org.xmpp.packet.Message;
import org.xmpp.packet.JID;
/**
* Represents an entry in the conversation log of a room. An entry basically obtains the necessary
......@@ -31,7 +31,7 @@ class ConversationLogEntry {
private String body;
private XMPPAddress sender;
private JID sender;
private String nickname;
......@@ -46,13 +46,13 @@ class ConversationLogEntry {
* @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).
*/
public ConversationLogEntry(Date date, MUCRoom room, Message message, XMPPAddress sender) {
public ConversationLogEntry(Date date, MUCRoom room, Message message, JID sender) {
this.date = date;
this.subject = message.getSubject();
this.body = message.getBody();
this.sender = sender;
this.roomID = room.getID();
this.nickname = message.getSender().getResourcePrep();
this.nickname = message.getFrom().getResource();
}
/**
......@@ -69,7 +69,7 @@ class ConversationLogEntry {
*
* @return the XMPP address of the logged message's sender.
*/
public XMPPAddress getSender() {
public JID getSender() {
return sender;
}
......
......@@ -12,15 +12,15 @@
package org.jivesoftware.messenger.muc.spi;
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.Presence;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.Log;
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
......@@ -73,12 +73,12 @@ public class MUCRoleImpl implements MUCRole {
/**
* 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.
*/
private MetaDataFragment extendedInformation;
private Element extendedInformation;
/**
* Create a new role.
......@@ -93,13 +93,10 @@ public class MUCRoleImpl implements MUCRole {
* @throws UnauthorizedException if the role could not be created due to security or permission
* violations
*/
public MUCRoleImpl(MultiUserChatServer chatserver,
MUCRoomImpl chatroom,
String nickname,
int role,
int affiliation,
MUCUserImpl chatuser,
PacketRouter packetRouter) throws UnauthorizedException {
public MUCRoleImpl(MultiUserChatServer chatserver, MUCRoomImpl chatroom,
String nickname, int role, int affiliation, MUCUserImpl chatuser,
PacketRouter packetRouter) throws UnauthorizedException
{
this.room = chatroom;
this.nick = nickname;
this.user = chatuser;
......@@ -109,22 +106,22 @@ public class MUCRoleImpl implements MUCRole {
this.affiliation = affiliation;
extendedInformation = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x");
calculateExtendedInformation();
rJID = new XMPPAddress(room.getName(), server.getServiceName(), nick);
setPresence(room.createPresence(Presence.STATUS_ONLINE));
rJID = new JID(room.getName(), server.getServiceName(), nick);
setPresence(room.createPresence(null));
}
public Presence getPresence() {
return presence;
}
public MetaDataFragment getExtendedPresenceInformation() {
public Element getExtendedPresenceInformation() {
return extendedInformation;
}
public void setPresence(Presence newPresence) {
this.presence = newPresence;
if (extendedInformation != null) {
presence.addFragment(extendedInformation);
presence.getElement().add(extendedInformation.createCopy());
}
}
......@@ -144,13 +141,7 @@ public class MUCRoleImpl implements MUCRole {
role = newRole;
if (MUCRole.NONE_ROLE == role) {
try {
presence.setAvailable(false);
presence.setVisible(false);
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
presence.setType(Presence.Type.unavailable);
}
calculateExtendedInformation();
}
......@@ -214,7 +205,7 @@ public class MUCRoleImpl implements MUCRole {
public void changeNickname(String nickname) {
this.nick = nickname;
rJID = new XMPPAddress(room.getName(), server.getServiceName(), nick);
rJID = new JID(room.getName(), server.getServiceName(), nick);
}
public MUCUser getChatUser() {
......@@ -225,30 +216,31 @@ public class MUCRoleImpl implements MUCRole {
return room;
}
public XMPPAddress getRoleAddress() {
public JID getRoleAddress() {
return rJID;
}
public void send(Presence packet) {
packet.setRecipient(user.getAddress());
packet.setTo(user.getAddress());
router.route(packet);
}
public void send(Message packet) {
packet.setRecipient(user.getAddress());
packet.setTo(user.getAddress());
router.route(packet);
}
public void send(IQ packet) {
packet.setRecipient(user.getAddress());
packet.setTo(user.getAddress());
router.route(packet);
}
/**
* Calculates and sets the extended presence information to add to the presence. The information
* to add contains the user's jid, affiliation and role.
* Calculates and sets the extended presence information to add to the presence.
* The information to add contains the user's jid, affiliation and role.
*/
private void calculateExtendedInformation() {
extendedInformation.setProperty("x.item:jid", user.getAddress().toString());
extendedInformation.setProperty("x.item:affiliation", getAffiliationAsString());
extendedInformation.setProperty("x.item:role", getRoleAsString());
......
......@@ -22,10 +22,10 @@ import org.jivesoftware.messenger.muc.*;
import org.jivesoftware.util.*;
import org.jivesoftware.messenger.*;
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.UserNotFoundException;
import org.xmpp.packet.*;
import org.dom4j.Element;
/**
* Simple in-memory implementation of a chatroom. A MUCRoomImpl could represent a persistent room
......@@ -62,7 +62,7 @@ public class MUCRoomImpl implements MUCRoom {
/**
* 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.
......@@ -392,7 +392,7 @@ public class MUCRoomImpl implements MUCRoom {
if (isDestroyed || (getMaxUsers() > 0 && getOccupantsCount() >= getMaxUsers())) {
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 (roomLocked) {
if (!isOwner) {
......@@ -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
// raise a ConflictException
if (members.containsValue(nickname)) {
if (!nickname.equals(members.get(user.getAddress().toBareStringPrep()))) {
if (!nickname.equals(members.get(user.getAddress().toBareJID()))) {
throw new ConflictException();
}
}
......@@ -426,23 +426,23 @@ public class MUCRoomImpl implements MUCRoom {
role = MUCRole.MODERATOR;
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
// although he won't appear in the list of owners
role = MUCRole.MODERATOR;
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.
role = MUCRole.MODERATOR;
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.
role = MUCRole.PARTICIPANT;
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.
throw new ForbiddenException();
}
......@@ -463,28 +463,28 @@ public class MUCRoomImpl implements MUCRoom {
// Send presence of existing occupants to new occupant
for (MUCRole occupantsRole : occupants.values()) {
Presence occupantsPresence = (Presence) occupantsRole.getPresence()
.createDeepCopy();
occupantsPresence.setSender(occupantsRole.getRoleAddress());
.createCopy();
occupantsPresence.setFrom(occupantsRole.getRoleAddress());
// Don't include the occupant's JID if the room is semi-anon and the new occupant
// is not a moderator
if (!canAnyoneDiscoverJID() && MUCRole.MODERATOR != joinRole.getRole()) {
MetaDataFragment frag = (MetaDataFragment) occupantsPresence.getFragment(
Element frag = occupantsPresence.getChildElement(
"x",
"http://jabber.org/protocol/muc#user");
frag.deleteProperty("x.item:jid");
frag.element("item").addAttribute("jid", null);
}
joinRole.send(occupantsPresence);
}
// Add the new user as an occupant of this room
occupants.put(nickname.toLowerCase(), joinRole);
// 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) {
list = new ArrayList<MUCRole>();
occupantsByBareJID.put(user.getAddress().toBareStringPrep(), list);
occupantsByBareJID.put(user.getAddress().toBareJID(), list);
}
list.add(joinRole);
occupantsByFullJID.put(user.getAddress().toStringPrep(), joinRole);
occupantsByFullJID.put(user.getAddress(), joinRole);
}
finally {
lock.writeLock().unlock();
......@@ -497,14 +497,13 @@ public class MUCRoomImpl implements MUCRoom {
params.add(nickname);
try {
// Send the presence of this new occupant to existing occupants
Presence joinPresence = (Presence) joinRole.getPresence().createDeepCopy();
Presence joinPresence = joinRole.getPresence().createCopy();
if (isRoomNew) {
MetaDataFragment frag = (MetaDataFragment) joinPresence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
frag.setProperty("x.status:code", "201");
Element frag = joinPresence.getChildElement(
"x", "http://jabber.org/protocol/muc#user");
frag.element("status").addAttribute("code", "201");
}
joinPresence.setSender(joinRole.getRoleAddress());
joinPresence.setFrom(joinRole.getRoleAddress());
broadcastPresence(joinPresence);
}
......@@ -518,25 +517,23 @@ public class MUCRoomImpl implements MUCRoom {
// If the room has just been created send the "room locked until configuration is
// confirmed" message
if (isRoomNew) {
Message message = new MessageImpl();
message.setType(Message.GROUP_CHAT);
Message message = new Message();
message.setType(Message.Type.groupchat);
message.setBody(LocaleUtils.getLocalizedString("muc.locked"));
message.setSender(role.getRoleAddress());
message.setRecipient(user.getAddress());
message.setFrom(role.getRoleAddress());
message.setTo(user.getAddress());
router.route(message);
}
else if (canAnyoneDiscoverJID()) {
// Warn the new occupant that the room is non-anonymous (i.e. his JID will be
// public)
Message message = new MessageImpl();
message.setType(Message.GROUP_CHAT);
Message message = new Message();
message.setType(Message.Type.groupchat);
message.setBody(LocaleUtils.getLocalizedString("muc.warnnonanonymous"));
message.setSender(role.getRoleAddress());
message.setRecipient(user.getAddress());
MetaDataFragment frag = new MetaDataFragment("http://jabber.org/protocol/muc#user",
"x");
frag.setProperty("x.status:code", "100");
message.addFragment(frag);
message.setFrom(role.getRoleAddress());
message.setTo(user.getAddress());
Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
frag.addElement("status").addAttribute("code", "100");
router.route(message);
}
if (historyRequest == null) {
......@@ -584,10 +581,10 @@ public class MUCRoomImpl implements MUCRoom {
if (leaveRole != null) {
try {
Presence presence = createPresence(Presence.STATUS_OFFLINE);
presence.setSender(leaveRole.getRoleAddress());
presence.addFragment(leaveRole.getExtendedPresenceInformation());
broadcastPresence((Presence) presence.createDeepCopy());
Presence presence = createPresence(Presence.Type.unavailable);
presence.setFrom(leaveRole.getRoleAddress());
presence.getElement().add(leaveRole.getExtendedPresenceInformation().createCopy());
broadcastPresence(presence.createCopy());
leaveRole.kick();
List params = new ArrayList();
params.add(nickname);
......@@ -610,14 +607,14 @@ public class MUCRoomImpl implements MUCRoom {
MUCUser user = leaveRole.getChatUser();
// 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) {
list.remove(leaveRole);
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) {
......@@ -631,24 +628,32 @@ public class MUCRoomImpl implements MUCRoom {
if (leaveRole != null) {
try {
// Send a presence stanza of type "unavailable" to the occupant
Presence presence = createPresence(Presence.STATUS_OFFLINE);
presence.setSender(leaveRole.getRoleAddress());
presence.setRecipient(leaveRole.getChatUser().getAddress());
Presence presence = createPresence(Presence.Type.unavailable);
presence.setFrom(leaveRole.getRoleAddress());
presence.setTo(leaveRole.getChatUser().getAddress());
// A fragment containing the x-extension for room destruction.
// TODO Analyze if we need/can reuse the same fragment instead of creating a
// new one each time
MetaDataFragment fragment;
fragment = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x");
fragment.setProperty("x.item:affiliation", "none");
fragment.setProperty("x.item:role", "none");
Element fragment;
fragment = presence.addChildElement("x", "http://jabber.org/protocol/muc#user");
Element item = fragment.addElement("item");
item.addAttribute("affiliation", "none");
item.addAttribute("role", "none");
if (alternateJID != null && alternateJID.length() > 0) {
fragment.setProperty("x.destroy:jid", alternateJID);
fragment.addElement("destroy").addAttribute("jid", alternateJID);
}
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);
leaveRole.kick();
......@@ -670,28 +675,18 @@ public class MUCRoomImpl implements MUCRoom {
}
}
public Presence createPresence(int presenceStatus) throws UnauthorizedException {
Presence presence = new PresenceImpl();
presence.setSender(role.getRoleAddress());
switch (presenceStatus) {
case Presence.STATUS_ONLINE:
presence.setAvailable(true);
presence.setVisible(true);
break;
case Presence.STATUS_OFFLINE:
presence.setAvailable(false);
presence.setVisible(false);
break;
default:
}
public Presence createPresence(Presence.Type presenceType) throws UnauthorizedException {
Presence presence = new Presence();
presence.setType(presenceType);
presence.setFrom(role.getRoleAddress());
return presence;
}
public void serverBroadcast(String msg) {
Message message = new MessageImpl();
message.setType(Message.GROUP_CHAT);
Message message = new Message();
message.setType(Message.Type.groupchat);
message.setBody(msg);
message.setSender(role.getRoleAddress());
message.setFrom(role.getRoleAddress());
roomHistory.addMessage(message);
broadcast(message);
}
......@@ -702,16 +697,16 @@ public class MUCRoomImpl implements MUCRoom {
throw new ForbiddenException();
}
// Send the message to all occupants
message.setSender(senderRole.getRoleAddress());
message.setFrom(senderRole.getRoleAddress());
send(message);
}
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());
if (occupant != null) {
message.setSender(senderRole.getRoleAddress());
message.setRecipient(occupant.getChatUser().getAddress());
message.setFrom(senderRole.getRoleAddress());
message.setTo(occupant.getChatUser().getAddress());
router.route(message);
}
else {
......@@ -730,10 +725,10 @@ public class MUCRoomImpl implements MUCRoom {
}
public void send(IQ packet) {
packet = (IQ) packet.createDeepCopy();
packet.setError(XMPPError.Code.BAD_REQUEST);
packet.setRecipient(packet.getSender());
packet.setSender(role.getRoleAddress());
packet = packet.createCopy();
packet.setError(PacketError.Condition.bad_request);
packet.setTo(packet.getFrom());
packet.setFrom(role.getRoleAddress());
router.route(packet);
}
......@@ -742,19 +737,17 @@ public class MUCRoomImpl implements MUCRoom {
return;
}
MetaDataFragment frag = null;
Element frag = null;
String jid = null;
if (hasToCheckRoleToBroadcastPresence()) {
frag = (MetaDataFragment) presence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
// 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
try {
MUCRole occupant = getOccupant(presence.getSender().getResourcePrep());
presence.setRecipient(occupant.getChatUser().getAddress());
MUCRole occupant = getOccupant(presence.getFrom().getResource());
presence.setTo(occupant.getChatUser().getAddress());
router.route(presence);
}
catch (UserNotFoundException e) {
......@@ -768,22 +761,20 @@ public class MUCRoomImpl implements MUCRoom {
// is not a moderator
if (!canAnyoneDiscoverJID()) {
if (frag == null) {
frag = (MetaDataFragment) presence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
}
jid = frag.getProperty("x.item:jid");
jid = frag.element("item").attributeValue("jid");
}
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
// is not a moderator
if (!canAnyoneDiscoverJID()) {
if (MUCRole.MODERATOR == occupant.getRole()) {
frag.setProperty("x.item:jid", jid);
frag.element("item").addAttribute("jid", jid);
}
else {
frag.deleteProperty("x.item:jid");
frag.element("item").addAttribute("jid", null);
}
}
router.route(presence);
......@@ -794,13 +785,13 @@ public class MUCRoomImpl implements MUCRoom {
lock.readLock().lock();
try {
for (MUCRole occupant : occupants.values()) {
message.setRecipient(occupant.getChatUser().getAddress());
message.setTo(occupant.getChatUser().getAddress());
router.route(message);
}
if (isLogEnabled()) {
MUCRole senderRole;
XMPPAddress senderAddress;
senderRole = occupants.get(message.getSender().getResourcePrep());
JID senderAddress;
senderRole = occupants.get(message.getTo().getResource());
if (senderRole == null) {
// The room itself is sending the message
senderAddress = getRole().getRoleAddress();
......@@ -834,7 +825,7 @@ public class MUCRoomImpl implements MUCRoom {
return null;
}
public MetaDataFragment getExtendedPresenceInformation() {
public Element getExtendedPresenceInformation() {
return null;
}
......@@ -878,11 +869,11 @@ public class MUCRoomImpl implements MUCRoom {
return room;
}
private XMPPAddress crJID = null;
private JID crJID = null;
public XMPPAddress getRoleAddress() {
public JID getRoleAddress() {
if (crJID == null) {
crJID = new XMPPAddress(room.getName(), server.getServiceName(), "");
crJID = new JID(room.getName(), server.getServiceName(), "");
}
return crJID;
}
......@@ -936,8 +927,8 @@ public class MUCRoomImpl implements MUCRoom {
role.setAffiliation(newAffiliation);
role.setRole(newRole);
// Prepare a new presence to be sent to all the room occupants
Presence presence = (Presence) role.getPresence().createDeepCopy();
presence.setSender(role.getRoleAddress());
Presence presence = role.getPresence().createCopy();
presence.setFrom(role.getRoleAddress());
presences.add(presence);
}
// Answer all the updated presences
......@@ -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
* 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.
* @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.
*/
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
MUCRole role = occupantsByFullJID.get(fullJID);
MUCRole role = occupantsByFullJID.get(jid);
if (role != null) {
// Update the presence with the new role
role.setRole(newRole);
// Prepare a new presence to be sent to all the room occupants
Presence presence = (Presence) role.getPresence().createDeepCopy();
presence.setSender(role.getRoleAddress());
Presence presence = role.getPresence().createCopy();
presence.setFrom(role.getRoleAddress());
return presence;
}
return null;
......@@ -1125,10 +1116,10 @@ public class MUCRoomImpl implements MUCRoom {
throw new ConflictException();
}
// 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
if (senderRole.getChatUser() != null) {
actorJID = senderRole.getChatUser().getAddress().toBareStringPrep();
actorJID = senderRole.getChatUser().getAddress();
}
List<Presence> updatedPresences = changeOccupantAffiliation(
bareJID,
......@@ -1136,19 +1127,17 @@ public class MUCRoomImpl implements MUCRoom {
MUCRole.NONE_ROLE);
if (!updatedPresences.isEmpty()) {
Presence presence;
MetaDataFragment frag;
Element frag;
// 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)
for (Iterator it = updatedPresences.iterator(); it.hasNext();) {
presence = (Presence) it.next();
frag = (MetaDataFragment) presence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
// 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
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
......@@ -1228,31 +1217,24 @@ public class MUCRoomImpl implements MUCRoom {
// code of 321 to indicate that the user was removed because of an affiliation
// change
Presence presence;
MetaDataFragment frag;
Element frag;
// Add the status code to the presences that will be sent to the room occupants
for (Iterator it = updatedPresences.iterator(); it.hasNext();) {
presence = (Presence) it.next();
// Set the presence as an unavailable presence
try {
presence.setAvailable(false);
presence.setVisible(false);
}
catch (UnauthorizedException e) {
}
frag = (MetaDataFragment) presence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
presence.setType(Presence.Type.unavailable);
frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
// Add the status code 321 that indicates that the user was removed because of
// 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
// different client resources, he/she will be kicked from all the client
// resources.
// Effectively kick the occupant from the room
MUCUser senderUser = senderRole.getChatUser();
String actorJID = (senderUser == null ?
null : senderUser.getAddress().toBareStringPrep());
JID actorJID = (senderUser == null ?
null : senderUser.getAddress());
kickPresence(presence, actorJID);
}
}
......@@ -1289,7 +1271,7 @@ public class MUCRoomImpl implements MUCRoom {
subject = packet.getSubject();
MUCPersistenceManager.updateRoomSubject(this, subject);
// Notify all the occupants that the subject has changed
packet.setSender(role.getRoleAddress());
packet.setFrom(role.getRoleAddress());
send(packet);
}
else {
......@@ -1305,35 +1287,36 @@ public class MUCRoomImpl implements MUCRoom {
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 {
if (!isInvitationRequiredToEnter() || canOccupantsInvite()
|| MUCRole.ADMINISTRATOR == senderRole.getAffiliation()
|| MUCRole.OWNER == senderRole.getAffiliation()) {
// 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
Message message = new MessageImpl();
message.setOriginatingSession(session);
message.setSender(role.getRoleAddress());
message.setRecipient(XMPPAddress.parseJID(to));
MetaDataFragment frag = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x");
Message message = new Message();
message.setFrom(role.getRoleAddress());
message.setTo(to);
Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
// ChatUser will be null if the room itself (ie. via admin console) made the request
if (senderRole.getChatUser() != null) {
frag.setProperty("x.invite:from", senderRole.getChatUser().getAddress()
.toBareStringPrep());
frag.addElement("invite").addAttribute("from", senderRole.getChatUser().getAddress()
.toBareJID());
}
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()) {
frag.setProperty("x.password", getPassword());
frag.addElement("password").setText(getPassword());
}
message.addFragment(frag);
// Include the jabber:x:conference information for backward compatibility
frag = new MetaDataFragment("jabber:x:conference", "x");
frag.setProperty("x:jid", role.getRoleAddress().toBareStringPrep());
message.addFragment(frag);
frag = message.addChildElement("x", "jabber:x:conference");
frag.addAttribute("jid", role.getRoleAddress().toBareJID());
// Send the message with the invitation
router.route(message);
......@@ -1343,18 +1326,15 @@ public class MUCRoomImpl implements MUCRoom {
}
}
public void sendInvitationRejection(String to, String reason, XMPPAddress sender,
Session session) {
Message message = new MessageImpl();
message.setOriginatingSession(session);
message.setSender(role.getRoleAddress());
message.setRecipient(XMPPAddress.parseJID(to));
MetaDataFragment frag = new MetaDataFragment("http://jabber.org/protocol/muc#user", "x");
frag.setProperty("x.decline:from", sender.toBareStringPrep());
public void sendInvitationRejection(JID to, String reason, JID sender) {
Message message = new Message();
message.setFrom(role.getRoleAddress());
message.setTo(to);
Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
frag.addElement("decline").addAttribute("from", sender.toBareJID());
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
router.route(message);
......@@ -1408,14 +1388,14 @@ public class MUCRoomImpl implements MUCRoom {
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()
&& MUCRole.OWNER != senderRole.getAffiliation()) {
throw new ForbiddenException();
}
// Update the presence with the new role and inform all occupants
try {
return changeOccupantRole(fullJID, MUCRole.MODERATOR);
return changeOccupantRole(jid, MUCRole.MODERATOR);
}
catch (NotAllowedException e) {
// We should never receive this exception....in theory
......@@ -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 {
if (MUCRole.MODERATOR != senderRole.getRole()) {
throw new ForbiddenException();
}
// 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) {
MetaDataFragment frag = (MetaDataFragment) updatedPresence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
Element frag = updatedPresence.getChildElement(
"x", "http://jabber.org/protocol/muc#user");
// Add the reason why the user was granted voice
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;
}
public Presence addVisitor(String fullJID, MUCRole senderRole) throws NotAllowedException,
public Presence addVisitor(JID jid, MUCRole senderRole) throws NotAllowedException,
ForbiddenException {
if (MUCRole.MODERATOR != senderRole.getRole()) {
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 {
// 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) {
MetaDataFragment frag = (MetaDataFragment) updatedPresence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
Element frag = updatedPresence.getChildElement(
"x", "http://jabber.org/protocol/muc#user");
// 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
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
......@@ -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
* was not provided.
*/
private void kickPresence(Presence kickPresence, String actorJID) {
private void kickPresence(Presence kickPresence, JID actorJID) {
MUCRole kickedRole;
// Get the role to kick
kickedRole = occupants.get(kickPresence.getSender().getResourcePrep());
kickedRole = occupants.get(kickPresence.getFrom().getResource());
if (kickedRole != null) {
kickPresence = (Presence) kickPresence.createDeepCopy();
kickPresence = kickPresence.createCopy();
// Add the actor's JID that kicked this user from the room
if (actorJID != null && actorJID.trim().length() > 0) {
MetaDataFragment frag = (MetaDataFragment) kickPresence.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
frag.setProperty("x.item.actor:jid", actorJID);
if (actorJID != null && actorJID.toString().length() > 0) {
Element frag = kickPresence.getChildElement(
"x", "http://jabber.org/protocol/muc#user");
Element item = frag.element("item");
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
kickedRole.send(kickPresence);
......@@ -1554,17 +1558,10 @@ public class MUCRoomImpl implements MUCRoom {
// of the room
for (MUCRole occupant : occupants.values()) {
if (occupant.getAffiliation() > MUCRole.MEMBER) {
try {
presences.add(kickOccupant(occupant.getChatUser().getAddress()
.toStringPrep(), null,
LocaleUtils.getLocalizedString("muc.roomIsNowMembersOnly")));
}
catch (NotAllowedException e) {
// Do Nothing
}
presences.add(kickOccupant(jid, null,
LocaleUtils.getLocalizedString("muc.roomIsNowMembersOnly")));
}
}
}
this.invitationRequiredToEnter = invitationRequiredToEnter;
return presences;
......@@ -1667,11 +1664,11 @@ public class MUCRoomImpl implements MUCRoom {
this.lockedTime = 0;
if (senderRole.getChatUser() != null) {
// Send to the occupant that unlocked the room a message saying so
Message message = new MessageImpl();
message.setType(Message.GROUP_CHAT);
Message message = new Message();
message.setType(Message.Type.groupchat);
message.setBody(LocaleUtils.getLocalizedString("muc.unlocked"));
message.setSender(getRole().getRoleAddress());
message.setRecipient(senderRole.getChatUser().getAddress());
message.setFrom(getRole().getRoleAddress());
message.setTo(senderRole.getChatUser().getAddress());
router.route(message);
}
}
......
......@@ -22,6 +22,7 @@ import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
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
......@@ -35,7 +36,7 @@ public class MUCUserImpl implements MUCUser {
private MultiUserChatServer server;
/** Real system XMPPAddress for the user. */
private XMPPAddress realjid;
private JID realjid;
/** Table: key roomName.toLowerCase(); value MUCRole. */
private Map<String, MUCRole> roles = new ConcurrentHashMap<String, MUCRole>();
......@@ -55,7 +56,7 @@ public class MUCUserImpl implements MUCUser {
* @param packetRouter the router for sending packets from this 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.router = packetRouter;
this.server = chatserver;
......@@ -89,22 +90,21 @@ public class MUCUserImpl implements MUCUser {
* Generate a conflict packet to indicate that the nickname being requested/used is already in
* 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) {
packet = (XMPPPacket) packet.createDeepCopy();
packet.setError(errorCode);
XMPPAddress sender = packet.getSender();
packet.setSender(packet.getRecipient());
packet.setRecipient(sender);
private void sendErrorPacket(Packet packet, PacketError error) {
packet = packet.createCopy();
packet.setError(error);
packet.setFrom(packet.getTo());
packet.setTo(packet.getFrom());
router.route(packet);
}
public XMPPAddress getAddress() {
public JID getAddress() {
return realjid;
}
public void process(XMPPPacket packet) throws UnauthorizedException, PacketException {
public void process(Packet packet) throws UnauthorizedException, PacketException {
if (packet instanceof IQ) {
process((IQ)packet);
}
......@@ -132,8 +132,8 @@ public class MUCUserImpl implements MUCUser {
*/
public void process(Message packet) {
lastPacketTime = System.currentTimeMillis();
XMPPAddress recipient = packet.getRecipient();
String group = recipient.getName();
JID recipient = packet.getTo();
String group = recipient.getNode();
if (group == null) {
// Ignore packets to the groupchat server
// 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 {
if (role == null) {
if (server.hasChatRoom(group)) {
boolean declinedInvitation = false;
XMPPDOMFragment userInfo = null;
if (Message.NORMAL == packet.getType()) {
Element userInfo = null;
if (Message.Type.normal == packet.getType()) {
// An user that is not an occupant could be declining an invitation
userInfo = (XMPPDOMFragment) packet.getFragment(
"x",
"http://jabber.org/protocol/muc#user");
userInfo = packet.getChildElement(
"x", "http://jabber.org/protocol/muc#user");
if (userInfo != null
&& userInfo.getRootElement().element("decline") != null) {
&& userInfo.element("decline") != null) {
// A user has declined an invitation to a room
// WARNING: Potential fraud if someone fakes the "from" of the
// message with the JID of a member and sends a "decline"
......@@ -160,12 +159,11 @@ public class MUCUserImpl implements MUCUser {
}
}
if (declinedInvitation) {
Element info = userInfo.getRootElement().element("decline");
Element info = userInfo.element("decline");
server.getChatRoom(group).sendInvitationRejection(
info.attributeValue("to"),
info.elementTextTrim("reason"),
packet.getSender(),
packet.getOriginatingSession());
packet.getFrom());
}
else {
// The sender is not an occupant of the room
......
......@@ -34,6 +34,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.dom4j.DocumentHelper;
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
......@@ -92,7 +96,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
* the chat service's hostname
*/
private String chatServiceName = null;
private XMPPAddress chatServiceAddress = null;
private JID chatServiceAddress = null;
/**
* chatrooms managed by this manager, table: key room name (String); value ChatRoom
......@@ -102,7 +106,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
/**
* 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 RoutingTable routingTable = null;
......@@ -196,7 +200,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
room = role.getChatRoom();
try {
kickedPresence =
room.kickOccupant(user.getAddress().toStringPrep(), null, null);
room.kickOccupant(user.getAddress(), null, null);
// Send the updated presence to the room occupants
room.send(kickedPresence);
}
......@@ -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;
synchronized (rooms) {
room = rooms.get(roomName.toLowerCase());
......@@ -270,15 +274,15 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
// The room does not exist so check for creation permissions
// Room creation is always allowed for sysadmin
if (isRoomCreationRestricted() &&
!sysadmins.contains(userjid.toBareStringPrep())) {
!sysadmins.contains(userjid.toBareJID())) {
// 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
// an exception
throw new UnauthorizedException();
}
}
room.addFirstOwner(userjid.toBareStringPrep());
room.addFirstOwner(userjid.toBareJID());
}
rooms.put(roomName.toLowerCase(), room);
}
......@@ -314,7 +318,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return historyStrategy;
}
public void removeUser(XMPPAddress jabberID) {
public void removeUser(JID jabberID) {
MUCUser user = users.remove(jabberID);
if (user != null) {
Iterator<MUCRole> roles = user.getRoles();
......@@ -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) {
throw new IllegalStateException("Not initialized");
}
......@@ -585,7 +589,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
if (serverName != null) {
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
// values)
userTimeoutTask = new UserTimeoutTask();
......@@ -619,16 +623,16 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
}
}
public XMPPAddress getAddress() {
public JID getAddress() {
if (chatServiceAddress == null) {
throw new IllegalStateException("Not initialized");
}
return chatServiceAddress;
}
public void process(XMPPPacket packet) {
public void process(Packet packet) {
try {
MUCUser user = getChatUser(packet.getSender());
MUCUser user = getChatUser(packet.getFrom());
user.process(packet);
}
catch (Exception e) {
......@@ -640,7 +644,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
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));
}
......@@ -675,7 +679,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
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
ArrayList identities = new ArrayList();
if (name == null && node == null) {
......@@ -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
MUCRoom room = getChatRoom(name);
if (room != null) {
String reservedNick = room.getReservedNickname(senderJID.toBareStringPrep());
String reservedNick = room.getReservedNickname(senderJID.toBareJID());
if (reservedNick != null) {
Element identity = DocumentHelper.createElement("identity");
identity.addAttribute("category", "conference");
......@@ -717,7 +721,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
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();
if (name == null && node == null) {
// Answer the features of the MUC service
......@@ -768,7 +772,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
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) {
// Answer the extended info of a given room
// TODO lock the room while gathering this info???
......@@ -808,7 +812,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return null;
}
public boolean hasInfo(String name, String node, XMPPAddress senderJID)
public boolean hasInfo(String name, String node, JID senderJID)
throws UnauthorizedException {
if (name == null && node == node) {
// We always have info about the MUC service
......@@ -825,7 +829,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return false;
}
public Iterator getItems(String name, String node, XMPPAddress senderJID)
public Iterator getItems(String name, String node, JID senderJID)
throws UnauthorizedException {
List answer = new ArrayList();
if (name == null && node == null) {
......@@ -834,7 +838,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
for (MUCRoom room : rooms.values()) {
if (room.isPublicRoom()) {
item = DocumentHelper.createElement("item");
item.addAttribute("jid", room.getRole().getRoleAddress().toStringPrep());
item.addAttribute("jid", room.getRole().getRoleAddress().toString());
item.addAttribute("name", room.getNaturalLanguageName());
answer.add(item);
......@@ -849,7 +853,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
for (MUCRole role : room.getOccupants()) {
// TODO Should we filter occupants that are invisible (presence is not broadcasted)?
item = DocumentHelper.createElement("item");
item.addAttribute("jid", role.getRoleAddress().toStringPrep());
item.addAttribute("jid", role.getRoleAddress().toString());
answer.add(item);
}
......
......@@ -16,6 +16,10 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.audit.Auditor;
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.InputStreamReader;
import java.net.Socket;
......@@ -113,16 +117,10 @@ public class SocketReadThread extends Thread {
Presence presence = session.getPresence();
if (presence != null) {
// Simulate an unavailable presence sent by the user.
Presence packet = (Presence) presence.createDeepCopy();
packet.setType(Presence.UNAVAILABLE);
try {
packet.setAvailable(false);
packet.setVisible(false);
}
catch (UnauthorizedException e) {}
packet.setOriginatingSession(session);
packet.setSender(session.getAddress());
packet.setSending(false);
Presence packet = presence.createCopy();
packet.setType(Presence.Type.unavailable);
packet.setType(null);
packet.setFrom(session.getAddress());
router.route(packet);
clearSignout = true;
}
......@@ -190,29 +188,23 @@ public class SocketReadThread extends Thread {
if ("message".equals(tag)) {
Message packet = packetFactory.getMessage(xpp);
packet.setOriginatingSession(session);
packet.setSender(session.getAddress());
packet.setSending(false);
packet.setFrom(session.getAddress());
auditor.audit(packet);
router.route(packet);
session.incrementClientPacketCount();
}
else if ("presence".equals(tag)) {
Presence packet = packetFactory.getPresence(xpp);
packet.setOriginatingSession(session);
packet.setSender(session.getAddress());
packet.setSending(false);
packet.setFrom(session.getAddress());
auditor.audit(packet);
router.route(packet);
session.incrementClientPacketCount();
// 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)) {
IQ packet = packetFactory.getIQ(xpp);
packet.setOriginatingSession(session);
packet.setSender(session.getAddress());
packet.setSending(false);
packet.setFrom(session.getAddress());
auditor.audit(packet);
router.route(packet);
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;
import org.jivesoftware.util.Version;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
import java.text.DateFormat;
import java.util.*;
......@@ -63,19 +65,19 @@ public class BasicServer extends BasicModule implements XMPPServer, BasicServerM
return new XMPPServerInfoImpl(name, version, startDate, stopDate, ports);
}
public boolean isLocal(XMPPAddress jid) {
public boolean isLocal(JID jid) {
boolean local = false;
if (jid != null && name != null && name.equalsIgnoreCase(jid.getHost())) {
if (jid != null && name != null && name.equalsIgnoreCase(jid.getDomain())) {
local = true;
}
return local;
}
public XMPPAddress createAddress(String username, String resource) {
return new XMPPAddress(username, name, resource);
public JID createJID(String username, String 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));
public Session getSession() {
......@@ -95,7 +97,7 @@ public class BasicServer extends BasicModule implements XMPPServer, BasicServerM
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;
}
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;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
/**
* Simple in memory implementation of the PresenceManager interface.
......@@ -81,7 +83,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
for (Presence presence : onlineUsers.values()) {
if (presence.isAvailable()) {
try {
users.add(userManager.getUser(presence.getUsername()));
users.add(userManager.getUser(presence.getFrom().getNode()));
}
catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
......@@ -134,9 +136,11 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
String presenceUser2 = "";
try {
presenceUser1 =
userManager.getUser(presence1.getUsername()).getUsername();
userManager.getUser(presence1.getFrom().getNode()
).getUsername();
presenceUser2 =
userManager.getUser(presence2.getUsername()).getUsername();
userManager.getUser(presence2.getFrom().getNode()
).getUsername();
}
catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
......@@ -162,7 +166,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
for (int i = 0; i < presences.size(); i++) {
Presence presence = (Presence)presences.get(i);
try {
users.add(userManager.getUser(presence.getUsername()));
users.add(userManager.getUser(presence.getFrom().getNode()));
}
catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
......@@ -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 = new PresenceImpl(user, uid);
presence = new Presence();
presence.setFrom(server.createJID(user.getUsername(), null));
setOnline(presence);
return presence;
}
......@@ -187,7 +192,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
public void setOnline(Presence presence) {
User user = null;
try {
user = userManager.getUser(presence.getUsername());
user = userManager.getUser(presence.getFrom().getNode());
}
catch (UserNotFoundException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
......@@ -206,9 +211,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
}
public void setOffline(Presence presence) {
if (presence.getUsername() != null) {
if (presence.getFrom().getNode() != null) {
synchronized (onlineUsers) {
onlineUsers.remove(presence.getUsername());
onlineUsers.remove(presence.getFrom().getNode());
}
}
else {
......@@ -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) {
......@@ -239,7 +244,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
if (presence == null) {
presence = session.getPresence();
}
else if (presence.getShow() > session.getPresence().getShow()) {
else if (presence.getShow().ordinal() > session.getPresence().getShow().ordinal()) {
presence = session.getPresence();
}
}
......@@ -286,17 +291,16 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
return null;
}
public void probePresence(String prober, XMPPAddress probee) {
public void probePresence(String prober, JID probee) {
try {
Component component = getPresenceComponent(probee);
if (server.isLocal(probee)) {
if (probee.getNamePrep() != null && !"".equals(probee.getNamePrep())) {
if (probee.getNode() != null && !"".equals(probee.getNode())) {
Collection<Session> sessions =
sessionManager.getSessions(probee.getNamePrep());
sessionManager.getSessions(probee.getNode());
for (Session session : sessions) {
Presence presencePacket =
(Presence)session.getPresence().createDeepCopy();
presencePacket.setSender(session.getAddress());
Presence presencePacket = session.getPresence().createCopy();
presencePacket.setFrom(session.getAddress());
try {
sessionManager.userBroadcast(prober, presencePacket);
}
......@@ -307,17 +311,17 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
}
}
else if (component != null) {
Presence presence = new PresenceImpl();
presence.setType(Presence.PROBE);
presence.setSender(server.createAddress(prober, ""));
presence.setRecipient(probee);
Presence presence = new Presence();
presence.setType(Presence.Type.probe);
presence.setFrom(server.createJID(prober, ""));
presence.setTo(probee);
component.processPacket(presence);
}
else {
Presence presence = (Presence)foreignUserCache.get(probee.toBareStringPrep());
Presence presence = (Presence)foreignUserCache.get(probee.toBareJID());
if (presence != null) {
Presence presencePacket = (Presence)presence.createDeepCopy();
presencePacket.setSender(probee);
Presence presencePacket = presence.createCopy();
presencePacket.setFrom(probee);
try {
sessionManager.userBroadcast(prober, presencePacket);
}
......@@ -326,7 +330,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
}
}
else {
XMPPAddress proberAddress = server.createAddress(prober, "");
JID proberAddress = server.createJID(prober, "");
componentManager.addPresenceRequest(proberAddress, probee);
}
}
......@@ -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 {
if (server.isLocal(probee)) {
Collection<Session> sessions =
sessionManager.getSessions(probee.getName().toLowerCase());
sessionManager.getSessions(probee.getNode());
for (Session session : sessions) {
Presence presencePacket =
(Presence)session.getPresence().createDeepCopy();
presencePacket.setSender(session.getAddress());
Presence presencePacket = session.getPresence().createCopy();
presencePacket.setFrom(session.getAddress());
try {
deliverer.deliver(presencePacket);
}
......@@ -355,10 +358,10 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
}
else {
Presence presence =
(Presence)foreignUserCache.get(probee.toBareStringPrep());
(Presence)foreignUserCache.get(probee.toBareJID());
if (presence != null) {
Presence presencePacket = (Presence)presence.createDeepCopy();
presencePacket.setSender(probee);
Presence presencePacket = presence.createCopy();
presencePacket.setFrom(probee);
try {
deliverer.deliver(presencePacket);
}
......@@ -392,9 +395,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
return trackInfo;
}
public Component getPresenceComponent(XMPPAddress probee) {
public Component getPresenceComponent(JID probee) {
// Check for registered components
Component component = componentManager.getComponent(probee.toBareStringPrep());
Component component = componentManager.getComponent(probee.toBareJID());
if (component != null) {
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;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.*;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
......@@ -43,26 +44,26 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
super("Routing table");
}
public ChannelHandler addRoute(XMPPAddress node, RoutableChannelHandler destination) {
public ChannelHandler addRoute(JID node, RoutableChannelHandler destination) {
ChannelHandler route = null;
routeLock.writeLock().lock();
try {
if (node.getName() == null) {
Object item = routes.put(node.getHostPrep(), destination);
if (node.getNode() == null) {
Object item = routes.put(node.getDomain(), destination);
if (item instanceof ChannelHandler) {
route = (ChannelHandler)item;
}
}
else {
Object nameRoutes = routes.get(node.getHostPrep());
Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes == null || nameRoutes instanceof ChannelHandler) {
nameRoutes = new Hashtable();
routes.put(node.getHostPrep(), nameRoutes);
routes.put(node.getDomain(), nameRoutes);
}
if (node.getResource() == null) {
Object item = ((Hashtable)nameRoutes).put(node.getNamePrep(),
Object item = ((Hashtable)nameRoutes).put(node.getNode(),
destination);
if (item instanceof ChannelHandler) {
route = (ChannelHandler)item;
......@@ -70,18 +71,18 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
}
else {
Object resourceRoutes =
((Hashtable)nameRoutes).get(node.getNamePrep());
((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes == null
|| resourceRoutes instanceof ChannelHandler) {
resourceRoutes = new Hashtable();
Object item = ((Hashtable)nameRoutes).put(node.getNamePrep(),
Object item = ((Hashtable)nameRoutes).put(node.getNode(),
resourceRoutes);
if (item instanceof ChannelHandler) {
route = (ChannelHandler)item;
}
}
Object resourceRoute =
((Hashtable)resourceRoutes).put(node.getResourcePrep(),
((Hashtable)resourceRoutes).put(node.getResource(),
destination);
if (resourceRoute != null) {
if (resourceRoute instanceof ChannelHandler) {
......@@ -99,22 +100,22 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
return route;
}
public RoutableChannelHandler getRoute(XMPPAddress node) throws NoSuchRouteException {
public RoutableChannelHandler getRoute(JID node) throws NoSuchRouteException {
RoutableChannelHandler route = null;
routeLock.readLock().lock();
try {
Object nameRoutes = routes.get(node.getHostPrep());
Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes instanceof ChannelHandler) {
route = (RoutableChannelHandler)nameRoutes;
}
else {
Object resourceRoutes = ((Hashtable)nameRoutes).get(node.getNamePrep());
Object resourceRoutes = ((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes instanceof ChannelHandler) {
route = (RoutableChannelHandler)resourceRoutes;
}
else if (resourceRoutes != null) {
route = (RoutableChannelHandler)
((Hashtable)resourceRoutes).get(node.getResourcePrep());
((Hashtable)resourceRoutes).get(node.getResource());
}
else {
//System.err.println(nameRoutes);
......@@ -135,28 +136,28 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
return route;
}
public Iterator getRoutes(XMPPAddress node) {
public Iterator getRoutes(JID node) {
LinkedList list = null;
routeLock.readLock().lock();
try {
if (node == null || node.getHost() == null) {
if (node == null || node.getDomain() == null) {
list = new LinkedList();
getRoutes(list, routes);
}
else {
Object nameRoutes = routes.get(node.getHostPrep());
Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes != null) {
if (nameRoutes instanceof ChannelHandler) {
list = new LinkedList();
list.add(nameRoutes);
}
else if (node.getName() == null) {
else if (node.getNode() == null) {
list = new LinkedList();
getRoutes(list, (Hashtable)nameRoutes);
}
else {
Object resourceRoutes =
((Hashtable)nameRoutes).get(node.getNamePrep());
((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes != null) {
if (resourceRoutes instanceof ChannelHandler) {
list = new LinkedList();
......@@ -168,7 +169,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
}
else {
Object entry =
((Hashtable)resourceRoutes).get(node.getResourcePrep());
((Hashtable)resourceRoutes).get(node.getResource());
if (entry != null) {
list = new LinkedList();
list.add(entry);
......@@ -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;
try {
route = getRoute(node);
}
catch (NoSuchRouteException e) {
XMPPAddress defaultNode = new XMPPAddress(node.getName(), node.getHost(), "");
JID defaultNode = new JID(node.getNode(), node.getDomain(), "");
route = getRoute(defaultNode);
}
if (route == null) {
......@@ -232,40 +233,40 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable {
return route;
}
public ChannelHandler removeRoute(XMPPAddress node) {
public ChannelHandler removeRoute(JID node) {
ChannelHandler route = null;
routeLock.writeLock().lock();
//System.err.println("Remove route " + node.toString());
try {
if (node.getName() == null) {
if (node.getNode() == null) {
// Chop off all hosted names for this domain
Object item = routes.remove(node.getHostPrep());
Object item = routes.remove(node.getDomain());
if (item instanceof ChannelHandler) {
route = (ChannelHandler)item;
}
}
else {
Object nameRoutes = routes.get(node.getHostPrep());
Object nameRoutes = routes.get(node.getDomain());
if (nameRoutes instanceof Hashtable) {
if (node.getResource() == null || node.getResource().trim().length() == 0) {
// 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) {
route = (ChannelHandler)item;
}
}
else {
Object resourceRoutes =
((Hashtable)nameRoutes).get(node.getNamePrep());
((Hashtable)nameRoutes).get(node.getNode());
if (resourceRoutes instanceof Hashtable) {
route = (ChannelHandler)
((Hashtable)resourceRoutes).remove(node.getResourcePrep());
((Hashtable)resourceRoutes).remove(node.getResource());
if (((Hashtable)resourceRoutes).isEmpty()) {
((Hashtable)nameRoutes).remove(node.getNamePrep());
((Hashtable)nameRoutes).remove(node.getNode());
if (((Hashtable)nameRoutes).isEmpty()) {
routes.remove(node.getHostPrep());
routes.remove(node.getDomain());
}
}
......
......@@ -56,8 +56,8 @@ public class XMPPServerProxy implements XMPPServer {
return server.isLocal(jid);
}
public XMPPAddress createAddress(String username, String resource) {
return server.createAddress(username, resource);
public XMPPAddress createJID(String username, String resource) {
return server.createJID(username, resource);
}
public Session getSession() throws UnauthorizedException {
......
......@@ -206,7 +206,7 @@ public class CachedRosterImpl extends BasicRoster implements CachedRoster {
if (server == null) {
server = (XMPPServer)ServiceLookupFactory.getLookup().lookup(XMPPServer.class);
}
XMPPAddress recipient = server.createAddress(username, null);
XMPPAddress recipient = server.createJID(username, null);
roster.setRecipient(recipient);
roster.setOriginatingSession(server.getSession());
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
Message response = packetFactory.getMessage();
response.setOriginatingSession(xmppServer.getSession());
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.");
message.getOriginatingSession().getConnection().deliver(response);
......
......@@ -6,7 +6,6 @@
<%@ page import="java.io.*,
org.jivesoftware.util.ParamUtils,
org.jivesoftware.util.Version,
org.jivesoftware.messenger.JiveGlobals,
org.jivesoftware.messenger.auth.UnauthorizedException,
org.jivesoftware.messenger.user.UserNotFoundException,
......
......@@ -13,7 +13,6 @@
org.jivesoftware.messenger.container.ServiceLookupFactory,
org.jivesoftware.messenger.container.ServiceLookup,
org.jivesoftware.messenger.JiveGlobals,
org.jivesoftware.util.Version,
org.jivesoftware.util.Log,
org.jivesoftware.admin.AdminConsole"
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