gloox 1.0

siprofileft.cpp

00001 /*
00002   Copyright (c) 2007-2009 by Jakob Schroeter <js@camaya.net>
00003   This file is part of the gloox library. http://camaya.net/gloox
00004 
00005   This software is distributed under a license. The full license
00006   agreement can be found in the file LICENSE in this distribution.
00007   This software may not be copied, modified, sold or distributed
00008   other than expressed in the named license agreement.
00009 
00010   This software is distributed without any warranty.
00011 */
00012 
00013 
00014 #include "siprofileft.h"
00015 
00016 #include "clientbase.h"
00017 #include "siprofilefthandler.h"
00018 #include "simanager.h"
00019 #include "dataform.h"
00020 #include "inbandbytestream.h"
00021 #include "oob.h"
00022 #include "socks5bytestream.h"
00023 #include "socks5bytestreammanager.h"
00024 
00025 #include <cstdlib>
00026 #include <map>
00027 
00028 namespace gloox
00029 {
00030 
00031   SIProfileFT::SIProfileFT( ClientBase* parent, SIProfileFTHandler* sipfth, SIManager* manager,
00032                             SOCKS5BytestreamManager* s5Manager )
00033     : m_parent( parent ), m_manager( manager ), m_handler( sipfth ),
00034       m_socks5Manager( s5Manager ), m_delManager( false ),
00035       m_delS5Manager( false )
00036   {
00037     if( !m_manager )
00038     {
00039       m_delManager = true;
00040       m_manager = new SIManager( m_parent );
00041     }
00042 
00043     m_manager->registerProfile( XMLNS_SI_FT, this );
00044 
00045     if( !m_socks5Manager )
00046     {
00047       m_socks5Manager = new SOCKS5BytestreamManager( m_parent, this );
00048       m_delS5Manager = true;
00049     }
00050   }
00051 
00052   SIProfileFT::~SIProfileFT()
00053   {
00054     m_manager->removeProfile( XMLNS_SI_FT );
00055 
00056     if( m_delManager )
00057       delete m_manager;
00058 
00059     if( m_socks5Manager && m_delS5Manager )
00060       delete m_socks5Manager;
00061   }
00062 
00063   const std::string SIProfileFT::requestFT( const JID& to, const std::string& name, long size,
00064                                             const std::string& hash, const std::string& desc,
00065                                             const std::string& date, const std::string& mimetype,
00066                                             int streamTypes, const JID& from,
00067                                             const std::string& sid )
00068   {
00069     if( name.empty() || size <= 0 || !m_manager )
00070       return EmptyString;
00071 
00072     Tag* file = new Tag( "file", XMLNS, XMLNS_SI_FT );
00073     file->addAttribute( "name", name );
00074     file->addAttribute( "size", size );
00075     if( !hash.empty() )
00076       file->addAttribute( "hash", hash );
00077     if( !date.empty() )
00078       file->addAttribute( "date", date );
00079     if( !desc.empty() )
00080       new Tag( file, "desc", desc );
00081 
00082     Tag* feature = new Tag( "feature", XMLNS, XMLNS_FEATURE_NEG );
00083     DataForm df( TypeForm );
00084     DataFormField* dff = df.addField( DataFormField::TypeListSingle, "stream-method" );
00085     StringMultiMap sm;
00086     if( streamTypes & FTTypeS5B )
00087       sm.insert( std::make_pair( "s5b", XMLNS_BYTESTREAMS ) );
00088     if( streamTypes & FTTypeIBB )
00089       sm.insert( std::make_pair( "ibb", XMLNS_IBB ) );
00090     if( streamTypes & FTTypeOOB )
00091       sm.insert( std::make_pair( "oob", XMLNS_IQ_OOB ) );
00092     dff->setOptions( sm );
00093     feature->addChild( df.tag() );
00094 
00095     return m_manager->requestSI( this, to, XMLNS_SI_FT, file, feature, mimetype, from, sid );
00096   }
00097 
00098   void SIProfileFT::acceptFT( const JID& to, const std::string& sid, StreamType type, const JID& from )
00099   {
00100     if( !m_manager )
00101       return;
00102 
00103     if( m_id2sid.find( sid ) == m_id2sid.end() )
00104       return;
00105 
00106     const std::string& id = m_id2sid[sid];
00107 
00108     Tag* feature = new Tag( "feature", XMLNS, XMLNS_FEATURE_NEG );
00109     DataFormField* dff = new DataFormField( "stream-method" );
00110     switch( type )
00111     {
00112       case FTTypeAll:
00113       case FTTypeS5B:
00114         dff->setValue( XMLNS_BYTESTREAMS );
00115         break;
00116       case FTTypeIBB:
00117         dff->setValue( XMLNS_IBB );
00118         if( m_handler )
00119         {
00120           InBandBytestream* ibb = new InBandBytestream( m_parent, m_parent->logInstance(), to,
00121                                                         from ? from : m_parent->jid(), sid );
00122           m_handler->handleFTBytestream( ibb );
00123         }
00124         break;
00125       case FTTypeOOB:
00126         dff->setValue( XMLNS_IQ_OOB );
00127         break;
00128     }
00129     DataForm df( TypeSubmit );
00130     df.addField( dff );
00131     feature->addChild( df.tag() );
00132 
00133     m_manager->acceptSI( to, id, 0, feature, from );
00134   }
00135 
00136   void SIProfileFT::declineFT( const JID& to, const std::string& sid, SIManager::SIError reason,
00137                                const std::string& text )
00138   {
00139     if( m_id2sid.find( sid ) == m_id2sid.end() || !m_manager )
00140       return;
00141 
00142     m_manager->declineSI( to, m_id2sid[sid], reason, text );
00143   }
00144 
00145   void SIProfileFT::dispose( Bytestream* bs )
00146   {
00147     if( bs )
00148     {
00149       if( bs->type() == Bytestream::S5B && m_socks5Manager )
00150         m_socks5Manager->dispose( static_cast<SOCKS5Bytestream*>( bs ) );
00151       else
00152         delete bs;
00153     }
00154   }
00155 
00156   void SIProfileFT::cancel( Bytestream* bs )
00157   {
00158     if( !bs )
00159       return;
00160 
00161     if( m_id2sid.find( bs->sid() ) == m_id2sid.end() || !m_manager )
00162       return;
00163 
00164     if( bs->type() == Bytestream::S5B && m_socks5Manager )
00165       m_socks5Manager->rejectSOCKS5Bytestream( bs->sid(), StanzaErrorServiceUnavailable );
00166 
00167     dispose( bs );
00168   }
00169 
00170   void SIProfileFT::setStreamHosts( StreamHostList hosts )
00171   {
00172     if( m_socks5Manager )
00173       m_socks5Manager->setStreamHosts( hosts );
00174   }
00175 
00176   void SIProfileFT::addStreamHost( const JID& jid, const std::string& host, int port )
00177   {
00178     if( m_socks5Manager )
00179       m_socks5Manager->addStreamHost( jid, host, port );
00180   }
00181 
00182   void SIProfileFT::handleSIRequest( const JID& from, const JID& to, const std::string& id,
00183                                      const SIManager::SI& si )
00184   {
00185     if( si.profile() != XMLNS_SI_FT || !si.tag1() )
00186       return;
00187 
00188     if( m_handler )
00189     {
00190       const Tag* t = si.tag1()->findChild( "desc" );
00191       const std::string& desc = t ? t->cdata() : EmptyString;
00192 
00193       const std::string& mt = si.mimetype();
00194       int types = 0;
00195 
00196       if( si.tag2() )
00197       {
00198         const DataForm df( si.tag2()->findChild( "x", XMLNS, XMLNS_X_DATA ) );
00199         const DataFormField* dff = df.field( "stream-method" );
00200 
00201         if( dff )
00202         {
00203           const StringMultiMap& options = dff->options();
00204           StringMultiMap::const_iterator it = options.begin();
00205           for( ; it != options.end(); ++it )
00206           {
00207             if( (*it).second == XMLNS_BYTESTREAMS )
00208               types |= FTTypeS5B;
00209             else if( (*it).second == XMLNS_IBB )
00210               types |= FTTypeIBB;
00211             else if( (*it).second == XMLNS_IQ_OOB )
00212               types |= FTTypeOOB;
00213           }
00214         }
00215       }
00216 
00217       const std::string& sid = si.id();
00218       m_id2sid[sid] = id;
00219       m_handler->handleFTRequest( from, to, sid, si.tag1()->findAttribute( "name" ),
00220                                   atol( si.tag1()->findAttribute( "size" ).c_str() ),
00221                                         si.tag1()->findAttribute( "hash" ),
00222                                             si.tag1()->findAttribute( "date" ),
00223                                   mt.empty() ? "binary/octet-stream" : mt,
00224                                   desc, types );
00225     }
00226   }
00227 
00228   void SIProfileFT::handleSIRequestResult( const JID& from, const JID& to, const std::string& sid,
00229                                            const SIManager::SI& si )
00230   {
00231     if( si.tag2() )
00232     {
00233       const DataForm df( si.tag2()->findChild( "x", XMLNS, XMLNS_X_DATA ) );
00234       const DataFormField* dff = df.field( "stream-method" );
00235 
00236       if( dff )
00237       {
00238         if( m_socks5Manager && dff->value() == XMLNS_BYTESTREAMS )
00239         {
00240           // check return value:
00241           m_socks5Manager->requestSOCKS5Bytestream( from, SOCKS5BytestreamManager::S5BTCP, sid, to );
00242         }
00243         else if( m_handler )
00244         {
00245           if( dff->value() == XMLNS_IBB )
00246           {
00247             InBandBytestream* ibb = new InBandBytestream( m_parent, m_parent->logInstance(),
00248                 to ? to : m_parent->jid(), from, sid );
00249 
00250             m_handler->handleFTBytestream( ibb );
00251           }
00252           else if( dff->value() == XMLNS_IQ_OOB )
00253           {
00254             const std::string& url = m_handler->handleOOBRequestResult( from, to, sid );
00255             if( !url.empty() )
00256             {
00257               const std::string& id = m_parent->getID();
00258               IQ iq( IQ::Set, from, id );
00259               if( to )
00260                 iq.setFrom( to );
00261 
00262               iq.addExtension( new OOB( url, EmptyString, true ) );
00263               m_parent->send( iq, this, OOBSent );
00264             }
00265           }
00266         }
00267       }
00268     }
00269   }
00270 
00271   void SIProfileFT::handleIqID( const IQ& /*iq*/, int context )
00272   {
00273     switch( context )
00274     {
00275       case OOBSent:
00276 //         if( iq->subtype() == IQ::Error )
00277 //           m_handler->handleOOBError
00278         break;
00279     }
00280   }
00281 
00282   void SIProfileFT::handleSIRequestError( const IQ& iq, const std::string& sid )
00283   {
00284     if( m_handler )
00285       m_handler->handleFTRequestError( iq, sid );
00286   }
00287 
00288   void SIProfileFT::handleIncomingBytestreamRequest( const std::string& sid, const JID& /*from*/ )
00289   {
00290 // TODO: check for valid sid/from tuple
00291     m_socks5Manager->acceptSOCKS5Bytestream( sid );
00292   }
00293 
00294   void SIProfileFT::handleIncomingBytestream( Bytestream* bs )
00295   {
00296     if( m_handler )
00297       m_handler->handleFTBytestream( bs );
00298   }
00299 
00300   void SIProfileFT::handleOutgoingBytestream( Bytestream* bs )
00301   {
00302     if( m_handler )
00303       m_handler->handleFTBytestream( bs );
00304   }
00305 
00306   void SIProfileFT::handleBytestreamError( const IQ& iq, const std::string& sid )
00307   {
00308     if( m_handler )
00309       m_handler->handleFTRequestError( iq, sid );
00310   }
00311 
00312 }