gloox  1.0
simanager.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 "simanager.h"
15 
16 #include "siprofilehandler.h"
17 #include "sihandler.h"
18 #include "clientbase.h"
19 #include "disco.h"
20 #include "error.h"
21 
22 namespace gloox
23 {
24 
25  // ---- SIManager::SI ----
26  SIManager::SI::SI( const Tag* tag )
27  : StanzaExtension( ExtSI ), m_tag1( 0 ), m_tag2( 0 )
28  {
29  if( !tag || tag->name() != "si" || tag->xmlns() != XMLNS_SI )
30  return;
31 
32  m_valid = true;
33 
34  m_id = tag->findAttribute( "id" );
35  m_mimetype = tag->findAttribute( "mime-type" );
36  m_profile = tag->findAttribute( "profile" );
37 
38  Tag* c = tag->findChild( "file", "xmlns", XMLNS_SI_FT );
39  if ( c )
40  m_tag1 = c->clone();
41  c = tag->findChild( "feature", "xmlns", XMLNS_FEATURE_NEG );
42  if( c )
43  m_tag2 = c->clone();
44  }
45 
46  SIManager::SI::SI( Tag* tag1, Tag* tag2, const std::string& id,
47  const std::string& mimetype, const std::string& profile )
48  : StanzaExtension( ExtSI ), m_tag1( tag1 ), m_tag2( tag2 ),
49  m_id( id ), m_mimetype( mimetype ), m_profile( profile )
50  {
51  m_valid = true;
52  }
53 
54  SIManager::SI::~SI()
55  {
56  delete m_tag1;
57  delete m_tag2;
58  }
59 
60  const std::string& SIManager::SI::filterString() const
61  {
62  static const std::string filter = "/iq/si[@xmlns='" + XMLNS_SI + "']";
63  return filter;
64  }
65 
66  Tag* SIManager::SI::tag() const
67  {
68  if( !m_valid )
69  return 0;
70 
71  Tag* t = new Tag( "si" );
72  t->setXmlns( XMLNS_SI );
73  if( !m_id.empty() )
74  t->addAttribute( "id", m_id );
75  if( !m_mimetype.empty() )
76  t->addAttribute( "mime-type", m_mimetype.empty() ? "binary/octet-stream" : m_mimetype );
77  if( !m_profile.empty() )
78  t->addAttribute( "profile", m_profile );
79  if( m_tag1 )
80  t->addChildCopy( m_tag1 );
81  if( m_tag2 )
82  t->addChildCopy( m_tag2 );
83 
84  return t;
85  }
86  // ---- ~SIManager::SI ----
87 
88  // ---- SIManager ----
89  SIManager::SIManager( ClientBase* parent, bool advertise )
90  : m_parent( parent ), m_advertise( advertise )
91  {
92  if( m_parent )
93  {
94  m_parent->registerStanzaExtension( new SI() );
95  m_parent->registerIqHandler( this, ExtSI );
96  if( m_parent->disco() && m_advertise )
97  m_parent->disco()->addFeature( XMLNS_SI );
98  }
99  }
100 
102  {
103  if( m_parent )
104  {
105  m_parent->removeIqHandler( this, ExtSI );
106  m_parent->removeIDHandler( this );
107  if( m_parent->disco() && m_advertise )
108  m_parent->disco()->removeFeature( XMLNS_SI );
109  }
110  }
111 
112  const std::string SIManager::requestSI( SIHandler* sih, const JID& to, const std::string& profile,
113  Tag* child1, Tag* child2, const std::string& mimetype,
114  const JID& from, const std::string& sid )
115  {
116  if( !m_parent || !sih )
117  return EmptyString;
118 
119  const std::string& id = m_parent->getID();
120  const std::string& sidToUse = sid.empty() ? m_parent->getID() : sid;
121 
122  IQ iq( IQ::Set, to, id );
123  iq.addExtension( new SI( child1, child2, sidToUse, mimetype, profile ) );
124  if( from )
125  iq.setFrom( from );
126 
127  TrackStruct t;
128  t.sid = sidToUse;
129  t.profile = profile;
130  t.sih = sih;
131  m_track[id] = t;
132  m_parent->send( iq, this, OfferSI );
133 
134  return sidToUse;
135  }
136 
137  void SIManager::acceptSI( const JID& to, const std::string& id, Tag* child1, Tag* child2, const JID& from )
138  {
139  IQ iq( IQ::Result, to, id );
140  iq.addExtension( new SI( child1, child2 ) );
141  if( from )
142  iq.setFrom( from );
143 
144  m_parent->send( iq );
145  }
146 
147  void SIManager::declineSI( const JID& to, const std::string& id, SIError reason, const std::string& text )
148  {
149  IQ iq( IQ::Error, to, id );
150  Error* error;
151  if( reason == NoValidStreams || reason == BadProfile )
152  {
153  Tag* appError = 0;
154  if( reason == NoValidStreams )
155  appError = new Tag( "no-valid-streams", XMLNS, XMLNS_SI );
156  else if( reason == BadProfile )
157  appError = new Tag( "bad-profile", XMLNS, XMLNS_SI );
158  error = new Error( StanzaErrorTypeCancel, StanzaErrorBadRequest, appError );
159  }
160  else
161  {
163  if( !text.empty() )
164  error->text( text );
165  }
166 
167  iq.addExtension( error );
168  m_parent->send( iq );
169  }
170 
171  void SIManager::registerProfile( const std::string& profile, SIProfileHandler* sih )
172  {
173  if( !sih || profile.empty() )
174  return;
175 
176  m_handlers[profile] = sih;
177 
178  if( m_parent && m_advertise && m_parent->disco() )
179  m_parent->disco()->addFeature( profile );
180  }
181 
182  void SIManager::removeProfile( const std::string& profile )
183  {
184  if( profile.empty() )
185  return;
186 
187  m_handlers.erase( profile );
188 
189  if( m_parent && m_advertise && m_parent->disco() )
190  m_parent->disco()->removeFeature( profile );
191  }
192 
193  bool SIManager::handleIq( const IQ& iq )
194  {
195  TrackMap::iterator itt = m_track.find( iq.id() );
196  if( itt != m_track.end() )
197  return false;
198 
199  const SI* si = iq.findExtension<SI>( ExtSI );
200  if( !si || si->profile().empty() )
201  return false;
202 
203  HandlerMap::const_iterator it = m_handlers.find( si->profile() );
204  if( it != m_handlers.end() && (*it).second )
205  {
206  (*it).second->handleSIRequest( iq.from(), iq.to(), iq.id(), *si );
207  return true;
208  }
209 
210  return false;
211  }
212 
213  void SIManager::handleIqID( const IQ& iq, int context )
214  {
215  switch( iq.subtype() )
216  {
217  case IQ::Result:
218  if( context == OfferSI )
219  {
220  TrackMap::iterator it = m_track.find( iq.id() );
221  if( it != m_track.end() )
222  {
223  const SI* si = iq.findExtension<SI>( ExtSI );
224  if( !si /*|| si->profile().empty()*/ )
225  return;
226 
227 // Tag* si = iq.query();
228 // Tag* ptag = 0;
229 // Tag* fneg = 0;
230 // if( si && si->name() == "si" && si->xmlns() == XMLNS_SI )
231 // {
232 // ptag = si->findChildWithAttrib( XMLNS, (*it).second.profile );
233 // fneg = si->findChild( "feature", XMLNS, XMLNS_FEATURE_NEG );
234 // }
235 
236  // FIXME: remove above commented code and
237  // check corectness of last 3 params!
238  (*it).second.sih->handleSIRequestResult( iq.from(), iq.to(), (*it).second.sid, *si );
239  m_track.erase( it );
240  }
241  }
242  break;
243  case IQ::Error:
244  if( context == OfferSI )
245  {
246  TrackMap::iterator it = m_track.find( iq.id() );
247  if( it != m_track.end() )
248  {
249  (*it).second.sih->handleSIRequestError( iq, (*it).second.sid );
250  m_track.erase( it );
251  }
252  }
253  break;
254  default:
255  break;
256  }
257  }
258 
259 }