freeswitch-types 0.19.1

FreeSWITCH protocol types and general-purpose SIP header parser (RFC 3261 name-addr)
Documentation

freeswitch-types

crates.io docs.rs

FreeSWITCH protocol types and general-purpose SIP header parser. No async runtime dependency.

Includes SipHeaderAddr, a standalone RFC 3261 name-addr parser with header-level parameters — usable in any SIP project, not just FreeSWITCH. With default-features = false, the only dependencies are sip-uri and percent-encoding.

Also provides FreeSWITCH ESL types (channel state, events, commands, variables) for CDR parsing, config generation, command building, or channel variable validation without pulling in tokio.

For async ESL transport (connecting to FreeSWITCH, sending commands, receiving events), see freeswitch-esl-tokio which re-exports everything from this crate.

What's included

Module Contents
sip_header_addr SipHeaderAddr — RFC 3261 name-addr parser with header-level parameters
sip_message extract_header — extract header values from raw SIP message text (RFC 3261 §7.3.1: folding, case-insensitive, multi-occurrence)
sip_header SipHeader enum, SipHeaderLookup trait, extract_from() for raw messages
channel ChannelState, CallState, AnswerState, CallDirection, HangupCause, ChannelTimetable
headers EventHeader enum (typed event header names)
lookup HeaderLookup trait (typed accessors for any key-value store)
variables ChannelVariable, SofiaVariable, SipInviteHeader (with header_name() and extract_from()), EslArray, MultipartBody
event EslEvent, EslEventType, EventFormat, EslEventPriority (requires esl feature)
commands Originate, BridgeDialString, UuidKill, UuidBridge, endpoint types (requires esl feature)
conference_info RFC 4575 conference-info+xml types (requires conference-info feature)

Features

  • esl (enabled by default) — ESL event and command types (EslEvent, Originate, Variables, etc.). Pulls in indexmap for ordered header storage. Disable if you only need SipHeaderAddr or channel state enums.
  • serde (enabled by default) — adds Serialize/Deserialize impls for all public types. Disable with default-features = false if you only need wire-format parsing (Display/FromStr) without pulling in serde.
  • conference-info — enables ConferenceInfo::from_xml()/to_xml() for parsing RFC 4575 application/conference-info+xml documents (pulls in quick-xml). Type definitions are always available without this feature.

Usage

[dependencies]
freeswitch-types = "1"

SIP header parsing only (no FreeSWITCH dependencies):

[dependencies]
freeswitch-types = { version = "1", default-features = false }

SIP header address parsing

SipHeaderAddr parses the (name-addr / addr-spec) *(SEMI generic-param) production from SIP headers like From, To, Contact, and Refer-To. It replaces sip_uri::NameAddr (deprecated since sip-uri 0.2.0) by handling header-level parameters that follow the URI. General-purpose SIP — no FreeSWITCH dependency.

use freeswitch_types::SipHeaderAddr;

let addr: SipHeaderAddr =
    r#""Alice" <sip:alice@example.com>;tag=abc123"#.parse().unwrap();
assert_eq!(addr.display_name(), Some("Alice"));
assert_eq!(addr.tag(), Some("abc123"));
assert_eq!(addr.sip_uri().unwrap().user(), Some("alice"));

Command builders (requires esl feature)

use std::time::Duration;
use freeswitch_types::commands::*;

let cmd = Originate::application(
    Endpoint::SofiaGateway(SofiaGateway::new("my_provider", "18005551234")),
    Application::simple("park"),
)
.cid_name("Outbound Call")
.cid_num("5551234")
.timeout(Duration::from_secs(30));

// All builders implement Display, producing the FreeSWITCH wire format
assert!(cmd.to_string().starts_with("originate sofia/gateway/"));

// All builders implement FromStr for round-trip parsing
let parsed: Originate = cmd.to_string().parse().unwrap();
assert_eq!(parsed.to_string(), cmd.to_string());

Typed event accessors

use freeswitch_types::{HeaderLookup, EventHeader, ChannelVariable};

// HeaderLookup works with any key-value store, not just EslEvent
struct MyHeaders(std::collections::HashMap<String, String>);

impl HeaderLookup for MyHeaders {
    fn header_str(&self, name: &str) -> Option<&str> {
        self.0.get(name).map(|s| s.as_str())
    }
    fn variable_str(&self, name: &str) -> Option<&str> {
        self.0.get(&format!("variable_{}", name)).map(|s| s.as_str())
    }
}

// Now MyHeaders has all typed accessors:
// h.channel_state(), h.call_direction(), h.hangup_cause(),
// h.header(EventHeader::UniqueId), h.variable(ChannelVariable::ReadCodec), etc.

Serde support (requires serde feature, enabled by default)

All builder types implement Serialize/Deserialize for config-driven usage:

use freeswitch_types::Originate;

let json = r#"{
    "endpoint": {"sofia_gateway": {"gateway": "carrier", "destination": "18005551234"}},
    "application": {"name": "park"},
    "timeout_secs": 30
}"#;
let cmd: Originate = serde_json::from_str(json).unwrap();
println!("{}", cmd);

Raw SIP message header extraction

extract_header pulls header values from raw SIP message text, handling case-insensitive matching, header folding, and multi-occurrence concatenation per RFC 3261 §7.3.1. Pairs naturally with the existing value parsers:

use freeswitch_types::{extract_header, SipHeaderAddr};
use freeswitch_types::variables::SipCallInfo;

let raw_invite = "INVITE sip:sos@bcf.example.com SIP/2.0\r\n\
    Call-Info: <urn:emergency:uid:callid:abc>;purpose=emergency-CallId\r\n\
    P-Asserted-Identity: \"Alice\" <sip:+15551234567@example.com>\r\n\
    \r\n";

let ci_val = extract_header(raw_invite, "Call-Info").unwrap();
let ci = SipCallInfo::parse(&ci_val).unwrap();
assert_eq!(ci.entries()[0].purpose(), Some("emergency-CallId"));

let pai_val = extract_header(raw_invite, "P-Asserted-Identity").unwrap();
let pai: SipHeaderAddr = pai_val.parse().unwrap();
assert_eq!(pai.display_name(), Some("Alice"));

SipInviteHeader and SipHeader also provide extract_from() for convenience when working with typed header enums.

Variable parsers

use freeswitch_types::variables::{EslArray, MultipartBody};

let arr = EslArray::parse("ARRAY::item1|:item2|:item3").unwrap();
assert_eq!(arr.items(), &["item1", "item2", "item3"]);

Relationship to freeswitch-esl-tokio

This crate contains all domain types extracted from the freeswitch-esl-tokio workspace. The ESL crate re-exports everything, so users of freeswitch-esl-tokio don't need to depend on this crate directly.

Depend on freeswitch-types directly when you need FreeSWITCH types without async transport (CDR processors, config validators, CLI tools, test harnesses).

License

MIT OR Apache-2.0