예제 #1
0
// Constructor
AppearanceGroup::AppearanceGroup(AppearanceGroupSet* appearanceGroupSet,
                       const char* user) :
//   mResource(resource),
   mAppearanceGroupSet(appearanceGroupSet),
   mSharedUser(user)
{
   Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                 "AppearanceGroup:: this = %p, mSharedUser = '******'",
                 this, mSharedUser.data());

   // Publish initial content (presumably empty)
   SipDialogEvent* lFullContent = new SipDialogEvent("full", mSharedUser.data());
   UtlHashMapIterator appitor(mAppearances);
   UtlString* handle;
   while ( (handle = dynamic_cast <UtlString*> (appitor())))
   {
      Appearance* inst = dynamic_cast <Appearance*> (appitor.value());
      inst->getDialogs(lFullContent);
   }
   lFullContent->buildBody();

  // Publish the content for this shared user to the Subscribe Server.
  // Make a copy, because mpSipPublishContentMgr will own it.
  HttpBody* pHttpBody = new HttpBody(*(HttpBody*)lFullContent);
  delete lFullContent;
  getAppearanceAgent()->getEventPublisher().publish(
        mSharedUser.data(),
        DIALOG_SLA_EVENT_TYPE, //eventTypeKey
        DIALOG_EVENT_TYPE,     //eventType
        1, &pHttpBody,
        TRUE, TRUE);

   startSubscription();
}
예제 #2
0
void AppearanceGroup::publish(bool bSendFullContent, bool bSendPartialContent, SipDialogEvent* lContent)
{
   Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
         "AppearanceGroup::publish sending NOTIFY for: '%s'", mSharedUser.data());
   if (bSendFullContent)
   {
      // Both the Full and the Partial dialog-infos are sent to the SIP Subscribe Server.
      // The Partial will then be sent out right away and the Full
      // will be stored in the Subscribe Server to be sent on any initial
      // SUBSCRIBEs and re-SUBSCRIBEs.
      // Note that the full-state publish() must be done before the partial-state
      // publish() to avoid race conditions with regard to starting a new
      // subscription.
      // The Full content is constructed from all dialogs being managed by all appearances.
      UtlHashMapIterator itor(mAppearances);
      SipDialogEvent* lFullContent = new SipDialogEvent("full", mSharedUser.data());
      UtlHashMapIterator appitor(mAppearances);
      UtlString* handle;
      while ( (handle = dynamic_cast <UtlString*> (appitor())))
      {
         Appearance* inst = dynamic_cast <Appearance*> (appitor.value());
         inst->getDialogs(lFullContent);
      }
      lFullContent->buildBody();

      // Publish the content to the subscribe server.
      // Make a copy, because SipPublishContentMgr will own it.
      HttpBody* pHttpBody = new HttpBody(*(HttpBody*)lFullContent);

      getAppearanceAgent()->getEventPublisher().publish(
            mSharedUser.data(),
            DIALOG_SLA_EVENT_TYPE, //eventTypeKey
            DIALOG_EVENT_TYPE,     //eventType
            1, &pHttpBody,
            TRUE, TRUE);
      delete lFullContent;
   }

   if ( bSendPartialContent )
   {
      // The Partial content is the incoming message, with unique dialog ids.
      lContent->setState(STATE_PARTIAL);
      lContent->buildBody();
      HttpBody* pPartialBody = new HttpBody(*(HttpBody*)lContent);
      getAppearanceAgent()->getEventPublisher().publish(
            mSharedUser.data(),
            DIALOG_SLA_EVENT_TYPE, //eventTypeKey
            DIALOG_EVENT_TYPE,     //eventType
            1, &pPartialBody,
            FALSE, FALSE);
   }

}
예제 #3
0
UtlBoolean DialogEventPublisher::handleMessage(OsMsg& rMsg)
{
   SipDialog sipDialog;
   UtlString sipDialogContent;
   Url requestUrl;
   UtlString entity;
   UtlString* pEntity;
   char dialogId[10];
   SipDialogEvent* pThisCall;
   Dialog* pDialog;
   UtlString localTag, remoteTag;
   Url localIdentity, remoteIdentity;
   Url localTarget, remoteTarget;
   UtlString identity, displayName;
   OsTime receivedTime;
   int numOldContents;
   HttpBody* oldContent[1];

   int length;
   UtlString dialogEvent;
   
   // React to telephony events
   if(rMsg.getMsgSubType()== TaoMessage::EVENT)
   {
      TaoMessage* taoMessage = (TaoMessage*)&rMsg;

      int taoEventId = taoMessage->getTaoObjHandle();
      UtlString argList(taoMessage->getArgList());
      TaoString arg(argList, TAOMESSAGE_DELIMITER);

#ifdef DEBUGGING
      dumpTaoMessageArgs(taoEventId, arg) ;
#endif        
      UtlBoolean localConnection = atoi(arg[TAO_OFFER_PARAM_LOCAL_CONNECTION]);
      UtlString  callId = arg[TAO_OFFER_PARAM_CALLID] ;
      UtlString  address = arg[TAO_OFFER_PARAM_ADDRESS] ;

      switch (taoEventId) 
      {
         case PtEvent::CONNECTION_OFFERED:

            mpCallManager->getSipDialog(callId, address, sipDialog);
#ifdef DEBUGGING            
            sipDialog.toString(sipDialogContent);
            OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: sipDialog = %s", 
                          sipDialogContent.data());
#endif            
            sipDialog.getRemoteRequestUri(entity);
            
            OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: Call arrived: callId %s address %s requestUrl %s", 
                          callId.data(), address.data(), entity.data());

            if (entity.isNull())
            {
               OsSysLog::add(FAC_SIP, PRI_WARNING, "DialogEventPublisher:: Call arrived: callId %s address %s without requestUrl", 
                             callId.data(), address.data());
               break;
            }
            else
            {
               requestUrl = Url(entity);
               requestUrl.getIdentity(entity);
            }
               
            // Create a dialog event if has not been created yet
            pThisCall = (SipDialogEvent *) mCalls.findValue(&entity);
            if (pThisCall == NULL)
            {
               pEntity = new UtlString(entity);
               pThisCall = new SipDialogEvent(STATE, entity);
               mCalls.insertKeyAndValue(pEntity, pThisCall);
               OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: insert DialogEvent object %p to the list",
                             pThisCall);
            }

            // Create the dialog element
            sipDialog.getLocalField(localIdentity);
            localIdentity.getFieldParameter("tag", localTag);
   
            sipDialog.getRemoteField(remoteIdentity);
            remoteIdentity.getFieldParameter("tag", remoteTag);
               
            sprintf(dialogId, "%ld", mDialogId);
            mDialogId++;

            pDialog = new Dialog(dialogId, callId, localTag, remoteTag, "recipient");
            pDialog->setState(STATE_EARLY, NULL, NULL);
   
            localIdentity.getIdentity(identity);
            localIdentity.getDisplayName(displayName);
            pDialog->setLocalIdentity(identity, displayName);
   
            remoteIdentity.getIdentity(identity);
            remoteIdentity.getDisplayName(displayName);
            pDialog->setRemoteIdentity(identity, displayName);
   
            sipDialog.getLocalContact(localTarget);
            pDialog->setLocalTarget(localTarget.toString());
   
            sipDialog.getRemoteContact(remoteTarget);
            pDialog->setRemoteTarget(remoteTarget.toString());
               
            pDialog->setDuration(OsDateTime::getSecsSinceEpoch());
   
            pThisCall->insertDialog(pDialog);
   
            // Insert it into the active call list
            pThisCall->buildBody();

            // Send the content to the subscribe server
            if (!mpSipPublishContentMgr->publish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, (HttpBody**)&pThisCall, 1, numOldContents, oldContent))
            {
               pThisCall->getBytes(&dialogEvent, &length);
               OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call arrived - DialogEvent %s\n was not successfully published to the subscribe server",
                             dialogEvent.data());
            }
                        
            break;

         case PtEvent::CONNECTION_ESTABLISHED:
            if (localConnection) 
            {
               mpCallManager->getSipDialog(callId, address, sipDialog);
#ifdef DEBUGGING            
               sipDialog.toString(sipDialogContent);
               OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: sipDialog = %s", 
                             sipDialogContent.data());
