Packages
smppex
2.3.3
3.3.0
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
retired
3.1.0
retired
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.4.0
2.3.3
2.3.2
2.3.1
2.3.0
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.1
2.0.0
1.0.1
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
SMPP 3.4 protocol and framework implemented in Elixir
Current section
Files
Jump to
Current section
Files
lib/smppex/protocol/mandatory_fields_builder.ex
defmodule SMPPEX.Protocol.MandatoryFieldsBuilder do
@moduledoc false
alias SMPPEX.Protocol.Pack
alias SMPPEX.Protocol.MandatoryFieldsSpecs
@spec build(map, MandatoryFieldsSpecs.fields_spec()) :: {:ok, iodata} | {:error, any}
def build(fields, spec) when is_map(fields) do
build(fields, Enum.reverse(spec), [])
end
defp build(_fields, [], built), do: {:ok, built}
defp build(fields, [field_spec | specs], built) do
case build_field(fields, field_spec) do
{:ok, new_fields, bin} -> build(new_fields, specs, [bin | built])
{:error, error} -> {:error, error}
end
end
defp build_field(fields, {name, {:octet_string, len}}) when is_atom(len) do
case fields[name] do
bin when is_binary(bin) -> {:ok, Map.put(fields, len, byte_size(bin)), bin}
_ -> {:error, "Field #{name} is not an octet_string"}
end
end
defp build_field(fields, {name, {:times, times, subspecs}}) when is_atom(times) do
case fields[name] do
values when is_list(values) ->
case build_subfields(values, subspecs, []) do
{:ok, bins} -> {:ok, Map.put(fields, times, length(values)), bins}
{:error, error} -> {:error, error}
end
_ ->
{:error, "Field #{name} is not a list"}
end
end
defp build_field(fields, {:case, cases}) when is_list(cases) do
build_cases(fields, cases)
end
defp build_field(fields, {name, simple_spec}) when is_tuple(simple_spec) do
case build_simple_value(fields[name], simple_spec) do
{:ok, bin} -> {:ok, fields, bin}
{:error, error} -> {:error, {"Error building simple field #{name}", error}}
end
end
defp build_subfields([], _specs, built), do: {:ok, Enum.reverse(built)}
defp build_subfields([value | values], specs, built) do
case build(value, specs) do
{:ok, bin} -> build_subfields(values, specs, [bin | built])
{:error, error} -> {:error, error}
end
end
defp build_cases(_fields, []), do: {:error, "No case matched given fields"}
defp build_cases(fields, [{cond_name, cond_value, specs} | other_cases]) do
if fields[cond_name] == cond_value do
case build(fields, specs) do
{:ok, bin} -> {:ok, fields, bin}
{:error, error} -> {:error, error}
end
else
build_cases(fields, other_cases)
end
end
defp build_simple_value(value, {:c_octet_string, {:max, n}}),
do: Pack.c_octet_string(value, {:max, n})
defp build_simple_value(value, {:c_octet_string, {:fixed, n}}),
do: Pack.c_octet_string(value, {:fixed, n})
defp build_simple_value(value, {:octet_string, n}), do: Pack.octet_string(value, n)
defp build_simple_value(value, {:integer, n}), do: Pack.integer(value, n)
end