use crate::utils::SendTextMessageTarget; use telnet::Event::Data; use telnet::Telnet; use crate::parameter::{Parameter, ParameterList}; use crate::response::Response; fn to_single_response(resp: Response) -> Response { match resp { Response::DataList(list) => Response::Data(list[0].clone()), _ => resp } } fn read_part(connection: &mut Telnet) -> Result<String, String> { match connection.read() { Ok(event) => { match event { Data(bytes) => Ok(String::from_utf8(bytes.to_vec()) .map_err(|_| "Teamspeak returned a badly formatted response.")?), _ => { Err(String::from("Received unknown event from Teamspeak.")) } } } Err(_) => { Err(String::from("Failed to read from Teamspeak.")) } } } fn read_response_buffer(connection: &mut Telnet, buffer: &mut String) -> Result<(String, String), String> { loop { buffer.push_str(&read_part(connection)?); match buffer.split_once("\n\r") { None => {} Some((response, remaining)) => { return Ok((String::from(response), String::from(remaining))); } } } } 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.")?; read_response(connection, skip_ok, String::new()) } fn read_response(connection: &mut Telnet, skip_ok: bool, mut buffer: String) -> Result<Response, String> { let (response_str, buffer) = read_response_buffer(connection, &mut buffer)?; match Response::try_from(response_str) { Ok(resp) => { Ok(resp) } Err(err) => { if err.is_error_okay() { if skip_ok { read_response(connection, skip_ok, buffer) } else { Ok(Response::Ok) } } else { Err(format!("Received error response from Teamspeak: {} ({})", err.msg, err.id)) } } } } pub fn login(connection: &mut Telnet, apikey: &str) -> Result<Response, String> { send_command(connection, &format!("auth apikey={}", apikey), false) } #[allow(dead_code)] pub fn set_name(connection: &mut Telnet, name: &str) -> Result<Response, String> { send_command(connection, &format!("clientupdate client_nickname={}", name), true) } pub fn channellist(connection: &mut Telnet) -> Result<Response, String> { send_command(connection, "channellist", true) } pub fn clientlist(connection: &mut Telnet) -> Result<Response, String> { send_command(connection, "clientlist", true) } pub fn whoami(connection: &mut Telnet) -> Result<Response, String> { send_command(connection, "whoami", true).map(to_single_response) } pub fn clientmove(connection: &mut Telnet, cid: &i32, clid_list: Vec<&i32>) -> Result<Response, String> { let clid_param_list = clid_list .into_iter() .map(|clid| Parameter::new("clid", &clid.to_string())) .collect::<Vec<Parameter>>(); let clid_str = Parameter::list_to_string_sep(clid_param_list, "|"); send_command(connection, &format!("clientmove cid={} {}", cid, clid_str), false) } pub fn clientupdate(connection: &mut Telnet, parameters: ParameterList) -> Result<Response, String> { let parameters_str = Parameter::list_to_string(parameters); send_command(connection, &format!("clientupdate {}", parameters_str), false) } pub fn sendtextmessage(connection: &mut Telnet, target: SendTextMessageTarget, msg: String) -> Result<Response, String> { let msg = String::from(Parameter::new("msg", &msg)); send_command(connection, &format!("sendtextmessage {} {}", msg, String::from(target)), false) }