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(VoicemailExternalCommands), command))
            {
                VoicemailExternalCommands externalCommand = WOSI.Utilities.EnumUtils <VoicemailExternalCommands> .Parse(command);

                switch (externalCommand)
                {
                case VoicemailExternalCommands.CALLBUTLERINTERNAL_AuthenticatePasscode:
                {
                    // Check to make sure our passcode matches our extension
                    string enteredPasscodeHash = WOSI.Utilities.CryptoUtils.CreateMD5Hash(commandData);

                    if (enteredPasscodeHash != extension.Password)
                    {
                        tsInterface.IMLInterpreter.SignalExternalEvent(VoicemailExternalEvents.CALLBUTLERINTERNAL_InvalidPasscode.ToString());
                    }
                    else
                    {
                        // Get our new voicemail count
                        int newVoicemailCount = dataProvider.GetNewVoicemailCount(extension.ExtensionID);

                        tsInterface.IMLInterpreter.SetLocalVariable("NewVoicemailCount", newVoicemailCount.ToString());

                        tsInterface.IMLInterpreter.SignalExternalEvent(VoicemailExternalEvents.CALLBUTLERINTERNAL_ValidPasscode.ToString());
                    }

                    break;
                }

                case VoicemailExternalCommands.CALLBUTLERINTERNAL_SaveNewGreeting:
                {
                    WOSI.CallButler.Data.CallButlerDataset.LocalizedGreetingsRow voicemailGreeting = dataProvider.GetLocalizedGreeting(Properties.Settings.Default.CustomerID, extension.ExtensionID, Properties.Settings.Default.DefaultLanguage);
                    string tmpGreetingFilename = commandData;

                    if (File.Exists(tmpGreetingFilename) && voicemailGreeting != null)
                    {
                        // Change our voicemail greeting to a sound file
                        voicemailGreeting.Type = (short)WOSI.CallButler.Data.GreetingType.SoundGreeting;

                        // Move our greeting sound over
                        string greetingDirectory = WOSI.Utilities.FileUtils.GetApplicationRelativePath(Properties.Settings.Default.GreetingSoundRootDirectory) + "\\" + Properties.Settings.Default.DefaultLanguage;
                        string greetingFilename  = greetingDirectory + "\\" + voicemailGreeting.GreetingID.ToString() + ".snd";

                        if (!Directory.Exists(greetingDirectory))
                        {
                            Directory.CreateDirectory(greetingDirectory);
                        }

                        File.Copy(tmpGreetingFilename, greetingFilename, true);
                        File.Delete(tmpGreetingFilename);

                        voicemailGreeting.Data = WOSI.Utilities.CryptoUtils.GetFileChecksum(greetingFilename);

                        dataProvider.PersistLocalizedGreeting(Properties.Settings.Default.CustomerID, voicemailGreeting);
                    }

                    tsInterface.IMLInterpreter.SignalEventCallback(eventToken);

                    break;
                }

                case VoicemailExternalCommands.CALLBUTLERINTERNAL_FetchNextVoicemail:
                {
                    // Get our voicemail rows
                    WOSI.CallButler.Data.CallButlerDataset.VoicemailsRow[] voicemails = (WOSI.CallButler.Data.CallButlerDataset.VoicemailsRow[])dataProvider.GetVoicemails(extension.ExtensionID).Select("", "Timestamp DESC");

                    // Get our voicemail message index
                    int voicemailIndex = Convert.ToInt32(tsInterface.IMLInterpreter.GetLocalVariable("VoicemailIndex"));
                    voicemailIndex++;

                    if (voicemailIndex < voicemails.Length)
                    {
                        WOSI.CallButler.Data.CallButlerDataset.VoicemailsRow voicemail = voicemails[voicemailIndex];

                        // Create our voicemail intro
                        string voicemailIntro = "";

                        if (voicemailIndex == 0)
                        {
                            voicemailIntro = "First ";
                        }
                        else
                        {
                            voicemailIntro = "Next ";
                        }

                        if (voicemail.IsNew)
                        {
                            voicemailIntro += "New ";
                        }

                        voicemailIntro += "Message received on " + voicemail.Timestamp.ToShortDateString() + " " + voicemail.Timestamp.ToShortTimeString();

                        tsInterface.IMLInterpreter.SetLocalVariable("VoicemailIntro", voicemailIntro);

                        string voicemailFilename = WOSI.Utilities.FileUtils.GetApplicationRelativePath(Properties.Settings.Default.VoicemailRootDirectory) + "\\" + voicemail.ExtensionID.ToString() + "\\" + voicemail.VoicemailID + ".snd";
                        tsInterface.IMLInterpreter.SetLocalVariable("VoicemailSound", voicemailFilename);

                        tsInterface.IMLInterpreter.SetLocalVariable("VoicemailIndex", voicemailIndex.ToString());

                        // Mark the voicemail as read
                        dataProvider.MarkVoicemailRead(voicemail.ExtensionID, voicemail.VoicemailID);

                        if (pbxRegistrar != null)
                        {
                            pbxRegistrar.SendMessageWaitingNotification(voicemail.ExtensionID);
                        }

                        tsInterface.IMLInterpreter.SignalEventCallback(eventToken);
                    }
                    else
                    {
                        tsInterface.IMLInterpreter.SignalExternalEvent(VoicemailExternalEvents.CALLBUTLERINTERNAL_EndOfMessages.ToString());
                    }

                    break;
                }

                case VoicemailExternalCommands.CALLBUTLERINTERNAL_DeleteVoicemail:
                {
                    // Get our voicemail rows
                    WOSI.CallButler.Data.CallButlerDataset.VoicemailsRow[] voicemails = (WOSI.CallButler.Data.CallButlerDataset.VoicemailsRow[])dataProvider.GetVoicemails(extension.ExtensionID).Select("", "Timestamp DESC");

                    // Get our voicemail message index
                    int voicemailIndex = Convert.ToInt32(tsInterface.IMLInterpreter.GetLocalVariable("VoicemailIndex"));

                    if (voicemailIndex < voicemails.Length)
                    {
                        WOSI.CallButler.Data.CallButlerDataset.VoicemailsRow voicemail = voicemails[voicemailIndex];

                        // Delete our voicemail
                        dataProvider.DeleteVoicemail(voicemail.ExtensionID, voicemail.VoicemailID);

                        // Delete our voicemail sound
                        string voicemailFilename = WOSI.Utilities.FileUtils.GetApplicationRelativePath(Properties.Settings.Default.VoicemailRootDirectory) + "\\" + voicemail.ExtensionID.ToString() + "\\" + voicemail.VoicemailID + ".snd";
                        if (File.Exists(voicemailFilename))
                        {
                            File.Delete(voicemailFilename);
                        }

                        voicemailIndex--;
                        tsInterface.IMLInterpreter.SetLocalVariable("VoicemailIndex", voicemailIndex.ToString());

                        if (pbxRegistrar != null)
                        {
                            pbxRegistrar.SendMessageWaitingNotification(voicemail.ExtensionID);
                        }
                    }

                    tsInterface.IMLInterpreter.SignalEventCallback(eventToken);

                    break;
                }
                }
            }
        }