private SIPRequest GetInviteRequest(IPEndPoint localContact, string inviteBody, IPEndPoint dstEndPoint)
            {
                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI("sip:" + dstEndPoint));

                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader("<sip:" + localContact + ">"), SIPToHeader.ParseToHeader("<sip:" + dstEndPoint + ">"), 1, CallProperties.CreateNewCallId());
                inviteHeader.From.FromTag = CallProperties.CreateNewTag();
                inviteHeader.Contact = SIPContactHeader.ParseContactHeader("sip:" + localContact);
                inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
                inviteHeader.UserAgent = "unit test";
                inviteRequest.Header = inviteHeader;

                SIPViaHeader viaHeader = new SIPViaHeader(localContact.Address.ToString(), localContact.Port,CallProperties.CreateBranchId(), SIPProtocolsEnum.udp);
                inviteRequest.Header.Vias.PushViaHeader(viaHeader);

                //inviteRequest.Body = inviteBody;
                //inviteRequest.Header.ContentLength = inviteBody.Length;
                inviteRequest.Header.ContentType = "application/sdp";

                return inviteRequest;
            }
            public void NoMatchingProviderUnitTest()
            {
                Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);

                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI("sip:1234@localhost"));
                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader("<sip:joe@localhost>"), SIPToHeader.ParseToHeader("<sip:jane@localhost>"), 23, CallProperties.CreateNewCallId());
                SIPViaHeader viaHeader = new SIPViaHeader("127.0.0.1", 5060, CallProperties.CreateBranchId());
                inviteHeader.Vias.PushViaHeader(viaHeader);
                inviteRequest.Header = inviteHeader;

                List<SIPProvider> providers = new List<SIPProvider>();
                SIPProvider provider = new SIPProvider("test", "blueface", "test", "password", SIPURI.ParseSIPURIRelaxed("sip.blueface.ie"), null, null, null, null, 3600, null, null, null, false, false);
                providers.Add(provider);

                DialStringParser dialStringParser = new DialStringParser(null, "test", null, providers, delegate { return null; }, null, (host, wildcard) => { return null; }, null);
                Queue<List<SIPCallDescriptor>> callQueue = dialStringParser.ParseDialString(DialPlanContextsEnum.Script, inviteRequest, "303@noprovider", null, null, null, null, null);

                Assert.IsNotNull(callQueue, "The call list should be returned.");
                Assert.IsTrue(callQueue.Count == 1, "The call queue list should not have contained one leg.");
                List<SIPCallDescriptor> firstLeg = callQueue.Dequeue();

                Assert.IsNotNull(firstLeg, "The first call leg should exist.");
                Assert.IsTrue(firstLeg.Count == 1, "The first call leg should have had one switch call.");
                Assert.IsTrue(firstLeg[0].Username == DialStringParser.m_anonymousUsername, "The username for the first call leg was not correct.");
                Assert.IsTrue(firstLeg[0].Uri.ToString() == "sip:303@noprovider", "The destination URI for the first call leg was not correct.");

                Console.WriteLine("---------------------------------");
            }
        private void AdjustContactHeader(SIPHeader sipHeader, SIPEndPoint localSIPEndPoint, IPAddress publicIPAddress)
        {
            try
            {
                // Set the Contact URI on the outgoing requests depending on which SIP socket the request is being sent on and whether
                // the request is going to an external network.
                if (sipHeader.Contact != null && sipHeader.Contact.Count == 1)
                {
                    SIPEndPoint proxyContact = localSIPEndPoint.CopyOf();
                    if (publicIPAddress != null)
                    {
                        proxyContact = new SIPEndPoint(proxyContact.Protocol, publicIPAddress, proxyContact.Port);
                    }

                    sipHeader.Contact[0].ContactURI.Host = proxyContact.GetIPEndPoint().ToString();
                    sipHeader.Contact[0].ContactURI.Protocol = proxyContact.Protocol;
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception AdjustContactHeader. " + excp.Message);
                throw;
            }
        }
        public SIPRequest GetRequest(SIPMethodsEnum method, SIPURI uri, SIPToHeader to, SIPEndPoint localSIPEndPoint)
        {
            if (localSIPEndPoint == null)
            {
                localSIPEndPoint = GetDefaultSIPEndPoint();
            }

            SIPRequest request = new SIPRequest(method, uri);
            request.LocalSIPEndPoint = localSIPEndPoint;

            SIPContactHeader contactHeader = new SIPContactHeader(null, new SIPURI(SIPSchemesEnum.sip, localSIPEndPoint));
            SIPFromHeader fromHeader = new SIPFromHeader(null, contactHeader.ContactURI, CallProperties.CreateNewTag());
            SIPHeader header = new SIPHeader(contactHeader, fromHeader, to, 1, CallProperties.CreateNewCallId());
            request.Header = header;
            header.CSeqMethod = method;
            header.Allow = ALLOWED_SIP_METHODS;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            header.Vias.PushViaHeader(viaHeader);

            return request;
        }
        private SIPRequest GetByeRequest(SIPEndPoint localSIPEndPoint)
        {
            SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, RemoteTarget);
            SIPFromHeader byeFromHeader = SIPFromHeader.ParseFromHeader(LocalUserField.ToString());
            SIPToHeader byeToHeader = SIPToHeader.ParseToHeader(RemoteUserField.ToString());
            int cseq = CSeq + 1;

            SIPHeader byeHeader = new SIPHeader(byeFromHeader, byeToHeader, cseq, CallId);
            byeHeader.CSeqMethod = SIPMethodsEnum.BYE;
            byeRequest.Header = byeHeader;
            byeRequest.Header.Routes = RouteSet;
            byeRequest.Header.ProxySendFrom = ProxySendFrom;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            byeRequest.Header.Vias.PushViaHeader(viaHeader);

            return byeRequest;
        }
        private SIPResponse GetAuthReqdResponse(SIPRequest sipRequest, string nonce, string realm)
        {
            try
            {
                SIPResponse authReqdResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Unauthorised, null);
                SIPAuthenticationHeader authHeader = new SIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, realm, nonce);
                SIPHeader requestHeader = sipRequest.Header;
                SIPHeader unauthHeader = new SIPHeader(requestHeader.Contact, requestHeader.From, requestHeader.To, requestHeader.CSeq, requestHeader.CallId);

                if (unauthHeader.To.ToTag == null || unauthHeader.To.ToTag.Trim().Length == 0)
                {
                    unauthHeader.To.ToTag = CallProperties.CreateNewTag();
                }

                unauthHeader.CSeqMethod = requestHeader.CSeqMethod;
                unauthHeader.Vias = requestHeader.Vias;
                unauthHeader.AuthenticationHeader = authHeader;
                unauthHeader.Server = m_serverAgent;
                unauthHeader.MaxForwards = Int32.MinValue;

                authReqdResponse.Header = unauthHeader;

                return authReqdResponse;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetAuthReqdResponse. " + excp.Message);
                throw excp;
            }
        }
        /// <summary>
        /// In transaction ACK requests are for non-2xx responses, i.e. INVITE rejected and no dialogue being created.
        /// </summary>
        private SIPRequest GetInTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());
            ackRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId);
            header.CSeqMethod = SIPMethodsEnum.ACK;
            header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader;
            header.Routes = base.TransactionRequest.Header.Routes;
            header.ProxySendFrom = base.TransactionRequest.Header.ProxySendFrom;

            ackRequest.Header = header;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, sipResponse.Header.Vias.TopViaHeader.Branch);
            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return ackRequest;
        }
        private SIPRequest GetCancelRequest(SIPRequest inviteRequest)
        {
            SIPRequest cancelRequest = new SIPRequest(SIPMethodsEnum.CANCEL, inviteRequest.URI);
            cancelRequest.LocalSIPEndPoint = inviteRequest.LocalSIPEndPoint;

            SIPHeader inviteHeader = inviteRequest.Header;
            SIPHeader cancelHeader = new SIPHeader(inviteHeader.From, inviteHeader.To, inviteHeader.CSeq, inviteHeader.CallId);
            cancelRequest.Header = cancelHeader;
            cancelHeader.CSeqMethod = SIPMethodsEnum.CANCEL;
            cancelHeader.Routes = inviteHeader.Routes;
            cancelHeader.ProxySendFrom = inviteHeader.ProxySendFrom;
            cancelHeader.Vias = inviteHeader.Vias;

            return cancelRequest;
        }
        //private void ByeFinalResponseReceived(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        //{
        //    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "BYE response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + ".", Owner));
        //}
        private SIPRequest GetInviteRequest(SIPCallDescriptor sipCallDescriptor, string branchId, string callId, SIPEndPoint localSIPEndPoint, SIPRouteSet routeSet, string content, string contentType)
        {
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, sipCallDescriptor.Uri);
            inviteRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader inviteHeader = new SIPHeader(sipCallDescriptor.GetFromHeader(), SIPToHeader.ParseToHeader(sipCallDescriptor.To), 1, callId);

            inviteHeader.From.FromTag = CallProperties.CreateNewTag();

            // For incoming calls forwarded via the dial plan the username needs to go into the Contact header.
            inviteHeader.Contact = new List<SIPContactHeader>() { new SIPContactHeader(null, new SIPURI(inviteRequest.URI.Scheme, localSIPEndPoint)) };
            inviteHeader.Contact[0].ContactURI.User = sipCallDescriptor.Username;
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteHeader.UserAgent = m_userAgent;
            inviteHeader.Routes = routeSet;
            inviteRequest.Header = inviteHeader;

            if (!sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
            {
                inviteHeader.ProxySendFrom = sipCallDescriptor.ProxySendFrom;
            }

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, branchId);
            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            inviteRequest.Body = content;
            inviteRequest.Header.ContentLength = (inviteRequest.Body != null) ? inviteRequest.Body.Length : 0;
            inviteRequest.Header.ContentType = contentType;

            // Add custom switchboard headers.
            if (CallDescriptor.SwitchboardHeaders != null)
            {
                inviteHeader.SwitchboardOriginalCallID = CallDescriptor.SwitchboardHeaders.SwitchboardOriginalCallID;
                //inviteHeader.SwitchboardCallerDescription = CallDescriptor.SwitchboardHeaders.SwitchboardCallerDescription;
                inviteHeader.SwitchboardLineName = CallDescriptor.SwitchboardHeaders.SwitchboardLineName;
                //inviteHeader.SwitchboardOwner = CallDescriptor.SwitchboardHeaders.SwitchboardOwner;
                //inviteHeader.SwitchboardOriginalFrom = CallDescriptor.SwitchboardHeaders.SwitchboardOriginalFrom;
            }

            // Add custom CRM headers.
            if (CallDescriptor.CRMHeaders != null)
            {
                inviteHeader.CRMPersonName = CallDescriptor.CRMHeaders.PersonName;
                inviteHeader.CRMCompanyName = CallDescriptor.CRMHeaders.CompanyName;
                inviteHeader.CRMPictureURL = CallDescriptor.CRMHeaders.AvatarURL;
            }

            try
            {
                if (sipCallDescriptor.CustomHeaders != null && sipCallDescriptor.CustomHeaders.Count > 0)
                {
                    foreach (string customHeader in sipCallDescriptor.CustomHeaders)
                    {
                        if (customHeader.IsNullOrBlank())
                        {
                            continue;
                        }
                        else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
                        {
                            inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
                        }
                        else
                        {
                            inviteRequest.Header.UnknownHeaders.Add(customHeader);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception Parsing CustomHeader for GetInviteRequest. " + excp.Message + sipCallDescriptor.CustomHeaders);
            }

            return inviteRequest;
        }
        private SIPRequest GetInviteRequest(SIPDialogue dialogue, SIPEndPoint localSIPEndPoint, string body)
        {
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, dialogue.RemoteTarget);

            SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader(dialogue.LocalUserField.ToString()), SIPToHeader.ParseToHeader(dialogue.RemoteUserField.ToString()), dialogue.CSeq, dialogue.CallId);
            SIPURI contactURI = new SIPURI(dialogue.RemoteTarget.Scheme, localSIPEndPoint);
            inviteHeader.Contact = SIPContactHeader.ParseContactHeader("<" + contactURI.ToString() + ">");
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteRequest.Header = inviteHeader;
            inviteRequest.Header.Routes = dialogue.RouteSet;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            inviteRequest.Body = body;
            inviteRequest.Header.ContentLength = body.Length;
            inviteRequest.Header.ContentType = "application/sdp";

            return inviteRequest;
        }
        private SIPRequest GetByeRequest(SIPResponse inviteResponse, SIPURI byeURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, byeURI);
            byeRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPFromHeader byeFromHeader = inviteResponse.Header.From;
            SIPToHeader byeToHeader = inviteResponse.Header.To;
            int cseq = inviteResponse.Header.CSeq + 1;

            SIPHeader byeHeader = new SIPHeader(byeFromHeader, byeToHeader, cseq, inviteResponse.Header.CallId);
            byeHeader.CSeqMethod = SIPMethodsEnum.BYE;
            byeHeader.ProxySendFrom = m_serverTransaction.TransactionRequest.Header.ProxySendFrom;
            byeRequest.Header = byeHeader;

            byeRequest.Header.Routes = (inviteResponse.Header.RecordRoutes != null) ? inviteResponse.Header.RecordRoutes.Reversed() : null;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            byeRequest.Header.Vias.PushViaHeader(viaHeader);

            return byeRequest;
        }
        private SIPRequest GetCallbackInviteRequest(IPEndPoint localSIPEndPoint, string sdp)
        {
            string callBackURI = "sip:[email protected]";
            string callBackUserField = "<" + callBackURI + ">";
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, callBackURI);
            SIPHeader inviteHeader = new SIPHeader(callBackUserField, callBackUserField, 1, CallProperties.CreateNewCallId());
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteHeader.ContentType = "application/sdp";
            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            inviteHeader.Vias.PushViaHeader(viaHeader);
            inviteRequest.Header = inviteHeader;

            if (sdp == null)
            {
                sdp =
                   "v=0" + CRLF +
                    "o=- " + Crypto.GetRandomInt(1000, 5000).ToString() + " 2 IN IP4 " + localSIPEndPoint.Address.ToString() + CRLF +
                    "s=session" + CRLF +
                    "c=IN IP4 " + localSIPEndPoint.Address.ToString() + CRLF +
                    "t=0 0" + CRLF +
                    "m=audio " + Crypto.GetRandomInt(10000, 20000).ToString() + " RTP/AVP 0 18 101" + CRLF +
                    "a=rtpmap:0 PCMU/8000" + CRLF +
                    "a=rtpmap:18 G729/8000" + CRLF +
                    "a=rtpmap:101 telephone-event/8000" + CRLF +
                    "a=fmtp:101 0-16" + CRLF +
                    "a=recvonly";
            }
            inviteHeader.ContentLength = sdp.Length;
            inviteRequest.Body = sdp;

            return inviteRequest;
        }
        public SIPRequest GetRequest(SIPMethodsEnum method, SIPURI uri, SIPToHeader to, SIPEndPoint localSIPEndPoint)
        {
            if (localSIPEndPoint == null)
            {
                localSIPEndPoint = GetDefaultSIPEndPoint();
            }

            SIPRequest request = new SIPRequest(method, uri);
            request.LocalSIPEndPoint = localSIPEndPoint;

            SIPContactHeader contactHeader = new SIPContactHeader(null, new SIPURI(SIPSchemesEnum.sip, localSIPEndPoint));
            if (!String.IsNullOrWhiteSpace(m_contactGruu))
            {
                contactHeader.ContactURI.Parameters.Set("gr", m_contactGruu);
            }

            SIPFromHeader fromHeader = new SIPFromHeader(null, contactHeader.ContactURI, CallProperties.CreateNewTag());
            SIPHeader header = new SIPHeader(contactHeader, fromHeader, to, 1, CallProperties.CreateNewCallId());
            request.Header = header;
            header.CSeqMethod = method;
            header.Allow = ALLOWED_SIP_METHODS;

            if (m_serviceRoute != null)
                header.Routes.AddBottomRoute(m_serviceRoute);

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            header.Vias.PushViaHeader(viaHeader);

            return request;
        }
            private SIPRequest GetDummyINVITERequest(SIPURI dummyURI)
            {
                string dummyFrom = "<sip:[email protected]>";
                string dummyContact = "sip:127.0.0.1:1234";
                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, dummyURI);

                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader(dummyFrom), new SIPToHeader(null, dummyURI, null), 1, CallProperties.CreateNewCallId());
                inviteHeader.From.FromTag = CallProperties.CreateNewTag();
                inviteHeader.Contact = SIPContactHeader.ParseContactHeader(dummyContact);
                inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
                inviteHeader.UserAgent = "unittest";
                inviteRequest.Header = inviteHeader;

                SIPViaHeader viaHeader = new SIPViaHeader("127.0.0.1", 1234, CallProperties.CreateBranchId(), SIPProtocolsEnum.udp);
                inviteRequest.Header.Vias.PushViaHeader(viaHeader);

                inviteRequest.Body = "dummy";
                inviteRequest.Header.ContentLength = inviteRequest.Body.Length;
                inviteRequest.Header.ContentType = "application/sdp";

                return inviteRequest;
            }
            private SIPRequest GetOptionsRequest(SIPURI serverURI, int cseq, IPEndPoint contact)
            {
                SIPRequest optionsRequest = new SIPRequest(SIPMethodsEnum.OPTIONS, serverURI);

                SIPFromHeader fromHeader = new SIPFromHeader(null, SIPURI.ParseSIPURI("sip:" + contact.ToString()), null);
                SIPToHeader toHeader = new SIPToHeader(null, serverURI, null);

                string callId = CallProperties.CreateNewCallId();
                string branchId = CallProperties.CreateBranchId();

                SIPHeader header = new SIPHeader(fromHeader, toHeader, cseq, callId);
                header.CSeqMethod = SIPMethodsEnum.OPTIONS;
                header.MaxForwards = 0;

                SIPViaHeader viaHeader = new SIPViaHeader(contact.Address.ToString(), contact.Port, branchId);
                header.Vias.PushViaHeader(viaHeader);

                optionsRequest.Header = header;

                return optionsRequest;
            }
        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;
        }
        private SIPRequest GetRequest(SIPMethodsEnum method)
        {
            try
            {
                SIPURI uri = SIPURI.ParseSIPURIRelaxed(m_callDescriptor.Uri);

                SIPRequest request = new SIPRequest(method, uri);
                SIPFromHeader fromHeader = m_callDescriptor.GetFromHeader();
                fromHeader.FromTag = CallProperties.CreateNewTag();
                SIPToHeader toHeader = new SIPToHeader(null, uri, null);
                int cseq = Crypto.GetRandomInt(10000, 20000);

                SIPHeader header = new SIPHeader(fromHeader, toHeader, cseq, CallProperties.CreateNewCallId());
                header.CSeqMethod = method;
                header.UserAgent = m_userAgent;
                request.Header = header;

                SIPViaHeader viaHeader = new SIPViaHeader(m_sipTransport.GetDefaultSIPEndPoint(), CallProperties.CreateBranchId());
                request.Header.Vias.PushViaHeader(viaHeader);

                try
                {
                    if (m_callDescriptor.CustomHeaders != null && m_callDescriptor.CustomHeaders.Count > 0)
                    {
                        foreach (string customHeader in m_callDescriptor.CustomHeaders)
                        {
                            if (customHeader.IsNullOrBlank())
                            {
                                continue;
                            }
                            else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
                            {
                                request.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
                            }
                            else
                            {
                                request.Header.UnknownHeaders.Add(customHeader);
                            }
                        }
                    }
                }
                catch (Exception excp)
                {
                    logger.Error("Exception Parsing CustomHeader for SIPNonInviteClientUserAgent GetRequest. " + excp.Message + m_callDescriptor.CustomHeaders);
                }

                if (!m_callDescriptor.Content.IsNullOrBlank())
                {
                    request.Body = m_callDescriptor.Content;
                    request.Header.ContentType = m_callDescriptor.ContentType;
                    request.Header.ContentLength = request.Body.Length;
                }

                return request;
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPNonInviteClientUserAgent GetRequest. " + excp.Message);
                throw excp;
            }
        }
        private SIPRequest GetRegistrationRequest(SIPProvider sipProvider, SIPProviderBinding binding, SIPEndPoint localSIPEndPoint, int expiry, SIPEndPoint registrarEndPoint)
        {
            try
            {
                if (!binding.BindingSIPURI.Parameters.Has(m_regAgentContactId))
                {
                    binding.BindingSIPURI.Parameters.Set(m_regAgentContactId, Crypto.GetRandomString(6));
                }

                string realm = binding.RegistrarRealm;

                SIPURI registerURI = SIPURI.ParseSIPURIRelaxed(realm);
                SIPURI regUserURI = SIPURI.ParseSIPURIRelaxed(sipProvider.ProviderUsername + "@" + realm);

                SIPFromHeader fromHeader = new SIPFromHeader(null, regUserURI, CallProperties.CreateNewTag());
                SIPToHeader toHeader = new SIPToHeader(null, regUserURI, null);
                SIPContactHeader contactHeader = new SIPContactHeader(null, binding.BindingSIPURI);
                //contactHeader.Expires = binding.BindingExpiry;
                string callId = binding.Id.ToString();
                int cseq = ++binding.CSeq;

                SIPRequest registerRequest = new SIPRequest(SIPMethodsEnum.REGISTER, registerURI);
                registerRequest.LocalSIPEndPoint = localSIPEndPoint;
                SIPHeader header = new SIPHeader(contactHeader, fromHeader, toHeader, cseq, callId);
                header.CSeqMethod = SIPMethodsEnum.REGISTER;
                header.UserAgent = m_userAgentString;
                header.Expires = binding.BindingExpiry;

                SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
                header.Vias.PushViaHeader(viaHeader);

                SIPRoute registrarRoute = new SIPRoute(new SIPURI(binding.RegistrarServer.Scheme, registrarEndPoint), true);
                header.Routes.PushRoute(registrarRoute);

                if (sipProvider != null && !sipProvider.CustomHeaders.IsNullOrBlank())
                {
                    string[] customerHeadersList = sipProvider.CustomHeaders.Split(SIPProvider.CUSTOM_HEADERS_SEPARATOR);

                    if (customerHeadersList != null && customerHeadersList.Length > 0)
                    {
                        foreach (string customHeader in customerHeadersList)
                        {
                            if (customHeader.IndexOf(':') == -1)
                            {
                                logger.Debug("Skipping custom header due to missing colon, " + customHeader + ".");
                                continue;
                            }
                            else
                            {
                                string headerName = customHeader.Substring(0, customHeader.IndexOf(':'));
                                if (headerName != null && Regex.Match(headerName.Trim(), "(Via|From|To|Contact|CSeq|Call-ID|Max-Forwards|Content)", RegexOptions.IgnoreCase).Success)
                                {
                                    logger.Debug("Skipping custom header due to an non-permitted string in header name, " + customHeader + ".");
                                    continue;
                                }
                                else
                                {
                                    if (headerName == SIPConstants.SIP_USERAGENT_STRING)
                                    {
                                        header.UserAgent = customHeader.Substring(customHeader.IndexOf(':') + 1);
                                    }
                                    else
                                    {
                                        header.UnknownHeaders.Add(customHeader.Trim());
                                    }
                                }
                            }
                        }
                    }
                }

                registerRequest.Header = header;
                return registerRequest;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetRegistrationRequest. " + excp.Message);
                throw excp;
            }
        }
        private SIPResponse GetErrorResponse(SIPRequest sipRequest, SIPResponseStatusCodesEnum errorResponseCode, string errorMessage)
        {
            try
            {
                SIPResponse errorResponse = SIPTransport.GetResponse(sipRequest, errorResponseCode, null);
                if (errorMessage != null)
                {
                    errorResponse.ReasonPhrase = errorMessage;
                }

                SIPHeader requestHeader = sipRequest.Header;
                SIPHeader errorHeader = new SIPHeader(requestHeader.Contact, requestHeader.From, requestHeader.To, requestHeader.CSeq, requestHeader.CallId);

                if (errorHeader.To.ToTag == null || errorHeader.To.ToTag.Trim().Length == 0)
                {
                    errorHeader.To.ToTag = CallProperties.CreateNewTag();
                }

                errorHeader.CSeqMethod = requestHeader.CSeqMethod;
                errorHeader.Vias = requestHeader.Vias;
                errorHeader.Server = m_serverAgent;
                errorHeader.MaxForwards = Int32.MinValue;

                errorResponse.Header = errorHeader;

                return errorResponse;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetErrorResponse. " + excp.Message);
                throw excp;
            }
        }
        /*private void IncrementDialPlanExecutionCount(SIPDialPlan dialPlan, Customer customer, int customerExecutionCount)
        {
            try
            {
                using (var trans = new TransactionScope())
                {
                    if (dialPlan != null && dialPlan.Id != Guid.Empty)
                    {
                        int executionCount = Convert.ToInt32(m_dialPlanPersistor.GetProperty(dialPlan.Id, m_sipDialPlanExecutionCountPropertyName));
                        logger.Debug("Incrementing dial plan execution count for " + dialPlan.DialPlanName + "@" + dialPlan.Owner + ", currently=" + executionCount + ".");
                        m_dialPlanPersistor.UpdateProperty(dialPlan.Id, m_sipDialPlanExecutionCountPropertyName, executionCount + 1);
                    }

                    int customerExecutionCount = Convert.ToInt32(m_customerPersistor.GetProperty(customer.Id, m_sipDialPlanExecutionCountPropertyName));
                    logger.Debug("Incrementing customer execution count for " + customer.CustomerUsername + ", currently=" + customerExecutionCount + ".");
                    m_customerPersistor.UpdateProperty(customer.Id, m_sipDialPlanExecutionCountPropertyName, customerExecutionCount + 1);

                    trans.Complete();
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPCallManager IncrementDialPlanExecutionCount. " + excp.Message);
                throw;
            }
        }

        private void DecrementDialPlanExecutionCount(SIPDialPlan dialPlan, Guid customerId, int customerExecutionCount)
        {
            try
            {
                using (var trans = new TransactionScope())
                {
                    if (dialPlan != null && dialPlan.Id != Guid.Empty)
                    {
                        int executionCount = Convert.ToInt32(m_dialPlanPersistor.GetProperty(dialPlan.Id, m_sipDialPlanExecutionCountPropertyName));
                        logger.Debug("Decrementing dial plan execution count for " + dialPlan.DialPlanName + "@" + dialPlan.Owner + ", currently=" + executionCount + ".");
                        executionCount = (executionCount > 0) ? executionCount - 1 : 0;
                        m_dialPlanPersistor.UpdateProperty(dialPlan.Id, m_sipDialPlanExecutionCountPropertyName, executionCount);
                    }

                    if (customerId != Guid.Empty)
                    {
                        int customerExecutionCount = Convert.ToInt32(m_customerPersistor.GetProperty(customerId, m_sipDialPlanExecutionCountPropertyName));
                        logger.Debug("Decrementing customer execution count for customer ID " + customerId + ", currently=" + customerExecutionCount + ".");
                        customerExecutionCount = (customerExecutionCount > 0) ? customerExecutionCount - 1 : 0;
                        m_customerPersistor.UpdateProperty(customerId, m_sipDialPlanExecutionCountPropertyName, customerExecutionCount);
                    }

                    trans.Complete();
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPCallManager DecrementDialPlanExecutionCount. " + excp.Message);
            }
        }*/
        /*private void IncrementCustomerExecutionCount(Customer customer)
        {
            try
            {
                execCountlogger.Info("Increment " + customer.CustomerUsername + ", current=" + customer.ExecutionCount + " (pid " + m_pid + ").");
                m_customerPersistor.IncrementProperty(customer.Id, m_sipDialPlanExecutionCountPropertyName);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPCallManager IncrementCustomerExecutionCount. " + excp.Message);
            }
        }

        private void DecrementCustomerExecutionCount(Customer customer)
        {
            try
            {
                execCountlogger.Info("Decrement " + customer.CustomerUsername + " (pid " + m_pid + ").");
                m_customerPersistor.DecrementProperty(customer.Id, m_sipDialPlanExecutionCountPropertyName);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPCallManager DecrementCustomerExecutionCount. " + excp.Message);
            }
        }*/
        /// <summary>
        /// Creates a dummy INVITE transaction to act as a substitute incoming call for dialplan executions that have been initiated from
        /// a web request.
        /// </summary>
        /// <param name="number">The number that will end up as req.URI.User in the dialplan.</param>
        private UASInviteTransaction GetDummyWebCallbackTransaction(string number)
        {
            SIPRequest dummyInvite = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURIRelaxed(number + "@sipsorcery.com"));
            SIPHeader dummyHeader = new SIPHeader("<sip:[email protected]>", "<sip:[email protected]>", 1, CallProperties.CreateNewCallId());
            dummyHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            SIPEndPoint blackholeEndPoint = new SIPEndPoint(new IPEndPoint(SIPTransport.BlackholeAddress, 0));
            dummyHeader.Vias.PushViaHeader(new SIPViaHeader(blackholeEndPoint, CallProperties.CreateBranchId()));
            dummyInvite.Header = dummyHeader;
            UASInviteTransaction dummyTransaction = m_sipTransport.CreateUASTransaction(dummyInvite, blackholeEndPoint, blackholeEndPoint, null);
            return dummyTransaction;
        }
        /// <summary>
        /// New transaction ACK requests are for 2xx responses, i.e. INVITE accepted and dialogue being created.
        /// </summary>
        /// <remarks>
        /// From RFC 3261 Chapter 17.1.1.3 - ACK for non-2xx final responses
        /// 
        /// IMPORTANT:
        /// an ACK for a non-2xx response will also have the same branch ID as the INVITE whose response it acknowledges.
        /// 
        /// The ACK request constructed by the client transaction MUST contain
        /// values for the Call-ID, From, and Request-URI that are equal to the
        /// values of those header fields in the request passed to the transport
        /// by the client transaction (call this the "original request").  The To
        /// header field in the ACK MUST equal the To header field in the
        /// response being acknowledged, and therefore will usually differ from
        /// the To header field in the original request by the addition of the
        /// tag parameter.  The ACK MUST contain a single Via header field, and
        /// this MUST be equal to the top Via header field of the original
        /// request.  The CSeq header field in the ACK MUST contain the same
        /// value for the sequence number as was present in the original request,
        /// but the method parameter MUST be equal to "ACK".
        ///
        /// If the INVITE request whose response is being acknowledged had Route
        /// header fields, those header fields MUST appear in the ACK.  This is
        /// to ensure that the ACK can be routed properly through any downstream
        /// stateless proxies.
        /// 
        /// From RFC 3261 Chapter 13.2.2.4 - ACK for 2xx final responses
        /// 
        /// IMPORTANT:
        /// an ACK for a 2xx final response is a new transaction and has a new branch ID.
        /// 
        /// The UAC core MUST generate an ACK request for each 2xx received from
        /// the transaction layer.  The header fields of the ACK are constructed
        /// in the same way as for any request sent within a dialog (see Section
        /// 12) with the exception of the CSeq and the header fields related to
        /// authentication.  The sequence number of the CSeq header field MUST be
        /// the same as the INVITE being acknowledged, but the CSeq method MUST
        /// be ACK.  The ACK MUST contain the same credentials as the INVITE.  If
        /// the 2xx contains an offer (based on the rules above), the ACK MUST
        /// carry an answer in its body.  If the offer in the 2xx response is not
        /// acceptable, the UAC core MUST generate a valid answer in the ACK and
        /// then send a BYE immediately.
        /// </remarks>
        private SIPRequest GetNewTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());
            ackRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId);
            header.CSeqMethod = SIPMethodsEnum.ACK;
            header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader;
            header.ProxySendFrom = base.TransactionRequest.Header.ProxySendFrom;

            if (sipResponse.Header.RecordRoutes != null)
            {
                header.Routes = sipResponse.Header.RecordRoutes.Reversed();
            }

            ackRequest.Header = header;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return ackRequest;
        }
            public void MultipleForwardsWithLocalUnitTest()
            {
                Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);

                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI("sip:1234@localhost"));
                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader("<sip:joe@localhost>"), SIPToHeader.ParseToHeader("<sip:jane@localhost>"), 23, CallProperties.CreateNewCallId());
                SIPViaHeader viaHeader = new SIPViaHeader("127.0.0.1", 5060, CallProperties.CreateBranchId());
                inviteHeader.Vias.PushViaHeader(viaHeader);
                inviteRequest.Header = inviteHeader;

                List<SIPProvider> providers = new List<SIPProvider>();
                SIPProvider provider = new SIPProvider("test", "provider1", "user", "password", SIPURI.ParseSIPURIRelaxed("sip.blueface.ie"), null, null, null, null, 3600, null, null, null, false, false);
                SIPProvider provider2 = new SIPProvider("test", "provider2", "user", "password", SIPURI.ParseSIPURIRelaxed("sip.blueface.ie"), null, null, null, null, 3600, null, null, null, false, false);
                providers.Add(provider);
                providers.Add(provider2);

                DialStringParser dialStringParser = new DialStringParser(null, "test", null, providers, (where) => { return null; }, (where, offset, count, orderby) => { return null; }, (host, wildcard) => { return null; }, null);
                Queue<List<SIPCallDescriptor>> callQueue = dialStringParser.ParseDialString(DialPlanContextsEnum.Script, inviteRequest, "local&1234@provider2", null, null, null, null, null);

                Assert.IsNotNull(callQueue, "The call list should have contained a call.");
                Assert.IsTrue(callQueue.Count == 1, "The call queue list should have contained one leg.");

                List<SIPCallDescriptor> firstLeg = callQueue.Dequeue();

                Assert.IsNotNull(firstLeg, "The first call leg should exist.");
                Assert.IsTrue(firstLeg.Count == 2, "The first call leg should have had two switch calls.");

                Console.WriteLine("First destination uri=" + firstLeg[0].Uri.ToString());
                Console.WriteLine("Second destination uri=" + firstLeg[1].Uri.ToString());

                Console.WriteLine("---------------------------------");
            }
        public static SIPHeader ParseSIPHeaders(string[] headersCollection)
        {
            try
            {
                SIPHeader sipHeader = new SIPHeader();
                sipHeader.MaxForwards = -1;		// This allows detection of whether this header is present or not.
                string lastHeader = null;

                for (int lineIndex = 0; lineIndex < headersCollection.Length; lineIndex++)
                {
                    string headerLine = headersCollection[lineIndex];

                    if (headerLine.IsNullOrBlank())
                    {
                        // No point processing blank headers.
                        continue;
                    }

                    string headerName = null;
                    string headerValue = null;

                    // If the first character of a line is whitespace it's a contiuation of the previous line.
                    if (headerLine.StartsWith(" "))
                    {
                        headerName = lastHeader;
                        headerValue = headerLine.Trim();
                    }
                    else
                    {
                        headerLine = headerLine.Trim();
                        int delimiterIndex = headerLine.IndexOf(SIPConstants.HEADER_DELIMITER_CHAR);

                        if (delimiterIndex == -1)
                        {
                            logger.Warn("Invalid SIP header, ignoring, " + headerLine + ".");
                            continue;
                        }

                        headerName = headerLine.Substring(0, delimiterIndex).Trim();
                        headerValue = headerLine.Substring(delimiterIndex + 1).Trim();
                    }

                    try
                    {
                        string headerNameLower = headerName.ToLower();

                        #region Via
                        if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_VIA.ToLower() ||
                            headerNameLower == SIPHeaders.SIP_HEADER_VIA.ToLower())
                        {
                            //sipHeader.RawVia += headerValue;

                            SIPViaHeader[] viaHeaders = SIPViaHeader.ParseSIPViaHeader(headerValue);

                            if (viaHeaders != null && viaHeaders.Length > 0)
                            {
                                foreach (SIPViaHeader viaHeader in viaHeaders)
                                {
                                    sipHeader.Vias.AddBottomViaHeader(viaHeader);
                                }
                            }
                        }
                        #endregion
                        #region CallId
                        else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CALLID.ToLower() ||
                                headerNameLower == SIPHeaders.SIP_HEADER_CALLID.ToLower())
                        {
                            sipHeader.CallId = headerValue;
                        }
                        #endregion
                        #region CSeq
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CSEQ.ToLower())
                        {
                            //sipHeader.RawCSeq += headerValue;

                            string[] cseqFields = headerValue.Split(' ');
                            if (cseqFields == null || cseqFields.Length == 0)
                            {
                                logger.Warn("The " + SIPHeaders.SIP_HEADER_CSEQ + " was empty.");
                            }
                            else
                            {
                                if (!Int32.TryParse(cseqFields[0], out sipHeader.CSeq))
                                {
                                    logger.Warn(SIPHeaders.SIP_HEADER_CSEQ + " did not contain a valid integer, " + headerLine + ".");
                                }

                                if (cseqFields != null && cseqFields.Length > 1)
                                {
                                    sipHeader.CSeqMethod = SIPMethods.GetMethod(cseqFields[1]);
                                }
                                else
                                {
                                    logger.Warn("There was no " + SIPHeaders.SIP_HEADER_CSEQ + " method, " + headerLine + ".");
                                }
                            }
                        }
                        #endregion
                        #region Expires
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_EXPIRES.ToLower())
                        {
                            //sipHeader.RawExpires += headerValue;

                            if (!Int32.TryParse(headerValue, out sipHeader.Expires))
                            {
                                logger.Warn("The Expires value was not a valid integer, " + headerLine + ".");
                            }
                        }
                        #endregion
                        #region Min-Expires
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_MINEXPIRES.ToLower())
                        {
                            if (!Int32.TryParse(headerValue, out sipHeader.MinExpires))
                            {
                                logger.Warn("The Min-Expires value was not a valid integer, " + headerLine + ".");
                            }
                        }
                        #endregion
                        #region Contact
                        else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CONTACT.ToLower() ||
                            headerNameLower == SIPHeaders.SIP_HEADER_CONTACT.ToLower())
                        {
                            List<SIPContactHeader> contacts = SIPContactHeader.ParseContactHeader(headerValue);
                            if(contacts != null && contacts.Count > 0)
                            {
                                sipHeader.Contact.AddRange(contacts);
                            }
                        }
                        #endregion
                        #region From
                        else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_FROM.ToLower() ||
                             headerNameLower == SIPHeaders.SIP_HEADER_FROM.ToLower())
                        {
                            //sipHeader.RawFrom = headerValue;
                            sipHeader.From = SIPFromHeader.ParseFromHeader(headerValue);
                        }
                        #endregion
                        #region To
                        else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_TO.ToLower() ||
                            headerNameLower == SIPHeaders.SIP_HEADER_TO.ToLower())
                        {
                            //sipHeader.RawTo = headerValue;
                            sipHeader.To = SIPToHeader.ParseToHeader(headerValue);
                        }
                        #endregion
                        #region WWWAuthenticate
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_WWWAUTHENTICATE.ToLower())
                        {
                            //sipHeader.RawAuthentication = headerValue;
                            sipHeader.AuthenticationHeader = SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, headerValue);
                        }
                        #endregion
                        #region Authorization
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_AUTHORIZATION.ToLower())
                        {
                            //sipHeader.RawAuthentication = headerValue;
                            sipHeader.AuthenticationHeader = SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.Authorize, headerValue);
                        }
                        #endregion
                        #region ProxyAuthentication
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXYAUTHENTICATION.ToLower())
                        {
                            //sipHeader.RawAuthentication = headerValue;
                            sipHeader.AuthenticationHeader = SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.ProxyAuthenticate, headerValue);
                        }
                        #endregion
                        #region ProxyAuthorization
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXYAUTHORIZATION.ToLower())
                        {
                            sipHeader.AuthenticationHeader = SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.ProxyAuthorization, headerValue);
                        }
                        #endregion
                        #region UserAgent
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_USERAGENT.ToLower())
                        {
                            sipHeader.UserAgent = headerValue;
                        }
                        #endregion
                        #region MaxForwards
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_MAXFORWARDS.ToLower())
                        {
                            if (!Int32.TryParse(headerValue, out sipHeader.MaxForwards))
                            {
                                logger.Warn("The " + SIPHeaders.SIP_HEADER_MAXFORWARDS + " could not be parsed as a valid integer, " + headerLine + ".");
                            }
                        }
                        #endregion
                        #region ContentLength
                        else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CONTENTLENGTH.ToLower() ||
                            headerNameLower == SIPHeaders.SIP_HEADER_CONTENTLENGTH.ToLower())
                        {
                            if (!Int32.TryParse(headerValue, out sipHeader.ContentLength))
                            {
                                logger.Warn("The " + SIPHeaders.SIP_HEADER_CONTENTLENGTH + " could not be parsed as a valid integer.");
                            }
                        }
                        #endregion
                        #region ContentType
                        else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_CONTENTTYPE.ToLower() ||
                            headerNameLower == SIPHeaders.SIP_HEADER_CONTENTTYPE.ToLower())
                        {
                            sipHeader.ContentType = headerValue;
                        }
                        #endregion
                        #region Accept
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPT.ToLower())
                        {
                            sipHeader.Accept = headerValue;
                        }
                        #endregion
                        #region Route
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ROUTE.ToLower())
                        {
                            SIPRouteSet routeSet = SIPRouteSet.ParseSIPRouteSet(headerValue);
                            if (routeSet != null)
                            {
                                while (routeSet.Length > 0)
                                {
                                    sipHeader.Routes.AddBottomRoute(routeSet.PopRoute());
                                }
                            }
                        }
                        #endregion
                        #region RecordRoute
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_RECORDROUTE.ToLower())
                        {
                            SIPRouteSet recordRouteSet = SIPRouteSet.ParseSIPRouteSet(headerValue);
                            if (recordRouteSet != null)
                            {
                                while (recordRouteSet.Length > 0)
                                {
                                    sipHeader.RecordRoutes.AddBottomRoute(recordRouteSet.PopRoute());
                                }
                            }
                        }
                        #endregion
                        #region Allow-Events
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ALLOW_EVENTS || headerNameLower == SIPHeaders.SIP_COMPACTHEADER_ALLOWEVENTS)
                        {
                            sipHeader.AllowEvents = headerValue;
                        }
                        #endregion
                        #region Event
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_EVENT.ToLower() || headerNameLower == SIPHeaders.SIP_COMPACTHEADER_EVENT)
                        {
                            sipHeader.Event = headerValue;
                        }
                        #endregion
                        #region SubscriptionState.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SUBSCRIPTION_STATE.ToLower())
                        {
                            sipHeader.SubscriptionState = headerValue;
                        }
                        #endregion
                        #region Timestamp.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_TIMESTAMP.ToLower())
                        {
                            sipHeader.Timestamp = headerValue;
                        }
                        #endregion
                        #region Date.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_DATE.ToLower())
                        {
                            sipHeader.Date = headerValue;
                        }
                        #endregion
                        #region Refer-Sub.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERSUB.ToLower())
                        {
                            if (sipHeader.ReferSub == null)
                            {
                                sipHeader.ReferSub = headerValue;
                            }
                            else
                            {
                                throw new SIPValidationException(SIPValidationFieldsEnum.ReferToHeader, "Only a single Refer-Sub header is permitted.");
                            }
                        }
                        #endregion
                        #region Refer-To.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERTO.ToLower() ||
                            headerNameLower == SIPHeaders.SIP_COMPACTHEADER_REFERTO)
                        {
                            if (sipHeader.ReferTo == null)
                            {
                                sipHeader.ReferTo = headerValue;
                            }
                            else
                            {
                                throw new SIPValidationException(SIPValidationFieldsEnum.ReferToHeader, "Only a single Refer-To header is permitted.");
                            }
                        }
                        #endregion
                        #region Referred-By.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_REFERREDBY.ToLower())
                        {
                            sipHeader.ReferredBy = headerValue;
                        }
                        #endregion
                        #region Require.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_REQUIRE.ToLower())
                        {
                            sipHeader.Require = headerValue;
                        }
                        #endregion
                        #region Reason.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_REASON.ToLower())
                        {
                            sipHeader.Reason = headerValue;
                        }
                        #endregion
                        #region Proxy-ReceivedFrom.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_RECEIVEDFROM.ToLower())
                        {
                            sipHeader.ProxyReceivedFrom = headerValue;
                        }
                        #endregion
                        #region Proxy-ReceivedOn.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_RECEIVEDON.ToLower())
                        {
                            sipHeader.ProxyReceivedOn = headerValue;
                        }
                        #endregion
                        #region Proxy-SendFrom.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_SENDFROM.ToLower())
                        {
                            sipHeader.ProxySendFrom = headerValue;
                        }
                        #endregion
                        #region Supported
                        else if (headerNameLower == SIPHeaders.SIP_COMPACTHEADER_SUPPORTED.ToLower() ||
                            headerNameLower == SIPHeaders.SIP_HEADER_SUPPORTED.ToLower())
                        {
                            sipHeader.Supported = headerValue;
                        }
                        #endregion
                        #region Authentication-Info
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_AUTHENTICATIONINFO)
                        {
                            sipHeader.AuthenticationInfo = headerValue;
                        }
                        #endregion
                        #region Accept-Encoding
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPTENCODING)
                        {
                            sipHeader.AcceptEncoding = headerValue;
                        }
                        #endregion
                        #region Accept-Language
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ACCEPTLANGUAGE)
                        {
                            sipHeader.AcceptLanguage = headerValue;
                        }
                        #endregion
                        #region Alert-Info
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ALERTINFO)
                        {
                            sipHeader.AlertInfo = headerValue;
                        }
                        #endregion
                        #region Allow
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ALLOW)
                        {
                            sipHeader.Allow = headerValue;
                        }
                        #endregion
                        #region Call-Info
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CALLINFO)
                        {
                            sipHeader.CallInfo = headerValue;
                        }
                        #endregion
                        #region Content-Disposition
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_DISPOSITION)
                        {
                            sipHeader.ContentDisposition = headerValue;
                        }
                        #endregion
                        #region Content-Encoding
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_ENCODING)
                        {
                            sipHeader.ContentEncoding = headerValue;
                        }
                        #endregion
                        #region Content-Language
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CONTENT_LANGUAGE)
                        {
                            sipHeader.ContentLanguage = headerValue;
                        }
                        #endregion
                        #region Error-Info
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ERROR_INFO)
                        {
                            sipHeader.ErrorInfo = headerValue;
                        }
                        #endregion
                        #region In-Reply-To
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_IN_REPLY_TO)
                        {
                            sipHeader.InReplyTo = headerValue;
                        }
                        #endregion
                        #region MIME-Version
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_MIME_VERSION)
                        {
                            sipHeader.MIMEVersion = headerValue;
                        }
                        #endregion
                        #region Organization
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_ORGANIZATION)
                        {
                            sipHeader.Organization = headerValue;
                        }
                        #endregion
                        #region Priority
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_PRIORITY)
                        {
                            sipHeader.Priority = headerValue;
                        }
                        #endregion
                        #region Proxy-Require
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_PROXY_REQUIRE)
                        {
                            sipHeader.ProxyRequire = headerValue;
                        }
                        #endregion
                        #region Reply-To
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_REPLY_TO)
                        {
                            sipHeader.ReplyTo = headerValue;
                        }
                        #endregion
                        #region Retry-After
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_RETRY_AFTER)
                        {
                            sipHeader.RetryAfter = headerValue;
                        }
                        #endregion
                        #region Subject
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SUBJECT)
                        {
                            sipHeader.Subject = headerValue;
                        }
                        #endregion
                        #region Unsupported
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_UNSUPPORTED)
                        {
                            sipHeader.Unsupported = headerValue;
                        }
                        #endregion
                        #region Warning
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_WARNING)
                        {
                            sipHeader.Warning = headerValue;
                        }
                        #endregion
                        #region Switchboard-CallID.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_CALLID.ToLower())
                        {
                            sipHeader.SwitchboardCallID = headerValue;
                        }
                        #endregion
                        #region Switchboard-To.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_TO.ToLower())
                        {
                            sipHeader.SwitchboardTo = headerValue;
                        }
                        #endregion
                        #region Switchboard-CallerDescription.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_CALLER_DESCRIPTION.ToLower())
                        {
                            sipHeader.SwitchboardCallerDescription = headerValue;
                        }
                        #endregion
                        #region Switchboard-Description.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_DESCRIPTION.ToLower())
                        {
                            sipHeader.SwitchboardDescription = headerValue;
                        }
                        #endregion
                        #region Switchboard-From.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_FROM.ToLower())
                        {
                            sipHeader.SwitchboardFrom = headerValue;
                        }
                        #endregion
                        #region Switchboard-FromContactURL.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_FROM_CONTACT_URL.ToLower())
                        {
                            sipHeader.SwitchboardFromContactURL = headerValue;
                        }
                        #endregion
                        #region Switchboard-Owner.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_OWNER.ToLower())
                        {
                            sipHeader.SwitchboardOwner = headerValue;
                        }
                        #endregion
                        #region Switchboard-Terminate.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_TERMINATE.ToLower())
                        {
                            sipHeader.SwitchboardTerminate = headerValue;
                        }
                        #endregion
                        #region Switchboard-Token.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_TOKEN.ToLower())
                        {
                            sipHeader.SwitchboardToken = headerValue;
                        }
                        #endregion
                        #region Switchboard-TokenRequest.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_SWITCHBOARD_TOKENREQUEST.ToLower())
                        {
                            Int32.TryParse(headerValue, out sipHeader.SwitchboardTokenRequest);
                        }
                        #endregion
                        #region CRM-PersonName.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CRM_PERSON_NAME.ToLower())
                        {
                            sipHeader.CRMPersonName = headerValue;
                        }
                        #endregion
                        #region CRM-CompanyName.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CRM_COMPANY_NAME.ToLower())
                        {
                            sipHeader.CRMCompanyName = headerValue;
                        }
                        #endregion
                        #region CRM-AvatarURL.
                        else if (headerNameLower == SIPHeaders.SIP_HEADER_CRM_AVATAR_URL.ToLower())
                        {
                            sipHeader.CRMAvatarURL = headerValue;
                        }
                        #endregion

                        else
                        {
                            sipHeader.UnknownHeaders.Add(headerLine);
                        }

                        lastHeader = headerName;
                    }
                    catch (SIPValidationException)
                    {
                        throw;
                    }
                    catch (Exception parseExcp)
                    {
                        logger.Error("Error parsing SIP header " + headerLine + ". " + parseExcp.Message);
                        throw new SIPValidationException(SIPValidationFieldsEnum.Headers, "Unknown error parsing Header.");
                    }
                }

                sipHeader.Validate();

                return sipHeader;
            }
            catch (SIPValidationException)
            {
                throw;
            }
            catch (Exception excp)
            {
                logger.Error("Exception ParseSIPHeaders. " + excp.Message);
                throw new SIPValidationException(SIPValidationFieldsEnum.Headers, "Unknown error parsing Headers.");
            }
        }
        private SIPRequest GetReferRequest(SIPEndPoint localSIPEndPoint, SIPURI referTo)
        {
            SIPRequest referRequest = new SIPRequest(SIPMethodsEnum.REFER, RemoteTarget);
            SIPFromHeader referFromHeader = SIPFromHeader.ParseFromHeader(LocalUserField.ToString());
            SIPToHeader referToHeader = SIPToHeader.ParseToHeader(RemoteUserField.ToString());
            int cseq = ++CSeq;

            SIPHeader referHeader = new SIPHeader(referFromHeader, referToHeader, cseq, CallId);
            referHeader.CSeqMethod = SIPMethodsEnum.REFER;
            referRequest.Header = referHeader;
            referRequest.Header.ReferTo = referTo.ToString();
            referRequest.Header.Routes = RouteSet;
            referRequest.Header.ProxySendFrom = ProxySendFrom;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            referRequest.Header.Vias.PushViaHeader(viaHeader);

            return referRequest;
        }