/// <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; } }