Starting commands support

[?]
May 1, 2019, 7:36 AM
SH3LIQ4SPV66L37M5XB3YARSWKH22EPD2FNSVXZST24EPOE7BIPQC

Dependencies

  • [2] SSOKGGCE Update dependencies
  • [3] PLWPCM47 Add id to initital presence
  • [4] CCLGGFKR Move out XmppConnection into own file
  • [5] VW7NVWAG Leave MUC properly
  • [6] H7R7Y3FQ Use new processing code to wait online
  • [7] O2GM5J4F Don't split xmpp receiving and sending
  • [8] FDHRCKH5 Unneded Box
  • [9] S754Y5DF Refactor IQ processing Always answer to set and get requests. Use XML encoding for stanzas.
  • [10] BYJPYYSM Process iq ping response
  • [11] OFLAP2G2 Fix possible utf8 errors
  • [12] LNUU5R56 Support disco#info from XEP-0030 Service Discovery
  • [13] X6L47BHQ Use different structure for established xmpp connection
  • [14] HDLI2X4H Ignore delayed XEP-0203 messages
  • [15] FVVPKFTL Initial commit
  • [16] YEMBT7TB Add support for XEP-0092: Software Version
  • [17] GVZ4JAR5 Process self-presence with incoming stanza processor
  • [18] FV6BJ5K6 Send self-presence and store account info in Rc so it willbe used in some future in parallel
  • [19] HU3NZX5Z Process self-presence via new processing code
  • [20] LQXBWNFT Remove unneeded requirement
  • [21] NDDQQP2P Update deps
  • [22] TPVUBB3F Answer to ping requests
  • [23] ZFBPXPAD Cleanup timeouted iq requests with ping Output elapsed time. Refactor iq handling.
  • [24] ZT3YEIVX Consume connection on processing command
  • [25] 3DSOPLCG Add rustdoc
  • [26] 5A5UVGNM Move receiver closing logic out of xmpp processing
  • [27] AA2ZWGRL Enter to MUC
  • [28] 4IPZTMFI Update dependencies
  • [29] 5GINRCKL Send ping XEP-0199
  • [30] FCPF2FV6 Break connection on iq error
  • [31] 2THKW66M Ignore .orig files
  • [32] RRLRZTMR Use element processor for iq
  • [33] IK3YDPTY Update deps
  • [34] 2L3JHRUL Create separate functions to process incoming XMPP stanzas
  • [35] DCGEFPRC Better README
  • [36] JD62RVOJ Update dependencies
  • [37] LL3D5CXK Staring using element processor
  • [38] QDHDTOLM Starting support for commands XEP-0050: Ad-Hoc Commands (there no support in xmpp_parsers still)
  • [39] Z3NQEYVI Rename IqSetHandler to IqResuestHandler as it should provide both get and set handling
  • [40] DISBBP3I Update dependencies
  • [41] AEH7WP42 Make element processors static
  • [42] JY4F7VBC Use element processor for incoming iq set
  • [43] HKSQO7JZ Enable hyper http server and configuration
  • [44] RQZCVDFD Implement applying timeout for expired iq await
  • [45] WBU7UOQW Read chatroom from config
  • [46] AYQZ2UIA Update deps
  • [47] YTN366WA Support disco#items
  • [48] 6UKCVM6E Use new iq processng for initial roster
  • [49] WDCZNZOP Fix rustdoc
  • [50] DYRPAV6T Update dependencies
  • [51] GXQCDLYQ Use element processor for incoming iq get
  • [52] PJV5HPIF Starting to imlements timeouts for iqs
  • [53] VS6AHRWI Move XMPP to separate dir
  • [54] DCMDASHV Mention XEP-0050 and XEP-0203 support
  • [55] 5IKA4GO7 Rename xmpp client field from "inner" to "client"

