public void Execute( DialPlanContext dialPlanContext, ISIPServerUserAgent uas, SIPCallDirection callDirection, DialogueBridgeCreatedDelegate createBridgeDelegate, ISIPCallManager callManager) { if (dialPlanContext == null) { throw new ArgumentNullException("The DialPlanContext parameter cannot be null when attempting to execute a dialplan."); } if (uas.IsUASAnswered) { // This can occur if the call is cancelled by the caller between when the INVITE was received and when the dialplan execution was ready. logger.Warn("Dialplan execution for " + dialPlanContext.SIPDialPlan.DialPlanName + " for " + uas.CallDirection + " call to " + uas.CallDestination + " did not proceed as call already answered."); dialPlanContext.DialPlanExecutionFinished(); } else { if (dialPlanContext.ContextType == DialPlanContextsEnum.Line) { ThreadPool.QueueUserWorkItem(delegate { ExecuteDialPlanLine((DialPlanLineContext)dialPlanContext, uas, callDirection, createBridgeDelegate, callManager); }); } else { ExecuteDialPlanScript((DialPlanScriptContext)dialPlanContext, uas, callDirection, createBridgeDelegate, callManager); } } }
//public event Action DialPlanComplete; public DialPlanContext( SIPMonitorLogDelegate monitorLogDelegate, SIPTransport sipTransport, DialogueBridgeCreatedDelegate createBridge, SIPEndPoint outboundProxy, ISIPServerUserAgent sipServerUserAgent, SIPDialPlan dialPlan, List <SIPProvider> sipProviders, string traceDirectory, string callersNetworkId, Customer customer, DialPlanEngine dialPlanEngine, GetCanonicalDomainDelegate getCanonicalDomain) { Log_External = monitorLogDelegate; CreateBridge_External = createBridge; m_sipTransport = sipTransport; m_outboundProxy = outboundProxy; m_sipServerUserAgent = sipServerUserAgent; m_dialPlan = dialPlan; m_sipProviders = sipProviders; m_traceDirectory = traceDirectory; CallersNetworkId = callersNetworkId; Customer = customer; m_dialPlanEngine = dialPlanEngine; GetCanonicalDomain_External = getCanonicalDomain; m_sipServerUserAgent.CallCancelled += ClientCallCancelled; m_sipServerUserAgent.NoRingTimeout += ClientCallNoRingTimeout; m_sipServerUserAgent.TransactionComplete += ClientTransactionRemoved; m_sipServerUserAgent.SetTraceDelegate(TransactionTraceMessage); }
private void ClientCallCancelled(ISIPServerUserAgent uas) { try { if (!m_isAnswered) { m_isAnswered = true; Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Client call cancelled halting dial plan.", Owner)); if (CallCancelledByClient != null) { CallCancelledByClient(CallCancelCause.ClientCancelled); } } else { logger.Warn("DialPlanContext ClientCallCancelled fired on already answered call."); } } catch (Exception excp) { logger.Error("Exception DialPlanContext ClientCallCancelled. " + excp.Message); } finally { DialPlanExecutionFinished(); } }
private void ClientTransactionRemoved(ISIPServerUserAgent uas) { try { if (!TraceEmailAddress.IsNullOrBlank() && TraceLog != null && TraceLog.Length > 0 && SendTrace) { ThreadPool.QueueUserWorkItem(delegate { CompleteTrace(); }); } } catch (Exception excp) { logger.Error("Exception DialPlanContext ClientTransactionRemoved. " + excp.Message); } }
public DialPlanScriptContext( SIPMonitorLogDelegate monitorLogDelegate, SIPTransport sipTransport, DialogueBridgeCreatedDelegate createBridge, SIPEndPoint outboundProxy, ISIPServerUserAgent sipServerUserAgent, SIPDialPlan dialPlan, List <SIPProvider> sipProviders, string traceDirectory, string callersNetworkId, Guid customerId) : base(monitorLogDelegate, sipTransport, createBridge, outboundProxy, sipServerUserAgent, dialPlan, sipProviders, traceDirectory, callersNetworkId, customerId) { ContextType = DialPlanContextsEnum.Script; }
public DialPlanScriptContext( SIPMonitorLogDelegate monitorLogDelegate, SIPTransport sipTransport, DialogueBridgeCreatedDelegate createBridge, SIPEndPoint outboundProxy, ISIPServerUserAgent sipServerUserAgent, SIPDialPlan dialPlan, List<SIPProvider> sipProviders, string traceDirectory, string callersNetworkId, Guid customerId) : base(monitorLogDelegate, sipTransport, createBridge, outboundProxy, sipServerUserAgent, dialPlan, sipProviders, traceDirectory, callersNetworkId, customerId) { ContextType = DialPlanContextsEnum.Script; }
private bool MatchIncomingCall(ISIPServerUserAgent incomingCall) { try { if (incomingCall.SIPAccount.Owner != m_username) { return(false); } else if (m_clientCallCancelled) { // If the call has been cancelled then don't match to avoid chance of a new incoming call matching a dead Google Voice call. return(false); } SIPHeader callHeader = incomingCall.CallRequest.Header; bool matchedCall = false; if (!m_fromURIUserRegexMatch.IsNullOrBlank()) { if (Regex.Match(callHeader.From.FromURI.User, m_fromURIUserRegexMatch).Success) { matchedCall = true; } } else if (callHeader.UnknownHeaders.Contains("X-GoogleVoice: true") && callHeader.To.ToURI.User == m_forwardingNumber.Substring(1)) { matchedCall = true; } if (matchedCall) { m_callbackCall = incomingCall; m_callbackCall.SetOwner(m_username, m_adminMemberId); m_waitForCallback.Set(); return(true); } else { return(false); } } catch (Exception excp) { logger.Error("Exception GoogleVoiceCall MatchIncomingCall. " + excp.Message); return(false); } }
public DialPlanLineContext( SIPMonitorLogDelegate monitorLogDelegate, SIPTransport sipTransport, DialogueBridgeCreatedDelegate createBridge, SIPEndPoint outboundProxy, ISIPServerUserAgent sipServerUserAgent, SIPDialPlan dialPlan, List<SIPProvider> sipProviders, string traceDirectory, string callersNetworkId, Customer customer) : base(monitorLogDelegate, sipTransport, createBridge, outboundProxy, sipServerUserAgent, dialPlan, sipProviders, traceDirectory, callersNetworkId, customer, null, null) { ContextType = DialPlanContextsEnum.Line; string[] dialPlanEntries = dialPlan.DialPlanScript.Split(new char[] { '\n' }); ParseDialPlan(dialPlanEntries); }
public DialPlanLineContext( SIPMonitorLogDelegate monitorLogDelegate, SIPTransport sipTransport, DialogueBridgeCreatedDelegate createBridge, SIPEndPoint outboundProxy, ISIPServerUserAgent sipServerUserAgent, SIPDialPlan dialPlan, List <SIPProvider> sipProviders, string traceDirectory, string callersNetworkId, Guid customerID) : base(monitorLogDelegate, sipTransport, createBridge, outboundProxy, sipServerUserAgent, dialPlan, sipProviders, traceDirectory, callersNetworkId, customerID) { ContextType = DialPlanContextsEnum.Line; string[] dialPlanEntries = dialPlan.DialPlanScript.Split(new char[] { '\n' }); ParseDialPlan(dialPlanEntries); }
/// <summary> /// The client transaction will time out after ringing for the maximum allowed time for an INVITE transaction (probably 10 minutes) or less /// if the invite transaction timeout value has been adjusted. /// </summary> /// <param name="sipTransaction"></param> private void ClientCallNoRingTimeout(ISIPServerUserAgent sipServerUserAgent) { try { m_isAnswered = true; Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Client call timed out, no ringing response was receved within the allowed time.", Owner)); if (CallCancelledByClient != null) { CallCancelledByClient(CallCancelCause.TimedOut); } } catch (Exception excp) { logger.Error("Exception ClientCallNoRingTimeout. " + excp.Message); } finally { DialPlanExecutionFinished(); } }
/// <summary> /// An incoming call was cancelled by the caller. /// </summary> private void UASCallCancelled(ISIPServerUserAgent uas) { //SetText(m_signallingStatus, "incoming call cancelled for: " + uas.CallDestination + "."); CallFinished(); }
private List<ISIPClientUserAgent> m_uacWaitingForCallDetails = new List<ISIPClientUserAgent>(); // UACs can indicate they would like the call details when available. #endregion Fields #region Constructors public DialPlanContext( SIPMonitorLogDelegate monitorLogDelegate, SIPTransport sipTransport, DialogueBridgeCreatedDelegate createBridge, SIPEndPoint outboundProxy, ISIPServerUserAgent sipServerUserAgent, SIPDialPlan dialPlan, List<SIPProvider> sipProviders, string traceDirectory, string callersNetworkId, Guid customerId) { Log_External = monitorLogDelegate; CreateBridge_External = createBridge; m_sipTransport = sipTransport; m_outboundProxy = outboundProxy; m_sipServerUserAgent = sipServerUserAgent; m_dialPlan = dialPlan; m_sipProviders = sipProviders; m_traceDirectory = traceDirectory; CallersNetworkId = callersNetworkId; CustomerId = customerId; m_sipServerUserAgent.CallCancelled += ClientCallCancelled; m_sipServerUserAgent.NoRingTimeout += ClientCallNoRingTimeout; m_sipServerUserAgent.TransactionComplete += ClientTransactionRemoved; m_sipServerUserAgent.SetTraceDelegate(TransactionTraceMessage); }
private void SIPCallCancelled(ISIPServerUserAgent uas) { CloseMediaSockets(); m_xmppCall.TerminateCall(); }
private static void UASCallCancelled(ISIPServerUserAgent uas) { Console.WriteLine("Incoming call cancelled for: " + uas.CallDestination + "\n"); }
public void QueueNewCall(ISIPServerUserAgent serverUA) { try { // Attempt to queue the call. if (m_newCalls.Count < MAX_NEWCALL_QUEUE) { lock (m_newCalls) { m_newCalls.Enqueue(serverUA); m_newCallReady.Set(); } } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call Manager rejected call as new calls queue full.", null)); serverUA.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Call Manager overloaded", null); } } catch (Exception excp) { logger.Error("Exception SIPCallManager QueueNewCall. " + excp.Message); } }
private bool GetDialPlanAndCustomer(string owner, string dialPlanName, ISIPServerUserAgent uas, out Customer customer, out SIPDialPlan dialPlan) { try { dialPlan = null; customer = m_customerPersistor.Get(c => c.CustomerUsername == owner); if (customer == null) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as no matching account found.", null)); uas.Reject(SIPResponseStatusCodesEnum.DoesNotExistAnywhere, "No matching user was found", null); } else if (customer.Suspended) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as account is suspended.", null)); uas.Reject(SIPResponseStatusCodesEnum.DoesNotExistAnywhere, "User account is suspended", null); } else if (dialPlanName.IsNullOrBlank() && uas.CallDirection == SIPCallDirection.Out) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as no dialplan is configured for an " + uas.CallDirection + " call.", null)); uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "SIP account missing dialplan setting", null); } else { dialPlan = GetDialPlan_External(d => d.Owner == owner && d.DialPlanName == dialPlanName); if (!IsDialPlanExecutionAllowed(dialPlan, customer)) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of dial plan " + dialPlanName + " was not processed as maximum execution count has been reached.", owner)); uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Dial plan execution exceeded maximum allowed", null); } else { if (m_dailyCallLimit == -1) { return true; } else { // Check whether the number of CDR's exceeds the daily call limit. DateTime yesterday = DateTime.Now.AddDays(-1); int cdrCount = m_sipCDRPersistor.Count(x => x.Owner == owner && x.Created > yesterday); if (cdrCount >= m_dailyCallLimit) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of call for " + owner + " was not processed as daily call limit reached.", owner)); uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Daily call limit reached", null); } else { return true; } } } } return false; } catch (Exception excp) { logger.Error("Exception GetDialPlanAndCustomer. " + excp.Message); throw; } }
/// <summary> /// Processes a dialplan script (currently Ruby scripts only) for a received SIP INVITE request. /// </summary> /// <param name="coreLogDelegate">A function delegate that passes log/diagnostics events back to the SIP Proxy Core.</param> /// <param name="createBridgeDelegate">A function delegate that is called in the event that the dial plan command results in a call being answered and a bridge needing to be created.</param> /// <param name="localEndPoint">The SIP Proxy socket the request was received on.</param> /// <param name="remoteEndPoint">The socket the request was recevied from.</param> /// <param name="clientTransaction">The SIP Invite transaction that initiated the dial plan processing.</param> /// <param name="canonicalFromDomain">If (and only if) the call is an outgoing call this will be set to the canonical domain of the host in the SIP From /// header. An outgoing call is one from an authenticated user destined for an external SIP URI. If the call is an incoming this will be null.</param> /// <param name="canonicalToDomain">If (and only if) the call is an incoming call this will be set to the canonical domain of the host in the SIP URI /// request. An incoming call is one from an external caller to a URI corresponding to a hosted domain on this SIP Proxy.</param> private void ExecuteDialPlanScript( DialPlanScriptContext dialPlanContext, ISIPServerUserAgent uas, SIPCallDirection callDirection, DialogueBridgeCreatedDelegate createBridgeDelegate, ISIPCallManager callManager) { try { if (uas == null) { throw new ArgumentNullException("The ISIPServerUserAgent parameter cannot be null when attempting to execute a dialplan script."); } FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.NewCall, "Executing script dial plan for call to " + uas.CallDestination + ".", dialPlanContext.Owner)); if (!dialPlanContext.DialPlanScript.IsNullOrBlank()) { DialPlanExecutingScript dialPlanExecutionScript = null; int runningScriptCount = (from script in m_runningScripts where !script.Complete select script).Count(); if (runningScriptCount < MAX_ALLOWED_SCRIPTSCOPES) { m_dialPlanScriptContextsCreated++; //FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Creating DialPlanExecutingScript number " + m_dialPlanScriptContextsCreated + " for dialplan execution for script owned by " + dialPlanContext.Owner + ".", null)); dialPlanExecutionScript = new DialPlanExecutingScript(FireProxyLogEvent); } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Running script limit of " + MAX_ALLOWED_SCRIPTSCOPES + " reached.", null)); lock (m_runningScripts) { foreach (DialPlanExecutingScript runningScript in m_runningScripts) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, " running script owner=" + runningScript.Owner + ", dialplan name=" + runningScript.ExecutingDialPlanContext.SIPDialPlan.DialPlanName + ", start time=" + runningScript.StartTime.ToString("dd MMM yyyy HH:mm:ss") + ", is complete=" + runningScript.Complete + ".", null)); } } } if (dialPlanExecutionScript != null) { dialPlanExecutionScript.Initialise(dialPlanContext); DialPlanScriptFacade planFacade = new DialPlanScriptFacade( m_sipTransport, dialPlanExecutionScript, FireProxyLogEvent, createBridgeDelegate, (uas.CallRequest != null) ? uas.CallRequest.Copy() : null, // A different copy to the req object. Stops inadvertent changes in the dialplan. callDirection, dialPlanContext, GetCanonicalDomainDelegate_External, callManager, m_sipSorceryPersistor, m_outboundProxySocket, this); DialPlanCRMFacade crmFacade = new DialPlanCRMFacade(FireProxyLogEvent, dialPlanContext); DialPlanLookupFacade lookupFacade = new DialPlanLookupFacade(FireProxyLogEvent, dialPlanContext.Owner); ScriptScope rubyScope = dialPlanExecutionScript.DialPlanScriptScope; rubyScope.SetVariable(SCRIPT_HELPEROBJECT_NAME, planFacade); rubyScope.SetVariable(SCRIPT_CRMOBJECT_NAME, crmFacade); rubyScope.SetVariable(SCRIPT_LOOKUPOBJECT_NAME, lookupFacade); if (uas.CallRequest != null) { rubyScope.SetVariable(SCRIPT_REQUESTOBJECT_NAME, uas.CallRequest.Copy()); } dialPlanExecutionScript.DialPlanScriptThread = new Thread(new ParameterizedThreadStart(delegate { ExecuteScript(dialPlanExecutionScript, dialPlanContext, planFacade, m_rubyScriptCommon + dialPlanContext.DialPlanScript); })); lock (m_runningScripts) { m_runningScripts.Add(dialPlanExecutionScript); } dialPlanExecutionScript.DialPlanScriptThread.Start(); } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Error processing call " + uas.CallDestination + " there were no script slots available, script could not be executed.", dialPlanContext.Owner)); dialPlanContext.CallFailed(SIPResponseStatusCodesEnum.InternalServerError, "Dial plan script engine was overloaded", null); } } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A script dial plan was empty, execution cannot continue.", dialPlanContext.Owner)); dialPlanContext.CallFailed(SIPResponseStatusCodesEnum.InternalServerError, "Dial plan script was empty", null); } } catch (Exception excp) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Error executing script dialplan for " + uas.CallDestination + ". " + excp.Message, dialPlanContext.Owner)); dialPlanContext.CallFailed(SIPResponseStatusCodesEnum.InternalServerError, "Dial plan exception starting script", null); } }
/// <summary> /// Processes the matched dial plan command for an outgoing call request. This method is used for "exten =>" formatted dial plans. In addition if the dial /// plan owner has requested that their dialplan be used for incoming calls it will process those as well. /// </summary> /// <param name="localEndPoint">The SIP Proxy socket the request was received on.</param> /// <param name="remoteEndPoint">The socket the request was recevied from.</param> /// <param name="transaction">The SIP Invite transaction that initiated the dial plan processing.</param> /// <param name="manglePrivateAddresses">If true private IP addresses will be subtituted for the remote socket.</param> /// <param name="canonicalFromDomain">If (and only if) the call is an outgoing call this will be set to the canonical domain of the host in the SIP From /// header. An outgoing call is one from an authenticated user destined for an external SIP URI. If the call is an incoming this will be null.</param> /// <param name="canonicalToDomain">If (and only if) the call is an incoming call this will be set to the canonical domain of the host in the SIP URI /// request. An incoming call is one from an external caller to a URI corresponding to a hosted domain on this SIP Proxy.</param> private void ExecuteDialPlanLine( DialPlanLineContext dialPlanContext, ISIPServerUserAgent uas, SIPCallDirection callDirection, DialogueBridgeCreatedDelegate createBridgeDelegate, ISIPCallManager callManager) { try { //SIPRequest sipRequest = uas.CallRequest; FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Executing line dial plan for call to " + uas.CallDestination + ".", dialPlanContext.Owner)); DialPlanCommand matchedCommand = dialPlanContext.GetDialPlanMatch(uas.CallDestination); if (matchedCommand == null) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Destination " + uas.CallDestination + " not found in line dial plan " + dialPlanContext.SIPDialPlan.DialPlanName + ".", dialPlanContext.Owner)); dialPlanContext.CallFailed(SIPResponseStatusCodesEnum.NotFound, null, null); } else if (Regex.Match(matchedCommand.Command, "Switch|Dial", RegexOptions.IgnoreCase).Success) { if (matchedCommand.Data != null && matchedCommand.Data.Trim().Length > 0) { DialStringParser dialStringParser = new DialStringParser(m_sipTransport, dialPlanContext.Owner, dialPlanContext.SIPAccount, dialPlanContext.SIPProviders, m_sipSorceryPersistor.SIPAccountsPersistor.Get, m_sipSorceryPersistor.SIPRegistrarBindingPersistor.Get, GetCanonicalDomainDelegate_External, LogDelegate_External, dialPlanContext.SIPDialPlan.DialPlanName); ForkCall ForkCall = new ForkCall(m_sipTransport, FireProxyLogEvent, callManager.QueueNewCall, dialStringParser, dialPlanContext.Owner, dialPlanContext.AdminMemberId, m_outboundProxySocket, null, null); ForkCall.CallProgress += dialPlanContext.CallProgress; ForkCall.CallFailed += dialPlanContext.CallFailed; ForkCall.CallAnswered += dialPlanContext.CallAnswered; Queue<List<SIPCallDescriptor>> calls = dialStringParser.ParseDialString(DialPlanContextsEnum.Line, uas.CallRequest.Copy(), matchedCommand.Data, null, null, null, dialPlanContext.CallersNetworkId, null, null, null, null, CustomerServiceLevels.None); ForkCall.Start(calls); } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Error processing dialplan Dial command the dial string was empty.", dialPlanContext.Owner)); } } //else if (Regex.Match(matchedCommand.Command, "RTSP", RegexOptions.IgnoreCase).Success) //{ // RTSPApp rtspCall = new RTSPApp(FireProxyLogEvent, (UASInviteTransaction)transaction, dialPlanContext.Owner); // rtspCall.Start(matchedCommand.Data); //} else if (Regex.Match(matchedCommand.Command, "SIPReply", RegexOptions.IgnoreCase).Success) { string[] replyFields = matchedCommand.Data.Split(','); string statusMessage = (replyFields.Length > 1 && replyFields[1] != null) ? replyFields[1].Trim() : null; SIPResponseStatusCodesEnum status = SIPResponseStatusCodes.GetStatusTypeForCode(Convert.ToInt32(replyFields[0])); if ((int)status >= 300) { dialPlanContext.CallFailed(status, statusMessage, null); } else if ((int)status < 200) { dialPlanContext.CallProgress(status, statusMessage, null, null, null, null); } } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Command " + matchedCommand.Command + " is not a valid dial plan command.", dialPlanContext.Owner)); dialPlanContext.CallFailed(SIPResponseStatusCodesEnum.InternalServerError, "Invalid dialplan command " + matchedCommand.Command, null); } } catch (Exception excp) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Error executing line dialplan for " + uas.CallRequest.URI.ToString() + ". " + excp.Message, dialPlanContext.Owner)); dialPlanContext.DialPlanExecutionFinished(); } }
/// <summary> /// Processes the matched dial plan command for an outgoing call request. This method is used for "exten =>" formatted dial plans. In addition if the dial /// plan owner has requested that their dialplan be used for incoming calls it will process those as well. /// </summary> /// <param name="localEndPoint">The SIP Proxy socket the request was received on.</param> /// <param name="remoteEndPoint">The socket the request was recevied from.</param> /// <param name="transaction">The SIP Invite transaction that initiated the dial plan processing.</param> /// <param name="manglePrivateAddresses">If true private IP addresses will be subtituted for the remote socket.</param> /// <param name="canonicalFromDomain">If (and only if) the call is an outgoing call this will be set to the canonical domain of the host in the SIP From /// header. An outgoing call is one from an authenticated user destined for an external SIP URI. If the call is an incoming this will be null.</param> /// <param name="canonicalToDomain">If (and only if) the call is an incoming call this will be set to the canonical domain of the host in the SIP URI /// request. An incoming call is one from an external caller to a URI corresponding to a hosted domain on this SIP Proxy.</param> private void ExecuteDialPlanLine( DialPlanLineContext dialPlanContext, ISIPServerUserAgent uas, SIPCallDirection callDirection, DialogueBridgeCreatedDelegate createBridgeDelegate, ISIPCallManager callManager) { try { //SIPRequest sipRequest = uas.CallRequest; FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Executing line dial plan for call to " + uas.CallDestination + ".", dialPlanContext.Owner)); DialPlanCommand matchedCommand = dialPlanContext.GetDialPlanMatch(uas.CallDestination); if (matchedCommand == null) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Destination " + uas.CallDestination + " not found in line dial plan " + dialPlanContext.SIPDialPlan.DialPlanName + ".", dialPlanContext.Owner)); dialPlanContext.CallFailed(SIPResponseStatusCodesEnum.NotFound, null, null); } else if (Regex.Match(matchedCommand.Command, "Switch|Dial", RegexOptions.IgnoreCase).Success) { if (matchedCommand.Data != null && matchedCommand.Data.Trim().Length > 0) { DialStringParser dialStringParser = new DialStringParser(m_sipTransport, dialPlanContext.Owner, dialPlanContext.SIPAccount, dialPlanContext.SIPProviders, m_sipSorceryPersistor.SIPAccountsPersistor.Get, m_sipSorceryPersistor.SIPRegistrarBindingPersistor.Get, GetCanonicalDomainDelegate_External, LogDelegate_External, dialPlanContext.SIPDialPlan.DialPlanName); ForkCall ForkCall = new ForkCall(m_sipTransport, FireProxyLogEvent, callManager.QueueNewCall, dialStringParser, dialPlanContext.Owner, dialPlanContext.AdminMemberId, m_outboundProxySocket, null, null); ForkCall.CallProgress += dialPlanContext.CallProgress; ForkCall.CallFailed += dialPlanContext.CallFailed; ForkCall.CallAnswered += dialPlanContext.CallAnswered; Queue <List <SIPCallDescriptor> > calls = dialStringParser.ParseDialString(DialPlanContextsEnum.Line, uas.CallRequest.Copy(), matchedCommand.Data, null, null, null, dialPlanContext.CallersNetworkId, null, null, null, null, CustomerServiceLevels.None); ForkCall.Start(calls); } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Error processing dialplan Dial command the dial string was empty.", dialPlanContext.Owner)); } } //else if (Regex.Match(matchedCommand.Command, "RTSP", RegexOptions.IgnoreCase).Success) //{ // RTSPApp rtspCall = new RTSPApp(FireProxyLogEvent, (UASInviteTransaction)transaction, dialPlanContext.Owner); // rtspCall.Start(matchedCommand.Data); //} else if (Regex.Match(matchedCommand.Command, "SIPReply", RegexOptions.IgnoreCase).Success) { string[] replyFields = matchedCommand.Data.Split(','); string statusMessage = (replyFields.Length > 1 && replyFields[1] != null) ? replyFields[1].Trim() : null; SIPResponseStatusCodesEnum status = SIPResponseStatusCodes.GetStatusTypeForCode(Convert.ToInt32(replyFields[0])); if ((int)status >= 300) { dialPlanContext.CallFailed(status, statusMessage, null); } else if ((int)status < 200) { dialPlanContext.CallProgress(status, statusMessage, null, null, null, null); } } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Command " + matchedCommand.Command + " is not a valid dial plan command.", dialPlanContext.Owner)); dialPlanContext.CallFailed(SIPResponseStatusCodesEnum.InternalServerError, "Invalid dialplan command " + matchedCommand.Command, null); } } catch (Exception excp) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Error executing line dialplan for " + uas.CallRequest.URI.ToString() + ". " + excp.Message, dialPlanContext.Owner)); dialPlanContext.DialPlanExecutionFinished(); } }
private bool MatchIncomingCall(ISIPServerUserAgent incomingCall) { try { if (incomingCall.SIPAccount.Owner != m_username) { return false; } else if (m_clientCallCancelled) { // If the call has been cancelled then don't match to avoid chance of a new incoming call matching a dead Google Voice call. return false; } SIPHeader callHeader = incomingCall.CallRequest.Header; bool matchedCall = false; if (!m_fromURIUserRegexMatch.IsNullOrBlank()) { if (Regex.Match(callHeader.From.FromURI.User, m_fromURIUserRegexMatch).Success) { matchedCall = true; } } else if (callHeader.UnknownHeaders.Contains("X-GoogleVoice: true") && callHeader.To.ToURI.User == m_forwardingNumber.Substring(1)) { matchedCall = true; } if (matchedCall) { m_callbackCall = incomingCall; m_callbackCall.SetOwner(m_username, m_adminMemberId); m_waitForCallback.Set(); return true; } else { return false; } } catch (Exception excp) { logger.Error("Exception GoogleVoiceCall MatchIncomingCall. " + excp.Message); return false; } }
private void SIPServerUserAgent_CallCancelled(ISIPServerUserAgent uas) { logger.LogDebug("B2BUserAgent server call was cancelled."); m_uac?.Cancel(); }
private void Agent_CallCancelled(ISIPServerUserAgent uas) { agent = null; }
private void UASCallCancelled(ISIPServerUserAgent uas) { AppendTraceMessage("Incoming call cancelled for: " + uas.CallDestination + "\n"); ResetToCallStartState(); }
private bool GetDialPlanAndCustomer(string owner, string dialPlanName, ISIPServerUserAgent uas, out Customer customer, out SIPDialPlan dialPlan) { try { dialPlan = null; customer = m_customerPersistor.Get(c => c.CustomerUsername == owner); if (customer == null) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as no matching account found.", null)); uas.Reject(SIPResponseStatusCodesEnum.DoesNotExistAnywhere, "No matching user was found", null); } else if (customer.Suspended) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as account is suspended.", null)); uas.Reject(SIPResponseStatusCodesEnum.DoesNotExistAnywhere, "User account is suspended", null); } else if (customer.ServiceLevel == CustomerServiceLevels.PremiumPayReqd.ToString() || customer.ServiceLevel == CustomerServiceLevels.ProfessionalPayReqd.ToString() || customer.ServiceLevel == CustomerServiceLevels.SwitchboardPayReqd.ToString()) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as payment is outstanding.", null)); uas.Reject(SIPResponseStatusCodesEnum.PaymentRequired, null, null); } else if (dialPlanName.IsNullOrBlank() && uas.CallDirection == SIPCallDirection.Out) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for customer " + owner + " as no dialplan is configured for an " + uas.CallDirection + " call.", null)); uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "SIP account missing dialplan setting", null); } else { if (dialPlanName.IsNullOrBlank()) { // Incoming call with no dialplan. return true; } else { dialPlan = GetDialPlan_External(d => d.Owner == owner && d.DialPlanName == dialPlanName); if (dialPlan == null) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected, dialplan " + dialPlanName + " could not be found.", owner)); uas.Reject(SIPResponseStatusCodesEnum.InternalServerError, "Could not load dialplan " + dialPlanName, null); } else if (dialPlan != null && dialPlan.IsReadOnly) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call rejected for read only dialplan " + dialPlanName + ". Upgrade to a Premium service to enable.", owner)); uas.Reject(SIPResponseStatusCodesEnum.PaymentRequired, "Dial plan is readonly, upgrade to Premium service", null); } else if (customer.ServiceLevel == CustomerServiceLevels.Free.ToString() && dialPlan.ScriptType == SIPDialPlanScriptTypesEnum.Asterisk) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Your service level does not permit the use of Asterisk dial plans.", owner)); uas.Reject(SIPResponseStatusCodesEnum.PaymentRequired, "Free plans cannot use Asterisk dial plans", null); } else if (!IsDialPlanExecutionAllowed(dialPlan, customer)) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of dial plan " + dialPlanName + " was not processed as maximum execution count has been reached.", owner)); uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Dial plan execution exceeded maximum allowed", null); } else { if (m_dailyCallLimit == -1) { return true; } else { // Check whether the number of CDR's exceeds the daily call limit. DateTime yesterday = DateTime.Now.AddDays(-1); int cdrCount = m_sipCDRPersistor.Count(x => x.Owner == owner && x.Created > yesterday); if (cdrCount >= m_dailyCallLimit) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Execution of call for " + owner + " was not processed as daily call limit reached.", owner)); uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Daily call limit reached", null); } else { return true; } } } } } return false; } catch (Exception excp) { logger.Error("Exception GetDialPlanAndCustomer. " + excp.Message); throw; } }
private void ProcessNewCall(ISIPServerUserAgent uas) { //bool wasExecutionCountIncremented = false; Customer customer = null; SIPDialPlan dialPlan = null; try { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call Manager processing new call on thread " + Thread.CurrentThread.Name + " for " + uas.CallRequest.Method + " to " + uas.CallRequest.URI.ToString() + ".", null)); #region Do some pre-flight checks on the SIP account to determine if the call should be processed. if (uas.SIPAccount == null) { if (uas.CallRequest.URI.User == DISPATCHER_SIPACCOUNT_NAME) { // This is a call from the monitoring system allow to proceed. } else if (uas.CallDirection == SIPCallDirection.Out) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.CallRequest.Header.From.FromURI.ToParameterlessString() + " not found for outgoing call to " + uas.CallRequest.URI.ToString() + ".", null)); uas.Reject(SIPResponseStatusCodesEnum.Forbidden, null, null); return; } else if (uas.CallDirection == SIPCallDirection.In) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.CallRequest.URI.ToParameterlessString() + " not found for incoming call.", null)); uas.Reject(SIPResponseStatusCodesEnum.NotFound, null, null); return; } } else { if (uas.SIPAccount.IsDisabled) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.SIPAccount.SIPUsername + "@" + uas.SIPAccount.SIPDomain + " is disabled for " + uas.CallDirection + " call.", uas.SIPAccount.Owner)); uas.Reject(SIPResponseStatusCodesEnum.Forbidden, "SIP account disabled", null); return; } else if (uas.SIPAccount.IsIncomingOnly && uas.CallDirection == SIPCallDirection.Out) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SIP account " + uas.SIPAccount.SIPUsername + "@" + uas.SIPAccount.SIPDomain + " is not permitted to make outgoing calls", uas.SIPAccount.Owner)); uas.Reject(SIPResponseStatusCodesEnum.Forbidden, "SIP account not permitted to make outgoing calls", null); return; } } #endregion SIPURI callURI = (uas.CallRequest != null) ? uas.CallRequest.URI : null; SIPAccount sipAccount = uas.SIPAccount; if (uas.CallDirection == SIPCallDirection.In && callURI.User == DISPATCHER_SIPACCOUNT_NAME) { uas.NoCDR(); #region Create a pseudo-dialplan to process the monitoring process call. string pseudoScript = //"sys.Log(\"Dispatcher Call.\")\n" + "result = sys.DoesSIPAccountExist(\"" + DISPATCHER_SIPACCOUNT_NAME + "\")\n" + // Allows the test call to check the database connectivity. //"sys.Log(\"DoesSIPAccountExist result=#{result}.\")\n" + "sys.Respond(420, nil, \"DialPlanEngine-ExecutionCount: " + m_dialPlanEngine.ScriptCount + "\")\n"; SIPDialPlan dispatcherDialPlan = new SIPDialPlan(null, null, null, pseudoScript, SIPDialPlanScriptTypesEnum.Ruby); dispatcherDialPlan.Id = Guid.Empty; // Prevents the increment and decrement on the execution counts. DialPlanScriptContext scriptContext = new DialPlanScriptContext( Log_External, m_sipTransport, CreateDialogueBridge, m_outboundProxy, uas, dispatcherDialPlan, null, null, null, null, null, null); m_dialPlanEngine.Execute(scriptContext, uas, uas.CallDirection, null, this); #endregion } else { string dialPlanName = (uas.CallDirection == SIPCallDirection.Out) ? sipAccount.OutDialPlanName : sipAccount.InDialPlanName; string owner = (uas.IsB2B) ? uas.SIPAccount.Owner : uas.Owner; if (GetDialPlanAndCustomer(owner, dialPlanName, uas, out customer, out dialPlan)) { //IncrementDialPlanExecutionCount(dialPlan, customer, originalExecutionCount + 1); //IncrementCustomerExecutionCount(customer); //wasExecutionCountIncremented = true; if (dialPlan != null) { if (!uas.IsInvite && !dialPlan.AcceptNonInvite) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A " + uas.CallRequest.Method + " was rejected for dialplan " + dialPlanName + " as it does not accept non-INVITE requests.", owner)); uas.Reject(SIPResponseStatusCodesEnum.MethodNotAllowed, "User has chosen not to accept request type", null); return; } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Using dialplan " + dialPlanName + " for " + uas.CallDirection + " call to " + callURI.ToString() + ".", owner)); if (dialPlan.ScriptType == SIPDialPlanScriptTypesEnum.Asterisk) { DialPlanLineContext lineContext = new DialPlanLineContext( Log_External, m_sipTransport, CreateDialogueBridge, m_outboundProxy, uas, dialPlan, GetSIPProviders_External(p => p.Owner == owner, null, 0, Int32.MaxValue), m_traceDirectory, (uas.CallDirection == SIPCallDirection.Out) ? sipAccount.NetworkId : null, customer); //lineContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer);} ; m_dialPlanEngine.Execute(lineContext, uas, uas.CallDirection, CreateDialogueBridge, this); } else { dialPlan.AuthorisedApps = customer.AuthorisedApps + ";" + dialPlan.AuthorisedApps; DialPlanScriptContext scriptContext = new DialPlanScriptContext( Log_External, m_sipTransport, CreateDialogueBridge, m_outboundProxy, uas, dialPlan, GetSIPProviders_External(p => p.Owner == owner, null, 0, Int32.MaxValue), m_traceDirectory, (uas.CallDirection == SIPCallDirection.Out) ? sipAccount.NetworkId : null, customer, m_dialPlanEngine, GetCanonicalDomain_External); uas.SetDialPlanContextID(scriptContext.DialPlanContextID); //scriptContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer);}; m_dialPlanEngine.Execute(scriptContext, uas, uas.CallDirection, CreateDialogueBridge, this); } } } else if (uas.CallDirection == SIPCallDirection.In) { if (uas.IsB2B) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Dialplan could not be loaded for incoming B2B call to " + callURI.ToString() + ".", owner)); uas.Reject(SIPResponseStatusCodesEnum.InternalServerError, "Error loading incoming dial plan for B2B call", null); //DecrementCustomerExecutionCount(customer); } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No dialplan specified for incoming call to " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + ", registered bindings will be used.", owner)); // The SIP account has no dialplan for an incoming call therefore send to the SIP account's bindings. List<SIPRegistrarBinding> bindings = GetSIPAccountBindings_External(b => b.SIPAccountId == sipAccount.Id, null, 0, MAX_FORWARD_BINDINGS); if (bindings != null && bindings.Count > 0) { // Create a pseudo-dialplan to process the incoming call. string pseudoScript = "sys.Dial(\"" + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + "\")\n"; Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Forwarding incoming call for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " to " + bindings.Count + " bindings.", owner)); SIPDialPlan incomingDialPlan = new SIPDialPlan(sipAccount.Owner, null, null, pseudoScript, SIPDialPlanScriptTypesEnum.Ruby); incomingDialPlan.Id = Guid.Empty; // Prevents the increment and decrement on the execution counts. DialPlanScriptContext scriptContext = new DialPlanScriptContext( Log_External, m_sipTransport, CreateDialogueBridge, m_outboundProxy, uas, incomingDialPlan, null, m_traceDirectory, null, customer, null, GetCanonicalDomain_External); //scriptContext.DialPlanComplete += () => { DecrementCustomerExecutionCount(customer); }; m_dialPlanEngine.Execute(scriptContext, uas, uas.CallDirection, CreateDialogueBridge, this); } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No bindings available for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " returning temporarily not available.", owner)); uas.Reject(SIPResponseStatusCodesEnum.TemporarilyUnavailable, null, null); //DecrementDialPlanExecutionCount(null, customer.Id); //DecrementCustomerExecutionCount(customer); } } } else { // Couldn't load a dialplan for an outgoing call. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Dialplan could not be loaded for " + uas.CallDirection + " call to " + callURI.ToString() + ".", owner)); uas.Reject(SIPResponseStatusCodesEnum.InternalServerError, "Error loading dial plan", null); //DecrementDialPlanExecutionCount(null, customer.Id); //DecrementCustomerExecutionCount(customer); } } } } catch (Exception excp) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.Error, "Exception SIPCallManager ProcessNewCall. " + excp.Message, null)); uas.Reject(SIPResponseStatusCodesEnum.InternalServerError, "Exception ProcessNewCall", null); //if (wasExecutionCountIncremented) //{ //DecrementDialPlanExecutionCount(dialPlan, customer.Id); // DecrementCustomerExecutionCount(customer); //} } }
/// <summary> /// An incoming call was cancelled by the caller. /// </summary> private void IncomingCallCancelled(ISIPServerUserAgent uas) { //SetText(m_signallingStatus, "incoming call cancelled for: " + uas.CallDestination + "."); CallFinished(); }
private void Agent_TransactionComplete(ISIPServerUserAgent uas) { }