mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
add an ibb plugin
This commit is contained in:
parent
64c8027936
commit
1378ca3724
3 changed files with 178 additions and 0 deletions
|
@ -6,6 +6,7 @@ use xmpp::plugins::stanza::StanzaPlugin;
|
||||||
use xmpp::plugins::unhandled_iq::UnhandledIqPlugin;
|
use xmpp::plugins::unhandled_iq::UnhandledIqPlugin;
|
||||||
use xmpp::plugins::messaging::{MessagingPlugin, MessageEvent};
|
use xmpp::plugins::messaging::{MessagingPlugin, MessageEvent};
|
||||||
use xmpp::plugins::presence::{PresencePlugin, Type};
|
use xmpp::plugins::presence::{PresencePlugin, Type};
|
||||||
|
use xmpp::plugins::ibb::IbbPlugin;
|
||||||
use xmpp::plugins::ping::{PingPlugin, PingEvent};
|
use xmpp::plugins::ping::{PingPlugin, PingEvent};
|
||||||
use xmpp::event::{Priority, Propagation};
|
use xmpp::event::{Priority, Propagation};
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ fn main() {
|
||||||
client.register_plugin(UnhandledIqPlugin::new());
|
client.register_plugin(UnhandledIqPlugin::new());
|
||||||
client.register_plugin(MessagingPlugin::new());
|
client.register_plugin(MessagingPlugin::new());
|
||||||
client.register_plugin(PresencePlugin::new());
|
client.register_plugin(PresencePlugin::new());
|
||||||
|
client.register_plugin(IbbPlugin::new());
|
||||||
client.register_plugin(PingPlugin::new());
|
client.register_plugin(PingPlugin::new());
|
||||||
client.register_handler(Priority::Max, |e: &MessageEvent| {
|
client.register_handler(Priority::Max, |e: &MessageEvent| {
|
||||||
println!("{:?}", e);
|
println!("{:?}", e);
|
||||||
|
|
175
src/plugins/ibb.rs
Normal file
175
src/plugins/ibb.rs
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
use std::collections::{HashMap, BTreeMap};
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::sync::{Mutex, Arc};
|
||||||
|
|
||||||
|
use plugin::PluginProxy;
|
||||||
|
use event::{Event, Priority, Propagation};
|
||||||
|
use jid::Jid;
|
||||||
|
|
||||||
|
use plugins::stanza::Iq;
|
||||||
|
use xmpp_parsers::iq::{IqType, IqPayload};
|
||||||
|
use xmpp_parsers::ibb::{IBB, Stanza};
|
||||||
|
use xmpp_parsers::stanza_error::{StanzaError, ErrorType, DefinedCondition};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Session {
|
||||||
|
stanza: Stanza,
|
||||||
|
block_size: u16,
|
||||||
|
cur_seq: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IbbOpen {
|
||||||
|
pub session: Session,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IbbData {
|
||||||
|
pub session: Session,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IbbClose {
|
||||||
|
pub session: Session,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event for IbbOpen {}
|
||||||
|
impl Event for IbbData {}
|
||||||
|
impl Event for IbbClose {}
|
||||||
|
|
||||||
|
fn generate_error(type_: ErrorType, defined_condition: DefinedCondition, text: &str) -> StanzaError {
|
||||||
|
StanzaError {
|
||||||
|
type_: type_,
|
||||||
|
defined_condition: defined_condition,
|
||||||
|
texts: {
|
||||||
|
let mut texts = BTreeMap::new();
|
||||||
|
texts.insert(String::new(), String::from(text));
|
||||||
|
texts
|
||||||
|
},
|
||||||
|
by: None,
|
||||||
|
other: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IbbPlugin {
|
||||||
|
proxy: PluginProxy,
|
||||||
|
sessions: Arc<Mutex<HashMap<(Jid, String), Session>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IbbPlugin {
|
||||||
|
pub fn new() -> IbbPlugin {
|
||||||
|
IbbPlugin {
|
||||||
|
proxy: PluginProxy::new(),
|
||||||
|
sessions: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ibb(&self, from: Jid, ibb: IBB) -> Result<(), StanzaError> {
|
||||||
|
let mut sessions = self.sessions.lock().unwrap();
|
||||||
|
match ibb {
|
||||||
|
IBB::Open { block_size, sid, stanza } => {
|
||||||
|
match sessions.entry((from.clone(), sid.clone())) {
|
||||||
|
Entry::Vacant(_) => Ok(()),
|
||||||
|
Entry::Occupied(_) => Err(generate_error(
|
||||||
|
ErrorType::Cancel,
|
||||||
|
DefinedCondition::NotAcceptable,
|
||||||
|
"This session is already open."
|
||||||
|
)),
|
||||||
|
}?;
|
||||||
|
let session = Session {
|
||||||
|
stanza,
|
||||||
|
block_size,
|
||||||
|
cur_seq: 65535u16,
|
||||||
|
};
|
||||||
|
sessions.insert((from, sid), session.clone());
|
||||||
|
self.proxy.dispatch(IbbOpen {
|
||||||
|
session: session,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
IBB::Data { seq, sid, data } => {
|
||||||
|
let entry = match sessions.entry((from, sid)) {
|
||||||
|
Entry::Occupied(entry) => Ok(entry),
|
||||||
|
Entry::Vacant(_) => Err(generate_error(
|
||||||
|
ErrorType::Cancel,
|
||||||
|
DefinedCondition::ItemNotFound,
|
||||||
|
"This session doesn’t exist."
|
||||||
|
)),
|
||||||
|
}?;
|
||||||
|
let mut session = entry.into_mut();
|
||||||
|
if session.stanza != Stanza::Iq {
|
||||||
|
return Err(generate_error(
|
||||||
|
ErrorType::Cancel,
|
||||||
|
DefinedCondition::NotAcceptable,
|
||||||
|
"Wrong stanza type."
|
||||||
|
))
|
||||||
|
}
|
||||||
|
let cur_seq = session.cur_seq.wrapping_add(1);
|
||||||
|
if seq != cur_seq {
|
||||||
|
return Err(generate_error(
|
||||||
|
ErrorType::Cancel,
|
||||||
|
DefinedCondition::NotAcceptable,
|
||||||
|
"Wrong seq number."
|
||||||
|
))
|
||||||
|
}
|
||||||
|
session.cur_seq = cur_seq;
|
||||||
|
self.proxy.dispatch(IbbData {
|
||||||
|
session: session.clone(),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
IBB::Close { sid } => {
|
||||||
|
let entry = match sessions.entry((from, sid)) {
|
||||||
|
Entry::Occupied(entry) => Ok(entry),
|
||||||
|
Entry::Vacant(_) => Err(generate_error(
|
||||||
|
ErrorType::Cancel,
|
||||||
|
DefinedCondition::ItemNotFound,
|
||||||
|
"This session doesn’t exist."
|
||||||
|
)),
|
||||||
|
}?;
|
||||||
|
let session = entry.remove();
|
||||||
|
self.proxy.dispatch(IbbClose {
|
||||||
|
session,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_iq(&self, iq: &Iq) -> Propagation {
|
||||||
|
let iq = iq.clone();
|
||||||
|
if let IqType::Set(payload) = iq.payload {
|
||||||
|
let from = iq.from.unwrap();
|
||||||
|
let id = iq.id.unwrap();
|
||||||
|
// TODO: use an intermediate plugin to parse this payload.
|
||||||
|
let payload = match IqPayload::try_from(payload) {
|
||||||
|
Ok(IqPayload::IBB(ibb)) => {
|
||||||
|
match self.handle_ibb(from.clone(), ibb) {
|
||||||
|
Ok(_) => IqType::Result(None),
|
||||||
|
Err(error) => IqType::Error(error),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => IqType::Error(generate_error(
|
||||||
|
ErrorType::Cancel,
|
||||||
|
DefinedCondition::NotAcceptable,
|
||||||
|
format!("{:?}", err).as_ref()
|
||||||
|
)),
|
||||||
|
Ok(_) => return Propagation::Continue,
|
||||||
|
};
|
||||||
|
self.proxy.send(Iq {
|
||||||
|
from: None,
|
||||||
|
to: Some(from),
|
||||||
|
id: Some(id),
|
||||||
|
payload: payload,
|
||||||
|
}.into());
|
||||||
|
Propagation::Stop
|
||||||
|
} else {
|
||||||
|
Propagation::Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_plugin!(IbbPlugin, proxy, [
|
||||||
|
(Iq, Priority::Default) => handle_iq,
|
||||||
|
]);
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod messaging;
|
pub mod messaging;
|
||||||
pub mod presence;
|
pub mod presence;
|
||||||
pub mod ping;
|
pub mod ping;
|
||||||
|
pub mod ibb;
|
||||||
pub mod stanza;
|
pub mod stanza;
|
||||||
pub mod stanza_debug;
|
pub mod stanza_debug;
|
||||||
pub mod unhandled_iq;
|
pub mod unhandled_iq;
|
||||||
|
|
Loading…
Reference in a new issue