You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

326 lines
11 KiB

//! Administration UI (new).
use huawei_modem::pdu::PduAddress;
use whatsappweb::Jid;
macro_rules! extract_command {
($inp:ident, $cmd:ident, $rest:ident) => {
if $inp.len() < 1 {
return None;
}
let ($cmd, $rest) = (&$inp[0], &$inp[1..]);
let $cmd = $cmd.to_lowercase();
let $cmd = &$cmd as &str;
}
}
pub enum GhostCommand {
ChangeNick(String),
SetWhatsapp(bool),
PresenceSubscribe,
Remove
}
impl GhostCommand {
pub fn help() -> &'static str {
"\x02*** GHOST subcommand ***\x0f
The following commands are available:
\x02RENAME\x0f \x1dnew_nick\x0f
Change the ghost's nickname to \x1dnew_nick\x0f.
\x02WHATSAPP\x0f \x1dtrue|false\x0f
Enable or disable WhatsApp mode for this recipient.
\x02REMOVE\x0f \x0307(aliases \x02KILL\x02, \x02DIE\x02)\x0f
Remove this recipient, causing them to disconnect.
\x02PRESUB\x0f
\x02Sub\x0fscribe to updates about the user's \x02pre\x0fsence, if they're using WhatsApp.
This command will usually not be required, and is mainly useful for debugging.
\x02*** End of subcommand help ***\x0f"
}
pub fn parse(inp: &[&str]) -> Option<Self> {
extract_command!(inp, cmd, rest);
match (cmd, rest) {
("rename", &[new_nick]) => {
Some(GhostCommand::ChangeNick(new_nick.to_owned()))
},
("whatsapp", &[value]) => {
if let Ok(b) = value.parse() {
Some(GhostCommand::SetWhatsapp(b))
}
else {
None
}
},
("presub", _) => {
Some(GhostCommand::PresenceSubscribe)
},
("die", _) | ("kill", _) | ("remove", _) => {
Some(GhostCommand::Remove)
},
_ => None
}
}
}
pub enum ModemCommand {
GetCsq,
GetReg,
Reinit,
TempPath(Option<String>)
}
impl ModemCommand {
pub fn help() -> &'static str {
"\x02*** MODEM subcommand ***\x0f
The following commands are available:
\x02SIGNAL\x0f \x0307(alias \x02CSQ\x02)\x0f
Get the current signal strength, as reported by the modem.
\x02REGISTRATION\x0f \x0307(alias \x02REG\x02)\x0f
Get the modem's registration state.
\x02RESTART\x0f
Reinitialize the connection to the modem.
\x02PATH\x0f \x1d[temp_path]\x0f
\x1f\x02Temporarily\x0f sets the modem path to \x1dtemp_path\x0f.
Not specifying a value for \x1dtemp_path\x0f will disable the modem.
\x1fTip: Change the \x11modem_path\x11 option in the configuration to make this permanent.\x1f
\x02*** End of subcommand help ***\x0f"
}
pub fn parse(inp: &[&str]) -> Option<Self> {
extract_command!(inp, cmd, rest);
match (cmd, rest) {
("signal", _) | ("csq", _) => Some(ModemCommand::GetCsq),
("registration", _) | ("reg", _) => Some(ModemCommand::GetReg),
("restart", _) => Some(ModemCommand::Reinit),
("path", &[path]) => {
Some(ModemCommand::TempPath(Some(path.to_owned())))
},
("path", _) => Some(ModemCommand::TempPath(None)),
_ => None
}
}
}
pub enum ContactCommand {
NewSms(PduAddress),
NewWhatsapp(PduAddress),
}
impl ContactCommand {
pub fn help() -> &'static str {
"\x02*** CONTACT subcommand ***\x0f
The following commands are available:
\x02WHATSAPP\x0f \x1dnumber\x0f
Contact someone new, with the phone number \x1dnumber\x0f, via WhatsApp.
\x02SMS\x0f \x1dnumber\x0f
Contact someone new, with the phone number \x1dnumber\x0f, via SMS.
\x02*** End of subcommand help ***\x0f"
}
pub fn parse(inp: &[&str]) -> Option<Self> {
extract_command!(inp, cmd, rest);
match (cmd, rest) {
(x @ "whatsapp", &[num]) | (x @ "sms", &[num]) => {
if let Ok(num) = num.parse() {
if x == "whatsapp" {
Some(ContactCommand::NewWhatsapp(num))
}
else {
Some(ContactCommand::NewSms(num))
}
}
else {
None
}
},
_ => None
}
}
}
pub enum WhatsappCommand {
Setup,
Logon,
ChatList,
UpdateAll,
PrintAcks
}
impl WhatsappCommand {
pub fn help() -> &'static str {
"\x02*** WHATSAPP subcommand ***\x0f
The following commands are available:
\x02SETUP\x0f
Begin the WhatsApp registration process. This requires you to have your phone ready, in order to scan a QR code.
\x1f\x02Warning:\x02 This command will \x02erase\x02 your existing WhatsApp credentials.\x1f
\x02LOGON\x0f
Log on to WhatsApp Web using stored credentials.
This command will usually not be required, but is helpful if the bridge appears stuck.
\x02CHATS\x0f
List all WhatsApp chats you're currently part of.
\x02RECEIPTS\x0f \x0307(alias \x02ACKS\x02)\x0f
Print delivery reports for recently sent messages.
\x02REBUILD\x0f
Refresh group metadata for all WhatsApp groups you're currently in.
This command will usually not be required, and is mainly useful for debugging.
\x02*** End of subcommand help ***\x0f"
}
pub fn parse(inp: &[&str]) -> Option<Self> {
extract_command!(inp, cmd, rest);
match (cmd, rest) {
("setup", _) => Some(WhatsappCommand::Setup),
("logon", _) => Some(WhatsappCommand::Logon),
("chats", _) => Some(WhatsappCommand::ChatList),
("rebuild", _) => Some(WhatsappCommand::UpdateAll),
("receipts", _) | ("acks", _) => Some(WhatsappCommand::PrintAcks),
_ => None
}
}
}
pub enum GroupCommand {
BridgeWhatsapp {
jid: Jid,
chan: String
},
Unbridge(String)
}
impl GroupCommand {
pub fn help() -> &'static str {
"\x02*** GROUP subcommand ***\x0f
The following commands are available:
\x02BRIDGE\x0f \x1djid\x0f \x1dchan\x0f
Bridges the WhatsApp groupchat with JID \x1djid\x0f to the IRC channel \x1dchan\x0f.
\x02UNBRIDGE\x0f \x1dchan\x0f
Unbridges the IRC channel \x1dchan\x0f.
\x02*** End of subcommand help ***\x0f"
}
pub fn parse(inp: &[&str]) -> Option<Self> {
extract_command!(inp, cmd, rest);
match (cmd, rest) {
("bridge", &[jid, chan]) => {
if let Ok(j) = jid.parse() {
if chan.starts_with("#") {
return Some(GroupCommand::BridgeWhatsapp {
jid: j,
chan: chan.to_owned()
});
}
}
None
},
("unbridge", &[chan]) => {
if chan.starts_with("#") {
Some(GroupCommand::Unbridge(chan.to_owned()))
}
else {
None
}
},
_ => None
}
}
}
pub enum InspCommand {
Raw(String),
QueryUuid(String),
QueryNickUuid(String)
}
impl InspCommand {
pub fn help() -> &'static str {
"\x02*** INSP subcommand ***\x0f
The following commands are available:
\x02RAW\x0f \x1draw IRC line\x0f
Sends the \x1draw IRC line\x0f to the linked IRC server.
\x1f\x02Warning:\x02 This command is very technical, and only intended for debugging. Misuse can cause the bridge to be disconnected!\x02
\x02UUQUERY\x0f \x1duuid\x0f
Returns the nickname associated with UUID \x1duuid\x0f, if there is one.
\x02NICKQUERY\x0f \x1dnick\x0f
Returns the UUID for the nickname \x1dnick\x0f, if we know it.
\x02*** End of subcommand help ***\x0f"
}
pub fn parse(inp: &[&str]) -> Option<Self> {
extract_command!(inp, cmd, rest);
match (cmd, rest) {
("raw", args) => Some(InspCommand::Raw(args[1..].join(" "))),
("uuquery", &[uuid]) => Some(InspCommand::QueryUuid(uuid.to_owned())),
("nickquery", &[uuid]) => Some(InspCommand::QueryNickUuid(uuid.to_owned())),
_ => None
}
}
}
pub enum AdminCommand {
Ghost(String, GhostCommand),
Contact(ContactCommand),
Whatsapp(WhatsappCommand),
Modem(ModemCommand),
Group(GroupCommand),
Insp(InspCommand),
Help(Option<String>)
}
impl AdminCommand {
pub fn help() -> &'static str {
"\x02*** sms-irc help ***\x0f
The following commands are available. Use \x02HELP\x02 \x1dcommand\x0f to get more information on each subcommand.
\x02GHOST\x02 \x1dnickname subcommand\x0f
Manages ghosts (i.e. IRC users that represent a message recipient).
Here, \x1dnickname\x0f represents the nickname of the ghost you're trying to manage.
\x1dFor example, \x11GHOST user REMOVE\x11 would remove the ghost named \x11user\x11.\x1d
\x02CONTACT\x0f \x1dsubcommand\x0f
Allows establishing contact with new people.
\x02WHATSAPP\x0f \x1dsubcommand\x0f
Manages WhatsApp registration, login and more.
\x02MODEM\x0f \x1dsubcommand\x0f
Queries the modem state and provides other management commands.
\x02GROUP\x0f \x1dsubcommand\x0f
Used to bridge and unbridge group chats to/from IRC channels.
(Currently, only WhatsApp group chats are supported.)
\x02INSP\x0f \x1dsubcommand\x0f
If sms-irc is using the InspIRCd server-to-server link, provides some debug commands.
\x02HELP\x0f \x1d[command]\x0f
Shows this help.
If a \x1dcommand\x0f is provided, shows help for that command.
\x02*** End of help ***\x0f"
}
pub fn parse(inp: &[&str]) -> Option<Self> {
if inp.len() < 1 {
return None;
}
match &inp[0].to_lowercase() as &str {
"contact" => {
ContactCommand::parse(&inp[1..])
.map(|x| AdminCommand::Contact(x))
},
"whatsapp" => {
WhatsappCommand::parse(&inp[1..])
.map(|x| AdminCommand::Whatsapp(x))
},
"group" => {
GroupCommand::parse(&inp[1..])
.map(|x| AdminCommand::Group(x))
},
"modem" => {
ModemCommand::parse(&inp[1..])
.map(|x| AdminCommand::Modem(x))
},
"insp" => {
InspCommand::parse(&inp[1..])
.map(|x| AdminCommand::Insp(x))
},
"ghost" => {
if inp.len() < 3 {
return None;
}
let tgt = inp[1].to_owned();
GhostCommand::parse(&inp[2..])
.map(|x| AdminCommand::Ghost(tgt, x))
},
"help" => {
let page = inp.get(1).map(|x| x.to_string());
Some(AdminCommand::Help(page))
}
_ => None
}
}
}
pub fn help_page(query: Option<&str>) -> Option<&'static str> {
let query = query.map(|x| x.to_lowercase());
match query.as_ref().map(|x| x as &str) {
Some("ghost") => Some(GhostCommand::help()),
Some("modem") => Some(ModemCommand::help()),
Some("contact") => Some(ContactCommand::help()),
Some("whatsapp") => Some(WhatsappCommand::help()),
Some("group") => Some(GroupCommand::help()),
Some("insp") => Some(InspCommand::help()),
None => Some(AdminCommand::help()),
_ => None
}
}