xmpp/pubsub/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
// Copyright (c) 2019 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use super::Agent;
use crate::Event;
use std::str::FromStr;
use tokio_xmpp::{
connect::ServerConnector,
jid::{BareJid, Jid},
minidom::Element,
parsers::{
bookmarks2, ns,
pubsub::{event::PubSubEvent, pubsub::PubSub},
},
};
#[cfg(feature = "avatars")]
pub(crate) mod avatar;
pub(crate) async fn handle_event<C: ServerConnector>(
#[cfg_attr(not(feature = "avatars"), allow(unused_variables))] from: &Jid,
elem: Element,
#[cfg_attr(not(feature = "avatars"), allow(unused_variables))] agent: &mut Agent<C>,
) -> Vec<Event> {
// We allow the useless mut warning for no-default-features,
// since for now only avatars pushes events here.
#[allow(unused_mut)]
let mut events = Vec::new();
let event = PubSubEvent::try_from(elem);
trace!("PubSub event: {:#?}", event);
match event {
Ok(PubSubEvent::PublishedItems { node, items }) => {
match node.0 {
#[cfg(feature = "avatars")]
ref node if node == ns::AVATAR_METADATA => {
let new_events =
avatar::handle_metadata_pubsub_event(&from, agent, items).await;
events.extend(new_events);
}
ref node if node == ns::BOOKMARKS2 => {
// TODO: Check that our bare JID is the sender.
assert_eq!(items.len(), 1);
let item = items.clone().pop().unwrap();
let jid = BareJid::from_str(&item.id.clone().unwrap().0).unwrap();
let payload = item.payload.clone().unwrap();
match bookmarks2::Conference::try_from(payload) {
Ok(conference) => {
if conference.autojoin {
if !agent.rooms_joined.contains_key(&jid) {
agent
.join_room(
jid.clone(),
conference.nick,
conference.password,
"",
"",
)
.await;
}
} else {
// So maybe another client of ours left the room... let's leave it too
agent.leave_room(jid.clone(), "", "").await;
}
}
Err(err) => println!("not bookmark: {}", err),
}
}
ref node => unimplemented!("node {}", node),
}
}
Ok(PubSubEvent::RetractedItems { node, items }) => {
match node.0 {
ref node if node == ns::BOOKMARKS2 => {
// TODO: Check that our bare JID is the sender.
assert_eq!(items.len(), 1);
let item = items.clone().pop().unwrap();
let jid = BareJid::from_str(&item.0).unwrap();
agent.leave_room(jid.clone(), "", "").await;
}
ref node => unimplemented!("node {}", node),
}
}
Ok(PubSubEvent::Purge { node }) => match node.0 {
ref node if node == ns::BOOKMARKS2 => {
warn!("The bookmarks2 PEP node was deleted!");
}
ref node => unimplemented!("node {}", node),
},
Err(e) => {
error!("Error parsing PubSub event: {}", e);
}
_ => unimplemented!("PubSub event: {:#?}", event),
}
events
}
pub(crate) async fn handle_iq_result<C: ServerConnector>(
#[cfg_attr(not(feature = "avatars"), allow(unused_variables))] from: &Jid,
elem: Element,
agent: &mut Agent<C>,
) -> impl IntoIterator<Item = Event> {
// We allow the useless mut warning for no-default-features,
// since for now only avatars pushes events here.
#[allow(unused_mut)]
let mut events = Vec::new();
let pubsub = PubSub::try_from(elem).unwrap();
trace!("PubSub: {:#?}", pubsub);
if let PubSub::Items(items) = pubsub {
match items.node.0.clone() {
#[cfg(feature = "avatars")]
ref node if node == ns::AVATAR_DATA => {
let new_events = avatar::handle_data_pubsub_iq(&from, &items);
events.extend(new_events);
}
ref node if node == ns::BOOKMARKS2 => {
// Keep track of the new added/removed rooms in the bookmarks2 list.
// The rooms we joined which are no longer in the list should be left ASAP.
let mut new_room_list: Vec<BareJid> = Vec::new();
for item in items.items {
let item = item.0;
let jid = BareJid::from_str(&item.id.clone().unwrap().0).unwrap();
let payload = item.payload.clone().unwrap();
match bookmarks2::Conference::try_from(payload) {
Ok(conference) => {
// This room was either marked for join or leave, but it was still in the bookmarks.
// Keep track in new_room_list.
new_room_list.push(jid.clone());
if conference.autojoin {
if !agent.rooms_joined.contains_key(&jid) {
agent
.join_room(
jid.clone(),
conference.nick,
conference.password,
"",
"",
)
.await;
}
} else {
// Leave the room that is no longer autojoin
agent.leave_room(jid.clone(), "", "").await;
}
}
Err(err) => {
warn!("Wrong payload type in bookmarks2 item: {}", err);
}
}
}
// Now we leave the rooms that are no longer in the bookmarks
let mut rooms_to_leave: Vec<BareJid> = Vec::new();
for (room, _nick) in &agent.rooms_joined {
if !new_room_list.contains(&room) {
rooms_to_leave.push(room.clone());
}
}
for room in rooms_to_leave {
agent.leave_room(room, "", "").await;
}
}
_ => unimplemented!(),
}
}
events
}