/[resiprocate]/main/resip/dum/Dialog.cxx
ViewVC logotype

Diff of /main/resip/dum/Dialog.cxx

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4001 by derek, Wed Mar 16 20:52:17 2005 UTC revision 4010 by jason, Sat Mar 19 03:54:17 2005 UTC
# Line 8  Line 8 
8  #include "resiprocate/dum/ClientSubscription.hxx"  #include "resiprocate/dum/ClientSubscription.hxx"
9  #include "resiprocate/dum/Dialog.hxx"  #include "resiprocate/dum/Dialog.hxx"
10  #include "resiprocate/dum/DialogUsageManager.hxx"  #include "resiprocate/dum/DialogUsageManager.hxx"
11    #include "resiprocate/dum/MasterProfile.hxx"
12  #include "resiprocate/dum/InviteSessionCreator.hxx"  #include "resiprocate/dum/InviteSessionCreator.hxx"
13  #include "resiprocate/dum/InviteSessionHandler.hxx"  #include "resiprocate/dum/InviteSessionHandler.hxx"
14  #include "resiprocate/dum/ServerInviteSession.hxx"  #include "resiprocate/dum/ServerInviteSession.hxx"
# Line 15  Line 16 
16  #include "resiprocate/dum/SubscriptionHandler.hxx"  #include "resiprocate/dum/SubscriptionHandler.hxx"
17  #include "resiprocate/dum/UsageUseException.hxx"  #include "resiprocate/dum/UsageUseException.hxx"
18  #include "resiprocate/os/Logger.hxx"  #include "resiprocate/os/Logger.hxx"
19    #include "resiprocate/os/Inserter.hxx"
20  #if defined(WIN32) && defined(_DEBUG) && defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio  #include "resiprocate/os/WinLeakCheck.hxx"
 #define _CRTDBG_MAP_ALLOC  
 #include <stdlib.h>  
 #include <crtdbg.h>  
 #define new   new( _NORMAL_BLOCK, __FILE__, __LINE__)  
 #endif // defined(WIN32) && defined(_DEBUG)  
21    
22  #define RESIPROCATE_SUBSYSTEM Subsystem::DUM  #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
23    
# Line 40  Line 36 
36       mLocalContact(),       mLocalContact(),
37       mLocalCSeq(0),       mLocalCSeq(0),
38       mRemoteCSeq(0),       mRemoteCSeq(0),
39         mAckId(0),
40       mRemoteTarget(),       mRemoteTarget(),
41       mLocalNameAddr(),       mLocalNameAddr(),
42       mRemoteNameAddr(),       mRemoteNameAddr(),
# Line 224  Line 221 
221     }     }
222    
223     delete mInviteSession;     delete mInviteSession;
   
224     mDialogSet.mDialogs.erase(this->getId());     mDialogSet.mDialogs.erase(this->getId());
225     delete mAppDialog;     delete mAppDialog;
226     mDialogSet.possiblyDie();     mDialogSet.possiblyDie();
# Line 237  Line 233 
233  }  }
234    
235  void  void
236    Dialog::cancel()
237    {
238       assert(mType == Invitation);
239       ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
240       assert (uac);
241       uac->cancel();
242    }
243    
244    void
245  Dialog::end()  Dialog::end()
246  {  {
247     if (mInviteSession)     if (mInviteSession)
# Line 277  Line 282 
282  void  void
283  Dialog::dispatch(const SipMessage& msg)  Dialog::dispatch(const SipMessage& msg)
284  {  {
285       // !jf! Should be checking for messages with out of order CSeq and rejecting
286    
287     DebugLog ( << "Dialog::dispatch: " << msg.brief());     DebugLog ( << "Dialog::dispatch: " << msg.brief());
288     handleTargetRefresh(msg);     handleTargetRefresh(msg);
289     if (msg.isRequest())     if (msg.isRequest())
# Line 304  Line 311 
311                 mInviteSession->dispatch(request);                 mInviteSession->dispatch(request);
312              }              }
313              break;              break;
314             case UPDATE:
315                if (mInviteSession == 0)
316                {
317                   InfoLog ( << "Spurious UPDATE" );
318                   return;
319                }
320                else
321                {
322                   mInviteSession->dispatch(request);
323                }
324                break;
325           case INFO:           case INFO:
326              if (mInviteSession == 0)              if (mInviteSession == 0)
327              {              {
# Line 351  Line 369 
369                    server->dispatch(request);                    server->dispatch(request);
370                 }                 }
371              }              }
 //            mDum.mInviteSessionHandler->onRefer(mInviteSession->getSessionHandle(), server->getHandle(), msg);  
