Commit 54f3e6d6 authored by Alex Wenckus's avatar Alex Wenckus Committed by alex

A huge file transfer refactoring, doesn't seem to have broken anything.

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@4531 b35dd754-fafc-0310-a699-88a17e54d16e
parent da50248a
......@@ -29,9 +29,9 @@ import org.jivesoftware.wildfire.disco.IQDiscoInfoHandler;
import org.jivesoftware.wildfire.disco.IQDiscoItemsHandler;
import org.jivesoftware.wildfire.disco.ServerFeaturesProvider;
import org.jivesoftware.wildfire.disco.ServerItemsProvider;
import org.jivesoftware.wildfire.filetransfer.proxy.FileTransferProxy;
import org.jivesoftware.wildfire.filetransfer.FileTransferManager;
import org.jivesoftware.wildfire.filetransfer.FileTransferProxy;
import org.jivesoftware.wildfire.filetransfer.spi.DefaultFileTransferManager;
import org.jivesoftware.wildfire.filetransfer.DefaultFileTransferManager;
import org.jivesoftware.wildfire.handler.*;
import org.jivesoftware.wildfire.muc.MultiUserChatServer;
import org.jivesoftware.wildfire.muc.spi.MultiUserChatServerImpl;
......@@ -286,7 +286,7 @@ public class XMPPServer {
name = JiveGlobals.getProperty("xmpp.domain", "127.0.0.1").toLowerCase();
version = new Version(3, 1, 0, Version.ReleaseStatus.Alpha, -1);
version = new Version(3, 0, 0, Version.ReleaseStatus.Release, -1);
if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
setupMode = false;
}
......
......@@ -18,6 +18,8 @@ import org.jivesoftware.wildfire.interceptor.InterceptorManager;
import org.jivesoftware.wildfire.interceptor.PacketInterceptor;
import org.jivesoftware.wildfire.interceptor.PacketRejectedException;
import org.jivesoftware.wildfire.Session;
import org.jivesoftware.wildfire.filetransfer.proxy.ProxyConnectionManager;
import org.jivesoftware.wildfire.filetransfer.proxy.ProxyTransfer;
import org.dom4j.Element;
import org.xmpp.packet.Packet;
import org.xmpp.packet.IQ;
......@@ -25,19 +27,13 @@ import org.xmpp.packet.JID;
import java.util.Map;
import java.util.List;
import java.util.Arrays;
/**
* Provides several utility methods for file transfer manager implementaions to utilize.
*
* @author Alexander Wenckus
*/
public abstract class AbstractFileTransferManager
extends BasicModule implements FileTransferManager
{
private static final List<String> FILETRANSFER_NAMESPACES
= Arrays.asList(NAMESPACE_BYTESTREAMS, NAMESPACE_SI);
public class DefaultFileTransferManager extends BasicModule implements FileTransferManager {
private static final String CACHE_NAME = "File Transfer Cache";
......@@ -46,7 +42,7 @@ public abstract class AbstractFileTransferManager
/**
* Default constructor creates the cache.
*/
public AbstractFileTransferManager() {
public DefaultFileTransferManager() {
super("File Transfer Manager");
fileTransferMap = createCache(CACHE_NAME, "fileTransfer", 128 * 1024, 1000 * 60 * 10);
InterceptorManager.getInstance().addInterceptor(new MetaFileTransferInterceptor());
......@@ -96,6 +92,24 @@ public abstract class AbstractFileTransferManager
return null;
}
public boolean acceptIncomingFileTransferRequest(FileTransfer transfer)
{
try {
fireFileTransferMetaIntercept(transfer);
}
catch (FileTransferRejectedException e) {
return false;
}
if(transfer != null) {
String streamID = transfer.getSessionID();
JID from = new JID(transfer.getInitiator());
JID to = new JID(transfer.getTarget());
cacheFileTransfer(ProxyConnectionManager.createDigest(streamID, from, to), transfer);
return true;
}
return false;
}
public void registerProxyTransfer(String transferDigest, ProxyTransfer proxyTransfer)
throws UnauthorizedException
{
......@@ -111,15 +125,30 @@ public abstract class AbstractFileTransferManager
cacheFileTransfer(transferDigest, transfer);
}
public void enableFileTransfer(boolean isEnabled) {
JiveGlobals.setProperty(JIVEPROPERTY_FILE_TRANSFER_ENABLED, Boolean.toString(isEnabled));
}
private FileTransfer createFileTransfer(String packetID, JID from,
JID to, Element siElement) {
String streamID = siElement.attributeValue("id");
String mimeType = siElement.attributeValue("mime-type");
String profile = siElement.attributeValue("profile");
// Check profile, the only type we deal with currently is file transfer
FileTransfer transfer = null;
if (NAMESPACE_SI_FILETRANSFER.equals(profile)) {
Element fileTransferElement = getChildElement(siElement, NAMESPACE_SI_FILETRANSFER);
// Not valid form, reject
if (fileTransferElement == null) {
return null;
}
String fileName = fileTransferElement.attributeValue("name");
long size = Long.parseLong(fileTransferElement.attributeValue("size"));
public boolean isFileTransferEnabled() {
return JiveGlobals.getBooleanProperty(JIVEPROPERTY_FILE_TRANSFER_ENABLED,
DEFAULT_IS_FILE_TRANSFER_ENABLED);
transfer = new FileTransfer(from.toString(), to.toString(),
streamID, fileName, size, mimeType);
}
return transfer;
}
public void addFileTransferInterceptor(FileTransferInterceptor interceptor) {
}
......@@ -131,6 +160,11 @@ public abstract class AbstractFileTransferManager
{
}
private void fireFileTransferMetaIntercept(FileTransfer transfer) throws
FileTransferRejectedException
{
}
/**
* Interceptor to grab and validate file transfer meta information.
*/
......@@ -148,17 +182,17 @@ public abstract class AbstractFileTransferManager
}
String namespace = childElement.getNamespaceURI();
if(!isFileTransferEnabled() && FILETRANSFER_NAMESPACES.contains(namespace)) {
throw new PacketRejectedException("File Transfer Disabled");
}
if (NAMESPACE_SI.equals(namespace)) {
// If this is a set, check the feature offer
if (iq.getType().equals(IQ.Type.set)) {
JID from = iq.getFrom();
JID to = iq.getTo();
String packetID = iq.getID();
if (!acceptIncomingFileTransferRequest(packetID, from, to, childElement)) {
FileTransfer transfer =
createFileTransfer(packetID, from, to, childElement);
if (transfer == null || !acceptIncomingFileTransferRequest(transfer)) {
throw new PacketRejectedException();
}
}
......
......@@ -16,9 +16,21 @@ package org.jivesoftware.wildfire.filetransfer;
public interface FileTransferInterceptor {
/**
* Invokes the interceptor on the specified file transfer. The interceptor can either modify
* the file transfer or throw a FileTransferRejectedException.
* the file transfer or throw a FileTransferRejectedException. The file transfer went sent to
* the interceptor can be in two states, ready and not ready. The not ready state indicates
* that this event was fired when the file transfer request was sent by the initatior. The ready
* state indicates that the file transfer is ready to begin, and the channels can be
* manipulated by the interceptor.
* <p>
* It is recommended for the the sake of user experience that
* when in the not ready state, any processing done on the file transfer should be quick.
*
* @param transfer the transfer being intercepted
* @param isReady true if the transfer is ready to commence or false if this is related to the
* initial file transfer request. An exception at this point will cause the transfer to
* not go through.
*
* @param transfer
*/
void interceptFileTransfer(FileTransfer transfer) throws FileTransferRejectedException;
void interceptFileTransfer(FileTransfer transfer, boolean isReady)
throws FileTransferRejectedException;
}
......@@ -10,10 +10,9 @@
*/
package org.jivesoftware.wildfire.filetransfer;
import org.xmpp.packet.JID;
import org.dom4j.Element;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.container.Module;
import org.jivesoftware.wildfire.filetransfer.proxy.ProxyTransfer;
/**
* Manages all file transfer currently happening originating from and/or ending at users of the
......@@ -22,23 +21,16 @@ import org.jivesoftware.wildfire.container.Module;
* @author Alexander Wenckus
*/
public interface FileTransferManager extends Module {
/**
* The JiveProperty relating to whether or not file transfer is currently enabled. If file
* transfer is disabled all known file transfer related packets are blocked, it also goes
* with out saying that the file transfer proxy is then disabled.
*/
static final String JIVEPROPERTY_FILE_TRANSFER_ENABLED = "xmpp.filetransfer.enabled";
/**
* Whether or not the file transfer is enabled by default.
* The Stream Initiation, SI, namespace.
*/
static final boolean DEFAULT_IS_FILE_TRANSFER_ENABLED = true;
static final String NAMESPACE_SI = "http://jabber.org/protocol/si";
/**
* Stream Initiation, SI, namespace
* Namespace for the file transfer profile of Stream Initiation.
*/
static final String NAMESPACE_SI = "http://jabber.org/protocol/si";
static final String NAMESPACE_SI_FILETRANSFER =
"http://jabber.org/protocol/si/profile/file-transfer";
/**
* Bytestreams namespace
......@@ -49,13 +41,10 @@ public interface FileTransferManager extends Module {
* Checks an incoming file transfer request to see if it should be accepted or rejected.
* If it is accepted true will be returned and if it is rejected false will be returned.
*
* @param packetID the packet ID of the packet being parsed.
* @param from the offerer The offerer of the file transfer.
* @param to The receiver the potential reciever of the file transfer.
* @param siElement the Stream Initiation element
* @param transfer the transfer to test for acceptance
* @return true if it should be accepted false if it should not.
*/
boolean acceptIncomingFileTransferRequest(String packetID, JID from, JID to, Element siElement);
boolean acceptIncomingFileTransferRequest(FileTransfer transfer);
/**
* Registers that a transfer has begun through the proxy connected to the server.
......@@ -69,21 +58,6 @@ public interface FileTransferManager extends Module {
void registerProxyTransfer(String transferDigest, ProxyTransfer proxyTransfer)
throws UnauthorizedException;
/**
* Enables or disable all file transfers going through the server. This includes the blocking
* of file transfer related packets from reaching their recipients.
*
* @param isEnabled true if file transfer should be enabled and false if it should not be.
*/
void enableFileTransfer(boolean isEnabled);
/**
* Returns whether or not file transfer is currently enabled in the server.
*
* @return true if file transfer is enabled and false if it is not
*/
boolean isFileTransferEnabled();
void addFileTransferInterceptor(FileTransferInterceptor interceptor);
void removeFileTransferInterceptor(FileTransferInterceptor interceptor);
......
......@@ -8,11 +8,9 @@
* 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.wildfire.filetransfer.spi;
package org.jivesoftware.wildfire.filetransfer.proxy;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.wildfire.filetransfer.ProxyTransfer;
import org.jivesoftware.wildfire.filetransfer.ProxyOutputStream;
import java.util.concurrent.Future;
import java.io.IOException;
......
......@@ -9,7 +9,7 @@
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.filetransfer;
package org.jivesoftware.wildfire.filetransfer.proxy;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
......@@ -18,6 +18,7 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import org.jivesoftware.wildfire.*;
import org.jivesoftware.wildfire.filetransfer.FileTransferManager;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.disco.*;
......@@ -69,7 +70,6 @@ public class FileTransferProxy extends BasicModule
private PacketRouter router;
private String proxyIP;
private ProxyConnectionManager connectionManager;
private FileTransferManager transferManager;
private InetAddress bindInterface;
......@@ -182,9 +182,8 @@ public class FileTransferProxy extends BasicModule
catch (UnknownHostException e) {
Log.error("Couldn't discover local host", e);
}
transferManager = getFileTransferManager(server);
connectionManager = new ProxyConnectionManager(transferManager);
connectionManager = new ProxyConnectionManager(getFileTransferManager(server));
}
private FileTransferManager getFileTransferManager(XMPPServer server) {
......@@ -250,8 +249,7 @@ public class FileTransferProxy extends BasicModule
}
private boolean isEnabled() {
return transferManager.isFileTransferEnabled() &&
JiveGlobals.getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED, DEFAULT_IS_PROXY_ENABLED);
return JiveGlobals.getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED, DEFAULT_IS_PROXY_ENABLED);
}
/**
......@@ -373,27 +371,13 @@ public class FileTransferProxy extends BasicModule
Object value = params.get("value");
boolean isEnabled = (value != null ? Boolean.parseBoolean(value.toString()) :
DEFAULT_IS_PROXY_ENABLED);
setEnabled(isEnabled && transferManager.isFileTransferEnabled());
}
else if(FileTransferManager.JIVEPROPERTY_FILE_TRANSFER_ENABLED
.equalsIgnoreCase(property))
{
Object value = params.get("value");
boolean isEnabled = (value != null ? Boolean.parseBoolean(value.toString())
: FileTransferManager.DEFAULT_IS_FILE_TRANSFER_ENABLED);
setEnabled(isEnabled && JiveGlobals.getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED,
DEFAULT_IS_PROXY_ENABLED));
setEnabled(isEnabled);
}
}
public void propertyDeleted(String property, Map params) {
if(JIVEPROPERTY_PROXY_ENABLED.equalsIgnoreCase(property)) {
setEnabled(DEFAULT_IS_PROXY_ENABLED && transferManager.isFileTransferEnabled());
}
else if(FileTransferManager.JIVEPROPERTY_FILE_TRANSFER_ENABLED.
equalsIgnoreCase(property)){setEnabled(FileTransferManager.
DEFAULT_IS_FILE_TRANSFER_ENABLED && JiveGlobals.
getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED, DEFAULT_IS_PROXY_ENABLED));
setEnabled(DEFAULT_IS_PROXY_ENABLED);
}
}
......
......@@ -8,11 +8,12 @@
* 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.wildfire.filetransfer;
package org.jivesoftware.wildfire.filetransfer.proxy;
import org.jivesoftware.util.*;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.filetransfer.spi.DefaultProxyTransfer;
import org.jivesoftware.wildfire.filetransfer.FileTransferManager;
import org.jivesoftware.wildfire.filetransfer.FileTransferRejectedException;
import org.jivesoftware.wildfire.stats.Statistic;
import org.jivesoftware.wildfire.stats.StatisticsManager;
import org.jivesoftware.wildfire.stats.i18nStatistic;
......@@ -60,7 +61,7 @@ public class ProxyConnectionManager {
connectionMap = new Cache<String, ProxyTransfer>(cacheName, -1, 1000 * 60 * 10);
className = JiveGlobals.getProperty("provider.transfer.proxy",
"org.jivesoftware.wildfire.filetransfer.spi.DefaultProxyTransfer");
"org.jivesoftware.wildfire.filetransfer.proxy.DefaultProxyTransfer");
transferManager = manager;
StatisticsManager.getInstance().addStatistic(proxyTransferRate, new ProxyTracker());
......
......@@ -6,7 +6,7 @@
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.wildfire.filetransfer;
package org.jivesoftware.wildfire.filetransfer.proxy;
import java.io.OutputStream;
import java.io.IOException;
......
......@@ -7,9 +7,10 @@
* 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.wildfire.filetransfer;
package org.jivesoftware.wildfire.filetransfer.proxy;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.wildfire.filetransfer.FileTransferProgress;
import java.io.IOException;
......@@ -19,14 +20,25 @@ import java.io.IOException;
*/
public interface ProxyTransfer extends Cacheable, FileTransferProgress {
/**
* Sets the transfer digest for a file transfer. The transfer digest uniquely identifies a file
* transfer in the system.
*
* @param digest the digest which uniquely identifies this transfer.
*/
public void setTransferDigest(String digest);
/**
* Returns the transfer digest uniquely identifies a file transfer in the system.
*
* @return the transfer digest uniquely identifies a file transfer in the system.
*/
public String getTransferDigest();
/**
* Returns true if the Bytestream is ready to be activated and the proxy transfer can begin.
* Returns true if the Bytestream is ready to be activated and the proxy transfer can begin.
*
* @return Returns true if the Bytestream is ready to be activated.
* @return true if the Bytestream is ready to be activated.
*/
public boolean isActivatable();
......
/**
* $RCSfile$
* $Revision: 1217 $
* $Date: 2005-04-11 18:11:06 -0300 (Mon, 11 Apr 2005) $
*
* Copyright (C) 1999-2006 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.wildfire.filetransfer.spi;
import org.xmpp.packet.JID;
import org.dom4j.Element;
import org.jivesoftware.wildfire.filetransfer.AbstractFileTransferManager;
import org.jivesoftware.wildfire.filetransfer.FileTransfer;
import org.jivesoftware.wildfire.filetransfer.ProxyConnectionManager;
/**
* The default implementation of the file transfer manager. The only acceptance criteria for a proxy
* transfer is employed in the <i>ProxyConnectionManager</i>, it checks that the file transfers stored
* here.
*/
public class DefaultFileTransferManager extends AbstractFileTransferManager {
public boolean acceptIncomingFileTransferRequest(String packetID, JID from, JID to, Element siElement) {
String streamID = siElement.attributeValue("id");
String mimeType = siElement.attributeValue("mime-type");
String profile = siElement.attributeValue("profile");
// Check profile, the only type we deal with currently is file transfer
if ("http://jabber.org/protocol/si/profile/file-transfer".equals(profile)) {
Element fileTransferElement =
getChildElement(siElement, "http://jabber.org/protocol/si/profile/file-transfer");
// Not valid form, reject
if (fileTransferElement == null) {
return false;
}
String fileName = fileTransferElement.attributeValue("name");
long size = Long.parseLong(fileTransferElement.attributeValue("size"));
FileTransfer transfer = new FileTransfer(from.toString(), to.toString(),
streamID, fileName, size, mimeType);
cacheFileTransfer(ProxyConnectionManager.createDigest(streamID, from, to), transfer);
}
return true;
}
}
......@@ -8,11 +8,10 @@
- a copy of which is included in this distribution.
--%>
<%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ page import="org.jivesoftware.wildfire.filetransfer.FileTransferProxy" %>
<%@ page import="org.jivesoftware.wildfire.filetransfer.proxy.FileTransferProxy" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page import="org.jivesoftware.wildfire.XMPPServer"%>
<%@ page import="org.jivesoftware.wildfire.filetransfer.FileTransferManager"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
......@@ -23,9 +22,6 @@
<%
Map<String, String> errors = new HashMap<String, String>();
FileTransferProxy transferProxy = XMPPServer.getInstance().getFileTransferProxy();
FileTransferManager manager = XMPPServer.getInstance().getFileTransferManager();
boolean isFileTransferEnabled = manager.isFileTransferEnabled();
boolean isUpdated = request.getParameter("update") != null;
boolean isProxyEnabled = ParamUtils.getBooleanParameter(request, "proxyEnabled");
......@@ -64,7 +60,7 @@
<p>
<fmt:message key="filetransferproxy.settings.info"/>
</p>
<% if (!isFileTransferEnabled || !errors.isEmpty()) { %>
<% if (!errors.isEmpty()) { %>
<div class="jive-error">
<table cellpadding="0" cellspacing="0" border="0">
......@@ -73,9 +69,7 @@
<td class="jive-icon"><img alt="error" src="images/error-16x16.gif" width="16" height="16"
border="0"/></td>
<td class="jive-icon-label">
<% if(!isFileTransferEnabled) { %>
<fmt:message key="filetransfer.error.disabled"/>
<% } else if (errors.get("port") != null) { %>
<% if (errors.get("port") != null) { %>
<fmt:message key="filetransferproxy.settings.valid.port"/>
<% } %>
</td>
......@@ -115,20 +109,20 @@ else { %>
<tr valign="middle">
<td width="1%" nowrap>
<input type="radio" name="proxyEnabled" value="true" id="rb02"
<%= (isProxyEnabled ? "checked" : "") %> <%=!isFileTransferEnabled ? "disabled" : ""%>>
<%= (isProxyEnabled ? "checked" : "") %> >
</td>
<td width="99%">
<label for="rb02">
<b><fmt:message key="filetransferproxy.settings.label_enable"/></b>
- <fmt:message key="filetransferproxy.settings.label_enable_info"/>
</label> <input type="text" size="5" maxlength="10" name="port"
value="<%= port %>" <%=!isFileTransferEnabled ? "disabled" : ""%>>
value="<%= port %>" >
</td>
</tr>
<tr valign="middle">
<td width="1%" nowrap>
<input type="radio" name="proxyEnabled" value="false" id="rb01"
<%= (!isProxyEnabled ? "checked" : "") %> <%=!isFileTransferEnabled ? "disabled" : ""%>>
<%= (!isProxyEnabled ? "checked" : "") %> >
</td>
<td width="99%">
<label for="rb01">
......@@ -144,8 +138,7 @@ else { %>
</fieldset>
<br>
<input type="submit" name="update" value="<fmt:message key="global.save_settings" />"
<%=!isFileTransferEnabled ? "disabled" : ""%>>
<input type="submit" name="update" value="<fmt:message key="global.save_settings" />">
</form>
</body>
......
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