Skip to content

Commit 52cc600

Browse files
committed
Implemented QWK command & QWK settings.
1 parent 0b45ae8 commit 52cc600

File tree

17 files changed

+771
-46
lines changed

17 files changed

+771
-46
lines changed

crates/icbsetup/src/import/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use icy_board_engine::{
1717
group_list::GroupList,
1818
icb_config::{
1919
BoardInformation, BoardOptions, ColorConfiguration, ConfigPaths, DEFAULT_PCBOARD_DATE_FORMAT, DisplayNewsBehavior, IcbColor, IcbConfig,
20-
NewUserSettings, SubscriptionMode, SysopCommandLevels, SysopInformation,
20+
NewUserSettings, QwkSettings, SubscriptionMode, SysopCommandLevels, SysopInformation,
2121
},
2222
icb_text::IcbTextFile,
2323
language::SupportedLanguages,
@@ -508,6 +508,7 @@ impl PCBoardImporter {
508508
logoff_file: accounting_logoff_file,
509509
accounting_config: None,
510510
},
511+
qwk_settings: QwkSettings::default(),
511512
};
512513
icb_cfg.board.allow_iemsi = false;
513514
icb_cfg.login_server.telnet.port = 1337;

crates/icbsetup/src/tabs/general/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ mod configuration_options;
2626
mod connection_info;
2727
mod event_setup;
2828
mod file_locations;
29+
mod msg_networking;
2930
mod new_user_options;
3031
mod security_levels;
3132
mod subscription_information;
@@ -55,7 +56,7 @@ impl GeneralTab {
5556
MenuItem::new(7, 'H', get_text("icb_setup_main_sec_levels")).with_help(get_text("icb_setup_main_sec_levels-help")),
5657
MenuItem::new(8, 'I', get_text("icb_setup_main_acc_cfg")).with_help(get_text("icb_setup_main_acc_cfg-help")),
5758
MenuItem::new(9, 'J', get_text("icb_setup_main_new_user")).with_help(get_text("icb_setup_main_new_user-help")),
58-
MenuItem::new(10, 'K', "TODO: Mailer/Tosser".to_string()),
59+
MenuItem::new(10, 'K', get_text("icb_setup_msg_networking")).with_help(get_text("icb_setup_msg_networking-help")),
5960
MenuItem::new(11, 'L', get_text("icb_setup_mb_conf")).with_help(get_text("icb_setup_mb_conf-help")),
6061
MenuItem::new(12, 'M', get_text("icb_setup_conferences")).with_help(get_text("icb_setup_conferences-help")),
6162
]))
@@ -137,6 +138,11 @@ impl TabPage for GeneralTab {
137138
return self.page.open_sup_page(Box::new(page));
138139
}
139140

