예제 #1
0
SipSubscribeServer* SipSubscribeServer::buildBasicServer(SipUserAgent& userAgent,
                                                         const char* eventType)
{
    // Create a default publisher container
    SipPublishContentMgr* publishContent = new SipPublishContentMgr();

    // Create a default event handler
    SipSubscribeServerEventHandler* eventHandler = new SipSubscribeServerEventHandler();

    // Create a default subscription mgr
    SipSubscriptionMgr* subscriptionMgr = new SipSubscriptionMgr();

    SipSubscribeServer* newServer =
       new SipSubscribeServer(SipSubscribeServer::terminationReasonNone,
                              userAgent,
                              *publishContent,
                              *subscriptionMgr,
                              *eventHandler);

    if (eventType && *eventType)
    {
        // Enable the server to accept the given SIP event package
        newServer->enableEventType(eventType,
                                   &userAgent,
                                   publishContent,
                                   eventHandler,
                                   subscriptionMgr,
                                   SipSubscribeServer::standardVersionCallback
           );
    }

    return newServer;
}
예제 #2
0
SipSubscribeServer* SipSubscribeServer::buildBasicServer(SipUserAgent& userAgent,
                                                         const char* eventType)
{
    SipSubscribeServer* newServer = NULL;

    // Create a default publisher container
    SipPublishContentMgr* publishContent = new SipPublishContentMgr();

    // Create a default event handler
    SipSubscribeServerEventHandler* eventHandler = new SipSubscribeServerEventHandler();

    // Create a default subscription mgr
    SipSubscriptionMgr* subscriptionMgr = new SipSubscriptionMgr();

    newServer = new SipSubscribeServer(userAgent, 
                                      *publishContent,
                                      *subscriptionMgr,
                                      *eventHandler);

    if(eventType && *eventType)
    {
        // Enable the server to accept the given SIP event package
        newServer->enableEventType(eventType, 
                                   &userAgent, 
                                   publishContent,
                                   eventHandler,
                                   subscriptionMgr);
    }

    return(newServer);
}
예제 #3
0
   void setUp()
      {
         hostIp = "127.0.0.1";

         eventName = SIP_EVENT_MESSAGE_SUMMARY;
         mwiMimeType = CONTENT_TYPE_SIMPLE_MESSAGE_SUMMARY;;

         // Construct a user agent that will function both as the subscriber
         // and the notfier.
         // Construct the URI of the notifier, which is also the URI of
         // the subscriber.
         // Also construct the name-addr version of the URI, which may be
         // different if it has a "transport" parameter.
         // And the resource-id to use, which is the AOR with any
         // parameters stripped off.

         createTestSipUserAgent(hostIp,
                                "111",
                                userAgentp,
                                aor,
                                aor_name_addr,
                                aor_contact_name_addr,
                                resource_id);

         subServerp =
            SipSubscribeServer::buildBasicServer(*userAgentp,
                                                 eventName);
         subServerp->start();

         // Get pointers to the Subscription Manager and Dialog Manager.
         subMgrp = subServerp->getSubscriptionMgr(eventName);
         CPPUNIT_ASSERT(subMgrp);
         dialogMgrp = subMgrp->getDialogMgr();
         CPPUNIT_ASSERT(dialogMgrp);

         // Create a simple Subscription client
         // Register an interest in SUBSCRIBE responses and NOTIFY requests
         // for this event type
         userAgentp->addMessageObserver(incomingClientMsgQueue,
                                        SIP_SUBSCRIBE_METHOD,
                                        FALSE, // no requests
                                        TRUE, // reponses
                                        TRUE, // incoming
                                        FALSE, // no outgoing
                                        eventName,
                                        NULL,
                                        NULL);
         userAgentp->addMessageObserver(incomingClientMsgQueue,
                                        SIP_NOTIFY_METHOD,
                                        TRUE, // requests
                                        FALSE, // not reponses
                                        TRUE, // incoming
                                        FALSE, // no outgoing
                                        eventName,
                                        NULL,
                                        NULL);
      }
