Refactor and add message command
This commit is contained in:
parent
e87bed00a2
commit
fa959136be
8 changed files with 370 additions and 263 deletions
54
src/cli.rs
54
src/cli.rs
|
@ -4,7 +4,8 @@ use telnet::Telnet;
|
||||||
use crate::parameter::{Parameter, ParameterList};
|
use crate::parameter::{Parameter, ParameterList};
|
||||||
use crate::response::channel::ResponseChannel;
|
use crate::response::channel::ResponseChannel;
|
||||||
use crate::response::client::ResponseClient;
|
use crate::response::client::ResponseClient;
|
||||||
use crate::utils;
|
use crate::utils::SendTextMessageTarget;
|
||||||
|
use crate::wrappers;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
@ -19,6 +20,7 @@ pub enum Commands {
|
||||||
Channels(ChannelsArgs),
|
Channels(ChannelsArgs),
|
||||||
Clients,
|
Clients,
|
||||||
Fetch(FetchArgs),
|
Fetch(FetchArgs),
|
||||||
|
Message(MessageArgs),
|
||||||
Move(MoveArgs),
|
Move(MoveArgs),
|
||||||
Update(UpdateArgs),
|
Update(UpdateArgs),
|
||||||
}
|
}
|
||||||
|
@ -41,6 +43,17 @@ pub struct FetchArgs {
|
||||||
client: Option<String>,
|
client: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct MessageArgs {
|
||||||
|
#[arg(long)]
|
||||||
|
strict_client: bool,
|
||||||
|
#[arg(long)]
|
||||||
|
client: Option<String>,
|
||||||
|
#[arg(long)]
|
||||||
|
server: bool,
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
pub struct MoveArgs {
|
pub struct MoveArgs {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
|
@ -76,31 +89,46 @@ impl FetchArgs {
|
||||||
|
|
||||||
pub fn channel(&self, connection: &mut Telnet) -> Result<Option<ResponseChannel>, String> {
|
pub fn channel(&self, connection: &mut Telnet) -> Result<Option<ResponseChannel>, String> {
|
||||||
if let Some(channel) = &self.channel {
|
if let Some(channel) = &self.channel {
|
||||||
utils::find_channel(connection, channel, self.strict_channel)
|
wrappers::find_channel(connection, channel, self.strict_channel)
|
||||||
} else {
|
} else {
|
||||||
Err("No channel specified.".to_string())
|
Err("No channel specified.".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn client(&self, connection: &mut Telnet) -> Result<Option<ResponseClient>, String> {
|
pub fn client(&self, connection: &mut Telnet) -> Result<Option<ResponseClient>, String> {
|
||||||
if let Some(client) = &self.client {
|
if let Some(client) = &self.client {
|
||||||
utils::find_client(connection, client, self.strict_client)
|
wrappers::find_client(connection, client, self.strict_client)
|
||||||
} else {
|
} else {
|
||||||
Err("No client specified.".to_string())
|
Err("No client specified.".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MessageArgs {
|
||||||
|
pub fn target(&self, connection: &mut Telnet) -> Result<SendTextMessageTarget, String> {
|
||||||
|
if self.server {
|
||||||
|
Ok(SendTextMessageTarget::Server)
|
||||||
|
} else if let Some(client) = &self.client {
|
||||||
|
if let Some(client) = wrappers::find_client(connection, client, self.strict_client)? {
|
||||||
|
return Ok(SendTextMessageTarget::Client(client.cid));
|
||||||
|
}
|
||||||
|
return Err("Could not find client.".to_string());
|
||||||
|
} else {
|
||||||
|
Ok(SendTextMessageTarget::Channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MoveArgs {
|
impl MoveArgs {
|
||||||
pub fn channel(&self, connection: &mut Telnet) -> Result<Option<ResponseChannel>, String> {
|
pub fn channel(&self, connection: &mut Telnet) -> Result<Option<ResponseChannel>, String> {
|
||||||
utils::find_channel(connection, &self.channel, self.strict_channel)
|
wrappers::find_channel(connection, &self.channel, self.strict_channel)
|
||||||
}
|
}
|
||||||
pub fn client(&self, connection: &mut Telnet) -> Result<Option<ResponseClient>, String> {
|
pub fn client(&self, connection: &mut Telnet) -> Result<Option<ResponseClient>, String> {
|
||||||
match &self.client {
|
match &self.client {
|
||||||
Some(client) => {
|
Some(client) => {
|
||||||
utils::find_client(connection, client, self.strict_client)
|
wrappers::find_client(connection, client, self.strict_client)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
match utils::find_self(connection) {
|
match wrappers::find_self(connection) {
|
||||||
Ok(client) => Ok(Some(client)),
|
Ok(client) => Ok(Some(client)),
|
||||||
Err(msg) => Err(msg)
|
Err(msg) => Err(msg)
|
||||||
}
|
}
|
||||||
|
@ -114,24 +142,22 @@ impl UpdateArgs {
|
||||||
let mut params: ParameterList = Vec::new();
|
let mut params: ParameterList = Vec::new();
|
||||||
|
|
||||||
if let Some(name) = &self.name {
|
if let Some(name) = &self.name {
|
||||||
params.push(Parameter::new(String::from("client_nickname"), name.clone()));
|
params.push(Parameter::new("client_nickname", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(away) = &self.away {
|
if let Some(away) = &self.away {
|
||||||
params.push(Parameter::new(String::from("client_away_message"), away.clone()));
|
params.push(Parameter::new("client_away_message", away));
|
||||||
params.push(Parameter::new(String::from("client_away"), String::from("1")));
|
params.push(Parameter::new("client_away", "1"));
|
||||||
}
|
}
|
||||||
if self.back {
|
if self.back {
|
||||||
params.push(Parameter::new(String::from("client_away"), String::from("0")));
|
params.push(Parameter::new("client_away", "0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(microphone) = self.microphone {
|
if let Some(microphone) = self.microphone {
|
||||||
let muted = u8::from(!microphone).to_string();
|
params.push(Parameter::new("client_input_muted", &u8::from(!microphone).to_string()));
|
||||||
params.push(Parameter::new(String::from("client_input_muted"), muted));
|
|
||||||
}
|
}
|
||||||
if let Some(speakers) = self.speakers {
|
if let Some(speakers) = self.speakers {
|
||||||
let muted = u8::from(!speakers).to_string();
|
params.push(Parameter::new("client_output_muted", &u8::from(!speakers).to_string()));
|
||||||
params.push(Parameter::new(String::from("client_output_muted"), muted));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
params
|
params
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
use crate::utils::SendTextMessageTarget;
|
||||||
use telnet::Event::Data;
|
use telnet::Event::Data;
|
||||||
use telnet::Telnet;
|
use telnet::Telnet;
|
||||||
|
|
||||||
use crate::parameter::ParameterList;
|
use crate::parameter::{Parameter, ParameterList};
|
||||||
use crate::response::Response;
|
use crate::response::Response;
|
||||||
|
|
||||||
fn to_single_response(resp: Response) -> Response {
|
fn to_single_response(resp: Response) -> Response {
|
||||||
|
@ -41,6 +42,7 @@ fn read_response_buffer(connection: &mut Telnet, buffer: &mut String) -> Result<
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_command(connection: &mut Telnet, command: &str, skip_ok: bool) -> Result<Response, String> {
|
fn send_command(connection: &mut Telnet, command: &str, skip_ok: bool) -> Result<Response, String> {
|
||||||
|
let command = format!("{}\n\r", command);
|
||||||
connection.write(command.as_bytes()).map_err(|_| "Failed to write to Teamspeak.")?;
|
connection.write(command.as_bytes()).map_err(|_| "Failed to write to Teamspeak.")?;
|
||||||
|
|
||||||
read_response(connection, skip_ok, String::new())
|
read_response(connection, skip_ok, String::new())
|
||||||
|
@ -68,40 +70,40 @@ fn read_response(connection: &mut Telnet, skip_ok: bool, mut buffer: String) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn login(connection: &mut Telnet, apikey: &str) -> Result<Response, String> {
|
pub fn login(connection: &mut Telnet, apikey: &str) -> Result<Response, String> {
|
||||||
send_command(connection, &format!("auth apikey={}\n", apikey), false)
|
send_command(connection, &format!("auth apikey={}", apikey), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn set_name(connection: &mut Telnet, name: &str) -> Result<Response, String> {
|
pub fn set_name(connection: &mut Telnet, name: &str) -> Result<Response, String> {
|
||||||
send_command(connection, &format!("clientupdate client_nickname={}\n", name), true)
|
send_command(connection, &format!("clientupdate client_nickname={}", name), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channellist(connection: &mut Telnet) -> Result<Response, String> {
|
pub fn channellist(connection: &mut Telnet) -> Result<Response, String> {
|
||||||
send_command(connection, "channellist\n", true)
|
send_command(connection, "channellist", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clientlist(connection: &mut Telnet) -> Result<Response, String> {
|
pub fn clientlist(connection: &mut Telnet) -> Result<Response, String> {
|
||||||
send_command(connection, "clientlist\n", true)
|
send_command(connection, "clientlist", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn whoami(connection: &mut Telnet) -> Result<Response, String> {
|
pub fn whoami(connection: &mut Telnet) -> Result<Response, String> {
|
||||||
send_command(connection, "whoami\n", true).map(to_single_response)
|
send_command(connection, "whoami", true).map(to_single_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clientmove(connection: &mut Telnet, cid: &i32, clid_list: Vec<&i32>) -> Result<Response, String> {
|
pub fn clientmove(connection: &mut Telnet, cid: &i32, clid_list: Vec<&i32>) -> Result<Response, String> {
|
||||||
let clid_str = clid_list
|
let clid_param_list = clid_list
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|clid| format!("clid={}", clid))
|
.map(|clid| Parameter::new("clid", &clid.to_string()))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<Parameter>>();
|
||||||
.join("|");
|
let clid_str = Parameter::list_to_string_sep(clid_param_list, "|");
|
||||||
send_command(connection, &format!("clientmove cid={} {}\n", cid, clid_str), false)
|
send_command(connection, &format!("clientmove cid={} {}", cid, clid_str), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clientupdate(connection: &mut Telnet, parameters: &ParameterList) -> Result<Response, String> {
|
pub fn clientupdate(connection: &mut Telnet, parameters: ParameterList) -> Result<Response, String> {
|
||||||
let parameters_str = parameters
|
let parameters_str = Parameter::list_to_string(parameters);
|
||||||
.iter()
|
send_command(connection, &format!("clientupdate {}", parameters_str), false)
|
||||||
.map(|param| format!("{}={}", param.name, param.value))
|
}
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(" ");
|
pub fn sendtextmessage(connection: &mut Telnet, target: SendTextMessageTarget, msg: String) -> Result<Response, String> {
|
||||||
send_command(connection, &format!("clientupdate {}\n", parameters_str), false)
|
let msg = String::from(Parameter::new("msg", &msg));
|
||||||
}
|
send_command(connection, &format!("sendtextmessage {} {}", msg, String::from(target)), false) }
|
||||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -7,10 +7,11 @@ use crate::response::channel::ResponseChannel;
|
||||||
use crate::response::client::ResponseClient;
|
use crate::response::client::ResponseClient;
|
||||||
|
|
||||||
mod response;
|
mod response;
|
||||||
mod utils;
|
mod wrappers;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod parameter;
|
mod parameter;
|
||||||
mod cli;
|
mod cli;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
fn channel_or_exit(channel_res: Result<Option<ResponseChannel>, String>) -> ResponseChannel {
|
fn channel_or_exit(channel_res: Result<Option<ResponseChannel>, String>) -> ResponseChannel {
|
||||||
channel_res.unwrap_or_else(|err| {
|
channel_res.unwrap_or_else(|err| {
|
||||||
|
@ -44,14 +45,14 @@ fn main() {
|
||||||
}
|
}
|
||||||
let mut connection = connection.unwrap();
|
let mut connection = connection.unwrap();
|
||||||
|
|
||||||
utils::skip_welcome(&mut connection);
|
wrappers::skip_welcome(&mut connection);
|
||||||
utils::login(&mut connection);
|
wrappers::login(&mut connection);
|
||||||
|
|
||||||
// You can check for the existence of subcommands, and if found use their
|
// You can check for the existence of subcommands, and if found use their
|
||||||
// matches just as you would the top level cmd
|
// matches just as you would the top level cmd
|
||||||
match &cli {
|
match cli {
|
||||||
Commands::Channels(args) => {
|
Commands::Channels(args) => {
|
||||||
match utils::get_channels(&mut connection, args.spacers) {
|
match wrappers::get_channels(&mut connection, args.spacers) {
|
||||||
Ok(channels) => {
|
Ok(channels) => {
|
||||||
for channel in channels {
|
for channel in channels {
|
||||||
println!("{}", channel.channel_name);
|
println!("{}", channel.channel_name);
|
||||||
|
@ -65,7 +66,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Clients => {
|
Commands::Clients => {
|
||||||
match utils::get_clients(&mut connection) {
|
match wrappers::get_clients(&mut connection) {
|
||||||
Ok(clients) => {
|
Ok(clients) => {
|
||||||
for client in clients {
|
for client in clients {
|
||||||
println!("{}", client.client_nickname);
|
println!("{}", client.client_nickname);
|
||||||
|
@ -91,7 +92,7 @@ fn main() {
|
||||||
if args.want_client() {
|
if args.want_client() {
|
||||||
let client = client_or_exit(args.client(&mut connection));
|
let client = client_or_exit(args.client(&mut connection));
|
||||||
|
|
||||||
match utils::fetch_client(&mut connection, &[client]) {
|
match wrappers::fetch_client(&mut connection, &[client]) {
|
||||||
Ok(_) => println!("Successfully fetched client."),
|
Ok(_) => println!("Successfully fetched client."),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
println!("Failed to fetch client: {}", msg);
|
println!("Failed to fetch client: {}", msg);
|
||||||
|
@ -103,7 +104,7 @@ fn main() {
|
||||||
if args.want_channel() {
|
if args.want_channel() {
|
||||||
let channel = channel_or_exit(args.channel(&mut connection));
|
let channel = channel_or_exit(args.channel(&mut connection));
|
||||||
|
|
||||||
match utils::fetch_channel(&mut connection, channel) {
|
match wrappers::fetch_channel(&mut connection, channel) {
|
||||||
Ok(_) => println!("Successfully fetched channel."),
|
Ok(_) => println!("Successfully fetched channel."),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
println!("Failed to fetch channel: {}", msg);
|
println!("Failed to fetch channel: {}", msg);
|
||||||
|
@ -113,11 +114,26 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Commands::Message(args) => {
|
||||||
|
let target = args.target(&mut connection).unwrap_or_else(|err| {
|
||||||
|
println!("Failed to get message target: {}", err);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
match wrappers::send_text_message(&mut connection, target, args.message) {
|
||||||
|
Ok(_) => println!("Successfully sent message."),
|
||||||
|
Err(msg) => {
|
||||||
|
println!("Failed to send message: {}", msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Commands::Move(args) => {
|
Commands::Move(args) => {
|
||||||
let channel = channel_or_exit(args.channel(&mut connection));
|
let channel = channel_or_exit(args.channel(&mut connection));
|
||||||
let client = client_or_exit(args.client(&mut connection));
|
let client = client_or_exit(args.client(&mut connection));
|
||||||
|
|
||||||
match utils::move_client(&mut connection, &channel, &[client]) {
|
match wrappers::move_client(&mut connection, &channel, &[client]) {
|
||||||
Ok(resp) => println!("Successfully moved client: {}", resp),
|
Ok(resp) => println!("Successfully moved client: {}", resp),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
println!("Failed to move client: {}", msg);
|
println!("Failed to move client: {}", msg);
|
||||||
|
@ -127,7 +143,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Update(args) => {
|
Commands::Update(args) => {
|
||||||
match utils::update_client(&mut connection, &args.to_parameter_list()) {
|
match wrappers::update_client(&mut connection, args.to_parameter_list()) {
|
||||||
Ok(_) => println!("Successfully updated client."),
|
Ok(_) => println!("Successfully updated client."),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
println!("Failed to update client: {}", msg);
|
println!("Failed to update client: {}", msg);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
use crate::utils::{decode_value, encode_value};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Parameter {
|
pub struct Parameter {
|
||||||
|
@ -49,19 +50,15 @@ pub fn parameter_parse(params_str: &str) -> ParameterList {
|
||||||
|
|
||||||
impl From<(&str, &str)> for Parameter {
|
impl From<(&str, &str)> for Parameter {
|
||||||
fn from(param: (&str, &str)) -> Parameter {
|
fn from(param: (&str, &str)) -> Parameter {
|
||||||
Parameter::new(String::from(param.0), String::from(param.1))
|
Parameter::new(param.0, param.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parameter {
|
impl Parameter {
|
||||||
pub fn new(name: String, value: String) -> Parameter {
|
pub fn new(name: &str, value: &str) -> Parameter {
|
||||||
let value = value
|
|
||||||
.replace("\\s", " ")
|
|
||||||
.replace("\\p", "|");
|
|
||||||
|
|
||||||
Parameter {
|
Parameter {
|
||||||
name,
|
name: String::from(name),
|
||||||
value,
|
value: decode_value(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +78,22 @@ impl Parameter {
|
||||||
pub fn to_i32(&self, default: i32) -> i32 {
|
pub fn to_i32(&self, default: i32) -> i32 {
|
||||||
self.value.parse::<i32>().unwrap_or(default)
|
self.value.parse::<i32>().unwrap_or(default)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn list_to_string(parameter_list: ParameterList) -> String {
|
||||||
|
parameter_list
|
||||||
|
.into_iter()
|
||||||
|
.map(String::from)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_to_string_sep(parameter_list: ParameterList, sep: &str) -> String {
|
||||||
|
parameter_list
|
||||||
|
.into_iter()
|
||||||
|
.map(String::from)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(sep)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Parameter {
|
impl Display for Parameter {
|
||||||
|
@ -97,6 +110,12 @@ impl Debug for Parameter {
|
||||||
|
|
||||||
impl Default for Parameter {
|
impl Default for Parameter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Parameter::new(String::from(""), String::from(""))
|
Parameter::new("", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Parameter> for String {
|
||||||
|
fn from(value: Parameter) -> Self {
|
||||||
|
format!("{}={}", value.name, encode_value(&value.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -93,10 +93,10 @@ impl ResponseError {
|
||||||
fn create_error(params: &Vec<Parameter>) -> ResponseError {
|
fn create_error(params: &Vec<Parameter>) -> ResponseError {
|
||||||
ResponseError {
|
ResponseError {
|
||||||
id: parameter_find(params, "id")
|
id: parameter_find(params, "id")
|
||||||
.unwrap_or_else(|| Parameter::new(String::from("id"), String::from("-1")))
|
.unwrap_or_else(|| Parameter::new("id", "-1"))
|
||||||
.to_i32(-1),
|
.to_i32(-1),
|
||||||
msg: parameter_find(params, "msg")
|
msg: parameter_find(params, "msg")
|
||||||
.unwrap_or_else(|| Parameter::new(String::from("msg"), String::from("Unknown error.")))
|
.unwrap_or_else(|| Parameter::new("msg", "Unknown error."))
|
||||||
.value,
|
.value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
237
src/utils.rs
237
src/utils.rs
|
@ -1,208 +1,39 @@
|
||||||
use std::process::exit;
|
use crate::parameter::Parameter;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use telnet::Event::TimedOut;
|
pub fn decode_value(value: &str) -> String {
|
||||||
use telnet::Telnet;
|
value
|
||||||
|
.replace("\\s", " ")
|
||||||
|
.replace("\\p", "|")
|
||||||
|
}
|
||||||
|
|
||||||
use crate::{commands, parameter};
|
pub fn encode_value(value: &str) -> String {
|
||||||
use crate::parameter::{parameter_list_find_all, ParameterList};
|
value
|
||||||
use crate::response::channel::ResponseChannel;
|
.replace(' ', "\\s")
|
||||||
use crate::response::client::ResponseClient;
|
.replace('|', "\\p")
|
||||||
use crate::response::Response;
|
}
|
||||||
|
|
||||||
pub fn skip_welcome(connection: &mut Telnet) {
|
pub enum SendTextMessageTarget {
|
||||||
loop {
|
Client(i32),
|
||||||
let event_result = connection.read_timeout(Duration::from_millis(100));
|
Channel,
|
||||||
match event_result {
|
Server,
|
||||||
Ok(event) => {
|
}
|
||||||
if let TimedOut = event {
|
|
||||||
break;
|
impl From<SendTextMessageTarget> for String {
|
||||||
}
|
fn from(value: SendTextMessageTarget) -> Self {
|
||||||
}
|
let target_mode = match value {
|
||||||
Err(_) => println!("Failed to read from Teamspeak."),
|
SendTextMessageTarget::Client(_) => "1",
|
||||||
}
|
SendTextMessageTarget::Channel => "2",
|
||||||
|
SendTextMessageTarget::Server => "3",
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = match value {
|
||||||
|
SendTextMessageTarget::Client(id) => id.to_string(),
|
||||||
|
_ => String::from("0"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Parameter::list_to_string(vec![
|
||||||
|
Parameter::new("targetmode", target_mode),
|
||||||
|
Parameter::new("target", &target)
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn login(connection: &mut Telnet) {
|
|
||||||
// read api key from environment variable
|
|
||||||
let apikey = std::env::var("TS3_CLIENT_API_KEY").unwrap_or_else(|_| {
|
|
||||||
println!("No API key found in environment variable TS3_CLIENT_API_KEY.");
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
match commands::login(connection, &apikey) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(msg) => {
|
|
||||||
println!("Failed to authenticate with Teamspeak: {}", msg);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_channels(connection: &mut Telnet, spacers: bool) -> Result<Vec<ResponseChannel>, String> {
|
|
||||||
match commands::channellist(connection) {
|
|
||||||
Ok(response) => {
|
|
||||||
match response {
|
|
||||||
Response::DataList(parameter_lists) => {
|
|
||||||
let channels: Vec<ResponseChannel> = parameter_lists.iter()
|
|
||||||
.map(|params| ResponseChannel::from(params.clone()))
|
|
||||||
.collect();
|
|
||||||
let mut channels = ResponseChannel::sort_list(channels);
|
|
||||||
if !spacers {
|
|
||||||
channels.retain(|c| !c.is_spacer());
|
|
||||||
}
|
|
||||||
Ok(channels)
|
|
||||||
}
|
|
||||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(msg) => Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_channel(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseChannel>, String> {
|
|
||||||
match commands::channellist(connection) {
|
|
||||||
Ok(response) => {
|
|
||||||
match response {
|
|
||||||
Response::DataList(parameter_lists) => {
|
|
||||||
match parameter::parameter_list_find(¶meter_lists, "channel_name", name, strict) {
|
|
||||||
Some(params) => {
|
|
||||||
Ok(Some(ResponseChannel::from(params)))
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(msg) => Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_clients(connection: &mut Telnet) -> Result<Vec<ResponseClient>, String> {
|
|
||||||
match commands::clientlist(connection) {
|
|
||||||
Ok(response) => {
|
|
||||||
match response {
|
|
||||||
Response::DataList(parameter_lists) => {
|
|
||||||
let mut clients: Vec<ResponseClient> = parameter_lists.iter()
|
|
||||||
.map(|params| ResponseClient::from(params.clone()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
clients.sort_by(|a, b| a.client_nickname.cmp(&b.client_nickname));
|
|
||||||
|
|
||||||
Ok(clients)
|
|
||||||
}
|
|
||||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(msg) => Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_client(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseClient>, String> {
|
|
||||||
match commands::clientlist(connection) {
|
|
||||||
Ok(response) => {
|
|
||||||
match response {
|
|
||||||
Response::DataList(parameter_lists) => {
|
|
||||||
match parameter::parameter_list_find(¶meter_lists, "client_nickname", name, strict) {
|
|
||||||
Some(params) => {
|
|
||||||
Ok(Some(ResponseClient::from(params)))
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(msg) => Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_channel_clients(connection: &mut Telnet, channel: &ResponseChannel) -> Result<Vec<ResponseClient>, String> {
|
|
||||||
match commands::clientlist(connection) {
|
|
||||||
Ok(response) => {
|
|
||||||
match response {
|
|
||||||
Response::DataList(parameter_lists) => {
|
|
||||||
let mut clients: Vec<ResponseClient> = Vec::new();
|
|
||||||
for client_params in parameter_list_find_all(¶meter_lists, "cid", &channel.cid.to_string(), true) {
|
|
||||||
clients.push(ResponseClient::from(client_params));
|
|
||||||
}
|
|
||||||
Ok(clients)
|
|
||||||
}
|
|
||||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(msg) => Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_self_clid(connection: &mut Telnet) -> Result<String, String> {
|
|
||||||
match commands::whoami(connection) {
|
|
||||||
Ok(response) => {
|
|
||||||
match response {
|
|
||||||
Response::Data(params) => {
|
|
||||||
match parameter::parameter_find(¶ms, "clid") {
|
|
||||||
None => Err(String::from("Could not find clid in response from Teamspeak.")),
|
|
||||||
Some(param) => Ok(param.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(String::from("Received unexpected response from Teamspeak for whoami."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(msg) => Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_self(connection: &mut Telnet) -> Result<ResponseClient, String> {
|
|
||||||
let clid = get_self_clid(connection)?;
|
|
||||||
|
|
||||||
match commands::clientlist(connection) {
|
|
||||||
Ok(response) => {
|
|
||||||
match response {
|
|
||||||
Response::DataList(parameter_lists) => {
|
|
||||||
match parameter::parameter_list_find(¶meter_lists, "clid", &clid, false) {
|
|
||||||
Some(params) => {
|
|
||||||
Ok(ResponseClient::from(params))
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
Err(String::from("Could not find self in response from Teamspeak."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(String::from("Received unexpected response from Teamspeak for clientlist."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(msg) => Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fetch_client(connection: &mut Telnet, clients: &[ResponseClient]) -> Result<Response, String> {
|
|
||||||
let cid = find_self(connection)?.cid;
|
|
||||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
|
||||||
|
|
||||||
commands::clientmove(connection, &cid, clid_list)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fetch_channel(connection: &mut Telnet, channel: ResponseChannel) -> Result<Response, String> {
|
|
||||||
let cid = find_self(connection)?.cid;
|
|
||||||
|
|
||||||
let clients = get_channel_clients(connection, &channel)?;
|
|
||||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
|
||||||
|
|
||||||
commands::clientmove(connection, &cid, clid_list)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn move_client(connection: &mut Telnet, channel: &ResponseChannel, clients: &[ResponseClient]) -> Result<Response, String> {
|
|
||||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
|
||||||
|
|
||||||
commands::clientmove(connection, &channel.cid, clid_list)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_client(connection: &mut Telnet, parameters: &ParameterList) -> Result<Response, String> {
|
|
||||||
commands::clientupdate(connection, parameters)
|
|
||||||
}
|
}
|
213
src/wrappers.rs
Normal file
213
src/wrappers.rs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
use std::process::exit;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use telnet::Event::TimedOut;
|
||||||
|
use telnet::Telnet;
|
||||||
|
|
||||||
|
use crate::{commands, parameter};
|
||||||
|
use crate::parameter::{parameter_list_find_all, ParameterList};
|
||||||
|
use crate::response::channel::ResponseChannel;
|
||||||
|
use crate::response::client::ResponseClient;
|
||||||
|
use crate::response::Response;
|
||||||
|
use crate::utils::SendTextMessageTarget;
|
||||||
|
|
||||||
|
pub fn skip_welcome(connection: &mut Telnet) {
|
||||||
|
loop {
|
||||||
|
let event_result = connection.read_timeout(Duration::from_millis(100));
|
||||||
|
match event_result {
|
||||||
|
Ok(event) => {
|
||||||
|
if let TimedOut = event {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => println!("Failed to read from Teamspeak."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn login(connection: &mut Telnet) {
|
||||||
|
// read api key from environment variable
|
||||||
|
let apikey = std::env::var("TS3_CLIENT_API_KEY").unwrap_or_else(|_| {
|
||||||
|
println!("No API key found in environment variable TS3_CLIENT_API_KEY.");
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
match commands::login(connection, &apikey) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(msg) => {
|
||||||
|
println!("Failed to authenticate with Teamspeak: {}", msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_channels(connection: &mut Telnet, spacers: bool) -> Result<Vec<ResponseChannel>, String> {
|
||||||
|
match commands::channellist(connection) {
|
||||||
|
Ok(response) => {
|
||||||
|
match response {
|
||||||
|
Response::DataList(parameter_lists) => {
|
||||||
|
let channels: Vec<ResponseChannel> = parameter_lists.iter()
|
||||||
|
.map(|params| ResponseChannel::from(params.clone()))
|
||||||
|
.collect();
|
||||||
|
let mut channels = ResponseChannel::sort_list(channels);
|
||||||
|
if !spacers {
|
||||||
|
channels.retain(|c| !c.is_spacer());
|
||||||
|
}
|
||||||
|
Ok(channels)
|
||||||
|
}
|
||||||
|
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_channel(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseChannel>, String> {
|
||||||
|
match commands::channellist(connection) {
|
||||||
|
Ok(response) => {
|
||||||
|
match response {
|
||||||
|
Response::DataList(parameter_lists) => {
|
||||||
|
match parameter::parameter_list_find(¶meter_lists, "channel_name", name, strict) {
|
||||||
|
Some(params) => {
|
||||||
|
Ok(Some(ResponseChannel::from(params)))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_clients(connection: &mut Telnet) -> Result<Vec<ResponseClient>, String> {
|
||||||
|
match commands::clientlist(connection) {
|
||||||
|
Ok(response) => {
|
||||||
|
match response {
|
||||||
|
Response::DataList(parameter_lists) => {
|
||||||
|
let mut clients: Vec<ResponseClient> = parameter_lists.iter()
|
||||||
|
.map(|params| ResponseClient::from(params.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
clients.sort_by(|a, b| a.client_nickname.cmp(&b.client_nickname));
|
||||||
|
|
||||||
|
Ok(clients)
|
||||||
|
}
|
||||||
|
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_client(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseClient>, String> {
|
||||||
|
match commands::clientlist(connection) {
|
||||||
|
Ok(response) => {
|
||||||
|
match response {
|
||||||
|
Response::DataList(parameter_lists) => {
|
||||||
|
match parameter::parameter_list_find(¶meter_lists, "client_nickname", name, strict) {
|
||||||
|
Some(params) => {
|
||||||
|
Ok(Some(ResponseClient::from(params)))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_channel_clients(connection: &mut Telnet, channel: &ResponseChannel) -> Result<Vec<ResponseClient>, String> {
|
||||||
|
match commands::clientlist(connection) {
|
||||||
|
Ok(response) => {
|
||||||
|
match response {
|
||||||
|
Response::DataList(parameter_lists) => {
|
||||||
|
let mut clients: Vec<ResponseClient> = Vec::new();
|
||||||
|
for client_params in parameter_list_find_all(¶meter_lists, "cid", &channel.cid.to_string(), true) {
|
||||||
|
clients.push(ResponseClient::from(client_params));
|
||||||
|
}
|
||||||
|
Ok(clients)
|
||||||
|
}
|
||||||
|
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_self_clid(connection: &mut Telnet) -> Result<String, String> {
|
||||||
|
match commands::whoami(connection) {
|
||||||
|
Ok(response) => {
|
||||||
|
match response {
|
||||||
|
Response::Data(params) => {
|
||||||
|
match parameter::parameter_find(¶ms, "clid") {
|
||||||
|
None => Err(String::from("Could not find clid in response from Teamspeak.")),
|
||||||
|
Some(param) => Ok(param.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(String::from("Received unexpected response from Teamspeak for whoami."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_self(connection: &mut Telnet) -> Result<ResponseClient, String> {
|
||||||
|
let clid = get_self_clid(connection)?;
|
||||||
|
|
||||||
|
match commands::clientlist(connection) {
|
||||||
|
Ok(response) => {
|
||||||
|
match response {
|
||||||
|
Response::DataList(parameter_lists) => {
|
||||||
|
match parameter::parameter_list_find(¶meter_lists, "clid", &clid, false) {
|
||||||
|
Some(params) => {
|
||||||
|
Ok(ResponseClient::from(params))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
Err(String::from("Could not find self in response from Teamspeak."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(String::from("Received unexpected response from Teamspeak for clientlist."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_client(connection: &mut Telnet, clients: &[ResponseClient]) -> Result<Response, String> {
|
||||||
|
let cid = find_self(connection)?.cid;
|
||||||
|
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||||
|
|
||||||
|
commands::clientmove(connection, &cid, clid_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_channel(connection: &mut Telnet, channel: ResponseChannel) -> Result<Response, String> {
|
||||||
|
let cid = find_self(connection)?.cid;
|
||||||
|
|
||||||
|
let clients = get_channel_clients(connection, &channel)?;
|
||||||
|
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||||
|
|
||||||
|
commands::clientmove(connection, &cid, clid_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_client(connection: &mut Telnet, channel: &ResponseChannel, clients: &[ResponseClient]) -> Result<Response, String> {
|
||||||
|
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||||
|
|
||||||
|
commands::clientmove(connection, &channel.cid, clid_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_client(connection: &mut Telnet, parameters: ParameterList) -> Result<Response, String> {
|
||||||
|
commands::clientupdate(connection, parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_text_message(connection: &mut Telnet, target: SendTextMessageTarget, msg: String) -> Result<Response, String> {
|
||||||
|
commands::sendtextmessage(connection, target, msg)
|
||||||
|
}
|
10
ts-control
10
ts-control
|
@ -9,7 +9,7 @@ back"
|
||||||
action=$(echo "$actions" | $DMENU)
|
action=$(echo "$actions" | $DMENU)
|
||||||
|
|
||||||
|
|
||||||
ts_control_move_self() {
|
_ts_control_move_self() {
|
||||||
channel=$(teamspeak-query-lib channels | $DMENU)
|
channel=$(teamspeak-query-lib channels | $DMENU)
|
||||||
if [ -z "$channel" ]; then
|
if [ -z "$channel" ]; then
|
||||||
return 1
|
return 1
|
||||||
|
@ -18,7 +18,7 @@ ts_control_move_self() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ts_control_fetch() {
|
_ts_control_fetch() {
|
||||||
target=$(teamspeak-query-lib "$1s" | $DMENU)
|
target=$(teamspeak-query-lib "$1s" | $DMENU)
|
||||||
if [ -z "$target" ]; then
|
if [ -z "$target" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -28,13 +28,13 @@ ts_control_fetch() {
|
||||||
|
|
||||||
case $action in
|
case $action in
|
||||||
"move")
|
"move")
|
||||||
ts_control_move_self
|
_ts_control_move_self
|
||||||
;;
|
;;
|
||||||
"fetch-client")
|
"fetch-client")
|
||||||
ts_control_fetch client
|
_ts_control_fetch client
|
||||||
;;
|
;;
|
||||||
"fetch-channel")
|
"fetch-channel")
|
||||||
ts_control_fetch channel
|
_ts_control_fetch channel
|
||||||
;;
|
;;
|
||||||
"not away")
|
"not away")
|
||||||
teamspeak-query-lib move "Not Away From Keyboard"
|
teamspeak-query-lib move "Not Away From Keyboard"
|
||||||
|
|
Loading…
Reference in a new issue