Exemple #1
0
UtlBoolean SipSubscribeServer::handleSubscribe(const SipMessage& subscribeRequest)
{
    UtlBoolean handledSubscribe = FALSE;
    UtlString eventName;
    subscribeRequest.getEventField(&eventName, NULL);

    // Not modifying the SubscribeServerEventData, just reading it
    lockForRead();

    // Get the event specific handler and information
    SubscribeServerEventData* eventPackageInfo =
       dynamic_cast <SubscribeServerEventData*> (mEventDefinitions.find(&eventName));

    // We handle this event type
    if (eventPackageInfo)
    {
        handledSubscribe = TRUE;
        SipSubscribeServerEventHandler* handler =
            eventPackageInfo->mpEventSpecificHandler;

        SipMessage subscribeResponse;

        // Check if authenticated (or if it needs to be authenticated)
        if (handler->isAuthenticated(subscribeRequest,
                                     subscribeResponse))
        {
            // Check if authorized (or if authorization is required)
            if (handler->isAuthorized(subscribeRequest,
                                     subscribeResponse))
            {
                // The subscription is allowed, so update the
                // subscription state.  Set the To field tag if
                // this request initiated the dialog
                UtlString subscribeDialogHandle;
                UtlBoolean isNewDialog;
                UtlBoolean isExpiredSubscription;
                UtlString resourceId, eventTypeKey, eventType;
                eventPackageInfo->mpEventSpecificSubscriptionMgr->
                   updateDialogInfo(
                      subscribeRequest,
                      resourceId,
                      eventTypeKey,
                      eventType,
                      subscribeDialogHandle,
                      isNewDialog,
                      isExpiredSubscription,
                      subscribeResponse,
                      // The event-specific handler provides a getKeys method
                      // which is used to determine the resource ID
                      // and event type if this is a new subscription.
                      *handler);

                 // Build a NOTIFY
                 SipMessage notifyRequest;

                 // Set the dialog information into the NOTIFY.
                 // Note that the dialog can have ended by now, because of
                 // a race condition with the processing of dialog-ending
                 // messages from the outside world.
                 if (eventPackageInfo->mpEventSpecificSubscriptionMgr->
                     getNotifyDialogInfo(subscribeDialogHandle,
                                         notifyRequest,
                                         "active;expires=%ld"))
                 {
                    // We still have record of the dialog, so the
                    // NOTIFY headers were set.

                    // Set the NOTIFY content
                    UtlString acceptHeaderValue;
                    if (!subscribeRequest.getAcceptField(acceptHeaderValue))
                    {
                       // No Accept header seen, set special value allowing any
                       // content type.
                       acceptHeaderValue = SipPublishContentMgr::acceptAllTypes;
                    }
                    // Note that since this NOTIFY is due to a SUBSCRIBE,
                    // it should contain 'full' content.  Hence,
                    // the fullState parameter of getNotifyContent is TRUE,
                    // and is not taken from
                    // eventPackageInfo->mEventSpecificFullState.
                    UtlString availableMediaTypes;
                    if (handler->getNotifyContent(resourceId,
                                                  eventTypeKey,
                                                  eventType,
                                                  *(eventPackageInfo->mpEventSpecificContentMgr),
                                                  acceptHeaderValue,
                                                  notifyRequest,
                                                  TRUE,
                                                  &availableMediaTypes))
                    {
                       // Update the NOTIFY content if required for this event type.
                       // Sets 'version' and 'eventTypeKey'.
                       int version;
                       eventPackageInfo->mpEventSpecificSubscriptionMgr->
                          updateNotifyVersion(eventPackageInfo->mpEventSpecificContentVersionCallback,
                                              notifyRequest,
                                              version,
                                              eventTypeKey);

                       // Update the saved record of the NOTIFY CSeq and the
                       // XML version number for the specified eventTypeKey,
                       // as needed by the subscription manager.
                       // In practice, this is only used by SipPersistentSubscriptionMgr
                       // to write the NOTIFY Cseq and XML version into the IMDB.
                       eventPackageInfo->mpEventSpecificSubscriptionMgr->
                          updateVersion(notifyRequest, version, eventTypeKey);

                       // Send the NOTIFY request
                       setContact(&notifyRequest);
                       eventPackageInfo->mpEventSpecificUserAgent->send(notifyRequest);

                       if (OsSysLog::willLog(FAC_SIP, PRI_INFO))
                       {
                          UtlString requestContact;
                          subscribeRequest.getContactField(0, requestContact);
                          OsSysLog::add(FAC_SIP, PRI_INFO,
                              "SipSubscribeServer::handleSubscribe: %s has setup subscription to %s, eventTypeKey %s",
                              requestContact.data(), resourceId.data(), eventTypeKey.data());
                       }
                    }
                    else
                    {
                       // No content was available, so the subscription fails.

                       // Determine the reason and set the response code.
                       if (availableMediaTypes.isNull())
                       {
                          // No MIME types are available, so the resource does not exist.
                          subscribeResponse.setResponseFirstHeaderLine(SIP_PROTOCOL_VERSION,
                                                                       SIP_NOT_FOUND_CODE,
                                                                       SIP_NOT_FOUND_TEXT);
                       }
                       else
                       {
                          // MIME types are available, so the resource exists.
                          subscribeResponse.setResponseFirstHeaderLine(SIP_PROTOCOL_VERSION,
                                                                       SIP_BAD_MEDIA_CODE,
                                                                       SIP_BAD_MEDIA_TEXT);
                          subscribeResponse.setAcceptField(availableMediaTypes);
                       }

                       // Destroy the subscription.
                       eventPackageInfo->mpEventSpecificSubscriptionMgr->
                          endSubscription(subscribeDialogHandle,
                                          SipSubscriptionMgr::subscriptionTerminated);

                       // Do not send the NOTIFY.
                    }
                 }
                 else
                 {
                    // Oops, the subscription was destroyed while we looked.
                    OsSysLog::add(FAC_SIP, PRI_WARNING,
                                  "SipSubscribeServer::handleSubscribe "
                                  "subscription '%s' vanished while being processed",
                                  subscribeDialogHandle.data());
                 }

                 // Send the response ASAP to minimize resending.
                 setContact(&subscribeResponse);
                 eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse);
            }
            // Not authorized
            else
            {
                // Send the response that was prepared by ::isAuthorized().
                setContact(&subscribeResponse);
                eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse);
            }
        }

        // Not authenticated
        else
        {
            // Send the response that was prepared by ::isAuthenticated().
            setContact(&subscribeResponse);
            eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse);
        }
    }

    // We should not have received SUBSCRIBE requests for this event type.
    // This event type has not been enabled in this SubscribeServer.
    else
    {
        OsSysLog::add(FAC_SIP, PRI_ERR,
            "SipSubscribeServer::handleSubscribe event type: %s not enabled",
            eventName.data());

        SipMessage eventTypeNotHandled;
        eventTypeNotHandled.setResponseData(&subscribeRequest,
                                            SIP_BAD_EVENT_CODE,
                                            SIP_BAD_EVENT_TEXT);

        setContact(&eventTypeNotHandled);
        mpDefaultUserAgent->send(eventTypeNotHandled);
    }
    unlockForRead();

    return(handledSubscribe);
}
   // 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);
            }
         }
      }
