Packages

Elixir libraries and OTP behaviours for building telecom applications with SIP protocol and media handling

Current section

Files

Jump to
parrot_platform lib parrot sip handler_adapter header_handler.ex
Raw

lib/parrot/sip/handler_adapter/header_handler.ex

defmodule Parrot.Sip.HandlerAdapter.HeaderHandler do
@moduledoc """
Functions for handling SIP message headers.
This module handles the manipulation of headers in SIP messages,
including adding, formatting, and parsing headers.
"""
require Logger
alias Parrot.Sip.Message
alias Parrot.Sip.Uri
alias Parrot.Sip.Headers.{From, To, Contact}
@doc """
Adds headers to a SIP message.
This function takes a SIP message and a map of headers to add, and returns
a new SIP message with the headers added.
## Parameters
* `sip_msg` - The SIP message to add headers to
* `headers_map` - A map of header names to values
## Returns
The SIP message with the headers added
"""
def add_headers(%Message{} = sip_msg, headers_map) when is_map(headers_map) do
Enum.reduce(headers_map, sip_msg, fn {name, value}, acc_msg ->
Logger.debug("Adding header: {#{inspect(name)}, #{inspect(value)}}")
# Normalize header name
header_name = normalize_header_name(name)
Logger.debug("Normalized header name: #{header_name}")
# Process the header value based on its type
cond do
# Handle address headers (From, To, Contact) passed as maps
is_map(value) and header_name in ["from", "to", "contact"] ->
Logger.debug("Processing address header as map")
add_address_header(acc_msg, header_name, value)
# Handle Contact as a list
is_list(value) and header_name == "contact" ->
Logger.debug("Processing contact list: #{inspect(value)}")
contacts = Enum.map(value, &parse_contact_value/1)
Message.set_header(acc_msg, "contact", contacts)
# Handle string values
is_binary(value) ->
Logger.debug("Processing string header value")
Message.set_header(acc_msg, header_name, value)
# Handle already parsed header structs
true ->
Logger.debug("Header value is already a parsed structure")
Message.set_header(acc_msg, header_name, value)
end
end)
end
@doc """
Normalizes a header name to lowercase string.
## Parameters
* `name` - The header name as a string or atom
## Returns
The normalized header name as a lowercase string
"""
def normalize_header_name(name) when is_binary(name) do
String.downcase(name)
end
def normalize_header_name(name) when is_atom(name) do
name
|> Atom.to_string()
|> String.replace("_", "-")
|> String.downcase()
end
@doc """
Adds an address header (From, To, Contact) to a SIP message.
## Parameters
* `sip_msg` - The SIP message to add the header to
* `header_name` - The header name as a string
* `map_value` - A map containing the address header information
## Returns
The SIP message with the header added
"""
def add_address_header(%Message{} = sip_msg, header_name, map_value) do
uri_str = Map.get(map_value, :uri) || Map.get(map_value, "uri")
display_name = Map.get(map_value, :display_name) || Map.get(map_value, "display_name")
tag = Map.get(map_value, :tag) || Map.get(map_value, "tag")
if uri_str do
uri = Uri.parse!(uri_str)
header =
case header_name do
"from" ->
from = %From{
display_name: display_name,
uri: uri,
parameters: if(tag, do: %{"tag" => tag}, else: %{})
}
from
"to" ->
to = %To{
display_name: display_name,
uri: uri,
parameters: if(tag, do: %{"tag" => tag}, else: %{})
}
to
"contact" ->
%Contact{
display_name: display_name,
uri: uri,
parameters: %{}
}
end
Message.set_header(sip_msg, header_name, header)
else
# No URI, skip adding the header
sip_msg
end
end
# Parses a contact value which can be a map or already parsed struct.
defp parse_contact_value(%Contact{} = contact), do: contact
defp parse_contact_value(contact_map) when is_map(contact_map) do
uri_str = Map.get(contact_map, :uri) || Map.get(contact_map, "uri")
display_name = Map.get(contact_map, :display_name) || Map.get(contact_map, "display_name")
if uri_str do
uri = Uri.parse!(uri_str)
%Contact{
display_name: display_name,
uri: uri,
parameters: %{}
}
else
# Return a wildcard contact if no URI
%Contact{wildcard: true}
end
end
defp parse_contact_value(uri_str) when is_binary(uri_str) do
uri = Uri.parse!(uri_str)
%Contact{
display_name: nil,
uri: uri,
parameters: %{}
}
end
end