aboutsummaryrefslogtreecommitdiff
path: root/src/encoding
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoding')
-rw-r--r--src/encoding/headermap.rs60
-rw-r--r--src/encoding/headers.rs182
-rw-r--r--src/encoding/method.rs39
-rw-r--r--src/encoding/mod.rs46
-rw-r--r--src/encoding/request.rs57
-rw-r--r--src/encoding/response.rs53
-rw-r--r--src/encoding/status.rs63
-rw-r--r--src/encoding/uri.rs55
8 files changed, 0 insertions, 555 deletions
diff --git a/src/encoding/headermap.rs b/src/encoding/headermap.rs
deleted file mode 100644
index 01e1962..0000000
--- a/src/encoding/headermap.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-use super::headers::Header;
-use anyhow::{anyhow, Result};
-use std::fmt::Display;
-
-#[derive(Debug, Clone)]
-pub struct HeaderMap(pub Vec<(String, String)>);
-
-impl HeaderMap {
- pub fn new() -> Self {
- Self(vec![])
- }
- pub fn add<H: Header>(mut self, h: H) -> Self {
- self.0.push((H::NAME.to_string(), format!("{h}")));
- self
- }
- pub fn insert<H: Header>(&mut self, h: H) {
- self.0.push((H::NAME.to_string(), format!("{h}")));
- }
- pub fn get_raw(&self, name: &str) -> Option<&str> {
- self.0
- .iter()
- .find(|(k, _)| k.eq_ignore_ascii_case(name))
- .map(|(_, v)| v.as_str())
- }
- pub fn get<H: Header>(&self) -> Option<Result<H>> {
- self.get_raw(H::NAME).map(H::from_str)
- }
- pub fn get_res<H: Header>(&self) -> Result<H> {
- self.get().ok_or(anyhow!("{} header missing", H::NAME))?
- }
- pub fn insert_raw(&mut self, key: String, value: String) {
- self.0.push((key, value))
- }
-}
-
-impl Display for HeaderMap {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- for (k, v) in &self.0 {
- write!(f, "{k}: {v}\r\n")?;
- }
- Ok(())
- }
-}
-impl HeaderMap {
- pub fn parse<'a>(lines: &mut impl Iterator<Item = &'a str>) -> Result<Self> {
- let mut headers = HeaderMap::new();
- for line in lines {
- // TODO multiline values
- let (key, value) = line.split_once(":").ok_or(anyhow!("header malformed"))?;
- headers.insert_raw(key.trim().to_string(), value.trim().to_string())
- }
- Ok(headers)
- }
-}
-
-impl FromIterator<(String, String)> for HeaderMap {
- fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
- Self(Vec::from_iter(iter))
- }
-}
diff --git a/src/encoding/headers.rs b/src/encoding/headers.rs
deleted file mode 100644
index e880739..0000000
--- a/src/encoding/headers.rs
+++ /dev/null
@@ -1,182 +0,0 @@
-use super::{headermap::HeaderMap, method::Method, uri::Uri};
-use anyhow::{anyhow, bail, Result};
-use std::{fmt::Display, str::FromStr};
-
-macro_rules! header {
- ($hname:literal, struct $name:ident($type:ty)) => {
- #[derive(Debug)]
- pub struct $name(pub $type);
- impl Header for $name {
- const NAME: &'static str = $hname;
- }
- impl Display for $name {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.0)
- }
- }
- impl FromStr for $name {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- Ok($name(<$type>::from_str(s)?))
- }
- }
- };
-}
-
-pub trait Header: FromStr<Err = anyhow::Error> + Display {
- const NAME: &'static str;
-}
-
-header!("Content-Length", struct ContentLength(usize));
-header!("Content-Type", struct ContentType(String));
-header!("Call-ID", struct CallID(String));
-header!("Via", struct Via(String));
-header!("Max-Forwards", struct MaxForwards(usize));
-header!("From", struct From(String));
-header!("To", struct To(String));
-header!("User-Agent", struct UserAgent(String));
-header!("Allow", struct Allow(String));
-
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct CSeq(pub u32, pub Method);
-
-impl Header for CSeq {
- const NAME: &'static str = "CSeq";
-}
-impl Display for CSeq {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{} {}", self.0, self.1)
- }
-}
-impl FromStr for CSeq {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let (seq, method) = s.split_once(" ").ok_or(anyhow!("method missing"))?;
- Ok(CSeq(seq.parse()?, method.parse()?))
- }
-}
-
-#[derive(Debug)]
-pub struct WWWAuthenticate {
- pub realm: String,
- pub nonce: String,
-}
-impl Header for WWWAuthenticate {
- const NAME: &'static str = "WWW-Authenticate";
-}
-impl Display for WWWAuthenticate {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "Digest realm={:?}, nonce={:?}", self.realm, self.nonce)
- }
-}
-impl FromStr for WWWAuthenticate {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- // TODO this is totally wrong
- let kvs = s
- .strip_prefix("Digest ")
- .ok_or(anyhow!("type not digest"))?
- .split(",")
- .map(|e| {
- let Some((k, v)) = e.split_once("=") else {
- bail!("not a KV-pair")
- };
- Ok((k.trim().to_string(), v.trim().to_string()))
- })
- .try_collect::<HeaderMap>()?;
- Ok(WWWAuthenticate {
- realm: unquote(
- &kvs.get_raw("realm")
- .ok_or(anyhow!("realm missing"))?
- .to_string(),
- )?,
- nonce: unquote(
- &kvs.get_raw("nonce")
- .ok_or(anyhow!("nonce missing"))?
- .to_string(),
- )?,
- })
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct Authorization {
- pub username: String,
- pub realm: String,
- pub uri: String,
- pub nonce: String,
- pub response: String,
-}
-impl Header for Authorization {
- const NAME: &'static str = "Authorization";
-}
-impl Display for Authorization {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let Self {
- username,
- realm,
- nonce,
- uri,
- response,
- } = self;
- write!(
- f,
- "Digest username={username:?},\r\n realm={realm:?},\r\n nonce={nonce:?},\r\n uri={uri:?},\r\n response={response:?},\r\n algorithm=MD5"
- )
- }
-}
-impl FromStr for Authorization {
- type Err = anyhow::Error;
- fn from_str(_s: &str) -> Result<Self, Self::Err> {
- todo!()
- }
-}
-
-pub fn unquote(v: &str) -> Result<String> {
- Ok(v.strip_prefix("\"")
- .ok_or(anyhow!("start quote missing"))?
- .strip_suffix("\"")
- .ok_or(anyhow!("end quote missing"))?
- .to_string())
-}
-
-#[derive(Debug)]
-pub struct Contact {
- pub display_name: Option<String>,
- pub uri: Uri,
- pub params: String,
-}
-
-impl Header for Contact {
- const NAME: &'static str = "Contact";
-}
-impl Display for Contact {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let Self {
- display_name,
- uri,
- params,
- } = self;
- if let Some(display_name) = display_name {
- write!(f, "{display_name} <{uri}>{params}")
- } else {
- write!(f, "<{uri}>{params}")
- }
- }
-}
-impl FromStr for Contact {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let (display_name, rest) = s.split_once("<").ok_or(anyhow!("malformed contact"))?;
- let (uri, params) = rest.split_once(">;").ok_or(anyhow!("malformed contact"))?;
- Ok(Self {
- display_name: if display_name.is_empty() {
- None
- } else {
- Some(display_name.to_string())
- },
- params: params.to_string(),
- uri: Uri::from_str(uri)?,
- })
- }
-}
diff --git a/src/encoding/method.rs b/src/encoding/method.rs
deleted file mode 100644
index 6d38cab..0000000
--- a/src/encoding/method.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-use anyhow::bail;
-use std::{fmt::Display, str::FromStr};
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum Method {
- Register,
- Invite,
- Ack,
- Options,
- Cancel,
- Bye,
-}
-
-impl Display for Method {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(match self {
- Method::Register => "REGISTER",
- Method::Invite => "INVITE",
- Method::Ack => "ACK",
- Method::Options => "OPTIONS",
- Method::Cancel => "CANCEL",
- Method::Bye => "BYE",
- })
- }
-}
-impl FromStr for Method {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- Ok(match s {
- "REGISTER" => Method::Register,
- "INVITE" => Method::Invite,
- "ACK" => Method::Ack,
- "OPTIONS" => Method::Options,
- "CANCEL" => Method::Cancel,
- "BYE" => Method::Bye,
- _ => bail!("unknown method"),
- })
- }
-}
diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs
deleted file mode 100644
index 816aa01..0000000
--- a/src/encoding/mod.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-use std::{fmt::Display, str::FromStr};
-
-use request::Request;
-use response::Response;
-
-pub mod headermap;
-pub mod headers;
-pub mod method;
-pub mod request;
-pub mod response;
-pub mod status;
-pub mod uri;
-
-#[derive(Debug, Clone)]
-pub enum Message {
- Request(Request),
- Response(Response),
-}
-
-impl Display for Message {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Message::Request(r) => write!(f, "{r}"),
- Message::Response(r) => write!(f, "{r}"),
- }
- }
-}
-impl FromStr for Message {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- if s.starts_with("SIP/") {
- Response::from_str(s).map(Message::Response)
- } else {
- Request::from_str(s).map(Message::Request)
- }
- }
-}
-
-impl Message {
- pub fn body_mut(&mut self) -> &mut String {
- match self {
- Message::Request(r) => &mut r.body,
- Message::Response(r) => &mut r.body,
- }
- }
-}
diff --git a/src/encoding/request.rs b/src/encoding/request.rs
deleted file mode 100644
index ab41b7c..0000000
--- a/src/encoding/request.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use super::{headermap::HeaderMap, method::Method, uri::Uri};
-use anyhow::{anyhow, bail};
-use std::{fmt::Display, str::FromStr};
-
-#[derive(Debug, Clone)]
-pub struct Request {
- pub method: Method,
- pub uri: Uri,
- pub headers: HeaderMap,
- pub body: String,
-}
-
-impl Display for Request {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let Self {
- headers,
- method,
- uri,
- ..
- } = self;
- write!(f, "{method} {uri} SIP/2.0\r\n")?;
- write!(f, "{headers}\r\n")?;
- Ok(())
- }
-}
-impl FromStr for Request {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let mut lines = s.lines();
- let statusline = lines.next().ok_or(anyhow!("status line missing"))?;
- let (method, rest) = statusline
- .split_once(" ")
- .ok_or(anyhow!("status line malformed"))?;
- let (uri, sipver) = rest
- .split_once(" ")
- .ok_or(anyhow!("status line malformed"))?;
-
- let Some(ver) = sipver.strip_prefix("SIP/") else {
- bail!("sip version malformed");
- };
- if ver != "2.0" {
- bail!("sip version {ver:?} is not supported");
- }
-
- let uri = Uri::from_str(uri)?;
-
- let headers = HeaderMap::parse(&mut lines)?;
- let method = Method::from_str(method)?;
-
- Ok(Self {
- body: String::new(),
- headers,
- method,
- uri,
- })
- }
-}
diff --git a/src/encoding/response.rs b/src/encoding/response.rs
deleted file mode 100644
index 0b7996c..0000000
--- a/src/encoding/response.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use super::{headermap::HeaderMap, status::Status};
-use anyhow::{anyhow, bail, Context};
-use std::{fmt::Display, str::FromStr};
-
-#[derive(Debug, Clone)]
-pub struct Response {
- pub status: Status,
- pub headers: HeaderMap,
- pub body: String,
-}
-
-impl FromStr for Response {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let mut lines = s.lines();
- let statusline = lines.next().ok_or(anyhow!("status line missing"))?;
- let (sipver, rest) = statusline
- .split_once(" ")
- .ok_or(anyhow!("status line malformed"))?;
- let (code, _status_str) = rest
- .split_once(" ")
- .ok_or(anyhow!("status line malformed"))?;
- let code = u16::from_str(code).context("status code")?;
-
- let Some(ver) = sipver.strip_prefix("SIP/") else {
- bail!("sip version malformed");
- };
- if ver != "2.0" {
- bail!("sip version {ver:?} is not supported");
- }
-
- let headers = HeaderMap::parse(&mut lines)?;
-
- let status = Status::from_code(code);
- Ok(Self {
- status,
- headers,
- body: String::new(),
- })
- }
-}
-impl Display for Response {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let Self {
- status,
- headers,
- body,
- } = self;
- write!(f, "SIP/2.0 {} {status:?}\r\n", status.to_code())?;
- write!(f, "{headers}\r\n{body}")?;
- Ok(())
- }
-}
diff --git a/src/encoding/status.rs b/src/encoding/status.rs
deleted file mode 100644
index 61b2d2a..0000000
--- a/src/encoding/status.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-macro_rules! status_enum {
- ($v:vis enum $name:ident { $($variant:ident = $value:literal),*, }) => {
- #[derive(Debug, Clone, Eq, PartialEq, Hash)]
- $v enum $name { $($variant),*, Other(u16) }
- impl $name { pub fn from_code(c: u16) -> Self { match c { $($value => Self::$variant),*, x => Self::Other(x) } } }
- impl $name { pub fn to_code(&self) -> u16 { match self { $(Self::$variant => $value),*, Self::Other(x) => *x } } }
- };
-}
-
-status_enum!(
- pub enum Status {
- Trying = 100,
- Ringing = 180,
- CallIsBeingForwarded = 181,
- Queued = 182,
- SessionProgress = 183,
- Ok = 200,
- MultipleChoices = 300,
- MovedPermanently = 301,
- MovedTemporarily = 302,
- UseProxy = 305,
- AlternativeService = 380,
- BadRequest = 400,
- Unauthorized = 401,
- PaymentRequired = 402,
- Forbidden = 403,
- NotFound = 404,
- MethodNotAllowed = 405,
- NotAcceptable = 406,
- ProxyAuthenticationRequired = 407,
- RequestTimeout = 408,
- Gone = 410,
- RequestEntityTooLarge = 413,
- RequestURITooLarge = 414,
- UnsupportedMediaType = 415,
- UnsupportedURIScheme = 416,
- BadExtension = 420,
- ExtensionRequired = 421,
- IntervalTooBrief = 423,
- TemporarilyNotAvailable = 480,
- CallLegTransactionDoesNotExist = 481,
- LoopDetected = 482,
- TooManyHops = 483,
- AddressIncomplete = 484,
- Ambiguous = 485,
- BusyHere = 486,
- RequestTerminated = 487,
- NotAcceptableHere = 488,
- RequestPending = 491,
- Undecipherable = 493,
- InternalServerError = 500,
- NotImplemented = 501,
- BadGateway = 502,
- ServiceUnavailable = 503,
- ServerTimeout = 504,
- SIPVersionNotSupported = 505,
- MessageTooLarge = 513,
- BusyEverywhere = 600,
- Decline = 603,
- DoesNotExistAnywhere = 604,
- GlobalNotAcceptable = 606,
- }
-);
diff --git a/src/encoding/uri.rs b/src/encoding/uri.rs
deleted file mode 100644
index b1a1282..0000000
--- a/src/encoding/uri.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use anyhow::anyhow;
-use std::{fmt::Display, str::FromStr};
-
-#[derive(Debug, Clone)]
-pub struct Uri {
- pub protocol: String,
- pub localpart: Option<String>,
- pub addr: String,
- pub params: String,
-}
-
-impl Display for Uri {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let Self {
- protocol,
- localpart,
- addr,
- params,
- } = self;
- write!(
- f,
- "{protocol}:{}{addr}{}",
- if let Some(localpart) = localpart {
- format!("{localpart}@")
- } else {
- "".to_string()
- },
- if params.is_empty() {
- "".to_string()
- } else {
- format!(";{params}")
- }
- )?;
- Ok(())
- }
-}
-impl FromStr for Uri {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let (pr, s) = s.split_once(":").ok_or(anyhow!("protocol sep"))?;
- let (lp, s) = s.split_once("@").unwrap_or(("", s));
- let (addr, params) = s.split_once(";").unwrap_or((s, ""));
-
- Ok(Self {
- addr: addr.to_owned(),
- localpart: if lp.is_empty() {
- None
- } else {
- Some(lp.to_string())
- },
- params: params.to_string(),
- protocol: pr.to_string(),
- })
- }
-}