1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
use native_tls::Error as TlsError;
use sasl::client::MechanismError as SaslMechanismError;
use std::borrow::Cow;
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;
use std::str::Utf8Error;
use trust_dns_proto::error::ProtoError;
use trust_dns_resolver::error::ResolveError;

use xmpp_parsers::sasl::DefinedCondition as SaslDefinedCondition;
use xmpp_parsers::{Error as ParsersError, JidParseError};

/// Top-level error type
#[derive(Debug)]
pub enum Error {
    /// I/O error
    Io(IoError),
    /// Error resolving DNS and establishing a connection
    Connection(ConnecterError),
    /// DNS label conversion error, no details available from module
    /// `idna`
    Idna,
    /// Error parsing Jabber-Id
    JidParse(JidParseError),
    /// Protocol-level error
    Protocol(ProtocolError),
    /// Authentication error
    Auth(AuthError),
    /// TLS error
    Tls(TlsError),
    /// Connection closed
    Disconnected,
    /// Shoud never happen
    InvalidState,
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Io(e) => write!(fmt, "IO error: {}", e),
            Error::Connection(e) => write!(fmt, "connection error: {}", e),
            Error::Idna => write!(fmt, "IDNA error"),
            Error::JidParse(e) => write!(fmt, "jid parse error: {}", e),
            Error::Protocol(e) => write!(fmt, "protocol error: {}", e),
            Error::Auth(e) => write!(fmt, "authentication error: {}", e),
            Error::Tls(e) => write!(fmt, "TLS error: {}", e),
            Error::Disconnected => write!(fmt, "disconnected"),
            Error::InvalidState => write!(fmt, "invalid state"),
        }
    }
}

impl From<IoError> for Error {
    fn from(e: IoError) -> Self {
        Error::Io(e)
    }
}

impl From<ConnecterError> for Error {
    fn from(e: ConnecterError) -> Self {
        Error::Connection(e)
    }
}

impl From<JidParseError> for Error {
    fn from(e: JidParseError) -> Self {
        Error::JidParse(e)
    }
}

impl From<ProtocolError> for Error {
    fn from(e: ProtocolError) -> Self {
        Error::Protocol(e)
    }
}

impl From<AuthError> for Error {
    fn from(e: AuthError) -> Self {
        Error::Auth(e)
    }
}

impl From<TlsError> for Error {
    fn from(e: TlsError) -> Self {
        Error::Tls(e)
    }
}

/// Causes for stream parsing errors
#[derive(Debug)]
pub enum ParserError {
    /// Encoding error
    Utf8(Utf8Error),
    /// XML parse error
    Parse(ParseError),
    /// Illegal `</>`
    ShortTag,
    /// Required by `impl Decoder`
    Io(IoError),
}

impl fmt::Display for ParserError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ParserError::Utf8(e) => write!(fmt, "UTF-8 error: {}", e),
            ParserError::Parse(e) => write!(fmt, "parse error: {}", e),
            ParserError::ShortTag => write!(fmt, "short tag"),
            ParserError::Io(e) => write!(fmt, "IO error: {}", e),
        }
    }
}

impl From<IoError> for ParserError {
    fn from(e: IoError) -> Self {
        ParserError::Io(e)
    }
}

impl From<ParserError> for Error {
    fn from(e: ParserError) -> Self {
        ProtocolError::Parser(e).into()
    }
}

/// XML parse error wrapper type
#[derive(Debug)]
pub struct ParseError(pub Cow<'static, str>);

impl StdError for ParseError {
    fn description(&self) -> &str {
        self.0.as_ref()
    }
    fn cause(&self) -> Option<&dyn StdError> {
        None
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// XMPP protocol-level error
#[derive(Debug)]
pub enum ProtocolError {
    /// XML parser error
    Parser(ParserError),
    /// Error with expected stanza schema
    Parsers(ParsersError),
    /// No TLS available
    NoTls,
    /// Invalid response to resource binding
    InvalidBindResponse,
    /// No xmlns attribute in <stream:stream>
    NoStreamNamespace,
    /// No id attribute in <stream:stream>
    NoStreamId,
    /// Encountered an unexpected XML token
    InvalidToken,
    /// Unexpected <stream:stream> (shouldn't occur)
    InvalidStreamStart,
}

impl fmt::Display for ProtocolError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ProtocolError::Parser(e) => write!(fmt, "XML parser error: {}", e),
            ProtocolError::Parsers(e) => write!(fmt, "error with expected stanza schema: {}", e),
            ProtocolError::NoTls => write!(fmt, "no TLS available"),
            ProtocolError::InvalidBindResponse => {
                write!(fmt, "invalid response to resource binding")
            }
            ProtocolError::NoStreamNamespace => {
                write!(fmt, "no xmlns attribute in <stream:stream>")
            }
            ProtocolError::NoStreamId => write!(fmt, "no id attribute in <stream:stream>"),
            ProtocolError::InvalidToken => write!(fmt, "encountered an unexpected XML token"),
            ProtocolError::InvalidStreamStart => write!(fmt, "unexpected <stream:stream>"),
        }
    }
}

impl From<ParserError> for ProtocolError {
    fn from(e: ParserError) -> Self {
        ProtocolError::Parser(e)
    }
}

impl From<ParsersError> for ProtocolError {
    fn from(e: ParsersError) -> Self {
        ProtocolError::Parsers(e)
    }
}

/// Authentication error
#[derive(Debug)]
pub enum AuthError {
    /// No matching SASL mechanism available
    NoMechanism,
    /// Local SASL implementation error
    Sasl(SaslMechanismError),
    /// Failure from server
    Fail(SaslDefinedCondition),
    /// Component authentication failure
    ComponentFail,
}

impl fmt::Display for AuthError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            AuthError::NoMechanism => write!(fmt, "no matching SASL mechanism available"),
            AuthError::Sasl(s) => write!(fmt, "local SASL implementation error: {}", s),
            AuthError::Fail(c) => write!(fmt, "failure from the server: {:?}", c),
            AuthError::ComponentFail => write!(fmt, "component authentication failure"),
        }
    }
}

/// Error establishing connection
#[derive(Debug)]
pub enum ConnecterError {
    /// All attempts failed, no error available
    AllFailed,
    /// DNS protocol error
    Dns(ProtoError),
    /// DNS resolution error
    Resolve(ResolveError),
}

impl std::error::Error for ConnecterError {}

impl std::fmt::Display for ConnecterError {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        write!(fmt, "{:?}", self)
    }
}