/// <summary> /// Helper method to convery notification to presence. /// </summary> /// <param name="notification">Notification</param> /// <returns>Presence subscription</returns> private PresenceInformation ConvertNotificationToPresence(RemotePresentityNotification notification) { //after the first notification for a contact, you only get the categories that changed next time //so after the first notification if presence changes, you only get presence; if name changes you only get contact card long availability = PresenceInformation.NoChangeInAvailability; string status = PresenceInformation.NoChange; string contactName = PresenceInformation.NoChange; string activityStatus = PresenceInformation.NoChange; var presence = notification.AggregatedPresenceState; if (presence != null) { //Get availability. availability = presence.AvailabilityValue; status = AvailabilityToStatusConverter.Convert(availability); //Get activity status. PresenceActivity activity = presence.Activity; if (activity != null && activity.CustomTokens != null && activity.CustomTokens.Count > 0) { //For now just take the first token. activityStatus = activity.CustomTokens[0].Value ?? PresenceInformation.NoChange; } } var contactCard = notification.ContactCard; if (contactCard != null) { contactName = contactCard.DisplayName; } return(new PresenceInformation { Availability = availability, ContactName = contactName, SipUri = notification.PresentityUri, Status = status, ActivityStatus = activityStatus }); }
// Publish note, state, contact card presence categories private void PublishPresenceCategories(bool publishFlag, string status = null) { try { if (publishFlag == true) { // The CustomPresenceCategory class enables creation of a // category using XML. This allows precise crafting of a // category, but it is also possible to create a category // in other, more simple ways, shown below. _note = new CustomPresenceCategory("note", String.Format(_noteXml, _noteValue)); switch (status) { default: //Available _userState = PresenceState.UserAvailable; Console.WriteLine(DateTime.Now.ToString() + " Setting available status."); // It is possible to create and publish state with a custom availablity string, shown below LocalizedString localizedAvailableString = new LocalizedString("Available"); // Create a PresenceActivity indicating the "In a call" state. PresenceActivity Available = new PresenceActivity(localizedAvailableString); // Set the Availability of the "In a call" state to Busy. Available.SetAvailabilityRange((int)PresenceAvailability.Online, (int)PresenceAvailability.Online); // Microsoft Lync will also show the Busy presence icon. _phoneState = new PresenceState( (int)PresenceAvailability.Online, Available, PhoneCallType.Voip, "phone uri"); break; case "Busy": //Busy Console.WriteLine(DateTime.Now.ToString() + " Setting busy status."); _userState = PresenceState.UserBusy; LocalizedString localizedBusyString = new LocalizedString("Busy"); PresenceActivity Busy = new PresenceActivity(localizedBusyString); Busy.SetAvailabilityRange((int)PresenceAvailability.Busy, (int)PresenceAvailability.IdleBusy); _phoneState = new PresenceState( (int)PresenceAvailability.Busy, Busy, PhoneCallType.Voip, "phone uri"); break; case "In a call": //In a call Console.WriteLine(DateTime.Now.ToString() + " Setting in a call status."); _userState = PresenceState.UserBusy; LocalizedString localizedCallString = new LocalizedString("In a call"); PresenceActivity inACall = new PresenceActivity(localizedCallString); inACall.SetAvailabilityRange((int)PresenceAvailability.Busy, (int)PresenceAvailability.IdleBusy); _phoneState = new PresenceState( (int)PresenceAvailability.Busy, inACall, PhoneCallType.Voip, "phone uri"); break; case "In a meeting": //In a meeting Console.WriteLine(DateTime.Now.ToString() + " Setting in a meeting status."); _userState = PresenceState.UserBusy; LocalizedString localizedMeetingString = new LocalizedString("In a meeting"); PresenceActivity inAMeeting = new PresenceActivity(localizedMeetingString); inAMeeting.SetAvailabilityRange((int)PresenceAvailability.Busy, (int)PresenceAvailability.IdleBusy); _phoneState = new PresenceState( (int)PresenceAvailability.Busy, inAMeeting, PhoneCallType.Voip, "phone uri"); break; case "In a conference call": //In a conference call Console.WriteLine(DateTime.Now.ToString() + " Setting in a conference call status."); _userState = PresenceState.UserBusy; LocalizedString localizedConferenceString = new LocalizedString("In a conference call"); PresenceActivity inAConference = new PresenceActivity(localizedConferenceString); inAConference.SetAvailabilityRange((int)PresenceAvailability.Busy, (int)PresenceAvailability.IdleBusy); _phoneState = new PresenceState( (int)PresenceAvailability.Busy, inAConference, PhoneCallType.Voip, "phone uri"); break; case "Presenting": //Presenting Console.WriteLine(DateTime.Now.ToString() + " Setting presenting status."); _userState = PresenceState.UserBusy; LocalizedString localizedPresentingString = new LocalizedString("Presenting"); PresenceActivity Presenting = new PresenceActivity(localizedPresentingString); Presenting.SetAvailabilityRange((int)PresenceAvailability.Busy, (int)PresenceAvailability.DoNotDisturb); _phoneState = new PresenceState( (int)PresenceAvailability.DoNotDisturb, Presenting, PhoneCallType.Voip, "phone uri"); break; case "Offline": //Offline Console.WriteLine(DateTime.Now.ToString() + " Setting offline status."); _userState = PresenceState.UserOffline; LocalizedString localizedOfflineString = new LocalizedString("Offline"); PresenceActivity Offline = new PresenceActivity(localizedOfflineString); Offline.SetAvailabilityRange((int)PresenceAvailability.Offline, (int)PresenceAvailability.Offline); _phoneState = new PresenceState( (int)PresenceAvailability.Offline, Offline, PhoneCallType.Voip, "phone uri"); break; } // Machine or Endpoint states must always be published to // indicate the endpoint is actually online, otherwise it is // assumed the endpoint is offline, and no presence // published from that endpoint will be displayed. _machineState = PresenceState.EndpointOnline; // It is also possible to create presence categories such // as ContactCard, Note, PresenceState, and Services with // their constructors. // Here we create a ContactCard and change the title. _contactCard = new ContactCard(0); /* The title string to be displayed. */ if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["UserTitle"])) { LocalizedString localizedTitleString = new LocalizedString(ConfigurationManager.AppSettings["UserTitle"]); _contactCard.JobTitle = localizedTitleString.Value; } if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["UserOffice"])) { LocalizedString localizedTitleString = new LocalizedString(ConfigurationManager.AppSettings["UserOffice"]); _contactCard.OfficeLocation = localizedTitleString.Value; } if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["JobTitle"])) { LocalizedString localizedTitleString = new LocalizedString(ConfigurationManager.AppSettings["JobTitle"]); _contactCard.JobTitle = localizedTitleString.Value; } // Publish a photo // If the supplied value for photo is null or empty, then set value of IsAllowedToShowPhoto to false _contactCard.IsAllowedToShowPhoto = false; string photoUri = ConfigurationManager.AppSettings["PhotoUri"]; if (!String.IsNullOrEmpty(photoUri)) { _contactCard.IsAllowedToShowPhoto = true; _contactCard.PhotoUri = photoUri; } // Publish all presence categories with new values. _localOwnerPresence.BeginPublishPresence( new PresenceCategory[] { _userState, _phoneState, _machineState, _note, _contactCard }, PublishPresenceCompleted, /* async callback when publishing operation completes. */ publishFlag /* value TRUE indicates that presence to be published with new values. */); } else { // Delete all presence categories. Console.WriteLine(DateTime.Now.ToString() + " Revert status back."); _localOwnerPresence.BeginDeletePresence( new PresenceCategory[] { _userState, _phoneState, _machineState, _note, _contactCard }, PublishPresenceCompleted, publishFlag /* value FALSE indicates that presence reverted to original values. */); } } catch (PublishSubscribeException pse) { // PublishSubscribeException is thrown when there were // exceptions during this presence operation such as badly // formed sip request, duplicate publications in the same // request etc. // TODO (Left to the reader): Include exception handling code // here. Console.WriteLine(pse.ToString()); } catch (RealTimeException rte) { // RealTimeException is thrown when SIP Transport, SIP // Authentication, and credential-related errors are // encountered. // TODO (Left to the reader): Include exception handling code // here. Console.WriteLine(rte.ToString()); } }
/// <summary> /// PublishPresenceToWebCustomers is a method that indicates Web Users different levels of Presence based on /// the average queue time, or whether the portal is getting drained. /// </summary> private void PublishPresenceToWebCustomers() { //Limitation: Note that this publication only makes sense if only one instance of the Application is in service. // If multiple instances of the application were running at the same time, one shall consider using a database to coordinate the publication // of the information. PresenceState aggregateState; if (_portalState == PortalState.Started || _portalState == PortalState.Draining) { if (_portalState == ContactCenter.PortalState.Started) { TimeSpan averageWaitTime = _agentHunter.AverageQueueTime.Value; if (averageWaitTime <= AcdPortal.OneMinuteSpan) { var presenceActivity = new PresenceActivity(new LocalizedString(1033, String.Format("Expected Wait Time is \r\n {0} min and {1} sec", averageWaitTime.Minutes, averageWaitTime.Seconds))); presenceActivity.SetAvailabilityRange(3500, 3500); aggregateState = new PresenceState(PresenceStateType.AggregateState, 3500, presenceActivity); } else if (averageWaitTime <= AcdPortal.FiveMinuteSpan) { var presenceActivity = new PresenceActivity(new LocalizedString(1033, String.Format("Expected Wait Time is \r\n {0} min and {1} sec", averageWaitTime.Minutes, averageWaitTime.Seconds))); presenceActivity.SetAvailabilityRange(6500, 6500); aggregateState = new PresenceState(PresenceStateType.AggregateState, 6500, presenceActivity); } else { string activityString = null; if (averageWaitTime.Hours > 0) { activityString = String.Format("Expect Long Wait Time; \r\n currently {0} hour {1} min and {2} sec", averageWaitTime.Hours, averageWaitTime.Minutes, averageWaitTime.Seconds); } else { activityString = String.Format("Expect Long Wait Time; \r\n currently {0} min and {1} sec", averageWaitTime.Minutes, averageWaitTime.Seconds); } var presenceActivity = new PresenceActivity(new LocalizedString(1033, activityString)); presenceActivity.SetAvailabilityRange(6500, 6500); aggregateState = new PresenceState(PresenceStateType.AggregateState, 6500, presenceActivity); } } else { var presenceActivity = new PresenceActivity(new LocalizedString(1033, "This service is not available at this time; please call again later.")); presenceActivity.SetAvailabilityRange(9500, 9500); aggregateState = new PresenceState(PresenceStateType.AggregateState, 9500, presenceActivity); } PresenceCategoryWithMetaData averageQueueTimePublication = new PresenceCategoryWithMetaData(1, ContainerIDForWebUsers, aggregateState); try { _endpoint.LocalOwnerPresence.BeginPublishPresence(new List <PresenceCategoryWithMetaData>() { averageQueueTimePublication }, pub => { try { _endpoint.LocalOwnerPresence.EndPublishPresence(pub); } catch (OperationFailureException ofex) { _logger.Log("AcdPortal failed to end publish average queue time", ofex); } catch (PublishSubscribeException psex) { _logger.Log("AcdPortal failed to end publish average queue time", psex); } catch (RealTimeException rtex) { _logger.Log("AcdPortal failed to end publish average queue time", rtex); } }, null); } catch (InvalidOperationException ivoex) { _logger.Log("AcdPortal failed to begin publish average queue time", ivoex); } } }
// Publish note, state, contact card presence categories private void PublishPresenceCategories(bool publishFlag) { try { if (publishFlag == true) { // The CustomPresenceCategory class enables creation of a // category using XML. This allows precise crafting of a // category, but it is also possible to create a category // in other, more simple ways, shown below. _note = new CustomPresenceCategory("note", String.Format(_noteXml, _noteValue)); // The PresenceState class has several static properties // and methods which will provide standard states such as // online, busy, and on-the-phone, for example. _userState = PresenceState.UserBusy; // It is possible to create and publish state with a // custom availablity string, shown below. "In a call" will // be shown in Microsoft Lync. LocalizedString localizedCallString = new LocalizedString( "In a call" /* The string to be displayed. */); // Create a PresenceActivity indicating the // "In a call" state. PresenceActivity inACall = new PresenceActivity( localizedCallString); // Set the Availability of the "In a call" state to Busy. inACall.SetAvailabilityRange((int)PresenceAvailability.Busy, (int)PresenceAvailability.IdleBusy); // Microsoft Lync will also show the Busy presence icon. _phoneState = new PresenceState( (int)PresenceAvailability.Busy, inACall, PhoneCallType.Voip, "phone uri"); // Machine or Endpoint states must always be published to // indicate the endpoint is actually online, otherwise it is // assumed the endpoint is offline, and no presence // published from that endpoint will be displayed. _machineState = PresenceState.EndpointOnline; // It is also possible to create presence categories such // as ContactCard, Note, PresenceState, and Services with // their constructors. // Here we create a ContactCard and change the title. _contactCard = new ContactCard(3); LocalizedString localizedTitleString = new LocalizedString( "The Boss" /* The title string to be displayed. */); _contactCard.JobTitle = localizedTitleString.Value; // Publish a photo // If the supplied value for photo is null or empty, then set value of IsAllowedToShowPhoto to false _contactCard.IsAllowedToShowPhoto = true; string photoUri = UCMASampleHelper.PromptUser("Please enter a Photo Uri in the form of http://mysite/photo1.jpg", "PhotoURI1"); if (String.IsNullOrEmpty(photoUri)) { photoUri = null; _contactCard.IsAllowedToShowPhoto = false; } _contactCard.PhotoUri = photoUri; // Publish all presence categories with new values. _localOwnerPresence.BeginPublishPresence( new PresenceCategory[] { _userState, _phoneState, _machineState, _note, _contactCard }, PublishPresenceCompleted, /* async callback when publishing operation completes. */ publishFlag /* value TRUE indicates that presence to be published with new values. */); } else { // Delete all presence categories. _localOwnerPresence.BeginDeletePresence( new PresenceCategory[] { _userState, _phoneState, _machineState, _note, _contactCard }, PublishPresenceCompleted, publishFlag /* value FALSE indicates that presence reverted to original values. */); } } catch (PublishSubscribeException pse) { // PublishSubscribeException is thrown when there were // exceptions during this presence operation such as badly // formed sip request, duplicate publications in the same // request etc. // TODO (Left to the reader): Include exception handling code // here. Console.WriteLine(pse.ToString()); } catch (RealTimeException rte) { // RealTimeException is thrown when SIP Transport, SIP // Authentication, and credential-related errors are // encountered. // TODO (Left to the reader): Include exception handling code // here. Console.WriteLine(rte.ToString()); } }