1 /* 2 * prese_ent.h 3 * 4 * Presence Entity classes for Opal 5 * 6 * Open Phone Abstraction Library (OPAL) 7 * 8 * Copyright (c) 2009 Post Increment 9 * 10 * The contents of this file are subject to the Mozilla Public License 11 * Version 1.0 (the "License"); you may not use this file except in 12 * compliance with the License. You may obtain a copy of the License at 13 * http://www.mozilla.org/MPL/ 14 * 15 * Software distributed under the License is distributed on an "AS IS" 16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 17 * the License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * The Original Code is Open Phone Abstraction Library. 21 * 22 * The Initial Developer of the Original Code is Post Increment 23 * 24 * Contributor(s): ______________________________________. 25 * 26 * $Revision: 28081 $ 27 * $Author: rjongbloed $ 28 * $Date: 2012-07-22 07:24:14 -0500 (Sun, 22 Jul 2012) $ 29 */ 30 31 #ifndef OPAL_IM_PRES_ENT_H 32 #define OPAL_IM_PRES_ENT_H 33 34 #include <ptlib.h> 35 #include <opal/buildopts.h> 36 37 #include <ptlib/pfactory.h> 38 #include <ptlib/safecoll.h> 39 #include <ptclib/url.h> 40 #include <ptclib/guid.h> 41 #include <ptclib/vcard.h> 42 43 #include <im/im.h> 44 45 #include <list> 46 #include <queue> 47 48 class OpalManager; 49 class OpalPresentityCommand; 50 51 52 //////////////////////////////////////////////////////////////////////////////////////////////////// 53 54 /**Presencu state information 55 */ 56 class OpalPresenceInfo : public PObject 57 { 58 public: 59 /// Presence states. 60 enum State { 61 InternalError = -3, // something bad happened 62 Forbidden = -2, // access to presence information was specifically forbidden 63 NoPresence = -1, // remove presence status - not the same as Unavailable or Away 64 65 // basic states (from RFC 3863) 66 Unchanged, 67 Available, 68 Unavailable, 69 70 // extended states (from RFC 4480) 71 // if this is changed, also change the tables in sippres.cxx and handlers.cxx - look for RFC 4480 72 ExtendedBase = 100, 73 UnknownExtended = ExtendedBase, 74 Appointment, 75 Away, 76 Breakfast, 77 Busy, 78 Dinner, 79 Holiday, 80 InTransit, 81 LookingForWork, 82 Lunch, 83 Meal, 84 Meeting, 85 OnThePhone, 86 Other, 87 Performance, 88 PermanentAbsence, 89 Playing, 90 Presentation, 91 Shopping, 92 Sleeping, 93 Spectator, 94 Steering, 95 Travel, 96 TV, 97 Vacation, 98 Working, 99 Worship 100 }; 101 102 State m_state; ///< New state for presentity 103 PString m_note; ///< Additional information about state change 104 PURL m_entity; ///< The presentity whose state had changed 105 PURL m_target; ///< The presentity that is being informed about the state change 106 PTime m_when; ///< Time/date of state change 107 m_state(state)108 OpalPresenceInfo(State state = Unchanged) : m_state(state) { } 109 110 static PString AsString(State state); 111 static State FromString(const PString & str); 112 PString AsString() const; 113 114 Comparison Compare(const PObject & other) const; 115 }; 116 117 ostream & operator<<(ostream & strm, OpalPresenceInfo::State state); 118 119 //////////////////////////////////////////////////////////////////////////////////////////////////// 120 121 class OpalSetLocalPresenceCommand; 122 class OpalSubscribeToPresenceCommand; 123 class OpalAuthorisationRequestCommand; 124 class OpalSendMessageToCommand; 125 126 /**Representation of a presence identity. 127 This class contains an abstraction of the functionality for "presence" 128 using a URL string as the "identity". The concrete class depends on the 129 scheme of the identity URL. 130 131 The general architecture is that commands will be sent to the preentity 132 concrete class via concrete versions of OpalPresentityCommand class. These 133 may be protocol specific or one of the abstracted versions. 134 */ 135 class OpalPresentity : public PSafeObject 136 { 137 PCLASSINFO(OpalPresentity, PSafeObject); 138 139 /**@name Construction */ 140 //@{ 141 protected: 142 /// Construct the presentity class 143 OpalPresentity(); 144 OpalPresentity(const OpalPresentity & other); 145 146 public: 147 ~OpalPresentity(); 148 149 /**Create a concrete class based on the scheme of the URL provided. 150 */ 151 static OpalPresentity * Create( 152 OpalManager & manager, ///< Manager for presentity 153 const PURL & url, ///< URL for presence identity 154 const PString & scheme = PString::Empty() ///< Overide the url scheme 155 ); 156 //@} 157 158 /**@name Initialisation */ 159 //@{ 160 /** Open the presentity handler. 161 This will perform whatever is required to allow this presentity 162 to access servers etc for the underlying protocol. It may start open 163 network channels, start threads etc. 164 165 Note that a return value of true does not necessarily mean that the 166 presentity has successfully been indicated as "present" on the server 167 only that the underlying system can do so at some time. 168 */ 169 virtual bool Open(); 170 171 /** Indicate if the presentity has been successfully opened. 172 */ IsOpen()173 virtual bool IsOpen() const { return m_open; } 174 175 /**Close the presentity. 176 */ 177 virtual bool Close(); 178 //@} 179 180 /**@name Attributes */ 181 //@{ 182 ///< Get the attributes for this presentity. GetAttributes()183 PStringOptions & GetAttributes() { return m_attributes; } 184 185 ///< Get all attribute names for this presentity class. 186 virtual PStringArray GetAttributeNames() const = 0; 187 188 ///< Get all attribute types for this presentity class. 189 virtual PStringArray GetAttributeTypes() const = 0; 190 191 static const PCaselessString & AuthNameKey(); ///< Key for authentication name attribute 192 static const PCaselessString & AuthPasswordKey(); ///< Key for authentication password attribute 193 static const PCaselessString & TimeToLiveKey(); ///< Key for Time-To-Live attribute, in seconds for underlying protocol 194 195 /** Get the address-of-record for the presentity. 196 This is typically a URL which represents our local identity in the 197 presense system. 198 */ GetAOR()199 const PURL & GetAOR() const { return m_aor; } 200 //@} 201 202 /**@name Commands */ 203 //@{ 204 /** Subscribe to presence state of another presentity. 205 This function is a wrapper and the OpalSubscribeToPresenceCommand 206 command. 207 208 Returns true if the command was queued. Note that this does not 209 mean the command succeeded, only that the underlying protocol is 210 capabable of the action. 211 */ 212 virtual bool SubscribeToPresence( 213 const PURL & presentity, ///< Other presentity to monitor 214 bool subscribe = true, ///< true if to subscribe, else unsubscribe 215 const PString & note = PString::Empty() ///< Optional extra note attached to subscription request 216 ); 217 218 /** Unsubscribe to presence state of another presentity. 219 This function is a wrapper and the OpalSubscribeToPresenceCommand 220 command. 221 222 Returns true if the command was queued. Note that this does not 223 mean the command succeeded, only that the underlying protocol is 224 capabable of the action. 225 */ 226 virtual bool UnsubscribeFromPresence( 227 const PURL & presentity ///< Other presentity to monitor 228 ); 229 230 /// Authorisation modes for SetPresenceAuthorisation() 231 enum Authorisation { 232 AuthorisationPermitted, 233 AuthorisationDenied, 234 AuthorisationDeniedPolitely, 235 AuthorisationConfirming, 236 AuthorisationRemove, 237 NumAuthorisations 238 }; 239 240 /** Called to allow/deny another presentity access to our presence 241 information. 242 243 This function is a wrapper and the OpalAuthorisationRequestCommand 244 command. 245 246 Returns true if the command was queued. Note that this does not 247 mean the command succeeded, only that the underlying protocol is 248 capabable of the action. 249 */ 250 virtual bool SetPresenceAuthorisation( 251 const PURL & presentity, ///< Remote presentity to be authorised 252 Authorisation authorisation ///< Authorisation mode 253 ); 254 255 /** Set our presence state. 256 This function is a wrapper and the OpalSetLocalPresenceCommand command. 257 258 Returns true if the command was queued. Note that this does not 259 mean the command succeeded, only that the underlying protocol is 260 capabable of the action. 261 */ 262 virtual bool SetLocalPresence( 263 OpalPresenceInfo::State state, ///< New state for our presentity 264 const PString & note = PString::Empty() ///< Additional note attached to the state change 265 ); 266 267 /** Get our presence state 268 */ 269 virtual bool GetLocalPresence( 270 OpalPresenceInfo::State & state, 271 PString & note 272 ); 273 274 275 /** Low level function to create a command. 276 As commands have protocol specific implementations, we use a factory 277 to create them. 278 */ 279 template <class cls> CreateCommand()280 __inline cls * CreateCommand() 281 { 282 return dynamic_cast<cls *>(InternalCreateCommand(typeid(cls).name())); 283 } 284 285 /** Lowlevel function to send a command to the presentity handler. 286 All commands are asynchronous. They will usually initiate an action 287 for which an indication (callback) will give a result. 288 289 Note that the command is typically created by the CreateCommand() 290 function and is subsequently deleted by this function. 291 292 Returns true if the command was queued. Note that this does not 293 mean the command succeeded, only that the underlying protocol is 294 processing commands. 295 */ 296 virtual bool SendCommand( 297 OpalPresentityCommand * cmd ///< Command to be processed 298 ); 299 //@} 300 301 /**@name Indications (callbacks) */ 302 //@{ 303 struct AuthorisationRequest 304 { 305 PURL m_presentity; ///< Other presentity requesting our presence 306 PString m_note; ///< Optional extra note attached to request 307 }; 308 309 /** Callback when another presentity requests access to our presence. 310 It is expected that the handler will call SetPresenceAuthorisation 311 with whatever policy is appropriate. 312 313 Default implementation calls m_onRequestPresenceNotifier if non-NULL 314 otherwise will authorise the request. 315 */ 316 virtual void OnAuthorisationRequest( 317 const AuthorisationRequest & request ///< Authorisation request information 318 ); 319 320 typedef PNotifierTemplate<const AuthorisationRequest &> AuthorisationRequestNotifier; 321 #define PDECLARE_AuthorisationRequestNotifier(cls, fn) PDECLARE_NOTIFIER2(OpalPresentity, cls, fn, const OpalPresentity::AuthorisationRequest &) 322 #define PCREATE_AuthorisationRequestNotifier(fn) PCREATE_NOTIFIER2(fn, const OpalPresentity::AuthorisationRequest &) 323 324 /// Set the notifier for the OnAuthorisationRequest() function. 325 void SetAuthorisationRequestNotifier( 326 const AuthorisationRequestNotifier & notifier ///< Notifier to be called by OnAuthorisationRequest() 327 ); 328 329 /** Callback when presentity has changed its state. 330 Note if the m_entity and m_target fields of the OpalPresenceInfo 331 structure are the same, then this indicates that the local presentity 332 itself has successfully "registered" itself with the presence agent 333 server. 334 335 Default implementation calls m_onPresenceChangeNotifier. 336 */ 337 virtual void OnPresenceChange( 338 const OpalPresenceInfo & info ///< Info on other presentity that changed state 339 ); 340 341 typedef PNotifierTemplate<const OpalPresenceInfo &> PresenceChangeNotifier; 342 #define PDECLARE_PresenceChangeNotifier(cls, fn) PDECLARE_NOTIFIER2(OpalPresentity, cls, fn, const OpalPresenceInfo &) 343 #define PCREATE_PresenceChangeNotifier(fn) PCREATE_NOTIFIER2(fn, const OpalPresenceInfo &) 344 345 /// Set the notifier for the OnPresenceChange() function. 346 void SetPresenceChangeNotifier( 347 const PresenceChangeNotifier & notifier ///< Notifier to be called by OnPresenceChange() 348 ); 349 //@} 350 351 /**@name Buddy Lists */ 352 //@{ 353 /**Buddy list entry. 354 The buddy list is a list of presentities that the application is 355 expecting to get presence status for. 356 */ 357 struct BuddyInfo { 358 BuddyInfo( 359 const PURL & presentity = PString::Empty(), 360 const PString & displayName = PString::Empty() m_presentityBuddyInfo361 ) : m_presentity(presentity) 362 , m_displayName(displayName) 363 { } 364 365 PURL m_presentity; ///< Typicall URI address-of-record 366 PString m_displayName; ///< Human readable name 367 368 // RFC4482 contact fields, note most of these are duplicated 369 // in the vCard structure 370 PvCard m_vCard; /**< vCard for the buddy. This is 371 either a URI pointing to the image, or the image 372 itself in the form: "data:text/x-vcard,xxxxx 373 as per RFC2397 */ 374 PURL m_icon; /**< The icon/avatar/photo for the buddy. This is 375 either a URI pointing to the image, or the image 376 itself in the form: "data:image/jpeg;base64,xxxxx 377 as per RFC2397 */ 378 PURL m_map; /**< The map reference for the buddy. This is may be URL 379 to a GIS system or an image file similar to m_icon */ 380 PURL m_sound; /**< The sound relating to the buddy. This is 381 either a URI pointing to the sound, or the sound 382 itself in the form: "data:audio/mpeg;base64,xxxxx 383 as per RFC2397 */ 384 PURL m_homePage; ///< Home page for buddy 385 386 // Extra field for protocol dependent "get out of gaol" card 387 PString m_contentType; ///< MIME type code for XML 388 PString m_rawXML; ///< Raw XML of buddy list entry 389 }; 390 391 typedef std::list<BuddyInfo> BuddyList; 392 393 enum BuddyStatus { 394 BuddyStatus_GenericFailure = -1, 395 BuddyStatus_OK = 0, 396 BuddyStatus_SpecifiedBuddyNotFound, 397 BuddyStatus_ListFeatureNotImplemented, 398 BuddyStatus_ListTemporarilyUnavailable, 399 BuddyStatus_ListMayBeIncomplete, 400 BuddyStatus_BadBuddySpecification, 401 BuddyStatus_ListSubscribeFailed, 402 BuddyStatus_AccountNotLoggedIn 403 }; 404 405 /**Get complete buddy list. 406 */ 407 virtual BuddyStatus GetBuddyListEx( 408 BuddyList & buddies ///< List of buddies 409 ); GetBuddyList(BuddyList & buddies)410 virtual bool GetBuddyList( 411 BuddyList & buddies ///< List of buddies 412 ) 413 { return GetBuddyListEx(buddies) == BuddyStatus_OK; } 414 415 /**Set complete buddy list. 416 */ 417 virtual BuddyStatus SetBuddyListEx( 418 const BuddyList & buddies ///< List of buddies 419 ); SetBuddyList(const BuddyList & buddies)420 virtual bool SetBuddyList( 421 const BuddyList & buddies ///< List of buddies 422 ) 423 { return SetBuddyListEx(buddies) == BuddyStatus_OK; } 424 425 426 /**Delete the buddy list. 427 */ 428 virtual BuddyStatus DeleteBuddyListEx(); DeleteBuddyList()429 virtual bool DeleteBuddyList() { return DeleteBuddyListEx() == BuddyStatus_OK; } 430 431 /**Get a specific buddy from the buddy list. 432 Note the buddy.m_presentity field must be preset to the URI to search 433 the buddy list for. 434 */ 435 virtual BuddyStatus GetBuddyEx( 436 BuddyInfo & buddy 437 ); GetBuddy(BuddyInfo & buddy)438 virtual bool GetBuddy( 439 BuddyInfo & buddy 440 ) 441 { return GetBuddyEx(buddy) == BuddyStatus_OK; } 442 443 /**Set/Add a buddy to the buddy list. 444 */ 445 virtual BuddyStatus SetBuddyEx( 446 const BuddyInfo & buddy 447 ); SetBuddy(const BuddyInfo & buddy)448 virtual bool SetBuddy( 449 const BuddyInfo & buddy 450 ) 451 { return SetBuddyEx(buddy) == BuddyStatus_OK; } 452 453 /**Delete a buddy to the buddy list. 454 */ 455 virtual BuddyStatus DeleteBuddyEx( 456 const PURL & presentity 457 ); DeleteBuddy(const PURL & presentity)458 virtual bool DeleteBuddy( 459 const PURL & presentity 460 ) 461 { return DeleteBuddyEx(presentity) == BuddyStatus_OK; } 462 463 /**Subscribe to buddy list. 464 Send a subscription for the presence of every presentity in the current 465 buddy list. This might cause multiple calls to SubscribeToPresence() or 466 if the underlying protocol allows a single call for all. 467 */ 468 virtual BuddyStatus SubscribeBuddyListEx( 469 PINDEX & successfulCount, 470 bool subscribe = true 471 ); 472 virtual bool SubscribeBuddyList( 473 bool subscribe = true 474 ) 475 { PINDEX successfulCount; return SubscribeBuddyListEx(successfulCount, subscribe) == BuddyStatus_OK; } 476 477 /**Unsubscribe to buddy list. 478 Send an unsubscription for the presence of every presentity in the current 479 buddy list. This might cause multiple calls to UnsubscribeFromPresence() or 480 if the underlying protocol allows a single call for all. 481 */ 482 virtual BuddyStatus UnsubscribeBuddyListEx(); UnsubscribeBuddyList()483 virtual bool UnsubscribeBuddyList() 484 { return UnsubscribeBuddyListEx() == BuddyStatus_OK; } 485 //@} 486 487 488 /**@name Instant Messaging */ 489 //@{ 490 virtual bool SendMessageTo( 491 const OpalIM & message 492 ); 493 494 /** Callback when presentity receives a message 495 496 Default implementation calls m_onReceivedMessageNotifier. 497 */ 498 virtual void OnReceivedMessage( 499 const OpalIM & message ///< incoming message 500 ); 501 502 typedef PNotifierTemplate<const OpalIM &> ReceivedMessageNotifier; 503 #define PDECLARE_ReceivedMessageNotifier(cls, fn) PDECLARE_NOTIFIER2(OpalPresentity, cls, fn, const OpalIM &) 504 #define PCREATE_ReceivedMessageNotifier(fn) PCREATE_NOTIFIER2(fn, const OpalIM &) 505 506 /// Set the notifier for the OnPresenceChange() function. 507 void SetReceivedMessageNotifier( 508 const ReceivedMessageNotifier & notifier ///< Notifier to be called by OnReceivedMessage() 509 ); 510 //@} 511 512 /** Used to set the AOR after the presentity is created 513 This override allows the descendant class to convert the internal URL into a real AOR, 514 usually by changing the scheme. 515 */ 516 virtual void SetAOR( 517 const PURL & aor 518 ); 519 520 void Internal_SendMessageToCommand(const OpalSendMessageToCommand & cmd); 521 522 protected: 523 OpalPresentityCommand * InternalCreateCommand(const char * cmdName); 524 525 OpalManager * m_manager; 526 PGloballyUniqueID m_guid; 527 PURL m_aor; 528 PStringOptions m_attributes; 529 530 AuthorisationRequestNotifier m_onAuthorisationRequestNotifier; 531 PresenceChangeNotifier m_onPresenceChangeNotifier; 532 ReceivedMessageNotifier m_onReceivedMessageNotifier; 533 534 PAtomicBoolean m_open; 535 PMutex m_notificationMutex; 536 bool m_temporarilyUnavailable; 537 OpalPresenceInfo::State m_localState; ///< our presentity state 538 PString m_localStateNote; ///< Additional note attached to the 539 }; 540 541 542 //////////////////////////////////////////////////////////////////////////////////////////////////// 543 544 /**Representation of a presence identity that uses a background thread to 545 process commands. 546 */ 547 class OpalPresentityWithCommandThread : public OpalPresentity 548 { 549 PCLASSINFO(OpalPresentityWithCommandThread, OpalPresentity); 550 551 /**@name Construction */ 552 //@{ 553 protected: 554 /// Construct the presentity class that uses a command thread. 555 OpalPresentityWithCommandThread(); 556 OpalPresentityWithCommandThread(const OpalPresentityWithCommandThread & other); 557 558 public: 559 /** Destory the presentity class that uses a command thread. 560 Note this will block until the background thread has stopped. 561 */ 562 ~OpalPresentityWithCommandThread(); 563 //@} 564 565 /**@name Overrides from OpalPresentity */ 566 //@{ 567 /** Lowlevel function to send a command to the presentity handler. 568 All commands are asynchronous. They will usually initiate an action 569 for which an indication (callback) will give a result. 570 571 The default implementation queues the command for the background 572 thread to handle. 573 574 Returns true if the command was queued. Note that this does not 575 mean the command succeeded, only that the underlying protocol is 576 processing commands, that is the backgrund thread is running 577 */ 578 virtual bool SendCommand( 579 OpalPresentityCommand * cmd ///< Command to execute 580 ); 581 //@} 582 583 /**@name new functions */ 584 //@{ 585 /**Start the background thread to handle commands. 586 This is typically called from the concrete classes Open() function. 587 588 If the argument is true (the default) then the thread starts processing 589 queue entries ASAP. 590 591 If the argument is false, the thread is still created and still runs, 592 but it does not process queue entries. This allows for presenties that 593 may need to allow commands to be paused, for example during initialisation 594 */ 595 void StartThread( 596 bool startQueue = true 597 ); 598 599 /**Stop the background thread to handle commands. 600 This is typically called from the concrete classes Close() function. 601 It is also called fro the destructor to be sure the thread has stopped 602 before the object is destroyed. 603 */ 604 void StopThread(); 605 606 /**Start/resume processing of queue commands 607 */ 608 void StartQueue( 609 bool startQueue = true 610 ); 611 612 //@} 613 614 protected: 615 void ThreadMain(); 616 617 typedef std::queue<OpalPresentityCommand *> CommandQueue; 618 CommandQueue m_commandQueue; 619 PMutex m_commandQueueMutex; 620 PAtomicInteger m_commandSequence; 621 PSyncPoint m_commandQueueSync; 622 623 bool m_threadRunning; 624 bool m_queueRunning; 625 PThread * m_thread; 626 }; 627 628 //////////////////////////////////////////////////////////////////////////////////////////////////// 629 630 /**Abstract class for all OpelPresentity commands. 631 */ 632 class OpalPresentityCommand { 633 public: 634 OpalPresentityCommand(bool responseNeeded = false) m_responseNeeded(responseNeeded)635 : m_responseNeeded(responseNeeded) 636 { } ~OpalPresentityCommand()637 virtual ~OpalPresentityCommand() { } 638 639 /**Function to process the command. 640 This typically calls functions on the concrete OpalPresentity class. 641 */ 642 virtual void Process( 643 OpalPresentity & presentity 644 ) = 0; 645 646 typedef PAtomicInteger::IntegerType CmdSeqType; 647 CmdSeqType m_sequence; 648 bool m_responseNeeded; 649 PURL m_presentity; 650 }; 651 652 /** Macro to define the factory that creates a concrete command class. 653 */ 654 #define OPAL_DEFINE_COMMAND(command, entity, func) \ 655 class entity##_##command : public command \ 656 { \ 657 public: virtual void Process(OpalPresentity & presentity) { dynamic_cast<entity &>(presentity).func(*this); } \ 658 }; \ 659 static PFactory<OpalPresentityCommand>::Worker<entity##_##command> \ 660 s_##entity##_##command(PDefaultPFactoryKey(entity::Class())+typeid(command).name()) 661 662 663 /** Command for subscribing to the status of another presentity. 664 */ 665 class OpalSubscribeToPresenceCommand : public OpalPresentityCommand { 666 public: m_subscribe(subscribe)667 OpalSubscribeToPresenceCommand(bool subscribe = true) : m_subscribe(subscribe) { } 668 669 bool m_subscribe; ///< Flag to indicate subscribing/unsubscribing 670 PString m_note; ///< Optional extra note attached to subscription request 671 }; 672 673 674 /** Command for authorising a request by some other presentity to see our status. 675 This action is typically due to some other presentity doing the equivalent 676 of a OpalSubscribeToPresenceCommand. The mechanism by which this happens 677 is dependent on the concrete OpalPresentity class and it's underlying 678 protocol. 679 */ 680 class OpalAuthorisationRequestCommand : public OpalPresentityCommand { 681 public: OpalAuthorisationRequestCommand()682 OpalAuthorisationRequestCommand() : m_authorisation(OpalPresentity::AuthorisationPermitted) { } 683 684 OpalPresentity::Authorisation m_authorisation; ///< Authorisation mode to indicate to remote 685 PString m_note; ///< Optional extra note attached to subscription request 686 }; 687 688 689 /** Command for adusting our current status. 690 This action typically causes all presentities to be notified of the 691 change. The mechanism by which this happens is dependent on the concrete 692 OpalPresentity class and it's underlying protocol. 693 */ 694 class OpalSetLocalPresenceCommand : public OpalPresentityCommand, public OpalPresenceInfo { 695 public: OpalPresenceInfo(state)696 OpalSetLocalPresenceCommand(State state = NoPresence) : OpalPresenceInfo(state) { } 697 }; 698 699 700 /** Command for sending an IM 701 */ 702 class OpalSendMessageToCommand : public OpalPresentityCommand 703 { 704 public: OpalSendMessageToCommand()705 OpalSendMessageToCommand() { } 706 707 OpalIM m_message; 708 }; 709 710 /////////////////////////////////////////////////////////////////////////////// 711 712 // Include concrete classes here so the factories are initialised 713 #if OPAL_SIP && OPAL_PTLIB_EXPAT 714 PFACTORY_LOAD(SIP_Presentity); 715 #endif 716 717 718 #endif // OPAL_IM_PRES_ENT_H 719 720