Пример #1
0
 void testReservedCharsInParameters()
 {
    OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "AlarmServerTest::testReservedCharsInParameters");
    UtlString localhost("localhost");
    UtlString alarmId("PARAMETER_WITH_RESERVED_CHARS");
    UtlSList alarmParams;
    UtlString alarmParam("<sample>; \"x=y\"");
    alarmParams.append(&alarmParam);
    cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
    OsTask::delay(DELAY);
    UtlString actualString;
    UtlString expectedString = "Parameters may contain xml reserved characters e.g. '<sample>; \\\"x=y\\\"'";
    tail(mAlarmFile, actualString);
    char msg[1000];
    sprintf(msg, "incorrect message was logged: actualString '%s'  expected '%s'", actualString.data(), expectedString.data());
    CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString));
 }
Пример #2
0
 void testNewlinesInStrings()
 {
    OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "AlarmServerTest::testNewlinesInStrings");
    UtlString localhost("localhost");
    UtlString alarmId("MESSAGE_WITH_NEWLINES");
    UtlSList alarmParams;
    UtlString alarmParam("1");
    alarmParams.append(&alarmParam);
    UtlString alarmParam2 = "\nparam on new line";
    alarmParams.append(&alarmParam2);
    cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
    OsTask::delay(DELAY);
    UtlString actualString;
    UtlString expectedString = "param on new line";
    tail(mAlarmFile, actualString);
    char msg[1000];
    sprintf(msg, "incorrect message was logged: actualString '%s'  expected '%s'", actualString.data(), expectedString.data());
    CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString));
 }
Пример #3
0
 void testParameterSubstitution()
 {
    OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "AlarmServerTest::testParameterSubstitution");
    UtlString localhost("localhost");
    UtlString alarmId("PARAMETER_SUBSTITUTION");
    UtlSList alarmParams;
    UtlString alarmParam("1");
    alarmParams.append(&alarmParam);
    UtlString alarmParam2 = "2";
    alarmParams.append(&alarmParam2);
    cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
    OsTask::delay(DELAY);
    UtlString actualString;
    UtlString expectedString = "Parameter 2, then parameter 1";
    tail(mAlarmFile, actualString);
    char msg[1000];
    sprintf(msg, "incorrect message was logged: actualString '%s'  expected '%s'", actualString.data(), expectedString.data());
    CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString));
 }
