diff --git a/.travis.yml b/.travis.yml index fdb76d6..c3b5e27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: csharp solution: ./Asterisk.2013/Asterisk.2013.sln -script: xbuild /p:Configuration=Travis ./Asterisk.2013/Asterisk.2013.sln +dotnet: 2.0.0 +mono: none +script: dotnet build ./Asterisk.2013/Asterisk.NET/AsterNET.csproj -c Travis -f netstandard2.0 diff --git a/Asterisk.2013/Asterisk.2013.sln b/Asterisk.2013/Asterisk.2013.sln index 618cf08..55eee43 100644 --- a/Asterisk.2013/Asterisk.2013.sln +++ b/Asterisk.2013/Asterisk.2013.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2026 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{80ADC18F-2BFC-4B79-B264-5244E4F2FEED}" ProjectSection(SolutionItems) = preProject @@ -10,7 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\README.md = ..\README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsterNET", "Asterisk.NET\AsterNET.csproj", "{BC6E7DBA-C05A-45FE-A2A3-B1637CE16274}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsterNET", "Asterisk.NET\AsterNET.csproj", "{BC6E7DBA-C05A-45FE-A2A3-B1637CE16274}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsterNET.WinForm", "Asterisk.NET.WinForm\AsterNET.WinForm.csproj", "{03687626-613A-4E41-8F60-7C7839D6DD5D}" EndProject @@ -52,4 +52,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FD16BE51-C7E5-49FB-B78C-D1E477961D6A} + EndGlobalSection EndGlobal diff --git a/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/AsterNET.Test.csproj b/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/AsterNET.Test.csproj index 39125cd..3ab171c 100644 --- a/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/AsterNET.Test.csproj +++ b/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/AsterNET.Test.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -11,7 +11,7 @@ Asterisk.NET.Test Asterisk.NET.Test false - v4.5 + v4.6 diff --git a/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/Program.cs b/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/Program.cs index e47cda1..bec6da2 100644 --- a/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/Program.cs +++ b/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/Program.cs @@ -138,13 +138,13 @@ Ctrl-C to exit"); manager.RegisterUserEventClass(typeof(UserAgentLoginEvent)); // Add or Remove events - manager.UserEvents += new UserEventHandler(dam_UserEvents); + manager.UserEvents += new EventHandler(dam_UserEvents); // Dont't display this event - manager.NewExten += new NewExtenEventHandler(manager_IgnoreEvent); + manager.NewExten += new EventHandler(manager_IgnoreEvent); // Display all other - manager.UnhandledEvent += new ManagerEventHandler(dam_Events); + manager.UnhandledEvent += new EventHandler(dam_Events); // +++ Only to debug purpose manager.FireAllEvents = true; @@ -288,7 +288,7 @@ Ctrl-C to exit"); Console.WriteLine("Redirect Call from " + ORIGINATE_CHANNEL + " to " + ORIGINATE_EXTRA_CHANNEL + " or press ESC."); // Wait for Dial Event from ORIGINATE_CHANNEL - DialEventHandler de = new DialEventHandler(dam_Dial); + EventHandler de = new EventHandler(dam_Dial); manager.Dial += de; while (transferChannel == null) { @@ -323,7 +323,7 @@ Ctrl-C to exit"); // Link event used to define monitor channel Console.WriteLine("Monitor call. Please call " + ORIGINATE_CHANNEL + " and answer or press ESC."); // Wait for Link event - LinkEventHandler le = new LinkEventHandler(dam_Link); + EventHandler le = new EventHandler(dam_Link); manager.Link += le; while (monitorChannel == null) { diff --git a/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/app.config b/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/app.config index b7a7ef1..2e71eab 100644 --- a/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/app.config +++ b/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/app.config @@ -1,3 +1,3 @@ - + diff --git a/Asterisk.2013/Asterisk.NET.WinForm/AsterNET.WinForm.csproj b/Asterisk.2013/Asterisk.NET.WinForm/AsterNET.WinForm.csproj index f4c93c4..6c0282d 100644 --- a/Asterisk.2013/Asterisk.NET.WinForm/AsterNET.WinForm.csproj +++ b/Asterisk.2013/Asterisk.NET.WinForm/AsterNET.WinForm.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,7 +10,7 @@ Properties Asterisk.NET.WinForm Asterisk.NET.WinForm - v4.5 + v4.6 diff --git a/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs b/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs index 0ebcbb5..6ac81b2 100644 --- a/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs +++ b/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs @@ -28,7 +28,7 @@ namespace AsterNET.WinForm btnConnect.Enabled = false; manager = new ManagerConnection(address, port, user, password); - manager.UnhandledEvent += new ManagerEventHandler(manager_Events); + manager.UnhandledEvent += new EventHandler(manager_Events); try { // Uncomment next 2 line comments to Disable timeout (debug mode) diff --git a/Asterisk.2013/Asterisk.NET.WinForm/Properties/Resources.Designer.cs b/Asterisk.2013/Asterisk.NET.WinForm/Properties/Resources.Designer.cs index feccfcb..8ebe8e5 100644 --- a/Asterisk.2013/Asterisk.NET.WinForm/Properties/Resources.Designer.cs +++ b/Asterisk.2013/Asterisk.NET.WinForm/Properties/Resources.Designer.cs @@ -1,14 +1,14 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.17929 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace AsterNET.WinForm.Properties { +namespace Asterisk.NET.WinForm.Properties { using System; @@ -19,7 +19,7 @@ namespace AsterNET.WinForm.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -39,7 +39,7 @@ namespace AsterNET.WinForm.Properties { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AsterNET.WinForm.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Asterisk.NET.WinForm.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; diff --git a/Asterisk.2013/Asterisk.NET.WinForm/Properties/Settings.Designer.cs b/Asterisk.2013/Asterisk.NET.WinForm/Properties/Settings.Designer.cs index ba6bd99..cab29c8 100644 --- a/Asterisk.2013/Asterisk.NET.WinForm/Properties/Settings.Designer.cs +++ b/Asterisk.2013/Asterisk.NET.WinForm/Properties/Settings.Designer.cs @@ -1,18 +1,18 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.17929 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace AsterNET.WinForm.Properties { +namespace Asterisk.NET.WinForm.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/Asterisk.2013/Asterisk.NET.WinForm/app.config b/Asterisk.2013/Asterisk.NET.WinForm/app.config index b7a7ef1..2e71eab 100644 --- a/Asterisk.2013/Asterisk.NET.WinForm/app.config +++ b/Asterisk.2013/Asterisk.NET.WinForm/app.config @@ -1,3 +1,3 @@ - + diff --git a/Asterisk.2013/Asterisk.NET/AsterNET.csproj b/Asterisk.2013/Asterisk.NET/AsterNET.csproj index 1a101cb..5a37305 100644 --- a/Asterisk.2013/Asterisk.NET/AsterNET.csproj +++ b/Asterisk.2013/Asterisk.NET/AsterNET.csproj @@ -1,42 +1,18 @@ - - + + - Debug - AnyCPU - 8.0.50727 - 2.0 - {BC6E7DBA-C05A-45FE-A2A3-B1637CE16274} - Library - Properties - AsterNET - AsterNET - v4.0 - - - - - 2.0 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - SAK - SAK - SAK - SAK + net46;netstandard2.0 + 1.3.0 + Copyright © 2017 + Ben Merrills + https://github.com/AsterNET/AsterNET/blob/master/LICENSE + https://github.com/AsterNET/AsterNET + VB.NET, Asterisk, C#, AsterNET, DotNET, Asterisk.NET + AsterNET an Asterisk FastAGI and AMI framework for .NET + Please see: https://github.com/AsterNET/AsterNET/commits/master + Debug;Release;Travis + true full @@ -70,338 +46,28 @@ bin\Travis\AsterNET.XML - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - + + - - - - + + + - - - - - - + + + + 4.3.0 + + + 4.3.0 + + + 4.3.0 + + + diff --git a/Asterisk.2013/Asterisk.NET/FastAGI/AGIChannel.cs b/Asterisk.2013/Asterisk.NET/FastAGI/AGIChannel.cs index c439272..54ed7e7 100644 --- a/Asterisk.2013/Asterisk.NET/FastAGI/AGIChannel.cs +++ b/Asterisk.2013/Asterisk.NET/FastAGI/AGIChannel.cs @@ -12,8 +12,6 @@ namespace AsterNET.FastAGI private readonly bool _SCHANGUP_CAUSES_EXCEPTION; private readonly AGIReader agiReader; private readonly AGIWriter agiWriter; - private AGIReply agiReply; - public AGIChannel(SocketConnection socket, bool SC511_CAUSES_EXCEPTION, bool SCHANGUP_CAUSES_EXCEPTION) { @@ -34,18 +32,10 @@ namespace AsterNET.FastAGI _SCHANGUP_CAUSES_EXCEPTION = SCHANGUP_CAUSES_EXCEPTION; } - /// - /// Get last AGI Reply. - /// - public AGIReply LastReply - { - get { return agiReply; } - } - public AGIReply SendCommand(AGICommand command) { agiWriter.SendCommand(command); - agiReply = agiReader.ReadReply(); + AGIReply agiReply = agiReader.ReadReply(); int status = agiReply.GetStatus(); if (status == (int) AGIReplyStatuses.SC_INVALID_OR_UNKNOWN_COMMAND) throw new InvalidOrUnknownCommandException(command.BuildCommand()); diff --git a/Asterisk.2013/Asterisk.NET/FastAGI/AGIRequest.cs b/Asterisk.2013/Asterisk.NET/FastAGI/AGIRequest.cs index c8d67fc..9985f3a 100644 --- a/Asterisk.2013/Asterisk.NET/FastAGI/AGIRequest.cs +++ b/Asterisk.2013/Asterisk.NET/FastAGI/AGIRequest.cs @@ -557,12 +557,12 @@ namespace AsterNET.FastAGI int i = parameter.IndexOf('='); if (i > 0) { - name = HttpUtility.UrlDecode(parameter.Substring(0, i)); + name = WebUtility.UrlDecode(parameter.Substring(0, i)); if (parameter.Length > i + 1) - val = HttpUtility.UrlDecode(parameter.Substring(i + 1)); + val = WebUtility.UrlDecode(parameter.Substring(i + 1)); } else if (i < 0) - name = HttpUtility.UrlDecode(parameter); + name = WebUtility.UrlDecode(parameter); else continue; diff --git a/Asterisk.2013/Asterisk.NET/FastAGI/AGIScript.cs b/Asterisk.2013/Asterisk.NET/FastAGI/AGIScript.cs index f1bbc4f..6f76111 100644 --- a/Asterisk.2013/Asterisk.NET/FastAGI/AGIScript.cs +++ b/Asterisk.2013/Asterisk.NET/FastAGI/AGIScript.cs @@ -102,8 +102,8 @@ namespace AsterNET.FastAGI protected internal int GetChannelStatus() { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.ChannelStatusCommand()); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.ChannelStatusCommand()); + return lastReply.ResultCode; } #endregion @@ -118,8 +118,8 @@ namespace AsterNET.FastAGI protected internal string GetData(string file) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetDataCommand(file)); - return channel.LastReply.GetResult(); + AGIReply lastReply = channel.SendCommand(new Command.GetDataCommand(file)); + return lastReply.GetResult(); } #endregion @@ -137,8 +137,8 @@ namespace AsterNET.FastAGI protected internal string GetData(string file, long timeout) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetDataCommand(file, timeout)); - return channel.LastReply.GetResult(); + AGIReply lastReply = channel.SendCommand(new Command.GetDataCommand(file, timeout)); + return lastReply.GetResult(); } #endregion @@ -158,8 +158,8 @@ namespace AsterNET.FastAGI protected internal string GetData(string file, long timeout, int maxDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetDataCommand(file, timeout, maxDigits)); - return channel.LastReply.GetResult(); + AGIReply lastReply = channel.SendCommand(new Command.GetDataCommand(file, timeout, maxDigits)); + return lastReply.GetResult(); } #endregion @@ -177,8 +177,8 @@ namespace AsterNET.FastAGI protected internal char GetOption(string file, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetOptionCommand(file, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.GetOptionCommand(file, escapeDigits)); + return lastReply.ResultCodeAsChar; } #endregion @@ -196,8 +196,8 @@ namespace AsterNET.FastAGI protected internal char GetOption(string file, string escapeDigits, int timeout) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetOptionCommand(file, escapeDigits, timeout)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.GetOptionCommand(file, escapeDigits, timeout)); + return lastReply.ResultCodeAsChar; } #endregion @@ -210,8 +210,8 @@ namespace AsterNET.FastAGI protected internal int Exec(string application) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.ExecCommand(application)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.ExecCommand(application)); + return lastReply.ResultCode; } #endregion @@ -225,8 +225,8 @@ namespace AsterNET.FastAGI protected internal int Exec(string application, string options) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.ExecCommand(application, options)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.ExecCommand(application, options)); + return lastReply.ResultCode; } #endregion @@ -291,8 +291,8 @@ namespace AsterNET.FastAGI protected internal char StreamFile(string file, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.StreamFileCommand(file, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.StreamFileCommand(file, escapeDigits)); + return lastReply.ResultCodeAsChar; } #endregion @@ -318,8 +318,8 @@ namespace AsterNET.FastAGI protected internal char SayDigits(string digits, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayDigitsCommand(digits, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayDigitsCommand(digits, escapeDigits)); + return lastReply.ResultCodeAsChar; } #endregion @@ -345,8 +345,8 @@ namespace AsterNET.FastAGI protected internal char SayNumber(string number, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayNumberCommand(number, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayNumberCommand(number, escapeDigits)); + return lastReply.ResultCodeAsChar; } #endregion @@ -372,8 +372,8 @@ namespace AsterNET.FastAGI protected internal char SayPhonetic(string text, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayPhoneticCommand(text, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayPhoneticCommand(text, escapeDigits)); + return lastReply.ResultCodeAsChar; } #endregion @@ -399,8 +399,8 @@ namespace AsterNET.FastAGI protected internal char SayAlpha(string text, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayAlphaCommand(text, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayAlphaCommand(text, escapeDigits)); + return lastReply.ResultCodeAsChar; } #endregion @@ -426,8 +426,8 @@ namespace AsterNET.FastAGI protected internal char SayTime(long time, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayTimeCommand(time, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayTimeCommand(time, escapeDigits)); + return lastReply.ResultCodeAsChar; } #endregion @@ -440,10 +440,10 @@ namespace AsterNET.FastAGI protected internal string GetVariable(string name) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetVariableCommand(name)); - if (channel.LastReply.ResultCode != 1) + AGIReply lastReply = channel.SendCommand(new Command.GetVariableCommand(name)); + if (lastReply.ResultCode != 1) return null; - return channel.LastReply.Extra; + return lastReply.Extra; } #endregion @@ -468,8 +468,8 @@ namespace AsterNET.FastAGI protected internal char WaitForDigit(int timeout) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.WaitForDigitCommand(timeout)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.WaitForDigitCommand(timeout)); + return lastReply.ResultCodeAsChar; } #endregion @@ -484,10 +484,10 @@ namespace AsterNET.FastAGI protected internal string GetFullVariable(string name) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetFullVariableCommand(name)); - if (channel.LastReply.ResultCode != 1) + AGIReply lastReply = channel.SendCommand(new Command.GetFullVariableCommand(name)); + if (lastReply.ResultCode != 1) return null; - return channel.LastReply.Extra; + return lastReply.Extra; } #endregion @@ -502,10 +502,10 @@ namespace AsterNET.FastAGI protected internal string GetFullVariable(string name, string channelName) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.GetFullVariableCommand(name, channelName)); - if (channel.LastReply.ResultCode != 1) + AGIReply lastReply = channel.SendCommand(new Command.GetFullVariableCommand(name, channelName)); + if (lastReply.ResultCode != 1) return null; - return channel.LastReply.Extra; + return lastReply.Extra; } #endregion @@ -530,8 +530,8 @@ namespace AsterNET.FastAGI protected internal char SayDateTime(long time, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits)); + return lastReply.ResultCodeAsChar; } /// @@ -545,8 +545,8 @@ namespace AsterNET.FastAGI protected internal char SayDateTime(long time, string escapeDigits, string format) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits, format)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits, format)); + return lastReply.ResultCodeAsChar; } /// @@ -561,8 +561,8 @@ namespace AsterNET.FastAGI protected internal char SayDateTime(long time, string escapeDigits, string format, string timezone) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits, format, timezone)); - return channel.LastReply.ResultCodeAsChar; + AGIReply lastReply = channel.SendCommand(new Command.SayDateTimeCommand(time, escapeDigits, format, timezone)); + return lastReply.ResultCodeAsChar; } #endregion @@ -576,10 +576,10 @@ namespace AsterNET.FastAGI protected internal string DatabaseGet(string family, string key) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.DatabaseGetCommand(family, key)); - if (channel.LastReply.ResultCode != 1) + AGIReply lastReply = channel.SendCommand(new Command.DatabaseGetCommand(family, key)); + if (lastReply.ResultCode != 1) return null; - return channel.LastReply.Extra; + return lastReply.Extra; } #endregion @@ -662,8 +662,8 @@ namespace AsterNET.FastAGI protected internal int RecordFile(string file, string format, string escapeDigits, int timeout) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.RecordFileCommand(file, format, escapeDigits, timeout)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.RecordFileCommand(file, format, escapeDigits, timeout)); + return lastReply.ResultCode; } /// @@ -687,8 +687,8 @@ namespace AsterNET.FastAGI protected internal int RecordFile(string file, string format, string escapeDigits, int timeout, int offset, bool beep, int maxSilence) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.RecordFileCommand(file, format, escapeDigits, timeout, offset, beep, maxSilence)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.RecordFileCommand(file, format, escapeDigits, timeout, offset, beep, maxSilence)); + return lastReply.ResultCode; } #endregion @@ -710,8 +710,8 @@ namespace AsterNET.FastAGI protected internal int ControlStreamFile(string file) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.ControlStreamFileCommand(file)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.ControlStreamFileCommand(file)); + return lastReply.ResultCode; } /// /// Plays the given file, allowing playback to be interrupted by the given @@ -731,8 +731,8 @@ namespace AsterNET.FastAGI protected internal int ControlStreamFile(string file, string escapeDigits) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits)); + return lastReply.ResultCode; } /// /// Plays the given file, allowing playback to be interrupted by the given @@ -753,8 +753,8 @@ namespace AsterNET.FastAGI protected internal int ControlStreamFile(string file, string escapeDigits, int offset) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits, offset)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits, offset)); + return lastReply.ResultCode; } /// /// Plays the given file, allowing playback to be interrupted by the given @@ -778,8 +778,8 @@ namespace AsterNET.FastAGI protected internal int ControlStreamFile(string file, string escapeDigits, int offset, string forwardDigit, string rewindDigit, string pauseDigit) { AGIChannel channel = this.Channel; - channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits, offset, forwardDigit, rewindDigit, pauseDigit)); - return channel.LastReply.ResultCode; + AGIReply lastReply = channel.SendCommand(new Command.ControlStreamFileCommand(file, escapeDigits, offset, forwardDigit, rewindDigit, pauseDigit)); + return lastReply.ResultCode; } #endregion diff --git a/Asterisk.2013/Asterisk.NET/Helper.cs b/Asterisk.2013/Asterisk.NET/Helper.cs index 80c9830..61125ed 100644 --- a/Asterisk.2013/Asterisk.NET/Helper.cs +++ b/Asterisk.2013/Asterisk.NET/Helper.cs @@ -647,7 +647,9 @@ namespace AsterNET { string name = line.Substring(0, delimiterIndex).ToLower(CultureInfo).Trim(); string val = line.Substring(delimiterIndex + 1).Trim(); - if (val == "") + if (list.Contains(name)) + list[name] += Environment.NewLine + val; + else if (val == "") list[name] = null; else list[name] = val; @@ -874,14 +876,15 @@ namespace AsterNET #region RegisterEventHandler(Dictionary list, int index, Type eventType) - internal static void RegisterEventHandler(Dictionary list, int index, Type eventType) + internal static void RegisterEventHandler(Dictionary> list, Type eventType, Func action) { - int eventHash = eventType.Name.GetHashCode(); + var eventTypeName = eventType.Name; + int eventHash = eventTypeName.GetHashCode(); if (list.ContainsKey(eventHash)) - throw new ArgumentException("Event class already registered : " + eventType.Name); - list.Add(eventHash, index); + throw new ArgumentException("Event class already registered : " + eventTypeName); + list.Add(eventHash, action); } #endregion } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs b/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs index 5df2484..e7d97fa 100644 --- a/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs +++ b/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs @@ -6,6 +6,9 @@ using System; namespace AsterNET.IO { + /// + /// Socket connection to asterisk. + /// public class SocketConnection { private TcpClient tcpClient; @@ -23,21 +26,29 @@ namespace AsterNET.IO /// client port /// encoding public SocketConnection(string host, int port, Encoding encoding) + :this(new TcpClient(host, port), encoding) { - initial = true; - this.encoding = encoding; - this.tcpClient = new TcpClient(host, port); - this.networkStream = this.tcpClient.GetStream(); - this.reader = new StreamReader(this.networkStream, encoding); - this.writer = new BinaryWriter(this.networkStream, encoding); } + + /// + /// Consructor + /// + /// client host + /// client port + /// encoding + /// size of the receive buffer. + public SocketConnection(string host, int port,int receiveBufferSize, Encoding encoding) + : this (new TcpClient(host, port) {ReceiveBufferSize = receiveBufferSize }, encoding) + { + } + #endregion #region Constructor - SocketConnection(socket) /// /// Constructor /// - /// TCP client from Listener + /// TCP client from Listener /// encoding internal SocketConnection(TcpClient tcpClient, Encoding encoding) { diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs new file mode 100644 index 0000000..9e7c43d --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AsterNET.Manager.Action +{ + /// + /// Redirect all channels currently bridged to the specified channel to the specified destination.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+ManagerAction_BlindTransfer + ///
+ class BlindTransferAction : ManagerAction + { + /// + /// Creates a new empty . + /// + public BlindTransferAction() + { + } + + /// + /// Creates a new . + /// + /// + /// + /// + public BlindTransferAction(string channel, string context, string extension) + { + Channel = channel; + Context = context; + Exten = extension; + } + + /// + /// Get the name of this action, i.e. "BlindTransfer". + /// + public override string Action + { + get { return "BlindTransfer"; } + } + + /// + /// Gets or sets the channel. + /// + public string Channel { get; set; } + + /// + /// Gets or sets the context. + /// + public string Context { get; set; } + + /// + /// Gets or sets the extension. + /// + public string Exten { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/ConfbridgeStartRecordAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/ConfbridgeStartRecordAction.cs index 1caff0c..86670ff 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/ConfbridgeStartRecordAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/ConfbridgeStartRecordAction.cs @@ -26,6 +26,8 @@ public string Conference { get; set; } + public string RecordFile { get; set; } + public override string Action { get { return "ConfbridgeStartRecord"; } diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs new file mode 100644 index 0000000..b5369df --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs @@ -0,0 +1,57 @@ +namespace AsterNET.Manager.Action +{ + /// + /// Dynamically add filters for the current manager session + /// The filters added are only used for the current session. Once the connection is closed the filters are removed. + /// This comand requires the system permission because this command can be used to create filters that may bypass filters defined in manager.conf + /// + public class FilterAction : ManagerAction + { + #region Action + + /// + /// Get the name of this action, i.e. "Filter". + /// + public override string Action + { + get { return "Filter"; } + } + + #endregion + + #region Operation + + /// + /// Add - Add a filter + /// + public string Operation { get; set; } + + #endregion + + #region Filter + + /// + /// Filters can be whitelist or blacklist + /// Example whitelist filter: "Event: Newchannel" + /// Example blacklist filter: "!Channel: DAHDI.*" + /// + public string Filter { get; set; } + + #endregion + + #region FilterAction(string filter) + + /// + /// Add - Add a filter + /// + /// Add a filter + /// Filters can be whitelist or blacklist + public FilterAction(string filter, string operation = "Add") + { + Filter = filter; + Operation = operation; + } + + #endregion + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/ModuleLoadAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/ModuleLoadAction.cs new file mode 100644 index 0000000..8e63ed5 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/ModuleLoadAction.cs @@ -0,0 +1,33 @@ +namespace AsterNET.Manager.Action +{ + /// + /// + /// The ModuleLoadAction loads/unloads Asterisk modules. + /// + public class ModuleLoadAction : ManagerAction + { + /// + /// Creates ModuleLoadAction for given module. + /// + //// module to load/unload. + //// loadType parameter can have the following values: load/unload + public ModuleLoadAction(string module, string loadType) + { + Module = module; + LoadType = loadType; + } + + /// + public override string Action => "ModuleLoad"; + + /// + /// Get the name of the module. + /// + public string Module { get; } + + /// + /// Get the type of action (load/unload). + /// + public string LoadType { get; } + } +} \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs index 0dd5469..a7ca8ee 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs @@ -67,6 +67,15 @@ namespace AsterNET.Manager.Action #endregion + #region ChannelId + + /// + /// Get/Set originated channel id + /// + public string ChannelId { get; set; } + + #endregion + #region Context /// diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs index c1f2205..30bcb04 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs @@ -94,5 +94,11 @@ namespace AsterNET.Manager.Action /// true if the queue member should be paused when added. /// public bool Paused { get; set; } + + /// + /// Get/Set an alternate interface to be used to determine the state of the member.
+ /// Available since Asterisk 12. + ///
+ public string StateInterface { get; set; } } } \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs index 4ad6cf9..ff4f5dd 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs @@ -2,7 +2,6 @@ namespace AsterNET.Manager.Action { /// /// The QueuePauseAction makes a queue member temporarily unavailabe (or available again).
- /// It is implemented in apps/app_queue.c
/// Available since Asterisk 1.2. ///
public class QueuePauseAction : ManagerAction @@ -57,11 +56,13 @@ namespace AsterNET.Manager.Action /// the interface of the member to make unavailable /// the queue the member is made unvailable on /// true to make the member unavailbale, false to make the member available - public QueuePauseAction(string iface, string queue, bool paused) + /// the reason for paused when the member is made unavailable + public QueuePauseAction(string iface, string queue, bool paused, string reason = null) { this.Interface = iface; this.Queue = queue; this.Paused = paused; + this.Reason = reason; } /// @@ -73,21 +74,26 @@ namespace AsterNET.Manager.Action } /// - /// Get/Set the interface of the member to make available or unavailable.
+ /// The name of the interface (tech/name) to pause or unpause.
/// This property is mandatory. ///
public string Interface { get; set; } /// - /// Get/Set Returns the name of the queue the member is made available or unavailable on. + /// The name of the queue in which to pause or unpause this member.
+ /// If null, the member will be paused or unpaused in all the queues it is a member of. ///
public string Queue { get; set; } /// - /// Get/Set if the member is made available or unavailable.
- /// true to make the member unavailbale,
- /// false make the member available + /// Pause or unpause the interface.
+ // Set to 'true' to pause the member or 'false' to unpause. ///
public bool Paused { get; set; } + + /// + /// Text description, returned in the event QueueMemberPaused. + /// + public string Reason { get; set; } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/QueueSummaryAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/QueueSummaryAction.cs new file mode 100644 index 0000000..703daae --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/QueueSummaryAction.cs @@ -0,0 +1,51 @@ +using AsterNET.Manager.Event; +using System; + +namespace AsterNET.Manager.Action +{ + /// + /// Show queue summary + /// + /// + public class QueueSummaryAction : ManagerActionEvent + { + #region Action + + /// + /// Get the name of this action, i.e. "Filter". + /// + public override string Action + { + get { return "QueueSummary"; } + } + + #endregion + + #region MyRegion + + /// + /// Name of queue + /// + public string Queue { get; set; } + + #endregion + + #region QueueSummaryAction(string queue) + + public QueueSummaryAction(string queue) + { + Queue = queue; + } + + #endregion + + #region ActionCompleteEventClass() + + public override Type ActionCompleteEventClass() + { + return typeof(QueueSummaryEvent); + } + + #endregion + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/ReloadAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/ReloadAction.cs new file mode 100644 index 0000000..5e27cab --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/ReloadAction.cs @@ -0,0 +1,26 @@ +namespace AsterNET.Manager.Action +{ + /// + /// + /// The ReloadAction reloads Asterisk modules. + /// + public class ReloadAction : ManagerAction + { + /// + /// Creates ReloadAction for given module. + /// + //// module to reload. + public ReloadAction(string module) + { + Module = module; + } + + /// + public override string Action => "Reload"; + + /// + /// Get the name of the module. + /// + public string Module { get; } + } +} \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/UpdateConfigAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/UpdateConfigAction.cs index e946169..f3b7526 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/UpdateConfigAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/UpdateConfigAction.cs @@ -114,7 +114,8 @@ namespace AsterNET.Manager.Action /// Variable to work on /// Value to work on /// Extra match required to match line - public void AddCommand(string action, string category, string variable, string value, string match) + /// Extra match required to match line + public void AddCommand(string action, string category, string variable, string value, string match, string options) { var i = actionCounter++; var index = i.ToString().PadLeft(6, '0'); @@ -133,31 +134,39 @@ namespace AsterNET.Manager.Action if (!string.IsNullOrEmpty(match)) actions.Add("Match-" + index, match); + + if (!string.IsNullOrEmpty(options)) + Actions.Add("Options-" + index, options); + } + + public void AddCommand(string action, string category, string variable, string value, string match) + { + AddCommand(action, category, variable, value, match, null); } public void AddCommand(string action, string category, string variable, string value) { - AddCommand(action, category, variable, value, null); + AddCommand(action, category, variable, value, null, null); } public void AddCommand(string action, string category, string variable) { - AddCommand(action, category, variable, null, null); + AddCommand(action, category, variable, null, null, null); } public void AddCommand(string action, string category) { - AddCommand(action, category, null, null, null); + AddCommand(action, category, null, null, null, null); } public void AddCommand(string action) { - AddCommand(action, null, null, null, null); + AddCommand(action, null, null, null, null, null); } public void AddCommand() { - AddCommand(null, null, null, null, null); + AddCommand(null, null, null, null, null, null); } #endregion diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/AbstractAgentEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/AbstractAgentEvent.cs index ba70968..2745531 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/AbstractAgentEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AbstractAgentEvent.cs @@ -16,7 +16,14 @@ namespace AsterNET.Manager.Event public string Queue { get; set; } /// - /// Get/Set the name of the member's interface. + /// Get/Set the name of the member's interface.
+ /// Added in Asterisk 12 + ///
+ public string Interface { get; set; } + + /// + /// Get/Set the name of the member's interface.
+ /// Removed in asterisk 12 ///
public string Member { get; set; } diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs index d49e70f..3764838 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs @@ -16,7 +16,8 @@ namespace AsterNET.Manager.Event public long HoldTime { get; set; } /// - /// Get/Set bridged channel. + /// Get/Set bridged channel.
+ /// Removed from Asterisk 12 ///
public string BridgedChannel { get; set; } diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs new file mode 100644 index 0000000..9b0b2d9 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AsterNET.Manager.Event +{ + /// + /// Raised when a queue member is notified of a caller in the queue and fails to answer.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+ManagerEvent_AgentRingNoAnswer + ///
+ public class AgentRingNoAnswerEvent : AbstractAgentVariables + { + /// + /// Creates a new using the given . + /// + /// + public AgentRingNoAnswerEvent(ManagerConnection source) + : base(source) + { + } + + + /// + /// Gets or sets the queue. + /// + public string Queue { get; set; } + + /// + /// Gets or sets the name of the agent. + /// + public string AgentName { get; set; } + + /// + /// Gets or sets the agent called. + /// + public string AgentCalled { get; set; } + + /// + /// Gets or sets the channel calling. + /// + public string ChannelCalling { get; set; } + + /// + /// Gets or sets the destination channel. + /// + public string DestinationChannel { get; set; } + + /// + /// Gets or sets the Caller*ID of the calling channel. + /// + public string CallerId { get; set; } + + /// + /// Get/Set the Caller*ID number of the calling channel. + /// + public string CallerIdNum { get; set; } + + /// + /// Get/Set the Caller*ID name of the calling channel. + /// + public string CallerIdName { get; set; } + + /// + /// Gets or sets the context. + /// + public string Context { get; set; } + + /// + /// Gets or sets the extension. + /// + public string Extension { get; set; } + + /// + /// Gets or sets the priority. + /// + public string Priority { get; set; } + + /// + /// Get/Set the amount of time the caller was on ring. + /// + public long RingTime { get; set; } + + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentsEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentsEvent.cs index 023d5da..297c8d4 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentsEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentsEvent.cs @@ -39,18 +39,102 @@ namespace AsterNET.Manager.Event public string Status { get; set; } /// - /// Get/Set the name of channel this agent logged in from or "n/a" if the agent is not logged in. + /// Get/Set the name of channel this agent logged in from or "n/a" if the agent is not logged in.
+ /// Removed on Asterisk 12 app_agent_pool.so module. Use Channel instead. ///
public string LoggedInChan { get; set; } /// - /// Get/Set the time (in seconds since 01/01/1970) when the agent logged in or 0 if the user is not logged. + /// Get/Set the numerical Caller*ID of the channel this agent is talking toor "n/a" if this agent is talking to nobody.
+ /// Removed on Asterisk 12 app_agent_pool.so module. Use TalkingToChan instead. + ///
+ public string TalkingTo { get; set; } + + /// + /// Get/Set BRIDGEPEER value on agent channel.
+ /// Present if Status value is AGENT_ONCALL. + ///
+ public string TalkingToChan { get; set; } + + /// + /// Get/Set Epoche time when the agent started talking with the caller.
+ /// Present if Status value is AGENT_ONCALL. + ///
+ public string CallStarted { get; set; } + + /// + /// Get/Set the time (in seconds since 01/01/1970).
+ /// Present if Status value is AGENT_IDLE or AGENT_ONCALL. ///
public long LoggedInTime { get; set; } /// - /// Get/Set the numerical Caller*ID of the channel this agent is talking toor "n/a" if this agent is talking to nobody. + /// Get/Set a numeric code for the channel's current state, related to ChannelStateDesc. /// - public string TalkingTo { get; set; } + public int ChannelState { get; set; } + + /// + /// Get/Set a description for the channel's current state.
+ /// This is one of + ///
+ ///
Down
+ ///
Rsrvd
+ ///
OffHook
+ ///
Dialing
+ ///
Ring
+ ///
Ringing
+ ///
Up
+ ///
Busy
+ ///
Dialing Offhook
+ ///
Pre-ring
+ ///
Unknown
+ ///
+ ///
+ public string ChannelStateDesc { get; set; } + + /// + /// Get/Set the callerID number. + /// + public string CallerIDNum { get; set; } + + /// + /// Get/Set the callerID name. + /// + public string CallerIDName { get; set; } + + /// + /// Get/Set the connected line number. + /// + public string ConnectedLineNum { get; set; } + + /// + /// Get/Set the connected line name. + /// + public string ConnectedLineName { get; set; } + + /// + /// Get/Set the account codee. + /// + public string AccountCode { get; set; } + + /// + /// Get/Set the context. + /// + public string Context { get; set; } + + /// + /// Get/Set the extension. + /// + public string Exten { get; set; } + + /// + /// Get/Set the agent priority. + /// + public int Priority { get; set; } + + /// + /// Get/Set the uniqueid of the oldest channel associated with this channel. + /// + public int Linkedid { get; set; } } } \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/BlindTransferEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/BlindTransferEvent.cs index 53e369d..b4b6c9e 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/BlindTransferEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/BlindTransferEvent.cs @@ -6,7 +6,7 @@ namespace AsterNET.Manager.Event { public class BlindTransferEvent : ManagerEvent { - public bool Result { get; set; } + public string Result { get; set; } public string TransfererChannel { get; set; } public string TransfererChannelState { get; set; } public string TransfererChannelStatedesc { get; set; } diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs index df155dc..3107bbe 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs @@ -1,16 +1,16 @@ -namespace AsterNET.Manager.Event -{ - - /// - /// Raised when an Asterisk service sends an authentication challenge to a request..
- ///
- public class ChallengeSentEvent : ManagerEvent - { - public ChallengeSentEvent(ManagerConnection source) - : base(source) - { - } - - public string Status { get; set; } - } +namespace AsterNET.Manager.Event +{ + + /// + /// Raised when an Asterisk service sends an authentication challenge to a request..
+ ///
+ public class ChallengeSentEvent : ManagerEvent + { + public ChallengeSentEvent(ManagerConnection source) + : base(source) + { + } + + public string Status { get; set; } + } } \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs index ff847b4..6a18b1f 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs @@ -6,11 +6,21 @@ using System.Threading.Tasks; namespace AsterNET.Manager.Event { + /// + /// An ConfbridgeListCompleteEvent is triggered after the state of all Confbridges has been reported in response to an ConfbridgeListAction.
+ /// See https://wiki.asterisk.org/wiki/display/AST/ConfBridge+AMI+Actions + ///
+ /// /// public class ConfbridgeListCompleteEvent : ResponseEvent { + /// + /// Creates a new . + /// + /// public ConfbridgeListCompleteEvent(ManagerConnection source) : base(source) { } } } + diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs index 56c89cb..135eb85 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs @@ -6,29 +6,122 @@ using System.Threading.Tasks; namespace AsterNET.Manager.Event { + /// + /// Raised as part of the ConfbridgeList action response list.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+ManagerEvent_ConfbridgeList + ///
public class ConfbridgeListEvent : AbstractConfbridgeEvent { - /// - /// - /// - public string CallerIDNum { get; set; } - - /// - /// - /// - public string CallerIDName { get; set; } - - /// - /// + /// Identifies this user as an admin user. /// public string Admin { get; set; } /// - /// + /// Identifies this user as a marked user. /// public string MarkedUser { get; set; } + /// + /// Must this user wait for a marked user to join? + /// + public string WaitMarked { get; set; } + + /// + /// Does this user get kicked after the last marked user leaves? + /// + public string EndMarked { get; set; } + + /// + /// Is this user waiting for a marked user to join? + /// + public string Waiting { get; set; } + + /// + /// The current mute status. + /// + public string Muted { get; set; } + + /// + /// Is this user talking? + /// + public string Talking { get; set; } + + /// + /// The number of seconds the channel has been up. + /// + public string AnsweredTime { get; set; } + + /// + /// A numeric code for the channel's current state, related to ChannelStateDesc + /// + public string ChannelState { get; set; } + + /// + /// The number of seconds the channel has been up. + /// + public string ChannelStateDesc { get; set; } + + /// + /// Gets or sets the Caller*ID number. + /// + public string CallerIDNum { get; set; } + + /// + /// Gets or sets the Caller*ID name. + /// + public string CallerIDName { get; set; } + + /// + /// Gets or sets the connected line number. + /// + public string ConnectedLineNum { get; set; } + + /// + /// Gets or sets the name of the connected line. + /// + public string ConnectedLineName { get; set; } + + /// + /// Gets or sets the language. + /// + public string Language { get; set; } + + /// + /// Gets or sets the account code. + /// + public string AccountCode { get; set; } + + /// + /// Gets or sets the context. + /// + public string Context { get; set; } + + /// + /// Gets or sets the exten. + /// + public string Exten { get; set; } + + /// + /// Gets or sets the priority. + /// + public string Priority { get; set; } + + /// + /// Gets or sets the Uniqueid. + /// + public string Uniqueid { get; set; } + + /// + /// Gets or sets the Linkedid. + /// Uniqueid of the oldest channel associated with this channel. + /// + public string Linkedid { get; set; } + + /// + /// Creates a new . + /// + /// public ConfbridgeListEvent(ManagerConnection source) : base(source) { diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs index f232c60..7d15d20 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs @@ -6,9 +6,17 @@ using System.Threading.Tasks; namespace AsterNET.Manager.Event { + /// + /// An ConfbridgeListRoomsCompleteEvent is triggered after the state of all ConfBridgeRooms has been reported in response to an ConfbridgeListRoomsAction.
+ /// See https://wiki.asterisk.org/wiki/display/AST/ConfBridge+AMI+Actions + ///
+ /// public class ConfbridgeListRoomsCompleteEvent : ResponseEvent { - + /// + /// Creates a new . + /// + /// public ConfbridgeListRoomsCompleteEvent(ManagerConnection source) : base(source) { diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs index 5d137ee..8b0431e 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs @@ -6,23 +6,31 @@ using System.Threading.Tasks; namespace AsterNET.Manager.Event { + /// + /// Raised as part of the ConfbridgeListRooms action response list.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+ManagerEvent_ConfbridgeList + ///
public class ConfbridgeListRoomsEvent : AbstractConfbridgeEvent { /// - /// + /// Gets or sets the parties. /// public int Parties { get; set; } /// - /// + /// Gets or sets the marked. /// public int Marked { get; set; } /// - /// + /// Gets or sets the locked. /// public string Locked { get; set; } + /// + /// Creates a new . + /// + /// public ConfbridgeListRoomsEvent(ManagerConnection source) : base(source) { diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeMuteEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeMuteEvent.cs new file mode 100644 index 0000000..8f52b7e --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeMuteEvent.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AsterNET.Manager.Event +{ + public class ConfbridgeMuteEvent : AbstractConfbridgeEvent + { + public ConfbridgeMuteEvent(ManagerConnection source) + : base(source) + { + } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeUnmuteEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeUnmuteEvent.cs new file mode 100644 index 0000000..f2fddf9 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeUnmuteEvent.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AsterNET.Manager.Event +{ + public class ConfbridgeUnmuteEvent : AbstractConfbridgeEvent + { + public ConfbridgeUnmuteEvent(ManagerConnection source) + : base(source) + { + } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConnectionStateEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConnectionStateEvent.cs index b9a0604..282356b 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConnectionStateEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConnectionStateEvent.cs @@ -12,11 +12,11 @@ namespace AsterNET.Manager.Event public bool Reconnect { get { return this.reconnect; } - set { this.reconnect = true; } + set { this.reconnect = value; } } public ConnectionStateEvent(ManagerConnection source) : base(source) { } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/DTMFBeginEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/DTMFBeginEvent.cs new file mode 100644 index 0000000..d6d1975 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/DTMFBeginEvent.cs @@ -0,0 +1,28 @@ +namespace AsterNET.Manager.Event +{ + /// + /// Raised when a DTMF digit has started on a channel.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+12+ManagerEvent_DTMFBegin + ///
+ public class DTMFBeginEvent : ManagerEvent + { + /// + /// Creates a new using the given . + /// + /// + public DTMFBeginEvent(ManagerConnection source) + : base(source) + { + } + + /// + /// Gets or sets the direction. + /// + public string Direction { get; set; } + + /// + /// Gets or sets the digit. + /// + public string Digit { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/DTMFEndEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/DTMFEndEvent.cs new file mode 100644 index 0000000..425cdbc --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/DTMFEndEvent.cs @@ -0,0 +1,33 @@ +namespace AsterNET.Manager.Event +{ + /// + /// Raised when a DTMF digit has ended on a channel.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+12+ManagerEvent_DTMFEnd + ///
+ public class DTMFEndEvent : ManagerEvent + { + /// + /// Creates a new using the given . + /// + /// + public DTMFEndEvent(ManagerConnection source) + : base(source) + { + } + + /// + /// Gets or sets the direction. + /// + public string Direction { get; set; } + + /// + /// Gets or sets the digit. + /// + public string Digit { get; set; } + + /// + /// Gets or sets the duration ms. + /// + public int DurationMs { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs index 415b3e1..3ffb3df 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs @@ -1,17 +1,17 @@ -namespace AsterNET.Manager.Event -{ - - /// - /// Raised when a device state changes.
- /// This differs from the ExtensionStatus event because this event is raised for all device state changes, not only for changes that affect dialplan hints. - ///
- public class DeviceStateChangeEvent : ManagerEvent - { - public DeviceStateChangeEvent(ManagerConnection source) - : base(source) - { - } - - public string Status { get; set; } - } +namespace AsterNET.Manager.Event +{ + + /// + /// Raised when a device state changes.
+ /// This differs from the ExtensionStatus event because this event is raised for all device state changes, not only for changes that affect dialplan hints. + ///
+ public class DeviceStateChangeEvent : ManagerEvent + { + public DeviceStateChangeEvent(ManagerConnection source) + : base(source) + { + } + + public string Status { get; set; } + } } \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs new file mode 100644 index 0000000..0b42980 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs @@ -0,0 +1,23 @@ +namespace AsterNET.Manager.Event +{ + /// + /// A HangupRequestEvent is raised when a channel is hang up.
+ ///
+ public class HangupRequestEvent : AbstractChannelEvent + { + /// + public HangupRequestEvent(ManagerConnection source) : base(source) + { + } + + /// + /// Uniqueid of the oldest channel associated with this channel. + /// + public string LinkedId { get; set; } + + /// + /// Get/Set the cause of the hangup. + /// + public int Cause { get; set; } + } +} \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/InvalidAccountIDEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/InvalidAccountIDEvent.cs index 44154dc..9971054 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/InvalidAccountIDEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/InvalidAccountIDEvent.cs @@ -1,16 +1,16 @@ -namespace AsterNET.Manager.Event -{ - - /// - /// Raised when a request fails an authentication check due to an invalid account ID.
- ///
- public class InvalidAccountIDEvent : ManagerEvent - { - public InvalidAccountIDEvent(ManagerConnection source) - : base(source) - { - } - - public string Status { get; set; } - } +namespace AsterNET.Manager.Event +{ + + /// + /// Raised when a request fails an authentication check due to an invalid account ID.
+ ///
+ public class InvalidAccountIDEvent : ManagerEvent + { + public InvalidAccountIDEvent(ManagerConnection source) + : base(source) + { + } + + public string Status { get; set; } + } } \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/JoinEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/JoinEvent.cs index b1b22f1..d9bc900 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/JoinEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/JoinEvent.cs @@ -15,7 +15,7 @@ namespace AsterNET.Manager.Event /// Get/Set the Caller*ID number of the channel that joined the queue if set. /// If the channel has no caller id set "unknown" is returned. ///
- public string CallerId { get; set; } + public string CallerIdNum { get; set; } /// /// Get/Set the Caller*ID name of the channel that joined the queue if set. diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs new file mode 100644 index 0000000..b460ccf --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs @@ -0,0 +1,45 @@ +namespace AsterNET.Manager.Event +{ + /// + /// A MusicOnHoldEvent is triggered when music on hold starts or stops on a channel.
+ /// It is implemented in res/res_musiconhold.c.
+ /// Available since Asterisk 1.6 + ///
+ public class MusicOnHoldEvent : ManagerEvent + { + /// + /// Creates a new . + /// + /// + public MusicOnHoldEvent(ManagerConnection source) : base(source) + { + } + + /// + /// Gets or sets the state. + /// + public string State { get; set; } + + /// + /// Gets or sets the class.
+ /// The class of music being played on the channel. + ///
+ public string Class { get; set; } + + /// + /// Gets or sets the account code. + /// + public string AccountCode { get; set; } + + /// + /// Gets or sets the language. + /// + public string Language { get; set; } + + /// + /// Gets or sets the Linked Id
+ /// UniqueId of the oldest channel associated with this channel. + ///
+ public string LinkedId { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStartEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStartEvent.cs new file mode 100644 index 0000000..f54096c --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStartEvent.cs @@ -0,0 +1,85 @@ +namespace AsterNET.Manager.Event +{ + /// + /// Raised when music on hold has started on a channel.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+ManagerEvent_MusicOnHoldStart + ///
+ public class MusicOnHoldStartEvent : ManagerEvent + { + /// + /// Creates a new . + /// + /// + public MusicOnHoldStartEvent(ManagerConnection source) : base(source) + { + } + + /// + /// Gets or sets the class.
+ /// The class of music being played on the channel. + ///
+ public string Class { get; set; } + + /// + /// Gets or sets the channel state.
+ /// A numeric code for the channel's current state, related to ChannelStateDesc + ///
+ public string ChannelState { get; set; } + + /// + /// Gets or sets the channel state description. + /// + public string ChannelStateDesc { get; set; } + + /// + /// Gets or sets the Caller*ID number. + /// + public string CallerIDNum { get; set; } + + /// + /// Gets or sets the Caller*ID name. + /// + public string CallerIDName { get; set; } + + /// + /// Gets or sets the connected line number. + /// + public string ConnectedLineNum { get; set; } + + /// + /// Gets or sets the connected line name. + /// + public string ConnectedLineName { get; set; } + + /// + /// Gets or sets the language. + /// + public string Language { get; set; } + + /// + /// Gets or sets the account code. + /// + public string AccountCode { get; set; } + + /// + /// Gets or sets the context. + /// + public string Context { get; set; } + + /// + /// Gets or sets the exten. + /// + public string Exten { get; set; } + + /// + /// Gets or sets the priority. + /// + public string Priority { get; set; } + + /// + /// Gets or sets the Linked Id + /// UniqueId of the oldest channel associated with this channel. + /// + public string LinkedId { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStopEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStopEvent.cs new file mode 100644 index 0000000..4789628 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStopEvent.cs @@ -0,0 +1,79 @@ +namespace AsterNET.Manager.Event +{ + /// + /// Raised when music on hold has stopped on a channel.
+ /// See https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+ManagerEvent_MusicOnHoldStop + ///
+ public class MusicOnHoldStopEvent : ManagerEvent + { + /// + /// Creates a new . + /// + /// + public MusicOnHoldStopEvent(ManagerConnection source) : base(source) + { + } + + /// + /// Gets or sets the channel state.
+ /// A numeric code for the channel's current state, related to ChannelStateDesc + ///
+ public string ChannelState { get; set; } + + /// + /// Gets or sets the channel state description. + /// + public string ChannelStateDesc { get; set; } + + /// + /// Gets or sets the Caller*ID number. + /// + public string CallerIDNum { get; set; } + + /// + /// Gets or sets the Caller*ID name. + /// + public string CallerIDName { get; set; } + + /// + /// Gets or sets the connected line number. + /// + public string ConnectedLineNum { get; set; } + + /// + /// Gets or sets the connected line name. + /// + public string ConnectedLineName { get; set; } + + /// + /// Gets or sets the language. + /// + public string Language { get; set; } + + /// + /// Gets or sets the account code. + /// + public string AccountCode { get; set; } + + /// + /// Gets or sets the context. + /// + public string Context { get; set; } + + /// + /// Gets or sets the exten. + /// + public string Exten { get; set; } + + /// + /// Gets or sets the priority. + /// + public string Priority { get; set; } + + /// + /// Gets or sets the Linked Id + /// UniqueId of the oldest channel associated with this channel. + /// + public string LinkedId { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs index ccee25b..9943041 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs @@ -17,11 +17,13 @@ namespace AsterNET.Manager.Event private int status; private bool paused; private string name; + private bool incall; + private string pausedReason; - /// - /// Get/Set the name of the queue member. - /// - public string Name + /// + /// Get/Set the name of the queue member. + /// + public string Name { get { return this.name; } set { this.name = value; } @@ -123,8 +125,27 @@ namespace AsterNET.Manager.Event get { return this.paused; } set { this.paused = value; } } + /// + /// Is this queue member in call??
+ /// Available since Asterisk 12.
+ /// true if this member is in call, + /// false if not + ///
+ public bool InCall + { + get { return this.incall; } + set { this.incall = value; } + } + /// + /// Paused reason if the queue member is paused + /// + public string PausedReason + { + get { return this.pausedReason; } + set { this.pausedReason = value; } + } - public QueueMemberEvent(ManagerConnection source) + public QueueMemberEvent(ManagerConnection source) : base(source) { } diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueSummaryEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueSummaryEvent.cs new file mode 100644 index 0000000..9f48db6 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueSummaryEvent.cs @@ -0,0 +1,48 @@ +namespace AsterNET.Manager.Event +{ + /// + /// + /// + public class QueueSummaryEvent : ManagerEvent + { + public QueueSummaryEvent(ManagerConnection source) + : base(source) + { + } + + /// + /// Queue name + /// + public string Queue { get; set; } + + /// + /// Logged operators count in queue + /// + public int LoggedIn { get; set; } + + /// + /// Available operators in queue + /// + public int Available { get; set; } + + /// + /// Calls count + /// + public int Callers { get; set; } + + /// + /// + /// + public int HoldTime { get; set; } + + /// + /// Total talk time + /// + public int TalkTime { get; set; } + + /// + /// + /// + public int LongestHoldTime { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/SuccessfulAuthEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/SuccessfulAuthEvent.cs index c87a9e0..32f7570 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/SuccessfulAuthEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/SuccessfulAuthEvent.cs @@ -1,16 +1,16 @@ -namespace AsterNET.Manager.Event -{ - - /// - /// Raised when a request successfully authenticates with a service..
- ///
- public class SuccessfulAuthEvent : ManagerEvent - { - public SuccessfulAuthEvent(ManagerConnection source) - : base(source) - { - } - - public string Status { get; set; } - } +namespace AsterNET.Manager.Event +{ + + /// + /// Raised when a request successfully authenticates with a service..
+ ///
+ public class SuccessfulAuthEvent : ManagerEvent + { + public SuccessfulAuthEvent(ManagerConnection source) + : base(source) + { + } + + public string Status { get; set; } + } } \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/IActionVariable.cs b/Asterisk.2013/Asterisk.NET/Manager/IActionVariable.cs index 09b0e66..125f06e 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/IActionVariable.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/IActionVariable.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; namespace AsterNET.Manager { + /// + /// IActionVariable + /// interface IActionVariable { Dictionary GetVariables(); diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index e94bd2c..8c42d95 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Threading; using System.Collections; using AsterNET.Manager.Action; @@ -7,1617 +6,1011 @@ using AsterNET.Manager.Event; using AsterNET.Manager.Response; using System.Text.RegularExpressions; using System.Text; -using System.Net.Sockets; using System.Collections.Generic; using System.Reflection; using AsterNET.IO; -using AsterNET.Util; +using System.Threading.Tasks; namespace AsterNET.Manager { - #region Event delegate - - public delegate void ManagerEventHandler(object sender, ManagerEvent e); - public delegate void AgentCallbackLoginEventHandler(object sender, Event.AgentCallbackLoginEvent e); - public delegate void AgentCallbackLogoffEventHandler(object sender, Event.AgentCallbackLogoffEvent e); - public delegate void AgentCalledEventHandler(object sender, Event.AgentCalledEvent e); - public delegate void AgentCompleteEventHandler(object sender, Event.AgentCompleteEvent e); - public delegate void AgentConnectEventHandler(object sender, Event.AgentConnectEvent e); - public delegate void AgentDumpEventHandler(object sender, Event.AgentDumpEvent e); - public delegate void AgentLoginEventHandler(object sender, Event.AgentLoginEvent e); - public delegate void AgentLogoffEventHandler(object sender, Event.AgentLogoffEvent e); - public delegate void AgentsCompleteEventHandler(object sender, Event.AgentsCompleteEvent e); - public delegate void AgentsEventHandler(object sender, Event.AgentsEvent e); - public delegate void AlarmClearEventHandler(object sender, Event.AlarmClearEvent e); - public delegate void AlarmEventHandler(object sender, Event.AlarmEvent e); - public delegate void BridgeEventHandler(object sender, Event.BridgeEvent e); - public delegate void CdrEventHandler(object sender, Event.CdrEvent e); - public delegate void DBGetResponseEventHandler(object sender, Event.DBGetResponseEvent e); - public delegate void DialEventHandler(object sender, Event.DialEvent e); - public delegate void DTMFEventHandler(object sender, Event.DTMFEvent e); - public delegate void DNDStateEventHandler(object sender, Event.DNDStateEvent e); - public delegate void ExtensionStatusEventHandler(object sender, Event.ExtensionStatusEvent e); - public delegate void HangupEventHandler(object sender, Event.HangupEvent e); - public delegate void HoldedCallEventHandler(object sender, Event.HoldedCallEvent e); - public delegate void HoldEventHandler(object sender, Event.HoldEvent e); - public delegate void JoinEventHandler(object sender, Event.JoinEvent e); - public delegate void LeaveEventHandler(object sender, Event.LeaveEvent e); - public delegate void LinkEventHandler(object sender, Event.LinkEvent e); - public delegate void LogChannelEventHandler(object sender, Event.LogChannelEvent e); - public delegate void MeetMeJoinEventHandler(object sender, Event.MeetmeJoinEvent e); - public delegate void MeetMeLeaveEventHandler(object sender, Event.MeetmeLeaveEvent e); - public delegate void MeetMeTalkingEventHandler(object sender, Event.MeetmeTalkingEvent e); - - public delegate void MessageWaitingEventHandler(object sender, Event.MessageWaitingEvent e); - public delegate void NewCallerIdEventHandler(object sender, Event.NewCallerIdEvent e); - public delegate void NewChannelEventHandler(object sender, Event.NewChannelEvent e); - public delegate void NewExtenEventHandler(object sender, Event.NewExtenEvent e); - public delegate void NewStateEventHandler(object sender, Event.NewStateEvent e); - public delegate void OriginateResponseEventHandler(object sender, Event.OriginateResponseEvent e); - public delegate void ParkedCallEventHandler(object sender, Event.ParkedCallEvent e); - public delegate void ParkedCallGiveUpEventHandler(object sender, Event.ParkedCallGiveUpEvent e); - public delegate void ParkedCallsCompleteEventHandler(object sender, Event.ParkedCallsCompleteEvent e); - public delegate void ParkedCallTimeOutEventHandler(object sender, Event.ParkedCallTimeOutEvent e); - public delegate void PeerEntryEventHandler(object sender, Event.PeerEntryEvent e); - public delegate void PeerlistCompleteEventHandler(object sender, Event.PeerlistCompleteEvent e); - public delegate void PeerStatusEventHandler(object sender, Event.PeerStatusEvent e); - public delegate void QueueEntryEventHandler(object sender, Event.QueueEntryEvent e); - public delegate void QueueMemberAddedEventHandler(object sender, Event.QueueMemberAddedEvent e); - public delegate void QueueMemberEventHandler(object sender, Event.QueueMemberEvent e); - public delegate void QueueMemberPausedEventHandler(object sender, Event.QueueMemberPausedEvent e); - public delegate void QueueMemberRemovedEventHandler(object sender, Event.QueueMemberRemovedEvent e); - public delegate void QueueMemberStatusEventHandler(object sender, Event.QueueMemberStatusEvent e); - public delegate void QueueParamsEventHandler(object sender, Event.QueueParamsEvent e); - public delegate void QueueStatusCompleteEventHandler(object sender, Event.QueueStatusCompleteEvent e); - public delegate void RegistryEventHandler(object sender, Event.RegistryEvent e); - public delegate void RenameEventHandler(object sender, Event.RenameEvent e); - public delegate void TransferEventHandler(object sender, Event.TransferEvent e); - public delegate void StatusCompleteEventHandler(object sender, Event.StatusCompleteEvent e); - public delegate void StatusEventHandler(object sender, Event.StatusEvent e); - public delegate void UnholdEventHandler(object sender, Event.UnholdEvent e); - public delegate void UnlinkEventHandler(object sender, Event.UnlinkEvent e); - public delegate void UnparkedCallEventHandler(object sender, Event.UnparkedCallEvent e); - public delegate void UserEventHandler(object sender, Event.UserEvent e); - public delegate void QueueCallerAbandonEventHandler(object sender, Event.QueueCallerAbandonEvent e); - public delegate void ZapShowChannelsCompleteEventHandler(object sender, Event.ZapShowChannelsCompleteEvent e); - public delegate void ZapShowChannelsEventHandler(object sender, Event.ZapShowChannelsEvent e); - public delegate void ConnectionStateEventHandler(object sender, Event.ConnectionStateEvent e); - public delegate void VarSetEventHandler(object sender, Event.VarSetEvent e); - public delegate void AGIExecHandler(object sender, Event.AGIExecEvent e); - public delegate void ConfbridgeStartEventHandler(object sender, Event.ConfbridgeStartEvent e); - public delegate void ConfbridgeJoinEventHandler(object sender, Event.ConfbridgeJoinEvent e); - public delegate void ConfbridgeLeaveEventHandler(object sender, Event.ConfbridgeLeaveEvent e); - public delegate void ConfbridgeEndEventHandler(object sender, Event.ConfbridgeEndEvent e); - public delegate void ConfbridgeTalkingEventHandler(object sender, Event.ConfbridgeTalkingEvent e); - public delegate void FailedACLEventHandler(object sender, Event.FailedACLEvent e); - public delegate void AttendedTransferEventHandler(object sender, Event.AttendedTransferEvent e); - public delegate void BlindTransferEventHandler(object sender, Event.BlindTransferEvent e); - public delegate void BridgeCreateEventHandler(object sender, Event.BridgeCreateEvent e); - public delegate void BridgeDestroyEventHandler(object sender, Event.BridgeDestroyEvent e); - public delegate void BridgeEnterEventHandler(object sender, Event.BridgeEnterEvent e); - public delegate void BridgeLeaveEventHandler(object sender, Event.BridgeLeaveEvent e); - public delegate void DialBeginEventHandler(object sender, Event.DialBeginEvent e); - public delegate void DialEndEventHandler(object sender, Event.DialEndEvent e); - public delegate void QueueCallerJoinEventHandler(object sender, Event.QueueCallerJoinEvent e); - public delegate void QueueCallerLeaveEventHandler(object sender, Event.QueueCallerLeaveEvent e); - public delegate void QueueMemberPauseEventHandler(object sender, Event.QueueMemberPauseEvent e); - public delegate void ChallengeResponseFailedEventHandler(object sender, Event.ChallengeResponseFailedEvent e); - public delegate void InvalidAccountIDEventHandler(object sender, Event.InvalidAccountIDEvent e); - public delegate void DeviceStateChangedEventHandler(object sender, Event.DeviceStateChangeEvent e); - public delegate void ChallengeSentEventHandler(object sender, Event.ChallengeSentEvent e); - public delegate void SuccessfulAuthEventHandler(object sender, Event.SuccessfulAuthEvent e); - - - #endregion - /// - /// Default implemention of the ManagerConnection interface. + /// Default implementation of the ManagerConnection interface. /// public class ManagerConnection - { - #region Variables + { + #region Variables #if LOGGER - private Logger logger = Logger.Instance(); + private Logger logger = Logger.Instance(); #endif - private long actionIdCount = 0; - private string hostname; - private int port; - private string username; - private string password; + private long actionIdCount = 0; + private string hostname; + private int port; + private string username; + private string password; - private SocketConnection mrSocket; - private Thread mrReaderThread; - private ManagerReader mrReader; + private SocketConnection mrSocket; + private Thread mrReaderThread; + private ManagerReader mrReader; - private int defaultResponseTimeout = 2000; - private int defaultEventTimeout = 5000; - private int sleepTime = 50; - private bool keepAlive = true; - private bool keepAliveAfterAuthenticationFailure = false; - private string protocolIdentifier; - private AsteriskVersion asteriskVersion; - private Dictionary responseHandlers; - private Dictionary pingHandlers; - private Dictionary responseEventHandlers; - private int pingInterval = 10000; + private int defaultResponseTimeout = 2000; + private int defaultEventTimeout = 5000; + private int sleepTime = 50; + private bool keepAlive = true; + private bool keepAliveAfterAuthenticationFailure = false; + private string protocolIdentifier; + private AsteriskVersion asteriskVersion; + private Dictionary responseHandlers; + private Dictionary pingHandlers; + private Dictionary responseEventHandlers; + private int pingInterval = 10000; - private object lockSocket = new object(); - private object lockHandlers = new object(); + private object lockSocket = new object(); + private object lockSocketWrite = new object(); + private object lockHandlers = new object(); - private bool enableEvents = true; - private string version = string.Empty; - private Encoding socketEncoding = Encoding.ASCII; - private bool reconnected = false; - private bool reconnectEnable = false; - private int reconnectCount; + private bool enableEvents = true; + private string version = string.Empty; + private Encoding socketEncoding = Encoding.ASCII; + private bool reconnected = false; + private bool reconnectEnable = false; + private int reconnectCount; - private Dictionary registeredEventClasses; - private Dictionary registeredEventHandlers; - private event ManagerEventHandler internalEvent; - private bool fireAllEvents = false; - private Thread callerThread; + private Dictionary registeredEventClasses; + private Dictionary> registeredEventHandlers; + private event EventHandler internalEvent; + private bool fireAllEvents = false; + private Thread callerThread; - /// Default Fast Reconnect retry counter. - private int reconnectRetryFast = 5; - /// Default Maximum Reconnect retry counter. - private int reconnectRetryMax = 10; - /// Default Fast Reconnect interval in milliseconds. - private int reconnectIntervalFast = 5000; - /// Default Slow Reconnect interval in milliseconds. - private int reconnectIntervalMax = 10000; + /// Default Fast Reconnect retry counter. + private int reconnectRetryFast = 5; + /// Default Maximum Reconnect retry counter. + private int reconnectRetryMax = 10; + /// Default Fast Reconnect interval in milliseconds. + private int reconnectIntervalFast = 5000; + /// Default Slow Reconnect interval in milliseconds. + private int reconnectIntervalMax = 10000; public char[] VAR_DELIMITER = { '|' }; - #endregion + #endregion /// /// Allows you to specifiy how events are fired. If false (default) then /// events will be fired in order. Otherwise events will be fired as they arrive and /// control logic in your application will need to handle synchronization. /// - public bool UseASyncEvents = false; + public bool UseASyncEvents = false; - #region Events + #region Events - /// - /// An UnhandledEvent is triggered on unknown event. - /// - public event ManagerEventHandler UnhandledEvent; - /// - /// An AgentCallbackLogin is triggered when an agent is successfully logged in. - /// - public event AgentCallbackLoginEventHandler AgentCallbackLogin; - /// - /// An AgentCallbackLogoff is triggered when an agent that previously logged in is logged of.
- ///
- public event AgentCallbackLogoffEventHandler AgentCallbackLogoff; - /// - /// An AgentCalled is triggered when an agent is ring.
- /// To enable AgentCalled you have to set eventwhencalled = yes in queues.conf.
- ///
- public event AgentCalledEventHandler AgentCalled; - /// - /// An AgentCompleteEvent is triggered when at the end of a call if the caller was connected to an agent. - /// - public event AgentCompleteEventHandler AgentComplete; - /// - /// An AgentConnectEvent is triggered when a caller is connected to an agent. - /// - public event AgentConnectEventHandler AgentConnect; - /// - /// An AgentDumpEvent is triggered when an agent dumps the caller while listening to the queue announcement. - /// - public event AgentDumpEventHandler AgentDump; - /// - /// An AgentLoginEvent is triggered when an agent is successfully logged in using AgentLogin. - /// - public event AgentLoginEventHandler AgentLogin; - /// - /// An AgentCallbackLogoffEvent is triggered when an agent that previously logged in using AgentLogin is logged of. - /// - public event AgentLogoffEventHandler AgentLogoff; - /// - /// An AgentsCompleteEvent is triggered after the state of all agents has been reported in response to an AgentsAction. - /// - public event AgentsCompleteEventHandler AgentsComplete; - /// - /// An AgentsEvent is triggered for each agent in response to an AgentsAction. - /// - public event AgentsEventHandler Agents; - /// - /// An AlarmEvent is triggered when a Zap channel leaves alarm state. - /// - public event AlarmClearEventHandler AlarmClear; - /// - /// - /// - public event BridgeEventHandler Bridge; - /// - /// An AlarmEvent is triggered when a Zap channel enters or changes alarm state. - /// - public event AlarmEventHandler Alarm; - /// - /// A CdrEvent is triggered when a call detail record is generated, usually at the end of a call. - /// - public event CdrEventHandler Cdr; - public event DBGetResponseEventHandler DBGetResponse; - /// - /// A Dial is triggered whenever a phone attempts to dial someone.
- ///
- public event DialEventHandler Dial; - public event DTMFEventHandler DTMF; - /// - /// A DNDStateEvent is triggered by the Zap channel driver when a channel enters or leaves DND (do not disturb) state. - /// - public event DNDStateEventHandler DNDState; - /// - /// An ExtensionStatus is triggered when the state of an extension changes.
- ///
- public event ExtensionStatusEventHandler ExtensionStatus; - /// - /// A Hangup is triggered when a channel is hung up.
- ///
- public event HangupEventHandler Hangup; - /// - /// A HoldedCall is triggered when a channel is put on hold.
- ///
- public event HoldedCallEventHandler HoldedCall; - /// - /// A Hold is triggered by the SIP channel driver when a channel is put on hold.
- ///
- public event HoldEventHandler Hold; - /// - /// A Join is triggered when a channel joines a queue.
- ///
- public event JoinEventHandler Join; - /// - /// A Leave is triggered when a channel leaves a queue.
- ///
- public event LeaveEventHandler Leave; - /// - /// A Link is triggered when two voice channels are linked together and voice data exchange commences.
- /// Several Link events may be seen for a single call. This can occur when Asterisk fails to setup a - /// native bridge for the call.This is when Asterisk must sit between two telephones and perform - /// CODEC conversion on their behalf. - ///
- public event LinkEventHandler Link; - /// - /// A LogChannel is triggered when logging is turned on or off.
- ///
- public event LogChannelEventHandler LogChannel; - /// - /// A MeetMeJoin is triggered if a channel joins a meet me conference.
- ///
- public event MeetMeJoinEventHandler MeetMeJoin; - /// - /// A MeetMeLeave is triggered if a channel leaves a meet me conference.
- ///
- public event MeetMeLeaveEventHandler MeetMeLeave; - // public event MeetMeStopTalkingEventHandler MeetMeStopTalking; - /// - /// A MeetMeTalkingEvent is triggered when a user starts talking in a meet me conference.
- /// To enable talker detection you must pass the option 'T' to the MeetMe application. - ///
- public event MeetMeTalkingEventHandler MeetMeTalking; - /// - /// A MessageWaiting is triggered when someone leaves voicemail.
- ///
- public event MessageWaitingEventHandler MessageWaiting; - /// - /// A NewCallerId is triggered when the caller id of a channel changes.
- ///
- public event NewCallerIdEventHandler NewCallerId; - /// - /// A NewChannel is triggered when a new channel is created.
- ///
- public event NewChannelEventHandler NewChannel; - /// - /// A NewExten is triggered when a channel is connected to a new extension.
- ///
- public event NewExtenEventHandler NewExten; - /// - /// A NewState is triggered when the state of a channel has changed.
- ///
- public event NewStateEventHandler NewState; - // public event OriginateEventHandler Originate; - /// - /// An OriginateFailure is triggered when the execution of an OriginateAction failed. - /// - // public event OriginateFailureEventHandler OriginateFailure; - /// - /// An OriginateSuccess is triggered when the execution of an OriginateAction succeeded. - /// - // public event OriginateSuccessEventHandler OriginateSuccess; - /// - /// An OriginateResponse is triggered when the execution of an Originate. - /// - public event OriginateResponseEventHandler OriginateResponse; - /// - /// A ParkedCall is triggered when a channel is parked (in this case no - /// action id is set) and in response to a ParkedCallsAction.
- ///
- public event ParkedCallEventHandler ParkedCall; - /// - /// A ParkedCallGiveUp is triggered when a channel that has been parked is hung up.
- ///
- public event ParkedCallGiveUpEventHandler ParkedCallGiveUp; - /// - /// A ParkedCallsComplete is triggered after all parked calls have been reported in response to a ParkedCallsAction. - /// - public event ParkedCallsCompleteEventHandler ParkedCallsComplete; - /// - /// A ParkedCallTimeOut is triggered when call parking times out for a given channel.
- ///
- public event ParkedCallTimeOutEventHandler ParkedCallTimeOut; - /// - /// A PeerEntry is triggered in response to a SIPPeersAction or SIPShowPeerAction and contains information about a peer.
- ///
- public event PeerEntryEventHandler PeerEntry; - /// - /// A PeerlistComplete is triggered after the details of all peers has been reported in response to an SIPPeersAction or SIPShowPeerAction.
- ///
- public event PeerlistCompleteEventHandler PeerlistComplete; - /// - /// A PeerStatus is triggered when a SIP or IAX client attempts to registrer at this asterisk server.
- ///
- public event PeerStatusEventHandler PeerStatus; - /// - /// A QueueEntryEvent is triggered in response to a QueueStatusAction and contains information about an entry in a queue. - /// - public event QueueCallerAbandonEventHandler QueueCallerAbandon; - /// - /// A QueueEntryEvent is triggered in response to a QueueStatusAction and contains information about an entry in a queue. - /// - public event QueueEntryEventHandler QueueEntry; - /// - /// A QueueMemberAddedEvent is triggered when a queue member is added to a queue. - /// - public event QueueMemberAddedEventHandler QueueMemberAdded; - /// - /// A QueueMemberEvent is triggered in response to a QueueStatusAction and contains information about a member of a queue. - /// - public event QueueMemberEventHandler QueueMember; + /// + /// An UnhandledEvent is triggered on unknown event. + /// + public event EventHandler UnhandledEvent; + /// + /// An AgentCallbackLogin is triggered when an agent is successfully logged in. + /// + public event EventHandler AgentCallbackLogin; + /// + /// An AgentCallbackLogoff is triggered when an agent that previously logged in is logged of.
+ ///
+ public event EventHandler AgentCallbackLogoff; + /// + /// An AgentCalled is triggered when an agent is ring.
+ /// To enable AgentCalled you have to set eventwhencalled = yes in queues.conf.
+ ///
+ public event EventHandler AgentCalled; + /// + /// An AgentCompleteEvent is triggered when at the end of a call if the caller was connected to an agent. + /// + public event EventHandler AgentComplete; + /// + /// An AgentConnectEvent is triggered when a caller is connected to an agent. + /// + public event EventHandler AgentConnect; + /// + /// An AgentDumpEvent is triggered when an agent dumps the caller while listening to the queue announcement. + /// + public event EventHandler AgentDump; + /// + /// An AgentLoginEvent is triggered when an agent is successfully logged in using AgentLogin. + /// + public event EventHandler AgentLogin; + /// + /// An AgentCallbackLogoffEvent is triggered when an agent that previously logged in using AgentLogin is logged of. + /// + public event EventHandler AgentLogoff; + /// + /// An AgentRingNoAnswer is triggered when an agent was rang and did not answer.
+ /// To enable AgentRingNoAnswer you have to set eventwhencalled = yes in queues.conf. + ///
+ public event EventHandler AgentRingNoAnswer; + /// + /// An AgentsCompleteEvent is triggered after the state of all agents has been reported in response to an AgentsAction. + /// + public event EventHandler AgentsComplete; + /// + /// An AgentsEvent is triggered for each agent in response to an AgentsAction. + /// + public event EventHandler Agents; + /// + /// An AlarmEvent is triggered when a Zap channel leaves alarm state. + /// + public event EventHandler AlarmClear; + /// + /// + /// + public event EventHandler Bridge; + /// + /// An AlarmEvent is triggered when a Zap channel enters or changes alarm state. + /// + public event EventHandler Alarm; + /// + /// A CdrEvent is triggered when a call detail record is generated, usually at the end of a call. + /// + public event EventHandler Cdr; + public event EventHandler DBGetResponse; + /// + /// A Dial is triggered whenever a phone attempts to dial someone.
+ ///
+ public event EventHandler Dial; + public event EventHandler DTMF; + /// + /// An DTMFBeginEvent is triggered when a DTMF digit has started on a channel. + /// + public event EventHandler DTMFBegin; + /// + /// An DTMFEndEvent is triggered when a DTMF digit has ended on a channel. + /// + public event EventHandler DTMFEnd; + /// + /// A DNDStateEvent is triggered by the Zap channel driver when a channel enters or leaves DND (do not disturb) state. + /// + public event EventHandler DNDState; + /// + /// An ExtensionStatus is triggered when the state of an extension changes.
+ ///
+ public event EventHandler ExtensionStatus; + /// + /// A Hangup is triggered when a channel is hung up.
+ ///
+ public event EventHandler Hangup; + /// + /// A HangupRequestEvent is raised when a channel is hang up.
+ ///
+ public event EventHandler HangupRequest; + /// + /// A HoldedCall is triggered when a channel is put on hold.
+ ///
+ public event EventHandler HoldedCall; + /// + /// A Hold is triggered by the SIP channel driver when a channel is put on hold.
+ ///
+ public event EventHandler Hold; + /// + /// A Join is triggered when a channel joines a queue.
+ ///
+ public event EventHandler Join; + /// + /// A Leave is triggered when a channel leaves a queue.
+ ///
+ public event EventHandler Leave; + /// + /// A Link is triggered when two voice channels are linked together and voice data exchange commences.
+ /// Several Link events may be seen for a single call. This can occur when Asterisk fails to setup a + /// native bridge for the call.This is when Asterisk must sit between two telephones and perform + /// CODEC conversion on their behalf. + ///
+ public event EventHandler Link; + /// + /// A LogChannel is triggered when logging is turned on or off.
+ ///
+ public event EventHandler LogChannel; + /// + /// A MeetMeJoin is triggered if a channel joins a meet me conference.
+ ///
+ public event EventHandler MeetMeJoin; + /// + /// A MeetMeLeave is triggered if a channel leaves a meet me conference.
+ ///
+ public event EventHandler MeetMeLeave; + // public event EventHandler MeetMeStopTalking; + /// + /// A MeetMeTalkingEvent is triggered when a user starts talking in a meet me conference.
+ /// To enable talker detection you must pass the option 'T' to the MeetMe application. + ///
+ public event EventHandler MeetMeTalking; + /// + /// A MessageWaiting is triggered when someone leaves voicemail.
+ ///
+ public event EventHandler MessageWaiting; + /// + /// A NewCallerId is triggered when the caller id of a channel changes.
+ ///
+ public event EventHandler NewCallerId; + /// + /// A NewChannel is triggered when a new channel is created.
+ ///
+ public event EventHandler NewChannel; + /// + /// A NewExten is triggered when a channel is connected to a new extension.
+ ///
+ public event EventHandler NewExten; + /// + /// A NewState is triggered when the state of a channel has changed.
+ ///
+ public event EventHandler NewState; + // public event EventHandler Originate; + /// + /// An OriginateFailure is triggered when the execution of an OriginateAction failed. + /// + // public event EventHandler OriginateFailure; + /// + /// An OriginateSuccess is triggered when the execution of an OriginateAction succeeded. + /// + // public event EventHandler OriginateSuccess; + /// + /// An OriginateResponse is triggered when the execution of an Originate. + /// + public event EventHandler OriginateResponse; + /// + /// A ParkedCall is triggered when a channel is parked (in this case no + /// action id is set) and in response to a ParkedCallsAction.
+ ///
+ public event EventHandler ParkedCall; + /// + /// A ParkedCallGiveUp is triggered when a channel that has been parked is hung up.
+ ///
+ public event EventHandler ParkedCallGiveUp; + /// + /// A ParkedCallsComplete is triggered after all parked calls have been reported in response to a ParkedCallsAction. + /// + public event EventHandler ParkedCallsComplete; + /// + /// A ParkedCallTimeOut is triggered when call parking times out for a given channel.
+ ///
+ public event EventHandler ParkedCallTimeOut; + /// + /// A PeerEntry is triggered in response to a SIPPeersAction or SIPShowPeerAction and contains information about a peer.
+ ///
+ public event EventHandler PeerEntry; + /// + /// A PeerlistComplete is triggered after the details of all peers has been reported in response to an SIPPeersAction or SIPShowPeerAction.
+ ///
+ public event EventHandler PeerlistComplete; + /// + /// A PeerStatus is triggered when a SIP or IAX client attempts to registrer at this asterisk server.
+ ///
+ public event EventHandler PeerStatus; + /// + /// A QueueEntryEvent is triggered in response to a QueueStatusAction and contains information about an entry in a queue. + /// + public event EventHandler QueueCallerAbandon; + /// + /// A QueueEntryEvent is triggered in response to a QueueStatusAction and contains information about an entry in a queue. + /// + public event EventHandler QueueEntry; + /// + /// A QueueMemberAddedEvent is triggered when a queue member is added to a queue. + /// + public event EventHandler QueueMemberAdded; + /// + /// A QueueMemberEvent is triggered in response to a QueueStatusAction and contains information about a member of a queue. + /// + public event EventHandler QueueMember; /// /// A QueueMemberPausedEvent is triggered when a queue member is paused or unpaused. /// Replaced by : since Asterisk 12.
/// Removed since : Asterisk 13.
///
- public event QueueMemberPausedEventHandler QueueMemberPaused; - /// - /// A QueueMemberRemovedEvent is triggered when a queue member is removed from a queue. - /// - public event QueueMemberRemovedEventHandler QueueMemberRemoved; - /// - /// A QueueMemberStatusEvent shows the status of a QueueMemberEvent. - /// - public event QueueMemberStatusEventHandler QueueMemberStatus; - /// - /// A QueueParamsEvent is triggered in response to a QueueStatusAction and contains the parameters of a queue. - /// - public event QueueParamsEventHandler QueueParams; - /// - /// A QueueStatusCompleteEvent is triggered after the state of all queues has been reported in response to a QueueStatusAction. - /// - public event QueueStatusCompleteEventHandler QueueStatusComplete; - /// - /// A Registry is triggered when this asterisk server attempts to register - /// as a client at another SIP or IAX server.
- ///
- public event RegistryEventHandler Registry; - /// - /// A RenameEvent is triggered when the name of a channel is changed. - /// - public event RenameEventHandler Rename; - /// - /// A StatusCompleteEvent is triggered after the state of all channels has been reported in response to a StatusAction. - /// - public event StatusCompleteEventHandler StatusComplete; - /// - /// A StatusEvent is triggered for each active channel in response to a StatusAction. - /// - public event StatusEventHandler Status; - /// - /// - /// - public event TransferEventHandler Transfer; - /// - /// An UnholdEvent is triggered by the SIP channel driver when a channel is no longer put on hold. - /// - public event UnholdEventHandler Unhold; - /// - /// An UnlinkEvent is triggered when a link between two voice channels is discontinued, for example, just before call completion. - /// - public event UnlinkEventHandler Unlink; - /// - /// A UnparkedCallEvent is triggered when a channel that has been parked is resumed. - /// - public event UnparkedCallEventHandler UnparkedCall; - /// - /// A ZapShowChannelsEvent is triggered on UserEvent in dialplan. - /// - public event UserEventHandler UserEvents; - /// - /// A ZapShowChannelsCompleteEvent is triggered after the state of all zap channels has been reported in response to a ZapShowChannelsAction. - /// - public event ZapShowChannelsCompleteEventHandler ZapShowChannelsComplete; - /// - /// A ZapShowChannelsEvent is triggered in response to a ZapShowChannelsAction and shows the state of a zap channel. - /// - public event ZapShowChannelsEventHandler ZapShowChannels; - /// - /// A ConnectionState is triggered after Connect/Disconnect/Reload/Shutdown events. - /// - public event ConnectionStateEventHandler ConnectionState; + public event EventHandler QueueMemberPaused; + /// + /// A QueueMemberRemovedEvent is triggered when a queue member is removed from a queue. + /// + public event EventHandler QueueMemberRemoved; + /// + /// A QueueMemberStatusEvent shows the status of a QueueMemberEvent. + /// + public event EventHandler QueueMemberStatus; + /// + /// A QueueParamsEvent is triggered in response to a QueueStatusAction and contains the parameters of a queue. + /// + public event EventHandler QueueParams; + /// + /// A QueueStatusCompleteEvent is triggered after the state of all queues has been reported in response to a QueueStatusAction. + /// + public event EventHandler QueueStatusComplete; + /// + /// A Registry is triggered when this asterisk server attempts to register + /// as a client at another SIP or IAX server.
+ ///
+ public event EventHandler Registry; + /// + /// A RenameEvent is triggered when the name of a channel is changed. + /// + public event EventHandler Rename; + /// + /// A StatusCompleteEvent is triggered after the state of all channels has been reported in response to a StatusAction. + /// + public event EventHandler StatusComplete; + /// + /// A StatusEvent is triggered for each active channel in response to a StatusAction. + /// + public event EventHandler Status; + /// + /// + /// + public event EventHandler Transfer; + /// + /// An UnholdEvent is triggered by the SIP channel driver when a channel is no longer put on hold. + /// + public event EventHandler Unhold; + /// + /// An UnlinkEvent is triggered when a link between two voice channels is discontinued, for example, just before call completion. + /// + public event EventHandler Unlink; + /// + /// A UnparkedCallEvent is triggered when a channel that has been parked is resumed. + /// + public event EventHandler UnparkedCall; + /// + /// A ZapShowChannelsEvent is triggered on UserEvent in dialplan. + /// + public event EventHandler UserEvents; + /// + /// A ZapShowChannelsCompleteEvent is triggered after the state of all zap channels has been reported in response to a ZapShowChannelsAction. + /// + public event EventHandler ZapShowChannelsComplete; + /// + /// A ZapShowChannelsEvent is triggered in response to a ZapShowChannelsAction and shows the state of a zap channel. + /// + public event EventHandler ZapShowChannels; + /// + /// A ConnectionState is triggered after Connect/Disconnect/Shutdown events. + /// + public event EventHandler ConnectionState; - /// - /// When a variable is set - /// - public event VarSetEventHandler VarSet; + /// + /// A Reload is triggered after Reload events. + /// + public event EventHandler Reload; - /// - /// AgiExec is execute - /// - public event AGIExecHandler AGIExec; + /// + /// When a variable is set + /// + public event EventHandler VarSet; - /// - /// This event is sent when the first user requests a conference and it is instantiated - /// - public event ConfbridgeStartEventHandler ConfbridgeStart; + /// + /// AgiExec is execute + /// + public event EventHandler AGIExec; - /// - /// This event is sent when a user joins a conference - either one already in progress or as the first user to join a newly instantiated bridge. - /// - public event ConfbridgeJoinEventHandler ConfbridgeJoin; + /// + /// This event is sent when the first user requests a conference and it is instantiated + /// + public event EventHandler ConfbridgeStart; - /// - /// This event is sent when a user leaves a conference. - /// - public event ConfbridgeLeaveEventHandler ConfbridgeLeave; + /// + /// This event is sent when a user joins a conference - either one already in progress or as the first user to join a newly instantiated bridge. + /// + public event EventHandler ConfbridgeJoin; - /// - /// This event is sent when the last user leaves a conference and it is torn down. - /// - public event ConfbridgeEndEventHandler ConfbridgeEnd; + /// + /// This event is sent when a user leaves a conference. + /// + public event EventHandler ConfbridgeLeave; - /// - /// This event is sent when the conference detects that a user has either begin or stopped talking. - /// - public event ConfbridgeTalkingEventHandler ConfbridgeTalking; + /// + /// This event is sent when the last user leaves a conference and it is torn down. + /// + public event EventHandler ConfbridgeEnd; + + /// + /// This event is sent when the conference detects that a user has either begin or stopped talking. + /// + public event EventHandler ConfbridgeTalking; + + /// + /// This event is sent when a Confbridge participant mutes. + /// + public event EventHandler ConfbridgeMute; + + /// + /// This event is sent when a Confbridge participant unmutes. + /// + public event EventHandler ConfbridgeUnmute; /// /// /// - public event FailedACLEventHandler FailedACL; + public event EventHandler FailedACL; - public event AttendedTransferEventHandler AttendedTransfer; - public event BlindTransferEventHandler BlindTransfer; + public event EventHandler AttendedTransfer; + public event EventHandler BlindTransfer; - public event BridgeCreateEventHandler BridgeCreate; - public event BridgeDestroyEventHandler BridgeDestroy; - public event BridgeEnterEventHandler BridgeEnter; - public event BridgeLeaveEventHandler BridgeLeave; + public event EventHandler BridgeCreate; + public event EventHandler BridgeDestroy; + public event EventHandler BridgeEnter; + public event EventHandler BridgeLeave; /// /// Raised when a dial action has started.
///
- public event DialBeginEventHandler DialBegin; + public event EventHandler DialBegin; /// /// Raised when a dial action has completed.
///
- public event DialEndEventHandler DialEnd; + public event EventHandler DialEnd; /// /// Raised when a caller joins a Queue.
///
- public event QueueCallerJoinEventHandler QueueCallerJoin; + public event EventHandler QueueCallerJoin; /// /// Raised when a caller leaves a Queue.
///
- public event QueueCallerLeaveEventHandler QueueCallerLeave; + public event EventHandler QueueCallerLeave; /// /// A QueueMemberPauseEvent is triggered when a queue member is paused or unpaused.
/// Available since : Asterisk 12. ///
- public event QueueMemberPauseEventHandler QueueMemberPause; - - /// - /// A ChallengeResponseFailed is triggered when a request's attempt to authenticate has been challenged, and the request failed the authentication challenge. - /// - public event ChallengeResponseFailedEventHandler ChallengeResponseFailed; + public event EventHandler QueueMemberPause; /// - /// A InvalidAccountID is triggered when a request fails an authentication check due to an invalid account ID. - /// - public event InvalidAccountIDEventHandler InvalidAccountID; + /// Raised when music on hold has started/stopped on a channel.
+ /// Available since : Asterisk 1.6. + ///
+ public event EventHandler MusicOnHold; /// - /// A DeviceStateChanged is triggered when a device state changes. - /// - public event DeviceStateChangedEventHandler DeviceStateChanged; + /// Raised when music on hold has started on a channel.
+ /// Available since : Asterisk 12. + ///
+ public event EventHandler MusicOnHoldStart; /// - /// A ChallengeSent is triggered when an Asterisk service sends an authentication challenge to a request.. - /// - public event ChallengeSentEventHandler ChallengeSent; + /// Raised when music on hold has stopped on a channel.
+ /// Available since : Asterisk 12. + ///
+ public event EventHandler MusicOnHoldStop; /// - /// A SuccessfulAuth is triggered when a request successfully authenticates with a service. - /// - public event SuccessfulAuthEventHandler SuccessfulAuth; + /// A ChallengeResponseFailed is triggered when a request's attempt to authenticate has been challenged, and the request failed the authentication challenge. + ///
+ public event EventHandler ChallengeResponseFailed; + + /// + /// A InvalidAccountID is triggered when a request fails an authentication check due to an invalid account ID. + /// + public event EventHandler InvalidAccountID; + + /// + /// A DeviceStateChanged is triggered when a device state changes. + /// + public event EventHandler DeviceStateChanged; + + /// + /// A ChallengeSent is triggered when an Asterisk service sends an authentication challenge to a request.. + /// + public event EventHandler ChallengeSent; + + /// + /// A SuccessfulAuth is triggered when a request successfully authenticates with a service. + /// + public event EventHandler SuccessfulAuth; + + /// + /// Raised when call queue summary + /// + public event EventHandler QueueSummary; #endregion #region Constructor - ManagerConnection() /// Creates a new instance. public ManagerConnection() - { - callerThread = Thread.CurrentThread; + { + callerThread = Thread.CurrentThread; - socketEncoding = Encoding.ASCII; + socketEncoding = Encoding.ASCII; - responseHandlers = new Dictionary(); - pingHandlers = new Dictionary(); - responseEventHandlers = new Dictionary(); - registeredEventClasses = new Dictionary(); + responseHandlers = new Dictionary(); + pingHandlers = new Dictionary(); + responseEventHandlers = new Dictionary(); + registeredEventClasses = new Dictionary(); - Helper.RegisterBuiltinEventClasses(registeredEventClasses); + Helper.RegisterBuiltinEventClasses(registeredEventClasses); - registeredEventHandlers = new Dictionary(); + registeredEventHandlers = new Dictionary>(); - #region Event mapping table - Helper.RegisterEventHandler(registeredEventHandlers, 0, typeof(AgentCallbackLoginEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 1, typeof(AgentCallbackLogoffEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 2, typeof(AgentCalledEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 3, typeof(AgentCompleteEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 4, typeof(AgentConnectEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 5, typeof(AgentDumpEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 6, typeof(AgentLoginEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 7, typeof(AgentLogoffEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 8, typeof(AgentsCompleteEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 9, typeof(AgentsEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 10, typeof(AlarmClearEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 11, typeof(AlarmEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 12, typeof(CdrEvent)); + #region Event mapping table + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentCallbackLoginEvent), arg => fireEvent(AgentCallbackLogin, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentCallbackLogoffEvent), arg => fireEvent(AgentCallbackLogoff, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentCalledEvent), arg => fireEvent(AgentCalled, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentCompleteEvent), arg => fireEvent(AgentComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentConnectEvent), arg => fireEvent(AgentConnect, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentDumpEvent), arg => fireEvent(AgentDump, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentLoginEvent), arg => fireEvent(AgentLogin, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentLogoffEvent), arg => fireEvent(AgentLogoff, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentRingNoAnswerEvent), arg => fireEvent(AgentRingNoAnswer, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentsCompleteEvent), arg => fireEvent(AgentsComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentsEvent), arg => fireEvent(Agents, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AlarmClearEvent), arg => fireEvent(AlarmClear, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AlarmEvent), arg => fireEvent(Alarm, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(CdrEvent), arg => fireEvent(Cdr, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 14, typeof(DBGetResponseEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 15, typeof(DialEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DBGetResponseEvent), arg => fireEvent(DBGetResponse, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DialEvent), arg => fireEvent(Dial, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DNDStateEvent), arg => fireEvent(DNDState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ExtensionStatusEvent), arg => fireEvent(ExtensionStatus, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(HangupEvent), arg => fireEvent(Hangup, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(HangupRequestEvent), arg => fireEvent(HangupRequest, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(HoldedCallEvent), arg => fireEvent(HoldedCall, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(HoldEvent), arg => fireEvent(Hold, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(JoinEvent), arg => fireEvent(Join, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(LeaveEvent), arg => fireEvent(Leave, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(LinkEvent), arg => fireEvent(Link, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(LogChannelEvent), arg => fireEvent(LogChannel, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(MeetmeJoinEvent), arg => fireEvent(MeetMeJoin, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(MeetmeLeaveEvent), arg => fireEvent(MeetMeLeave, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(MeetmeTalkingEvent), arg => fireEvent(MeetMeTalking, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(MessageWaitingEvent), arg => fireEvent(MessageWaiting, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(NewCallerIdEvent), arg => fireEvent(NewCallerId, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(NewChannelEvent), arg => fireEvent(NewChannel, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(NewExtenEvent), arg => fireEvent(NewExten, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(NewStateEvent), arg => fireEvent(NewState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(OriginateResponseEvent), arg => fireEvent(OriginateResponse, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ParkedCallEvent), arg => fireEvent(ParkedCall, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ParkedCallGiveUpEvent), arg => fireEvent(ParkedCallGiveUp, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ParkedCallsCompleteEvent), arg => fireEvent(ParkedCallsComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ParkedCallTimeOutEvent), arg => fireEvent(ParkedCallTimeOut, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(PeerEntryEvent), arg => fireEvent(PeerEntry, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(PeerlistCompleteEvent), arg => fireEvent(PeerlistComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(PeerStatusEvent), arg => fireEvent(PeerStatus, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueEntryEvent), arg => fireEvent(QueueEntry, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueMemberAddedEvent), arg => fireEvent(QueueMemberAdded, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueMemberEvent), arg => fireEvent(QueueMember, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueMemberPausedEvent), arg => fireEvent(QueueMemberPaused, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueMemberRemovedEvent), arg => fireEvent(QueueMemberRemoved, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueMemberStatusEvent), arg => fireEvent(QueueMemberStatus, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueParamsEvent), arg => fireEvent(QueueParams, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueStatusCompleteEvent), arg => fireEvent(QueueStatusComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(RegistryEvent), arg => fireEvent(Registry, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueCallerAbandonEvent), arg => fireEvent(QueueCallerAbandon, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(RenameEvent), arg => fireEvent(Rename, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 17, typeof(DNDStateEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 18, typeof(ExtensionStatusEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 19, typeof(HangupEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 20, typeof(HoldedCallEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 21, typeof(HoldEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 22, typeof(JoinEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 23, typeof(LeaveEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 24, typeof(LinkEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 25, typeof(LogChannelEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 26, typeof(MeetmeJoinEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 27, typeof(MeetmeLeaveEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 28, typeof(MeetmeTalkingEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 29, typeof(MessageWaitingEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 30, typeof(NewCallerIdEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 31, typeof(NewChannelEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 32, typeof(NewExtenEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 33, typeof(NewStateEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 34, typeof(OriginateResponseEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 35, typeof(ParkedCallEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 36, typeof(ParkedCallGiveUpEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 37, typeof(ParkedCallsCompleteEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 38, typeof(ParkedCallTimeOutEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 39, typeof(PeerEntryEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 40, typeof(PeerlistCompleteEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 41, typeof(PeerStatusEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 42, typeof(QueueEntryEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 43, typeof(QueueMemberAddedEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 44, typeof(QueueMemberEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 45, typeof(QueueMemberPausedEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 46, typeof(QueueMemberRemovedEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 47, typeof(QueueMemberStatusEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 48, typeof(QueueParamsEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 49, typeof(QueueStatusCompleteEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 50, typeof(RegistryEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 51, typeof(QueueCallerAbandonEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 52, typeof(RenameEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(StatusCompleteEvent), arg => fireEvent(StatusComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(StatusEvent), arg => fireEvent(Status, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(UnholdEvent), arg => fireEvent(Unhold, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(UnlinkEvent), arg => fireEvent(Unlink, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(UnparkedCallEvent), arg => fireEvent(UnparkedCall, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(UserEvent), arg => fireEvent(UserEvents, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ZapShowChannelsCompleteEvent), arg => fireEvent(ZapShowChannelsComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ZapShowChannelsEvent), arg => fireEvent(ZapShowChannels, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 54, typeof(StatusCompleteEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 55, typeof(StatusEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 56, typeof(UnholdEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 57, typeof(UnlinkEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 58, typeof(UnparkedCallEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 59, typeof(UserEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 60, typeof(ZapShowChannelsCompleteEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 61, typeof(ZapShowChannelsEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConnectEvent), arg => fireEvent(ConnectionState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DisconnectEvent), arg => fireEvent(ConnectionState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ReloadEvent), arg => fireEvent(Reload, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ShutdownEvent), arg => fireEvent(ConnectionState, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(ConnectEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(DisconnectEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(ReloadEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 62, typeof(ShutdownEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(BridgeEvent), arg => fireEvent(Bridge, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(TransferEvent), arg => fireEvent(Transfer, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DTMFEvent), arg => fireEvent(DTMF, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DTMFBeginEvent), arg => fireEvent(DTMFBegin, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DTMFEndEvent), arg => fireEvent(DTMFEnd, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 63, typeof(BridgeEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 64, typeof(TransferEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 65, typeof(DTMFEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(VarSetEvent), arg => fireEvent(VarSet, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AGIExecEvent), arg => fireEvent(AGIExec, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 70, typeof(VarSetEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 80, typeof(AGIExecEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConfbridgeStartEvent), arg => fireEvent(ConfbridgeStart, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConfbridgeJoinEvent), arg => fireEvent(ConfbridgeJoin, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConfbridgeLeaveEvent), arg => fireEvent(ConfbridgeLeave, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConfbridgeEndEvent), arg => fireEvent(ConfbridgeEnd, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConfbridgeTalkingEvent), arg => fireEvent(ConfbridgeTalking, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConfbridgeMuteEvent), arg => fireEvent(ConfbridgeMute, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ConfbridgeUnmuteEvent), arg => fireEvent(ConfbridgeUnmute, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 81, typeof(ConfbridgeStartEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 82, typeof(ConfbridgeJoinEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 83, typeof(ConfbridgeLeaveEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 84, typeof(ConfbridgeEndEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 85, typeof(ConfbridgeTalkingEvent)); - - Helper.RegisterEventHandler(registeredEventHandlers, 86, typeof(FailedACLEvent)); - - Helper.RegisterEventHandler(registeredEventHandlers, 87, typeof(AttendedTransferEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 88, typeof(BridgeCreateEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 89, typeof(BridgeDestroyEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 90, typeof(BridgeEnterEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 91, typeof(BridgeLeaveEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 92, typeof(BlindTransferEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 93, typeof(DialBeginEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 94, typeof(DialEndEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 95, typeof(QueueCallerJoinEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 96, typeof(QueueCallerLeaveEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 97, typeof(QueueMemberPauseEvent)); - - Helper.RegisterEventHandler(registeredEventHandlers, 98, typeof(ChallengeResponseFailedEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 99, typeof(InvalidAccountIDEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 100, typeof(DeviceStateChangeEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 101, typeof(ChallengeSentEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 102, typeof(SuccessfulAuthEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(FailedACLEvent), arg => fireEvent(FailedACL, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AttendedTransferEvent), arg => fireEvent(AttendedTransfer, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(BridgeCreateEvent), arg => fireEvent(BridgeCreate, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(BridgeDestroyEvent), arg => fireEvent(BridgeDestroy, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(BridgeEnterEvent), arg => fireEvent(BridgeEnter, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(BridgeLeaveEvent), arg => fireEvent(BridgeLeave, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(BlindTransferEvent), arg => fireEvent(BlindTransfer, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DialBeginEvent), arg => fireEvent(DialBegin, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DialEndEvent), arg => fireEvent(DialEnd, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueCallerJoinEvent), arg => fireEvent(QueueCallerJoin, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueCallerLeaveEvent), arg => fireEvent(QueueCallerLeave, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueMemberPauseEvent), arg => fireEvent(QueueMemberPause, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(MusicOnHoldEvent), arg => fireEvent(MusicOnHold, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(MusicOnHoldStartEvent), arg => fireEvent(MusicOnHoldStart, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(MusicOnHoldStopEvent), arg => fireEvent(MusicOnHoldStop, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ChallengeResponseFailedEvent), arg => fireEvent(ChallengeResponseFailed, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(InvalidAccountIDEvent), arg => fireEvent(InvalidAccountID, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DeviceStateChangeEvent), arg => fireEvent(DeviceStateChanged, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ChallengeSentEvent), arg => fireEvent(ChallengeSent, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(SuccessfulAuthEvent), arg => fireEvent(SuccessfulAuth, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(QueueSummaryEvent), arg => fireEvent(QueueSummary, arg)); + #endregion - this.internalEvent += new ManagerEventHandler(internalEventHandler); - } - #endregion + this.internalEvent += new EventHandler(internalEventHandler); + } + #endregion - #region Constructor - ManagerConnection(hostname, port, username, password) - /// - /// Creates a new instance with the given connection parameters. - /// - /// the hosname of the Asterisk server to connect to. - /// the port where Asterisk listens for incoming Manager API connections, usually 5038. - /// the username to use for login - /// the password to use for login - public ManagerConnection(string hostname, int port, string username, string password) - : this() - { - this.hostname = hostname; - this.port = port; - this.username = username; - this.password = password; - } - #endregion + #region Constructor - ManagerConnection(hostname, port, username, password) + /// + /// Creates a new instance with the given connection parameters. + /// + /// the hosname of the Asterisk server to connect to. + /// the port where Asterisk listens for incoming Manager API connections, usually 5038. + /// the username to use for login + /// the password to use for login + public ManagerConnection(string hostname, int port, string username, string password) + : this() + { + this.hostname = hostname; + this.port = port; + this.username = username; + this.password = password; + } + #endregion - #region Constructor - ManagerConnection(hostname, port, username, password, Encoding socketEncoding) - /// - /// Creates a new instance with the given connection parameters. - /// - /// the hosname of the Asterisk server to connect to. - /// the port where Asterisk listens for incoming Manager API connections, usually 5038. - /// the username to use for login - /// the password to use for login - /// text encoding to asterisk input/output stream - public ManagerConnection(string hostname, int port, string username, string password, Encoding encoding) - : this() - { - this.hostname = hostname; - this.port = port; - this.username = username; - this.password = password; - this.socketEncoding = encoding; - } - #endregion + #region Constructor - ManagerConnection(hostname, port, username, password, Encoding socketEncoding) + /// + /// Creates a new instance with the given connection parameters. + /// + /// the hosname of the Asterisk server to connect to. + /// the port where Asterisk listens for incoming Manager API connections, usually 5038. + /// the username to use for login + /// the password to use for login + /// text encoding to asterisk input/output stream + public ManagerConnection(string hostname, int port, string username, string password, Encoding socketEncoding) + : this() + { + this.hostname = hostname; + this.port = port; + this.username = username; + this.password = password; + this.socketEncoding = socketEncoding; + } + #endregion - /// - /// Default Fast Reconnect retry counter. - /// - public int ReconnectRetryFast - { - get { return reconnectRetryFast; } - set { reconnectRetryFast = value; } - } - /// Default Maximum Reconnect retry counter. - public int ReconnectRetryMax - { - get { return reconnectRetryMax; } - set { reconnectRetryMax = value; } - } - /// Default Fast Reconnect interval in milliseconds. - public int ReconnectIntervalFast - { - get { return reconnectIntervalFast; } - set { reconnectIntervalFast = value; } - } - /// Default Slow Reconnect interval in milliseconds. - public int ReconnectIntervalMax - { - get { return reconnectIntervalMax; } - set { reconnectIntervalMax = value; } - } + /// + /// Default Fast Reconnect retry counter. + /// + public int ReconnectRetryFast + { + get { return reconnectRetryFast; } + set { reconnectRetryFast = value; } + } + /// Default Maximum Reconnect retry counter. + public int ReconnectRetryMax + { + get { return reconnectRetryMax; } + set { reconnectRetryMax = value; } + } + /// Default Fast Reconnect interval in milliseconds. + public int ReconnectIntervalFast + { + get { return reconnectIntervalFast; } + set { reconnectIntervalFast = value; } + } + /// Default Slow Reconnect interval in milliseconds. + public int ReconnectIntervalMax + { + get { return reconnectIntervalMax; } + set { reconnectIntervalMax = value; } + } - #region CallerThread - internal Thread CallerThread - { - get { return callerThread; } - } - #endregion + #region CallerThread + internal Thread CallerThread + { + get { return callerThread; } + } + #endregion - #region internalEventHandler(object sender, ManagerEvent e) - private void internalEventHandler(object sender, ManagerEvent e) - { - int eventHash = e.GetType().Name.GetHashCode(); - if (registeredEventHandlers.ContainsKey(eventHash)) - { - switch (registeredEventHandlers[eventHash]) - { - #region A-C - case 0: - if (AgentCallbackLogin != null) - { - AgentCallbackLogin(this, (AgentCallbackLoginEvent)e); - return; - } - break; - case 1: - if (AgentCallbackLogoff != null) - { - AgentCallbackLogoff(this, (AgentCallbackLogoffEvent)e); - return; - } - break; - case 2: - if (AgentCalled != null) - { - AgentCalled(this, (Event.AgentCalledEvent)e); - return; - } - break; - case 3: - if (AgentComplete != null) - { - AgentComplete(this, (Event.AgentCompleteEvent)e); - return; - } - break; - case 4: - if (AgentConnect != null) - { - AgentConnect(this, (Event.AgentConnectEvent)e); - return; - } - break; - case 5: - if (AgentDump != null) - { - AgentDump(this, (Event.AgentDumpEvent)e); - return; - } - break; - case 6: - if (AgentLogin != null) - { - AgentLogin(this, (Event.AgentLoginEvent)e); - return; - } - break; - case 7: - if (AgentLogoff != null) - { - AgentLogoff(this, (Event.AgentLogoffEvent)e); - return; - } - break; - case 8: - if (AgentsComplete != null) - { - AgentsComplete(this, (AgentsCompleteEvent)e); - return; - } - break; - case 9: - if (Agents != null) - { - Agents(this, (AgentsEvent)e); - return; - } - break; - case 10: - if (AlarmClear != null) - { - AlarmClear(this, (AlarmClearEvent)e); - return; - } - break; - case 11: - if (Alarm != null) - { - Alarm(this, (AlarmEvent)e); - return; - } - break; - case 12: - if (Cdr != null) - { - Cdr(this, (CdrEvent)e); - return; - } - break; - #endregion - #region D-L - case 14: - if (DBGetResponse != null) - { - DBGetResponse(this, (DBGetResponseEvent)e); - return; - } - break; - case 15: - if (Dial != null) - { - Dial(this, (DialEvent)e); - return; - } - break; - case 17: - if (DNDState != null) - { - DNDState(this, (DNDStateEvent)e); - return; - } - break; - case 18: - if (ExtensionStatus != null) - { - ExtensionStatus(this, (ExtensionStatusEvent)e); - return; - } - break; - case 19: - if (Hangup != null) - { - Hangup(this, (HangupEvent)e); - return; - } - break; - case 20: - if (HoldedCall != null) - { - HoldedCall(this, (HoldedCallEvent)e); - return; - } - break; - case 21: - if (Hold != null) - { - Hold(this, (HoldEvent)e); - return; - } - break; - case 22: - if (Join != null) - { - Join(this, (JoinEvent)e); - return; - } - break; - case 23: - if (Leave != null) - { - Leave(this, (LeaveEvent)e); - return; - } - break; - case 24: - if (Link != null) - { - Link(this, (LinkEvent)e); - return; - } - break; - case 25: - if (LogChannel != null) - { - LogChannel(this, (LogChannelEvent)e); - return; - } - break; - #endregion - #region M-P - case 26: - if (MeetMeJoin != null) - { - MeetMeJoin(this, (MeetmeJoinEvent)e); - return; - } - break; - case 27: - if (MeetMeLeave != null) - { - MeetMeLeave(this, (MeetmeLeaveEvent)e); - return; - } - break; - case 28: - if (MeetMeTalking != null) - { - MeetMeTalking(this, (MeetmeTalkingEvent)e); - return; - } - break; - case 29: - if (MessageWaiting != null) - { - MessageWaiting(this, (MessageWaitingEvent)e); - return; - } - break; - case 30: - if (NewCallerId != null) - { - NewCallerId(this, (NewCallerIdEvent)e); - return; - } - break; - case 31: - if (NewChannel != null) - { - NewChannel(this, (NewChannelEvent)e); - return; - } - break; - case 32: - if (NewExten != null) - { - NewExten(this, (NewExtenEvent)e); - return; - } - break; - case 33: - if (NewState != null) - { - NewState(this, (NewStateEvent)e); - return; - } - break; - case 34: - if (OriginateResponse != null) - { - OriginateResponse(this, (OriginateResponseEvent)e); - return; - } - break; - case 35: - if (ParkedCall != null) - { - ParkedCall(this, (ParkedCallEvent)e); - return; - } - break; - case 36: - if (ParkedCallGiveUp != null) - { - ParkedCallGiveUp(this, (ParkedCallGiveUpEvent)e); - return; - } - break; - case 37: - if (ParkedCallsComplete != null) - { - ParkedCallsComplete(this, (ParkedCallsCompleteEvent)e); - return; - } - break; - case 38: - if (ParkedCallTimeOut != null) - { - ParkedCallTimeOut(this, (ParkedCallTimeOutEvent)e); - return; - } - break; - case 39: - if (PeerEntry != null) - { - PeerEntry(this, (PeerEntryEvent)e); - return; - } - break; - case 40: - if (PeerlistComplete != null) - { - PeerlistComplete(this, (PeerlistCompleteEvent)e); - return; - } - break; - case 41: - if (PeerStatus != null) - { - PeerStatus(this, (PeerStatusEvent)e); - return; - } - break; - #endregion - #region Q-Z - case 42: - if (QueueEntry != null) - { - QueueEntry(this, (QueueEntryEvent)e); - return; - } - break; - case 43: - if (QueueMemberAdded != null) - { - QueueMemberAdded(this, (QueueMemberAddedEvent)e); - return; - } - break; - case 44: - if (QueueMember != null) - { - QueueMember(this, (QueueMemberEvent)e); - return; - } - break; - case 45: - if (QueueMemberPaused != null) - { - QueueMemberPaused(this, (QueueMemberPausedEvent)e); - return; - } - break; - case 46: - if (QueueMemberRemoved != null) - { - QueueMemberRemoved(this, (QueueMemberRemovedEvent)e); - return; - } - break; - case 47: - if (QueueMemberStatus != null) - { - QueueMemberStatus(this, (QueueMemberStatusEvent)e); - return; - } - break; - case 48: - if (QueueParams != null) - { - QueueParams(this, (QueueParamsEvent)e); - return; - } - break; - case 49: - if (QueueStatusComplete != null) - { - QueueStatusComplete(this, (QueueStatusCompleteEvent)e); - return; - } - break; - case 50: - if (Registry != null) - { - Registry(this, (RegistryEvent)e); - return; - } - break; - case 51: - if (QueueCallerAbandon != null) - { - QueueCallerAbandon(this, (QueueCallerAbandonEvent)e); - return; - } - break; - case 52: - if (Rename != null) - { - Rename(this, (RenameEvent)e); - return; - } - break; - case 54: - if (StatusComplete != null) - { - StatusComplete(this, (StatusCompleteEvent)e); - return; - } - break; - case 55: - if (Status != null) - { - Status(this, (StatusEvent)e); - return; - } - break; - case 56: - if (Unhold != null) - { - Unhold(this, (UnholdEvent)e); - return; - } - break; - case 57: - if (Unlink != null) - { - Unlink(this, (UnlinkEvent)e); - return; - } - break; - case 58: - if (UnparkedCall != null) - { - UnparkedCall(this, (UnparkedCallEvent)e); - return; - } - break; - case 59: - if (UserEvents != null) - { - UserEvents(this, (UserEvent)e); - return; - } - break; - case 60: - if (ZapShowChannelsComplete != null) - { - ZapShowChannelsComplete(this, (ZapShowChannelsCompleteEvent)e); - return; - } - break; - case 61: - if (ZapShowChannels != null) - { - ZapShowChannels(this, (ZapShowChannelsEvent)e); - return; - } - break; - #endregion + #region internalEventHandler(object sender, ManagerEvent e) + private void internalEventHandler(object sender, ManagerEvent e) + { + int eventHash = e.GetType().Name.GetHashCode(); + if (registeredEventHandlers.ContainsKey(eventHash)) + { + var currentEvent = registeredEventHandlers[eventHash]; + if (currentEvent(e)) + { + return; + } + } - case 62: - if (ConnectionState != null) - { - ConnectionState(this, (ConnectionStateEvent)e); - return; - } - break; - case 63: - if (Bridge != null) - { - Bridge(this, (BridgeEvent)e); - } - break; - case 64: - if (Transfer != null) - { - Transfer(this, (TransferEvent)e); - } - break; - case 65: - if (DTMF != null) - { - DTMF(this, (DTMFEvent)e); - } - break; - case 70: - if (VarSet != null) - { - VarSet(this, (VarSetEvent)e); - } - break; - case 80: - if (AGIExec != null) - { - AGIExec(this, (AGIExecEvent)e); - } - break; - case 81: - if (ConfbridgeStart != null) - { - ConfbridgeStart(this, (ConfbridgeStartEvent)e); - } - break; - case 82: - if (ConfbridgeJoin != null) - { - ConfbridgeJoin(this, (ConfbridgeJoinEvent)e); - } - break; - case 83: - if (ConfbridgeLeave != null) - { - ConfbridgeLeave(this, (ConfbridgeLeaveEvent)e); - } - break; - case 84: - if (ConfbridgeEnd != null) - { - ConfbridgeEnd(this, (ConfbridgeEndEvent)e); - } - break; - case 85: - if (ConfbridgeTalking != null) - { - ConfbridgeTalking(this, (ConfbridgeTalkingEvent)e); - } - break; - case 86: - if (FailedACL != null) - { - FailedACL(this, (FailedACLEvent)e); - } - break; - case 87: - if (AttendedTransfer != null) - { - AttendedTransfer(this, (AttendedTransferEvent) e); - } - break; - case 88: - if (BridgeCreate != null) - { - BridgeCreate(this, (BridgeCreateEvent) e); - } - break; - case 89: - if (BridgeDestroy != null) - { - BridgeDestroy(this, (BridgeDestroyEvent)e); - } - break; - case 90: - if (BridgeEnter != null) - { - BridgeEnter(this, (BridgeEnterEvent)e); - } - break; - case 91: - if (BridgeLeave != null) - { - BridgeLeave(this, (BridgeLeaveEvent)e); - } - break; - case 92: - if (BlindTransfer != null) - { - BlindTransfer(this, (BlindTransferEvent)e); - } - break; - case 93: - if (DialBegin != null) - { - DialBegin(this, (DialBeginEvent)e); - } - break; - case 94: - if (DialEnd != null) - { - DialEnd(this, (DialEndEvent)e); - } - break; - case 95: - if (QueueCallerJoin != null) - { - QueueCallerJoin(this, (QueueCallerJoinEvent)e); - } - break; - case 96: - if (QueueCallerLeave != null) - { - QueueCallerLeave(this, (QueueCallerLeaveEvent)e); - } - break; - case 97: - if (QueueMemberPause != null) - { - QueueMemberPause(this, (QueueMemberPauseEvent)e); - } - break; - case 98: - if (ChallengeResponseFailed != null) - { - ChallengeResponseFailed(this, (ChallengeResponseFailedEvent)e); - return; - } - break; - case 99: - if (InvalidAccountID != null) - { - InvalidAccountID(this, (InvalidAccountIDEvent)e); - return; - } - break; - case 100: - if (DeviceStateChanged != null) - { - DeviceStateChanged(this, (DeviceStateChangeEvent)e); - return; - } - break; - case 101: - if (ChallengeSent != null) - { - ChallengeSent(this, (ChallengeSentEvent)e); - return; - } - break; - case 102: - if (SuccessfulAuth != null) - { - SuccessfulAuth(this, (SuccessfulAuthEvent)e); - return; - } - break; - default: - if (UnhandledEvent != null) - UnhandledEvent(this, e); - return; - } - } - if (fireAllEvents && UnhandledEvent != null) - UnhandledEvent(this, e); - } - #endregion + if (fireAllEvents) + { + fireEvent(UnhandledEvent, e); + } + } + #endregion - #region FireAllEvents - /// - /// If this property set to true then ManagerConnection send all unassigned events to UnhandledEvent handler,
- /// if set to false then all unassgned events lost and send only UnhandledEvent.
- /// Default: false - ///
- public bool FireAllEvents - { - get { return this.fireAllEvents; } - set { this.fireAllEvents = value; } - } - #endregion + #region FireAllEvents + /// + /// If this property set to true then ManagerConnection send all unassigned events to UnhandledEvent handler,
+ /// if set to false then all unassgned events lost and send only UnhandledEvent.
+ /// Default: false + ///
+ public bool FireAllEvents + { + get { return this.fireAllEvents; } + set { this.fireAllEvents = value; } + } + #endregion - #region PingInterval - /// - /// Timeout from Ping to Pong. If no Pong received send Disconnect event. Set to zero to disable. - /// - public int PingInterval - { - get { return pingInterval; } - set { pingInterval = value; } - } - #endregion + #region PingInterval + /// + /// Timeout from Ping to Pong. If no Pong received send Disconnect event. Set to zero to disable. + /// + public int PingInterval + { + get { return pingInterval; } + set { pingInterval = value; } + } + #endregion - #region Hostname - /// Sets the hostname of the asterisk server to connect to.
- /// Default is localhost. - ///
- public string Hostname - { - get { return hostname; } - set { hostname = value; } - } - #endregion + #region Hostname + /// Sets the hostname of the asterisk server to connect to.
+ /// Default is localhost. + ///
+ public string Hostname + { + get { return hostname; } + set { hostname = value; } + } + #endregion - #region Port - /// - /// Sets the port to use to connect to the asterisk server. This is the port - /// specified in asterisk's manager.conf file.
- /// Default is 5038. - ///
- public int Port - { - get { return port; } - set { port = value; } - } - #endregion + #region Port + /// + /// Sets the port to use to connect to the asterisk server. This is the port + /// specified in asterisk's manager.conf file.
+ /// Default is 5038. + ///
+ public int Port + { + get { return port; } + set { port = value; } + } + #endregion - #region UserName - /// - /// Sets the username to use to connect to the asterisk server. This is the - /// username specified in asterisk's manager.conf file. - /// - public string Username - { - get { return username; } - set { username = value; } - } - #endregion + #region UserName + /// + /// Sets the username to use to connect to the asterisk server. This is the + /// username specified in asterisk's manager.conf file. + /// + public string Username + { + get { return username; } + set { username = value; } + } + #endregion - #region Password - /// - /// Sets the password to use to connect to the asterisk server. This is the - /// password specified in asterisk's manager.conf file. - /// - public string Password - { - get { return password; } - set { password = value; } - } - #endregion + #region Password + /// + /// Sets the password to use to connect to the asterisk server. This is the + /// password specified in asterisk's manager.conf file. + /// + public string Password + { + get { return password; } + set { password = value; } + } + #endregion - #region DefaultResponseTimeout - /// Sets the time in milliseconds the synchronous method - /// will wait for a response before throwing a TimeoutException.
- /// Default is 2000. - ///
- public int DefaultResponseTimeout - { - get { return defaultResponseTimeout; } - set { defaultResponseTimeout = value; } - } - #endregion + #region DefaultResponseTimeout + /// Sets the time in milliseconds the synchronous method + /// will wait for a response before throwing a TimeoutException.
+ /// Default is 2000. + ///
+ public int DefaultResponseTimeout + { + get { return defaultResponseTimeout; } + set { defaultResponseTimeout = value; } + } + #endregion - #region DefaultEventTimeout - /// Sets the time in milliseconds the synchronous method - /// will wait for a response and the last response event before throwing a TimeoutException.
- /// Default is 5000. - ///
- public int DefaultEventTimeout - { - get { return defaultEventTimeout; } - set { defaultEventTimeout = value; } - } - #endregion + #region DefaultEventTimeout + /// Sets the time in milliseconds the synchronous method + /// will wait for a response and the last response event before throwing a TimeoutException.
+ /// Default is 5000. + ///
+ public int DefaultEventTimeout + { + get { return defaultEventTimeout; } + set { defaultEventTimeout = value; } + } + #endregion - #region SleepTime - /// Sets the time in milliseconds the synchronous methods - /// SendAction(Action.ManagerAction) and - /// SendAction(Action.ManagerAction, long) will sleep between two checks - /// for the arrival of a response. This value should be rather small.
- /// The sleepTime attribute is also used when checking for the protocol - /// identifer.
- /// Default is 50. - ///
- /// this has been replaced by an interrupt based response checking approach. - public int SleepTime - { - get { return sleepTime; } - set { sleepTime = value; } - } - #endregion + #region SleepTime + /// Sets the time in milliseconds the synchronous methods + /// SendAction(Action.ManagerAction) and + /// SendAction(Action.ManagerAction, long) will sleep between two checks + /// for the arrival of a response. This value should be rather small.
+ /// The sleepTime attribute is also used when checking for the protocol + /// identifer.
+ /// Default is 50. + ///
+ /// this has been replaced by an interrupt based response checking approach. + public int SleepTime + { + get { return sleepTime; } + set { sleepTime = value; } + } + #endregion - #region KeepAliveAfterAuthenticationFailure - /// Set to true to try reconnecting to ther asterisk serve - /// even if the reconnection attempt threw an AuthenticationFailedException.
- /// Default is false. - ///
- public bool KeepAliveAfterAuthenticationFailure - { - set { keepAliveAfterAuthenticationFailure = value; } - get { return keepAliveAfterAuthenticationFailure; } - } - #endregion + #region KeepAliveAfterAuthenticationFailure + /// Set to true to try reconnecting to ther asterisk serve + /// even if the reconnection attempt threw an AuthenticationFailedException.
+ /// Default is false. + ///
+ public bool KeepAliveAfterAuthenticationFailure + { + set { keepAliveAfterAuthenticationFailure = value; } + get { return keepAliveAfterAuthenticationFailure; } + } + #endregion - #region KeepAlive - /// - /// Should we attempt to reconnect when the connection is lost?
- /// This is set to true after successful login and to false after logoff or after an authentication failure when keepAliveAfterAuthenticationFailure is false. - ///
- public bool KeepAlive - { - get { return keepAlive; } - set { keepAlive = value; } - } - #endregion + #region KeepAlive + /// + /// Should we attempt to reconnect when the connection is lost?
+ /// This is set to true after successful login and to false after logoff or after an authentication failure when keepAliveAfterAuthenticationFailure is false. + ///
+ public bool KeepAlive + { + get { return keepAlive; } + set { keepAlive = value; } + } + #endregion - #region SocketEncoding - /// - /// Socket Encoding - default ASCII - /// - public Encoding SocketEncoding - { - get { return socketEncoding; } - set { socketEncoding = value; } - } - #endregion + #region Socket Settings - #region Version - public string Version - { - get { return version; } - } - #endregion + /// + /// Socket Encoding - default ASCII + /// + /// + /// Attention! + /// + /// The value of this property must be set before establishing a connection with the Asterisk. + /// Changing the property doesn't do anything while you are already connected. + /// + /// + public Encoding SocketEncoding + { + get { return socketEncoding; } + set { socketEncoding = value; } + } - #region AsteriskVersion - public AsteriskVersion AsteriskVersion - { - get { return asteriskVersion; } - } - #endregion + /// + /// Socket Receive Buffer Size + /// + /// + /// Attention! + /// + /// The value of this property must be set before establishing a connection with the Asterisk. + /// Changing the property doesn't do anything while you are already connected. + /// + /// + public int SocketReceiveBufferSize { get; set;} - #region login(timeout) - /// - /// Does the real login, following the steps outlined below.
- /// Connects to the asterisk server by calling connect() if not already connected
- /// Waits until the protocol identifier is received. This is checked every sleepTime ms but not longer than timeout ms in total.
- /// Sends a ChallengeAction requesting a challenge for authType MD5.
- /// When the ChallengeResponse is received a LoginAction is sent using the calculated key (MD5 hash of the password appended to the received challenge).
- ///
- /// the maximum time to wait for the protocol identifier (in ms) - /// - /// AuthenticationFailedException if username or password are incorrect and the login action returns an error or if the MD5 - /// hash cannot be computed. The connection is closed in this case. - /// - /// - /// TimeoutException if a timeout occurs either while waiting for the - /// protocol identifier or when sending the challenge or login - /// action. The connection is closed in this case. - /// - private void login(int timeout) - { - enableEvents = false; - if (reconnected) - { + #endregion + + #region Version + public string Version + { + get { return version; } + } + #endregion + + #region AsteriskVersion + public AsteriskVersion AsteriskVersion + { + get { return asteriskVersion; } + } + #endregion + + #region login(timeout) + /// + /// Does the real login, following the steps outlined below.
+ /// Connects to the asterisk server by calling connect() if not already connected
+ /// Waits until the protocol identifier is received. This is checked every sleepTime ms but not longer than timeout ms in total.
+ /// Sends a ChallengeAction requesting a challenge for authType MD5.
+ /// When the ChallengeResponse is received a LoginAction is sent using the calculated key (MD5 hash of the password appended to the received challenge).
+ ///
+ /// the maximum time to wait for the protocol identifier (in ms) + /// + /// AuthenticationFailedException if username or password are incorrect and the login action returns an error or if the MD5 + /// hash cannot be computed. The connection is closed in this case. + /// + /// + /// TimeoutException if a timeout occurs either while waiting for the + /// protocol identifier or when sending the challenge or login + /// action. The connection is closed in this case. + /// + private void login(int timeout) + { + enableEvents = false; + if (reconnected) + { #if LOGGER - logger.Error("Login during reconnect state."); + logger.Error("Login during reconnect state."); #endif - throw new AuthenticationFailedException("Unable login during reconnect state."); - } + throw new AuthenticationFailedException("Unable login during reconnect state."); + } - reconnectEnable = false; - DateTime start = DateTime.Now; - do - { - if (connect()) - { - // Increase delay after connection up to 500 ms - Thread.Sleep(10 * sleepTime); // 200 milliseconds delay - } - try - { - Thread.Sleep(4 * sleepTime); // 200 milliseconds delay - } - catch - { } + reconnectEnable = false; + DateTime start = DateTime.Now; + do + { + if (connect()) + { + // Increase delay after connection up to 500 ms + Thread.Sleep(10 * sleepTime); // 200 milliseconds delay + } + try + { + Thread.Sleep(4 * sleepTime); // 200 milliseconds delay + } + catch + { } - if (string.IsNullOrEmpty(protocolIdentifier) && timeout > 0 && Helper.GetMillisecondsFrom(start) > timeout) - { - disconnect(true); - throw new TimeoutException("Timeout waiting for protocol identifier"); - } - } while (string.IsNullOrEmpty(protocolIdentifier)); + if (string.IsNullOrEmpty(protocolIdentifier) && timeout > 0 && Helper.GetMillisecondsFrom(start) > timeout) + { + disconnect(true); + throw new TimeoutException("Timeout waiting for protocol identifier"); + } + } while (string.IsNullOrEmpty(protocolIdentifier)); - ChallengeAction challengeAction = new ChallengeAction(); - Response.ManagerResponse response = SendAction(challengeAction, defaultResponseTimeout * 2); - if (response is ChallengeResponse) - { - ChallengeResponse challengeResponse = (ChallengeResponse)response; - string key, challenge = challengeResponse.Challenge; - try - { - Util.MD5Support md = Util.MD5Support.GetInstance(); - if (challenge != null) - md.Update(UTF8Encoding.UTF8.GetBytes(challenge)); - if (password != null) - md.Update(UTF8Encoding.UTF8.GetBytes(password)); - key = Helper.ToHexString(md.DigestData); - } - catch (Exception ex) - { - disconnect(true); + ChallengeAction challengeAction = new ChallengeAction(); + Response.ManagerResponse response = SendAction(challengeAction, defaultResponseTimeout * 2); + if (response is ChallengeResponse) + { + ChallengeResponse challengeResponse = (ChallengeResponse)response; + string key, challenge = challengeResponse.Challenge; + try + { + Util.MD5Support md = Util.MD5Support.GetInstance(); + if (challenge != null) + md.Update(UTF8Encoding.UTF8.GetBytes(challenge)); + if (password != null) + md.Update(UTF8Encoding.UTF8.GetBytes(password)); + key = Helper.ToHexString(md.DigestData); + } + catch (Exception ex) + { + disconnect(true); #if LOGGER - logger.Error("Unable to create login key using MD5 Message Digest.", ex); + logger.Error("Unable to create login key using MD5 Message Digest.", ex); #endif - throw new AuthenticationFailedException("Unable to create login key using MD5 Message Digest.", ex); - } + throw new AuthenticationFailedException("Unable to create login key using MD5 Message Digest.", ex); + } - Action.LoginAction loginAction = new Action.LoginAction(username, "MD5", key); - Response.ManagerResponse loginResponse = SendAction(loginAction); - if (loginResponse is Response.ManagerError) - { - disconnect(true); - throw new AuthenticationFailedException(loginResponse.Message); - } + Action.LoginAction loginAction = new Action.LoginAction(username, "MD5", key); + Response.ManagerResponse loginResponse = SendAction(loginAction); + if (loginResponse is Response.ManagerError) + { + disconnect(true); + throw new AuthenticationFailedException(loginResponse.Message); + } - // successfully logged in so assure that we keep trying to reconnect when disconnected - reconnectEnable = keepAlive; + // successfully logged in so assure that we keep trying to reconnect when disconnected + reconnectEnable = keepAlive; #if LOGGER - logger.Info("Successfully logged in"); + logger.Info("Successfully logged in"); #endif - asteriskVersion = determineVersion(); + asteriskVersion = determineVersion(); #if LOGGER - logger.Info("Determined Asterisk version: " + asteriskVersion); + logger.Info("Determined Asterisk version: " + asteriskVersion); #endif enableEvents = true; ConnectEvent ce = new ConnectEvent(this); @@ -1744,23 +1137,26 @@ namespace AsterNET.Manager if (mrSocket == null) { #if LOGGER - logger.Info("Connecting to {0}:{1}", hostname, port); + logger.Info("Connecting to {0}:{1}", hostname, port); #endif - try - { - mrSocket = new SocketConnection(hostname, port, socketEncoding); - result = mrSocket.IsConnected; - } + try + { + if (SocketReceiveBufferSize>0) + mrSocket = new SocketConnection(hostname, port, SocketReceiveBufferSize, socketEncoding); + else + mrSocket = new SocketConnection(hostname, port, socketEncoding); + result = mrSocket.IsConnected; + } #if LOGGER - catch (Exception ex) - { - logger.Info("Connect - Exception : {0}", ex.Message); + catch (Exception ex) + { + logger.Info("Connect - Exception : {0}", ex.Message); #else - catch - { + catch + { #endif - result = false; - } + result = false; + } if (result) { if (mrReader == null) @@ -1781,862 +1177,927 @@ namespace AsterNET.Manager { mrSocket = null; } - } - } + } + } if (startReader) { mrReaderThread.Start(); } - return IsConnected(); - } - #endregion + return IsConnected(); + } + #endregion - #region disconnect() - /// Closes the socket connection. - private void disconnect(bool withDie) - { - lock (lockSocket) - { - if (withDie) - { - reconnectEnable = false; - reconnected = false; - enableEvents = true; - } + #region disconnect() + /// Closes the socket connection. + private void disconnect(bool withDie) + { + lock (lockSocket) + { + if (withDie) + { + reconnectEnable = false; + reconnected = false; + enableEvents = true; + } - if (mrReader != null) - { - if (withDie) - { - mrReader.Die = true; - mrReader = null; - } - else - mrReader.Socket = null; - } + if (mrReader != null) + { + if (withDie) + { + mrReader.Die = true; + mrReader = null; + } + else + mrReader.Socket = null; + } - if (this.mrSocket != null) - { - mrSocket.Close(); - mrSocket = null; - } + if (this.mrSocket != null) + { + mrSocket.Close(); + mrSocket = null; + } - responseEventHandlers.Clear(); - responseHandlers.Clear(); - pingHandlers.Clear(); - } - } - #endregion + responseEventHandlers.Clear(); + responseHandlers.Clear(); + pingHandlers.Clear(); + } + } + #endregion - #region reconnect(bool init) - /// - /// Reconnects to the asterisk server when the connection is lost.
- /// While keepAlive is true we will try to reconnect. - /// Reconnection attempts will be stopped when the logoff() method - /// is called or when the login after a successful reconnect results in an - /// AuthenticationFailedException suggesting that the manager - /// credentials have changed and keepAliveAfterAuthenticationFailure is not set.
- /// This method is called when a DisconnectEvent is received from the reader. - ///
- private void reconnect(bool init) - { + #region reconnect(bool init) + /// + /// Reconnects to the asterisk server when the connection is lost.
+ /// While keepAlive is true we will try to reconnect. + /// Reconnection attempts will be stopped when the logoff() method + /// is called or when the login after a successful reconnect results in an + /// AuthenticationFailedException suggesting that the manager + /// credentials have changed and keepAliveAfterAuthenticationFailure is not set.
+ /// This method is called when a DisconnectEvent is received from the reader. + ///
+ private void reconnect(bool init) + { #if LOGGER - logger.Warning("reconnect (init: {0}), reconnectCount:{1}", init, reconnectCount); + logger.Warning("reconnect (init: {0}), reconnectCount:{1}", init, reconnectCount); #endif - if (init) - reconnectCount = 0; - else if (reconnectCount++ > reconnectRetryMax) - reconnectEnable = false; + if (init) + reconnectCount = 0; + else if (reconnectCount++ > reconnectRetryMax) + reconnectEnable = false; - if (reconnectEnable) - { + if (reconnectEnable) + { #if LOGGER - logger.Warning("Try reconnect."); + logger.Warning("Try reconnect."); #endif - enableEvents = false; - reconnected = true; - disconnect(false); + enableEvents = false; + reconnected = true; + disconnect(false); - int retryCount = 0; - while (reconnectEnable && !mrReader.Die) - { - if (retryCount >= reconnectRetryMax) - reconnectEnable = false; - else - { - try - { - if (retryCount < reconnectRetryFast) - { - // Try to reconnect quite fast for the first times - // this succeeds if the server has just been restarted + int retryCount = 0; + while (reconnectEnable && !mrReader.Die) + { + if (retryCount >= reconnectRetryMax) + reconnectEnable = false; + else + { + try + { + if (retryCount < reconnectRetryFast) + { + // Try to reconnect quite fast for the first times + // this succeeds if the server has just been restarted #if LOGGER - logger.Info("Reconnect delay : {0}, retry : {1}", reconnectIntervalFast, retryCount); + logger.Info("Reconnect delay : {0}, retry : {1}", reconnectIntervalFast, retryCount); #endif - Thread.Sleep(reconnectIntervalFast); - } - else - { - // slow down after unsuccessful attempts assuming a shutdown of the server + Thread.Sleep(reconnectIntervalFast); + } + else + { + // slow down after unsuccessful attempts assuming a shutdown of the server #if LOGGER - logger.Info("Reconnect delay : {0}, retry : {1}", reconnectIntervalMax, retryCount); + logger.Info("Reconnect delay : {0}, retry : {1}", reconnectIntervalMax, retryCount); #endif - Thread.Sleep(reconnectIntervalMax); - } - } - catch (ThreadInterruptedException) - { - continue; - } + Thread.Sleep(reconnectIntervalMax); + } + } + catch (ThreadInterruptedException) + { + continue; + } #if LOGGER - catch (Exception ex) - { - logger.Info("Reconnect delay exception : ", ex.Message); + catch (Exception ex) + { + logger.Info("Reconnect delay exception : ", ex.Message); #else catch { #endif - continue; - } + continue; + } - try - { + try + { #if LOGGER - logger.Info("Try connect."); + logger.Info("Try connect."); #endif - if (connect()) - break; - } + if (connect()) + break; + } #if LOGGER - catch(Exception ex) - { - logger.Info("Connect exception : ", ex.Message); + catch (Exception ex) + { + logger.Info("Connect exception : ", ex.Message); #else catch { #endif - } - retryCount++; - } - } - } + } + retryCount++; + } + } + } - if (!reconnectEnable) - { + if (!reconnectEnable) + { #if LOGGER - logger.Info("Can't reconnect."); + logger.Info("Can't reconnect."); #endif - enableEvents = true; - reconnected = false; - disconnect(true); - fireEvent(new DisconnectEvent(this)); - } - } - #endregion + enableEvents = true; + reconnected = false; + disconnect(true); + fireEvent(new DisconnectEvent(this)); + } + } + #endregion - #region createInternalActionId() - /// - /// Creates a new unique internal action id based on the hash code of this connection and a sequence. - /// - private string createInternalActionId() - { - return this.GetHashCode() + "_" + (this.actionIdCount++); - } - #endregion + #region createInternalActionId() + /// + /// Creates a new unique internal action id based on the hash code of this connection and a sequence. + /// + private string createInternalActionId() + { + return this.GetHashCode() + "_" + (this.actionIdCount++); + } + #endregion - #region Login() - /// - /// Logs in to the Asterisk manager using asterisk's MD5 based - /// challenge/response protocol. The login is delayed until the protocol - /// identifier has been received by the reader. - /// - /// AuthenticationFailedException if the username and/or password are incorrect - /// TimeoutException if no response is received within the specified timeout period - /// - /// - public void Login() - { - login(defaultResponseTimeout); - } - /// - /// Log in to the Asterisk manager using asterisk's MD5 based - /// challenge/response protocol. The login is delayed until the protocol - /// identifier has been received by the reader. - /// - /// Timeout in milliseconds to login. - public void Login(int timeout) - { - login(timeout); - } - #endregion + #region Login() + /// + /// Logs in to the Asterisk manager using asterisk's MD5 based + /// challenge/response protocol. The login is delayed until the protocol + /// identifier has been received by the reader. + /// + /// AuthenticationFailedException if the username and/or password are incorrect + /// TimeoutException if no response is received within the specified timeout period + /// + /// + public void Login() + { + login(defaultResponseTimeout); + } + /// + /// Log in to the Asterisk manager using asterisk's MD5 based + /// challenge/response protocol. The login is delayed until the protocol + /// identifier has been received by the reader. + /// + /// Timeout in milliseconds to login. + public void Login(int timeout) + { + login(timeout); + } + #endregion - #region IsConnected() - /// Returns true if there is a socket connection to the - /// asterisk server, false otherwise. - /// - /// - /// true if there is a socket connection to the - /// asterisk server, false otherwise. - /// - public bool IsConnected() - { - bool result = false; - lock (lockSocket) - result = mrSocket != null && mrSocket.IsConnected; - return result; - } - #endregion + #region IsConnected() + /// Returns true if there is a socket connection to the + /// asterisk server, false otherwise. + /// + /// + /// true if there is a socket connection to the + /// asterisk server, false otherwise. + /// + public bool IsConnected() + { + bool result = false; + lock (lockSocket) + result = mrSocket != null && mrSocket.IsConnected; + return result; + } + #endregion - #region Logoff() - /// - /// Sends a LogoffAction and disconnects from the server. - /// - public void Logoff() - { - lock (lockSocket) - { - // stop reconnecting when we got disconnected - reconnectEnable = false; - if (mrReader != null && mrSocket != null) - try - { - mrReader.IsLogoff = true; - SendAction(new Action.LogoffAction()); - } - catch - { } - } - disconnect(true); - } - #endregion + #region Logoff() + /// + /// Sends a LogoffAction and disconnects from the server. + /// + public void Logoff() + { + lock (lockSocket) + { + // stop reconnecting when we got disconnected + reconnectEnable = false; + if (mrReader != null && mrSocket != null) + try + { + mrReader.IsLogoff = true; + SendAction(new Action.LogoffAction()); + } + catch + { } + } + disconnect(true); + } + #endregion - #region SendAction(action) - /// - /// Send Action with default timeout. - /// - /// - /// - public Response.ManagerResponse SendAction(Action.ManagerAction action) - { - return SendAction(action, defaultResponseTimeout); - } - #endregion + #region SendAction(action) + /// + /// Send Action with default timeout. + /// + /// + /// + public Response.ManagerResponse SendAction(Action.ManagerAction action) + { + return SendAction(action, defaultResponseTimeout); + } + #endregion - #region SendAction(action, timeout) - /// - /// Send action ans with timeout (milliseconds) - /// - /// action to send - /// timeout in milliseconds - /// - public Response.ManagerResponse SendAction(ManagerAction action, int timeOut) - { - AutoResetEvent autoEvent = new AutoResetEvent(false); - ResponseHandler handler = new ResponseHandler(action, autoEvent); + #region SendAction(action, timeout) + /// + /// Send action ans with timeout (milliseconds) + /// + /// action to send + /// timeout in milliseconds + /// + public Response.ManagerResponse SendAction(ManagerAction action, int timeout) + { + AutoResetEvent autoEvent = new AutoResetEvent(false); + ResponseHandler handler = new ResponseHandler(action, autoEvent); - int hash = SendAction(action, handler); - bool result = autoEvent.WaitOne(timeOut <= 0 ? -1 : timeOut, true); + int hash = SendAction(action, handler); + bool result = autoEvent.WaitOne(timeout <= 0 ? -1 : timeout, true); - RemoveResponseHandler(handler); + RemoveResponseHandler(handler); - if (result) - return handler.Response; - throw new TimeoutException("Timeout waiting for response to " + action.Action); - } - #endregion + if (result) + return handler.Response; + throw new TimeoutException("Timeout waiting for response to " + action.Action); + } + #endregion - #region SendAction(action, responseHandler) - public int SendAction(ManagerAction action, ResponseHandler responseHandler) - { - if (action == null) - throw new ArgumentException("Unable to send action: action is null."); + #region SendAction(action, responseHandler) + /// + /// Send action ans with timeout (milliseconds) + /// + /// action to send + /// Response Handler + /// + public int SendAction(ManagerAction action, IResponseHandler responseHandler) + { + if (action == null) + throw new ArgumentException("Unable to send action: action is null."); - if (mrSocket == null) - throw new SystemException("Unable to send " + action.Action + " action: not connected."); + if (mrSocket == null) + throw new SystemException("Unable to send " + action.Action + " action: not connected."); - // if the responseHandler is null the user is obviously not interested in the response, thats fine. - string internalActionId = string.Empty; - if (responseHandler != null) - { - internalActionId = createInternalActionId(); - responseHandler.Hash = internalActionId.GetHashCode(); - AddResponseHandler(responseHandler); - } + // if the responseHandler is null the user is obviously not interested in the response, thats fine. + string internalActionId = string.Empty; + if (responseHandler != null) + { + internalActionId = createInternalActionId(); + responseHandler.Hash = internalActionId.GetHashCode(); + AddResponseHandler(responseHandler); + } - SendToAsterisk(action, internalActionId); + SendToAsterisk(action, internalActionId); - return responseHandler != null ? responseHandler.Hash : 0; - } - #endregion + return responseHandler != null ? responseHandler.Hash : 0; + } + #endregion - #region SendEventGeneratingAction(action) - public ResponseEvents SendEventGeneratingAction(ManagerActionEvent action) - { - return SendEventGeneratingAction(action, defaultEventTimeout); - } - #endregion - #region SendEventGeneratingAction(action, timeout) - /// - /// - /// - /// - /// wait timeout in milliseconds - /// - public ResponseEvents SendEventGeneratingAction(ManagerActionEvent action, int timeout) - { - if (action == null) - throw new ArgumentException("Unable to send action: action is null."); - else if (action.ActionCompleteEventClass() == null) - throw new ArgumentException("Unable to send action: ActionCompleteEventClass is null."); - else if (!typeof(ResponseEvent).IsAssignableFrom(action.ActionCompleteEventClass())) - throw new ArgumentException("Unable to send action: ActionCompleteEventClass is not a ResponseEvent."); - if (mrSocket == null) - throw new SystemException("Unable to send " + action.Action + " action: not connected."); + #region SendActionAsync(action) + /// + /// Asynchronously send Action async with default timeout. + /// + /// action to send + public Task SendActionAsync(ManagerAction action) + { + return SendActionAsync(action, null); + } + #endregion - AutoResetEvent autoEvent = new AutoResetEvent(false); - ResponseEventHandler handler = new ResponseEventHandler(this, action, autoEvent); + #region SendActionAsync(action, timeout) + /// + /// Asynchronously send Action async. + /// + /// action to send + /// cancellation Token + public Task SendActionAsync(ManagerAction action, CancellationTokenSource cancellationToken) + { + var handler = new TaskResponseHandler(action); + var source = handler.TaskCompletionSource; - string internalActionId = createInternalActionId(); - handler.Hash = internalActionId.GetHashCode(); - AddResponseHandler(handler); - AddResponseEventHandler(handler); + SendAction(action, handler); - SendToAsterisk(action, internalActionId); + if (cancellationToken != null) + cancellationToken.Token.Register(() => { source.TrySetCanceled(); }); - bool result = autoEvent.WaitOne(timeout <= 0 ? -1 : timeout, true); + return source.Task.ContinueWith(x => + { + RemoveResponseHandler(handler); + return x.Result; + }); + } + #endregion + #region SendEventGeneratingAction(action) + public ResponseEvents SendEventGeneratingAction(ManagerActionEvent action) + { + return SendEventGeneratingAction(action, defaultEventTimeout); + } + #endregion - RemoveResponseHandler(handler); - RemoveResponseEventHandler(handler); + #region SendEventGeneratingAction(action, timeout) + /// + /// + /// + /// + /// wait timeout in milliseconds + /// + public ResponseEvents SendEventGeneratingAction(ManagerActionEvent action, int timeout) + { + if (action == null) + throw new ArgumentException("Unable to send action: action is null."); + else if (action.ActionCompleteEventClass() == null) + throw new ArgumentException("Unable to send action: ActionCompleteEventClass is null."); + else if (!typeof(ResponseEvent).IsAssignableFrom(action.ActionCompleteEventClass())) + throw new ArgumentException("Unable to send action: ActionCompleteEventClass is not a ResponseEvent."); - if (result) - return handler.ResponseEvents; + if (mrSocket == null) + throw new SystemException("Unable to send " + action.Action + " action: not connected."); - throw new EventTimeoutException("Timeout waiting for response or response events to " + action.Action, handler.ResponseEvents); - } - #endregion + AutoResetEvent autoEvent = new AutoResetEvent(false); + ResponseEventHandler handler = new ResponseEventHandler(this, action, autoEvent); - #region Response Handler helpers - private void AddResponseHandler(IResponseHandler handler) - { - lock (lockHandlers) - { - if (handler.Action is PingAction) - pingHandlers[handler.Hash] = handler; - else - responseHandlers[handler.Hash] = handler; - } - } + string internalActionId = createInternalActionId(); + handler.Hash = internalActionId.GetHashCode(); + AddResponseHandler(handler); + AddResponseEventHandler(handler); - private void AddResponseEventHandler(IResponseHandler handler) - { - lock (lockHandlers) - responseEventHandlers[handler.Hash] = handler; - } + SendToAsterisk(action, internalActionId); - internal void RemoveResponseHandler(IResponseHandler handler) - { - int hash = handler.Hash; - if (hash != 0) - lock (lockHandlers) - if (responseHandlers.ContainsKey(hash)) - responseHandlers.Remove(hash); - } + bool result = autoEvent.WaitOne(timeout <= 0 ? -1 : timeout, true); - internal void RemoveResponseEventHandler(IResponseHandler handler) - { - int hash = handler.Hash; - if (hash != 0) - lock (lockHandlers) - if (responseEventHandlers.ContainsKey(hash)) - responseEventHandlers.Remove(hash); - } + RemoveResponseHandler(handler); + RemoveResponseEventHandler(handler); - private IResponseHandler GetRemoveResponseHandler(int hash) - { - IResponseHandler handler = null; - if (hash != 0) - lock (lockHandlers) - if (responseHandlers.ContainsKey(hash)) - { - handler = responseHandlers[hash]; - responseHandlers.Remove(hash); - } - return handler; - } + if (result) + return handler.ResponseEvents; - private IResponseHandler GetRemoveResponseEventHandler(int hash) - { - IResponseHandler handler = null; - if (hash != 0) - lock (lockHandlers) - if (responseEventHandlers.ContainsKey(hash)) - { - handler = responseEventHandlers[hash]; - responseEventHandlers.Remove(hash); - } - return handler; - } + throw new EventTimeoutException("Timeout waiting for response or response events to " + action.Action, handler.ResponseEvents); + } + #endregion - private IResponseHandler GetResponseHandler(int hash) - { - IResponseHandler handler = null; - if (hash != 0) - lock (lockHandlers) - if (responseHandlers.ContainsKey(hash)) - handler = responseHandlers[hash]; - return handler; - } + #region Response Handler helpers + private void AddResponseHandler(IResponseHandler handler) + { + lock (lockHandlers) + { + if (handler.Action is PingAction) + pingHandlers[handler.Hash] = handler; + else + responseHandlers[handler.Hash] = handler; + } + } - private IResponseHandler GetResponseEventHandler(int hash) - { - IResponseHandler handler = null; - if (hash != 0) - lock (lockHandlers) - if (responseEventHandlers.ContainsKey(hash)) - handler = responseEventHandlers[hash]; - return handler; - } - #endregion + private void AddResponseEventHandler(IResponseHandler handler) + { + lock (lockHandlers) + responseEventHandlers[handler.Hash] = handler; + } - #region SendToAsterisk(ManagerAction action, string internalActionId) + /// + /// Delete an instance of a class from handlers list. + /// + /// Class instance . + public void RemoveResponseHandler(IResponseHandler handler) + { + int hash = handler.Hash; + if (hash != 0) + lock (lockHandlers) + if (responseHandlers.ContainsKey(hash)) + responseHandlers.Remove(hash); + } - internal void SendToAsterisk(ManagerAction action, string internalActionId) - { - if (mrSocket == null) - throw new SystemException("Unable to send action: socket is null"); + internal void RemoveResponseEventHandler(IResponseHandler handler) + { + int hash = handler.Hash; + if (hash != 0) + lock (lockHandlers) + if (responseEventHandlers.ContainsKey(hash)) + responseEventHandlers.Remove(hash); + } + private IResponseHandler GetRemoveResponseHandler(int hash) + { + IResponseHandler handler = null; + if (hash != 0) + lock (lockHandlers) + if (responseHandlers.ContainsKey(hash)) + { + handler = responseHandlers[hash]; + responseHandlers.Remove(hash); + } + return handler; + } - string buffer = BuildAction(action, internalActionId); + private IResponseHandler GetRemoveResponseEventHandler(int hash) + { + IResponseHandler handler = null; + if (hash != 0) + lock (lockHandlers) + if (responseEventHandlers.ContainsKey(hash)) + { + handler = responseEventHandlers[hash]; + responseEventHandlers.Remove(hash); + } + return handler; + } + + private IResponseHandler GetResponseHandler(int hash) + { + IResponseHandler handler = null; + if (hash != 0) + lock (lockHandlers) + if (responseHandlers.ContainsKey(hash)) + handler = responseHandlers[hash]; + return handler; + } + + private IResponseHandler GetResponseEventHandler(int hash) + { + IResponseHandler handler = null; + if (hash != 0) + lock (lockHandlers) + if (responseEventHandlers.ContainsKey(hash)) + handler = responseEventHandlers[hash]; + return handler; + } + #endregion + + #region SendToAsterisk(ManagerAction action, string internalActionId) + + internal void SendToAsterisk(ManagerAction action, string internalActionId) + { + if (mrSocket == null) + throw new SystemException("Unable to send action: socket is null"); + + string buffer = BuildAction(action, internalActionId); #if LOGGER - logger.Debug("Sent action : '{0}' : {1}", internalActionId, action); + logger.Debug("Sent action : '{0}' : {1}", internalActionId, action); #endif - if (sa == null) - sa = new SendToAsteriskDelegate(sendToAsterisk); - sa.Invoke(buffer); - } + if (sa == null) + sa = new SendToAsteriskDelegate(sendToAsterisk); + sa.Invoke(buffer); + } - private delegate void SendToAsteriskDelegate(string buffer); - private SendToAsteriskDelegate sa = null; + private delegate void SendToAsteriskDelegate(string buffer); + private SendToAsteriskDelegate sa = null; - private void sendToAsterisk(string buffer) - { - mrSocket.Write(buffer); - } + private void sendToAsterisk(string buffer) + { + lock (lockSocketWrite) + { + mrSocket.Write(buffer); + } + } - #endregion + #endregion - #region BuildAction(action) - public string BuildAction(Action.ManagerAction action) - { - return BuildAction(action, null); - } - #endregion + #region BuildAction(action) + public string BuildAction(Action.ManagerAction action) + { + return BuildAction(action, null); + } + #endregion - #region BuildAction(action, internalActionId) - public string BuildAction(ManagerAction action, string internalActionId) - { - MethodInfo getter; - object value; - StringBuilder sb = new StringBuilder(); - string valueAsString = string.Empty; + #region BuildAction(action, internalActionId) + public string BuildAction(ManagerAction action, string internalActionId) + { + MethodInfo getter; + object value; + StringBuilder sb = new StringBuilder(); + string valueAsString = string.Empty; - if (typeof(Action.ProxyAction).IsAssignableFrom(action.GetType())) - sb.Append(string.Concat("ProxyAction: ", action.Action, Common.LINE_SEPARATOR)); - else - sb.Append(string.Concat("Action: ", action.Action, Common.LINE_SEPARATOR)); + if (typeof(Action.ProxyAction).IsAssignableFrom(action.GetType())) + sb.Append(string.Concat("ProxyAction: ", action.Action, Common.LINE_SEPARATOR)); + else + sb.Append(string.Concat("Action: ", action.Action, Common.LINE_SEPARATOR)); - if (string.IsNullOrEmpty(internalActionId)) - valueAsString = action.ActionId; - else - valueAsString = string.Concat(internalActionId, Common.INTERNAL_ACTION_ID_DELIMITER, action.ActionId); + if (string.IsNullOrEmpty(internalActionId)) + valueAsString = action.ActionId; + else + valueAsString = string.Concat(internalActionId, Common.INTERNAL_ACTION_ID_DELIMITER, action.ActionId); - if (!string.IsNullOrEmpty(valueAsString)) - sb.Append(string.Concat("ActionID: ", valueAsString, Common.LINE_SEPARATOR)); + if (!string.IsNullOrEmpty(valueAsString)) + sb.Append(string.Concat("ActionID: ", valueAsString, Common.LINE_SEPARATOR)); - Dictionary getters = Helper.GetGetters(action.GetType()); + Dictionary getters = Helper.GetGetters(action.GetType()); - foreach (string name in getters.Keys) - { - string nameLower = name.ToLower(Helper.CultureInfo); - if (nameLower == "class" || nameLower == "action" || nameLower == "actionid") - continue; + foreach (string name in getters.Keys) + { + string nameLower = name.ToLower(Helper.CultureInfo); + if (nameLower == "class" || nameLower == "action" || nameLower == "actionid") + continue; - getter = getters[name]; - Type propType = getter.ReturnType; - if (!(propType == typeof(string) - || propType == typeof(bool) - || propType == typeof(double) - || propType == typeof(DateTime) - || propType == typeof(int) - || propType == typeof(long) - || propType == typeof(Dictionary) - ) - ) - continue; + getter = getters[name]; + Type propType = getter.ReturnType; + if (!(propType == typeof(string) + || propType == typeof(bool) + || propType == typeof(double) + || propType == typeof(DateTime) + || propType == typeof(int) + || propType == typeof(long) + || propType == typeof(Dictionary) + ) + ) + continue; - try - { - value = getter.Invoke(action, new object[] { }); - } - catch (UnauthorizedAccessException ex) - { + try + { + value = getter.Invoke(action, new object[] { }); + } + catch (UnauthorizedAccessException ex) + { #if LOGGER - logger.Error("Unable to retrieve property '" + name + "' of " + action.GetType(), ex); - continue; + logger.Error("Unable to retrieve property '" + name + "' of " + action.GetType(), ex); + continue; #else throw new ManagerException("Unable to retrieve property '" + name + "' of " + action.GetType(), ex); #endif - } - catch (TargetInvocationException ex) - { + } + catch (TargetInvocationException ex) + { #if LOGGER - logger.Error("Unable to retrieve property '" + name + "' of " + action.GetType(), ex); - continue; + logger.Error("Unable to retrieve property '" + name + "' of " + action.GetType(), ex); + continue; #else throw new ManagerException("Unable to retrieve property '" + name + "' of " + action.GetType(), ex); #endif - } + } - if (value == null) - continue; - if (value is string) - { - valueAsString = (string)value; - if (valueAsString.Length == 0) - continue; - } - else if (value is bool) - valueAsString = ((bool)value ? "true" : "false"); - else if (value is DateTime) - valueAsString = value.ToString(); - else if (value is IDictionary) - { - valueAsString = Helper.JoinVariables((IDictionary)value, Common.LINE_SEPARATOR, ": "); - if (valueAsString.Length == 0) - continue; - sb.Append(valueAsString); - sb.Append(Common.LINE_SEPARATOR); - continue; - } - else - valueAsString = value.ToString(); + if (value == null) + continue; + if (value is string) + { + valueAsString = (string)value; + if (valueAsString.Length == 0) + continue; + } + else if (value is bool) + valueAsString = ((bool)value ? "true" : "false"); + else if (value is DateTime) + valueAsString = value.ToString(); + else if (value is IDictionary) + { + valueAsString = Helper.JoinVariables((IDictionary)value, Common.LINE_SEPARATOR, ": "); + if (valueAsString.Length == 0) + continue; + sb.Append(valueAsString); + sb.Append(Common.LINE_SEPARATOR); + continue; + } + else + valueAsString = value.ToString(); - sb.Append(string.Concat(name, ": ", valueAsString, Common.LINE_SEPARATOR)); - } + sb.Append(string.Concat(name, ": ", valueAsString, Common.LINE_SEPARATOR)); + } IActionVariable actionVar = action as IActionVariable; - if ( actionVar != null ) + if (actionVar != null) { var variables = actionVar.GetVariables(); - if ( variables != null && variables.Count > 0 ) + if (variables != null && variables.Count > 0) { - sb.Append( string.Concat( "Variable: ", Helper.JoinVariables( actionVar.GetVariables(), VAR_DELIMITER, "=" ), Common.LINE_SEPARATOR ) ); + sb.Append(string.Concat("Variable: ", Helper.JoinVariables(actionVar.GetVariables(), VAR_DELIMITER, "="), Common.LINE_SEPARATOR)); } } sb.Append(Common.LINE_SEPARATOR); - return sb.ToString(); - } - #endregion + return sb.ToString(); + } + #endregion - #region GetProtocolIdentifier() - public string GetProtocolIdentifier() - { - return this.protocolIdentifier; - } - #endregion + #region GetProtocolIdentifier() + public string GetProtocolIdentifier() + { + return this.protocolIdentifier; + } + #endregion - #region RegisterUserEventClass(class) - /// - /// Register User Event Class - /// - /// - public void RegisterUserEventClass(Type userEventClass) - { - Helper.RegisterEventClass(registeredEventClasses, userEventClass); - } - #endregion + #region RegisterUserEventClass(class) + /// + /// Register User Event Class + /// + /// + public void RegisterUserEventClass(Type userEventClass) + { + Helper.RegisterEventClass(registeredEventClasses, userEventClass); + } + #endregion - #region DispatchResponse(response) - /// - /// This method is called by the reader whenever a ManagerResponse is - /// received. The response is dispatched to the associated ManagerResponseHandler. - /// - /// the response received by the reader - /// - internal void DispatchResponse(Dictionary buffer) - { + #region DispatchResponse(response) + /// + /// This method is called by the reader whenever a ManagerResponse is + /// received. The response is dispatched to the associated ManagerResponseHandler. + /// + /// the response received by the reader + /// + internal void DispatchResponse(Dictionary buffer) + { #if LOGGER - logger.Debug("Dispatch response packet : {0}", Helper.JoinVariables(buffer, ", ", ": ")); + logger.Debug("Dispatch response packet : {0}", Helper.JoinVariables(buffer, ", ", ": ")); #endif - DispatchResponse(buffer, null); - } + DispatchResponse(buffer, null); + } - internal void DispatchResponse(ManagerResponse response) - { + internal void DispatchResponse(ManagerResponse response) + { #if LOGGER - logger.Debug("Dispatch response : {0}", response); + logger.Debug("Dispatch response : {0}", response); #endif - DispatchResponse(null, response); - } + DispatchResponse(null, response); + } - internal void DispatchResponse(Dictionary buffer, ManagerResponse response) - { - string responseActionId = string.Empty; - string actionId = string.Empty; - IResponseHandler responseHandler = null; + internal void DispatchResponse(Dictionary buffer, ManagerResponse response) + { + string responseActionId = string.Empty; + string actionId = string.Empty; + IResponseHandler responseHandler = null; - if (buffer != null) - { - if (buffer["response"].ToLower(Helper.CultureInfo) == "error") - response = new ManagerError(buffer); - else if (buffer.ContainsKey("actionid")) - actionId = buffer["actionid"]; - } + if (buffer != null) + { + if (buffer["response"].ToLower(Helper.CultureInfo) == "error") + response = new ManagerError(buffer); + else if (buffer.ContainsKey("actionid")) + actionId = buffer["actionid"]; + } - if (response != null) - actionId = response.ActionId; + if (response != null) + actionId = response.ActionId; - if (!string.IsNullOrEmpty(actionId)) - { - int hash = Helper.GetInternalActionId(actionId).GetHashCode(); - responseActionId = Helper.StripInternalActionId(actionId); - responseHandler = GetRemoveResponseHandler(hash); + if (!string.IsNullOrEmpty(actionId)) + { + int hash = Helper.GetInternalActionId(actionId).GetHashCode(); + responseActionId = Helper.StripInternalActionId(actionId); + responseHandler = GetRemoveResponseHandler(hash); - if (response != null) - response.ActionId = responseActionId; - if (responseHandler != null) - { - if (response == null) - { - ManagerActionResponse action = responseHandler.Action as ManagerActionResponse; - if (action == null || (response = action.ActionCompleteResponseClass() as ManagerResponse) == null) - response = Helper.BuildResponse(buffer); - else - Helper.SetAttributes(response, buffer); - response.ActionId = responseActionId; - } + if (response != null) + response.ActionId = responseActionId; + if (responseHandler != null) + { + if (response == null) + { + ManagerActionResponse action = responseHandler.Action as ManagerActionResponse; + if (action == null || (response = action.ActionCompleteResponseClass() as ManagerResponse) == null) + response = Helper.BuildResponse(buffer); + else + Helper.SetAttributes(response, buffer); + response.ActionId = responseActionId; + } - try - { - responseHandler.HandleResponse(response); - } - catch (Exception ex) - { + try + { + responseHandler.HandleResponse(response); + } + catch (Exception ex) + { #if LOGGER - logger.Error("Unexpected exception in responseHandler {0}\n{1}", response, ex); + logger.Error("Unexpected exception in responseHandler {0}\n{1}", response, ex); #else throw new ManagerException("Unexpected exception in responseHandler " + responseHandler.GetType().FullName, ex); #endif - } - } - } - - if (response == null && buffer.ContainsKey("ping") && buffer["ping"] == "Pong") - { - response = Helper.BuildResponse(buffer); - foreach (ResponseHandler pingHandler in pingHandlers.Values) - pingHandler.HandleResponse(response); - pingHandlers.Clear(); - } + } + } + } - if (!reconnected) - return; + if (response == null && buffer.ContainsKey("ping") && buffer["ping"] == "Pong") + { + response = Helper.BuildResponse(buffer); + foreach (ResponseHandler pingHandler in pingHandlers.Values) + pingHandler.HandleResponse(response); + pingHandlers.Clear(); + } - if (response == null) - { - response = Helper.BuildResponse(buffer); - response.ActionId = responseActionId; - } + if (!reconnected) + return; + + if (response == null) + { + response = Helper.BuildResponse(buffer); + response.ActionId = responseActionId; + } #if LOGGER - logger.Info("Reconnected - DispatchEvent : " + response); + logger.Info("Reconnected - DispatchEvent : " + response); #endif - #region Support background reconnect - if (response is ChallengeResponse) - { - string key = null; - if (response.IsSuccess()) - { - ChallengeResponse challengeResponse = (ChallengeResponse)response; - string challenge = challengeResponse.Challenge; - try - { - Util.MD5Support md = Util.MD5Support.GetInstance(); - if (challenge != null) - md.Update(UTF8Encoding.UTF8.GetBytes(challenge)); - if (password != null) - md.Update(UTF8Encoding.UTF8.GetBytes(password)); - key = Helper.ToHexString(md.DigestData); - } + #region Support background reconnect + if (response is ChallengeResponse) + { + string key = null; + if (response.IsSuccess()) + { + ChallengeResponse challengeResponse = (ChallengeResponse)response; + string challenge = challengeResponse.Challenge; + try + { + Util.MD5Support md = Util.MD5Support.GetInstance(); + if (challenge != null) + md.Update(UTF8Encoding.UTF8.GetBytes(challenge)); + if (password != null) + md.Update(UTF8Encoding.UTF8.GetBytes(password)); + key = Helper.ToHexString(md.DigestData); + } #if LOGGER - catch (Exception ex) - { - logger.Error("Unable to create login key using MD5 Message Digest", ex); + catch (Exception ex) + { + logger.Error("Unable to create login key using MD5 Message Digest", ex); #else catch { #endif - key = null; - } - } - bool fail = true; - if (!string.IsNullOrEmpty(key)) - try - { - Action.LoginAction loginAction = new Action.LoginAction(username, "MD5", key); - SendAction(loginAction, null); - fail = false; - } - catch { } - if (fail) - if (keepAliveAfterAuthenticationFailure) - reconnect(true); - else - disconnect(true); - } - else if (response is ManagerError) - { - if (keepAliveAfterAuthenticationFailure) - reconnect(true); - else - disconnect(true); - } - else if (response is ManagerResponse) - { - if (response.IsSuccess()) - { - reconnected = false; - enableEvents = true; - reconnectEnable = keepAlive; - ConnectEvent ce = new ConnectEvent(this); - ce.Reconnect = true; - ce.ProtocolIdentifier = protocolIdentifier; - fireEvent(ce); - } - else if (keepAliveAfterAuthenticationFailure) - reconnect(true); - else - disconnect(true); - } - #endregion - } - #endregion + key = null; + } + } + bool fail = true; + if (!string.IsNullOrEmpty(key)) + try + { + Action.LoginAction loginAction = new Action.LoginAction(username, "MD5", key); + SendAction(loginAction, null); + fail = false; + } + catch { } + if (fail) + if (keepAliveAfterAuthenticationFailure) + reconnect(true); + else + disconnect(true); + } + else if (response is ManagerError) + { + if (keepAliveAfterAuthenticationFailure) + reconnect(true); + else + disconnect(true); + } + else if (response is ManagerResponse) + { + if (response.IsSuccess()) + { + reconnected = false; + enableEvents = true; + reconnectEnable = keepAlive; + ConnectEvent ce = new ConnectEvent(this); + ce.Reconnect = true; + ce.ProtocolIdentifier = protocolIdentifier; + fireEvent(ce); + } + else if (keepAliveAfterAuthenticationFailure) + reconnect(true); + else + disconnect(true); + } + #endregion + } + #endregion - #region DispatchEvent(...) - /// - /// This method is called by the reader whenever a ManagerEvent is received. - /// The event is dispatched to all registered ManagerEventHandlers. - /// - /// the event received by the reader - /// - internal void DispatchEvent(Dictionary buffer) - { - ManagerEvent e = Helper.BuildEvent(registeredEventClasses, this, buffer); - DispatchEvent(e); - } + #region DispatchEvent(...) + /// + /// This method is called by the reader whenever a ManagerEvent is received. + /// The event is dispatched to all registered ManagerEventHandlers. + /// + /// the event received by the reader + /// + internal void DispatchEvent(Dictionary buffer) + { + ManagerEvent e = Helper.BuildEvent(registeredEventClasses, this, buffer); + DispatchEvent(e); + } - internal void DispatchEvent(ManagerEvent e) - { + internal void DispatchEvent(ManagerEvent e) + { #if LOGGER - logger.Debug("Dispatching event: {0}", e); + logger.Debug("Dispatching event: {0}", e); #endif - if (e is ResponseEvent) - { - ResponseEvent responseEvent = (ResponseEvent)e; - if (!string.IsNullOrEmpty(responseEvent.ActionId) && !string.IsNullOrEmpty(responseEvent.InternalActionId)) - { - ResponseEventHandler eventHandler = (ResponseEventHandler)GetResponseEventHandler(responseEvent.InternalActionId.GetHashCode()); - if (eventHandler != null) - try - { - eventHandler.HandleEvent(e); - } - catch (SystemException ex) - { + if (e is ResponseEvent) + { + ResponseEvent responseEvent = (ResponseEvent)e; + if (!string.IsNullOrEmpty(responseEvent.ActionId) && !string.IsNullOrEmpty(responseEvent.InternalActionId)) + { + ResponseEventHandler eventHandler = (ResponseEventHandler)GetResponseEventHandler(responseEvent.InternalActionId.GetHashCode()); + if (eventHandler != null) + try + { + eventHandler.HandleEvent(e); + } + catch (SystemException ex) + { #if LOGGER - logger.Error("Unexpected exception", ex); + logger.Error("Unexpected exception", ex); #else throw ex; #endif - } - } - } + } + } + } - #region ConnectEvent - if (e is ConnectEvent) - { - string protocol = ((ConnectEvent)e).ProtocolIdentifier; + #region ConnectEvent + if (e is ConnectEvent) + { + string protocol = ((ConnectEvent)e).ProtocolIdentifier; #if LOGGER - logger.Info("Connected via {0}", protocol); + logger.Info("Connected via {0}", protocol); #endif - if (!string.IsNullOrEmpty(protocol) && protocol.StartsWith("Asterisk Call Manager")) - { - this.protocolIdentifier = protocol; - } - else - { - this.protocolIdentifier = (string.IsNullOrEmpty(protocol) ? "Empty" : protocol); + if (!string.IsNullOrEmpty(protocol) && protocol.StartsWith("Asterisk Call Manager")) + { + this.protocolIdentifier = protocol; + } + else + { + this.protocolIdentifier = (string.IsNullOrEmpty(protocol) ? "Empty" : protocol); #if LOGGER - logger.Warning("Unsupported protocol version '{0}'. Use at your own risk.", protocol); + logger.Warning("Unsupported protocol version '{0}'. Use at your own risk.", protocol); #endif - } - if (reconnected) - { + } + if (reconnected) + { #if LOGGER - logger.Info("Send Challenge action."); + logger.Info("Send Challenge action."); #endif - ChallengeAction challengeAction = new ChallengeAction(); - try - { - SendAction(challengeAction, null); - } + ChallengeAction challengeAction = new ChallengeAction(); + try + { + SendAction(challengeAction, null); + } #if LOGGER - catch(Exception ex) - { - logger.Info("Send Challenge fail : ", ex.Message); + catch (Exception ex) + { + logger.Info("Send Challenge fail : ", ex.Message); #else catch { #endif - disconnect(true); - } - return; - } - } - #endregion + disconnect(true); + } + return; + } + } + #endregion - if (reconnected && e is DisconnectEvent) - { - ((DisconnectEvent)e).Reconnect = true; - fireEvent(e); - reconnect(false); - } - else if (!reconnected && reconnectEnable && (e is DisconnectEvent || e is ReloadEvent || e is ShutdownEvent)) - { - ((ConnectionStateEvent)e).Reconnect = true; - fireEvent(e); - reconnect(true); - } - else - fireEvent(e); - } + if (reconnected && e is DisconnectEvent) + { + ((DisconnectEvent)e).Reconnect = true; + fireEvent(e); + reconnect(false); + } + else if (!reconnected && reconnectEnable && (e is DisconnectEvent || e is ShutdownEvent)) + { + ((ConnectionStateEvent)e).Reconnect = true; + fireEvent(e); + reconnect(true); + } + else + fireEvent(e); + } - private void eventComplete(IAsyncResult result) - { - } + private void eventComplete(IAsyncResult result) + { + } - private void fireEvent(ManagerEvent e) - { - if (enableEvents && internalEvent != null) - if(UseASyncEvents) - internalEvent.BeginInvoke(this, e, new AsyncCallback(eventComplete), null); + private void fireEvent(ManagerEvent e) + { + if (enableEvents && internalEvent != null) + if (UseASyncEvents) + Task.Run(() => internalEvent.Invoke(this, e)).ContinueWith(eventComplete); else internalEvent.Invoke(this, e); - } - #endregion - } + } + + /// + /// This method is called when send event to client if subscribed + /// + /// EventHandler argument + /// Event delegate + /// ManagerEvent or inherited class. Argument of eventHandler. + private bool fireEvent(EventHandler asterEvent, ManagerEvent arg) where T : ManagerEvent + { + if (asterEvent != null) + { + asterEvent(this, (T)arg); + return true; + } + + return false; + } + #endregion + } } diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs index 2f33f40..5766855 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs @@ -273,11 +273,10 @@ namespace AsterNET.Manager if (processingCommandResult) { string lineLower = line.ToLower(Helper.CultureInfo); - if (lineLower == "--end command--") + if (lineLower == "--end command--" || lineLower == "") { var commandResponse = new CommandResponse(); Helper.SetAttributes(commandResponse, packet); - commandList.Add(line); commandResponse.Result = commandList; processingCommandResult = false; packet.Clear(); @@ -308,11 +307,11 @@ namespace AsterNET.Manager mrConnector.DispatchEvent(connectEvent); continue; } - if (line.Trim().ToLower(Helper.CultureInfo) == "response: follows") + if (line.Trim().ToLower(Helper.CultureInfo) == "response: follows" + || line.Trim().ToLower(Helper.CultureInfo).EndsWith("command output follows")) { - // Switch to wait "--END COMMAND--" mode + // Switch to wait "--END COMMAND--"/"" mode processingCommandResult = true; - packet.Clear(); commandList.Clear(); Helper.AddKeyValue(packet, line); continue; diff --git a/Asterisk.2013/Asterisk.NET/Manager/Originate.cs b/Asterisk.2013/Asterisk.NET/Manager/Originate.cs index 426ff66..d66a91e 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Originate.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Originate.cs @@ -2,6 +2,11 @@ using System.Collections.Generic; namespace AsterNET.Manager { + /// + /// Originates an outbound call and connects it to a specified extension or application.
+ /// It will block until the outgoing call fails or gets answered.
+ /// At that point, it will exit with the status variable set and dialplan processing will continue. + ///
public class Originate { private string account; @@ -18,9 +23,8 @@ namespace AsterNET.Manager #region Account /// - /// Get/Set the account code to use for the originated call. - /// The account code is included in the call detail record generated for this - /// call and will be used for billing. + /// Get/Set the account code to use for the originated call.
+ /// The account code is included in the call detail record generated for this call and will be used for billing. ///
public string Account { @@ -60,7 +64,7 @@ namespace AsterNET.Manager #region Context /// - /// Get/Set the name of the context of the extension to connect to. + /// Get/Set the name of the context of the extension to connect to.
/// If you set the context you also have to set the exten and priority properties. ///
public string Context @@ -74,7 +78,7 @@ namespace AsterNET.Manager #region Exten /// - /// Get/Set the extension to connect to. + /// Get/Set the extension to connect to.
/// If you set the extension you also have to set the context and priority properties. ///
public string Exten @@ -88,8 +92,8 @@ namespace AsterNET.Manager #region Priority /// - /// Get/Set the priority of the extension to connect to. If you set the priority - /// you also have to set the context and exten properties. + /// Get/Set the priority of the extension to connect to.
+ /// If you set the priority you also have to set the context and exten properties. ///
public int Priority { @@ -129,8 +133,7 @@ namespace AsterNET.Manager /// /// Get/Set the timeout for the origination (in seconds) for the origination.
- /// The channel must be answered within this time, otherwise the origination - /// is considered to have failed and an OriginateFailureEvent is generated.
+ /// The channel must be answered within this time, otherwise the origination is considered to have failed and an OriginateFailureEvent is generated.
/// If not set, a default value of 30 seconds. ///
public long Timeout diff --git a/Asterisk.2013/Asterisk.NET/Manager/ResponseEventHandler.cs b/Asterisk.2013/Asterisk.NET/Manager/ResponseEventHandler.cs index 2ada508..87e8cdc 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ResponseEventHandler.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ResponseEventHandler.cs @@ -6,7 +6,7 @@ using AsterNET.Manager.Response; namespace AsterNET.Manager { /// - /// A combinded event and response handler that adds received events and the response to a ResponseEvents object. + /// A combined event and response handler that adds received events and the response to a ResponseEvents object. /// public class ResponseEventHandler : IResponseHandler { @@ -17,11 +17,11 @@ namespace AsterNET.Manager private int hash; /// - /// Creates a new instance. + /// Creates a new instance. /// - /// the ResponseEvents to store the events in - /// the type of event that indicates that all events have been received - /// the thread to interrupt when the actionCompleteEventClass has been received + /// + /// + /// public ResponseEventHandler(ManagerConnection connection, ManagerActionEvent action, AutoResetEvent autoEvent) { this.connection = connection; @@ -30,22 +30,34 @@ namespace AsterNET.Manager this.autoEvent = autoEvent; } + /// + /// Gets the response events. + /// public ResponseEvents ResponseEvents { get { return events; } } + /// + /// Gets the action. + /// public ManagerAction Action { get { return action; } } + /// + /// Gets or sets the hash. + /// public int Hash { get { return hash; } set { hash = value; } } + /// + /// Frees this instance. + /// public void Free() { connection = null; @@ -56,6 +68,10 @@ namespace AsterNET.Manager events = null; } + /// + /// This method is called when a response is received. + /// + /// public void HandleResponse(ManagerResponse response) { events.Response = response; @@ -66,6 +82,10 @@ namespace AsterNET.Manager autoEvent.Set(); } + /// + /// Handles the event. + /// + /// public void HandleEvent(ManagerEvent e) { // should always be a ResponseEvent, anyway... diff --git a/Asterisk.2013/Asterisk.NET/Manager/ResponseEvents.cs b/Asterisk.2013/Asterisk.NET/Manager/ResponseEvents.cs index 0d2b1db..c0836b7 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ResponseEvents.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ResponseEvents.cs @@ -12,29 +12,37 @@ namespace AsterNET.Manager { private readonly List events; - /// Creates a new instance. + /// + /// Creates a new . + /// public ResponseEvents() { events = new List(); Complete = false; } + /// + /// Gets or sets the response. + /// public ManagerResponse Response { get; set; } + /// + /// Gets the list of events. + /// public List Events { get { return events; } } /// - /// Indicats if all events have been received. + /// Indicates if all events have been received. /// public bool Complete { get; set; } /// /// Adds a ResponseEvent that has been received. /// - /// the ResponseEvent that has been received. + /// public void AddEvent(ResponseEvent e) { lock (((IList) events).SyncRoot) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ResponseHandler.cs b/Asterisk.2013/Asterisk.NET/Manager/ResponseHandler.cs index a0f1013..bdeb634 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ResponseHandler.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ResponseHandler.cs @@ -15,10 +15,10 @@ namespace AsterNET.Manager private ManagerResponse response; /// - /// Creates a new instance. + /// Creates a new . /// - /// the result to store the response in - /// the thread to interrupt when the response has been received + /// + /// public ResponseHandler(ManagerAction action, AutoResetEvent autoEvent) { response = null; @@ -26,22 +26,34 @@ namespace AsterNET.Manager this.autoEvent = autoEvent; } + /// + /// Gets the response. + /// public ManagerResponse Response { get { return this.response; } } + /// + /// Gets the action. + /// public ManagerAction Action { get { return this.action; } } + /// + /// Gets or sets the hash. + /// public int Hash { get { return hash; } set { hash = value; } } + /// + /// Frees this instance. + /// public void Free() { autoEvent = null; @@ -49,6 +61,10 @@ namespace AsterNET.Manager response = null; } + /// + /// This method is called when a response is received. + /// + /// the response received public virtual void HandleResponse(ManagerResponse response) { this.response = response; diff --git a/Asterisk.2013/Asterisk.NET/Manager/ResponseHandlers/TaskResponseHandler.cs b/Asterisk.2013/Asterisk.NET/Manager/ResponseHandlers/TaskResponseHandler.cs new file mode 100644 index 0000000..7d09607 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/ResponseHandlers/TaskResponseHandler.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using AsterNET.Manager.Action; + +namespace AsterNET.Manager.Response +{ + /// + /// + /// + public class TaskResponseHandler : IResponseHandler + { + public TaskResponseHandler(ManagerAction action) + { + TaskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + Action = action; + } + + public TaskCompletionSource TaskCompletionSource { get; } + + public ManagerAction Action { get; } + + public int Hash { get; set; } + + public void HandleResponse(ManagerResponse response) + { + TaskCompletionSource.TrySetResult(response); + } + + public void Free() { } + } +} diff --git a/Asterisk.2013/Documentation/Documentation.shfbproj b/Asterisk.2013/Documentation/Documentation.shfbproj index 513d87e..4bc17dc 100644 --- a/Asterisk.2013/Documentation/Documentation.shfbproj +++ b/Asterisk.2013/Documentation/Documentation.shfbproj @@ -7,7 +7,7 @@ AnyCPU 2.0 186124f7-82fa-4562-8b87-33d53a84e8ba - 1.9.9.0 + 2017.9.26.0 Documentation Documentation @@ -49,16 +49,17 @@ AboveNamespaces -AsterNet -AsterNet FastAGI -AsterNet FastAGI Command -AsterNet FastAGI Mapping Strategies -AsterNet IO -AsterNet Manager -AsterNet Manager Action -AsterNet Manager Event -AsterNet Manager Response -AsterNet Util + AsterNet + AsterNet FastAGI + AsterNet FastAGI Command + AsterNet FastAGI Mapping Strategies + AsterNet IO + AsterNet Manager + AsterNet Manager Action + AsterNet Manager Event + AsterNet Manager Response + AsterNet Util + AsterNET is an open source .NET framework for Asterisk AMI and FastAGI. AsterNET allows you to talk to Asterisk AMI from any .NET application and create FastAGI applications in any .NET language. http://www.xdev.net/projects/asternet/ diff --git a/README.md b/README.md index b0ac189..e3cfe68 100644 --- a/README.md +++ b/README.md @@ -7,21 +7,27 @@ AsterNET is an open source framework for Asterisk AMI and FastAGI. AsterNET allo AsterNET is made up of two key components, FastAGI and Manager Interface. Each allows you to interact with Asterisk in different ways. FastAGI allows you to control the flow of a call from another machine (a dedicated AGI server for example) and Manager Interface allows you to obtain state information and interact with Asterisk. ## AsterNET on IRC -Join in the conversation on Freenode, #asternet +Join in the conversation on Freenode, [#asternet](https://webchat.freenode.net/?channels=asternet) ## How to Get AsterNET -You can now get AsterNET via nuget by doing +- Download a release: https://github.com/AsterNET/AsterNET/releases + +- Download the latest source code from GitHub project + +- Download via NuGet: > PM> Install-Package AsterNET or by visiting: https://www.nuget.org/packages/AsterNET/ ## Documentation -[http://asternet.github.io/AsterNET](http://asternet.github.io/AsterNET/html/79b6241e-05a3-441c-b6a1-51f2b5b7f265.htm) +- [AsterNET Documentation](http://asternet.github.io/AsterNET) + +- [Official Asterisk Documentation](https://wiki.asterisk.org/wiki/display/AST/Asterisk+14+Documentation) ## History AsterNET is a fork of Asterisk.NET. Now we've reached release status and AsterNET version 1.0.0 we feel this is a good separation point from the original project. -*Special Thanks* +## Special Thanks http://www.zapappi.com and http://www.jetbrains.com/resharper/ We'd like to thank JetBrains for our community licenses of ReShaper. A very useful tool that's helping us to refactor the code and improve general development much quicker. If you'd like to try it yourself, visit http://www.jetbrains.com