gloox  1.0
capabilities.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 "capabilities.h"
00015 
00016 #include "base64.h"
00017 #include "disco.h"
00018 #include "dataform.h"
00019 #include "sha.h"
00020 #include "tag.h"
00021 
00022 namespace gloox
00023 {
00024 
00025   Capabilities::Capabilities( Disco* disco )
00026     : StanzaExtension( ExtCaps ), m_disco( disco ), m_node( GLOOX_CAPS_NODE ),
00027       m_hash( "sha-1" ), m_valid( false )
00028   {
00029     if( m_disco )
00030       m_valid = true;
00031   }
00032 
00033   Capabilities::Capabilities( const Tag* tag )
00034     : StanzaExtension( ExtCaps ), m_disco( 0 ), m_valid( false )
00035   {
00036     if( !tag || tag->name() != "c" || !tag->hasAttribute( XMLNS, XMLNS_CAPS )
00037         || !tag->hasAttribute( "node" ) || !tag->hasAttribute( "ver" ) )
00038       return;
00039 
00040     m_node = tag->findAttribute( "node" );
00041     m_ver = tag->findAttribute( "ver" );
00042     m_hash = tag->findAttribute( "hash" );
00043     m_valid = true;
00044   }
00045 
00046   Capabilities::~Capabilities()
00047   {
00048     if( m_disco )
00049       m_disco->removeNodeHandlers( const_cast<Capabilities*>( this ) );
00050   }
00051 
00052   const std::string Capabilities::ver() const
00053   {
00054     if( !m_disco )
00055       return m_ver;
00056 
00057     SHA sha;
00058     sha.feed( generate( m_disco->identities(), m_disco->features( true ), m_disco->form() ) );
00059     const std::string& hash = Base64::encode64( sha.binary() );
00060     m_disco->removeNodeHandlers( const_cast<Capabilities*>( this ) );
00061     m_disco->registerNodeHandler( const_cast<Capabilities*>( this ), m_node + '#' + hash );
00062     return hash;
00063   }
00064 
00065   std::string Capabilities::generate( const Disco::IdentityList& il, const StringList& features, const DataForm* form )
00066   {
00067     StringList sl;
00068     Disco::IdentityList::const_iterator it = il.begin();
00069     for( ; it != il.end(); ++it )
00070     {
00071       std::string id = (*it)->category();
00072       id += '/';
00073       id += (*it)->type();
00074       id += '/';
00075       // FIXME add xml:lang caps here. see XEP-0115 Section 5
00076       id += '/';
00077       id += (*it)->name();
00078       sl.push_back( id );
00079     }
00080     sl.sort();
00081 
00082     std::string s;
00083     StringList::const_iterator it2 = sl.begin();
00084     for( ; it2 != sl.end(); ++it2 )
00085     {
00086       s += (*it2);
00087       s += '<';
00088     }
00089 
00090     StringList f = features;
00091     f.sort();
00092     it2 = f.begin();
00093     for( ; it2 != f.end(); ++it2 )
00094     {
00095       s += (*it2);
00096       s += '<';
00097     }
00098 
00099     if( form )
00100     {
00101       DataForm::FieldList::const_iterator it3 = form->fields().begin();
00102       typedef std::map<std::string, StringList> MapSSL;
00103 
00104       MapSSL m;
00105       for( ; it3 != form->fields().end(); ++it3 )
00106       {
00107         if( (*it3)->name() == "FORM_TYPE" )
00108         {
00109           s += (*it3)->value();
00110           s += '<';
00111         }
00112         else
00113           m.insert( std::make_pair( (*it3)->name(), (*it3)->values() ) );
00114       }
00115 
00116       MapSSL::iterator it4 = m.begin();
00117       for( ; it4 != m.end(); ++it4 )
00118       {
00119         s += it4->first;
00120         s += '<';
00121         it2 = it4->second.begin();
00122         for( ; it2 != it4->second.end(); ++it2 )
00123         {
00124           s += (*it2);
00125           s += '<';
00126         }
00127       }
00128     }
00129     return s;
00130   }
00131 
00132   std::string Capabilities::generate( const Disco::Info* info )
00133   {
00134     return info ? generate( info->identities(), info->features(), info->form() ) : EmptyString;
00135   }
00136 
00137   std::string Capabilities::generate( const Disco* disco )
00138   {
00139     return disco ? generate( disco->identities(), disco->features(), disco->form() ) : EmptyString;
00140   }
00141 
00142   const std::string& Capabilities::filterString() const
00143   {
00144     static const std::string filter = "/presence/c[@xmlns='" + XMLNS_CAPS + "']";
00145     return filter;
00146   }
00147 
00148   Tag* Capabilities::tag() const
00149   {
00150     if( !m_valid || m_node.empty() )
00151       return 0;
00152 
00153     Tag* t = new Tag( "c" );
00154     t->setXmlns( XMLNS_CAPS );
00155     t->addAttribute( "hash", m_hash );
00156     t->addAttribute( "node", m_node );
00157     t->addAttribute( "ver", ver() );
00158     return t;
00159   }
00160 
00161   StringList Capabilities::handleDiscoNodeFeatures( const JID&, const std::string& )
00162   {
00163     return m_disco->features();
00164   }
00165 
00166   Disco::IdentityList Capabilities::handleDiscoNodeIdentities( const JID&, const std::string& )
00167   {
00168     const Disco::IdentityList& il = m_disco->identities();
00169     Disco::IdentityList ret;
00170     Disco::IdentityList::const_iterator it = il.begin();
00171     for( ; it != il.end(); ++it )
00172     {
00173       ret.push_back( new Disco::Identity( *(*it) ) );
00174     }
00175     return ret;
00176   }
00177 
00178   Disco::ItemList Capabilities::handleDiscoNodeItems( const JID&, const JID&, const std::string& )
00179   {
00180     return Disco::ItemList();
00181   }
00182 
00183 }