Пример #4
0
UtlBoolean SipRegistrar::handleMessage( OsMsg& eventMessage )
{
    UtlBoolean handled = FALSE;

    int msgType = eventMessage.getMsgType();
    int msgSubType = eventMessage.getMsgSubType();

    if (   (msgType == OsMsg::PHONE_APP)
        && (msgSubType == SipMessage::NET_SIP_MESSAGE)
        )
    {
        Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRegistrar::handleMessage()"
                      " Start processing SIP message") ;

        const SipMessage* message =
           ((SipMessageEvent&)eventMessage).getMessage();
        UtlString callId;
        if ( message )
        {
            message->getCallIdField(&callId);
            UtlString method;
            message->getRequestMethod(&method);

            if ( !message->isResponse() ) // is a request ?
            {
                if ( method.compareTo(SIP_REGISTER_METHOD) == 0 )
                {
                    //send to Register Thread
                    sendToRegistrarServer(eventMessage);
                }
                else if ( method.compareTo(SIP_OPTIONS_METHOD) == 0 )
                {
                    UtlString requestUri;
                    message->getRequestUri(&requestUri);

                    // Check if the OPTIONS request URI is addressed to a user or
                    // to the domain.
                    if (!requestUri.contains("@"))
                    {
                        UtlString contentEncoding;
                        message->getContentEncodingField(&contentEncoding);

                        UtlString disallowedExtensions;

                        int extensionIndex = 0;
                        UtlString extension;

                        disallowedExtensions.remove(0);
                        while(message->getRequireExtension(extensionIndex, &extension))
                        {
                            if(!(mSipUserAgent->isExtensionAllowed(extension.data())) )
                            {
                                if(!disallowedExtensions.isNull())
                                {
                                    disallowedExtensions.append(SIP_MULTIFIELD_SEPARATOR);
                                    disallowedExtensions.append(SIP_SINGLE_SPACE);
                                }
                                disallowedExtensions.append(extension.data());
                            }
                            extensionIndex++;
                        }

                        //delete leading and trailing white spaces
                        disallowedExtensions = disallowedExtensions.strip(UtlString::both);

                        SipMessage response;

                        // Check if the extensions are supported
                        if(!disallowedExtensions.isNull() )
                        {
                           // error response - bad extension
                           response.setRequestBadExtension(message,
                                                           disallowedExtensions);
                        }
                        // Check if the encoding is supported
                        // i.e. no encoding
                        else if(!contentEncoding.isNull())
                        {
                           // error response - content encoding
                           response.setRequestBadContentEncoding(message,"");
                        }
                        else
                        {
                            // Send an OK, the allowed field will get added to all final responses.
                            // Options 200 response
                            response.setResponseData(message,
                                                     SIP_OK_CODE,
                                                     SIP_OK_TEXT);
                        }

                        mSipUserAgent->send(response);
                    }
                    else
                    {
                        //OPTIONS is addressed to a user, send to redirect thread
                        sendToRedirectServer(eventMessage);
                    }
                }
                else
                {
                    //send to redirect thread
                    sendToRedirectServer(eventMessage);
                }
            }
            else
            {
               // responses are ignored.
            }
        }
        else
        {
           Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                         "SipRegistrar::handleMessage no message."
                         ) ;
        }

        handled = TRUE;
    }
    else if ( OsMsg::OS_SHUTDOWN == msgType )
    {
       Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                     "SipRegistrar::handleMessage shutting down all tasks");

       // Do an orderly shutdown of all the various threads.


       if ( mSipUserAgent )
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRegistrar::handleMessage shutting down SipUserAgent");
          mSipUserAgent->shutdown();
          delete mSipUserAgent ;
          mSipUserAgent = NULL ;
       }


       if ( mRegistrarPersist )
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRegistrar::handleMessage shutting down RegistrarPersist");
          mRegistrarPersist->requestShutdown();
          delete mRegistrarPersist;
          mRegistrarPersist = NULL;
       }

       if ( mRedirectServer )
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRegistrar::handleMessage shutting down RedirectServer");
          mRedirectServer->requestShutdown();
          delete mRedirectServer;
          mRedirectServer = NULL;
          mRedirectMsgQ = NULL;
       }

       if ( mRegistrarServer )
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRegistrar::handleMessage shutting down RegistrarServer");
          mRegistrarServer->requestShutdown();
          delete mRegistrarServer;
          mRegistrarServer = NULL;
          mRegistrarMsgQ = NULL;
       }

       if ( mRegisterEventServer )
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRegistrar::handleMessage shutting down RegisterEventServer");
          delete mRegisterEventServer;
          mRegisterEventServer = NULL;
       }

       OsTask::requestShutdown(); // tell OsServerTask::run to exit
       handled = TRUE;
    }
    else
    {
       Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                     "SipRegistrar::handleMessage unhandled type %d/%d",
                     msgType, msgSubType
                     ) ;
    }

    return handled;
}
Пример #5
0
UtlBoolean TestRegistrar::handleRegisterRequest(SipMessage message)
{
    UtlBoolean messageProcessed = false;
    SipMessage finalResponse;
    UtlString responseToAddress;
    UtlString protocol;
    int responseToPort;
    int seqNum;
    UtlString method;
    UtlString contactField;
    int expires;
    static int retrySeqNum = 0;
    UtlString callId;

    message.getCallIdField(&callId);

    message.getContactField(0, contactField);
    message.getExpiresField(&expires);

    message.getCSeqField(&seqNum, &method);
    message.getFromAddress(&responseToAddress, &responseToPort, &protocol);

    finalResponse.setContactField(contactField);
    finalResponse.setExpiresField(expires);
    finalResponse.setFromField("sip:127.0.0.1:5070", 5070);
    finalResponse.setSendAddress(contactField, responseToPort);
    finalResponse.setToField(contactField, responseToPort, protocol);
    finalResponse.setUserAgentField("TestRegistrar");
//    finalResponse.setRegisterData(responseToAddress, contactField, "127.0.0.1", contactField, callId, seqNum);

    if (contactField.contains("anon"))      // anonymous user doesnt need authentication, just say ok
    {
        finalResponse.setResponseData(&message, 200, "OK");
    }
    else if (contactField.contains("mike"))  // mike requires registration, say 401
    {
        UtlString realm;

        UtlString requestUser;
        UtlString requestRealm;
        UtlString requestNonce;
        UtlString uriParam;

        // TBD - 25-jan-2010 work might be needed if these tests are re-enabled
        message.getDigestAuthorizationData(
                   &requestUser, &requestRealm, &requestNonce,
                   NULL, NULL, &uriParam,
                   NULL,  // TBD cnonce
                   NULL,  // TBD nonceCount
                   NULL,  // TBD qop
                   HttpMessage::SERVER, 0);

        if (seqNum == retrySeqNum) // if this is a retry response
        {
            // if they've sent any auth field, just accept it.
            // TODO:  figure out if a username and password has been encrypted and sent.
            finalResponse.setCSeqField(++seqNum, SIP_REGISTER_METHOD);
            finalResponse.setResponseData(&message, 200, "OK");
        }
        else
        {
            message.getCSeqField(&seqNum, &method);
            finalResponse.setCSeqField(++seqNum, method);
            retrySeqNum = seqNum;
#ifdef _WIN32
            finalResponse.setAuthenticateData("md5", "TestRegistrar", NULL, NULL, NULL, HttpMessage::HttpEndpointEnum::SERVER );
#else
            finalResponse.setAuthenticateData("md5", "TestRegistrar", NULL, NULL, NULL, HttpMessage::SERVER );
#endif
            finalResponse.setResponseData(&message, 401, "Not authorized");
        }
    }
    else if (contactField.contains("xyzzy"))
    {
        // this is our special username that will cause a response
        // to be echoed back with the 3 digit value after xyzzy.
        // for instance, the contact xyzzy401 will cause a 401 response
        int pos = contactField.first("xyzzy");
        char szCode[4];
        szCode[0] = contactField[pos + 5];
        szCode[1] = contactField[pos + 6];
        szCode[2] = contactField[pos + 7];
        szCode[3] = '\0';

        finalResponse.setResponseData(&message, atoi(szCode), "OK");
    }


    mpUserAgent->send(finalResponse);

    return messageProcessed;
}
Пример #6
0
   void testHandleAlarm()
   {
      OsSysLog::add(FAC_ALARM, PRI_DEBUG, "AlarmServerTest::testHandleAlarm");

      UtlString localhost("localhost");
      UtlString alarmId("NO_LOG");
      UtlString alarmParam("testing");
      UtlSList alarmParams;
      alarmParams.append(&alarmParam);
      UtlString oldLastString;
      tail(mAlarmFile, oldLastString);
      OsSysLog::add(FAC_ALARM, PRI_DEBUG, "oldLastString %s", oldLastString.data());
      bool rc=cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
      OsTask::delay(500);
      CPPUNIT_ASSERT_MESSAGE("handleAlarm('NO_LOG') failed", rc==true);
      UtlString newLastString;
      tail(mAlarmFile, newLastString);
      OsSysLog::add(FAC_ALARM, PRI_DEBUG, "newLastString %s", newLastString.data());
      CPPUNIT_ASSERT_MESSAGE("alarm with 'NO_LOG' was logged", !oldLastString.compareTo(newLastString));

      alarmId = "TEST_LOG";
      alarmParam = "single parameter";
      alarmParams.removeAll();
      alarmParams.append(&alarmParam);
      OsSysLog::add(FAC_ALARM, PRI_DEBUG, "Test TEST_LOG");
      cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
      OsTask::delay(DELAY);
      UtlString actualString;
      UtlString expectedString = "This is a test of the log function. Single parameter should be here: single parameter, and that's all that is required";
      tail(mAlarmFile, actualString);
      char msg[1000];
      sprintf(msg, "incorrect message was logged: actualString '%s'  expected '%s'", actualString.data(), expectedString.data());
      CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString));

      // test that non-existant alarm returns false
      alarmId = "NONEXISTANT_ID";
      rc=cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
      CPPUNIT_ASSERT_MESSAGE("handleAlarm('NONEXISTANT_ID') did not fail, and should have", rc!=true);

      // test that alarm with min_threshold is only logged after n attempts
      alarmId = "MIN_THRESHOLD";
      alarmParam = "one";
      alarmParams.removeAll();
      alarmParams.append(&alarmParam);
      tail(mAlarmFile, oldLastString);
      OsSysLog::add(FAC_ALARM, PRI_DEBUG, "oldLastString %s", oldLastString.data());
      cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
      OsTask::delay(DELAY);
      tail(mAlarmFile, newLastString);
      OsSysLog::add(FAC_ALARM, PRI_DEBUG, "newLastString %s", newLastString.data());
      CPPUNIT_ASSERT_MESSAGE("first instance of alarm with 'min_threshold' was logged", !oldLastString.compareTo(newLastString));
      alarmParam = "two";
      alarmParams.append(&alarmParam);
      cAlarmServer::getInstance()->handleAlarm(localhost, alarmId, alarmParams);
      OsTask::delay(DELAY);
      tail(mAlarmFile, actualString);
      expectedString = "This should only be logged the second time";
      sprintf(msg, "incorrect message was logged: actualString '%s'  expected '%s'", actualString.data(), expectedString.data());
      CPPUNIT_ASSERT_MESSAGE(msg, actualString.contains(expectedString));

   }
