1 /* 2 Copyright (c) 2004-2019 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 15 #ifndef DISCO_H__ 16 #define DISCO_H__ 17 18 #include "gloox.h" 19 20 #include "iqhandler.h" 21 #include "jid.h" 22 23 #include <string> 24 #include <list> 25 #include <map> 26 27 namespace gloox 28 { 29 30 class ClientBase; 31 class DataForm; 32 class DiscoHandler; 33 class DiscoNodeHandler; 34 class IQ; 35 36 /** 37 * @brief This class implements @xep{0030} (Service Discovery) and @xep{0092} (Software Version). 38 * 39 * ClientBase will automatically instantiate a Disco object. It can be used to 40 * announce special features of your client, or its version, or... 41 * 42 * XEP version: 2.2 43 * @author Jakob Schröter <js@camaya.net> 44 */ 45 class GLOOX_API Disco : public IqHandler 46 { 47 friend class ClientBase; 48 49 public: 50 51 class Identity; // declared below class Info 52 53 /** 54 * A list of pointers to Identity objects. Used with Disco::Info. 55 */ 56 typedef std::list<Identity*> IdentityList; 57 58 /** 59 * @brief An abstraction of a Disco Info element (from Service Discovery, @xep{0030}) 60 * as a StanzaExtension. 61 * 62 * @author Jakob Schröter <js@camaya.net> 63 * @since 1.0 64 */ 65 class GLOOX_API Info : public StanzaExtension 66 { 67 friend class Disco; 68 69 public: 70 /** 71 * Returns the queried node identifier, if any. 72 * @return The node identifier. May be empty. 73 */ node()74 const std::string& node() const { return m_node; } 75 76 /** 77 * Returns the entity's supported features. 78 * @return A list of supported features/namespaces. 79 */ features()80 const StringList& features() const { return m_features; } 81 82 /** 83 * Use this function to check if the entity the Info came from supports agiven feature. 84 * @param feature The feature to check for. 85 * @return @b True if the entity announces support for the feature, @b false otherwise. 86 */ 87 bool hasFeature( const std::string& feature ) const; 88 89 /** 90 * Returns the entity's identities. 91 * @return A list of pointers to Identity objects. 92 */ identities()93 const IdentityList& identities() const { return m_identities; } 94 95 /** 96 * Returns an optionally included data form. This is used by e.g. MUC (@xep{0045}). 97 * @return An optional data form included in the disco#info. May be 0. 98 */ form()99 const DataForm* form() const { return m_form; } 100 101 /** 102 * Adds an optional DataForm, e.g. for @xep{0232}. Only one form can be added 103 * at this point. 104 * @param form An optional DataForm to include in the Info reply. 105 * The form will be owned by and deleted on destruction of the Info object. 106 * @note If called more than once the previously set form will be deleted. 107 */ 108 void setForm( DataForm* form ); 109 110 // reimplemented from StanzaExtension 111 virtual const std::string& filterString() const; 112 113 // reimplemented from StanzaExtension newInstance(const Tag * tag)114 virtual StanzaExtension* newInstance( const Tag* tag ) const 115 { 116 return new Info( tag ); 117 } 118 119 // reimplemented from StanzaExtension clone()120 virtual StanzaExtension* clone() const 121 { 122 return new Info( *this ); 123 } 124 125 // reimplemented from StanzaExtension 126 virtual Tag* tag() const; 127 128 private: 129 #ifdef DISCO_INFO_TEST 130 public: 131 #endif 132 /** 133 * Creates a empty Info object, suitable for making disco#info requests. 134 * @param node The node identifier to query (optional). 135 * @param defaultFeatures Indicates whether or not the default features should be 136 * included in the Info. Should be @b false for requests, @b true for replies. 137 * Defaults to @b false. 138 */ 139 Info( const std::string& node = EmptyString, bool defaultFeatures = false ); 140 141 /** 142 * Creates an Info object from the given Tag. 143 * @param tag A <query> tag in the disco#info namespace, (possibly) containing 144 * a disco#info reply. 145 */ 146 Info( const Tag* tag ); 147 148 /** 149 * Copy constructor. 150 * @param info An Info object to copy. 151 */ 152 Info( const Info& info ); 153 154 /** 155 * Virtual destructor. 156 */ 157 virtual ~Info(); 158 159 /** 160 * Sets the current info node. 161 * @param node The info node. 162 */ setNode(const std::string & node)163 void setNode( const std::string& node ) { m_node = node; } 164 165 /** 166 * This function can be used to set the entity's features. 167 * @param features A list of supported features/namespaces. 168 */ setFeatures(const StringList & features)169 void setFeatures( const StringList& features ) 170 { 171 StringList fl( features ); 172 fl.sort(); // needed on win32 173 m_features.merge( fl ); 174 } 175 176 /** 177 * This function can be used to set the entity's identities. 178 * @param identities A list of pointers to the entity's identities. 179 * @note The Identity objects pointed to will be owned by the Info object. The 180 * list should neither be used again nor should the Identity objects be deleted. 181 */ setIdentities(const IdentityList & identities)182 void setIdentities( const IdentityList& identities ) { m_identities = identities; } 183 184 std::string m_node; 185 StringList m_features; 186 IdentityList m_identities; 187 DataForm* m_form; 188 }; 189 190 /** 191 * @brief An abstraction of a Disco identity (Service Discovery, @xep{0030}). 192 * 193 * @author Jakob Schröter <js@camaya.net> 194 * @since 1.0 195 */ 196 class GLOOX_API Identity 197 { 198 friend class Info; 199 friend class Disco; 200 201 public: 202 /** 203 * Constructs a Disco Identity from a category, type and name. 204 * See http://www.xmpp.org/registrar/disco-categories.html for more info. 205 * @param category The identity's category. 206 * @param type The identity's type. 207 * @param name The identity's name. 208 */ 209 Identity( const std::string& category, 210 const std::string& type, 211 const std::string& name ); 212 213 /** 214 * Copy Contructor. 215 * @param id An Identity to create a new Identity object from. 216 */ 217 Identity( const Identity& id ); 218 219 /** 220 * Destructor. 221 */ 222 ~Identity(); 223 224 /** 225 * Returns the identity's category. 226 * @return The identity's category. 227 */ category()228 const std::string& category() const { return m_category; } 229 230 /** 231 * Returns the identity's type. 232 * @return The identity's type. 233 */ type()234 const std::string& type() const { return m_type; } 235 236 /** 237 * Returns the identity's name. 238 * @return The identity's name. 239 */ name()240 const std::string& name() const { return m_name; } 241 242 /** 243 * Creates and returns a Tag representation of this identity. 244 * @return A Tag, or 0. 245 */ 246 Tag* tag() const; 247 248 private: 249 /** 250 * Creates a Disco Identity from the given Tag. 251 * @param tag A Tag representation of a disco identity. 252 */ 253 Identity( const Tag* tag ); 254 255 std::string m_category; /**< The identity's category. */ 256 std::string m_type; /**< The identity's type. */ 257 std::string m_name; /**< The identity's name. */ 258 259 }; 260 261 class Item; // declared below class Items 262 263 /** 264 * A list of pointers to Item objects. Used with Disco::Items. 265 */ 266 typedef std::list<Item*> ItemList; 267 268 /** 269 * @brief An abstraction of a Disco query element (from Service Discovery, @xep{0030}) 270 * in the disco#items namespace, implemented as a StanzaExtension. 271 * 272 * @author Jakob Schröter <js@camaya.net> 273 * @since 1.0 274 */ 275 class GLOOX_API Items : public StanzaExtension 276 { 277 friend class Disco; 278 279 public: 280 // This needs to be public so one can proactively send a list of adhoc commands 281 // see @xep{0050} 282 /** 283 * Creates an empty Items object, suitable for making disco#items requests. 284 * @param node The node identifier to query (optional). 285 */ 286 Items( const std::string& node = EmptyString ); 287 288 /** 289 * Virtual destructor. 290 */ 291 virtual ~Items(); 292 293 /** 294 * This function can be used to set the entity's/node's items. 295 * @param items A list of pointers to the entity's/node's items. 296 * @note The Item objects pointed to will be owned by the Items object. The 297 * list should neither be used again nor should the Item objects be deleted. 298 */ 299 void setItems( const ItemList& items ); 300 301 /** 302 * Returns the queried node identifier, if any. 303 * @return The node identifier. May be empty. 304 */ node()305 const std::string& node() const { return m_node; } 306 307 /** 308 * Returns the entity's/node's items. 309 * @return A list of pointers to Item objects. 310 */ items()311 const ItemList& items() const { return m_items; } 312 313 // reimplemented from StanzaExtension 314 virtual const std::string& filterString() const; 315 316 // reimplemented from StanzaExtension newInstance(const Tag * tag)317 virtual StanzaExtension* newInstance( const Tag* tag ) const 318 { 319 return new Items( tag ); 320 } 321 322 // reimplemented from StanzaExtension 323 virtual Tag* tag() const; 324 325 // reimplemented from StanzaExtension clone()326 virtual StanzaExtension* clone() const 327 { 328 return new Items( *this ); 329 } 330 331 private: 332 #ifdef DISCO_ITEMS_TEST 333 public: 334 #endif 335 /** 336 * Creates an Items object from the given Tag. 337 * @param tag A <query> tag in the disco#items namespace, (possibly) containing 338 * a disco#items reply. 339 */ 340 Items( const Tag* tag ); 341 342 std::string m_node; 343 ItemList m_items; 344 }; 345 346 /** 347 * @brief An abstraction of a Disco item (Service Discovery, @xep{0030}). 348 * 349 * @author Jakob Schröter <js@camaya.net> 350 * @since 1.0 351 */ 352 class GLOOX_API Item 353 { 354 friend class Items; 355 356 public: 357 /** 358 * Constructs a Disco Item from a JID, node and name. 359 * @param jid The item's JID. 360 * @param node The item's type. 361 * @param name The item's name. 362 */ Item(const JID & jid,const std::string & node,const std::string & name)363 Item( const JID& jid, 364 const std::string& node, 365 const std::string& name ) 366 : m_jid( jid ), m_node( node ), m_name( name ) {} 367 368 /** 369 * Destructor. 370 */ ~Item()371 ~Item() {} 372 373 /** 374 * Returns the item's JID. 375 * @return The item's JID. 376 */ jid()377 const JID& jid() const { return m_jid; } 378 379 /** 380 * Returns the item's node. 381 * @return The item's node. 382 */ node()383 const std::string& node() const { return m_node; } 384 385 /** 386 * Returns the item's name. 387 * @return The item's name. 388 */ name()389 const std::string& name() const { return m_name; } 390 391 /** 392 * Creates and returns a Tag representation of this item. 393 * @return A Tag, or 0. 394 */ 395 Tag* tag() const; 396 397 private: 398 /** 399 * Creates a Disco Item from the given Tag. 400 * @param tag A Tag representation of a Disco item. 401 */ 402 Item( const Tag* tag ); 403 404 JID m_jid; /**< The item's jid. */ 405 std::string m_node; /**< The item's type. */ 406 std::string m_name; /**< The item's name. */ 407 408 }; 409 410 /** 411 * Adds a feature to the list of supported Jabber features. 412 * The list will be posted as an answer to IQ queries in the 413 * "http://jabber.org/protocol/disco#info" namespace. 414 * These IQ packets will also be forwarded to the 415 * application's IqHandler, if it listens to the @c disco\#info namespace. 416 * By default, disco(very) queries are handled by the library. 417 * By default, all supported, not disabled features are announced. 418 * @param feature A feature (namespace) the host app supports. 419 * @note Use this function for non-queryable features. For nodes that shall 420 * answer to @c disco\#info queries, use registerNodeHandler(). 421 */ addFeature(const std::string & feature)422 void addFeature( const std::string& feature ) 423 { m_features.push_back( feature ); } 424 425 /** 426 * Removes the given feature from the list of advertised client features. 427 * @param feature The feature to remove. 428 * @since 0.9 429 */ removeFeature(const std::string & feature)430 void removeFeature( const std::string& feature ) 431 { m_features.remove( feature ); } 432 433 /** 434 * Lets you retrieve the features this Disco instance supports. 435 * @param defaultFeatures Include default features. Defaults to @b false. 436 * @return A list of supported features/namespaces. 437 */ 438 const StringList features( bool defaultFeatures = false ) const; 439 440 /** 441 * Queries the given JID for general infomation according to 442 * @xep{0030} (Service Discovery). 443 * To receive the results inherit from DiscoHandler and register with the Disco object. 444 * @param to The destination-JID of the query. 445 * @param node An optional node to query. Not inserted if empty. 446 * @param dh The DiscoHandler to notify about results. 447 * @param context A context identifier. 448 * @param tid An optional id that is going to be used as the IQ request's id. Only 449 * necessary if you need to know the request's id. 450 */ 451 void getDiscoInfo( const JID& to, const std::string& node, DiscoHandler* dh, int context, 452 const std::string& tid = EmptyString ) 453 { getDisco( to, node, dh, context, GetDiscoInfo, tid ); } 454 455 /** 456 * Queries the given JID for its items according to 457 * @xep{0030} (Service Discovery). 458 * To receive the results inherit from DiscoHandler and register with the Disco object. 459 * @param to The destination-JID of the query. 460 * @param node An optional node to query. Not inserted if empty. 461 * @param dh The DiscoHandler to notify about results. 462 * @param context A context identifier. 463 * @param tid An optional id that is going to be used as the IQ request's id. Only 464 * necessary if you need to know the request's id. 465 */ 466 void getDiscoItems( const JID& to, const std::string& node, DiscoHandler* dh, int context, 467 const std::string& tid = EmptyString ) 468 { getDisco( to, node, dh, context, GetDiscoItems, tid ); } 469 470 /** 471 * Sets the version of the host application using this library. 472 * The library takes care of jabber:iq:version requests. These 473 * IQ packets will not be forwarded to the IqHandlers. 474 * @param name The name to be returned to inquiring clients. 475 * @param version The version to be returned to inquiring clients. 476 * @param os The operating system to announce. Default: don't include. 477 */ 478 void setVersion( const std::string& name, const std::string& version, 479 const std::string& os = EmptyString ); 480 481 /** 482 * Returns the application's advertised name. 483 * @return The application's advertised name. 484 */ name()485 const std::string& name() const { return m_versionName; } 486 487 /** 488 * Returns the application's advertised version. 489 * @return The application's advertised version. 490 */ version()491 const std::string& version() const { return m_versionVersion; } 492 493 /** 494 * Returns the application's advertised operating system. 495 * @return The application's advertised operating system. 496 */ os()497 const std::string& os() const { return m_versionOs; } 498 499 /** 500 * Sets the identity of this entity. 501 * The library uses this information to answer disco#info requests 502 * with a correct identity. 503 * @xep{0030} requires an entity to have at least one identity. See @xep{0030} 504 * for more information on categories and types. 505 * @param category The entity category of this client. Default: client. May not be empty. 506 * @param type The type of this entity. Default: bot. May not be empty. 507 * @param name The name of the entity. Default: empty. 508 * @note An entity can have more than one identity. You cann add more identities 509 * using addIdentity(). A call to setIdentity() will clear the list of identities 510 * and, after that, add the new identity given by the arguments to setIdentity(). 511 */ 512 void setIdentity( const std::string& category, const std::string& type, 513 const std::string& name = EmptyString ); 514 515 /** 516 * Adds another identity to the list of identities. 517 * @param category The entity category of this client. Default: client. May not be empty. 518 * @param type The type of this entity. Default: bot. May not be empty. 519 * @param name The name of the entity. Default: empty. 520 */ 521 void addIdentity( const std::string& category, const std::string& type, 522 const std::string& name = EmptyString ) 523 { m_identities.push_back( new Identity( category, type, name ) ); } 524 525 /** 526 * Returns the entity's identities. 527 * @return The entity's identities. 528 */ identities()529 const IdentityList& identities() const { return m_identities; } 530 531 /** 532 * Adds an optional DataForm to Disco:Info replies, e.g. for @xep{0232}. 533 * Only one form can be added at this point. 534 * @param form An optional DataForm to include in the Info reply. 535 * The form will be owned by and deleted on destruction of the Disco object. 536 * @note If called more than once the previously set form will be deleted. 537 */ 538 void setForm( DataForm* form ); 539 540 /** 541 * Returns the DataForm set by setForm(). Used by Capabilities. 542 * @return The DataForm, or 0. 543 */ form()544 const DataForm* form() const { return m_form; } 545 546 /** 547 * Use this function to register an @ref DiscoHandler with the Disco 548 * object. This is only necessary if you want to receive Disco-set requests. Else 549 * a one-time registration happens when calling getDiscoInfo() and getDiscoItems(), respectively. 550 * @param dh The DiscoHandler-derived object to register. 551 */ registerDiscoHandler(DiscoHandler * dh)552 void registerDiscoHandler( DiscoHandler* dh ) 553 { m_discoHandlers.push_back( dh ); } 554 555 /** 556 * Unregisters the given DiscoHandler. 557 * @param dh The DiscoHandler to unregister. 558 */ 559 void removeDiscoHandler( DiscoHandler* dh ); 560 561 /** 562 * Use this function to register a @ref DiscoNodeHandler with the Disco 563 * object. The DiscoNodeHandler will receive disco#items queries which are 564 * directed to the corresponding node registered for the handler. 565 * @param nh The NodeHandler-derived object to register. 566 * @param node The node name to associate with this handler. Use an empty string to 567 * register for the root node. 568 */ 569 void registerNodeHandler( DiscoNodeHandler* nh, const std::string& node ); 570 571 /** 572 * Removes the node handler for the given node. 573 * @param nh The NodeHandler to unregister. 574 * @param node The node for which the handler shall be removed. Use an empty string to 575 * remove the root node's handler. 576 */ 577 void removeNodeHandler( DiscoNodeHandler* nh, const std::string& node ); 578 579 /** 580 * Removes all registered nodes of the given node handler. 581 * @param nh The NodeHandler to unregister. 582 */ 583 void removeNodeHandlers( DiscoNodeHandler* nh ); 584 585 // reimplemented from IqHandler. 586 virtual bool handleIq( const IQ& iq ); 587 588 // reimplemented from IqHandler. 589 virtual void handleIqID( const IQ& iq, int context ); 590 591 private: 592 #ifdef DISCO_TEST 593 public: 594 #endif 595 Disco( ClientBase* parent ); 596 virtual ~Disco(); 597 598 enum IdType 599 { 600 GetDiscoInfo, 601 GetDiscoItems 602 }; 603 604 void getDisco( const JID& to, const std::string& node, DiscoHandler* dh, 605 int context, IdType idType, const std::string& tid ); 606 607 struct DiscoHandlerContext 608 { 609 DiscoHandler* dh; 610 int context; 611 }; 612 613 ClientBase* m_parent; 614 615 typedef std::list<DiscoHandler*> DiscoHandlerList; 616 typedef std::list<DiscoNodeHandler*> DiscoNodeHandlerList; 617 typedef std::map<std::string, DiscoNodeHandlerList> DiscoNodeHandlerMap; 618 typedef std::map<std::string, DiscoHandlerContext> DiscoHandlerMap; 619 620 DiscoHandlerList m_discoHandlers; 621 DiscoNodeHandlerMap m_nodeHandlers; 622 DiscoHandlerMap m_track; 623 IdentityList m_identities; 624 StringList m_features; 625 StringMap m_queryIDs; 626 DataForm* m_form; 627 628 std::string m_versionName; 629 std::string m_versionVersion; 630 std::string m_versionOs; 631 632 }; 633 634 } 635 636 #endif // DISCO_H__ 637