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(¬ifyRequest); 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(¬ifyMethod); 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(¬ifyBodyBytes, ¬ifyBodySize); 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); }