use bottlers::cbor::{append_uvarint, read_uvarint};
use bottlers::{Bottle, HeaderValue, OpenResult};
use crate::error::{Error, Result};
#[derive(Debug, Clone, Default)]
pub struct InstantMessage {
pub id: [u8; 16],
pub flags: u64,
pub recipient: String,
pub sender: String,
pub body: Vec<u8>,
pub encrypted: bool,
pub signed_by: Vec<Vec<u8>>,
}
impl InstantMessage {
pub fn decode(buf: Vec<u8>, res: &OpenResult) -> Result<InstantMessage> {
let b = res.last();
let mut im = InstantMessage {
body: buf,
..Default::default()
};
match b.header.get("mid") {
Some(HeaderValue::Bytes(v)) => {
let n = v.len().min(16);
im.id[..n].copy_from_slice(&v[..n]);
}
_ => {
return Err(Error::Other(
"invalid message, message ID is missing".into(),
))
}
}
if let Some(HeaderValue::Integer(v)) = b.header.get("flg") {
im.flags = i128::from(*v) as u64;
}
if let Some(HeaderValue::Text(v)) = b.header.get("dst") {
im.recipient = v.clone();
}
if let Some(HeaderValue::Text(v)) = b.header.get("rto") {
im.sender = v.clone();
}
im.encrypted = res.decryption > 0;
im.signed_by = res.signatures.iter().map(|s| s.signer.clone()).collect();
Ok(im)
}
pub fn bottle(&self) -> Bottle {
let mut b = Bottle::new(self.body.clone());
b.header
.insert("mid".into(), HeaderValue::Bytes(self.id.to_vec()));
if self.flags != 0 {
b.header.insert(
"flg".into(),
HeaderValue::Integer((self.flags as i64).into()),
);
}
if !self.recipient.is_empty() {
b.header
.insert("dst".into(), HeaderValue::Text(self.recipient.clone()));
}
if !self.sender.is_empty() {
b.header
.insert("rto".into(), HeaderValue::Text(self.sender.clone()));
}
b
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&self.id);
append_uvarint(&mut buf, self.flags);
append_uvarint(&mut buf, self.recipient.len() as u64);
buf.extend_from_slice(self.recipient.as_bytes());
append_uvarint(&mut buf, self.sender.len() as u64);
buf.extend_from_slice(self.sender.as_bytes());
buf.extend_from_slice(&self.body);
buf
}
pub fn read_header(&mut self, buf: &[u8]) -> Result<usize> {
if buf.len() < 16 {
return Err(Error::Other("truncated instant message".into()));
}
self.id.copy_from_slice(&buf[..16]);
let (flags, n) =
read_uvarint(&buf[16..]).map_err(|e| Error::Other(format!("bad flags varint: {e}")))?;
self.flags = flags;
Ok(16 + n)
}
}