public void ProcessExternalCommand(string command, string commandData, string eventToken, TelecomScriptInterface tsInterface, CallButler.Telecom.TelecomProviderBase telecomProvider, WOSI.CallButler.Data.DataProviders.CallButlerDataProviderBase dataProvider, Utilities.PluginManagement.PluginManager pluginManager, PBXRegistrarService pbxRegistrar)
        {
            // Parse out our external event action
            if (Enum.IsDefined(typeof(BaseExternalCommands), command))
            {
                BaseExternalCommands externalCommand = WOSI.Utilities.EnumUtils<BaseExternalCommands>.Parse(command);

                string languageID = "en";

                switch (externalCommand)
                {
                    case BaseExternalCommands.CALLBUTLERINTERNAL_StartAddonModule:

                        CallButler.Service.Plugin.CallButlerAddonModulePlugin[] addonModules = pluginManager.GetAllPluginsOfType<CallButler.Service.Plugin.CallButlerAddonModulePlugin>();

                        foreach (CallButler.Service.Plugin.CallButlerAddonModulePlugin addonModule in addonModules)
                        {
                            if (addonModule.PluginID.ToString() == commandData)
                            {
                                try
                                {
                                    // Make sure the module is licensed
                                    if (!addonModule.IsLicensed)
                                        break;

                                    // We found our module and we should load the script it uses
                                    tsInterface.ScriptProcessor = new AddonModuleScriptProcessor(addonModule);
                                    tsInterface.ScriptProcessor.StartProcessing(tsInterface, telecomProvider, dataProvider);
                                    return;

                                }
                                catch (Exception e)
                                {
                                    LoggingService.AddLogEntry(WOSI.CallButler.ManagementInterface.LogLevel.ErrorsOnly, "Failed to load Addon-Module '" + addonModule.PluginName + "'\r\n\r\n" + e.Message + "\r\n\r\n" + e.StackTrace, true);
                                }
                            }
                        }

                        break;

                    case BaseExternalCommands.CALLBUTLERINTERNAL_ReturnToCallFlowMainMenu:

                        // Return to the Call flow main menu.
                        tsInterface.ScriptProcessor = new StandardScriptProcessor(pluginManager, pbxRegistrar);
                        ((StandardScriptProcessor)tsInterface.ScriptProcessor).StartFromMainMenu(tsInterface);

                        break;

                    case BaseExternalCommands.CALLBUTLERINTERNAL_PlayLicenseIntroGreeting:

                        // If the line isn't in use, don't do anything
                        if (!telecomProvider.IsLineInUse(tsInterface.LineNumber))
                        {
                            tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                            break;
                        }

                        // Read our intro sound bytes
                        byte[] introSoundBytes = null;

                        if (telecomProvider.AudioInputRate == 8000)
                        {
                            introSoundBytes = new byte[Properties.Resources.powered_by_8khz.Length];
                            Properties.Resources.powered_by_8khz.Read(introSoundBytes, 0, introSoundBytes.Length);
                        }
                        else if (telecomProvider.AudioInputRate == 16000)
                        {
                            introSoundBytes = new byte[Properties.Resources.powered_by_16khz.Length];
                            Properties.Resources.powered_by_16khz.Read(introSoundBytes, 0, introSoundBytes.Length);
                        }

                        // Play our license intro sound
                        if (introSoundBytes != null)
                        {
                            telecomProvider.PlaySound(tsInterface.LineNumber, introSoundBytes);
                        }

                        break;

                    case BaseExternalCommands.CALLBUTLERINTERNAL_PlaySystemSound:

                        // If the line isn't in use, don't do anything
                        if (!telecomProvider.IsLineInUse(tsInterface.LineNumber))
                        {
                            tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                            break;
                        }

                        // Get the sound with the current language
                        languageID = tsInterface.IMLInterpreter.GetLocalVariable("LanguageID");

                        string soundFilename = GetSoundFileForLanguage(languageID, commandData);

                        if (soundFilename == null)
                        {
                            // If we don't get a sound with the current language, try the default language
                            soundFilename = GetSoundFileForLanguage(Properties.Settings.Default.DefaultLanguage, commandData);

                            if (soundFilename == null)
                            {
                                // If we don't get a sound file with the default language, try english
                                soundFilename = GetSoundFileForLanguage("en", commandData);

                                if (soundFilename == null)
                                {
                                    if (!File.Exists(soundFilename))
                                    {
                                        // If the sound still doesn't exist, tell the IML interpreter to move on
                                        tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                                        break;
                                    }
                                }
                            }
                        }

                        // If we get here, our system sound should exist and we should play it.
                        if(string.Compare(commandData, "ring.snd", true) == 0)
                            telecomProvider.PlaySound(tsInterface.LineNumber, soundFilename, true);
                        else
                            telecomProvider.PlaySound(tsInterface.LineNumber, soundFilename, false);

                        LoggingService.AddLogEntry(LogLevel.Extended, "(Line " + tsInterface.LineNumber + ") Playing sound at " + soundFilename, false);

                        break;

                    case BaseExternalCommands.CALLBUTLERINTERNAL_PlayGreeting:

                        // If the line isn't in use, don't do anything
                        if (!telecomProvider.IsLineInUse(tsInterface.LineNumber))
                        {
                            tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                            break;
                        }

                        // Get our current language
                        languageID = tsInterface.IMLInterpreter.GetLocalVariable("LanguageID");

                        // Create our greetingID
                        Guid greetingID = new Guid(commandData);

                        // Get the greeting in our selected language
                        WOSI.CallButler.Data.CallButlerDataset.GreetingsRow greeting = dataProvider.GetGreeting(Properties.Settings.Default.CustomerID, greetingID);

                        if (greeting != null)
                        {
                            // Get the greeting for our specified language
                            WOSI.CallButler.Data.CallButlerDataset.LocalizedGreetingsRow localizedGreeting = dataProvider.GetLocalizedGreeting(Properties.Settings.Default.CustomerID, greetingID, languageID);

                            if (localizedGreeting == null)
                            {
                                // If the greeting doesn't exist in the current language, try using the default language
                                localizedGreeting = dataProvider.GetLocalizedGreeting(Properties.Settings.Default.CustomerID, greetingID, Properties.Settings.Default.DefaultLanguage);

                                if (localizedGreeting == null)
                                {
                                    // If the greeting doesn't exist in the default language, heck just return the first one that exists
                                    WOSI.CallButler.Data.CallButlerDataset.LocalizedGreetingsRow[] localizedGreetings = greeting.GetLocalizedGreetingsRows();

                                    if (localizedGreetings.Length > 0)
                                        localizedGreeting = localizedGreetings[0];
                                }
                            }

                            if (localizedGreeting != null)
                            {
                                // Determine how we should play this greeting
                                WOSI.CallButler.Data.GreetingType greetingType = (WOSI.CallButler.Data.GreetingType)localizedGreeting.Type;

                                switch (greetingType)
                                {
                                    case WOSI.CallButler.Data.GreetingType.SoundGreeting:
                                        // Create our sound file path
                                        string soundFilePath = WOSI.Utilities.FileUtils.GetApplicationRelativePath(Properties.Settings.Default.GreetingSoundRootDirectory) + "\\" + localizedGreeting.LanguageID + "\\" + greetingID.ToString() + ".snd";

                                        if (File.Exists(soundFilePath))
                                        {
                                            telecomProvider.PlaySound(tsInterface.LineNumber, soundFilePath, false);
                                            LoggingService.AddLogEntry(LogLevel.Extended, "(Line " + tsInterface.LineNumber + ") Playing sound at " + soundFilePath, false);
                                        }
                                        else
                                            tsInterface.IMLInterpreter.SignalEventCallback(eventToken);

                                        break;

                                    case WOSI.CallButler.Data.GreetingType.TextGreeting:

                                        // Speak our text
                                        string textToSpeak = tsInterface.IMLInterpreter.ParseVariableTokens(localizedGreeting.Data);

                                        // Take out any XML
                                        if (!WOSI.Utilities.StringUtils.IsWellFormedXml(textToSpeak))
                                            textToSpeak = WOSI.Utilities.StringUtils.XmlEncodeString(textToSpeak);

                                        if (textToSpeak.Length > 0)
                                        {
                                            if (!localizedGreeting.IsVoiceNull() && localizedGreeting.Voice.Length > 0)
                                                textToSpeak = "<voice required=\"Name=" + localizedGreeting.Voice + "\">" + textToSpeak + "</voice>";
                                            else if(Properties.Settings.Default.DefaultTTSVoice != null && Properties.Settings.Default.DefaultTTSVoice.Length > 0)
                                                textToSpeak = "<voice required=\"Name=" + Properties.Settings.Default.DefaultTTSVoice + "\">" + textToSpeak + "</voice>";

                                            telecomProvider.SpeakText(tsInterface.LineNumber, textToSpeak);
                                            LoggingService.AddLogEntry(LogLevel.Extended, "(Line " + tsInterface.LineNumber + ") Speaking '" + textToSpeak + "'", false);
                                        }
                                        else
                                        {
                                            tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                                        }

                                        break;
                                }
                            }
                            else
                            {
                                // If no greeting is found in the right language, tell the interpreter to move on
                                tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                            }
                        }
                        // If the greeting isn't found, tell the interpreter to go on
                        else
                        {
                            tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                        }

                        break;
                }
            }
            else
            {
                OnExternalCommand(command, commandData, eventToken, tsInterface, telecomProvider, dataProvider);

                if (linkedScriptProcessor != null)
                    linkedScriptProcessor.OnLinkedExternalCommand(command, commandData, eventToken, tsInterface, telecomProvider, dataProvider);
            }
        }
        protected override void OnExternalCommand(string command, string commandData, string eventToken, TelecomScriptInterface tsInterface, CallButler.Telecom.TelecomProviderBase telecomProvider, WOSI.CallButler.Data.DataProviders.CallButlerDataProviderBase dataProvider)
        {
            // Parse out our external event action
            if (Enum.IsDefined(typeof(ExtensionExternalCommands), command))
            {
                ExtensionExternalCommands externalCommand = WOSI.Utilities.EnumUtils<ExtensionExternalCommands>.Parse(command);

                switch (externalCommand)
                {
                    case ExtensionExternalCommands.CALLBUTLERINTERNAL_ForwardCall:
                        {

                            onholdTsInterface.IMLInterpreter.SetLocalVariable("TransferNumber", commandData);
                            onholdTsInterface.IMLInterpreter.SignalExternalEvent(VoicemailExternalEvents.CALLBUTLERINTERNAL_CallForwarded.ToString());

                            break;
                        }
                    case ExtensionExternalCommands.CALLBUTLERINTERNAL_ConfirmingTransfer:
                        {
                            if (disableCallScreening || !extension.EnableCallScreening)
                            {
                                tsInterface.IMLInterpreter.SignalExternalEvent(ExtensionExternalEvents.CALLBUTLERINTERNAL_SkipConfirmation.ToString());
                            }
                            else
                            {
                                tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                            }

                            break;
                        }
                    case ExtensionExternalCommands.CALLBUTLERINTERNAL_GetNextNumber:
                        {
                            string callerID = onholdTsInterface.IMLInterpreter.CallerDisplayName;
                            string callerNumber = onholdTsInterface.IMLInterpreter.CallerUsername;

                            if (callerID == null || callerID.Length == 0)
                                callerID = "Unknown Caller";

                            if (callerNumber == null || callerNumber.Length == 0)
                                callerNumber = "";

                            // If we have a previous call, end it
                            if (telecomProvider.IsLineInUse(tsInterface.LineNumber))
                            {
                                telecomProvider.EndCall(tsInterface.LineNumber);
                            }
                            else
                            {
                                // Get our extension contact numbers
                                List<WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow> contactNumbers = new List<WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow>((WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow[])dataProvider.GetExtensionContactNumbers(extension.ExtensionID).Select("", "Priority ASC"));

                                if (extensionNumberIndex + 1 >= contactNumbers.Count && parentExtension != null)
                                {
                                    extensionNumberIndex = parentExtensionIndex;
                                    parentExtensionIndex = -1;

                                    extension = parentExtension;
                                    parentExtension = null;

                                    contactNumbers.Clear();
                                    contactNumbers.AddRange((WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow[])dataProvider.GetExtensionContactNumbers(extension.ExtensionID).Select("", "Priority ASC"));
                                }

                                extensionNumberIndex++;

                                List<string> callBlastNumbers = new List<string>();
                                List<string> callBlastProfiles = new List<string>();
                                int callBlastTimeout = Properties.Settings.Default.CallBlastTimeout;

                                while (extensionNumberIndex < contactNumbers.Count)
                                {
                                    WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow contactNumber = contactNumbers[extensionNumberIndex];

                                    // Is the number online?
                                    if (contactNumber.Online)
                                    {
                                        // Does the number have hours?
                                        TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);

                                        if (!contactNumber.IsHoursOfOperationUTCOffsetNull())
                                            utcOffset = contactNumber.HoursOfOperationUTCOffset;

                                        if (!contactNumber.HasHoursOfOperation || (contactNumber.HasHoursOfOperation && ScriptUtils.IsInHoursOfOperation(contactNumber.HoursOfOperation, utcOffset)))
                                        {
                                            // Check to see if this number is a PBX IP line
                                            if ((contactNumber.CallPBXPhone || (WOSI.CallButler.Data.ExtensionContactNumberType)contactNumber.Type == WOSI.CallButler.Data.ExtensionContactNumberType.IPPhone) && registrarService != null)
                                            {
                                                int extNumber = extension.ExtensionNumber;

                                                // If this was filled in from another extension, we'll need to check the status of that extension
                                                if (contactNumber.ExtensionID != extension.ExtensionID)
                                                {
                                                    WOSI.CallButler.Data.CallButlerDataset.ExtensionsRow tmpExtension = dataProvider.GetExtension(Properties.Settings.Default.CustomerID, contactNumber.ExtensionID);

                                                    if (tmpExtension != null)
                                                        extNumber = tmpExtension.ExtensionNumber;
                                                }

                                                // Check to see if this pbx phone is online
                                                PBXPresenceInfo[] presInfos = registrarService.GetPresenceInfoForExtension(extNumber);

                                                if (presInfos != null && presInfos.Length > 0)
                                                {
                                                    foreach (PBXPresenceInfo presInfo in presInfos)
                                                    {
                                                        if (presInfo.Status == PBXPresenceStatus.Online)
                                                        {
                                                            if (presInfos.Length > 1 || extension.UseCallBlast)
                                                            {
                                                                if (contactNumbers.Count == 1)
                                                                    callBlastTimeout = contactNumber.Timeout;

                                                                string callBlastNumber = string.Format("sip:{0}@{1}:{2}", presInfo.ExtensionNumber, presInfo.RemoteAddress, presInfo.RemotePort);

                                                                if (!callBlastNumbers.Contains(callBlastNumber))
                                                                {
                                                                    callBlastNumbers.Add(callBlastNumber);
                                                                    callBlastProfiles.Add(TelecomScriptInterface.InternalProviderProfileName);
                                                                }
                                                            }
                                                            else
                                                            {
                                                                TryContactNumber(tsInterface, string.Format("sip:{0}@{1}:{2}", presInfo.ExtensionNumber, presInfo.RemoteAddress, presInfo.RemotePort), callerID, callerNumber, TelecomScriptInterface.InternalProviderProfileName, contactNumber.Timeout.ToString(), eventToken);
                                                                return;
                                                            }
                                                        }
                                                    }

                                                    if (!extension.UseCallBlast && callBlastNumbers.Count > 0)
                                                        break;
                                                }
                                            }
                                            else if ((WOSI.CallButler.Data.ExtensionContactNumberType)contactNumber.Type == WOSI.CallButler.Data.ExtensionContactNumberType.TelephoneNumber)
                                            {
                                                if (extension.UseCallBlast)
                                                {
                                                    if (!callBlastNumbers.Contains(contactNumber.ContactNumber))
                                                    {
                                                        callBlastNumbers.Add(contactNumber.ContactNumber);
                                                        callBlastProfiles.Add("");
                                                    }
                                                }
                                                else
                                                {
                                                    TryContactNumber(tsInterface, contactNumber.ContactNumber, callerID, callerNumber, "", contactNumber.Timeout.ToString(), eventToken);
                                                    return;
                                                }
                                            }
                                            else if ((WOSI.CallButler.Data.ExtensionContactNumberType)contactNumber.Type == WOSI.CallButler.Data.ExtensionContactNumberType.Extension && parentExtension == null)
                                            {
                                                try
                                                {
                                                    // Get our new extension
                                                    WOSI.CallButler.Data.CallButlerDataset.ExtensionsRow newExtension = dataProvider.GetExtension(Properties.Settings.Default.CustomerID, new Guid(contactNumber.ContactNumber));

                                                    if (newExtension != null)
                                                    {
                                                        if (extension.UseCallBlast)
                                                        {
                                                            WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow[] newContacts = (WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow[])dataProvider.GetExtensionContactNumbers(newExtension.ExtensionID).Select("Type <> " + (int)WOSI.CallButler.Data.ExtensionContactNumberType.Extension, "Priority ASC");
                                                            contactNumbers.AddRange(newContacts);
                                                        }
                                                        else
                                                        {
                                                            parentExtension = extension;
                                                            parentExtensionIndex = extensionNumberIndex;

                                                            extensionNumberIndex = -1;
                                                            extension = newExtension;

                                                            tsInterface.IMLInterpreter.SignalExternalEvent(ExtensionExternalEvents.CALLBUTLERINTERNAL_GetNextNumber.ToString());
                                                            return;
                                                        }
                                                    }
                                                }
                                                catch
                                                {
                                                }
                                            }
                                        }
                                    }

                                    extensionNumberIndex++;
                                }

                                if (callBlastNumbers.Count > 0)
                                {
                                    TryCallBlast(telecomProvider, tsInterface, callBlastNumbers.ToArray(), callBlastProfiles.ToArray(), callerID, callerNumber, callBlastTimeout.ToString());
                                    return;
                                }
                                else
                                {
                                    tsInterface.IMLInterpreter.SignalExternalEvent(ExtensionExternalEvents.CALLBUTLERINTERNAL_NoMoreNumbers.ToString());
                                }
                            }

                            break;
                        }
                    case ExtensionExternalCommands.CALLBUTLERINTERNAL_SendToVoicemail:
                        {
                            onholdTsInterface.IMLInterpreter.SyncExternalAction -= IMLInterpreter_SyncExternalAction;

                            // Allow this line to answer calls again
                            tsInterface.Locked = false;

                            if (telecomProvider.IsLineInUse(onholdTsInterface.LineNumber))
                            {
                                telecomProvider.SendingToVoicemail(onholdTsInterface.LineNumber);
                            }

                            onholdTsInterface.IMLInterpreter.SignalExternalEvent(VoicemailExternalEvents.CALLBUTLERINTERNAL_ExtensionNotAvailable.ToString());
                            tsInterface.IMLInterpreter.SignalEventCallback(eventToken);

                            break;
                        }
                    case ExtensionExternalCommands.CALLBUTLERINTERNAL_ConnectCalls:
                        {
                            onholdTsInterface.IMLInterpreter.SyncExternalAction -= IMLInterpreter_SyncExternalAction;

                            onholdTsInterface.IMLInterpreter.SignalExternalEvent(ExtensionExternalCommands.CALLBUTLERINTERNAL_ConnectCalls.ToString());

                            // Allow this line to answer calls again
                            tsInterface.Locked = false;

                            if (autoConnect)
                            {
                                if (telecomProvider.IsLineInUse(tsInterface.LineNumber) && telecomProvider.IsLineInUse(onholdTsInterface.LineNumber))
                                {
                                    if (extension.IsUseConferenceTransferNull() || !extension.UseConferenceTransfer /*|| !Licensing.Management.AppPermissions.StatIsPermitted("Handoff")*/)
                                    {
                                        telecomProvider.TransferCallAttended(onholdTsInterface.LineNumber, tsInterface.LineNumber, Properties.Settings.Default.UseBridgedTransfers);
                                        tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                                    }
                                    else
                                    {
                                        telecomProvider.StopSound(tsInterface.LineNumber);
                                        telecomProvider.StopSound(onholdTsInterface.LineNumber);
                                        int conferenceID = telecomProvider.ConferenceLines(tsInterface.LineNumber, onholdTsInterface.LineNumber);

                                        // Check to see if the person calling is an internal extension
                                        if (onholdTsInterface.Extension != null)
                                        {
                                            onholdTsInterface.ScriptProcessor = new TransferConferenceScriptProcessor(conferenceID, scriptService, tsInterface, registrarService, extension, vmMailerService);
                                        }
                                        else
                                        {
                                            onholdTsInterface.ScriptProcessor = new TransferConferenceParticipantScriptProcessor(conferenceID, tsInterface, extension, vmMailerService);
                                        }

                                        tsInterface.ScriptProcessor = new TransferConferenceScriptProcessor(conferenceID, scriptService, onholdTsInterface, registrarService, extension, vmMailerService);

                                        onholdTsInterface.ScriptProcessor.StartProcessing(onholdTsInterface, telecomProvider, dataProvider);
                                        tsInterface.ScriptProcessor.StartProcessing(tsInterface, telecomProvider, dataProvider);
                                    }
                                }
                                else
                                {
                                    tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                                }
                            }

                            break;
                        }
                }
            }
        }
        protected override void OnExternalCommand(string command, string commandData, string eventToken, TelecomScriptInterface tsInterface, CallButler.Telecom.TelecomProviderBase telecomProvider, WOSI.CallButler.Data.DataProviders.CallButlerDataProviderBase dataProvider)
        {
            // Parse out our external event action
            if (Enum.IsDefined(typeof(ReceptionistFinderExternalCommands), command))
            {
                ReceptionistFinderExternalCommands externalCommand = WOSI.Utilities.EnumUtils<ReceptionistFinderExternalCommands>.Parse(command);

                switch (externalCommand)
                {
                    case ReceptionistFinderExternalCommands.CALLBUTLERINTERNAL_SendToAutoAttendant:
                        {
                            scriptService.ProcessAutoAttendantAnswer(tsInterface.LineNumber, tsInterface, false);
                            break;
                        }
                    case ReceptionistFinderExternalCommands.CALLBUTLERINTERNAL_AnswerCall:
                        {
                            if (telecomProvider.IsLineInUse(tsInterface.LineNumber))
                            {
                                if (tsInterface.Extension != null)
                                    telecomProvider.AnswerCall(tsInterface.LineNumber, true);
                                else
                                    telecomProvider.AnswerCall(tsInterface.LineNumber, false);
                            }
                            break;
                        }
                }
            }
        }
        protected override void OnExternalCommand(string command, string commandData, string eventToken, TelecomScriptInterface tsInterface, CallButler.Telecom.TelecomProviderBase telecomProvider, WOSI.CallButler.Data.DataProviders.CallButlerDataProviderBase dataProvider)
        {
            // Parse out our external event action
            if (Enum.IsDefined(typeof(ScheduleReminderExternalCommands), command))
            {
                ScheduleReminderExternalCommands externalCommand = WOSI.Utilities.EnumUtils<ScheduleReminderExternalCommands>.Parse(command);

                switch (externalCommand)
                {
                    case ScheduleReminderExternalCommands.CALLBUTLERINTERNAL_GetNextNumber:
                        {
                            // If we have a previous call, end it
                            if (telecomProvider.IsLineInUse(tsInterface.LineNumber))
                                telecomProvider.EndCall(tsInterface.LineNumber);

                            extensionNumberIndex++;

                            // Get our extension contact numbers
                            WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow[] contactNumbers = (WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow[])dataProvider.GetExtensionContactNumbers(extension.ExtensionID).Select("", "Priority ASC");

                            while (extensionNumberIndex < contactNumbers.Length)
                            {
                                WOSI.CallButler.Data.CallButlerDataset.ExtensionContactNumbersRow contactNumber = contactNumbers[extensionNumberIndex];

                                // Is the number online?
                                if (contactNumber.Online)
                                {
                                    // Does the number have hours?
                                    if (!contactNumber.HasHoursOfOperation || (contactNumber.HasHoursOfOperation && ScriptUtils.IsInHoursOfOperation(contactNumber.HoursOfOperation, contactNumber.HoursOfOperationUTCOffset)))
                                    {
                                        // If we get here, try the number
                                        tsInterface.IMLInterpreter.SetLocalVariable("NumberToCall", contactNumber.ContactNumber);

                                        tsInterface.IMLInterpreter.SetLocalVariable("ExtensionTimeout", contactNumber.Timeout.ToString());

                                        string introDetails = "You have " + reminders.Length + " upcoming appointment";

                                        if (reminders.Length > 1)
                                        {
                                            introDetails += "s";
                                        }

                                        introDetails += ".";

                                        tsInterface.IMLInterpreter.SetLocalVariable("IntroDetails", introDetails);

                                        tsInterface.IMLInterpreter.SignalEventCallback(eventToken);

                                        return;
                                    }
                                }

                                extensionNumberIndex++;
                            }

                            if(telecomProvider.IsLineInUse(tsInterface.LineNumber))
                                telecomProvider.EndCall(tsInterface.LineNumber);

                            tsInterface.IMLInterpreter.StopScript();
                            break;
                        }
                    case ScheduleReminderExternalCommands.CALLBUTLERINTERNAL_FetchNextReminder:
                        {
                            reminderIndex++;

                            if (reminderIndex < reminders.Length)
                            {
                                OutlookReminder reminder = reminders[reminderIndex];

                                tsInterface.IMLInterpreter.SetLocalVariable("ScheduleDetails", GetReminderDetails(reminder));

                                if (reminderIndex == reminders.Length - 1)
                                {
                                    tsInterface.IMLInterpreter.SignalExternalEvent(ScheduleReminderExternalEvents.CALLBUTLERINTERNAL_LastReminder.ToString());
                                }
                                else
                                {
                                    tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                                }

                            }
                            else
                            {
                                tsInterface.IMLInterpreter.SignalExternalEvent(ScheduleReminderExternalEvents.CALLBUTLERINTERNAL_EndOfReminders.ToString());
                            }

                            break;
                        }
                }
            }
        }