141+
10 => {
142+
let page = msg_networking::MsgNetworking::new(self.icy_board.clone());
143+
return self.page.open_sup_page(Box::new(page));
144+
}
145+
140146
11 => {
141147
// Main Board Configuration
142148
let page = conferences::ConferenceEditor::new(self.icy_board.clone(), 0);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::sync::{Arc, Mutex};
2+
3+
use crossterm::event::KeyEvent;
4+
use icy_board_engine::icy_board::IcyBoard;
5+
use icy_board_tui::{
6+
config_menu::ResultState,
7+
get_text,
8+
icbsetupmenu::IcbSetupMenuUI,
9+
select_menu::{MenuItem, SelectMenu},
10+
tab_page::{Page, PageMessage},
11+
};
12+
use ratatui::{Frame, layout::Rect};
13+
14+
mod qwk;
15+
16+
pub struct MsgNetworking {
17+
pub page: IcbSetupMenuUI,
18+
icy_board: Arc<Mutex<IcyBoard>>,
19+
}
20+
21+
impl MsgNetworking {
22+
pub fn new(icy_board: Arc<Mutex<IcyBoard>>) -> Self {
23+
Self {
24+
page: IcbSetupMenuUI::new(SelectMenu::new(vec![
25+
MenuItem::new(0, 'A', get_text("msg_networking_qwk")),
26+
MenuItem::new(1, 'B', "FTN TODO".to_string()),
27+
MenuItem::new(2, 'C', "UUCP TODO".to_string()),
28+
]))
29+
.with_center_title(get_text("msg_networking_title")),
30+
icy_board,
31+
}
32+
}
33+
}
34+
35+
impl Page for MsgNetworking {
36+
fn render(&mut self, frame: &mut Frame, area: Rect) {
37+
self.page.render(frame, area);
38+
}
39+
40+
fn request_status(&self) -> ResultState {
41+
self.page.request_status()
42+
}
43+
44+
fn handle_key_press(&mut self, key: KeyEvent) -> PageMessage {
45+
if key.code == crossterm::event::KeyCode::Esc {
46+
return PageMessage::Close;
47+
}
48+
let (_state, opt) = self.page.handle_key_press(key);
49+
50+
if let Some(selected) = opt {
51+
return match selected {
52+
0 => PageMessage::OpenSubPage(Box::new(qwk::QwkSettings::new(self.icy_board.clone()))),
53+
// 1 => PageMessage::OpenSubPage(Box::new(ssh::SSH::new(self.icy_board.clone()))),
54+
//2 => PageMessage::OpenSubPage(Box::new(Websockets::new(self.icy_board.clone()))),
55+
// 2 => PageMessage::OpenSubPage(Box::new(SecureWebsockets::new(self.icy_board.clone()))),
56+
_ => PageMessage::None,
57+
};
58+
}
59+
PageMessage::None
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use std::sync::{Arc, Mutex};
2+
3+
use crossterm::event::KeyEvent;
4+
use icy_board_engine::icy_board::IcyBoard;
5+
use icy_board_tui::{
6+
cfg_entry_path, cfg_entry_text,
7+
config_menu::{ConfigEntry, ConfigMenu, ResultState},
8+
get_text,
9+
icbconfigmenu::ICBConfigMenuUI,
10+
tab_page::{Page, PageMessage},
11+
};
12+
13+
pub struct QwkSettings {
14+
menu: ICBConfigMenuUI,
15+
}
16+
17+
impl QwkSettings {
18+
pub fn new(icy_board: Arc<Mutex<IcyBoard>>) -> Self {
19+
let menu = {
20+
let lock = icy_board.lock().unwrap();
21+
let label_width = 14;
22+
let sysop_info: Vec<icy_board_tui::config_menu::ConfigEntry<Arc<Mutex<IcyBoard>>>> = vec![
23+
ConfigEntry::Separator,
24+
ConfigEntry::Label(get_text("qwk_bbs_label")),
25+
cfg_entry_text!("qwk_bbs_name", label_width, 25, qwk_settings, bbs_name, lock),
26+
cfg_entry_text!("qwk_bbs_city_and_state", label_width, 25, qwk_settings, bbs_city_and_state, lock),
27+
cfg_entry_text!("qwk_bbs_phone_number", label_width, 25, qwk_settings, bbs_phone_number, lock),
28+
cfg_entry_text!("qwk_bbs_sysop_name", label_width, 25, qwk_settings, bbs_sysop_name, lock),
29+
cfg_entry_text!("qwk_bbs_id", label_width, 25, qwk_settings, bbs_id, lock),
30+
ConfigEntry::Separator,
31+
ConfigEntry::Label(get_text("qwk_files_label")),
32+
cfg_entry_path!("qwk_welcome_screen", label_width, qwk_settings, welcome_screen, lock),
33+
cfg_entry_path!("qwk_goodbye_screen", label_width, qwk_settings, goodbye_screen, lock),
34+
cfg_entry_path!("qwk_news_sceen", label_width, qwk_settings, news_sceen, lock),
35+
];
36+
ConfigMenu {
37+
obj: icy_board.clone(),
38+
entry: sysop_info,
39+
}
40+
};
41+
Self {
42+
menu: ICBConfigMenuUI::new(get_text("qwk_settings_title"), menu),
43+
}
44+
}
45+
}
46+
47+
impl Page for QwkSettings {
48+
fn render(&mut self, frame: &mut ratatui::Frame, disp_area: ratatui::prelude::Rect) {
49+
self.menu.render(frame, disp_area)
50+
}
51+
fn request_status(&self) -> ResultState {
52+
self.menu.request_status()
53+
}
54+
fn handle_key_press(&mut self, key: KeyEvent) -> PageMessage {
55+
self.menu.handle_key_press(key)
56+
}
57+
}

crates/icy_board_engine/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ semver = { workspace = true }
2424
regex = { workspace = true }
2525
walkdir = { workspace = true }
2626
bitflag = { workspace = true }
27+
tempfile = { workspace = true }
2728

2829
unicase = { workspace = true }
2930
rand = { workspace = true }
@@ -48,6 +49,7 @@ temp-file = "0.1.9"
4849
glob = "0.3.2"
4950
chumsky = "0.9.3"
5051
creditcard = "0.1.0"
52+
zip = "2.2.3"
5153

5254
# interpreter deps
5355
[dev-dependencies]

crates/icy_board_engine/src/data/ICBTEXT.toml

+23-3
Original file line numberDiff line numberDiff line change
@@ -2233,11 +2233,11 @@ text = "(H)elp, (1-@NUMDIR@), File List Command"
22332233
style = "Yellow"
22342234

22352235
[ConferenceHeader1]
2236-
text = "Conference Last High"
2236+
text = "Conference"
22372237
style = "White"
22382238

22392239
[ConferenceHeader2]
2240-
text = " # Name Read Num. Flags"
2240+
text = "# Name Flags"
22412241
style = "White"
22422242

22432243
[CTTYOn]
@@ -2595,7 +2595,7 @@ text = "Error compressing file."
25952595
style = "Red"
25962596

25972597
[QWKCommands]
2598-
text = "QWK Commands: (D)ownload, (U)pload"
2598+
text = "QWK Commands: (D)ownload, (U)pload, (S)canned bases"
25992599
style = "Green"
26002600

26012601
[ExtractingMessages]
@@ -2959,3 +2959,23 @@ style = "Yellow"
29592959
[ScanningArea]
29602960
text = "Scanning Area"
29612961
style = "White"
2962+
2963+
[QWKListCommands]
2964+
text = "Enter Area Numbers, (S)elect All, (D)eselect All, (Enter)=none"
2965+
style = "Yellow"
2966+
2967+
[QWKListCommandsExpertmode]
2968+
text = "(S), (D), (Enter)"
2969+
style = "Yellow"
2970+
2971+
[MessageAreaListHeader1]
2972+
text = "Message Area Last High"
2973+
style = "White"
2974+
2975+
[MessageAreaListHeader2]
2976+
text = " # Name Read Num."
2977+
style = "White"
2978+
2979+
[SelectArea]
2980+
text = "@OPTEXT@ Select Area"
2981+
style = "Yellow"

crates/icy_board_engine/src/icy_board/commands.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ impl CommandType {
613613
CommandType::RunPPE => "hlpppe",
614614
CommandType::TextSearch => "hlpts",
615615
CommandType::ChangeMessageArea => "hlparea",
616-
616+
CommandType::QWK => "hlpqwk",
617617
_ => "",
618618
}
619619
}

crates/icy_board_engine/src/icy_board/icb_config.rs

+16
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,8 @@ pub struct IcbConfig {
691691
pub options: BoardOptions,
692692
pub event: EventOptions,
693693
pub accounting: AccountingOptions,
694+
#[serde(default)]
695+
pub qwk_settings: QwkSettings,
694696

695697
pub login_server: LoginServer,
696698

@@ -962,6 +964,7 @@ impl IcbConfig {
962964
logoff_file: PathBuf::new(),
963965
accounting_config: None,
964966
},
967+
qwk_settings: QwkSettings::default(),
965968
}
966969
}
967970
}
@@ -975,3 +978,16 @@ impl Default for IcbConfig {
975978
Self::new()
976979
}
977980
}
981+
982+
#[derive(Default, Clone, Serialize, Deserialize, PartialEq)]
983+
pub struct QwkSettings {
984+
pub bbs_name: String,
985+
pub bbs_city_and_state: String,
986+
pub bbs_phone_number: String,
987+
pub bbs_sysop_name: String,
988+
pub bbs_id: String,
989+
990+
pub welcome_screen: PathBuf,
991+
pub goodbye_screen: PathBuf,
992+
pub news_sceen: PathBuf,
993+
}