Пример #7
0
OsStatus
NotificationHelper::send (
    const UtlString& rMailboxIdentity,
    const UtlString& rSMTPServer,
    const Url&      mailboxServiceUrl,
    const UtlString& rContact,
    const UtlString& rFrom,
    const UtlString& rReplyTo,
    const UtlString& rDate,
    const UtlString& rDurationMSecs,
    const UtlString& wavFileName,
    const char*     pAudioData,
    const int&      rAudioDatasize,
    const UtlBoolean& rAttachmentEnabled) const
{
    OsStatus status = OS_SUCCESS;

    // For forwarded messages, duration = aggregate of duration of different
    // messages that make up the forwarded message.
    // Skip duration for forwarded messages in this release (1.1).
    UtlString durationText = "" ;
    if( !wavFileName.contains("-FW") )
    {
        durationText += "Duration " ;
        int iDuration = atoi(rDurationMSecs);
        if( iDuration > 0 )
        {
                        // Convert to seconds
                        iDuration = iDuration / 1000;

                        char temp[10];
                        if( iDuration >= 3600 )
                        {
                                // Retrieve the hour.
                                int hours = iDuration / 3600  ;
                                iDuration = iDuration - (hours * 3600);
                                sprintf( temp, "%02d", hours );
                                durationText = UtlString( temp ) + ":" ;
                        }

                        if( iDuration >= 60 )
                        {
                                // Retrieve the hour.
                                int mins = iDuration / 60  ;
                                iDuration = iDuration - (mins * 60);
                                sprintf( temp, "%02d", mins );

                                durationText += UtlString( temp ) + ":" ;
                        }
                        else
                        {
                                durationText += "00:" ;
                        }

                        // append the seconds
                        sprintf( temp, "%02d", iDuration );
                        durationText += temp;
        }
        else
        {
            durationText = UtlString("00:00") ;
        }
    }

    UtlString strFrom = "Unknown" ;
    if( !rFrom.isNull() && rFrom.length() > 0)
        strFrom = rFrom ;
    UtlString subject = "New Voicemail from " + strFrom ;

    UtlString rawMessageId = wavFileName(0, wavFileName.first('-'));
    UtlString userId = rMailboxIdentity(0, rMailboxIdentity.first('@'));

    UtlString plainBodyText, htmlBodyText;

    MailMessage message ( "Voicemail Notification Service", rReplyTo, rSMTPServer );

    UtlString baseMailboxLink = mailboxServiceUrl.toString();
    baseMailboxLink.append("/").append(userId).append("/inbox");

    UtlString playMessageLink = baseMailboxLink;
    playMessageLink.append("/").append(rawMessageId);
    UtlString deleteMessageLink = baseMailboxLink;
    deleteMessageLink.append("/").append(rawMessageId).append("/delete");
    UtlString showMailboxLink = baseMailboxLink;

    plainBodyText += "On " + rDate + ", " + strFrom + " left new voicemail. " +
        durationText + "\n";
    plainBodyText += "Listen to message " + playMessageLink + "\n";
    plainBodyText += "Show Voicemail Inbox "   + showMailboxLink + "\n";
    plainBodyText += "Delete message " + deleteMessageLink + "\n";

    UtlString playMessageLinkXml ;
    UtlString deleteMessageLinkXml;
    UtlString showMailboxLinkXml;
    XmlEscape(playMessageLinkXml, playMessageLink) ;
    XmlEscape(deleteMessageLinkXml, deleteMessageLink) ;
    XmlEscape(showMailboxLinkXml, showMailboxLink) ;
    // Format the html text if supported by the browser
    htmlBodyText =
        (UtlString)"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n" +
                  "   \"http://www.w3.org/TR/html4/strict.dtd\">\n" +
                  "<HTML>\n" +
                  "<HEAD>\n" +
                  "<TITLE>Voicemail Notification</TITLE>\n" +
                  "</HEAD>\n<BODY>\n";
    htmlBodyText +=
        "<p>On " + rDate + ", " + strFrom + " left new voicemail. " +
        durationText + "</p>\n";
    htmlBodyText +=
        "<p><a href=\"" + playMessageLinkXml + "\">Listen to message</a></p>\n";
    htmlBodyText +=
        "<p><a href=\"" + showMailboxLinkXml + "\">Show Voicemail Inbox</a></p>\n";
    htmlBodyText +=
        "<p><a href=\"" + deleteMessageLinkXml + "\">Delete message</a></p>\n";
    htmlBodyText +=
        (UtlString)"</BODY>\n" +
                                  "</HTML>\n";

    if ( rAttachmentEnabled == TRUE )
    {
        unsigned char* unsignedAudioData = (unsigned char*) pAudioData;
        message.Attach( unsignedAudioData, rAudioDatasize, wavFileName);
    }

    message.Body( plainBodyText , htmlBodyText );
    message.Subject( subject );
    message.To( rContact, rContact );
    UtlString response = message.Send();
    if ( !response.isNull() )
    {
        if( response.length() > 0 )
        {
            OsSysLog::add(FAC_MEDIASERVER_CGI, PRI_ERR,
                          "NotificationHelper: "
                          "Error sending e-mail to '%s' via SMTP server '%s'\n    %s",
                          rContact.data(), rSMTPServer.data(), response.data());
            OsSysLog::flush();
        }
    }
    return status;
}
Пример #8
0
/// Process an incoming NOTIFY from an Appearance.  Always sends a response.
void AppearanceGroup::handleNotifyRequest(const UtlString* dialogHandle,
                                          const SipMessage* msg)
{
   SipMessage response;
   Appearance* pThisAppearance = findAppearance(*dialogHandle);
   if ( !pThisAppearance )
   {
      UtlString swappedDialogHandle;
      mAppearanceGroupSet->swapTags(*dialogHandle, swappedDialogHandle);
      pThisAppearance = findAppearance(swappedDialogHandle);
      if ( !pThisAppearance )
      {
         // should never happen, since the NOTIFY was sent straight to the Appearance
         Os::Logger::instance().log(FAC_SAA, PRI_WARNING,
               "AppearanceGroup::handleNotifyRequest: ignoring NOTIFY from unknown subscription, dialogHandle %s",
               dialogHandle->data());
         response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort());
         response.setResponseData(msg, 481, "Subscription does not exist");
         getAppearanceAgent()->getServerUserAgent().send(response);
         return;
      }
   }
   UtlString contactUri = pThisAppearance->getUri()->data();

   // check that event type is supported
   UtlString eventType;
   msg->getEventField(eventType);
   if (eventType != SLA_EVENT_TYPE)
   {
      Os::Logger::instance().log(FAC_SAA, PRI_INFO,
                    "AppearanceGroup::handleNotifyRequest: ignoring NOTIFY(%s): not an SLA event", eventType.data());
      response.setOkResponseData(msg, NULL);
      getAppearanceAgent()->getServerUserAgent().send(response);
      return;
   }

   // Get the NOTIFY content.
   const char* content;
   ssize_t l;
   const HttpBody* body = msg->getBody();
   if (body)
   {
      body->getBytes(&content, &l);
   }
   else
   {
      Os::Logger::instance().log(FAC_SAA, PRI_WARNING,
            "AppearanceGroup::handleNotifyRequest: could not get NOTIFY content, dialogHandle %s",
            dialogHandle->data());
      response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort());
      response.setResponseData(msg, 493, "Undecipherable");
      getAppearanceAgent()->getServerUserAgent().send(response);
      return;
   }
   SipDialogEvent* lContent = new SipDialogEvent(content);

   UtlString state;
   UtlString entity;
   lContent->getState(state);
   lContent->getEntity(entity);

   UtlString dialogState = STATE_TERMINATED;
   UtlString event;
   UtlString code;
   UtlString appearanceId;

   if (state == STATE_TERMINATED)
   {
      // probably not needed now that SipSubscribeClient checks for NOTIFY with terminated state
      // our subscription to this Appearance has terminated.
      Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                    "AppearanceGroup::handleNotifyRequest: subscription to %s has been terminated",
                    contactUri.data());
      // terminate any non-held dialogs? or all dialogs?
   }

   Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                 "AppearanceGroup::handleNotifyRequest: %s update from %s",
                 state.data(), contactUri.data());

   // Assign each dialog a globally-unique ID, if not done yet
   UtlSListIterator* itor = lContent->getDialogIterator();
   Dialog* pDialog;
   while ( (pDialog = dynamic_cast <Dialog*> ((*itor)())) )
   {
      UtlString dialogId;
      UtlString uniqueDialogId;
      UtlString rendering;
      pDialog->getDialogId(dialogId);
      pDialog->getLocalParameter("x-line-id", appearanceId);
      pDialog->getLocalParameter("+sip.rendering", rendering);
      pDialog->getState(dialogState, event, code);

      // Ignore calls with no appearanceId -  these are considered "exclusive".
      // (e.g. MoH calls are private to the set involved)
      // These dialogs are not forwarded on to other sets in either partial or full updates.
      if ( appearanceId == "" )
      {
         Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest skipping call with no appearance info");
         delete lContent->removeDialog(pDialog);
         continue;
      }

      if ( dialogId.contains("@@") )
      {
         // this is one of our identifiers already
         uniqueDialogId = dialogId;
      }
      else
      {
         // make a guaranteed unique dialog id, by
         // prepending to each id value the call-id of the subscription
         // from which the dialog event was obtained, with "@@" as a separator
         msg->getCallIdField(&uniqueDialogId);
         uniqueDialogId.append("@@");
         uniqueDialogId.append(dialogId);
         pDialog->setDialogId(uniqueDialogId);
      }
      Os::Logger::instance().log(FAC_SAA, PRI_INFO,
                    "AppearanceGroup::handleNotifyRequest: "
                    "%s update from %s: dialogId %s, x-line-id %s, state %s(%s)",
                    state.data(), contactUri.data(), uniqueDialogId.data(),
                    appearanceId.data(), dialogState.data(), rendering.data());
   }
   delete itor;

   // Check to see if this appearance (of the Appearance) is available
   bool okToProceed = true;
   if ( state == "partial" && dialogState == "trying" )
   {
      UtlHashMapIterator appitor(mAppearances);
      UtlString* handle;
      while ( okToProceed && (handle = dynamic_cast <UtlString*> (appitor())))
      {
         Appearance* inst = dynamic_cast <Appearance*> (appitor.value());
         okToProceed = !inst->appearanceIdIsSeized(appearanceId);
      }
   }

   bool bSendPartialContent = false;
   bool bSendFullContent = false;

   // Send the response.
   if (okToProceed)
   {
      response.setOkResponseData(msg, NULL);
   }
   else
   {
      Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                    "AppearanceGroup::handleNotifyRequest '%s' appearanceId %s is busy",
                    entity.data(), appearanceId.data());
      response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort());
      response.setResponseData(msg, 409, "Conflict");
   }
   getAppearanceAgent()->getServerUserAgent().send(response);

   if (okToProceed)
   {
      if (lContent)
      {
         // Send the content to the proper Appearance instance, so it can
         // save these dialogs, and set flag to indicate whether they should be sent in partial update
         bSendPartialContent = pThisAppearance->updateState(lContent, bSendFullContent);
      }
      // Publish full and partial updates to the SipPublishContentMgr
      publish(bSendFullContent, bSendPartialContent, lContent);
   }

   // Adjust the expiration of the subscription if the set has the line "seized"
   // and return it to the longer default if it does not.
   UtlHashMapIterator appitor(mAppearances);
   UtlString* handle;
   while ( (handle = dynamic_cast <UtlString*> (appitor())))
   {
      Appearance* inst = dynamic_cast <Appearance*> (appitor.value());

      // if set has line seized, use short subscription timer
      if ( inst->appearanceIsBusy() )
      {
         inst->setResubscribeInterval(true);
      }
      else
      {
         inst->setResubscribeInterval(false);
      }
   }

   if (lContent)
   {
      delete lContent;
   }
}