private SIPRequest GetUpdateRequest(SIPRequest inviteRequest, CRMHeaders crmHeaders) { SIPRequest updateRequest = new SIPRequest(SIPMethodsEnum.UPDATE, inviteRequest.URI); updateRequest.SetSendFromHints(inviteRequest.LocalSIPEndPoint); SIPHeader inviteHeader = inviteRequest.Header; SIPHeader updateHeader = new SIPHeader(inviteHeader.From, inviteHeader.To, inviteHeader.CSeq + 1, inviteHeader.CallId); inviteRequest.Header.CSeq++; updateRequest.Header = updateHeader; updateHeader.CSeqMethod = SIPMethodsEnum.UPDATE; updateHeader.Routes = inviteHeader.Routes; updateHeader.ProxySendFrom = inviteHeader.ProxySendFrom; SIPViaHeader viaHeader = new SIPViaHeader(new IPEndPoint(IPAddress.Any, 0), CallProperties.CreateBranchId()); updateHeader.Vias.PushViaHeader(viaHeader); return(updateRequest); }
//public DialPlanAppResult Dial(string data, CRMHeaders contact) //{ // return Dial(data, m_maxRingTime, 0, m_sipRequest, null); //} public DialPlanAppResult Dial(string data, int ringTimeout, int answeredCallLimit, CRMHeaders contact) { return Dial(data, ringTimeout, answeredCallLimit, m_sipRequest, contact); }
/// <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; } } }
/// <summary> /// Sets CRM headers for the dialplan context. Typically the CRM headers will contain extra information about the caller /// that has been obtained from an external CRM system. /// </summary> public void SetCallerCRMDetails(CRMHeaders crmHeader) { m_dialPlanContext.SetCallerDetails(crmHeader); }
public void Update(CRMHeaders crmHeaders) { throw new NotImplementedException(); }
/// <summary> /// Can't be used for local destinations! /// </summary> /// <param name="sipRequest"></param> /// <param name="command"></param> /// <returns></returns> private SIPCallDescriptor GetForwardsForExternalLeg( SIPRequest sipRequest, SIPURI callLegURI, string customContentType, string customContent, string fromDisplayName, string fromUsername, string fromHost, CRMHeaders contact) { try { SIPCallDescriptor sipCallDescriptor = null; Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Attempting to locate a provider for call leg: " + callLegURI.ToString() + ".", m_username)); bool providerFound = false; string contentType = (sipRequest != null) ? sipRequest.Header.ContentType : null; string content = (sipRequest != null) ? sipRequest.Body : null; if (!customContentType.IsNullOrBlank()) { contentType = customContentType; } if (!customContent.IsNullOrBlank()) { content = customContent; } IPAddress publicSDPAddress = PublicIPAddress; if (publicSDPAddress == null && sipRequest != null) { publicSDPAddress = SIPPacketMangler.GetRequestIPAddress(sipRequest); } if (m_sipProviders != null) { foreach (SIPProvider provider in m_sipProviders) { if (callLegURI.Host.ToUpper() == provider.ProviderName.ToUpper()) { if (provider.ProviderType == ProviderTypes.GoogleVoice) { sipCallDescriptor = new SIPCallDescriptor( provider.ProviderUsername, provider.ProviderPassword, callLegURI.User + "@" + provider.ProviderName, provider.GVCallbackNumber, provider.GVCallbackPattern, (provider.GVCallbackType != null) ? (int)provider.GVCallbackType.Value : DEFAULT_GVCALLBACK_TYPE, content, contentType); sipCallDescriptor.CRMHeaders = contact; providerFound = true; break; } else { SIPURI providerURI = SIPURI.ParseSIPURI(provider.ProviderServer); if (providerURI != null) { providerURI.User = callLegURI.User; if (callLegURI.Parameters.Count > 0) { foreach (string parameterName in callLegURI.Parameters.GetKeys()) { if (!providerURI.Parameters.Has(parameterName)) { providerURI.Parameters.Set(parameterName, callLegURI.Parameters.Get(parameterName)); } } } if (callLegURI.Headers.Count > 0) { foreach (string headerName in callLegURI.Headers.GetKeys()) { if (!providerURI.Headers.Has(headerName)) { providerURI.Headers.Set(headerName, callLegURI.Headers.Get(headerName)); } } } SIPFromHeader fromHeader = ParseFromHeaderOption(provider.ProviderFrom, sipRequest, provider.ProviderUsername, providerURI.Host); sipCallDescriptor = new SIPCallDescriptor( provider.ProviderUsername, provider.ProviderPassword, providerURI.ToString(), fromHeader.ToString(), providerURI.ToString(), null, SIPCallDescriptor.ParseCustomHeaders(SubstituteRequestVars(sipRequest, provider.CustomHeaders)), provider.ProviderAuthUsername, SIPCallDirection.Out, contentType, content, publicSDPAddress); sipCallDescriptor.CRMHeaders = contact; if (!provider.ProviderOutboundProxy.IsNullOrBlank()) { sipCallDescriptor.ProxySendFrom = provider.ProviderOutboundProxy.Trim(); } providerFound = true; if (provider.ProviderFrom.IsNullOrBlank()) { // If there is already a custom From header set on the provider that overrides the general settings. sipCallDescriptor.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost); } break; } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Could not parse SIP URI from Provider Server " + provider.ProviderServer + " in GetForwardsForExternalLeg.", m_username)); } } } } } if (!providerFound) { // Treat as an anonymous SIP URI. // Copy the From header so the tag can be removed before adding to the forwarded request. string fromHeaderStr = (sipRequest != null) ? sipRequest.Header.From.ToString() : m_anonymousFromURI; SIPFromHeader forwardedFromHeader = SIPFromHeader.ParseFromHeader(fromHeaderStr); forwardedFromHeader.FromTag = null; sipCallDescriptor = new SIPCallDescriptor( m_anonymousUsername, null, callLegURI.ToString(), forwardedFromHeader.ToString(), callLegURI.ToString(), null, null, null, SIPCallDirection.Out, contentType, content, publicSDPAddress); sipCallDescriptor.CRMHeaders = contact; sipCallDescriptor.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost); } return sipCallDescriptor; } catch (Exception excp) { logger.Error("Exception GetForwardsForExternalLeg. " + excp.Message); return null; } }
/// <summary> /// Creates a list of calls based on the registered contacts for a user registration. /// </summary> /// <param name="user"></param> /// <param name="domain"></param> /// <param name="from">The From header that will be set on the forwarded call leg.</param> /// <returns></returns> public List<SIPCallDescriptor> GetForwardsForLocalLeg( SIPRequest sipRequest, SIPAccount sipAccount, List<string> customHeaders, string customContentType, string customContent, string options, string callersNetworkId, string fromDisplayName, string fromUsername, string fromHost, CRMHeaders contact) { List<SIPCallDescriptor> localUserSwitchCalls = new List<SIPCallDescriptor>(); try { if (sipAccount == null) { throw new ApplicationException("Cannot lookup forwards for a null SIP account."); } List<SIPRegistrarBinding> bindings = GetRegistrarBindings_External(b => b.SIPAccountId == sipAccount.Id, null, 0, Int32.MaxValue); if (bindings != null) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, bindings.Count + " found for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + ".", m_username)); // Build list of registered contacts. for (int index = 0; index < bindings.Count; index++) { SIPRegistrarBinding binding = bindings[index]; SIPURI contactURI = binding.MangledContactSIPURI; // Determine the content based on a custom request, caller's network id and whether mangling is required. string contentType = (sipRequest != null) ? sipRequest.Header.ContentType : null; string content = (sipRequest != null) ? sipRequest.Body : null; if (!customContentType.IsNullOrBlank()) { contentType = customContentType; } if (!customContent.IsNullOrBlank()) { content = customContent; } IPAddress publicSDPAddress = PublicIPAddress; if (publicSDPAddress == null && sipRequest != null) { publicSDPAddress = SIPPacketMangler.GetRequestIPAddress(sipRequest); } string fromHeader = (sipRequest != null) ? sipRequest.Header.From.ToString() : m_anonymousFromURI; SIPCallDescriptor switchCall = new SIPCallDescriptor( null, null, contactURI.ToString(), fromHeader, new SIPToHeader(null, SIPURI.ParseSIPURIRelaxed(sipAccount.SIPUsername + "@" + sipAccount.SIPDomain), null).ToString(), null, customHeaders, null, SIPCallDirection.In, contentType, content, publicSDPAddress); switchCall.CRMHeaders = contact; // If the binding for the call is a switchboard add the custom switchboard headers. if (!sipRequest.Header.SwitchboardFrom.IsNullOrBlank()) { switchCall.SwitchboardHeaders.SwitchboardFrom = sipRequest.Header.SwitchboardFrom; } // If the binding has a proxy socket defined set the header to ask the upstream proxy to use it. if (binding.ProxySIPEndPoint != null) { switchCall.ProxySendFrom = binding.ProxySIPEndPoint.ToString(); } switchCall.ParseCallOptions(options); if (sipAccount != null && !sipAccount.NetworkId.IsNullOrBlank() && sipAccount.NetworkId == callersNetworkId) { switchCall.MangleResponseSDP = false; } switchCall.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost); localUserSwitchCalls.Add(switchCall); } } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No current bindings found for local SIP account " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + ".", m_username)); } return localUserSwitchCalls; } catch (Exception excp) { logger.Error("Exception GetForwardsForLocalLeg. " + excp); return localUserSwitchCalls; } }
/// <summary> /// Processes dial strings using the multi-legged format. Each leg is separated from the proceeding one by the | character and each subsequent leg /// will only be used if all the forwards in the preceeding one fail. Within each leg the forwards are separated by the & character. /// /// Example: /// Dial(123@provider1&provider2|[email protected]|provider4&456@provider5[,trace]) /// </summary> private Queue<List<SIPCallDescriptor>> ParseScriptDialString( SIPRequest sipRequest, string command, List<string> customHeaders, string customContentType, string customContent, string callersNetworkId, string fromDisplayName, string fromUsername, string fromHost, CRMHeaders contact) { try { Queue<List<SIPCallDescriptor>> callsQueue = new Queue<List<SIPCallDescriptor>>(); string[] followonLegs = command.Split(CALLLEG_FOLLOWON_SEPARATOR); foreach (string followOnLeg in followonLegs) { List<SIPCallDescriptor> switchCalls = new List<SIPCallDescriptor>(); string[] callLegs = followOnLeg.Split(CALLLEG_SIMULTANEOUS_SEPARATOR); foreach (string callLeg in callLegs) { if (!callLeg.IsNullOrBlank()) { // Strip off the options string if present. string options = null; string callLegDestination = callLeg; int optionsStartIndex = callLeg.IndexOf(CALLLEG_OPTIONS_START_CHAR); int optionsEndIndex = callLeg.IndexOf(CALLLEG_OPTIONS_END_CHAR); if (optionsStartIndex != -1) { callLegDestination = callLeg.Substring(0, optionsStartIndex); options = callLeg.Substring(optionsStartIndex, optionsEndIndex - optionsStartIndex); } // Determine whether the call forward is for a local domain or not. SIPURI callLegSIPURI = SIPURI.ParseSIPURIRelaxed(SubstituteRequestVars(sipRequest, callLegDestination)); if (callLegSIPURI != null && callLegSIPURI.User == null) { callLegSIPURI.User = sipRequest.URI.User; } if (callLegSIPURI != null) { string localDomain = GetCanonicalDomain_External(callLegSIPURI.Host, false); if (localDomain != null) { SIPAccount calledSIPAccount = GetSIPAccount_External(s => s.SIPUsername == callLegSIPURI.User && s.SIPDomain == localDomain); if (calledSIPAccount == null && callLegSIPURI.User.Contains(".")) { // A full lookup failed. Now try a partial lookup if the incoming username is in a dotted domain name format. string sipUsernameSuffix = callLegSIPURI.User.Substring(callLegSIPURI.User.LastIndexOf(".") + 1); calledSIPAccount = GetSIPAccount_External(s => s.SIPUsername == sipUsernameSuffix && s.SIPDomain == localDomain); } if (calledSIPAccount != null) { // An incoming dialplan won't be used if it's invoked from itself. if (calledSIPAccount.InDialPlanName.IsNullOrBlank() || (m_username == calledSIPAccount.Owner && m_dialPlanName == calledSIPAccount.InDialPlanName)) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg is for local domain looking up bindings for " + callLegSIPURI.User + "@" + localDomain + " for call leg " + callLegDestination + ".", m_username)); switchCalls.AddRange(GetForwardsForLocalLeg(sipRequest, calledSIPAccount, customHeaders, customContentType, customContent, options, callersNetworkId, fromDisplayName, fromUsername, fromHost, contact)); } else { // An incoming call for a SIP account that has an incoming dialplan specified. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg is for local domain forwarding to incoming dialplan for " + callLegSIPURI.User + "@" + localDomain + ".", m_username)); string sipUsername = (m_sipAccount != null) ? m_sipAccount.SIPUsername : m_username; string sipDomain = (m_sipAccount != null) ? m_sipAccount.SIPDomain : GetCanonicalDomain_External(SIPDomainManager.DEFAULT_LOCAL_DOMAIN, false); SIPFromHeader fromHeader = ParseFromHeaderOption(null, sipRequest, sipUsername, sipDomain); string content = customContent; string contentType = customContentType; if (contentType.IsNullOrBlank()) { contentType = sipRequest.Header.ContentType; } if (content.IsNullOrBlank()) { content = sipRequest.Body; } SIPCallDescriptor loopbackCall = new SIPCallDescriptor(calledSIPAccount, callLegSIPURI.ToString(), fromHeader.ToString(), contentType, content); loopbackCall.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost); loopbackCall.MangleIPAddress = (PublicIPAddress != null) ? PublicIPAddress : SIPPacketMangler.GetRequestIPAddress(sipRequest); loopbackCall.ParseCallOptions(options); switchCalls.Add(loopbackCall); } } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No sip account could be found for local call leg " + callLeg + ".", m_username)); } } else { // Construct a call forward for a remote destination. SIPCallDescriptor sipCallDescriptor = GetForwardsForExternalLeg(sipRequest, callLegSIPURI, customContentType, customContent, fromDisplayName, fromUsername, fromHost, contact); if (sipCallDescriptor != null) { // Add and provided custom headers to those already present in the call descriptor and overwrite if an existing // header is already present. if (customHeaders != null && customHeaders.Count > 0) { foreach (string customHeader in customHeaders) { string customHeaderValue = SubstituteRequestVars(sipRequest, customHeader); sipCallDescriptor.CustomHeaders.Add(customHeaderValue); } } sipCallDescriptor.ParseCallOptions(options); switchCalls.Add(sipCallDescriptor); } } } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Could not parse a SIP URI from " + callLeg + " in ParseMultiDialString.", m_username)); } } } // Calls will not be added if the URI is already in the queue! List<SIPCallDescriptor> callList = new List<SIPCallDescriptor>(); callsQueue.Enqueue(callList); foreach (SIPCallDescriptor callToAdd in switchCalls) { if (!IsURIInQueue(callsQueue, callToAdd.Uri)) { callList.Add(callToAdd); } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg " + callToAdd.Uri.ToString() + " already added duplicate ignored.", m_username)); } } } return callsQueue; } catch (Exception excp) { logger.Error("Exception ParseScriptDialString. " + excp.Message); throw excp; } }
/// <summary> /// Parses a dial string that has been used in a dial plan Dial command. The format of the dial string is likely to continue to evolve, check the class /// summary for the different formats available. This method determines which format the dial string is in and passes off to the appropriate method to /// build the call list. /// </summary> /// <param name="dialPlanType">The type of dialplan that generated the Dial command.</param> /// <param name="sipRequest">The SIP Request that originated this command. Can be null if the call was not initiated by a SIP request such as /// by a HTTP web service.</param> /// <param name="command">The Dial command string being parsed.</param> /// <param name="customHeaders">If non-empty contains a list of custom SIP headers that will be added to the forwarded request.</param> /// <param name="customContentType">If set indicates a custom content type header is required on the forwarded request and it /// overrides any other value.</param> /// <param name="customContent">If set indicates a custom body is required on the forwarded request and it /// overrides any other value.</param> /// <param name="callersNetworkId">If the call originated from a locally administered account this will hold the account's /// networkid which is used to determine if two local accounts are on the same network and therefore should have their SDP /// left alone.</param> /// <param name="fromDisplayName">If set will be used the From header display name instead of the value from the originating SIP request.</param> /// <param name="fromUsername">If set will be used the From header user name instead of the value from the originating SIP request.</param> /// <param name="fromHost">If set will be used the From header host instead of the value from the originating SIP request.</param> /// <returns>A queue where each item is a list of calls. If there was only a single forward there would only be one item in the list which contained a /// single call. For dial strings containing multiple forwards each queue item can be a list with multiple calls.</returns> public Queue<List<SIPCallDescriptor>> ParseDialString( DialPlanContextsEnum dialPlanType, SIPRequest sipRequest, string command, List<string> customHeaders, string customContentType, string customContent, string callersNetworkId, string fromDisplayName, string fromUsername, string fromHost, CRMHeaders contact) { try { if (command == null || command.Trim().Length == 0) { throw new ArgumentException("The dial string cannot be empty."); } else { Queue<List<SIPCallDescriptor>> prioritisedCallList = new Queue<List<SIPCallDescriptor>>(); if (dialPlanType == DialPlanContextsEnum.Line || (!command.Contains("[") && Regex.Match(command, @"\S+,.*,\S+").Success)) { // Singled legged call (Asterisk format). SIPCallDescriptor SIPCallDescriptor = ParseAsteriskDialString(command, sipRequest); List<SIPCallDescriptor> callList = new List<SIPCallDescriptor>(); callList.Add(SIPCallDescriptor); prioritisedCallList.Enqueue(callList); } else { // Multi legged call (Script sys.Dial format). //string providersString = (command.IndexOf(',') == -1) ? command : command.Substring(0, command.IndexOf(',')); prioritisedCallList = ParseScriptDialString(sipRequest, command, customHeaders, customContentType, customContent, callersNetworkId, fromDisplayName, fromUsername, fromHost, contact); } return prioritisedCallList; } } catch (Exception excp) { logger.Error("Exception ParseDialString. " + excp); throw excp; } }
public void SetCallerDetails(CRMHeaders crmHeaders) { try { CallerCRMDetails = crmHeaders; if (!CallerCRMDetails.Pending) { lock (m_uacWaitingForCallDetails) { if (m_uacWaitingForCallDetails.Count > 0) { foreach (var waitingUAC in m_uacWaitingForCallDetails) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Sending CRM caller details to " + waitingUAC.CallDescriptor.Uri + ".", Owner)); waitingUAC.Update(crmHeaders); m_uacCallDetailsSent.Add(waitingUAC); } m_uacWaitingForCallDetails.Clear(); } } } } catch (Exception excp) { logger.Error("Exception SetCallerDetails. " + excp.Message); } }
private SIPRequest GetUpdateRequest(SIPRequest inviteRequest, CRMHeaders crmHeaders) { SIPRequest updateRequest = new SIPRequest(SIPMethodsEnum.UPDATE, inviteRequest.URI); updateRequest.LocalSIPEndPoint = inviteRequest.LocalSIPEndPoint; SIPHeader inviteHeader = inviteRequest.Header; SIPHeader updateHeader = new SIPHeader(inviteHeader.From, inviteHeader.To, inviteHeader.CSeq + 1, inviteHeader.CallId); inviteRequest.Header.CSeq++; updateRequest.Header = updateHeader; updateHeader.CSeqMethod = SIPMethodsEnum.UPDATE; updateHeader.Routes = inviteHeader.Routes; updateHeader.ProxySendFrom = inviteHeader.ProxySendFrom; SIPViaHeader viaHeader = new SIPViaHeader(inviteRequest.LocalSIPEndPoint, CallProperties.CreateBranchId()); updateHeader.Vias.PushViaHeader(viaHeader); // Add custom CRM headers. if (crmHeaders != null) { updateHeader.CRMPersonName = crmHeaders.PersonName; updateHeader.CRMCompanyName = crmHeaders.CompanyName; updateHeader.CRMPictureURL = crmHeaders.AvatarURL; } return updateRequest; }
public void Update(CRMHeaders crmHeaders) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Sending UPDATE to " + m_serverTransaction.TransactionRequest.URI.ToString() + ".", Owner)); SIPRequest updateRequest = GetUpdateRequest(m_serverTransaction.TransactionRequest, crmHeaders); SIPNonInviteTransaction updateTransaction = m_sipTransport.CreateNonInviteTransaction(updateRequest, m_serverEndPoint, m_serverTransaction.LocalSIPEndPoint, m_outboundProxy); updateTransaction.TransactionTraceMessage += TransactionTraceMessage; updateTransaction.SendReliableRequest(); }
/// <summary> /// Looks up a person contact in the 37 Signals Highrise application. /// </summary> /// <param name="url">The URL of the Highrise account to attempt the lookup on.</param> /// <param name="authToken">The auth token for the Highrise account to attempt the lookup with.</param> /// <param name="name">The name of the person to attempt a match on.</param> /// <param name="addCallNote">If true it indicates a Highrise note should be created if a matching contact is found.</param> //public CRMHeaders LookupHighriseContact(string url, string authToken, string name, bool addCallNote, bool async) //{ // LogToMonitor(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Looking up Highrise contact on " + url + " for " + name + ".", m_context.Owner)); // if (async) // { // m_context.SetCallerDetails(new CRMHeaders() { Pending = true }); // ThreadPool.QueueUserWorkItem(delegate { DoLookup(url, authToken, name, addCallNote, (result) => { m_context.SetCallerDetails(result); }); }); // return null; // } // else // { // return DoLookup(url, authToken, name, addCallNote, null); // } //} private CRMHeaders DoLookup(string url, string authToken, SIPFromHeader from, bool addCallNote, Action<CRMHeaders> callback) { try { string searchString = null; string lookupType = null; if (from.FromName != null && Regex.Match(from.FromName, @"\D").Success) { // The From display name has a non-digit character do a name lookup. lookupType = "name"; searchString = from.FromName.Trim(); } else if (from.FromName != null) { // The From display name is all digits do a phone number lookup. lookupType = "phonenumber"; searchString = from.FromName.Trim(); } else if (!Regex.Match(from.FromURI.User, @"\D").Success) { // The From URI user is all digits do a phone number lookup. lookupType = "phonenumber"; searchString = from.FromURI.User.Trim(); } else { // Last resort is to do a SIP URI lookup. lookupType = "sipaddress"; searchString = from.FromURI.ToAOR(); } LogToMonitor(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Highrise contact lookup type " + lookupType + " commencing for " + searchString + ".", m_context.Owner)); CRMHeaders result = null; DateTime startLookup = DateTime.Now; PersonRequest personRequest = new PersonRequest(url, authToken); People people = null; if (lookupType == "name") { people = personRequest.GetByName(searchString); } else if (lookupType == "phonenumber") { people = personRequest.GetByPhoneNumber(searchString); } else if (lookupType == "sipaddress") { people = personRequest.GetByCustomField("sip_address", searchString); } if (people != null && people.PersonList != null && people.PersonList.Count > 0) { Person person = people.PersonList[0]; string companyName = null; if (person.CompanyID != null) { CompanyRequest companyRequest = new CompanyRequest(url, authToken); Company company = companyRequest.GetByID(person.CompanyID.Value); if (company != null) { companyName = company.Name; } } double secondsDuration = DateTime.Now.Subtract(startLookup).TotalSeconds; if (companyName != null) { LogToMonitor(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Highrise contact match " + person.FirstName + " " + person.LastName + " of " + companyName + ", time taken " + secondsDuration.ToString("0.##") + "s.", m_context.Owner)); } else { LogToMonitor(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Highrise contact match " + person.FirstName + " " + person.LastName + ", time taken " + secondsDuration.ToString("0.##") + "s.", m_context.Owner)); } //m_context.SetCallerDetails(new CRMHeaders(person.FirstName + " " + person.LastName, companyName, person.AvatarURL)); string personName = (!person.LastName.IsNullOrBlank()) ? person.FirstName + " " + person.LastName : person.FirstName; result = new CRMHeaders(personName, companyName, person.AvatarURL); if (addCallNote) { ThreadPool.QueueUserWorkItem(delegate { AddHighriseCallNote(url, authToken, from, person); }); } } else { double secondsDuration = DateTime.Now.Subtract(startLookup).TotalSeconds; LogToMonitor(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No Highrise contact match, time taken " + secondsDuration.ToString("0.##") + "s.", m_context.Owner)); result = new CRMHeaders() { Pending = false, LookupError = "No Highrise contact match." }; } if (callback != null) { callback(result); } return result; } catch (Exception excp) { logger.Error("Exception LookupHighriseContact. " + excp.Message); LogToMonitor(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Error looking up Highrise contact.", m_context.Owner)); var errorResult = new CRMHeaders() { Pending = false, LookupError = "Error looking up Highrise contact." }; if (callback != null) { callback(errorResult); } return errorResult; } }