public void CallFailed(SIPResponseStatusCodesEnum failureStatus, string reasonPhrase, string[] customHeaders)
 {
     try
     {
         if (m_sipServerUserAgent != null && !m_isAnswered)
         {
             Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call failed with a failure status of " + failureStatus + " and " + reasonPhrase + ".", Owner));
             m_isAnswered = true;
             if ((int)failureStatus >= 300 && (int)failureStatus <= 399)
             {
                 SIPURI redirectURI = SIPURI.ParseSIPURIRelaxed(customHeaders[0]);
                 m_sipServerUserAgent.Redirect(failureStatus, redirectURI);
             }
             else
             {
                 m_sipServerUserAgent.Reject(failureStatus, reasonPhrase, customHeaders);
             }
         }
     }
     catch (Exception excp)
     {
         logger.Error("Exception DialPlanContext CallFailed. " + excp.Message);
     }
     finally
     {
         DialPlanExecutionFinished();
     }
 }
 public void CallFailed(SIPResponseStatusCodesEnum failureStatus, string reasonPhrase, string[] customHeaders)
 {
     try
     {
         if (!m_isAnswered)
         {
             m_isAnswered = true;
             if ((int)failureStatus >= 300 && (int)failureStatus <= 399)
             {
                 SIPURI redirectURI = SIPURI.ParseSIPURIRelaxed(customHeaders[0]);
                 m_sipServerUserAgent.Redirect(failureStatus, redirectURI);
             }
             else
             {
                 m_sipServerUserAgent.Reject(failureStatus, reasonPhrase, customHeaders);
             }
         }
     }
     catch (Exception excp)
     {
         logger.Error("Exception DialPlanContext CallFailed. " + excp.Message);
     }
     finally
     {
         DialPlanExecutionFinished();
     }
 }
        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);
                //}
            }
        }
        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;
            }
        }
 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;
            }
        }