1use super::Agent;
8use crate::Event;
9use std::fs::{self, File};
10use std::io::{self, Write};
11use tokio_xmpp::parsers::{
12 avatar::{Data, Metadata},
13 iq::Iq,
14 jid::Jid,
15 ns,
16 pubsub::{
17 event::Item,
18 pubsub::{Items, PubSub},
19 NodeName,
20 },
21};
22
23pub(crate) async fn handle_metadata_pubsub_event(
24 from: &Jid,
25 agent: &mut Agent,
26 items: Vec<Item>,
27) -> Vec<Event> {
28 let mut events = Vec::new();
29 for item in items {
30 let payload = item.payload.clone().unwrap();
31 if payload.is("metadata", ns::AVATAR_METADATA) {
32 match Metadata::try_from(payload) {
33 Ok(metadata) => {
34 for info in metadata.infos {
35 let filename = format!("data/{}/{}", from, &*info.id.to_hex());
36 let file_length = match fs::metadata(filename.clone()) {
37 Ok(metadata) => metadata.len(),
38 Err(_) => 0,
39 };
40 if info.bytes as u64 == file_length {
42 events.push(Event::AvatarRetrieved(from.clone(), filename));
43 } else {
44 let iq = download_avatar(from);
45 let _ = agent.client.send_stanza(iq.into()).await;
46 }
47 }
48 }
49
50 Err(e) => error!("Error parsing avatar metadata: {}", e),
51 }
52 }
53 }
54 events
55}
56
57fn download_avatar(from: &Jid) -> Iq {
58 Iq::from_get(
59 "coucou",
60 PubSub::Items(Items {
61 max_items: None,
62 node: NodeName(String::from(ns::AVATAR_DATA)),
63 subid: None,
64 items: Vec::new(),
65 }),
66 )
67 .with_to(from.clone())
68}
69
70pub(crate) fn handle_data_pubsub_iq<'a>(
73 from: &'a Jid,
74 items: &'a Items,
75) -> impl IntoIterator<Item = Event> + 'a {
76 let from = from.clone();
77 items
78 .items
79 .iter()
80 .filter_map(move |item| match (&item.id, &item.payload) {
81 (Some(id), Some(payload)) => {
82 let data = Data::try_from(payload.clone()).unwrap();
83 let filename = save_avatar(&from, id.0.clone(), &data.data).unwrap();
84 Some(Event::AvatarRetrieved(from.clone(), filename))
85 }
86 _ => None,
87 })
88}
89
90fn save_avatar(from: &Jid, id: String, data: &[u8]) -> io::Result<String> {
91 let directory = format!("data/{}", from);
92 let filename = format!("data/{}/{}", from, id);
93 fs::create_dir_all(directory)?;
94 let mut file = File::create(&filename)?;
95 file.write_all(data)?;
96 Ok(filename)
97}