xmpp: add support leaving MUCs via unavailable presence (#71)

Reviewed-on: lavina/lavina#71
This commit is contained in:
Nikita Vilunov 2024-05-27 14:24:23 +00:00
parent 43d105ab23
commit 1a21c05d7d
1 changed files with 80 additions and 30 deletions

View File

@ -23,9 +23,39 @@ impl<'a> XmppConnection<'a> {
server,
// resources in MUCs are members' personas not implemented (yet?)
resource: Some(_),
}) if server.0 == self.hostname_rooms => {
}) if server.0 == self.hostname_rooms => match p.r#type.as_deref() {
None => {
self.join_muc(output, p.id, name).await?;
}
Some("unavailable") => {
self.leave_muc(output, p.id, name).await?;
}
_ => {
tracing::error!("Unimplemented case")
}
},
_ => {
// TODO other presence cases
let response = Presence::<()>::default();
response.serialize(output);
}
}
Ok(())
}
async fn join_muc(&mut self, output: &mut Vec<Event<'static>>, id: Option<String>, name: Name) -> Result<()> {
// Response presence
let mut muc_presence = self.retrieve_muc_presence(&name).await?;
muc_presence.id = p.id;
muc_presence.id = id;
muc_presence.serialize(output);
// N last messages from the room history before the user joined
let messages = self.retrieve_message_history(&name).await?;
for message in messages {
message.serialize(output)
}
// The subject is the last stanza sent during a MUC join process.
let subject = Message::<()> {
from: Some(Jid {
name: Some(name.clone()),
@ -44,21 +74,41 @@ impl<'a> XmppConnection<'a> {
body: None,
custom: vec![],
};
muc_presence.serialize(output);
let messages = self.retrieve_message_history(&name).await?;
for message in messages {
message.serialize(output)
}
// The subject is the last stanza sent during a MUC join process.
subject.serialize(output);
Ok(())
}
_ => {
// TODO other presence cases
let response = Presence::<()>::default();
async fn leave_muc(&mut self, output: &mut Vec<Event<'static>>, id: Option<String>, name: Name) -> Result<()> {
self.user_handle.leave_room(RoomId::try_from(name.0.clone())?).await?;
let response = Presence {
id,
to: Some(Jid {
name: Some(self.user.xmpp_name.clone()),
server: Server(self.hostname.clone()),
resource: Some(self.user.xmpp_resource.clone()),
}),
from: Some(Jid {
name: Some(name.clone()),
server: Server(self.hostname_rooms.clone()),
resource: Some(self.user.xmpp_muc_name.clone()),
}),
r#type: Some("unavailable".into()),
custom: vec![XUser {
item: XUserItem {
affiliation: Affiliation::Member,
role: Role::None,
jid: Jid {
name: Some(self.user.xmpp_name.clone()),
server: Server(self.hostname.clone()),
resource: Some(self.user.xmpp_resource.clone()),
},
},
self_presence: true,
just_created: false,
}],
..Default::default()
};
response.serialize(output);
}
}
Ok(())
}
@ -92,7 +142,7 @@ impl<'a> XmppConnection<'a> {
#[tracing::instrument(skip(self), name = "XmppConnection::retrieve_muc_presence")]
async fn retrieve_muc_presence(&mut self, name: &Name) -> Result<Presence<XUser>> {
let a = self.user_handle.join_room(RoomId::try_from(name.0.clone())?).await?;
let _ = self.user_handle.join_room(RoomId::try_from(name.0.clone())?).await?;
// TODO handle bans
let response = Presence {
to: Some(Jid {