use bstr::{BString, ByteSlice};
use super::QwkError;
#[derive(Debug, Clone)]
pub struct Conference {
pub number: u16,
pub name: bstr::BString,
}
#[derive(Debug, Clone)]
pub struct ControlDat {
pub bbs_name: bstr::BString,
pub bbs_city_and_state: bstr::BString,
pub bbs_phone_number: bstr::BString,
pub bbs_sysop_name: bstr::BString,
pub bbs_id: bstr::BString,
pub serial_number: i32,
pub creation_time: bstr::BString,
pub qmail_user_name: bstr::BString,
pub qmail_menu_name: bstr::BString,
pub zero_line: bstr::BString,
pub message_count: u32,
pub conferences: Vec<Conference>,
pub welcome_screen: bstr::BString,
pub news_screen: bstr::BString,
pub logoff_screen: bstr::BString,
pub extra_lines: Vec<BString>,
}
const EOL: &[u8; 1] = b"\n";
impl ControlDat {
pub fn read(s: &[u8]) -> crate::Result<Self> {
let mut lines = s.lines();
let bbs_name = BString::from(lines.next().unwrap_or_default());
let bbs_city_and_state = BString::from(lines.next().unwrap_or_default());
let bbs_phone_number = BString::from(lines.next().unwrap_or_default());
let bbs_sysop_name = BString::from(lines.next().unwrap_or_default());
let id_line = lines.next().unwrap_or_default();
let mut bbs_id = BString::from(id_line);
let mut serial_number = 0;
for i in 0..id_line.len() {
if id_line[i] == b',' {
let (serial, id) = id_line.split_at(i);
bbs_id = BString::from(&id[1..]);
if let Ok(num) = serial.to_str()?.parse::<i32>() {
serial_number = num;
}
break;
}
}
let creation_time = BString::from(lines.next().unwrap_or_default());
let qmail_user_name = BString::from(lines.next().unwrap_or_default());
let qmail_menu_name = BString::from(lines.next().unwrap_or_default());
let zero_line = BString::from(lines.next().unwrap_or_default());
let num_messages_txt = lines.next().unwrap_or_default();
let message_count = if let Ok(num) = num_messages_txt.to_str()?.parse::<u32>() {
num
} else {
return Err(QwkError::CantParseMessageNumbers(num_messages_txt.into()).into());
};
let num_conferences = lines.next().unwrap_or_default();
let mut conferences = Vec::new();
if let Ok(num) = num_conferences.to_str()?.parse::<u16>() {
for _ in 0..num {
let number_txt = lines.next().unwrap_or_default();
let name = BString::from(lines.next().unwrap_or_default());
if let Ok(number) = number_txt.to_str()?.parse::<u16>() {
let conference = Conference { number, name };
conferences.push(conference);
} else {
return Err(QwkError::CantParseConferenceNumber(num_conferences.into()).into());
}
}
} else {
return Err(QwkError::CantParseConferenceNumber(num_conferences.into()).into());
}
let welcome_screen = BString::from(lines.next().unwrap_or_default());
let news_screen = BString::from(lines.next().unwrap_or_default());
let logoff_screen = BString::from(lines.next().unwrap_or_default());
let mut extra_lines: Vec<BString> = lines.map(BString::from).collect();
while extra_lines.last().is_some_and(|line| line.is_empty()) {
extra_lines.pop();
}
Ok(Self {
bbs_name,
bbs_city_and_state,
bbs_phone_number,
bbs_sysop_name,
bbs_id,
serial_number,
creation_time,
qmail_user_name,
qmail_menu_name,
zero_line,
message_count,
conferences,
welcome_screen,
news_screen,
logoff_screen,
extra_lines,
})
}
pub fn to_vec(&self) -> Vec<u8> {
let mut s = Vec::new();
s.extend(self.bbs_name.bytes());
s.extend(EOL);
s.extend(self.bbs_city_and_state.bytes());
s.extend(EOL);
s.extend(self.bbs_phone_number.bytes());
s.extend(EOL);
s.extend(self.bbs_sysop_name.bytes());
s.extend(EOL);
s.extend(format!("{},", self.serial_number).as_bytes());
s.extend(self.bbs_id.bytes());
s.extend(EOL);
s.extend(self.creation_time.bytes());
s.extend(EOL);
s.extend(self.qmail_user_name.bytes());
s.extend(EOL);
s.extend(self.qmail_menu_name.bytes());
s.extend(EOL);
s.push(b'0');
s.extend(EOL);
s.extend(self.message_count.to_string().as_bytes());
s.extend(EOL);
s.extend((self.conferences.len() as u16).to_string().as_bytes());
s.extend(EOL);
for conference in &self.conferences {
s.extend(conference.number.to_string().as_bytes());
s.extend(EOL);
s.extend(conference.name.bytes());
s.extend(EOL);
}
s.extend(self.welcome_screen.bytes());
s.extend(EOL);
s.extend(self.news_screen.bytes());
s.extend(EOL);
s.extend(self.logoff_screen.bytes());
for line in &self.extra_lines {
s.extend(EOL);
s.extend(line.bytes());
}
s
}
}