Fix possible utf8 errors

[?]
Apr 14, 2019, 8:19 AM
OFLAP2G2GH52BDQ7LXXF7P3IMTNW6MS4RQPW3DX2HX4GAYVW6FLAC

Dependencies

  • [2] CCLGGFKR Move out XmppConnection into own file
  • [3] VS6AHRWI Move XMPP to separate dir
  • [4] V5HDBSZM Use jid for receiver address
  • [5] J7VX56FW ToDo
  • [6] 2VZBEEXA Messages fixed
  • [7] 5OBTKGDL Update deps
  • [8] VW7NVWAG Leave MUC properly
  • [9] NDDQQP2P Update deps
  • [10] DISBBP3I Update dependencies
  • [11] RGOSS73U Convert self-presence to xmpp_parser's type
  • [12] TPVUBB3F Answer to ping requests
  • [13] ZI4GJ72V Add message to xmpp command
  • [14] 5GINRCKL Send ping XEP-0199
  • [15] YZVEEOYT Update dependencies
  • [16] RRLRZTMR Use element processor for iq
  • [17] 5Y6YJ6UH Add shutdown function to make actions before offline
  • [18] LL3D5CXK Staring using element processor
  • [19] DCGEFPRC Better README
  • [20] OB3HA2MD Use Client::new_with_jid to parse jid only once
  • [21] UO4WTU6U Update dependencies
  • [22] FV6BJ5K6 Send self-presence and store account info in Rc so it willbe used in some future in parallel
  • [23] FCPF2FV6 Break connection on iq error
  • [24] 5A5UVGNM Move receiver closing logic out of xmpp processing
  • [25] AYQZ2UIA Update deps
  • [26] HU3NZX5Z Process self-presence via new processing code
  • [27] L3D22A5J Prepare to check incoming presence
  • [28] AA2ZWGRL Enter to MUC
  • [29] QYY3KRGL Use failure instead Box<dyn Error>
  • [30] WBU7UOQW Read chatroom from config
  • [31] 5IKA4GO7 Rename xmpp client field from "inner" to "client"
  • [32] JD62RVOJ Update dependencies
  • [33] OGMBXBKP Move online to XmppConnection
  • [34] X6L47BHQ Use different structure for established xmpp connection
  • [35] FVVPKFTL Initial commit
  • [36] ACXUIS63 Update dependecies
  • [37] EOHEZXX3 Move request processing to structure
  • [38] SYH7UQP6 Make xmpp command enum to allow different commands Save subscription ask status. Don't ask if already requested subscription.
  • [39] HKSQO7JZ Enable hyper http server and configuration
  • [40] IK3YDPTY Update deps