372           }           }
373           break;           break;
374           case REFER:           case REFER:
# Line 403  Line 420 
420              {              {
421                 BaseCreator* creator = mDialogSet.getCreator();                 BaseCreator* creator = mDialogSet.getCreator();
422                 if (creator && (creator->getLastRequest().header(h_RequestLine).method() == SUBSCRIBE ||                 if (creator && (creator->getLastRequest().header(h_RequestLine).method() == SUBSCRIBE ||
423                                 creator->getLastRequest().header(h_RequestLine).method() == REFER))                                 creator->getLastRequest().header(h_RequestLine).method() == REFER))  // !slg! OOD Refer?  Click-to-Call?
424                 {                 {
425                    DebugLog (<< "Making subscription (from creator) request: " << creator->getLastRequest());                    DebugLog (<< "Making subscription (from creator) request: " << creator->getLastRequest());
426                    ClientSubscription* sub = makeClientSubscription(creator->getLastRequest());                    ClientSubscription* sub = makeClientSubscription(creator->getLastRequest());
427                    mClientSubscriptions.push_back(sub);                    mClientSubscriptions.push_back(sub);
428                    sub->dispatch(request);                    sub->dispatch(request);
429                 }                 }
430                 else if (mInviteSession->mLastRequest.header(h_RequestLine).method() == REFER)                 else
431                   {
432                               if (mInviteSession != 0 && (!msg.exists(h_Event) || msg.header(h_Event).value() == "refer"))
433                 {                 {
434                    DebugLog (<< "Making subscription from refer: " << mInviteSession->mLastRequest);                            DebugLog (<< "Making subscription from NOTIFY: " << msg);
435                    ClientSubscription* sub = makeClientSubscription(mInviteSession->mLastRequest);                        ClientSubscription* sub = makeClientSubscription(msg);
436                    mClientSubscriptions.push_back(sub);                    mClientSubscriptions.push_back(sub);
437                                      ClientSubscriptionHandle client = sub->getHandle();
438                                          InviteSessionHandler* handler = mDum.mInviteSessionHandler;
439                    sub->dispatch(request);                    sub->dispatch(request);
440                          if (client.isValid())
441                          {
442                             handler->onReferAccepted(mInviteSession->getSessionHandle(), client, msg);
443                 }                 }
444                 else                 else
445                 {                 {
446                    SipMessage failure;                           handler->onReferRejected(mInviteSession->getSessionHandle(), msg);
                   makeResponse(failure, request, 481);  
                   failure.header(h_To).remove(p_tag); // otherwise it will be INVALID  
                   InfoLog (<< "Sending 481 - no dialog created " << endl << failure);  
                   mDum.sendResponse(failure);  
                   return;  
                }  
447              }              }
448           }           }
          break;  
         default:  
            assert(0);  
            return;  
       }  
    }  
    else if (msg.isResponse())  
    {  
       if (!mDialogSet.getCreator() ||  
           !(msg.header(h_CSeq) == mDialogSet.getCreator()->getLastRequest().header(h_CSeq)))  
       {  
          SipMessage* lastRequest = 0;              
          switch (msg.header(h_CSeq).method())  
          {  
             case INVITE:  
             case CANCEL:  
             case REFER:  
             case BYE:  
                if (mInviteSession == 0)  
                {  
                   //spurious  
                   return;  
                }  
449                 else                 else
450                 {                 {
451                    lastRequest = &mInviteSession->mLastRequest;                        SipMessage response;
452                          makeResponse(response, msg, 406);
453                          send(response);
454                                       }
455                 }                 }
                break;  
             case SUBSCRIBE:  //doesn't handle multiple usages  
                if (mClientSubscriptions.empty())  
                {  
                   //spurious  
                   return;  
456                 }                 }
                else  
                {  
                   lastRequest = &mClientSubscriptions.front()->mLastRequest;  
457                 }                 }
458                 break;                 break;
459              case NOTIFY: //doesn't handle multiple usages          default:
460                 if (mServerSubscriptions.empty())             assert(0);
                {  
                   //spurious  
461                    return;                    return;
462                 }                 }
                else  
                {  
                   lastRequest = &mServerSubscriptions.front()->mLastNotify;  
463                 }                 }
464                 break;                   else if (msg.isResponse())
             case INFO:  
