aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/message/handshake/clientinit.rs30
-rw-r--r--src/message/handshake/clientinitack.rs46
-rw-r--r--src/message/handshake/clientinitreject.rs28
-rw-r--r--src/message/handshake/clientlogin.rs26
-rw-r--r--src/message/handshake/clientloginack.rs2
-rw-r--r--src/message/handshake/clientloginreject.rs26
-rw-r--r--src/message/handshake/init.rs10
-rw-r--r--src/message/handshake/mod.rs46
-rw-r--r--src/message/handshake/sessioninit.rs84
-rw-r--r--src/message/signalproxy/objects/identity.rs119
-rw-r--r--src/primitive/datetime.rs2
11 files changed, 278 insertions, 141 deletions
diff --git a/src/message/handshake/clientinit.rs b/src/message/handshake/clientinit.rs
index 17ec9a1..d21d6aa 100644
--- a/src/message/handshake/clientinit.rs
+++ b/src/message/handshake/clientinit.rs
@@ -1,6 +1,5 @@
-use crate::error::ProtocolError;
use crate::primitive::{StringList, Variant, VariantMap};
-use crate::{HandshakeDeserialize, HandshakeSerialize};
+use crate::HandshakeSerialize;
use failure::Error;
@@ -32,7 +31,7 @@ use failure::Error;
/// | -- | EcdsaCertfpKeys | ECDSA keys for CertFP in identities |
/// | -- | LongMessageId | 64-bit IDs for messages |
/// | -- | SyncedCoreInfo | CoreInfo dynamically updated using signals |
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ClientInit {
/// Version of the client
pub client_version: String,
@@ -68,24 +67,13 @@ impl HandshakeSerialize for ClientInit {
}
}
-impl HandshakeDeserialize for ClientInit {
- fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
- let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?;
-
- let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8);
-
- if msgtype == "ClientInit" {
- return Ok((
- len,
- Self {
- client_version: match_variant!(values["ClientVersion"], Variant::String),
- client_date: match_variant!(values["ClientDate"], Variant::String),
- feature_list: match_variant!(values["FeatureList"], Variant::StringList),
- client_features: match_variant!(values["Features"], Variant::u32),
- },
- ));
- } else {
- bail!(ProtocolError::WrongMsgType);
+impl From<VariantMap> for ClientInit {
+ fn from(input: VariantMap) -> Self {
+ ClientInit {
+ client_version: match_variant!(input.get("ClientVersion").unwrap(), Variant::String),
+ client_date: match_variant!(input.get("ClientDate").unwrap(), Variant::String),
+ client_features: match_variant!(input.get("Features").unwrap(), Variant::u32),
+ feature_list: match_variant!(input.get("FeatureList").unwrap(), Variant::StringList),
}
}
}
diff --git a/src/message/handshake/clientinitack.rs b/src/message/handshake/clientinitack.rs
index 637b989..f881113 100644
--- a/src/message/handshake/clientinitack.rs
+++ b/src/message/handshake/clientinitack.rs
@@ -1,11 +1,10 @@
-use crate::error::ProtocolError;
-use crate::primitive::{StringList, Variant, VariantList, VariantMap};
-use crate::{HandshakeDeserialize, HandshakeSerialize};
+use crate::primitive::{Variant, VariantList, VariantMap};
+use crate::HandshakeSerialize;
use failure::Error;
/// ClientInitAck is received when the initialization was successfull
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ClientInitAck {
/// Flags of supported legacy features
pub core_features: u32,
@@ -16,7 +15,7 @@ pub struct ClientInitAck {
/// List of VariantMaps of info on available authenticators
pub authenticators: VariantList,
/// List of supported extended features
- pub feature_list: StringList,
+ pub feature_list: Vec<String>,
}
impl HandshakeSerialize for ClientInitAck {
@@ -47,28 +46,21 @@ impl HandshakeSerialize for ClientInitAck {
}
}
-impl HandshakeDeserialize for ClientInitAck {
- fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
- let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?;
-
- let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8);
-
- if msgtype == "ClientInitAck" {
- return Ok((
- len,
- Self {
- core_features: 0x00008000,
- core_configured: match_variant!(values["Configured"], Variant::bool),
- storage_backends: match_variant!(
- values["StorageBackends"],
- Variant::VariantList
- ),
- authenticators: match_variant!(values["Authenticators"], Variant::VariantList),
- feature_list: match_variant!(values["FeatureList"], Variant::StringList),
- },
- ));
- } else {
- bail!(ProtocolError::WrongMsgType);
+impl From<VariantMap> for ClientInitAck {
+ fn from(input: VariantMap) -> Self {
+ ClientInitAck {
+ // TODO make this compatible with older clients
+ core_features: 0,
+ core_configured: match_variant!(input.get("Configured").unwrap(), Variant::bool),
+ storage_backends: match_variant!(
+ input.get("StorageBackends").unwrap(),
+ Variant::VariantList
+ ),
+ authenticators: match_variant!(
+ input.get("Authenticators").unwrap(),
+ Variant::VariantList
+ ),
+ feature_list: match_variant!(input.get("FeatureList").unwrap(), Variant::StringList),
}
}
}
diff --git a/src/message/handshake/clientinitreject.rs b/src/message/handshake/clientinitreject.rs
index 06960b7..d93413d 100644
--- a/src/message/handshake/clientinitreject.rs
+++ b/src/message/handshake/clientinitreject.rs
@@ -1,14 +1,13 @@
-use crate::error::ProtocolError;
use crate::primitive::{Variant, VariantMap};
-use crate::{HandshakeDeserialize, HandshakeSerialize};
+use crate::HandshakeSerialize;
use failure::Error;
/// ClientInitReject is received when the initialization fails
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ClientInitReject {
/// String with an error message of what went wrong
- pub error_string: String,
+ pub error: String,
}
impl HandshakeSerialize for ClientInitReject {
@@ -20,27 +19,16 @@ impl HandshakeSerialize for ClientInitReject {
);
values.insert(
"ErrorString".to_string(),
- Variant::String(self.error_string.clone()),
+ Variant::String(self.error.clone()),
);
return HandshakeSerialize::serialize(&values);
}
}
-impl HandshakeDeserialize for ClientInitReject {
- fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
- let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?;
-
- let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8);
-
- if msgtype == "ClientInitReject" {
- return Ok((
- len,
- Self {
- error_string: match_variant!(values["ErrorString"], Variant::String),
- },
- ));
- } else {
- bail!(ProtocolError::WrongMsgType);
+impl From<VariantMap> for ClientInitReject {
+ fn from(input: VariantMap) -> Self {
+ ClientInitReject {
+ error: match_variant!(input.get("ErrorString").unwrap(), Variant::String),
}
}
}
diff --git a/src/message/handshake/clientlogin.rs b/src/message/handshake/clientlogin.rs
index 769245b..dffd996 100644
--- a/src/message/handshake/clientlogin.rs
+++ b/src/message/handshake/clientlogin.rs
@@ -1,12 +1,11 @@
-use crate::error::ProtocolError;
use crate::primitive::{Variant, VariantMap};
-use crate::{HandshakeDeserialize, HandshakeSerialize};
+use crate::HandshakeSerialize;
use failure::Error;
/// Login to the core with user data
/// username and password are transmitted in plain text
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ClientLogin {
pub user: String,
pub password: String,
@@ -28,22 +27,11 @@ impl HandshakeSerialize for ClientLogin {
}
}
-impl HandshakeDeserialize for ClientLogin {
- fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
- let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?;
-
- let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8);
-
- if msgtype == "ClientLogin" {
- return Ok((
- len,
- Self {
- user: match_variant!(values["User"], Variant::String),
- password: match_variant!(values["Password"], Variant::String),
- },
- ));
- } else {
- bail!(ProtocolError::WrongMsgType);
+impl From<VariantMap> for ClientLogin {
+ fn from(input: VariantMap) -> Self {
+ ClientLogin {
+ user: match_variant!(input.get("User").unwrap(), Variant::String),
+ password: match_variant!(input.get("Password").unwrap(), Variant::String),
}
}
}
diff --git a/src/message/handshake/clientloginack.rs b/src/message/handshake/clientloginack.rs
index 674d307..e385a81 100644
--- a/src/message/handshake/clientloginack.rs
+++ b/src/message/handshake/clientloginack.rs
@@ -6,7 +6,7 @@ use failure::Error;
/// ClientLoginAck is received after the client has successfully logged in
/// it has no fields
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ClientLoginAck;
impl HandshakeSerialize for ClientLoginAck {
diff --git a/src/message/handshake/clientloginreject.rs b/src/message/handshake/clientloginreject.rs
index e8380d6..0c0fc85 100644
--- a/src/message/handshake/clientloginreject.rs
+++ b/src/message/handshake/clientloginreject.rs
@@ -1,14 +1,13 @@
-use crate::error::ProtocolError;
use crate::primitive::{Variant, VariantMap};
-use crate::{HandshakeDeserialize, HandshakeSerialize};
+use crate::HandshakeSerialize;
use failure::Error;
/// ClientLoginReject is received after the client failed to login
/// It contains an error message as String
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ClientLoginReject {
- error: String,
+ pub error: String,
}
impl HandshakeSerialize for ClientLoginReject {
@@ -26,21 +25,10 @@ impl HandshakeSerialize for ClientLoginReject {
}
}
-impl HandshakeDeserialize for ClientLoginReject {
- fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
- let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?;
-
- let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8);
-
- if msgtype == "ClientLogin" {
- return Ok((
- len,
- Self {
- error: match_variant!(values["ErrorString"], Variant::String),
- },
- ));
- } else {
- bail!(ProtocolError::WrongMsgType);
+impl From<VariantMap> for ClientLoginReject {
+ fn from(input: VariantMap) -> Self {
+ ClientLoginReject {
+ error: match_variant!(input.get("ErrorString").unwrap(), Variant::String),
}
}
}
diff --git a/src/message/handshake/init.rs b/src/message/handshake/init.rs
index e4c0fa9..860df8a 100644
--- a/src/message/handshake/init.rs
+++ b/src/message/handshake/init.rs
@@ -37,7 +37,15 @@ impl Init {
handshake |= 0x02;
}
- return handshake.serialize().unwrap();
+ // Select Protocol 2: Datastream
+
+ let mut init: Vec<u8> = vec![];
+
+ // Add handshake and protocol to our buffer
+ init.extend(handshake.serialize().unwrap());
+ init.extend(crate::message::Protocol::Datastream.serialize());
+
+ return init;
}
pub fn parse(buf: &[u8]) -> Self {
diff --git a/src/message/handshake/mod.rs b/src/message/handshake/mod.rs
index 9b3bcee..9885012 100644
--- a/src/message/handshake/mod.rs
+++ b/src/message/handshake/mod.rs
@@ -21,3 +21,49 @@ pub use init::*;
pub use protocol::*;
pub use sessioninit::*;
pub use types::*;
+
+use crate::primitive::{Variant, VariantMap};
+use crate::{HandshakeDeserialize, HandshakeSerialize};
+
+#[derive(Debug, Clone)]
+pub enum HandshakeMessage {
+ ClientInit(ClientInit),
+ ClientInitAck(ClientInitAck),
+ ClientInitReject(ClientInitReject),
+ ClientLogin(ClientLogin),
+ ClientLoginAck,
+ ClientLoginReject(ClientLoginReject),
+ SessionInit(SessionInit),
+}
+
+impl HandshakeSerialize for HandshakeMessage {
+ fn serialize(&self) -> Result<Vec<u8>, failure::Error> {
+ match self {
+ HandshakeMessage::ClientInit(inner) => inner.serialize(),
+ HandshakeMessage::ClientInitAck(inner) => inner.serialize(),
+ HandshakeMessage::ClientInitReject(inner) => inner.serialize(),
+ HandshakeMessage::ClientLogin(inner) => inner.serialize(),
+ HandshakeMessage::ClientLoginAck => ClientLoginAck.serialize(),
+ HandshakeMessage::ClientLoginReject(inner) => inner.serialize(),
+ HandshakeMessage::SessionInit(inner) => inner.serialize(),
+ }
+ }
+}
+
+impl HandshakeDeserialize for HandshakeMessage {
+ fn parse(b: &[u8]) -> Result<(usize, Self), failure::Error> {
+ let (size, res) = VariantMap::parse(b)?;
+
+ let msgtype = match_variant!(&res["MsgType"], Variant::String);
+ match msgtype.as_str() {
+ "ClientInit" => Ok((size, HandshakeMessage::ClientInit(res.into()))),
+ "ClientInitAck" => Ok((size, HandshakeMessage::ClientInitAck(res.into()))),
+ "ClientInitReject" => Ok((size, HandshakeMessage::ClientInitReject(res.into()))),
+ "ClientLogin" => Ok((size, HandshakeMessage::ClientLogin(res.into()))),
+ "ClientLoginAck" => Ok((size, HandshakeMessage::ClientLoginAck)),
+ "ClientLoginReject" => Ok((size, HandshakeMessage::ClientLoginReject(res.into()))),
+ "SessionInit" => Ok((size, HandshakeMessage::SessionInit(res.into()))),
+ _ => unimplemented!(),
+ }
+ }
+}
diff --git a/src/message/handshake/sessioninit.rs b/src/message/handshake/sessioninit.rs
index eca4c10..d1b4b90 100644
--- a/src/message/handshake/sessioninit.rs
+++ b/src/message/handshake/sessioninit.rs
@@ -1,61 +1,81 @@
-use crate::error::ProtocolError;
-use crate::primitive::{Variant, VariantList, VariantMap};
-use crate::{HandshakeDeserialize, HandshakeSerialize};
+use crate::message::objects::Identity;
+use crate::primitive::{BufferInfo, Variant, VariantMap};
+use crate::HandshakeSerialize;
use failure::Error;
/// SessionInit is received along with ClientLoginAck to initialize that user Session
// TODO Replace with proper types
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct SessionInit {
/// List of all configured identities
- identities: VariantList,
+ pub identities: Vec<Identity>,
/// List of all existing buffers
- buffers: VariantList,
+ pub buffers: Vec<BufferInfo>,
/// Ids of all networks
- network_ids: VariantList,
+ pub network_ids: Vec<i32>,
+}
+
+impl From<VariantMap> for SessionInit {
+ fn from(input: VariantMap) -> Self {
+ let state = match_variant!(input.get("SessionState").unwrap(), Variant::VariantMap);
+ SessionInit {
+ identities: match_variant!(state.get("Identities").unwrap(), Variant::VariantList)
+ .iter()
+ .map(|ident| Identity::from(match_variant!(ident, Variant::VariantMap)))
+ .collect(),
+ buffers: match_variant!(state.get("BufferInfos").unwrap(), Variant::VariantList)
+ .iter()
+ .map(|buffer| match buffer {
+ Variant::BufferInfo(buffer) => buffer.clone(),
+ _ => unimplemented!(),
+ })
+ .collect(),
+ network_ids: match_variant!(state.get("NetworkIds").unwrap(), Variant::VariantList)
+ .iter()
+ .map(|network| match network {
+ Variant::i32(network) => network.clone(),
+ _ => unimplemented!(),
+ })
+ .collect(),
+ }
+ }
}
impl HandshakeSerialize for SessionInit {
fn serialize(&self) -> Result<Vec<u8>, Error> {
- let mut values: VariantMap = VariantMap::with_capacity(1);
+ let mut values: VariantMap = VariantMap::with_capacity(4);
values.insert(
"MsgType".to_string(),
Variant::String("SessionInit".to_string()),
);
values.insert(
"Identities".to_string(),
- Variant::VariantList(self.identities.clone()),
+ Variant::VariantList(
+ self.identities
+ .iter()
+ .map(|ident| Variant::VariantMap(ident.clone().into()))
+ .collect(),
+ ),
);
values.insert(
"BufferInfos".to_string(),
- Variant::VariantList(self.buffers.clone()),
+ Variant::VariantList(
+ self.buffers
+ .iter()
+ .map(|buffer| Variant::BufferInfo(buffer.clone()))
+ .collect(),
+ ),
);
values.insert(
"NetworkIds".to_string(),
- Variant::VariantList(self.network_ids.clone()),
+ Variant::VariantList(
+ self.network_ids
+ .iter()
+ .map(|id| Variant::i32(id.clone()))
+ .collect(),
+ ),
);
return HandshakeSerialize::serialize(&values);
}
}
-
-impl HandshakeDeserialize for SessionInit {
- fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
- let (len, values): (usize, VariantMap) = HandshakeDeserialize::parse(b)?;
-
- let msgtype = match_variant!(&values["MsgType"], Variant::StringUTF8);
-
- if msgtype == "ClientLogin" {
- return Ok((
- len,
- Self {
- identities: match_variant!(values["Identities"], Variant::VariantList),
- buffers: match_variant!(values["BufferInfos"], Variant::VariantList),
- network_ids: match_variant!(values["NetworkIds"], Variant::VariantList),
- },
- ));
- } else {
- bail!(ProtocolError::WrongMsgType);
- }
- }
-}
diff --git a/src/message/signalproxy/objects/identity.rs b/src/message/signalproxy/objects/identity.rs
new file mode 100644
index 0000000..a710e5d
--- /dev/null
+++ b/src/message/signalproxy/objects/identity.rs
@@ -0,0 +1,119 @@
+use crate::primitive::{Variant, VariantMap};
+
+#[derive(Debug, Clone)]
+pub struct Identity {
+ identity_id: i32,
+ identity_name: String,
+ real_name: String,
+ nicks: Vec<String>,
+ away_nick: String,
+ away_nick_enabled: bool,
+ away_reason: String,
+ away_reason_enabled: bool,
+ auto_away_enabled: bool,
+ auto_away_time: i32,
+ auto_away_reason: String,
+ auto_away_reason_enabled: bool,
+ detach_away_enabled: bool,
+ detach_away_reason: String,
+ detach_away_reason_enabled: bool,
+ ident: String,
+ kick_reason: String,
+ part_reason: String,
+ quit_reason: String,
+}
+
+impl From<VariantMap> for Identity {
+ fn from(input: VariantMap) -> Self {
+ Identity {
+ identity_id: match_variant!(input.get("identityId").unwrap(), Variant::i32),
+ identity_name: match_variant!(input.get("identityName").unwrap(), Variant::String),
+ real_name: match_variant!(input.get("realName").unwrap(), Variant::String),
+ nicks: match_variant!(input.get("nicks").unwrap(), Variant::StringList),
+ away_nick: match_variant!(input.get("awayNick").unwrap(), Variant::String),
+ away_nick_enabled: match_variant!(input.get("awayNickEnabled").unwrap(), Variant::bool),
+ away_reason: match_variant!(input.get("awayReason").unwrap(), Variant::String),
+ away_reason_enabled: match_variant!(
+ input.get("awayReasonEnabled").unwrap(),
+ Variant::bool
+ ),
+ auto_away_enabled: match_variant!(input.get("autoAwayEnabled").unwrap(), Variant::bool),
+ auto_away_time: match_variant!(input.get("autoAwayTime").unwrap(), Variant::i32),
+ auto_away_reason: match_variant!(input.get("autoAwayReason").unwrap(), Variant::String),
+ auto_away_reason_enabled: match_variant!(
+ input.get("autoAwayReasonEnabled").unwrap(),
+ Variant::bool
+ ),
+ detach_away_enabled: match_variant!(
+ input.get("detachAwayEnabled").unwrap(),
+ Variant::bool
+ ),
+ detach_away_reason: match_variant!(
+ input.get("detachAwayReason").unwrap(),
+ Variant::String
+ ),
+ detach_away_reason_enabled: match_variant!(
+ input.get("detachAwayReasonEnabled").unwrap(),
+ Variant::bool
+ ),
+ ident: match_variant!(input.get("ident").unwrap(), Variant::String),
+ kick_reason: match_variant!(input.get("kickReason").unwrap(), Variant::String),
+ part_reason: match_variant!(input.get("partReason").unwrap(), Variant::String),
+ quit_reason: match_variant!(input.get("quitReason").unwrap(), Variant::String),
+ }
+ }
+}
+
+impl Into<std::collections::HashMap<String, Variant>> for Identity {
+ fn into(self) -> VariantMap {
+ let mut res = VariantMap::with_capacity(19);
+
+ res.insert("identityId".to_string(), Variant::i32(self.identity_id));
+ res.insert(
+ "identityName".to_string(),
+ Variant::String(self.identity_name),
+ );
+ res.insert("realName".to_string(), Variant::String(self.real_name));
+ res.insert("nicks".to_string(), Variant::StringList(self.nicks));
+ res.insert("awayNick".to_string(), Variant::String(self.away_nick));
+ res.insert(
+ "awayNickEnabled".to_string(),
+ Variant::bool(self.away_nick_enabled),
+ );
+ res.insert("awayReason".to_string(), Variant::String(self.away_reason));
+ res.insert(
+ "awayReasonEnabled".to_string(),
+ Variant::bool(self.away_reason_enabled),
+ );
+ res.insert(
+ "autoAwayEnabled".to_string(),
+ Variant::bool(self.auto_away_enabled),
+ );
+ res.insert(
+ "autoAwayTime".to_string(),
+ Variant::i32(self.auto_away_time),
+ );
+ res.insert(
+ "autoAwayReason".to_string(),
+ Variant::String(self.auto_away_reason),
+ );
+ res.insert(
+ "detachAwayEnabled".to_string(),
+ Variant::bool(self.detach_away_enabled),
+ );
+ res.insert(
+ "detachAwayReason".to_string(),
+ Variant::String(self.detach_away_reason),
+ );
+ res.insert(
+ "detachAwayReasonEnabled".to_string(),
+ Variant::bool(self.detach_away_reason_enabled),
+ );
+ res.insert("ident".to_string(), Variant::String(self.ident));
+ res.insert("kickReason".to_string(), Variant::String(self.kick_reason));
+ res.insert("partReason".to_string(), Variant::String(self.part_reason));
+ res.insert("quitReason".to_string(), Variant::String(self.quit_reason));
+
+ res
+ }
+}
diff --git a/src/primitive/datetime.rs b/src/primitive/datetime.rs
index cbcdd51..f3ace1d 100644
--- a/src/primitive/datetime.rs
+++ b/src/primitive/datetime.rs
@@ -79,7 +79,7 @@ impl Deserialize for OffsetDateTime {
let offset: UtcOffset;
match zone {
TimeSpec::LocalUnknown | TimeSpec::LocalStandard | TimeSpec::LocalDST => {
- offset = UtcOffset::current_local_offset()
+ offset = UtcOffset::try_current_local_offset()?
}
TimeSpec::UTC => offset = UtcOffset::UTC,
TimeSpec::OffsetFromUTC => {