Commit 0ea79c82 authored by Axel Brand's avatar Axel Brand Committed by daeva

-removed IQLastProcessor as its no longer necessary

-Implemented MucFilter, working now
-made the ComponentEventListener unload properly
-fixed Error searchJIDforSubdomain in ClienttoComponentUpdateProcessor
-PersistantRoster has its checkbox in GoJara options menu again
-fixed autologin to Transports in Persistant Mode

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/branches/plugins@13555 b35dd754-fafc-0310-a699-88a17e54d16e
parent 3d6245b0
......@@ -47,14 +47,16 @@ GoJara Plugin Changelog
<p><b>2.0.0</b> -- Mar 07, 2013</p>
<ul>
<li>Major refactoring of the Interceptor- and Processor-Structure used by GoJara</li>
<li>One-Interceptor structure should allow easier Debugging & control of Features</li>
<li>We completely ignore Packets with malformed JIDs now, this should cause less Warnings/Errors</li>
<li>Freezing the Interceptor on Destroy of the Plugin should make GoJara properly shutdown and not cause trouble on reload/update</li>
<li>Optimized Processors to have better performance</li>
<li>Reject iq:roster packets with item jid=subdomain as they will throw errors on register:remove</li>
<li>Stopped OF from sending Presence Packets to users of legacy roster, this was leading to OF automatically logging you into S2 if you were registered,
even if you did not check "Autologin" (only when persistant = true).</li>
<li>Major refactoring of the Interceptor- and Processor-Structure used by GoJara.</li>
<li>One-Interceptor structure should allow easier Debugging & control of Features.</li>
<li>We completely ignore Packets with malformed JIDs now, this should cause less Warnings/Errors.</li>
<li>Freezing the Interceptor on Destroy of the Plugin should make GoJara properly shutdown and not cause trouble on reload/update.</li>
<li>Optimized Processors to have better performance.</li>
<li>Reject iq:roster packets with item jid=subdomain as they will throw errors on register:remove.</li>
<li>Fixed auto-connecting to transports in Persistant-mode by blocking Presence forwarding to legacy-roster items.</li>
<li>New Feature: MUC-Filter allows to filter MUC from disco#info of transports if only internal conference service should be allowed.</li>
<li>Persistent Roster has its place in GoJara Options view back.</li>
<li>Fixed Errors thrown after unloading GoJara by unloading ComponentEventListener properly</li>
</ul>
......
......@@ -44,8 +44,10 @@ public class RemoteRosterPlugin implements Plugin {
private static PluginManager pluginManager;
private Set<String> _waitingForIQResponse = new HashSet<String>();
private PropertyEventListener _settingsObserver;
private ComponentEventListener _componentObserver;
private MainInterceptor mainInterceptor = new MainInterceptor();
private InterceptorManager iManager = InterceptorManager.getInstance();
private InternalComponentManager compManager = InternalComponentManager.getInstance();
public void initializePlugin(PluginManager manager, File pluginDirectory) {
......@@ -62,8 +64,7 @@ public class RemoteRosterPlugin implements Plugin {
* external component is maybe a gateway and interesting for us
*/
private void manageExternalComponents() {
InternalComponentManager compManager = InternalComponentManager.getInstance();
compManager.addListener(new ComponentEventListener() {
_componentObserver = new ComponentEventListener() {
/*
* Check if the unregistered component contains to one of our
* package interceptors
......@@ -96,9 +97,6 @@ public class RemoteRosterPlugin implements Plugin {
Element packet = iq.getChildElement();
Document doc = packet.getDocument();
List<Node> nodes = XpathHelper.findNodesInDocument(doc, "//disco:identity[@category='gateway']");
// Is this external component a gateway and there is no
// package interceptor for it?
// if (nodes.size() > 0 && !_interceptors.containsKey(from)) {
if (nodes.size() > 0) {
updateInterceptors(from);
}
......@@ -108,7 +106,8 @@ public class RemoteRosterPlugin implements Plugin {
_waitingForIQResponse.remove(from);
}
}
});
};
compManager.addListener(_componentObserver);
}
/*
......@@ -130,8 +129,10 @@ public class RemoteRosterPlugin implements Plugin {
mainInterceptor.freeze();
iManager.removeInterceptor(mainInterceptor);
PropertyEventDispatcher.removeListener(_settingsObserver);
compManager.removeListener(_componentObserver);
pluginManager = null;
mainInterceptor = null;
compManager = null;
}
private void updateInterceptors(String componentJID) {
......
......@@ -8,14 +8,7 @@ import org.dom4j.Element;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.ClientToComponentUpdateProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.DiscoIQRegisteredProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.IQLastProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.IQRosterPayloadProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.NonPersistantRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.StatisticsProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.WhitelistProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.*;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.ConcurrentHashSet;
......@@ -42,24 +35,20 @@ public class MainInterceptor implements PacketInterceptor {
AbstractRemoteRosterProcessor iqRosterPayloadProcessor = new IQRosterPayloadProcessor(rosterMananger);
AbstractRemoteRosterProcessor nonPersistantProcessor = new NonPersistantRosterProcessor(rosterMananger);
AbstractRemoteRosterProcessor statisticsProcessor = new StatisticsProcessor();
AbstractRemoteRosterProcessor iqLastProcessor = new IQLastProcessor();
AbstractRemoteRosterProcessor updateToComponentProcessor = new ClientToComponentUpdateProcessor(activeTransports);
AbstractRemoteRosterProcessor whitelistProcessor = new WhitelistProcessor(activeTransports);
// AbstractRemoteRosterProcessor mucblockProcessor = new
// MucBlockProcessor();
AbstractRemoteRosterProcessor mucfilterProcessor = new MucFilterProcessor();
packetProcessors.put("sparkIQRegistered", iqRegisteredProcessor);
packetProcessors.put("iqRosterPayload", iqRosterPayloadProcessor);
packetProcessors.put("handleNonPersistant", nonPersistantProcessor);
packetProcessors.put("statisticsProcessor", statisticsProcessor);
packetProcessors.put("iqLastProcessor", iqLastProcessor);
packetProcessors.put("clientToComponentUpdate", updateToComponentProcessor);
packetProcessors.put("whitelistProcessor", whitelistProcessor);
// packetProcessors.put("mucblockProcessor", mucblockProcessor);
packetProcessors.put("mucfilterProcessor", mucfilterProcessor);
frozen = false;
}
// These get called from our RemoteRosterPlugin
public boolean addTransport(String subDomain) {
Log.info("Trying to add " + subDomain + " to Set of watched Transports.");
return this.activeTransports.add(subDomain);
......@@ -81,10 +70,9 @@ public class MainInterceptor implements PacketInterceptor {
}
/**
* As our Set of Subdomains is a Hash of Strings like icq.domain.tld, if we
* want to check if a jid CONTAINS a watched subdomain we need to iterate
* over the set. We also return the subdomain as a string so we can use it
* if we find it.
* As our Set of Subdomains is a Hash of Strings like icq.domain.tld, if we want to check if a jid CONTAINS a
* watched subdomain we need to iterate over the set. We also return the subdomain as a string so we can use it if
* we find it.
*/
private String searchJIDforSubdomain(String jid) {
if (!jid.isEmpty()) {
......@@ -97,14 +85,12 @@ public class MainInterceptor implements PacketInterceptor {
}
/**
* This Interceptor tests if GoJara needs to process this package. We
* decided to do one global Interceptor so we would'nt redundantly test for
* cases we already checked in previous Interceptors, also we have only one
* big ugly If Structure to maintain instead of several.
* This Interceptor tests if GoJara needs to process this package. We decided to do one global Interceptor so we
* would'nt redundantly test for cases we already checked in previous Interceptors, also we have only one big ugly
* If Structure to maintain instead of several.
*
* @see org.jivesoftware.openfire.interceptor.PacketInterceptor#interceptPacket
* (org.xmpp.packet.Packet, org.jivesoftware.openfire.session.Session,
* boolean, boolean)
* @see org.jivesoftware.openfire.interceptor.PacketInterceptor#interceptPacket (org.xmpp.packet.Packet,
* org.jivesoftware.openfire.session.Session, boolean, boolean)
*/
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) throws PacketRejectedException {
if (frozen)
......@@ -132,44 +118,41 @@ public class MainInterceptor implements PacketInterceptor {
Element query = iqPacket.getChildElement();
if (query == null)
return;
// Jabber:IQ:roster Indicates Client to Component update or
// Rosterpush
// Jabber:IQ:roster Indicates Client to Component update or Rosterpush
else if (query.getNamespaceURI().equals("jabber:iq:roster")) {
if (to.isEmpty() && iqPacket.getType().equals(IQ.Type.set))
packetProcessors.get("clientToComponentUpdate").process(packet, "", to, from);
else if (!from.isEmpty() && activeTransports.contains(from))
packetProcessors.get("iqRosterPayload").process(packet, from, to, from);
}
// Disco#Info - check for register processing
// SPARK IQ REGISTERED Feature
else if (query.getNamespaceURI().equals("http://jabber.org/protocol/disco#info") && !to.isEmpty()
&& activeTransports.contains(to) && iqPacket.getType().equals(IQ.Type.get)) {
packetProcessors.get("sparkIQRegistered").process(packet, to, to, from);
}
// Check for Rostercleanup in Nonpersistant-mode
} else if (!JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false) && packet instanceof Presence) {
if (activeTransports.contains(from))
// JABBER:IQ:LAST - Autoresponse Feature
else if (JiveGlobals.getBooleanProperty("plugin.remoteroster.iqLastFilter", false)
&& query.getNamespaceURI().equals("jabber:iq:last")) {
String to_s = searchJIDforSubdomain(to);
if (!to_s.isEmpty() && iqPacket.getType().equals(IQ.Type.get))
throw new PacketRejectedException();
}
// NONPERSISTANT Feature
} else if (!JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false)) {
if (packet instanceof Presence && activeTransports.contains(from))
packetProcessors.get("handleNonPersistant").process(packet, from, to, from);
}
} else if (incoming && processed) {
// We ignore Pings from S2 to S2 itself. We test for Log first so
// that we can return in case
// The packet doesnt have any watched namespace, but we still may
// want to log it.
// We ignore Pings from S2 to S2 itself.
// STATISTICS - Feature
String from_s = searchJIDforSubdomain(from);
String to_s = searchJIDforSubdomain(to);
String subdomain = from_s.isEmpty() ? to_s : from_s;
if (!from.equals(to) && !subdomain.isEmpty())
packetProcessors.get("statisticsProcessor").process(packet, subdomain, to, from);
// JABBER:IQ:LAST - Autoresponse Feature
if (JiveGlobals.getBooleanProperty("plugin.remoteroster.iqLastFilter", false) && packet instanceof IQ) {
IQ iqPacket = (IQ) packet;
Element query = iqPacket.getChildElement();
if (query != null && query.getNamespaceURI().equals("jabber:iq:last") && !to_s.isEmpty())
packetProcessors.get("iqLastProcessor").process(packet, to_s, to, from);
}
} else if (!incoming && !processed) {
if (packet instanceof IQ) {
......@@ -181,18 +164,13 @@ public class MainInterceptor implements PacketInterceptor {
// DISCO#ITEMS - Whitelisting Feature
if (query.getNamespaceURI().equals("http://jabber.org/protocol/disco#items"))
packetProcessors.get("whitelistProcessor").process(packet, "", to, from);
// DISCO#INFO - MUC-block-Feature
// else if
// (JiveGlobals.getBooleanProperty("plugin.remoteroster.mucBlock",
// false)
// &&
// query.getNamespaceURI().equals("http://jabber.org/protocol/disco#info")
// && !from.isEmpty() && activeTransports.contains(from))
// packetProcessors.get("mucblockProcessor").process(packet,
// from, to, from);
// DISCO#INFO - MUC-Filter-Feature
else if (JiveGlobals.getBooleanProperty("plugin.remoteroster.mucFilter", false)
&& query.getNamespaceURI().equals("http://jabber.org/protocol/disco#info") && !from.isEmpty()
&& activeTransports.contains(from))
packetProcessors.get("mucfilterProcessor").process(packet, from, to, from);
} else if (packet instanceof Presence) {
// We block Presences to users of a subdomain so OF/S2 wont log you
// in automatically if you have a
// We block Presences to users of a subdomain so OF/S2 wont log you in automatically if you have a
// subdomain user in your roster
String to_s = searchJIDforSubdomain(to);
if (!to_s.isEmpty() && !activeTransports.contains(to))
......
package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import java.util.List;
import java.util.Set;
import org.dom4j.Element;
......@@ -32,7 +33,7 @@ public class ClientToComponentUpdateProcessor extends AbstractRemoteRosterProces
private String searchJIDforSubdomain(String jid) {
for (String subdomain : watchedSubdomains) {
if (subdomain.contains(jid))
if (jid.contains(subdomain))
return subdomain;
}
return "";
......@@ -43,11 +44,11 @@ public class ClientToComponentUpdateProcessor extends AbstractRemoteRosterProces
Log.debug("Processing packet in ClientToComponentUpdateProcessor: " + packet.toString());
Element query = ((IQ) packet).getChildElement();
if (findNodesInDocument(query.getDocument(), "//roster:item").size() > 0) {
List<Node> nodes = findNodesInDocument(query.getDocument(), "//roster:item");
if (nodes.size() > 0) {
// We now know we have to check the JID of the to be added User
// against our valid subdomains.
for (Node n : findNodesInDocument(query.getDocument(), "//roster:item")) {
for (Node n : nodes) {
String jid = n.valueOf("@jid");
// TODO: We ignore remove iq packets for now. There might be
// conflicts
......
package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
*
* Some clients try to check how long a contact is already offline. This feature
* is not supported by spectrum so it won't response to this IQ stanza. To
* prevent the client from waiting for a response we could answer with a
* service-unavailable message as described in XEP-12.
*
* @author Holger Bergunde
* @author axel.frederik.brand
*
*/
public class IQLastProcessor extends AbstractRemoteRosterProcessor{
public IQLastProcessor() {
Log.info("Created IQLastProcessor");
}
/**
* At this point we know:
* IQLastFilter is ACTIVATED
* Packet is incoming and NOT processed
* Packet is instance of IQ
* To contains the watched subdomain represented in String subdomain
*/
@Override
public void process(Packet packet, String subdomain, String to, String from)
throws PacketRejectedException {
IQ iqpacket = (IQ) packet;
if (iqpacket.getType().equals(IQ.Type.get)) {
Log.debug("Processing IQLast Packet for " + subdomain + " : " + packet.toString());
IQ answer = IQ.createResultIQ(iqpacket);
answer.setType(IQ.Type.error);
DefaultElement errorElement = new DefaultElement("error");
errorElement.addAttribute("type", "cancel");
errorElement.addAttribute("code", "503");
DefaultElement serviceElement = new DefaultElement("service-unavailable");
serviceElement.addNamespace("", "urn:ietf:params:xml:ns:xmpp-stanzas");
errorElement.add(serviceElement);
answer.setChildElement(errorElement);
Log.debug("Auto response to jabber:iq:last for " + subdomain);
PacketRouter router = _server.getPacketRouter();
router.route(answer);
}
}
}
......@@ -10,14 +10,12 @@ import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
*
* @author axel.frederik.brand
*
*/
public class MUCBlockProcessor extends AbstractRemoteRosterProcessor {
public class MucFilterProcessor extends AbstractRemoteRosterProcessor {
public MUCBlockProcessor() {
Log.info("Created MUCBlockProcessor");
public MucFilterProcessor() {
Log.info("Created MucFilterProcessor");
}
/**
......@@ -30,10 +28,9 @@ public class MUCBlockProcessor extends AbstractRemoteRosterProcessor {
IQ iqPacket = (IQ) packet;
if (iqPacket.getType().equals(IQ.Type.result) && !to.isEmpty()) {
Element root = iqPacket.getChildElement();
List<Node> nodes = XpathHelper.findNodesInDocument(root.getDocument(), "//discoinfo:feature");
List<Node> nodes = XpathHelper.findNodesInDocument(root.getDocument(), "//disco:feature");
for (Node node : nodes) {
String var = node.valueOf("@var");
if (var.equals("http://jabber.org/protocol/muc"))
......@@ -42,5 +39,4 @@ public class MUCBlockProcessor extends AbstractRemoteRosterProcessor {
}
}
}
......@@ -19,16 +19,17 @@
webManager.init(request, response, session, application, out);
boolean save = request.getParameter("save") != null;
boolean success = request.getParameter("success") != null;
//boolean persistentRoster = ParamUtils.getBooleanAttribute(request, "persistentEnabled");
boolean persistentRoster = true;
String persistentRosterParam = request.getParameter("persistentEnabled");
boolean persistentRoster = persistentRosterParam == null? false : persistentRosterParam.equals("true");
String sparkdiscoParam = request.getParameter("sparkDiscoInfo");
boolean sparkDiscoInfo = sparkdiscoParam == null ? false : sparkdiscoParam.equals("true");
String iqLastFilterPram = request.getParameter("iqLastFilter");
boolean iqLastFilter = iqLastFilterPram == null ? false : iqLastFilterPram.equals("true");
String mucBlockParam = request.getParameter("mucBlock");
boolean mucBlock = mucBlockParam == null ? false : mucBlockParam.equals("true");
String mucFilterParam = request.getParameter("mucFilter");
boolean mucFilter = mucFilterParam == null ? false : mucFilterParam.equals("true");
String[] componentsEnabled = request.getParameterValues("enabledComponents[]");
PermissionManager _pmanager = new PermissionManager();
......@@ -51,7 +52,7 @@
JiveGlobals.setProperty("plugin.remoteroster.persistent", (persistentRoster ? "true" : "false"));
JiveGlobals.setProperty("plugin.remoteroster.sparkDiscoInfo", (sparkDiscoInfo ? "true" : "false"));
JiveGlobals.setProperty("plugin.remoteroster.iqLastFilter", (iqLastFilter ? "true" : "false"));
JiveGlobals.setProperty("plugin.remoteroster.mucBlock", (mucBlock ? "true" : "false"));
JiveGlobals.setProperty("plugin.remoteroster.mucFilter", (mucFilter ? "true" : "false"));
response.sendRedirect("rr-main.jsp?success=true");
return;
}
......@@ -277,31 +278,41 @@
}
%>
</div>
<!-- DISABLED PERSISTENT ROSTER UNTIL SPECTRUM SUPPORTS IT
<div class="jive-contentBoxHeader">Options</div>
<div class="jive-contentBoxHeader">General Options</div>
<div class="jive-contentBox">
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody>
<tr valign="top">
<td width="1%" nowrap class="c1">
Persistent Roster:
</td>
<td width="99%">
<td width="100%">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr>
<td>
<input type="radio" name="persistentEnabled" value="true" checked id="PER01">
</td>
<td><label for="PER01">Enabled (remote rosters are saved into the user's stored roster)</label></td>
</tr>
<tr>
<td>
<input type="radio" name="persistentEnabled" value="false" id="PER02">
</td>
<td><label for="PER02">Disabled (remote rosters exist only in memory)</label></td>
</tr>
<tr>
<td><input type="checkbox" name="persistentEnabled" id="GO1" value="true"
<%=JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false) ? "checked=\"checked\"" : ""%> />
</td>
<td><label for="GO1">Enable persistent Roster</label></td>
</tr>
<tr>
<td />
<td align="left" style="font-size: -3; color: grey">When Persistent-Roster is enabled, no contacts will be deleted
by GoJara automatically.<br>
When Persistent-Roster is disabled, GoJara will automatically delete all Legacy-RosterItems from the OF-Roster of a User upon logout. </td>
</tr>
<tr>
<td><input type="checkbox" name="mucFilter" id="GO2" value="true"
<%=JiveGlobals.getBooleanProperty("plugin.remoteroster.mucFilter", false) ? "checked=\"checked\"" : ""%> />
</td>
<td><label for="GO2">Only allow internal Jabber Conferences</label></td>
</tr>
<tr>
<td />
<td align="left" style="font-size: -3; color: grey">Spectrum might add MUC(Multi User Chat) to supported features
of some Transports. If this should not be allowed, because only internal Jabber Conferences should be used, GoJara
can remove these.</td>
</tr>
</tbody>
</table>
</td>
......@@ -310,10 +321,6 @@
</table>
</div>
-->
<br /> <br />
<div class="jive-contentBoxHeader">Client specific options</div>
<div class="jive-contentBox">
......@@ -353,20 +360,6 @@
This feature is not supported by spectrum so it won't response to this IQ stanza. To prevent the client from waiting
for a response we could answer with a service-unavailable message as described in XEP-12.</td>
</tr>
<tr>
<td><input type="checkbox" name="mucBlock" id="SDI3" value="true"
<%=JiveGlobals.getBooleanProperty("plugin.remoteroster.mucBlock", false) ? "checked=\"checked\""
: ""%> />
</td>
<td><label for="SDI">Only allow internal Jabber Conferences</label></td>
</tr>
<tr>
<td />
<td align="left" style="font-size: -3; color: grey">Spectrum might add MUC(Multi User Chat) to supported features
of some Transports. If this should not be allowed, because only internal Jabber Conferences should be used, GoJara
can remove these.</td>
</tr>
</tbody>
</table>
</td>
......
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