blob: b32f49a6697a6d3b49a1424bebd5d42d6454c935 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/**
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 */
20package org.jivesoftware.smackx.filetransfer;
21
22import java.io.InputStream;
23import java.io.OutputStream;
24
25import org.jivesoftware.smack.Connection;
26import org.jivesoftware.smack.XMPPException;
27import org.jivesoftware.smack.filter.AndFilter;
28import org.jivesoftware.smack.filter.FromContainsFilter;
29import org.jivesoftware.smack.filter.PacketFilter;
30import org.jivesoftware.smack.filter.PacketTypeFilter;
31import org.jivesoftware.smack.packet.IQ;
32import org.jivesoftware.smack.packet.Packet;
33import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
34import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
35import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
36import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
37import 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 */
49public 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}