465              {              {
466                 if (mInviteSession == 0)        // !jf! There is a substantial change in how this works in teltel-branch
467          // from how it worked in main branch pre merge.
468          // If the response doesn't match a cseq for a request I've sent, ignore
469          // the response
470          RequestMap::iterator r = mRequests.find(msg.header(h_CSeq).sequence());
471          if (r != mRequests.end())
472                 {                 {
473                    //spurious           if (mDum.mClientAuthManager.get() && mDum.mClientAuthManager->handle(*mDialogSet.getUserProfile(), r->second, msg))
                   return;  
                }  
                else  
                {  
                   lastRequest = &mInviteSession->mLastNit;  
                }  
                break;                
             }  
             default:  
                break;  
          }  
                  if ( lastRequest && mDum.mClientAuthManager.get() && mDum.mClientAuthManager->handle( *lastRequest, msg ) )  
474           {           {
475              InfoLog( << "about to re-send request with digest credentials" );              InfoLog( << "about to re-send request with digest credentials" );
476              InfoLog( << *lastRequest );              InfoLog( << r->second );
477              mLocalCSeq++;              
478              mDum.send(*lastRequest);              assert (r->second.isRequest());
479              return;              if (r->second.header(h_RequestLine).method() == ACK)
          }  
          else  
480           {                       {            
481              InfoLog( << "Not handling challenge: " << msg);                 // store the CSeq for ACK
482                   mAckId = mLocalCSeq;
483                }
484    
485                mLocalCSeq++;
486                send(r->second);
487           }           }
488             mRequests.erase(r);
489        }        }
490                
491        const SipMessage& response = msg;        const SipMessage& response = msg;
# Line 523  Line 503 
503        switch (response.header(h_CSeq).method())        switch (response.header(h_CSeq).method())
504        {        {
505           case INVITE:           case INVITE:
506                // store the CSeq for ACK
507                mAckId = msg.header(h_CSeq).sequence();
508              if (mInviteSession == 0)              if (mInviteSession == 0)
509              {              {
510                 // #if!jf! don't think creator needs a dispatch                 // #if!jf! don't think creator needs a dispatch
# Line 544  Line 526 
526           case ACK:           case ACK:
527           case CANCEL:           case CANCEL:
528           case INFO:           case INFO:
529              if (mInviteSession != 0)           case UPDATE:
530                if (mInviteSession)
531              {              {
532                 mInviteSession->dispatch(response);                 mInviteSession->dispatch(response);
533              }              }
534              // else drop on the floor              // else drop on the floor
535              break;                            break;              
536    
537           case REFER:           case REFER:
538                if (code >= 300)
539           {           {
540              int code = response.header(h_StatusLine).statusCode();                         InviteSessionHandler* handler = mDum.mInviteSessionHandler;
541              if (code < 300)                 handler->onReferRejected(mInviteSession->getSessionHandle(), msg);
             {  
                // throw it away  
                return;  
             }              
             else  
             {  
                if (mInviteSession && mDum.mInviteSessionHandler)  
                {  
                   mDum.mInviteSessionHandler->onReferRejected(mInviteSession->getSessionHandle(), response);  
                }  
             }          
542           }           }
543                // else no need for action - first Notify will cause onReferAccepted to be called
544           break;                   break;        
545    
546           case SUBSCRIBE:           case SUBSCRIBE:
547           {           {
548              int code = response.header(h_StatusLine).statusCode();              int code = response.header(h_StatusLine).statusCode();
# Line 638  Line 614 
614              assert(0);              assert(0);
615              return;              return;
616        }        }
617  #if 0      
618    #if 0     // merged from head back to teltel-branch
619        if (msg.header(h_StatusLine).statusCode() >= 400        if (msg.header(h_StatusLine).statusCode() >= 400
620            && Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)            && Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)
621        {        {
# Line 745  Line 722 
722     return handles;     return handles;
723  }  }
724    
   
725  std::vector<ClientSubscriptionHandle>  std::vector<ClientSubscriptionHandle>
726  Dialog::getClientSubscriptions()  Dialog::getClientSubscriptions()
727  {  {
# Line 787  Line 763 
763        ClientInviteSession* cInv = dynamic_cast<ClientInviteSession*>(mInviteSession);        ClientInviteSession* cInv = dynamic_cast<ClientInviteSession*>(mInviteSession);
764        if (cInv)        if (cInv)
765        {        {
766           cInv->redirected(msg);                   cInv->handleRedirect(msg);
       }  
    }  
 }  
   
   
 #if 0  
 void  
 Dialog::processNotify(const SipMessage& notify)  
 {  
    if (notify.isRequest())  
    {  
       if (findSubscriptions().empty())  
       {  
          SubscriptionCreator* creator = dynamic_cast<SubscriptionCreator*>(DialogSetId(notify).getCreator());  
          if (creator)  
          {  
             creator->makeNewSubscription(notify);  
767           }           }
768        }        }
       else  
       {  
          for (std::list<BaseUsage*>::iterator i=mUsages.begin(); i!=mUsages.end(); i++)  
          {  
             ClientSubscription* sub = dynamic_cast<ClientSubscription*>(*i);  
             if (sub && sub->matches(notify))  
             {  
                sub->process(notify);  
                break;  
             }  
769           }           }
       }  
    }  
 }  
 #endif  
   
770    
771  void  void
772  Dialog::makeRequest(SipMessage& request, MethodTypes method)  Dialog::makeRequest(SipMessage& request, MethodTypes method)
# Line 841  Line 785 
785    
786     request.remove(h_RecordRoutes);  //!dcm! -- all of this is rather messy     request.remove(h_RecordRoutes);  //!dcm! -- all of this is rather messy
787    
788     request.header(h_Contacts).clear();       request.remove(h_Contacts);
789     request.header(h_Contacts).push_front(mLocalContact);       request.header(h_Contacts).push_front(mLocalContact);  
790    
791     request.header(h_CSeq).method() = method;     request.header(h_CSeq).method() = method;
792     request.header(h_MaxForwards).value() = 70;     request.header(h_MaxForwards).value() = 70;
793    
# Line 875  Line 820 
820        request.remove(h_Requires);        request.remove(h_Requires);
821        request.remove(h_ProxyRequires);        request.remove(h_ProxyRequires);
822        request.remove(h_Supporteds);        request.remove(h_Supporteds);
823          request.header(h_CSeq).sequence() = mAckId;
824     }     }
825    
826     // If method is INVITE then advertise required headers     // If method is INVITE then advertise required headers
827     if(method == INVITE)     if(method == INVITE || method == UPDATE)
828     {     {
829        if(mDum.getProfile()->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getProfile()->getAllowedMethods();        if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
830        if(mDum.getProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getProfile()->getSupportedEncodings();        if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
831        if(mDum.getProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) request.header(h_AcceptLanguages) = mDum.getProfile()->getSupportedLanguages();        if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) request.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
832        if(mDum.getProfile()->isAdvertisedCapability(Headers::Supported)) request.header(h_Supporteds) = mDum.getProfile()->getSupportedOptionTags();        if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) request.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
833     }     }
834    
    // Remove Session Timer headers for all requests except INVITE and UPDATE  
    if(method != INVITE && method != UPDATE)  
    {  
       request.remove(h_SessionExpires);  
       request.remove(h_MinSE);  
    }  
