// CW2 - Hexchat Plugin for Content Warnings // Copyright (C) 2021 Soni L. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #[macro_use] extern crate hexchat_plugin; mod parsing; mod hexchat_plugin_ext; use std::cell::Cell; use hexchat_plugin::Plugin as HexchatPlugin; use hexchat_plugin::PluginHandle as Ph; use hexchat_plugin::CommandHookHandle; use hexchat_plugin::PrintHookHandle; use hexchat_plugin_ext::PhExt; #[derive(Default)] struct Cw2Plugin { cmd_cw: Cell>, cmd_cwmsg: Cell>, print_hooks: Cell>, } const PLUG_NAME: &'static str = "CW2"; const PLUG_VER: &'static str = "1.0.0"; const PLUG_DESC: &'static str = "Adds support for content warnings."; const CMD_CW: &'static str = "CW"; const CMD_CW_HELP: &'static str = "Sends a content warned msg. \ Example usage: /cw [thing] message"; const CMD_CW_EPARSE: &'static str = "Error parsing CW. \ Example usage: /cw [thing] message"; const CMD_CW_ENOARG: &'static str = "This command requires more arguments. \ Example usage: /cw [thing] message"; const CMD_CWMSG: &'static str = "CWMSG"; const CMD_CWMSG_HELP: &'static str = "Sends a content warned msg to an user. \ Example usage: /cwmsg user [thing] message"; const CMD_CWMSG_EPARSE: &'static str = "Error parsing CW. \ Example usage: /cwmsg user [thing] message"; const CMD_CWMSG_ENOARG: &'static str = "This command requires more arguments. \ Example usage: /cwmsg user [thing] message"; impl HexchatPlugin for Cw2Plugin { fn init(&self, ph: &mut Ph, _: Option<&str>) -> bool { ph.register(PLUG_NAME, PLUG_VER, PLUG_DESC); ph.make_command(CMD_CW, |ph, arg, arg_eol| { if arg.len() < 2 { ph.print(CMD_CW_ENOARG); return hexchat_plugin::EAT_ALL } if let Some(message) = parsing::try_to_cw2(arg_eol[1]) { ph.ensure_valid_context(|ph| { ph.command(&format!("say {}", message)); }); } else { ph.print(CMD_CW_EPARSE); } hexchat_plugin::EAT_ALL }).set_help(CMD_CW_HELP).build_into(&self.cmd_cw); ph.make_command(CMD_CWMSG, |ph, arg, arg_eol| { if arg.len() < 3 { ph.print(CMD_CWMSG_ENOARG); return hexchat_plugin::EAT_ALL } let user = arg_eol[1]; if let Some(message) = parsing::try_to_cw2(arg_eol[2]) { ph.ensure_valid_context(|ph| { ph.command(&format!("msg {} {}", user, message)); }); } else { ph.print(CMD_CWMSG_EPARSE); } hexchat_plugin::EAT_ALL }).set_help(CMD_CWMSG_HELP).build_into(&self.cmd_cwmsg); let mut hooks = Vec::new(); let to_hook = [ ("Channel Message", 2,), ("Channel Msg Hilight", 2,), ("Channel Notice", 3,), ("Private Message", 2,), ("Private Message to Dialog", 2,), ("Notice", 2,), ("Your Message", 2,), ("Notice Send", 2,), ("Message Send", 2,), ]; for &(msg, idx) in &to_hook { let h = ph.make_print_attrs(msg, move |ph, arg, attrs| { if arg.len() < idx { return hexchat_plugin::EAT_NONE } // hexchat uses 1-indexed arg // but hexchat_plugin uses 0-indexed // (ah well) let x = arg[idx-1]; if let Some((reason, content)) = parsing::try_parse_cw2(x) { let mut newargs = Vec::new(); newargs.extend(arg.iter().map(|x| String::from(*x))); // NOTE: must not start with "[CW ", as that'd cause an // infinite loop! newargs[idx-1] = format!("[Content Hidden: {}]", reason); ph.print(&format!("\x0326*\t[Content Hidden: {}]\x03\x08{}\x08 \x0324(Copy and paste this line to expand)\x03", reason, content)); ph.ensure_valid_context(|ph| { let iter = newargs.iter().map(|x| &**x); // TODO ideally we'd avoid recursion but eh it's fine // .-. // (we guess as long as the above isn't "[CW {}]", // this is probably fine.) ph.emit_print_attrs(attrs, msg, iter); }); hexchat_plugin::EAT_ALL } else { hexchat_plugin::EAT_NONE } }).set_priority(i32::MAX).build(); hooks.push(h); } self.print_hooks.set(hooks); ph.print("CW2 plugin loaded!"); true } } hexchat_plugin!(Cw2Plugin);