UtlBoolean SipSubscribeServer::handleSubscribe(const SipMessage& subscribeRequest)
{
    UtlBoolean handledSubscribe = FALSE;
    UtlString eventName;
    subscribeRequest.getEventField(&eventName, NULL);

    // Not modifying the SubscribeServerEventData, just reading it
    lockForRead();

    // Get the event specific handler and information
    SubscribeServerEventData* eventPackageInfo = (SubscribeServerEventData*)
        mEventDefinitions.find(&eventName);

    // We handle this event type
    if(eventPackageInfo)
    {
        handledSubscribe = TRUE;
        UtlString resourceId;
        UtlString eventTypeKey, eventType;
        SipSubscribeServerEventHandler* handler =
            eventPackageInfo->mpEventSpecificHandler;

        // Get the keys used to identify the event state content
        handler->getKeys(subscribeRequest,
                         resourceId,
                         eventTypeKey,
                         eventType);

        SipMessage subscribeResponse;

        // Check if authenticated (or if it needs to be authenticated)
        if(handler->isAuthenticated(subscribeRequest,
                                     resourceId,
                                     eventTypeKey,
                                     subscribeResponse))
        {
            // Check if authorized (or if authorization is required)
            if(handler->isAuthorized(subscribeRequest,
                                     resourceId,
                                     eventTypeKey,
                                     subscribeResponse))
            {
                // The subscription is allowed, so update the
                // subscription state.  Set the To field tag if
                // this request initiated the dialog
                UtlString subscribeDialogHandle;
                UtlBoolean isNewDialog;
                UtlBoolean isExpiredSubscription;
                eventPackageInfo->mpEventSpecificSubscriptionMgr->updateDialogInfo(
                                                            subscribeRequest,
                                                            resourceId, 
                                                            eventTypeKey, 
                                                            getMessageQueue(),
                                                            subscribeDialogHandle, 
                                                            isNewDialog, 
                                                            isExpiredSubscription,
                                                            subscribeResponse);

                // Send the response ASAP to minimize resend handling of request
                 eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse);

                 // Build a NOTIFY
                 SipMessage notifyRequest;

                 // Set the dialog information
                 eventPackageInfo->mpEventSpecificSubscriptionMgr->getNotifyDialogInfo(subscribeDialogHandle,
                                                                    notifyRequest);

                 // Set the NOTIFY content
                 UtlString acceptHeaderValue;
                 subscribeRequest.getAcceptField(acceptHeaderValue);
                 handler->getNotifyContent(resourceId, 
                                           eventTypeKey, 
                                           eventType, 
                                           *(eventPackageInfo->mpEventSpecificContentMgr),
                                           acceptHeaderValue,
                                           notifyRequest);

                 // Send the notify request
                 eventPackageInfo->mpEventSpecificUserAgent->send(notifyRequest);
            }
            // Not authorized
            else
            {
                // Send the response
                eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse);
            }
        }

        // Not authenticated
        else
        {
            // Send the response
            eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse);
        }
    }


    // We should not have received SUBSCRIBE requests for this event type
    // This event type has not been enabled in this SubscribeServer
    else
    {
        OsSysLog::add(FAC_SIP, PRI_ERR, 
            "SipSubscribeServer::handleSubscribe event type: %s not enabled",
            eventName.data());

        SipMessage eventTypeNotHandled;
        eventTypeNotHandled.setResponseData(&subscribeRequest,
            SIP_BAD_EVENT_CODE, SIP_BAD_EVENT_TEXT);

        mpDefaultUserAgent->send(eventTypeNotHandled);
    }
    unlockForRead();

    return(handledSubscribe);
}
UtlBoolean SipSubscriptionMgr::updateDialogInfo(const SipMessage& subscribeRequest,
                                                UtlString& resourceId,
                                                UtlString& eventTypeKey,
                                                UtlString& eventType,
                                                UtlString& subscribeDialogHandle,
                                                UtlBoolean& isNew,
                                                UtlBoolean& isSubscriptionExpired,
                                                SipMessage& subscribeResponse,
                                                SipSubscribeServerEventHandler& handler)
{
    isNew = FALSE;
    UtlBoolean subscriptionSucceeded = FALSE;
    UtlString dialogHandle;
    subscribeRequest.getDialogHandle(dialogHandle);
    SubscriptionServerState* state = NULL;
    int expiration = -1;
    isSubscriptionExpired = TRUE;
    
    // Double check the sanity of the class attributes
    
    if(mMaxExpiration < mMinExpiration)
    {
        // This is an error case. Switch the values so that we do not
        // run into any negative expiration times.
        int tmp = mMaxExpiration;
        mMaxExpiration = mMinExpiration;
        mMinExpiration = tmp;
        
        OsSysLog::add(FAC_SIP, PRI_WARNING,
            "Swapping values as mMinExpiration => %d is greater than mMaxExpiration => %d",
            mMinExpiration, mMaxExpiration);
    }
    
    if(mMaxExpiration < mDefaultExpiration)
    {
        // This is an error case. Switch the values so that we do not
        // run into any negative expiration times.
        int tmp = mMaxExpiration;
        mMaxExpiration = mDefaultExpiration;
        mDefaultExpiration = tmp;
        
        OsSysLog::add(FAC_SIP, PRI_WARNING,
            "Swapping values as mDefaultExpiration => %d is greater than mMaxExpiration => %d",
            mDefaultExpiration, mMaxExpiration);
    }
    
    // Set the expires period randomly
    int spreadFloor = mMinExpiration*2;
    if(!subscribeRequest.getExpiresField(&expiration))
    {
        // no expires field
        // spread it between the default expiration and max allowed expiration
        expiration = (  (rand() % (mMaxExpiration - mDefaultExpiration))
                       + mDefaultExpiration);
    }
    else if ( expiration >= mMaxExpiration )
    {
        if (mMaxExpiration > spreadFloor)
        {
            // - spread it between the spreadFloor and the max allowed expiration
            expiration = (  (rand() % (mMaxExpiration - spreadFloor))
                           + spreadFloor);
        }
        else
        {                
            // Max Expiration is smaller than the spreadFloor, hence
            // spread it between the min and the max allowed expiration
            expiration = (  (rand() % (mMaxExpiration - mMinExpiration))
                           + mMinExpiration);
        }
    }
    else if ( expiration > spreadFloor )
    {
        // a normal (long) expiration
        // - spread it between the spreadFloor and the longest they asked for
        expiration = (  (rand() % (expiration - spreadFloor))
                       + spreadFloor);
    }
    else if ( expiration > mMinExpiration )
    {
        // a short but greater than minimum expiration
        // - spread it between the min and the longest they asked for
        expiration = (  (rand() % (expiration - mMinExpiration))
                       + mMinExpiration);
    }
    // Cases where the expiration is less than the min value is handled below.

    // If this is an early dialog we need to make it an established dialog.
    if(SipDialog::isEarlyDialog(dialogHandle))
    {
        UtlString establishedDialogHandle;
        if(mDialogMgr.getEstablishedDialogHandleFor(dialogHandle, establishedDialogHandle))
        {
            OsSysLog::add(FAC_SIP, PRI_WARNING,
                "Incoming early SUBSCRIBE dialog: %s matches established dialog: %s",
                dialogHandle.data(), establishedDialogHandle.data());
        }

        // make up a To tag and set it
        UtlString toTag;
        CallId::getNewTag(dialogHandle.data(), toTag);

        // Acceptable expiration, create a subscription and dialog
        if(expiration >= mMinExpiration ||
           expiration == 0 ||
           // :WORKAROUND:  Also allow expiration == 1, to support the
           // 1-second subscriptions the pick-up agent makes because
           // current Snom phones do not respond to 0-second subscriptions.
           // See XPB-399 and ENG-319.
           expiration == 1)
        {
            // Call the event-specific function to determine the resource ID
            // and event type for this SUBSCRIBE.
            handler.getKeys(subscribeRequest,
                            resourceId,
                            eventTypeKey,
                            eventType);

            // Create a dialog and subscription state even if
            // the expiration is zero as we need the dialog info
            // to route the one-time NOTIFY.  The immediately
            // expired dialog will be garbage collected.

            SipMessage* subscribeCopy = new SipMessage(subscribeRequest);
            subscribeCopy->setToFieldTag(toTag);

            // Re-get the dialog handle now that the To tag is set
            subscribeCopy->getDialogHandle(dialogHandle);

            // Create the dialog
            mDialogMgr.createDialog(*subscribeCopy, FALSE, dialogHandle);
            isNew = TRUE;

            // Create a subscription state
            state = new SubscriptionServerState();
            *((UtlString*) state) = dialogHandle;
            state->mEventTypeKey = eventTypeKey;
            state->mpLastSubscribeRequest = subscribeCopy;
            state->mResourceId = resourceId;
            subscribeCopy->getAcceptField(state->mAcceptHeaderValue);

            long now = OsDateTime::getSecsSinceEpoch();
            state->mExpirationDate = now + expiration;

            // TODO: currently the SipSubsribeServer does not handle timeout
            // events to send notifications that the subscription has ended.
            // So we do not set a timer at the end of the subscription
            state->mpExpirationTimer = NULL;

            // Create the index by resourceId and eventTypeKey key
            SubscriptionServerStateIndex* stateKey = new SubscriptionServerStateIndex;
            *((UtlString*) stateKey) = resourceId;
            stateKey->append(eventTypeKey);
            stateKey->mpState = state;

            subscribeResponse.setResponseData(subscribeCopy, 
                                              SIP_ACCEPTED_CODE,
                                              SIP_ACCEPTED_TEXT, 
                                              NULL);
            subscribeResponse.setExpiresField(expiration);
            subscribeCopy->getDialogHandle(subscribeDialogHandle);

            lock();
            mSubscriptionStatesByDialogHandle.insert(state);
            mSubscriptionStateResourceIndex.insert(stateKey);
	    if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG))
	    {
	       UtlString requestContact;
	       subscribeRequest.getContactField(0, requestContact);
	       OsSysLog::add(FAC_SIP, PRI_DEBUG,
			     "SipSubscriptionMgr::updateDialogInfo insert early-dialog subscription for dialog handle '%s', key '%s', contact '%s', mExpirationDate %ld",
			     state->data(), stateKey->data(),
                             requestContact.data(), state->mExpirationDate);
            }

            // Not safe to touch these after we unlock
            stateKey = NULL;
            state = NULL;
            subscribeCopy = NULL;
            unlock();

            subscriptionSucceeded = TRUE;

            // One time subscribe?
            isSubscriptionExpired = expiration == 0;
        }
        // Expiration too small
        else
        {
            // Set expiration too small error
            subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_TOO_BRIEF_CODE,
                                                SIP_SUB_TOO_BRIEF_TEXT);
            subscribeResponse.setMinExpiresField(mMinExpiration);
            isSubscriptionExpired = TRUE;
        }
    }

    // Not an early dialog handle -- The dialog for this message should already exist
    else
    {
        // Acceptable expiration, create a subscription and dialog
        if(expiration > mMinExpiration ||
           expiration == 0)
        {
            // Update the dialog state
            mDialogMgr.updateDialog(subscribeRequest, dialogHandle);

            // Get the subscription state and update that
            // TODO:  This assumes that no one reuses the same dialog
            // to subscribe to more than one event type.  mSubscriptionStatesByDialogHandle
            // will need to be changed to a HashBag and we will need to
            // search through to find a matching event type
            lock();
            state = (SubscriptionServerState*)
                mSubscriptionStatesByDialogHandle.find(&dialogHandle);
            if(state)
            {
                // Update the expiration time.
                long now = OsDateTime::getSecsSinceEpoch();
                state->mExpirationDate = now + expiration;
                // Record this SUBSCRIBE as the latest SUBSCRIBE request.
                if(state->mpLastSubscribeRequest)
                {
                    delete state->mpLastSubscribeRequest;
                }
                state->mpLastSubscribeRequest = new SipMessage(subscribeRequest);
                subscribeRequest.getAcceptField(state->mAcceptHeaderValue);

                // Set our Contact to the same request URI that came in
                UtlString contact;
                subscribeRequest.getRequestUri(&contact);

                // Add the angle brackets to Contact, since it is a name-addr.
                Url url(contact);
                url.includeAngleBrackets();
                contact = url.toString();

                subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_ACCEPTED_CODE,
                                                SIP_ACCEPTED_TEXT, 
                                                contact);
                subscribeResponse.setExpiresField(expiration);
                subscriptionSucceeded = TRUE;
                isSubscriptionExpired = FALSE;
                subscribeDialogHandle = dialogHandle;

                // Set the resource information so our caller can generate a NOTIFY.
                resourceId = state->mResourceId;
                eventTypeKey = state->mEventTypeKey;
                // Unfortuantely, we don't record the eventType separately.
                eventType = state->mEventTypeKey;
            }

            // No state, but SUBSCRIBE had a to-tag.
            else
            {
               // Unknown subscription.
               subscribeResponse.setResponseData(&subscribeRequest, 
                                                 SIP_BAD_SUBSCRIPTION_CODE,
                                                 SIP_BAD_SUBSCRIPTION_TEXT);
            }
            unlock();
        }

        // Expiration too small
        else
        {
            // Set expiration too small error
            subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_TOO_BRIEF_CODE,
                                                SIP_SUB_TOO_BRIEF_TEXT);
            subscribeResponse.setMinExpiresField(mMinExpiration);
            isSubscriptionExpired = isExpired(dialogHandle);
        }
    }

    return(subscriptionSucceeded);
}