835     DebugLog ( << "Dialog::makeRequest: " << request );     DebugLog ( << "Dialog::makeRequest: " << request );
836  }  }
837    
# Line 913  Line 853 
853     //not sure of these     //not sure of these
854     request.header(h_To).remove(p_tag);       request.header(h_To).remove(p_tag);  
855     request.remove(h_RecordRoutes);     request.remove(h_RecordRoutes);
856     request.header(h_Contacts).clear();       request.remove(h_Contacts);
857     request.header(h_Contacts).push_front(mLocalContact);       request.header(h_Contacts).push_front(mLocalContact);  
858     request.header(h_MaxForwards).value() = 70;     request.header(h_MaxForwards).value() = 70;
859  }  }
# Line 934  Line 874 
874               request.header(h_RequestLine).getMethod() == MESSAGE ||               request.header(h_RequestLine).getMethod() == MESSAGE ||
875               request.header(h_RequestLine).getMethod() == NOTIFY ||               request.header(h_RequestLine).getMethod() == NOTIFY ||
876               request.header(h_RequestLine).getMethod() == INFO ||               request.header(h_RequestLine).getMethod() == INFO ||
877               request.header(h_RequestLine).getMethod() == OPTIONS               request.header(h_RequestLine).getMethod() == OPTIONS ||
878                 request.header(h_RequestLine).getMethod() == UPDATE
879               );               );
880                
881  //      assert (request.header(h_RequestLine).getMethod() == CANCEL ||  // Contact header is not required for Requests that do not form a dialog  //      assert (request.header(h_RequestLine).getMethod() == CANCEL ||  // Contact header is not required for Requests that do not form a dialog
# Line 942  Line 883 
883  //                    request.header(h_Contacts).size() == 1);  //                    request.header(h_Contacts).size() == 1);
884        Helper::makeResponse(response, request, code, mLocalContact);        Helper::makeResponse(response, request, code, mLocalContact);
885        response.header(h_To).param(p_tag) = mId.getLocalTag();        response.header(h_To).param(p_tag) = mId.getLocalTag();
886    
887          if((request.header(h_RequestLine).getMethod() == INVITE ||
888              request.header(h_RequestLine).getMethod() == UPDATE)
889             && code >= 200 && code < 300)
890          {
891             // Check if we should add our capabilites to the invite success response
892             if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) response.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
893             if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) response.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
894             if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) response.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
895             if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) response.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
896          }
897     }     }
898     else     else
899     {     {
900        Helper::makeResponse(response, request, code);        Helper::makeResponse(response, request, code);
901        response.header(h_To).param(p_tag) = mId.getLocalTag();        response.header(h_To).param(p_tag) = mId.getLocalTag();
   
902     }     }
903     DebugLog ( << "Dialog::makeResponse: " << response);       DebugLog ( << "Dialog::makeResponse: " << response);  
904  }  }
# Line 989  Line 940 
940  {  {
941  }  }
942    
 void  
 Dialog::update(const SipMessage& msg)  
 {  
 }  
