using CallFlow.CFD; using CallFlow; using MimeKit; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks.Dataflow; using System.Threading.Tasks; using System.Threading; using System; using TCX.Configuration; namespace _73_dynWeiterleitung_aus { public class Main : ScriptBase
, ICallflow, ICallflowProcessor { private bool executionStarted; private bool executionFinished; private bool disconnectFlowPending; private BufferBlock eventBuffer; private int currentComponentIndex; private List mainFlowComponentList; private List disconnectFlowComponentList; private List errorFlowComponentList; private List currentFlowComponentList; private LogFormatter logFormatter; private TimerManager timerManager; private Dictionary variableMap; private TempWavFileManager tempWavFileManager; private PromptQueue promptQueue; private OnlineServices onlineServices; private OfficeHoursManager officeHoursManager; private CfdAppScope scope; private void DisconnectCallAndExitCallflow() { if (currentFlowComponentList == disconnectFlowComponentList) logFormatter.Trace("Callflow finished..."); else { logFormatter.Trace("Callflow finished, disconnecting call..."); MyCall.Terminate(); } } private async Task ExecuteErrorFlow() { if (currentFlowComponentList == errorFlowComponentList) { logFormatter.Trace("Error during error handler flow, exiting callflow..."); DisconnectCallAndExitCallflow(); } else if (currentFlowComponentList == disconnectFlowComponentList) { logFormatter.Trace("Error during disconnect handler flow, exiting callflow..."); executionFinished = true; } else { currentFlowComponentList = errorFlowComponentList; currentComponentIndex = 0; if (errorFlowComponentList.Count > 0) { logFormatter.Trace("Start executing error handler flow..."); await ProcessStart(); } else { logFormatter.Trace("Error handler flow is empty..."); DisconnectCallAndExitCallflow(); } } } private async Task ExecuteDisconnectFlow() { currentFlowComponentList = disconnectFlowComponentList; currentComponentIndex = 0; disconnectFlowPending = false; if (disconnectFlowComponentList.Count > 0) { logFormatter.Trace("Start executing disconnect handler flow..."); await ProcessStart(); } else { logFormatter.Trace("Disconnect handler flow is empty..."); executionFinished = true; } } private EventResults CheckEventResult(EventResults eventResult) { if (eventResult == EventResults.MoveToNextComponent && ++currentComponentIndex == currentFlowComponentList.Count) { DisconnectCallAndExitCallflow(); return EventResults.Exit; } else if (eventResult == EventResults.Exit) DisconnectCallAndExitCallflow(); return eventResult; } private void InitializeVariables(string callID) { // Call variables variableMap["session.ani"] = new Variable(MyCall.Caller.CallerID); variableMap["session.callid"] = new Variable(callID); variableMap["session.dnis"] = new Variable(MyCall.DN.Number); variableMap["session.did"] = new Variable(MyCall.Caller.CalledNumber); variableMap["session.audioFolder"] = new Variable(Path.Combine(RecordingManager.Instance.AudioFolder, promptQueue.ProjectAudioFolder)); variableMap["session.transferingExtension"] = new Variable(MyCall.ReferredByDN?.Number ?? string.Empty); variableMap["session.forwardingExtension"] = new Variable(MyCall.OnBehalfOf?.Number ?? string.Empty); // Standard variables variableMap["RecordResult.NothingRecorded"] = new Variable(RecordComponent.RecordResults.NothingRecorded); variableMap["RecordResult.StopDigit"] = new Variable(RecordComponent.RecordResults.StopDigit); variableMap["RecordResult.Completed"] = new Variable(RecordComponent.RecordResults.Completed); variableMap["MenuResult.Timeout"] = new Variable(MenuComponent.MenuResults.Timeout); variableMap["MenuResult.InvalidOption"] = new Variable(MenuComponent.MenuResults.InvalidOption); variableMap["MenuResult.ValidOption"] = new Variable(MenuComponent.MenuResults.ValidOption); variableMap["UserInputResult.Timeout"] = new Variable(UserInputComponent.UserInputResults.Timeout); variableMap["UserInputResult.InvalidDigits"] = new Variable(UserInputComponent.UserInputResults.InvalidDigits); variableMap["UserInputResult.ValidDigits"] = new Variable(UserInputComponent.UserInputResults.ValidDigits); variableMap["VoiceInputResult.Timeout"] = new Variable(VoiceInputComponent.VoiceInputResults.Timeout); variableMap["VoiceInputResult.InvalidInput"] = new Variable(VoiceInputComponent.VoiceInputResults.InvalidInput); variableMap["VoiceInputResult.ValidInput"] = new Variable(VoiceInputComponent.VoiceInputResults.ValidInput); variableMap["VoiceInputResult.ValidDtmfInput"] = new Variable(VoiceInputComponent.VoiceInputResults.ValidDtmfInput); // User variables variableMap["project$.ExtensionNr"] = new Variable(""); variableMap["project$.AuswahlOpt"] = new Variable(""); variableMap["project$.ZielNr"] = new Variable(""); variableMap["RecordResult.NothingRecorded"] = new Variable(RecordComponent.RecordResults.NothingRecorded); variableMap["RecordResult.StopDigit"] = new Variable(RecordComponent.RecordResults.StopDigit); variableMap["RecordResult.Completed"] = new Variable(RecordComponent.RecordResults.Completed); variableMap["MenuResult.Timeout"] = new Variable(MenuComponent.MenuResults.Timeout); variableMap["MenuResult.InvalidOption"] = new Variable(MenuComponent.MenuResults.InvalidOption); variableMap["MenuResult.ValidOption"] = new Variable(MenuComponent.MenuResults.ValidOption); variableMap["UserInputResult.Timeout"] = new Variable(UserInputComponent.UserInputResults.Timeout); variableMap["UserInputResult.InvalidDigits"] = new Variable(UserInputComponent.UserInputResults.InvalidDigits); variableMap["UserInputResult.ValidDigits"] = new Variable(UserInputComponent.UserInputResults.ValidDigits); variableMap["VoiceInputResult.Timeout"] = new Variable(VoiceInputComponent.VoiceInputResults.Timeout); variableMap["VoiceInputResult.InvalidInput"] = new Variable(VoiceInputComponent.VoiceInputResults.InvalidInput); variableMap["VoiceInputResult.ValidInput"] = new Variable(VoiceInputComponent.VoiceInputResults.ValidInput); variableMap["VoiceInputResult.ValidDtmfInput"] = new Variable(VoiceInputComponent.VoiceInputResults.ValidDtmfInput); } private void InitializeComponents(ICallflow callflow, ICall myCall, string logHeader) { scope = CfdModule.Instance.CreateScope(callflow, myCall, logHeader); { VariableAssignmentComponent variableAssignmentExtensionNr = scope.CreateComponent("variableAssignmentExtensionNr"); variableAssignmentExtensionNr.VariableName = "project$.ExtensionNr"; variableAssignmentExtensionNr.VariableValueHandler = () => { return variableMap["session.ani"].Value; }; mainFlowComponentList.Add(variableAssignmentExtensionNr); VariableAssignmentComponent variableAssignmentZielNr = scope.CreateComponent("variableAssignmentZielNr"); variableAssignmentZielNr.VariableName = "project$.ZielNr"; variableAssignmentZielNr.VariableValueHandler = () => { return variableMap["session.ani"].Value; }; mainFlowComponentList.Add(variableAssignmentZielNr); setStateAndFWDestination setStateAndFWDestination1 = new setStateAndFWDestination(onlineServices, officeHoursManager, scope, "setStateAndFWDestination1", callflow, myCall, logHeader); setStateAndFWDestination1.strDestNoSetter = () => { return variableMap["project$.ZielNr"].Value; }; setStateAndFWDestination1.strExtensionNoSetter = () => { return variableMap["project$.ExtensionNr"].Value; }; mainFlowComponentList.Add(setStateAndFWDestination1); } { } { } // Add a final DisconnectCall component to the main and error handler flows, in order to complete pending prompt playbacks... DisconnectCallComponent mainAutoAddedFinalDisconnectCall = scope.CreateComponent("mainAutoAddedFinalDisconnectCall"); DisconnectCallComponent errorHandlerAutoAddedFinalDisconnectCall = scope.CreateComponent("errorHandlerAutoAddedFinalDisconnectCall"); mainFlowComponentList.Add(mainAutoAddedFinalDisconnectCall); errorFlowComponentList.Add(errorHandlerAutoAddedFinalDisconnectCall); } public Main() { this.executionStarted = false; this.executionFinished = false; this.disconnectFlowPending = false; this.eventBuffer = new BufferBlock(); this.currentComponentIndex = 0; this.mainFlowComponentList = new List(); this.disconnectFlowComponentList = new List(); this.errorFlowComponentList = new List(); this.currentFlowComponentList = mainFlowComponentList; this.timerManager = new TimerManager(); this.timerManager.OnTimeout += (state) => eventBuffer.Post(new TimeoutEvent(state)); this.variableMap = new Dictionary(); AbsTextToSpeechEngine textToSpeechEngine = null; AbsSpeechToTextEngine speechToTextEngine = null; this.onlineServices = new OnlineServices(textToSpeechEngine, speechToTextEngine); } public override void Start() { string callID = MyCall?.Caller["chid"] ?? "Unknown"; string logHeader = $"_73_dynWeiterleitung_aus - CallID {callID}"; this.logFormatter = new LogFormatter(MyCall, logHeader, "Callflow"); this.promptQueue = new PromptQueue(this, MyCall, "_73_dynWeiterleitung_aus", logHeader); this.tempWavFileManager = new TempWavFileManager(logFormatter); this.timerManager.CallStarted(); this.officeHoursManager = new OfficeHoursManager(MyCall); logFormatter.Info($"ConnectionStatus:`{MyCall.Status}`"); if (MyCall.Status == ConnectionStatus.Ringing) MyCall.AssureMedia().ContinueWith(_ => StartInternal(logHeader, callID)); else StartInternal(logHeader, callID); } private void StartInternal(string logHeader, string callID) { logFormatter.Trace("SetBackgroundAudio to false"); MyCall.SetBackgroundAudio(false, new string[] { }); logFormatter.Trace("Initialize components"); InitializeComponents(this, MyCall, logHeader); logFormatter.Trace("Initialize variables"); InitializeVariables(callID); MyCall.OnTerminated += () => eventBuffer.Post(new CallTerminatedEvent()); MyCall.OnDTMFInput += x => eventBuffer.Post(new DTMFReceivedEvent(x)); logFormatter.Trace("Start executing main flow..."); eventBuffer.Post(new StartEvent()); Task.Run(() => EventProcessingLoop()); } public void PostStartEvent() { eventBuffer.Post(new StartEvent()); } public void PostDTMFReceivedEvent(char digit) { eventBuffer.Post(new DTMFReceivedEvent(digit)); } public void PostPromptPlayedEvent() { eventBuffer.Post(new PromptPlayedEvent()); } public void PostTransferFailedEvent() { eventBuffer.Post(new TransferFailedEvent()); } public void PostMakeCallResultEvent(bool result) { eventBuffer.Post(new MakeCallResultEvent(result)); } public void PostCallTerminatedEvent() { eventBuffer.Post(new CallTerminatedEvent()); } public void PostTimeoutEvent(object state) { eventBuffer.Post(new TimeoutEvent(state)); } private async Task EventProcessingLoop() { executionStarted = true; while (!executionFinished) { AbsEvent evt = await eventBuffer.ReceiveAsync(); await evt?.ProcessEvent(this); } if (scope != null) scope.Dispose(); } public async Task ProcessStart() { try { EventResults eventResult; do { AbsComponent currentComponent = currentFlowComponentList[currentComponentIndex]; logFormatter.Trace("Start executing component '" + currentComponent.Name + "'"); eventResult = await currentComponent.Start(timerManager, variableMap, tempWavFileManager, promptQueue); } while (CheckEventResult(eventResult) == EventResults.MoveToNextComponent); if (eventResult == EventResults.Exit) executionFinished = true; } catch (Exception exc) { logFormatter.Error("Error executing last component: " + exc.ToString()); await ExecuteErrorFlow(); } } public async Task ProcessDTMFReceived(char digit) { try { AbsComponent currentComponent = currentFlowComponentList[currentComponentIndex]; logFormatter.Trace("OnDTMFReceived for component '" + currentComponent.Name + "' - Digit: '" + digit + "'"); EventResults eventResult = CheckEventResult(await currentComponent.OnDTMFReceived(timerManager, variableMap, tempWavFileManager, promptQueue, digit)); if (eventResult == EventResults.MoveToNextComponent) { if (disconnectFlowPending) await ExecuteDisconnectFlow(); else await ProcessStart(); } else if (eventResult == EventResults.Exit) executionFinished = true; } catch (Exception exc) { logFormatter.Error("Error executing last component: " + exc.ToString()); await ExecuteErrorFlow(); } } public async Task ProcessPromptPlayed() { try { promptQueue.NotifyPlayFinished(); AbsComponent currentComponent = currentFlowComponentList[currentComponentIndex]; logFormatter.Trace("OnPromptPlayed for component '" + currentComponent.Name + "'"); EventResults eventResult = CheckEventResult(await currentComponent.OnPromptPlayed(timerManager, variableMap, tempWavFileManager, promptQueue)); if (eventResult == EventResults.MoveToNextComponent) { if (disconnectFlowPending) await ExecuteDisconnectFlow(); else await ProcessStart(); } else if (eventResult == EventResults.Exit) executionFinished = true; } catch (Exception exc) { logFormatter.Error("Error executing last component: " + exc.ToString()); await ExecuteErrorFlow(); } } public async Task ProcessTransferFailed() { try { AbsComponent currentComponent = currentFlowComponentList[currentComponentIndex]; logFormatter.Trace("OnTransferFailed for component '" + currentComponent.Name + "'"); EventResults eventResult = CheckEventResult(await currentComponent.OnTransferFailed(timerManager, variableMap, tempWavFileManager, promptQueue)); if (eventResult == EventResults.MoveToNextComponent) { if (disconnectFlowPending) await ExecuteDisconnectFlow(); else await ProcessStart(); } else if (eventResult == EventResults.Exit) executionFinished = true; } catch (Exception exc) { logFormatter.Error("Error executing last component: " + exc.ToString()); await ExecuteErrorFlow(); } } public async Task ProcessMakeCallResult(bool result) { try { AbsComponent currentComponent = currentFlowComponentList[currentComponentIndex]; logFormatter.Trace("OnMakeCallResult for component '" + currentComponent.Name + "' - Result: '" + result + "'"); EventResults eventResult = CheckEventResult(await currentComponent.OnMakeCallResult(timerManager, variableMap, tempWavFileManager, promptQueue, result)); if (eventResult == EventResults.MoveToNextComponent) { if (disconnectFlowPending) await ExecuteDisconnectFlow(); else await ProcessStart(); } else if (eventResult == EventResults.Exit) executionFinished = true; } catch (Exception exc) { logFormatter.Error("Error executing last component: " + exc.ToString()); await ExecuteErrorFlow(); } } public async Task ProcessCallTerminated() { try { if (executionStarted) { // First notify the call termination to the current component AbsComponent currentComponent = currentFlowComponentList[currentComponentIndex]; logFormatter.Trace("OnCallTerminated for component '" + currentComponent.Name + "'"); // Don't wrap around CheckEventResult, because the call has been already disconnected, // and the following action to execute depends on the returned value. EventResults eventResult = await currentComponent.OnCallTerminated(timerManager, variableMap, tempWavFileManager, promptQueue); if (eventResult == EventResults.MoveToNextComponent) { // Next, if the current component has completed its job, execute the disconnect flow await ExecuteDisconnectFlow(); } else if (eventResult == EventResults.Wait) { // If the user component needs more events, wait for it to finish, and signal here that we need to execute // the disconnect handler flow of the callflow next... disconnectFlowPending = true; } else if (eventResult == EventResults.Exit) executionFinished = true; } } catch (Exception exc) { logFormatter.Error("Error executing last component: " + exc.ToString()); await ExecuteErrorFlow(); } finally { // Finally, delete temporary files tempWavFileManager.DeleteFilesAndFolders(); } } public async Task ProcessTimeout(object state) { try { AbsComponent currentComponent = currentFlowComponentList[currentComponentIndex]; logFormatter.Trace("OnTimeout for component '" + currentComponent.Name + "'"); EventResults eventResult = CheckEventResult(await currentComponent.OnTimeout(timerManager, variableMap, tempWavFileManager, promptQueue, state)); if (eventResult == EventResults.MoveToNextComponent) { if (disconnectFlowPending) await ExecuteDisconnectFlow(); else await ProcessStart(); } else if (eventResult == EventResults.Exit) executionFinished = true; } catch (Exception exc) { logFormatter.Error("Error executing last component: " + exc.ToString()); await ExecuteErrorFlow(); } } // ------------------------------------------------------------------------------------------------------------ // User Defined component // ------------------------------------------------------------------------------------------------------------ public class setStateAndFWDestination : AbsUserComponent { private OnlineServices onlineServices; private OfficeHoursManager officeHoursManager; private CfdAppScope scope; private ObjectExpressionHandler _strDestNoHandler = null; private ObjectExpressionHandler _strExtensionNoHandler = null; protected override void InitializeVariables() { componentVariableMap["callflow$.strDestNo"] = new Variable(""); componentVariableMap["callflow$.strExtensionNo"] = new Variable(""); } protected override void InitializeComponents() { Dictionary variableMap = componentVariableMap; { SetExtDNDDest1962110077ECCComponent SetExtDNDDest = new SetExtDNDDest1962110077ECCComponent("SetExtDNDDest", callflow, myCall, logHeader); SetExtDNDDest.Parameters.Add(new CallFlow.CFD.Parameter("strExtNr", () => { return variableMap["callflow$.strExtensionNo"].Value; })); SetExtDNDDest.Parameters.Add(new CallFlow.CFD.Parameter("strDestNr", () => { return variableMap["callflow$.strDestNo"].Value; })); mainFlowComponentList.Add(SetExtDNDDest); ConditionalComponent CreateCondition1 = scope.CreateComponent("CreateCondition1"); mainFlowComponentList.Add(CreateCondition1); CreateCondition1.ConditionList.Add(() => { return Convert.ToBoolean(CFDFunctions.EQUAL(SetExtDNDDest.ReturnValue,0)); }); CreateCondition1.ContainerList.Add(scope.CreateComponent("conditionalComponentBranch1")); TcxSetExtensionStatusComponent SetAvailable = scope.CreateComponent("SetAvailable"); SetAvailable.ExtensionHandler = () => { return Convert.ToString(variableMap["callflow$.strExtensionNo"].Value); }; SetAvailable.ProfileNameHandler = () => { return "Available"; }; CreateCondition1.ContainerList[0].ComponentList.Add(SetAvailable); PromptPlaybackComponent Weiterleitung_entfernt = scope.CreateComponent("Weiterleitung_entfernt"); Weiterleitung_entfernt.AllowDtmfInput = true; Weiterleitung_entfernt.Prompts.Add(new AudioFilePrompt(() => { return "Weiterleitung wurde entfernt.wav"; })); CreateCondition1.ContainerList[0].ComponentList.Add(Weiterleitung_entfernt); CreateCondition1.ConditionList.Add(() => { return Convert.ToBoolean(CFDFunctions.EQUAL(SetExtDNDDest.ReturnValue,4)); }); CreateCondition1.ContainerList.Add(scope.CreateComponent("conditionalComponentBranch2")); TcxSetExtensionStatusComponent SetExtCustom2 = scope.CreateComponent("SetExtCustom2"); SetExtCustom2.ExtensionHandler = () => { return Convert.ToString(variableMap["callflow$.strExtensionNo"].Value); }; SetExtCustom2.ProfileNameHandler = () => { return "Custom 2"; }; CreateCondition1.ContainerList[1].ComponentList.Add(SetExtCustom2); PromptPlaybackComponent PlayDigits = scope.CreateComponent("PlayDigits"); PlayDigits.AllowDtmfInput = true; PlayDigits.Prompts.Add(new AudioFilePrompt(() => { return "IhreAnrufeWerdenAufDieFolgendeNummerWeitergeleitet-vicki.wav"; })); PlayDigits.Prompts.Add(new NumberPrompt(NumberPrompt.NumberFormats.OneByOne, () => { return Convert.ToString(variableMap["callflow$.strDestNo"].Value); })); CreateCondition1.ContainerList[1].ComponentList.Add(PlayDigits); } { } { } } public setStateAndFWDestination(OnlineServices onlineServices, OfficeHoursManager officeHoursManager, CfdAppScope scope, string name, ICallflow callflow, ICall myCall, string logHeader) : base(name, callflow, myCall, logHeader) { this.onlineServices = onlineServices; this.officeHoursManager = officeHoursManager; this.scope = scope; } protected override void GetVariableValues() { if (_strDestNoHandler != null) componentVariableMap["callflow$.strDestNo"].Set(_strDestNoHandler()); if (_strExtensionNoHandler != null) componentVariableMap["callflow$.strExtensionNo"].Set(_strExtensionNoHandler()); } public ObjectExpressionHandler strDestNoSetter { set { _strDestNoHandler = value; } } public object strDestNo { get { return componentVariableMap["callflow$.strDestNo"].Value; } } public ObjectExpressionHandler strExtensionNoSetter { set { _strExtensionNoHandler = value; } } public object strExtensionNo { get { return componentVariableMap["callflow$.strExtensionNo"].Value; } } private bool IsServerInHoliday(ICall myCall) { Tenant tenant = myCall.PS.GetTenant(); return tenant != null && tenant.IsHoliday(new DateTimeOffset(DateTime.Now)); } private bool IsServerOfficeHourActive(ICall myCall) { Tenant tenant = myCall.PS.GetTenant(); if (tenant == null) return false; string overrideOfficeTime = tenant.GetPropertyValue("OVERRIDEOFFICETIME"); if (!String.IsNullOrEmpty(overrideOfficeTime)) { if (overrideOfficeTime == "1") // Forced to in office hours return true; else if (overrideOfficeTime == "2") // Forced to out of office hours return false; } DateTime nowDt = DateTime.Now; if (tenant.IsHoliday(new DateTimeOffset(nowDt))) return false; Schedule officeHours = tenant.Hours; Nullable result = officeHours.IsActiveTime(nowDt); return result.GetValueOrDefault(false); } } public class SetExtDNDDest1962110077ECCComponent : ExternalCodeExecutionComponent { public List Parameters { get; } = new List(); public SetExtDNDDest1962110077ECCComponent(string name, ICallflow callflow, ICall myCall, string projectName) : base(name, callflow, myCall, projectName) {} protected override object ExecuteCode() { return SetExtDNDDest(Convert.ToString(Parameters[0].Value), Convert.ToString(Parameters[1].Value)); } private object SetExtDNDDest(string strExtNr, string strDestNr) { var ext = PhoneSystem.Root.GetDNByNumber(strExtNr) as Extension; var profile=ext.FwdProfiles.Where( x => x.Name == "Custom 2").First(); // 'Available', 'Away', 'Out of office', 'Custom 1', 'Custom 2', maybe parameter? var NewStatus=-1; if( profile != null ) { // DestinationStruct need 3 parameter // 1 DestinationType: 'None', 'VoiceMail', 'Extension', 'Queue', 'RingGroup', 'IVR', 'External', 'Fax', 'Boomerang' (external number), // 'Deflect', 'VoiceMailOfDestination', 'Callback' (reserved), 'RoutePoint' // 2 internal DN, maybe select by parameter - OR - // 3 external number as string, maybe select by parameter // DestinationType anhand der Zielnummer (strDestNr) bestimmen bool isInternal = false; bool isExtension = false; bool isRG = false; bool isIVR = false; bool isQUEUE = false; // check if strDestNr is a internal extension var extension = PhoneSystem.Root.GetDNByNumber(strDestNr) as Extension; if( extension != null ) { isInternal = true; isExtension = true; } // check if strDestNr is a ringgroup var allRGs = PhoneSystem.Root.GetRingGroups(); foreach (var rg in allRGs) { if (rg.Number == strDestNr) { isInternal = true; isRG = true; break; } } // check if strDestNr is a IVR/receptionist var allIVRs = PhoneSystem.Root.GetIVRs(); foreach (var ivr in allIVRs) { if (ivr.Number == strDestNr) { isInternal = true; isIVR = true; break; } } // check if strDestNr is a Queue var allQUEUQs = PhoneSystem.Root.GetQueues(); foreach (var queue in allQUEUQs) { if (queue.Number == strDestNr) { isInternal = true; isQUEUE = true; break; } } // define the DestinationStruct depending on the type of the destination target.... var dest = new DestinationStruct(); if (strExtNr.Equals(strDestNr)) { // set state to available if destination number is the number of the extension NewStatus = 0; } else { if( isInternal) { if( isExtension ) { dest.To=DestinationType.Extension; dest.Internal=PhoneSystem.Root.GetDNByNumber(strDestNr); // needed if internal destination } else if( isRG ) { dest.To=DestinationType.RingGroup; dest.Internal=PhoneSystem.Root.GetDNByNumber(strDestNr); // needed if internal destination } else if( isIVR ) { dest.To=DestinationType.IVR; dest.Internal=PhoneSystem.Root.GetDNByNumber(strDestNr); // needed if internal destination } else if( isQUEUE ) { dest.To=DestinationType.Queue; dest.Internal=PhoneSystem.Root.GetDNByNumber(strDestNr); // needed if internal destination } } else { dest.To=DestinationType.External; dest.External=strDestNr; // needed if external destination } NewStatus = 4; } if( NewStatus >0) { // Depending on the type of status (present or absent), the forwarding must be entered in other target fields if( profile.TypeOfRouting == RoutingType.Available) { var route=profile.AvailableRoute; // maybe select by parameter? route.NoAnswer.AllCalls = dest; route.NoAnswer.Internal = dest; route.Busy.AllCalls = route.NotRegistered.AllCalls = dest; route.Busy.Internal = route.NotRegistered.Internal = dest; } if( profile.TypeOfRouting == RoutingType.Away) { var route=profile.AwayRoute; var external = profile.AwayRoute.External; route.Internal.AllHours = dest; // maybe select by parameter? route.Internal.OutOfOfficeHours = dest; route.External.AllHours = dest; route.External.OutOfOfficeHours = dest; } ext.Save(); } } return( NewStatus); } } } }