gloox 1.0.28
siprofileft.cpp
1/*
2 Copyright (c) 2007-2023 by Jakob Schröter <js@camaya.net>
3 This file is part of the gloox library. http://camaya.net/gloox
4
5 This software is distributed under a license. The full license
6 agreement can be found in the file LICENSE in this distribution.
7 This software may not be copied, modified, sold or distributed
8 other than expressed in the named license agreement.
9
10 This software is distributed without any warranty.
11*/
12
13
14#include "siprofileft.h"
15
16#include "clientbase.h"
17#include "siprofilefthandler.h"
18#include "simanager.h"
19#include "dataform.h"
20#include "inbandbytestream.h"
21#include "oob.h"
22#include "socks5bytestream.h"
23#include "socks5bytestreammanager.h"
24
25#include <cstdlib>
26#include <map>
27
28namespace gloox
29{
30
32 SOCKS5BytestreamManager* s5Manager )
33 : m_parent( parent ), m_manager( manager ), m_handler( sipfth ),
34 m_socks5Manager( s5Manager ), m_delManager( false ),
35 m_delS5Manager( false )
36 {
37 if( !m_manager )
38 {
39 m_delManager = true;
40 m_manager = new SIManager( m_parent );
41 }
42
43 m_manager->registerProfile( XMLNS_SI_FT, this );
44
45 if( !m_socks5Manager )
46 {
47 m_socks5Manager = new SOCKS5BytestreamManager( m_parent, this );
48 m_delS5Manager = true;
49 }
50 }
51
53 {
54 m_manager->removeProfile( XMLNS_SI_FT );
55
56 if( m_delManager )
57 delete m_manager;
58
59 if( m_socks5Manager && m_delS5Manager )
60 delete m_socks5Manager;
61 }
62
63 const std::string SIProfileFT::requestFT( const JID& to, const std::string& name, long size,
64 const std::string& hash, const std::string& desc,
65 const std::string& date, const std::string& mimetype,
66 int streamTypes, const JID& from,
67 const std::string& sid )
68 {
69 if( name.empty() || size <= 0 || !m_manager )
70 return EmptyString;
71
72 Tag* file = new Tag( "file", XMLNS, XMLNS_SI_FT );
73 file->addAttribute( "name", name );
74 file->addAttribute( "size", size );
75 if( !hash.empty() )
76 file->addAttribute( "hash", hash );
77 if( !date.empty() )
78 file->addAttribute( "date", date );
79 if( !desc.empty() )
80 new Tag( file, "desc", desc );
81
82 Tag* feature = new Tag( "feature", XMLNS, XMLNS_FEATURE_NEG );
83 DataForm df( TypeForm );
84 DataFormField* dff = df.addField( DataFormField::TypeListSingle, "stream-method" );
86 if( streamTypes & FTTypeS5B )
87 sm.insert( std::make_pair( std::string( "s5b" ), XMLNS_BYTESTREAMS ) );
88 if( streamTypes & FTTypeIBB )
89 sm.insert( std::make_pair( std::string( "ibb" ), XMLNS_IBB ) );
90 if( streamTypes & FTTypeOOB )
91 sm.insert( std::make_pair( std::string( "oob" ), XMLNS_IQ_OOB ) );
92 dff->setOptions( sm );
93 feature->addChild( df.tag() );
94
95 return m_manager->requestSI( this, to, XMLNS_SI_FT, file, feature, mimetype, from, sid );
96 }
97
98 void SIProfileFT::acceptFT( const JID& to, const std::string& sid, StreamType type, const JID& from )
99 {
100 if( !m_manager )
101 return;
102
103 if( m_id2sid.find( sid ) == m_id2sid.end() )
104 return;
105
106 const std::string& id = m_id2sid[sid];
107
108 Tag* feature = new Tag( "feature", XMLNS, XMLNS_FEATURE_NEG );
109 DataFormField* dff = new DataFormField( "stream-method" );
110 switch( type )
111 {
112 case FTTypeAll:
113 case FTTypeS5B:
115 break;
116 case FTTypeIBB:
117 dff->setValue( XMLNS_IBB );
118 if( m_handler )
119 {
120 InBandBytestream* ibb = new InBandBytestream( m_parent, m_parent->logInstance(), to,
121 from ? from : m_parent->jid(), sid );
122 m_handler->handleFTBytestream( ibb );
123 }
124 break;
125 case FTTypeOOB:
126 dff->setValue( XMLNS_IQ_OOB );
127 break;
128 }
129 DataForm df( TypeSubmit );
130 df.addField( dff );
131 feature->addChild( df.tag() );
132
133 m_manager->acceptSI( to, id, 0, feature, from );
134 }
135
136 void SIProfileFT::declineFT( const JID& to, const std::string& sid, SIManager::SIError reason,
137 const std::string& text )
138 {
139 if( m_id2sid.find( sid ) == m_id2sid.end() || !m_manager )
140 return;
141
142 m_manager->declineSI( to, m_id2sid[sid], reason, text );
143 }
144
146 {
147 if( bs )
148 {
149 if( bs->type() == Bytestream::S5B && m_socks5Manager )
150 m_socks5Manager->dispose( static_cast<SOCKS5Bytestream*>( bs ) );
151 else
152 delete bs;
153 }
154 }
155
157 {
158 if( !bs )
159 return;
160
161 if( m_id2sid.find( bs->sid() ) == m_id2sid.end() || !m_manager )
162 return;
163
164 if( bs->type() == Bytestream::S5B && m_socks5Manager )
166
167 dispose( bs );
168 }
169
171 {
172 if( m_socks5Manager )
173 m_socks5Manager->setStreamHosts( hosts );
174 }
175
176 void SIProfileFT::addStreamHost( const JID& jid, const std::string& host, int port )
177 {
178 if( m_socks5Manager )
179 m_socks5Manager->addStreamHost( jid, host, port );
180 }
181
182 void SIProfileFT::handleSIRequest( const JID& from, const JID& to, const std::string& id,
183 const SIManager::SI& si )
184 {
185 if( si.profile() != XMLNS_SI_FT || !si.tag1() )
186 return;
187
188 if( m_handler )
189 {
190 const Tag* t = si.tag1()->findChild( "desc" );
191 const std::string& desc = t ? t->cdata() : EmptyString;
192
193 const std::string& mt = si.mimetype();
194 int types = 0;
195
196 if( si.tag2() )
197 {
198 const DataForm df( si.tag2()->findChild( "x", XMLNS, XMLNS_X_DATA ) );
199 const DataFormField* dff = df.field( "stream-method" );
200
201 if( dff )
202 {
203 const StringMultiMap& options = dff->options();
204 StringMultiMap::const_iterator it = options.begin();
205 for( ; it != options.end(); ++it )
206 {
207 if( (*it).second == XMLNS_BYTESTREAMS )
208 types |= FTTypeS5B;
209 else if( (*it).second == XMLNS_IBB )
210 types |= FTTypeIBB;
211 else if( (*it).second == XMLNS_IQ_OOB )
212 types |= FTTypeOOB;
213 }
214 }
215 }
216
217 const std::string& sid = si.id();
218 m_id2sid[sid] = id;
219 m_handler->handleFTRequest( from, to, sid, si.tag1()->findAttribute( "name" ),
220 atol( si.tag1()->findAttribute( "size" ).c_str() ),
221 si.tag1()->findAttribute( "hash" ),
222 si.tag1()->findAttribute( "date" ),
223 mt.empty() ? "binary/octet-stream" : mt,
224 desc, types );
225 }
226 }
227
228 void SIProfileFT::handleSIRequestResult( const JID& from, const JID& to, const std::string& sid,
229 const SIManager::SI& si )
230 {
231 if( si.tag2() )
232 {
233 const DataForm df( si.tag2()->findChild( "x", XMLNS, XMLNS_X_DATA ) );
234 const DataFormField* dff = df.field( "stream-method" );
235
236 if( dff )
237 {
238 if( m_socks5Manager && dff->value() == XMLNS_BYTESTREAMS )
239 {
240 // check return value:
241 m_socks5Manager->requestSOCKS5Bytestream( from, SOCKS5BytestreamManager::S5BTCP, sid, to );
242 }
243 else if( m_handler )
244 {
245 if( dff->value() == XMLNS_IBB )
246 {
247 InBandBytestream* ibb = new InBandBytestream( m_parent, m_parent->logInstance(),
248 to ? to : m_parent->jid(), from, sid );
249
250 m_handler->handleFTBytestream( ibb );
251 }
252 else if( dff->value() == XMLNS_IQ_OOB )
253 {
254 const std::string& url = m_handler->handleOOBRequestResult( from, to, sid );
255 if( !url.empty() )
256 {
257 const std::string& id = m_parent->getID();
258 IQ iq( IQ::Set, from, id );
259 if( to )
260 iq.setFrom( to );
261
262 iq.addExtension( new OOB( url, EmptyString, true ) );
263 m_parent->send( iq, this, OOBSent );
264 }
265 }
266 }
267 }
268 }
269 }
270
271 void SIProfileFT::handleIqID( const IQ& /*iq*/, int context )
272 {
273 switch( context )
274 {
275 case OOBSent:
276// if( iq->subtype() == IQ::Error )
277// m_handler->handleOOBError
278 break;
279 }
280 }
281
282 void SIProfileFT::handleSIRequestError( const IQ& iq, const std::string& sid )
283 {
284 if( m_handler )
285 m_handler->handleFTRequestError( iq, sid );
286 }
287
288 void SIProfileFT::handleIncomingBytestreamRequest( const std::string& sid, const JID& /*from*/ )
289 {
290// TODO: check for valid sid/from tuple
291 m_socks5Manager->acceptSOCKS5Bytestream( sid );
292 }
293
295 {
296 if( m_handler )
297 m_handler->handleFTBytestream( bs );
298 }
299
301 {
302 if( m_handler )
303 m_handler->handleFTBytestream( bs );
304 }
305
306 void SIProfileFT::handleBytestreamError( const IQ& iq, const std::string& sid )
307 {
308 if( m_handler )
309 m_handler->handleFTRequestError( iq, sid );
310 }
311
312}
An abstraction of a single bytestream.
Definition bytestream.h:37
StreamType type() const
Definition bytestream.h:120
const std::string & sid() const
Definition bytestream.h:114
This is the common base class for a Jabber/XMPP Client and a Jabber Component.
Definition clientbase.h:79
const std::string getID()
LogSink & logInstance()
Definition clientbase.h:599
void send(Tag *tag)
const JID & jid()
Definition clientbase.h:147
virtual void addField(DataFormField *field)
DataFormField * field(const std::string &field) const
An abstraction of a single field in a XEP-0004 Data Form.
void setOptions(const StringMultiMap &options)
const StringMultiMap & options() const
const std::string & value() const
void setValue(const std::string &value)
An abstraction of a XEP-0004 Data Form.
Definition dataform.h:57
virtual Tag * tag() const
Definition dataform.cpp:106
An abstraction of an IQ stanza.
Definition iq.h:34
@ Set
Definition iq.h:46
An implementation of a single In-Band Bytestream (XEP-0047).
An abstraction of a JID.
Definition jid.h:31
This is an abstraction of a jabber:x:oob namespace element or a jabber:iq:oob namespace element as sp...
Definition oob.h:36
This class manages streams initiated using XEP-0095.
Definition simanager.h:35
void acceptSI(const JID &to, const std::string &id, Tag *child1, Tag *child2=0, const JID &from=JID())
void registerProfile(const std::string &profile, SIProfileHandler *sih)
void declineSI(const JID &to, const std::string &id, SIError reason, const std::string &text=EmptyString)
void removeProfile(const std::string &profile)
const std::string requestSI(SIHandler *sih, const JID &to, const std::string &profile, Tag *child1, Tag *child2=0, const std::string &mimetype="binary/octet-stream", const JID &from=JID(), const std::string &sid=EmptyString)
An abstract base class to handle file transfer (FT) requests.
virtual void handleFTRequestError(const IQ &iq, const std::string &sid)=0
virtual void handleFTBytestream(Bytestream *bs)=0
virtual void handleFTRequest(const JID &from, const JID &to, const std::string &sid, const std::string &name, long size, const std::string &hash, const std::string &date, const std::string &mimetype, const std::string &desc, int stypes)=0
virtual const std::string handleOOBRequestResult(const JID &from, const JID &to, const std::string &sid)=0
void setStreamHosts(StreamHostList hosts)
virtual void handleIncomingBytestream(Bytestream *bs)
virtual void handleIqID(const IQ &iq, int context)
void addStreamHost(const JID &jid, const std::string &host, int port)
virtual void handleSIRequest(const JID &from, const JID &to, const std::string &id, const SIManager::SI &si)
void cancel(Bytestream *bs)
virtual void handleSIRequestError(const IQ &iq, const std::string &sid)
virtual void handleIncomingBytestreamRequest(const std::string &sid, const JID &from)
virtual void handleOutgoingBytestream(Bytestream *bs)
const std::string requestFT(const JID &to, const std::string &name, long size, const std::string &hash=EmptyString, const std::string &desc=EmptyString, const std::string &date=EmptyString, const std::string &mimetype=EmptyString, int streamTypes=FTTypeAll, const JID &from=JID(), const std::string &sid=EmptyString)
void dispose(Bytestream *bs)
void acceptFT(const JID &to, const std::string &sid, StreamType type=FTTypeS5B, const JID &from=JID())
virtual void handleBytestreamError(const IQ &iq, const std::string &sid)
virtual void handleSIRequestResult(const JID &from, const JID &to, const std::string &sid, const SIManager::SI &si)
SIProfileFT(ClientBase *parent, SIProfileFTHandler *sipfth, SIManager *manager=0, SOCKS5BytestreamManager *s5Manager=0)
void declineFT(const JID &to, const std::string &sid, SIManager::SIError reason, const std::string &text=EmptyString)
An SOCKS5BytestreamManager dispatches SOCKS5 Bytestreams.
void setStreamHosts(StreamHostList hosts)
void addStreamHost(const JID &jid, const std::string &host, int port)
void rejectSOCKS5Bytestream(const std::string &sid, StanzaError reason=StanzaErrorNotAcceptable)
bool requestSOCKS5Bytestream(const JID &to, S5BMode mode, const std::string &sid=EmptyString, const JID &from=JID())
void acceptSOCKS5Bytestream(const std::string &sid)
An implementation of a single SOCKS5 Bytestream (XEP-0065).
void addExtension(const StanzaExtension *se)
Definition stanza.cpp:52
void setFrom(const JID &from)
Definition stanza.h:45
This is an abstraction of an XML element.
Definition tag.h:47
Tag * findChild(const std::string &name) const
Definition tag.cpp:624
bool addAttribute(Attribute *attr)
Definition tag.cpp:354
void addChild(Tag *child)
Definition tag.cpp:424
const std::string cdata() const
Definition tag.cpp:497
The namespace for the gloox library.
Definition adhoc.cpp:28
const std::string XMLNS_IQ_OOB
Definition gloox.cpp:48
std::multimap< std::string, std::string > StringMultiMap
Definition gloox.h:1266
const std::string XMLNS_IBB
Definition gloox.cpp:32
const std::string XMLNS_FEATURE_NEG
Definition gloox.cpp:33
const std::string XMLNS_X_DATA
Definition gloox.cpp:49
const std::string EmptyString
Definition gloox.cpp:124
const std::string XMLNS
Definition gloox.cpp:122
const std::string XMLNS_SI_FT
Definition gloox.cpp:65
@ StanzaErrorServiceUnavailable
Definition gloox.h:936
@ TypeSubmit
Definition dataform.h:37
@ TypeForm
Definition dataform.h:35
std::list< StreamHost > StreamHostList
const std::string XMLNS_BYTESTREAMS
Definition gloox.cpp:66