943    
 #if 0  
944  void  void
945  Dialog::setLocalContact(const NameAddr& localContact)  Dialog::send(SipMessage& msg)
946  {  {
947     mLocalContact = localContact;     if (msg.isRequest() && msg.header(h_CSeq).method() != ACK)
948       {
949          mRequests[msg.header(h_CSeq).sequence()] = msg;
950       }
951       mDum.send(msg);
952  }  }
953    
954  void  void
955  Dialog::setRemoteTarget(const NameAddr& remoteTarget)  Dialog::onForkAccepted()
956    {
957       ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
958       if (uac)
959  {  {
960     mRemoteTarget = remoteTarget;        uac->onForkAccepted();
961       }
962  }  }
 #endif  
963    
964  void Dialog::possiblyDie()  void Dialog::possiblyDie()
965  {  {
# Line 1016  Line 969 
969            mServerSubscriptions.empty() &&            mServerSubscriptions.empty() &&
970            !mInviteSession)            !mInviteSession)
971        {        {
972           delete this;           mDum.destroy(this);
       }  
    }    
 }  
   
 bool  
 Dialog::matches(const SipMessage& msg)  
 {  
    //currently only responses are passed to this method  
    if (msg.isRequest())  
    {  
       return false;  
    }  
   
    switch (msg.header(h_CSeq).method())  
    {  
       case INVITE:  
       case CANCEL:  
       case REFER:  
       case BYE:  
          if (mInviteSession == 0)  
          {  
             return false;  
          }  
          else  
          {  
             return msg.getTransactionId() == mInviteSession->mLastRequest.getTransactionId();  
          }  
          break;                
       case INFO:  
          if (mInviteSession == 0)  
          {  
             return false;  
          }  
          else  
          {  
             return msg.getTransactionId() == mInviteSession->mLastNit.getTransactionId();  
          }  
          break;  
       case SUBSCRIBE:  
          if (mClientSubscriptions.empty())  
          {  
             return false;  
          }  
          else  
          {  
             for (std::list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();  
                  it != mClientSubscriptions.end(); it++)  
             {  
                return msg.getTransactionId() == (*it)->mLastRequest.getTransactionId();  
             }  
          }  
          break;  
       case NOTIFY:  
          if (mServerSubscriptions.empty())  
          {  
             return false;  
973           }           }
          else  
          {  
             for (std::list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();  
                  it != mServerSubscriptions.end(); it++)  
             {  
                return msg.getTransactionId() == (*it)->mLastNotify.getTransactionId();  
             }  
          }  
          break;  
       default:  
          return false;  
974     }     }
    return false;    