#endif            
               sipDialog.getRemoteRequestUri(entity);

               OsSysLog::add(FAC_SIP, PRI_DEBUG, "Call connected: callId %s address %s with request %s",
                             callId.data(), address.data(), entity.data());

               if (entity.isNull())
               {
                  OsSysLog::add(FAC_SIP, PRI_WARNING, "DialogEventPublisher:: Call connected: callId %s address %s without requestUrl", 
                                callId.data(), address.data());
                  break;
               }
               else
               {
                  requestUrl = Url(entity);
                  requestUrl.getIdentity(entity);
               }
               
               pThisCall = (SipDialogEvent *) mCalls.findValue(&entity);
               if (pThisCall == NULL)
               {
                  pEntity = new UtlString(entity);
                  pThisCall = new SipDialogEvent(STATE, entity);
   
                  // Insert it into the active call list
                  mCalls.insertKeyAndValue(pEntity, pThisCall);
               }
               
               // Get the new callId because it might be changed
               sipDialog.getCallId(callId);

               pDialog = pThisCall->getDialog(callId);
               // Update the dialog content if exist
               if (pDialog)
               {
                  sipDialog.getLocalField(localIdentity);
                  localIdentity.getFieldParameter("tag", localTag);
   
                  sipDialog.getRemoteField(remoteIdentity);
                  remoteIdentity.getFieldParameter("tag", remoteTag);
               
                  pDialog->setTags(localTag, remoteTag);
   
                  sipDialog.getLocalContact(localTarget);
                  pDialog->setLocalTarget(localTarget.toString());
   
                  sipDialog.getRemoteContact(remoteTarget);
                  pDialog->setRemoteTarget(remoteTarget.toString());
   
                  pDialog->setState(STATE_CONFIRMED, NULL, NULL);
               }
               else
               {
                  // Create a new dialog element
                  sipDialog.getLocalField(localIdentity);
                  localIdentity.getFieldParameter("tag", localTag);
   
                  sipDialog.getRemoteField(remoteIdentity);
                  remoteIdentity.getFieldParameter("tag", remoteTag);
               
                  sprintf(dialogId, "%ld", mDialogId);
                  mDialogId++;
   
                  pDialog = new Dialog(dialogId, callId, localTag, remoteTag, "recipient");
                  pDialog->setState(STATE_CONFIRMED, NULL, NULL);
   
                  localIdentity.getIdentity(identity);
                  localIdentity.getDisplayName(displayName);
                  pDialog->setLocalIdentity(identity, displayName);
   
                  remoteIdentity.getIdentity(identity);
                  remoteIdentity.getDisplayName(displayName);
                  pDialog->setRemoteIdentity(identity, displayName);
   
                  sipDialog.getLocalContact(localTarget);
                  pDialog->setLocalTarget(localTarget.toString());
   
                  sipDialog.getRemoteContact(remoteTarget);
                  pDialog->setRemoteTarget(remoteTarget.toString());
   
                  pDialog->setDuration(OsDateTime::getSecsSinceEpoch());
   
                  pThisCall->insertDialog(pDialog);
               }
                   
               pThisCall->buildBody();

               // Publish the content to the subscribe server
               if (!mpSipPublishContentMgr->publish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, (HttpBody**)&pThisCall, 1, numOldContents, oldContent))
               {
                  pThisCall->getBytes(&dialogEvent, &length);
                  OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call connected - DialogEvent %s\n was not successfully published to the subscribe server",
                                dialogEvent.data());
               }
            }

            break;
            
         case PtEvent::CONNECTION_DISCONNECTED:
            if (!localConnection) 
            {
               mpCallManager->getSipDialog(callId, address, sipDialog);
#ifdef DEBUGGING            
               sipDialog.toString(sipDialogContent);
               OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: sipDialog = %s", 
                             sipDialogContent.data());