crates/icy_board_engine/src/icy_board/icb_text.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -1374,7 +1374,7 @@ pub enum IceText {
13741374
CreatingQWK = 676,
13751375
/// `Error compressing file.`
13761376
ErrorCompressing = 677,
1377-
/// `QWK Commands: (D)ownload, (U)pload`
1377+
/// `QWK Commands: (D)ownload, (U)pload, (S)canned bases`
13781378
QWKCommands = 678,
13791379
/// `Extracting messages, please wait...`
13801380
ExtractingMessages = 679,
@@ -1587,9 +1587,24 @@ pub enum IceText {
15871587

15881588
/// `Scanning Area`
15891589
ScanningArea = 773,
1590+
1591+
/// `Enter Area Numbers, (S)elect All, (D)eselect All, (L)ast Read, (Enter)=none`
1592+
QWKListCommands = 774,
1593+
1594+
/// `(S), (D), (L), (Enter)`
1595+
QWKListCommandsExpertmode = 775,
1596+
1597+
/// `Message Area Last High`
1598+
MessageAreaListHeader1 = 776,
1599+
1600+
/// ` # Name Read Num. Include`
1601+
MessageAreaListHeader2 = 777,
1602+
1603+
/// `@OPTEXT@ Select Area`
1604+
SelectArea = 778,
15901605
}
15911606

1592-
const LAST_ENTRY: usize = 773;
1607+
const LAST_ENTRY: usize = 778;
15931608

15941609
impl IceText {
15951610
pub fn from(i: usize) -> Self {

crates/icy_board_engine/src/icy_board/message_area.rs

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
};
55

66
use async_trait::async_trait;
7+
use jamjam::jam::JamMessageBase;
78
use serde::{Deserialize, Serialize};
89
use serde_with::{DisplayFromStr, serde_as};
910

@@ -38,6 +39,14 @@ pub struct MessageArea {
3839
pub req_level_to_save_attach: SecurityExpression,
3940
}
4041

42+
impl MessageArea {
43+
pub fn get_high_msg(&self) -> u32 {
44+
JamMessageBase::open(&self.path)
45+
.map(|jam| jam.base_messagenumber() + jam.active_messages())
46+
.unwrap_or(0)
47+
}
48+
}
49+
4150
#[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
4251
pub struct AreaList {
4352
#[serde(rename = "area")]

0 commit comments

Comments
 (0)