use std::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult};
use crate::*;
macro_rules! impl_simple_header_method {
($name:ident, $variant:ident, $ty:ident) => {
pub fn $name(&self) -> IoResult<$ty> {
if let Some(Header::$variant(header)) = self.headers.$name() {
Ok(header)
} else {
Err(IoError::new(
IoErrorKind::InvalidInput,
format!("message doesnt contain a {} header", stringify!($variant)),
))
}
}
};
}
pub struct MessageHelper {
pub uri: Uri,
pub headers: Headers,
pub body: Vec<u8>,
}
impl MessageHelper {
impl_simple_header_method!(from, From, NamedHeader);
impl_simple_header_method!(to, To, NamedHeader);
impl_simple_header_method!(contact, Contact, NamedHeader);
impl_simple_header_method!(call_id, CallId, String);
impl_simple_header_method!(xfs_sending_message, XFsSendingMessage, String);
impl_simple_header_method!(via, Via, ViaHeader);
pub fn new(msg: SipMessage) -> IoResult<MessageHelper> {
match msg {
SipMessage::Request {
uri, headers, body, ..
} => MessageHelper::new_from_vars(uri, headers, body),
SipMessage::Response { .. } => Err(IoError::new(
IoErrorKind::InvalidData,
"Expected a SIP request",
)),
}
}
pub fn new_from_vars(uri: Uri, headers: Headers, body: Vec<u8>) -> IoResult<MessageHelper> {
Ok(MessageHelper { uri, headers, body })
}
pub fn data(&self) -> Vec<u8> {
self.body.clone()
}
pub fn received(&self, header_cfg: &HeaderWriteConfig) -> IoResult<SipMessage> {
let mut req = ResponseGenerator::new()
.code(200)
.header(self.headers.from().unwrap())
.header(self.headers.to().unwrap())
.header(self.headers.call_id().unwrap())
.header(self.headers.cseq().unwrap())
.header(self.headers.via().unwrap())
.header(Header::ContentLength(0));
header_cfg.write_headers(req.headers_ref_mut());
req.build()
}
}
pub struct MessageWriter {
cseq: u32,
uri: Uri,
call_id: String,
}
impl MessageWriter {
pub fn new(uri: Uri) -> MessageWriter {
let _call_id = md5::compute(rand::random::<[u8; 16]>());
let call_id = format!("{:x}@{}", _call_id, uri.host);
MessageWriter {
cseq: 0,
uri,
call_id,
}
}
pub fn write_message(
&mut self,
body: Vec<u8>,
to: Uri,
via_header: Header,
header_cfg: &HeaderWriteConfig,
) -> IoResult<SipMessage> {
self.cseq += 1;
let mut req = RequestGenerator::new()
.method(Method::Message)
.uri(to.clone().schema(UriSchema::Sip))
.header(via_header)
.header(Header::To(NamedHeader::new(to)))
.header(self.from())
.header(self.cseq())
.header(self.call_id())
.header(self.content_type())
.header(Header::ContentLength(body.len() as u32))
.header(self.max_forwards());
header_cfg.write_headers(req.headers_ref_mut());
req.body(body).build()
}
pub fn cseq(&self) -> Header {
Header::CSeq(self.cseq, Method::Message)
}
pub fn content_type(&self) -> Header {
Header::ContentType(ContentType::PlainText)
}
pub fn max_forwards(&self) -> Header {
Header::MaxForwards(70)
}
pub fn call_id(&self) -> Header {
Header::CallId(self.call_id.clone())
}
pub fn from(&self) -> Header {
Header::From(NamedHeader::new(self.uri.clone()))
}
}