Start() public method

Starts a call based on a single multi forward call leg.
public Start ( List callDescriptors ) : void
callDescriptors List
return void
Ejemplo n.º 1
0
        private SIPDialogue Dial(
            ForkCall call,
            string data,
            int ringTimeout,
            int answeredCallLimit,
            SIPRequest clientRequest,
            List <string> customHeaders)
        {
            SIPDialogue      answeredDialogue     = null;
            ManualResetEvent waitForCallCompleted = new ManualResetEvent(false);

            //call.CallProgress += (s, r, h, t, b) => { Log("Progress response of " + s + " received on CallBack Dial" + "."); };
            call.CallProgress += CallProgress;
            call.CallFailed   += (s, r, h) => { waitForCallCompleted.Set(); };
            call.CallAnswered += (s, r, toTag, h, t, b, d, transferMode) => { answeredDialogue = d; waitForCallCompleted.Set(); };

            try {
                Queue <List <SIPCallDescriptor> > callsQueue = m_dialStringParser.ParseDialString(DialPlanContextsEnum.Script, clientRequest, data, customHeaders, null, null, null, null, null, null, null, CustomerServiceLevels.None);
                call.Start(callsQueue);

                // Wait for an answer.
                ringTimeout = (ringTimeout > MAXCALLBACK_RINGTIME_SECONDS || ringTimeout <= 0) ? MAXCALLBACK_RINGTIME_SECONDS : ringTimeout;
                logger.Debug("Set callback cancel timeout to " + ringTimeout + " seconds.");
                if (!waitForCallCompleted.WaitOne(ringTimeout * 1000, false))
                {
                    call.CancelNotRequiredCallLegs(CallCancelCause.TimedOut);
                }

                logger.Debug("Callback dial returning has dialogue ? " + (answeredDialogue == null) + ".");

                return(answeredDialogue);
            }
            catch (Exception excp) {
                logger.Error("Exception CallbackApp Dial. " + excp);
                return(null);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="ringTimeout"></param>
        /// <param name="answeredCallLimit"></param>
        /// <param name="redirectMode"></param>
        /// <param name="clientTransaction"></param>
        /// <param name="keepScriptAlive">If false will let the dial plan engine know the script has finished and the call is answered. For applications
        /// like Callback which need to have two calls answered it will be true.</param>
        /// <returns></returns>
        private DialPlanAppResult Dial(
            string data,
            int ringTimeout,
            int answeredCallLimit,
            SIPRequest clientRequest,
            CRMHeaders contact)
        {
            if (m_dialPlanContext.IsAnswered)
            {
                Log("The call has already been answered the Dial command was not processed.");
                return DialPlanAppResult.AlreadyAnswered;
            }
            else if (data.IsNullOrBlank())
            {
                Log("The dial string cannot be empty when calling Dial.");
                return DialPlanAppResult.Error;
            }
            else if (m_callInitialisationCount > MAX_CALLS_ALLOWED)
            {
                Log("You have exceeded the maximum allowed calls for a dialplan execution.");
                return DialPlanAppResult.Error;
            }
            else
            {
                Log("Commencing Dial with: " + data + ".");

                DialPlanAppResult result = DialPlanAppResult.Unknown;
                m_waitForCallCompleted = new ManualResetEvent(false);

                SIPResponseStatusCodesEnum answeredStatus = SIPResponseStatusCodesEnum.None;
                string answeredReason = null;
                string answeredContentType = null;
                string answeredBody = null;
                SIPDialogue answeredDialogue = null;
                SIPDialogueTransferModesEnum uasTransferMode = SIPDialogueTransferModesEnum.Default;
                int numberLegs = 0;

                QueueNewCallDelegate queueNewCall = (m_callManager != null) ? m_callManager.QueueNewCall : (QueueNewCallDelegate)null;
                m_currentCall = new ForkCall(m_sipTransport, FireProxyLogEvent, queueNewCall, m_dialStringParser, Username, m_adminMemberId, m_outboundProxySocket, m_callManager, m_dialPlanContext, out LastDialled);
                m_currentCall.CallProgress += m_dialPlanContext.CallProgress;
                m_currentCall.CallFailed += (status, reason, headers) =>
                {
                    LastFailureStatus = status;
                    LastFailureReason = reason;
                    result = DialPlanAppResult.Failed;
                    m_waitForCallCompleted.Set();
                };
                m_currentCall.CallAnswered += (status, reason, toTag, headers, contentType, body, dialogue, transferMode) =>
                {
                    answeredStatus = status;
                    answeredReason = reason;
                    answeredContentType = contentType;
                    answeredBody = body;
                    answeredDialogue = dialogue;
                    uasTransferMode = transferMode;
                    result = DialPlanAppResult.Answered;
                    m_waitForCallCompleted.Set();
                };

                try
                {
                    Queue<List<SIPCallDescriptor>> callsQueue = m_dialStringParser.ParseDialString(
                        DialPlanContextsEnum.Script,
                        clientRequest,
                        data,
                        m_customSIPHeaders,
                        m_customContentType,
                        m_customContent,
                        m_dialPlanContext.CallersNetworkId,
                        m_customFromName,
                        m_customFromUser,
                        m_customFromHost,
                        contact,
                        ServiceLevel);

                    List<SIPCallDescriptor>[] callListArray = callsQueue.ToArray();
                    callsQueue.ToList().ForEach((list) => numberLegs += list.Count);

                    if (numberLegs == 0)
                    {
                        Log("The dial string did not result in any call legs.");
                        return DialPlanAppResult.Error;
                    }
                    else
                    {
                        m_callInitialisationCount += numberLegs;
                        if (m_callInitialisationCount > MAX_CALLS_ALLOWED)
                        {
                            Log("You have exceeded the maximum allowed calls for a dialplan execution.");
                            return DialPlanAppResult.Error;
                        }
                    }

                    m_currentCall.Start(callsQueue);

                    // Wait for an answer.
                    if (ringTimeout <= 0 || ringTimeout * 1000 > m_maxRingTime)
                    {
                        ringTimeout = m_maxRingTime;
                    }
                    else
                    {
                        ringTimeout = ringTimeout * 1000;
                    }
                    ExtendScriptTimeout(ringTimeout / 1000 + DEFAULT_CREATECALL_RINGTIME);
                    DateTime startTime = DateTime.Now;

                    if (m_waitForCallCompleted.WaitOne(ringTimeout, false))
                    {
                        if (!m_clientCallCancelled)
                        {
                            if (result == DialPlanAppResult.Answered)
                            {
                                // The call limit duration is only used if there hasn't already been a per leg duration set on the call.
                                if (answeredCallLimit > 0 && answeredDialogue.CallDurationLimit == 0)
                                {
                                    answeredDialogue.CallDurationLimit = answeredCallLimit;
                                }

                                m_dialPlanContext.CallAnswered(answeredStatus, answeredReason, null, null, answeredContentType, answeredBody, answeredDialogue, uasTransferMode);

                                // Dial plan script stops once there is an answered call to bridge to or the client call is cancelled.
                                Log("Dial command was successfully answered in " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString("0.00") + "s.");

                                // Do some Google Analytics call tracking.
                                if (answeredDialogue.RemoteUserField != null)
                                {
                                    SendGoogleAnalyticsEvent("Call", "Answered", answeredDialogue.RemoteUserField.URI.Host, 1);
                                }

                                m_executingScript.StopExecution();
                            }
                            else if (result == DialPlanAppResult.Failed)
                            {
                                // Check whether any of the responses were redirects.
                                if (LastDialled != null && LastDialled.Count > 0)
                                {
                                    var redirect = (from trans in LastDialled
                                                    where trans.TransactionFinalResponse != null && trans.TransactionFinalResponse.StatusCode >= 300 &&
                                                        trans.TransactionFinalResponse.StatusCode <= 399 && trans.TransactionFinalResponse.Header.Contact != null
                                                        && trans.TransactionFinalResponse.Header.Contact.Count > 0
                                                    select trans.TransactionFinalResponse).FirstOrDefault();

                                    if (redirect != null)
                                    {
                                        m_redirectResponse = redirect;
                                        m_redirectURI = RedirectResponse.Header.Contact[0].ContactURI;
                                        result = DialPlanAppResult.Redirect;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (!m_clientCallCancelled)
                        {
                            // Call timed out.
                            m_currentCall.CancelNotRequiredCallLegs(CallCancelCause.TimedOut);
                            result = DialPlanAppResult.TimedOut;
                        }
                    }

                    if (m_clientCallCancelled)
                    {
                        Log("Dial command was halted by cancellation of client call after " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString("#.00") + "s.");
                        m_executingScript.StopExecution();
                    }

                    return result;
                }
                catch (ThreadAbortException)
                {
                    return DialPlanAppResult.Unknown;
                }
                catch (Exception excp)
                {
                    logger.Error("Exception DialPlanScriptFacade Dial. " + excp.Message);
                    return DialPlanAppResult.Error;
                }
            }
        }
Ejemplo n.º 3
0
        /// <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();
            }
        }
Ejemplo n.º 4
0
        private SIPDialogue Dial(
          string data,
          int ringTimeout,
          int answeredCallLimit,
          SIPRequest clientRequest,
          List<string> customHeaders)
        {
            SIPDialogue answeredDialogue = null;
            ManualResetEvent waitForCallCompleted = new ManualResetEvent(false);

            ForkCall call = new ForkCall(m_sipTransport, Log_External, m_callManager.QueueNewCall, null, m_username, m_adminMemberId, m_outboundProxy, m_callManager, null);
            //call.CallProgress += (s, r, h, t, b) => { Log("Progress response of " + s + " received on CallBack Dial" + "."); };
            call.CallProgress += CallProgress;
            call.CallFailed += (s, r, h) => { waitForCallCompleted.Set(); };
            call.CallAnswered += (s, r, toTag, h, t, b, d, transferMode) => { answeredDialogue = d; waitForCallCompleted.Set(); };

            try {
                Queue<List<SIPCallDescriptor>> callsQueue = m_dialStringParser.ParseDialString(DialPlanContextsEnum.Script, clientRequest, data, customHeaders, null, null, null, null, null, null, null, CustomerServiceLevels.None);
                call.Start(callsQueue);

                // Wait for an answer.
                ringTimeout = (ringTimeout > m_maxRingTime) ? m_maxRingTime : ringTimeout;
                if (waitForCallCompleted.WaitOne(ringTimeout * 1000, false)) {
                    // Call timed out.
                    call.CancelNotRequiredCallLegs(CallCancelCause.TimedOut);
                }

                return answeredDialogue;
            }
            catch (Exception excp) {
                logger.Error("Exception CallbackApp Dial. " + excp);
                return null;
            }
        }
Ejemplo n.º 5
0
        private SIPDialogue Dial(
            ForkCall call,
            string data,
            int ringTimeout,
            int answeredCallLimit,
            SIPRequest clientRequest,
            List<string> customHeaders)
        {
            SIPDialogue answeredDialogue = null;
            ManualResetEvent waitForCallCompleted = new ManualResetEvent(false);

            //call.CallProgress += (s, r, h, t, b) => { Log("Progress response of " + s + " received on CallBack Dial" + "."); };
            call.CallProgress += CallProgress;
            call.CallFailed += (s, r, h) => { waitForCallCompleted.Set(); };
            call.CallAnswered += (s, r, toTag, h, t, b, d, transferMode) => { answeredDialogue = d; waitForCallCompleted.Set(); };

            try {
                Queue<List<SIPCallDescriptor>> callsQueue = m_dialStringParser.ParseDialString(DialPlanContextsEnum.Script, clientRequest, data, customHeaders, null, null, null, null, null, null, null, CustomerServiceLevels.None);
                call.Start(callsQueue);

                // Wait for an answer.
                ringTimeout = (ringTimeout > MAXCALLBACK_RINGTIME_SECONDS || ringTimeout <= 0) ? MAXCALLBACK_RINGTIME_SECONDS : ringTimeout;
                logger.Debug("Set callback cancel timeout to " + ringTimeout + " seconds.");
                if (!waitForCallCompleted.WaitOne(ringTimeout * 1000, false)) {
                    call.CancelNotRequiredCallLegs(CallCancelCause.TimedOut);
                }

                logger.Debug("Callback dial returning has dialogue ? " + (answeredDialogue == null) + ".");

                return answeredDialogue;
            }
            catch (Exception excp) {
                logger.Error("Exception CallbackApp Dial. " + excp);
                return null;
            }
        }
Ejemplo n.º 6
0
        /// <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();
            }
        }