i18n: sweep all remaining dynamic prose (oper commands, XLINE/FILTER/DNSBL notices, whois/vhost/knock/dcc/title/reputation/tline/rmode, hash, rename) through trf; +\xNN catalog escape; fr+es now 236 entries each
This commit is contained in:
parent
ef96bcbd06
commit
9b51db07f5
32 changed files with 295 additions and 128 deletions
57
lang/es.conf
57
lang/es.conf
|
|
@ -31,6 +31,63 @@
|
|||
"{0} created channel {1}" = "{0} creó el canal {1}"
|
||||
"{0} used OJOIN to enter {1}" = "{0} usó OJOIN para entrar a {1}"
|
||||
|
||||
# --- comandos de operador: SA*/CHG/XLINE/FILTER/RLINE/etc. (prosa dinámica) ---
|
||||
"GLOBOPS from {0}: {1}" = "GLOBOPS de {0}: {1}"
|
||||
"{0}-line not found: {1}" = "línea {0} no encontrada: {1}"
|
||||
"R-line not found: {0}" = "línea R no encontrada: {0}"
|
||||
"Invalid RLINE regex: {0}" = "expresión regular RLINE no válida: {0}"
|
||||
"{0} used NICKLOCK on {1}" = "{0} usó NICKLOCK en {1}"
|
||||
"{0} used NICKUNLOCK on {1}" = "{0} usó NICKUNLOCK en {1}"
|
||||
"{0} used SQUIT on {1}" = "{0} usó SQUIT en {1}"
|
||||
"{0} used SAMODE: {1}" = "{0} usó SAMODE: {1}"
|
||||
"{0} used SATOPIC on {1}" = "{0} usó SATOPIC en {1}"
|
||||
"{0} used SAKICK on {1} in {2}" = "{0} usó SAKICK en {1} en {2}"
|
||||
"{0} used SAQUIT on {1}: {2}" = "{0} usó SAQUIT en {1}: {2}"
|
||||
"{0} used CHGNAME on {1}: {2}" = "{0} usó CHGNAME en {1}: {2}"
|
||||
"{0} used CLEARCHAN on {1}" = "{0} usó CLEARCHAN en {1}"
|
||||
"{0} used SWHOIS on {1}: {2}" = "{0} usó SWHOIS en {1}: {2}"
|
||||
"{0} is already banned on {1}" = "{0} ya está vetado en {1}"
|
||||
"[Knock] {0} is knocking: {1}" = "[Knock] {0} está llamando: {1}"
|
||||
"Channel invite list is full" = "La lista de invitaciones del canal está llena"
|
||||
"Your invite to {0} was revoked" = "Tu invitación a {0} fue revocada"
|
||||
"{0} renamed to {1} by {2}" = "{0} renombrado a {1} por {2}"
|
||||
"SSLINFO {0}: TLS={1} certfp={2}" = "SSLINFO {0}: TLS={1} certfp={2}"
|
||||
"{0} did a /WHOIS on you" = "{0} te hizo un /WHOIS"
|
||||
"Cannot message {0}: a TLS connection is required (+z)" = "No se puede enviar mensaje a {0}: se requiere una conexión TLS (+z)"
|
||||
"{0} IRC network" = "Red IRC {0}"
|
||||
"Your vhost is now {0}" = "Tu vhost ahora es {0}"
|
||||
"Your SIGNORE list is full ({0} max)." = "Tu lista SIGNORE está llena ({0} máx.)."
|
||||
"SIGNORE \x02{0}\x02 added — you and they can no longer see each other's messages." = "SIGNORE \x02{0}\x02 añadido — tú y esa persona ya no podéis ver los mensajes del otro."
|
||||
"SIGNORE \x02{0}\x02 removed." = "SIGNORE \x02{0}\x02 eliminado."
|
||||
"{0} (Flagged by the spam filter; network operators have been notified.)" = "{0} (Detectado por el filtro antispam; se ha notificado a los operadores de la red.)"
|
||||
"User {0} had an /amsg or /ame blocked" = "Al usuario {0} se le bloqueó un /amsg o /ame"
|
||||
"Cloudflare Challenge: {0}" = "Cloudflare Challenge: {0}"
|
||||
"connect class {0} is full ({1})" = "la clase de conexión {0} está llena ({1})"
|
||||
"connect class {0} refused {1}: {2}" = "la clase de conexión {0} rechazó {1}: {2}"
|
||||
"TITLE: you are now known as \"{0}\"." = "TITLE: ahora se le conoce como \"{0}\"."
|
||||
"Your DCC to {0} was blocked; they must /DCCALLOW +{1} first." = "Su DCC a {0} fue bloqueado; primero debe hacer /DCCALLOW +{1}."
|
||||
"{0} tried to send you {1} — blocked. /DCCALLOW +{2} to allow it, then ask them to resend." = "{0} intentó enviarle {1} — bloqueado. Haga /DCCALLOW +{2} para permitirlo, y luego pídale que lo reenvíe."
|
||||
"oper type '{0}' is not defined — granting full access" = "el tipo de operador '{0}' no está definido — otorgando acceso completo"
|
||||
"{0} hashed password: {1}" = "contraseña cifrada con {0}: {1}"
|
||||
"Unknown hash '{0}' (try md5, sha1, sha256, sha512, pbkdf2, bcrypt)" = "hash desconocido '{0}' (pruebe md5, sha1, sha256, sha512, pbkdf2, bcrypt)"
|
||||
"REPUTATION {0} ({1}) set to {2}" = "REPUTATION {0} ({1}) establecido en {2}"
|
||||
"RMODE: removed {0} +{1} entr{2} from {3}" = "RMODE: eliminó {0} entr{2} +{1} de {3}"
|
||||
"{0} is in security groups: {1}" = "{0} está en los grupos de seguridad: {1}"
|
||||
"{0}: file not available." = "{0}: archivo no disponible."
|
||||
"To cut spam, answer this to send your message — what is {0} {1} {2} ?" = "Para reducir el spam, responda esto para enviar su mensaje — ¿cuánto es {0} {1} {2} ?"
|
||||
"TLINE: {0} matches {1} of {2} local users ({3}%)" = "TLINE: {0} coincide con {1} de {2} usuarios locales ({3}%)"
|
||||
"RPC initiated a link to {0}" = "RPC inició un enlace hacia {0}"
|
||||
"slow event: a command took {0}ms on the core thread" = "evento lento: un comando tardó {0}ms en el hilo principal"
|
||||
"Could not hash with '{0}'" = "No se pudo cifrar con '{0}'"
|
||||
"Link denied: {0}" = "Enlace denegado: {0}"
|
||||
"End of channel {0}" = "Fin de {0} del canal"
|
||||
"{0} is now known as {1}" = "{0} ahora se conoce como {1}"
|
||||
"FILTER rejected ({0})" = "FILTER rechazado ({0})"
|
||||
"{0} added FILTER {1} (engine={2} action={3})" = "{0} añadió FILTER {1} (engine={2} action={3})"
|
||||
"XLINE: {0} added a {1}: {2}" = "XLINE: {0} añadió un {1}: {2}"
|
||||
"XLINE: {0} removed a {1}" = "XLINE: {0} eliminó un {1}"
|
||||
"XLINE: {0}-line on {1} expired" = "XLINE: la {0}-line sobre {1} ha expirado"
|
||||
|
||||
# --- avisos / desafíos ---
|
||||
"*** Cloudflare Challenge: verification successful — you may continue." = "*** Desafío de Cloudflare: verificación exitosa — puedes continuar."
|
||||
"*** Correct — you may now message freely; please resend your message." = "*** Correcto — ya puedes enviar mensajes libremente; por favor reenvía tu mensaje."
|
||||
|
|
|
|||
57
lang/fr.conf
57
lang/fr.conf
|
|
@ -31,6 +31,63 @@
|
|||
"{0} created channel {1}" = "{0} a créé le salon {1}"
|
||||
"{0} used OJOIN to enter {1}" = "{0} a utilisé OJOIN pour entrer dans {1}"
|
||||
|
||||
# --- commandes oper : SA*/CHG/XLINE/FILTER/RLINE/etc. (prose dynamique) ---
|
||||
"GLOBOPS from {0}: {1}" = "GLOBOPS de {0} : {1}"
|
||||
"{0}-line not found: {1}" = "ligne {0} introuvable : {1}"
|
||||
"R-line not found: {0}" = "ligne R introuvable : {0}"
|
||||
"Invalid RLINE regex: {0}" = "expression régulière RLINE invalide : {0}"
|
||||
"{0} used NICKLOCK on {1}" = "{0} a utilisé NICKLOCK sur {1}"
|
||||
"{0} used NICKUNLOCK on {1}" = "{0} a utilisé NICKUNLOCK sur {1}"
|
||||
"{0} used SQUIT on {1}" = "{0} a utilisé SQUIT sur {1}"
|
||||
"{0} used SAMODE: {1}" = "{0} a utilisé SAMODE : {1}"
|
||||
"{0} used SATOPIC on {1}" = "{0} a utilisé SATOPIC sur {1}"
|
||||
"{0} used SAKICK on {1} in {2}" = "{0} a utilisé SAKICK sur {1} dans {2}"
|
||||
"{0} used SAQUIT on {1}: {2}" = "{0} a utilisé SAQUIT sur {1} : {2}"
|
||||
"{0} used CHGNAME on {1}: {2}" = "{0} a utilisé CHGNAME sur {1} : {2}"
|
||||
"{0} used CLEARCHAN on {1}" = "{0} a utilisé CLEARCHAN sur {1}"
|
||||
"{0} used SWHOIS on {1}: {2}" = "{0} a utilisé SWHOIS sur {1} : {2}"
|
||||
"{0} is already banned on {1}" = "{0} est déjà banni sur {1}"
|
||||
"[Knock] {0} is knocking: {1}" = "[Knock] {0} frappe à la porte : {1}"
|
||||
"Channel invite list is full" = "La liste d'invitations du salon est pleine"
|
||||
"Your invite to {0} was revoked" = "Votre invitation à {0} a été révoquée"
|
||||
"{0} renamed to {1} by {2}" = "{0} renommé en {1} par {2}"
|
||||
"SSLINFO {0}: TLS={1} certfp={2}" = "SSLINFO {0} : TLS={1} certfp={2}"
|
||||
"{0} did a /WHOIS on you" = "{0} a fait un /WHOIS sur vous"
|
||||
"Cannot message {0}: a TLS connection is required (+z)" = "Impossible d'envoyer un message à {0} : une connexion TLS est requise (+z)"
|
||||
"{0} IRC network" = "Réseau IRC {0}"
|
||||
"Your vhost is now {0}" = "Votre vhost est maintenant {0}"
|
||||
"Your SIGNORE list is full ({0} max)." = "Votre liste SIGNORE est pleine ({0} max)."
|
||||
"SIGNORE \x02{0}\x02 added — you and they can no longer see each other's messages." = "SIGNORE \x02{0}\x02 ajouté — vous et cette personne ne pouvez plus voir vos messages respectifs."
|
||||
"SIGNORE \x02{0}\x02 removed." = "SIGNORE \x02{0}\x02 retiré."
|
||||
"{0} (Flagged by the spam filter; network operators have been notified.)" = "{0} (Signalé par le filtre anti-spam ; les opérateurs du réseau ont été avertis.)"
|
||||
"User {0} had an /amsg or /ame blocked" = "L'utilisateur {0} a eu un /amsg ou /ame bloqué"
|
||||
"Cloudflare Challenge: {0}" = "Cloudflare Challenge : {0}"
|
||||
"connect class {0} is full ({1})" = "la classe de connexion {0} est pleine ({1})"
|
||||
"connect class {0} refused {1}: {2}" = "la classe de connexion {0} a refusé {1} : {2}"
|
||||
"TITLE: you are now known as \"{0}\"." = "TITLE : vous êtes désormais connu sous le nom de « {0} »."
|
||||
"Your DCC to {0} was blocked; they must /DCCALLOW +{1} first." = "Votre DCC vers {0} a été bloqué ; il doit d'abord faire /DCCALLOW +{1}."
|
||||
"{0} tried to send you {1} — blocked. /DCCALLOW +{2} to allow it, then ask them to resend." = "{0} a tenté de vous envoyer {1} — bloqué. Faites /DCCALLOW +{2} pour l'autoriser, puis demandez-lui de renvoyer."
|
||||
"oper type '{0}' is not defined — granting full access" = "le type d'opérateur '{0}' n'est pas défini — octroi d'un accès complet"
|
||||
"{0} hashed password: {1}" = "mot de passe haché en {0} : {1}"
|
||||
"Unknown hash '{0}' (try md5, sha1, sha256, sha512, pbkdf2, bcrypt)" = "hachage inconnu '{0}' (essayez md5, sha1, sha256, sha512, pbkdf2, bcrypt)"
|
||||
"REPUTATION {0} ({1}) set to {2}" = "REPUTATION {0} ({1}) réglé sur {2}"
|
||||
"RMODE: removed {0} +{1} entr{2} from {3}" = "RMODE : a supprimé {0} entr{2} +{1} de {3}"
|
||||
"{0} is in security groups: {1}" = "{0} est dans les groupes de sécurité : {1}"
|
||||
"{0}: file not available." = "{0} : fichier non disponible."
|
||||
"To cut spam, answer this to send your message — what is {0} {1} {2} ?" = "Pour limiter le spam, répondez à ceci pour envoyer votre message — combien font {0} {1} {2} ?"
|
||||
"TLINE: {0} matches {1} of {2} local users ({3}%)" = "TLINE : {0} correspond à {1} des {2} utilisateurs locaux ({3}%)"
|
||||
"RPC initiated a link to {0}" = "RPC a initié une liaison vers {0}"
|
||||
"slow event: a command took {0}ms on the core thread" = "événement lent : une commande a pris {0}ms sur le thread principal"
|
||||
"Could not hash with '{0}'" = "Impossible de hacher avec '{0}'"
|
||||
"Link denied: {0}" = "Lien refusé : {0}"
|
||||
"End of channel {0}" = "Fin de {0} du salon"
|
||||
"{0} is now known as {1}" = "{0} est maintenant connu sous le nom de {1}"
|
||||
"FILTER rejected ({0})" = "FILTER rejeté ({0})"
|
||||
"{0} added FILTER {1} (engine={2} action={3})" = "{0} a ajouté FILTER {1} (engine={2} action={3})"
|
||||
"XLINE: {0} added a {1}: {2}" = "XLINE : {0} a ajouté un {1} : {2}"
|
||||
"XLINE: {0} removed a {1}" = "XLINE : {0} a supprimé un {1}"
|
||||
"XLINE: {0}-line on {1} expired" = "XLINE : la {0}-line sur {1} a expiré"
|
||||
|
||||
# --- notices / défis ---
|
||||
"*** Cloudflare Challenge: verification successful — you may continue." = "*** Défi Cloudflare : vérification réussie — vous pouvez continuer."
|
||||
"*** Correct — you may now message freely; please resend your message." = "*** Correct — vous pouvez maintenant envoyer des messages librement ; veuillez renvoyer votre message."
|
||||
|
|
|
|||
|
|
@ -66,12 +66,10 @@ impl Command for Tban {
|
|||
(u.nick.clone(), u.prefix())
|
||||
};
|
||||
if s.channels[&key].bans.iter().any(|b| b.mask == mask) {
|
||||
let m = s.trf("{0} is already banned on {1}", &[mask.as_str(), chan.as_str()]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :{mask} is already banned on {chan}",
|
||||
s.name
|
||||
),
|
||||
format!(":{} NOTICE {nick} :{m}", s.name),
|
||||
);
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
|
|
@ -127,12 +125,10 @@ impl Command for Knock {
|
|||
.cloned()
|
||||
.unwrap_or_else(|| "requesting an invite".to_string());
|
||||
let who = s.users[&uid].prefix();
|
||||
let m = s.trf("[Knock] {0} is knocking: {1}", &[who.as_str(), reason.as_str()]);
|
||||
s.to_channel(
|
||||
&key,
|
||||
&format!(
|
||||
":{} NOTICE {chan} :[Knock] {who} is knocking: {reason}",
|
||||
s.name
|
||||
),
|
||||
&format!(":{} NOTICE {chan} :{m}", s.name),
|
||||
None,
|
||||
);
|
||||
s.numeric(
|
||||
|
|
@ -314,9 +310,10 @@ impl Command for Invite {
|
|||
let maxinv = s.conf_num("maxinvites", 100usize);
|
||||
if s.channels[&key].invites.len() >= maxinv && !s.channels[&key].invites.contains(&tuid) {
|
||||
let nick = s.users.get(&uid).map(|u| u.nick.clone()).unwrap_or_default();
|
||||
let m = s.trf("Channel invite list is full", &[]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :{chan} :Channel invite list is full", s.name),
|
||||
format!(":{} NOTICE {nick} :{chan} :{m}", s.name),
|
||||
);
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
|
|
@ -408,12 +405,10 @@ impl Command for Uninvite {
|
|||
format!(":{} NOTICE {nick} :{who} {word} {chan}", s.name),
|
||||
);
|
||||
if removed {
|
||||
let m = s.trf("Your invite to {0} was revoked", &[chan.as_str()]);
|
||||
s.send(
|
||||
tuid,
|
||||
format!(
|
||||
":{} NOTICE {who} :Your invite to {chan} was revoked",
|
||||
s.name
|
||||
),
|
||||
format!(":{} NOTICE {who} :{m}", s.name),
|
||||
);
|
||||
}
|
||||
CmdResult::Ok
|
||||
|
|
@ -563,7 +558,8 @@ impl Command for Rename {
|
|||
s.fail(uid, "RENAME", "CANNOT_RENAME", "The channel cannot be renamed.");
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
s.snotice_c('a', &format!("{oldname} renamed to {new} by {prefix}"));
|
||||
let m = s.trf("{0} renamed to {1} by {2}", &[oldname.as_str(), new.as_str(), prefix.as_str()]);
|
||||
s.snotice_c('a', &m);
|
||||
s.propagate_rename(&uuid, &oldname, new, &reason, None);
|
||||
CmdResult::Ok
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,7 +245,9 @@ impl Command for Admin {
|
|||
RPL_ADMINME,
|
||||
&format!("{} :Administrative info", s.name),
|
||||
);
|
||||
s.numeric(uid, RPL_ADMINLOC1, &format!(":{} IRC network", s.network));
|
||||
let network = s.network.clone();
|
||||
let m = s.trf("{0} IRC network", &[network.as_str()]);
|
||||
s.numeric(uid, RPL_ADMINLOC1, &format!(":{m}"));
|
||||
s.numeric(
|
||||
uid,
|
||||
RPL_ADMINLOC2,
|
||||
|
|
|
|||
|
|
@ -53,12 +53,10 @@ impl Command for SslInfo {
|
|||
};
|
||||
let tls = if secure { "yes" } else { "no" };
|
||||
let fp = certfp.unwrap_or_else(|| "none".to_string());
|
||||
let m = s.trf("SSLINFO {0}: TLS={1} certfp={2}", &[nick.as_str(), tls, fp.as_str()]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {asker} :SSLINFO {nick}: TLS={tls} certfp={fp}",
|
||||
s.name
|
||||
),
|
||||
format!(":{} NOTICE {asker} :{m}", s.name),
|
||||
);
|
||||
CmdResult::Ok
|
||||
}
|
||||
|
|
@ -437,9 +435,10 @@ impl Command for Whois {
|
|||
// +W showwhois — tell the target that someone looked them up
|
||||
if showwhois && !is_self {
|
||||
let by = s.users.get(&uid).map(|u| u.prefix()).unwrap_or_default();
|
||||
let m = s.trf("{0} did a /WHOIS on you", &[by.as_str()]);
|
||||
s.send(
|
||||
tuid,
|
||||
format!(":{} NOTICE {nick} :*** {by} did a /WHOIS on you", s.name),
|
||||
format!(":{} NOTICE {nick} :*** {m}", s.name),
|
||||
);
|
||||
}
|
||||
s.numeric(uid, RPL_ENDOFWHOIS, &format!("{nick} :End of /WHOIS list"));
|
||||
|
|
|
|||
|
|
@ -543,12 +543,10 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool)
|
|||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
let m = s.trf("Cannot message {0}: a TLS connection is required (+z)", &[tn.as_str()]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {sn} :Cannot message {tn}: a TLS connection is required (+z)",
|
||||
s.name
|
||||
),
|
||||
format!(":{} NOTICE {sn} :{m}", s.name),
|
||||
);
|
||||
}
|
||||
return CmdResult::Fail;
|
||||
|
|
|
|||
|
|
@ -398,14 +398,12 @@ impl Command for GlobOps {
|
|||
.filter(|(_, u)| u.flags.oper)
|
||||
.map(|(&u, _)| u)
|
||||
.collect();
|
||||
let m = s.trf("GLOBOPS from {0}: {1}", &[from.as_str(), params[0].as_str()]);
|
||||
for o in opers {
|
||||
let nick = s.users.get(&o).map(|u| u.nick.clone()).unwrap_or_default();
|
||||
s.send(
|
||||
o,
|
||||
format!(
|
||||
":{} NOTICE {nick} :*** GLOBOPS from {from}: {}",
|
||||
s.name, params[0]
|
||||
),
|
||||
format!(":{} NOTICE {nick} :*** {m}", s.name),
|
||||
);
|
||||
}
|
||||
CmdResult::Ok
|
||||
|
|
@ -731,9 +729,10 @@ fn do_xline(s: &mut Server, uid: Uid, params: &[String], kind: XKind) -> CmdResu
|
|||
if s.remove_xline(kind, &mask, &nick) {
|
||||
s.propagate_delline(kind.tag(), &mask);
|
||||
} else {
|
||||
let m = s.trf("{0}-line not found: {1}", &[kind.tag(), mask.as_str()]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :{}-line not found: {mask}", s.name, kind.tag()),
|
||||
format!(":{} NOTICE {nick} :{m}", s.name),
|
||||
);
|
||||
}
|
||||
return CmdResult::Ok;
|
||||
|
|
@ -878,17 +877,20 @@ impl Command for Rline {
|
|||
if s.remove_xline(XKind::Rline, &pattern, &nick) {
|
||||
s.propagate_delline("R", &pattern);
|
||||
} else {
|
||||
let m = s.trf("R-line not found: {0}", &[pattern.as_str()]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :R-line not found: {pattern}", s.name),
|
||||
format!(":{} NOTICE {nick} :{m}", s.name),
|
||||
);
|
||||
}
|
||||
return CmdResult::Ok;
|
||||
}
|
||||
if let Err(e) = crate::regex::Regex::new(&pattern) {
|
||||
let e = e.to_string();
|
||||
let m = s.trf("Invalid RLINE regex: {0}", &[e.as_str()]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :Invalid RLINE regex: {e}", s.name),
|
||||
format!(":{} NOTICE {nick} :{m}", s.name),
|
||||
);
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
|
|
@ -952,7 +954,8 @@ impl Command for NickLock {
|
|||
u.flags.nick_locked = true;
|
||||
}
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used NICKLOCK on {newnick}"));
|
||||
let m = s.trf("{0} used NICKLOCK on {1}", &[by.as_str(), newnick.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
@ -977,7 +980,8 @@ impl Command for NickUnlock {
|
|||
u.flags.nick_locked = false;
|
||||
}
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used NICKUNLOCK on {}", params[0]));
|
||||
let m = s.trf("{0} used NICKUNLOCK on {1}", &[by.as_str(), params[0].as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
@ -1049,7 +1053,8 @@ impl Command for Squit {
|
|||
return CmdResult::Fail;
|
||||
};
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('l', &format!("{by} used SQUIT on {name}"));
|
||||
let m = s.trf("{0} used SQUIT on {1}", &[by.as_str(), name.as_str()]);
|
||||
s.snotice_c('l', &m);
|
||||
s.close_link(via, &format!("SQUIT from {by}"));
|
||||
CmdResult::Ok
|
||||
}
|
||||
|
|
@ -1209,7 +1214,9 @@ impl Command for SaMode {
|
|||
let r = apply_mode(s, uid, params);
|
||||
s.mode_sudo = false;
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used SAMODE: {}", params.join(" ")));
|
||||
let joined = params.join(" ");
|
||||
let m = s.trf("{0} used SAMODE: {1}", &[by.as_str(), joined.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
|
@ -1248,7 +1255,8 @@ impl Command for SaTopic {
|
|||
s.to_channel(&key, &format!(":{prefix} TOPIC {chan} :{text}"), None);
|
||||
s.propagate_topic(uid, chan, &text);
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used SATOPIC on {chan}"));
|
||||
let m = s.trf("{0} used SATOPIC on {1}", &[by.as_str(), chan.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
@ -1313,7 +1321,8 @@ impl Command for SaKick {
|
|||
s.events
|
||||
.push_back(Hook::Part(tuid, key, "kicked".to_string()));
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used SAKICK on {victim} in {chan}"));
|
||||
let m = s.trf("{0} used SAKICK on {1} in {2}", &[by.as_str(), victim.as_str(), chan.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
@ -1343,7 +1352,8 @@ impl Command for SaQuit {
|
|||
s.send(tuid, format!("ERROR :Closing link: (SAQUIT: {reason})"));
|
||||
s.remove_user(tuid, &format!("Quit: {reason}"));
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used SAQUIT on {}: {reason}", params[0]));
|
||||
let m = s.trf("{0} used SAQUIT on {1}: {2}", &[by.as_str(), params[0].as_str(), reason.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
@ -1379,7 +1389,8 @@ impl Command for ChgName {
|
|||
}
|
||||
s.notify_peers(t, &line, |c| c.setname);
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used CHGNAME on {}: {realname}", params[0]));
|
||||
let m = s.trf("{0} used CHGNAME on {1}: {2}", &[by.as_str(), params[0].as_str(), realname.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
@ -1436,7 +1447,8 @@ impl Command for ClearChan {
|
|||
}
|
||||
s.channels.retain(|_, c| c.keep_alive());
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used CLEARCHAN on {chan}"));
|
||||
let m = s.trf("{0} used CLEARCHAN on {1}", &[by.as_str(), chan.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
@ -1553,7 +1565,8 @@ impl Command for SwhoisCmd {
|
|||
}
|
||||
}
|
||||
let by = oper_nick(s, uid);
|
||||
s.snotice_c('v', &format!("{by} used SWHOIS on {}: {text}", params[0]));
|
||||
let m = s.trf("{0} used SWHOIS on {1}: {2}", &[by.as_str(), params[0].as_str(), text.as_str()]);
|
||||
s.snotice_c('v', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,9 +60,10 @@ impl Command for Vhost {
|
|||
match host {
|
||||
Some(h) => {
|
||||
s.change_host_ident(uid, None, Some(&h));
|
||||
let m = s.trf("Your vhost is now {0}", &[h.as_str()]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :Your vhost is now {h}", s.name),
|
||||
format!(":{} NOTICE {nick} :{m}", s.name),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -351,7 +351,9 @@ impl Command for Signore {
|
|||
.map(|u| u.signore.len() >= max && !u.signore.contains(&mask))
|
||||
.unwrap_or(true);
|
||||
if full {
|
||||
s.send(uid, format!(":{sn} NOTICE {nick} :Your SIGNORE list is full ({max} max)."));
|
||||
let maxs = max.to_string();
|
||||
let m = s.trf("Your SIGNORE list is full ({0} max).", &[maxs.as_str()]);
|
||||
s.send(uid, format!(":{sn} NOTICE {nick} :{m}"));
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
if let Some(u) = s.users.get_mut(&uid) {
|
||||
|
|
@ -359,12 +361,14 @@ impl Command for Signore {
|
|||
u.signore.push(mask.clone());
|
||||
}
|
||||
}
|
||||
s.send(uid, format!(":{sn} NOTICE {nick} :SIGNORE \x02{mask}\x02 added — you and they can no longer see each other's messages."));
|
||||
let m = s.trf("SIGNORE \x02{0}\x02 added — you and they can no longer see each other's messages.", &[mask.as_str()]);
|
||||
s.send(uid, format!(":{sn} NOTICE {nick} :{m}"));
|
||||
} else {
|
||||
if let Some(u) = s.users.get_mut(&uid) {
|
||||
u.signore.retain(|x| x != &mask);
|
||||
}
|
||||
s.send(uid, format!(":{sn} NOTICE {nick} :SIGNORE \x02{mask}\x02 removed."));
|
||||
let m = s.trf("SIGNORE \x02{0}\x02 removed.", &[mask.as_str()]);
|
||||
s.send(uid, format!(":{sn} NOTICE {nick} :{m}"));
|
||||
}
|
||||
// Persist the change to the user's services account (no-op if not logged in).
|
||||
s.push_signore_to_services(uid);
|
||||
|
|
|
|||
14
src/i18n.rs
14
src/i18n.rs
|
|
@ -231,6 +231,20 @@ fn read_quoted(s: &str) -> Option<(String, &str)> {
|
|||
't' => out.push('\t'),
|
||||
'"' => out.push('"'),
|
||||
'\\' => out.push('\\'),
|
||||
// \xNN — a raw byte, so IRC formatting controls (e.g. \x02 bold) in a
|
||||
// msgid match the literal byte the source `"\x02"` compiles to.
|
||||
'x' => {
|
||||
let (h1, h2) = (chars.next()?.1, chars.next()?.1);
|
||||
match u8::from_str_radix(&format!("{h1}{h2}"), 16) {
|
||||
Ok(b) => out.push(b as char),
|
||||
Err(_) => {
|
||||
out.push('\\');
|
||||
out.push('x');
|
||||
out.push(h1);
|
||||
out.push(h2);
|
||||
}
|
||||
}
|
||||
}
|
||||
other => {
|
||||
out.push('\\');
|
||||
out.push(other);
|
||||
|
|
|
|||
22
src/ircd.rs
22
src/ircd.rs
|
|
@ -175,8 +175,11 @@ impl Ircd {
|
|||
busy.store(0, Ordering::Relaxed);
|
||||
let ms = start.elapsed().as_millis() as u64;
|
||||
if slow_ms != 0 && ms >= slow_ms {
|
||||
self.server
|
||||
.snotice(&format!("slow event: a command took {ms}ms on the core thread"));
|
||||
let ms_s = ms.to_string();
|
||||
let m = self
|
||||
.server
|
||||
.trf("slow event: a command took {0}ms on the core thread", &[ms_s.as_str()]);
|
||||
self.server.snotice(&m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -260,11 +263,16 @@ impl Ircd {
|
|||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default();
|
||||
let line = match hash {
|
||||
Some(h) => format!(
|
||||
":{} NOTICE {nick} :{algo} hashed password: {h}",
|
||||
self.server.name
|
||||
),
|
||||
None => format!(":{} NOTICE {nick} :Could not hash with '{algo}'", self.server.name),
|
||||
Some(h) => {
|
||||
let m = self
|
||||
.server
|
||||
.trf("{0} hashed password: {1}", &[algo.as_str(), h.as_str()]);
|
||||
format!(":{} NOTICE {nick} :{m}", self.server.name)
|
||||
}
|
||||
None => {
|
||||
let m = self.server.trf("Could not hash with '{0}'", &[algo.as_str()]);
|
||||
format!(":{} NOTICE {nick} :{m}", self.server.name)
|
||||
}
|
||||
};
|
||||
self.server.send(uid, line);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -340,7 +340,8 @@ impl Server {
|
|||
}
|
||||
|
||||
fn reject_link(&mut self, uid: Uid, why: &str) {
|
||||
self.link_out(uid, format!("ERROR :Link denied: {why}"));
|
||||
let m = self.trf("Link denied: {0}", &[why]);
|
||||
self.link_out(uid, format!("ERROR :{m}"));
|
||||
eprintln!("[link] rejected {uid}: {why}");
|
||||
self.close_link(uid, why);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -726,7 +726,8 @@ impl ChanMode for ListMode {
|
|||
for (m, setter, ts) in rows {
|
||||
s.numeric(uid, entry_num, &format!("{chan} {m} {setter} {ts}"));
|
||||
}
|
||||
s.numeric(uid, end_num, &format!("{chan} :End of channel {noun}"));
|
||||
let m = s.trf("End of channel {0}", &[noun]);
|
||||
s.numeric(uid, end_num, &format!("{chan} :{m}"));
|
||||
return Applied::No;
|
||||
};
|
||||
// autoop (+w) embeds a status prefix to grant on join, applied under server
|
||||
|
|
|
|||
|
|
@ -285,12 +285,14 @@ impl Module for AntiMixedUtf8 {
|
|||
|
||||
// Notify the sender even for punitive actions: the writer flushes queued
|
||||
// lines before a disconnect.
|
||||
let block_msg = srv.amu.block_msg.clone();
|
||||
let m = srv.trf(
|
||||
"{0} (Flagged by the spam filter; network operators have been notified.)",
|
||||
&[block_msg.as_str()],
|
||||
);
|
||||
srv.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :*** {} (Flagged by the spam filter; network operators have been notified.)",
|
||||
srv.name, srv.amu.block_msg
|
||||
),
|
||||
format!(":{} NOTICE {nick} :*** {m}", srv.name),
|
||||
);
|
||||
|
||||
let action = srv.amu.action.to_ascii_lowercase();
|
||||
|
|
|
|||
|
|
@ -90,7 +90,8 @@ impl Module for BlockAmsg {
|
|||
let notify_opers = matches!(action.as_str(), "killopers" | "noticeopers" | "zlineopers");
|
||||
if notify_opers {
|
||||
let mask = srv.users.get(&uid).map(|u| u.prefix()).unwrap_or_default();
|
||||
srv.snotice(&format!("User {mask} had an /amsg or /ame blocked"));
|
||||
let m = srv.trf("User {0} had an /amsg or /ame blocked", &[mask.as_str()]);
|
||||
srv.snotice(&m);
|
||||
}
|
||||
let reason = "Attempted to global message (/amsg or /ame)";
|
||||
match action.as_str() {
|
||||
|
|
|
|||
|
|
@ -158,9 +158,10 @@ impl Command for VerifyChallenge {
|
|||
.unwrap_or_default();
|
||||
|
||||
let fail = |s: &mut Server, why: &str| {
|
||||
let m = s.trf("Cloudflare Challenge: {0}", &[why]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :*** Cloudflare Challenge: {why}", s.name),
|
||||
format!(":{} NOTICE {nick} :*** {m}", s.name),
|
||||
);
|
||||
CmdResult::Fail
|
||||
};
|
||||
|
|
|
|||
|
|
@ -289,7 +289,9 @@ fn pick(
|
|||
if let Some(max) = c.limit {
|
||||
if class_count(s, &c.name, uid) >= max {
|
||||
if c.maxconnwarn {
|
||||
s.snotice_c('c', &format!("connect class {} is full ({max})", c.name));
|
||||
let max_s = max.to_string();
|
||||
let m = s.trf("connect class {0} is full ({1})", &[c.name.as_str(), max_s.as_str()]);
|
||||
s.snotice_c('c', &m);
|
||||
}
|
||||
continue; // full — try the next class
|
||||
}
|
||||
|
|
@ -355,7 +357,11 @@ pub fn assign(s: &mut Server, uid: Uid) -> Option<String> {
|
|||
};
|
||||
let warn = |s: &Server, why: &str| {
|
||||
if class.maxconnwarn {
|
||||
s.snotice_c('c', &format!("connect class {} refused {ip}: {why}", class.name));
|
||||
let m = s.trf(
|
||||
"connect class {0} refused {1}: {2}",
|
||||
&[class.name.as_str(), ip.as_str(), why],
|
||||
);
|
||||
s.snotice_c('c', &m);
|
||||
}
|
||||
};
|
||||
if let Some(max) = class.localmax {
|
||||
|
|
|
|||
|
|
@ -45,9 +45,10 @@ pub fn grant(s: &mut Server, uid: Uid, title: &str, vhost: &str) {
|
|||
s.change_host_ident(uid, None, Some(vhost));
|
||||
}
|
||||
let nick = nick(s, uid);
|
||||
let m = s.trf("TITLE: you are now known as \"{0}\".", &[title]);
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :*** TITLE: you are now known as \"{title}\".", s.name),
|
||||
format!(":{} NOTICE {nick} :*** {m}", s.name),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,19 +117,21 @@ impl Module for DccAllow {
|
|||
return ModResult::Passthru;
|
||||
}
|
||||
let tnick = s.users.get(&tuid).map(|u| u.nick.clone()).unwrap_or_default();
|
||||
let m1 = s.trf(
|
||||
"Your DCC to {0} was blocked; they must /DCCALLOW +{1} first.",
|
||||
&[tnick.as_str(), sender.as_str()],
|
||||
);
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {sender} :*** Your DCC to {tnick} was blocked; they must /DCCALLOW +{sender} first.",
|
||||
s.name
|
||||
),
|
||||
format!(":{} NOTICE {sender} :*** {m1}", s.name),
|
||||
);
|
||||
let m2 = s.trf(
|
||||
"{0} tried to send you {1} — blocked. /DCCALLOW +{2} to allow it, then ask them to resend.",
|
||||
&[sender.as_str(), what.as_str(), sender.as_str()],
|
||||
);
|
||||
s.send(
|
||||
tuid,
|
||||
format!(
|
||||
":{} NOTICE {tnick} :*** {sender} tried to send you {what} — blocked. /DCCALLOW +{sender} to allow it, then ask them to resend.",
|
||||
s.name
|
||||
),
|
||||
format!(":{} NOTICE {tnick} :*** {m2}", s.name),
|
||||
);
|
||||
ModResult::Deny
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,14 +185,20 @@ impl Command for FilterCmd {
|
|||
let filter = match SpamFilter::new(pattern.clone(), engine.clone(), action.clone(), duration, reason) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
s.send(uid, format!(":{} NOTICE {nick} :FILTER rejected ({e})", s.name));
|
||||
let e_s = e.to_string();
|
||||
let m = s.trf("FILTER rejected ({0})", &[e_s.as_str()]);
|
||||
s.send(uid, format!(":{} NOTICE {nick} :{m}", s.name));
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
};
|
||||
let f = s.ext.get_or_insert_with::<Filters>(Filters::default);
|
||||
f.0.retain(|r| r.pattern != pattern);
|
||||
f.0.push(filter);
|
||||
s.snotice_c('f', &format!("{nick} added FILTER {pattern} (engine={engine} action={action})"));
|
||||
let m = s.trf(
|
||||
"{0} added FILTER {1} (engine={2} action={3})",
|
||||
&[nick.as_str(), pattern.as_str(), engine.as_str(), action.as_str()],
|
||||
);
|
||||
s.snotice_c('f', &m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ impl Command for GlobopsCmd {
|
|||
return CmdResult::Fail;
|
||||
}
|
||||
let nick = s.users.get(&uid).map(|u| u.nick.clone()).unwrap_or_default();
|
||||
s.snotice_c('g', &format!("GLOBOPS from {nick}: {}", params.join(" ")));
|
||||
let body = params.join(" ");
|
||||
let m = s.trf("GLOBOPS from {0}: {1}", &[nick.as_str(), body.as_str()]);
|
||||
s.snotice_c('g', &m);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,8 @@ pub fn apply(s: &mut Server, uid: Uid, type_id: Option<&str>) {
|
|||
return;
|
||||
};
|
||||
let Some(r) = with_resolved(s, |m| m.get(&id).cloned()) else {
|
||||
s.snotice_c('o', &format!("oper type '{id}' is not defined — granting full access"));
|
||||
let m = s.trf("oper type '{0}' is not defined — granting full access", &[id.as_str()]);
|
||||
s.snotice_c('o', &m);
|
||||
return;
|
||||
};
|
||||
if !r.modes.is_empty() {
|
||||
|
|
|
|||
|
|
@ -199,23 +199,16 @@ impl Command for MkPasswd {
|
|||
}
|
||||
match make(&algo, &pass) {
|
||||
Some(hashed) => {
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :{algo} hashed password: {hashed}",
|
||||
s.name
|
||||
),
|
||||
);
|
||||
let m = s.trf("{0} hashed password: {1}", &[algo.as_str(), hashed.as_str()]);
|
||||
s.send(uid, format!(":{} NOTICE {nick} :{m}", s.name));
|
||||
CmdResult::Ok
|
||||
}
|
||||
None => {
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :Unknown hash '{algo}' (try md5, sha1, sha256, sha512, pbkdf2, bcrypt)",
|
||||
s.name
|
||||
),
|
||||
let m = s.trf(
|
||||
"Unknown hash '{0}' (try md5, sha1, sha256, sha512, pbkdf2, bcrypt)",
|
||||
&[algo.as_str()],
|
||||
);
|
||||
s.send(uid, format!(":{} NOTICE {nick} :{m}", s.name));
|
||||
CmdResult::Fail
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,13 +289,13 @@ impl Command for ReputationCmd {
|
|||
e.score = val.min(cap);
|
||||
e.last_seen = n;
|
||||
save(s);
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {anick} :REPUTATION {nick} ({k}) set to {val}",
|
||||
s.name
|
||||
),
|
||||
let ks = k.to_string();
|
||||
let vals = val.to_string();
|
||||
let m = s.trf(
|
||||
"REPUTATION {0} ({1}) set to {2}",
|
||||
&[nick.as_str(), ks.as_str(), vals.as_str()],
|
||||
);
|
||||
s.send(uid, format!(":{} NOTICE {anick} :{m}", s.name));
|
||||
} else {
|
||||
let score = score_of(s, tuid);
|
||||
s.send(
|
||||
|
|
|
|||
|
|
@ -99,13 +99,13 @@ impl Command for RMode {
|
|||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default();
|
||||
let plural = if removed == 1 { "y" } else { "ies" };
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :RMODE: removed {removed} +{mode} entr{plural} from {chan}",
|
||||
s.name
|
||||
),
|
||||
let removeds = removed.to_string();
|
||||
let modes = mode.to_string();
|
||||
let m = s.trf(
|
||||
"RMODE: removed {0} +{1} entr{2} from {3}",
|
||||
&[removeds.as_str(), modes.as_str(), plural, chan.as_str()],
|
||||
);
|
||||
s.send(uid, format!(":{} NOTICE {nick} :{m}", s.name));
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ pub fn handle(s: &mut Server, action: &str, params: &str) -> Result<String, RpcE
|
|||
std::thread::spawn(move || {
|
||||
crate::socketengine::connect_link(&addr, tx, counter, max_line)
|
||||
});
|
||||
s.snotice_c('l', &format!("RPC initiated a link to {}", b.name));
|
||||
let m = s.trf("RPC initiated a link to {0}", &[b.name.as_str()]);
|
||||
s.snotice_c('l', &m);
|
||||
Ok(obj(&[("result", "true".into())]))
|
||||
}
|
||||
"disconnect" => {
|
||||
|
|
|
|||
|
|
@ -221,13 +221,8 @@ impl Command for SecGroupsCmd {
|
|||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {anick} :{tnick} is in security groups: {list}",
|
||||
s.name
|
||||
),
|
||||
);
|
||||
let m = s.trf("{0} is in security groups: {1}", &[tnick.as_str(), list.as_str()]);
|
||||
s.send(uid, format!(":{} NOTICE {anick} :{m}", s.name));
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ pub fn maybe_show(s: &mut Server, uid: Uid, cmd: &str) -> bool {
|
|||
s.send(uid, format!(":{} NOTICE {nick} :{line}", s.name));
|
||||
}
|
||||
}
|
||||
None => s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :*** {cmd}: file not available.", s.name),
|
||||
),
|
||||
None => {
|
||||
let m = s.trf("{0}: file not available.", &[cmd]);
|
||||
s.send(uid, format!(":{} NOTICE {nick} :*** {m}", s.name));
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,13 +97,13 @@ impl Module for SolveMsg {
|
|||
answer: Some(ans),
|
||||
});
|
||||
}
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :*** To cut spam, answer this to send your message — what is {a} {sym} {b} ?",
|
||||
s.name
|
||||
),
|
||||
let as_ = a.to_string();
|
||||
let bs = b.to_string();
|
||||
let m = s.trf(
|
||||
"To cut spam, answer this to send your message — what is {0} {1} {2} ?",
|
||||
&[as_.as_str(), sym, bs.as_str()],
|
||||
);
|
||||
s.send(uid, format!(":{} NOTICE {nick} :*** {m}", s.name));
|
||||
ModResult::Deny
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,13 +48,14 @@ impl Command for TLine {
|
|||
.get(&uid)
|
||||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default();
|
||||
s.send(
|
||||
uid,
|
||||
format!(
|
||||
":{} NOTICE {nick} :*** TLINE: {mask} matches {matched} of {total} local users ({pct}%)",
|
||||
s.name
|
||||
),
|
||||
let matcheds = matched.to_string();
|
||||
let totals = total.to_string();
|
||||
let pcts = pct.to_string();
|
||||
let m = s.trf(
|
||||
"TLINE: {0} matches {1} of {2} local users ({3}%)",
|
||||
&[mask.as_str(), matcheds.as_str(), totals.as_str(), pcts.as_str()],
|
||||
);
|
||||
s.send(uid, format!(":{} NOTICE {nick} :*** {m}", s.name));
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -438,7 +438,8 @@ impl Server {
|
|||
self.send(t, line.clone());
|
||||
}
|
||||
if self.conf_bool("seenicks", false) {
|
||||
self.snotice_c('n', &format!("{old} is now known as {newnick}"));
|
||||
let m = self.trf("{0} is now known as {1}", &[old.as_str(), newnick]);
|
||||
self.snotice_c('n', &m);
|
||||
}
|
||||
// WATCH/MONITOR: the old nick is now gone, the new one is here
|
||||
self.watch_notify_offline(&old);
|
||||
|
|
|
|||
|
|
@ -304,7 +304,8 @@ impl Server {
|
|||
crate::server::long_date(expires)
|
||||
)
|
||||
};
|
||||
self.snotice_c('x', &format!("XLINE: {setter} added a {detail}: {reason}"));
|
||||
let m = self.trf("XLINE: {0} added a {1}: {2}", &[setter, detail.as_str(), reason]);
|
||||
self.snotice_c('x', &m);
|
||||
self.save_xlines();
|
||||
self.enforce_xlines();
|
||||
}
|
||||
|
|
@ -335,7 +336,8 @@ impl Server {
|
|||
Some(e) if e != 0 => format!("timed {tag}-line on {mask} (already expired)"),
|
||||
_ => format!("permanent {tag}-line on {mask}"),
|
||||
};
|
||||
self.snotice_c('x', &format!("XLINE: {remover} removed a {detail}"));
|
||||
let m = self.trf("XLINE: {0} removed a {1}", &[remover, detail.as_str()]);
|
||||
self.snotice_c('x', &m);
|
||||
self.save_xlines();
|
||||
}
|
||||
removed
|
||||
|
|
@ -383,7 +385,8 @@ impl Server {
|
|||
}
|
||||
self.xlines.retain(|x| x.expires == 0 || x.expires > n);
|
||||
for (kind, mask) in &expired {
|
||||
self.snotice_c('x', &format!("XLINE: {}-line on {mask} expired", kind.tag()));
|
||||
let m = self.trf("XLINE: {0}-line on {1} expired", &[kind.tag(), mask.as_str()]);
|
||||
self.snotice_c('x', &m);
|
||||
}
|
||||
self.save_xlines(); // an expiry changed the set — persist it
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue