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
// 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,
    parsers::{
        bookmarks2::{self, Autojoin},
        ns,
        pubsub::event::{PubSubEvent, PubSubEventItems},
        pubsub::pubsub::PubSub,
        BareJid, Element, Jid,
    },
};

#[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> {
    let mut events = Vec::new();
    let event = PubSubEvent::try_from(elem);
    trace!("PubSub event: {:#?}", event);
    match event {
        Ok(PubSubEvent::Items {
            node,
            items: PubSubEventItems::Published(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 == Autojoin::True {
                                events.push(Event::JoinRoom(jid, conference));
                            } else {
                                events.push(Event::LeaveRoom(jid));
                            }
                        }
                        Err(err) => println!("not bookmark: {}", err),
                    }
                }
                ref node => unimplemented!("node {}", node),
            }
        }
        Ok(PubSubEvent::Items {
            node,
            items: PubSubEventItems::Retracted(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();
                    events.push(Event::LeaveRoom(jid));
                }
                ref node => unimplemented!("node {}", node),
            }
        }
        Ok(PubSubEvent::Purge { node }) => {
            match node.0 {
                ref node if node == ns::BOOKMARKS2 => {
                    // TODO: Check that our bare JID is the sender.
                    events.push(Event::LeaveAllRooms);
                }
                ref node => unimplemented!("node {}", node),
            }
        }
        Err(e) => {
            error!("Error parsing PubSub event: {}", e);
        }
        _ => unimplemented!("PubSub event: {:#?}", event),
    }
    events
}

pub(crate) fn handle_iq_result(
    #[cfg_attr(not(feature = "avatars"), allow(unused_variables))] from: &Jid,
    elem: Element,
) -> impl IntoIterator<Item = Event> {
    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 => {
                events.push(Event::LeaveAllRooms);
                for item in items.items {
                    let item = item;
                    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 let Autojoin::True = conference.autojoin {
                                events.push(Event::JoinRoom(jid, conference));
                            }
                        }
                        Err(err) => panic!("Wrong payload type in bookmarks 2 item: {}", err),
                    }
                }
            }
            _ => unimplemented!(),
        }
    }
    events
}