Change contents

  • replacement in src/xmpp/xmpp_connection.rs at line 0
    [3.21][2.0:38895]()
    use tokio_xmpp::{Client, Event, Packet};
    use tokio::prelude::future::{self, Either};
    use tokio::prelude::stream;
    use tokio::prelude::{Future, Stream};
    use std::collections::{HashMap, VecDeque};
    use std::time::{Duration, Instant};
    use super::stanzas;
    use super::element_processor;
    use crate::config;
    #[derive(Debug)]
    pub enum XmppCommand {
    /// Send message to someone by jid
    Chat {
    xmpp_to: xmpp_parsers::Jid,
    message: String,
    },
    /// Send message to MUC
    Chatroom { muc_id: String, message: String },
    /// Send ping request to the server to test connection
    Ping,
    /// Check iq requests if some have expired timeouts
    TimeoutCleanup,
    }
    /// trait of processing iq
    /// each function consumes handlers and
    /// returns false if connection should be reset
    trait IqHandler {
    /// process result
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool;
    /// process error
    fn error(
    self: Box<Self>,
    conn: &mut XmppConnection,
    error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool;
    /// process tmeout
    fn timeout(self: Box<Self>, conn: &mut XmppConnection) -> bool;
    }
    struct AddRosterIqHandler {
    jid: xmpp_parsers::Jid,
    }
    impl IqHandler for AddRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    match opt_element {
    Some(element) => {
    warn!(
    "Wrong payload when adding {} to roster: {}",
    self.jid,
    String::from(&element)
    );
    }
    None => {
    if conn.state.data.roster.contains_key(&self.jid) {
    info!("Jid {} updated to roster", self.jid);
    } else {
    info!("Jid {} added in roster", self.jid);
    conn.state.data.roster.insert(
    self.jid.clone(),
    (
    xmpp_parsers::roster::Subscription::None,
    xmpp_parsers::roster::Ask::None,
    ),
    );
    }
    conn.process_jid(&self.jid);
    }
    }
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    true
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    true // ignore
    }
    }
    struct PingIqHandler {}
    impl IqHandler for PingIqHandler {
    fn result(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    info!("ping successed");
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    struct InitRosterIqHandler {}
    impl IqHandler for InitRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    if let Some(result) = opt_element {
    use std::convert::TryInto;
    match result.try_into() as Result<xmpp_parsers::roster::Roster, _> {
    Ok(roster) => {
    conn.state.data.roster_init = true;
    conn.state.data.roster.clear();
    info!("Got first roster:");
    for i in roster.items {
    info!(" >>> {:?}", i);
    conn.state
    .data
    .roster
    .insert(i.jid, (i.subscription, i.ask));
    }
    true
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    false
    }
    }
    } else {
    error!("No roster responded");
    false
    }
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// if roster was initialized
    /// ToDo: remove it as it is used only for initialization
    roster_init: bool,
    /// if self-presence accepted
    /// ToDo: remove it as it is used only for initialization
    self_presence: bool,
    /// ids counter
    counter: usize,
    /// stanzas to send
    send_queue: VecDeque<minidom::Element>,
    /// outgoing mailbox
    outgoing_mailbox: HashMap<xmpp_parsers::Jid, Vec<String>>,
    /// muc id to muc jid
    mucs: HashMap<String, xmpp_parsers::Jid>,
    /// map from iq's id to handler of this type of iqs
    pending_ids: HashMap<String, (Instant, Box<dyn IqHandler>)>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    pub struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: XmppState,
    }
    trait IqRequestHandler {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq;
    }
    struct IqRequestUnknown {
    element: xmpp_parsers::Element,
    type_: &'static str,
    }
    impl IqRequestHandler for IqRequestUnknown {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    warn!(
    "Unsupported IQ {} request from {:?}: {}",
    self.type_,
    from,
    String::from(&self.element)
    );
    stanzas::make_iq_unsupported_error(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqSetRoster {}
    impl IqRequestHandler for IqSetRoster {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got roster push {} from {:?}", id, from);
    stanzas::make_roster_push_answer(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetPing {}
    impl IqRequestHandler for IqGetPing {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got ping {} from {:?}", id, from);
    stanzas::make_pong(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetVersion {}
    impl IqRequestHandler for IqGetVersion {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got version query {} from {:?}", id, from);
    stanzas::make_version(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoInfo {}
    impl IqRequestHandler for IqGetDiscoInfo {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco query {} from {:?}", id, from);
    stanzas::make_disco_info_result(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoItems {}
    impl IqRequestHandler for IqGetDiscoItems {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco items query {} from {:?}", id, from);
    stanzas::make_disco_items_result(id, conn.state.client.jid.clone(), from)
    }
    }
    lazy_static! {
    static ref INCOMING: element_processor::Processor<XmppConnection, bool, xmpp_parsers::Element> = {
    let mut incoming = element_processor::Processor::new(&|_, e| {
    warn!("Unknown stanza {}", String::from(&e));
    true
    });
    incoming.register(&XmppConnection::incoming_iq_processing);
    incoming.register(&XmppConnection::incoming_presence_processing);
    incoming.register(&XmppConnection::incoming_message_processing);
    incoming
    };
    static ref INCOMING_IQ_SET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_set =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "set",
    }) as Box<dyn IqRequestHandler>
    });
    iq_set.register(&XmppConnection::incoming_iq_processing_set_roster);
    iq_set
    };
    static ref INCOMING_IQ_GET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_get =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "get",
    }) as Box<dyn IqRequestHandler>
    });
    iq_get.register(&XmppConnection::incoming_iq_processing_get_ping);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_info);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_items);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_version);
    iq_get
    };
    }
    pub struct MaybeXmppConnection {
    account: std::rc::Rc<config::Account>,
    state: Option<XmppState>,
    }
    impl From<XmppConnection> for MaybeXmppConnection {
    fn from(from: XmppConnection) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from.account,
    state: Some(from.state),
    }
    }
    }
    impl From<config::Account> for MaybeXmppConnection {
    fn from(from: config::Account) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: std::rc::Rc::new(from),
    state: None,
    }
    }
    }
    impl From<std::rc::Rc<config::Account>> for MaybeXmppConnection {
    fn from(from: std::rc::Rc<config::Account>) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from,
    state: None,
    }
    }
    }
    impl MaybeXmppConnection {
    /// connects if nothing connected
    /// don't connect only if stop_future resolved
    pub fn connect<F>(
    self,
    stop_future: F,
    ) -> impl Future<Item = XmppConnection, Error = failure::Error>
    where
    F: future::Future + Clone + 'static,
    <F as hyper::rt::Future>::Error: Into<failure::Error> + Send,
    {
    info!("xmpp connection...");
    let MaybeXmppConnection { account, state } = self;
    if let Some(state) = state {
    Box::new(future::ok(XmppConnection { account, state }))
    as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    stop_future
    .clone()
    .select2(
    future::loop_fn(account, move |account| {
    info!("xmpp initialization...");
    let client =
    Client::new_with_jid(account.jid.clone(), &account.password);
    info!("xmpp initialized");
    let stop_future2 = stop_future.clone();
    let stop_future3 = stop_future.clone();
    let stop_future4 = stop_future.clone();
    // future to wait for online
    Box::new(
    XmppConnection {
    state: XmppState {
    client,
    data: std::default::Default::default(),
    },
    account,
    }
    .processing(XmppConnection::online, stop_future.clone())
    .map_err(|(acc, _)| acc)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    .and_then(|conn| conn.initial_roster(stop_future2))
    .and_then(|conn| conn.self_presence(stop_future3))
    .and_then(|conn| conn.enter_mucs(stop_future4))
    .then(|r| match r {
    Ok(conn) => future::ok(future::Loop::Break(conn)),
    Err(acc) => future::ok(future::Loop::Continue(acc)),
    }),
    )
    })
    .map_err(|_: ()| ()),
    )
    .then(|r| match r {
    Ok(Either::A((_x, _b))) => future::err(format_err!("Stop XMMP connection")),
    Ok(Either::B((x, _a))) => future::ok(x),
    Err(Either::A((e, _b))) => future::err(e.into()),
    Err(Either::B((_, _a))) => {
    future::err(format_err!("Cann't initiate XMPP connection"))
    }
    }),
    )
    }
    }
    }
    impl XmppConnection {
    /// base XMPP processing
    /// Returns false on error to disconnect
    fn xmpp_processing(&mut self, event: &Event) -> bool {
    match event {
    Event::Stanza(stanza) => INCOMING.process(self, stanza.clone()),
    Event::Online => true,
    e => {
    warn!("Unexpected event {:?}", e);
    false
    }
    }
    }
    /// Process roster push
    /// see RFC 6212 2.1.6. Roster Push
    fn incoming_iq_processing_set_roster(
    &mut self,
    roster: xmpp_parsers::roster::Roster,
    ) -> Box<dyn IqRequestHandler> {
    for i in roster.items {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(&i.jid) {
    info!("Update {} in roster", i.jid);
    rdata.0 = i.subscription;
    rdata.1 = i.ask;
    } else {
    info!("Add {} to roster", i.jid);
    self.state
    .data
    .roster
    .insert(i.jid.clone(), (i.subscription, i.ask));
    }
    self.process_jid(&i.jid);
    }
    Box::new(IqSetRoster {})
    }
    /// Enforce to answer to IQ "set"
    fn incoming_iq_processing_set(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_SET
    .process(self, element)
    .process(self, id, from)
    }
    /// Process ping request
    /// see XEP-0199: XMPP Ping
    fn incoming_iq_processing_get_ping(
    &mut self,
    _ping: xmpp_parsers::ping::Ping,
    ) -> Box<dyn IqRequestHandler> {
    Box::new(IqGetPing {})
    }
    /// Process disco query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_info(
    &mut self,
    disco: xmpp_parsers::disco::DiscoInfoQuery,
    ) -> Box<dyn IqRequestHandler> {
    if let Some(ref node) = disco.node {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    } else {
    Box::new(IqGetDiscoInfo {})
    }
    }
    /// Process disco items query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_items(
    &mut self,
    disco: xmpp_parsers::disco::DiscoItemsQuery,
    ) -> Box<dyn IqRequestHandler> {
    if let Some(ref node) = disco.node {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    } else {
    Box::new(IqGetDiscoItems {})
    }
    }
    /// Process version query
    /// see XEP-0092: Software Version
    fn incoming_iq_processing_get_version(
    &mut self,
    _version: xmpp_parsers::version::VersionQuery,
    ) -> Box<dyn IqRequestHandler> {
    Box::new(IqGetVersion {})
    }
    /// Enforce to answer to IQ "get"
    fn incoming_iq_processing_get(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_GET
    .process(self, element)
    .process(self, id, from)
    }
    fn incoming_iq_processing(&mut self, iq: xmpp_parsers::iq::Iq) -> bool {
    match iq.payload {
    xmpp_parsers::iq::IqType::Set(element) => {
    let iq_answer = self.incoming_iq_processing_set(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Error(e) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.error(self, e);
    }
    error!("iq error: {:?}", e);
    return false;
    }
    xmpp_parsers::iq::IqType::Get(element) => {
    let iq_answer = self.incoming_iq_processing_get(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Result(opt_element) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.result(self, opt_element);
    }
    warn!(
    "Unwanted iq result id {} from {:?}: {:?}",
    iq.id,
    iq.from,
    opt_element.map(|e| String::from(&e))
    );
    }
    }
    true
    }
    fn incoming_presence_processing(&mut self, presence: xmpp_parsers::presence::Presence) -> bool {
    if presence.from.as_ref() == Some(&self.state.client.jid) {
    info!("Self-presence accepted");
    self.state.data.self_presence = true;
    } else {
    warn!("Incoming presence stanza: {:?}", presence);
    }
    true
    }
    fn incoming_message_processing(&mut self, message: xmpp_parsers::message::Message) -> bool {
    for payload in message.payloads.iter() {
    use std::convert::TryInto;
    if let Some(_delay) =
    payload.clone().try_into().ok() as Option<xmpp_parsers::delay::Delay>
    {
    return true; // ignore delayed messages
    }
    }
    warn!("Incoming message stanza: {:?}", message);
    true
    }
    /// process event from xmpp stream
    /// returns from future when condition met
    /// or stop future was resolved.
    /// Return item if connection was preserved or error otherwise.
    /// Second part is a state of stop_future
    pub fn processing<S, F, T, E>(
    self,
    stop_condition: S,
    stop_future: F,
    ) -> impl Future<
    Item = (Self, Result<Either<F, T>, E>),
    Error = (std::rc::Rc<config::Account>, Result<Either<F, T>, E>),
    >
    where
    F: Future<Item = T, Error = E> + 'static,
    S: FnMut(&mut Self, Event) -> Result<bool, ()> + 'static,
    T: 'static,
    E: 'static,
    {
    future::loop_fn(
    (self, stop_future, stop_condition),
    |(xmpp, stop_future, mut stop_condition)| {
    // ToDo: check timeouts if iqs
    let XmppConnection {
    state: XmppState { client, mut data },
    account,
    } = xmpp;
    if let Some(send_element) = data.send_queue.pop_front() {
    use tokio::prelude::Sink;
    info!("Sending {}", String::from(&send_element));
    Box::new(
    client
    .send(Packet::Stanza(send_element))
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A((client, b))) => {
    Box::new(future::ok(future::Loop::Continue((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    b,
    stop_condition,
    ))))
    as Box<dyn Future<Item = _, Error = _>>
    }
    Ok(Either::B((t, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Ok(Either::B(t))))
    }
    })),
    Err(Either::A((e, b))) => {
    warn!("XMPP sending error: {}", e);
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    Err(Either::B((e, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Err(e)))
    }
    })),
    }),
    ) as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    client
    .into_future()
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A(((event, client), b))) => {
    if let Some(event) = event {
    let mut xmpp = XmppConnection {
    state: XmppState { client, data },
    account,
    };
    if xmpp.xmpp_processing(&event) {
    match stop_condition(&mut xmpp, event) {
    Ok(true) => future::ok(future::Loop::Break((
    xmpp,
    Ok(Either::A(b)),
    ))),
    Ok(false) => future::ok(future::Loop::Continue((
    xmpp,
    b,
    stop_condition,
    ))),
    Err(_e) => {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    }
    } else {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    } else {
    future::err((account, Ok(Either::A(b))))
    }
    }
    Ok(Either::B((t, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    )))
    } else {
    future::err((account, Ok(Either::B(t))))
    }
    }
    Err(Either::A((e, b))) => {
    warn!("XMPP error: {}", e.0);
    future::err((account, Ok(Either::A(b))))
    }
    Err(Either::B((e, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    )))
    } else {
    future::err((account, Err(e)))
    }
    }
    }),
    )
    }
    },
    )
    }
    /// get connection and wait for online status and set presence
    /// returns error if something went wrong and xmpp connection is broken
    fn online(&mut self, event: Event) -> Result<bool, ()> {
    match event {
    Event::Online => {
    info!("Online!");
    Ok(true)
    }
    Event::Stanza(s) => {
    warn!("Stanza before online: {}", String::from(&s));
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    fn initial_roster<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, mut data },
    } = self;
    use tokio::prelude::Sink;
    data.counter += 1;
    let id_init_roster = format!("id_init_roster{}", data.counter);
    let get_roster = stanzas::make_get_roster(&id_init_roster);
    let account2 = account.clone();
    info!("Quering roster... {}", String::from(&get_roster));
    data.pending_ids.insert(
    id_init_roster.clone(),
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(InitRosterIqHandler {}),
    ),
    );
    client
    .send(Packet::Stanza(get_roster))
    .map_err(move |e| {
    error!("Error on querying roster: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(move |conn, _| Ok(conn.state.data.roster_init), stop_future)
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn self_presence<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, data },
    } = self;
    use tokio::prelude::Sink;
    let presence = stanzas::make_presence(&account);
    let account2 = account.clone();
    info!("Sending presence... {}", String::from(&presence));
    client
    .send(Packet::Stanza(presence))
    .map_err(|e| {
    error!("Error on send self-presence: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(
    move |conn, _| Ok(conn.state.data.self_presence),
    stop_future,
    )
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn process_jid(&mut self, xmpp_to: &xmpp_parsers::Jid) {
    if let Some(ref mut mailbox) = self.state.data.outgoing_mailbox.get_mut(xmpp_to) {
    if !mailbox.is_empty() {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(xmpp_to) {
    info!("Jid {} in roster", xmpp_to);
    let sub_to = match rdata.0 {
    xmpp_parsers::roster::Subscription::To => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if sub_to {
    info!("Subscribed to {}", xmpp_to);
    self.state.data.send_queue.extend(
    mailbox.drain(..).map(|message| {
    stanzas::make_chat_message(xmpp_to.clone(), message)
    }),
    );
    } else if rdata.1 == xmpp_parsers::roster::Ask::None {
    info!("Not subscribed to {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_ask_subscribe(xmpp_to.clone()));
    }
    let sub_from = match rdata.0 {
    xmpp_parsers::roster::Subscription::From => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if !sub_from {
    info!("Not subscription from {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_allow_subscribe(xmpp_to.clone()));
    }
    } else {
    info!("Jid {} not in roster", xmpp_to);
    self.state.data.counter += 1;
    let id_add_roster = format!("id_add_roster{}", self.state.data.counter);
    let add_roster = stanzas::make_add_roster(&id_add_roster, xmpp_to.clone());
    info!("Adding jid {} to roster id {}", xmpp_to, id_add_roster);
    self.state.data.pending_ids.insert(
    id_add_roster,
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(AddRosterIqHandler {
    jid: xmpp_to.clone(),
    }),
    ),
    );
    self.state.data.send_queue.push_back(add_roster);
    }
    }
    }
    }
    pub fn process_command(&mut self, cmd: XmppCommand) {
    info!("Got command");
    match cmd {
    XmppCommand::Chat { xmpp_to, message } => {
    self.state
    .data
    .outgoing_mailbox
    .entry(xmpp_to.clone())
    .or_default()
    .push(message);
    self.process_jid(&xmpp_to);
    }
    XmppCommand::Chatroom { muc_id, message } => {
    if let Some(muc) = self.state.data.mucs.get(&muc_id) {
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_muc_message(muc.clone(), message));
    } else {
    error!("Not found MUC {}", muc_id);
    }
    }
    XmppCommand::Ping => {
    self.state.data.counter += 1;
    let id_ping = format!("id_ping{}", self.state.data.counter);
    let ping = stanzas::make_ping(&id_ping, self.state.client.jid.clone());
    self.state.data.send_queue.push_back(ping);
    self.state.data.pending_ids.insert(
    id_ping,
    (
    Instant::now() + Duration::from_secs(30),
    Box::new(PingIqHandler {}),
    ),
    );
    }
    XmppCommand::TimeoutCleanup => {
    let now = Instant::now();
    let timeouted: Vec<String> = self
    .state
    .data
    .pending_ids
    .iter()
    .filter_map(|(id, (timeout, _))| {
    if now >= *timeout {
    Some(id.to_string())
    } else {
    None
    }
    })
    .collect();
    let mut correct = true;
    timeouted.into_iter().for_each(|id| {
    if let Some((_, handler)) = self.state.data.pending_ids.remove(&id) {
    correct &= handler.timeout(&mut self);
    }
    })
    }
    }
    }
    pub fn shutdown(self) -> impl Future<Item = (), Error = failure::Error> {
    info!("Shutdown connection");
    let XmppConnection { account, state } = self;
    stream::iter_ok(
    state
    .data
    .mucs
    .values()
    .map(std::clone::Clone::clone)
    .collect::<Vec<_>>(),
    )
    .fold(state, move |XmppState { client, data }, muc_jid| {
    let muc_presence =
    stanzas::make_muc_presence_leave(account.jid.clone(), muc_jid.clone());
    info!(
    "Sending muc leave presence... {}",
    String::from(&muc_presence)
    );
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    e
    })
    .and_then(|client| future::ok(XmppState { client, data }))
    })
    .map(|_| ())
    }
    fn enter_mucs<F, E>(
    self,
    _stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection { account, state } = self;
    let account2 = account.clone();
    let account3 = account.clone();
    stream::iter_ok(account.chatrooms.clone())
    .fold(state, move |XmppState { client, mut data }, muc_jid| {
    data.counter += 1;
    let id_muc_presence = format!("id_muc_presence{}", data.counter);
    let muc_presence = stanzas::make_muc_presence(
    &id_muc_presence,
    account2.jid.clone(),
    muc_jid.1.clone(),
    );
    info!("Sending muc presence... {}", String::from(&muc_presence));
    let account4 = account2.clone();
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    account4
    })
    .and_then(|client| {
    data.mucs.insert(muc_jid.0, muc_jid.1);
    future::ok(XmppState { client, data })
    })
    })
    .map(|state| XmppConnection {
    account: account3,
    state,
    })
    }
    }
    [3.21]
    use tokio_xmpp::{Client, Event, Packet};
    use tokio::prelude::future::{self, Either};
    use tokio::prelude::stream;
    use tokio::prelude::{Future, Stream};
    use std::collections::{HashMap, VecDeque};
    use std::time::{Duration, Instant};
    use super::stanzas;
    use super::element_processor;
    use crate::config;
    #[derive(Debug)]
    pub enum XmppCommand {
    /// Send message to someone by jid
    Chat {
    xmpp_to: xmpp_parsers::Jid,
    message: String,
    },
    /// Send message to MUC
    Chatroom { muc_id: String, message: String },
    /// Send ping request to the server to test connection
    Ping,
    /// Check iq requests if some have expired timeouts
    TimeoutCleanup,
    }
    /// trait of processing iq
    /// each function consumes handlers and
    /// returns false if connection should be reset
    trait IqHandler {
    /// process result
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool;
    /// process error
    fn error(
    self: Box<Self>,
    conn: &mut XmppConnection,
    error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool;
    /// process tmeout
    fn timeout(self: Box<Self>, conn: &mut XmppConnection) -> bool;
    }
    struct AddRosterIqHandler {
    jid: xmpp_parsers::Jid,
    }
    impl IqHandler for AddRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    match opt_element {
    Some(element) => {
    warn!(
    "Wrong payload when adding {} to roster: {}",
    self.jid,
    String::from(&element)
    );
    }
    None => {
    if conn.state.data.roster.contains_key(&self.jid) {
    info!("Jid {} updated to roster", self.jid);
    } else {
    info!("Jid {} added in roster", self.jid);
    conn.state.data.roster.insert(
    self.jid.clone(),
    (
    xmpp_parsers::roster::Subscription::None,
    xmpp_parsers::roster::Ask::None,
    ),
    );
    }
    conn.process_jid(&self.jid);
    }
    }
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    true
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    true // ignore
    }
    }
    struct PingIqHandler {}
    impl IqHandler for PingIqHandler {
    fn result(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    info!("ping successed");
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    struct InitRosterIqHandler {}
    impl IqHandler for InitRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    if let Some(result) = opt_element {
    use std::convert::TryInto;
    match result.try_into() as Result<xmpp_parsers::roster::Roster, _> {
    Ok(roster) => {
    conn.state.data.roster_init = true;
    conn.state.data.roster.clear();
    info!("Got first roster:");
    for i in roster.items {
    info!(" >>> {:?}", i);
    conn.state
    .data
    .roster
    .insert(i.jid, (i.subscription, i.ask));
    }
    true
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    false
    }
    }
    } else {
    error!("No roster responded");
    false
    }
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// if roster was initialized
    /// ToDo: remove it as it is used only for initialization
    roster_init: bool,
    /// if self-presence accepted
    /// ToDo: remove it as it is used only for initialization
    self_presence: bool,
    /// ids counter
    counter: usize,
    /// stanzas to send
    send_queue: VecDeque<minidom::Element>,
    /// outgoing mailbox
    outgoing_mailbox: HashMap<xmpp_parsers::Jid, Vec<String>>,
    /// muc id to muc jid
    mucs: HashMap<String, xmpp_parsers::Jid>,
    /// map from iq's id to handler of this type of iqs
    pending_ids: HashMap<String, (Instant, Box<dyn IqHandler>)>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    pub struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: XmppState,
    }
    trait IqRequestHandler {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq;
    }
    struct IqRequestUnknown {
    element: xmpp_parsers::Element,
    type_: &'static str,
    }
    impl IqRequestHandler for IqRequestUnknown {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    warn!(
    "Unsupported IQ {} request from {:?}: {}",
    self.type_,
    from,
    String::from(&self.element)
    );
    stanzas::make_iq_unsupported_error(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqSetRoster {}
    impl IqRequestHandler for IqSetRoster {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got roster push {} from {:?}", id, from);
    stanzas::make_roster_push_answer(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetPing {}
    impl IqRequestHandler for IqGetPing {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got ping {} from {:?}", id, from);
    stanzas::make_pong(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetVersion {}
    impl IqRequestHandler for IqGetVersion {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got version query {} from {:?}", id, from);
    stanzas::make_version(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoInfo {}
    impl IqRequestHandler for IqGetDiscoInfo {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco query {} from {:?}", id, from);
    stanzas::make_disco_info_result(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoItems {}
    impl IqRequestHandler for IqGetDiscoItems {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco items query {} from {:?}", id, from);
    stanzas::make_disco_items_result(id, conn.state.client.jid.clone(), from)
    }
    }
    lazy_static! {
    static ref INCOMING: element_processor::Processor<XmppConnection, bool, xmpp_parsers::Element> = {
    let mut incoming = element_processor::Processor::new(&|_, e| {
    warn!("Unknown stanza {}", String::from(&e));
    true
    });
    incoming.register(&XmppConnection::incoming_iq_processing);
    incoming.register(&XmppConnection::incoming_presence_processing);
    incoming.register(&XmppConnection::incoming_message_processing);
    incoming
    };
    static ref INCOMING_IQ_SET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_set =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "set",
    }) as Box<dyn IqRequestHandler>
    });
    iq_set.register(&XmppConnection::incoming_iq_processing_set_roster);
    iq_set
    };
    static ref INCOMING_IQ_GET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_get =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "get",
    }) as Box<dyn IqRequestHandler>
    });
    iq_get.register(&XmppConnection::incoming_iq_processing_get_ping);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_info);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_items);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_version);
    iq_get
    };
    }
    pub struct MaybeXmppConnection {
    account: std::rc::Rc<config::Account>,
    state: Option<XmppState>,
    }
    impl From<XmppConnection> for MaybeXmppConnection {
    fn from(from: XmppConnection) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from.account,
    state: Some(from.state),
    }
    }
    }
    impl From<config::Account> for MaybeXmppConnection {
    fn from(from: config::Account) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: std::rc::Rc::new(from),
    state: None,
    }
    }
    }
    impl From<std::rc::Rc<config::Account>> for MaybeXmppConnection {
    fn from(from: std::rc::Rc<config::Account>) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from,
    state: None,
    }
    }
    }
    impl MaybeXmppConnection {
    /// connects if nothing connected
    /// don't connect only if stop_future resolved
    pub fn connect<F>(
    self,
    stop_future: F,
    ) -> impl Future<Item = XmppConnection, Error = failure::Error>
    where
    F: future::Future + Clone + 'static,
    <F as hyper::rt::Future>::Error: Into<failure::Error> + Send,
    {
    info!("xmpp connection...");
    let MaybeXmppConnection { account, state } = self;
    if let Some(state) = state {
    Box::new(future::ok(XmppConnection { account, state }))
    as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    stop_future
    .clone()
    .select2(
    future::loop_fn(account, move |account| {
    info!("xmpp initialization...");
    let client =
    Client::new_with_jid(account.jid.clone(), &account.password);
    info!("xmpp initialized");
    let stop_future2 = stop_future.clone();
    let stop_future3 = stop_future.clone();
    let stop_future4 = stop_future.clone();
    // future to wait for online
    Box::new(
    XmppConnection {
    state: XmppState {
    client,
    data: std::default::Default::default(),
    },
    account,
    }
    .processing(XmppConnection::online, stop_future.clone())
    .map_err(|(acc, _)| acc)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    .and_then(|conn| conn.initial_roster(stop_future2))
    .and_then(|conn| conn.self_presence(stop_future3))
    .and_then(|conn| conn.enter_mucs(stop_future4))
    .then(|r| match r {
    Ok(conn) => future::ok(future::Loop::Break(conn)),
    Err(acc) => future::ok(future::Loop::Continue(acc)),
    }),
    )
    })
    .map_err(|_: ()| ()),
    )
    .then(|r| match r {
    Ok(Either::A((_x, _b))) => future::err(format_err!("Stop XMMP connection")),
    Ok(Either::B((x, _a))) => future::ok(x),
    Err(Either::A((e, _b))) => future::err(e.into()),
    Err(Either::B((_, _a))) => {
    future::err(format_err!("Cann't initiate XMPP connection"))
    }
    }),
    )
    }
    }
    }
    impl XmppConnection {
    /// base XMPP processing
    /// Returns false on error to disconnect
    fn xmpp_processing(&mut self, event: &Event) -> bool {
    match event {
    Event::Stanza(stanza) => INCOMING.process(self, stanza.clone()),
    Event::Online => true,
    e => {
    warn!("Unexpected event {:?}", e);
    false
    }
    }
    }
    /// Process roster push
    /// see RFC 6212 2.1.6. Roster Push
    fn incoming_iq_processing_set_roster(
    &mut self,
    roster: xmpp_parsers::roster::Roster,
    ) -> Box<dyn IqRequestHandler> {
    for i in roster.items {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(&i.jid) {
    info!("Update {} in roster", i.jid);
    rdata.0 = i.subscription;
    rdata.1 = i.ask;
    } else {
    info!("Add {} to roster", i.jid);
    self.state
    .data
    .roster
    .insert(i.jid.clone(), (i.subscription, i.ask));
    }
    self.process_jid(&i.jid);
    }
    Box::new(IqSetRoster {})
    }
    /// Enforce to answer to IQ "set"
    fn incoming_iq_processing_set(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_SET
    .process(self, element)
    .process(self, id, from)
    }
    /// Process ping request
    /// see XEP-0199: XMPP Ping
    fn incoming_iq_processing_get_ping(
    &mut self,
    _ping: xmpp_parsers::ping::Ping,
    ) -> Box<dyn IqRequestHandler> {
    Box::new(IqGetPing {})
    }
    /// Process disco query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_info(
    &mut self,
    disco: xmpp_parsers::disco::DiscoInfoQuery,
    ) -> Box<dyn IqRequestHandler> {
    if let Some(ref node) = disco.node {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    } else {
    Box::new(IqGetDiscoInfo {})
    }
    }
    /// Process disco items query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_items(
    &mut self,
    disco: xmpp_parsers::disco::DiscoItemsQuery,
    ) -> Box<dyn IqRequestHandler> {
    if let Some(ref node) = disco.node {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    } else {
    Box::new(IqGetDiscoItems {})
    }
    }
    /// Process version query
    /// see XEP-0092: Software Version
    fn incoming_iq_processing_get_version(
    &mut self,
    _version: xmpp_parsers::version::VersionQuery,
    ) -> Box<dyn IqRequestHandler> {
    Box::new(IqGetVersion {})
    }
    /// Enforce to answer to IQ "get"
    fn incoming_iq_processing_get(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_GET
    .process(self, element)
    .process(self, id, from)
    }
    fn incoming_iq_processing(&mut self, iq: xmpp_parsers::iq::Iq) -> bool {
    match iq.payload {
    xmpp_parsers::iq::IqType::Set(element) => {
    let iq_answer = self.incoming_iq_processing_set(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Error(e) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.error(self, e);
    }
    error!("iq error: {:?}", e);
    return false;
    }
    xmpp_parsers::iq::IqType::Get(element) => {
    let iq_answer = self.incoming_iq_processing_get(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Result(opt_element) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.result(self, opt_element);
    }
    warn!(
    "Unwanted iq result id {} from {:?}: {:?}",
    iq.id,
    iq.from,
    opt_element.map(|e| String::from(&e))
    );
    }
    }
    true
    }
    fn incoming_presence_processing(&mut self, presence: xmpp_parsers::presence::Presence) -> bool {
    if presence.from.as_ref() == Some(&self.state.client.jid) {
    info!("Self-presence accepted");
    self.state.data.self_presence = true;
    } else {
    warn!("Incoming presence stanza: {:?}", presence);
    }
    true
    }
    fn incoming_message_processing(&mut self, message: xmpp_parsers::message::Message) -> bool {
    for payload in message.payloads.iter() {
    use std::convert::TryInto;
    if let Some(_delay) =
    payload.clone().try_into().ok() as Option<xmpp_parsers::delay::Delay>
    {
    return true; // ignore delayed messages
    }
    }
    warn!("Incoming message stanza: {:?}", message);
    true
    }
    /// process event from xmpp stream
    /// returns from future when condition met
    /// or stop future was resolved.
    /// Return item if connection was preserved or error otherwise.
    /// Second part is a state of stop_future
    pub fn processing<S, F, T, E>(
    self,
    stop_condition: S,
    stop_future: F,
    ) -> impl Future<
    Item = (Self, Result<Either<F, T>, E>),
    Error = (std::rc::Rc<config::Account>, Result<Either<F, T>, E>),
    >
    where
    F: Future<Item = T, Error = E> + 'static,
    S: FnMut(&mut Self, Event) -> Result<bool, ()> + 'static,
    T: 'static,
    E: 'static,
    {
    future::loop_fn(
    (self, stop_future, stop_condition),
    |(xmpp, stop_future, mut stop_condition)| {
    // ToDo: check timeouts if iqs
    let XmppConnection {
    state: XmppState { client, mut data },
    account,
    } = xmpp;
    if let Some(send_element) = data.send_queue.pop_front() {
    use tokio::prelude::Sink;
    info!("Sending {}", String::from(&send_element));
    Box::new(
    client
    .send(Packet::Stanza(send_element))
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A((client, b))) => {
    Box::new(future::ok(future::Loop::Continue((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    b,
    stop_condition,
    ))))
    as Box<dyn Future<Item = _, Error = _>>
    }
    Ok(Either::B((t, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Ok(Either::B(t))))
    }
    })),
    Err(Either::A((e, b))) => {
    warn!("XMPP sending error: {}", e);
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    Err(Either::B((e, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Err(e)))
    }
    })),
    }),
    ) as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    client
    .into_future()
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A(((event, client), b))) => {
    if let Some(event) = event {
    let mut xmpp = XmppConnection {
    state: XmppState { client, data },
    account,
    };
    if xmpp.xmpp_processing(&event) {
    match stop_condition(&mut xmpp, event) {
    Ok(true) => future::ok(future::Loop::Break((
    xmpp,
    Ok(Either::A(b)),
    ))),
    Ok(false) => future::ok(future::Loop::Continue((
    xmpp,
    b,
    stop_condition,
    ))),
    Err(_e) => {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    }
    } else {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    } else {
    future::err((account, Ok(Either::A(b))))
    }
    }
    Ok(Either::B((t, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    )))
    } else {
    future::err((account, Ok(Either::B(t))))
    }
    }
    Err(Either::A((e, b))) => {
    warn!("XMPP error: {}", e.0);
    future::err((account, Ok(Either::A(b))))
    }
    Err(Either::B((e, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    )))
    } else {
    future::err((account, Err(e)))
    }
    }
    }),
    )
    }
    },
    )
    }
    /// get connection and wait for online status and set presence
    /// returns error if something went wrong and xmpp connection is broken
    fn online(&mut self, event: Event) -> Result<bool, ()> {
    match event {
    Event::Online => {
    info!("Online!");
    Ok(true)
    }
    Event::Stanza(s) => {
    warn!("Stanza before online: {}", String::from(&s));
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    fn initial_roster<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, mut data },
    } = self;
    use tokio::prelude::Sink;
    data.counter += 1;
    let id_init_roster = format!("id_init_roster{}", data.counter);
    let get_roster = stanzas::make_get_roster(&id_init_roster);
    let account2 = account.clone();
    info!("Quering roster... {}", String::from(&get_roster));
    data.pending_ids.insert(
    id_init_roster.clone(),
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(InitRosterIqHandler {}),
    ),
    );
    client
    .send(Packet::Stanza(get_roster))
    .map_err(move |e| {
    error!("Error on querying roster: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(move |conn, _| Ok(conn.state.data.roster_init), stop_future)
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn self_presence<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, data },
    } = self;
    use tokio::prelude::Sink;
    let presence = stanzas::make_presence(&account);
    let account2 = account.clone();
    info!("Sending presence... {}", String::from(&presence));
    client
    .send(Packet::Stanza(presence))
    .map_err(|e| {
    error!("Error on send self-presence: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(
    move |conn, _| Ok(conn.state.data.self_presence),
    stop_future,
    )
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn process_jid(&mut self, xmpp_to: &xmpp_parsers::Jid) {
    if let Some(ref mut mailbox) = self.state.data.outgoing_mailbox.get_mut(xmpp_to) {
    if !mailbox.is_empty() {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(xmpp_to) {
    info!("Jid {} in roster", xmpp_to);
    let sub_to = match rdata.0 {
    xmpp_parsers::roster::Subscription::To => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if sub_to {
    info!("Subscribed to {}", xmpp_to);
    self.state.data.send_queue.extend(
    mailbox.drain(..).map(|message| {
    stanzas::make_chat_message(xmpp_to.clone(), message)
    }),
    );
    } else if rdata.1 == xmpp_parsers::roster::Ask::None {
    info!("Not subscribed to {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_ask_subscribe(xmpp_to.clone()));
    }
    let sub_from = match rdata.0 {
    xmpp_parsers::roster::Subscription::From => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if !sub_from {
    info!("Not subscription from {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_allow_subscribe(xmpp_to.clone()));
    }
    } else {
    info!("Jid {} not in roster", xmpp_to);
    self.state.data.counter += 1;
    let id_add_roster = format!("id_add_roster{}", self.state.data.counter);
    let add_roster = stanzas::make_add_roster(&id_add_roster, xmpp_to.clone());
    info!("Adding jid {} to roster id {}", xmpp_to, id_add_roster);
    self.state.data.pending_ids.insert(
    id_add_roster,
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(AddRosterIqHandler {
    jid: xmpp_to.clone(),
    }),
    ),
    );
    self.state.data.send_queue.push_back(add_roster);
    }
    }
    }
    }
    pub fn process_command(&mut self, cmd: XmppCommand) {
    info!("Got command");
    match cmd {
    XmppCommand::Chat { xmpp_to, message } => {
    self.state
    .data
    .outgoing_mailbox
    .entry(xmpp_to.clone())
    .or_default()
    .push(message);
    self.process_jid(&xmpp_to);
    }
    XmppCommand::Chatroom { muc_id, message } => {
    if let Some(muc) = self.state.data.mucs.get(&muc_id) {
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_muc_message(muc.clone(), message));
    } else {
    error!("Not found MUC {}", muc_id);
    }
    }
    XmppCommand::Ping => {
    self.state.data.counter += 1;
    let id_ping = format!("id_ping{}", self.state.data.counter);
    let ping = stanzas::make_ping(&id_ping, self.state.client.jid.clone());
    self.state.data.send_queue.push_back(ping);
    self.state.data.pending_ids.insert(
    id_ping,
    (
    Instant::now() + Duration::from_secs(30),
    Box::new(PingIqHandler {}),
    ),
    );
    }
    XmppCommand::TimeoutCleanup => {
    let now = Instant::now();
    let timeouted: Vec<String> = self
    .state
    .data
    .pending_ids
    .iter()
    .filter_map(|(id, (timeout, _))| {
    if now >= *timeout {
    Some(id.to_string())
    } else {
    None
    }
    })
    .collect();
    let mut correct = true;
    timeouted.into_iter().for_each(|id| {
    if let Some((_, handler)) = self.state.data.pending_ids.remove(&id) {
    correct &= handler.timeout(&mut self);
    }
    })
    }
    }
    }
    pub fn shutdown(self) -> impl Future<Item = (), Error = failure::Error> {
    info!("Shutdown connection");
    let XmppConnection { account, state } = self;
    stream::iter_ok(
    state
    .data
    .mucs
    .values()
    .map(std::clone::Clone::clone)
    .collect::<Vec<_>>(),
    )
    .fold(state, move |XmppState { client, data }, muc_jid| {
    let muc_presence =
    stanzas::make_muc_presence_leave(account.jid.clone(), muc_jid.clone());
    info!(
    "Sending muc leave presence... {}",
    String::from(&muc_presence)
    );
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    e
    })
    .and_then(|client| future::ok(XmppState { client, data }))
    })
    .map(|_| ())
    }
    fn enter_mucs<F, E>(
    self,
    _stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection { account, state } = self;
    let account2 = account.clone();
    let account3 = account.clone();
    stream::iter_ok(account.chatrooms.clone())
    .fold(state, move |XmppState { client, mut data }, muc_jid| {
    data.counter += 1;
    let id_muc_presence = format!("id_muc_presence{}", data.counter);
    let muc_presence = stanzas::make_muc_presence(
    &id_muc_presence,
    account2.jid.clone(),
    muc_jid.1.clone(),
    );
    info!("Sending muc presence... {}", String::from(&muc_presence));
    let account4 = account2.clone();
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    account4
    })
    .and_then(|client| {
    data.mucs.insert(muc_jid.0, muc_jid.1);
    future::ok(XmppState { client, data })
    })
    })
    .map(|state| XmppConnection {
    account: account3,
    state,
    })
    }
    }
  • replacement in src/xmpp/stanzas.rs at line 18
    [3.35611][3.39128:39254]()
    Iq::from_get(
    id,
    Roster {
    items: vec![],
    ver: None,
    },
    )
    .into()
    [3.35611]
    [3.35737]
    let mut get_roster = Iq::from_get(Roster {
    items: vec![],
    ver: None,
    });
    get_roster.id = Some(id.to_string());
    get_roster.into()
  • replacement in src/xmpp/stanzas.rs at line 27
    [3.35810][3.39255:39608]()
    Iq::from_set(
    id,
    Roster {
    items: vec![Item {
    jid,
    name: None,
    subscription: xmpp_parsers::roster::Subscription::None,
    ask: xmpp_parsers::roster::Ask::None,
    groups: vec![],
    }],
    ver: None,
    },
    )
    .into()
    [3.35810]
    [3.39858]
    let mut add_roster = Iq::from_set(Roster {
    items: vec![Item {
    jid,
    name: None,
    subscription: xmpp_parsers::roster::Subscription::None,
    ask: xmpp_parsers::roster::Ask::None,
    groups: vec![],
    }],
    ver: None,
    });
    add_roster.id = Some(id.to_string());
    add_roster.into()
  • replacement in src/xmpp/stanzas.rs at line 78
    [3.40352][3.40352:40395]()
    let mut ping = Iq::from_get(id, Ping);
    [3.40352]
    [3.40395]
    let mut ping = Iq::from_get(Ping);
    ping.id = Some(id.to_string());
  • edit in src/xmpp/stanzas.rs at line 83
    [3.40491][3.40491:40494](),[3.40494][3.38896:38992](),[3.38992][3.40587:40697](),[3.40587][3.40587:40697](),[3.40697][3.38993:39009]()
    }
    pub fn make_pong(id: &str, from: xmpp_parsers::Jid, to: Option<xmpp_parsers::Jid>) -> Element {
    let mut pong = Iq::from_result(id, None as Option<Roster>);
    pong.from = Some(from);
    pong.to = to;
    pong.into()
  • replacement in src/xmpp/mod.rs at line 150
    [3.44627][3.44627:44731]()
    /// Returns false on error to disconnect
    fn xmpp_processing(&mut self, event: &Event) -> bool {
    [3.44627]
    [3.44731]
    fn xmpp_processing(
    mut self,
    event: &Event,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>> {
  • replacement in src/xmpp/mod.rs at line 159
    [3.45092][2.39002:39526]()
    use std::convert::TryInto;
    if let Some(iq) = stanza.clone().try_into().ok() as Option<xmpp_parsers::iq::Iq> {
    if let Some((_, jid)) =
    self.state.data.pending_add_roster_ids.remove_entry(&iq.id)
    {
    if let xmpp_parsers::iq::IqType::Result(None) = iq.payload {
    if self.state.data.roster.contains_key(&jid) {
    info!("Jid {} updated to roster", jid);
    [3.45092]
    [2.39526]
    use try_from::TryInto;
    if let Some(iq) = stanza.try_into().ok() as Option<xmpp_parsers::iq::Iq> {
    if let Some(id) = iq.id {
    if let Some((_, jid)) =
    self.state.data.pending_add_roster_ids.remove_entry(&id)
    {
    if let xmpp_parsers::iq::IqType::Result(None) = iq.payload {
    if self.state.data.roster.contains_key(&jid) {
    info!("Jid {} updated to roster", jid);
    } else {
    info!("Jid {} added in roster", jid);
    self.state.data.roster.insert(
    jid.clone(),
    (
    xmpp_parsers::roster::Subscription::None,
    xmpp_parsers::roster::Ask::None,
    ),
    );
    }
    self.process_jid(&jid);
  • replacement in src/xmpp/mod.rs at line 180
    [2.39563][2.39563:39977]()
    info!("Jid {} added in roster", jid);
    self.state.data.roster.insert(
    jid.clone(),
    (
    xmpp_parsers::roster::Subscription::None,
    xmpp_parsers::roster::Ask::None,
    ),
    [2.39563]
    [2.39977]
    warn!(
    "Wrong payload when adding {} to roster: {:?}",
    jid, iq.payload
  • edit in src/xmpp/mod.rs at line 185
    [2.40042][2.40042:40094](),[2.40094][3.46646:46679](),[3.46646][3.46646:46679](),[3.46679][2.40095:40289]()
    self.process_jid(&jid);
    } else {
    warn!(
    "Wrong payload when adding {} to roster: {:?}",
    jid, iq.payload
    );
  • replacement in src/xmpp/mod.rs at line 187
    [2.40337][2.40337:41523]()
    match iq.payload {
    xmpp_parsers::iq::IqType::Set(element) => {
    if let Some(roster) =
    element.try_into().ok() as Option<xmpp_parsers::roster::Roster>
    {
    for i in roster.items {
    if let Some(ref mut rdata) =
    self.state.data.roster.get_mut(&i.jid)
    {
    info!("Update {} in roster", i.jid);
    rdata.0 = i.subscription;
    rdata.1 = i.ask;
    } else {
    info!("Add {} to roster", i.jid);
    self.state
    .data
    .roster
    .insert(i.jid.clone(), (i.subscription, i.ask));
    }
    self.process_jid(&i.jid);
    [2.40337]
    [2.41523]
    if let xmpp_parsers::iq::IqType::Set(element) = iq.payload {
    if let Some(roster) =
    element.try_into().ok() as Option<xmpp_parsers::roster::Roster>
    {
    for i in roster.items {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(&i.jid)
    {
    info!("Update {} in roster", i.jid);
    rdata.0 = i.subscription;
    rdata.1 = i.ask;
    } else {
    info!("Add {} to roster", i.jid);
    self.state
    .data
    .roster
    .insert(i.jid.clone(), (i.subscription, i.ask));
  • replacement in src/xmpp/mod.rs at line 204
    [2.41557][2.41557:42371]()
    }
    }
    xmpp_parsers::iq::IqType::Error(e) => {
    error!("iq error: {:?}", e);
    return false;
    }
    xmpp_parsers::iq::IqType::Get(element) => {
    if let Some(_ping) =
    element.try_into().ok() as Option<xmpp_parsers::ping::Ping>
    {
    let pong = stanzas::make_pong(
    &iq.id,
    self.state.client.jid.clone(),
    iq.from,
    );
    self.state.data.send_queue.push_back(pong);
    [2.41557]
    [2.42371]
    self.process_jid(&i.jid);
  • edit in src/xmpp/mod.rs at line 207
    [3.46965][2.42402:42445]()
    _ => (), // ignore
  • edit in src/xmpp/mod.rs at line 208
    [3.47037][2.42446:42652]()
    } else if let Some(_presence) =
    stanza.try_into().ok() as Option<xmpp_parsers::presence::Presence>
    {
    // to do something with presence
  • replacement in src/xmpp/mod.rs at line 209
    [3.47055][2.42653:42674]()
    true
    [3.47055]
    [3.47055]
    future::ok(self)
  • replacement in src/xmpp/mod.rs at line 211
    [3.47069][2.42675:42710]()
    Event::Online => true,
    [3.47069]
    [2.42710]
    Event::Online => future::ok(self),
  • replacement in src/xmpp/mod.rs at line 214
    [2.42780][2.42780:42802]()
    false
    [2.42780]
    [3.47196]
    future::err(self.account)
  • replacement in src/xmpp/mod.rs at line 306
    [3.51858][3.51858:51930]()
    let mut xmpp = XmppConnection {
    [3.51858]
    [3.51930]
    let xmpp = XmppConnection {
  • replacement in src/xmpp/mod.rs at line 310
    [3.38835][3.3355:3356](),[3.29886][3.3355:3356](),[3.864][3.3355:3356](),[3.34299][3.3355:3356](),[3.29542][3.3355:3356](),[3.33386][3.3355:3356](),[3.39458][3.3355:3356](),[3.52105][3.3355:3356](),[3.32946][3.3355:3356](),[3.42797][3.3355:3356](),[3.3355][3.3355:3356](),[3.3356][3.52106:53029]()
    if xmpp.xmpp_processing(&event) {
    match stop_condition(&mut xmpp, event) {
    Ok(true) => future::ok(future::Loop::Break((
    xmpp,
    Ok(Either::A(b)),
    ))),
    Ok(false) => future::ok(future::Loop::Continue((
    xmpp,
    b,
    stop_condition,
    ))),
    Err(_e) => {
    future::err((xmpp.account, Ok(Either::A(b))))
    [3.52105]
    [3.53029]
    Box::new(xmpp.xmpp_processing(&event).then(|r| match r {
    Ok(mut xmpp) => {
    match stop_condition(&mut xmpp, event) {
    Ok(true) => future::ok(future::Loop::Break((
    xmpp,
    Ok(Either::A(b)),
    ))),
    Ok(false) => {
    future::ok(future::Loop::Continue((
    xmpp,
    b,
    stop_condition,
    )))
    }
    Err(_e) => future::err((
    xmpp.account,
    Ok(Either::A(b)),
    )),
  • replacement in src/xmpp/mod.rs at line 330
    [3.53125][3.53125:53306]()
    } else {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    [3.53125]
    [3.53306]
    Err(account) => {
    future::err((account, Ok(Either::A(b))))
    }
    }))
    as Box<dyn Future<Item = _, Error = _>>
  • replacement in src/xmpp/mod.rs at line 336
    [3.53351][3.53351:53432]()
    future::err((account, Ok(Either::A(b))))
    [3.53351]
    [3.53432]
    Box::new(future::err((account, Ok(Either::A(b)))))
  • replacement in src/xmpp/mod.rs at line 340
    [3.53563][3.53563:53638]()
    if let Some(client) = a.into_inner() {
    [3.53563]
    [3.53638]
    Box::new(if let Some(client) = a.into_inner() {
  • replacement in src/xmpp/mod.rs at line 350
    [3.54191][3.54191:54229]()
    }
    [3.54191]
    [3.54229]
    })
  • replacement in src/xmpp/mod.rs at line 354
    [3.54389][3.54389:54466]()
    future::err((account, Ok(Either::A(b))))
    [3.54389]
    [3.54466]
    Box::new(future::err((account, Ok(Either::A(b)))))
  • replacement in src/xmpp/mod.rs at line 357
    [3.54560][3.54560:54635]()
    if let Some(client) = a.into_inner() {
    [3.54560]
    [3.54635]
    Box::new(if let Some(client) = a.into_inner() {
  • replacement in src/xmpp/mod.rs at line 367
    [3.55168][3.55168:55206]()
    }
    [3.55168]
    [3.55206]
    })
  • replacement in src/xmpp/mod.rs at line 397
    [3.56072][3.56072:56111]()
    use std::convert::TryInto;
    [3.56072]
    [3.56111]
    use try_from::TryInto;
  • replacement in src/xmpp/mod.rs at line 400
    [3.56207][3.56207:57267]()
    if iq.id == id_init_roster {
    match iq.payload {
    xmpp_parsers::iq::IqType::Error(_e) => {
    error!("Get error instead of roster");
    Err(())
    }
    xmpp_parsers::iq::IqType::Result(Some(result)) => {
    match result.try_into() as Result<xmpp_parsers::roster::Roster, _> {
    Ok(roster) => {
    self.state.data.roster.clear();
    info!("Got first roster:");
    for i in roster.items {
    info!(" >>> {:?}", i);
    self.state
    .data
    .roster
    .insert(i.jid, (i.subscription, i.ask));
    [3.56207]
    [3.57267]
    if let Some(id) = iq.id {
    if id == id_init_roster {
    match iq.payload {
    xmpp_parsers::iq::IqType::Error(_e) => {
    error!("Get error instead of roster");
    Err(())
    }
    xmpp_parsers::iq::IqType::Result(Some(result)) => {
    match result.try_into()
    as Result<xmpp_parsers::roster::Roster, _>
    {
    Ok(roster) => {
    self.state.data.roster.clear();
    info!("Got first roster:");
    for i in roster.items {
    info!(" >>> {:?}", i);
    self.state
    .data
    .roster
    .insert(i.jid, (i.subscription, i.ask));
    }
    Ok(true)
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    Err(())
  • edit in src/xmpp/mod.rs at line 427
    [3.57309][3.57309:57358]()
    Ok(true)
  • replacement in src/xmpp/mod.rs at line 428
    [3.57396][3.57396:57608]()
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    Err(())
    }
    [3.57396]
    [3.57608]
    }
    _ => {
    error!("Unknown result of roster");
    Err(())
  • replacement in src/xmpp/mod.rs at line 434
    [3.57672][3.57672:57845]()
    _ => {
    error!("Unknown result of roster");
    Err(())
    }
    [3.57672]
    [3.57845]
    } else {
    Ok(false)
  • replacement in src/xmpp/mod.rs at line 438
    [3.57900][3.57900:57934]()
    Ok(false)
    [3.57900]
    [3.57934]
    error!("Iq stanza without id");
    Err(())
  • replacement in src/xmpp/mod.rs at line 526
    [3.60651][3.60651:61178]()
    use std::convert::TryInto;
    match s.try_into() as Result<xmpp_parsers::presence::Presence, _> {
    Ok(presence) => {
    Ok(presence.from.as_ref() == Some(&conn.state.client.jid))
    }
    Err(e) => {
    warn!("Not a self-presence: {}", e);
    Ok(false)
    }
    [3.60651]
    [3.61178]
    if s.name() == "presence"
    && s.attr("from").map_or(false, |f| f == conn.account.jid)
    && s.attr("to").map_or(false, |f| f == conn.account.jid)
    {
    Ok(true)
    } else {
    Ok(false)
  • replacement in src/xmpp/element_processor.rs at line 0
    [3.11301][2.42803:43905]()
    type Func<S, T, E> = dyn Fn(&mut S, E) -> T;
    /// TryFrom based visitor
    pub struct Processor<S: 'static, T: 'static, E: Clone + 'static> {
    processors: Vec<Box<Func<S, Option<T>, E>>>,
    default: &'static Func<S, T, E>,
    }
    impl<S: 'static, T: 'static, E: Clone + 'static> Processor<S, T, E> {
    pub fn new<F>(f: &'static F) -> Processor<S, T, E>
    where
    F: Fn(&mut S, E) -> T + 'static,
    {
    Processor {
    processors: vec![],
    default: f,
    }
    }
    pub fn register<F, A>(&mut self, f: &'static F)
    where
    F: Fn(&mut S, A) -> T + 'static,
    A: std::convert::TryFrom<E>,
    {
    self.processors.push(Box::new(move |s, e: E| {
    use std::convert::TryInto;
    (e.try_into().ok() as Option<A>).map(|a| f(s, a))
    }));
    }
    pub fn process(&self, s: &mut S, e: E) -> T {
    for processor in self.processors.iter() {
    match processor(s, e.clone()) {
    Some(t) => return t,
    None => continue,
    }
    }
    (*self.default)(s, e)
    }
    }
    [3.11301]
    type Func<S, T, E> = dyn Fn(&mut S, E) -> T;
    /// TryFrom based visitor
    pub struct Processor<S: 'static, T: 'static, E: Clone + 'static> {
    processors: Vec<Box<Func<S, Option<T>, E>>>,
    default: &'static Func<S, T, E>,
    }
    impl<S: 'static, T: 'static, E: Clone + 'static> Processor<S, T, E> {
    pub fn new<F>(f: &'static F) -> Processor<S, T, E>
    where
    F: Fn(&mut S, E) -> T + 'static,
    {
    Processor {
    processors: vec![],
    default: f,
    }
    }
    pub fn register<F, A>(&mut self, f: &'static F)
    where
    F: Fn(&mut S, A) -> T + 'static,
    A: std::convert::TryFrom<E>,
    {
    self.processors.push(Box::new(move |s, e: E| {
    use std::convert::TryInto;
    (e.try_into().ok() as Option<A>).map(|a| f(s, a))
    }));
    }
    pub fn process(&self, s: &mut S, e: E) -> T {
    for processor in self.processors.iter() {
    match processor(s, e.clone()) {
    Some(t) => return t,
    None => continue,
    }
    }
    (*self.default)(s, e)
    }
    }
  • edit in src/main.rs at line 215
    [3.49351]
    [3.49388]
    use hyper::rt::{Future, Stream};
  • replacement in src/config.rs at line 0
    [3.1396][3.46318:46349]()
    use std::collections::HashMap;
    [3.1396]
    [3.1397]
    use std::collections::{HashMap, HashSet};
  • edit in src/config.rs at line 13
    [3.46496]
    [3.1549]
    }
    #[derive(Debug, Deserialize)]
    pub struct CmdArgs {
    pub name: String,
    }
    /// Allowed sources of command
    #[derive(Debug, Deserialize, PartialEq, Eq, Hash)]
    pub enum Source {
    /// Direct message
    Message,
    /// Groupchat message
    GroupChat,
    /// Private groupchat message
    PrivateGroupChat,
    }
    /// Command to execute
    #[derive(Debug, Deserialize)]
    pub struct Command {
    pub source: HashSet<Source>,
    /// Command arguments
    pub args: Vec<CmdArgs>,
  • edit in src/config.rs at line 43
    [3.1664]
    [3.1664]
    /// map from command name to command definition
    pub commands: HashMap<String, Command>,
  • replacement in Cargo.toml at line 15
    [3.52750][3.47527:47540]()
    toml = "0.5"
    [3.52750]
    [3.52763]
    toml = "0.4"
  • replacement in Cargo.toml at line 21
    [3.54573][3.47541:47563]()
    xmpp-parsers = "0.13"
    [3.54573]
    [3.54595]
    xmpp-parsers = "0.12.2"
  • edit in Cargo.toml at line 23
    [3.54630]
    try_from = "=0.3.2" # xmpp-parsers
  • edit in Cargo.lock at line 2
    [3.47733]
    [3.53201]
    [[package]]
    name = "MacTypes-sys"
    version = "2.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
  • replacement in Cargo.lock at line 12
    [3.53235][3.47807:47825]()
    version = "0.7.3"
    [3.53235]
    [3.53253]
    version = "0.6.10"
  • replacement in Cargo.lock at line 23
    [3.53543][3.47900:47973]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.53543]
    [3.53616]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 28
    [3.53649][2.43906:43925]()
    version = "0.3.11"
    [3.53649]
    [3.46847]
    version = "0.3.7"
  • replacement in Cargo.lock at line 44
    [3.54069][2.43926:44072](),[2.44072][3.48067:48140](),[3.54215][3.48067:48140]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.54069]
    [3.54288]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 56
    [3.54435][3.48141:48160]()
    version = "0.3.15"
    [3.54435]
    [3.54454]
    version = "0.3.14"
  • replacement in Cargo.lock at line 61
    [3.55649][3.48161:48234](),[3.48234][2.44073:44145](),[2.44145][3.48306:48461](),[3.48306][3.48306:48461]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55649]
    [3.54991]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 72
    [3.55130][3.48462:48532](),[3.48532][2.44146:44218]()
    "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55130]
    [3.55272]
    "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 102
    [3.56068][2.44219:44237]()
    version = "0.7.3"
    [3.56068]
    [3.56538]
    version = "0.7.0"
  • replacement in Cargo.lock at line 105
    [3.56620][2.44238:44318]()
    "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.56620]
    [3.56635]
    "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 113
    [3.56907][2.44319:44337]()
    version = "0.1.4"
    [3.56907]
    [3.56925]
    version = "0.1.3"
  • replacement in Cargo.lock at line 131
    [3.56958][3.48624:48643]()
    version = "0.4.12"
    [3.56958]
    [3.56977]
    version = "0.4.11"
  • replacement in Cargo.lock at line 145
    [3.57344][3.48644:48663]()
    version = "1.0.35"
    [3.57344]
    [3.57363]
    version = "1.0.30"
  • replacement in Cargo.lock at line 150
    [3.57457][3.48664:48682]()
    version = "0.1.7"
    [3.57457]
    [3.57475]
    version = "0.1.6"
  • replacement in Cargo.lock at line 165
    [3.57926][3.48683:48702]()
    version = "2.33.0"
    [3.57926]
    [3.57945]
    version = "2.32.0"
  • replacement in Cargo.lock at line 171
    [3.58251][3.48703:48852]()
    "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.58251]
    [3.58400]
    "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 187
    [3.58802][2.44338:44356]()
    version = "0.6.4"
    [3.58802]
    [3.58820]
    version = "0.5.1"
  • replacement in Cargo.lock at line 190
    [3.58902][2.44357:44515]()
    "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.58902]
    [3.59060]
    "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 196
    [3.59104][2.44516:44534]()
    version = "0.6.2"
    [3.59104]
    [3.59638]
    version = "0.5.1"
  • edit in Cargo.lock at line 198
    [3.59703]
    [3.60184]
    dependencies = [
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
  • replacement in Cargo.lock at line 217
    [3.71853][3.49018:49091]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.71853]
    [3.71926]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 237
    [3.60544][3.49394:49467]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60544]
    [3.49467]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 273
    [3.61686][3.49566:49639]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61686]
    [3.61759]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 278
    [3.61794][3.49640:49658]()
    version = "0.6.1"
    [3.61794]
    [3.61812]
    version = "0.6.0"
  • replacement in Cargo.lock at line 284
    [3.59057][2.44535:44607]()
    "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59057]
    [3.62184]
    "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 293
    [3.62396][3.49732:49809]()
    "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62396]
    [3.62473]
    "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 301
    [3.62605][3.49810:49887]()
    "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62605]
    [3.59304]
    "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 310
    [3.62902][2.44608:44687](),[2.44687][3.49888:49961](),[3.59484][3.49888:49961](),[3.49961][2.44688:44760]()
    "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62902]
    [3.59629]
    "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 369
    [3.64642][3.50123:50142]()
    version = "0.1.26"
    [3.64642]
    [3.64661]
    version = "0.1.25"
  • replacement in Cargo.lock at line 377
    [3.64864][3.50143:50218]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64864]
    [3.50218]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 391
    [3.65256][3.50295:50314]()
    version = "0.1.18"
    [3.65256]
    [3.65275]
    version = "0.1.16"
  • replacement in Cargo.lock at line 395
    [3.60207][3.50315:50388]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60207]
    [3.65506]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 397
    [3.65576][3.50389:50536]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.65576]
    [3.65723]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 420
    [3.66500][2.44761:44833]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.66500]
    [3.66572]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 426
    [3.66675][3.50687:50706]()
    version = "0.1.17"
    [3.66675]
    [3.66694]
    version = "0.1.16"
  • replacement in Cargo.lock at line 429
    [3.66776][3.50707:50780]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.66776]
    [3.66849]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 449
    [3.67346][3.50781:50801]()
    version = "0.12.27"
    [3.67346]
    [3.67366]
    version = "0.12.25"
  • replacement in Cargo.lock at line 452
    [3.67448][3.50802:50950]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.67448]
    [3.67596]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 455
    [3.67678][3.50951:51093]()
    "h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.67678]
    [3.67820]
    "h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 464
    [3.61721][2.44834:44907](),[2.44907][3.51248:51329](),[3.51248][3.51248:51329]()
    "tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61721]
    [3.51329]
    "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 469
    [3.62107][2.44908:44992]()
    "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62107]
    [3.62191]
    "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 494
    [3.69566][2.44993:45065]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.69566]
    [3.69638]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 506
    [3.70073][3.51644:51717]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70073]
    [3.70146]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 551
    [3.71348][2.45066:45085]()
    version = "0.2.53"
    [3.71348]
    [3.71367]
    version = "0.2.49"
  • replacement in Cargo.lock at line 556
    [3.71470][3.51757:51775]()
    version = "0.5.2"
    [3.71470]
    [3.71488]
    version = "0.4.2"
  • replacement in Cargo.lock at line 573
    [3.54885][3.51776:51849]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.54885]
    [3.72039]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 578
    [3.72073][3.51850:51868]()
    version = "0.1.2"
    [3.72073]
    [3.72091]
    version = "0.1.1"
  • replacement in Cargo.lock at line 581
    [3.72173][3.51869:51951]()
    "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.72173]
    [3.72255]
    "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 596
    [3.63314][3.51952:52105]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.63314]
    [3.52105]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 639
    [3.63968][2.45086:45158]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.63968]
    [3.64040]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 653
    [3.74980][2.45159:45231]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.74980]
    [3.75052]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 670
    [3.75588][2.45232:45250]()
    version = "0.2.3"
    [3.75588]
    [3.75606]
    version = "0.2.2"
  • replacement in Cargo.lock at line 674
    [3.52505][2.45251:45323]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.52505]
    [3.64406]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 676
    [3.64476][3.52578:52654]()
    "openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64476]
    [3.75984]
    "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 678
    [3.76064][3.52655:52734]()
    "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76064]
    [3.52734]
    "openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 680
    [3.52810][2.45324:45498]()
    "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.52810]
    [3.52811]
    "security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 690
    [3.76598][3.52887:52960](),[3.52960][2.45499:45571](),[2.45571][3.53032:53105](),[3.53032][3.53032:53105]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76598]
    [3.76816]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 723
    [3.77520][2.45572:45644]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.77520]
    [3.77592]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 727
    [3.65322][2.45645:45757]()
    name = "numtoa"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    [[package]]
  • replacement in Cargo.lock at line 733
    [3.77742][3.53218:53238]()
    version = "0.10.20"
    [3.77742]
    [3.77762]
    version = "0.10.19"
  • replacement in Cargo.lock at line 737
    [3.77919][3.53239:53312]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.77919]
    [3.77992]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 740
    [3.53391][2.45758:45830](),[2.45830][3.53463:53542](),[3.53463][3.53463:53542]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.53391]
    [3.78301]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 751
    [3.78456][3.53543:53562]()
    version = "0.9.43"
    [3.78456]
    [3.78475]
    version = "0.9.42"
  • replacement in Cargo.lock at line 754
    [3.78557][3.53563:53633](),[3.53633][2.45831:45903]()
    "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.78557]
    [3.78699]
    "cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 783
    [3.79584][2.45904:45976]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.79584]
    [3.66285]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 787
    [3.53935][3.53935:54008]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.53935]
    [3.66505]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 850
    [3.81639][2.45977:45996]()
    version = "0.4.29"
    [3.81639]
    [3.81658]
    version = "0.4.27"
  • replacement in Cargo.lock at line 879
    [3.82508][3.54183:54202]()
    version = "0.6.12"
    [3.82508]
    [3.82527]
    version = "0.6.11"
  • replacement in Cargo.lock at line 882
    [3.82609][2.45997:46076]()
    "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.82609]
    [3.82688]
    "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 892
    [3.67870][2.46077:46149]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.67870]
    [3.67942]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 894
    [3.68018][3.54276:54349]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68018]
    [3.83193]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 903
    [3.68266][2.46150:46222]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68266]
    [3.68338]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 909
    [3.68721][3.54423:54497]()
    "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68721]
    [3.54497]
    "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 912
    [3.68950][3.54573:54646]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68950]
    [3.69023]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 958
    [3.69961][2.46223:46295]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.69961]
    [3.70033]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 960
    [3.70109][3.54720:54793]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70109]
    [3.70182]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 965
    [3.70214][3.54794:54812]()
    version = "0.1.3"
    [3.70214]
    [3.70232]
    version = "0.1.2"
  • replacement in Cargo.lock at line 970
    [3.70469][2.46296:46368]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70469]
    [3.70541]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 973
    [3.70690][3.54886:54959]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70690]
    [3.70763]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1003
    [3.86863][3.55130:55149]()
    version = "0.1.54"
    [3.86863]
    [3.86882]
    version = "0.1.51"
  • replacement in Cargo.lock at line 1011
    [3.87083][3.55150:55231]()
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87083]
    [3.87164]
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1016
    [3.87194][2.46369:46387]()
    version = "1.1.6"
    [3.87194]
    [3.87212]
    version = "1.1.2"
  • replacement in Cargo.lock at line 1019
    [3.87294][3.55251:55330]()
    "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87294]
    [3.55330]
    "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1021
    [3.55403][3.55403:55482]()
    "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55403]
    [3.87525]
    "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1028
    [3.87719][3.55483:55501]()
    version = "0.6.6"
    [3.87719]
    [3.87737]
    version = "0.6.5"
  • replacement in Cargo.lock at line 1039
    [3.88033][3.55502:55575]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.88033]
    [3.88106]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1053
    [3.88434][3.55576:55595]()
    version = "0.1.14"
    [3.88434]
    [3.88453]
    version = "0.1.13"
  • replacement in Cargo.lock at line 1077
    [3.72302][3.55596:55670]()
    "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.72302]
    [3.72376]
    "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1088
    [3.55769][3.55769:55842]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55769]
    [3.89685]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1098
    [3.89844][2.46388:46406]()
    version = "0.3.1"
    [3.89844]
    [3.89862]
    version = "0.2.2"
  • replacement in Cargo.lock at line 1101
    [3.89944][2.46407:46736]()
    "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
    "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.89944]
    [3.90273]
    "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1109
    [3.90320][2.46737:46755]()
    version = "0.3.1"
    [3.90320]
    [3.90338]
    version = "0.2.3"
  • replacement in Cargo.lock at line 1112
    [3.90420][2.46756:46842]()
    "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.90420]
    [3.90657]
    "MacTypes-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1134
    [3.91027][3.55989:56138]()
    "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.91027]
    [3.73194]
    "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1137
    [3.73268][3.56139:56213]()
    "hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.73268]
    [3.73420]
    "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1140
    [3.73565][3.56292:56445](),[3.56445][2.46843:46916]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.73565]
    [3.91695]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1146
    [3.73948][3.56519:56670]()
    "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "xmpp-parsers 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.73948]
    [3.92082]
    "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
    "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "xmpp-parsers 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1153
    [3.92112][3.56671:56690]()
    version = "1.0.90"
    [3.92112]
    [3.92131]
    version = "1.0.89"
  • replacement in Cargo.lock at line 1158
    [3.92231][3.56691:56710]()
    version = "1.0.90"
    [3.92231]
    [3.92250]
    version = "1.0.89"
  • replacement in Cargo.lock at line 1161
    [3.92332][2.46917:46996](),[2.46996][3.56711:56784](),[3.74219][3.56711:56784](),[3.56784][2.46997:47069]()
    "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.92332]
    [3.92556]
    "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1173
    [3.74455][3.56877:56950]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.74455]
    [3.92906]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1181
    [3.93036][2.47070:47149]()
    "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.93036]
    [3.74627]
    "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1192
    [3.93472][2.47150:47229]()
    "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.93472]
    [3.74879]
    "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1200
    [3.93808][2.47230:47248]()
    version = "0.8.2"
    [3.93808]
    [3.93826]
    version = "0.8.1"
  • replacement in Cargo.lock at line 1203
    [3.93908][2.47249:47328]()
    "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.93908]
    [3.75131]
    "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1212
    [3.94325][2.47329:47651]()
    version = "0.1.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "signal-hook-registry 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
    [[package]]
    name = "signal-hook-registry"
    version = "1.0.0"
    [3.94325]
    [3.94343]
    version = "0.1.8"
  • replacement in Cargo.lock at line 1215
    [3.94425][2.47652:47800]()
    "arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.94425]
    [3.94573]
    "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1239
    [3.95044][3.57378:57451](),[3.57451][2.47801:47873](),[2.47873][3.57523:57677](),[3.57523][3.57523:57677]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.95044]
    [3.95343]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1264
    [3.96043][3.57845:57918]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.96043]
    [3.96116]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1276
    [3.76365][2.47874:47953](),[2.47953][3.57919:57992](),[3.76444][3.57919:57992]()
    "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76365]
    [3.96745]
    "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1288
    [3.96987][3.57993:58011]()
    version = "0.8.0"
    [3.96987]
    [3.76536]
    version = "0.7.0"
  • replacement in Cargo.lock at line 1308
    [3.97562][2.47954:47974]()
    version = "0.15.33"
    [3.97562]
    [3.97582]
    version = "0.15.27"
  • replacement in Cargo.lock at line 1311
    [3.97664][2.47975:48054](),[2.48054][3.58033:58106](),[3.76749][3.58033:58106]()
    "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.97664]
    [3.97816]
    "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1329
    [3.98241][2.48055:48134](),[2.48134][3.58107:58180](),[3.76922][3.58107:58180](),[3.58180][2.48135:48207]()
    "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.98241]
    [3.98465]
    "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1340
    [3.98676][3.58272:58345](),[3.58345][2.48208:48280]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.98676]
    [3.77232]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1343
    [3.77303][3.58418:58499]()
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.77303]
    [3.98973]
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1345
    [3.99054][3.58500:58573]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.99054]
    [3.99127]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1368
    [3.99713][2.48281:48299]()
    version = "1.5.2"
    [3.99713]
    [3.99731]
    version = "1.5.1"
  • replacement in Cargo.lock at line 1371
    [3.99813][2.48300:48445](),[2.48445][3.58646:58727](),[3.58646][3.58646:58727]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.99813]
    [3.99966]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1378
    [3.100079][3.58728:58747]()
    version = "0.11.0"
    [3.100079]
    [3.100098]
    version = "0.10.0"
  • replacement in Cargo.lock at line 1397
    [3.100605][2.48446:48518](),[2.48518][3.58899:59053](),[3.58899][3.58899:59053]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.100605]
    [3.100831]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1404
    [3.100861][2.48519:48538]()
    version = "0.1.19"
    [3.100861]
    [3.100880]
    version = "0.1.16"
  • replacement in Cargo.lock at line 1407
    [3.100962][3.59074:59222]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.100962]
    [3.101110]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1412
    [3.101335][3.59300:59468]()
    "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.101335]
    [3.59468]
    "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1417
    [3.59699][2.48539:48616]()
    "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59699]
    [3.78773]
    "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1419
    [3.78849][2.48617:48701]()
    "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.78849]
    [3.78933]
    "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1421
    [3.79012][3.59862:59945]()
    "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1430
    [3.102423][3.59946:60021]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.102423]
    [3.102498]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1438
    [3.102634][3.60022:60170]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.102634]
    [3.60170]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1445
    [3.102903][3.60247:60265]()
    version = "0.1.6"
    [3.102903]
    [3.102921]
    version = "0.1.5"
  • replacement in Cargo.lock at line 1448
    [3.103003][3.60266:60422]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.103003]
    [3.103159]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1454
    [3.103198][3.60423:60441]()
    version = "0.1.7"
    [3.103198]
    [3.103216]
    version = "0.1.6"
  • replacement in Cargo.lock at line 1458
    [3.79826][3.60442:60517]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.79826]
    [3.103455]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1466
    [3.103588][3.60537:60612]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.103588]
    [3.60612]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1468
    [3.60688][2.48702:48786]()
    "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60688]
    [3.103823]
    "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1476
    [3.103957][3.60793:60941]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.103957]
    [3.80325]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1487
    [3.80497][3.60961:61036]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.80497]
    [3.61036]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1494
    [3.80946][3.61192:61273]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.80946]
    [3.61273]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1496
    [3.61349][2.48787:48864]()
    "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61349]
    [3.105148]
    "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1504
    [3.105285][3.61427:61502](),[3.61502][2.48865:48937]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.105285]
    [3.105432]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1508
    [3.105577][2.48938:49016](),[2.49016][3.61653:61734](),[3.61653][3.61653:61734]()
    "signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.105577]
    [3.61734]
    "signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1512
    [3.61890][3.61890:61963](),[3.61890][3.61890:61963]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61890]
    [3.81736]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1517
    [3.81771][2.49017:49035]()
    version = "0.1.5"
    [3.81771]
    [3.81789]
    version = "0.1.3"
  • replacement in Cargo.lock at line 1521
    [3.62053][3.62053:62128]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62053]
    [3.105965]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1529
    [3.106379][3.62129:62277]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.106379]
    [3.106527]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1539
    [3.106867][2.49036:49055]()
    version = "0.1.14"
    [3.106867]
    [3.106886]
    version = "0.1.12"
  • replacement in Cargo.lock at line 1545
    [3.82608][3.62620:62695]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.82608]
    [3.82683]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1550
    [3.82971][3.62773:62854]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.82971]
    [3.107658]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1559
    [3.83155][3.62855:62930]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.83155]
    [3.83230]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1561
    [3.83301][3.62931:63012]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.83301]
    [3.108104]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1569
    [3.108238][3.63013:63088](),[3.63088][2.49056:49133]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.108238]
    [3.63089]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1575
    [3.63180][3.63180:63384](),[3.63180][3.63180:63384](),[3.86070][3.83554:83569](),[3.63384][3.83554:83569](),[3.83554][3.83554:83569]()
    name = "tokio-trace-core"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
    [[package]]
  • replacement in Cargo.lock at line 1579
    [3.108819][3.63385:63533]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.108819]
    [3.83941]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1593
    [3.109476][3.63691:63839]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.109476]
    [3.109624]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1596
    [3.109696][2.49134:49206]()
    "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.109696]
    [3.84409]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1610
    [3.110352][3.64070:64143]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.110352]
    [3.110425]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1612
    [3.110504][3.64144:64219]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.110504]
    [3.110579]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1614
    [3.110650][2.49207:49284]()
    "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.110650]
    [3.64220]
    "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1617
    [3.85032][2.49285:49358]()
    "tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.85032]
    [3.110948]
    "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1629
    [3.111531][3.64449:64467]()
    version = "0.5.0"
    [3.111531]
    [3.111549]
    version = "0.4.10"
  • replacement in Cargo.lock at line 1632
    [3.111631][3.64468:64541]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.111631]
    [3.111704]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1642
    [3.85845][3.64542:64617]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.85845]
    [3.112069]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1649
    [3.112508][3.64773:64854]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.112508]
    [3.64854]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1663
    [3.113190][3.65011:65084]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.113190]
    [3.86848]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1665
    [3.86922][3.65085:65160]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.86922]
    [3.86997]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1669
    [3.87220][3.65240:65316]()
    "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87220]
    [3.87296]
    "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1672
    [3.65392][2.49359:49432]()
    "tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.65392]
    [3.87522]
    "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1686
    [3.87641][3.65466:65539]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87641]
    [3.87714]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1765
    [3.116272][3.65616:65691]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.116272]
    [3.87982]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1782
    [3.116751][3.65692:65710]()
    version = "0.3.7"
    [3.116751]
    [3.116769]
    version = "0.3.6"
  • replacement in Cargo.lock at line 1804
    [3.117425][3.65711:65784]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.117425]
    [3.117498]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1817
    [3.117765][3.65785:65858]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.117765]
    [3.88238]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1826
    [3.118047][3.65859:65932]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.118047]
    [3.118120]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1834
    [3.118252][3.65933:66006]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.118252]
    [3.118325]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1870
    [3.89236][2.49433:49504]()
    "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.89236]
    [3.89307]
    "sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1872
    [3.89382][3.66007:66726](),[3.66726][2.49505:49576]()
    ]
    [[package]]
    name = "xmpp-parsers"
    version = "0.13.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "jid 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
    "minidom 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1875
    [3.90328][3.66798:66953]()
    "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
    [3.120705]
    [3.121015]
    "checksum MacTypes-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eaf9f0d0b1cc33a4d2aee14fb4b2eac03462ef4db29c8ac4057327d8a71ad86f"
    "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
  • replacement in Cargo.lock at line 1878
    [3.121168][2.49577:49729]()
    "checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
    [3.121168]
    [3.90636]
    "checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6"
  • replacement in Cargo.lock at line 1882
    [3.90939][3.67107:67260]()
    "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
    [3.90939]
    [3.91092]
    "checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
  • replacement in Cargo.lock at line 1887
    [3.91549][2.49730:50041]()
    "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
    "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09"
    [3.91549]
    [3.91860]
    "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d"
    "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591"
  • replacement in Cargo.lock at line 1891
    [3.92165][3.67417:67566]()
    "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
    [3.92165]
    [3.123295]
    "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
  • replacement in Cargo.lock at line 1893
    [3.123442][3.67567:67862]()
    "checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
    "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
    [3.123442]
    [3.123737]
    "checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92"
    "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
  • replacement in Cargo.lock at line 1896
    [3.123886][3.67863:68011]()
    "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
    [3.123886]
    [3.124034]
    "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
  • replacement in Cargo.lock at line 1898
    [3.124185][2.50042:50362]()
    "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
    "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
    [3.124185]
    [3.68012]
    "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980"
    "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa"
  • replacement in Cargo.lock at line 1908
    [3.68485][3.68485:68638]()
    "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
    [3.68485]
    [3.125902]
    "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
  • replacement in Cargo.lock at line 1920
    [3.127601][3.68639:68790]()
    "checksum futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981"
    [3.127601]
    [3.127752]
    "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
  • replacement in Cargo.lock at line 1923
    [3.94778][3.68791:68937]()
    "checksum h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "85ab6286db06040ddefb71641b50017c06874614001a134b423783e2db2920bd"
    [3.94778]
    [3.94924]
    "checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e"
  • replacement in Cargo.lock at line 1926
    [3.128511][3.68938:69086]()
    "checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a"
    [3.128511]
    [3.128659]
    "checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a"
  • replacement in Cargo.lock at line 1929
    [3.95373][3.69087:69237]()
    "checksum hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4f2777434f26af6e4ce4fdcdccd3bed9d861d11e87bcbe72c0f51ddaca8ff848"
    [3.95373]
    [3.129112]
    "checksum hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5b6658b016965ae301fa995306db965c93677880ea70765a84235a96eae896"
  • replacement in Cargo.lock at line 1940
    [3.96128][2.50363:50511](),[2.50511][3.69541:69699](),[3.69541][3.69541:69699]()
    "checksum libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)" = "ec350a9417dfd244dc9a6c4a71e13895a4db6b92f0b106f07ebbc3f3bc580cee"
    "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
    [3.96128]
    [3.96434]
    "checksum libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)" = "413f3dfc802c5dc91dc570b05125b6cda9855edfaa9825c9849807876376e70e"
    "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
  • replacement in Cargo.lock at line 1944
    [3.96731][3.69700:69852]()
    "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
    [3.96731]
    [3.131366]
    "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21"
  • replacement in Cargo.lock at line 1954
    [3.132712][2.50512:50665]()
    "checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
    [3.132712]
    [3.132865]
    "checksum native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8e08de0070bbf4c31f452ea2a70db092f36f6f2e4d897adf5674477d488fb2"
  • edit in Cargo.lock at line 1961
    [3.70320][2.50666:50815]()
    "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
  • replacement in Cargo.lock at line 1962
    [3.97963][3.70321:70473]()
    "checksum openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)" = "5a0d6b781aac4ac1bd6cafe2a2f0ad8c16ae8e1dd5184822a16c50139f8838d9"
    [3.97963]
    [3.134094]
    "checksum openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)" = "84321fb9004c3bce5611188a644d6171f895fa2889d155927d528782edb21c5d"
  • replacement in Cargo.lock at line 1964
    [3.134250][3.70474:70629]()
    "checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d"
    [3.134250]
    [3.98271]
    "checksum openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cb534d752bf98cf363b473950659ac2546517f9c6be9723771614ab3f03bbc9e"
  • replacement in Cargo.lock at line 1976
    [3.136105][2.50816:50971]()
    "checksum proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)" = "64c827cea7a7ab30ce4593e5e04d7a11617ad6ece2fa230605a78b00ff965316"
    [3.136105]
    [3.136260]
    "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
  • replacement in Cargo.lock at line 1980
    [3.136716][3.70784:70933]()
    "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
    [3.136716]
    [3.99960]
    "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
  • replacement in Cargo.lock at line 1989
    [3.101169][3.70934:71084]()
    "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
    [3.101169]
    [3.71084]
    "checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
  • replacement in Cargo.lock at line 1993
    [3.101775][3.71236:71393]()
    "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
    [3.101775]
    [3.138837]
    "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
  • replacement in Cargo.lock at line 1995
    [3.138993][2.50972:51120](),[2.51120][3.71542:71697](),[3.71542][3.71542:71697]()
    "checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
    "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
    [3.138993]
    [3.139296]
    "checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f"
    "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
  • replacement in Cargo.lock at line 1999
    [3.102391][3.71698:71856]()
    "checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
    [3.102391]
    [3.139765]
    "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
  • replacement in Cargo.lock at line 2005
    [3.140519][2.51121:51447]()
    "checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
    "checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
    [3.140519]
    [3.140845]
    "checksum security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfab8dda0e7a327c696d893df9ffa19cadc4bd195797997f5223cf5831beaf05"
    "checksum security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d6696852716b589dff9e886ff83778bb635150168e83afa8ac6b8a78cb82abc"
  • replacement in Cargo.lock at line 2009
    [3.141150][3.72010:72315]()
    "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4"
    "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79"
    [3.141150]
    [3.72315]
    "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560"
    "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c"
  • replacement in Cargo.lock at line 2014
    [3.104077][2.51448:51912]()
    "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
    "checksum signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "72ab58f1fda436857e6337dcb6a5aaa34f16c5ddc87b3a8b6ef7a212f90b9c5a"
    "checksum signal-hook-registry 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "591fe2ee5a2412968f63a008a190d99918c2cda3f616411026f0975715e1cf62"
    [3.104077]
    [3.142205]
    "checksum sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a"
    "checksum signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "97a47ae722318beceb0294e6f3d601205a1e6abaa4437d9d33e3a212233e3021"
  • replacement in Cargo.lock at line 2025
    [3.143595][3.72777:72926]()
    "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
    [3.143595]
    [3.104977]
    "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
  • replacement in Cargo.lock at line 2028
    [3.144041][2.51913:52061]()
    "checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836"
    [3.144041]
    [3.144189]
    "checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec"
  • replacement in Cargo.lock at line 2034
    [3.144947][2.52062:52212](),[2.52212][3.73228:73380](),[3.145097][3.73228:73380]()
    "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
    "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
    [3.144947]
    [3.145249]
    "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
    "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
  • replacement in Cargo.lock at line 2038
    [3.106035][2.52213:52362]()
    "checksum tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "cec6c34409089be085de9403ba2010b80e36938c9ca992c4f67f407bb13db0b1"
    [3.106035]
    [3.145701]
    "checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230"
  • replacement in Cargo.lock at line 2041
    [3.146011][3.73531:73851]()
    "checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
    "checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e"
    [3.146011]
    [3.73851]
    "checksum tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c756b04680eea21902a46fca4e9f410a2332c04995af590e07ff262e2193a9a3"
    "checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0"
  • replacement in Cargo.lock at line 2047
    [3.107119][2.52363:52516]()
    "checksum tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2f843ffdf8d6e1f90bddd48da43f99ab071660cd92b7ec560ef3cdfd7a409a"
    [3.107119]
    [3.107272]
    "checksum tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363"
  • replacement in Cargo.lock at line 2049
    [3.107424][2.52517:52677]()
    "checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2"
    [3.107424]
    [3.107584]
    "checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801"
  • edit in Cargo.lock at line 2052
    [3.107891][3.74626:74785]()
    "checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3"
  • replacement in Cargo.lock at line 2055
    [3.108507][3.74786:74933]()
    "checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e"
    [3.108507]
    [3.108654]
    "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
  • replacement in Cargo.lock at line 2075
    [3.151382][3.74934:75083]()
    "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
    [3.151382]
    [3.151531]
    "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
  • edit in Cargo.lock at line 2086
    [3.110506][3.75084:75240]()
    "checksum xmpp-parsers 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5094cec449beca92f82ae4d7fe13cda058005849766d71b86c23e6217f61a357"