1#if defined(HAVE_CONFIG_H)
45#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
66 const int registrationTimeSeconds,
67 const int subscriptionTimeSeconds)
73 mRegistrationDialog(
NameAddr(contact)),
74 mNextTimeToRegister(0),
75 mRegistrationPassword(
Data::Empty ),
77 mRegistrationTimeSeconds(registrationTimeSeconds),
78 mSubscriptionTimeSeconds(subscriptionTimeSeconds),
106 if ( !encryptFor.
empty() )
114 if ( (!encryptFor.
empty()) || (sign) )
125 const bool sign,
const Data& encryptFor)
129 DebugLog( <<
"tried to send blank message - dropped " );
132 DebugLog( <<
"send to <" << dest <<
">" <<
"\n" << text );
141 contact.
uri() = mContact;
151 page.encryptFor = encryptFor;
152 page.dialog = dialog;
154 mPages.push_back(page);
161#if defined( USE_SSL )
162 if ( !encryptFor.
empty() )
168 old->
header(h_ContentTransferEncoding) = msg->header(h_ContentTransferEncoding);
169 body = sec->
encrypt( old, encryptFor );
189 old->
header(h_ContentTransferEncoding) = msg->header(h_ContentTransferEncoding);
205 msg->setContents(body);
213 msg->header(h_Date) = now;
225 mStack->
send( *msg );
236 processMessageRequest(msg);
241 processSubscribeRequest(msg);
246 processRegisterRequest(msg);
251 processNotifyRequest(msg);
255 InfoLog(<<
"Don't support this METHOD, send 405" );
269 InfoLog(<<
"Received message with no contents" );
273 InfoLog(<<
"Received message with body contents" );
281#if defined( USE_SSL )
293 InfoLog( <<
"Some problem decoding multipart/signed message");
297 InfoLog( <<
"Signed by " << signedBy <<
" stat = " << sigStat );
306 InfoLog( <<
"Got a multipart mixed" );
311 for( MultipartMixedContents::Parts::const_iterator i = parts.begin();
319 if ( c->
getType() ==
Mime(
"application",
"sipfrag") )
326 InfoLog( <<
"Got a sipFrag inside mixed" );
364 processSipFrag( msg );
366 int expires=mSubscriptionTimeSeconds;
367 if ( msg->
exists(h_Expires) )
369 expires = msg->
header(h_Expires).value();
371 if (expires > mSubscriptionTimeSeconds )
373 expires = mSubscriptionTimeSeconds;
379 for ( SubscriberIterator i=mSubscribers.begin(); i != mSubscribers.end(); i++)
395 DebugLog ( <<
"Creating new subscrition dialog ");
408 mSubscribers.push_back( s );
414 unique_ptr<SipMessage> response( dialog->
makeResponse( *msg, 200 ));
416 response->header(h_Expires).value() = expires;
417 response->header(h_Event).value() =
Data(
"presence");
419 mStack->
send( *response );
421 sendNotify( dialog );
430 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++)
432 Data buddyAor = i->uri.getAor();
434 if ( ! (i->presDialog->isCreated()) )
436 if ( from.
getAor() == i->uri.getAor() )
440 i->mNextTimeToSubscribe = now;
455 int expires = msg->
header(h_Expires).value();
464 response->
remove(h_Contacts);
466 if ( msg->
exists(h_Contacts) )
470 int multipleContacts = (int)providedContacts.size();
472 DebugLog ( << multipleContacts <<
" contacts were in received message." );
475 for ( ; i != providedContacts.end() ; ++ i) {
476 if ( i->isAllContacts() && multipleContacts )
480 mStack->
send( *response );
484 if ( !i->exists(p_expires) )
486 i->param(p_expires) = expires;
488 response->
header(h_Contacts).push_back(*i);
493 mStack->
send( *response );
505 processSipFrag( msg );
508 mStack->
send( *response );
511 DebugLog ( <<
"got notify from " << from );
516 InfoLog(<<
"Received NOTIFY message event with no contents" );
522 DebugLog ( <<
"got NOTIFY event with body of type " << mime.
type() <<
"/" << mime.
subType() );
527 InfoLog(<<
"Received NOTIFY message event with no PIDF contents" );
539 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++)
546 if ( (i->status == note) &&
547 (i->online == open) )
557 InfoLog(<<
"Processed NOTIFY message : Presence changed: " << changed );
574 contact.
uri() = mContact;
577 mStack->
send( *response );
578 delete response; response=0;
583 InfoLog(<<
"Received Message message with no contents" );
593 bool encrypted=
false;
595#if defined( USE_SSL )
599 InfoLog ( <<
"assuming signedBy is " << signedBy );
614 InfoLog( <<
"Some problem decoding multipart/signed message");
633 InfoLog( <<
"Some problem decoding signed SMIME message");
654 InfoLog( <<
"Some problem decoding SMIME message");
672 DebugLog ( <<
"got message from with text of <" << text <<
">" );
675 DebugLog ( <<
"got message from " << from );
678 mCallback->
receivedPage( text, from, signedBy, sigStat, encrypted );
687 DebugLog ( <<
"got CPIM message from with text of <" << text <<
">" );
691 DebugLog ( <<
"got message from " << from );
694 mCallback->
receivedPage( text, from, signedBy, sigStat, encrypted );
701 InfoLog( <<
"Got a multipart mixed" );
706 for( MultipartMixedContents::Parts::const_iterator i = parts.begin();
722 const Data& text = plainBody->
text();
723 DebugLog ( <<
"got message from with text of <" << text <<
">" );
726 DebugLog ( <<
"got message from " << from );
729 mCallback->
receivedPage( text, from, signedBy, sigStat, encrypted );
747 DebugLog ( <<
"got message from with text of <" << text <<
">" );
750 DebugLog ( <<
"got message from " << from );
753 mCallback->
receivedPage( text, from, signedBy, sigStat, encrypted );
776 processSipFrag( msg );
781 Data v1 =
id.value();
784 InfoLog( <<
"want id =" <<
id );
788 InfoLog ( <<
"matched the reg dialog"
789 << mRegistrationDialog.
getCallId() <<
" = " <<
id );
790 processRegisterResponse( msg );
795 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++)
799 InfoLog( <<
"check buddy id =" << buddy.presDialog->getCallId() );
800 if ( buddy.presDialog->getCallId() ==
id )
802 DebugLog ( <<
"matched the subscribe dialog" );
803 processSubscribeResponse( msg, buddy );
809 for ( StateAgentIterator i=mStateAgents.begin(); i != mStateAgents.end(); i++)
812 InfoLog( <<
"check publish id =" << i->dialog->getCallId() );
813 if ( i->dialog->getCallId() ==
id )
815 DebugLog ( <<
"matched the publish dialog" );
816 processPublishResponse( msg, *i );
822 for ( SubscriberIterator i=mSubscribers.begin(); i != mSubscribers.end(); i++)
829 DebugLog ( <<
"matched the notify dialog" );
830 processNotifyResponse( msg, *dialog );
836 for ( PageIterator i=mPages.begin(); i != mPages.end(); i++)
839 InfoLog( <<
"check page id =" << i->dialog->getCallId() );
840 if ( i->dialog->getCallId() ==
id )
842 DebugLog ( <<
"matched the MESSAGE dialog" );
843 processPageResponse( msg, *i );
849 InfoLog( <<
"got response that DID NOT MATCH of type " << number );
858 InfoLog ( <<
"register of " << to <<
" got response " << number );
859 unsigned int cSeq = msg->
header(h_CSeq).sequence();
871 if ( ((number == 401) || (number == 407)) && (cSeq != mLastAuthCSeq) )
876 unsigned int nonceCount=0;
880 mLastAuthCSeq = reg->
header(h_CSeq).sequence();
882 reg->
header(h_Expires).value() = mRegistrationTimeSeconds;
883 reg->
header(h_Contacts).front().param(p_expires) = mRegistrationTimeSeconds;
891 mStack->
send( *reg );
893 delete reg; reg=NULL;
905 if ( (number>=200) && (number<300) )
907 int expires = mRegistrationTimeSeconds;
909 if ( msg->
exists(h_Expires) )
911 expires = msg->
header(h_Expires).value();
916 while ( i != msg->
header(h_Contacts).end() )
924 int e = i->param(p_expires);
932 InfoLog(<<
"Bad contact in 2xx to register - skipped" );
940 InfoLog(<<
"Got very small expiers of " << expires );
957 DebugLog( <<
"got NOTIFY response of type " << number );
967TuIM::processPublishResponse(
SipMessage* msg, StateAgent& sa )
970 DebugLog( <<
"got PUBLISH response of type " << number );
980TuIM::processPageResponse(
SipMessage* msg, Page& page )
983 DebugLog( <<
"got MESSAGE response of type " << number );
992 if ( (number>=300) && (number<400) )
995 while ( dest != msg->
header(h_Contacts).end() )
997 DebugLog(<<
"Got a 3xx to" << *dest );
1000 Uri uri = dest->uri();
1001 sendPage( page.text, uri, page.sign, page.encryptFor );
1007 if ( (number>=200) && (number<300) )
1012 for( PageIterator i=mPages.begin(); i != mPages.end(); i++ )
1014 if ( i->dialog->getCallId() == id )
1016 i = mPages.erase( i );
1024TuIM::processSubscribeResponse(
SipMessage* msg, Buddy& buddy)
1028 InfoLog ( <<
"subscribe got response " << number <<
" from " << to );
1030 if ( (number>=200) && (number<300) )
1032 int expires = mSubscriptionTimeSeconds;
1033 if ( msg->
exists(h_Expires) )
1035 expires = msg->
header(h_Expires).value();
1039 InfoLog( <<
"Got very small expiers of " << expires );
1044 buddy.presDialog->createDialogAsUAC( *msg );
1049 if ( (number>=300) && (number<400) )
1052 while ( dest != msg->
header(h_Contacts).end() )
1054 DebugLog(<<
"Got a 3xx to" << *dest );
1055 Uri uri = dest->uri();
1065 if ( (number>=400) )
1067 DebugLog( <<
"Got an error to some subscription" );
1073 bool changed =
true;
1075 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++)
1081 if ( i->online ==
false )
1109 if ( now > mNextTimeToRegister )
1113 unique_ptr<SipMessage> msg( mRegistrationDialog.
makeRegister() );
1114 msg->header(h_Expires).value() = mRegistrationTimeSeconds;
1115 setOutbound( *msg );
1116 mStack->
send( *msg );
1122 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++)
1124 if ( now > i->mNextTimeToSubscribe )
1128 buddy.mNextTimeToSubscribe
1132 if ( buddy.presDialog->isCreated() )
1134 unique_ptr<SipMessage> msg( buddy.presDialog->makeSubscribe() );
1136 msg->header(h_Event).value() =
Data(
"presence");;
1137 msg->header(h_Accepts).push_back(
Mime(
"application",
"pidf+xml") );
1138 msg->header(h_Expires).value() = mSubscriptionTimeSeconds;
1140 setOutbound( *msg );
1142 mStack->
send( *msg );
1147 subscribeBuddy( buddy );
1158 DebugLog ( <<
"got message: " << *msg);
1162 processResponse( msg );
1167 processRequest( msg );
1178 mRegistrationPassword = password;
1188 msg->header(h_Expires).value() = mRegistrationTimeSeconds;
1189 msg->header(h_Contacts).front().param(p_expires) = mRegistrationTimeSeconds;
1197 setOutbound( *msg );
1199 mStack->
send( *msg );
1206 return int(mBuddies.size());
1216 return mBuddies[index].uri;
1226 return mBuddies[index].group;
1238 *status = mBuddies[index].status;
1241 bool online = mBuddies[index].online;
1248TuIM::subscribeBuddy( Buddy& buddy )
1251 unique_ptr<SipMessage> msg( buddy.presDialog->makeInitialSubscribe(
NameAddr(buddy.uri),
NameAddr(mAor)) );
1253 msg->
header(h_Event).value() =
Data(
"presence");;
1254 msg->
header(h_Accepts).push_back(
Mime(
"application",
"pidf+xml") );
1255 msg->
header(h_Expires).value() = mSubscriptionTimeSeconds;
1259 setOutbound( *msg );
1261 mStack->
send( *msg );
1270 buddy.online =
false;
1272 buddy.group = group;
1276 subscribeBuddy( buddy );
1278 mBuddies.push_back( buddy );
1285 TuIM::BuddyIterator i;
1287 i = mBuddies.begin();
1288 while ( i != mBuddies.end() )
1296 i = mBuddies.erase(i);
1311 unique_ptr<SipMessage> msg( dialog->
makeNotify() );
1315 msg->
header(h_Event).value() =
"presence";
1320 msg->
header(h_SubscriptionState) = state;
1324 setOutbound( *msg );
1326 mStack->
send( *msg );
1331TuIM::sendPublish(StateAgent& sa)
1335 unique_ptr<SipMessage> msg( sa.dialog->makeInitialPublish(
NameAddr(sa.uri),
NameAddr(mAor)) );
1339 msg->
header(h_Event).value() =
"presence";
1343 setOutbound( *msg );
1345 mStack->
send( *msg );
1363 for ( SubscriberIterator i=mSubscribers.begin(); i != mSubscribers.end(); i++)
1371 for ( StateAgentIterator i=mStateAgents.begin(); i != mStateAgents.end(); i++)
1381 InfoLog( <<
"Set outbound proxy to " << uri );
1382 mOutboundProxy = uri;
1389 DebugLog( <<
"Set User Agent Name to " << name );
1405 msg.
header(h_Routes).push_front( proxy );
1408 if ( !mUAName.
empty() )
1410 DebugLog( <<
"UserAgent name=" << mUAName );
1411 msg.
header(h_UserAgent).value() = mUAName;
1427 mDefaultProtocol = protocol;
1439 mStateAgents.push_back( sa );
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
static int IMMethodList[]
const int IMMethodListSize
static void callback(void *arg, int status, unsigned char *abuf, int alen)
bool hasUserCert(const Data &aor) const
Contents * checkSignature(MultipartSignedContents *, Data *signedBy, SignatureStatus *sigStat)
Contents * decrypt(const Data &decryptorAor, const Pkcs7Contents *)
bool hasUserPrivateKey(const Data &aor) const
MultipartSignedContents * sign(const Data &senderAor, Contents *)
Pkcs7Contents * encrypt(Contents *, const Data &recipCertName)
Represents the "callid" element in the SIP grammar.
Base class for all SIP body types.
virtual Data getBodyData() const
const H_ContentType::Type & header(const H_ContentType &headerType) const
returns the value of the Content-Type header Throws an Contents::Exception if the header doesn't exis...
const Mime & getType() const
getter for mime type of message
SIP body type for holding CPIM (Common Profile for Instant Messaging) contents (MIME content-type mes...
Data & text()
Get the CPIM message text.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
static const Data Empty
Constant that represents a zero-length data.
bool empty() const noexcept
Checks whether the Data is empty.
Represents the "SIP-date" element in the RFC 3261 grammar.
SipMessage * makeNotify()
const CallID & getCallId() const
SipMessage * makeRegister()
SipMessage * makeInitialMessage(const NameAddr &target, const NameAddr &from)
SipMessage * makeInitialRegister(const NameAddr ®istrar, const NameAddr &from)
void setExpirySeconds(int secondsInFuture)
SipMessage * makeResponse(const SipMessage &request, int code=200)
void createDialogAsUAC(const SipMessage &response)
SIP body type for holding PIDF contents (MIME content-type application/pidf+xml).
void setSimplePresenceTupleNode(const Data &id, bool online, const Data ×tamp=Data::Empty, const Data ¬e=Data::Empty, const Data &contact=Data::Empty, const Data &contactPriority=Data::Empty)
const Data & getSimplePresenceTupleId()
const bool getSimplePresenceOnline()
const Data & getSimplePresenceNote()
void setEntity(const Uri &entity)
static SipMessage & addAuthorization(SipMessage &request, const SipMessage &challenge, const Data &username, const Data &password, const Data &cnonce, unsigned int &nonceCount)
static SipMessage * make405(const SipMessage &request, const int *allowedMethods=0, int nMethods=-1)
Make a 405 response to a provided request.
static void makeResponse(SipMessage &response, const SipMessage &request, int responseCode, const Data &reason=Data::Empty, const Data &hostname=Data::Empty, const Data &warning=Data::Empty)
Make a response to a provided request.
Represents an Identity header from RFC8824.
Represents the "media-type" element in the RFC 3261 grammar.
const Data & subType() const
const Data & type() const
SIP body type for holding Multipart-Mixed body contents (MIME content-type multipart/mixed).
std::vector< Contents * > Parts
SIP body type for holding Multipart-Signed body contents (MIME content-type multipart/signed).
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
SIP body type for holding Octet contents (MIME content-type application/octet-stream).
An iterator class (bidirectional)
Container class for ParserCategory, used by SipMessage to represent multi-valued headers (Contact,...
SIP body type for holding PKCS7 contents (MIME content-type application/pkcs7-mime).
SIP body type for holding PKCS7 Signed contents (MIME content-type application/pkcs7-signature).
SIP body type for holding plain contents (MIME content-type text/plain).
const Data & text() const
static Data getRandomHex(unsigned int numBytes)
MethodTypes getMethod() const
SIP body type for holding SipFrag contents (MIME content-type message/sipfrag).
Represents a SIP message.
void setContents(const Contents *contents)
Set the contents of the message.
bool isRequest() const
Returns true if message is a request, false otherwise.
Contents * getContents() const
Retrieves the body of a SIP message.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
bool isResponse() const
Returns true if message is a response, false otherwise.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
void remove(const HeaderBase &headerType)
Prevents a header field from being present when the message is prepared for sending to a transport.
This is the primary point of interaction between the app-layer and the stack.
Security * getSecurity() const
Returns a pointer to the embedded Security object, 0 if not set.
void send(const SipMessage &msg, TransactionUser *tu=0)
allows a TU to send a message
SipMessage * receive()
retrieve a SipMessage off the old TuFifo
Represents the "header-value" element in the RFC 3261 grammar (ie, an unknown header field value).
static uint64_t getRandomFutureTimeMs(uint64_t futureMs)
Returns an absolute time in ms that is between 50% and 90% of passed in ms from now.
static uint64_t getTimeMs()
Returns the current clock time in milliseconds.
static uint64_t getForever()
Infinit time in future.
Represents the "token" element in the RFC 3261 grammar.
const Data & value() const
Gets the value (ie; no parameters) of this Token as a Data&.
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
virtual void registrationWorked(const Uri &dest)=0
virtual void registrationFailed(const Uri &dest, int respNumber)=0
virtual void sendPageFailed(const Uri &dest, int respNumber)=0
virtual bool authorizeSubscription(const Uri &user)
virtual void presenceUpdate(const Uri &user, bool open, const Data &status)=0
virtual void receivePageFailed(const Uri &sender)=0
virtual void receivedPage(const Data &msg, const Uri &from, const Data &signedBy, SignatureStatus sigStatus, bool wasEncryped)=0
bool getBuddyStatus(const int index, Data *status=NULL)
const Uri getBuddyUri(const int index)
void setDefaultProtocol(TransportType protocol)
void authorizeSubscription(const Data &user)
void registerAor(const Uri &uri, const Data &password=Data::Empty)
const Data getBuddyGroup(const int index)
void sendPage(const Data &text, const Uri &dest, const bool sign=false, const Data &encryptFor=Data::Empty)
void setOutboundProxy(const Uri &uri)
void removeBuddy(const Uri &name)
void setMyPresence(const bool open, const Data &status=Data::Empty, const Data &user=Data::Empty)
TuIM(SipStack *stack, const Uri &aor, const Uri &contact, Callback *callback, const int registrationTimeSeconds=1 *60 *60, const int subscriptionTimeSeconds=10 *60)
void setUAName(const Data &name)
void addBuddy(const Uri &uri, const Data &group)
int getNumBuddies() const
bool haveCerts(bool sign, const Data &encryptFor)
void addStateAgent(const Uri &uri)
static const Data & toDataLower(TransportType type)
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Data getAorNoPort() const
bool exists(const Param< Uri > ¶mType) const
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
unsigned long long uint64_t
TransportType
An enumeration of transport protocols.
RequestLineType h_RequestLine
H_AllowEventss h_AllowEvents
unsigned __int64 uint64_t