use super::error::Error;
use super::spec;
use super::util;
use log::{error, warn};
use std::fmt;
const PASSWORD_REDACTED: &str = "REDACTED";
#[derive(PartialEq, Debug)]
pub struct FixedField {
spec: &'static spec::FixedField,
value: String,
}
impl FixedField {
pub fn new(spec: &'static spec::FixedField, value: &str) -> Result<Self, Error> {
if value.len() == spec.length {
Ok(FixedField {
spec,
value: value.to_string(),
})
} else {
Err(Error::FixedFieldLengthError)
}
}
pub fn spec(&self) -> &'static spec::FixedField {
self.spec
}
pub fn value(&self) -> &str {
&self.value
}
pub fn set_value(&mut self, value: &str) -> Result<(), Error> {
if value.len() == self.spec.length {
self.value = value.to_string();
Ok(())
} else {
Err(Error::FixedFieldLengthError)
}
}
pub fn to_sip(&self) -> String {
util::sip_string(&self.value)
}
}
#[derive(PartialEq, Debug)]
pub struct Field {
code: String,
value: String,
}
impl Field {
pub fn new(code: &str, value: &str) -> Self {
Field {
code: code.to_string(),
value: value.to_string(),
}
}
pub fn value(&self) -> &str {
&self.value
}
pub fn set_value(&mut self, value: &str) {
self.value = value.to_string();
}
pub fn code(&self) -> &str {
&self.code
}
pub fn to_sip(&self) -> String {
self.code.to_string() + &util::sip_string(&self.value) + &String::from("|")
}
}
#[derive(PartialEq, Debug)]
pub struct Message {
spec: &'static spec::Message,
fixed_fields: Vec<FixedField>,
fields: Vec<Field>,
}
impl Message {
pub fn new(
spec: &'static spec::Message,
fixed_fields: Vec<FixedField>,
fields: Vec<Field>,
) -> Self {
let mut msg = Message {
spec,
fixed_fields,
fields,
};
msg.sort_fields();
msg
}
pub fn from_ff_values(msg_code: &str, fixed_fields: &[&str]) -> Result<Message, Error> {
let msg_spec = match spec::Message::from_code(msg_code) {
Some(s) => s,
None => {
log::error!("Unknown message code: {msg_code}");
return Err(Error::UnknownMessageError);
}
};
let mut ff: Vec<FixedField> = Vec::new();
for (idx, ff_spec) in msg_spec.fixed_fields.iter().enumerate() {
if let Some(v) = fixed_fields.get(idx) {
ff.push(FixedField::new(ff_spec, v)?);
}
}
if ff.len() != msg_spec.fixed_fields.len() {
log::warn!(
"SIP message {} contains incorrect number of fixed fields",
msg_spec.code
);
return Err(Error::MessageFormatError);
}
Ok(Message {
spec: msg_spec,
fixed_fields: ff,
fields: Vec::new(),
})
}
pub fn from_values(
msg_code: &str,
fixed_fields: &[&str],
fields: &[(&str, &str)],
) -> Result<Message, Error> {
let mut msg = Message::from_ff_values(msg_code, fixed_fields)?;
for field in fields {
msg.add_field(field.0, field.1);
}
Ok(msg)
}
fn sort_fields(&mut self) {
self.fields.sort_by(|a, b| a.code.cmp(&b.code));
}
pub fn add_field(&mut self, code: &str, value: &str) {
self.fields.push(Field::new(code, value));
self.sort_fields();
}
pub fn maybe_add_field(&mut self, code: &str, value: Option<&str>) {
if let Some(v) = value {
self.fields.push(Field::new(code, v));
self.sort_fields();
}
}
pub fn remove_field(&mut self, code: &str, all: bool) -> usize {
let mut count: usize = 0;
loop {
let pos = match self.fields.iter().position(|f| f.code().eq(code)) {
Some(p) => p,
None => return count, };
self.fields.remove(pos);
count += 1;
if !all {
return count;
}
}
}
pub fn get_field_value(&self, code: &str) -> Option<&str> {
if let Some(f) = self.fields().iter().find(|f| f.code() == code) {
Some(f.value.as_str())
} else {
None
}
}
pub fn spec(&self) -> &'static spec::Message {
self.spec
}
pub fn fields(&self) -> &Vec<Field> {
&self.fields
}
pub fn fields_mut(&mut self) -> &mut Vec<Field> {
&mut self.fields
}
pub fn fixed_fields(&self) -> &Vec<FixedField> {
&self.fixed_fields
}
pub fn fixed_fields_mut(&mut self) -> &mut Vec<FixedField> {
&mut self.fixed_fields
}
pub fn to_sip(&self) -> String {
let mut s = self.spec.code.to_string();
for ff in self.fixed_fields.iter() {
s.push_str(&ff.to_sip());
}
for f in self.fields.iter() {
s.push_str(&f.to_sip());
}
s
}
pub fn to_sip_redacted(&self) -> String {
let mut s = self.spec.code.to_string();
for ff in self.fixed_fields.iter() {
s.push_str(&ff.to_sip());
}
for f in self.fields.iter() {
if f.code() == spec::F_PATRON_PWD.code {
s += f.code();
s += PASSWORD_REDACTED;
s += "|";
} else {
s.push_str(&f.to_sip());
}
}
s
}
pub fn from_sip(text: &str) -> Result<Message, Error> {
if text.len() < 2 {
log::warn!("SIP message is incomplete: {text}");
return Err(Error::MessageFormatError);
}
let msg_spec = match spec::Message::from_code(&text[0..2]) {
Some(m) => m,
None => {
error!("Unknown message type: {}", &text[0..2]);
return Err(Error::MessageFormatError);
}
};
let mut msg = Message {
spec: msg_spec,
fixed_fields: vec![],
fields: vec![],
};
let mut msg_text = &text[2..];
for ff_spec in msg_spec.fixed_fields.iter() {
if msg_text.len() < ff_spec.length {
warn!(
"Message has invalid fixed field: {} : {}",
ff_spec.label, msg_text
);
return Err(Error::MessageFormatError);
}
let value = &msg_text[0..ff_spec.length];
msg_text = &msg_text[ff_spec.length..];
msg.fixed_fields
.push(FixedField::new(ff_spec, value).unwrap());
}
if msg_text.is_empty() {
return Ok(msg);
}
for part in msg_text.split('|') {
if part.len() > 1 {
let val = match part.len() > 2 {
true => &part[2..],
_ => "",
};
msg.fields.push(Field::new(&part[0..2], val));
}
}
Ok(msg)
}
}
impl fmt::Display for Message {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{} {}", self.spec.code, self.spec.label)?;
for ff in self.fixed_fields.iter() {
writeln!(f, " {:.<35} {}", ff.spec.label, ff.value)?;
}
for field in self.fields.iter() {
if let Some(spec) = spec::Field::from_code(&field.code) {
writeln!(f, "{} {:.<35} {}", spec.code, spec.label, field.value)?;
} else {
writeln!(f, "{} {:.<35} {}", field.code, "custom", field.value)?;
}
}
write!(f, "")
}
}