diff options
Diffstat (limited to 'filamento/src/logic/online.rs')
-rw-r--r-- | filamento/src/logic/online.rs | 82 |
1 files changed, 79 insertions, 3 deletions
diff --git a/filamento/src/logic/online.rs b/filamento/src/logic/online.rs index 05d3f2b..c76907b 100644 --- a/filamento/src/logic/online.rs +++ b/filamento/src/logic/online.rs @@ -4,18 +4,20 @@ use lampada::{Connected, WriteMessage, error::WriteError}; use stanza::{ client::{ Stanza, - iq::{self, Iq, IqType}, + iq::{self, Iq, IqType, Query}, }, + xep_0030::info, xep_0203::Delay, }; use tokio::sync::oneshot; -use tracing::{debug, info}; +use tracing::{debug, error, info}; use uuid::Uuid; use crate::{ Command, UpdateMessage, chat::{Body, Message}, - error::{DatabaseError, Error, MessageSendError, RosterError, StatusError}, + disco::Info, + error::{DatabaseError, DiscoError, Error, MessageSendError, RosterError, StatusError}, presence::{Online, Presence, PresenceType}, roster::{Contact, ContactUpdate}, }; @@ -532,6 +534,76 @@ pub async fn handle_send_presence( Ok(()) } +// TODO: cache disco infos +pub async fn handle_disco_info( + logic: &ClientLogic, + connection: Connected, + jid: Option<JID>, +) -> Result<Info, DiscoError> { + let id = Uuid::new_v4().to_string(); + let request = Iq { + from: Some(connection.jid().clone()), + id: id.clone(), + to: jid.clone(), + r#type: IqType::Get, + lang: None, + query: Some(Query::DiscoInfo(info::Query { + node: None, + features: Vec::new(), + identities: Vec::new(), + })), + errors: Vec::new(), + }; + match logic + .pending() + .request(&connection, Stanza::Iq(request), id) + .await? + { + Stanza::Iq(Iq { + from, + r#type, + query, + mut errors, + .. + // TODO: maybe abstract a bunch of these different errors related to iqs into an iq error thing? as in like call iq.result(), get the query from inside, error otherwise. + }) if r#type == IqType::Result || r#type == IqType::Error => { + if from == jid || { + if jid == None { + from == Some(connection.jid().as_bare()) + } else { + false + } + } { + match r#type { + IqType::Result => { + if let Some(query) = query { + match query { + Query::DiscoInfo(info) => Ok(info.into()), + q => Err(DiscoError::MismatchedQuery(q)), + } + } else { + Err(DiscoError::MissingQuery) + } + } + IqType::Error => { + if let Some(error) = errors.pop() { + Err(error.into()) + } else { + Err(DiscoError::MissingError) + } + } + _ => unreachable!(), + } + } else { + Err(DiscoError::IncorrectEntity( + from.unwrap_or_else(|| connection.jid().as_bare()), + )) + } + } + s => Err(DiscoError::UnexpectedStanza(s)), + } +} + // TODO: could probably macro-ise? pub async fn handle_online_result( logic: &ClientLogic, @@ -629,6 +701,10 @@ pub async fn handle_online_result( let result = handle_send_presence(connection, jid, presence).await; let _ = sender.send(result); } + Command::DiscoInfo(jid, sender) => { + let result = handle_disco_info(logic, connection, jid).await; + let _ = sender.send(result); + } } Ok(()) } |