예제 #4
0
void SipSubscribeServer::contentChangeCallback(void* applicationData,
                                               const char* resourceId,
                                               const char* eventTypeKey,
                                               const char* eventType,
                                               UtlBoolean isDefaultContent)
{
    SipSubscribeServer* subServer = (SipSubscribeServer*)applicationData;
    subServer->notifySubscribers(resourceId, 
                                 eventTypeKey,
                                 eventType,
                                 isDefaultContent);
}
예제 #5
0
void SipSubscribeServer::contentChangeCallback(void* applicationData,
                                               const char* resourceId,
                                               const char* eventTypeKey,
                                               const char* eventType,
                                               const char* reason)
{
    SipSubscribeServer* subServer =
       (SipSubscribeServer*) applicationData;
    subServer->notifySubscribers(resourceId,
                                 eventTypeKey,
                                 eventType,
                                 reason);
}
예제 #6
0
int main(int argc, char* argv[])
{
    bool bError = true ;
    int iSipPort, iRtpPort ;
    bool bLoopback ;
    char* szIdentity ;
    char* szUsername ;
    char* szPassword ;
    char* szRealm ;
    char* szStunServer ;
    char* szProxy ;
    bool bDialogEvents ;
    // The default run time is 2^31-1 seconds, which is over 68 years.
    long int runTime = LONG_MAX;
    SIPX_INST hInst ;
    SIPX_LINE hLine ;
    // Support for the dialog event notifier.
    // Component for holding the subscription data
    SipSubscriptionMgr* pSubscriptionMgr;
    // Component for granting the subscription rights
    SipSubscribeServerEventHandler* pPolicyHolder;
    // Component for publishing the event contents
    SipPublishContentMgr* pPublisher;
    SipSubscribeServer* pSubscribeServer;
    // The dialog event publisher
    DialogEventPublisher* pDialogEvents;

    // Parse Arguments
    if (parseArgs(argc, argv, &iDuration, &iSipPort, &iRtpPort, &g_szPlayTones,
                  &g_szFile, &bLoopback, &szIdentity, &szUsername, &szPassword,
                  &szRealm, &szStunServer, &szProxy, &bDialogEvents,
                  &g_callAnswerDelay, &g_timestamp, &runTime) &&
        (iDuration > 0) && (portIsValid(iSipPort)) && (portIsValid(iRtpPort)))
    {
        if (bLoopback)
        {
            initLoopback() ;
        }

        // initialize sipx TAPI-like API
        sipxConfigSetLogLevel(LOG_LEVEL_DEBUG) ;
        sipxConfigSetLogFile("ReceiveCall.log");
        if (sipxInitialize(&hInst, iSipPort, iSipPort, 5061, iRtpPort, 16, szIdentity) == SIPX_RESULT_SUCCESS)
        {
           // Start dialog event notifier if requested.
           if (bDialogEvents)
           {
              // Get pointer to the call manager.
              CallManager* pCallManager =
                 ((SIPX_INSTANCE_DATA*) hInst)->pCallManager;
              SipUserAgent* pUserAgent =
                 ((SIPX_INSTANCE_DATA*) hInst)->pSipUserAgent;

              // Start the SIP Subscribe Server
              pSubscriptionMgr = new SipSubscriptionMgr();
              pPolicyHolder = new SipSubscribeServerEventHandler;
              pPublisher = new SipPublishContentMgr;
              pSubscribeServer = new SipSubscribeServer(*pUserAgent,
                                                        *pPublisher,
                                                        *pSubscriptionMgr,
                                                        *pPolicyHolder);
              pSubscribeServer->enableEventType(DIALOG_EVENT_TYPE,
                                                NULL,
                                                NULL,
                                                NULL,
                                                NULL,
                                                SipSubscribeServer::standardVersionCallback);
              pSubscribeServer->start();

              // Create the dialog event publisher
              pDialogEvents = new DialogEventPublisher(pCallManager,
                                                       pPublisher);
              pCallManager->addTaoListener(pDialogEvents);
              pDialogEvents->start();
           }

            if (szProxy)
            {
                sipxConfigSetOutboundProxy(hInst, szProxy);
            }
            sipxConfigEnableRport(hInst, true) ;
            if (szStunServer)
            {
                sipxConfigEnableStun(hInst, szStunServer, 28) ;
            }
            sipxEventListenerAdd(hInst, EventCallBack, NULL) ;
            hLine = lineInit(hInst, szIdentity, szUsername, szPassword, szRealm) ;

            dumpLocalContacts(hInst) ;

            // Run as long as requested.
            for (long int i = 0; i < runTime; i++)
            {
                SLEEP(1000) ;
            }

            lineShutdown(hInst, hLine);
            // Wait a bit, so that we can re-send the REGISTER if it needs
            // authorization.
            SLEEP(5000);
        }
        else
        {
            printf("unable to initialize sipXtapi layer\n") ;
        }
    }
    else
    {
        usage(argv[0]) ;
    }

    return (int) bError ;
}
예제 #7
0
    void subscribeMwiClientTest()
    {
        smClientExpiration = -1;
        smNumClientNotifiesReceived = 0;
        smLastClientNotifyReceived = NULL;
        smNumClientSubResponsesReceived = 0;
        smLastClientSubResponseReceived = NULL;


        UtlString resourceId("[email protected]:");
        UtlString eventTypeKey("message-summary");
        UtlString eventType(eventTypeKey);
        UtlString from("Frida<sip:111@localhost:");
        UtlString to("Tia<sip:222@localhost:");
        UtlString contact("sip:[email protected]:");
        char portString[20];
        sprintf(portString, "%d", UNIT_TEST_SIP_PORT);
        resourceId.append(portString);
        from.append(portString);
        from.append('>');
        to.append(portString);
        to.append('>');
        contact.append(portString);
        SipUserAgent* userAgent = new SipUserAgent(UNIT_TEST_SIP_PORT, UNIT_TEST_SIP_PORT);
        userAgent->start();

        // Set up the subscribe client
        SipDialogMgr* clientDialogMgr = new SipDialogMgr();
        SipRefreshManager* refreshMgr = new SipRefreshManager(*userAgent, *clientDialogMgr);
        refreshMgr->start();
        SipSubscribeClient* subClient = new SipSubscribeClient(*userAgent, *clientDialogMgr, *refreshMgr);
        subClient->start();

        // Set up the subscribe server
        SipSubscribeServer* subServer = 
           SipSubscribeServer::buildBasicServer(*userAgent, 
                                                eventType);
        SipSubscriptionMgr* subMgr = subServer->getSubscriptionMgr(eventType);
        SipDialogMgr* serverDialogMgr = subMgr->getDialogMgr();
        SipPublishContentMgr* contentMgr = subServer->getPublishMgr(eventType);
        HttpBody* preexistingBodyPtr = NULL;
        UtlBoolean isDefaultContent;

        subServer->start();
        // Enable the handler for the MWI server
        subServer->enableEventType(eventType, userAgent);

        //CPPUNIT_ASSERT(TRUE);
        //ASSERT_STR_EQUAL("a", "a");

        // Create a crude Subscription server/observer
        OsMsgQ incomingServerMsgQueue;
        // Register an interest in SUBSCRIBE requests 
        // for this event type
        userAgent->addMessageObserver(incomingServerMsgQueue,
                                    SIP_SUBSCRIBE_METHOD,
                                    TRUE, // requests
                                    FALSE, // no reponses
                                    TRUE, // incoming
                                    FALSE, // no outgoing
                                    eventType,
                                    NULL,
                                    NULL);

        OsMsgQ incomingClientMsgQueue;
        userAgent->addMessageObserver(incomingClientMsgQueue,
                                    SIP_SUBSCRIBE_METHOD,
                                    FALSE, // no requests
                                    TRUE, // reponses
                                    TRUE, // incoming
                                    FALSE, // no outgoing
                                    eventType,
                                    NULL,
                                    NULL);

        // Should not be any pre-existing content
        CPPUNIT_ASSERT(!contentMgr->getContent(resourceId, eventTypeKey, NULL, preexistingBodyPtr, 
            isDefaultContent));
        int numDefaultContent = -1;
        int numResourceSpecificContent = -1;
        int numCallbacksRegistered = -1;
        contentMgr->getStats(numDefaultContent,
                             numResourceSpecificContent,
                             numCallbacksRegistered);
        CPPUNIT_ASSERT(numDefaultContent == 0);
        CPPUNIT_ASSERT(numResourceSpecificContent == 0);
        CPPUNIT_ASSERT(numCallbacksRegistered == 1);

        // Create a subscribe request, send it and keep it refreshed
        UtlString earlyDialogHandle;
        CPPUNIT_ASSERT(subClient->addSubscription(resourceId,
                                                  eventType,
                                                  from,
                                                  to,
                                                  contact,
                                                  60, // seconds expiration
                                                  this,
                                                  subStateCallback,
                                                  notifyCallback,
                                                  earlyDialogHandle));


        contentMgr->getStats(numDefaultContent,
                             numResourceSpecificContent,
                             numCallbacksRegistered);
        CPPUNIT_ASSERT(numDefaultContent == 0);
        CPPUNIT_ASSERT(numResourceSpecificContent == 0);
        CPPUNIT_ASSERT(numCallbacksRegistered == 1);

        // See if a subscribe was sent and received
       /*OsTime messageTimeout(5, 0);  // 5 seconds
       OsMsg* osMessage = NULL;
       const SipMessage* subscribeResponse = NULL;
       const SipMessage* notifyRequest = NULL;
       incomingServerMsgQueue.receive(osMessage, messageTimeout);
       CPPUNIT_ASSERT(osMessage);
       int msgType = osMessage->getMsgType();
       int msgSubType = osMessage->getMsgSubType();
       CPPUNIT_ASSERT(msgType == OsMsg::PHONE_APP);
       CPPUNIT_ASSERT(msgSubType == SipMessage::NET_SIP_MESSAGE);
       const SipMessage* sipMessage = ((SipMessageEvent*)osMessage)->getMessage();
       int messageType = ((SipMessageEvent*)osMessage)->getMessageStatus();
       CPPUNIT_ASSERT(sipMessage);
       CPPUNIT_ASSERT(messageType == SipMessageEvent::APPLICATION);*/
       const SipMessage* serverSideSubRequest = NULL;
       CPPUNIT_ASSERT(removeMessage(incomingServerMsgQueue,
                     5000, // milliseconds
                     serverSideSubRequest));
       CPPUNIT_ASSERT(serverSideSubRequest); // Sub request got to server

       const SipMessage* clientSideSubResponse = NULL;
       CPPUNIT_ASSERT(removeMessage(incomingClientMsgQueue,
                      5000, // milliseconds
                      clientSideSubResponse));
       CPPUNIT_ASSERT(clientSideSubResponse);

       //UtlString clientStateString;
       //subClient->dumpStates(clientStateString);
       //printf("client states:\n%s\n", clientStateString.data());


        int waitIterations = 0;
        while(smLastClientNotifyReceived == NULL ||
            smLastClientSubResponseReceived == NULL)
        {
            OsTask::delay(100);
            waitIterations++;
            if(waitIterations >= 100)
            {
                break;
            }
        }

        CPPUNIT_ASSERT(smLastClientSubResponseReceived);
        CPPUNIT_ASSERT(smLastClientNotifyReceived);
        SipMessage* firstSubResponse = smLastClientSubResponseReceived;
        smLastClientSubResponseReceived = NULL;
        int firstSubCseq;
        firstSubResponse->getCSeqField(&firstSubCseq, NULL);
        SipMessage* firstNotifyRequest = smLastClientNotifyReceived;
        smLastClientNotifyReceived = NULL;
        int firstNotifyCseq;
        firstNotifyRequest->getCSeqField(&firstNotifyCseq, NULL);
        CPPUNIT_ASSERT(firstSubCseq == 1);
        CPPUNIT_ASSERT(firstNotifyCseq == 0);

        //subClient->dumpStates(clientStateString);
        //printf("client states:\n%s\n", clientStateString.data());

        //UtlString dialogMgrDumpString;
        //clientDialogMgr.toString(dialogMgrDumpString);
        //printf("Client Dialog manager dump 1:\n%s\n",
        //       dialogMgrDumpString.data());

        // The refresh manager should re-SUBSCRIBE
        // Wait for the next notify request and subscribe response
        int secondMessageWait = 60;
        int resendTimeout = 0.55 * secondMessageWait;
        if(resendTimeout < 40)
        {
            resendTimeout = 40;
        }
        for(int i = 0; i < secondMessageWait - 1; i++)
        {
            if(i == resendTimeout - 1)
            {
                printf("v");
            }
            else
            {
                printf("=");
            }
        }
        printf("v\n");
        SipMessage* secondSubResponse = NULL;
        SipMessage* secondNotifyRequest = NULL;

        while(secondNotifyRequest == NULL ||
            secondSubResponse == NULL)
        {
            OsTask::delay(1000);
            if(smLastClientSubResponseReceived)
            {
                secondSubResponse = smLastClientSubResponseReceived;
                smLastClientSubResponseReceived = NULL;
            }
            if(smLastClientNotifyReceived)
            {
                secondNotifyRequest = smLastClientNotifyReceived;
                smLastClientNotifyReceived = NULL;
            }
            printf(".");
            waitIterations++;
            if(waitIterations >= secondMessageWait)
            {
                printf("\n");
                break;
            }
        }

        //subClient->dumpStates(clientStateString);
        //printf("client states:\n%s\n", clientStateString.data());

        //clientDialogMgr.toString(dialogMgrDumpString);
        //printf("Client Dialog manager dump 2:\n%s\n",
        //       dialogMgrDumpString.data());

       CPPUNIT_ASSERT(removeMessage(incomingServerMsgQueue,
                     5000, // milliseconds
                     serverSideSubRequest));
       CPPUNIT_ASSERT(serverSideSubRequest); // Sub request got to server
       //UtlString subRequestDump;
       //int len;
       //serverSideSubRequest->getBytes(&subRequestDump, &len);
       //printf("server side sub request:\n%s\n",
       //    subRequestDump.data());

       CPPUNIT_ASSERT(removeMessage(incomingClientMsgQueue,
                      5000, // milliseconds
                      clientSideSubResponse));
       CPPUNIT_ASSERT(clientSideSubResponse); // Sub respon got to client
       //UtlString subResponseDump;
       //clientSideSubResponse->getBytes(&subResponseDump, &len);
       //printf("client side sub response:\n%s\n",
       //       subResponseDump.data());

        CPPUNIT_ASSERT(secondNotifyRequest);
        CPPUNIT_ASSERT(secondSubResponse);
        int secondSubCseq = -1;
        int secondNotifyCseq = -1;
        smLastClientSubResponseReceived = NULL;
        secondSubResponse->getCSeqField(&secondSubCseq, NULL);
        smLastClientNotifyReceived = NULL;
        secondNotifyRequest->getCSeqField(&secondNotifyCseq, NULL);
        CPPUNIT_ASSERT(firstSubCseq < secondSubCseq);
        CPPUNIT_ASSERT(firstNotifyCseq < secondNotifyCseq);

        // Unregister the queues so we stop receiving messages on them
        userAgent->removeMessageObserver(incomingServerMsgQueue);
        userAgent->removeMessageObserver(incomingClientMsgQueue);

        refreshMgr->requestShutdown();
        subClient->requestShutdown();

    }
