Commit e7418085 authored by Armando Jagucki's avatar Armando Jagucki Committed by ajagucki

Ported changes since r8740 from trunk.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/branches@8945 b35dd754-fafc-0310-a699-88a17e54d16e
parent 121c0480
...@@ -30,9 +30,9 @@ jtds.jar | 1.2 ...@@ -30,9 +30,9 @@ jtds.jar | 1.2
junit.jar | 4.3.1 junit.jar | 4.3.1
jzlib.jar | 1.0.7 jzlib.jar | 1.0.7
mail.jar | 1.4.0 (JavaMail) mail.jar | 1.4.0 (JavaMail)
mina-core-1.2.0.jar | https://svn.apache.org/repos/asf/mina/branches/1.1 mina-core-1.2.0.jar | 1.1.1 https://svn.apache.org/repos/asf/mina/branches/1.1
mina-filter-compression-1.2.0.jar | https://svn.apache.org/repos/asf/mina/branches/1.1 mina-filter-compression-1.2.0.jar | 1.1.1 https://svn.apache.org/repos/asf/mina/branches/1.1
mina-filter-ssl-1.2.0.jar | https://svn.apache.org/repos/asf/mina/branches/1.1 mina-filter-ssl-1.2.0.jar | 1.1.1 https://svn.apache.org/repos/asf/mina/branches/1.1
mysql.jar | 3.1.13 mysql.jar | 3.1.13
objenesis | 1.0 (JMock 2.1.0) objenesis | 1.0 (JMock 2.1.0)
pack200task.jar | August 5, 2004 pack200task.jar | August 5, 2004
......
...@@ -19,6 +19,24 @@ ...@@ -19,6 +19,24 @@
<SOURCES /> <SOURCES />
</library> </library>
</orderEntry> </orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/web/WEB-INF/lib/commons-fileupload.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/web/WEB-INF/lib/commons-io.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntryProperties /> <orderEntryProperties />
</component> </component>
<component name="WebModuleBuildComponent"> <component name="WebModuleBuildComponent">
...@@ -56,6 +74,11 @@ ...@@ -56,6 +74,11 @@
<attribute name="URI" value="/WEB-INF/lib/ant.jar" /> <attribute name="URI" value="/WEB-INF/lib/ant.jar" />
<url>jar://$MODULE_DIR$/../lib/ant.jar!/</url> <url>jar://$MODULE_DIR$/../lib/ant.jar!/</url>
</containerElement> </containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/cglib-nodep.jar" />
<url>jar://$MODULE_DIR$/../lib/cglib-nodep.jar!/</url>
</containerElement>
<containerElement type="library" level="module"> <containerElement type="library" level="module">
<attribute name="method" value="0" /> <attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/commons-el.jar" /> <attribute name="URI" value="/WEB-INF/lib/commons-el.jar" />
...@@ -101,6 +124,16 @@ ...@@ -101,6 +124,16 @@
<attribute name="URI" value="&lt;N/A&gt;" /> <attribute name="URI" value="&lt;N/A&gt;" />
<url>jar://$MODULE_DIR$/../lib/dist/servlet.jar!/</url> <url>jar://$MODULE_DIR$/../lib/dist/servlet.jar!/</url>
</containerElement> </containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/hamcrest-api.jar" />
<url>jar://$MODULE_DIR$/../lib/hamcrest-api.jar!/</url>
</containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/hamcrest-library.jar" />
<url>jar://$MODULE_DIR$/../lib/hamcrest-library.jar!/</url>
</containerElement>
<containerElement type="library" level="module"> <containerElement type="library" level="module">
<attribute name="method" value="0" /> <attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/i4jruntime.jar" /> <attribute name="URI" value="/WEB-INF/lib/i4jruntime.jar" />
...@@ -116,6 +149,16 @@ ...@@ -116,6 +149,16 @@
<attribute name="URI" value="/WEB-INF/lib/jasper-runtime.jar" /> <attribute name="URI" value="/WEB-INF/lib/jasper-runtime.jar" />
<url>jar://$MODULE_DIR$/../lib/jasper-runtime.jar!/</url> <url>jar://$MODULE_DIR$/../lib/jasper-runtime.jar!/</url>
</containerElement> </containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/jmock-junit4.jar" />
<url>jar://$MODULE_DIR$/../lib/jmock-junit4.jar!/</url>
</containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/jmock.jar" />
<url>jar://$MODULE_DIR$/../lib/jmock.jar!/</url>
</containerElement>
<containerElement type="library" level="module"> <containerElement type="library" level="module">
<attribute name="method" value="0" /> <attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/junit.jar" /> <attribute name="URI" value="/WEB-INF/lib/junit.jar" />
...@@ -236,6 +279,11 @@ ...@@ -236,6 +279,11 @@
<attribute name="URI" value="/WEB-INF/lib/xpp3.jar" /> <attribute name="URI" value="/WEB-INF/lib/xpp3.jar" />
<url>jar://$MODULE_DIR$/../lib/merge/xpp3.jar!/</url> <url>jar://$MODULE_DIR$/../lib/merge/xpp3.jar!/</url>
</containerElement> </containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/objenesis.jar" />
<url>jar://$MODULE_DIR$/../lib/objenesis.jar!/</url>
</containerElement>
<containerElement type="library" level="module"> <containerElement type="library" level="module">
<attribute name="method" value="0" /> <attribute name="method" value="0" />
<attribute name="URI" value="/WEB-INF/lib/xmltask.jar" /> <attribute name="URI" value="/WEB-INF/lib/xmltask.jar" />
...@@ -426,6 +474,16 @@ ...@@ -426,6 +474,16 @@
<attribute name="URI" value="/WEB-INF/classes" /> <attribute name="URI" value="/WEB-INF/classes" />
<url>file://$MODULE_DIR$/../../src/resources/jar</url> <url>file://$MODULE_DIR$/../../src/resources/jar</url>
</containerElement> </containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="1" />
<attribute name="URI" value="/WEB-INF/lib/commons-fileupload.jar" />
<url>jar://$MODULE_DIR$/../../src/web/WEB-INF/lib/commons-fileupload.jar!/</url>
</containerElement>
<containerElement type="library" level="module">
<attribute name="method" value="1" />
<attribute name="URI" value="/WEB-INF/lib/commons-io.jar" />
<url>jar://$MODULE_DIR$/../../src/web/WEB-INF/lib/commons-io.jar!/</url>
</containerElement>
<containerElement type="library" level="module"> <containerElement type="library" level="module">
<attribute name="method" value="1" /> <attribute name="method" value="1" />
<attribute name="URI" value="/WEB-INF/lib/dwr.jar" /> <attribute name="URI" value="/WEB-INF/lib/dwr.jar" />
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module version="4" relativePaths="true" type="JAVA_MODULE"> <module version="4" relativePaths="true" type="JAVA_MODULE">
<component name="ModuleRootManager" /> <component name="ModuleRootManager" />
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/../../make/work/classes" /> <output url="file://$MODULE_DIR$/../../make/work/classes" />
<exclude-output /> <exclude-output />
<exclude-exploded /> <exclude-exploded />
...@@ -455,5 +455,9 @@ ...@@ -455,5 +455,9 @@
</orderEntry> </orderEntry>
<orderEntryProperties /> <orderEntryProperties />
</component> </component>
<component name="VcsManagerConfiguration">
<option name="ACTIVE_VCS_NAME" value="svn" />
<option name="USE_PROJECT_VCS" value="false" />
</component>
</module> </module>
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/ymsg_network.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/picocontainer.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/picocontainer.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/cindy.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -90,7 +90,7 @@ ...@@ -90,7 +90,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/ymsg_support.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/jml.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/irclib.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/joscar-protocol.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/cindy.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/joscar-common.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/jml.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/joscar-client.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -126,7 +126,7 @@ ...@@ -126,7 +126,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/joscar-protocol.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/dwr.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/joscar-common.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/log4j.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -144,7 +144,7 @@ ...@@ -144,7 +144,7 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/joscar-client.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/jainsipapi.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
...@@ -153,7 +153,88 @@ ...@@ -153,7 +153,88 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/dwr.jar!/" /> <root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/xmlrpc.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/smack.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/jakarta-regexp.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/openymsg.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/jggapi.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/martyr.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/jainsipri.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/smackx.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/concurrent.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../src/plugins/gateway/lib/jsocks.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
......
...@@ -201,6 +201,32 @@ ...@@ -201,6 +201,32 @@
## Added key: 'user.roster.delete.info' ## Added key: 'user.roster.delete.info'
## Added key: 'sidebar.user-roster' ## Added key: 'sidebar.user-roster'
## Added key: 'sidebar.user-roster.descr' ## Added key: 'sidebar.user-roster.descr'
## Added key: 'user.roster.edit'
## Added key: 'user.roster.add'
## Added key: 'user.roster.edited'
## Added key: 'user.roster.edit.title'
## Added key: 'user.roster.edit.info'
## Added key: 'user.roster.added'
## Added key: 'user.roster.add.title'
## Added key: 'user.roster.add.info'
## Added key: 'user.roster.add.error_adding_item'
## Added key: 'user.roster.add.item_exists'
## Added key: 'user.roster.add.uneditable_group'
## Added key: 'user.roster.add.success'
## Added key: 'user.roster.add.new_item'
## Added key: 'user.roster.add.add'
## Added key: 'user.roster.add.add_another'
## Added key: 'user.roster.add.required'
## Added key: 'user.roster.item.settings'
## Added key: 'user.roster.add.illegal_jid'
## Added key: 'user.roster.shared_groups'
## Added key: 'user.roster.click_view'
## Added key: 'user.roster.cant_delete'
## Added key: 'plugin.admin.uploaded_success'
## Added key: 'plugin.admin.uploaded_failure'
## Added key: 'plugin.admin.upload_plugin'
## Added key: 'plugin.admin.upload_plugin.info'
# Openfire # Openfire
...@@ -1893,19 +1919,40 @@ user.properties.registered=Registered ...@@ -1893,19 +1919,40 @@ user.properties.registered=Registered
# User roster Page # User roster Page
user.roster.title=User Roster user.roster.title=User Roster
user.roster.info=Below is the list of roster items for user {0}. user.roster.info=Below is the list of roster items for user {0}. Shared groups are underlined.
user.roster.jid=JID user.roster.jid=JID
user.roster.nickname=Nickname user.roster.nickname=Nickname
user.roster.groups=Groups user.roster.groups=Groups
user.roster.shared_groups=Shared Groups
user.roster.subscription=Subscription user.roster.subscription=Subscription
user.roster.cant_delete=This roster item is a member of a shared group and can not be deleted via this interface.
user.roster.total_items=Total Items user.roster.total_items=Total Items
user.roster.sorted=Sorted by JID user.roster.sorted=Sorted by JID
user.roster.items_per_page=Items per page user.roster.items_per_page=Items per page
user.roster.edit=Edit
user.roster.add=Add New Item
user.roster.none_found=No roster items found. user.roster.none_found=No roster items found.
user.roster.click_view=Click to view...
user.roster.deleted=Roster item deleted successfully. user.roster.deleted=Roster item deleted successfully.
user.roster.delete.title=Delete Roster Item user.roster.delete.title=Delete Roster Item
user.roster.delete.delete=Delete Roster Item user.roster.delete.delete=Delete Roster Item
user.roster.delete.info=Are you sure you want to delete the JID {0} from the roster of {1}? user.roster.delete.info=Are you sure you want to delete the JID {0} from the roster of {1}?
user.roster.edited=Roster item edited successfully.
user.roster.edit.title=Edit Roster Item
user.roster.edit.info=Use the form below to edit the roster item of user {0}.
user.roster.added=Roster item added successfully.
user.roster.add.title=Add Roster Item
user.roster.add.info=Use the form below to add a new roster item for user {0}.
user.roster.add.error_adding_item=Error adding roster item. Please check your server logs.
user.roster.add.item_exists=Roster item of the same JID already exists.
user.roster.add.uneditable_group=Attempted to remove item from a group that is not editable. (probably a shared group)
user.roster.add.illegal_jid=JID was not of a valid format.
user.roster.add.success=Successfully added roster item.
user.roster.add.new_item=Add New Roster Item
user.roster.add.add=Add Item
user.roster.add.add_another=Add & Add Another
user.roster.add.required=Required fields
user.roster.item.settings=Roster Item Settings
# User search Page # User search Page
...@@ -1942,6 +1989,11 @@ plugin.admin.info=Plugins add new functionality to the server. The list of plugi ...@@ -1942,6 +1989,11 @@ plugin.admin.info=Plugins add new functionality to the server. The list of plugi
<a href="available-plugins.jsp">Available Plugins</a> page. <a href="available-plugins.jsp">Available Plugins</a> page.
plugin.admin.deleted_success=Plugin deleted successfully. plugin.admin.deleted_success=Plugin deleted successfully.
plugin.admin.deleted_failure=Unable to delete plugin. plugin.admin.deleted_failure=Unable to delete plugin.
plugin.admin.uploaded_success=Plugin uploaded successfully. It may take a short time for the \
plugin to appear in the list of installed plugins.
plugin.admin.uploaded_failure=Unable to upload plugin. See server error logs.
plugin.admin.upload_plugin=Upload Plugin
plugin.admin.upload_plugin.info=Plugin files (.jar) can be uploaded directly by using the form below.
plugin.admin.click_reload=Reload the plugin. plugin.admin.click_reload=Reload the plugin.
plugin.admin.reload_success=Plugin was successfully reloaded. It may take a short time for the \ plugin.admin.reload_success=Plugin was successfully reloaded. It may take a short time for the \
plugin to appear in the list of installed plugins again. plugin to appear in the list of installed plugins again.
......
...@@ -95,21 +95,18 @@ public class SessionPacketRouter implements PacketRouter { ...@@ -95,21 +95,18 @@ public class SessionPacketRouter implements PacketRouter {
} }
public void route(IQ packet) { public void route(IQ packet) {
router.route(packet);
packet.setFrom(session.getAddress()); packet.setFrom(session.getAddress());
router.route(packet); router.route(packet);
session.incrementClientPacketCount(); session.incrementClientPacketCount();
} }
public void route(Message packet) { public void route(Message packet) {
router.route(packet);
packet.setFrom(session.getAddress()); packet.setFrom(session.getAddress());
router.route(packet); router.route(packet);
session.incrementClientPacketCount(); session.incrementClientPacketCount();
} }
public void route(Presence packet) { public void route(Presence packet) {
router.route(packet);
packet.setFrom(session.getAddress()); packet.setFrom(session.getAddress());
router.route(packet); router.route(packet);
session.incrementClientPacketCount(); session.incrementClientPacketCount();
......
...@@ -105,7 +105,7 @@ public class XMPPServer { ...@@ -105,7 +105,7 @@ public class XMPPServer {
private boolean initialized = false; private boolean initialized = false;
private boolean started = false; private boolean started = false;
private NodeID nodeID; private NodeID nodeID;
private static final NodeID DEFAULT_NODE_ID = new NodeID(new byte[0]); private static final NodeID DEFAULT_NODE_ID = NodeID.getInstance(new byte[0]);
/** /**
* All modules loaded by this server * All modules loaded by this server
...@@ -319,7 +319,7 @@ public class XMPPServer { ...@@ -319,7 +319,7 @@ public class XMPPServer {
name = JiveGlobals.getProperty("xmpp.domain", "127.0.0.1").toLowerCase(); name = JiveGlobals.getProperty("xmpp.domain", "127.0.0.1").toLowerCase();
version = new Version(3, 4, 0, Version.ReleaseStatus.Alpha, 1); version = new Version(3, 4, 0, Version.ReleaseStatus.Alpha, 2);
if ("true".equals(JiveGlobals.getXMLProperty("setup"))) { if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
setupMode = false; setupMode = false;
} }
......
...@@ -145,7 +145,7 @@ public class AuthorizationManager { ...@@ -145,7 +145,7 @@ public class AuthorizationManager {
UserManager.getUserProvider().loadUser(username); UserManager.getUserProvider().loadUser(username);
} }
catch (UserNotFoundException nfe) { catch (UserNotFoundException nfe) {
Log.debug("AuthorizationManager: User "+username+" not found."); Log.debug("AuthorizationManager: User "+username+" not found "+nfe.toString());
// Should we add the user? // Should we add the user?
if(JiveGlobals.getBooleanProperty("xmpp.auth.autoadd",false)) { if(JiveGlobals.getBooleanProperty("xmpp.auth.autoadd",false)) {
if (UserManager.getUserProvider().isReadOnly()) { if (UserManager.getUserProvider().isReadOnly()) {
......
...@@ -66,7 +66,7 @@ public class DefaultAuthorizationPolicy implements AuthorizationPolicy { ...@@ -66,7 +66,7 @@ public class DefaultAuthorizationPolicy implements AuthorizationPolicy {
* Returns true if the principal is explicity authorized to the JID * Returns true if the principal is explicity authorized to the JID
* *
* @param username The username requested. * @param username The username requested.
* @param authenID The authenticated ID requesting the username. * @param authenID The authenticated ID (principal) requesting the username.
* @return true if the authenticated ID is authorized to the requested user. * @return true if the authenticated ID is authorized to the requested user.
*/ */
public boolean authorize(String username, String authenID) { public boolean authorize(String username, String authenID) {
......
...@@ -334,6 +334,20 @@ public class ClusterManager { ...@@ -334,6 +334,20 @@ public class ClusterManager {
return CacheFactory.isSeniorClusterMember(); return CacheFactory.isSeniorClusterMember();
} }
/**
* Returns the id of the node that is the senior cluster member. When not in a cluster the returned
* node id will be the {@link XMPPServer#getNodeID()}.
*
* @return the id of the node that is the senior cluster member.
*/
public static NodeID getSeniorClusterMember() {
byte[] clusterMemberID = CacheFactory.getSeniorClusterMemberID();
if (clusterMemberID == null) {
return XMPPServer.getInstance().getNodeID();
}
return NodeID.getInstance(clusterMemberID);
}
private static class Event { private static class Event {
private EventType type; private EventType type;
private byte[] nodeID; private byte[] nodeID;
......
...@@ -17,7 +17,9 @@ import java.io.Externalizable; ...@@ -17,7 +17,9 @@ import java.io.Externalizable;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
/** /**
* Class which wraps the byte[] we use to identify cluster members. The main reason * Class which wraps the byte[] we use to identify cluster members. The main reason
...@@ -29,12 +31,38 @@ import java.util.Arrays; ...@@ -29,12 +31,38 @@ import java.util.Arrays;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class NodeID implements Externalizable { public class NodeID implements Externalizable {
private static List<NodeID> instances = new ArrayList<NodeID>();
private byte[] nodeID; private byte[] nodeID;
public static synchronized NodeID getInstance(byte[] nodeIdBytes) {
for (NodeID nodeID : instances) {
if (nodeID.equals(nodeIdBytes)) {
return nodeID;
}
}
NodeID answer = new NodeID(nodeIdBytes);
instances.add(answer);
return answer;
}
public static synchronized void deleteInstance(byte[] nodeIdBytes) {
NodeID toDelete = null;
for (NodeID nodeID : instances) {
if (nodeID.equals(nodeIdBytes)) {
toDelete = nodeID;
break;
}
}
if (toDelete != null) {
instances.remove(toDelete);
}
}
public NodeID() { public NodeID() {
} }
public NodeID(byte[] nodeIdBytes) { private NodeID(byte[] nodeIdBytes) {
this.nodeID = nodeIdBytes; this.nodeID = nodeIdBytes;
} }
......
...@@ -524,45 +524,44 @@ public class PluginManager { ...@@ -524,45 +524,44 @@ public class PluginManager {
Log.debug("Unloading plugin " + pluginName); Log.debug("Unloading plugin " + pluginName);
Plugin plugin = plugins.get(pluginName); Plugin plugin = plugins.get(pluginName);
if (plugin == null) { if (plugin != null) {
return; // Remove from dev mode if it exists.
} pluginDevelopment.remove(plugin);
// Remove from dev mode if it exists. // See if any child plugins are defined.
pluginDevelopment.remove(plugin); if (parentPluginMap.containsKey(plugin)) {
for (String childPlugin : parentPluginMap.get(plugin)) {
Log.debug("Unloading child plugin: " + childPlugin);
unloadPlugin(childPlugin);
}
parentPluginMap.remove(plugin);
}
// See if any child plugins are defined. File webXML = new File(pluginDirectory, pluginName + File.separator + "web" + File.separator + "WEB-INF" +
if (parentPluginMap.containsKey(plugin)) { File.separator + "web.xml");
for (String childPlugin : parentPluginMap.get(plugin)) { if (webXML.exists()) {
Log.debug("Unloading child plugin: " + childPlugin); AdminConsole.removeModel(pluginName);
unloadPlugin(childPlugin); PluginServlet.unregisterServlets(webXML);
}
File customWebXML = new File(pluginDirectory, pluginName + File.separator + "web" + File.separator + "WEB-INF" +
File.separator + "web-custom.xml");
if (customWebXML.exists()) {
PluginServlet.unregisterServlets(customWebXML);
} }
parentPluginMap.remove(plugin);
}
File webXML = new File(pluginDirectory, pluginName + File.separator + "web" + File.separator + "WEB-INF" + // Wrap destroying the plugin in a try/catch block. Otherwise, an exception raised
File.separator + "web.xml"); // in the destroy plugin process will disrupt the whole unloading process. It's still
if (webXML.exists()) { // possible that classloader destruction won't work in the case that destroying the plugin
AdminConsole.removeModel(pluginName); // fails. In that case, Openfire may need to be restarted to fully cleanup the plugin
PluginServlet.unregisterServlets(webXML); // resources.
} try {
File customWebXML = new File(pluginDirectory, pluginName + File.separator + "web" + File.separator + "WEB-INF" + plugin.destroyPlugin();
File.separator + "web-custom.xml"); }
if (customWebXML.exists()) { catch (Exception e) {
PluginServlet.unregisterServlets(customWebXML); Log.error(e);
}
} }
// Wrap destroying the plugin in a try/catch block. Otherwise, an exception raised
// in the destroy plugin process will disrupt the whole unloading process. It's still
// possible that classloader destruction won't work in the case that destroying the plugin
// fails. In that case, Openfire may need to be restarted to fully cleanup the plugin
// resources.
try {
plugin.destroyPlugin();
}
catch (Exception e) {
Log.error(e);
}
// Try to remove the folder where the plugin was exploded. If this works then // Try to remove the folder where the plugin was exploded. If this works then
// the plugin was successfully removed. Otherwise, some objects created by the // the plugin was successfully removed. Otherwise, some objects created by the
// plugin are still in memory. // plugin are still in memory.
...@@ -584,7 +583,7 @@ public class PluginManager { ...@@ -584,7 +583,7 @@ public class PluginManager {
Log.error(e); Log.error(e);
} }
if (!dir.exists()) { if (plugin != null && !dir.exists()) {
plugins.remove(pluginName); plugins.remove(pluginName);
pluginDirs.remove(plugin); pluginDirs.remove(plugin);
classloaders.remove(plugin); classloaders.remove(plugin);
......
...@@ -322,7 +322,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene ...@@ -322,7 +322,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene
public void leftCluster(byte[] nodeID) { public void leftCluster(byte[] nodeID) {
if (ClusterManager.isSeniorClusterMember()) { if (ClusterManager.isSeniorClusterMember()) {
NodeID leftNode = new NodeID(nodeID); NodeID leftNode = NodeID.getInstance(nodeID);
// Remove server features added by node that is gone // Remove server features added by node that is gone
for (Map.Entry<String, Set<NodeID>> entry : serverFeatures.entrySet()) { for (Map.Entry<String, Set<NodeID>> entry : serverFeatures.entrySet()) {
String namespace = entry.getKey(); String namespace = entry.getKey();
......
...@@ -399,7 +399,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -399,7 +399,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
public void leftCluster(byte[] nodeID) { public void leftCluster(byte[] nodeID) {
if (ClusterManager.isSeniorClusterMember()) { if (ClusterManager.isSeniorClusterMember()) {
NodeID leftNode = new NodeID(nodeID); NodeID leftNode = NodeID.getInstance(nodeID);
for (Map.Entry<String, ClusteredServerItem> entry : serverItems.entrySet()) { for (Map.Entry<String, ClusteredServerItem> entry : serverItems.entrySet()) {
String jid = entry.getKey(); String jid = entry.getKey();
Lock lock = LockManager.getLock(jid + "item"); Lock lock = LockManager.getLock(jid + "item");
......
...@@ -76,7 +76,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; ...@@ -76,7 +76,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
*/ */
public class PresenceUpdateHandler extends BasicModule implements ChannelHandler, ClusterEventListener { public class PresenceUpdateHandler extends BasicModule implements ChannelHandler, ClusterEventListener {
private static final String PRESENCE_CACHE_NAME = "Directed Presences"; public static final String PRESENCE_CACHE_NAME = "Directed Presences";
/** /**
* Keeps track of entities that sent directed presences to other entities. In this map * Keeps track of entities that sent directed presences to other entities. In this map
...@@ -413,6 +413,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler ...@@ -413,6 +413,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
if (affectedDirectedPresence == null) { if (affectedDirectedPresence == null) {
affectedDirectedPresence = new DirectedPresence(handlerJID); affectedDirectedPresence = new DirectedPresence(handlerJID);
directedPresences.add(affectedDirectedPresence);
} }
affectedDirectedPresence.addReceiver(jid); affectedDirectedPresence.addReceiver(jid);
......
...@@ -70,6 +70,14 @@ public class LdapUserProvider implements UserProvider { ...@@ -70,6 +70,14 @@ public class LdapUserProvider implements UserProvider {
} }
public User loadUser(String username) throws UserNotFoundException { public User loadUser(String username) throws UserNotFoundException {
String userDomain = JiveGlobals.getProperty("xmpp.domain");
if(username.contains("@")) {
userDomain = username.substring((username.lastIndexOf("@")+1));
username = username.substring(0,username.lastIndexOf("@"));
}
if(!userDomain.equals(JiveGlobals.getProperty("xmpp.domain"))) {
throw new UserNotFoundException("Unknown domain: "+userDomain);
}
// Un-escape username. // Un-escape username.
username = JID.unescapeNode(username); username = JID.unescapeNode(username);
DirContext ctx = null; DirContext ctx = null;
......
...@@ -11,21 +11,16 @@ ...@@ -11,21 +11,16 @@
package org.jivesoftware.openfire.muc; package org.jivesoftware.openfire.muc;
import org.dom4j.Element;
import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.Log;
import org.xmpp.packet.Message;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.*;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.TimeZone;
import org.jivesoftware.openfire.muc.spi.MUCRoleImpl;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.FastDateFormat;
import org.dom4j.Element;
import org.xmpp.packet.Message;
/** /**
* Represents the amount of history requested by an occupant while joining a room. There are * Represents the amount of history requested by an occupant while joining a room. There are
...@@ -136,7 +131,7 @@ public class HistoryRequest { ...@@ -136,7 +131,7 @@ public class HistoryRequest {
* @param joinRole the user that will receive the history. * @param joinRole the user that will receive the history.
* @param roomHistory the history of the room. * @param roomHistory the history of the room.
*/ */
public void sendHistory(MUCRoleImpl joinRole, MUCRoomHistory roomHistory) { public void sendHistory(LocalMUCRole joinRole, MUCRoomHistory roomHistory) {
if (!isConfigured()) { if (!isConfigured()) {
Iterator history = roomHistory.getMessageHistory(); Iterator history = roomHistory.getMessageHistory();
while (history.hasNext()) { while (history.hasNext()) {
......
...@@ -11,13 +11,13 @@ ...@@ -11,13 +11,13 @@
package org.jivesoftware.openfire.muc; package org.jivesoftware.openfire.muc;
import org.jivesoftware.openfire.muc.cluster.UpdateHistoryStrategy;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.CacheFactory;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
import java.util.Iterator; import java.util.*;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
/** /**
...@@ -96,10 +96,18 @@ public class HistoryStrategy { ...@@ -96,10 +96,18 @@ public class HistoryStrategy {
* @param max the maximum number of messages to store in applicable strategies. * @param max the maximum number of messages to store in applicable strategies.
*/ */
public void setMaxNumber(int max) { public void setMaxNumber(int max) {
if (maxNumber == max) {
// Do nothing since value has not changed
return;
}
this.maxNumber = max; this.maxNumber = max;
if (contextPrefix != null){ if (contextPrefix != null){
JiveGlobals.setProperty(contextPrefix + ".maxNumber", Integer.toString(maxNumber)); JiveGlobals.setProperty(contextPrefix + ".maxNumber", Integer.toString(maxNumber));
} }
if (parent == null) {
// Update the history strategy of the MUC service
CacheFactory.doClusterTask(new UpdateHistoryStrategy(this));
}
} }
/** /**
...@@ -108,12 +116,20 @@ public class HistoryStrategy { ...@@ -108,12 +116,20 @@ public class HistoryStrategy {
* @param newType The new type of chat history to use. * @param newType The new type of chat history to use.
*/ */
public void setType(Type newType){ public void setType(Type newType){
if (type == newType) {
// Do nothing since value has not changed
return;
}
if (newType != null){ if (newType != null){
type = newType; type = newType;
} }
if (contextPrefix != null){ if (contextPrefix != null){
JiveGlobals.setProperty(contextPrefix + ".type", type.toString()); JiveGlobals.setProperty(contextPrefix + ".type", type.toString());
} }
if (parent == null) {
// Update the history strategy of the MUC service
CacheFactory.doClusterTask(new UpdateHistoryStrategy(this));
}
} }
/** /**
...@@ -195,6 +211,8 @@ public class HistoryStrategy { ...@@ -195,6 +211,8 @@ public class HistoryStrategy {
*/ */
public Iterator<Message> getMessageHistory(){ public Iterator<Message> getMessageHistory(){
LinkedList<Message> list = new LinkedList<Message>(history); LinkedList<Message> list = new LinkedList<Message>(history);
// Sort messages. Messages may be out of order when running inside of a cluster
Collections.sort(list, new MessageComparator());
return list.iterator(); return list.iterator();
} }
...@@ -207,6 +225,8 @@ public class HistoryStrategy { ...@@ -207,6 +225,8 @@ public class HistoryStrategy {
*/ */
public ListIterator<Message> getReverseMessageHistory(){ public ListIterator<Message> getReverseMessageHistory(){
LinkedList<Message> list = new LinkedList<Message>(history); LinkedList<Message> list = new LinkedList<Message>(history);
// Sort messages. Messages may be out of order when running inside of a cluster
Collections.sort(list, new MessageComparator());
return list.listIterator(list.size()); return list.listIterator(list.size());
} }
...@@ -227,14 +247,14 @@ public class HistoryStrategy { ...@@ -227,14 +247,14 @@ public class HistoryStrategy {
*/ */
public void setTypeFromString(String typeName) { public void setTypeFromString(String typeName) {
try { try {
setType(Type.valueOf(typeName)); type = Type.valueOf(typeName);
} }
catch (Exception e) { catch (Exception e) {
if (parent != null) { if (parent != null) {
setType(Type.defaulType); type = Type.defaulType;
} }
else { else {
setType(Type.number); type = Type.number;
} }
} }
} }
...@@ -251,7 +271,7 @@ public class HistoryStrategy { ...@@ -251,7 +271,7 @@ public class HistoryStrategy {
String maxNumberString = JiveGlobals.getProperty(prefix + ".maxNumber"); String maxNumberString = JiveGlobals.getProperty(prefix + ".maxNumber");
if (maxNumberString != null && maxNumberString.trim().length() > 0){ if (maxNumberString != null && maxNumberString.trim().length() > 0){
try { try {
setMaxNumber(Integer.parseInt(maxNumberString)); this.maxNumber = Integer.parseInt(maxNumberString);
} }
catch (Exception e){ catch (Exception e){
Log.info("Jive property " + prefix + ".maxNumber not a valid number."); Log.info("Jive property " + prefix + ".maxNumber not a valid number.");
...@@ -269,4 +289,12 @@ public class HistoryStrategy { ...@@ -269,4 +289,12 @@ public class HistoryStrategy {
public boolean hasChangedSubject() { public boolean hasChangedSubject() {
return roomSubject != null; return roomSubject != null;
} }
private static class MessageComparator implements Comparator<Message> {
public int compare(Message o1, Message o2) {
String stamp1 = o1.getChildElement("x", "jabber:x:delay").attributeValue("stamp");
String stamp2 = o2.getChildElement("x", "jabber:x:delay").attributeValue("stamp");
return stamp1.compareTo(stamp2);
}
}
} }
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
package org.jivesoftware.openfire.muc; package org.jivesoftware.openfire.muc;
import org.dom4j.Element; import org.jivesoftware.openfire.cluster.NodeID;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
...@@ -27,6 +27,139 @@ import org.xmpp.packet.Presence; ...@@ -27,6 +27,139 @@ import org.xmpp.packet.Presence;
*/ */
public interface MUCRole { public interface MUCRole {
/**
* Obtain the current presence status of a user in a chatroom.
*
* @return The presence of the user in the room.
*/
public Presence getPresence();
/**
* Set the current presence status of a user in a chatroom.
*
* @param presence The presence of the user in the room.
*/
public void setPresence(Presence presence);
/**
* Call this method to promote or demote a user's role in a chatroom.
* It is common for the chatroom or other chat room members to change
* the role of users (a moderator promoting another user to moderator
* status for example).<p>
* <p/>
* Owning ChatUsers should have their membership roles updated.
*
* @param newRole The new role that the user will play.
* @throws NotAllowedException Thrown if trying to change the moderator role to an owner or
* administrator.
*/
public void setRole(Role newRole) throws NotAllowedException;
/**
* Obtain the role state of the user.
*
* @return The role status of this user.
*/
public Role getRole();
/**
* Call this method to promote or demote a user's affiliation in a chatroom.
*
* @param newAffiliation the new affiliation that the user will play.
* @throws NotAllowedException thrown if trying to ban an owner or an administrator.
*/
public void setAffiliation(Affiliation newAffiliation) throws NotAllowedException;
/**
* Obtain the affiliation state of the user.
*
* @return The affiliation status of this user.
*/
public Affiliation getAffiliation();
/**
* Changes the nickname of the occupant within the room to the new nickname.
*
* @param nickname the new nickname of the occupant in the room.
*/
void changeNickname(String nickname);
/**
* Obtain the nickname for the user in the chatroom.
*
* @return The user's nickname in the room or null if invisible.
*/
public String getNickname();
/**
* Destroys this role after the occupant left the room. This role will be
* removed from MUCUser.
*/
public void destroy();
/**
* Returns true if the room occupant does not want to get messages broadcasted to all
* room occupants. This type of users are called "deaf" occupants. Deaf occupants will still
* be able to get private messages, presences, IQ packets or room history.<p>
*
* To be a deaf occupant the initial presence sent to the room while joining the room has
* to include the following child element:
* <pre>
* &lt;x xmlns='http://jivesoftware.org/protocol/muc'&gt;
* &lt;deaf-occupant/&gt;
* &lt;/x&gt;
* </pre>
*
* Note that this is a custom extension to the MUC specification.
*
* @return true if the room occupant does not want to get messages broadcasted to all
* room occupants.
*/
boolean isVoiceOnly();
/**
* Obtain the chat room that hosts this user's role.
*
* @return The chatroom hosting this role.
*/
public MUCRoom getChatRoom();
/**
* Obtain the XMPPAddress representing this role in a room: room@server/nickname
*
* @return The Jabber ID that represents this role in the room.
*/
public JID getRoleAddress();
/**
* Obtain the XMPPAddress of the user that joined the room. A <tt>null</tt> null value
* represents the room's role.
*
* @return The address of the user that joined the room or null if this role belongs to the room itself.
*/
public JID getUserAddress();
/**
* Returns true if this room occupant is hosted by this JVM.
*
* @return true if this room occupant is hosted by this JVM
*/
public boolean isLocal();
/**
* Returns the id of the node that is hosting the room occupant.
*
* @return the id of the node that is hosting the room occupant.
*/
public NodeID getNodeID();
/**
* Sends a packet to the user.
*
* @param packet The packet to send
*/
public void send(Packet packet);
public enum Role { public enum Role {
/** /**
...@@ -141,125 +274,4 @@ public interface MUCRole { ...@@ -141,125 +274,4 @@ public interface MUCRole {
} }
} }
} }
/**
* Obtain the current presence status of a user in a chatroom.
*
* @return The presence of the user in the room.
*/
public Presence getPresence();
/**
* Returns the extended presence information that includes information about roles,
* affiliations, JIDs, etc.
*
* @return the extended presence information that includes information about roles,
* affiliations.
*/
public Element getExtendedPresenceInformation();
/**
* Set the current presence status of a user in a chatroom.
*
* @param presence The presence of the user in the room.
*/
public void setPresence(Presence presence);
/**
* Call this method to promote or demote a user's role in a chatroom.
* It is common for the chatroom or other chat room members to change
* the role of users (a moderator promoting another user to moderator
* status for example).<p>
* <p/>
* Owning ChatUsers should have their membership roles updated.
*
* @param newRole The new role that the user will play.
* @throws NotAllowedException Thrown if trying to change the moderator role to an owner or
* administrator.
*/
public void setRole(Role newRole) throws NotAllowedException;
/**
* Obtain the role state of the user.
*
* @return The role status of this user.
*/
public Role getRole();
/**
* Call this method to promote or demote a user's affiliation in a chatroom.
*
* @param newAffiliation the new affiliation that the user will play.
* @throws NotAllowedException thrown if trying to ban an owner or an administrator.
*/
public void setAffiliation(Affiliation newAffiliation) throws NotAllowedException;
/**
* Obtain the affiliation state of the user.
*
* @return The affiliation status of this user.
*/
public Affiliation getAffiliation();
/**
* Obtain the nickname for the user in the chatroom.
*
* @return The user's nickname in the room or null if invisible.
*/
public String getNickname();
/**
* Changes the nickname of the occupant within the room to the new nickname.
*
* @param nickname the new nickname of the occupant in the room.
*/
public void changeNickname(String nickname);
/**
* Returns true if the room occupant does not want to get messages broadcasted to all
* room occupants. This type of users are called "deaf" occupants. Deaf occupants will still
* be able to get private messages, presences, IQ packets or room history.<p>
*
* To be a deaf occupant the initial presence sent to the room while joining the room has
* to include the following child element:
* <pre>
* &lt;x xmlns='http://jivesoftware.org/protocol/muc'&gt;
* &lt;deaf-occupant/&gt;
* &lt;/x&gt;
* </pre>
*
* Note that this is a custom extension to the MUC specification.
*
* @return true if the room occupant does not want to get messages broadcasted to all
* room occupants.
*/
boolean isVoiceOnly();
/**
* Obtain the chat user that plays this role.
*
* @return The chatuser playing this role.
*/
public MUCUser getChatUser();
/**
* Obtain the chat room that hosts this user's role.
*
* @return The chatroom hosting this role.
*/
public MUCRoom getChatRoom();
/**
* Obtain the XMPPAddress representing this role in a room: room@server/nickname
*
* @return The Jabber ID that represents this role in the room.
*/
public JID getRoleAddress();
/**
* Sends a packet to the user.
*
* @param packet The packet to send
*/
public void send(Packet packet);
} }
\ No newline at end of file
...@@ -11,23 +11,26 @@ ...@@ -11,23 +11,26 @@
package org.jivesoftware.openfire.muc; package org.jivesoftware.openfire.muc;
import java.util.List;
import java.util.Date;
import java.util.Collection;
import org.dom4j.Element; import org.dom4j.Element;
import org.jivesoftware.database.JiveID;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.muc.spi.IQAdminHandler; import org.jivesoftware.openfire.muc.spi.IQAdminHandler;
import org.jivesoftware.openfire.muc.spi.IQOwnerHandler; import org.jivesoftware.openfire.muc.spi.IQOwnerHandler;
import org.jivesoftware.util.NotFoundException; import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
import org.jivesoftware.util.JiveConstants; import org.jivesoftware.openfire.muc.spi.LocalMUCUser;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.user.UserAlreadyExistsException; import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.database.JiveID; import org.jivesoftware.util.JiveConstants;
import org.xmpp.packet.Presence; import org.jivesoftware.util.NotFoundException;
import org.xmpp.packet.Message;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import java.io.Externalizable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/** /**
...@@ -37,7 +40,7 @@ import org.xmpp.packet.Packet; ...@@ -37,7 +40,7 @@ import org.xmpp.packet.Packet;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
@JiveID(JiveConstants.MUC_ROOM) @JiveID(JiveConstants.MUC_ROOM)
public interface MUCRoom { public interface MUCRoom extends Externalizable {
/** /**
* Get the name of this room. * Get the name of this room.
...@@ -139,13 +142,13 @@ public interface MUCRoom { ...@@ -139,13 +142,13 @@ public interface MUCRoom {
List<MUCRole> getOccupantsByBareJID(String jid) throws UserNotFoundException; List<MUCRole> getOccupantsByBareJID(String jid) throws UserNotFoundException;
/** /**
* Obtain the role of a given user in the room by his full JID. * Returns the role of a given user in the room by his full JID or <tt>null</tt>
* if no role was found for the specified user.
* *
* @param jid The full jid of the user you'd like to obtain * @param jid The full jid of the user you'd like to obtain
* @return The user's role in the room * @return The user's role in the room or null if not found.
* @throws UserNotFoundException If there is no user with the given nickname
*/ */
MUCRole getOccupantByFullJID(JID jid) throws UserNotFoundException; MUCRole getOccupantByFullJID(JID jid);
/** /**
* Obtain the roles of all users in the chatroom. * Obtain the roles of all users in the chatroom.
...@@ -209,7 +212,7 @@ public interface MUCRoom { ...@@ -209,7 +212,7 @@ public interface MUCRoom {
* @throws NotAcceptableException If the registered user is trying to join with a * @throws NotAcceptableException If the registered user is trying to join with a
* nickname different than the reserved nickname. * nickname different than the reserved nickname.
*/ */
MUCRole joinRoom(String nickname, String password, HistoryRequest historyRequest, MUCUser user, LocalMUCRole joinRoom(String nickname, String password, HistoryRequest historyRequest, LocalMUCUser user,
Presence presence) throws UnauthorizedException, UserAlreadyExistsException, Presence presence) throws UnauthorizedException, UserAlreadyExistsException,
RoomLockedException, ForbiddenException, RegistrationRequiredException, RoomLockedException, ForbiddenException, RegistrationRequiredException,
ConflictException, ServiceUnavailableException, NotAcceptableException; ConflictException, ServiceUnavailableException, NotAcceptableException;
...@@ -217,10 +220,9 @@ public interface MUCRoom { ...@@ -217,10 +220,9 @@ public interface MUCRoom {
/** /**
* Remove a member from the chat room. * Remove a member from the chat room.
* *
* @param nickname The user to remove * @param leaveRole room occupant that left the room.
* @throws UserNotFoundException If the nickname is not found.
*/ */
void leaveRoom(String nickname) throws UserNotFoundException; void leaveRoom(MUCRole leaveRole);
/** /**
* Destroys the room. Each occupant will be removed and will receive a presence stanza of type * Destroys the room. Each occupant will be removed and will receive a presence stanza of type
...@@ -417,13 +419,23 @@ public interface MUCRoom { ...@@ -417,13 +419,23 @@ public interface MUCRoom {
*/ */
public boolean isManuallyLocked(); public boolean isManuallyLocked();
/**
* An event callback fired whenever an occupant updated his presence in the chatroom.
*
* @param occupantRole occupant that changed his presence in the room.
* @param newPresence presence sent by the occupant.
*/
public void presenceUpdated(MUCRole occupantRole, Presence newPresence);
/** /**
* An event callback fired whenever an occupant changes his nickname within the chatroom. * An event callback fired whenever an occupant changes his nickname within the chatroom.
* *
* @param occupantRole occupant that changed his nickname in the room.
* @param newPresence presence sent by the occupant with the new nickname.
* @param oldNick old nickname within the room. * @param oldNick old nickname within the room.
* @param newNick new nickname within the room. * @param newNick new nickname within the room.
*/ */
public void nicknameChanged(String oldNick, String newNick); public void nicknameChanged(MUCRole occupantRole, Presence newPresence, String oldNick, String newNick);
/** /**
* Changes the room's subject if the occupant has enough permissions. The occupant must be * Changes the room's subject if the occupant has enough permissions. The occupant must be
......
...@@ -83,7 +83,7 @@ public final class MUCRoomHistory { ...@@ -83,7 +83,7 @@ public final class MUCRoomHistory {
// Set the Full JID as the "from" attribute // Set the Full JID as the "from" attribute
try { try {
MUCRole role = room.getOccupant(message.getFrom().getResource()); MUCRole role = room.getOccupant(message.getFrom().getResource());
delayElement.addAttribute("from", role.getChatUser().getAddress().toString()); delayElement.addAttribute("from", role.getUserAddress().toString());
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
// Ignore. // Ignore.
...@@ -105,8 +105,7 @@ public final class MUCRoomHistory { ...@@ -105,8 +105,7 @@ public final class MUCRoomHistory {
// Set the Full JID as the "from" attribute // Set the Full JID as the "from" attribute
try { try {
MUCRole role = room.getOccupant(packet.getFrom().getResource()); MUCRole role = room.getOccupant(packet.getFrom().getResource());
delayInformation.addAttribute("from", role.getChatUser().getAddress() delayInformation.addAttribute("from", role.getUserAddress().toString());
.toString());
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
// Ignore. // Ignore.
......
...@@ -11,12 +11,9 @@ ...@@ -11,12 +11,9 @@
package org.jivesoftware.openfire.muc; package org.jivesoftware.openfire.muc;
import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.openfire.ChannelHandler; import org.jivesoftware.openfire.ChannelHandler;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import java.util.Iterator;
/** /**
* The chat user is a separate user abstraction for interacting with * The chat user is a separate user abstraction for interacting with
* the chat server. Centralizing chat users to the Jabber entity that * the chat server. Centralizing chat users to the Jabber entity that
...@@ -32,13 +29,6 @@ import java.util.Iterator; ...@@ -32,13 +29,6 @@ import java.util.Iterator;
*/ */
public interface MUCUser extends ChannelHandler { public interface MUCUser extends ChannelHandler {
/**
* Obtain a user ID (useful for database indexing).
*
* @return The user's id number if any (-1 indicates the implementation doesn't support ids)
*/
long getID();
/** /**
* Obtain the address of the user. The address is used by services like the core * Obtain the address of the user. The address is used by services like the core
* server packet router to determine if a packet should be sent to the handler. * server packet router to determine if a packet should be sent to the handler.
...@@ -48,51 +38,4 @@ public interface MUCUser extends ChannelHandler { ...@@ -48,51 +38,4 @@ public interface MUCUser extends ChannelHandler {
* @return the address of the packet handler. * @return the address of the packet handler.
*/ */
public JID getAddress(); public JID getAddress();
/**
* Obtain the role of the user in a particular room.
*
* @param roomName The name of the room we're interested in
* @return The role the user plays in that room
* @throws NotFoundException if the user does not have a role in the given room
*/
MUCRole getRole(String roomName) throws NotFoundException;
/**
* Get all roles for this user.
*
* @return Iterator over all roles for this user
*/
Iterator<MUCRole> getRoles();
/**
* Adds the role of the user in a particular room.
*
* @param roomName The name of the room.
* @param role The new role of the user.
*/
void addRole(String roomName, MUCRole role);
/**
* Removes the role of the user in a particular room.<p>
*
* Note: PREREQUISITE: A lock on this object has already been obtained.
*
* @param roomName The name of the room we're being removed
*/
void removeRole(String roomName);
/**
* Returns true if the user is currently present in one or more rooms.
*
* @return true if the user is currently present in one or more rooms.
*/
boolean isJoined();
/**
* Get time (in milliseconds from System currentTimeMillis()) since last packet.
*
* @return The time when the last packet was sent from this user
*/
long getLastPacketTime();
} }
\ No newline at end of file
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
package org.jivesoftware.openfire.muc; package org.jivesoftware.openfire.muc;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.xmpp.component.Component; import org.xmpp.component.Component;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
...@@ -235,30 +234,6 @@ public interface MultiUserChatServer extends Component { ...@@ -235,30 +234,6 @@ public interface MultiUserChatServer extends Component {
*/ */
void removeChatRoom(String roomName); void removeChatRoom(String roomName);
/**
* Removes a user from all chat rooms.
*
* @param jabberID The user's normal jid, not the chat nickname jid.
*/
void removeUser(JID jabberID);
/**
* Obtain a chat user by XMPPAddress.
*
* @param userjid The XMPPAddress of the user.
* @return The chatuser corresponding to that XMPPAddress.
* @throws UserNotFoundException If the user is not found and can't be auto-created.
*/
MUCUser getChatUser(JID userjid) throws UserNotFoundException;
/**
* Broadcast a given message to all members of this chat room. The sender is always set to be
* the chatroom.
*
* @param msg The message to broadcast.
*/
void serverBroadcast(String msg);
/** /**
* Returns the total chat time of all rooms combined. * Returns the total chat time of all rooms combined.
* *
......
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.Message;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that broadcasts a message to local room occupants. When a room occupant sends a
* message to the room each cluster node will execute this task and broadcast the message
* to its local room occupants.
*
* @author Gaston Dombiak
*/
public class BroascastMessageRequest extends MUCRoomTask {
private int occupants;
private Message message;
public BroascastMessageRequest() {
}
public BroascastMessageRequest(LocalMUCRoom room, Message message, int occupants) {
super(room);
this.message = message;
this.occupants = occupants;
}
public Message getMessage() {
return message;
}
public int getOccupants() {
return occupants;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().broadcast(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) message.getElement());
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
message = new Message(packetElement, true);
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.Presence;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that broadcasts the presence of a room occupant to the occupants of the room
* being hosted by the cluster node. When a room occupant changes his presence an
* instance of this class will be sent to each cluster node and when executed a broadcast
* of the updated presence will be sent to local room occupants.
*
* @author Gaston Dombiak
*/
public class BroascastPresenceRequest extends MUCRoomTask {
private Presence presence;
public BroascastPresenceRequest() {
}
public BroascastPresenceRequest(LocalMUCRoom room, Presence message) {
super(room);
this.presence = message;
}
public Presence getPresence() {
return presence;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().broadcast(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true);
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.Presence;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that changes the nickname of an existing room occupant in the cluster node. When
* a room occupant changes his nickname the other cluster nodes, that hold a
* {@link org.jivesoftware.openfire.muc.spi.RemoteMUCRole} will need to update their local
* information with the new nickname.
*
* @author Gaston Dombiak
*/
public class ChangeNickname extends MUCRoomTask {
private String oldNick;
private String newNick;
private Presence presence;
public ChangeNickname() {
}
public ChangeNickname(LocalMUCRoom room, String oldNick, String newNick, Presence presence) {
super(room);
this.oldNick = oldNick;
this.newNick = newNick;
this.presence = presence;
}
public String getOldNick() {
return oldNick;
}
public String getNewNick() {
return newNick;
}
public Presence getPresence() {
return presence;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().nicknameChanged(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
ExternalizableUtil.getInstance().writeSafeUTF(out, oldNick);
ExternalizableUtil.getInstance().writeSafeUTF(out, newNick);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true);
oldNick = ExternalizableUtil.getInstance().readSafeUTF(in);
newNick = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that destroys the local room in the cluster node. Local room occupants
* hosted in the cluster node will get the notification of the room being
* destroyed.
*
* @author Gaston Dombiak
*/
public class DestroyRoomRequest extends MUCRoomTask {
private String alternateJID;
private String reason;
public DestroyRoomRequest() {
}
public DestroyRoomRequest(LocalMUCRoom room, String alternateJID, String reason) {
super(room);
this.alternateJID = alternateJID;
this.reason = reason;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().destroyRoom(this);
}
public String getAlternateJID() {
return alternateJID;
}
public String getReason() {
return reason;
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeBoolean(out, alternateJID != null);
if (alternateJID != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, alternateJID);
}
ExternalizableUtil.getInstance().writeBoolean(out, reason != null);
if (reason != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, reason);
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
if (ExternalizableUtil.getInstance().readBoolean(in)) {
alternateJID = ExternalizableUtil.getInstance().readSafeUTF(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
reason = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ClusterTask;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Task requested by each cluster node when a new node joins the cluster. Each existing cluster
* node will request the list of rooms with occupants <tt>hosted by</tt> the new cluster node.
*
* @author Gaston Dombiak
*/
public class GetNewMemberRoomsRequest implements ClusterTask {
private List<RoomInfo> rooms;
public GetNewMemberRoomsRequest() {
}
public Object getResult() {
return rooms;
}
public void run() {
rooms = new ArrayList<RoomInfo>();
// Get rooms that have local occupants and include them in the reply
MultiUserChatServer mucServer = XMPPServer.getInstance().getMultiUserChatServer();
for (MUCRoom room : mucServer.getChatRooms()) {
LocalMUCRoom localRoom = (LocalMUCRoom) room;
Collection<MUCRole> localOccupants = new ArrayList<MUCRole>();
for (MUCRole occupant : room.getOccupants()) {
if (occupant.isLocal()) {
localOccupants.add(occupant);
}
}
if (!localOccupants.isEmpty()) {
rooms.add(new RoomInfo(localRoom, localOccupants));
}
}
}
public void writeExternal(ObjectOutput out) throws IOException {
// Do nothing
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// Do nothing
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.spi.MultiUserChatServerImpl;
import org.jivesoftware.util.cache.ClusterTask;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task to be executed in each cluster node to obtain the total number of
* users using the multi user chat service.
*
* @author Gaston Dombiak
*/
public class GetNumberConnectedUsers implements ClusterTask{
private Integer count;
public Object getResult() {
return count;
}
public void run() {
MultiUserChatServerImpl mucServer = (MultiUserChatServerImpl) XMPPServer.getInstance().getMultiUserChatServer();
count = mucServer.getNumberConnectedUsers(true);
}
public void writeExternal(ObjectOutput out) throws IOException {
// Do nothing
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// Do nothing
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task related to a room to be executed in a cluster node. This is a base
* class to specific room tasks. The base class just keeps track of the room
* related to the task.
*
* @author Gaston Dombiak
*/
public abstract class MUCRoomTask implements ClusterTask {
private boolean originator;
private LocalMUCRoom room;
protected MUCRoomTask() {
}
protected MUCRoomTask(LocalMUCRoom room) {
this.room = room;
}
public LocalMUCRoom getRoom() {
return room;
}
public boolean isOriginator() {
return originator;
}
public void setOriginator(boolean originator) {
this.originator = originator;
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeBoolean(out, originator);
ExternalizableUtil.getInstance().writeSafeUTF(out, room.getName());
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
originator = ExternalizableUtil.getInstance().readBoolean(in);
String roomName = ExternalizableUtil.getInstance().readSafeUTF(in);
room = (LocalMUCRoom) XMPPServer.getInstance().getMultiUserChatServer().getChatRoom(roomName);
if (room == null) {
throw new IllegalArgumentException("Room not found: " + roomName);
}
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that will remove a room occupant from the list of occupants in the room.
*
* @author Gaston Dombiak
*/
public class OccupantAddedEvent extends MUCRoomTask {
private Presence presence;
private int role;
private int affiliation;
private boolean voiceOnly;
private JID roleAddress;
private JID userAddress;
private NodeID nodeID;
private boolean sendPresence;
public OccupantAddedEvent() {
}
public OccupantAddedEvent(LocalMUCRoom room, MUCRole occupant) {
super(room);
presence = occupant.getPresence();
role = occupant.getRole().ordinal();
affiliation = occupant.getAffiliation().ordinal();
voiceOnly = occupant.isVoiceOnly();
roleAddress = occupant.getRoleAddress();
userAddress = occupant.getUserAddress();
nodeID = XMPPServer.getInstance().getNodeID();
}
public Presence getPresence() {
return presence;
}
public String getNickname() {
return presence.getTo().getResource();
}
public MUCRole.Role getRole() {
return MUCRole.Role.values()[role];
}
public MUCRole.Affiliation getAffiliation() {
return MUCRole.Affiliation.values()[affiliation];
}
public boolean isVoiceOnly() {
return voiceOnly;
}
public JID getRoleAddress() {
return roleAddress;
}
public JID getUserAddress() {
return userAddress;
}
public NodeID getNodeID() {
return nodeID;
}
/**
* Sets if the room should broadcast presence of the new occupant to occupants
* hosted by this cluster node.
*
* @param sendPresence true if the room should broadcast presence of the new occupant to occupants
* hosted by this cluster node.
*/
public void setSendPresence(boolean sendPresence) {
this.sendPresence = sendPresence;
}
/**
* Returns true if the room should broadcast presence of the new occupant to occupants
* hosted by this cluster node.
*
* @return true if the room should broadcast presence of the new occupant to occupants
* hosted by this cluster node.
*/
public boolean isSendPresence() {
return sendPresence;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().occupantAdded(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
ExternalizableUtil.getInstance().writeInt(out, role);
ExternalizableUtil.getInstance().writeInt(out, affiliation);
ExternalizableUtil.getInstance().writeBoolean(out, voiceOnly);
ExternalizableUtil.getInstance().writeSerializable(out, roleAddress);
ExternalizableUtil.getInstance().writeSerializable(out, userAddress);
ExternalizableUtil.getInstance().writeByteArray(out, nodeID.toByteArray());
ExternalizableUtil.getInstance().writeBoolean(out, sendPresence);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true);
role = ExternalizableUtil.getInstance().readInt(in);
affiliation = ExternalizableUtil.getInstance().readInt(in);
voiceOnly = ExternalizableUtil.getInstance().readBoolean(in);
roleAddress = (JID) ExternalizableUtil.getInstance().readSerializable(in);
userAddress = (JID) ExternalizableUtil.getInstance().readSerializable(in);
nodeID = NodeID.getInstance(ExternalizableUtil.getInstance().readByteArray(in));
sendPresence = ExternalizableUtil.getInstance().readBoolean(in);
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that removes a room occupant from the list of occupants in the room. The
* occupant to remove is actualy a {@link org.jivesoftware.openfire.muc.spi.RemoteMUCRole}.
*
* @author Gaston Dombiak
*/
public class OccupantLeftEvent extends MUCRoomTask {
private MUCRole role;
private String nickname;
public OccupantLeftEvent() {
}
public OccupantLeftEvent(LocalMUCRoom room, MUCRole role) {
super(room);
this.role = role;
this.nickname = role.getNickname();
}
public MUCRole getRole() {
if (role == null) {
try {
role = getRoom().getOccupant(nickname);
} catch (UserNotFoundException e) {
// Ignore
}
}
return role;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().leaveRoom(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, nickname);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
nickname = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.openfire.muc.spi.MultiUserChatServerImpl;
import org.jivesoftware.util.cache.ClusterTask;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that adds a new local room to the cluster node. When a room is created in a
* cluster node the rest of the cluster nodes will need to get the new room added
* in their list of existing rooms.
*
* @author Gaston Dombiak
*/
public class RoomAvailableEvent implements ClusterTask {
private LocalMUCRoom room;
public RoomAvailableEvent() {
}
public RoomAvailableEvent(LocalMUCRoom room) {
this.room = room;
}
public Object getResult() {
return null;
}
public void run() {
MultiUserChatServerImpl mucServer = (MultiUserChatServerImpl) XMPPServer.getInstance().getMultiUserChatServer();
mucServer.chatRoomAdded(room);
}
public void writeExternal(ObjectOutput out) throws IOException {
room.writeExternal(out);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
room = new LocalMUCRoom();
room.readExternal(in);
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Representation of a room configuration and its occupants. This information is requested
* by a cluster node when joining the cluster (requested to the senior member) and also from
* each cluster node to the new node joining the cluster. Each cluster node (existing and
* new one) has to merge its local rooms with the new ones.
*
* @author Gaston Dombiak
*/
public class RoomInfo implements Externalizable {
private LocalMUCRoom room;
private List<OccupantAddedEvent> occupants = new ArrayList<OccupantAddedEvent>();
/**
* Do not use this constructor. Needed for Externalizable interface.
*/
public RoomInfo() {
}
public RoomInfo(LocalMUCRoom room, Collection<MUCRole> occupants) {
this.room = room;
for (MUCRole occupant : occupants) {
this.occupants.add(new OccupantAddedEvent(room, occupant));
}
}
public LocalMUCRoom getRoom() {
return room;
}
public List<OccupantAddedEvent> getOccupants() {
return occupants;
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSerializable(out, room);
ExternalizableUtil.getInstance().writeExternalizableCollection(out, occupants);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
room = (LocalMUCRoom) ExternalizableUtil.getInstance().readSerializable(in);
ExternalizableUtil.getInstance().readExternalizableCollection(in, occupants, getClass().getClassLoader());
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.spi.MultiUserChatServerImpl;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that will remove a local room from the cluster node. When a room is destroyed
* in a cluster node the rest of the cluster nodes will need to destroy their copy
* and send notifications to the room occupants hosted in the local cluster node.
*
* @author Gaston Dombiak
*/
public class RoomRemovedEvent implements ClusterTask {
private String roomName;
public RoomRemovedEvent() {
}
public RoomRemovedEvent(String roomName) {
this.roomName = roomName;
}
public Object getResult() {
return null;
}
public void run() {
MultiUserChatServerImpl mucServer = (MultiUserChatServerImpl) XMPPServer.getInstance().getMultiUserChatServer();
mucServer.chatRoomRemoved(roomName);
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSafeUTF(out, roomName);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
roomName = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that updates the configuration of a local room. When a room gets updated in a
* cluster node the rest of the cluster nodes will need to update their copy of the
* local room.
*
* @author Gaston Dombiak
*/
public class RoomUpdatedEvent extends MUCRoomTask {
private LocalMUCRoom room;
public RoomUpdatedEvent() {
}
public RoomUpdatedEvent(LocalMUCRoom room) {
super(room);
this.room = room;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().updateConfiguration(room);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
room.writeExternal(out);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
room = new LocalMUCRoom();
room.readExternal(in);
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ClusterTask;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
/**
* Task to be requested by a node that joins a cluster and be executed in the senior cluster member to get
* the rooms with occupants. The list of rooms with occupants is returned to the new cluster node so that
* the new cluster node can be updated and have the same information shared by the cluster.<p>
*
* Moreover, each existing cluster node will also need to learn the rooms with occupants that exist in
* the new cluster node and replicate them. This work is accomplished using {@link GetNewMemberRoomsRequest}.
*
* @author Gaston Dombiak
*/
public class SeniorMemberRoomsRequest implements ClusterTask {
private List<RoomInfo> rooms;
public SeniorMemberRoomsRequest() {
}
public Object getResult() {
return rooms;
}
public void run() {
rooms = new ArrayList<RoomInfo>();
// Get rooms that have occupants and include them in the reply
MultiUserChatServer mucServer = XMPPServer.getInstance().getMultiUserChatServer();
for (MUCRoom room : mucServer.getChatRooms()) {
LocalMUCRoom localRoom = (LocalMUCRoom) room;
if (!room.getOccupants().isEmpty()) {
rooms.add(new RoomInfo(localRoom, localRoom.getOccupants()));
}
}
}
public void writeExternal(ObjectOutput out) throws IOException {
// Do nothing
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// Do nothing
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.HistoryStrategy;
import org.jivesoftware.openfire.muc.spi.MultiUserChatServerImpl;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Cluster task that will update the history strategy used by the MultiUserChatServer
* service. It is currently not possible to edit the history strategy of a given room
* but only of the service. Therefore, this task will only update the service's strategy.
*
* @author Gaston Dombiak
*/
public class UpdateHistoryStrategy implements ClusterTask {
private int type;
private int maxNumber;
public UpdateHistoryStrategy() {
}
public UpdateHistoryStrategy(HistoryStrategy historyStrategy) {
type = historyStrategy.getType().ordinal();
maxNumber = historyStrategy.getMaxNumber();
}
public Object getResult() {
return null;
}
public void run() {
MultiUserChatServerImpl mucServer = (MultiUserChatServerImpl) XMPPServer.getInstance().getMultiUserChatServer();
HistoryStrategy strategy = mucServer.getHistoryStrategy();
strategy.setType(HistoryStrategy.Type.values()[type]);
strategy.setMaxNumber(maxNumber);
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeInt(out, type);
ExternalizableUtil.getInstance().writeInt(out, maxNumber);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
type = ExternalizableUtil.getInstance().readInt(in);
maxNumber = ExternalizableUtil.getInstance().readInt(in);
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.Presence;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that updates all information regarding a room occupant. Whenever a room
* occupant gets his affiliation, role, nickname or presence updated the other
* cluster nodes will need to reflect these changes.
*
* @author Gaston Dombiak
*/
public class UpdateOccupant extends MUCRoomTask {
private Presence presence;
private String nickname;
private int role;
private int affiliation;
public UpdateOccupant() {
}
public UpdateOccupant(LocalMUCRoom room, MUCRole role) {
super(room);
this.presence = role.getPresence();
this.nickname = role.getNickname();
this.role = role.getRole().ordinal();
this.affiliation = role.getAffiliation().ordinal();
}
public Presence getPresence() {
return presence;
}
public String getNickname() {
return nickname;
}
public MUCRole.Role getRole() {
return MUCRole.Role.values()[role];
}
public MUCRole.Affiliation getAffiliation() {
return MUCRole.Affiliation.values()[affiliation];
}
public Object getResult() {
return null;
}
public void run() {
getRoom().occupantUpdated(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
ExternalizableUtil.getInstance().writeSafeUTF(out, nickname);
ExternalizableUtil.getInstance().writeInt(out, role);
ExternalizableUtil.getInstance().writeInt(out, affiliation);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true);
nickname = ExternalizableUtil.getInstance().readSafeUTF(in);
role = ExternalizableUtil.getInstance().readInt(in);
affiliation = ExternalizableUtil.getInstance().readInt(in);
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.cluster;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.Presence;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that updates the presence of an occupant in a room. Each time an occupant
* changes his presence in the room the other cluster nodes will need to get the
* presence updated too for the occupant.
*
* @author Gaston Dombiak
*/
public class UpdatePresence extends MUCRoomTask {
private Presence presence;
private String nickname;
public UpdatePresence() {
}
public UpdatePresence(LocalMUCRoom room, Presence presence, String nickname) {
super(room);
this.presence = presence;
this.nickname = nickname;
}
public Presence getPresence() {
return presence;
}
public String getNickname() {
return nickname;
}
public Object getResult() {
return null;
}
public void run() {
getRoom().presenceUpdated(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
ExternalizableUtil.getInstance().writeSafeUTF(out, nickname);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true);
nickname = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
...@@ -36,11 +36,11 @@ import java.util.List; ...@@ -36,11 +36,11 @@ import java.util.List;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class IQAdminHandler { public class IQAdminHandler {
private MUCRoomImpl room; private LocalMUCRoom room;
private PacketRouter router; private PacketRouter router;
public IQAdminHandler(MUCRoomImpl chatroom, PacketRouter packetRouter) { public IQAdminHandler(LocalMUCRoom chatroom, PacketRouter packetRouter) {
this.room = chatroom; this.room = chatroom;
this.router = packetRouter; this.router = packetRouter;
} }
...@@ -170,7 +170,7 @@ public class IQAdminHandler { ...@@ -170,7 +170,7 @@ public class IQAdminHandler {
for (MUCRole role : room.getModerators()) { for (MUCRole role : room.getModerators()) {
metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin"); metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
metaData.addAttribute("role", "moderator"); metaData.addAttribute("role", "moderator");
metaData.addAttribute("jid", role.getChatUser().getAddress().toString()); metaData.addAttribute("jid", role.getUserAddress().toString());
metaData.addAttribute("nick", role.getNickname()); metaData.addAttribute("nick", role.getNickname());
metaData.addAttribute("affiliation", role.getAffiliation().toString()); metaData.addAttribute("affiliation", role.getAffiliation().toString());
} }
...@@ -183,7 +183,7 @@ public class IQAdminHandler { ...@@ -183,7 +183,7 @@ public class IQAdminHandler {
for (MUCRole role : room.getParticipants()) { for (MUCRole role : room.getParticipants()) {
metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin"); metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
metaData.addAttribute("role", "participant"); metaData.addAttribute("role", "participant");
metaData.addAttribute("jid", role.getChatUser().getAddress().toString()); metaData.addAttribute("jid", role.getUserAddress().toString());
metaData.addAttribute("nick", role.getNickname()); metaData.addAttribute("nick", role.getNickname());
metaData.addAttribute("affiliation", role.getAffiliation().toString()); metaData.addAttribute("affiliation", role.getAffiliation().toString());
} }
...@@ -219,7 +219,7 @@ public class IQAdminHandler { ...@@ -219,7 +219,7 @@ public class IQAdminHandler {
else { else {
// Get the JID based on the requested nick // Get the JID based on the requested nick
nick = item.attributeValue("nick"); nick = item.attributeValue("nick");
jid = room.getOccupant(nick).getChatUser().getAddress(); jid = room.getOccupant(nick).getUserAddress();
} }
room.lock.writeLock().lock(); room.lock.writeLock().lock();
...@@ -262,8 +262,7 @@ public class IQAdminHandler { ...@@ -262,8 +262,7 @@ public class IQAdminHandler {
if (MUCRole.Role.moderator != senderRole.getRole()) { if (MUCRole.Role.moderator != senderRole.getRole()) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
presences.add(room.kickOccupant(jid, presences.add(room.kickOccupant(jid, senderRole.getUserAddress(),
senderRole.getChatUser().getAddress(),
item.elementTextTrim("reason"))); item.elementTextTrim("reason")));
} }
} }
......
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
package org.jivesoftware.openfire.muc.spi; package org.jivesoftware.openfire.muc.spi;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.forms.DataForm; import org.jivesoftware.openfire.forms.DataForm;
import org.jivesoftware.openfire.forms.FormField; import org.jivesoftware.openfire.forms.FormField;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl; import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
...@@ -18,18 +22,16 @@ import org.jivesoftware.openfire.forms.spi.XFormFieldImpl; ...@@ -18,18 +22,16 @@ import org.jivesoftware.openfire.forms.spi.XFormFieldImpl;
import org.jivesoftware.openfire.muc.ConflictException; import org.jivesoftware.openfire.muc.ConflictException;
import org.jivesoftware.openfire.muc.ForbiddenException; import org.jivesoftware.openfire.muc.ForbiddenException;
import org.jivesoftware.openfire.muc.MUCRole; import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.openfire.muc.cluster.RoomUpdatedEvent;
import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import java.util.*; import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.cache.CacheFactory;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError; import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;
import java.util.*;
/** /**
* A handler for the IQ packet with namespace http://jabber.org/protocol/muc#owner. This kind of * A handler for the IQ packet with namespace http://jabber.org/protocol/muc#owner. This kind of
...@@ -39,7 +41,7 @@ import org.xmpp.packet.PacketError; ...@@ -39,7 +41,7 @@ import org.xmpp.packet.PacketError;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class IQOwnerHandler { public class IQOwnerHandler {
private MUCRoomImpl room; private LocalMUCRoom room;
private PacketRouter router; private PacketRouter router;
...@@ -47,7 +49,7 @@ public class IQOwnerHandler { ...@@ -47,7 +49,7 @@ public class IQOwnerHandler {
private Element probeResult; private Element probeResult;
public IQOwnerHandler(MUCRoomImpl chatroom, PacketRouter packetRouter) { public IQOwnerHandler(LocalMUCRoom chatroom, PacketRouter packetRouter) {
this.room = chatroom; this.room = chatroom;
this.router = packetRouter; this.router = packetRouter;
init(); init();
...@@ -209,7 +211,7 @@ public class IQOwnerHandler { ...@@ -209,7 +211,7 @@ public class IQOwnerHandler {
else { else {
// Get the bare JID based on the requested nick // Get the bare JID based on the requested nick
nick = item.attributeValue("nick"); nick = item.attributeValue("nick");
bareJID = room.getOccupant(nick).getChatUser().getAddress().toBareJID(); bareJID = room.getOccupant(nick).getUserAddress().toBareJID();
} }
jids.put(bareJID, affiliation); jids.put(bareJID, affiliation);
} }
...@@ -313,6 +315,10 @@ public class IQOwnerHandler { ...@@ -313,6 +315,10 @@ public class IQOwnerHandler {
if (room.isLocked() && !room.isManuallyLocked()) { if (room.isLocked() && !room.isManuallyLocked()) {
room.unlock(senderRole); room.unlock(senderRole);
} }
if (!room.isDestroyed) {
// Let other cluster nodes that the room has been updated
CacheFactory.doClusterTask(new RoomUpdatedEvent(room));
}
} }
} }
......
/** /**
* $RCSfile: MUCRoleImpl.java,v $ * $RCSfile: LocalMUCRole.java,v $
* $Revision: 3168 $ * $Revision: 3168 $
* $Date: 2005-12-07 13:55:47 -0300 (Wed, 07 Dec 2005) $ * $Date: 2005-12-07 13:55:47 -0300 (Wed, 07 Dec 2005) $
* *
...@@ -16,7 +16,11 @@ import org.dom4j.Element; ...@@ -16,7 +16,11 @@ import org.dom4j.Element;
import org.dom4j.QName; import org.dom4j.QName;
import org.jivesoftware.openfire.PacketRouter; import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.*; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.openfire.muc.NotAllowedException;
import org.jivesoftware.openfire.session.ClientSession; import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.ElementUtil; import org.jivesoftware.util.ElementUtil;
...@@ -25,21 +29,21 @@ import org.xmpp.packet.Packet; ...@@ -25,21 +29,21 @@ import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
/** /**
* Simple in-memory implementation of a role in a chatroom * Implementation of a local room occupant.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class MUCRoleImpl implements MUCRole { public class LocalMUCRole implements MUCRole {
/** /**
* The room this role is valid in. * The room this role is valid in.
*/ */
private MUCRoomImpl room; private LocalMUCRoom room;
/** /**
* The user of the role. * The user of the role.
*/ */
private MUCUserImpl user; private LocalMUCUser user;
/** /**
* The user's nickname in the room. * The user's nickname in the room.
...@@ -105,8 +109,8 @@ public class MUCRoleImpl implements MUCRole { ...@@ -105,8 +109,8 @@ public class MUCRoleImpl implements MUCRole {
* @param presence the presence sent by the user to join the room. * @param presence the presence sent by the user to join the room.
* @param packetRouter the packet router for sending messages from this role. * @param packetRouter the packet router for sending messages from this role.
*/ */
public MUCRoleImpl(MultiUserChatServer chatserver, MUCRoomImpl chatroom, String nickname, public LocalMUCRole(MultiUserChatServer chatserver, LocalMUCRoom chatroom, String nickname,
MUCRole.Role role, MUCRole.Affiliation affiliation, MUCUserImpl chatuser, Presence presence, MUCRole.Role role, MUCRole.Affiliation affiliation, LocalMUCUser chatuser, Presence presence,
PacketRouter packetRouter) PacketRouter packetRouter)
{ {
this.room = chatroom; this.room = chatroom;
...@@ -138,10 +142,6 @@ public class MUCRoleImpl implements MUCRole { ...@@ -138,10 +142,6 @@ public class MUCRoleImpl implements MUCRole {
return presence; return presence;
} }
public Element getExtendedPresenceInformation() {
return extendedInformation;
}
public void setPresence(Presence newPresence) { public void setPresence(Presence newPresence) {
// Try to remove the element whose namespace is "http://jabber.org/protocol/muc" since we // Try to remove the element whose namespace is "http://jabber.org/protocol/muc" since we
// don't need to include that element in future presence broadcasts // don't need to include that element in future presence broadcasts
...@@ -204,16 +204,13 @@ public class MUCRoleImpl implements MUCRole { ...@@ -204,16 +204,13 @@ public class MUCRoleImpl implements MUCRole {
} }
public void changeNickname(String nickname) { public void changeNickname(String nickname) {
String oldNickname = this.nick;
this.nick = nickname; this.nick = nickname;
setRoleAddress(new JID(room.getName(), server.getServiceDomain(), nick)); setRoleAddress(new JID(room.getName(), server.getServiceDomain(), nick));
// Fire event that user changed his nickname
((MultiUserChatServerImpl) server)
.fireNicknameChanged(room.getRole().getRoleAddress(), user.getAddress(), oldNickname, nickname);
} }
public MUCUser getChatUser() { public void destroy() {
return user; // Notify the user that he/she is no longer in the room
user.removeRole(room.getName());
} }
public MUCRoom getChatRoom() { public MUCRoom getChatRoom() {
...@@ -224,6 +221,18 @@ public class MUCRoleImpl implements MUCRole { ...@@ -224,6 +221,18 @@ public class MUCRoleImpl implements MUCRole {
return rJID; return rJID;
} }
public JID getUserAddress() {
return user.getAddress();
}
public boolean isLocal() {
return true;
}
public NodeID getNodeID() {
return XMPPServer.getInstance().getNodeID();
}
private void setRoleAddress(JID jid) { private void setRoleAddress(JID jid) {
rJID = jid; rJID = jid;
// Set the new sender of the user presence in the room // Set the new sender of the user presence in the room
......
...@@ -12,12 +12,12 @@ ...@@ -12,12 +12,12 @@
package org.jivesoftware.openfire.muc.spi; package org.jivesoftware.openfire.muc.spi;
import org.jivesoftware.database.DbConnectionManager; import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.openfire.PacketRouter; import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.muc.MUCRole; import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.MUCRoom; import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatServer; import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
...@@ -144,7 +144,7 @@ public class MUCPersistenceManager { ...@@ -144,7 +144,7 @@ public class MUCPersistenceManager {
* *
* @param room the room to load from the database if persistent * @param room the room to load from the database if persistent
*/ */
public static void loadFromDB(MUCRoomImpl room) { public static void loadFromDB(LocalMUCRoom room) {
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
try { try {
...@@ -294,7 +294,7 @@ public class MUCPersistenceManager { ...@@ -294,7 +294,7 @@ public class MUCPersistenceManager {
* *
* @param room The room to save its configuration. * @param room The room to save its configuration.
*/ */
public static void saveToDB(MUCRoomImpl room) { public static void saveToDB(LocalMUCRoom room) {
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
try { try {
...@@ -415,19 +415,19 @@ public class MUCPersistenceManager { ...@@ -415,19 +415,19 @@ public class MUCPersistenceManager {
* @param packetRouter the PacketRouter that loaded rooms will use to send packets. * @param packetRouter the PacketRouter that loaded rooms will use to send packets.
* @return a collection with all the persistent rooms. * @return a collection with all the persistent rooms.
*/ */
public static Collection<MUCRoom> loadRoomsFromDB(MultiUserChatServer chatserver, public static Collection<LocalMUCRoom> loadRoomsFromDB(MultiUserChatServer chatserver,
Date emptyDate, PacketRouter packetRouter) { Date emptyDate, PacketRouter packetRouter) {
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
Map<Long,MUCRoom> rooms = new HashMap<Long,MUCRoom>(); Map<Long, LocalMUCRoom> rooms = new HashMap<Long, LocalMUCRoom>();
try { try {
con = DbConnectionManager.getConnection(); con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_ALL_ROOMS); pstmt = con.prepareStatement(LOAD_ALL_ROOMS);
pstmt.setString(1, StringUtils.dateToMillis(emptyDate)); pstmt.setString(1, StringUtils.dateToMillis(emptyDate));
ResultSet rs = pstmt.executeQuery(); ResultSet rs = pstmt.executeQuery();
MUCRoomImpl room = null; LocalMUCRoom room = null;
while (rs.next()) { while (rs.next()) {
room = new MUCRoomImpl(chatserver, rs.getString(4), packetRouter); room = new LocalMUCRoom(chatserver, rs.getString(4), packetRouter);
room.setID(rs.getLong(1)); room.setID(rs.getLong(1));
room.setCreationDate(new Date(Long.parseLong(rs.getString(2).trim()))); // creation date room.setCreationDate(new Date(Long.parseLong(rs.getString(2).trim()))); // creation date
room.setModificationDate(new Date(Long.parseLong(rs.getString(3).trim()))); // modification date room.setModificationDate(new Date(Long.parseLong(rs.getString(3).trim()))); // modification date
...@@ -478,7 +478,7 @@ public class MUCPersistenceManager { ...@@ -478,7 +478,7 @@ public class MUCPersistenceManager {
// Load the rooms conversations from the last two days // Load the rooms conversations from the last two days
rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
while (rs.next()) { while (rs.next()) {
room = (MUCRoomImpl) rooms.get(rs.getLong(1)); room = (LocalMUCRoom) rooms.get(rs.getLong(1));
// Skip to the next position if the room does not exist // Skip to the next position if the room does not exist
if (room == null) { if (room == null) {
continue; continue;
...@@ -521,7 +521,7 @@ public class MUCPersistenceManager { ...@@ -521,7 +521,7 @@ public class MUCPersistenceManager {
long roomID = rs.getLong(1); long roomID = rs.getLong(1);
String jid = rs.getString(2); String jid = rs.getString(2);
MUCRole.Affiliation affiliation = MUCRole.Affiliation.valueOf(rs.getInt(3)); MUCRole.Affiliation affiliation = MUCRole.Affiliation.valueOf(rs.getInt(3));
room = (MUCRoomImpl) rooms.get(roomID); room = (LocalMUCRoom) rooms.get(roomID);
// Skip to the next position if the room does not exist // Skip to the next position if the room does not exist
if (room == null) { if (room == null) {
continue; continue;
...@@ -552,7 +552,7 @@ public class MUCPersistenceManager { ...@@ -552,7 +552,7 @@ public class MUCPersistenceManager {
pstmt = con.prepareStatement(LOAD_ALL_MEMBERS); pstmt = con.prepareStatement(LOAD_ALL_MEMBERS);
rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
while (rs.next()) { while (rs.next()) {
room = (MUCRoomImpl) rooms.get(rs.getLong(1)); room = (LocalMUCRoom) rooms.get(rs.getLong(1));
// Skip to the next position if the room does not exist // Skip to the next position if the room does not exist
if (room == null) { if (room == null) {
continue; continue;
...@@ -626,7 +626,7 @@ public class MUCPersistenceManager { ...@@ -626,7 +626,7 @@ public class MUCPersistenceManager {
* *
* @param room the room to update its lock status in the database. * @param room the room to update its lock status in the database.
*/ */
public static void updateRoomLock(MUCRoomImpl room) { public static void updateRoomLock(LocalMUCRoom room) {
if (!room.isPersistent() || !room.wasSavedToDB()) { if (!room.isPersistent() || !room.wasSavedToDB()) {
return; return;
} }
......
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.spi;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.openfire.muc.cluster.OccupantAddedEvent;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Representation of a room occupant of a local room that is being hosted by
* another cluster node. An instance of this class will exist for each room
* occupant that is hosted by another cluster node. Local rooms keep track of
* local and remote occupants in a transparent way.
*
* @author Gaston Dombiak
*/
public class RemoteMUCRole implements MUCRole, Externalizable {
private MultiUserChatServer server;
private Presence presence;
private Role role;
private Affiliation affiliation;
private String nickname;
private boolean voiceOnly;
private JID roleAddress;
private JID userAddress;
private MUCRoom room;
private NodeID nodeID;
/**
* Do not use this constructor. Only used for Externalizable.
*/
public RemoteMUCRole() {
}
public RemoteMUCRole(MultiUserChatServer server, OccupantAddedEvent event) {
this.server = server;
presence = event.getPresence();
role = event.getRole();
affiliation = event.getAffiliation();
nickname = event.getNickname();
voiceOnly = event.isVoiceOnly();
roleAddress = event.getRoleAddress();
userAddress = event.getUserAddress();
room = event.getRoom();
this.nodeID = event.getNodeID();
}
public Presence getPresence() {
return presence;
}
public void setPresence(Presence presence) {
this.presence = presence;
}
public void setRole(Role newRole) {
this.role = newRole;
}
public Role getRole() {
return role;
}
public void setAffiliation(Affiliation newAffiliation) {
this.affiliation = newAffiliation;
}
public Affiliation getAffiliation() {
return affiliation;
}
public void changeNickname(String nickname) {
this.nickname = nickname;
setRoleAddress(new JID(room.getName(), server.getServiceDomain(), nickname, true));
}
private void setRoleAddress(JID jid) {
roleAddress = jid;
// Set the new sender of the user presence in the room
presence.setFrom(jid);
}
public String getNickname() {
return nickname;
}
public void destroy() {
// Do nothing
}
public boolean isVoiceOnly() {
return voiceOnly;
}
public MUCRoom getChatRoom() {
return room;
}
public JID getRoleAddress() {
return roleAddress;
}
public JID getUserAddress() {
return userAddress;
}
public boolean isLocal() {
return false;
}
public NodeID getNodeID() {
return nodeID;
}
public void send(Packet packet) {
XMPPServer.getInstance().getPacketRouter().route(packet);
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
ExternalizableUtil.getInstance().writeInt(out, role.ordinal());
ExternalizableUtil.getInstance().writeInt(out, affiliation.ordinal());
ExternalizableUtil.getInstance().writeSafeUTF(out, nickname);
ExternalizableUtil.getInstance().writeBoolean(out, voiceOnly);
ExternalizableUtil.getInstance().writeSerializable(out, roleAddress);
ExternalizableUtil.getInstance().writeSerializable(out, userAddress);
ExternalizableUtil.getInstance().writeByteArray(out, nodeID.toByteArray());
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
presence = new Presence((Element)ExternalizableUtil.getInstance().readSerializable(in), true);
role = Role.values()[ExternalizableUtil.getInstance().readInt(in)];
affiliation = Affiliation.values()[ExternalizableUtil.getInstance().readInt(in)];
nickname = ExternalizableUtil.getInstance().readSafeUTF(in);
voiceOnly = ExternalizableUtil.getInstance().readBoolean(in);
roleAddress = (JID) ExternalizableUtil.getInstance().readSerializable(in);
userAddress = (JID) ExternalizableUtil.getInstance().readSerializable(in);
nodeID = NodeID.getInstance(ExternalizableUtil.getInstance().readByteArray(in));
}
}
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2007 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.openfire.muc.spi;
import org.jivesoftware.openfire.PacketException;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.MUCUser;
import org.xmpp.packet.*;
/**
* User hosted by another cluster node that is presente in a local room. Remote users are
* only created when processing unavailable presences sent when the node hosting the actual
* user went down. Each cluster node remaining in the cluster will create an unavailable
* presence for each user hosted in the cluster node that went down as a way to indicate
* the remaining room occupants that the user is offline.
*
* @author Gaston Dombiak
*/
public class RemoteMUCUser implements MUCUser {
/**
* JID of the user hosted by other cluster node.
*/
private JID realjid;
/**
* Local room that keep a reference to the RemoteMUCRole for this user.
*/
private LocalMUCRoom room;
public RemoteMUCUser(JID realjid, LocalMUCRoom room) {
this.realjid = realjid;
this.room = room;
}
public JID getAddress() {
return realjid;
}
public void process(Packet packet) throws UnauthorizedException, PacketException {
if (packet instanceof IQ) {
throw new UnsupportedOperationException("Cannot process IQ packets of remote users: " + packet);
}
else if (packet instanceof Message) {
throw new UnsupportedOperationException("Cannot process Message packets of remote users: " + packet);
}
else if (packet instanceof Presence) {
process((Presence)packet);
}
}
private void process(Presence presence) {
if (presence.getType() == Presence.Type.unavailable) {
MUCRole mucRole = room.getOccupantByFullJID(realjid);
if (mucRole != null) {
room.leaveRoom(mucRole);
}
}
else {
throw new UnsupportedOperationException("Cannot process Presence packets of remote users: " + presence);
}
}
}
...@@ -109,6 +109,7 @@ public class XMPPCallbackHandler implements CallbackHandler { ...@@ -109,6 +109,7 @@ public class XMPPCallbackHandler implements CallbackHandler {
} }
else { else {
Log.debug("XMPPCallbackHandler: "+principal + " not authorized to " + username); Log.debug("XMPPCallbackHandler: "+principal + " not authorized to " + username);
authCallback.setAuthorized(false);
} }
} }
else { else {
......
...@@ -115,8 +115,14 @@ public class SaslServerPlainImpl implements SaslServer { ...@@ -115,8 +115,14 @@ public class SaslServerPlainImpl implements SaslServer {
vpcb.clearPassword(); vpcb.clearPassword();
AuthorizeCallback acb = new AuthorizeCallback(principal,username); AuthorizeCallback acb = new AuthorizeCallback(principal,username);
cbh.handle(new Callback[]{acb}); cbh.handle(new Callback[]{acb});
username = acb.getAuthorizationID(); if(acb.isAuthorized()) {
completed = true; username = acb.getAuthorizationID();
completed = true;
} else {
completed = true;
username = null;
throw new SaslException("PLAIN: user not authorized: "+principal);
}
} else { } else {
throw new SaslException("PLAIN: user not authorized: "+principal); throw new SaslException("PLAIN: user not authorized: "+principal);
} }
......
...@@ -113,6 +113,10 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -113,6 +113,10 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
// hostname (i.e. remote server). If no one exists then create a new session. The same // hostname (i.e. remote server). If no one exists then create a new session. The same
// session will be used for the same hostname for all the domains to authenticate // session will be used for the same hostname for all the domains to authenticate
SessionManager sessionManager = SessionManager.getInstance(); SessionManager sessionManager = SessionManager.getInstance();
if (sessionManager == null) {
// Server is shutting down while we are trying to create a new s2s connection
return false;
}
session = sessionManager.getOutgoingServerSession(hostname); session = sessionManager.getOutgoingServerSession(hostname);
if (session == null) { if (session == null) {
// Try locating if the remote server has previously authenticated with this server // Try locating if the remote server has previously authenticated with this server
......
...@@ -73,8 +73,7 @@ public class ClientRoute implements Cacheable, Externalizable { ...@@ -73,8 +73,7 @@ public class ClientRoute implements Cacheable, Externalizable {
nodeID = XMPPServer.getInstance().getNodeID(); nodeID = XMPPServer.getInstance().getNodeID();
} }
else { else {
// TODO Keep singleton instances in NodeID nodeID = NodeID.getInstance(bytes);
nodeID = new NodeID(bytes);
} }
available = ExternalizableUtil.getInstance().readBoolean(in); available = ExternalizableUtil.getInstance().readBoolean(in);
} }
......
...@@ -57,6 +57,14 @@ public class DefaultUserProvider implements UserProvider { ...@@ -57,6 +57,14 @@ public class DefaultUserProvider implements UserProvider {
"UPDATE jiveUser SET modificationDate=? WHERE username=?"; "UPDATE jiveUser SET modificationDate=? WHERE username=?";
public User loadUser(String username) throws UserNotFoundException { public User loadUser(String username) throws UserNotFoundException {
String userDomain = JiveGlobals.getProperty("xmpp.domain");
if(username.contains("@")) {
userDomain = username.substring((username.lastIndexOf("@")+1));
username = username.substring(0,username.lastIndexOf("@"));
}
if(!userDomain.equals(JiveGlobals.getProperty("xmpp.domain"))) {
throw new UserNotFoundException("Unknown domain: "+userDomain);
}
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
ResultSet rs = null; ResultSet rs = null;
...@@ -488,4 +496,4 @@ public class DefaultUserProvider implements UserProvider { ...@@ -488,4 +496,4 @@ public class DefaultUserProvider implements UserProvider {
public boolean isReadOnly() { public boolean isReadOnly() {
return false; return false;
} }
} }
\ No newline at end of file
...@@ -97,6 +97,14 @@ public class JDBCUserProvider implements UserProvider { ...@@ -97,6 +97,14 @@ public class JDBCUserProvider implements UserProvider {
} }
public User loadUser(String username) throws UserNotFoundException { public User loadUser(String username) throws UserNotFoundException {
String userDomain = JiveGlobals.getProperty("xmpp.domain");
if(username.contains("@")) {
userDomain = username.substring((username.lastIndexOf("@")+1));
username = username.substring(0,username.lastIndexOf("@"));
}
if(!userDomain.equals(JiveGlobals.getProperty("xmpp.domain"))) {
throw new UserNotFoundException("Unknown domain: "+userDomain);
}
Connection con = null; Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
ResultSet rs = null; ResultSet rs = null;
...@@ -394,4 +402,4 @@ public class JDBCUserProvider implements UserProvider { ...@@ -394,4 +402,4 @@ public class JDBCUserProvider implements UserProvider {
public boolean isReadOnly() { public boolean isReadOnly() {
return true; return true;
} }
} }
\ No newline at end of file
...@@ -134,6 +134,16 @@ public class CacheFactory { ...@@ -134,6 +134,16 @@ public class CacheFactory {
} }
} }
/**
* Returns a byte[] that uniquely identifies this senior cluster member or <tt>null</tt>
* when not in a cluster.
*
* @return a byte[] that uniquely identifies this senior cluster member or null when not in a cluster.
*/
public static byte[] getSeniorClusterMemberID() {
return cacheFactoryStrategy.getSeniorClusterMemberID();
}
/** /**
* Returns true if this member is the senior member in the cluster. If clustering * Returns true if this member is the senior member in the cluster. If clustering
* is not enabled, this method will also return true. This test is useful for * is not enabled, this method will also return true. This test is useful for
......
...@@ -52,6 +52,14 @@ public interface CacheFactoryStrategy { ...@@ -52,6 +52,14 @@ public interface CacheFactoryStrategy {
*/ */
boolean isSeniorClusterMember(); boolean isSeniorClusterMember();
/**
* Returns a byte[] that uniquely identifies this senior cluster member or <tt>null</tt>
* when not in a cluster.
*
* @return a byte[] that uniquely identifies this senior cluster member or null when not in a cluster.
*/
byte[] getSeniorClusterMemberID();
/** /**
* Returns a byte[] that uniquely identifies this member within the cluster or <tt>null</tt> * Returns a byte[] that uniquely identifies this member within the cluster or <tt>null</tt>
* when not in a cluster. * when not in a cluster.
......
...@@ -159,6 +159,10 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy { ...@@ -159,6 +159,10 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy {
return true; return true;
} }
public byte[] getSeniorClusterMemberID() {
return null;
}
public byte[] getClusterMemberID() { public byte[] getClusterMemberID() {
return new byte[0]; return new byte[0];
} }
......
Name | Version
-------------------------------------------------------------------------
commons-fileupload.jar | 1.2
commons-io.jar | 1.3.2
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
- Use is subject to license terms. - Use is subject to license terms.
--%> --%>
<%@ page import="org.jivesoftware.util.ParamUtils, <%@ page import="org.jivesoftware.openfire.muc.MUCRole,
org.jivesoftware.openfire.muc.MUCRole,
org.jivesoftware.openfire.muc.MUCRoom, org.jivesoftware.openfire.muc.MUCRoom,
org.jivesoftware.util.ParamUtils,
java.net.URLEncoder, java.net.URLEncoder,
java.text.DateFormat" java.text.DateFormat"
errorPage="error.jsp" errorPage="error.jsp"
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
<tbody> <tbody>
<% for (MUCRole role : room.getOccupants()) { %> <% for (MUCRole role : room.getOccupants()) { %>
<tr> <tr>
<td><%= role.getChatUser().getAddress() %></td> <td><%= role.getUserAddress() %></td>
<td><%= role.getNickname() %></td> <td><%= role.getNickname() %></td>
<td><%= role.getRole() %></td> <td><%= role.getRole() %></td>
<td><%= role.getAffiliation() %></td> <td><%= role.getAffiliation() %></td>
......
...@@ -13,15 +13,20 @@ ...@@ -13,15 +13,20 @@
org.jivesoftware.openfire.update.Update" org.jivesoftware.openfire.update.Update"
%> %>
<%@ page import="org.jivesoftware.openfire.update.UpdateManager" %> <%@ page import="org.jivesoftware.openfire.update.UpdateManager" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.File" %>
<%@ page import="java.io.FileReader" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.net.URLEncoder" %> <%@ page import="java.net.URLEncoder" %>
<%@ page import="java.util.ArrayList" %> <%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.Collections" %> <%@ page import="java.util.Collections" %>
<%@ page import="java.util.Comparator" %> <%@ page import="java.util.Comparator" %>
<%@ page import="java.util.List" %> <%@ page import="java.util.List" %>
<%@ page import="org.apache.commons.fileupload.DiskFileUpload" %>
<%@ page import="java.io.*" %>
<%@ page import="org.jivesoftware.util.JiveGlobals" %>
<%@ page import="org.jivesoftware.util.Log" %>
<%@ page import="org.apache.commons.fileupload.FileItemFactory" %>
<%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>
<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>
<%@ page import="org.apache.commons.fileupload.FileItem" %>
<%@ page import="org.apache.commons.fileupload.FileUploadException" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
...@@ -36,7 +41,9 @@ ...@@ -36,7 +41,9 @@
boolean showChangelog = ParamUtils.getBooleanParameter(request, "showChangelog", false); boolean showChangelog = ParamUtils.getBooleanParameter(request, "showChangelog", false);
boolean showIcon = ParamUtils.getBooleanParameter(request, "showIcon", false); boolean showIcon = ParamUtils.getBooleanParameter(request, "showIcon", false);
boolean downloadRequested = request.getParameter("download") != null; boolean downloadRequested = request.getParameter("download") != null;
boolean uploadPlugin = request.getParameter("uploadplugin") != null;
String url = request.getParameter("url"); String url = request.getParameter("url");
Boolean uploadEnabled = JiveGlobals.getBooleanProperty("plugins.upload.enabled", true);
final PluginManager pluginManager = webManager.getXMPPServer().getPluginManager(); final PluginManager pluginManager = webManager.getXMPPServer().getPluginManager();
...@@ -80,6 +87,52 @@ ...@@ -80,6 +87,52 @@
} }
} }
} }
if (uploadEnabled && uploadPlugin) {
Boolean installed = false;
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
try {
// Parse the request
List items = upload.parseRequest(request);
for (Object objItem : items) {
FileItem item = (FileItem)objItem;
String fileName = item.getName();
if (fileName != null) {
InputStream is = item.getInputStream();
if (is != null) {
installed = XMPPServer.getInstance().getPluginManager().installPlugin(is, fileName);
if (!installed) {
Log.error("Plugin manager failed to install plugin: " + fileName);
}
is.close();
}
else {
Log.error("Unable to open file stream for uploaded file: " + fileName);
}
}
else {
Log.error("No filename specified for file upload.");
}
}
}
catch (FileUploadException e) {
Log.error("Unable to upload plugin file.", e);
}
if (installed) {
response.sendRedirect("plugin-admin.jsp?uploadsuccess=true");
return;
} else {
response.sendRedirect("plugin-admin.jsp?uploadsuccess=false");
return;
}
}
%> %>
<% if (showReadme) { <% if (showReadme) {
...@@ -385,6 +438,23 @@ else if ("false".equals(request.getParameter("deletesuccess"))) { %> ...@@ -385,6 +438,23 @@ else if ("false".equals(request.getParameter("deletesuccess"))) { %>
<% } %> <% } %>
<% if ("true".equals(request.getParameter("uploadsuccess"))) { %>
<div class="success">
<fmt:message key="plugin.admin.uploaded_success"/>
</div>
<br>
<% }
else if ("false".equals(request.getParameter("uploadsuccess"))) { %>
<div class="error">
<fmt:message key="plugin.admin.uploaded_failure"/>
</div>
<br>
<% } %>
<p> <p>
<fmt:message key="plugin.admin.info"/> <fmt:message key="plugin.admin.info"/>
</p> </p>
...@@ -551,5 +621,18 @@ else if ("false".equals(request.getParameter("deletesuccess"))) { %> ...@@ -551,5 +621,18 @@ else if ("false".equals(request.getParameter("deletesuccess"))) { %>
</table> </table>
</div> </div>
<% if (uploadEnabled) { %>
<br /><br />
<div>
<h3><fmt:message key="plugin.admin.upload_plugin" /></h3>
<p><fmt:message key="plugin.admin.upload_plugin.info" /></p>
<form action="plugin-admin.jsp?uploadplugin" enctype="multipart/form-data" method="post">
<input type="file" name="uploadfile" />
<input type="submit" value="<fmt:message key="plugin.admin.upload_plugin" />" />
</form>
</div>
<% } %>
</body> </body>
</html> </html>
\ No newline at end of file
This diff is collapsed.
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" /> <jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out ); %> <% webManager.init(request, response, session, application, out ); %>
<% // Get parameters // <% // Get parameters
boolean cancel = request.getParameter("cancel") != null; boolean cancel = request.getParameter("cancel") != null;
boolean delete = request.getParameter("delete") != null; boolean delete = request.getParameter("delete") != null;
String username = ParamUtils.getParameter(request, "username"); String username = ParamUtils.getParameter(request, "username");
...@@ -50,14 +50,14 @@ ...@@ -50,14 +50,14 @@
<head> <head>
<title><fmt:message key="user.roster.delete.title"/></title> <title><fmt:message key="user.roster.delete.title"/></title>
<meta name="subPageID" content="user-roster"/> <meta name="subPageID" content="user-roster"/>
<meta name="extraParams" content="<%= "username="+URLEncoder.encode(username, "UTF-8")+"&jid="+URLEncoder.encode(jid, "UTF-8") %>"/> <meta name="extraParams" content="<%= "username="+URLEncoder.encode(username, "UTF-8") %>"/>
</head> </head>
<body> <body>
<p> <p>
<fmt:message key="user.roster.delete.info"> <fmt:message key="user.roster.delete.info">
<fmt:param value="<%= "<b>"+URLEncoder.encode(jid, "UTF-8")+"</b>" %>" /> <fmt:param value="<%= "<b>"+jid+"</b>" %>" />
<fmt:param value="<%= "<b>"+URLEncoder.encode(username, "UTF-8")+"</b>" %>" /> <fmt:param value="<%= "<b>"+username+"</b>" %>" />
</fmt:message> </fmt:message>
</p> </p>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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