reSIProcate/stack  9694
TuIM.cxx
Go to the documentation of this file.
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( &note );
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  */