|
reSIProcate/stack
9694
|
00001 #if defined(HAVE_CONFIG_H) 00002 #include "config.h" 00003 #endif 00004 00005 /* TODO list for this file .... 00006 handle 302 in message 00007 handle 302 in subscribe 00008 00009 sort out how contact is formed 00010 keep track of ourstanding message dialogs 00011 add a publish sending dialogs 00012 send options to register, see if do publish, if so use 00013 00014 suppport loading destination certificates from server 00015 */ 00016 00017 #include <cassert> 00018 #include <memory> 00019 00020 #include "resip/stack/SipStack.hxx" 00021 #include "resip/stack/DeprecatedDialog.hxx" 00022 #include "resip/stack/SipMessage.hxx" 00023 #include "resip/stack/TuIM.hxx" 00024 #include "resip/stack/Contents.hxx" 00025 #include "resip/stack/ParserCategories.hxx" 00026 #include "resip/stack/PlainContents.hxx" 00027 #include "resip/stack/CpimContents.hxx" 00028 #include "resip/stack/Pkcs7Contents.hxx" 00029 #include "resip/stack/MultipartSignedContents.hxx" 00030 #include "resip/stack/MultipartMixedContents.hxx" 00031 #include "resip/stack/OctetContents.hxx" 00032 #include "resip/stack/Helper.hxx" 00033 #include "resip/stack/Pidf.hxx" 00034 #include "resip/stack/SipFrag.hxx" 00035 #include "rutil/Data.hxx" 00036 #include "rutil/Logger.hxx" 00037 #include "rutil/Random.hxx" 00038 #include "rutil/Socket.hxx" 00039 #include "rutil/WinLeakCheck.hxx" 00040 00041 #ifdef USE_SSL 00042 #include "resip/stack/ssl/Security.hxx" 00043 #endif 00044 00045 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP 00046 00047 using namespace resip; 00048 using namespace std; 00049 00050 static int IMMethodList[] = { (int) REGISTER, 00051 (int) MESSAGE, 00052 (int) SUBSCRIBE, 00053 (int) NOTIFY }; 00054 const int IMMethodListSize = sizeof(IMMethodList) / sizeof(*IMMethodList); 00055 00056 00057 TuIM::Callback::~Callback() 00058 { 00059 } 00060 00061 00062 TuIM::TuIM(SipStack* stack, 00063 const Uri& aor, 00064 const Uri& contact, 00065 Callback* callback, 00066 const int registrationTimeSeconds, 00067 const int subscriptionTimeSeconds) 00068 : mCallback(callback), 00069 mStack(stack), 00070 mAor(aor), 00071 mContact(contact), 00072 mPidf( new Pidf ), 00073 mRegistrationDialog(NameAddr(contact)), 00074 mNextTimeToRegister(0), 00075 mRegistrationPassword( Data::Empty ), 00076 mLastAuthCSeq(0), 00077 mRegistrationTimeSeconds(registrationTimeSeconds), 00078 mSubscriptionTimeSeconds(subscriptionTimeSeconds), 00079 mDefaultProtocol( UNKNOWN_TRANSPORT ) 00080 { 00081 assert( mStack ); 00082 assert(mCallback); 00083 assert(mPidf); 00084 00085 mPidf->setSimpleId( Random::getRandomHex(4) ); 00086 mPidf->setEntity(mAor); 00087 mPidf->setSimpleStatus( true, Data::Empty, mContact.getAor() ); 00088 } 00089 00090 00091 bool 00092 TuIM::haveCerts( bool sign, const Data& encryptFor ) 00093 { 00094 /* assert(0); */ 00095 00096 #if defined( USE_SSL ) 00097 Security* sec = mStack->getSecurity(); 00098 assert(sec); 00099 00100 if ( sign ) 00101 { 00102 if ( !sec->hasUserPrivateKey(mAor.getAor()) ) 00103 { 00104 return false; 00105 } 00106 } 00107 if ( !encryptFor.empty() ) 00108 { 00109 if ( !sec->hasUserCert( encryptFor ) ) 00110 { 00111 return false; 00112 } 00113 } 00114 #else 00115 if ( (!encryptFor.empty()) || (sign) ) 00116 { 00117 return false; 00118 } 00119 #endif 00120 return true; 00121 } 00122 00123 00124 void 00125 TuIM::sendPage(const Data& text, const Uri& dest, 00126 const bool sign, const Data& encryptFor) 00127 { 00128 if ( text.empty() ) 00129 { 00130 DebugLog( << "tried to send blank message - dropped " ); 00131 return; 00132 } 00133 DebugLog( << "send to <" << dest << ">" << "\n" << text ); 00134 00135 NameAddr target; 00136 target.uri() = dest; 00137 00138 NameAddr from; 00139 from.uri() = mAor; 00140 00141 NameAddr contact; 00142 contact.uri() = mContact; 00143 00144 DeprecatedDialog* dialog = new DeprecatedDialog( NameAddr(mContact) ); 00145 00146 auto_ptr<SipMessage> msg( dialog->makeInitialMessage(NameAddr(target),NameAddr(from)) ); 00147 00148 Page page; 00149 page.text = text; 00150 page.uri = dest; 00151 page.sign = sign; 00152 page.encryptFor = encryptFor; 00153 page.dialog = dialog; 00154 00155 mPages.push_back(page); 00156 00157 Contents* body = ( new PlainContents(text) ); 00158 #if 1 00159 msg->header(h_ContentTransferEncoding) = StringCategory(Data("binary")); 00160 #endif 00161 00162 #if defined( USE_SSL ) 00163 if ( !encryptFor.empty() ) 00164 { 00165 Security* sec = mStack->getSecurity(); 00166 assert(sec); 00167 00168 Contents* old = body; 00169 old->header(h_ContentTransferEncoding) = msg->header(h_ContentTransferEncoding); 00170 body = sec->encrypt( old, encryptFor ); 00171 delete old; 00172 00173 if ( !body ) 00174 { 00175 mCallback->sendPageFailed( dest, -2 ); 00176 return; 00177 } 00178 00179 #if 0 00180 msg->header(h_ContentTransferEncoding) = StringCategory(Data("binary")); 00181 #endif 00182 } 00183 00184 if ( sign ) 00185 { 00186 Security* sec = mStack->getSecurity(); 00187 assert(sec); 00188 00189 Contents* old = body; 00190 old->header(h_ContentTransferEncoding) = msg->header(h_ContentTransferEncoding); 00191 body = sec->sign( mAor.getAor(), old ); 00192 delete old; 00193 00194 if ( !body ) 00195 { 00196 mCallback->sendPageFailed( dest, -1 ); 00197 return; 00198 } 00199 00200 #if 0 00201 msg->header(h_ContentTransferEncoding) = StringCategory(Data("binary")); 00202 #endif 00203 } 00204 #endif 00205 00206 msg->setContents(body); 00207 00208 if (1) // Compute the identity header. 00209 { 00210 //Security* sec = mStack->getSecurity(); 00211 //assert(sec); 00212 00213 DateCategory now; 00214 msg->header(h_Date) = now; 00215 00216 //Data token = msg->getCanonicalIdentityString(); 00217 //Data res = sec->computeIdentity( token ); 00218 00219 msg->header(h_Identity).value() = Data::Empty; 00220 } 00221 00222 setOutbound( *msg ); 00223 //ErrLog( "About to send " << *msg ); 00224 00225 mStack->send( *msg ); 00226 00227 delete body; 00228 } 00229 00230 00231 void 00232 TuIM::processRequest(SipMessage* msg) 00233 { 00234 if ( msg->header(h_RequestLine).getMethod() == MESSAGE ) 00235 { 00236 processMessageRequest(msg); 00237 return; 00238 } 00239 if ( msg->header(h_RequestLine).getMethod() == SUBSCRIBE ) 00240 { 00241 processSubscribeRequest(msg); 00242 return; 00243 } 00244 if ( msg->header(h_RequestLine).getMethod() == REGISTER ) 00245 { 00246 processRegisterRequest(msg); 00247 return; 00248 } 00249 if ( msg->header(h_RequestLine).getMethod() == NOTIFY ) 00250 { 00251 processNotifyRequest(msg); 00252 return; 00253 } 00254 00255 InfoLog(<< "Don't support this METHOD, send 405" ); 00256 00257 SipMessage * resp = Helper::make405( *msg, IMMethodList, IMMethodListSize ); 00258 mStack->send(*resp); 00259 delete resp; 00260 } 00261 00262 00263 void 00264 TuIM::processSipFrag(SipMessage* msg) 00265 { 00266 Contents* contents = msg->getContents(); 00267 if ( !contents ) 00268 { 00269 InfoLog(<< "Received message with no contents" ); 00270 return; 00271 } 00272 00273 InfoLog(<< "Received message with body contents" ); 00274 00275 assert( contents ); 00276 Mime mime = contents->getType(); 00277 DebugLog ( << "got body of type " << mime.type() << "/" << mime.subType() ); 00278 00279 Data signedBy; 00280 00281 #if defined( USE_SSL ) 00282 SignatureStatus sigStat = SignatureNone; 00283 MultipartSignedContents* mBody = dynamic_cast<MultipartSignedContents*>(contents); 00284 if ( mBody ) 00285 { 00286 Security* sec = mStack->getSecurity(); 00287 assert(sec); 00288 00289 contents = sec->checkSignature( mBody, &signedBy, &sigStat ); 00290 00291 if ( !contents ) 00292 { 00293 InfoLog( << "Some problem decoding multipart/signed message"); 00294 return; 00295 } 00296 00297 InfoLog( << "Signed by " << signedBy << " stat = " << sigStat ); 00298 } 00299 #endif 00300 00301 if ( contents ) 00302 { 00303 MultipartMixedContents* mixed = dynamic_cast<MultipartMixedContents*>(contents); 00304 if ( mixed ) 00305 { 00306 InfoLog( << "Got a multipart mixed" ); 00307 00308 contents = NULL; 00309 00310 MultipartMixedContents::Parts& parts = mixed->parts(); 00311 for( MultipartMixedContents::Parts::const_iterator i = parts.begin(); 00312 i != parts.end(); 00313 ++i) 00314 { 00315 Contents* c = *i; 00316 assert( c ); 00317 InfoLog ( << "mixed has a " << c->getType() ); 00318 00319 if ( c->getType() == Mime("application","sipfrag") ) 00320 { 00321 InfoLog ( << "mixed has sipfrag " << c->getType() ); 00322 00323 SipFrag* frag = dynamic_cast<SipFrag*>(c); 00324 if ( frag ) 00325 { 00326 InfoLog( << "Got a sipFrag inside mixed" ); 00327 00328 SipMessage& m = frag->message(); 00329 00330 InfoLog( <<"Frag is " << m ); 00331 } 00332 } 00333 } 00334 } 00335 } 00336 00337 if ( contents ) 00338 { 00339 SipFrag* frag = dynamic_cast<SipFrag*>(contents); 00340 if ( frag ) 00341 { 00342 InfoLog( << "Got a sipFrag" ); 00343 00344 SipMessage& m = frag->message(); 00345 00346 InfoLog( <<"Frag is " << m ); 00347 } 00348 else 00349 { 00350 InfoLog ( << "Can not handle type " << contents->getType() ); 00351 00352 return; 00353 } 00354 } 00355 } 00356 00357 00358 void 00359 TuIM::processSubscribeRequest(SipMessage* msg) 00360 { 00361 assert( msg->header(h_RequestLine).getMethod() == SUBSCRIBE ); 00362 CallId id = msg->header(h_CallId); 00363 00364 processSipFrag( msg ); 00365 00366 int expires=mSubscriptionTimeSeconds; 00367 if ( msg->exists(h_Expires) ) 00368 { 00369 expires = msg->header(h_Expires).value(); 00370 } 00371 if (expires > mSubscriptionTimeSeconds ) 00372 { 00373 expires = mSubscriptionTimeSeconds; 00374 } 00375 00376 DeprecatedDialog* dialog = NULL; 00377 00378 // see if we already have this subscription 00379 for ( SubscriberIterator i=mSubscribers.begin(); i != mSubscribers.end(); i++) 00380 { 00381 DeprecatedDialog* d = i->dialog; 00382 assert( d ); 00383 00384 if ( d->getCallId() == id ) 00385 { 00386 // found the subscrition in list of current subscrbtions 00387 dialog = d; 00388 break; 00389 } 00390 } 00391 00392 if ( !dialog ) 00393 { 00394 // create a new subscriber 00395 DebugLog ( << "Creating new subscrition dialog "); 00396 00397 Subscriber s; 00398 00399 s.dialog = new DeprecatedDialog( NameAddr(mContact) ); 00400 dialog = s.dialog; 00401 00402 Uri from = msg->header(h_From).uri(); 00403 s.aor = from.getAorNoPort(); 00404 00405 assert( mCallback ); 00406 s.authorized = mCallback->authorizeSubscription( from ); 00407 00408 mSubscribers.push_back( s ); 00409 } 00410 00411 assert( dialog ); 00412 dialog->setExpirySeconds( expires ); 00413 00414 auto_ptr<SipMessage> response( dialog->makeResponse( *msg, 200 )); 00415 00416 response->header(h_Expires).value() = expires; 00417 response->header(h_Event).value() = Data("presence"); 00418 00419 mStack->send( *response ); 00420 00421 sendNotify( dialog ); 00422 00423 #if 1 00424 // do symetric subscriptions 00425 // See if this person is our buddy list and if we are not subscribed to them 00426 00427 UInt64 now = Timer::getTimeMs(); 00428 Uri from = msg->header(h_From).uri(); 00429 00430 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++) 00431 { 00432 Data buddyAor = i->uri.getAor(); 00433 00434 if ( ! (i->presDialog->isCreated()) ) 00435 { 00436 if ( from.getAor() == i->uri.getAor() ) 00437 { 00438 if ( from.getAor() != mAor.getAor() ) 00439 { 00440 i->mNextTimeToSubscribe = now; 00441 } 00442 } 00443 } 00444 } 00445 #endif 00446 } 00447 00448 00449 void 00450 TuIM::processRegisterRequest(SipMessage* msg) 00451 { 00452 assert( msg->header(h_RequestLine).getMethod() == REGISTER ); 00453 CallId id = msg->header(h_CallId); 00454 00455 int expires = msg->header(h_Expires).value(); 00456 if ( expires == 0 ) 00457 { 00458 expires = 3600; 00459 } 00460 00461 SipMessage* response = Helper::makeResponse( *msg, 200 ); 00462 00463 // the Contacts from the default Helper are wrong for a Registration 00464 response->remove(h_Contacts); 00465 00466 if ( msg->exists(h_Contacts) ) 00467 { 00468 ParserContainer<NameAddr> &providedContacts(msg->header(h_Contacts)); 00469 00470 int multipleContacts = (int)providedContacts.size(); 00471 00472 DebugLog ( << multipleContacts << " contacts were in received message." ); 00473 00474 ParserContainer<NameAddr>::iterator i(providedContacts.begin()); 00475 for ( ; i != providedContacts.end() ; ++ i) { 00476 if ( i->isAllContacts() && multipleContacts ) // oops, multiple Contacts and one is "*" 00477 { 00478 delete response; // do I need to do this? 00479 response = Helper::makeResponse( *msg, 400 ); 00480 mStack->send( *response ); 00481 delete response; 00482 return; 00483 } 00484 if ( !i->exists(p_expires) ) // add expires params where they don't exist 00485 { 00486 i->param(p_expires) = expires; 00487 } 00488 response->header(h_Contacts).push_back(*i); // copy each Contact into response 00489 } 00490 } 00491 // else the REGISTER is a query, just send the message with no Contacts 00492 00493 mStack->send( *response ); 00494 00495 delete response; 00496 } 00497 00498 00499 void 00500 TuIM::processNotifyRequest(SipMessage* msg) 00501 { 00502 assert( mCallback ); 00503 assert( msg->header(h_RequestLine).getMethod() == NOTIFY ); 00504 00505 processSipFrag( msg ); 00506 00507 auto_ptr<SipMessage> response( Helper::makeResponse( *msg, 200 )); 00508 mStack->send( *response ); 00509 00510 Uri from = msg->header(h_From).uri(); 00511 DebugLog ( << "got notify from " << from ); 00512 00513 Contents* contents = msg->getContents(); 00514 if ( !contents ) 00515 { 00516 InfoLog(<< "Received NOTIFY message event with no contents" ); 00517 mCallback->presenceUpdate( from, true, Data::Empty ); 00518 return; 00519 } 00520 00521 Mime mime = contents->getType(); 00522 DebugLog ( << "got NOTIFY event with body of type " << mime.type() << "/" << mime.subType() ); 00523 00524 Pidf* body = dynamic_cast<Pidf*>(contents); 00525 if ( !body ) 00526 { 00527 InfoLog(<< "Received NOTIFY message event with no PIDF contents" ); 00528 mCallback->presenceUpdate( from, true, Data::Empty ); 00529 return; 00530 } 00531 00532 Data note; 00533 bool open = body->getSimpleStatus( ¬e ); 00534 00535 bool changed = true; 00536 00537 00538 // update if found in budy list 00539 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++) 00540 { 00541 Uri u = i->uri; // getBuddyUri(i); 00542 00543 if ( u.getAor() == from.getAor() ) 00544 { 00545 00546 if ( (i->status == note) && 00547 (i->online == open) ) 00548 { 00549 changed = false; 00550 } 00551 00552 i->status = note; 00553 i->online = open; 00554 } 00555 } 00556 00557 InfoLog(<< "Processed NOTIFY message : Presence changed: " << changed ); 00558 // notify callback 00559 if (changed) 00560 { 00561 assert(mCallback); 00562 mCallback->presenceUpdate( from, open, note ); 00563 } 00564 } 00565 00566 00567 void 00568 TuIM::processMessageRequest(SipMessage* msg) 00569 { 00570 assert( msg ); 00571 assert( msg->header(h_RequestLine).getMethod() == MESSAGE ); 00572 00573 NameAddr contact; 00574 contact.uri() = mContact; 00575 00576 SipMessage* response = Helper::makeResponse(*msg, 200, contact, "OK"); 00577 mStack->send( *response ); 00578 delete response; response=0; 00579 00580 Contents* contents = msg->getContents(); 00581 if ( !contents ) 00582 { 00583 InfoLog(<< "Received Message message with no contents" ); 00584 // .kw. NO: delete msg; msg=0; // our caller owns msg 00585 return; 00586 } 00587 00588 Mime mime = contents->getType(); 00589 DebugLog ( << "got body of type " << mime.type() << "/" << mime.subType() ); 00590 00591 Data signedBy; 00592 SignatureStatus sigStat = SignatureNone; 00593 bool encrypted=false; 00594 00595 #if defined( USE_SSL ) 00596 Uri from = msg->header(h_From).uri(); 00597 signedBy = from.getAorNoPort(); 00598 00599 InfoLog ( << "assuming signedBy is " << signedBy ); 00600 00601 MultipartSignedContents* mBody = dynamic_cast<MultipartSignedContents*>(contents); 00602 if ( mBody ) 00603 { 00604 Security* sec = mStack->getSecurity(); 00605 assert(sec); 00606 00607 contents = sec->checkSignature( mBody, &signedBy, &sigStat ); 00608 00609 //ErrLog("Signed by " << signedBy << " stat = " << sigStat ); 00610 00611 if ( !contents ) 00612 { 00613 Uri from = msg->header(h_From).uri(); 00614 InfoLog( << "Some problem decoding multipart/signed message"); 00615 00616 mCallback->receivePageFailed( from ); 00617 return; 00618 } 00619 } 00620 00621 Pkcs7SignedContents* sBody = dynamic_cast<Pkcs7SignedContents*>(contents); 00622 if ( sBody ) 00623 { 00624 assert( sBody ); 00625 Security* sec = mStack->getSecurity(); 00626 assert(sec); 00627 00628 contents = sec->decrypt( mAor.getAor(), sBody ); 00629 00630 if ( !contents ) 00631 { 00632 Uri from = msg->header(h_From).uri(); 00633 InfoLog( << "Some problem decoding signed SMIME message"); 00634 00635 mCallback->receivePageFailed( from ); 00636 return; 00637 } 00638 00639 encrypted=true; 00640 } 00641 00642 Pkcs7Contents* eBody = dynamic_cast<Pkcs7Contents*>(contents); 00643 if ( eBody ) 00644 { 00645 assert( eBody ); 00646 Security* sec = mStack->getSecurity(); 00647 assert(sec); 00648 00649 contents = sec->decrypt( mAor.getAor(), eBody ); 00650 00651 if ( !contents ) 00652 { 00653 Uri from = msg->header(h_From).uri(); 00654 InfoLog( << "Some problem decoding SMIME message"); 00655 00656 mCallback->receivePageFailed( from ); 00657 return; 00658 } 00659 00660 encrypted=true; 00661 } 00662 00663 #endif 00664 00665 if ( contents ) 00666 { 00667 PlainContents* plain = dynamic_cast<PlainContents*>(contents); 00668 if ( plain ) 00669 { 00670 assert( plain ); 00671 const Data& text = plain->text(); 00672 DebugLog ( << "got message from with text of <" << text << ">" ); 00673 00674 Uri from = msg->header(h_From).uri(); 00675 DebugLog ( << "got message from " << from ); 00676 00677 assert( mCallback ); 00678 mCallback->receivedPage( text, from, signedBy, sigStat, encrypted ); 00679 return; 00680 } 00681 00682 CpimContents* cpim = dynamic_cast<CpimContents*>(contents); 00683 if ( cpim ) 00684 { 00685 assert( cpim ); 00686 const Data& text = cpim->text(); 00687 DebugLog ( << "got CPIM message from with text of <" << text << ">" ); 00688 00689 // !cj! TODO - should get from out of CPIM message 00690 Uri from = msg->header(h_From).uri(); 00691 DebugLog ( << "got message from " << from ); 00692 00693 assert( mCallback ); 00694 mCallback->receivedPage( text, from, signedBy, sigStat, encrypted ); 00695 return; 00696 } 00697 00698 MultipartMixedContents* mixed = dynamic_cast<MultipartMixedContents*>(contents); 00699 if ( mixed ) 00700 { 00701 InfoLog( << "Got a multipart mixed" ); 00702 00703 contents = NULL; 00704 00705 MultipartMixedContents::Parts& parts = mixed->parts(); 00706 for( MultipartMixedContents::Parts::const_iterator i = parts.begin(); 00707 i != parts.end(); 00708 ++i) 00709 { 00710 Contents* c = *i; 00711 assert( c ); 00712 InfoLog ( << "mixed has a " << c->getType() ); 00713 00714 if ( c->getType() == Mime("text","plain") ) 00715 { 00716 InfoLog ( << "mixed has sipfrag " << c->getType() ); 00717 00718 PlainContents* plainBody = dynamic_cast<PlainContents*>(c); 00719 if ( plainBody ) 00720 { 00721 assert( plainBody ); 00722 const Data& text = plainBody->text(); 00723 DebugLog ( << "got message from with text of <" << text << ">" ); 00724 00725 Uri from = msg->header(h_From).uri(); 00726 DebugLog ( << "got message from " << from ); 00727 00728 assert( mCallback ); 00729 mCallback->receivedPage( text, from, signedBy, sigStat, encrypted ); 00730 return; 00731 } 00732 00733 // !cj! TODO - should deal with CPIM too 00734 } 00735 00736 } 00737 00738 return; 00739 } 00740 00741 #if 1 // !cj! TODO remove 00742 OctetContents* octets = dynamic_cast<OctetContents*>(contents); 00743 if (octets) 00744 { 00745 assert( contents ); 00746 const Data& text = octets->getBodyData(); 00747 DebugLog ( << "got message from with text of <" << text << ">" ); 00748 00749 Uri from = msg->header(h_From).uri(); 00750 DebugLog ( << "got message from " << from ); 00751 00752 assert( mCallback ); 00753 mCallback->receivedPage( text, from, signedBy, sigStat, encrypted ); 00754 return; 00755 } 00756 #endif 00757 00758 // deal with it if no one else has 00759 { 00760 InfoLog ( << "Can not handle type " << contents->getType() ); 00761 Uri from = msg->header(h_From).uri(); 00762 mCallback->receivePageFailed( from ); 00763 return; 00764 } 00765 } 00766 } 00767 00768 00769 void 00770 TuIM::processResponse(SipMessage* msg) 00771 { 00772 assert( msg->exists(h_CallId)); 00773 CallId id = msg->header(h_CallId); 00774 assert( id.value() != Data::Empty ); 00775 00776 processSipFrag( msg ); 00777 00778 // see if it is a registraition response 00779 CallId regId = mRegistrationDialog.getCallId(); 00780 00781 Data v1 = id.value(); 00782 Data v2 = regId.value(); 00783 00784 InfoLog( << "want id =" << id ); 00785 00786 if ( id == regId ) 00787 { 00788 InfoLog ( << "matched the reg dialog" 00789 << mRegistrationDialog.getCallId() << " = " << id ); 00790 processRegisterResponse( msg ); 00791 return; 00792 } 00793 00794 // see if it is a subscribe response 00795 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++) 00796 { 00797 Buddy& buddy = *i; 00798 assert( buddy.presDialog ); 00799 InfoLog( << "check buddy id =" << buddy.presDialog->getCallId() ); 00800 if ( buddy.presDialog->getCallId() == id ) 00801 { 00802 DebugLog ( << "matched the subscribe dialog" ); 00803 processSubscribeResponse( msg, buddy ); 00804 return; 00805 } 00806 } 00807 00808 // see if it is a publish response 00809 for ( StateAgentIterator i=mStateAgents.begin(); i != mStateAgents.end(); i++) 00810 { 00811 assert( i->dialog ); 00812 InfoLog( << "check publish id =" << i->dialog->getCallId() ); 00813 if ( i->dialog->getCallId() == id ) 00814 { 00815 DebugLog ( << "matched the publish dialog" ); 00816 processPublishResponse( msg, *i ); 00817 return; 00818 } 00819 } 00820 00821 // see if it is a notify response 00822 for ( SubscriberIterator i=mSubscribers.begin(); i != mSubscribers.end(); i++) 00823 { 00824 DeprecatedDialog* dialog = i->dialog; 00825 assert( dialog ); 00826 InfoLog( << "check subscriber id =" << dialog->getCallId() ); 00827 if ( dialog->getCallId() == id ) 00828 { 00829 DebugLog ( << "matched the notify dialog" ); 00830 processNotifyResponse( msg, *dialog ); 00831 return; 00832 } 00833 } 00834 00835 // see if it is a page response 00836 for ( PageIterator i=mPages.begin(); i != mPages.end(); i++) 00837 { 00838 assert( i->dialog ); 00839 InfoLog( << "check page id =" << i->dialog->getCallId() ); 00840 if ( i->dialog->getCallId() == id ) 00841 { 00842 DebugLog ( << "matched the MESSAGE dialog" ); 00843 processPageResponse( msg, *i ); 00844 return; 00845 } 00846 } 00847 00848 int number = msg->header(h_StatusLine).responseCode(); 00849 InfoLog( << "got response that DID NOT MATCH of type " << number ); 00850 } 00851 00852 00853 void 00854 TuIM::processRegisterResponse(SipMessage* msg) 00855 { 00856 int number = msg->header(h_StatusLine).responseCode(); 00857 Uri to = msg->header(h_To).uri(); 00858 InfoLog ( << "register of " << to << " got response " << number ); 00859 unsigned int cSeq = msg->header(h_CSeq).sequence(); 00860 00861 if ( number<200 ) 00862 { 00863 return; 00864 } 00865 00866 if ( number >= 200 ) 00867 { 00868 mRegistrationDialog.createDialogAsUAC( *msg ); 00869 } 00870 00871 if ( ((number == 401) || (number == 407)) && (cSeq != mLastAuthCSeq) ) 00872 { 00873 SipMessage* reg = mRegistrationDialog.makeRegister(); 00874 00875 const Data cnonce = Data::Empty; 00876 unsigned int nonceCount=0; 00877 00878 Helper::addAuthorization(*reg,*msg,mAor.user(),mRegistrationPassword,cnonce,nonceCount); 00879 00880 mLastAuthCSeq = reg->header(h_CSeq).sequence(); 00881 00882 reg->header(h_Expires).value() = mRegistrationTimeSeconds; 00883 reg->header(h_Contacts).front().param(p_expires) = mRegistrationTimeSeconds; 00884 00885 mNextTimeToRegister = Timer::getRandomFutureTimeMs( mRegistrationTimeSeconds*1000 ); 00886 00887 InfoLog( << *reg ); 00888 00889 setOutbound( *reg ); 00890 00891 mStack->send( *reg ); 00892 00893 delete reg; reg=NULL; 00894 00895 return; 00896 } 00897 00898 if ( number >= 300 ) 00899 { 00900 assert( mCallback ); 00901 mCallback->registrationFailed( to, number ); 00902 return; 00903 } 00904 00905 if ( (number>=200) && (number<300) ) 00906 { 00907 int expires = mRegistrationTimeSeconds; 00908 00909 if ( msg->exists(h_Expires) ) 00910 { 00911 expires = msg->header(h_Expires).value(); 00912 } 00913 00914 // loop throught the contacts, find me, and extract expire time 00915 resip::ParserContainer<resip::NameAddr>::iterator i = msg->header(h_Contacts).begin(); 00916 while ( i != msg->header(h_Contacts).end() ) 00917 { 00918 try 00919 { 00920 Uri uri = i->uri(); 00921 00922 if ( uri.getAor() == mContact.getAor() ) 00923 { 00924 int e = i->param(p_expires); 00925 DebugLog(<< "match " << uri.getAor() << " e=" << e ); 00926 00927 expires = e; 00928 } 00929 } 00930 catch ( exception* ) 00931 { 00932 InfoLog(<< "Bad contact in 2xx to register - skipped" ); 00933 } 00934 00935 i++; 00936 } 00937 00938 if ( expires < 15 ) 00939 { 00940 InfoLog(<< "Got very small expiers of " << expires ); 00941 expires = 15; 00942 } 00943 00944 mNextTimeToRegister = Timer::getRandomFutureTimeMs( expires*1000 ); 00945 00946 mCallback->registrationWorked( to ); 00947 00948 return; 00949 } 00950 } 00951 00952 00953 void 00954 TuIM::processNotifyResponse(SipMessage* msg, DeprecatedDialog& d ) 00955 { 00956 int number = msg->header(h_StatusLine).responseCode(); 00957 DebugLog( << "got NOTIFY response of type " << number ); 00958 00959 if ( number >= 300 ) 00960 { 00961 // TODO 00962 } 00963 } 00964 00965 00966 void 00967 TuIM::processPublishResponse(SipMessage* msg, StateAgent& sa ) 00968 { 00969 int number = msg->header(h_StatusLine).responseCode(); 00970 DebugLog( << "got PUBLISH response of type " << number ); 00971 00972 if ( number >= 300 ) 00973 { 00974 // TODO 00975 } 00976 } 00977 00978 00979 void 00980 TuIM::processPageResponse(SipMessage* msg, Page& page ) 00981 { 00982 int number = msg->header(h_StatusLine).responseCode(); 00983 DebugLog( << "got MESSAGE response of type " << number ); 00984 00985 if ( number >= 400 ) 00986 { 00987 Uri dest = msg->header(h_To).uri(); 00988 assert( mCallback ); 00989 mCallback->sendPageFailed( dest,number ); 00990 } 00991 00992 if ( (number>=300) && (number<400) ) 00993 { 00994 ParserContainer<NameAddr>::iterator dest = msg->header(h_Contacts).begin(); 00995 while ( dest != msg->header(h_Contacts).end() ) 00996 { 00997 DebugLog(<< "Got a 3xx to" << *dest ); 00998 00999 // send a message to redirected location 01000 Uri uri = dest->uri(); 01001 sendPage( page.text, uri, page.sign, page.encryptFor ); 01002 01003 dest++; 01004 } 01005 } 01006 01007 if ( (number>=200) && (number<300) ) 01008 { 01009 // got a final response for notify - can remove this dialog information 01010 CallId id = msg->header(h_CallId); 01011 01012 for( PageIterator i=mPages.begin(); i != mPages.end(); i++ ) 01013 { 01014 if ( i->dialog->getCallId() == id ) 01015 { 01016 i = mPages.erase( i ); 01017 } 01018 } 01019 } 01020 } 01021 01022 01023 void 01024 TuIM::processSubscribeResponse(SipMessage* msg, Buddy& buddy) 01025 { 01026 int number = msg->header(h_StatusLine).responseCode(); 01027 Uri to = msg->header(h_To).uri(); 01028 InfoLog ( << "subscribe got response " << number << " from " << to ); 01029 01030 if ( (number>=200) && (number<300) ) 01031 { 01032 int expires = mSubscriptionTimeSeconds; 01033 if ( msg->exists(h_Expires) ) 01034 { 01035 expires = msg->header(h_Expires).value(); 01036 } 01037 if ( expires < 15 ) 01038 { 01039 InfoLog( << "Got very small expiers of " << expires ); 01040 expires = 15; 01041 } 01042 01043 assert( buddy.presDialog ); 01044 buddy.presDialog->createDialogAsUAC( *msg ); 01045 01046 buddy.mNextTimeToSubscribe = Timer::getRandomFutureTimeMs( expires*1000 ); 01047 } 01048 01049 if ( (number>=300) && (number<400) ) 01050 { 01051 ParserContainer<NameAddr>::iterator dest = msg->header(h_Contacts).begin(); 01052 while ( dest != msg->header(h_Contacts).end() ) 01053 { 01054 DebugLog(<< "Got a 3xx to" << *dest ); 01055 Uri uri = dest->uri(); 01056 01057 addBuddy( uri , buddy.group ); 01058 01059 buddy.mNextTimeToSubscribe = Timer::getForever(); 01060 01061 dest++; 01062 } 01063 } 01064 01065 if ( (number>=400) ) 01066 { 01067 DebugLog( << "Got an error to some subscription" ); 01068 01069 // take this buddy off line 01070 Uri to = msg->header(h_To).uri(); 01071 assert( mCallback ); 01072 01073 bool changed = true; 01074 01075 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++) 01076 { 01077 Uri u = i->uri; // getBuddyUri(i); 01078 01079 if ( u.getAor() == to.getAor() ) 01080 { 01081 if ( i->online == false ) 01082 { 01083 changed = false; 01084 } 01085 01086 i->online = false; 01087 } 01088 } 01089 01090 if ( changed ) 01091 { 01092 mCallback->presenceUpdate( to, false, Data::Empty ); 01093 } 01094 01095 // try to contact this buddy again later 01096 buddy.mNextTimeToSubscribe = Timer::getRandomFutureTimeMs( mSubscriptionTimeSeconds*1000 ); 01097 } 01098 } 01099 01100 01101 void 01102 TuIM::process() 01103 { 01104 assert( mStack ); 01105 01106 UInt64 now = Timer::getTimeMs(); 01107 01108 // check if register needs refresh 01109 if ( now > mNextTimeToRegister ) 01110 { 01111 if ( mRegistrationDialog.isCreated() ) 01112 { 01113 auto_ptr<SipMessage> msg( mRegistrationDialog.makeRegister() ); 01114 msg->header(h_Expires).value() = mRegistrationTimeSeconds; 01115 setOutbound( *msg ); 01116 mStack->send( *msg ); 01117 } 01118 mNextTimeToRegister = Timer::getRandomFutureTimeMs( mRegistrationTimeSeconds*1000 ); 01119 } 01120 01121 // check if any subscribes need refresh 01122 for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++) 01123 { 01124 if ( now > i->mNextTimeToSubscribe ) 01125 { 01126 Buddy& buddy = *i; 01127 01128 buddy.mNextTimeToSubscribe 01129 = Timer::getRandomFutureTimeMs( mSubscriptionTimeSeconds*1000 ); 01130 01131 assert( buddy.presDialog ); 01132 if ( buddy.presDialog->isCreated() ) 01133 { 01134 auto_ptr<SipMessage> msg( buddy.presDialog->makeSubscribe() ); 01135 01136 msg->header(h_Event).value() = Data("presence");; 01137 msg->header(h_Accepts).push_back( Mime( "application","pidf+xml") ); 01138 msg->header(h_Expires).value() = mSubscriptionTimeSeconds; 01139 01140 setOutbound( *msg ); 01141 01142 mStack->send( *msg ); 01143 } 01144 else 01145 { 01146 // person was not available last time - try to subscribe now 01147 subscribeBuddy( buddy ); 01148 } 01149 } 01150 } 01151 01152 // TODO - go and clean out any subscrption to us that have expired 01153 01154 // check for any messages from the sip stack 01155 SipMessage* msg( mStack->receive() ); 01156 if ( msg ) 01157 { 01158 DebugLog ( << "got message: " << *msg); 01159 01160 if ( msg->isResponse() ) 01161 { 01162 processResponse( msg ); 01163 } 01164 01165 if ( msg->isRequest() ) 01166 { 01167 processRequest( msg ); 01168 } 01169 01170 delete msg; msg=0; 01171 } 01172 } 01173 01174 01175 void 01176 TuIM::registerAor( const Uri& uri, const Data& password ) 01177 { 01178 mRegistrationPassword = password; 01179 01180 //const NameAddr aorName; 01181 //const NameAddr contactName; 01182 //aorName.uri() = uri; 01183 //contactName.uri() = mContact; 01184 //SipMessage* msg = Helper::makeRegister(aorName,aorName,contactName); 01185 01186 auto_ptr<SipMessage> msg( mRegistrationDialog.makeInitialRegister(NameAddr(uri),NameAddr(uri)) ); 01187 01188 msg->header(h_Expires).value() = mRegistrationTimeSeconds; 01189 msg->header(h_Contacts).front().param(p_expires) = mRegistrationTimeSeconds; 01190 01191 Token t; 01192 t = Token(Data("presence")); 01193 msg->header(h_AllowEvents).push_back( t ); 01194 01195 mNextTimeToRegister = Timer::getRandomFutureTimeMs( mRegistrationTimeSeconds*1000 ); 01196 01197 setOutbound( *msg ); 01198 01199 mStack->send( *msg ); 01200 } 01201 01202 01203 int 01204 TuIM::getNumBuddies() const 01205 { 01206 return int(mBuddies.size()); 01207 } 01208 01209 01210 const Uri 01211 TuIM::getBuddyUri(const int index) 01212 { 01213 assert( index >= 0 ); 01214 assert( index < getNumBuddies() ); 01215 01216 return mBuddies[index].uri; 01217 } 01218 01219 01220 const Data 01221 TuIM::getBuddyGroup(const int index) 01222 { 01223 assert( index >= 0 ); 01224 assert( index < getNumBuddies() ); 01225 01226 return mBuddies[index].group; 01227 } 01228 01229 01230 bool 01231 TuIM::getBuddyStatus(const int index, Data* status) 01232 { 01233 assert( index >= 0 ); 01234 assert( index < getNumBuddies() ); 01235 01236 if (status) 01237 { 01238 *status = mBuddies[index].status; 01239 } 01240 01241 bool online = mBuddies[index].online; 01242 01243 return online; 01244 } 01245 01246 01247 void 01248 TuIM::subscribeBuddy( Buddy& buddy ) 01249 { 01250 // subscribe to this budy 01251 auto_ptr<SipMessage> msg( buddy.presDialog->makeInitialSubscribe(NameAddr(buddy.uri),NameAddr(mAor)) ); 01252 01253 msg->header(h_Event).value() = Data("presence");; 01254 msg->header(h_Accepts).push_back( Mime( "application","pidf+xml") ); 01255 msg->header(h_Expires).value() = mSubscriptionTimeSeconds; 01256 01257 buddy.mNextTimeToSubscribe = Timer::getRandomFutureTimeMs( mSubscriptionTimeSeconds*1000 ); 01258 01259 setOutbound( *msg ); 01260 01261 mStack->send( *msg ); 01262 } 01263 01264 01265 void 01266 TuIM::addBuddy( const Uri& uri, const Data& group ) 01267 { 01268 Buddy buddy; 01269 buddy.uri = uri; 01270 buddy.online = false; 01271 buddy.status = Data::Empty; 01272 buddy.group = group; 01273 buddy.presDialog = new DeprecatedDialog( NameAddr(mContact) ); 01274 assert( buddy.presDialog ); 01275 01276 subscribeBuddy( buddy ); 01277 01278 mBuddies.push_back( buddy ); 01279 } 01280 01281 01282 void 01283 TuIM::removeBuddy( const Uri& name) 01284 { 01285 TuIM::BuddyIterator i; 01286 01287 i = mBuddies.begin(); 01288 while ( i != mBuddies.end() ) 01289 { 01290 Uri u = i->uri; 01291 01292 if ( u.getAor() == name.getAor() ) 01293 { 01294 // remove this buddy 01295 // !cj! - should unsubscribe 01296 i = mBuddies.erase(i); 01297 } 01298 else 01299 { 01300 i++; 01301 } 01302 } 01303 } 01304 01305 01306 void 01307 TuIM::sendNotify(DeprecatedDialog* dialog) 01308 { 01309 assert( dialog ); 01310 01311 auto_ptr<SipMessage> msg( dialog->makeNotify() ); 01312 01313 Pidf* pidf = new Pidf( *mPidf ); 01314 01315 msg->header(h_Event).value() = "presence"; 01316 01317 Token state; 01318 state.value() = Data("active"); 01319 state.param(p_expires) = dialog->getExpirySeconds(); 01320 msg->header(h_SubscriptionState) = state; 01321 01322 msg->setContents( pidf ); 01323 01324 setOutbound( *msg ); 01325 01326 mStack->send( *msg ); 01327 } 01328 01329 01330 void 01331 TuIM::sendPublish(StateAgent& sa) 01332 { 01333 assert( sa.dialog ); 01334 01335 auto_ptr<SipMessage> msg( sa.dialog->makeInitialPublish(NameAddr(sa.uri),NameAddr(mAor)) ); 01336 01337 Pidf* pidf = new Pidf( *mPidf ); 01338 01339 msg->header(h_Event).value() = "presence"; 01340 01341 msg->setContents( pidf ); 01342 01343 setOutbound( *msg ); 01344 01345 mStack->send( *msg ); 01346 } 01347 01348 01349 void 01350 TuIM::authorizeSubscription( const Data& user ) 01351 { 01352 // TODO implement this 01353 } 01354 01355 01356 void 01357 TuIM::setMyPresence( const bool open, const Data& status, const Data& user ) 01358 { 01359 // TODO implement the pser user status (when user is not empty) 01360 assert( mPidf ); 01361 mPidf->setSimpleStatus( open, status, mContact.getAor() ); 01362 01363 for ( SubscriberIterator i=mSubscribers.begin(); i != mSubscribers.end(); i++) 01364 { 01365 DeprecatedDialog* dialog = i->dialog; 01366 assert( dialog ); 01367 01368 sendNotify(dialog); 01369 } 01370 01371 for ( StateAgentIterator i=mStateAgents.begin(); i != mStateAgents.end(); i++) 01372 { 01373 sendPublish( *i ); 01374 } 01375 } 01376 01377 01378 void 01379 TuIM::setOutboundProxy( const Uri& uri ) 01380 { 01381 InfoLog( << "Set outbound proxy to " << uri ); 01382 mOutboundProxy = uri; 01383 } 01384 01385 01386 void 01387 TuIM::setUAName( const Data& name ) 01388 { 01389 DebugLog( << "Set User Agent Name to " << name ); 01390 mUAName = name; 01391 } 01392 01393 01394 void 01395 TuIM::setOutbound( SipMessage& msg ) 01396 { 01397 if ( msg.isResponse() ) 01398 { 01399 return; 01400 } 01401 01402 if ( !mOutboundProxy.host().empty() ) 01403 { 01404 NameAddr proxy( mOutboundProxy ); 01405 msg.header(h_Routes).push_front( proxy ); 01406 } 01407 01408 if ( !mUAName.empty() ) 01409 { 01410 DebugLog( << "UserAgent name=" << mUAName ); 01411 msg.header(h_UserAgent).value() = mUAName; 01412 } 01413 01414 if ( mDefaultProtocol != UNKNOWN_TRANSPORT ) 01415 { 01416 if ( ! msg.header(h_RequestLine).uri().exists(p_transport) ) 01417 { 01418 msg.header(h_RequestLine).uri().param(p_transport) = Tuple::toDataLower(mDefaultProtocol); 01419 } 01420 } 01421 } 01422 01423 01424 void 01425 TuIM::setDefaultProtocol( TransportType protocol ) 01426 { 01427 mDefaultProtocol = protocol; 01428 } 01429 01430 01431 void 01432 TuIM::addStateAgent( const Uri& uri ) 01433 { 01434 StateAgent sa; 01435 01436 sa.dialog = new DeprecatedDialog( NameAddr(mContact) ); 01437 sa.uri = uri; 01438 01439 mStateAgents.push_back( sa ); 01440 01441 sendPublish( sa ); 01442 } 01443 01444 01445 bool 01446 TuIM::Callback::authorizeSubscription( const Uri& user ) 01447 { 01448 return true; 01449 } 01450 01451 01452 /* ==================================================================== 01453 * The Vovida Software License, Version 1.0 01454 * 01455 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 01456 * 01457 * Redistribution and use in source and binary forms, with or without 01458 * modification, are permitted provi 01459 ded that the following conditions 01460 * are met: 01461 * 01462 * 1. Redistributions of source code must retain the above copyright 01463 * notice, this list of conditions and the following disclaimer. 01464 * 01465 * 2. Redistributions in binary form must reproduce the above copyright 01466 * notice, this list of conditions and the following disclaimer in 01467 * the documentation and/or other materials provided with the 01468 * distribution. 01469 * 01470 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 01471 * and "Vovida Open Communication Application Library (VOCAL)" must 01472 * not be used to endorse or promote products derived from this 01473 * software without prior written permission. For written 01474 * permission, please contact vocal@vovida.org. 01475 * 01476 * 4. Products derived from this software may not be called "VOCAL", nor 01477 * may "VOCAL" appear in their name, without prior written 01478 * permission of Vovida Networks, Inc. 01479 * 01480 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 01481 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 01482 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 01483 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 01484 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 01485 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 01486 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 01487 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 01488 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 01489 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 01490 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 01491 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 01492 * DAMAGE. 01493 * 01494 * ==================================================================== 01495 * 01496 * This software consists of voluntary contributions made by Vovida 01497 * Networks, Inc. and many individuals on behalf of Vovida Networks, 01498 * Inc. For more information on Vovida Networks, Inc., please see 01499 * <http://www.vovida.org/>. 01500 * 01501 */
1.7.5.1