1 /* 2 * im_mf.h 3 * 4 * Media formats for Instant Messaging 5 * 6 * Open Phone Abstraction Library (OPAL) 7 * 8 * Copyright (c) 2008 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: 27149 $ 27 * $Author: rjongbloed $ 28 * $Date: 2012-03-07 18:32:36 -0600 (Wed, 07 Mar 2012) $ 29 */ 30 31 #ifndef OPAL_IM_IM_H 32 #define OPAL_IM_IM_H 33 34 #include <ptlib.h> 35 #include <opal/buildopts.h> 36 37 #include <ptclib/url.h> 38 #include <ptclib/threadpool.h> 39 40 #include <opal/transports.h> 41 42 class OpalIM : public PObject 43 { 44 public: 45 OpalIM(); 46 47 enum Type { 48 Text, 49 CompositionIndication_Idle, // aka RFC 3994 50 CompositionIndication_Active, // aka RFC 3994 51 Disposition // aka RFC 5438 52 } m_type; 53 54 PURL m_to; 55 PURL m_from; 56 PString m_fromName; 57 PString m_mimeType; 58 PString m_body; 59 PString m_conversationId; 60 61 OpalTransportAddress m_fromAddr; 62 OpalTransportAddress m_toAddr; 63 64 PAtomicInteger::IntegerType m_messageId; 65 66 static PAtomicInteger::IntegerType GetNextMessageId(); 67 }; 68 69 #if OPAL_HAS_IM 70 71 #include <opal/mediastrm.h> 72 #include <im/rfc4103.h> 73 74 class OpalIMMediaType : public OpalMediaTypeDefinition 75 { 76 public: OpalIMMediaType(const char * mediaType,const char * sdpType)77 OpalIMMediaType( 78 const char * mediaType, ///< name of the media type (audio, video etc) 79 const char * sdpType ///< name of the SDP type 80 ) 81 : OpalMediaTypeDefinition(mediaType, sdpType, 0, OpalMediaType::DontOffer) 82 { } 83 GetRTPEncoding()84 PString GetRTPEncoding() const { return PString::Empty(); } CreateRTPSession(OpalRTPConnection &,unsigned,bool)85 RTP_UDP * CreateRTPSession(OpalRTPConnection & , unsigned , bool ) { return NULL; } UsesRTP()86 virtual bool UsesRTP() const { return false; } 87 }; 88 89 ///////////////////////////////////////////////////////////////////// 90 91 class OpalIMManager; 92 class OpalPresentity; 93 94 class OpalIMContext : public PSafeObject 95 { 96 PCLASSINFO(OpalIMContext, PSafeObject); 97 98 public: 99 friend class OpalIMManager; 100 101 OpalIMContext(); 102 ~OpalIMContext(); 103 104 static PSafePtr<OpalIMContext> Create( 105 OpalManager & manager, 106 const PURL & localURL, 107 const PURL & remoteURL 108 ); 109 110 static PSafePtr<OpalIMContext> Create( 111 OpalManager & manager, 112 PSafePtr<OpalConnection> conn 113 ); 114 115 static PSafePtr<OpalIMContext> Create( 116 OpalManager & manager, 117 PSafePtr<OpalPresentity> presentity, 118 const PURL & remoteURL 119 ); 120 121 enum SentStatus { 122 SentOK, 123 SentPending, 124 SentAccepted, 125 SentUnacceptableContent, 126 SentInvalidContent, 127 SentConnectionClosed, 128 SentNoTransport, 129 SentNoAnswer, 130 SentDestinationUnknown, 131 SentFailedGeneric, 132 }; 133 134 // send text message in this conversation 135 virtual SentStatus Send(OpalIM * message); 136 virtual SentStatus SendCompositionIndication(bool active = true); 137 138 /// Called when an outgoing message has been delivered for this context 139 /// Default implementation calls MessageSentNotifier, if set 140 struct MessageSentInfo { 141 PAtomicInteger::IntegerType messageId; 142 OpalIMContext::SentStatus status; 143 }; 144 virtual void OnMessageSent(const MessageSentInfo & info); 145 146 typedef PNotifierTemplate<const MessageSentInfo &> MessageSentNotifier; 147 #define PDECLARE_MessageSentNotifier(cls, fn) PDECLARE_NOTIFIER2(OpalIMContext, cls, fn, const MessageSentInfo &) 148 #define PCREATE_MessageSentNotifier(fn) PCREATE_NOTIFIER2(fn, const MessageSentInfo &) 149 150 /// Set the notifier for the OnMessageSent() function. 151 void SetMessageSentNotifier( 152 const MessageSentNotifier & notifier ///< Notifier to be called by OnIncomingIM() 153 ); 154 155 /// Called when an incoming message arrives for this context 156 /// Default implementation calls IncomingIMNotifier, if set, else returns true 157 virtual SentStatus OnIncomingIM(OpalIM & message); 158 159 typedef PNotifierTemplate<const OpalIM &> IncomingIMNotifier; 160 #define PDECLARE_IncomingIMNotifier(cls, fn) PDECLARE_NOTIFIER2(OpalIMContext, cls, fn, const OpalIM &) 161 #define PCREATE_IncomingIMNotifier(fn) PCREATE_NOTIFIER2(fn, const OpalIM &) 162 163 /// Set the notifier for the OnIncomingMessage() function. 164 void SetIncomingIMNotifier( 165 const IncomingIMNotifier & notifier ///< Notifier to be called by OnIncomingIM() 166 ); 167 168 /// Called when the remote composition indication changes state for this context 169 /// Default implementation calls IncomingIMNotifier, if set, else returns true 170 virtual void OnCompositionIndicationChanged(const PString & state); 171 172 typedef PNotifierTemplate<const PString &> CompositionIndicationChangedNotifier; 173 #define PDECLARE_CompositionIndicationChangedNotifier(cls, fn) PDECLARE_NOTIFIER2(OpalIMContext, cls, fn, const PString &) 174 #define PCREATE_CompositionIndicationChangedNotifier(fn) PCREATE_NOTIFIER2(fn, const PString &) 175 176 /// Set the notifier for the OnIncomingMessage() function. 177 void SetCompositionIndicationChangedNotifier( 178 const CompositionIndicationChangedNotifier & notifier ///< Notifier to be called by OnIncomingIM() 179 ); 180 181 virtual bool CheckContentType(const PString & contentType) const; 182 virtual PStringArray GetContentTypes() const; 183 184 // start of internal functions 185 GetID()186 PString GetID() const { return m_id; } SetID(const PString & id)187 void SetID(const PString & id) { m_id = id; } GetKey()188 PString GetKey() const { return m_key; } GetLocalURL()189 PString GetLocalURL() const { return m_localURL; } GetRemoteURL()190 PString GetRemoteURL() const { return m_remoteURL; } 191 192 /**@name Attributes */ 193 //@{ 194 ///< Get the attributes for this presentity. GetAttributes()195 PStringOptions & GetAttributes() { return m_attributes; } GetAttributes()196 const PStringOptions & GetAttributes() const { return m_attributes; } 197 198 virtual bool OnNewIncomingIM(); 199 200 virtual bool AddIncomingIM(OpalIM * message); 201 202 virtual void OnCompositionIndicationTimeout(); 203 204 OpalIM * GetIncomingMessage(); 205 206 virtual void InternalOnMessageSent(const MessageSentInfo & info); 207 208 static PString CreateKey(const PString & from, const PString & to); 209 210 void ResetLastUsed(); 211 212 protected: 213 virtual SentStatus InternalSend(); 214 virtual SentStatus InternalSendOutsideCall(OpalIM * message); 215 virtual SentStatus InternalSendInsideCall(OpalIM * message); 216 217 PMutex m_notificationMutex; 218 IncomingIMNotifier m_incomingMessageNotifier; 219 MessageSentNotifier m_messageSentNotifier; 220 CompositionIndicationChangedNotifier m_compositionIndicationChangedNotifier; 221 222 OpalManager * m_manager; 223 PStringOptions m_attributes; 224 225 PSafePtr<OpalConnection> m_connection; 226 PSafePtr<OpalPresentity> m_presentity; 227 228 PMutex m_incomingMessagesMutex; 229 PQueue<OpalIM> m_incomingMessages; 230 231 PMutex m_outgoingMessagesMutex; 232 OpalIM * m_currentOutgoingMessage; 233 PQueue<OpalIM> m_outgoingMessages; 234 235 PMutex m_lastUsedMutex; 236 PTime m_lastUsed; 237 238 private: 239 PString m_id, m_localURL, m_remoteURL, m_key; 240 241 }; 242 243 class OpalConnectionIMContext : public OpalIMContext 244 { 245 public: 246 OpalConnectionIMContext(); 247 }; 248 249 class OpalPresentityIMContext : public OpalIMContext 250 { 251 public: 252 OpalPresentityIMContext(); 253 }; 254 255 ///////////////////////////////////////////////////////////////////// 256 257 class OpalIMManager : public PObject 258 { 259 public: 260 OpalIMManager(OpalManager & manager); 261 ~OpalIMManager(); 262 263 class IM_Work; 264 265 OpalIMContext::SentStatus OnIncomingMessage(OpalIM * im, PString & conversationId, PSafePtr<OpalConnection> conn = NULL); 266 void OnCompositionIndicationTimeout(const PString & conversationId); 267 268 void AddContext(PSafePtr<OpalIMContext> context); 269 void RemoveContext(OpalIMContext * context); 270 271 void GarbageCollection(); 272 273 PSafePtr<OpalIMContext> FindContextByIdWithLock( 274 const PString & key, 275 PSafetyMode mode = PSafeReadWrite 276 ); 277 278 PSafePtr<OpalIMContext> FindContextByNamesWithLock( 279 const PString & local, 280 const PString & remote, 281 PSafetyMode mode = PSafeReadWrite 282 ); 283 284 PSafePtr<OpalIMContext> FindContextForMessageWithLock(OpalIM & im, OpalConnection * conn = NULL); 285 286 typedef PNotifierTemplate<OpalIMContext &> NewConversationNotifier; 287 #define PDECLARE_NewConversationNotifier(cls, fn) PDECLARE_NOTIFIER2(OpalIMManager, cls, fn, OpalIMContext &) 288 #define PCREATE_NewConversationNotifier(fn) PCREATE_NOTIFIER2(fn, OpalIMContext &) 289 290 class NewConversationCallBack : public PObject { 291 public: 292 NewConversationNotifier m_notifier; 293 PString m_scheme; 294 }; 295 296 void AddNotifier(const NewConversationNotifier & notifier, const PString & scheme); 297 bool RemoveNotifier(const NewConversationNotifier & notifier, const PString & scheme); 298 299 300 // thread pool declarations 301 class IM_Work 302 { 303 public: 304 IM_Work(OpalIMManager & mgr, const PString & conversationId); 305 virtual ~IM_Work(); 306 307 virtual void Work() = 0; 308 309 OpalIMManager & m_mgr; 310 PString m_conversationId; 311 }; 312 313 class NewIncomingIM_Work : public IM_Work 314 { 315 public: NewIncomingIM_Work(OpalIMManager & mgr,const PString & conversationId)316 NewIncomingIM_Work(OpalIMManager & mgr, const PString & conversationId) 317 : IM_Work(mgr, conversationId) 318 { } Work()319 virtual void Work() 320 { m_mgr.InternalOnNewIncomingIM(m_conversationId); } 321 }; 322 323 class NewConversation_Work : public IM_Work 324 { 325 public: NewConversation_Work(OpalIMManager & mgr,const PString & conversationId)326 NewConversation_Work(OpalIMManager & mgr, const PString & conversationId) 327 : IM_Work(mgr, conversationId) 328 { } Work()329 virtual void Work() 330 { m_mgr.InternalOnNewConversation(m_conversationId); } 331 }; 332 333 class MessageSent_Work : public IM_Work 334 { 335 public: MessageSent_Work(OpalIMManager & mgr,const PString & conversationId,const OpalIMContext::MessageSentInfo & info)336 MessageSent_Work(OpalIMManager & mgr, const PString & conversationId, const OpalIMContext::MessageSentInfo & info) 337 : IM_Work(mgr, conversationId) 338 , m_info(info) 339 { } Work()340 virtual void Work() 341 { m_mgr.InternalOnMessageSent(m_conversationId, m_info); } 342 343 OpalIMContext::MessageSentInfo m_info; 344 }; 345 346 class CompositionIndicationTimeout_Work : public IM_Work 347 { 348 public: CompositionIndicationTimeout_Work(OpalIMManager & mgr,const PString & conversationId)349 CompositionIndicationTimeout_Work(OpalIMManager & mgr, const PString & conversationId) 350 : IM_Work(mgr, conversationId) 351 { } Work()352 virtual void Work() 353 { m_mgr.InternalOnCompositionIndicationTimeout(m_conversationId); } 354 }; 355 356 357 void AddWork(IM_Work * work); 358 virtual void InternalOnNewConversation(const PString & conversation); 359 virtual void InternalOnNewIncomingIM(const PString & conversation); 360 virtual void InternalOnMessageSent(const PString & conversation, const OpalIMContext::MessageSentInfo & info); 361 virtual void InternalOnCompositionIndicationTimeout(const PString & conversationId); 362 363 protected: 364 PQueuedThreadPool<IM_Work> m_imThreadPool; 365 366 PTime m_lastGarbageCollection; 367 OpalManager & m_manager; 368 bool m_deleting; 369 typedef PSafeDictionary<PString, OpalIMContext> ContextsByConversationId; 370 ContextsByConversationId m_contextsByConversationId; 371 372 PMutex m_contextsByNamesMutex; 373 typedef std::multimap<std::string, PString> ContextsByNames; 374 ContextsByNames m_contextsByNames; 375 376 PMutex m_notifierMutex; 377 PList<NewConversationCallBack> m_callbacks; 378 }; 379 380 ///////////////////////////////////////////////////////////////////// 381 382 class RTP_IMFrame : public RTP_DataFrame 383 { 384 public: 385 RTP_IMFrame(); 386 RTP_IMFrame(const PString & contentType); 387 RTP_IMFrame(const PString & contentType, const T140String & content); 388 RTP_IMFrame(const BYTE * data, PINDEX len, PBoolean dynamic = true); 389 390 void SetContentType(const PString & contentType); 391 PString GetContentType() const; 392 393 void SetContent(const T140String & text); 394 bool GetContent(T140String & text) const; 395 AsString()396 PString AsString() const { return PString((const char *)GetPayloadPtr(), GetPayloadSize()); } 397 }; 398 399 class OpalIMMediaStream : public OpalMediaStream 400 { 401 public: 402 OpalIMMediaStream( 403 OpalConnection & conn, 404 const OpalMediaFormat & mediaFormat, ///< Media format for stream 405 unsigned sessionID, ///< Session number for stream 406 bool isSource ///< Is a source stream 407 ); 408 IsSynchronous()409 virtual PBoolean IsSynchronous() const { return false; } RequiresPatchThread()410 virtual PBoolean RequiresPatchThread() const { return false; } 411 412 bool ReadPacket(RTP_DataFrame & packet); 413 bool WritePacket(RTP_DataFrame & packet); 414 415 protected: InternalClose()416 virtual void InternalClose() { } 417 }; 418 419 #endif // OPAL_HAS_IM 420 421 #endif // OPAL_IM_IM_H 422