diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FaultTolerantNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FaultTolerantNegotiator.java deleted file mode 100644 index dc09bc317..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FaultTolerantNegotiator.java +++ /dev/null @@ -1,189 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.PacketCollector; -import org.jivesoftware.smack.SmackConfiguration; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.filter.OrFilter; -import org.jivesoftware.smack.filter.PacketFilter; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smackx.packet.StreamInitiation; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.concurrent.*; -import java.util.List; -import java.util.ArrayList; - - -/** - * The fault tolerant negotiator takes two stream negotiators, the primary and the secondary - * negotiator. If the primary negotiator fails during the stream negotiaton process, the second - * negotiator is used. - */ -public class FaultTolerantNegotiator extends StreamNegotiator { - - private StreamNegotiator primaryNegotiator; - private StreamNegotiator secondaryNegotiator; - private XMPPConnection connection; - private PacketFilter primaryFilter; - private PacketFilter secondaryFilter; - - public FaultTolerantNegotiator(XMPPConnection connection, StreamNegotiator primary, - StreamNegotiator secondary) { - this.primaryNegotiator = primary; - this.secondaryNegotiator = secondary; - this.connection = connection; - } - - public PacketFilter getInitiationPacketFilter(String from, String streamID) { - if (primaryFilter == null || secondaryFilter == null) { - primaryFilter = primaryNegotiator.getInitiationPacketFilter(from, streamID); - secondaryFilter = secondaryNegotiator.getInitiationPacketFilter(from, streamID); - } - return new OrFilter(primaryFilter, secondaryFilter); - } - - InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException { - throw new UnsupportedOperationException("Negotiation only handled by create incoming " + - "stream method."); - } - - final Packet initiateIncomingStream(XMPPConnection connection, StreamInitiation initiation) { - throw new UnsupportedOperationException("Initiation handled by createIncomingStream " + - "method"); - } - - public InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException { - PacketCollector collector = connection.createPacketCollector( - getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID())); - - System.out.println(new java.util.Date().toString() + ": FaultTolerantNegotiator>createIncomingStream:80"); - connection.sendPacket(super.createInitiationAccept(initiation, getNamespaces())); - System.out.println(new java.util.Date().toString() + ": FaultTolerantNegotiator>createIncomingStream:82"); - - CompletionService service - = new ExecutorCompletionService(Executors.newFixedThreadPool(2)); - List> futures = new ArrayList>(); - InputStream stream = null; - XMPPException exception = null; - try { - futures.add(service.submit(new NegotiatorService(collector))); - futures.add(service.submit(new NegotiatorService(collector))); - System.out.println(new java.util.Date().toString() + ": FaultTolerantNegotiator>createIncomingStream:92"); - - int i = 0; - while (stream == null && i < futures.size()) { - Future future; - try { - i++; - System.out.println(new java.util.Date().toString() + ": FaultTolerantNegotiator>createIncomingStream:99"); - future = service.poll(10, TimeUnit.SECONDS); - System.out.println(new java.util.Date().toString() + ": FaultTolerantNegotiator>createIncomingStream:101"); - } - catch (InterruptedException e) { - continue; - } - - if (future == null) { - continue; - } - - try { - stream = future.get(); - } - catch (InterruptedException e) { - /* Do Nothing */ - } - catch (ExecutionException e) { - exception = new XMPPException(e.getCause()); - } - } - } - finally { - for (Future future : futures) { - future.cancel(true); - } - collector.cancel(); - } - if (stream == null) { - if (exception != null) { - throw exception; - } - else { - throw new XMPPException("File transfer negotiation failed."); - } - } - - return stream; - } - - private StreamNegotiator determineNegotiator(Packet streamInitiation) { - return primaryFilter.accept(streamInitiation) ? primaryNegotiator : secondaryNegotiator; - } - - public OutputStream createOutgoingStream(String streamID, String initiator, String target) - throws XMPPException { - OutputStream stream; - try { - stream = primaryNegotiator.createOutgoingStream(streamID, initiator, target); - } - catch (XMPPException ex) { - stream = secondaryNegotiator.createOutgoingStream(streamID, initiator, target); - } - - return stream; - } - - public String[] getNamespaces() { - String[] primary = primaryNegotiator.getNamespaces(); - String[] secondary = secondaryNegotiator.getNamespaces(); - - String[] namespaces = new String[primary.length + secondary.length]; - System.arraycopy(primary, 0, namespaces, 0, primary.length); - System.arraycopy(secondary, 0, namespaces, primary.length, secondary.length); - - return namespaces; - } - - public void cleanup() { - } - - private class NegotiatorService implements Callable { - - private PacketCollector collector; - - NegotiatorService(PacketCollector collector) { - this.collector = collector; - } - - public InputStream call() throws Exception { - Packet streamInitiation = collector.nextResult( - SmackConfiguration.getPacketReplyTimeout() * 2); - if (streamInitiation == null) { - throw new XMPPException("No response from remote client"); - } - StreamNegotiator negotiator = determineNegotiator(streamInitiation); - return negotiator.negotiateIncomingStream(streamInitiation); - } - } -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransfer.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransfer.java deleted file mode 100644 index 9954adf4e..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransfer.java +++ /dev/null @@ -1,376 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.jivesoftware.smack.XMPPException; - -/** - * Contains the generic file information and progress related to a particular - * file transfer. - * - * @author Alexander Wenckus - * - */ -public abstract class FileTransfer { - - private String fileName; - - private String filePath; - - private long fileSize; - - private String peer; - - private Status status = Status.initial; - - private final Object statusMonitor = new Object(); - - protected FileTransferNegotiator negotiator; - - protected String streamID; - - protected long amountWritten = -1; - - private Error error; - - private Exception exception; - - /** - * Buffer size between input and output - */ - private static final int BUFFER_SIZE = 8192; - - protected FileTransfer(String peer, String streamID, - FileTransferNegotiator negotiator) { - this.peer = peer; - this.streamID = streamID; - this.negotiator = negotiator; - } - - protected void setFileInfo(String fileName, long fileSize) { - this.fileName = fileName; - this.fileSize = fileSize; - } - - protected void setFileInfo(String path, String fileName, long fileSize) { - this.filePath = path; - this.fileName = fileName; - this.fileSize = fileSize; - } - - /** - * Returns the size of the file being transfered. - * - * @return Returns the size of the file being transfered. - */ - public long getFileSize() { - return fileSize; - } - - /** - * Returns the name of the file being transfered. - * - * @return Returns the name of the file being transfered. - */ - public String getFileName() { - return fileName; - } - - /** - * Returns the local path of the file. - * - * @return Returns the local path of the file. - */ - public String getFilePath() { - return filePath; - } - - /** - * Returns the JID of the peer for this file transfer. - * - * @return Returns the JID of the peer for this file transfer. - */ - public String getPeer() { - return peer; - } - - /** - * Returns the progress of the file transfer as a number between 0 and 1. - * - * @return Returns the progress of the file transfer as a number between 0 - * and 1. - */ - public double getProgress() { - if (amountWritten <= 0 || fileSize <= 0) { - return 0; - } - return (double) amountWritten / (double) fileSize; - } - - /** - * Returns true if the transfer has been cancelled, if it has stopped because - * of a an error, or the transfer completed succesfully. - * - * @return Returns true if the transfer has been cancelled, if it has stopped - * because of a an error, or the transfer completed succesfully. - */ - public boolean isDone() { - return status == Status.cancelled || status == Status.error - || status == Status.complete || status == Status.refused; - } - - /** - * Retuns the current status of the file transfer. - * - * @return Retuns the current status of the file transfer. - */ - public Status getStatus() { - return status; - } - - protected void setError(Error type) { - this.error = type; - } - - /** - * When {@link #getStatus()} returns that there was an {@link Status#error} - * during the transfer, the type of error can be retrieved through this - * method. - * - * @return Returns the type of error that occured if one has occured. - */ - public Error getError() { - return error; - } - - /** - * If an exception occurs asynchronously it will be stored for later - * retrival. If there is an error there maybe an exception set. - * - * @return The exception that occured or null if there was no exception. - * @see #getError() - */ - public Exception getException() { - return exception; - } - - /** - * Cancels the file transfer. - */ - public abstract void cancel(); - - protected void setException(Exception exception) { - this.exception = exception; - } - - protected void setStatus(Status status) { - synchronized (statusMonitor) { - this.status = status; - } - } - - protected boolean updateStatus(Status oldStatus, Status newStatus) { - synchronized (statusMonitor) { - if (oldStatus != status) { - return false; - } - status = newStatus; - return true; - } - } - - protected void writeToStream(final InputStream in, final OutputStream out) - throws XMPPException - { - final byte[] b = new byte[BUFFER_SIZE]; - int count = 0; - amountWritten = 0; - - do { - // write to the output stream - try { - out.write(b, 0, count); - } catch (IOException e) { - throw new XMPPException("error writing to output stream", e); - } - - amountWritten += count; - - // read more bytes from the input stream - try { - count = in.read(b); - } catch (IOException e) { - throw new XMPPException("error reading from input stream", e); - } - } while (count != -1 && !getStatus().equals(Status.cancelled)); - - // the connection was likely terminated abrubtly if these are not equal - if (!getStatus().equals(Status.cancelled) && getError() == Error.none - && amountWritten != fileSize) { - setStatus(Status.error); - this.error = Error.connection; - } - } - - /** - * A class to represent the current status of the file transfer. - * - * @author Alexander Wenckus - * - */ - public enum Status { - - /** - * An error occured during the transfer. - * - * @see FileTransfer#getError() - */ - error("Error"), - - /** - * The initial status of the file transfer. - */ - initial("Initial"), - - /** - * The file transfer is being negotiated with the peer. The party - * recieving the file has the option to accept or refuse a file transfer - * request. If they accept, then the process of stream negotiation will - * begin. If they refuse the file will not be transfered. - * - * @see #negotiating_stream - */ - negotiating_transfer("Negotiating Transfer"), - - /** - * The peer has refused the file transfer request halting the file - * transfer negotiation process. - */ - refused("Refused"), - - /** - * The stream to transfer the file is being negotiated over the chosen - * stream type. After the stream negotiating process is complete the - * status becomes negotiated. - * - * @see #negotiated - */ - negotiating_stream("Negotiating Stream"), - - /** - * After the stream negotitation has completed the intermediate state - * between the time when the negotiation is finished and the actual - * transfer begins. - */ - negotiated("Negotiated"), - - /** - * The transfer is in progress. - * - * @see FileTransfer#getProgress() - */ - in_progress("In Progress"), - - /** - * The transfer has completed successfully. - */ - complete("Complete"), - - /** - * The file transfer was canceled - */ - cancelled("Cancelled"); - - private String status; - - private Status(String status) { - this.status = status; - } - - public String toString() { - return status; - } - } - - /** - * Return the length of bytes written out to the stream. - * @return the amount in bytes written out. - */ - public long getAmountWritten(){ - return amountWritten; - } - - public enum Error { - /** - * No error - */ - none("No error"), - - /** - * The peer did not find any of the provided stream mechanisms - * acceptable. - */ - not_acceptable("The peer did not find any of the provided stream mechanisms acceptable."), - - /** - * The provided file to transfer does not exist or could not be read. - */ - bad_file("The provided file to transfer does not exist or could not be read."), - - /** - * The remote user did not respond or the connection timed out. - */ - no_response("The remote user did not respond or the connection timed out."), - - /** - * An error occured over the socket connected to send the file. - */ - connection("An error occured over the socket connected to send the file."), - - /** - * An error occured while sending or recieving the file - */ - stream("An error occured while sending or recieving the file."); - - private final String msg; - - private Error(String msg) { - this.msg = msg; - } - - /** - * Returns a String representation of this error. - * - * @return Returns a String representation of this error. - */ - public String getMessage() { - return msg; - } - - public String toString() { - return msg; - } - } - -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferListener.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferListener.java deleted file mode 100644 index 69b5c105d..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferListener.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -/** - * File transfers can cause several events to be raised. These events can be - * monitored through this interface. - * - * @author Alexander Wenckus - */ -public interface FileTransferListener { - /** - * A request to send a file has been recieved from another user. - * - * @param request - * The request from the other user. - */ - public void fileTransferRequest(final FileTransferRequest request); -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferManager.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferManager.java deleted file mode 100644 index 8294fbd6f..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferManager.java +++ /dev/null @@ -1,178 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import java.util.ArrayList; -import java.util.List; - -import org.jivesoftware.smack.PacketListener; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.filter.AndFilter; -import org.jivesoftware.smack.filter.IQTypeFilter; -import org.jivesoftware.smack.filter.PacketTypeFilter; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.packet.XMPPError; -import org.jivesoftware.smack.util.StringUtils; -import org.jivesoftware.smackx.packet.StreamInitiation; - -/** - * The file transfer manager class handles the sending and recieving of files. - * To send a file invoke the {@link #createOutgoingFileTransfer(String)} method. - *

- * And to recieve a file add a file transfer listener to the manager. The - * listener will notify you when there is a new file transfer request. To create - * the {@link IncomingFileTransfer} object accept the transfer, or, if the - * transfer is not desirable reject it. - * - * @author Alexander Wenckus - * - */ -public class FileTransferManager { - - private final FileTransferNegotiator fileTransferNegotiator; - - private List listeners; - - private XMPPConnection connection; - - /** - * Creates a file transfer manager to initiate and receive file transfers. - * - * @param connection - * The XMPPConnection that the file transfers will use. - */ - public FileTransferManager(XMPPConnection connection) { - this.connection = connection; - this.fileTransferNegotiator = FileTransferNegotiator - .getInstanceFor(connection); - } - - /** - * Add a file transfer listener to listen to incoming file transfer - * requests. - * - * @param li - * The listener - * @see #removeFileTransferListener(FileTransferListener) - * @see FileTransferListener - */ - public void addFileTransferListener(final FileTransferListener li) { - if (listeners == null) { - initListeners(); - } - synchronized (this.listeners) { - listeners.add(li); - } - } - - private void initListeners() { - listeners = new ArrayList(); - - connection.addPacketListener(new PacketListener() { - public void processPacket(Packet packet) { - fireNewRequest((StreamInitiation) packet); - } - }, new AndFilter(new PacketTypeFilter(StreamInitiation.class), - new IQTypeFilter(IQ.Type.SET))); - } - - protected void fireNewRequest(StreamInitiation initiation) { - FileTransferListener[] listeners = null; - synchronized (this.listeners) { - listeners = new FileTransferListener[this.listeners.size()]; - this.listeners.toArray(listeners); - } - FileTransferRequest request = new FileTransferRequest(this, initiation); - for (int i = 0; i < listeners.length; i++) { - listeners[i].fileTransferRequest(request); - } - } - - /** - * Removes a file transfer listener. - * - * @param li - * The file transfer listener to be removed - * @see FileTransferListener - */ - public void removeFileTransferListener(final FileTransferListener li) { - if (listeners == null) { - return; - } - synchronized (this.listeners) { - listeners.remove(li); - } - } - - /** - * Creates an OutgoingFileTransfer to send a file to another user. - * - * @param userID - * The fully qualified jabber ID with resource of the user to - * send the file to. - * @return The send file object on which the negotiated transfer can be run. - */ - public OutgoingFileTransfer createOutgoingFileTransfer(String userID) { - if (userID == null || StringUtils.parseName(userID).length() <= 0 - || StringUtils.parseServer(userID).length() <= 0 - || StringUtils.parseResource(userID).length() <= 0) { - throw new IllegalArgumentException( - "The provided user id was not fully qualified"); - } - - return new OutgoingFileTransfer(connection.getUser(), userID, - fileTransferNegotiator.getNextStreamID(), - fileTransferNegotiator); - } - - /** - * When the file transfer request is acceptable, this method should be - * invoked. It will create an IncomingFileTransfer which allows the - * transmission of the file to procede. - * - * @param request - * The remote request that is being accepted. - * @return The IncomingFileTransfer which manages the download of the file - * from the transfer initiator. - */ - protected IncomingFileTransfer createIncomingFileTransfer( - FileTransferRequest request) { - if (request == null) { - throw new NullPointerException("RecieveRequest cannot be null"); - } - - IncomingFileTransfer transfer = new IncomingFileTransfer(request, - fileTransferNegotiator); - transfer.setFileInfo(request.getFileName(), request.getFileSize()); - - return transfer; - } - - protected void rejectIncomingFileTransfer(FileTransferRequest request) { - StreamInitiation initiation = request.getStreamInitiation(); - - IQ rejection = FileTransferNegotiator.createIQ( - initiation.getPacketID(), initiation.getFrom(), initiation - .getTo(), IQ.Type.ERROR); - rejection.setError(new XMPPError(XMPPError.Condition.forbidden)); - connection.sendPacket(rejection); - } -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferNegotiator.java deleted file mode 100644 index 1d2354b8e..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferNegotiator.java +++ /dev/null @@ -1,462 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.ConnectionListener; -import org.jivesoftware.smack.PacketCollector; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.filter.PacketIDFilter; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.packet.XMPPError; -import org.jivesoftware.smackx.Form; -import org.jivesoftware.smackx.FormField; -import org.jivesoftware.smackx.ServiceDiscoveryManager; -import org.jivesoftware.smackx.packet.DataForm; -import org.jivesoftware.smackx.packet.StreamInitiation; - -import java.net.URLConnection; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Manages the negotiation of file transfers according to JEP-0096. If a file is - * being sent the remote user chooses the type of stream under which the file - * will be sent. - * - * @author Alexander Wenckus - * @see JEP-0096: File Transfer - */ -public class FileTransferNegotiator { - - // Static - - /** - * The XMPP namespace of the SOCKS5 bytestream - */ - public static final String BYTE_STREAM = "http://jabber.org/protocol/bytestreams"; - - /** - * The XMPP namespace of the In-Band bytestream - */ - public static final String INBAND_BYTE_STREAM = "http://jabber.org/protocol/ibb"; - - private static final String[] NAMESPACE = { - "http://jabber.org/protocol/si/profile/file-transfer", - "http://jabber.org/protocol/si", BYTE_STREAM, INBAND_BYTE_STREAM}; - - private static final String[] PROTOCOLS = {BYTE_STREAM, INBAND_BYTE_STREAM}; - - private static final Map transferObject = - new ConcurrentHashMap(); - - private static final String STREAM_INIT_PREFIX = "jsi_"; - - protected static final String STREAM_DATA_FIELD_NAME = "stream-method"; - - private static final Random randomGenerator = new Random(); - - /** - * A static variable to use only offer IBB for file transfer. It is generally recommend to only - * set this variable to true for testing purposes as IBB is the backup file transfer method - * and shouldn't be used as the only transfer method in production systems. - */ - public static boolean IBB_ONLY = false; - - /** - * Returns the file transfer negotiator related to a particular connection. - * When this class is requested on a particular connection the file transfer - * service is automatically enabled. - * - * @param connection The connection for which the transfer manager is desired - * @return The IMFileTransferManager - */ - public static FileTransferNegotiator getInstanceFor( - final XMPPConnection connection) { - if (connection == null) { - throw new IllegalArgumentException("Connection cannot be null"); - } - if (!connection.isConnected()) { - return null; - } - - if (transferObject.containsKey(connection)) { - return transferObject.get(connection); - } - else { - FileTransferNegotiator transfer = new FileTransferNegotiator( - connection); - setServiceEnabled(connection, true); - transferObject.put(connection, transfer); - return transfer; - } - } - - /** - * Enable the Jabber services related to file transfer on the particular - * connection. - * - * @param connection The connection on which to enable or disable the services. - * @param isEnabled True to enable, false to disable. - */ - public static void setServiceEnabled(final XMPPConnection connection, - final boolean isEnabled) { - ServiceDiscoveryManager manager = ServiceDiscoveryManager - .getInstanceFor(connection); - for (String ns : NAMESPACE) { - if (isEnabled) { - manager.addFeature(ns); - } - else { - manager.removeFeature(ns); - } - } - } - - /** - * Checks to see if all file transfer related services are enabled on the - * connection. - * - * @param connection The connection to check - * @return True if all related services are enabled, false if they are not. - */ - public static boolean isServiceEnabled(final XMPPConnection connection) { - for (String ns : NAMESPACE) { - if (!ServiceDiscoveryManager.getInstanceFor(connection).includesFeature(ns)) - return false; - } - return true; - } - - /** - * A convience method to create an IQ packet. - * - * @param ID The packet ID of the - * @param to To whom the packet is addressed. - * @param from From whom the packet is sent. - * @param type The iq type of the packet. - * @return The created IQ packet. - */ - public static IQ createIQ(final String ID, final String to, - final String from, final IQ.Type type) { - IQ iqPacket = new IQ() { - public String getChildElementXML() { - return null; - } - }; - iqPacket.setPacketID(ID); - iqPacket.setTo(to); - iqPacket.setFrom(from); - iqPacket.setType(type); - - return iqPacket; - } - - /** - * Returns a collection of the supported transfer protocols. - * - * @return Returns a collection of the supported transfer protocols. - */ - public static Collection getSupportedProtocols() { - return Collections.unmodifiableList(Arrays.asList(PROTOCOLS)); - } - - // non-static - - private final XMPPConnection connection; - - private final Socks5TransferNegotiatorManager byteStreamTransferManager; - - private final StreamNegotiator inbandTransferManager; - - private FileTransferNegotiator(final XMPPConnection connection) { - configureConnection(connection); - - this.connection = connection; - byteStreamTransferManager = new Socks5TransferNegotiatorManager(connection); - inbandTransferManager = new IBBTransferNegotiator(connection); - } - - private void configureConnection(final XMPPConnection connection) { - connection.addConnectionListener(new ConnectionListener() { - public void connectionClosed() { - cleanup(connection); - } - - public void connectionClosedOnError(Exception e) { - cleanup(connection); - } - - public void reconnectionFailed(Exception e) { - // ignore - } - - public void reconnectionSuccessful() { - // ignore - } - - public void reconnectingIn(int seconds) { - // ignore - } - }); - } - - private void cleanup(final XMPPConnection connection) { - if (transferObject.remove(connection) != null) { - byteStreamTransferManager.cleanup(); - inbandTransferManager.cleanup(); - } - } - - /** - * Selects an appropriate stream negotiator after examining the incoming file transfer request. - * - * @param request The related file transfer request. - * @return The file transfer object that handles the transfer - * @throws XMPPException If there are either no stream methods contained in the packet, or - * there is not an appropriate stream method. - */ - public StreamNegotiator selectStreamNegotiator( - FileTransferRequest request) throws XMPPException { - StreamInitiation si = request.getStreamInitiation(); - FormField streamMethodField = getStreamMethodField(si - .getFeatureNegotiationForm()); - - if (streamMethodField == null) { - String errorMessage = "No stream methods contained in packet."; - XMPPError error = new XMPPError(XMPPError.Condition.bad_request, errorMessage); - IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(), - IQ.Type.ERROR); - iqPacket.setError(error); - connection.sendPacket(iqPacket); - throw new XMPPException(errorMessage, error); - } - - // select the appropriate protocol - - StreamNegotiator selectedStreamNegotiator; - try { - selectedStreamNegotiator = getNegotiator(streamMethodField); - } - catch (XMPPException e) { - IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(), - IQ.Type.ERROR); - iqPacket.setError(e.getXMPPError()); - connection.sendPacket(iqPacket); - throw e; - } - - // return the appropriate negotiator - - return selectedStreamNegotiator; - } - - private FormField getStreamMethodField(DataForm form) { - FormField field = null; - for (Iterator it = form.getFields(); it.hasNext();) { - field = (FormField) it.next(); - if (field.getVariable().equals(STREAM_DATA_FIELD_NAME)) { - break; - } - field = null; - } - return field; - } - - private StreamNegotiator getNegotiator(final FormField field) - throws XMPPException { - String variable; - boolean isByteStream = false; - boolean isIBB = false; - for (Iterator it = field.getOptions(); it.hasNext();) { - variable = ((FormField.Option) it.next()).getValue(); - if (variable.equals(BYTE_STREAM) && !IBB_ONLY) { - isByteStream = true; - } - else if (variable.equals(INBAND_BYTE_STREAM)) { - isIBB = true; - } - } - - if (!isByteStream && !isIBB) { - XMPPError error = new XMPPError(XMPPError.Condition.bad_request, - "No acceptable transfer mechanism"); - throw new XMPPException(error.getMessage(), error); - } - - if (isByteStream && isIBB && field.getType().equals(FormField.TYPE_LIST_MULTI)) { - return new FaultTolerantNegotiator(connection, - byteStreamTransferManager.createNegotiator(), - inbandTransferManager); - } - else if (isByteStream) { - return byteStreamTransferManager.createNegotiator(); - } - else { - return inbandTransferManager; - } - } - - /** - * Reject a stream initiation request from a remote user. - * - * @param si The Stream Initiation request to reject. - */ - public void rejectStream(final StreamInitiation si) { - XMPPError error = new XMPPError(XMPPError.Condition.forbidden, "Offer Declined"); - IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(), - IQ.Type.ERROR); - iqPacket.setError(error); - connection.sendPacket(iqPacket); - } - - /** - * Returns a new, unique, stream ID to identify a file transfer. - * - * @return Returns a new, unique, stream ID to identify a file transfer. - */ - public String getNextStreamID() { - StringBuilder buffer = new StringBuilder(); - buffer.append(STREAM_INIT_PREFIX); - buffer.append(Math.abs(randomGenerator.nextLong())); - - return buffer.toString(); - } - - /** - * Send a request to another user to send them a file. The other user has - * the option of, accepting, rejecting, or not responding to a received file - * transfer request. - *

- * If they accept, the packet will contain the other user's choosen stream - * type to send the file across. The two choices this implementation - * provides to the other user for file transfer are SOCKS5 Bytestreams, - * which is the prefered method of transfer, and In-Band Bytestreams, - * which is the fallback mechanism. - *

- * The other user may choose to decline the file request if they do not - * desire the file, their client does not support JEP-0096, or if there are - * no acceptable means to transfer the file. - *

- * Finally, if the other user does not respond this method will return null - * after the specified timeout. - * - * @param userID The userID of the user to whom the file will be sent. - * @param streamID The unique identifier for this file transfer. - * @param fileName The name of this file. Preferably it should include an - * extension as it is used to determine what type of file it is. - * @param size The size, in bytes, of the file. - * @param desc A description of the file. - * @param responseTimeout The amount of time, in milliseconds, to wait for the remote - * user to respond. If they do not respond in time, this - * @return Returns the stream negotiator selected by the peer. - * @throws XMPPException Thrown if there is an error negotiating the file transfer. - */ - public StreamNegotiator negotiateOutgoingTransfer(final String userID, - final String streamID, final String fileName, final long size, - final String desc, int responseTimeout) throws XMPPException { - StreamInitiation si = new StreamInitiation(); - si.setSesssionID(streamID); - si.setMimeType(URLConnection.guessContentTypeFromName(fileName)); - - StreamInitiation.File siFile = new StreamInitiation.File(fileName, size); - siFile.setDesc(desc); - si.setFile(siFile); - - si.setFeatureNegotiationForm(createDefaultInitiationForm()); - - si.setFrom(connection.getUser()); - si.setTo(userID); - si.setType(IQ.Type.SET); - - PacketCollector collector = connection - .createPacketCollector(new PacketIDFilter(si.getPacketID())); - connection.sendPacket(si); - Packet siResponse = collector.nextResult(responseTimeout); - collector.cancel(); - - if (siResponse instanceof IQ) { - IQ iqResponse = (IQ) siResponse; - if (iqResponse.getType().equals(IQ.Type.RESULT)) { - StreamInitiation response = (StreamInitiation) siResponse; - return getOutgoingNegotiator(getStreamMethodField(response - .getFeatureNegotiationForm())); - - } - else if (iqResponse.getType().equals(IQ.Type.ERROR)) { - throw new XMPPException(iqResponse.getError()); - } - else { - throw new XMPPException("File transfer response unreadable"); - } - } - else { - return null; - } - } - - private StreamNegotiator getOutgoingNegotiator(final FormField field) - throws XMPPException { - String variable; - boolean isByteStream = false; - boolean isIBB = false; - for (Iterator it = field.getValues(); it.hasNext();) { - variable = it.next(); - if (variable.equals(BYTE_STREAM) && !IBB_ONLY) { - isByteStream = true; - } - else if (variable.equals(INBAND_BYTE_STREAM)) { - isIBB = true; - } - } - - if (!isByteStream && !isIBB) { - XMPPError error = new XMPPError(XMPPError.Condition.bad_request, - "No acceptable transfer mechanism"); - throw new XMPPException(error.getMessage(), error); - } - - if (isByteStream && isIBB) { - return new FaultTolerantNegotiator(connection, - byteStreamTransferManager.createNegotiator(), inbandTransferManager); - } - else if (isByteStream) { - return byteStreamTransferManager.createNegotiator(); - } - else { - return inbandTransferManager; - } - } - - private DataForm createDefaultInitiationForm() { - DataForm form = new DataForm(Form.TYPE_FORM); - FormField field = new FormField(STREAM_DATA_FIELD_NAME); - field.setType(FormField.TYPE_LIST_MULTI); - if (!IBB_ONLY) { - field.addOption(new FormField.Option(BYTE_STREAM)); - } - field.addOption(new FormField.Option(INBAND_BYTE_STREAM)); - form.addField(field); - return form; - } -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferNegotiatorManager.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferNegotiatorManager.java deleted file mode 100644 index e63c9ebf6..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferNegotiatorManager.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * $Revision:$ - * $Date:$ - * - * Copyright 2003-2007 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -/** - * - */ -public interface FileTransferNegotiatorManager { - StreamNegotiator createNegotiator(); -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferRequest.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferRequest.java deleted file mode 100644 index d202dca62..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/FileTransferRequest.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smackx.packet.StreamInitiation; - -/** - * A request to send a file recieved from another user. - * - * @author Alexander Wenckus - * - */ -public class FileTransferRequest { - private final StreamInitiation streamInitiation; - - private final FileTransferManager manager; - - /** - * A recieve request is constructed from the Stream Initiation request - * received from the initator. - * - * @param manager - * The manager handling this file transfer - * - * @param si - * The Stream initiaton recieved from the initiator. - */ - public FileTransferRequest(FileTransferManager manager, StreamInitiation si) { - this.streamInitiation = si; - this.manager = manager; - } - - /** - * Returns the name of the file. - * - * @return Returns the name of the file. - */ - public String getFileName() { - return streamInitiation.getFile().getName(); - } - - /** - * Returns the size in bytes of the file. - * - * @return Returns the size in bytes of the file. - */ - public long getFileSize() { - return streamInitiation.getFile().getSize(); - } - - /** - * Returns the description of the file provided by the requestor. - * - * @return Returns the description of the file provided by the requestor. - */ - public String getDescription() { - return streamInitiation.getFile().getDesc(); - } - - /** - * Returns the mime-type of the file. - * - * @return Returns the mime-type of the file. - */ - public String getMimeType() { - return streamInitiation.getMimeType(); - } - - /** - * Returns the fully-qualified jabber ID of the user that requested this - * file transfer. - * - * @return Returns the fully-qualified jabber ID of the user that requested - * this file transfer. - */ - public String getRequestor() { - return streamInitiation.getFrom(); - } - - /** - * Returns the stream ID that uniquely identifies this file transfer. - * - * @return Returns the stream ID that uniquely identifies this file - * transfer. - */ - public String getStreamID() { - return streamInitiation.getSessionID(); - } - - /** - * Returns the stream initiation packet that was sent by the requestor which - * contains the parameters of the file transfer being transfer and also the - * methods available to transfer the file. - * - * @return Returns the stream initiation packet that was sent by the - * requestor which contains the parameters of the file transfer - * being transfer and also the methods available to transfer the - * file. - */ - protected StreamInitiation getStreamInitiation() { - return streamInitiation; - } - - /** - * Accepts this file transfer and creates the incoming file transfer. - * - * @return Returns the IncomingFileTransfer on which the - * file transfer can be carried out. - */ - public IncomingFileTransfer accept() { - return manager.createIncomingFileTransfer(this); - } - - /** - * Rejects the file transfer request. - */ - public void reject() { - manager.rejectIncomingFileTransfer(this); - } - -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/IBBTransferNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/IBBTransferNegotiator.java deleted file mode 100644 index 19fc23368..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/IBBTransferNegotiator.java +++ /dev/null @@ -1,459 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.*; -import org.jivesoftware.smack.util.StringUtils; -import org.jivesoftware.smack.filter.*; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.packet.XMPPError; -import org.jivesoftware.smackx.packet.IBBExtensions; -import org.jivesoftware.smackx.packet.IBBExtensions.Open; -import org.jivesoftware.smackx.packet.StreamInitiation; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * The in-band bytestream file transfer method, or IBB for short, transfers the - * file over the same XML Stream used by XMPP. It is the fall-back mechanism in - * case the SOCKS5 bytestream method of transfering files is not available. - * - * @author Alexander Wenckus - * @see JEP-0047: In-Band - * Bytestreams (IBB) - */ -public class IBBTransferNegotiator extends StreamNegotiator { - - protected static final String NAMESPACE = "http://jabber.org/protocol/ibb"; - - public static final int DEFAULT_BLOCK_SIZE = 4096; - - private XMPPConnection connection; - - /** - * The default constructor for the In-Band Bystream Negotiator. - * - * @param connection The connection which this negotiator works on. - */ - protected IBBTransferNegotiator(XMPPConnection connection) { - this.connection = connection; - } - - public PacketFilter getInitiationPacketFilter(String from, String streamID) { - return new AndFilter(new FromContainsFilter( - from), new IBBOpenSidFilter(streamID)); - } - - InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException { - Open openRequest = (Open) streamInitiation; - - if (openRequest.getType().equals(IQ.Type.ERROR)) { - throw new XMPPException(openRequest.getError()); - } - - PacketFilter dataFilter = new IBBMessageSidFilter(openRequest.getFrom(), - openRequest.getSessionID()); - PacketFilter closeFilter = new AndFilter(new PacketTypeFilter( - IBBExtensions.Close.class), new FromMatchesFilter(openRequest - .getFrom())); - - InputStream stream = new IBBInputStream(openRequest.getSessionID(), - dataFilter, closeFilter); - - initInBandTransfer(openRequest); - - return stream; - } - - public InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException { - Packet openRequest = initiateIncomingStream(connection, initiation); - return negotiateIncomingStream(openRequest); - } - - /** - * Creates and sends the response for the open request. - * - * @param openRequest The open request recieved from the peer. - */ - private void initInBandTransfer(final Open openRequest) { - connection.sendPacket(FileTransferNegotiator.createIQ(openRequest - .getPacketID(), openRequest.getFrom(), openRequest.getTo(), - IQ.Type.RESULT)); - } - - public OutputStream createOutgoingStream(String streamID, String initiator, - String target) throws XMPPException { - Open openIQ = new Open(streamID, DEFAULT_BLOCK_SIZE); - openIQ.setTo(target); - openIQ.setType(IQ.Type.SET); - - // wait for the result from the peer - PacketCollector collector = connection - .createPacketCollector(new PacketIDFilter(openIQ.getPacketID())); - connection.sendPacket(openIQ); - // We don't want to wait forever for the result - IQ openResponse = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); - collector.cancel(); - - if (openResponse == null) { - throw new XMPPException("No response from peer on IBB open"); - } - - IQ.Type type = openResponse.getType(); - if (!type.equals(IQ.Type.RESULT)) { - if (type.equals(IQ.Type.ERROR)) { - throw new XMPPException("Target returned an error", - openResponse.getError()); - } - else { - throw new XMPPException("Target returned unknown response"); - } - } - - return new IBBOutputStream(target, streamID, DEFAULT_BLOCK_SIZE); - } - - public String[] getNamespaces() { - return new String[]{NAMESPACE}; - } - - public void cleanup() { - } - - private class IBBOutputStream extends OutputStream { - - protected byte[] buffer; - - protected int count = 0; - - protected int seq = 0; - - final String userID; - - final private IQ closePacket; - - private String messageID; - private String sid; - - IBBOutputStream(String userID, String sid, int blockSize) { - if (blockSize <= 0) { - throw new IllegalArgumentException("Buffer size <= 0"); - } - buffer = new byte[blockSize]; - this.userID = userID; - - Message template = new Message(userID); - messageID = template.getPacketID(); - this.sid = sid; - closePacket = createClosePacket(userID, sid); - } - - private IQ createClosePacket(String userID, String sid) { - IQ packet = new IBBExtensions.Close(sid); - packet.setTo(userID); - packet.setType(IQ.Type.SET); - return packet; - } - - public void write(int b) throws IOException { - if (count >= buffer.length) { - flushBuffer(); - } - - buffer[count++] = (byte) b; - } - - public synchronized void write(byte b[], int off, int len) - throws IOException { - if (len >= buffer.length) { - // "byte" off the first chunck to write out - writeOut(b, off, buffer.length); - // recursivly call this method again with the lesser amount subtracted. - write(b, off + buffer.length, len - buffer.length); - } else { - writeOut(b, off, len); - } - } - - private void writeOut(byte b[], int off, int len) { - if (len > buffer.length - count) { - flushBuffer(); - } - System.arraycopy(b, off, buffer, count, len); - count += len; - } - - private void flushBuffer() { - writeToXML(buffer, 0, count); - - count = 0; - } - - private synchronized void writeToXML(byte[] buffer, int offset, int len) { - Message template = createTemplate(messageID + "_" + seq); - IBBExtensions.Data ext = new IBBExtensions.Data(sid); - template.addExtension(ext); - - String enc = StringUtils.encodeBase64(buffer, offset, len, false); - - ext.setData(enc); - ext.setSeq(seq); - synchronized (this) { - try { - this.wait(100); - } - catch (InterruptedException e) { - /* Do Nothing */ - } - } - - connection.sendPacket(template); - - seq = (seq + 1 == 65535 ? 0 : seq + 1); - } - - public void close() throws IOException { - connection.sendPacket(closePacket); - } - - public void flush() throws IOException { - flushBuffer(); - } - - public void write(byte[] b) throws IOException { - write(b, 0, b.length); - } - - public Message createTemplate(String messageID) { - Message template = new Message(userID); - template.setPacketID(messageID); - return template; - } - } - - private class IBBInputStream extends InputStream implements PacketListener { - - private String streamID; - - private PacketCollector dataCollector; - - private byte[] buffer; - - private int bufferPointer; - - private int seq = -1; - - private boolean isDone; - - private boolean isEOF; - - private boolean isClosed; - - private IQ closeConfirmation; - - private Message lastMess; - - private IBBInputStream(String streamID, PacketFilter dataFilter, - PacketFilter closeFilter) { - this.streamID = streamID; - this.dataCollector = connection.createPacketCollector(dataFilter); - connection.addPacketListener(this, closeFilter); - this.bufferPointer = -1; - } - - public synchronized int read() throws IOException { - if (isEOF || isClosed) { - return -1; - } - if (bufferPointer == -1 || bufferPointer >= buffer.length) { - loadBufferWait(); - } - - return (int) buffer[bufferPointer++]; - } - - public synchronized int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - public synchronized int read(byte[] b, int off, int len) - throws IOException { - if (isEOF || isClosed) { - return -1; - } - if (bufferPointer == -1 || bufferPointer >= buffer.length) { - if (!loadBufferWait()) { - isEOF = true; - return -1; - } - } - - if (len - off > buffer.length - bufferPointer) { - len = buffer.length - bufferPointer; - } - - System.arraycopy(buffer, bufferPointer, b, off, len); - bufferPointer += len; - return len; - } - - private boolean loadBufferWait() throws IOException { - IBBExtensions.Data data; - - Message mess = null; - while (mess == null) { - if (isDone) { - mess = (Message) dataCollector.pollResult(); - if (mess == null) { - return false; - } - } - else { - mess = (Message) dataCollector.nextResult(1000); - } - } - lastMess = mess; - data = (IBBExtensions.Data) mess.getExtension( - IBBExtensions.Data.ELEMENT_NAME, - IBBExtensions.NAMESPACE); - - checkSequence(mess, (int) data.getSeq()); - buffer = StringUtils.decodeBase64(data.getData()); - bufferPointer = 0; - return true; - } - - private void checkSequence(Message mess, int seq) throws IOException { - if (this.seq == 65535) { - this.seq = -1; - } - if (seq - 1 != this.seq) { - cancelTransfer(mess); - throw new IOException("Packets out of sequence"); - } - else { - this.seq = seq; - } - } - - private void cancelTransfer(Message mess) { - cleanup(); - - sendCancelMessage(mess); - } - - private void cleanup() { - dataCollector.cancel(); - connection.removePacketListener(this); - } - - private void sendCancelMessage(Message message) { - IQ error = FileTransferNegotiator.createIQ(message.getPacketID(), message.getFrom(), message.getTo(), - IQ.Type.ERROR); - error.setError(new XMPPError(XMPPError.Condition.remote_server_timeout, "Cancel Message Transfer")); - connection.sendPacket(error); - } - - public boolean markSupported() { - return false; - } - - public void processPacket(Packet packet) { - IBBExtensions.Close close = (IBBExtensions.Close) packet; - if (close.getSessionID().equals(streamID)) { - isDone = true; - closeConfirmation = FileTransferNegotiator.createIQ(packet - .getPacketID(), packet.getFrom(), packet.getTo(), - IQ.Type.RESULT); - } - } - - public synchronized void close() throws IOException { - if (isClosed) { - return; - } - cleanup(); - - if (isEOF) { - sendCloseConfirmation(); - } - else if (lastMess != null) { - sendCancelMessage(lastMess); - } - isClosed = true; - } - - private void sendCloseConfirmation() { - connection.sendPacket(closeConfirmation); - } - } - - private static class IBBOpenSidFilter implements PacketFilter { - - private String sessionID; - - public IBBOpenSidFilter(String sessionID) { - if (sessionID == null) { - throw new IllegalArgumentException("StreamID cannot be null"); - } - this.sessionID = sessionID; - } - - public boolean accept(Packet packet) { - if (!IBBExtensions.Open.class.isInstance(packet)) { - return false; - } - IBBExtensions.Open open = (IBBExtensions.Open) packet; - String sessionID = open.getSessionID(); - - return (sessionID != null && sessionID.equals(this.sessionID)); - } - } - - private static class IBBMessageSidFilter implements PacketFilter { - - private final String sessionID; - private String from; - - public IBBMessageSidFilter(String from, String sessionID) { - this.from = from; - this.sessionID = sessionID; - } - - public boolean accept(Packet packet) { - if (!(packet instanceof Message)) { - return false; - } - if (!packet.getFrom().equalsIgnoreCase(from)) { - return false; - } - - IBBExtensions.Data data = (IBBExtensions.Data) packet. - getExtension(IBBExtensions.Data.ELEMENT_NAME, IBBExtensions.NAMESPACE); - return data != null && data.getSessionID() != null - && data.getSessionID().equalsIgnoreCase(sessionID); - } - } - -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/IncomingFileTransfer.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/IncomingFileTransfer.java deleted file mode 100644 index da20e0c24..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/IncomingFileTransfer.java +++ /dev/null @@ -1,219 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.XMPPException; - -import java.io.*; -import java.util.concurrent.*; - -/** - * An incoming file transfer is created when the - * {@link FileTransferManager#createIncomingFileTransfer(FileTransferRequest)} - * method is invoked. It is a file being sent to the local user from another - * user on the jabber network. There are two stages of the file transfer to be - * concerned with and they can be handled in different ways depending upon the - * method that is invoked on this class. - *

- * The first way that a file is recieved is by calling the - * {@link #recieveFile()} method. This method, negotiates the appropriate stream - * method and then returns the InputStream to read the file - * data from. - *

- * The second way that a file can be recieved through this class is by invoking - * the {@link #recieveFile(File)} method. This method returns immediatly and - * takes as its parameter a file on the local file system where the file - * recieved from the transfer will be put. - * - * @author Alexander Wenckus - */ -public class IncomingFileTransfer extends FileTransfer { - - private FileTransferRequest recieveRequest; - - private InputStream inputStream; - - protected IncomingFileTransfer(FileTransferRequest request, - FileTransferNegotiator transferNegotiator) { - super(request.getRequestor(), request.getStreamID(), transferNegotiator); - this.recieveRequest = request; - } - - /** - * Negotiates the stream method to transfer the file over and then returns - * the negotiated stream. - * - * @return The negotiated InputStream from which to read the data. - * @throws XMPPException If there is an error in the negotiation process an exception - * is thrown. - */ - public InputStream recieveFile() throws XMPPException { - if (inputStream != null) { - throw new IllegalStateException("Transfer already negotiated!"); - } - - try { - inputStream = negotiateStream(); - } - catch (XMPPException e) { - setException(e); - throw e; - } - - return inputStream; - } - - /** - * This method negotitates the stream and then transfer's the file over the - * negotiated stream. The transfered file will be saved at the provided - * location. - *

- * This method will return immedialtly, file transfer progress can be - * monitored through several methods: - *

- *

    - *
  • {@link FileTransfer#getStatus()} - *
  • {@link FileTransfer#getProgress()} - *
  • {@link FileTransfer#isDone()} - *
- * - * @param file The location to save the file. - * @throws XMPPException when the file transfer fails - * @throws IllegalArgumentException This exception is thrown when the the provided file is - * either null, or cannot be written to. - */ - public void recieveFile(final File file) throws XMPPException { - if (file != null) { - if (!file.exists()) { - try { - file.createNewFile(); - } - catch (IOException e) { - throw new XMPPException( - "Could not create file to write too", e); - } - } - if (!file.canWrite()) { - throw new IllegalArgumentException("Cannot write to provided file"); - } - } - else { - throw new IllegalArgumentException("File cannot be null"); - } - - Thread transferThread = new Thread(new Runnable() { - public void run() { - try { - inputStream = negotiateStream(); - } - catch (XMPPException e) { - handleXMPPException(e); - return; - } - - OutputStream outputStream = null; - try { - outputStream = new FileOutputStream(file); - setStatus(Status.in_progress); - writeToStream(inputStream, outputStream); - } - catch (XMPPException e) { - setStatus(Status.error); - setError(Error.stream); - setException(e); - } - catch (FileNotFoundException e) { - setStatus(Status.error); - setError(Error.bad_file); - setException(e); - } - - if (getStatus().equals(Status.in_progress)) { - setStatus(Status.complete); - } - if (inputStream != null) { - try { - inputStream.close(); - } - catch (Throwable io) { - /* Ignore */ - } - } - if (outputStream != null) { - try { - outputStream.close(); - } - catch (Throwable io) { - /* Ignore */ - } - } - } - }, "File Transfer " + streamID); - transferThread.start(); - } - - private void handleXMPPException(XMPPException e) { - setStatus(FileTransfer.Status.error); - setException(e); - } - - private InputStream negotiateStream() throws XMPPException { - setStatus(Status.negotiating_transfer); - final StreamNegotiator streamNegotiator = negotiator - .selectStreamNegotiator(recieveRequest); - setStatus(Status.negotiating_stream); - FutureTask streamNegotiatorTask = new FutureTask( - new Callable() { - - public InputStream call() throws Exception { - System.out.println(new java.util.Date().toString() + ": IncomingFileTransfer>negotiateStream:186"); - return streamNegotiator - .createIncomingStream(recieveRequest.getStreamInitiation()); - } - }); - streamNegotiatorTask.run(); - InputStream inputStream = null; - try { - System.out.println(new java.util.Date().toString() + ": IncomingFileTransfer>negotiateStream:194"); - inputStream = streamNegotiatorTask.get(15, TimeUnit.SECONDS); - System.out.println(new java.util.Date().toString() + ": IncomingFileTransfer>negotiateStream:196"); - } - catch (InterruptedException e) { - // throw new XMPPException("Interruption while executing", e); - } - catch (ExecutionException e) { - System.out.println(new java.util.Date().toString() + ": IncomingFileTransfer>negotiateStream:202 Error in execution"); - // throw new XMPPException("Error in execution", e); - } - catch (TimeoutException e) { - // throw new XMPPException("Request timed out", e); - } - finally { - streamNegotiatorTask.cancel(true); - } - setStatus(Status.negotiated); - return inputStream; - } - - public void cancel() { - setStatus(Status.cancelled); - } - -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/OutgoingFileTransfer.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/OutgoingFileTransfer.java deleted file mode 100644 index f5ef15293..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/OutgoingFileTransfer.java +++ /dev/null @@ -1,387 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.packet.XMPPError; - -import java.io.*; - -/** - * Handles the sending of a file to another user. File transfer's in jabber have - * several steps and there are several methods in this class that handle these - * steps differently. - * - * @author Alexander Wenckus - * - */ -public class OutgoingFileTransfer extends FileTransfer { - - private static int RESPONSE_TIMEOUT = 60 * 1000; - private NegotiationProgress callback; - - /** - * Returns the time in milliseconds after which the file transfer - * negotiation process will timeout if the other user has not responded. - * - * @return Returns the time in milliseconds after which the file transfer - * negotiation process will timeout if the remote user has not - * responded. - */ - public static int getResponseTimeout() { - return RESPONSE_TIMEOUT; - } - - /** - * Sets the time in milliseconds after which the file transfer negotiation - * process will timeout if the other user has not responded. - * - * @param responseTimeout - * The timeout time in milliseconds. - */ - public static void setResponseTimeout(int responseTimeout) { - RESPONSE_TIMEOUT = responseTimeout; - } - - private OutputStream outputStream; - - private String initiator; - - private Thread transferThread; - - protected OutgoingFileTransfer(String initiator, String target, - String streamID, FileTransferNegotiator transferNegotiator) { - super(target, streamID, transferNegotiator); - this.initiator = initiator; - } - - protected void setOutputStream(OutputStream stream) { - if (outputStream == null) { - this.outputStream = stream; - } - } - - /** - * Returns the output stream connected to the peer to transfer the file. It - * is only available after it has been succesfully negotiated by the - * {@link StreamNegotiator}. - * - * @return Returns the output stream connected to the peer to transfer the - * file. - */ - protected OutputStream getOutputStream() { - if (getStatus().equals(FileTransfer.Status.negotiated)) { - return outputStream; - } else { - return null; - } - } - - /** - * This method handles the negotiation of the file transfer and the stream, - * it only returns the created stream after the negotiation has been completed. - * - * @param fileName - * The name of the file that will be transmitted. It is - * preferable for this name to have an extension as it will be - * used to determine the type of file it is. - * @param fileSize - * The size in bytes of the file that will be transmitted. - * @param description - * A description of the file that will be transmitted. - * @return The OutputStream that is connected to the peer to transmit the - * file. - * @throws XMPPException - * Thrown if an error occurs during the file transfer - * negotiation process. - */ - public synchronized OutputStream sendFile(String fileName, long fileSize, - String description) throws XMPPException { - if (isDone() || outputStream != null) { - throw new IllegalStateException( - "The negotation process has already" - + " been attempted on this file transfer"); - } - try { - this.outputStream = negotiateStream(fileName, fileSize, description); - } catch (XMPPException e) { - handleXMPPException(e); - throw e; - } - return outputStream; - } - - /** - * This methods handles the transfer and stream negotiation process. It - * returns immediately and its progress will be updated through the - * {@link NegotiationProgress} callback. - * - * @param fileName - * The name of the file that will be transmitted. It is - * preferable for this name to have an extension as it will be - * used to determine the type of file it is. - * @param fileSize - * The size in bytes of the file that will be transmitted. - * @param description - * A description of the file that will be transmitted. - * @param progress - * A callback to monitor the progress of the file transfer - * negotiation process and to retrieve the OutputStream when it - * is complete. - */ - public synchronized void sendFile(final String fileName, - final long fileSize, final String description, - final NegotiationProgress progress) - { - if(progress == null) { - throw new IllegalArgumentException("Callback progress cannot be null."); - } - checkTransferThread(); - if (isDone() || outputStream != null) { - throw new IllegalStateException( - "The negotation process has already" - + " been attempted for this file transfer"); - } - this.callback = progress; - transferThread = new Thread(new Runnable() { - public void run() { - try { - OutgoingFileTransfer.this.outputStream = negotiateStream( - fileName, fileSize, description); - progress.outputStreamEstablished(OutgoingFileTransfer.this.outputStream); - } - catch (XMPPException e) { - handleXMPPException(e); - } - } - }, "File Transfer Negotiation " + streamID); - transferThread.start(); - } - - private void checkTransferThread() { - if (transferThread != null && transferThread.isAlive() || isDone()) { - throw new IllegalStateException( - "File transfer in progress or has already completed."); - } - } - - /** - * This method handles the stream negotiation process and transmits the file - * to the remote user. It returns immediatly and the progress of the file - * transfer can be monitored through several methods: - * - *
    - *
  • {@link FileTransfer#getStatus()} - *
  • {@link FileTransfer#getProgress()} - *
  • {@link FileTransfer#isDone()} - *
- * - * @param file the file to transfer to the remote entity. - * @param description a description for the file to transfer. - * @throws XMPPException - * If there is an error during the negotiation process or the - * sending of the file. - */ - public synchronized void sendFile(final File file, final String description) - throws XMPPException { - checkTransferThread(); - if (file == null || !file.exists() || !file.canRead()) { - throw new IllegalArgumentException("Could not read file"); - } else { - setFileInfo(file.getAbsolutePath(), file.getName(), file.length()); - } - - transferThread = new Thread(new Runnable() { - public void run() { - try { - outputStream = negotiateStream(file.getName(), file - .length(), description); - } catch (XMPPException e) { - handleXMPPException(e); - return; - } - if (outputStream == null) { - return; - } - - if (!updateStatus(Status.negotiated, Status.in_progress)) { - return; - } - - InputStream inputStream = null; - try { - inputStream = new FileInputStream(file); - writeToStream(inputStream, outputStream); - } catch (FileNotFoundException e) { - setStatus(FileTransfer.Status.error); - setError(Error.bad_file); - setException(e); - } catch (XMPPException e) { - setStatus(FileTransfer.Status.error); - setException(e); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - - outputStream.flush(); - outputStream.close(); - } catch (IOException e) { - /* Do Nothing */ - } - } - updateStatus(Status.in_progress, FileTransfer.Status.complete); - } - - }, "File Transfer " + streamID); - transferThread.start(); - } - - private void handleXMPPException(XMPPException e) { - XMPPError error = e.getXMPPError(); - if (error != null) { - int code = error.getCode(); - if (code == 403) { - setStatus(Status.refused); - return; - } - else if (code == 400) { - setStatus(Status.error); - setError(Error.not_acceptable); - } - else { - setStatus(FileTransfer.Status.error); - } - } - - setException(e); - } - - /** - * Returns the amount of bytes that have been sent for the file transfer. Or - * -1 if the file transfer has not started. - *

- * Note: This method is only useful when the {@link #sendFile(File, String)} - * method is called, as it is the only method that actualy transmits the - * file. - * - * @return Returns the amount of bytes that have been sent for the file - * transfer. Or -1 if the file transfer has not started. - */ - public long getBytesSent() { - return amountWritten; - } - - private OutputStream negotiateStream(String fileName, long fileSize, - String description) throws XMPPException { - // Negotiate the file transfer profile - - if (!updateStatus(Status.initial, Status.negotiating_transfer)) { - throw new XMPPException("Illegal state change"); - } - StreamNegotiator streamNegotiator = negotiator.negotiateOutgoingTransfer( - getPeer(), streamID, fileName, fileSize, description, - RESPONSE_TIMEOUT); - - if (streamNegotiator == null) { - setStatus(Status.error); - setError(Error.no_response); - return null; - } - - // Negotiate the stream - if (!updateStatus(Status.negotiating_transfer, Status.negotiating_stream)) { - throw new XMPPException("Illegal state change"); - } - outputStream = streamNegotiator.createOutgoingStream(streamID, - initiator, getPeer()); - - if (!updateStatus(Status.negotiating_stream, Status.negotiated)) { - throw new XMPPException("Illegal state change"); - } - return outputStream; - } - - public void cancel() { - setStatus(Status.cancelled); - } - - @Override - protected boolean updateStatus(Status oldStatus, Status newStatus) { - boolean isUpdated = super.updateStatus(oldStatus, newStatus); - if(callback != null && isUpdated) { - callback.statusUpdated(oldStatus, newStatus); - } - return isUpdated; - } - - @Override - protected void setStatus(Status status) { - Status oldStatus = getStatus(); - super.setStatus(status); - if(callback != null) { - callback.statusUpdated(oldStatus, status); - } - } - - @Override - protected void setException(Exception exception) { - super.setException(exception); - if(callback != null) { - callback.errorEstablishingStream(exception); - } - } - - /** - * A callback class to retrive the status of an outgoing transfer - * negotiation process. - * - * @author Alexander Wenckus - * - */ - public interface NegotiationProgress { - - /** - * Called when the status changes - * - * @param oldStatus the previous status of the file transfer. - * @param newStatus the new status of the file transfer. - */ - void statusUpdated(Status oldStatus, Status newStatus); - - /** - * Once the negotiation process is completed the output stream can be - * retrieved. - * - * @param stream the established stream which can be used to transfer the file to the remote - * entity - */ - void outputStreamEstablished(OutputStream stream); - - /** - * Called when an exception occurs during the negotiation progress. - * - * @param e the exception that occured. - */ - void errorEstablishingStream(Exception e); - } - -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/Socks5TransferNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/Socks5TransferNegotiator.java deleted file mode 100644 index a98771292..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/Socks5TransferNegotiator.java +++ /dev/null @@ -1,576 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.PacketCollector; -import org.jivesoftware.smack.SmackConfiguration; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.filter.AndFilter; -import org.jivesoftware.smack.filter.FromMatchesFilter; -import org.jivesoftware.smack.filter.PacketFilter; -import org.jivesoftware.smack.filter.PacketIDFilter; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.packet.XMPPError; -import org.jivesoftware.smack.util.StringUtils; -import org.jivesoftware.smackx.packet.Bytestream; -import org.jivesoftware.smackx.packet.Bytestream.StreamHost; -import org.jivesoftware.smackx.packet.Bytestream.StreamHostUsed; -import org.jivesoftware.smackx.packet.StreamInitiation; - -import java.io.*; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.Iterator; -import java.util.Date; - -/** - * A SOCKS5 bytestream is negotiated partly over the XMPP XML stream and partly - * over a seperate socket. The actual transfer though takes place over a - * seperatly created socket. - *

- * A SOCKS5 file transfer generally has three parites, the initiator, the - * target, and the stream host. The stream host is a specialized SOCKS5 proxy - * setup on the server, or, the Initiator can act as the Stream Host if the - * proxy is not available. - *

- * The advantage of having a seperate proxy over directly connecting to - * eachother is if the Initator and the Target are not on the same LAN and are - * operating behind NAT, the proxy allows for a common location for both parties - * to connect to and transfer the file. - *

- * Smack will attempt to automatically discover any proxies present on your - * server. If any are detected they will be forwarded to any user attempting to - * recieve files from you. - * - * @author Alexander Wenckus - * @see JEP-0065: SOCKS5 - * Bytestreams - */ -public class Socks5TransferNegotiator extends StreamNegotiator { - - protected static final String NAMESPACE = "http://jabber.org/protocol/bytestreams"; - - /** - * The number of connection failures it takes to a streamhost for that particular streamhost - * to be blacklisted. When a host is blacklisted no more connection attempts will be made to - * it for a period of 2 hours. - */ - private static final int CONNECT_FAILURE_THRESHOLD = 2; - - public static boolean isAllowLocalProxyHost = true; - - private final XMPPConnection connection; - - private Socks5TransferNegotiatorManager transferNegotiatorManager; - - public Socks5TransferNegotiator(Socks5TransferNegotiatorManager transferNegotiatorManager, - final XMPPConnection connection) - { - this.connection = connection; - this.transferNegotiatorManager = transferNegotiatorManager; - } - - public PacketFilter getInitiationPacketFilter(String from, String sessionID) { - return new AndFilter(new FromMatchesFilter(from), - new BytestreamSIDFilter(sessionID)); - } - - /* - * (non-Javadoc) - * - * @see org.jivesoftware.smackx.filetransfer.StreamNegotiator#initiateDownload( - * org.jivesoftware.smackx.packet.StreamInitiation, java.io.File) - */ - InputStream negotiateIncomingStream(Packet streamInitiation) - throws XMPPException { - Bytestream streamHostsInfo = (Bytestream) streamInitiation; - - if (streamHostsInfo.getType().equals(IQ.Type.ERROR)) { - throw new XMPPException(streamHostsInfo.getError()); - } - SelectedHostInfo selectedHost; - try { - // select appropriate host - System.out.println(new java.util.Date().toString() + ": Socks5TransferNegotiator>negotiateIncomingStream:115"); - selectedHost = selectHost(streamHostsInfo); - System.out.println(new java.util.Date().toString() + ": Socks5TransferNegotiator>negotiateIncomingStream:117"); - } - catch (XMPPException ex) { - if (ex.getXMPPError() != null) { - IQ errorPacket = super.createError(streamHostsInfo.getTo(), - streamHostsInfo.getFrom(), streamHostsInfo.getPacketID(), - ex.getXMPPError()); - connection.sendPacket(errorPacket); - } - throw (ex); - } - - // send used-host confirmation - Bytestream streamResponse = createUsedHostConfirmation( - selectedHost.selectedHost, streamHostsInfo.getFrom(), - streamHostsInfo.getTo(), streamHostsInfo.getPacketID()); - connection.sendPacket(streamResponse); - - try { - PushbackInputStream stream = new PushbackInputStream( - selectedHost.establishedSocket.getInputStream()); - int firstByte = stream.read(); - stream.unread(firstByte); - return stream; - } - catch (IOException e) { - throw new XMPPException("Error establishing input stream", e); - } - - } - - public InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException { - Packet streamInitiation = initiateIncomingStream(connection, initiation); - return negotiateIncomingStream(streamInitiation); - } - - /** - * The used host confirmation is sent to the initiator to indicate to them - * which of the hosts they provided has been selected and successfully - * connected to. - * - * @param selectedHost The selected stream host. - * @param initiator The initiator of the stream. - * @param target The target of the stream. - * @param packetID The of the packet being responded to. - * @return The packet that was created to send to the initiator. - */ - private Bytestream createUsedHostConfirmation(StreamHost selectedHost, - String initiator, String target, String packetID) { - Bytestream streamResponse = new Bytestream(); - streamResponse.setTo(initiator); - streamResponse.setFrom(target); - streamResponse.setType(IQ.Type.RESULT); - streamResponse.setPacketID(packetID); - streamResponse.setUsedHost(selectedHost.getJID()); - return streamResponse; - } - - /** - * Selects a host to connect to over which the file will be transmitted. - * - * @param streamHostsInfo the packet recieved from the initiator containing the available hosts - * to transfer the file - * @return the selected host and socket that were created. - * @throws XMPPException when there is no appropriate host. - */ - private SelectedHostInfo selectHost(Bytestream streamHostsInfo) - throws XMPPException { - Iterator it = streamHostsInfo.getStreamHosts().iterator(); - StreamHost selectedHost = null; - Socket socket = null; - while (it.hasNext()) { - selectedHost = (StreamHost) it.next(); - String address = selectedHost.getAddress(); - - // Check to see if this address has been blacklisted - int failures = getConnectionFailures(address); - if (failures >= CONNECT_FAILURE_THRESHOLD) { - continue; - } - // establish socket - try { - socket = new Socket(address, selectedHost - .getPort()); - establishSOCKS5ConnectionToProxy(socket, createDigest( - streamHostsInfo.getSessionID(), streamHostsInfo - .getFrom(), streamHostsInfo.getTo())); - break; - } - catch (IOException e) { - e.printStackTrace(); - incrementConnectionFailures(address); - selectedHost = null; - socket = null; - } - } - if (selectedHost == null || socket == null || !socket.isConnected()) { - String errorMessage = "Could not establish socket with any provided host"; - throw new XMPPException(errorMessage, new XMPPError( - XMPPError.Condition.no_acceptable, errorMessage)); - } - - return new SelectedHostInfo(selectedHost, socket); - } - - private void incrementConnectionFailures(String address) { - transferNegotiatorManager.incrementConnectionFailures(address); - } - - private int getConnectionFailures(String address) { - return transferNegotiatorManager.getConnectionFailures(address); - } - - /** - * Creates the digest needed for a byte stream. It is the SHA1(sessionID + - * initiator + target). - * - * @param sessionID The sessionID of the stream negotiation - * @param initiator The inititator of the stream negotiation - * @param target The target of the stream negotiation - * @return SHA-1 hash of the three parameters - */ - private String createDigest(final String sessionID, final String initiator, - final String target) { - return StringUtils.hash(sessionID + StringUtils.parseName(initiator) - + "@" + StringUtils.parseServer(initiator) + "/" - + StringUtils.parseResource(initiator) - + StringUtils.parseName(target) + "@" - + StringUtils.parseServer(target) + "/" - + StringUtils.parseResource(target)); - } - - /* - * (non-Javadoc) - * - * @see org.jivesoftware.smackx.filetransfer.StreamNegotiator#initiateUpload(java.lang.String, - * org.jivesoftware.smackx.packet.StreamInitiation, java.io.File) - */ - public OutputStream createOutgoingStream(String streamID, String initiator, - String target) throws XMPPException - { - Socket socket; - try { - socket = initBytestreamSocket(streamID, initiator, target); - } - catch (Exception e) { - throw new XMPPException("Error establishing transfer socket", e); - } - - if (socket != null) { - try { - return new BufferedOutputStream(socket.getOutputStream()); - } - catch (IOException e) { - throw new XMPPException("Error establishing output stream", e); - } - } - return null; - } - - private Socket initBytestreamSocket(final String sessionID, - String initiator, String target) throws Exception { - Socks5TransferNegotiatorManager.ProxyProcess process; - try { - process = establishListeningSocket(); - } - catch (IOException io) { - process = null; - } - - Socket conn; - try { - String localIP; - try { - localIP = discoverLocalIP(); - } - catch (UnknownHostException e1) { - localIP = null; - } - - Bytestream query = createByteStreamInit(initiator, target, sessionID, - localIP, (process != null ? process.getPort() : 0)); - - // if the local host is one of the options we need to wait for the - // remote connection. - conn = waitForUsedHostResponse(sessionID, process, createDigest( - sessionID, initiator, target), query).establishedSocket; - } - finally { - cleanupListeningSocket(); - } - - return conn; - } - - - /** - * Waits for the peer to respond with which host they chose to use. - * - * @param sessionID The session id of the stream. - * @param proxy The server socket which will listen locally for remote - * connections. - * @param digest the digest of the userids and the session id - * @param query the query which the response is being awaited - * @return the selected host - * @throws XMPPException when the response from the peer is an error or doesn't occur - * @throws IOException when there is an error establishing the local socket - */ - private SelectedHostInfo waitForUsedHostResponse(String sessionID, - final Socks5TransferNegotiatorManager.ProxyProcess proxy, final String digest, - final Bytestream query) throws XMPPException, IOException - { - SelectedHostInfo info = new SelectedHostInfo(); - - PacketCollector collector = connection - .createPacketCollector(new PacketIDFilter(query.getPacketID())); - connection.sendPacket(query); - - Packet packet = collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); - collector.cancel(); - Bytestream response; - if (packet != null && packet instanceof Bytestream) { - response = (Bytestream) packet; - } - else { - throw new XMPPException("Unexpected response from remote user"); - } - - // check for an error - if (response.getType().equals(IQ.Type.ERROR)) { - throw new XMPPException("Remote client returned error, stream hosts expected", - response.getError()); - } - - StreamHostUsed used = response.getUsedHost(); - StreamHost usedHost = query.getStreamHost(used.getJID()); - if (usedHost == null) { - throw new XMPPException("Remote user responded with unknown host"); - } - // The local computer is acting as the proxy - if (used.getJID().equals(query.getFrom())) { - info.establishedSocket = proxy.getSocket(digest); - info.selectedHost = usedHost; - return info; - } - else { - info.establishedSocket = new Socket(usedHost.getAddress(), usedHost - .getPort()); - establishSOCKS5ConnectionToProxy(info.establishedSocket, digest); - - Bytestream activate = createByteStreamActivate(sessionID, response - .getTo(), usedHost.getJID(), response.getFrom()); - - collector = connection.createPacketCollector(new PacketIDFilter( - activate.getPacketID())); - connection.sendPacket(activate); - - IQ serverResponse = (IQ) collector.nextResult(SmackConfiguration - .getPacketReplyTimeout()); - collector.cancel(); - if (!serverResponse.getType().equals(IQ.Type.RESULT)) { - info.establishedSocket.close(); - return null; - } - return info; - } - } - - private Socks5TransferNegotiatorManager.ProxyProcess establishListeningSocket() - throws IOException { - return transferNegotiatorManager.addTransfer(); - } - - private void cleanupListeningSocket() { - transferNegotiatorManager.removeTransfer(); - } - - private String discoverLocalIP() throws UnknownHostException { - return InetAddress.getLocalHost().getHostAddress(); - } - - /** - * The bytestream init looks like this: - *

- *

-     * <iq type='set'
-     *     from='initiator@host1/foo'
-     *     to='target@host2/bar'
-     *     id='initiate'>
-     *   <query xmlns='http://jabber.org/protocol/bytestreams'
-     *          sid='mySID'
-     * 	 mode='tcp'>
-     *     <streamhost
-     *         jid='initiator@host1/foo'
-     *         host='192.168.4.1'
-     *        port='5086'/>
-     *     <streamhost
-     *         jid='proxy.host3'
-     *         host='24.24.24.1'
-     *         zeroconf='_jabber.bytestreams'/>
-     *   </query>
-     * </iq>
-     * 
- * - * @param from initiator@host1/foo - the file transfer initiator. - * @param to target@host2/bar - the file transfer target. - * @param sid 'mySID' - the unique identifier for this file transfer - * @param localIP the IP of the local machine if it is being provided, null otherwise. - * @param port the port of the local mahine if it is being provided, null otherwise. - * @return the created Bytestream packet - */ - private Bytestream createByteStreamInit(final String from, final String to, - final String sid, final String localIP, final int port) - { - Bytestream bs = new Bytestream(); - bs.setTo(to); - bs.setFrom(from); - bs.setSessionID(sid); - bs.setType(IQ.Type.SET); - bs.setMode(Bytestream.Mode.tcp); - if (localIP != null && port > 0) { - bs.addStreamHost(from, localIP, port); - } - // make sure the proxies have been initialized completely - Collection streamHosts = transferNegotiatorManager.getStreamHosts(); - - if (streamHosts != null) { - for (StreamHost host : streamHosts) { - bs.addStreamHost(host); - } - } - - return bs; - } - - - /** - * Returns the packet to send notification to the stream host to activate - * the stream. - * - * @param sessionID the session ID of the file transfer to activate. - * @param from the sender of the bytestreeam - * @param to the JID of the stream host - * @param target the JID of the file transfer target. - * @return the packet to send notification to the stream host to - * activate the stream. - */ - private static Bytestream createByteStreamActivate(final String sessionID, - final String from, final String to, final String target) - { - Bytestream activate = new Bytestream(sessionID); - activate.setMode(null); - activate.setToActivate(target); - activate.setFrom(from); - activate.setTo(to); - activate.setType(IQ.Type.SET); - return activate; - } - - public String[] getNamespaces() { - return new String[]{NAMESPACE}; - } - - private void establishSOCKS5ConnectionToProxy(Socket socket, String digest) - throws IOException { - - byte[] cmd = new byte[3]; - - cmd[0] = (byte) 0x05; - cmd[1] = (byte) 0x01; - cmd[2] = (byte) 0x00; - - OutputStream out = new DataOutputStream(socket.getOutputStream()); - out.write(cmd); - - InputStream in = new DataInputStream(socket.getInputStream()); - byte[] response = new byte[2]; - - in.read(response); - - cmd = createOutgoingSocks5Message(1, digest); - out.write(cmd); - createIncomingSocks5Message(in); - } - - static String createIncomingSocks5Message(InputStream in) - throws IOException { - byte[] cmd = new byte[5]; - in.read(cmd, 0, 5); - - byte[] addr = new byte[cmd[4]]; - in.read(addr, 0, addr.length); - String digest = new String(addr); - in.read(); - in.read(); - - return digest; - } - - static byte[] createOutgoingSocks5Message(int cmd, String digest) { - byte addr[] = digest.getBytes(); - - byte[] data = new byte[7 + addr.length]; - data[0] = (byte) 5; - data[1] = (byte) cmd; - data[2] = (byte) 0; - data[3] = (byte) 0x3; - data[4] = (byte) addr.length; - - System.arraycopy(addr, 0, data, 5, addr.length); - data[data.length - 2] = (byte) 0; - data[data.length - 1] = (byte) 0; - - return data; - } - - public void cleanup() { - - } - - private static class SelectedHostInfo { - - protected XMPPException exception; - - protected StreamHost selectedHost; - - protected Socket establishedSocket; - - SelectedHostInfo(StreamHost selectedHost, Socket establishedSocket) { - this.selectedHost = selectedHost; - this.establishedSocket = establishedSocket; - } - - public SelectedHostInfo() { - } - } - - - private static class BytestreamSIDFilter implements PacketFilter { - - private String sessionID; - - public BytestreamSIDFilter(String sessionID) { - if (sessionID == null) { - throw new IllegalArgumentException("StreamID cannot be null"); - } - this.sessionID = sessionID; - } - - public boolean accept(Packet packet) { - if (!Bytestream.class.isInstance(packet)) { - return false; - } - Bytestream bytestream = (Bytestream) packet; - String sessionID = bytestream.getSessionID(); - - return (sessionID != null && sessionID.equals(this.sessionID)); - } - } -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/Socks5TransferNegotiatorManager.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/Socks5TransferNegotiatorManager.java deleted file mode 100644 index 35f2c3509..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/Socks5TransferNegotiatorManager.java +++ /dev/null @@ -1,388 +0,0 @@ -/** - * $Revision:$ - * $Date:$ - * - * Copyright 2003-2007 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.util.Cache; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.PacketCollector; -import org.jivesoftware.smack.SmackConfiguration; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.filter.PacketIDFilter; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.ServiceDiscoveryManager; -import org.jivesoftware.smackx.packet.DiscoverItems; -import org.jivesoftware.smackx.packet.Bytestream; -import org.jivesoftware.smackx.packet.DiscoverInfo; - -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.util.*; -import java.io.*; - -/** - * - */ -public class Socks5TransferNegotiatorManager implements FileTransferNegotiatorManager { - - private static final long BLACKLIST_LIFETIME = 60 * 1000 * 120; - // locks the proxies during their initialization process - private final Object proxyLock = new Object(); - - private static ProxyProcess proxyProcess; - - // locks on the proxy process during its initiatilization process - private final Object processLock = new Object(); - - private final Cache addressBlacklist - = new Cache(100, BLACKLIST_LIFETIME); - - private XMPPConnection connection; - - private List proxies; - - private List streamHosts; - - public Socks5TransferNegotiatorManager(XMPPConnection connection) { - this.connection = connection; - } - - public StreamNegotiator createNegotiator() { - return new Socks5TransferNegotiator(this, connection); - } - - public void incrementConnectionFailures(String address) { - Integer count = addressBlacklist.get(address); - if (count == null) { - count = 1; - } - else { - count += 1; - } - addressBlacklist.put(address, count); - } - - public int getConnectionFailures(String address) { - Integer count = addressBlacklist.get(address); - return count != null ? count : 0; - } - - public ProxyProcess addTransfer() throws IOException { - synchronized (processLock) { - if (proxyProcess == null) { - proxyProcess = new ProxyProcess(new ServerSocket(7777)); - proxyProcess.start(); - } - } - proxyProcess.addTransfer(); - return proxyProcess; - } - - public void removeTransfer() { - if (proxyProcess == null) { - return; - } - proxyProcess.removeTransfer(); - } - - public Collection getStreamHosts() { - synchronized (proxyLock) { - if (proxies == null) { - initProxies(); - } - } - return Collections.unmodifiableCollection(streamHosts); - } - - /** - * Checks the service discovery item returned from a server component to verify if it is - * a File Transfer proxy or not. - * - * @param manager the service discovery manager which will be used to query the component - * @param item the discovered item on the server relating - * @return returns the JID of the proxy if it is a proxy or null if the item is not a proxy. - */ - private String checkIsProxy(ServiceDiscoveryManager manager, DiscoverItems.Item item) { - DiscoverInfo info; - try { - info = manager.discoverInfo(item.getEntityID()); - } - catch (XMPPException e) { - return null; - } - Iterator itx = info.getIdentities(); - while (itx.hasNext()) { - DiscoverInfo.Identity identity = (DiscoverInfo.Identity) itx.next(); - if ("proxy".equalsIgnoreCase(identity.getCategory()) - && "bytestreams".equalsIgnoreCase( - identity.getType())) { - return info.getFrom(); - } - } - return null; - } - - private void initProxies() { - proxies = new ArrayList(); - ServiceDiscoveryManager manager = ServiceDiscoveryManager - .getInstanceFor(connection); - try { - DiscoverItems discoItems = manager.discoverItems(connection.getServiceName()); - Iterator it = discoItems.getItems(); - while (it.hasNext()) { - DiscoverItems.Item item = (DiscoverItems.Item) it.next(); - String proxy = checkIsProxy(manager, item); - if (proxy != null) { - proxies.add(proxy); - } - } - } - catch (XMPPException e) { - return; - } - if (proxies.size() > 0) { - initStreamHosts(); - } - } - - /** - * Loads streamhost address and ports from the proxies on the local server. - */ - private void initStreamHosts() { - List streamHosts = new ArrayList(); - Iterator it = proxies.iterator(); - IQ query; - PacketCollector collector; - Bytestream response; - while (it.hasNext()) { - String jid = it.next().toString(); - query = new IQ() { - public String getChildElementXML() { - return ""; - } - }; - query.setType(IQ.Type.GET); - query.setTo(jid); - - collector = connection.createPacketCollector(new PacketIDFilter( - query.getPacketID())); - connection.sendPacket(query); - - response = (Bytestream) collector.nextResult(SmackConfiguration - .getPacketReplyTimeout()); - if (response != null) { - streamHosts.addAll(response.getStreamHosts()); - } - collector.cancel(); - } - this.streamHosts = streamHosts; - } - - public void cleanup() { - synchronized (processLock) { - if (proxyProcess != null) { - proxyProcess.stop(); - proxyProcess = null; - } - } - } - - class ProxyProcess implements Runnable { - - private final ServerSocket listeningSocket; - - private final Map connectionMap = new HashMap(); - - private boolean done = false; - - private Thread thread; - private int transfers; - - public void run() { - try { - try { - listeningSocket.setSoTimeout(10000); - } - catch (SocketException e) { - // There was a TCP error, lets print the stack trace - e.printStackTrace(); - return; - } - while (!done) { - Socket conn = null; - synchronized (ProxyProcess.this) { - while (transfers <= 0 && !done) { - transfers = -1; - try { - ProxyProcess.this.wait(); - } - catch (InterruptedException e) { - /* Do nothing */ - } - } - } - if (done) { - break; - } - try { - synchronized (listeningSocket) { - conn = listeningSocket.accept(); - } - if (conn == null) { - continue; - } - String digest = establishSocks5UploadConnection(conn); - synchronized (connectionMap) { - connectionMap.put(digest, conn); - } - } - catch (SocketTimeoutException e) { - /* Do Nothing */ - } - catch (IOException e) { - /* Do Nothing */ - } - catch (XMPPException e) { - e.printStackTrace(); - if (conn != null) { - try { - conn.close(); - } - catch (IOException e1) { - /* Do Nothing */ - } - } - } - } - } - finally { - try { - listeningSocket.close(); - } - catch (IOException e) { - /* Do Nothing */ - } - } - } - - /** - * Negotiates the Socks 5 bytestream when the local computer is acting as - * the proxy. - * - * @param connection the socket connection with the peer. - * @return the SHA-1 digest that is used to uniquely identify the file - * transfer. - * @throws XMPPException - * @throws IOException - */ - private String establishSocks5UploadConnection(Socket connection) throws XMPPException, IOException { - OutputStream out = new DataOutputStream(connection.getOutputStream()); - InputStream in = new DataInputStream(connection.getInputStream()); - - // first byte is version should be 5 - int b = in.read(); - if (b != 5) { - throw new XMPPException("Only SOCKS5 supported"); - } - - // second byte number of authentication methods supported - b = in.read(); - int[] auth = new int[b]; - for (int i = 0; i < b; i++) { - auth[i] = in.read(); - } - - int authMethod = -1; - for (int anAuth : auth) { - authMethod = (anAuth == 0 ? 0 : -1); // only auth method - // 0, no - // authentication, - // supported - if (authMethod == 0) { - break; - } - } - if (authMethod != 0) { - throw new XMPPException("Authentication method not supported"); - } - byte[] cmd = new byte[2]; - cmd[0] = (byte) 0x05; - cmd[1] = (byte) 0x00; - out.write(cmd); - - String responseDigest = Socks5TransferNegotiator.createIncomingSocks5Message(in); - cmd = Socks5TransferNegotiator.createOutgoingSocks5Message(0, responseDigest); - - if (!connection.isConnected()) { - throw new XMPPException("Socket closed by remote user"); - } - out.write(cmd); - return responseDigest; - } - - - public void start() { - thread.start(); - } - - public void stop() { - done = true; - synchronized (this) { - this.notify(); - } - synchronized (listeningSocket) { - listeningSocket.notify(); - } - } - - public int getPort() { - return listeningSocket.getLocalPort(); - } - - ProxyProcess(ServerSocket listeningSocket) { - thread = new Thread(this, "File Transfer Connection Listener"); - this.listeningSocket = listeningSocket; - } - - public Socket getSocket(String digest) { - synchronized (connectionMap) { - return connectionMap.get(digest); - } - } - - public void addTransfer() { - synchronized (this) { - if (transfers == -1) { - transfers = 1; - this.notify(); - } - else { - transfers++; - } - } - } - - public void removeTransfer() { - synchronized (this) { - transfers--; - } - } - } -} diff --git a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/StreamNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/StreamNegotiator.java deleted file mode 100644 index f5021a451..000000000 --- a/source/org/jivesoftware/smackx/filetransfer/CopyOffiletransfer/StreamNegotiator.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright 2003-2006 Jive Software. - * - * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.filetransfer; - -import org.jivesoftware.smack.PacketCollector; -import org.jivesoftware.smack.SmackConfiguration; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.filter.PacketFilter; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.packet.XMPPError; -import org.jivesoftware.smackx.Form; -import org.jivesoftware.smackx.FormField; -import org.jivesoftware.smackx.packet.DataForm; -import org.jivesoftware.smackx.packet.StreamInitiation; - -import java.io.InputStream; -import java.io.OutputStream; - -/** - * After the file transfer negotiation process is completed according to - * JEP-0096, the negotation process is passed off to a particular stream - * negotiator. The stream negotiator will then negotiate the chosen stream and - * return the stream to transfer the file. - * - * @author Alexander Wenckus - */ -public abstract class StreamNegotiator { - - /** - * Creates the initiation acceptance packet to forward to the stream - * initiator. - * - * @param streamInitiationOffer The offer from the stream initatior to connect for a stream. - * @param namespaces The namespace that relates to the accepted means of transfer. - * @return The response to be forwarded to the initator. - */ - public StreamInitiation createInitiationAccept( - StreamInitiation streamInitiationOffer, String[] namespaces) - { - StreamInitiation response = new StreamInitiation(); - response.setTo(streamInitiationOffer.getFrom()); - response.setFrom(streamInitiationOffer.getTo()); - response.setType(IQ.Type.RESULT); - response.setPacketID(streamInitiationOffer.getPacketID()); - - DataForm form = new DataForm(Form.TYPE_SUBMIT); - FormField field = new FormField( - FileTransferNegotiator.STREAM_DATA_FIELD_NAME); - for (String namespace : namespaces) { - field.addValue(namespace); - } - form.addField(field); - - response.setFeatureNegotiationForm(form); - return response; - } - - - public IQ createError(String from, String to, String packetID, XMPPError xmppError) { - IQ iq = FileTransferNegotiator.createIQ(packetID, to, from, IQ.Type.ERROR); - iq.setError(xmppError); - return iq; - } - - Packet initiateIncomingStream(XMPPConnection connection, StreamInitiation initiation) throws XMPPException { - StreamInitiation response = createInitiationAccept(initiation, - getNamespaces()); - - // establish collector to await response - PacketCollector collector = connection - .createPacketCollector(getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID())); - connection.sendPacket(response); - - Packet streamMethodInitiation = collector - .nextResult(SmackConfiguration.getPacketReplyTimeout()); - collector.cancel(); - if (streamMethodInitiation == null) { - throw new XMPPException("No response from file transfer initiator"); - } - - return streamMethodInitiation; - } - - /** - * Returns the packet filter that will return the initiation packet for the appropriate stream - * initiation. - * - * @param from The initiatior of the file transfer. - * @param streamID The stream ID related to the transfer. - * @return The PacketFilter that will return the packet relatable to the stream - * initiation. - */ - public abstract PacketFilter getInitiationPacketFilter(String from, String streamID); - - - abstract InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException; - - /** - * This method handles the file stream download negotiation process. The - * appropriate stream negotiator's initiate incoming stream is called after - * an appropriate file transfer method is selected. The manager will respond - * to the initatior with the selected means of transfer, then it will handle - * any negotation specific to the particular transfer method. This method - * returns the InputStream, ready to transfer the file. - * - * @param initiation The initation that triggered this download. - * @return After the negotation process is complete, the InputStream to - * write a file to is returned. - * @throws XMPPException If an error occurs during this process an XMPPException is - * thrown. - */ - public abstract InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException; - - /** - * This method handles the file upload stream negotiation process. The - * particular stream negotiator is determined during the file transfer - * negotiation process. This method returns the OutputStream to transmit the - * file to the remote user. - * - * @param streamID The streamID that uniquely identifies the file transfer. - * @param initiator The fully-qualified JID of the initiator of the file transfer. - * @param target The fully-qualified JID of the target or reciever of the file - * transfer. - * @return The negotiated stream ready for data. - * @throws XMPPException If an error occurs during the negotiation process an - * exception will be thrown. - */ - public abstract OutputStream createOutgoingStream(String streamID, - String initiator, String target) throws XMPPException; - - /** - * Returns the XMPP namespace reserved for this particular type of file - * transfer. - * - * @return Returns the XMPP namespace reserved for this particular type of - * file transfer. - */ - public abstract String[] getNamespaces(); - - /** - * Cleanup any and all resources associated with this negotiator. - */ - public abstract void cleanup(); - -}