diff --git a/src/engine/db/mod.rs b/src/engine/db/mod.rs index fd428a3..0b79c24 100644 --- a/src/engine/db/mod.rs +++ b/src/engine/db/mod.rs @@ -707,7 +707,11 @@ impl ChannelInfo { '+' => adding = true, '-' => adding = false, m if m.is_ascii_alphabetic() => { - if (m == 'r' || self.lock_on.contains(m)) && !adding && !readd.contains(m) { + // A param mode (e.g. +f) is re-asserted whenever it's touched — set + // as well as unset — so changing its param is reverted to the locked + // one, not just re-added after a plain `-f`. + let param_locked = self.lock_params.iter().any(|(c, _)| *c == m); + if (m == 'r' || self.lock_on.contains(m)) && (!adding || param_locked) && !readd.contains(m) { readd.push(m); } else if self.lock_off.contains(m) && adding && !reremove.contains(m) { reremove.push(m); diff --git a/src/engine/db/tests.rs b/src/engine/db/tests.rs index cf66719..487533b 100644 --- a/src/engine/db/tests.rs +++ b/src/engine/db/tests.rs @@ -764,6 +764,14 @@ assert_eq!(info.enforce("-r"), Some("+r".to_string())); // +r always locked assert_eq!(info.enforce("+m"), None); // unrelated mode ignored + // A param mode (+f): both a plain unset AND a changed param revert to the + // locked param — not just the unset case. + db.set_mlock_params("#chan", "ntf", "s", vec![('f', "kick:4:5s".to_string())]).unwrap(); + let info = db.channel("#chan").unwrap(); + assert_eq!(info.enforce("-f"), Some("+f kick:4:5s".to_string())); // unset re-added with param + assert_eq!(info.enforce("+f"), Some("+f kick:4:5s".to_string())); // changed param reverted + db.set_mlock("#chan", "nt", "s").unwrap(); // restore for the reopen check + drop(db); let db = Db::open(&p, "local"); assert_eq!(db.channel("#chan").unwrap().lock_modes(), "+rnt-s", "survives reopen");