From 5e738cdd3cf5f95e00b2dae1c729d6cedb90d9d4 Mon Sep 17 00:00:00 2001 From: zsender Date: Wed, 5 Apr 2017 08:32:55 +0300 Subject: [PATCH 01/52] Used EventHandler delegate because the event signature is the same for all. Changed the call of the event so that the indexes are not used. Action allows you to use the delegate value at the current real time --- .../Asterisk.NET.Test/Program.cs | 10 +- .../Asterisk.NET.WinForm/FormMain.cs | 2 +- Asterisk.2013/Asterisk.NET/Helper.cs | 11 +- .../Asterisk.NET/Manager/ManagerConnection.cs | 3709 +++++++---------- 4 files changed, 1545 insertions(+), 2187 deletions(-) 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..d39c86e 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 += dam_UserEvents; // Dont't display this event - manager.NewExten += new NewExtenEventHandler(manager_IgnoreEvent); + manager.NewExten += manager_IgnoreEvent; // Display all other - manager.UnhandledEvent += new ManagerEventHandler(dam_Events); + manager.UnhandledEvent += 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 = 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 = dam_Link; manager.Link += le; while (monitorChannel == null) { diff --git a/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs b/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs index 0ebcbb5..89dcec4 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 += manager_Events; try { // Uncomment next 2 line comments to Disable timeout (debug mode) diff --git a/Asterisk.2013/Asterisk.NET/Helper.cs b/Asterisk.2013/Asterisk.NET/Helper.cs index 80c9830..8d2ff60 100644 --- a/Asterisk.2013/Asterisk.NET/Helper.cs +++ b/Asterisk.2013/Asterisk.NET/Helper.cs @@ -872,14 +872,15 @@ namespace AsterNET #endregion - #region RegisterEventHandler(Dictionary list, int index, Type eventType) + #region RegisterEventHandler(Dictionary> list, Type eventType, Action action) - internal static void RegisterEventHandler(Dictionary list, int index, Type eventType) + internal static void RegisterEventHandler(Dictionary> list, Type eventType, Action 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 diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index cd594b1..d3dd4be 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -15,1566 +15,917 @@ using AsterNET.Util; 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); - - - - #endregion - /// /// Default implemention 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 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 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 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; + /// + /// 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 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 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 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 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 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/Reload/Shutdown events. + /// + public event EventHandler ConnectionState; - /// - /// When a variable is set - /// - public event VarSetEventHandler VarSet; + /// + /// When a variable is set + /// + public event EventHandler VarSet; - /// - /// AgiExec is execute - /// - public event AGIExecHandler AGIExec; + /// + /// AgiExec is execute + /// + public event EventHandler AGIExec; - /// - /// This event is sent when the first user requests a conference and it is instantiated - /// - public event ConfbridgeStartEventHandler ConfbridgeStart; + /// + /// 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 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 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 a user leaves a conference. - /// - public event ConfbridgeLeaveEventHandler ConfbridgeLeave; + /// + /// This event is sent when a user leaves a conference. + /// + public event EventHandler ConfbridgeLeave; - /// - /// 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 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 ConfbridgeTalkingEventHandler ConfbridgeTalking; + /// + /// This event is sent when the conference detects that a user has either begin or stopped talking. + /// + public event EventHandler ConfbridgeTalking; /// /// /// - 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; + public event EventHandler QueueMemberPause; #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(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, 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(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(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(ParkedCallsComplete, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(PeerEntryEvent), arg => fireEvent(ParkedCallTimeOut, 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, 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(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, 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(ConnectEvent), arg => fireEvent(ConnectionState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(DisconnectEvent), arg => fireEvent(ConnectionState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ReloadEvent), arg => fireEvent(ConnectionState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ShutdownEvent), arg => fireEvent(ConnectionState, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, 63, typeof(BridgeEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 64, typeof(TransferEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 65, typeof(DTMFEvent)); + 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, 70, typeof(VarSetEvent)); - Helper.RegisterEventHandler(registeredEventHandlers, 80, typeof(AGIExecEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(VarSetEvent), arg => fireEvent(VarSet, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(AGIExecEvent), arg => fireEvent(AGIExec, 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, 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, 86, typeof(FailedACLEvent)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(FailedACLEvent), arg => fireEvent(FailedACL, arg)); - 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, 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)); #endregion - this.internalEvent += new ManagerEventHandler(internalEventHandler); - } - #endregion + this.internalEvent += new EventHandler(internalEventHandler); - #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 + } + #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) + /// + /// 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 - /// - /// 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 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 CallerThread - internal Thread CallerThread - { - get { return callerThread; } - } - #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; } + } - #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 CallerThread + internal Thread CallerThread + { + get { return callerThread; } + } + #endregion - 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; - default: - if (UnhandledEvent != null) - UnhandledEvent(this, e); - return; - } - } - if (fireAllEvents && UnhandledEvent != null) - UnhandledEvent(this, e); - } - #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]; + currentEvent(e); + } + else + { + fireEvent(UnhandledEvent, e); + } - #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 + if (fireAllEvents) + fireEvent(UnhandledEvent, e); + } + #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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 SocketEncoding - /// - /// Socket Encoding - default ASCII - /// - public Encoding SocketEncoding - { - get { return socketEncoding; } - set { socketEncoding = 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 Version - public string Version - { - get { return version; } - } - #endregion + #region SocketEncoding + /// + /// Socket Encoding - default ASCII + /// + public Encoding SocketEncoding + { + get { return socketEncoding; } + set { socketEncoding = value; } + } + #endregion - #region AsteriskVersion - public AsteriskVersion AsteriskVersion - { - get { return asteriskVersion; } - } - #endregion + #region Version + public string Version + { + get { return version; } + } + #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) - { + #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); - ce.ProtocolIdentifier = this.protocolIdentifier; - DispatchEvent(ce); - } - else if (response is ManagerError) - throw new ManagerException("Unable login to Asterisk - " + response.Message); - else - throw new ManagerException("Unknown response during login to Asterisk - " + response.GetType().Name + " with message " + response.Message); + enableEvents = true; + ConnectEvent ce = new ConnectEvent(this); + ce.ProtocolIdentifier = this.protocolIdentifier; + DispatchEvent(ce); + } + else if (response is ManagerError) + throw new ManagerException("Unable login to Asterisk - " + response.Message); + else + throw new ManagerException("Unknown response during login to Asterisk - " + response.GetType().Name + " with message " + response.Message); - } - #endregion + } + #endregion - #region determineVersion() - protected internal AsteriskVersion determineVersion() - { - Response.ManagerResponse response; - response = SendAction(new Action.CommandAction("core show version"), defaultResponseTimeout * 2); - if (response is Response.CommandResponse) - { - foreach (string line in ((Response.CommandResponse)response).Result) - { - foreach (Match m in Common.ASTERISK_VERSION.Matches(line)) - { - if (m.Groups.Count >= 2) - { - version = m.Groups[1].Value; + #region determineVersion() + protected internal AsteriskVersion determineVersion() + { + Response.ManagerResponse response; + response = SendAction(new Action.CommandAction("core show version"), defaultResponseTimeout * 2); + if (response is Response.CommandResponse) + { + foreach (string line in ((Response.CommandResponse)response).Result) + { + foreach (Match m in Common.ASTERISK_VERSION.Matches(line)) + { + if (m.Groups.Count >= 2) + { + version = m.Groups[1].Value; if (version.StartsWith("1.4.")) { VAR_DELIMITER = new char[] { '|' }; @@ -1612,56 +963,56 @@ namespace AsterNET.Manager } else throw new ManagerException("Unknown Asterisk version " + version); - } - } - } - } + } + } + } + } - Response.ManagerResponse showVersionFilesResponse = SendAction(new Action.CommandAction("show version files"), defaultResponseTimeout * 2); - if (showVersionFilesResponse is Response.CommandResponse) - { - IList showVersionFilesResult = ((Response.CommandResponse)showVersionFilesResponse).Result; - if (showVersionFilesResult != null && showVersionFilesResult.Count > 0) - { - string line1; - line1 = (string)showVersionFilesResult[0]; - if (line1 != null && line1.StartsWith("File")) - return AsteriskVersion.ASTERISK_1_2; - } - } - return AsteriskVersion.ASTERISK_1_0; - } + Response.ManagerResponse showVersionFilesResponse = SendAction(new Action.CommandAction("show version files"), defaultResponseTimeout * 2); + if (showVersionFilesResponse is Response.CommandResponse) + { + IList showVersionFilesResult = ((Response.CommandResponse)showVersionFilesResponse).Result; + if (showVersionFilesResult != null && showVersionFilesResult.Count > 0) + { + string line1; + line1 = (string)showVersionFilesResult[0]; + if (line1 != null && line1.StartsWith("File")) + return AsteriskVersion.ASTERISK_1_2; + } + } + return AsteriskVersion.ASTERISK_1_0; + } - #endregion + #endregion - #region connect() - protected internal bool connect() - { - bool result = false; - bool startReader = false; + #region connect() + protected internal bool connect() + { + bool result = false; + bool startReader = false; - lock (lockSocket) - { - if (mrSocket == null) - { + lock (lockSocket) + { + 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 + { + 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 { #endif - result = false; - } + result = false; + } if (result) { if (mrReader == null) @@ -1682,862 +1033,868 @@ 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) + public int SendAction(ManagerAction action, ResponseHandler 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) + 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."); + #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."); + if (mrSocket == null) + throw new SystemException("Unable to send " + action.Action + " action: not connected."); - AutoResetEvent autoEvent = new AutoResetEvent(false); - ResponseEventHandler handler = new ResponseEventHandler(this, action, autoEvent); + AutoResetEvent autoEvent = new AutoResetEvent(false); + ResponseEventHandler handler = new ResponseEventHandler(this, action, autoEvent); - string internalActionId = createInternalActionId(); - handler.Hash = internalActionId.GetHashCode(); - AddResponseHandler(handler); - AddResponseEventHandler(handler); + string internalActionId = createInternalActionId(); + handler.Hash = internalActionId.GetHashCode(); + AddResponseHandler(handler); + AddResponseEventHandler(handler); - SendToAsterisk(action, internalActionId); + SendToAsterisk(action, internalActionId); - bool result = autoEvent.WaitOne(timeout <= 0 ? -1 : timeout, true); + bool result = autoEvent.WaitOne(timeout <= 0 ? -1 : timeout, true); - RemoveResponseHandler(handler); - RemoveResponseEventHandler(handler); + RemoveResponseHandler(handler); + RemoveResponseEventHandler(handler); - if (result) - return handler.ResponseEvents; + if (result) + return handler.ResponseEvents; - throw new EventTimeoutException("Timeout waiting for response or response events to " + action.Action, handler.ResponseEvents); - } - #endregion + throw new EventTimeoutException("Timeout waiting for response or response events to " + action.Action, handler.ResponseEvents); + } + #endregion - #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; - } - } + #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 void AddResponseEventHandler(IResponseHandler handler) - { - lock (lockHandlers) - responseEventHandlers[handler.Hash] = handler; - } + private void AddResponseEventHandler(IResponseHandler handler) + { + lock (lockHandlers) + responseEventHandlers[handler.Hash] = handler; + } - internal void RemoveResponseHandler(IResponseHandler handler) - { - int hash = handler.Hash; - if (hash != 0) - lock (lockHandlers) - if (responseHandlers.ContainsKey(hash)) - responseHandlers.Remove(hash); - } + internal void RemoveResponseHandler(IResponseHandler handler) + { + int hash = handler.Hash; + if (hash != 0) + lock (lockHandlers) + if (responseHandlers.ContainsKey(hash)) + responseHandlers.Remove(hash); + } - internal void RemoveResponseEventHandler(IResponseHandler handler) - { - int hash = handler.Hash; - if (hash != 0) - lock (lockHandlers) - if (responseEventHandlers.ContainsKey(hash)) - responseEventHandlers.Remove(hash); - } + 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; - } + 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; + } - 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 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 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 + 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) + #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"); + 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); + 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) + { + 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 ReloadEvent || 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) + internalEvent.BeginInvoke(this, e, new AsyncCallback(eventComplete), null); else internalEvent.Invoke(this, e); - } - #endregion - } + } + + private void fireEvent(EventHandler astEvent, ManagerEvent arg) where T : ManagerEvent + { + if (astEvent != null) + astEvent(this, (T)arg); + } + #endregion + } } \ No newline at end of file From d1bb4249b88e3bbe3b1e897bf335071d5335887a Mon Sep 17 00:00:00 2001 From: zsender Date: Thu, 6 Apr 2017 09:25:48 +0300 Subject: [PATCH 02/52] fix subscribe event (for better code readability) addcomment to method fireEvent --- .../Asterisk.NET.Test/Program.cs | 12 ++++---- .../Asterisk.NET.WinForm/FormMain.cs | 2 +- .../Asterisk.NET/Manager/ManagerConnection.cs | 29 ++++++++++++------- 3 files changed, 26 insertions(+), 17 deletions(-) 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 d39c86e..5d2eeeb 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 += dam_UserEvents; + manager.UserEvents += new EventHandler(dam_UserEvents); // Dont't display this event - manager.NewExten += manager_IgnoreEvent; + manager.NewExten += new EventHandler(manager_IgnoreEvent); // Display all other - manager.UnhandledEvent += dam_Events; + manager.UnhandledEvent += new EventHandler(dam_Events); // +++ Only to debug purpose manager.FireAllEvents = true; @@ -289,7 +289,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 EventHandler de = dam_Dial; - manager.Dial += de; + manager.Dial += new EventHandler(de); while (transferChannel == null) { System.Threading.Thread.Sleep(100); @@ -323,8 +323,8 @@ 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 - EventHandler le = dam_Link; - manager.Link += le; + EventHandler le = new EventHandler(dam_Link); + manager.Link += new EventHandler(le); while (monitorChannel == null) { System.Threading.Thread.Sleep(100); diff --git a/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs b/Asterisk.2013/Asterisk.NET.WinForm/FormMain.cs index 89dcec4..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 += 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/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index d3dd4be..943c8bb 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -58,7 +58,6 @@ namespace AsterNET.Manager private int reconnectCount; private Dictionary registeredEventClasses; - //private Dictionary registeredEventHandlers; private Dictionary> registeredEventHandlers; private event EventHandler internalEvent; private bool fireAllEvents = false; @@ -639,7 +638,9 @@ namespace AsterNET.Manager } if (fireAllEvents) + { fireEvent(UnhandledEvent, e); + } } #endregion @@ -1183,7 +1184,7 @@ namespace AsterNET.Manager enableEvents = true; reconnected = false; disconnect(true); - fireEvent(new DisconnectEvent(this)); + fireInternalEvent(new DisconnectEvent(this)); } } #endregion @@ -1766,7 +1767,7 @@ namespace AsterNET.Manager ConnectEvent ce = new ConnectEvent(this); ce.Reconnect = true; ce.ProtocolIdentifier = protocolIdentifier; - fireEvent(ce); + fireInternalEvent(ce); } else if (keepAliveAfterAuthenticationFailure) reconnect(true); @@ -1864,36 +1865,44 @@ namespace AsterNET.Manager if (reconnected && e is DisconnectEvent) { ((DisconnectEvent)e).Reconnect = true; - fireEvent(e); + fireInternalEvent(e); reconnect(false); } else if (!reconnected && reconnectEnable && (e is DisconnectEvent || e is ReloadEvent || e is ShutdownEvent)) { ((ConnectionStateEvent)e).Reconnect = true; - fireEvent(e); + fireInternalEvent(e); reconnect(true); } else - fireEvent(e); + fireInternalEvent(e); } private void eventComplete(IAsyncResult result) { } - private void fireEvent(ManagerEvent e) + private void fireInternalEvent(ManagerEvent e) { if (enableEvents && internalEvent != null) + { if (UseASyncEvents) internalEvent.BeginInvoke(this, e, new AsyncCallback(eventComplete), null); else internalEvent.Invoke(this, e); + } } - private void fireEvent(EventHandler astEvent, ManagerEvent arg) where T : ManagerEvent + /// + /// This method is called when send event to client if subscribed + /// + /// EventHandler argument + /// Event delegate + /// ManagerEvent or inherited class. Argument of eventHandler. + private void fireEvent(EventHandler asterEvent, ManagerEvent arg) where T : ManagerEvent { - if (astEvent != null) - astEvent(this, (T)arg); + if (asterEvent != null) + asterEvent(this, (T)arg); } #endregion } From 269ac0e5d907def5682bfba74a33fed90b00243c Mon Sep 17 00:00:00 2001 From: Nadobko Bogdan Date: Mon, 15 Jan 2018 21:03:40 +0200 Subject: [PATCH 03/52] Fixed indent of brace --- Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index 943c8bb..99660df 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -640,7 +640,7 @@ namespace AsterNET.Manager if (fireAllEvents) { fireEvent(UnhandledEvent, e); - } + } } #endregion From a4f79d68ae68805399a3ca5715ab5026cd88d036 Mon Sep 17 00:00:00 2001 From: Nadobko Bogdan Date: Mon, 15 Jan 2018 21:28:22 +0200 Subject: [PATCH 04/52] fixed of parameter name in description --- Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index 99660df..77c92e3 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -577,7 +577,7 @@ namespace AsterNET.Manager /// 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 + /// text encoding to asterisk input/output stream public ManagerConnection(string hostname, int port, string username, string password, Encoding encoding) : this() { @@ -635,6 +635,7 @@ namespace AsterNET.Manager else { fireEvent(UnhandledEvent, e); + return; } if (fireAllEvents) From 6c6f327606199d0e51d98ed7f6401dc35d1c6ea6 Mon Sep 17 00:00:00 2001 From: zsender Date: Mon, 15 Jan 2018 22:43:35 +0200 Subject: [PATCH 05/52] fixed by comment "Need to add return after this line still." --- Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index 77c92e3..15cede9 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -631,11 +631,11 @@ namespace AsterNET.Manager { var currentEvent = registeredEventHandlers[eventHash]; currentEvent(e); + return; } else { fireEvent(UnhandledEvent, e); - return; } if (fireAllEvents) From 0f61e78fe6d5985638b9a1c4a5caa2369025d7cc Mon Sep 17 00:00:00 2001 From: zsender Date: Tue, 16 Jan 2018 08:39:11 +0200 Subject: [PATCH 06/52] fixed for PR 121. Called UnhandledEvent, allows you see events that you aren't currently subscribed --- Asterisk.2013/Asterisk.NET/Helper.cs | 2 +- .../Asterisk.NET/Manager/ManagerConnection.cs | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Helper.cs b/Asterisk.2013/Asterisk.NET/Helper.cs index 8d2ff60..49bb485 100644 --- a/Asterisk.2013/Asterisk.NET/Helper.cs +++ b/Asterisk.2013/Asterisk.NET/Helper.cs @@ -874,7 +874,7 @@ namespace AsterNET #region RegisterEventHandler(Dictionary> list, Type eventType, Action action) - internal static void RegisterEventHandler(Dictionary> list, Type eventType, Action action) + internal static void RegisterEventHandler(Dictionary> list, Type eventType, Func action) { var eventTypeName = eventType.Name; int eventHash = eventTypeName.GetHashCode(); diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index 15cede9..5620d3f 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,11 +6,9 @@ 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; namespace AsterNET.Manager { @@ -58,7 +55,7 @@ namespace AsterNET.Manager private int reconnectCount; private Dictionary registeredEventClasses; - private Dictionary> registeredEventHandlers; + private Dictionary> registeredEventHandlers; private event EventHandler internalEvent; private bool fireAllEvents = false; private Thread callerThread; @@ -446,7 +443,7 @@ namespace AsterNET.Manager Helper.RegisterBuiltinEventClasses(registeredEventClasses); - registeredEventHandlers = new Dictionary>(); + registeredEventHandlers = new Dictionary>(); #region Event mapping table Helper.RegisterEventHandler(registeredEventHandlers, typeof(AgentCallbackLoginEvent), arg => fireEvent(AgentCallbackLogin, arg)); @@ -630,12 +627,10 @@ namespace AsterNET.Manager if (registeredEventHandlers.ContainsKey(eventHash)) { var currentEvent = registeredEventHandlers[eventHash]; - currentEvent(e); - return; - } - else - { - fireEvent(UnhandledEvent, e); + if (currentEvent(e)) + { + return; + } } if (fireAllEvents) @@ -1900,10 +1895,15 @@ namespace AsterNET.Manager /// EventHandler argument /// Event delegate /// ManagerEvent or inherited class. Argument of eventHandler. - private void fireEvent(EventHandler asterEvent, ManagerEvent arg) where T : ManagerEvent + private bool fireEvent(EventHandler asterEvent, ManagerEvent arg) where T : ManagerEvent { if (asterEvent != null) + { asterEvent(this, (T)arg); + return true; + } + + return false; } #endregion } From 697e2890370f27abf63523a003b90a19ccd2472d Mon Sep 17 00:00:00 2001 From: Sandro Pazzi Date: Tue, 6 Feb 2018 23:10:44 +0100 Subject: [PATCH 07/52] app_chan_agent modify some agents actions and events --- .../Manager/Action/QueueAddAction.cs | 6 ++ .../Asterisk.NET/Manager/Event/AgentsEvent.cs | 92 ++++++++++++++++++- .../Manager/Event/QueueMemberEvent.cs | 22 ++++- 3 files changed, 111 insertions(+), 9 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs index c1f2205..a0b87dd 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/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/QueueMemberEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs index ccee25b..4fd05a8 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs @@ -17,11 +17,12 @@ namespace AsterNET.Manager.Event private int status; private bool paused; private string name; + private bool incall; - /// - /// 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 +124,19 @@ 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; } + } - public QueueMemberEvent(ManagerConnection source) + public QueueMemberEvent(ManagerConnection source) : base(source) { } From 9dc2564c8a1a87ff3fa91e9946cafd3ff3b42d9b Mon Sep 17 00:00:00 2001 From: Sandro Pazzi Date: Wed, 7 Feb 2018 18:23:21 +0100 Subject: [PATCH 08/52] app_chan_agent other modify some agents events --- .../Asterisk.NET/Manager/Event/AbstractAgentEvent.cs | 9 ++++++++- .../Asterisk.NET/Manager/Event/AgentConnectEvent.cs | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) 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..35a4866 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs @@ -17,6 +17,7 @@ namespace AsterNET.Manager.Event /// /// Get/Set bridged channel. + /// Removed from Asterisk 12 /// public string BridgedChannel { get; set; } From 8d7a23269eacb70525eb0363695708015445e9ec Mon Sep 17 00:00:00 2001 From: Michael Cramer Date: Mon, 26 Mar 2018 16:10:29 -0700 Subject: [PATCH 09/52] Changed \n from string to character representation --- Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs index 98cca81..2f33f40 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs @@ -133,7 +133,7 @@ namespace AsterNET.Manager // \n - because not all dev in Digium use \r\n // .Trim() kill \r lock (((ICollection) lineQueue).SyncRoot) - while (!string.IsNullOrEmpty(mrReader.lineBuffer) && (idx = mrReader.lineBuffer.IndexOf("\n")) >= 0) + while (!string.IsNullOrEmpty(mrReader.lineBuffer) && (idx = mrReader.lineBuffer.IndexOf('\n')) >= 0) { line = idx > 0 ? mrReader.lineBuffer.Substring(0, idx).Trim() : string.Empty; mrReader.lineBuffer = (idx + 1 < mrReader.lineBuffer.Length From c855c584c8d03e14dca3c9a1ab93ea947d965d4c Mon Sep 17 00:00:00 2001 From: Deantwo Date: Mon, 25 Jun 2018 15:05:20 +0200 Subject: [PATCH 10/52] Error Waiting to Happen Changed the strange `true` to `value`. --- .../Asterisk.NET/Manager/Event/ConnectionStateEvent.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 +} From d69f7ffd642f125210177c833fc706832481bb9e Mon Sep 17 00:00:00 2001 From: zsender Date: Fri, 6 Jul 2018 00:59:19 +0300 Subject: [PATCH 11/52] Fixed PR conflicts --- .../Asterisk.NET.Test/Program.cs | 6 +- Asterisk.2013/Asterisk.NET/AsterNET.csproj | 8 ++ .../Asterisk.NET/FastAGI/AsteriskFastAGI.cs | 23 ++++- .../GeneralMappingStrategy.cs | 3 +- Asterisk.2013/Asterisk.NET/Helper.cs | 2 +- .../Asterisk.NET/IO/SocketConnection.cs | 11 ++- .../Manager/Action/FilterAction.cs | 55 ++++++++++++ .../Manager/Action/OriginateAction.cs | 2 +- .../Manager/Action/QueueSummaryAction.cs | 51 ++++++++++++ .../Manager/Event/AbstractAgentVariables.cs | 18 ++-- .../Event/ChallengeResponseFailedEvent.cs | 16 ++++ .../Manager/Event/ChallengeSentEvent.cs | 16 ++++ .../Manager/Event/DeviceStateChangeEvent.cs | 17 ++++ .../Manager/Event/InvalidAccountIDEvent.cs | 16 ++++ .../Manager/Event/QueueCallerJoinEvent.cs | 26 ++++-- .../Manager/Event/QueueCallerLeaveEvent.cs | 22 +++-- .../Manager/Event/QueueMemberAddedEvent.cs | 76 +++-------------- .../Manager/Event/QueueMemberPausedEvent.cs | 52 +++++------- .../Manager/Event/QueueMemberPenaltyEvent.cs | 11 +-- .../Manager/Event/QueueMemberRemovedEvent.cs | 28 +++---- .../Event/QueueMemberRinginuseEvent.cs | 27 +++--- .../Manager/Event/QueueMemberStatusEvent.cs | 83 +++---------------- .../Manager/Event/QueueSummaryEvent.cs | 48 +++++++++++ .../Manager/Event/SuccessfulAuthEvent.cs | 16 ++++ .../Asterisk.NET/Manager/ManagerConnection.cs | 70 +++++++++++----- README.md | 1 + 26 files changed, 433 insertions(+), 271 deletions(-) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Action/QueueSummaryAction.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeResponseFailedEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/InvalidAccountIDEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/QueueSummaryEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/SuccessfulAuthEvent.cs 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 5d2eeeb..bec6da2 100644 --- a/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/Program.cs +++ b/Asterisk.2013/Asterisk.NET.Test/Asterisk.NET.Test/Program.cs @@ -288,8 +288,8 @@ 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 - EventHandler de = dam_Dial; - manager.Dial += new EventHandler(de); + EventHandler de = new EventHandler(dam_Dial); + manager.Dial += de; while (transferChannel == null) { System.Threading.Thread.Sleep(100); @@ -324,7 +324,7 @@ Ctrl-C to exit"); Console.WriteLine("Monitor call. Please call " + ORIGINATE_CHANNEL + " and answer or press ESC."); // Wait for Link event EventHandler le = new EventHandler(dam_Link); - manager.Link += new EventHandler(le); + manager.Link += le; while (monitorChannel == null) { System.Threading.Thread.Sleep(100); diff --git a/Asterisk.2013/Asterisk.NET/AsterNET.csproj b/Asterisk.2013/Asterisk.NET/AsterNET.csproj index 7301a75..7efe675 100644 --- a/Asterisk.2013/Asterisk.NET/AsterNET.csproj +++ b/Asterisk.2013/Asterisk.NET/AsterNET.csproj @@ -167,6 +167,7 @@ + @@ -195,6 +196,7 @@ + @@ -256,6 +258,7 @@ + @@ -323,6 +326,11 @@ + + + + + diff --git a/Asterisk.2013/Asterisk.NET/FastAGI/AsteriskFastAGI.cs b/Asterisk.2013/Asterisk.NET/FastAGI/AsteriskFastAGI.cs index 8e7decf..c200a7c 100644 --- a/Asterisk.2013/Asterisk.NET/FastAGI/AsteriskFastAGI.cs +++ b/Asterisk.2013/Asterisk.NET/FastAGI/AsteriskFastAGI.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Net; using System.Text; @@ -233,13 +234,29 @@ namespace AsterNET.FastAGI var ipAddress = IPAddress.Parse(address); serverSocket = new ServerSocket(port, ipAddress, SocketEncoding); } - catch (IOException ex) + catch (Exception ex) { #if LOGGER - logger.Error("Unable start AGI Server: cannot to bind to " + address + ":" + port + ".", ex); + if (ex is IOException) + { + logger.Error("Unable start AGI Server: cannot to bind to " + address + ":" + port + ".", ex); + } #endif + + if (serverSocket != null) + { + serverSocket.Close(); + serverSocket = null; + } + + pool.Shutdown(); +#if LOGGER + logger.Info("AGI Server shut down."); +#endif + throw ex; } + #if LOGGER logger.Info("Listening on " + address + ":" + port + "."); #endif @@ -287,7 +304,7 @@ namespace AsterNET.FastAGI serverSocket = null; pool.Shutdown(); #if LOGGER - logger.Info("AGIServer shut down."); + logger.Info("AGI Server shut down."); #endif } } diff --git a/Asterisk.2013/Asterisk.NET/FastAGI/MappingStrategies/GeneralMappingStrategy.cs b/Asterisk.2013/Asterisk.NET/FastAGI/MappingStrategies/GeneralMappingStrategy.cs index 344fc94..b149ebd 100644 --- a/Asterisk.2013/Asterisk.NET/FastAGI/MappingStrategies/GeneralMappingStrategy.cs +++ b/Asterisk.2013/Asterisk.NET/FastAGI/MappingStrategies/GeneralMappingStrategy.cs @@ -47,6 +47,7 @@ namespace AsterNET.FastAGI.MappingStrategies /// public string ScriptAssmebly { get; set; } + [XmlIgnoreAttribute] public Assembly PreLoadedAssembly { get; set; } public static List LoadMappings(string pathToXml) @@ -184,4 +185,4 @@ namespace AsterNET.FastAGI.MappingStrategies } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Helper.cs b/Asterisk.2013/Asterisk.NET/Helper.cs index 49bb485..e6fc507 100644 --- a/Asterisk.2013/Asterisk.NET/Helper.cs +++ b/Asterisk.2013/Asterisk.NET/Helper.cs @@ -872,7 +872,7 @@ namespace AsterNET #endregion - #region RegisterEventHandler(Dictionary> list, Type eventType, Action action) + #region RegisterEventHandler(Dictionary list, int index, Type eventType) internal static void RegisterEventHandler(Dictionary> list, Type eventType, Func action) { diff --git a/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs b/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs index 07145ae..5df2484 100644 --- a/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs +++ b/Asterisk.2013/Asterisk.NET/IO/SocketConnection.cs @@ -11,7 +11,7 @@ namespace AsterNET.IO private TcpClient tcpClient; private NetworkStream networkStream; private StreamReader reader; - private StreamWriter writer; + private BinaryWriter writer; private Encoding encoding; private bool initial; @@ -29,8 +29,7 @@ namespace AsterNET.IO this.tcpClient = new TcpClient(host, port); this.networkStream = this.tcpClient.GetStream(); this.reader = new StreamReader(this.networkStream, encoding); - this.writer = new StreamWriter(this.networkStream, encoding); - this.writer.AutoFlush = true; + this.writer = new BinaryWriter(this.networkStream, encoding); } #endregion @@ -47,8 +46,7 @@ namespace AsterNET.IO this.tcpClient = tcpClient; this.networkStream = this.tcpClient.GetStream(); this.reader = new StreamReader(this.networkStream, encoding); - this.writer = new StreamWriter(this.networkStream, encoding); - this.writer.AutoFlush = true; + this.writer = new BinaryWriter(this.networkStream, encoding); } #endregion @@ -156,7 +154,8 @@ namespace AsterNET.IO /// connection has already been closed. public void Write(string s) { - writer.Write(s); + writer.Write(encoding.GetBytes(s)); + writer.Flush(); } #endregion 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..765f99b --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs @@ -0,0 +1,55 @@ +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 + /// + /// + public FilterAction(string filter) + { + Filter = filter; + } + + #endregion + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs index a57e46d..0dd5469 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/OriginateAction.cs @@ -159,7 +159,7 @@ namespace AsterNET.Manager.Action /// Example: "VAR1=abc|VAR2=def" sets the channel variables VAR1 to "abc" and VAR2 to "def". /// - [Obsolete("Don't use this anymore - the delimiter is not server context aware", true)] + [Obsolete("Use GetVariables and SetVariables instead.", true)] public string Variable { get { return null; /* return Helper.JoinVariables(variables, Common.GET_VAR_DELIMITER(this.Server), "="); */ } 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/Event/AbstractAgentVariables.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/AbstractAgentVariables.cs index 365dc2a..bd87013 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/AbstractAgentVariables.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AbstractAgentVariables.cs @@ -18,26 +18,26 @@ namespace AsterNET.Manager.Event /// Get/Set the variables to set on the queue call in native asterisk format.
/// Example: "VAR1=abc|VAR2=def". /// - [Obsolete("Don't use this anymore - the delimiter is not server context aware", true)] - public string Variable - { - get { return null; /* return Helper.JoinVariables(variables, Common.GET_VAR_DELIMITER(this.Server), "="); */ } - set { /* variables = Helper.ParseVariables(variables, value, Common.GET_VAR_DELIMITER(this.Server)); */ } - } + [Obsolete("Use GetVariables and SetVariables instead.", true)] + public string Variable + { + get { return null; /* return Helper.JoinVariables(variables, Common.GET_VAR_DELIMITER(this.Server), "="); */ } + set { /* variables = Helper.ParseVariables(variables, value, Common.GET_VAR_DELIMITER(this.Server)); */ } + } #endregion #region GetVariables() /// /// Get the variables dictionary to set on the originated call. /// - public Dictionary GetVariables() + public Dictionary GetVariables() { return variables; } #endregion - #region SetVariables(Dictionary vars) - /// + #region SetVariables(Dictionary vars) + /// /// Set the variables dictionary to set on the originated call. /// public void SetVariables(Dictionary vars) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeResponseFailedEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeResponseFailedEvent.cs new file mode 100644 index 0000000..170b5cb --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeResponseFailedEvent.cs @@ -0,0 +1,16 @@ +namespace AsterNET.Manager.Event +{ + + /// + /// Raised when a request's attempt to authenticate has been challenged, and the request failed the authentication challenge.
+ ///
+ public class ChallengeResponseFailedEvent : ManagerEvent +{ + public ChallengeResponseFailedEvent(ManagerConnection source) + : base(source) + { + } + + public string Status { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs new file mode 100644 index 0000000..3107bbe --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ChallengeSentEvent.cs @@ -0,0 +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; } + } +} \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs new file mode 100644 index 0000000..3ffb3df --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/DeviceStateChangeEvent.cs @@ -0,0 +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; } + } +} \ 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 new file mode 100644 index 0000000..9971054 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/InvalidAccountIDEvent.cs @@ -0,0 +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; } + } +} \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerJoinEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerJoinEvent.cs index 0416417..78e7c65 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerJoinEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerJoinEvent.cs @@ -1,15 +1,23 @@ namespace AsterNET.Manager.Event { - /// - /// A QueueCallerJoinEvent is triggered when a channel joins a queue.
- ///
- public class QueueCallerJoinEvent : QueueEvent - { - public string Position { get; set; } - - public QueueCallerJoinEvent(ManagerConnection source) + /// + /// A QueueCallerJoinEvent is triggered when a channel joins a queue.
+ ///
+ public class QueueCallerJoinEvent : JoinEvent + { + // "Channel" in ManagerEvent.cs + + // "Queue" in QueueEvent.cs + + // "CallerId" in JoinEvent.cs + + // "CallerIdName" in JoinEvent.cs + + // "Position" in JoinEvent.cs + + public QueueCallerJoinEvent(ManagerConnection source) : base(source) { } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerLeaveEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerLeaveEvent.cs index dff535a..86fc7b8 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerLeaveEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueCallerLeaveEvent.cs @@ -1,15 +1,19 @@ namespace AsterNET.Manager.Event { - /// - /// A QueueCallerLeaveEvent is triggered when a channel leaves a queue.
- ///
- public class QueueCallerLeaveEvent : QueueEvent - { - public string Position { get; set; } - - public QueueCallerLeaveEvent(ManagerConnection source) + /// + /// A QueueCallerLeaveEvent is triggered when a channel leaves a queue.
+ ///
+ public class QueueCallerLeaveEvent : LeaveEvent + { + // "Channel" in ManagerEvent.cs + + // "Queue" in QueueEvent.cs + + // "Count" in QueueEvent.cs + + public QueueCallerLeaveEvent(ManagerConnection source) : base(source) { } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberAddedEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberAddedEvent.cs index 0bd5cd9..4ee20fa 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberAddedEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberAddedEvent.cs @@ -1,73 +1,21 @@ namespace AsterNET.Manager.Event { - /// - /// A QueueMemberAddedEvent is triggered when a queue member is added to a queue.
- /// It is implemented in apps/app_queue.c.
- /// - /// Available since : Asterisk 1.2.
- ///
- ///
- public class QueueMemberAddedEvent : AbstractQueueMemberEvent + /// + /// A QueueMemberAddedEvent is triggered when a queue member is added to a queue.
+ /// It is implemented in apps/app_queue.c.
+ /// + /// Available since : Asterisk 1.2.
+ ///
+ ///
+ public class QueueMemberAddedEvent : AbstractQueueMemberEvent { /// - /// Returns the name of the member's interface.
- /// E.g. the channel name or agent group. + /// Creates a new QueueMemberAddedEvent ///
- public new string MemberName { get; set; } - - /// - /// Get/Set if the added member is a dynamic or static queue member. - /// "dynamic" if the added member is a dynamic queue member, - /// "static" if the added member is a static queue member. - /// - public new string Membership { get; set; } - - /// - /// Get/Set the penalty for the added member. When calls are distributed - /// members with higher penalties are considered last. - /// - public new int Penalty { get; set; } - - /// - /// Get/Set the number of calls answered by the member. - /// - public new int CallsTaken { get; set; } - - /// - /// Get/Set the time (in seconds since 01/01/1970) the last successful call answered by the added member was hungup. - /// - public new long LastCall { get; set; } - - /// - /// Get/Set the status of this queue member.
- /// Valid status codes are:
- /// - /// AST_DEVICE_UNKNOWN - /// AST_DEVICE_NOT_INUSE - /// AST_DEVICE_INUSE - /// AST_DEVICE_BUSY - /// AST_DEVICE_INVALID - /// AST_DEVICE_UNAVAILABLE - /// AST_DEVICE_RINGING - /// AST_DEVICE_RINGINUSE - /// AST_DEVICE_ONHOLD - /// - ///
- public new int Status { get; set; } - - /// - /// Get/Set value if this queue member is paused (not accepting calls).
- /// true if this member has been paused or false if not. - ///
- public new bool Paused { get; set; } - - /// - /// Creates a new QueueMemberAddedEvent - /// - /// ManagerConnection passed through in the event. - public QueueMemberAddedEvent(ManagerConnection source) + /// ManagerConnection passed through in the event. + public QueueMemberAddedEvent(ManagerConnection source) : base(source) { } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPausedEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPausedEvent.cs index 6d00390..1aff4ba 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPausedEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPausedEvent.cs @@ -2,39 +2,29 @@ using System; namespace AsterNET.Manager.Event { - /// - /// A QueueMemberPausedEvent is triggered when a queue member is paused or unpaused.
- /// It is implemented in apps/app_queue.c.
- /// - /// Available since : Asterisk 1.2.
- /// Replaced by : since Asterisk 12.
- /// Removed since : Asterisk 13.
- ///
- ///
+ /// + /// A QueueMemberPausedEvent is triggered when a queue member is paused or unpaused.
+ /// It is implemented in apps/app_queue.c.
+ /// + /// Available since : Asterisk 1.2.
+ /// Replaced by : since Asterisk 12.
+ /// Removed since : Asterisk 13.
+ ///
+ ///
public class QueueMemberPausedEvent : AbstractQueueMemberEvent { - /// - /// The reason a member was paused - /// - public string Reason { get; set; } - - /// - /// Not Available, use instead. - /// - public new string PausedReason { get; set; } - - /// - /// Not Available, use instead. - /// - public new bool InCall { get; set; } - - /// - /// Creates a new QueueMemberPausedEvent - /// - /// ManagerConnection passed through in the event. - public QueueMemberPausedEvent(ManagerConnection source) + /// + /// The reason a member was paused + /// + public string Reason { get; set; } + + /// + /// Creates a new QueueMemberPausedEvent + /// + /// ManagerConnection passed through in the event. + public QueueMemberPausedEvent(ManagerConnection source) : base(source) { - } + } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPenaltyEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPenaltyEvent.cs index 417c46b..8918042 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPenaltyEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberPenaltyEvent.cs @@ -6,15 +6,10 @@ namespace AsterNET.Manager.Event public class QueueMemberPenaltyEvent : AbstractQueueMemberEvent { /// - /// Get/Set the penalty for the queue location. + /// Creates a new QueueMemberPenaltyEvent /// - public new int Penalty { get; set; } - - /// - /// Creates a new QueueMemberPenaltyEvent - /// - /// ManagerConnection passed through in the event. - public QueueMemberPenaltyEvent(ManagerConnection source) + /// ManagerConnection passed through in the event. + public QueueMemberPenaltyEvent(ManagerConnection source) : base(source) { } diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRemovedEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRemovedEvent.cs index b8d424d..27182e1 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRemovedEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRemovedEvent.cs @@ -1,27 +1,21 @@ namespace AsterNET.Manager.Event { - /// - /// A QueueMemberRemovedEvent is triggered when a queue member is removed from a queue.
- /// It is implemented in apps/app_queue.c.
- /// - /// Available since : Asterisk 1.2.
- ///
- ///
- public class QueueMemberRemovedEvent : AbstractQueueMemberEvent + /// + /// A QueueMemberRemovedEvent is triggered when a queue member is removed from a queue.
+ /// It is implemented in apps/app_queue.c.
+ /// + /// Available since : Asterisk 1.2.
+ ///
+ ///
+ public class QueueMemberRemovedEvent : AbstractQueueMemberEvent { /// - /// Returns the name of the member's interface.
- /// E.g. the channel name or agent group. + /// Creates a new QueueMemberRemovedEvent ///
- public new string MemberName { get; set; } - - /// - /// Creates a new QueueMemberRemovedEvent - /// - /// ManagerConnection passed through in the event. + /// ManagerConnection passed through in the event. public QueueMemberRemovedEvent(ManagerConnection source) : base(source) { } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRinginuseEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRinginuseEvent.cs index 97a2b23..05c1c0c 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRinginuseEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberRinginuseEvent.cs @@ -1,24 +1,17 @@ namespace AsterNET.Manager.Event { - /// - /// Raised when a member's ringinuse setting is changed - /// - public class QueueMemberRinginuseEvent : AbstractQueueMemberEvent - { - - /// - /// Evaluates if Ringinuse, - /// if not.
- ///
- public new bool Ringinuse { get; set; } - - /// - /// Creates a new QueueMemberRinginuseEvent - /// - /// ManagerConnection passed through in the event. + /// + /// Raised when a member's ringinuse setting is changed + /// + public class QueueMemberRinginuseEvent : AbstractQueueMemberEvent + { + /// + /// Creates a new QueueMemberRinginuseEvent + /// + /// ManagerConnection passed through in the event. public QueueMemberRinginuseEvent(ManagerConnection source) : base(source) { } } -} \ No newline at end of file +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberStatusEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberStatusEvent.cs index fb1fce9..8cafaf7 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberStatusEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberStatusEvent.cs @@ -1,80 +1,17 @@ namespace AsterNET.Manager.Event { - /// - /// Raised when a Queue member's status has changed - /// - public class QueueMemberStatusEvent : AbstractQueueMemberEvent - { - /// - /// Returns the name of the member's interface.
- /// E.g. the channel name or agent group. - ///
- public new string MemberName { get; set; } - - /// - /// Channel technology or location from which to read device state changes.
- ///
- public new string StateInterface { get; set; } - - /// - /// Get/Set if the added member is a dynamic or static queue member. - /// "dynamic" if the added member is a dynamic queue member, - /// "static" if the added member is a static queue member. - /// - public new string Membership { get; set; } - - /// - /// Get/Set the penalty for the added member. When calls are distributed - /// members with higher penalties are considered last. - /// - public new int Penalty { get; set; } - - /// - /// Get/Set the number of calls answered by the member. - /// - public new int CallsTaken { get; set; } - - /// - /// Get/Set the time (in seconds since 01/01/1970) the last successful call answered by the added member was hungup. - /// - public new long LastCall { get; set; } - - /// - /// Evaluates if member is in call, - /// after LastCall time is updated.
- ///
- public new bool InCall { get; set; } - - /// - /// Get/Set the status of this queue member.
- /// Valid status codes are:
- /// - /// AST_DEVICE_UNKNOWN - /// AST_DEVICE_NOT_INUSE - /// AST_DEVICE_INUSE - /// AST_DEVICE_BUSY - /// AST_DEVICE_INVALID - /// AST_DEVICE_UNAVAILABLE - /// AST_DEVICE_RINGING - /// AST_DEVICE_RINGINUSE - /// AST_DEVICE_ONHOLD - /// - ///
- public new int Status { get; set; } - - /// - /// Get/Set value if this queue member is paused (not accepting calls).
- /// true if this member has been paused or false if not. - ///
- public new bool Paused { get; set; } - - /// - /// Creates a new QueueMemberStatusEvent - /// - /// ManagerConnection passed through in the event. + /// + /// Raised when a Queue member's status has changed + /// + public class QueueMemberStatusEvent : AbstractQueueMemberEvent + { + /// + /// Creates a new QueueMemberStatusEvent + /// + /// ManagerConnection passed through in the event. public QueueMemberStatusEvent(ManagerConnection source) : base(source) { } } -} \ No newline at end of file +} 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 new file mode 100644 index 0000000..32f7570 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/SuccessfulAuthEvent.cs @@ -0,0 +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; } + } +} \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index 5620d3f..d1fe667 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -196,7 +196,7 @@ namespace AsterNET.Manager /// A MeetMeLeave is triggered if a channel leaves a meet me conference.
///
public event EventHandler MeetMeLeave; - // public event MeetMeStopTalkingEventHandler MeetMeStopTalking; + // 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. @@ -222,15 +222,15 @@ namespace AsterNET.Manager /// A NewState is triggered when the state of a channel has changed.
///
public event EventHandler NewState; - // public event OriginateEventHandler Originate; + // public event EventHandler Originate; /// /// An OriginateFailure is triggered when the execution of an OriginateAction failed. /// - // public event OriginateFailureEventHandler OriginateFailure; + // public event EventHandler OriginateFailure; /// /// An OriginateSuccess is triggered when the execution of an OriginateAction succeeded. /// - // public event OriginateSuccessEventHandler OriginateSuccess; + // public event EventHandler OriginateSuccess; /// /// An OriginateResponse is triggered when the execution of an Originate. /// @@ -426,6 +426,36 @@ namespace AsterNET.Manager /// public event EventHandler QueueMemberPause; + /// + /// 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() @@ -462,7 +492,6 @@ namespace AsterNET.Manager 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)); @@ -484,8 +513,8 @@ namespace AsterNET.Manager 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(ParkedCallsComplete, arg)); - Helper.RegisterEventHandler(registeredEventHandlers, typeof(PeerEntryEvent), arg => fireEvent(ParkedCallTimeOut, 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)); @@ -540,11 +569,16 @@ namespace AsterNET.Manager 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(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 EventHandler(internalEventHandler); - } #endregion @@ -574,7 +608,7 @@ namespace AsterNET.Manager /// 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 + /// text encoding to asterisk input/output stream public ManagerConnection(string hostname, int port, string username, string password, Encoding encoding) : this() { @@ -1180,7 +1214,7 @@ namespace AsterNET.Manager enableEvents = true; reconnected = false; disconnect(true); - fireInternalEvent(new DisconnectEvent(this)); + fireEvent(new DisconnectEvent(this)); } } #endregion @@ -1763,7 +1797,7 @@ namespace AsterNET.Manager ConnectEvent ce = new ConnectEvent(this); ce.Reconnect = true; ce.ProtocolIdentifier = protocolIdentifier; - fireInternalEvent(ce); + fireEvent(ce); } else if (keepAliveAfterAuthenticationFailure) reconnect(true); @@ -1861,32 +1895,30 @@ namespace AsterNET.Manager if (reconnected && e is DisconnectEvent) { ((DisconnectEvent)e).Reconnect = true; - fireInternalEvent(e); + fireEvent(e); reconnect(false); } else if (!reconnected && reconnectEnable && (e is DisconnectEvent || e is ReloadEvent || e is ShutdownEvent)) { ((ConnectionStateEvent)e).Reconnect = true; - fireInternalEvent(e); + fireEvent(e); reconnect(true); } else - fireInternalEvent(e); + fireEvent(e); } private void eventComplete(IAsyncResult result) { } - private void fireInternalEvent(ManagerEvent e) + private void fireEvent(ManagerEvent e) { if (enableEvents && internalEvent != null) - { if (UseASyncEvents) internalEvent.BeginInvoke(this, e, new AsyncCallback(eventComplete), null); else internalEvent.Invoke(this, e); - } } /// @@ -1907,4 +1939,4 @@ namespace AsterNET.Manager } #endregion } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 4396a66..b0ac189 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Build Status](https://travis-ci.org/AsterNET/AsterNET.svg?branch=master)](https://travis-ci.org/AsterNET/AsterNET) +[![NuGet](https://img.shields.io/nuget/v/AsterNET.svg)](https://www.nuget.org/packages/AsterNET) AsterNET is an open source 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. From 84fe677d7a9b8a4eab2593a10cdff209da7dd086 Mon Sep 17 00:00:00 2001 From: zsender Date: Fri, 6 Jul 2018 08:51:03 +0300 Subject: [PATCH 12/52] Added argument "operation" in constructor --- Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs index 765f99b..b5369df 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/FilterAction.cs @@ -44,10 +44,12 @@ /// /// Add - Add a filter /// - /// - public FilterAction(string filter) + /// Add a filter + /// Filters can be whitelist or blacklist + public FilterAction(string filter, string operation = "Add") { Filter = filter; + Operation = operation; } #endregion From 2aaeeb2a40c49d51c18e189d07dc8d9a1bd3818a Mon Sep 17 00:00:00 2001 From: Deantwo Date: Tue, 10 Jul 2018 16:15:42 +0200 Subject: [PATCH 13/52] AsterNET 1.3 release (#156) --- Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs b/Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs index 7a1c035..6051534 100644 --- a/Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs +++ b/Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs @@ -11,8 +11,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: Guid("abe98502-ea83-4b04-98c3-ffe3eabe06b0")] -[assembly: AssemblyVersion("1.2.0.0")] -[assembly: AssemblyFileVersion("1.2.0.0")] +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.0")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from From ec35897ca238bddc3a4cc696c9966c5d1e974c3b Mon Sep 17 00:00:00 2001 From: Deantwo Date: Mon, 16 Jul 2018 11:05:46 +0200 Subject: [PATCH 14/52] Added Reason to QueuePauseAction Updated property documentation to match better with Asterisk doc. --- .../Manager/Action/QueuePauseAction.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs index 4ad6cf9..d462928 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 @@ -73,21 +72,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 +} From 9f3ae2d87b4f4596bb219f5649a5673dee0ecf8f Mon Sep 17 00:00:00 2001 From: Deantwo Date: Tue, 17 Jul 2018 14:31:47 +0200 Subject: [PATCH 15/52] Update README.md --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 From c2750423ac1a8b3eec5a4cedf3fec457dfa095f1 Mon Sep 17 00:00:00 2001 From: Sandro Pazzi Date: Mon, 30 Jul 2018 11:08:50 +0200 Subject: [PATCH 16/52] Updated comments for missing
--- Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs | 2 +- Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs index a0b87dd..30bcb04 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/QueueAddAction.cs @@ -96,7 +96,7 @@ namespace AsterNET.Manager.Action public bool Paused { get; set; } /// - /// Get/Set an alternate interface to be used to determine the state of the member. + /// Get/Set an alternate interface to be used to determine the state of the member.
/// Available since Asterisk 12. ///
public string StateInterface { get; set; } diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs index 35a4866..3764838 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentConnectEvent.cs @@ -16,7 +16,7 @@ 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; } From f2cf683c1fa397ae7415f55b6f4bcda26eb955f9 Mon Sep 17 00:00:00 2001 From: Gennady Pundikov Date: Tue, 14 Aug 2018 16:27:37 +0300 Subject: [PATCH 17/52] add support NetStandard2.0 --- Asterisk.2013/Asterisk.2013.sln | 9 +- Asterisk.2013/Asterisk.NET/AsterNET.csproj | 399 ++---------------- .../Asterisk.NET/Properties/AssemblyInfo.cs | 20 - 3 files changed, 37 insertions(+), 391 deletions(-) delete mode 100644 Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs 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/AsterNET.csproj b/Asterisk.2013/Asterisk.NET/AsterNET.csproj index cf51e8c..20803b2 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 + net40;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,341 +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/Properties/AssemblyInfo.cs b/Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs deleted file mode 100644 index 6051534..0000000 --- a/Asterisk.2013/Asterisk.NET/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("AsterNET")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("AsterNET")] -[assembly: AssemblyCopyright("Copyright © 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: Guid("abe98502-ea83-4b04-98c3-ffe3eabe06b0")] -[assembly: AssemblyVersion("1.3.0.0")] -[assembly: AssemblyFileVersion("1.3.0.0")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] From c4c97239ed3933e4725a19aefb0ea735e2b95bea Mon Sep 17 00:00:00 2001 From: Gennady Pundikov Date: Tue, 14 Aug 2018 20:22:10 +0300 Subject: [PATCH 18/52] Update travis config --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 124283b4757e013e01cfbf6e45c65e77b025e91a Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Mon, 20 Aug 2018 22:07:19 -0400 Subject: [PATCH 19/52] spelling error spelling error --- Asterisk.2013/Asterisk.NET/Manager/Event/BridgeEvent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/BridgeEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/BridgeEvent.cs index c26b825..65c665f 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/BridgeEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/BridgeEvent.cs @@ -22,7 +22,7 @@ namespace AsterNET.Manager.Event public enum BridgeTypes { - Unknnown, + Unknown, /// A channel.c bridge BRIDGE_TYPE_CORE, /// An RTP peer-2-peer bridge (NAT support only). From 6fda78301c4c8d5878538239d646f6008c4f0137 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Wed, 29 Aug 2018 18:56:26 -0400 Subject: [PATCH 20/52] async/await --- .../Asterisk.NET/Manager/ManagerConnection.cs | 56 +++++++++++++++++-- .../ResponseHandlers/TaskResponseHandler.cs | 30 ++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/ResponseHandlers/TaskResponseHandler.cs diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index d1fe667..3e7bdba 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -9,6 +9,7 @@ using System.Text; using System.Collections.Generic; using System.Reflection; using AsterNET.IO; +using System.Threading.Tasks; namespace AsterNET.Manager { @@ -1314,13 +1315,13 @@ namespace AsterNET.Manager /// action to send /// timeout in milliseconds /// - public Response.ManagerResponse SendAction(ManagerAction action, int timeOut) + 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); + bool result = autoEvent.WaitOne(timeout <= 0 ? -1 : timeout, true); RemoveResponseHandler(handler); @@ -1331,7 +1332,13 @@ namespace AsterNET.Manager #endregion #region SendAction(action, responseHandler) - public int SendAction(ManagerAction action, ResponseHandler 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."); @@ -1354,6 +1361,42 @@ namespace AsterNET.Manager } #endregion + + + #region SendActionAsync(action) + /// + /// Asynchronously send Action async with default timeout. + /// + /// action to send + public Task SendActionAsync(ManagerAction action) + { + return SendActionAsync(action, null); + } + #endregion + + #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; + + SendAction(action, handler); + + if (cancellationToken != null) + cancellationToken.Token.Register(() => { source.TrySetCanceled(); }); + + return source.Task.ContinueWith(x => + { + RemoveResponseHandler(handler); + return x.Result; + }); + } + #endregion #region SendEventGeneratingAction(action) public ResponseEvents SendEventGeneratingAction(ManagerActionEvent action) { @@ -1420,7 +1463,11 @@ namespace AsterNET.Manager responseEventHandlers[handler.Hash] = handler; } - internal void RemoveResponseHandler(IResponseHandler handler) + /// + /// Delete an instance of a class from handlers list. + /// + /// Class instance . + public void RemoveResponseHandler(IResponseHandler handler) { int hash = handler.Hash; if (hash != 0) @@ -1437,7 +1484,6 @@ namespace AsterNET.Manager if (responseEventHandlers.ContainsKey(hash)) responseEventHandlers.Remove(hash); } - private IResponseHandler GetRemoveResponseHandler(int hash) { IResponseHandler handler = null; 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..d96ccbf --- /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(); + 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() { } + } +} From 6da426507e90bc458713c8fa922e239df4d42c1d Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Wed, 29 Aug 2018 19:06:47 -0400 Subject: [PATCH 21/52] Add MusicOnHoldEvent --- .../Manager/Event/MusicOnHoldEvent.cs | 41 +++++++++++++++++++ .../Asterisk.NET/Manager/ManagerConnection.cs | 15 ++++++- .../Documentation/Documentation.shfbproj | 23 ++++++----- 3 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs 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..dd75af4 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs @@ -0,0 +1,41 @@ +namespace AsterNET.Manager.Event +{ + /// + /// The MusicOnHoldEvent event triggers when the music starts or ends playing the hold music. + /// + public class MusicOnHoldEvent : ManagerEvent + { + /// + /// Creates a new instance of the class . + /// + public MusicOnHoldEvent(ManagerConnection source) : base(source) + { + } + + /// + /// States + /// + public enum MusicOnHoldStates + { + /// + /// Unknown + /// + Unknown, + + /// + /// Music on hold is started. + /// + Start, + + /// + /// Music on hold is stoped. + /// + Stop + } + + /// + /// Get or set state + /// + public MusicOnHoldStates State { get; set; } + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index d1fe667..c5e1ae9 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -425,6 +425,10 @@ namespace AsterNET.Manager /// Available since : Asterisk 12. ///
public event EventHandler QueueMemberPause; + /// + /// Raised when started or stopped music on hold by channel. + /// + public event EventHandler MusicOnHold; /// /// A ChallengeResponseFailed is triggered when a request's attempt to authenticate has been challenged, and the request failed the authentication challenge. @@ -569,6 +573,7 @@ namespace AsterNET.Manager 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(ChallengeResponseFailedEvent), arg => fireEvent(ChallengeResponseFailed, arg)); Helper.RegisterEventHandler(registeredEventHandlers, typeof(InvalidAccountIDEvent), arg => fireEvent(InvalidAccountID, arg)); Helper.RegisterEventHandler(registeredEventHandlers, typeof(DeviceStateChangeEvent), arg => fireEvent(DeviceStateChanged, arg)); @@ -1314,13 +1319,13 @@ namespace AsterNET.Manager /// action to send /// timeout in milliseconds /// - public Response.ManagerResponse SendAction(ManagerAction action, int timeOut) + 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); + bool result = autoEvent.WaitOne(timeout <= 0 ? -1 : timeout, true); RemoveResponseHandler(handler); @@ -1331,6 +1336,12 @@ namespace AsterNET.Manager #endregion #region SendAction(action, responseHandler) + /// + /// Send action ans with timeout (milliseconds) + /// + /// action to send + /// Response Handler + /// public int SendAction(ManagerAction action, ResponseHandler responseHandler) { if (action == null) 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/ From 803576272115ce3d309100ce21c65182f660ce8f Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Wed, 29 Aug 2018 19:11:43 -0400 Subject: [PATCH 22/52] Add AgentRingNoAnswerEvent --- .../Manager/Event/AgentRingNoAnswerEvent.cs | 86 +++++++++++++++++++ .../Asterisk.NET/Manager/ManagerConnection.cs | 6 ++ 2 files changed, 92 insertions(+) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs 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..efe0b64 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs @@ -0,0 +1,86 @@ +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/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index d1fe667..e450fa2 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -120,6 +120,11 @@ namespace AsterNET.Manager /// 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; @@ -484,6 +489,7 @@ namespace AsterNET.Manager 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)); From 54abb777041fef06953b29f6227f1847368e75f6 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Wed, 29 Aug 2018 19:29:02 -0400 Subject: [PATCH 23/52] Add BlindTransferAction --- .../Manager/Action/BlindTransferAction.cs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs 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..2468eaf --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs @@ -0,0 +1,58 @@ +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 exten. + /// + public string Exten { get; set; } + } +} From deccbc2b4b1f0bffe164788fa4823579c380b8fa Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 30 Aug 2018 15:05:02 -0400 Subject: [PATCH 24/52] fix some comments --- .../Manager/Event/MusicOnHoldEvent.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs index dd75af4..998c24e 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs @@ -1,34 +1,33 @@ namespace AsterNET.Manager.Event { - /// - /// The MusicOnHoldEvent event triggers when the music starts or ends playing the hold music. - /// - public class MusicOnHoldEvent : ManagerEvent + /// + /// The MusicOnHoldEvent event triggers when the music starts or ends playing the hold music.
+ /// See LINK + ///
+ public class MusicOnHoldEvent : ManagerEvent { - /// - /// Creates a new instance of the class . - /// - public MusicOnHoldEvent(ManagerConnection source) : base(source) + /// + /// Creates a new empty using the given . + /// + public MusicOnHoldEvent(ManagerConnection source) : base(source) { } /// - /// States + /// States /// public enum MusicOnHoldStates { /// - /// Unknown + /// Unknown /// Unknown, - /// - /// Music on hold is started. + /// Music on hold is started. /// Start, - /// - /// Music on hold is stoped. + /// Music on hold is stopped. /// Stop } From 3c74cf4131c47e11c14f98c3b34300caadba5829 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 30 Aug 2018 15:05:34 -0400 Subject: [PATCH 25/52] fix comment --- Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs index 998c24e..2655688 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs @@ -33,7 +33,7 @@ } /// - /// Get or set state + /// Get or set state /// public MusicOnHoldStates State { get; set; } } From 672c8e9e10cc6a9e8eaa02f3c5f34a0e544f596c Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 30 Aug 2018 15:08:19 -0400 Subject: [PATCH 26/52] update comments --- .../Asterisk.NET/Manager/Action/BlindTransferAction.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs index 2468eaf..9e7c43d 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/BlindTransferAction.cs @@ -6,8 +6,7 @@ using System.Text; namespace AsterNET.Manager.Action { /// - /// Redirect all channels currently bridged to the specified channel to the specified destination. - /// + /// 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 @@ -41,17 +40,17 @@ namespace AsterNET.Manager.Action } /// - /// Gets or sets the channel. + /// Gets or sets the channel. /// public string Channel { get; set; } /// - /// Gets or sets the context. + /// Gets or sets the context. /// public string Context { get; set; } /// - /// Gets or sets the exten. + /// Gets or sets the extension. /// public string Exten { get; set; } } From 1a8c4cd329eeaee8606306f135c81fc5e6653253 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 30 Aug 2018 15:16:46 -0400 Subject: [PATCH 27/52] update comments --- .../Manager/Event/AgentRingNoAnswerEvent.cs | 21 +++++++++---------- .../Asterisk.NET/Manager/ManagerConnection.cs | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs index efe0b64..9b0b2d9 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/AgentRingNoAnswerEvent.cs @@ -6,8 +6,7 @@ using System.Text; namespace AsterNET.Manager.Event { /// - /// Raised when a queue member is notified of a caller in the queue and fails to answer. - /// + /// 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 @@ -23,32 +22,32 @@ namespace AsterNET.Manager.Event /// - /// Gets or sets the queue. + /// Gets or sets the queue. /// public string Queue { get; set; } /// - /// Gets or sets the name of the agent. + /// Gets or sets the name of the agent. /// public string AgentName { get; set; } /// - /// Gets or sets the agent called. + /// Gets or sets the agent called. /// public string AgentCalled { get; set; } /// - /// Gets or sets the channel calling. + /// Gets or sets the channel calling. /// public string ChannelCalling { get; set; } /// - /// Gets or sets the destination channel. + /// Gets or sets the destination channel. /// public string DestinationChannel { get; set; } /// - /// Gets or sets the Caller*ID of the calling channel. + /// Gets or sets the Caller*ID of the calling channel. /// public string CallerId { get; set; } @@ -63,17 +62,17 @@ namespace AsterNET.Manager.Event public string CallerIdName { get; set; } /// - /// Gets or sets the context. + /// Gets or sets the context. /// public string Context { get; set; } /// - /// Gets or sets the extension. + /// Gets or sets the extension. /// public string Extension { get; set; } /// - /// Gets or sets the priority. + /// Gets or sets the priority. /// public string Priority { get; set; } diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index e450fa2..f56b77e 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -120,8 +120,8 @@ namespace AsterNET.Manager /// 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.
+ /// 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; /// From d4dd90b65b5b05ea54613691c3f3945b80c725f6 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 30 Aug 2018 15:27:52 -0400 Subject: [PATCH 28/52] update comment add line break --- Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index f56b77e..1bb228a 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -120,7 +120,7 @@ namespace AsterNET.Manager /// public event EventHandler AgentLogoff; /// - /// An AgentRingNoAnswer is triggered when an agent was rang and did not answer. + /// 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; From 41ed8276d8a6625d4dc4c70efb87f3cdc03414e9 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Sun, 2 Sep 2018 14:07:26 -0400 Subject: [PATCH 29/52] add DTMFBegin and DTMFEnd events --- .../Manager/Event/DTMFBeginEvent.cs | 28 ++++++++++++++++ .../Manager/Event/DTMFEndEvent.cs | 33 +++++++++++++++++++ .../Asterisk.NET/Manager/ManagerConnection.cs | 10 ++++++ 3 files changed, 71 insertions(+) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/DTMFBeginEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/DTMFEndEvent.cs 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/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index d1fe667..7edca80 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -150,6 +150,14 @@ namespace AsterNET.Manager 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; @@ -546,6 +554,8 @@ namespace AsterNET.Manager 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, typeof(VarSetEvent), arg => fireEvent(VarSet, arg)); Helper.RegisterEventHandler(registeredEventHandlers, typeof(AGIExecEvent), arg => fireEvent(AGIExec, arg)); From 1769b2213d24521b783f6bcfed6d9154435645cf Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Sun, 2 Sep 2018 14:35:20 -0400 Subject: [PATCH 30/52] comment updates (Manager) --- .../Asterisk.NET/Manager/Originate.cs | 21 +++++++------ .../Manager/ResponseEventHandler.cs | 30 +++++++++++++++---- .../Asterisk.NET/Manager/ResponseEvents.cs | 14 +++++++-- .../Asterisk.NET/Manager/ResponseHandler.cs | 22 ++++++++++++-- 4 files changed, 67 insertions(+), 20 deletions(-) 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; From ddd9b6086bdf40b434341224aa24c4a960c0deb6 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 6 Sep 2018 19:12:06 -0400 Subject: [PATCH 31/52] add missing fields and summaries --- .../Event/ConfbridgeListCompleteEvent.cs | 12 ++ .../Manager/Event/ConfbridgeListEvent.cs | 120 ++++++++++++++++-- .../Event/ConfbridgeListRoomsCompleteEvent.cs | 13 +- .../Manager/Event/ConfbridgeListRoomsEvent.cs | 15 ++- 4 files changed, 143 insertions(+), 17 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs index ff847b4..80158b0 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs @@ -6,11 +6,23 @@ 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 using the given . + /// + /// 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..bd66d6b 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs @@ -6,29 +6,123 @@ 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 using the given . + /// + /// 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..1038b7d 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs @@ -6,9 +6,20 @@ 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 using the given . + /// + /// 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..ff711c4 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs @@ -6,23 +6,32 @@ 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 using the given . + /// + /// public ConfbridgeListRoomsEvent(ManagerConnection source) : base(source) { From 9d1aae4f9b2dce5f6992d6da41df71b86a5a14a2 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 6 Sep 2018 19:28:18 -0400 Subject: [PATCH 32/52] remove changes not related to this commit --- .../Asterisk.NET/Manager/ManagerConnection.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index c5e1ae9..37f983a 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -425,6 +425,7 @@ namespace AsterNET.Manager /// Available since : Asterisk 12. /// public event EventHandler QueueMemberPause; + /// /// Raised when started or stopped music on hold by channel. /// @@ -1319,13 +1320,13 @@ namespace AsterNET.Manager /// action to send /// timeout in milliseconds /// - public Response.ManagerResponse SendAction(ManagerAction action, int timeout) + 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); + bool result = autoEvent.WaitOne(timeOut <= 0 ? -1 : timeOut, true); RemoveResponseHandler(handler); @@ -1336,12 +1337,6 @@ namespace AsterNET.Manager #endregion #region SendAction(action, responseHandler) - /// - /// Send action ans with timeout (milliseconds) - /// - /// action to send - /// Response Handler - /// public int SendAction(ManagerAction action, ResponseHandler responseHandler) { if (action == null) From bc29b8feb559767f1b76e9e38b6cbd05a5faca4d Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 6 Sep 2018 19:58:20 -0400 Subject: [PATCH 33/52] add musiconhold start/stop events --- .../Manager/Event/MusicOnHoldEvent.cs | 40 ------------------- .../Manager/Event/MusicOnHoldStartEvent.cs | 38 ++++++++++++++++++ .../Manager/Event/MusicOnHoldStopEvent.cs | 33 +++++++++++++++ .../Asterisk.NET/Manager/ManagerConnection.cs | 12 ++++-- 4 files changed, 80 insertions(+), 43 deletions(-) delete mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStartEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStopEvent.cs diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs deleted file mode 100644 index 2655688..0000000 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace AsterNET.Manager.Event -{ - /// - /// The MusicOnHoldEvent event triggers when the music starts or ends playing the hold music.
- /// See LINK - ///
- public class MusicOnHoldEvent : ManagerEvent - { - /// - /// Creates a new empty using the given . - /// - public MusicOnHoldEvent(ManagerConnection source) : base(source) - { - } - - /// - /// States - /// - public enum MusicOnHoldStates - { - /// - /// Unknown - /// - Unknown, - /// - /// Music on hold is started. - /// - Start, - /// - /// Music on hold is stopped. - /// - Stop - } - - /// - /// Get or set state - /// - public MusicOnHoldStates State { 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..bfefb31 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStartEvent.cs @@ -0,0 +1,38 @@ +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 of music being played on the channel. + /// + public string Class { get; set; } + + public string ChannelState { get; set; } + public string ChannelStateDesc { get; set; } + + public string CallerIDNum { get; set; } + public string CallerIDName { get; set; } + + public string ConnectedLineNum { get; set; } + public string ConnectedLineName { get; set; } + + public string Language { get; set; } + public string AccountCode { get; set; } + public string Context { get; set; } + public string Exten { get; set; } + public string Priority { 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..66598f3 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStopEvent.cs @@ -0,0 +1,33 @@ +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) + { + } + + public string ChannelState { get; set; } + public string ChannelStateDesc { get; set; } + + public string CallerIDNum { get; set; } + public string CallerIDName { get; set; } + + public string ConnectedLineNum { get; set; } + public string ConnectedLineName { get; set; } + + public string Language { get; set; } + public string AccountCode { get; set; } + public string Context { get; set; } + public string Exten { get; set; } + public string Priority { get; set; } + + } +} diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index 37f983a..d6a34f1 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -427,9 +427,14 @@ namespace AsterNET.Manager public event EventHandler QueueMemberPause; /// - /// Raised when started or stopped music on hold by channel. + /// Raised when music on hold has started on a channel. /// - public event EventHandler MusicOnHold; + public event EventHandler MusicOnHoldStart; + + /// + /// Raised when music on hold has stopped on a channel. + /// + public event EventHandler MusicOnHoldStop; /// /// A ChallengeResponseFailed is triggered when a request's attempt to authenticate has been challenged, and the request failed the authentication challenge. @@ -574,7 +579,8 @@ namespace AsterNET.Manager 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)); From 5b2dece94547843338d18544df65847424ab6dfe Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Thu, 6 Sep 2018 21:59:58 -0400 Subject: [PATCH 34/52] re-add musiconholdevent re-add musiconholdevent add summaries --- .../Manager/Event/MusicOnHoldEvent.cs | 45 +++++++++++++++++ .../Manager/Event/MusicOnHoldStartEvent.cs | 49 +++++++++++++++++- .../Manager/Event/MusicOnHoldStopEvent.cs | 50 ++++++++++++++++++- .../Asterisk.NET/Manager/ManagerConnection.cs | 13 ++++- 4 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldEvent.cs 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 index bfefb31..f54096c 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStartEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStartEvent.cs @@ -15,24 +15,71 @@ } /// - /// Gets or sets the class of music being played on the channel. + /// 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 index 66598f3..4789628 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStopEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/MusicOnHoldStopEvent.cs @@ -13,21 +13,67 @@ 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/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index d6a34f1..e17075a 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -427,12 +427,20 @@ namespace AsterNET.Manager public event EventHandler QueueMemberPause; /// - /// Raised when music on hold has started on a channel. + /// Raised when music on hold has started/stopped on a channel.
+ /// Available since : Asterisk 1.6. + ///
+ public event EventHandler MusicOnHold; + + /// + /// Raised when music on hold has started on a channel.
+ /// Available since : Asterisk 12. ///
public event EventHandler MusicOnHoldStart; /// - /// Raised when music on hold has stopped on a channel. + /// Raised when music on hold has stopped on a channel.
+ /// Available since : Asterisk 12. ///
public event EventHandler MusicOnHoldStop; @@ -579,6 +587,7 @@ namespace AsterNET.Manager 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)); From bc65355dda9e2fc83d2ad6b9657ea20e82e52ada Mon Sep 17 00:00:00 2001 From: Richard J Schnorenberg Date: Thu, 13 Sep 2018 21:10:11 -0500 Subject: [PATCH 35/52] Synchronize ManagerConnection socket writes to make SendAction thread safe --- Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index d1fe667..bd551a3 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -45,6 +45,7 @@ namespace AsterNET.Manager private int pingInterval = 10000; private object lockSocket = new object(); + private object lockSocketWrite = new object(); private object lockHandlers = new object(); private bool enableEvents = true; @@ -1506,7 +1507,10 @@ namespace AsterNET.Manager private void sendToAsterisk(string buffer) { - mrSocket.Write(buffer); + lock (lockSocketWrite) + { + mrSocket.Write(buffer); + } } #endregion From d3ccb2c059f1c7ed0f0353772d0963bac7e33aba Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Fri, 21 Sep 2018 18:12:58 -0400 Subject: [PATCH 36/52] fixed line breaks --- .../Manager/Event/ConfbridgeListCompleteEvent.cs | 8 +++----- .../Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs | 5 ++--- .../Manager/Event/ConfbridgeListRoomsCompleteEvent.cs | 9 +++------ .../Manager/Event/ConfbridgeListRoomsEvent.cs | 7 +++---- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs index 80158b0..6a18b1f 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListCompleteEvent.cs @@ -7,18 +7,16 @@ 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. - /// + /// 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 using the given . + /// 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 bd66d6b..135eb85 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListEvent.cs @@ -7,8 +7,7 @@ using System.Threading.Tasks; namespace AsterNET.Manager.Event { /// - /// Raised as part of the ConfbridgeList action response list. - /// + /// 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 @@ -120,7 +119,7 @@ namespace AsterNET.Manager.Event public string Linkedid { get; set; } /// - /// Creates a new using the given . + /// Creates a new . /// /// public ConfbridgeListEvent(ManagerConnection source) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs index 1038b7d..7d15d20 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsCompleteEvent.cs @@ -7,19 +7,16 @@ 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. - /// + /// 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 using the given . + /// 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 ff711c4..8b0431e 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeListRoomsEvent.cs @@ -7,8 +7,7 @@ using System.Threading.Tasks; namespace AsterNET.Manager.Event { /// - /// Raised as part of the ConfbridgeListRooms action response list. - /// + /// 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 @@ -29,9 +28,9 @@ namespace AsterNET.Manager.Event public string Locked { get; set; } /// - /// Creates a new using the given . + /// Creates a new . /// - /// + /// public ConfbridgeListRoomsEvent(ManagerConnection source) : base(source) { From 1772aa17dcf84c51aa533c632421ce6d34776db5 Mon Sep 17 00:00:00 2001 From: Craig Roberts Date: Fri, 21 Sep 2018 18:50:34 -0400 Subject: [PATCH 37/52] add summaries --- Asterisk.2013/Asterisk.NET/Manager/AsteriskVersion.cs | 3 +++ Asterisk.2013/Asterisk.NET/Manager/IActionVariable.cs | 8 ++++---- Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/AsteriskVersion.cs b/Asterisk.2013/Asterisk.NET/Manager/AsteriskVersion.cs index 7877fdc..e204a77 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/AsteriskVersion.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/AsteriskVersion.cs @@ -1,5 +1,8 @@ namespace AsterNET.Manager { + /// + /// Asterisk Version + /// public enum AsteriskVersion { ASTERISK_1_0 = 10, 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 d1fe667..aba1a27 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -13,7 +13,7 @@ using AsterNET.IO; namespace AsterNET.Manager { /// - /// Default implemention of the ManagerConnection interface. + /// Default implementation of the ManagerConnection interface. /// public class ManagerConnection { From de6326bda9ffba58ca018a9be85a91c22bb529d5 Mon Sep 17 00:00:00 2001 From: orastarter Date: Mon, 24 Sep 2018 09:30:48 +0300 Subject: [PATCH 38/52] Fix https://github.com/AsterNET/AsterNET/issues/120 --- .../Asterisk.NET/FastAGI/AGIChannel.cs | 12 +- .../Asterisk.NET/FastAGI/AGIScript.cs | 120 +++++++++--------- 2 files changed, 61 insertions(+), 71 deletions(-) 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/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 From ac993790be8a543ae37a166d688c3cbc5899fa3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BD=D0=B8=D1=81=20=D0=95=D0=B2=D0=B3=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9?= Date: Fri, 26 Apr 2019 19:44:36 +0700 Subject: [PATCH 39/52] - ReloadEvent fix - OriginateAction improve - UpdateCOnfigAction improve - ModuleLoadAction - ReloadAction --- .../Manager/Action/ModuleLoadAction.cs | 33 +++++++++++++++++++ .../Manager/Action/OriginateAction.cs | 9 +++++ .../Manager/Action/ReloadAction.cs | 26 +++++++++++++++ .../Manager/Action/UpdateConfigAction.cs | 21 ++++++++---- .../Asterisk.NET/Manager/ManagerConnection.cs | 11 +++++-- 5 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Action/ModuleLoadAction.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Action/ReloadAction.cs 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/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/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index fda032d..49d2302 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -362,10 +362,15 @@ namespace AsterNET.Manager /// public event EventHandler ZapShowChannels; /// - /// A ConnectionState is triggered after Connect/Disconnect/Reload/Shutdown events. + /// A ConnectionState is triggered after Connect/Disconnect/Shutdown events. /// public event EventHandler ConnectionState; + /// + /// A Reload is triggered after Reload events. + /// + public event EventHandler Reload; + /// /// When a variable is set /// @@ -573,7 +578,7 @@ namespace AsterNET.Manager 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(ConnectionState, arg)); + Helper.RegisterEventHandler(registeredEventHandlers, typeof(ReloadEvent), arg => fireEvent(Reload, arg)); Helper.RegisterEventHandler(registeredEventHandlers, typeof(ShutdownEvent), arg => fireEvent(ConnectionState, arg)); Helper.RegisterEventHandler(registeredEventHandlers, typeof(BridgeEvent), arg => fireEvent(Bridge, arg)); @@ -1981,7 +1986,7 @@ namespace AsterNET.Manager fireEvent(e); reconnect(false); } - else if (!reconnected && reconnectEnable && (e is DisconnectEvent || e is ReloadEvent || e is ShutdownEvent)) + else if (!reconnected && reconnectEnable && (e is DisconnectEvent || e is ShutdownEvent)) { ((ConnectionStateEvent)e).Reconnect = true; fireEvent(e); From 1a56d4e5ea57881c75f88f1e4525973e58161ca3 Mon Sep 17 00:00:00 2001 From: "Victor V. Grekov" Date: Mon, 25 Mar 2019 23:05:12 +0300 Subject: [PATCH 40/52] migrate to net46, add more asynchrony --- .../Asterisk.NET.Test/AsterNET.Test.csproj | 4 ++-- .../Asterisk.NET.Test/Asterisk.NET.Test/app.config | 2 +- .../Asterisk.NET.WinForm/AsterNET.WinForm.csproj | 4 ++-- .../Asterisk.NET.WinForm/Properties/Resources.Designer.cs | 8 ++++---- .../Asterisk.NET.WinForm/Properties/Settings.Designer.cs | 6 +++--- Asterisk.2013/Asterisk.NET.WinForm/app.config | 2 +- Asterisk.2013/Asterisk.NET/AsterNET.csproj | 4 ++-- Asterisk.2013/Asterisk.NET/FastAGI/AGIRequest.cs | 6 +++--- .../Manager/ResponseHandlers/TaskResponseHandler.cs | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) 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/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/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 20803b2..5a37305 100644 --- a/Asterisk.2013/Asterisk.NET/AsterNET.csproj +++ b/Asterisk.2013/Asterisk.NET/AsterNET.csproj @@ -1,7 +1,7 @@  - net40;netstandard2.0 + net46;netstandard2.0 1.3.0 Copyright © 2017 Ben Merrills @@ -12,7 +12,7 @@ Please see: https://github.com/AsterNET/AsterNET/commits/master Debug;Release;Travis - + true full 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/Manager/ResponseHandlers/TaskResponseHandler.cs b/Asterisk.2013/Asterisk.NET/Manager/ResponseHandlers/TaskResponseHandler.cs index d96ccbf..7d09607 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ResponseHandlers/TaskResponseHandler.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ResponseHandlers/TaskResponseHandler.cs @@ -10,7 +10,7 @@ namespace AsterNET.Manager.Response { public TaskResponseHandler(ManagerAction action) { - TaskCompletionSource = new TaskCompletionSource(); + TaskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); Action = action; } From c8d725c717a8b7d7dfae4f4357c2e9f45f7a0cec Mon Sep 17 00:00:00 2001 From: Amyn Virani Date: Thu, 16 Jan 2020 16:27:27 -0500 Subject: [PATCH 41/52] 1. Pass unavailable reason when creating QueuePauseAction 2. QueueMember JoinEvent provides CallerIdNum instead of CallerId 3. QueueMemberEvent now retrieves paused reason 4. Added ConfbridgeMuteEvent and ConfbridgeUnmuteEvent classes so they can be triggered --- .../Manager/Action/QueuePauseAction.cs | 4 +++- .../Manager/Event/ConfbridgeMuteEvent.cs | 16 ++++++++++++++++ .../Manager/Event/ConfbridgeUnmuteEvent.cs | 16 ++++++++++++++++ .../Asterisk.NET/Manager/Event/JoinEvent.cs | 2 +- .../Manager/Event/QueueMemberEvent.cs | 9 +++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeMuteEvent.cs create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/ConfbridgeUnmuteEvent.cs diff --git a/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs b/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs index d462928..ff4f5dd 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Action/QueuePauseAction.cs @@ -56,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; } /// 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/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/QueueMemberEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs index 4fd05a8..9943041 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/QueueMemberEvent.cs @@ -18,6 +18,7 @@ namespace AsterNET.Manager.Event private bool paused; private string name; private bool incall; + private string pausedReason; /// /// Get/Set the name of the queue member. @@ -135,6 +136,14 @@ namespace AsterNET.Manager.Event 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) : base(source) From 4e5d7ee2e35bf7f1fff0a0c9790b9f3fa47d6cf5 Mon Sep 17 00:00:00 2001 From: Amyn Virani Date: Thu, 16 Jan 2020 17:11:10 -0500 Subject: [PATCH 42/52] Added event handlers for Confbridge Mute and Unmute events --- .../Asterisk.NET/Manager/ManagerConnection.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index f44421c..e463846 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -407,6 +407,16 @@ namespace AsterNET.Manager /// 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; + /// /// /// @@ -596,6 +606,8 @@ namespace AsterNET.Manager 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, typeof(FailedACLEvent), arg => fireEvent(FailedACL, arg)); From 0f260a753c6f0f96d5e139e9a7766fd95a731caf Mon Sep 17 00:00:00 2001 From: Denis Dyner Date: Fri, 24 Jan 2020 13:08:40 +0300 Subject: [PATCH 43/52] Add socket ReceiveBufferSize settings to public property --- .../Asterisk.NET/IO/SocketConnection.cs | 25 +++++++++++++------ .../Asterisk.NET/Manager/ManagerConnection.cs | 22 +++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) 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/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index f44421c..b14a5fa 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -653,14 +653,14 @@ namespace AsterNET.Manager /// 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) + 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 = encoding; + this.socketEncoding = socketEncoding; } #endregion @@ -855,7 +855,8 @@ namespace AsterNET.Manager } #endregion - #region SocketEncoding + #region Socket Settings + /// /// Socket Encoding - default ASCII /// @@ -864,6 +865,12 @@ namespace AsterNET.Manager get { return socketEncoding; } set { socketEncoding = value; } } + + /// + /// Socket Receive Buffer Size + /// + public int SocketReceiveBufferSize { get; set;} + #endregion #region Version @@ -1075,7 +1082,10 @@ namespace AsterNET.Manager #endif try { - mrSocket = new SocketConnection(hostname, port, socketEncoding); + if (SocketReceiveBufferSize>0) + mrSocket = new SocketConnection(hostname, port, SocketReceiveBufferSize, socketEncoding); + else + mrSocket = new SocketConnection(hostname, port, socketEncoding); result = mrSocket.IsConnected; } #if LOGGER @@ -1083,8 +1093,8 @@ namespace AsterNET.Manager { logger.Info("Connect - Exception : {0}", ex.Message); #else - catch - { + catch + { #endif result = false; } From a54ea18b1be8492a1ef541df3f58ac66b0545b95 Mon Sep 17 00:00:00 2001 From: Denis Dyner Date: Fri, 24 Jan 2020 15:41:29 +0300 Subject: [PATCH 44/52] Changed the type of the result field of the BlindTransferEvent class --- Asterisk.2013/Asterisk.NET/Manager/Event/BlindTransferEvent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } From e1c51cafcbbd690fb238bf873416213731cb3eeb Mon Sep 17 00:00:00 2001 From: Denis Dyner Date: Fri, 24 Jan 2020 22:13:52 +0300 Subject: [PATCH 45/52] add HangupRequest event --- .../Manager/Event/HangupRequestEvent.cs | 28 +++++++++++++++++++ .../Asterisk.NET/Manager/ManagerConnection.cs | 5 ++++ 2 files changed, 33 insertions(+) create mode 100644 Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs 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..51ad4c7 --- /dev/null +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs @@ -0,0 +1,28 @@ +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; } + + /// + /// Get/Set the textual representation of the hangup cause. + /// + public string CauseTxt { get; set; } + } +} \ No newline at end of file diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index f44421c..d35fde7 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -177,6 +177,10 @@ namespace AsterNET.Manager ///
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; @@ -534,6 +538,7 @@ namespace AsterNET.Manager 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)); From ccd319d3d00dcca31dc14c9d378ee29eb5e0e259 Mon Sep 17 00:00:00 2001 From: Denis Dyner Date: Mon, 27 Jan 2020 08:33:54 +0300 Subject: [PATCH 46/52] Added xml-comment to SocketEncoding and SocketReceiveBufferSize property --- .../Asterisk.NET/Manager/ManagerConnection.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index b14a5fa..62e6891 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -860,6 +860,13 @@ namespace AsterNET.Manager /// /// 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; } @@ -869,6 +876,13 @@ namespace AsterNET.Manager /// /// 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;} #endregion From 2bfa6badecf65328e16c8b6e9ca6f548c493b463 Mon Sep 17 00:00:00 2001 From: Denis Dyner Date: Mon, 27 Jan 2020 14:26:46 +0300 Subject: [PATCH 47/52] Remove CauseTxt property --- .../Asterisk.NET/Manager/Event/HangupRequestEvent.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs b/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs index 51ad4c7..0b42980 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/Event/HangupRequestEvent.cs @@ -19,10 +19,5 @@ /// Get/Set the cause of the hangup. ///
public int Cause { get; set; } - - /// - /// Get/Set the textual representation of the hangup cause. - /// - public string CauseTxt { get; set; } } } \ No newline at end of file From d2ed993a60769fad306ec728dceb88733e3046e6 Mon Sep 17 00:00:00 2001 From: Deantwo <2676134+Deantwo@users.noreply.github.com> Date: Mon, 20 Jul 2020 23:34:22 +0200 Subject: [PATCH 48/52] Fixed multiple entries with same key If the reply from the asterisk server has multiple of the same key, they are override. This should fix that issue. See: #233 --- Asterisk.2013/Asterisk.NET/Helper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Asterisk.2013/Asterisk.NET/Helper.cs b/Asterisk.2013/Asterisk.NET/Helper.cs index e6fc507..56f5dd4 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.ContainsKey(name)) + list[name] += Environment.NewLine + val; + else if (val == "") list[name] = null; else list[name] = val; @@ -885,4 +887,4 @@ namespace AsterNET #endregion } -} \ No newline at end of file +} From 53281322d4d83c24e4e9d183afddd503e659c890 Mon Sep 17 00:00:00 2001 From: Deantwo <2676134+Deantwo@users.noreply.github.com> Date: Tue, 21 Jul 2020 14:17:07 +0200 Subject: [PATCH 49/52] Fixed use of incorrect Contains method --- Asterisk.2013/Asterisk.NET/Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Helper.cs b/Asterisk.2013/Asterisk.NET/Helper.cs index 56f5dd4..61125ed 100644 --- a/Asterisk.2013/Asterisk.NET/Helper.cs +++ b/Asterisk.2013/Asterisk.NET/Helper.cs @@ -647,7 +647,7 @@ namespace AsterNET { string name = line.Substring(0, delimiterIndex).ToLower(CultureInfo).Trim(); string val = line.Substring(delimiterIndex + 1).Trim(); - if (list.ContainsKey(name)) + if (list.Contains(name)) list[name] += Environment.NewLine + val; else if (val == "") list[name] = null; From 26b8e610f9f663812cee0c31a55e7449d2d3ec16 Mon Sep 17 00:00:00 2001 From: brook2006 Date: Tue, 25 Aug 2020 15:24:24 +0100 Subject: [PATCH 50/52] Update ManagerConnection.cs I was getting a PlatformNotSupported exception with .Net Core 3.1 saying "Operation is not supported on this platform". This code change fixes that and maintains functionality. --- Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs index 54c23eb..c3253f8 100644 --- a/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs +++ b/Asterisk.2013/Asterisk.NET/Manager/ManagerConnection.cs @@ -2049,7 +2049,7 @@ namespace AsterNET.Manager { if (enableEvents && internalEvent != null) if (UseASyncEvents) - internalEvent.BeginInvoke(this, e, new AsyncCallback(eventComplete), null); + Task.Run(() => internalEvent.Invoke(this, e)).ContinueWith(eventComplete); else internalEvent.Invoke(this, e); } From ad6cdc6e2109a817e04e20e54eb231b9df76be55 Mon Sep 17 00:00:00 2001 From: Marian Ionita Date: Mon, 14 Sep 2020 12:46:16 +0300 Subject: [PATCH 51/52] Added RecordFile property to ConfbridgeStartRecordAction. --- .../Asterisk.NET/Manager/Action/ConfbridgeStartRecordAction.cs | 2 ++ 1 file changed, 2 insertions(+) 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"; } From 3667c2d115180f305364b47c14fe0dafc514c80d Mon Sep 17 00:00:00 2001 From: "Chen, Mei" Date: Wed, 16 Sep 2020 17:14:03 +0200 Subject: [PATCH 52/52] Fix: Invalid Cast Exception #194 --- Asterisk.2013/Asterisk.NET/Manager/ManagerReader.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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;