forked from lavina/lavina
send subject
This commit is contained in:
parent
3724465c72
commit
dd33b41beb
|
@ -20,7 +20,8 @@ impl<'a> XmppConnection<'a> {
|
|||
}) = m.to
|
||||
{
|
||||
if server.0.as_ref() == &*self.hostname_rooms && m.r#type == MessageType::Groupchat {
|
||||
self.user_handle.send_message(RoomId::from(name.0.clone())?, m.body.clone().into()).await?;
|
||||
let Some(body) = &m.body else { return Ok(()) };
|
||||
self.user_handle.send_message(RoomId::from(name.0.clone())?, body.clone()).await?;
|
||||
Message::<()> {
|
||||
to: Some(Jid {
|
||||
name: Some(self.user.xmpp_name.clone()),
|
||||
|
@ -42,7 +43,8 @@ impl<'a> XmppConnection<'a> {
|
|||
.serialize(output);
|
||||
Ok(())
|
||||
} else if server.0.as_ref() == &*self.hostname && m.r#type == MessageType::Chat {
|
||||
self.user_handle.send_dialog_message(PlayerId::from(name.0.clone())?, m.body.clone()).await?;
|
||||
let Some(body) = &m.body else { return Ok(()) };
|
||||
self.user_handle.send_dialog_message(PlayerId::from(name.0.clone())?, body.clone()).await?;
|
||||
Ok(())
|
||||
} else {
|
||||
todo!()
|
||||
|
|
|
@ -5,8 +5,8 @@ use quick_xml::events::Event;
|
|||
|
||||
use lavina_core::room::RoomId;
|
||||
use proto_xmpp::bind::{Jid, Name, Server};
|
||||
use proto_xmpp::client::Presence;
|
||||
use proto_xmpp::muc::XUser;
|
||||
use proto_xmpp::client::{Message, MessageType, Presence, Subject};
|
||||
use proto_xmpp::muc::{Affiliation, Role, XUser, XUserItem};
|
||||
use proto_xmpp::xml::{Ignore, ToXml};
|
||||
|
||||
use crate::XmppConnection;
|
||||
|
@ -23,8 +23,28 @@ impl<'a> XmppConnection<'a> {
|
|||
// resources in MUCs are members' personas – not implemented (yet?)
|
||||
resource: Some(_),
|
||||
}) if server.0 == self.hostname_rooms => {
|
||||
let response = self.muc_presence(&name).await?;
|
||||
let mut response = self.muc_presence(&name).await?;
|
||||
response.id = p.id;
|
||||
let subject = Message::<()> {
|
||||
from: Some(Jid {
|
||||
name: Some(name),
|
||||
server: Server(self.hostname_rooms.clone()),
|
||||
resource: None,
|
||||
}),
|
||||
id: None,
|
||||
to: Some(Jid {
|
||||
name: Some(self.user.xmpp_name.clone()),
|
||||
server: Server(self.hostname.clone()),
|
||||
resource: Some(self.user.xmpp_resource.clone()),
|
||||
}),
|
||||
r#type: MessageType::Groupchat,
|
||||
lang: None,
|
||||
subject: Some(Subject(None)),
|
||||
body: None,
|
||||
custom: vec![],
|
||||
};
|
||||
response.serialize(output);
|
||||
subject.serialize(output);
|
||||
}
|
||||
_ => {
|
||||
// TODO other presence cases
|
||||
|
@ -56,7 +76,9 @@ impl<'a> XmppConnection<'a> {
|
|||
};
|
||||
response.serialize(output);
|
||||
}
|
||||
_ => todo!(),
|
||||
e => {
|
||||
tracing::error!("TODO: unknown presence type: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +97,17 @@ impl<'a> XmppConnection<'a> {
|
|||
server: Server(self.hostname_rooms.clone()),
|
||||
resource: Some(self.user.xmpp_muc_name.clone()),
|
||||
}),
|
||||
custom: vec![XUser],
|
||||
custom: vec![XUser {
|
||||
item: XUserItem {
|
||||
affiliation: Affiliation::Member,
|
||||
role: Role::Participant,
|
||||
jid: Jid {
|
||||
name: Some(self.user.xmpp_name.clone()),
|
||||
server: Server(self.hostname.clone()),
|
||||
resource: Some(self.user.xmpp_resource.clone()),
|
||||
},
|
||||
},
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
Ok(response)
|
||||
|
|
|
@ -20,8 +20,8 @@ pub struct Message<T> {
|
|||
// default is Normal
|
||||
pub r#type: MessageType,
|
||||
pub lang: Option<Str>,
|
||||
pub subject: Option<Str>,
|
||||
pub body: Str,
|
||||
pub subject: Option<Subject>,
|
||||
pub body: Option<Str>,
|
||||
pub custom: Vec<T>,
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,20 @@ impl<T: FromXml> FromXml for Message<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct Subject(pub Option<Str>);
|
||||
impl ToXml for Subject {
|
||||
fn serialize(&self, events: &mut Vec<Event<'static>>) {
|
||||
if let Some(ref s) = self.0 {
|
||||
events.push(Event::Start(BytesStart::new("subject")));
|
||||
events.push(Event::Text(BytesText::new(s).into_owned()));
|
||||
events.push(Event::End(BytesEnd::new("subject")));
|
||||
} else {
|
||||
events.push(Event::Empty(BytesStart::new("subject")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
struct MessageParser<T: FromXml>(MessageParserInner<T>);
|
||||
|
||||
|
@ -57,7 +71,7 @@ struct MessageParserState<T> {
|
|||
to: Option<Jid>,
|
||||
r#type: MessageType,
|
||||
lang: Option<Str>,
|
||||
subject: Option<Str>,
|
||||
subject: Option<Subject>,
|
||||
body: Option<Str>,
|
||||
custom: Vec<T>,
|
||||
}
|
||||
|
@ -130,7 +144,7 @@ impl<T: FromXml> Parser for MessageParser<T> {
|
|||
r#type: state.r#type,
|
||||
lang: state.lang,
|
||||
subject: state.subject,
|
||||
body,
|
||||
body: Some(body),
|
||||
custom: state.custom,
|
||||
}))
|
||||
} else {
|
||||
|
@ -153,7 +167,7 @@ impl<T: FromXml> Parser for MessageParser<T> {
|
|||
InSubject(mut state) => match event {
|
||||
Event::Text(ref bytes) => {
|
||||
let subject = fail_fast!(std::str::from_utf8(&*bytes));
|
||||
state.subject = Some(subject.into());
|
||||
state.subject = Some(Subject(Some(subject.into())));
|
||||
Continuation::Continue(InSubject(state).into())
|
||||
}
|
||||
Event::End(_) => Continuation::Continue(Outer(state).into()),
|
||||
|
@ -208,9 +222,14 @@ impl<T: ToXml> ToXml for Message<T> {
|
|||
value: self.r#type.as_str().as_bytes().into(),
|
||||
});
|
||||
events.push(Event::Start(bytes));
|
||||
if let Some(subject) = &self.subject {
|
||||
subject.serialize(events);
|
||||
}
|
||||
if let Some(body) = &self.body {
|
||||
events.push(Event::Start(BytesStart::new("body")));
|
||||
events.push(Event::Text(BytesText::new(&self.body).into_owned()));
|
||||
events.push(Event::Text(BytesText::new(body).into_owned()));
|
||||
events.push(Event::End(BytesEnd::new("body")));
|
||||
}
|
||||
events.push(Event::End(BytesEnd::new("message")));
|
||||
}
|
||||
}
|
||||
|
@ -577,7 +596,7 @@ impl<T: FromXml> FromXml for Presence<T> {
|
|||
}
|
||||
b"id" => {
|
||||
let s = std::str::from_utf8(&attr.value)?;
|
||||
p.r#type = Option::from(s.to_string());
|
||||
p.id = Option::from(s.to_string());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use quick_xml::events::{BytesEnd, BytesStart, Event};
|
||||
use quick_xml::name::ResolveResult;
|
||||
|
||||
use crate::bind::Jid;
|
||||
use crate::xml::*;
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
|
@ -145,31 +146,94 @@ impl FromXml for X {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct XUser;
|
||||
pub struct XUser {
|
||||
pub item: XUserItem,
|
||||
}
|
||||
impl ToXml for XUser {
|
||||
fn serialize(&self, output: &mut Vec<Event<'static>>) {
|
||||
let mut tag = BytesStart::new("x");
|
||||
tag.push_attribute(("xmlns", XMLNS_USER));
|
||||
output.push(Event::Start(tag));
|
||||
|
||||
let mut meg = BytesStart::new("item");
|
||||
meg.push_attribute(("affiliation", "owner"));
|
||||
meg.push_attribute(("role", "moderator"));
|
||||
meg.push_attribute(("jid", "sauer@localhost"));
|
||||
output.push(Event::Empty(meg));
|
||||
|
||||
let mut veg = BytesStart::new("status");
|
||||
veg.push_attribute(("code", "100"));
|
||||
output.push(Event::Empty(veg));
|
||||
|
||||
let mut veg = BytesStart::new("status");
|
||||
veg.push_attribute(("code", "110"));
|
||||
output.push(Event::Empty(veg));
|
||||
|
||||
self.item.serialize(output);
|
||||
output.push(Event::End(BytesEnd::new("x")));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct XUserItem {
|
||||
pub affiliation: Affiliation,
|
||||
pub jid: Jid,
|
||||
pub role: Role,
|
||||
}
|
||||
impl ToXml for XUserItem {
|
||||
fn serialize(&self, output: &mut Vec<Event<'static>>) {
|
||||
let mut meg = BytesStart::new("item");
|
||||
meg.push_attribute(("affiliation", self.affiliation.to_str()));
|
||||
meg.push_attribute(("role", self.role.to_str()));
|
||||
meg.push_attribute(("jid", self.jid.to_string().as_str()));
|
||||
output.push(Event::Empty(meg));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Affiliation {
|
||||
Owner,
|
||||
Admin,
|
||||
Member,
|
||||
Outcast,
|
||||
None,
|
||||
}
|
||||
impl Affiliation {
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"owner" => Some(Self::Owner),
|
||||
"admin" => Some(Self::Admin),
|
||||
"member" => Some(Self::Member),
|
||||
"outcast" => Some(Self::Outcast),
|
||||
"none" => Some(Self::None),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Owner => "owner",
|
||||
Self::Admin => "admin",
|
||||
Self::Member => "member",
|
||||
Self::Outcast => "outcast",
|
||||
Self::None => "none",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Role {
|
||||
Moderator,
|
||||
Participant,
|
||||
Visitor,
|
||||
None,
|
||||
}
|
||||
impl Role {
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"moderator" => Some(Self::Moderator),
|
||||
"participant" => Some(Self::Participant),
|
||||
"visitor" => Some(Self::Visitor),
|
||||
"none" => Some(Self::None),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Moderator => "moderator",
|
||||
Self::Participant => "participant",
|
||||
Self::Visitor => "visitor",
|
||||
Self::None => "none",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in New Issue