aboutsummaryrefslogtreecommitdiffstats
path: root/filamento/src/logic/online.rs
diff options
context:
space:
mode:
Diffstat (limited to 'filamento/src/logic/online.rs')
-rw-r--r--filamento/src/logic/online.rs82
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(())
}