Change contents

  • replacement in src/xmpp/xmpp_connection.rs at line 0
    [2.21][2.22:29211]()
    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 super::XmppCommand;
    use super::stanzas;
    use super::element_processor;
    use crate::config;
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// ids counter
    counter: usize,
    /// map from id of adding item to roster and jid of item
    pending_add_roster_ids: HashMap<String, xmpp_parsers::Jid>,
    /// 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>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    pub struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: XmppState,
    }
    struct XmppElementProcessor {
    incoming: element_processor::Processor<XmppConnection, bool, xmpp_parsers::Element>,
    }
    impl XmppElementProcessor {
    fn new() -> XmppElementProcessor {
    let mut incoming = element_processor::Processor::new(&|_, e| {
    warn!("Unknown stanza {:#?}", e);
    true
    });
    incoming.register(&XmppConnection::incoming_iq_processing);
    XmppElementProcessor { incoming }
    }
    }
    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) => {
    let processors = XmppElementProcessor::new();
    processors.incoming.process(self, stanza.clone())
    }
    Event::Online => true,
    e => {
    warn!("Unexpected event {:?}", e);
    false
    }
    }
    }
    fn incoming_iq_processing(&mut self, iq: xmpp_parsers::iq::Iq) -> bool {
    use std::convert::TryInto;
    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);
    } 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);
    } else {
    warn!(
    "Wrong payload when adding {} to roster: {:?}",
    jid, iq.payload
    );
    }
    }
    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);
    }
    }
    }
    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);
    }
    }
    _ => (), // ignore
    }
    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)| {
    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 {:?}", 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: {:?}", s);
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    fn process_initial_roster(&mut self, event: Event, id_init_roster: &str) -> Result<bool, ()> {
    if let Event::Stanza(s) = event {
    use std::convert::TryInto;
    match s.try_into() as Result<xmpp_parsers::iq::Iq, _> {
    Ok(iq) => {
    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));
    }
    Ok(true)
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    Err(())
    }
    }
    }
    _ => {
    error!("Unknown result of roster");
    Err(())
    }
    }
    } else {
    Ok(false)
    }
    }
    Err(_e) => Ok(false),
    }
    } else {
    error!("Wrong event while waiting roster");
    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... {:?}", get_roster);
    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, event| conn.process_initial_roster(event, &id_init_roster),
    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... {:?}", 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, event| {
    if let Event::Stanza(s) = event {
    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)
    }
    }
    } else {
    error!("Wrong event while waiting self-presence");
    Err(())
    }
    },
    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());
    self.state
    .data
    .pending_add_roster_ids
    .insert(id_add_roster, xmpp_to.clone());
    info!("Adding jid to roster... {:?}", add_roster);
    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);
    }
    }
    }
    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... {:?}", 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... {:?}", 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,
    })
    }
    }
    [2.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 super::XmppCommand;
    use super::stanzas;
    use super::element_processor;
    use crate::config;
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// ids counter
    counter: usize,
    /// map from id of adding item to roster and jid of item
    pending_add_roster_ids: HashMap<String, xmpp_parsers::Jid>,
    /// 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>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    pub struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: XmppState,
    }
    struct XmppElementProcessor {
    incoming: element_processor::Processor<XmppConnection, bool, xmpp_parsers::Element>,
    }
    impl XmppElementProcessor {
    fn new() -> XmppElementProcessor {
    let mut incoming = element_processor::Processor::new(&|_, e| {
    warn!("Unknown stanza {:#?}", e);
    true
    });
    incoming.register(&XmppConnection::incoming_iq_processing);
    XmppElementProcessor { incoming }
    }
    }
    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) => {
    let processors = XmppElementProcessor::new();
    processors.incoming.process(self, stanza.clone())
    }
    Event::Online => true,
    e => {
    warn!("Unexpected event {:?}", e);
    false
    }
    }
    }
    fn incoming_iq_processing(&mut self, iq: xmpp_parsers::iq::Iq) -> bool {
    use std::convert::TryInto;
    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);
    } 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);
    } else {
    warn!(
    "Wrong payload when adding {} to roster: {:?}",
    jid, iq.payload
    );
    }
    }
    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);
    }
    }
    }
    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);
    }
    }
    _ => (), // ignore
    }
    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)| {
    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 {:?}", 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: {:?}", s);
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    fn process_initial_roster(&mut self, event: Event, id_init_roster: &str) -> Result<bool, ()> {
    if let Event::Stanza(s) = event {
    use std::convert::TryInto;
    match s.try_into() as Result<xmpp_parsers::iq::Iq, _> {
    Ok(iq) => {
    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));
    }
    Ok(true)
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    Err(())
    }
    }
    }
    _ => {
    error!("Unknown result of roster");
    Err(())
    }
    }
    } else {
    Ok(false)
    }
    }
    Err(_e) => Ok(false),
    }
    } else {
    error!("Wrong event while waiting roster");
    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... {:?}", get_roster);
    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, event| conn.process_initial_roster(event, &id_init_roster),
    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... {:?}", 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, event| {
    if let Event::Stanza(s) = event {
    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)
    }
    }
    } else {
    error!("Wrong event while waiting self-presence");
    Err(())
    }
    },
    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());
    self.state
    .data
    .pending_add_roster_ids
    .insert(id_add_roster, xmpp_to.clone());
    info!("Adding jid to roster... {:?}", add_roster);
    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);
    }
    }
    }
    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... {:?}", 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... {:?}", 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,
    })
    }
    }
  • edit in src/xmpp/stanzas.rs at line 4
    [3.57][3.57:87]()
    use xmpp_parsers::ping::Ping;
  • replacement in src/xmpp/stanzas.rs at line 17
    [3.196][3.131:257]()
    Iq::from_get(
    id,
    Roster {
    items: vec![],
    ver: None,
    },
    )
    .into()
    [3.196]
    [3.257]
    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 26
    [3.330][3.330:683]()
    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.330]
    [3.683]
    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()
  • edit in src/xmpp/stanzas.rs at line 46
    [2.29264][2.29264:29393](),[2.29393][3.812:864](),[3.812][3.812:864]()
    pub fn make_allow_subscribe(jid: xmpp_parsers::Jid) -> Element {
    let mut presence = Presence::new(PresenceType::Subscribed);
    presence.to = Some(jid);
    presence.into()
    }
  • edit in src/xmpp/stanzas.rs at line 67
    [3.157][3.357:359](),[3.161][3.357:359](),[3.196][3.357:359](),[3.126][3.357:359](),[3.1689][3.357:359](),[3.357][3.357:359](),[3.359][3.1690:1928]()
    }
    pub fn make_muc_presence_leave(from: xmpp_parsers::Jid, to: xmpp_parsers::Jid) -> Element {
    let mut presence = Presence::new(PresenceType::Unavailable);
    presence.from = Some(from);
    presence.to = Some(to);
    presence.into()
  • edit in src/xmpp/stanzas.rs at line 68
    [3.1930][3.1930:2362]()
    pub fn make_ping(id: &str, from: xmpp_parsers::Jid) -> Element {
    let mut ping = Iq::from_get(id, Ping);
    ping.to = Some(from.clone().into_domain_jid());
    ping.from = Some(from);
    ping.into()
    }
    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 0
    [3.17][2.29394:29446]()
    use tokio::prelude::future::{self, Either, Future};
    [3.17]
    [3.62]
    use tokio::prelude::future::{self, Either};
  • edit in src/xmpp/mod.rs at line 2
    [3.90]
    [3.197]
    use tokio::prelude::{Future, Stream};
    use tokio_xmpp::{Client, Event, Packet};
  • replacement in src/xmpp/mod.rs at line 8
    [3.377][3.377:400]()
    mod element_processor;
    [3.297]
    [3.3355]
    use std::collections::{HashMap, VecDeque};
  • edit in src/xmpp/mod.rs at line 11
    [2.29460]
    [3.16484]
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// ids counter
    counter: usize,
    /// map from id of adding item to roster and jid of item
    pending_add_roster_ids: HashMap<String, xmpp_parsers::Jid>,
    /// 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>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    struct MaybeXmppConnection {
    account: std::rc::Rc<config::Account>,
    state: Option<XmppState>,
    }
    struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: 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
    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
    fn xmpp_processing(
    mut self,
    event: &Event,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>> {
    match event {
    Event::Stanza(stanza) => {
    info!("Incoming xmpp event: {:?}", stanza);
    let stanza = stanza.clone();
    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);
    } else {
    warn!(
    "Wrong payload when adding {} to roster: {:?}",
    jid, iq.payload
    );
    }
    }
    }
    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));
    }
    self.process_jid(&i.jid);
    }
    }
    }
    }
    future::ok(self)
    }
    Event::Online => future::ok(self),
    e => {
    warn!("Unexpected event {:?}", e);
    future::err(self.account)
    }
    }
    }
    /// 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
    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)| {
    let XmppConnection {
    state: XmppState { client, mut data },
    account,
    } = xmpp;
  • replacement in src/xmpp/mod.rs at line 246
    [3.16485][2.29461:29524]()
    mod xmpp_connection;
    use xmpp_connection::MaybeXmppConnection;
    [3.16485]
    [3.20740]
    if let Some(send_element) = data.send_queue.pop_front() {
    use tokio::prelude::Sink;
    info!("Sending {:?}", 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 xmpp = XmppConnection {
    state: XmppState { client, data },
    account,
    };
    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)),
    )),
    }
    }
    Err(account) => {
    future::err((account, Ok(Either::A(b))))
    }
    }))
    as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    }
    Ok(Either::B((t, a))) => {
    Box::new(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);
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    Err(Either::B((e, a))) => {
    Box::new(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: {:?}", s);
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    fn process_initial_roster(&mut self, event: Event, id_init_roster: &str) -> Result<bool, ()> {
    if let Event::Stanza(s) = event {
    use try_from::TryInto;
    match s.try_into() as Result<xmpp_parsers::iq::Iq, _> {
    Ok(iq) => {
    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(())
    }
    }
    }
    _ => {
    error!("Unknown result of roster");
    Err(())
    }
    }
    } else {
    Ok(false)
    }
    } else {
    error!("Iq stanza without id");
    Err(())
    }
    }
    Err(_e) => Ok(false),
    }
    } else {
    error!("Wrong event while waiting roster");
    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... {:?}", get_roster);
    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, event| conn.process_initial_roster(event, &id_init_roster),
    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... {:?}", 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, event| {
    if let Event::Stanza(s) = event {
    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)
    }
    } else {
    error!("Wrong event while waiting self-presence");
    Err(())
    }
    },
    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()));
    }
    } 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());
    self.state
    .data
    .pending_add_roster_ids
    .insert(id_add_roster, xmpp_to.clone());
    info!("Adding jid to roster... {:?}", add_roster);
    self.state.data.send_queue.push_back(add_roster);
    }
    }
    }
    }
    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);
    }
    }
    }
    }
    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... {:?}", 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,
    })
    }
    }
  • edit in src/xmpp/mod.rs at line 673
    [3.23323][3.23323:23333]()
    Ping,
  • replacement in src/xmpp/mod.rs at line 722
    [3.23805][3.23805:23949]()
    error!("Command receiver is gone");
    future::ok(future::Loop::Break(Some(conn)))
    [3.23805]
    [3.23949]
    future::err(format_err!("Command receiver is gone"))
  • replacement in src/xmpp/mod.rs at line 735
    [3.24895][3.24297:24373]()
    future::ok(future::Loop::Break(Some(conn)))
    [3.24895]
    [3.24963]
    future::ok(future::Loop::Break(()))
  • replacement in src/xmpp/mod.rs at line 738
    [3.2257][3.24374:24574]()
    Err(_) => {
    error!("Command receiver is broken");
    future::ok(future::Loop::Break(Some(conn)))
    }
    [3.2257]
    [3.25109]
    Err(_) => future::err(format_err!("Command receiver is broken")),
  • replacement in src/xmpp/mod.rs at line 761
    [3.26249][3.24627:24697]()
    future::ok(future::Loop::Break(None))
    [3.26249]
    [3.26317]
    future::ok(future::Loop::Break(()))
  • edit in src/xmpp/mod.rs at line 768
    [3.26491][3.24722:24938]()
    })
    .and_then(|opt_conn| {
    if let Some(conn) = opt_conn {
    Box::new(conn.shutdown()) as Box<dyn Future<Item = (), Error = _>>
    } else {
    Box::new(future::ok(()))
    }
  • replacement in src/xmpp/element_processor.rs at line 0
    [3.11301][2.29525:30601]()
    type Func<S, T, E> = dyn Fn(&mut S, E) -> T;
    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;
    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)
    }
    }
  • replacement in src/main.rs at line 27
    [3.4155][3.26046:26090]()
    use tokio::prelude::{Future, Sink, Stream};
    [3.4155]
    [3.4092]
    use tokio::prelude::{future, Future, Sink, Stream};
  • edit in src/main.rs at line 38
    [3.26092]
    [3.26092]
    /// Return future with body converted to String
  • replacement in src/main.rs at line 42
    [3.26249][3.26249:26410]()
    .fold(String::new(), |mut acc, ch| {
    std::str::from_utf8(&*ch).map(|s| {
    acc.push_str(s);
    acc
    })
    [3.26249]
    [3.26410]
    .fold(Vec::new(), |mut acc, ch| {
    acc.extend_from_slice(&*ch);
    future::ok::<_, failure::Error>(acc)
    })
    .and_then(|acc| {
    std::str::from_utf8(&acc)
    .map(std::string::ToString::to_string)
    .map_err(std::convert::Into::into)
  • replacement in src/main.rs at line 71
    [3.27159][3.27159:27259]()
    .and_then(|s| std::str::FromStr::from_str(s).map_err(std::convert::Into::into))
    [3.27159]
    [3.27259]
    .and_then(|s| {
    std::str::FromStr::from_str(s)
    .map_err(std::convert::Into::into)
    })
  • replacement in src/main.rs at line 236
    [3.5155][3.33339:33411](),[3.13203][3.11293:11304](),[3.33411][3.11293:11304](),[3.11293][3.11293:11304]()
    .serve(MakeServiceCmd {
    cmd_send: cmd_send.clone(),
    })
    [3.5155]
    [3.5935]
    .serve(MakeServiceCmd { cmd_send })
  • edit in src/main.rs at line 242
    [3.6049][3.33412:34224]()
    if let Some(ping) = config.account.ping {
    let ping = tokio::timer::Interval::new_interval(std::time::Duration::from_secs(ping));
    rt.spawn(
    ping.map_err(|e| {
    error!("Ping error: {}", e);
    })
    .for_each(move |_| {
    cmd_send
    .clone()
    .send(XmppCommand::Ping)
    .map_err(|e| {
    error!("Ping command error: {}", e);
    })
    .map(|_| ())
    })
    .select(
    ctrl_c
    .clone()
    .map(|_| ())
    .map_err(|e| error!("ping server error: {}", e)),
    )
    .map(|_| ())
    .map_err(|_| ()),
    );
    }
  • edit in src/config.rs at line 0
    [3.1396][3.34225:34256]()
    use std::collections::HashMap;
  • edit in src/config.rs at line 9
    [3.1549][3.34341:34487]()
    #[serde(default, deserialize_with = "deserialize_jid_map")]
    pub chatrooms: HashMap<String, xmpp_parsers::Jid>,
    pub ping: Option<u64>,
  • edit in src/config.rs at line 35
    [3.34761][3.34761:35510]()
    }
    fn deserialize_jid_map<'de, D>(
    deserializer: D,
    ) -> Result<HashMap<String, xmpp_parsers::Jid>, D::Error>
    where
    D: serde::Deserializer<'de>,
    {
    use serde::Deserialize;
    let s = HashMap::<String, String>::deserialize(deserializer)?;
    let size = s.len();
    s.into_iter()
    .map(|(k, v)| (k, std::str::FromStr::from_str(&v)))
    .take_while(|(_k, r)| r.is_ok())
    .fold(Ok(HashMap::with_capacity(size)), |res, (k, r)| match res {
    Ok(mut res) => match r {
    Ok(v) => {
    res.insert(k, v);
    Ok(res)
    }
    Err(e) => Err(e),
    },
    Err(e) => Err(e),
    })
    .map_err(serde::de::Error::custom)
  • replacement in Cargo.toml at line 15
    [3.6950][3.35777:35790]()
    toml = "0.5"
    [3.6950]
    [3.6963]
    toml = "0.4"
  • replacement in Cargo.toml at line 21
    [3.6425][3.35791:35813]()
    xmpp-parsers = "0.13"
    [3.6425]
    [3.35813]
    xmpp-parsers = "0.12.2"
  • edit in Cargo.toml at line 23
    [3.35848]
    try_from = "=0.3.2" # xmpp-parsers
  • replacement in Cargo.lock at line 7
    [3.36063][3.36063:36135]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.36063]
    [3.36135]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 12
    [3.6577][3.36151:36169]()
    version = "0.7.3"
    [3.6577]
    [3.6595]
    version = "0.6.10"
  • replacement in Cargo.lock at line 23
    [3.7455][3.36244:36317]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.7455]
    [3.7528]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 28
    [3.7561][3.36318:36337]()
    version = "0.3.10"
    [3.7561]
    [3.13580]
    version = "0.3.7"
  • replacement in Cargo.lock at line 44
    [3.8093][3.36358:36430]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.8093]
    [3.8165]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 46
    [3.8239][3.36431:36504]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.8239]
    [3.8312]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 56
    [3.9017][3.36541:36560]()
    version = "0.3.15"
    [3.9017]
    [3.9035]
    version = "0.3.14"
  • replacement in Cargo.lock at line 61
    [3.36716][3.36716:37016]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (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.36716]
    [3.9497]
    "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.9636][3.37037:37179]()
    "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.9636]
    [3.9778]
    "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 131
    [3.11081][3.38190:38209]()
    version = "0.4.12"
    [3.11081]
    [3.11100]
    version = "0.4.11"
  • replacement in Cargo.lock at line 145
    [3.11467][3.38287:38306]()
    version = "1.0.35"
    [3.11467]
    [3.11486]
    version = "1.0.30"
  • replacement in Cargo.lock at line 150
    [3.11580][3.38307:38325]()
    version = "0.1.7"
    [3.11580]
    [3.11598]
    version = "0.1.6"
  • replacement in Cargo.lock at line 165
    [3.12049][3.38399:38418]()
    version = "2.33.0"
    [3.12049]
    [3.12068]
    version = "2.32.0"
  • replacement in Cargo.lock at line 171
    [3.12374][3.38419:38568]()
    "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.12374]
    [3.12523]
    "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 191
    [3.13233][3.38569:38641]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.13233]
    [3.13305]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 199
    [3.10117][3.38642:38714]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.10117]
    [3.13825]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 217
    [3.38994][3.38994:39067]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.38994]
    [3.39067]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 237
    [3.7801][3.39399:39472]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.7801]
    [3.39472]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 273
    [3.15926][3.39866:39939]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.15926]
    [3.7897]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 278
    [3.7932][3.39940:39958]()
    version = "0.6.1"
    [3.7932]
    [3.7950]
    version = "0.6.0"
  • replacement in Cargo.lock at line 284
    [3.8250][3.39959:40031]()
    "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.8250]
    [3.8322]
    "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 293
    [3.16849][3.40032:40109]()
    "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.16849]
    [3.16925]
    "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 301
    [3.17057][3.40129:40206]()
    "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.17057]
    [3.40206]
    "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 311
    [3.40386][3.40386:40531]()
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.40386]
    [3.8623]
    "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.18974][3.40741:40760]()
    version = "0.1.26"
    [3.18974]
    [3.18993]
    version = "0.1.25"
  • replacement in Cargo.lock at line 377
    [3.19196][3.40761:40836]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.19196]
    [3.40836]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 391
    [3.19586][3.40933:40952]()
    version = "0.1.18"
    [3.19586]
    [3.19605]
    version = "0.1.16"
  • replacement in Cargo.lock at line 395
    [3.41029][3.41029:41102]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.41029]
    [3.19836]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 397
    [3.19906][3.41103:41250]()
    "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.19906]
    [3.20053]
    "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.20551][3.41751:41823]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.20551]
    [3.20623]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 426
    [3.20726][3.41824:41843]()
    version = "0.1.17"
    [3.20726]
    [3.20745]
    version = "0.1.16"
  • replacement in Cargo.lock at line 429
    [3.20827][3.41844:41917]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.20827]
    [3.20900]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 449
    [3.21397][3.41918:41938]()
    version = "0.12.27"
    [3.21397]
    [3.21417]
    version = "0.12.25"
  • replacement in Cargo.lock at line 452
    [3.21499][3.41939:42087]()
    "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.21499]
    [3.21647]
    "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.21729][3.42088:42230]()
    "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.21729]
    [3.21871]
    "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.42383][3.42383:42537]()
    "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.42383]
    [3.42537]
    "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.42769][3.42769:42853]()
    "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.42769]
    [3.42853]
    "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 494
    [3.23535][3.43022:43094]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.23535]
    [3.23607]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 506
    [3.24042][3.43095:43168]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.24042]
    [3.24115]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 551
    [3.25316][3.43438:43457]()
    version = "0.2.51"
    [3.25316]
    [3.25335]
    version = "0.2.49"
  • replacement in Cargo.lock at line 556
    [3.25438][3.43458:43476]()
    version = "0.5.2"
    [3.25438]
    [3.25456]
    version = "0.4.2"
  • replacement in Cargo.lock at line 573
    [3.25934][3.43477:43550]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.25934]
    [3.26007]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 578
    [3.26041][3.43551:43569]()
    version = "0.1.2"
    [3.26041]
    [3.26059]
    version = "0.1.1"
  • replacement in Cargo.lock at line 581
    [3.26141][3.43570:43652]()
    "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.26141]
    [3.26223]
    "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 596
    [3.43822][3.43822:43975]()
    "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.43822]
    [3.43975]
    "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.10535][3.44401:44473]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.10535]
    [3.10607]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 653
    [3.29191][3.44546:44618]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.29191]
    [3.29263]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 674
    [3.44697][3.44697:44769]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.44697]
    [3.10901]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 676
    [3.10971][3.44770:44846]()
    "openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.10971]
    [3.30195]
    "openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 678
    [3.30275][3.44847:44926]()
    "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.30275]
    [3.44926]
    "openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 690
    [3.30809][3.45252:45470]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.30809]
    [3.31027]
    "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.31827][3.45510:45582]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.31827]
    [3.31899]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 733
    [3.31931][3.45702:45722]()
    version = "0.10.20"
    [3.31931]
    [3.31951]
    version = "0.10.19"
  • replacement in Cargo.lock at line 737
    [3.32108][3.45723:45796]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.32108]
    [3.32181]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 740
    [3.45875][3.45875:46026]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.45875]
    [3.32490]
    "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.32645][3.46027:46046]()
    version = "0.9.43"
    [3.32645]
    [3.32664]
    version = "0.9.42"
  • replacement in Cargo.lock at line 754
    [3.32746][3.46047:46189]()
    "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.32746]
    [3.32888]
    "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.33693][3.46393:46465]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.33693]
    [3.46465]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 787
    [3.46612][3.46612:46685]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.46612]
    [3.46685]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 879
    [3.36333][3.47707:47726]()
    version = "0.6.12"
    [3.36333]
    [3.13435]
    version = "0.6.11"
  • replacement in Cargo.lock at line 892
    [3.47906][3.47906:47978]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.47906]
    [3.47978]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 894
    [3.48054][3.48054:48127]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.48054]
    [3.12245]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 903
    [3.48221][3.48221:48293]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.48221]
    [3.48293]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 909
    [3.48526][3.48526:48600]()
    "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.48526]
    [3.48600]
    "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 912
    [3.48755][3.48755:48828]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.48755]
    [3.13143]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 958
    [3.49403][3.49403:49475]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.49403]
    [3.49475]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 960
    [3.49551][3.49551:49624]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.49551]
    [3.49624]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 965
    [3.49656][3.49656:49674]()
    version = "0.1.3"
    [3.49656]
    [3.49674]
    version = "0.1.2"
  • replacement in Cargo.lock at line 970
    [3.49911][3.49911:49983]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.49911]
    [3.49983]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 973
    [3.50132][3.50132:50205]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.50132]
    [3.30943]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1003
    [3.39910][3.50684:50703]()
    version = "0.1.54"
    [3.39910]
    [3.39929]
    version = "0.1.51"
  • replacement in Cargo.lock at line 1011
    [3.14463][3.50704:50785]()
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.14463]
    [3.14544]
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1016
    [3.14574][3.50786:50804]()
    version = "1.1.5"
    [3.14574]
    [3.14592]
    version = "1.1.2"
  • replacement in Cargo.lock at line 1019
    [3.14674][3.50805:50884]()
    "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.14674]
    [3.50884]
    "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1021
    [3.50957][3.50957:51036]()
    "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.50957]
    [3.14905]
    "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1028
    [3.15099][3.51037:51055]()
    version = "0.6.6"
    [3.15099]
    [3.40259]
    version = "0.6.5"
  • replacement in Cargo.lock at line 1039
    [3.41080][3.51056:51129]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.41080]
    [3.41153]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1053
    [3.41481][3.51149:51168]()
    version = "0.1.14"
    [3.41481]
    [3.41499]
    version = "0.1.13"
  • replacement in Cargo.lock at line 1077
    [3.51406][3.51406:51480]()
    "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.51406]
    [3.51480]
    "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1088
    [3.51722][3.51722:51795]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.51722]
    [3.42558]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1103
    [3.42985][3.51815:51887]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.42985]
    [3.51887]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1114
    [3.43379][3.52076:52148]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.43379]
    [3.43451]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1134
    [3.43832][3.52149:52298]()
    "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.43832]
    [3.52298]
    "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.52372][3.52372:52446]()
    "hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.52372]
    [3.15663]
    "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1140
    [3.52522][3.52522:52748]()
    "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.18 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.52522]
    [3.15881]
    "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.52826][3.52826:52977]()
    "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.52826]
    [3.44887]
    "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.44917][3.52978:52997]()
    version = "1.0.90"
    [3.44917]
    [3.44936]
    version = "1.0.89"
  • replacement in Cargo.lock at line 1158
    [3.45036][3.52998:53017]()
    version = "1.0.90"
    [3.45036]
    [3.45055]
    version = "1.0.89"
  • replacement in Cargo.lock at line 1162
    [3.53097][3.53097:53242]()
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.53097]
    [3.45361]
    "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.16584][3.53263:53336]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.16584]
    [3.45711]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1215
    [3.47147][3.54189:54337]()
    "arc-swap 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.47147]
    [3.47294]
    "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.47862][3.54376:54675]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (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.47862]
    [3.48161]
    "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.48861][3.54940:55013]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.48861]
    [3.48934]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1277
    [3.55252][3.55252:55325]()
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55252]
    [3.49563]
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1288
    [3.49805][3.55326:55344]()
    version = "0.8.0"
    [3.49805]
    [3.55344]
    version = "0.7.0"
  • replacement in Cargo.lock at line 1308
    [3.50268][3.55457:55477]()
    version = "0.15.30"
    [3.50268]
    [3.50288]
    version = "0.15.27"
  • replacement in Cargo.lock at line 1312
    [3.55557][3.55557:55630]()
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55557]
    [3.50522]
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1330
    [3.55710][3.55710:55855]()
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55710]
    [3.51171]
    "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.51382][3.55875:56020]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.51382]
    [3.56020]
    "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.56091][3.56091:56172]()
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.56091]
    [3.51679]
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1345
    [3.51760][3.56173:56246]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.51760]
    [3.51833]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1371
    [3.52519][3.56339:56492]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.52519]
    [3.52672]
    "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.52785][3.56493:56512]()
    version = "0.11.0"
    [3.52785]
    [3.52804]
    version = "0.10.0"
  • replacement in Cargo.lock at line 1397
    [3.53311][3.56612:56838]()
    "libc 0.2.51 (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.53311]
    [3.53537]
    "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.53567][3.56839:56858]()
    version = "0.1.18"
    [3.53567]
    [3.53586]
    version = "0.1.16"
  • replacement in Cargo.lock at line 1407
    [3.53668][3.56859:57007]()
    "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.53668]
    [3.53816]
    "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.54040][3.57085:57253]()
    "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.54040]
    [3.57253]
    "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.57484][3.57484:57561]()
    "tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.57484]
    [3.57561]
    "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1419
    [3.57637][3.57637:57721]()
    "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.57637]
    [3.57721]
    "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1421
    [3.57800][3.57800:57883]()
    "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1430
    [3.19363][3.57961:58036]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.19363]
    [3.55024]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1438
    [3.55160][3.58037:58185]()
    "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.55160]
    [3.58185]
    "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.55429][3.58262:58280]()
    version = "0.1.6"
    [3.55429]
    [3.55447]
    version = "0.1.5"
  • replacement in Cargo.lock at line 1448
    [3.55529][3.58281:58437]()
    "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.55529]
    [3.55685]
    "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.55724][3.58438:58456]()
    version = "0.1.7"
    [3.55724]
    [3.55742]
    version = "0.1.6"
  • replacement in Cargo.lock at line 1458
    [3.58539][3.58539:58614]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.58539]
    [3.55899]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1466
    [3.56032][3.58634:58709]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.56032]
    [3.58709]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1468
    [3.58785][3.58785:58869]()
    "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.58785]
    [3.56266]
    "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1476
    [3.56400][3.58890:59038]()
    "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.56400]
    [3.19690]
    "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.59140][3.59140:59215]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59140]
    [3.59215]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1494
    [3.59519][3.59519:59600]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59519]
    [3.59600]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1496
    [3.59676][3.59676:59753]()
    "tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59676]
    [3.57513]
    "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1504
    [3.57650][3.59754:59901]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.57650]
    [3.57797]
    "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 1509
    [3.59980][3.59980:60061]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59980]
    [3.60061]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1512
    [3.60217][3.60217:60290]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60217]
    [3.60290]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1517
    [3.60325][3.60325:60343]()
    version = "0.1.4"
    [3.60325]
    [3.60343]
    version = "0.1.3"
  • replacement in Cargo.lock at line 1521
    [3.60495][3.60495:60570]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60495]
    [3.39434]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1529
    [3.58464][3.60590:60738]()
    "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.58464]
    [3.58612]
    "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.58952][3.60896:60915]()
    version = "0.1.13"
    [3.58952]
    [3.58970]
    version = "0.1.12"
  • replacement in Cargo.lock at line 1545
    [3.61162][3.61162:61237]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61162]
    [3.20603]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1550
    [3.61456][3.61456:61537]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61456]
    [3.59588]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1559
    [3.61640][3.61640:61715]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61640]
    [3.61715]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1561
    [3.61786][3.61786:61867]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61786]
    [3.60033]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1569
    [3.60167][3.61887:61962]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60167]
    [3.60242]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1572
    [3.62039][3.62039:62258]()
    ]
    [[package]]
    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)",
  • replacement in Cargo.lock at line 1579
    [3.60529][3.62259:62407]()
    "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.60529]
    [3.20941]
    "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.61186][3.62584:62732]()
    "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.61186]
    [3.61334]
    "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.61406][3.62733:62805]()
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61406]
    [3.21258]
    "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1610
    [3.62062][3.62982:63055]()
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62062]
    [3.62135]
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1612
    [3.62214][3.63056:63131]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62214]
    [3.62289]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1617
    [3.63280][3.63280:63353]()
    "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.63280]
    [3.62802]
    "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1629
    [3.63459][3.63756:63774]()
    version = "0.5.0"
    [3.63459]
    [3.63478]
    version = "0.4.10"
  • replacement in Cargo.lock at line 1632
    [3.63560][3.63775:63848]()
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.63560]
    [3.63633]
    "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1642
    [3.64018][3.64018:64093]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64018]
    [3.64003]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1649
    [3.64442][3.64320:64401]()
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64442]
    [3.64401]
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1663
    [3.65122][3.64733:64806]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.65122]
    [3.64806]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1665
    [3.64880][3.64880:64955]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64880]
    [3.22265]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1669
    [3.22488][3.65035:65111]()
    "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.22488]
    [3.65111]
    "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1672
    [3.65264][3.65264:65337]()
    "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.65264]
    [3.65337]
    "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1686
    [3.65456][3.65456:65529]()
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.65456]
    [3.65529]
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1765
    [3.68476][3.65665:65740]()
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68476]
    [3.22890]
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1782
    [3.68955][3.65741:65759]()
    version = "0.3.7"
    [3.68955]
    [3.68973]
    version = "0.3.6"
  • replacement in Cargo.lock at line 1804
    [3.23082][3.65779:65852]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.23082]
    [3.23155]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1817
    [3.23303][3.65853:65926]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.23303]
    [3.65926]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1826
    [3.70251][3.66005:66078]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70251]
    [3.70324]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1834
    [3.70456][3.66079:66152]()
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70456]
    [3.70529]
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1872
    [3.66979][3.66979:67769]()
    ]
    [[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.1 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1876
    [3.67925][3.67925:68080]()
    "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
    [3.67925]
    [3.72272]
    "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
  • replacement in Cargo.lock at line 1878
    [3.72425][3.68081:68233]()
    "checksum arc-swap 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "a57a5698f85c6fd92f19dad87ff2d822fc4ba79dd85c13914d8c4dad589cb815"
    [3.72425]
    [3.68233]
    "checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6"
  • replacement in Cargo.lock at line 1882
    [3.68536][3.68536:68689]()
    "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
    [3.68536]
    [3.68689]
    "checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
  • replacement in Cargo.lock at line 1891
    [3.69762][3.69762:69911]()
    "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
    [3.69762]
    [3.74545]
    "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
  • replacement in Cargo.lock at line 1893
    [3.74692][3.69912:70207]()
    "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.74692]
    [3.74987]
    "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.75136][3.70208:70356]()
    "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
    [3.75136]
    [3.75284]
    "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
  • replacement in Cargo.lock at line 1908
    [3.71447][3.71447:71600]()
    "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
    [3.71447]
    [3.77462]
    "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
  • replacement in Cargo.lock at line 1920
    [3.79005][3.72066:72217]()
    "checksum futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981"
    [3.79005]
    [3.79156]
    "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
  • replacement in Cargo.lock at line 1923
    [3.72375][3.72375:72521]()
    "checksum h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "85ab6286db06040ddefb71641b50017c06874614001a134b423783e2db2920bd"
    [3.72375]
    [3.72521]
    "checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e"
  • replacement in Cargo.lock at line 1926
    [3.79767][3.72669:72817]()
    "checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a"
    [3.79767]
    [3.79915]
    "checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a"
  • replacement in Cargo.lock at line 1929
    [3.25390][3.72818:72968]()
    "checksum hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4f2777434f26af6e4ce4fdcdccd3bed9d861d11e87bcbe72c0f51ddaca8ff848"
    [3.25390]
    [3.80368]
    "checksum hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5b6658b016965ae301fa995306db965c93677880ea70765a84235a96eae896"
  • replacement in Cargo.lock at line 1940
    [3.25998][3.73271:73577]()
    "checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
    "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
    [3.25998]
    [3.26147]
    "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.26444][3.73578:73730]()
    "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
    [3.26444]
    [3.82622]
    "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21"
  • replacement in Cargo.lock at line 1962
    [3.74660][3.74660:74812]()
    "checksum openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)" = "5a0d6b781aac4ac1bd6cafe2a2f0ad8c16ae8e1dd5184822a16c50139f8838d9"
    [3.74660]
    [3.85193]
    "checksum openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)" = "84321fb9004c3bce5611188a644d6171f895fa2889d155927d528782edb21c5d"
  • replacement in Cargo.lock at line 1964
    [3.85349][3.74813:74968]()
    "checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d"
    [3.85349]
    [3.26746]
    "checksum openssl-sys 0.9.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cb534d752bf98cf363b473950659ac2546517f9c6be9723771614ab3f03bbc9e"
  • replacement in Cargo.lock at line 1980
    [3.87666][3.76356:76505]()
    "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
    [3.87666]
    [3.76505]
    "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
  • replacement in Cargo.lock at line 1989
    [3.77412][3.77412:77562]()
    "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
    [3.77412]
    [3.77562]
    "checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
  • replacement in Cargo.lock at line 1993
    [3.78018][3.78018:78175]()
    "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
    [3.78018]
    [3.89481]
    "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
  • replacement in Cargo.lock at line 1995
    [3.89637][3.78176:78479]()
    "checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0"
    "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
    [3.89637]
    [3.89940]
    "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.78634][3.78634:78792]()
    "checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
    [3.78634]
    [3.90408]
    "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
  • replacement in Cargo.lock at line 2009
    [3.91943][3.79420:79725]()
    "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.91943]
    [3.79725]
    "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 2025
    [3.94388][3.80925:81074]()
    "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
    [3.94388]
    [3.81074]
    "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
  • replacement in Cargo.lock at line 2028
    [3.94685][3.81224:81372]()
    "checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
    [3.94685]
    [3.94833]
    "checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec"
  • replacement in Cargo.lock at line 2035
    [3.95741][3.81675:81827]()
    "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
    [3.95741]
    [3.29949]
    "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
  • replacement in Cargo.lock at line 2038
    [3.81976][3.81976:82125]()
    "checksum tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "65641e515a437b308ab131a82ce3042ff9795bef5d6c5a9be4eb24195c417fd9"
    [3.81976]
    [3.30254]
    "checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230"
  • replacement in Cargo.lock at line 2041
    [3.96655][3.82126:82446]()
    "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.96655]
    [3.82446]
    "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.30886][3.82906:83059]()
    "checksum tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fda385df506bf7546e70872767f71e81640f1f251bdf2fd8eb81a0eaec5fe022"
    [3.30886]
    [3.83059]
    "checksum tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363"
  • replacement in Cargo.lock at line 2049
    [3.83211][3.83211:83371]()
    "checksum tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ec5759cf26cf9659555f36c431b515e3d05f66831741c85b4b5d5dfb9cf1323c"
    [3.83211]
    [3.83371]
    "checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801"
  • edit in Cargo.lock at line 2052
    [3.83678][3.83678:83837]()
    "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.84143][3.84143:84290]()
    "checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e"
    [3.84143]
    [3.84290]
    "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
  • replacement in Cargo.lock at line 2075
    [3.102169][3.85077:85226]()
    "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
    [3.102169]
    [3.102318]
    "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
  • edit in Cargo.lock at line 2086
    [3.85538][3.85538:85694]()
    "checksum xmpp-parsers 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5094cec449beca92f82ae4d7fe13cda058005849766d71b86c23e6217f61a357"