975  }  }
976    
977  ostream&  ostream&
978  resip::operator<<(ostream& strm, const Dialog& dialog)  resip::operator<<(ostream& strm, const Dialog& dialog)
979  {  {
980       strm
981          << "mClientSubscriptions("
982          << dialog.mClientSubscriptions.size()
983          << "), "
984          << "mServerSubscriptions("
985          << dialog.mServerSubscriptions.size()
986          << ")";
987     return strm;     return strm;
988  }  }
989    
 void  
 Dialog::forked(const SipMessage& msg)  
 {  
    assert(msg.isResponse() && msg.header(h_StatusLine).statusCode() < 300);  
990    
991     ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);  /* ====================================================================
992     if (uac)   * The Vovida Software License, Version 1.0
993     {   *
994        uac->forked();   * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
995     }   *
996  }   * Redistribution and use in source and binary forms, with or without
997     * modification, are permitted provided that the following conditions
998  void   * are met:
999  Dialog::cancel()   *
1000  {   * 1. Redistributions of source code must retain the above copyright
1001     ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);   *    notice, this list of conditions and the following disclaimer.
1002     if (uac)   *
1003     {   * 2. Redistributions in binary form must reproduce the above copyright
1004        uac->cancel();   *    notice, this list of conditions and the following disclaimer in
1005     }   *    the documentation and/or other materials provided with the
1006  }   *    distribution.
1007     *
1008     * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1009     *    and "Vovida Open Communication Application Library (VOCAL)" must
1010     *    not be used to endorse or promote products derived from this
1011     *    software without prior written permission. For written
1012     *    permission, please contact vocal@vovida.org.
1013     *
1014     * 4. Products derived from this software may not be called "VOCAL", nor
1015     *    may "VOCAL" appear in their name, without prior written
1016     *    permission of Vovida Networks, Inc.
1017     *
1018     * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1019     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1020     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1021     * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
1022     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1023     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1024     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1025     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1026     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1027     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1028     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1029     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1030     * DAMAGE.
1031     *
1032     * ====================================================================
1033     *
1034     * This software consists of voluntary contributions made by Vovida
1035     * Networks, Inc. and many individuals on behalf of Vovida Networks,
1036     * Inc.  For more information on Vovida Networks, Inc., please see
1037     * <http://www.vovida.org/>.
1038     *
1039     */
1040    

Legend:
Removed from v.4001  
changed lines
  Added in v.4010

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27