forked from lavina/lavina
1
0
Fork 0

xmpp: add support leaving MUCs via unavailable presence

This commit is contained in:
Nikita Vilunov 2024-05-26 18:18:30 +02:00
parent f02971d407
commit fe802aca26
1 changed files with 80 additions and 31 deletions

View File

@ -23,9 +23,39 @@ impl<'a> XmppConnection<'a> {
server, server,
// resources in MUCs are members' personas not implemented (yet?) // resources in MUCs are members' personas not implemented (yet?)
resource: Some(_), 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?; 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::<()> { let subject = Message::<()> {
from: Some(Jid { from: Some(Jid {
name: Some(name.clone()), name: Some(name.clone()),
@ -44,21 +74,40 @@ impl<'a> XmppConnection<'a> {
body: None, body: None,
custom: vec![], 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); subject.serialize(output);
Ok(())
} }
_ => {
// TODO other presence cases async fn leave_muc(&mut self, output: &mut Vec<Event<'static>>, id: Option<String>, name: Name) -> Result<()> {
let response = Presence::<()>::default(); self.user_handle.leave_room(RoomId::try_from(name.0.clone())?).await?;
let response = Presence {
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); response.serialize(output);
}
}
Ok(()) Ok(())
} }
@ -92,7 +141,7 @@ impl<'a> XmppConnection<'a> {
#[tracing::instrument(skip(self), name = "XmppConnection::retrieve_muc_presence")] #[tracing::instrument(skip(self), name = "XmppConnection::retrieve_muc_presence")]
async fn retrieve_muc_presence(&mut self, name: &Name) -> Result<Presence<XUser>> { 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 // TODO handle bans
let response = Presence { let response = Presence {
to: Some(Jid { to: Some(Jid {