diff --git a/sip/parse_uri.go b/sip/parse_uri.go index 55032e6..e2d75d5 100644 --- a/sip/parse_uri.go +++ b/sip/parse_uri.go @@ -62,6 +62,18 @@ func uriStateSlashes(uri *Uri, s string) (uriFSM, string, error) { func uriStateUser(uri *Uri, s string) (uriFSM, string, error) { var userend int = 0 + // For scheme tel RFC3966 use other flow for parsing + // https://datatracker.ietf.org/doc/html/rfc3966#section-3 + if uri.Scheme == "tel" { + for i, c := range s { + if c == ';' { + uri.User = s[:i] + return uriStateUriParams, s[i+1:], nil + } + } + uri.User = s + return uriStateUriParams, "", nil + } for i, c := range s { if c == '[' { // IPV6 diff --git a/sip/parse_uri_test.go b/sip/parse_uri_test.go index 28884ed..ac39b69 100644 --- a/sip/parse_uri_test.go +++ b/sip/parse_uri_test.go @@ -214,3 +214,37 @@ func TestParseUriIPV6(t *testing.T) { assert.Equal(t, "user", uri.User) }) } + +// Examples from https://datatracker.ietf.org/doc/html/rfc3966#section-6 +// and https://datatracker.ietf.org/doc/html/rfc4694#section-6 +func TestParseTelUri(t *testing.T) { + t.Run("schema tel global", func(t *testing.T) { + uri := Uri{} + str := "tel:+1-201-555-0123" + err := ParseUri(str, &uri) + require.NoError(t, err) + assert.Equal(t, "", uri.Host) + assert.Equal(t, "+1-201-555-0123", uri.User) + }) + + t.Run("schema tel local", func(t *testing.T) { + uri := Uri{} + str := "tel:7042;phone-context=example.com" + err := ParseUri(str, &uri) + require.NoError(t, err) + assert.Equal(t, "", uri.Host) + assert.Equal(t, "7042", uri.User) + assert.Equal(t, "example.com", uri.UriParams["phone-context"]) + }) + + t.Run("schema tel local with context", func(t *testing.T) { + uri := Uri{} + str := "tel:+1-202-533-6789;npdi" + err := ParseUri(str, &uri) + require.NoError(t, err) + assert.Equal(t, "", uri.Host) + assert.Equal(t, "+1-202-533-6789", uri.User) + assert.NotEmpty(t, "example.com", uri.UriParams["npdi"]) + }) + +} diff --git a/sip/uri.go b/sip/uri.go index 1851e42..36f7344 100644 --- a/sip/uri.go +++ b/sip/uri.go @@ -75,11 +75,17 @@ func (uri *Uri) StringWrite(buffer io.StringWriter) { buffer.WriteString(":") buffer.WriteString(uri.Password) } - buffer.WriteString("@") + + if uri.Scheme != "tel" { + buffer.WriteString("@") + } + } // Compulsory hostname. - buffer.WriteString(uriIP(uri.Host)) + if uri.Host != "" { + buffer.WriteString(uriIP(uri.Host)) + } // Optional port number. if uri.Port > 0 { @@ -133,8 +139,10 @@ func (uri *Uri) Addr() string { } addr := uri.Host - if uri.User != "" { + if uri.User != "" && uri.Scheme != "tel" { addr = uri.User + "@" + addr + } else if uri.Scheme == "tel" { + addr = uri.User } if uri.Port > 0 { addr += ":" + strconv.Itoa(uri.Port)