Home | History | Annotate | Download | only in filetransfer
      1 /**
      2  * $RCSfile$
      3  * $Revision$
      4  * $Date$
      5  *
      6  * Copyright 2003-2006 Jive Software.
      7  *
      8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *     http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 package org.jivesoftware.smackx.filetransfer;
     21 
     22 import java.io.InputStream;
     23 import java.io.OutputStream;
     24 
     25 import org.jivesoftware.smack.Connection;
     26 import org.jivesoftware.smack.XMPPException;
     27 import org.jivesoftware.smack.filter.AndFilter;
     28 import org.jivesoftware.smack.filter.FromContainsFilter;
     29 import org.jivesoftware.smack.filter.PacketFilter;
     30 import org.jivesoftware.smack.filter.PacketTypeFilter;
     31 import org.jivesoftware.smack.packet.IQ;
     32 import org.jivesoftware.smack.packet.Packet;
     33 import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
     34 import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
     35 import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
     36 import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
     37 import org.jivesoftware.smackx.packet.StreamInitiation;
     38 
     39 /**
     40  * The In-Band Bytestream file transfer method, or IBB for short, transfers the
     41  * file over the same XML Stream used by XMPP. It is the fall-back mechanism in
     42  * case the SOCKS5 bytestream method of transferring files is not available.
     43  *
     44  * @author Alexander Wenckus
     45  * @author Henning Staib
     46  * @see <a href="http://xmpp.org/extensions/xep-0047.html">XEP-0047: In-Band
     47  *      Bytestreams (IBB)</a>
     48  */
     49 public class IBBTransferNegotiator extends StreamNegotiator {
     50 
     51     private Connection connection;
     52 
     53     private InBandBytestreamManager manager;
     54 
     55     /**
     56      * The default constructor for the In-Band Bytestream Negotiator.
     57      *
     58      * @param connection The connection which this negotiator works on.
     59      */
     60     protected IBBTransferNegotiator(Connection connection) {
     61         this.connection = connection;
     62         this.manager = InBandBytestreamManager.getByteStreamManager(connection);
     63     }
     64 
     65     public OutputStream createOutgoingStream(String streamID, String initiator,
     66                     String target) throws XMPPException {
     67         InBandBytestreamSession session = this.manager.establishSession(target, streamID);
     68         session.setCloseBothStreamsEnabled(true);
     69         return session.getOutputStream();
     70     }
     71 
     72     public InputStream createIncomingStream(StreamInitiation initiation)
     73                     throws XMPPException {
     74         /*
     75          * In-Band Bytestream initiation listener must ignore next in-band
     76          * bytestream request with given session ID
     77          */
     78         this.manager.ignoreBytestreamRequestOnce(initiation.getSessionID());
     79 
     80         Packet streamInitiation = initiateIncomingStream(this.connection, initiation);
     81         return negotiateIncomingStream(streamInitiation);
     82     }
     83 
     84     public PacketFilter getInitiationPacketFilter(String from, String streamID) {
     85         /*
     86          * this method is always called prior to #negotiateIncomingStream() so
     87          * the In-Band Bytestream initiation listener must ignore the next
     88          * In-Band Bytestream request with the given session ID
     89          */
     90         this.manager.ignoreBytestreamRequestOnce(streamID);
     91 
     92         return new AndFilter(new FromContainsFilter(from), new IBBOpenSidFilter(streamID));
     93     }
     94 
     95     public String[] getNamespaces() {
     96         return new String[] { InBandBytestreamManager.NAMESPACE };
     97     }
     98 
     99     InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException {
    100         // build In-Band Bytestream request
    101         InBandBytestreamRequest request = new ByteStreamRequest(this.manager,
    102                         (Open) streamInitiation);
    103 
    104         // always accept the request
    105         InBandBytestreamSession session = request.accept();
    106         session.setCloseBothStreamsEnabled(true);
    107         return session.getInputStream();
    108     }
    109 
    110     public void cleanup() {
    111     }
    112 
    113     /**
    114      * This PacketFilter accepts an incoming In-Band Bytestream open request
    115      * with a specified session ID.
    116      */
    117     private static class IBBOpenSidFilter extends PacketTypeFilter {
    118 
    119         private String sessionID;
    120 
    121         public IBBOpenSidFilter(String sessionID) {
    122             super(Open.class);
    123             if (sessionID == null) {
    124                 throw new IllegalArgumentException("StreamID cannot be null");
    125             }
    126             this.sessionID = sessionID;
    127         }
    128 
    129         public boolean accept(Packet packet) {
    130             if (super.accept(packet)) {
    131                 Open bytestream = (Open) packet;
    132 
    133                 // packet must by of type SET and contains the given session ID
    134                 return this.sessionID.equals(bytestream.getSessionID())
    135                                 && IQ.Type.SET.equals(bytestream.getType());
    136             }
    137             return false;
    138         }
    139     }
    140 
    141     /**
    142      * Derive from InBandBytestreamRequest to access protected constructor.
    143      */
    144     private static class ByteStreamRequest extends InBandBytestreamRequest {
    145 
    146         private ByteStreamRequest(InBandBytestreamManager manager, Open byteStreamRequest) {
    147             super(manager, byteStreamRequest);
    148         }
    149 
    150     }
    151 
    152 }
    153