diff --git a/modules/protocol/inspircd/src/lib.rs b/modules/protocol/inspircd/src/lib.rs index c332f4e..062f586 100644 --- a/modules/protocol/inspircd/src/lib.rs +++ b/modules/protocol/inspircd/src/lib.rs @@ -11,14 +11,17 @@ pub struct InspIrcd { password: String, protocol: u32, ts: u64, + // User modes our pseudo-clients (services + bots) are introduced with, e.g. + // "iHkBT" — invisible, hideoper, servprotect (U-line only), bot, block-CTCP. + service_modes: String, // Monotonic membership id for our own IJOINs. InspIRCd requires a membid on // IJOIN (`IJOIN `); it need only be unique among our members. membid: u64, } impl InspIrcd { - pub fn new(name: String, description: String, sid: String, password: String, protocol: u32, ts: u64) -> Self { - Self { sid, name, description, password, protocol, ts, membid: 0 } + pub fn new(name: String, description: String, sid: String, password: String, protocol: u32, ts: u64, service_modes: String) -> Self { + Self { sid, name, description, password, protocol, ts, service_modes, membid: 0 } } fn sourced(&self, cmd: String) -> String { @@ -298,8 +301,8 @@ impl Protocol for InspIrcd { // insp4 UID: uuid nickts nick realhost disphost realuser dispuser ip signonts +modes :gecos // (both a real AND a displayed user field — see m_spanningtree/uid.cpp Builder). NetAction::IntroduceUser { uid, nick, ident, host, gecos } => vec![self.sourced(format!( - "UID {uid} {ts} {nick} {host} {host} {ident} {ident} 0.0.0.0 {ts} +i :{gecos}", - uid = uid, ts = self.ts, nick = nick, host = host, ident = ident, gecos = gecos + "UID {uid} {ts} {nick} {host} {host} {ident} {ident} 0.0.0.0 {ts} +{modes} :{gecos}", + uid = uid, ts = self.ts, nick = nick, host = host, ident = ident, modes = self.service_modes, gecos = gecos ))], NetAction::Privmsg { from, to, text } => { vec![format!(":{} PRIVMSG {} :{}", from, to, text)] @@ -488,7 +491,7 @@ mod tests { use super::*; fn proto() -> InspIrcd { - InspIrcd::new("services.test".into(), "Federated Services".into(), "42S".into(), "pw".into(), 1206, 1) + InspIrcd::new("services.test".into(), "Federated Services".into(), "42S".into(), "pw".into(), 1206, 1, "iHkBT".into()) } // A remote nick change must surface as a NickChange for the source uid, or diff --git a/src/config.rs b/src/config.rs index 33b0526..7fb895d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -280,6 +280,15 @@ pub struct Server { // rather than the generic default. #[serde(default)] pub service_host: String, + // User modes the service pseudo-clients (services + bots) are introduced with. + // Default "iHkBT": invisible, hideoper, servprotect (unkillable — needs the + // services server U-lined), bot, block-CTCP. Set per the ircd's loaded modules. + #[serde(default = "default_service_modes")] + pub service_modes: String, +} + +fn default_service_modes() -> String { + "iHkBT".to_string() } fn default_protocol() -> u32 { diff --git a/src/main.rs b/src/main.rs index 5e68a86..f96134e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,6 +82,7 @@ async fn main() -> Result<()> { cfg.uplink.password.clone(), cfg.server.protocol, ts, + cfg.server.service_modes.clone(), )); // Bring up the service modules named in [modules] (default: the full