gloox  1.0
siprofileft.cpp
1 /*
2  Copyright (c) 2007-2009 by Jakob Schroeter <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 
28 namespace 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" );
85  StringMultiMap sm;
86  if( streamTypes & FTTypeS5B )
87  sm.insert( std::make_pair( "s5b", XMLNS_BYTESTREAMS ) );
88  if( streamTypes & FTTypeIBB )
89  sm.insert( std::make_pair( "ibb", XMLNS_IBB ) );
90  if( streamTypes & FTTypeOOB )
91  sm.insert( std::make_pair( "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:
114  dff->setValue( XMLNS_BYTESTREAMS );
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 )
165  m_socks5Manager->rejectSOCKS5Bytestream( bs->sid(), StanzaErrorServiceUnavailable );
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 }