001/**
002 *
003 * Copyright 2003-2006 Jive Software.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.filetransfer;
018
019import java.io.InputStream;
020import java.io.OutputStream;
021
022import org.jivesoftware.smack.SmackException.NoResponseException;
023import org.jivesoftware.smack.SmackException.NotConnectedException;
024import org.jivesoftware.smack.XMPPConnection;
025import org.jivesoftware.smack.XMPPException.XMPPErrorException;
026import org.jivesoftware.smack.packet.Stanza;
027
028import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
029import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
030import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
031import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
032import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
033import org.jivesoftware.smackx.si.packet.StreamInitiation;
034
035import org.jxmpp.jid.Jid;
036
037/**
038 * The In-Band Bytestream file transfer method, or IBB for short, transfers the
039 * file over the same XML Stream used by XMPP. It is the fall-back mechanism in
040 * case the SOCKS5 bytestream method of transferring files is not available.
041 *
042 * @author Alexander Wenckus
043 * @author Henning Staib
044 * @see <a href="http://xmpp.org/extensions/xep-0047.html">XEP-0047: In-Band
045 *      Bytestreams (IBB)</a>
046 */
047public class IBBTransferNegotiator extends StreamNegotiator {
048
049    private final InBandBytestreamManager manager;
050
051    /**
052     * The default constructor for the In-Band Bytestream Negotiator.
053     *
054     * @param connection The connection which this negotiator works on.
055     */
056    protected IBBTransferNegotiator(XMPPConnection connection) {
057        super(connection);
058        this.manager = InBandBytestreamManager.getByteStreamManager(connection);
059    }
060
061    @Override
062    public OutputStream createOutgoingStream(String streamID, Jid initiator,
063                    Jid target) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
064        InBandBytestreamSession session = this.manager.establishSession(target, streamID);
065        session.setCloseBothStreamsEnabled(true);
066        return session.getOutputStream();
067    }
068
069    @Override
070    public InputStream createIncomingStream(StreamInitiation initiation)
071                    throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
072        /*
073         * In-Band Bytestream initiation listener must ignore next in-band bytestream request with
074         * given session ID
075         */
076        this.manager.ignoreBytestreamRequestOnce(initiation.getSessionID());
077
078        Stanza streamInitiation = initiateIncomingStream(connection(), initiation);
079        return negotiateIncomingStream(streamInitiation);
080    }
081
082    @Override
083    public void newStreamInitiation(Jid from, String streamID) {
084        /*
085         * this method is always called prior to #negotiateIncomingStream() so
086         * the In-Band Bytestream initiation listener must ignore the next
087         * In-Band Bytestream request with the given session ID
088         */
089        this.manager.ignoreBytestreamRequestOnce(streamID);
090    }
091
092    @Override
093    public String getNamespace() {
094        return DataPacketExtension.NAMESPACE;
095    }
096
097    @Override
098    InputStream negotiateIncomingStream(Stanza streamInitiation) throws NotConnectedException, InterruptedException {
099        // build In-Band Bytestream request
100        InBandBytestreamRequest request = new ByteStreamRequest(this.manager,
101                        (Open) streamInitiation);
102
103        // always accept the request
104        InBandBytestreamSession session = request.accept();
105        session.setCloseBothStreamsEnabled(true);
106        return session.getInputStream();
107    }
108
109    /**
110     * Derive from InBandBytestreamRequest to access protected constructor.
111     */
112    private static final class ByteStreamRequest extends InBandBytestreamRequest {
113
114        private ByteStreamRequest(InBandBytestreamManager manager, Open byteStreamRequest) {
115            super(manager, byteStreamRequest);
116        }
117
118    }
119
120}