#endif            
               sipDialog.getLocalContact(requestUrl);
               requestUrl.getIdentity(entity);

               OsSysLog::add(FAC_SIP, PRI_DEBUG, "Call dropped: %s address %s with entity %s",
                             callId.data(), address.data(), entity.data());

               if (entity.isNull())
               {
                  OsSysLog::add(FAC_SIP, PRI_WARNING, "DialogEventPublisher:: Call dropped: callId %s address %s without requestUrl", 
                                callId.data(), address.data());
                  break;
               }
               
               // Get the new callId because it might be changed
               sipDialog.getCallId(callId);

               // Remove the call from the pool and clean up the call
               pThisCall = (SipDialogEvent *) mCalls.findValue(&entity);
               if (pThisCall)
               {
                  pDialog = pThisCall->getDialog(callId);
                  if (pDialog)
                  {
                     pDialog->setState(STATE_TERMINATED, NULL, NULL);
                   
                     pThisCall->buildBody();

                     // Publish the content to the subscribe server
                     if (!mpSipPublishContentMgr->publish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, (HttpBody**)&pThisCall, 1, numOldContents, oldContent))
                     {
                        pThisCall->getBytes(&dialogEvent, &length);
                        OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call dropped - DialogEvent %s\n was not successfully published to the subscribe server",
                                      dialogEvent.data());
                     }
                       
                     // Remove the dialog from the dialog event package
                     pDialog = pThisCall->removeDialog(pDialog);
                     delete pDialog;
                  }
                  
                  if (pThisCall->isEmpty())
                  {
                     // Unpublisher the content from the subscribe server
                     if (!mpSipPublishContentMgr->unpublish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, numOldContents, oldContent))
                     {
                        pThisCall->getBytes(&dialogEvent, &length);
                        OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call dropped - DialogEvent %s\n was not successfully unpublished to the subscribe server",
                                      dialogEvent.data());
                     }
                     
                     UtlContainable *foundValue;
                     mCalls.removeKeyAndValue(pEntity, foundValue);
                     if (foundValue)
                     {
                        OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: remove DialogEvent object %p from the list",
                                      pThisCall);
                        pThisCall = (SipDialogEvent *) foundValue;
                        delete pThisCall;
                        delete pEntity;
                     }
                  }
               }
               else
               {
                  OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call dropped - no entity %s founded in the active call list",
                                entity.data());
               }
            }

            break;
            
         case PtEvent::CONNECTION_FAILED:
            OsSysLog::add(FAC_SIP, PRI_WARNING, "Connection failed on call: %s", callId.data());

            break;
      }
   }
   return(TRUE);
}
예제 #4
0
// Update the subscriptions we maintain to agree with the current contact state
void AppearanceGroup::updateSubscriptions()
{
   Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                 "AppearanceGroup::updateSubscriptions mUri = '%s'",
                 mSharedUser.data());

   // First, scan mSubscriptions to construct a list of all the
   // call-id/contact combinations.
   // (If a phone reboots and starts registering with a different Call-Id,
   // the call-id/contact combination will be different even if the contact
   // URI is unchanged.  So the new registration will appear to be different
   // to this machinery, and it will establish a new Appearance to
   // the contact URI.  This compensates for the fact that the previous
   // Appearance to the contact URI appears to the Appearance Agent to be
   // working but the phone no longer knows of the subscription.  The
   // reg events will eventually terminate the old combination and we
   // will delete its Appearance.)
   UtlHashBag callid_contacts;

   UtlHashMapIterator subs_itor(mSubscriptions);
   while (subs_itor())
   {
      if (Os::Logger::instance().willLog(FAC_SAA, PRI_DEBUG))
      {
         Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                       "AppearanceGroup::updateSubscriptions subscription '%s'",
                       (dynamic_cast <UtlString*> (subs_itor.key()))->data());
      }
      UtlHashMap* contact_state =
         dynamic_cast <UtlHashMap*> (subs_itor.value());
      Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                    "AppearanceGroup::updateSubscriptions contact_state = %p",
                    contact_state);
      UtlHashMapIterator contact_itor(*contact_state);
      while (contact_itor())
      {
         UtlString* contact =
            dynamic_cast <UtlString*> (contact_itor.value());
         if (Os::Logger::instance().willLog(FAC_SAA, PRI_DEBUG))
         {
            Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                          "AppearanceGroup::updateSubscriptions contact id '%s', Call-Id/URI '%s'",
                          (dynamic_cast <UtlString*> (contact_itor.key()))->data(),
                          contact->data());
         }
         // Check if the contact is already in callid_contacts.
         if (!callid_contacts.find(contact))
         {
            // If not, add it.
            UtlString* c = new UtlString(*contact);
            callid_contacts.insert(c);
            Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                          "AppearanceGroup::updateSubscriptions contact '%s' added", c->data());
         }
      }
   }

   // Now that we have a clean list of callid_contacts, update
   // Appearances to match it.

   // If we both terminate subscriptions and create subscriptions,
   // wait a short while to allow the terminations to complete.  This
   // should not be necessary, but it makes life easier on Polycom
   // phones which (at this time) cannot support two subscriptions at
   // a time, and if the termination of the old subscription arrives
   // after the initiation of the new subscription, the new
   // subscription will be lost.
   // This variable tracks whether such a wait is needed before a
   // subscription is started.
   bool subscription_ended_but_no_wait_done_yet = false;

   // Iterate through the list of Appearances and remove any that aren't
   // in callid_contacts.
   {
      UtlHashMapIterator itor(mAppearances);
      UtlString* ss;
      while ((ss = dynamic_cast <UtlString*> (itor())))
      {
         if (!callid_contacts.find(ss))
         {
            Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                          "AppearanceGroup::updateSubscriptions deleting subscription for '%s' in mUri = '%s'",
                          ss->data(), mSharedUser.data());
            // Terminate all dialogs for this Appearance, then publish - before we delete it
            bool bContentChanged = false;
            SipDialogEvent* lPartialContent = new SipDialogEvent("partial", mSharedUser.data());
            Appearance* inst = dynamic_cast <Appearance*> (itor.value());
            bContentChanged = inst->terminateDialogs(true); // terminate all dialogs
            inst->getDialogs(lPartialContent);
            if (bContentChanged)
            {
               lPartialContent->buildBody();
               publish(true, true, lPartialContent);
               delete lPartialContent;
            }
            mAppearances.destroy(ss);
            subscription_ended_but_no_wait_done_yet = true;
         }
         else
         {
            Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                          "AppearanceGroup::updateSubscriptions found subscription for '%s' in mUri = '%s'",
                          ss->data(), mSharedUser.data());
         }
      }
   }

   // Iterate through callid_contacts and add an Appearance for
   // any that aren't in mAppearances.
   // We don't limit the number of additions here, as the size of
   // callid_contacts is guarded by the tests in notifyEventCallback.
   {
      UtlHashBagIterator itor(callid_contacts);
      UtlString* callid_contact;
      while ((callid_contact = dynamic_cast <UtlString*> (itor())))
      {
         if (!mAppearances.find(callid_contact))
         {
            // If we both terminate subscriptions and create subscriptions,
            // wait a short while to allow the terminations to complete.
            if (SUBSCRIPTION_WAIT > 0)
            {
               if (subscription_ended_but_no_wait_done_yet)
               {
                  Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                                "AppearanceGroup::updateSubscriptions waiting for %d msec",
                                SUBSCRIPTION_WAIT);
                  OsTask::delay(SUBSCRIPTION_WAIT);
                  subscription_ended_but_no_wait_done_yet = false;
               }
            }

            Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                          "AppearanceGroup::updateSubscriptions adding subscription for '%s' in mUri = '%s'",
                          callid_contact->data(), mSharedUser.data());
            // Get the contact URI into a UtlString.
            UtlString uri(callid_contact->data() +
                          callid_contact->index(';') +
                          1);
            mAppearances.insertKeyAndValue(new UtlString(*callid_contact),
                                           new Appearance(getAppearanceAgent(), this,  uri)
                                           );
         }
         else
         {
            Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                          "AppearanceGroup::updateSubscriptions using existing subscription for '%s' in mUri = '%s'",
                          callid_contact->data(), mSharedUser.data());
         }
      }
   }

   // Free callid_contacts.
   callid_contacts.destroyAll();
}
예제 #5
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;
   }
}
예제 #6
0
// Destructor
AppearanceGroup::~AppearanceGroup()
{
   Os::Logger::instance().log(FAC_SAA, PRI_DEBUG,
                 "AppearanceGroup::~ this = %p, mSharedUser = '******'",
                 this, mSharedUser.data());
   // Delete this AppearanceGroup from mSubscribeMap (for the "reg" subscription).
   getAppearanceAgent()->getAppearanceGroupSet().deleteSubscribeMapping(&mSubscriptionEarlyDialogHandle);

   // End the "reg" subscription.
   UtlBoolean ret;
   ret = getAppearanceAgent()->getSubscribeClient().
      endSubscriptionGroup(mSubscriptionEarlyDialogHandle);
   Os::Logger::instance().log(FAC_SAA,
                 ret ? PRI_INFO : PRI_WARNING,
                 "AppearanceGroup::~ endSubscriptionGroup %s mSharedUser = '******', mSubscriptionEarlyDialogHandle = '%s'",
                 ret ? "succeeded" : "failed",
                 mSharedUser.data(),
                 mSubscriptionEarlyDialogHandle.data());

   // Remove this AppearanceGroup from mNotifyMap for all subscriptions.
   {
      UtlHashMapIterator itor(mSubscriptions);
      UtlString* handle;
      while ((handle = dynamic_cast <UtlString*> (itor())))
      {
         getAppearanceAgent()->getAppearanceGroupSet().deleteNotifyMapping(handle);
      }
   }

   // Delete the contents of mSubscriptions.
   mSubscriptions.destroyAll();

   // Terminate all dialogs for this shared Appearance Group, then publish
   bool bContentChanged = false;
   SipDialogEvent* lPartialContent = new SipDialogEvent("partial", mSharedUser.data());
   {
      UtlHashMapIterator itor(mAppearances);
      UtlString* handle;
      while ( (handle = dynamic_cast <UtlString*> (itor())) )
      {
         Appearance* pApp = dynamic_cast <Appearance*> (itor.value());
         bContentChanged |= pApp->terminateDialogs(true); // terminate all dialogs
         pApp->getDialogs(lPartialContent);
      }
   }
   if (bContentChanged)
   {
      lPartialContent->buildBody();
      publish(true, true, lPartialContent);
   }
   delete lPartialContent;

   // Delete the subordinate Appearance's for the contacts.
   {
      // Have to use a loop to remove items individually, because
      // destroyAll() deadlocks with the access to mAppearances
      // during the the attempt to publish new status for the resource
      // as the Appearances are recursively deleted.
      int changeDelay = getAppearanceAgent()->getChangeDelay();
      UtlHashMapIterator itor(mAppearances);
      UtlContainable* k;
      while ((k = itor()))
      {
         UtlContainable* v = itor.value();
         mAppearances.removeReference(k);
         delete k;
         delete v;
         // Delay to allow the consequent processing to catch up.
         OsTask::delay(changeDelay);
      }
   }
}