예제 #8
0
   // Basic server functionality test.
   // Checks that server answers SUBSCRIBES, sends NOTIFY, sends NOTIFY
   // when content changes.
   void basicSubscriptionTest()
      {
         // Verify that authentication and authorization are
         // disabled by default.
         {
            SipSubscribeServerEventHandler* eventHandler =
               subServerp->getEventHandler(eventName);
            CPPUNIT_ASSERT(eventHandler);

            SipMessage bogusSubscribeRequest;
            SipMessage bogusSubscribeResponse;
            CPPUNIT_ASSERT(eventHandler->isAuthenticated(bogusSubscribeRequest,
                                                         bogusSubscribeResponse));
            CPPUNIT_ASSERT(eventHandler->isAuthorized(bogusSubscribeRequest,
                                                      bogusSubscribeResponse));
         }

         // Send a SUBSCRIBE to the notifier.
         SipMessage mwiSubscribeRequest;
         {
            UtlString c;
            CallId::getNewCallId(c);
            mwiSubscribeRequest.setSubscribeData(notifier_aor, // request URI
                                                 subscriber_name_addr, // From
                                                 notifier_name_addr, // To
                                                 c, // Call-Id
                                                 0, // CSeq
                                                 eventName, // Event
                                                 mwiMimeType, // Accept
                                                 NULL, // Event id
                                                 subscriber_name_addr, // Contact
                                                 NULL, // Route
                                                 3600 // Expires
               );
         }

         CPPUNIT_ASSERT(subscriberUserAgentp->send(mwiSubscribeRequest));

         // We should get a 202 response and a NOTIFY request in the queue
         OsTime messageTimeout(1, 0);  // 1 second
         {
            const SipMessage* subscribeResponse;
            const SipMessage* notifyRequest;
            runListener(incomingClientMsgQueue,
                        *subscriberUserAgentp,
                        messageTimeout,
                        messageTimeout,
                        notifyRequest,
                        subscribeResponse,
                        SIP_OK_CODE,
                        FALSE,
                        0,
                        NULL);

            // We should have received a SUBSCRIBE response and a NOTIFY request.
            CPPUNIT_ASSERT(subscribeResponse);
            CPPUNIT_ASSERT(notifyRequest);

            // Check that the response code and CSeq method in the
            // subscribe response are OK.
            {
               CPPUNIT_ASSERT(subscribeResponse->getResponseStatusCode() ==
                              SIP_ACCEPTED_CODE);
               UtlString subscribeMethod;
               subscribeResponse->getCSeqField(NULL, &subscribeMethod);
               ASSERT_STR_EQUAL(SIP_SUBSCRIBE_METHOD, subscribeMethod.data());
            }

            // Check that the method in the notify request is OK.
            {
               UtlString notifyMethod;
               notifyRequest->getRequestMethod(&notifyMethod);
               ASSERT_STR_EQUAL(SIP_NOTIFY_METHOD, notifyMethod.data());
            }

            // Check that the Event header in the NOTIFY is the same as the
            // one in the SUBSCRIBE.
            {
               UtlString notifyEventHeader;
               UtlString subscribeEventHeader;
               notifyRequest->getEventField(notifyEventHeader);
               mwiSubscribeRequest.getEventField(subscribeEventHeader);
               ASSERT_STR_EQUAL(subscribeEventHeader, notifyEventHeader);
            }

            // The NOTIFY should have no body because none has been published yet.
            {
               const HttpBody* bodyPtr = notifyRequest->getBody();
               CPPUNIT_ASSERT(bodyPtr == NULL);
            }

            // The Contact in the subscribe response should be the notifier.
            ASSERT_STR_EQUAL(notifier_contact_name_addr,
                             subscribeResponse->
                                 getHeaderValue(0, SIP_CONTACT_FIELD));

            // The Contact in the NOTIFY should be the notifier.
            CPPUNIT_ASSERT(notifyRequest->
                           getHeaderValue(0, SIP_CONTACT_FIELD));
            ASSERT_STR_EQUAL(notifier_contact_name_addr,
                             notifyRequest->
                                 getHeaderValue(0, SIP_CONTACT_FIELD));
         }

         // Publish some content (mwiStateString) for this resourceID
         {
            HttpBody* newMwiBodyPtr = new HttpBody(mwiStateString,
                                                   strlen(mwiStateString),
                                                   mwiMimeType);
            SipPublishContentMgr* publishMgr = subServerp->getPublishMgr(eventName);
            CPPUNIT_ASSERT(publishMgr);
            publishMgr->publish(notifier_resource_id,
                                eventName,
                                eventName,
                                1,
                                &newMwiBodyPtr);
         }

         // Should get a NOTIFY queued up
         {
            const SipMessage* subscribeResponse;
            const SipMessage* secondNotify;
            runListener(incomingClientMsgQueue,
                        *subscriberUserAgentp,
                        messageTimeout,
                        messageTimeout,
                        secondNotify,
                        subscribeResponse,
                        SIP_OK_CODE,
                        FALSE,
                        0,
                        NULL);
            CPPUNIT_ASSERT(secondNotify);
            CPPUNIT_ASSERT(subscribeResponse == NULL);

            // Check that the body of the NOTIFY is what we expect (mwiStateString).
            {
               const HttpBody* secondNotifyBody = secondNotify->getBody();
               CPPUNIT_ASSERT(secondNotifyBody);
               ssize_t notifyBodySize;
               const char* notifyBodyBytes;
               secondNotifyBody->getBytes(&notifyBodyBytes, &notifyBodySize);
               CPPUNIT_ASSERT(notifyBodyBytes);
               ASSERT_STR_EQUAL(mwiStateString, notifyBodyBytes);
            }

            // Check that the Dialog Manager reports that the dialog handle is OK.
            {
               UtlString secondNotifyDialogHandle;
               secondNotify->getDialogHandle(secondNotifyDialogHandle);
               CPPUNIT_ASSERT(!secondNotifyDialogHandle.isNull());
               CPPUNIT_ASSERT(dialogMgrp->dialogExists(secondNotifyDialogHandle));
               CPPUNIT_ASSERT(dialogMgrp->countDialogs() == 1);
            }
         }

         // Create a new one-time SUBSCRIBE
         SipMessage oneTimeMwiSubscribeRequest;
         {
            UtlString c;
            CallId::getNewCallId(c);
            oneTimeMwiSubscribeRequest.
               setSubscribeData(notifier_aor, // request URI
                                subscriber_name_addr, // From
                                notifier_name_addr, // To
                                c, // Call-Id
                                0, // CSeq
                                eventName, // Event
                                mwiMimeType, // Accept
                                NULL, // Event id
                                subscriber_name_addr, // Contact
                                NULL, // Route
                                0 // Expires
                  );
         }

         CPPUNIT_ASSERT(subscriberUserAgentp->send(oneTimeMwiSubscribeRequest));

         {
            const SipMessage* oneTimeNotifyRequest;
            const SipMessage* oneTimeSubscribeResponse;
            runListener(incomingClientMsgQueue,
                        *subscriberUserAgentp,
                        messageTimeout,
                        messageTimeout,
                        oneTimeNotifyRequest,
                        oneTimeSubscribeResponse,
                        SIP_OK_CODE,
                        FALSE,
                        0,
                        NULL);

            // Validate the one time subscribe response and notify request
            CPPUNIT_ASSERT(oneTimeSubscribeResponse);
            CPPUNIT_ASSERT(oneTimeNotifyRequest);

            {
               CPPUNIT_ASSERT(oneTimeSubscribeResponse->getResponseStatusCode() ==
                              SIP_ACCEPTED_CODE);
               UtlString oneTimeSubscribeMethod;
               oneTimeSubscribeResponse->getCSeqField(NULL, &oneTimeSubscribeMethod);
               ASSERT_STR_EQUAL(SIP_SUBSCRIBE_METHOD, oneTimeSubscribeMethod.data());
               UtlString oneTimeSubscribeEventHeader;
               oneTimeSubscribeResponse->getEventField(oneTimeSubscribeEventHeader);
               // The Event: header never appears in responses -- see RFC 3265 section 7.2.
               // The "R" in the "where" column means that "Event" appears only in
               // requests -- see RFC 3261 table 2 and page 160.
               ASSERT_STR_EQUAL("", oneTimeSubscribeEventHeader);
            }

            {
               UtlString oneTimeNotifyMethod;
               oneTimeNotifyRequest->getRequestMethod(&oneTimeNotifyMethod);
               ASSERT_STR_EQUAL(SIP_NOTIFY_METHOD, oneTimeNotifyMethod.data());
               UtlString oneTimeNotifyEventHeader;
               oneTimeNotifyRequest->getEventField(oneTimeNotifyEventHeader);
               // The Event: header should appear in the NOTIFY.
               ASSERT_STR_EQUAL(SIP_EVENT_MESSAGE_SUMMARY, oneTimeNotifyEventHeader);
            }

            {
               const HttpBody* oneTimeBodyPtr = oneTimeNotifyRequest->getBody();
               CPPUNIT_ASSERT(oneTimeBodyPtr != NULL);
               const char* oneTimeBodyString;
               ssize_t oneTimeNotifyBodySize;
               oneTimeBodyPtr->getBytes(&oneTimeBodyString, &oneTimeNotifyBodySize);
               ASSERT_STR_EQUAL(mwiStateString, oneTimeBodyString);
            }

            {
               UtlString oneTimeNotifyDialogHandle;
               oneTimeNotifyRequest->getDialogHandle(oneTimeNotifyDialogHandle);
               CPPUNIT_ASSERT(!oneTimeNotifyDialogHandle.isNull());
               CPPUNIT_ASSERT(dialogMgrp->dialogExists(oneTimeNotifyDialogHandle));
               CPPUNIT_ASSERT(dialogMgrp->countDialogs() == 2);
               long now = OsDateTime::getSecsSinceEpoch();
               subMgrp->removeOldSubscriptions(now + 1);
               // The one time subscription should get garbage collected
               // leaving only the persistant 3600 second subscription
               CPPUNIT_ASSERT(dialogMgrp->countDialogs() == 1);
            }
         }
      }