/** | |
* $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.InputStream; | |
import java.io.OutputStream; | |
import org.jivesoftware.smack.Connection; | |
import org.jivesoftware.smack.XMPPException; | |
import org.jivesoftware.smack.filter.AndFilter; | |
import org.jivesoftware.smack.filter.FromContainsFilter; | |
import org.jivesoftware.smack.filter.PacketFilter; | |
import org.jivesoftware.smack.filter.PacketTypeFilter; | |
import org.jivesoftware.smack.packet.IQ; | |
import org.jivesoftware.smack.packet.Packet; | |
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager; | |
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest; | |
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession; | |
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open; | |
import org.jivesoftware.smackx.packet.StreamInitiation; | |
/** | |
* 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 transferring files is not available. | |
* | |
* @author Alexander Wenckus | |
* @author Henning Staib | |
* @see <a href="http://xmpp.org/extensions/xep-0047.html">XEP-0047: In-Band | |
* Bytestreams (IBB)</a> | |
*/ | |
public class IBBTransferNegotiator extends StreamNegotiator { | |
private Connection connection; | |
private InBandBytestreamManager manager; | |
/** | |
* The default constructor for the In-Band Bytestream Negotiator. | |
* | |
* @param connection The connection which this negotiator works on. | |
*/ | |
protected IBBTransferNegotiator(Connection connection) { | |
this.connection = connection; | |
this.manager = InBandBytestreamManager.getByteStreamManager(connection); | |
} | |
public OutputStream createOutgoingStream(String streamID, String initiator, | |
String target) throws XMPPException { | |
InBandBytestreamSession session = this.manager.establishSession(target, streamID); | |
session.setCloseBothStreamsEnabled(true); | |
return session.getOutputStream(); | |
} | |
public InputStream createIncomingStream(StreamInitiation initiation) | |
throws XMPPException { | |
/* | |
* In-Band Bytestream initiation listener must ignore next in-band | |
* bytestream request with given session ID | |
*/ | |
this.manager.ignoreBytestreamRequestOnce(initiation.getSessionID()); | |
Packet streamInitiation = initiateIncomingStream(this.connection, initiation); | |
return negotiateIncomingStream(streamInitiation); | |
} | |
public PacketFilter getInitiationPacketFilter(String from, String streamID) { | |
/* | |
* this method is always called prior to #negotiateIncomingStream() so | |
* the In-Band Bytestream initiation listener must ignore the next | |
* In-Band Bytestream request with the given session ID | |
*/ | |
this.manager.ignoreBytestreamRequestOnce(streamID); | |
return new AndFilter(new FromContainsFilter(from), new IBBOpenSidFilter(streamID)); | |
} | |
public String[] getNamespaces() { | |
return new String[] { InBandBytestreamManager.NAMESPACE }; | |
} | |
InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException { | |
// build In-Band Bytestream request | |
InBandBytestreamRequest request = new ByteStreamRequest(this.manager, | |
(Open) streamInitiation); | |
// always accept the request | |
InBandBytestreamSession session = request.accept(); | |
session.setCloseBothStreamsEnabled(true); | |
return session.getInputStream(); | |
} | |
public void cleanup() { | |
} | |
/** | |
* This PacketFilter accepts an incoming In-Band Bytestream open request | |
* with a specified session ID. | |
*/ | |
private static class IBBOpenSidFilter extends PacketTypeFilter { | |
private String sessionID; | |
public IBBOpenSidFilter(String sessionID) { | |
super(Open.class); | |
if (sessionID == null) { | |
throw new IllegalArgumentException("StreamID cannot be null"); | |
} | |
this.sessionID = sessionID; | |
} | |
public boolean accept(Packet packet) { | |
if (super.accept(packet)) { | |
Open bytestream = (Open) packet; | |
// packet must by of type SET and contains the given session ID | |
return this.sessionID.equals(bytestream.getSessionID()) | |
&& IQ.Type.SET.equals(bytestream.getType()); | |
} | |
return false; | |
} | |
} | |
/** | |
* Derive from InBandBytestreamRequest to access protected constructor. | |
*/ | |
private static class ByteStreamRequest extends InBandBytestreamRequest { | |
private ByteStreamRequest(InBandBytestreamManager manager, Open byteStreamRequest) { | |
super(manager, byteStreamRequest); | |
} | |
} | |
} |