ts3plugin/
lib.rs

1//! TeamSpeak 3.6 updates the plugin api version to 26.  
2//! Version 0.3 is compatible with this version.
3//!
4//! At the moment, not all methods that are exposed by the TeamSpeak API are
5//! available for plugins. If a method that you need is missing, please file an
6//! issue or open a pull request.
7//!
8//! # Usage
9//!
10//! Add the following to your `Cargo.toml`:
11//!
12//! ```toml
13//! [package]
14//! name = "<pluginname>"
15//! version = "<version>"
16//! authors = ["<your name>"]
17//! description = "<description>"
18//!
19//! [lib]
20//! name = "<pluginname>"
21//! crate-type = ["cdylib"]
22//!
23//! [dependencies]
24//! ts3plugin = "0.3"
25//! ```
26//!
27//! # Example
28//!
29//! A fully working example, which creates a plugin that does nothing:
30//!
31//! ```
32//! #[macro_use]
33//! extern crate ts3plugin;
34//!
35//! use ts3plugin::*;
36//!
37//! struct MyTsPlugin;
38//!
39//! impl Plugin for MyTsPlugin {
40//!     // The default name is the crate name, but we can overwrite it here.
41//!     fn name()        -> String { String::from("My Ts Plugin") }
42//!     fn command() -> Option<String> { Some(String::from("myplugin")) }
43//!     fn autoload() -> bool { false }
44//!     fn configurable() -> ConfigureOffer { ConfigureOffer::No }
45//!
46//!     // The only required method
47//!     fn new(api: &TsApi) -> Result<Box<MyTsPlugin>, InitError> {
48//!         api.log_or_print("Inited", "MyTsPlugin", LogLevel::Info);
49//!         Ok(Box::new(MyTsPlugin))
50//!         // Or return Err(InitError::Failure) on failure
51//!     }
52//!
53//!     // Implement callbacks here
54//!
55//!     fn shutdown(&mut self, api: &TsApi) {
56//!         api.log_or_print("Shutdown", "MyTsPlugin", LogLevel::Info);
57//!     }
58//! }
59//!
60//! create_plugin!(MyTsPlugin);
61//!
62//! # fn main() { }
63//! ```
64
65// TODO This should be removed at some time, when more code is ready
66#![allow(dead_code)]
67
68extern crate chrono;
69#[macro_use]
70extern crate lazy_static;
71extern crate ts3plugin_sys;
72
73pub use ts3plugin_sys::plugin_definitions::*;
74pub use ts3plugin_sys::public_definitions::*;
75pub use ts3plugin_sys::public_errors::Error;
76pub use ts3plugin_sys::ts3functions::Ts3Functions;
77
78pub use crate::plugin::*;
79
80use chrono::*;
81use std::collections::HashMap as Map;
82use std::ffi::{CStr, CString};
83use std::fmt;
84use std::mem::transmute;
85use std::ops::{Deref, DerefMut};
86use std::os::raw::{c_char, c_int};
87use std::sync::{MutexGuard, RwLock};
88
89/// Converts a normal `String` to a `CString`.
90macro_rules! to_cstring {
91	($string: expr_2021) => {
92		CString::new($string).unwrap_or(CString::new("String contains null character").unwrap())
93	};
94}
95
96/// Converts a `CString` to a normal `String`.
97macro_rules! to_string {
98	($string: expr_2021) => {{ String::from_utf8_lossy(CStr::from_ptr($string).to_bytes()).into_owned() }};
99}
100
101// Declare modules here so the macros are visible in the modules
102pub mod plugin;
103pub mod ts3interface;
104
105// Import automatically generated structs
106include!(concat!(env!("OUT_DIR"), "/channel.rs"));
107include!(concat!(env!("OUT_DIR"), "/connection.rs"));
108include!(concat!(env!("OUT_DIR"), "/server.rs"));
109
110/// The api functions provided by TeamSpeak
111///
112/// This is not part of the official api and is only public to permit dirty
113/// hacks!
114#[doc(hidden)]
115pub static TS3_FUNCTIONS: RwLock<Option<Ts3Functions>> = RwLock::new(None);
116
117// ******************** Structs ********************
118/// The possible receivers of a message. A message can be sent to a specific
119/// connection, to the current channel chat or to the server chat.
120#[derive(Clone)]
121pub enum MessageReceiver {
122	Connection(ConnectionId),
123	Channel,
124	Server,
125}
126
127/// Permissions - TODO not yet implemented
128#[derive(Debug, PartialEq, Eq, Clone)]
129pub struct Permissions;
130
131/// A wrapper for a server id.
132#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
133pub struct ServerId(u64);
134
135/// A wrapper for a channel id.
136#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
137pub struct ChannelId(u64);
138
139/// A wrapper for a connection id.
140#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
141pub struct ConnectionId(u16);
142
143#[derive(Debug, Clone)]
144pub struct Permission {}
145
146#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
147pub struct PermissionId(u32);
148
149#[derive(Debug, Clone)]
150pub struct ServerGroup {}
151
152#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
153pub struct ServerGroupId(u64);
154
155#[derive(Debug, Clone)]
156pub struct ChannelGroup {}
157
158#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
159pub struct ChannelGroupId(u64);
160
161// ******************** Implementation ********************
162
163// ********** Invoker **********
164#[derive(Debug, Eq)]
165pub struct InvokerData {
166	id: ConnectionId,
167	uid: String,
168	name: String,
169}
170
171impl PartialEq<InvokerData> for InvokerData {
172	fn eq(&self, other: &InvokerData) -> bool {
173		self.id == other.id
174	}
175}
176
177impl InvokerData {
178	fn new(id: ConnectionId, uid: String, name: String) -> InvokerData {
179		InvokerData { id, uid, name }
180	}
181
182	/// Get the connection id of this invoker.
183	pub fn get_id(&self) -> ConnectionId {
184		self.id
185	}
186
187	/// Get the unique id of this invoker.
188	pub fn get_uid(&self) -> &String {
189		&self.uid
190	}
191
192	/// Get the name of this invoker.
193	pub fn get_name(&self) -> &String {
194		&self.name
195	}
196}
197
198/// The invoker is maybe not visible to the user, but we can get events caused
199/// by him, so some information about him are passed along with his id.
200#[derive(Debug, Eq)]
201pub struct Invoker<'a> {
202	server: Server<'a>,
203	data: InvokerData,
204}
205
206impl<'a, 'b> PartialEq<Invoker<'b>> for Invoker<'a> {
207	fn eq(&self, other: &Invoker) -> bool {
208		self.server == other.server && self.data == other.data
209	}
210}
211impl<'a> Deref for Invoker<'a> {
212	type Target = InvokerData;
213	fn deref(&self) -> &Self::Target {
214		&self.data
215	}
216}
217
218impl<'a> Invoker<'a> {
219	fn new(server: Server<'a>, data: InvokerData) -> Invoker<'a> {
220		Invoker { server, data }
221	}
222
223	pub fn get_connection(&'_ self) -> Option<Connection<'_>> {
224		self.server.get_connection(self.id)
225	}
226}
227
228// ********** Server **********
229#[derive(Clone)]
230pub struct Server<'a> {
231	api: &'a TsApi,
232	data: Result<&'a ServerData, ServerId>,
233}
234
235impl<'a, 'b> PartialEq<Server<'b>> for Server<'a> {
236	fn eq(&self, other: &Server<'b>) -> bool {
237		self.get_id() == other.get_id()
238	}
239}
240impl<'a> Eq for Server<'a> {}
241impl<'a> fmt::Debug for Server<'a> {
242	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243		write!(f, "Server({})", self.get_id().0)
244	}
245}
246
247impl PartialEq<ServerData> for ServerData {
248	fn eq(&self, other: &ServerData) -> bool {
249		self.id == other.id
250	}
251}
252impl Eq for ServerData {}
253
254impl ServerData {
255	/// Get a server property that is stored as a string.
256	fn get_property_as_string(
257		id: ServerId, property: VirtualServerProperties,
258	) -> Result<String, Error> {
259		unsafe {
260			let mut name: *mut c_char = std::ptr::null_mut();
261			let res: Error =
262				transmute((TS3_FUNCTIONS
263					.read()
264					.unwrap()
265					.as_ref()
266					.expect("Functions should be loaded")
267					.get_server_variable_as_string)(id.0, property as usize, &mut name));
268			match res {
269				Error::Ok => Ok(to_string!(name)),
270				_ => Err(res),
271			}
272		}
273	}
274
275	/// Get a server property that is stored as an int.
276	fn get_property_as_int(id: ServerId, property: VirtualServerProperties) -> Result<i32, Error> {
277		unsafe {
278			let mut number: c_int = 0;
279			let res: Error =
280				transmute((TS3_FUNCTIONS
281					.read()
282					.unwrap()
283					.as_ref()
284					.expect("Functions should be loaded")
285					.get_server_variable_as_int)(id.0, property as usize, &mut number));
286			match res {
287				Error::Ok => Ok(number as i32),
288				_ => Err(res),
289			}
290		}
291	}
292
293	/// Get a server property that is stored as an int.
294	fn get_property_as_uint64(
295		id: ServerId, property: VirtualServerProperties,
296	) -> Result<u64, Error> {
297		unsafe {
298			let mut number: u64 = 0;
299			let res: Error = transmute((TS3_FUNCTIONS
300				.read()
301				.unwrap()
302				.as_ref()
303				.expect("Functions should be loaded")
304				.get_server_variable_as_uint64)(
305				id.0, property as usize, &mut number
306			));
307			match res {
308				Error::Ok => Ok(number),
309				_ => Err(res),
310			}
311		}
312	}
313
314	/// Get the connection id of our own client.
315	/// Called when a new Server is created.
316	fn query_own_connection_id(id: ServerId) -> Result<ConnectionId, Error> {
317		unsafe {
318			let mut number: u16 = 0;
319			let res: Error = transmute((TS3_FUNCTIONS
320				.read()
321				.unwrap()
322				.as_ref()
323				.expect("Functions should be loaded")
324				.get_client_id)(id.0, &mut number));
325			match res {
326				Error::Ok => Ok(ConnectionId(number)),
327				_ => Err(res),
328			}
329		}
330	}
331
332	/// Get all currently active connections on this server.
333	/// Called when a new Server is created.
334	/// When an error occurs, users are not inserted into the map.
335	fn query_connections(id: ServerId) -> Map<ConnectionId, ConnectionData> {
336		let mut map = Map::new();
337		// Query connected connections
338		let mut result: *mut u16 = std::ptr::null_mut();
339		let res: Error = unsafe {
340			transmute((TS3_FUNCTIONS
341				.read()
342				.unwrap()
343				.as_ref()
344				.expect("Functions should be loaded")
345				.get_client_list)(id.0, &mut result))
346		};
347		if res == Error::Ok {
348			unsafe {
349				let mut counter = 0;
350				while *result.offset(counter) != 0 {
351					let connection_id = ConnectionId(*result.offset(counter));
352					let mut connection = ConnectionData::new(id, connection_id);
353					connection.update();
354					map.insert(connection_id, connection);
355					counter += 1;
356				}
357			}
358		}
359		map
360	}
361
362	/// Get all channels on this server.
363	/// Called when a new Server is created.
364	/// When an error occurs, channels are not inserted into the map.
365	fn query_channels(id: ServerId) -> Result<Map<ChannelId, ChannelData>, Error> {
366		let mut map = Map::new();
367		// Query connected connections
368		let mut result: *mut u64 = std::ptr::null_mut();
369		let res: Error = unsafe {
370			transmute((TS3_FUNCTIONS
371				.read()
372				.unwrap()
373				.as_ref()
374				.expect("Functions should be loaded")
375				.get_channel_list)(id.0, &mut result))
376		};
377		if res == Error::Ok {
378			unsafe {
379				let mut counter = 0;
380				while *result.offset(counter) != 0 {
381					let channel_id = ChannelId(*result.offset(counter));
382					let mut channel = ChannelData::new(id, channel_id);
383					channel.update();
384					map.insert(channel_id, channel);
385					counter += 1;
386				}
387			}
388			Ok(map)
389		} else {
390			Err(res)
391		}
392	}
393
394	// ********** Private Interface **********
395
396	fn add_connection(&mut self, connection_id: ConnectionId) -> &mut ConnectionData {
397		let mut connection = ConnectionData::new(self.id, connection_id);
398		connection.update();
399		self.visible_connections.insert(connection_id, connection);
400		self.visible_connections.get_mut(&connection_id).unwrap()
401	}
402
403	fn remove_connection(&mut self, connection_id: ConnectionId) -> Option<ConnectionData> {
404		self.visible_connections.remove(&connection_id)
405	}
406
407	fn add_channel(&mut self, channel_id: ChannelId) -> Result<&mut ChannelData, Error> {
408		match self.channels {
409			Ok(ref mut cs) => {
410				let mut channel = ChannelData::new(self.id, channel_id);
411				channel.update();
412				cs.insert(channel_id, channel);
413				Ok(cs.get_mut(&channel_id).unwrap())
414			}
415			Err(error) => Err(error),
416		}
417	}
418
419	fn remove_channel(&mut self, channel_id: ChannelId) -> Option<ChannelData> {
420		self.channels.as_mut().ok().and_then(|cs| cs.remove(&channel_id))
421	}
422
423	/// Get the mutable connection on this server that has the specified id, returns
424	/// `None` if there is no such connection.
425	fn get_mut_connection(&mut self, connection_id: ConnectionId) -> Option<&mut ConnectionData> {
426		self.visible_connections.get_mut(&connection_id)
427	}
428
429	/// Get the mutable channel on this server that has the specified id, returns
430	/// `None` if there is no such channel.
431	fn get_mut_channel(&mut self, channel_id: ChannelId) -> Option<&mut ChannelData> {
432		self.channels.as_mut().ok().and_then(|cs| cs.get_mut(&channel_id))
433	}
434}
435
436impl<'a> Server<'a> {
437	fn new(api: &'a TsApi, data: &'a ServerData) -> Server<'a> {
438		Server { api, data: Ok(data) }
439	}
440
441	fn new_err(api: &'a TsApi, server_id: ServerId) -> Server<'a> {
442		Server { api, data: Err(server_id) }
443	}
444
445	pub fn get_id(&self) -> ServerId {
446		match self.data {
447			Ok(data) => data.get_id(),
448			Err(id) => id,
449		}
450	}
451
452	/// Get the connection on this server that has the specified id, returns
453	/// `None` if there is no such connection.
454	fn get_connection_unwrap(&self, connection_id: ConnectionId) -> Connection<'a> {
455		self.get_connection(connection_id).unwrap_or_else(|| {
456			self.api.log_or_print(
457				format!("Can't find connection {:?}", connection_id),
458				"rust-ts3plugin",
459				crate::LogLevel::Warning,
460			);
461			Connection::new_err(&self.api, self.get_id(), connection_id)
462		})
463	}
464
465	/// Get the channel on this server that has the specified id, returns
466	/// `None` if there is no such channel.
467	fn get_channel_unwrap(&self, channel_id: ChannelId) -> Channel<'a> {
468		self.get_channel(channel_id).unwrap_or_else(|| {
469			self.api.log_or_print(
470				format!("Can't find channel {:?}", channel_id),
471				"rust-ts3plugin",
472				crate::LogLevel::Warning,
473			);
474			Channel::new_owned(&self.api, self.get_id(), channel_id)
475		})
476	}
477
478	fn get_server_group_unwrap(&self, server_group_id: ServerGroupId) -> ServerGroup {
479		self.get_server_group(server_group_id).unwrap_or_else(|| {
480			/*self.api.log_or_print(
481			format!("Can't find server group {:?}", server_group_id),
482			"rust-ts3plugin", ::LogLevel::Warning);*/
483			ServerGroup {}
484		})
485	}
486
487	fn get_channel_group_unwrap(&self, channel_group_id: ChannelGroupId) -> ChannelGroup {
488		self.get_channel_group(channel_group_id).unwrap_or_else(|| {
489			//self.api.log_or_print(format!("Can't find channel group {:?}", channel_group_id),
490			// "rust-ts3plugin", ::LogLevel::Warning);
491			ChannelGroup {}
492		})
493	}
494
495	// ********** Public Interface **********
496
497	/*/// The server properties that are only available on request.
498	pub fn get_optional_data(&self) -> Option<&OptionalServerData> {
499		self.data.ok().map(|data| &data.optional_data)
500	}*/
501
502	/// Get the own connection to the server.
503	pub fn get_own_connection(&self) -> Result<Connection<'a>, Error> {
504		match self.data {
505			Ok(data) => data.get_own_connection_id().map(|id| self.get_connection_unwrap(id)),
506			Err(_) => Err(Error::Ok),
507		}
508	}
509
510	/// Get the ids of all visible connections on this server.
511	pub fn get_connections(&self) -> Vec<Connection<'a>> {
512		match self.data {
513			Ok(data) => {
514				data.visible_connections.values().map(|c| Connection::new(self.api, &c)).collect()
515			}
516			Err(_) => Vec::new(),
517		}
518	}
519
520	/// Get the ids of all channels on this server.
521	pub fn get_channels(&self) -> Vec<Channel<'a>> {
522		match self.data {
523			Ok(data) => match data.channels {
524				Ok(ref cs) => cs.values().map(|c| Channel::new(self.api, &c)).collect(),
525				Err(_) => Vec::new(),
526			},
527			Err(_) => Vec::new(),
528		}
529	}
530
531	/// Get the connection on this server that has the specified id, returns
532	/// `None` if there is no such connection.
533	pub fn get_connection(&self, connection_id: ConnectionId) -> Option<Connection<'a>> {
534		self.data.ok().and_then(|data| {
535			data.visible_connections.get(&connection_id).map(|c| Connection::new(&self.api, c))
536		})
537	}
538
539	/// Get the channel on this server that has the specified id, returns
540	/// `None` if there is no such channel.
541	pub fn get_channel(&self, channel_id: ChannelId) -> Option<Channel<'a>> {
542		self.data.ok().and_then(|data| {
543			data.channels
544				.as_ref()
545				.ok()
546				.and_then(|cs| cs.get(&channel_id))
547				.map(|c| Channel::new(&self.api, c))
548		})
549	}
550
551	pub fn get_server_group(&self, _server_group_id: ServerGroupId) -> Option<ServerGroup> {
552		// TODO
553		Some(ServerGroup {})
554	}
555
556	pub fn get_channel_group(&self, _channel_group_id: ChannelGroupId) -> Option<ChannelGroup> {
557		// TODO
558		Some(ChannelGroup {})
559	}
560
561	/// Send a message to the server chat.
562	pub fn send_message<S: AsRef<str>>(&self, message: S) -> Result<(), Error> {
563		unsafe {
564			let text = to_cstring!(message.as_ref());
565			let res: Error = transmute((TS3_FUNCTIONS
566				.read()
567				.unwrap()
568				.as_ref()
569				.expect("Functions should be loaded")
570				.request_send_server_text_msg)(
571				self.get_id().0, text.as_ptr(), std::ptr::null()
572			));
573			match res {
574				Error::Ok => Ok(()),
575				_ => Err(res),
576			}
577		}
578	}
579
580	/// Sends a plugin message to all connections on the server.
581	///
582	/// Messages can be received in [`Plugin::plugin_message`].
583	/// This is refered to as `PluginCommand` in TeamSpeak.
584	///
585	/// [`Plugin::plugin_message`]: plugin/trait.Plugin.html#method.plugin_message
586	pub fn send_plugin_message<S: AsRef<str>>(&self, message: S) {
587		let text = to_cstring!(message.as_ref());
588		(TS3_FUNCTIONS
589			.read()
590			.unwrap()
591			.as_ref()
592			.expect("Functions should be loaded")
593			.send_plugin_command)(
594			self.get_id().0,
595			to_cstring!(self.api.get_plugin_id()).as_ptr(),
596			text.as_ptr(),
597			PluginTargetMode::Server as i32,
598			std::ptr::null(),
599			std::ptr::null(),
600		);
601	}
602
603	/// Print a message into the server or channel tab of this server. This is only
604	/// visible in the window of this client and will not be sent to the server.
605	pub fn print_message<S: AsRef<str>>(&self, message: S, target: MessageTarget) {
606		let text = to_cstring!(message.as_ref());
607		(TS3_FUNCTIONS.read().unwrap().as_ref().expect("Functions should be loaded").print_message)(
608			self.get_id().0,
609			text.as_ptr(),
610			target,
611		);
612	}
613}
614
615// ********** Channel **********
616#[derive(Clone)]
617pub struct Channel<'a> {
618	api: &'a TsApi,
619	data: Result<&'a ChannelData, (ServerId, ChannelId)>,
620}
621
622impl<'a, 'b> PartialEq<Channel<'b>> for Channel<'a> {
623	fn eq(&self, other: &Channel<'b>) -> bool {
624		self.get_server_id() == other.get_server_id() && self.get_id() == other.get_id()
625	}
626}
627impl<'a> Eq for Channel<'a> {}
628impl<'a> fmt::Debug for Channel<'a> {
629	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
630		write!(f, "Channel({})", self.get_id().0)
631	}
632}
633
634impl PartialEq<ChannelData> for ChannelData {
635	fn eq(&self, other: &ChannelData) -> bool {
636		self.server_id == other.server_id && self.id == other.id
637	}
638}
639impl Eq for ChannelData {}
640
641impl ChannelData {
642	/// Get a channel property that is stored as a string.
643	fn get_property_as_string(
644		server_id: ServerId, id: ChannelId, property: ChannelProperties,
645	) -> Result<String, Error> {
646		unsafe {
647			let mut name: *mut c_char = std::ptr::null_mut();
648			let res: Error = transmute((TS3_FUNCTIONS
649				.read()
650				.unwrap()
651				.as_ref()
652				.expect("Functions should be loaded")
653				.get_channel_variable_as_string)(
654				server_id.0, id.0, property as usize, &mut name
655			));
656			match res {
657				Error::Ok => Ok(to_string!(name)),
658				_ => Err(res),
659			}
660		}
661	}
662
663	/// Get a channel property that is stored as an int.
664	fn get_property_as_int(
665		server_id: ServerId, id: ChannelId, property: ChannelProperties,
666	) -> Result<i32, Error> {
667		unsafe {
668			let mut number: c_int = 0;
669			let res: Error = transmute((TS3_FUNCTIONS
670				.read()
671				.unwrap()
672				.as_ref()
673				.expect("Functions should be loaded")
674				.get_channel_variable_as_int)(
675				server_id.0, id.0, property as usize, &mut number
676			));
677			match res {
678				Error::Ok => Ok(number as i32),
679				_ => Err(res),
680			}
681		}
682	}
683
684	/// Get a channel property that is stored as an uint64.
685	fn get_property_as_uint64(
686		server_id: ServerId, id: ChannelId, property: ChannelProperties,
687	) -> Result<i32, Error> {
688		unsafe {
689			let mut number: u64 = 0;
690			let res: Error = transmute((TS3_FUNCTIONS
691				.read()
692				.unwrap()
693				.as_ref()
694				.expect("Functions should be loaded")
695				.get_channel_variable_as_uint64)(
696				server_id.0, id.0, property as usize, &mut number
697			));
698			match res {
699				Error::Ok => Ok(number as i32),
700				_ => Err(res),
701			}
702		}
703	}
704
705	/// Ask the TeamSpeak api about the parent channel id of a channel.
706	fn query_parent_channel_id(server_id: ServerId, id: ChannelId) -> Result<ChannelId, Error> {
707		unsafe {
708			let mut number: u64 = 0;
709			let res: Error =
710				transmute((TS3_FUNCTIONS
711					.read()
712					.unwrap()
713					.as_ref()
714					.expect("Functions should be loaded")
715					.get_parent_channel_of_channel)(server_id.0, id.0, &mut number));
716			match res {
717				Error::Ok => Ok(ChannelId(number)),
718				_ => Err(res),
719			}
720		}
721	}
722}
723
724impl<'a> Channel<'a> {
725	fn new(api: &'a TsApi, data: &'a ChannelData) -> Channel<'a> {
726		Channel { api, data: Ok(data) }
727	}
728
729	fn new_owned(api: &'a TsApi, server_id: ServerId, channel_id: ChannelId) -> Channel<'a> {
730		Channel { api, data: Err((server_id, channel_id)) }
731	}
732
733	fn get_server_id(&self) -> ServerId {
734		match self.data {
735			Ok(data) => data.get_server_id(),
736			Err((server_id, _)) => server_id,
737		}
738	}
739
740	pub fn get_id(&self) -> ChannelId {
741		match self.data {
742			Ok(data) => data.get_id(),
743			Err((_, channel_id)) => channel_id,
744		}
745	}
746
747	/// Get the server of this channel.
748	pub fn get_server(&self) -> Server<'a> {
749		self.api.get_server_unwrap(self.get_server_id())
750	}
751
752	pub fn get_parent_channel(&self) -> Result<Option<Channel<'a>>, Error> {
753		match self.data {
754			Ok(data) => data.get_parent_channel_id().map(|parent_channel_id| {
755				if parent_channel_id.0 == 0 {
756					None
757				} else {
758					Some(self.get_server().get_channel_unwrap(parent_channel_id))
759				}
760			}),
761			Err(_) => Err(Error::Ok),
762		}
763	}
764
765	/// Send a message to this channel chat.
766	pub fn send_message<S: AsRef<str>>(&self, message: S) -> Result<(), Error> {
767		unsafe {
768			let text = to_cstring!(message.as_ref());
769			let res: Error = transmute((TS3_FUNCTIONS
770				.read()
771				.unwrap()
772				.as_ref()
773				.expect("Functions should be loaded")
774				.request_send_channel_text_msg)(
775				self.data.unwrap().server_id.0,
776				text.as_ptr(),
777				self.data.unwrap().id.0,
778				std::ptr::null(),
779			));
780			match res {
781				Error::Ok => Ok(()),
782				_ => Err(res),
783			}
784		}
785	}
786}
787
788// ********** Connection **********
789#[derive(Clone)]
790pub struct Connection<'a> {
791	api: &'a TsApi,
792	data: Result<&'a ConnectionData, (ServerId, ConnectionId)>,
793}
794
795impl<'a, 'b> PartialEq<Connection<'b>> for Connection<'a> {
796	fn eq(&self, other: &Connection<'b>) -> bool {
797		self.get_server_id() == other.get_server_id() && self.get_id() == other.get_id()
798	}
799}
800impl<'a> Eq for Connection<'a> {}
801impl<'a> fmt::Debug for Connection<'a> {
802	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
803		write!(f, "Connection({})", self.get_id().0)
804	}
805}
806
807impl PartialEq<ConnectionData> for ConnectionData {
808	fn eq(&self, other: &ConnectionData) -> bool {
809		self.server_id == other.server_id && self.id == other.id
810	}
811}
812impl Eq for ConnectionData {}
813
814impl ConnectionData {
815	/// Get a connection property that is stored as a string.
816	fn get_connection_property_as_string(
817		server_id: ServerId, id: ConnectionId, property: ConnectionProperties,
818	) -> Result<String, Error> {
819		unsafe {
820			let mut name: *mut c_char = std::ptr::null_mut();
821			let res: Error = transmute((TS3_FUNCTIONS
822				.read()
823				.unwrap()
824				.as_ref()
825				.expect("Functions should be loaded")
826				.get_connection_variable_as_string)(
827				server_id.0, id.0, property as usize, &mut name
828			));
829			match res {
830				Error::Ok => Ok(to_string!(name)),
831				_ => Err(res),
832			}
833		}
834	}
835
836	/// Get a connection property that is stored as a uint64.
837	fn get_connection_property_as_uint64(
838		server_id: ServerId, id: ConnectionId, property: ConnectionProperties,
839	) -> Result<u64, Error> {
840		unsafe {
841			let mut number: u64 = 0;
842			let res: Error = transmute((TS3_FUNCTIONS
843				.read()
844				.unwrap()
845				.as_ref()
846				.expect("Functions should be loaded")
847				.get_connection_variable_as_uint64)(
848				server_id.0, id.0, property as usize, &mut number
849			));
850			match res {
851				Error::Ok => Ok(number),
852				_ => Err(res),
853			}
854		}
855	}
856
857	/// Get a connection property that is stored as a double.
858	fn get_connection_property_as_double(
859		server_id: ServerId, id: ConnectionId, property: ConnectionProperties,
860	) -> Result<f64, Error> {
861		unsafe {
862			let mut number: f64 = 0.0;
863			let res: Error = transmute((TS3_FUNCTIONS
864				.read()
865				.unwrap()
866				.as_ref()
867				.expect("Functions should be loaded")
868				.get_connection_variable_as_double)(
869				server_id.0, id.0, property as usize, &mut number
870			));
871			match res {
872				Error::Ok => Ok(number),
873				_ => Err(res),
874			}
875		}
876	}
877
878	/// Get a client property that is stored as a string.
879	fn get_client_property_as_string(
880		server_id: ServerId, id: ConnectionId, property: ClientProperties,
881	) -> Result<String, Error> {
882		unsafe {
883			let mut name: *mut c_char = std::ptr::null_mut();
884			let res: Error = transmute((TS3_FUNCTIONS
885				.read()
886				.unwrap()
887				.as_ref()
888				.expect("Functions should be loaded")
889				.get_client_variable_as_string)(
890				server_id.0, id.0, property as usize, &mut name
891			));
892			match res {
893				Error::Ok => Ok(to_string!(name)),
894				_ => Err(res),
895			}
896		}
897	}
898
899	/// Get a client property that is stored as an int.
900	fn get_client_property_as_int(
901		server_id: ServerId, id: ConnectionId, property: ClientProperties,
902	) -> Result<c_int, Error> {
903		unsafe {
904			let mut number: c_int = 0;
905			let res: Error = transmute((TS3_FUNCTIONS
906				.read()
907				.unwrap()
908				.as_ref()
909				.expect("Functions should be loaded")
910				.get_client_variable_as_int)(
911				server_id.0, id.0, property as usize, &mut number
912			));
913			match res {
914				Error::Ok => Ok(number),
915				_ => Err(res),
916			}
917		}
918	}
919
920	/// Ask the TeamSpeak api about the current channel id of a connection.
921	fn query_channel_id(server_id: ServerId, id: ConnectionId) -> Result<ChannelId, Error> {
922		unsafe {
923			let mut number: u64 = 0;
924			let res: Error = transmute((TS3_FUNCTIONS
925				.read()
926				.unwrap()
927				.as_ref()
928				.expect("Functions should be loaded")
929				.get_channel_of_client)(server_id.0, id.0, &mut number));
930			match res {
931				Error::Ok => Ok(ChannelId(number)),
932				_ => Err(res),
933			}
934		}
935	}
936
937	/// Ask the TeamSpeak api, if the specified connection is currently whispering to our own
938	/// client.
939	fn query_whispering(server_id: ServerId, id: ConnectionId) -> Result<bool, Error> {
940		unsafe {
941			let mut number: c_int = 0;
942			let res: Error = transmute((TS3_FUNCTIONS
943				.read()
944				.unwrap()
945				.as_ref()
946				.expect("Functions should be loaded")
947				.is_whispering)(server_id.0, id.0, &mut number));
948			match res {
949				Error::Ok => Ok(number != 0),
950				_ => Err(res),
951			}
952		}
953	}
954}
955
956impl<'a> Connection<'a> {
957	fn new(api: &'a TsApi, data: &'a ConnectionData) -> Connection<'a> {
958		Connection { api, data: Ok(data) }
959	}
960
961	fn new_err(api: &'a TsApi, server_id: ServerId, connection_id: ConnectionId) -> Connection<'a> {
962		Connection { api, data: Err((server_id, connection_id)) }
963	}
964
965	fn get_server_id(&self) -> ServerId {
966		match self.data {
967			Ok(data) => data.get_server_id(),
968			Err((server_id, _)) => server_id,
969		}
970	}
971
972	pub fn get_id(&self) -> ConnectionId {
973		match self.data {
974			Ok(data) => data.get_id(),
975			Err((_, connection_id)) => connection_id,
976		}
977	}
978
979	/// Get the server of this connection.
980	pub fn get_server(&self) -> Server<'a> {
981		self.api.get_server_unwrap(self.get_server_id())
982	}
983
984	/// Get the channel of this connection.
985	pub fn get_channel(&self) -> Result<Channel<'a>, Error> {
986		match self.data {
987			Ok(data) => data.get_channel_id().map(|c| self.get_server().get_channel_unwrap(c)),
988			Err(_) => Err(Error::Ok),
989		}
990	}
991
992	pub fn get_channel_group_inherited_channel(&self) -> Result<Channel<'a>, Error> {
993		match self.data {
994			Ok(data) => data
995				.get_channel_group_inherited_channel_id()
996				.map(|c| self.get_server().get_channel_unwrap(c)),
997			Err(_) => Err(Error::Ok),
998		}
999	}
1000
1001	/*/// The connection properties that are only available for our own client.
1002	pub fn get_own_data(&self) -> Option<&OwnConnectionData> {
1003		self.data.ok().and_then(|data| data.own_data.as_ref())
1004	}
1005
1006	/// The connection properties that are only available for server queries.
1007	pub fn get_serverquery_data(&self) -> Option<&ServerqueryConnectionData> {
1008		self.data.ok().and_then(|data| data.serverquery_data.as_ref())
1009	}
1010
1011	/// The connection properties that are only available on request.
1012	pub fn get_optional_data(&self) -> Option<&OptionalConnectionData> {
1013		self.data.ok().map(|data| &data.optional_data)
1014	}*/
1015
1016	/// Send a private message to this connection.
1017	pub fn send_message<S: AsRef<str>>(&self, message: S) -> Result<(), Error> {
1018		unsafe {
1019			let text = to_cstring!(message.as_ref());
1020			let res: Error = transmute((TS3_FUNCTIONS
1021				.read()
1022				.unwrap()
1023				.as_ref()
1024				.expect("Functions should be loaded")
1025				.request_send_private_text_msg)(
1026				self.data.unwrap().server_id.0,
1027				text.as_ptr(),
1028				self.data.unwrap().id.0,
1029				std::ptr::null(),
1030			));
1031			match res {
1032				Error::Ok => Ok(()),
1033				_ => Err(res),
1034			}
1035		}
1036	}
1037}
1038
1039pub struct TsApiLock {
1040	guard: MutexGuard<'static, (Option<(TsApi, Box<dyn Plugin>)>, Option<String>)>,
1041}
1042impl Deref for TsApiLock {
1043	type Target = TsApi;
1044	fn deref(&self) -> &Self::Target {
1045		&self.guard.0.as_ref().unwrap().0
1046	}
1047}
1048impl DerefMut for TsApiLock {
1049	fn deref_mut(&mut self) -> &mut Self::Target {
1050		&mut self.guard.0.as_mut().unwrap().0
1051	}
1052}
1053
1054pub struct PluginLock {
1055	guard: MutexGuard<'static, (Option<(TsApi, Box<dyn Plugin>)>, Option<String>)>,
1056}
1057impl Deref for PluginLock {
1058	type Target = dyn Plugin;
1059	fn deref(&self) -> &Self::Target {
1060		&*self.guard.0.as_ref().unwrap().1
1061	}
1062}
1063impl DerefMut for PluginLock {
1064	fn deref_mut(&mut self) -> &mut Self::Target {
1065		&mut *self.guard.0.as_mut().unwrap().1
1066	}
1067}
1068
1069// ********** TsApi **********
1070/// The main struct that contains all permanently save data.
1071pub struct TsApi {
1072	/// All known servers.
1073	servers: Map<ServerId, ServerData>,
1074	/// The plugin id from TeamSpeak.
1075	plugin_id: String,
1076}
1077
1078// Don't provide a default Implementation because we don't want the TsApi
1079// to be publicly constructable.
1080impl TsApi {
1081	/// Create a new TsApi instance without loading anything.
1082	fn new(plugin_id: String) -> TsApi {
1083		TsApi { servers: Map::new(), plugin_id: plugin_id }
1084	}
1085
1086	/// Load all currently connected server and their data.
1087	/// This should normally be executed after `new()`.
1088	fn load(&mut self) -> Result<(), Error> {
1089		// Query available connections
1090		let mut result: *mut u64 = std::ptr::null_mut();
1091		let res: Error = unsafe {
1092			transmute((TS3_FUNCTIONS
1093				.read()
1094				.unwrap()
1095				.as_ref()
1096				.expect("Functions should be loaded")
1097				.get_server_connection_handler_list)(&mut result))
1098		};
1099		match res {
1100			Error::Ok => unsafe {
1101				let mut counter = 0;
1102				while *result.offset(counter) != 0 {
1103					// Test if we have a connection to this server.
1104					// We get open tabs, even if they are disconnected.
1105					let mut status: c_int = 0;
1106					let res: Error = transmute((TS3_FUNCTIONS
1107						.read()
1108						.unwrap()
1109						.as_ref()
1110						.expect("Functions should be loaded")
1111						.get_connection_status)(
1112						*result.offset(counter), &mut status
1113					));
1114					if res == Error::Ok
1115						&& transmute::<c_int, ConnectStatus>(status) != ConnectStatus::Disconnected
1116					{
1117						self.add_server(ServerId(*result.offset(counter)));
1118					}
1119					counter += 1;
1120				}
1121			},
1122			_ => return Err(res),
1123		}
1124		Ok(())
1125	}
1126
1127	/// Lock the global `TsApi` object. This will be `None` when the plugin is
1128	/// constructed.
1129	pub fn lock_api() -> Option<TsApiLock> {
1130		let guard = ts3interface::DATA.lock().unwrap();
1131		if guard.0.is_none() { None } else { Some(TsApiLock { guard }) }
1132	}
1133
1134	/// Lock the global `Plugin` object.
1135	pub fn lock_plugin() -> Option<PluginLock> {
1136		let guard = ts3interface::DATA.lock().unwrap();
1137		if guard.0.is_none() { None } else { Some(PluginLock { guard }) }
1138	}
1139
1140	/// Please try to use the member method `log_message` instead of this static method.
1141	pub fn static_log_message<S1: AsRef<str>, S2: AsRef<str>>(
1142		message: S1, channel: S2, severity: LogLevel,
1143	) -> Result<(), Error> {
1144		unsafe {
1145			let res: Error = transmute((TS3_FUNCTIONS
1146				.read()
1147				.unwrap()
1148				.as_ref()
1149				.expect("Functions should be loaded")
1150				.log_message)(
1151				to_cstring!(message.as_ref()).as_ptr(),
1152				severity,
1153				to_cstring!(channel.as_ref()).as_ptr(),
1154				0,
1155			));
1156			match res {
1157				Error::Ok => Ok(()),
1158				_ => Err(res),
1159			}
1160		}
1161	}
1162
1163	/// Please try to use the member method `log_or_print` instead of this static method.
1164	pub fn static_log_or_print<S1: AsRef<str>, S2: AsRef<str>>(
1165		message: S1, channel: S2, severity: LogLevel,
1166	) {
1167		if let Err(error) = TsApi::static_log_message(message.as_ref(), channel.as_ref(), severity)
1168		{
1169			println!(
1170				"Error {:?} while printing '{}' to '{}' ({:?})",
1171				error,
1172				message.as_ref(),
1173				channel.as_ref(),
1174				severity
1175			);
1176		}
1177	}
1178
1179	/// Please try to use the member method `get_error_message` instead of this static method.
1180	pub fn static_get_error_message(error: Error) -> Result<String, Error> {
1181		unsafe {
1182			let mut message: *mut c_char = std::ptr::null_mut();
1183			let res: Error = transmute((TS3_FUNCTIONS
1184				.read()
1185				.unwrap()
1186				.as_ref()
1187				.expect("Functions should be loaded")
1188				.get_error_message)(error as u32, &mut message));
1189			match res {
1190				Error::Ok => Ok(to_string!(message)),
1191				_ => Err(res),
1192			}
1193		}
1194	}
1195
1196	// ********** Private Interface **********
1197
1198	/// Add the server with the specified id to the server list.
1199	/// The currently available data of this server will be stored.
1200	fn add_server(&mut self, server_id: ServerId) -> &mut ServerData {
1201		self.servers.insert(server_id, ServerData::new(server_id));
1202		let server = self.servers.get_mut(&server_id).unwrap();
1203		server.update();
1204		server
1205	}
1206
1207	/// Returns true if a server was removed
1208	fn remove_server(&mut self, server_id: ServerId) -> Option<ServerData> {
1209		self.servers.remove(&server_id)
1210	}
1211
1212	/// Get the plugin id assigned by TeamSpeak.
1213	pub fn get_plugin_id(&self) -> &str {
1214		&self.plugin_id
1215	}
1216
1217	/// Update the data of a connection with the data from the same connection
1218	/// as an invoker if possible.
1219	fn try_update_invoker(&mut self, server_id: ServerId, invoker: &InvokerData) {
1220		if let Some(server) = self.get_mut_server(server_id) {
1221			if let Some(connection) = server.get_mut_connection(invoker.get_id()) {
1222				if connection.get_uid() != Ok(invoker.get_uid()) {
1223					connection.uid = Ok(invoker.get_uid().clone());
1224				}
1225				if connection.get_name() != Ok(invoker.get_name()) {
1226					connection.name = Ok(invoker.get_name().clone())
1227				}
1228			}
1229		}
1230	}
1231
1232	/// A reusable function that takes a TeamSpeak3 api function like
1233	/// `get_plugin_path` and returns the path.
1234	/// The buffer that holds the path will be automatically enlarged up to a
1235	/// limit.
1236	/// The function that is colled takes a pointer to a string buffer that will
1237	/// be filled and the max lenght of the buffer.
1238	fn get_path<F: Fn(*mut c_char, usize)>(fun: F) -> String {
1239		const START_SIZE: usize = 512;
1240		const MAX_SIZE: usize = 100_000;
1241		let mut size = START_SIZE;
1242		loop {
1243			let mut buf = vec![0 as u8; size];
1244			fun(buf.as_mut_ptr() as *mut c_char, size - 1);
1245			// Test if the allocated buffer was long enough
1246			if buf[size - 3] != 0 {
1247				size *= 2;
1248				if size > MAX_SIZE {
1249					return String::new();
1250				}
1251			} else {
1252				// Be sure that the string is terminated
1253				buf[size - 1] = 0;
1254				let s = unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) };
1255				let result = s.to_string_lossy();
1256				return result.into_owned();
1257			}
1258		}
1259	}
1260
1261	/// Get the mutable server that has the specified id, returns `None` if there is no
1262	/// such server.
1263	fn get_mut_server(&mut self, server_id: ServerId) -> Option<&mut ServerData> {
1264		self.servers.get_mut(&server_id)
1265	}
1266
1267	fn get_server_unwrap<'a>(&'a self, server_id: ServerId) -> Server<'a> {
1268		self.servers.get(&server_id).map(|s| Server::<'a>::new(&self, s)).unwrap_or_else(|| {
1269			// Ignore here, there are too many messages when we are not yet
1270			// fully connected (or already disconnected), but sound is sent.
1271			// self.log_or_print(format!("Can't find server {:?}\n{:?}",
1272			//     server_id, backtrace::Backtrace::new()), "rust-ts3plugin", ::LogLevel::Warning);
1273			Server::new_err(&self, server_id)
1274		})
1275	}
1276
1277	// ********** Public Interface **********
1278
1279	/// Get the raw TeamSpeak api functions.
1280	/// These functions can be used to invoke actions that are not yet
1281	/// implemented by this library. You should file a bug report or make a pull
1282	/// request if you need to use this function.
1283	//pub unsafe fn get_raw_api() -> &'static Ts3Functions { unsafe { TS3_FUNCTIONS.lock().unwrap().as_ref().unwrap() }}
1284
1285	/// Get all servers to which this client is currently connected.
1286	pub fn get_servers<'a>(&'a self) -> Vec<Server<'a>> {
1287		self.servers.values().map(|s| Server::new(&self, &s)).collect()
1288	}
1289
1290	/// Log a message using the TeamSpeak logging API.
1291	pub fn log_message<S1: AsRef<str>, S2: AsRef<str>>(
1292		&self, message: S1, channel: S2, severity: LogLevel,
1293	) -> Result<(), Error> {
1294		TsApi::static_log_message(message, channel, severity)
1295	}
1296
1297	/// Log a message using the TeamSpeak logging API.
1298	/// If that fails, print the message to stdout.
1299	pub fn log_or_print<S1: AsRef<str>, S2: AsRef<str>>(
1300		&self, message: S1, channel: S2, severity: LogLevel,
1301	) {
1302		TsApi::static_log_or_print(message, channel, severity)
1303	}
1304
1305	/// Get the server that has the specified id, returns `None` if there is no
1306	/// such server.
1307	pub fn get_server(&'_ self, server_id: ServerId) -> Option<Server<'_>> {
1308		self.servers.get(&server_id).map(|s| Server::new(&self, s))
1309	}
1310
1311	pub fn get_permission(&self, _permission_id: PermissionId) -> Option<&Permission> {
1312		// TODO
1313		Some(&Permission {})
1314	}
1315
1316	/// Print a message to the currently selected tab. This is only
1317	/// visible in the window of this client and will not be sent to the server.
1318	pub fn print_message<S: AsRef<str>>(&self, message: S) {
1319		let text = to_cstring!(message.as_ref());
1320		(TS3_FUNCTIONS
1321			.read()
1322			.unwrap()
1323			.as_ref()
1324			.expect("Functions should be loaded")
1325			.print_message_to_current_tab)(text.as_ptr());
1326	}
1327
1328	/// Get the application path of the TeamSpeak executable.
1329	pub fn get_app_path(&self) -> String {
1330		TsApi::get_path(|p, l| {
1331			(TS3_FUNCTIONS
1332				.read()
1333				.unwrap()
1334				.as_ref()
1335				.expect("Functions should be loaded")
1336				.get_app_path)(p, l)
1337		})
1338	}
1339
1340	/// Get the resource path of TeamSpeak.
1341	pub fn get_resources_path(&self) -> String {
1342		TsApi::get_path(|p, l| {
1343			(TS3_FUNCTIONS
1344				.read()
1345				.unwrap()
1346				.as_ref()
1347				.expect("Functions should be loaded")
1348				.get_resources_path)(p, l)
1349		})
1350	}
1351
1352	/// Get the path, where configuration files are stored.
1353	/// This is e.g. `~/.ts3client` on linux or `%AppData%/TS3Client` on Windows.
1354	pub fn get_config_path(&self) -> String {
1355		TsApi::get_path(|p, l| {
1356			(TS3_FUNCTIONS
1357				.read()
1358				.unwrap()
1359				.as_ref()
1360				.expect("Functions should be loaded")
1361				.get_config_path)(p, l)
1362		})
1363	}
1364
1365	/// Get the path where TeamSpeak plugins are stored.
1366	pub fn get_plugin_path(&self) -> String {
1367		TsApi::get_path(|p, l| {
1368			(TS3_FUNCTIONS
1369				.read()
1370				.unwrap()
1371				.as_ref()
1372				.expect("Functions should be loaded")
1373				.get_plugin_path)(p, l, to_cstring!(self.plugin_id.as_str()).as_ptr())
1374		})
1375	}
1376}