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