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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
//! A general purpose library of common SIP types
//!
//! Like [http](https://docs.rs/http/) crate, this crate is a general purpose
//! library for common types found when working
//! with the SIP protocol. You'll find [SipMessage](SipMessage)
//! and its [Request](Request)
//! / [Response](Response)
//! variant types for working as either a client or a server as well
//! as all of their components, like [Method](Method),
//! a very flexible [Uri](Uri),
//! [Version](Version),
//! [StatusCode](StatusCode) etc.
//!
//! Rsip is capable of parsing messages from `bytes`, `&str` or `String` using
//! [nom](https://github.com/Geal/nom) parser and can also generate SIP messages
//! using helpful struct builders.
//!
//! You will notably not find an implementation of sending requests or spinning up
//! a SIP server in this crate. SIP servers, by nature of SIP protocol, are very
//! complex usually and will sit at different crates/libs. Rsip is intended to be
//! the de-facto SIP base library for Rust. It was built to be used inside
//! [viska](https://github.com/vasilakisfil/viska) initially but then was split
//! to a different crate. It was inspired by [libsip](https://github.com/ByteHeathen/libsip)
//! but has taken a bit different path regarding parsing, flexibility & safety.
//!
//! For locating SIP servers ([RFC3263](https://datatracker.ietf.org/doc/html/rfc3263)) take a
//! look on [rsip-dns](https://github.com/vasilakisfil/rsip-dns) library.
//!
//! ## SIP: It's all about headers
//! In case you haven't worked with SIP before let me tell you one thing: headers in SIP play
//! a crucial role, basically most of your logic resides around the headers (and there are plenty
//! of them :) ). `Status` and `Method` of course have their role, but there decisions are more
//! straightforward on what you need to do.
//!
//! Rsip takes a unique role regarding headers mixing together safety and flexibility: by default
//! rsip will parse all headers and convert them to distinct
//! [untyped header](headers::untyped) types,
//! as part of the big fat [Header enum](Header).
//! Each untyped header is basically a NewType around String.
//! This means that, apart from non-UTF8 compliant headers, any header is supported even if your
//! client has a bug or rsip itself has a bug somewhere in a typed header.
//! Also, any parsing on complex headers takes place only when needed, on demand.
//!
//! [Untyped headers](headers::untyped) have their use, but in practice when you want to
//! interact with a header, you need to convert it to its [typed form](headers::typed).
//! Not all headers have a typed form, for instance, some
//! headers are just opaque strings (like [CallID](headers::CallId)), or some headers just need helpful methods
//! instead of a whole new typed struct (like
//! [Expires](headers::Expires), which provides the [seconds](headers::Expires::seconds) method).
//!
//! For instance, creating a new `Call-ID` header can easily be done like (examples taken from
//! [RFC3665](https://datatracker.ietf.org/doc/html/rfc3665)):
//!
//! ```
//! use rsip::headers::UntypedHeader;
//! rsip::headers::CallId::new("1j9FpLxk3uxtm8tn@biloxi.example.com");
//! ```
//!
//! Similarly, generating a `From` header:
//! ```
//! use rsip::headers::{From, UntypedHeader};
//! let from = rsip::headers::From::new("Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl");
//! ```
//!
//! If you want to automatically include all defined traits in Rsip, you can include the prelude:
//! ```
//! use rsip::prelude::*;
//! let from = rsip::headers::From::new("Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl");
//! ```
//!
//! While for `Call-Id`, it's fine to pass in an str (which probably will be generated & saved
//! somewhere else in your application), for many headers working with plain strings doesn't make
//! much sense, like in the `From` header. As mentioned, the main reason untyped headers exist is
//! performance (parsing takes place only when needed) and flexibility (you can throw in there
//! whatever you like ^_^).
//!
//! In order to generate a From header, you will probably need to use its [typed](typed::From) version:
//! ```
//! use rsip::headers::typed::TypedHeader;
//!
//! let typed_from: rsip::typed::From = rsip::typed::From {
//!     display_name: Some("Bob".into()),
//!     uri: rsip::Uri {
//!         scheme: Some(rsip::Scheme::Sips),
//!         auth: Some(rsip::Auth {
//!             user: "Bob".into(),
//!             password: None,
//!         }),
//!         host_with_port: rsip::Domain::from("biloxi.example.com").into(),
//!         ..Default::default()
//!     },
//!     params: vec![rsip::Param::Tag(rsip::param::Tag::new("a73kszlfl"))],
//! };
//! ```
//!
//! ## Uri: a flexible uri struct
//!
//! As you can see in the typed `From` example, a very crucial part is the [Uri](Uri). The uri we want to generate is
//! `sips:bob@biloxi.example.com` as in the untyped header above. Hence:
//! * we specify hat the [scheme](Scheme) of the Uri is `Scheme::Sips`
//! * we specify the auth part of the Uri, but only the user part which is `Bob`. We do that
//! using the helpful [Auth](Auth) struct,
//! * we specify the host part of the Uri, which is defined in the Uri as
//! [HostWithPort](HostWithPort) struct.
//! In our case, it is a simple domain without a port specified.
//! For that we can use the [Domain](Domain) struct that has an automatic convertion to [HostWithPort](HostWithPort)
//! struct. In general you will find a lot of helpful `(Try)From/(Try)Into` convertions to remove
//! boilerplate. According to SIP spec, the URI can hold params (like `method`) and headers,
//! although in practice none really puts those to a SIP URI. That's why we have defaults in there.
//!
//! It is important to note that in order to set the `tag` param, we use the [Tag](param::Tag) struct, found
//! inside the [param](param) module. In the same module you will find various other params that can be
//! used in headers like [From](headers::From), [To](headers::To), [Contact](headers::Contact),
//! [Via](headers::Via) etc.
//!
//! In general, there are tons of helpful `(Try)From/(Try)Into` convertions to remove boilerplate.
//! So when you have a typed header, it's easy to take its untyped form:
//!
//! ```
//! # let typed_from: rsip::typed::From = rsip::typed::From {
//! #     display_name: Some("Bob".into()),
//! #     uri: rsip::Uri {
//! #         scheme: Some(rsip::Scheme::Sips),
//! #         auth: Some(rsip::Auth {
//! #             user: "Bob".into(),
//! #             password: None,
//! #         }),
//! #         host_with_port: rsip::Domain::from("biloxi.example.com").into(),
//! #         ..Default::default()
//! #     },
//! #     params: vec![rsip::Param::Tag(rsip::param::Tag::new("a73kszlfl"))],
//! # };
//! let untyped_from: rsip::headers::From = typed_from.into();
//! ```
//!
//! ## Header: the matching enum
//! [Header](Header) is the enum that holds all variants of the headers. It is there so it's easy to do
//! matches to find relevant headers.
//!
//! Continuing from the previous section, if you want to get the typed or untyped headers as part of
//! the `Header` enum you can do the following:
//! ```
//! # let typed_from: rsip::typed::From = rsip::typed::From {
//! #     display_name: Some("Bob".into()),
//! #     uri: rsip::Uri {
//! #         scheme: Some(rsip::Scheme::Sips),
//! #         auth: Some(rsip::Auth {
//! #             user: "Bob".into(),
//! #             password: None,
//! #         }),
//! #         host_with_port: rsip::Domain::from("biloxi.example.com").into(),
//! #         ..Default::default()
//! #     },
//! #     params: vec![rsip::Param::Tag(rsip::param::Tag::new("a73kszlfl"))],
//! # };
//! let from: rsip::Header = typed_from.into();
//! //or
//! # use rsip::prelude::*;
//! # let untyped_from = rsip::headers::From::new("Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl");
//! let from: rsip::Header = untyped_from.into();
//! ```
//!
//! In case a header is not defined in Rsip, parsing will store it in `Header` enum in the `Other`
//! variant. For instance, constructing the `X-Fs-Sending-Message` header (related to SMS in SIP),
//! you can do:
//! ```
//! let x_fs_sending_message = rsip::Header::Other("X-FS-Sending-Message".into(), "f9c4adc8-9c2a-47d5-a7f1-63d20784685e".into());
//! ```
//! ## Headers: a vec of headers
//! [Headers](Headers) is a newtype around `Vec<Header>`, but it's there to give you better safety along
//! with some helpful methods. In SIP, many headers are allowed to appear more than once time, so
//! if we want to provide something else, maybe we should go with something similar to what the
//! http crate does (a multimap HashMap to take advantage of the characteristics of HTTP headers).
//! But this shouldn't worry you as the external API will remain the same even if the internal
//! implementation is moved from a `Vec<Header>` to a multimap HashMap.
//!
//! In order to push some headers in the [Headers](Headers) you can simple do:
//! ```
//! # use rsip::prelude::*;
//! # let from = rsip::headers::From::new("Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl");
//! # let to = rsip::headers::To::new("Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl");
//! let mut request_headers: rsip::Headers = Default::default();
//! request_headers.push(from.into());
//! request_headers.push(to.into());
//! //.
//! //.
//! //.
//! ```
//!
//! ## The SIP Messages: Request & Response
//! [Request](Request) & [Response](Response) are the main structs that you will use just before you finish creating
//! a SIP message. Creating those are very intuitive as you will only need to "fill-in" their
//! fields. Creating a SIP request while having already a `Headers` vec:
//! ```
//! # let request_headers = Default::default();
//! let request = rsip::Request {
//!     method: rsip::Method::Register,
//!     uri: rsip::Uri {
//!         scheme: Some(rsip::Scheme::Sips),
//!         host_with_port: rsip::Domain::from("ss2.biloxi.example.com").into(),
//!         ..Default::default()
//!     },
//!     headers: request_headers,
//!     version: rsip::Version::V2,
//!     body: vec![],
//! };
//! ```
//!
//! Now you have an [rsip::Request](Request), but sometimes it is helpful to work with the
//! [rsip::SipMessage](SipMessage) enum, especially when you are sitting on the receiver's side.
//! In order to convert a [Request](Request) (or a [Response](Response)) to a
//! [SipMessage](SipMessage) it's simple:
//!
//! ```
//! # let request_headers = Default::default();
//! # let request = rsip::Request {
//! #     method: rsip::Method::Register,
//! #     uri: rsip::Uri {
//! #         scheme: Some(rsip::Scheme::Sips),
//! #         host_with_port: rsip::Domain::from("ss2.biloxi.example.com").into(),
//! #         ..Default::default()
//! #     },
//! #     headers: request_headers,
//! #     version: rsip::Version::V2,
//! #     body: vec![],
//! # };
//! let sip_message: rsip::SipMessage = request.into();
//! //similar
//! # let request_headers = Default::default();
//! # let request = rsip::Request {
//! #     method: rsip::Method::Register,
//! #     uri: rsip::Uri {
//! #         scheme: Some(rsip::Scheme::Sips),
//! #         host_with_port: rsip::Domain::from("ss2.biloxi.example.com").into(),
//! #         ..Default::default()
//! #     },
//! #     headers: request_headers,
//! #     version: rsip::Version::V2,
//! #     body: vec![],
//! # };
//! let sip_message = rsip::SipMessage::Request(request);
//! ```
//!
//! Similarly, creating a response when having already defined the headers in a `response_headers`
//! variable:
//!
//! ```
//! # let response_headers = Default::default();
//! let response = rsip::Response {
//!     status_code: 401.into(),
//!     headers: response_headers,
//!     version: rsip::Version::V2,
//!     body: vec![],
//! };
//!
//! let sip_message: rsip::SipMessage = response.into();
//! ```
//!
//!

pub mod common;
mod error;

pub mod headers;
pub mod message;
pub mod services;

pub use error::{Error, TokenizerError};

pub use headers::{Header, Headers};
pub use message::{Request, Response, SipMessage};

pub use crate::common::uri::*;
pub use crate::common::*;

pub use crate::message::header_macros::*;

pub mod typed {
    pub use crate::headers::typed::*;
}

pub mod prelude {
    pub use crate::{
        headers::{typed::TypedHeader, ToTypedHeader, UntypedHeader},
        message::{HasHeaders, HeadersExt},
    };
}

pub(crate) type NomError<'a> = nom::Err<nom::error::VerboseError<&'a [u8]>>;
pub(crate) type NomStrError<'a> = nom::Err<nom::error::VerboseError<&'a str>>;
pub(crate) type GenericNomError<'a, T> = nom::Err<nom::error::VerboseError<T>>;
pub(crate) type IResult<'a, T> = Result<(&'a [u8], T), nom::Err<TokenizerError>>;
//pub(crate) type SResult<'a, T> = Result<(&'a str, T), nom::Err<TokenizerError>>;
pub(crate) type GResult<I, T> = Result<(I, T), nom::Err<TokenizerError>>;

//need to include &str or &[u8] in definition
pub trait AbstractInput<'a, I>:
    nom::InputTakeAtPosition<Item = I>
    + nom::InputTake
    + Clone
    + Copy
    + nom::FindSubstring<&'a str>
    + nom::Slice<nom::lib::std::ops::RangeFrom<usize>>
    + nom::InputLength
    + nom::InputIter
    + nom::Compare<&'a str>
    + std::fmt::Debug
    + Into<&'a bstr::BStr>
    + Default
{
    fn is_empty(&self) -> bool;
}

pub trait AbstractInputItem<I>: nom::AsChar + std::cmp::PartialEq<I> + From<u8> + Clone {
    fn is_alphabetic(c: I) -> bool;
    fn is_alphanumeric(c: I) -> bool;
    fn is_token(c: I) -> bool;
}

impl<'a> AbstractInput<'a, char> for &'a str {
    fn is_empty(&self) -> bool {
        <str>::is_empty(self)
    }
}

impl AbstractInputItem<char> for char {
    fn is_alphabetic(c: char) -> bool {
        c.is_ascii_alphabetic()
    }

    fn is_alphanumeric(c: char) -> bool {
        c.is_ascii_alphanumeric()
    }

    fn is_token(c: char) -> bool {
        Self::is_alphanumeric(c) || "-.!%*_+`'~".contains(c)
    }
}

impl<'a> AbstractInput<'a, u8> for &'a [u8] {
    fn is_empty(&self) -> bool {
        <[u8]>::is_empty(self)
    }
}
impl AbstractInputItem<u8> for u8 {
    fn is_alphabetic(c: u8) -> bool {
        nom::character::is_alphabetic(c)
    }

    fn is_alphanumeric(c: u8) -> bool {
        nom::character::is_alphanumeric(c)
    }

    fn is_token(c: u8) -> bool {
        use nom::character::is_alphanumeric;

        is_alphanumeric(c) || "-.!%*_+`'~".contains(char::from(c))
    }
}

pub(crate) mod utils {
    pub fn opt_trim(input: &str) -> Option<&str> {
        let input = input.trim();

        match input.is_empty() {
            true => None,
            false => Some(input),
        }
    }
}

pub(crate) mod parser_utils {
    use crate::TokenizerError;

    pub fn is_token(c: u8) -> bool {
        use nom::character::is_alphanumeric;

        is_alphanumeric(c) || "-.!%*_+`'~".contains(char::from(c))
    }

    pub fn is_empty_or_fail_with<'a, I, T: crate::AbstractInput<'a, I>, S: Into<&'a bstr::BStr>>(
        rem: T,
        tuple: (&'static str, S),
    ) -> Result<(), nom::Err<crate::TokenizerError>> {
        if !rem.is_empty() {
            //TODO: specify that this is trailing input
            //use a comma in params tests to test
            Err(TokenizerError::from(tuple).into())
        } else {
            Ok(())
        }
    }

    /*
    pub fn create_error_for<'a>(rem: &'a [u8], error: &'static str) -> super::NomError<'a> {
        nom::Err::Error(nom::error::VerboseError {
            errors: vec![(rem, nom::error::VerboseErrorKind::Context(error))],
        })
    }
    */

    /*
        pub fn is_unreserved(chr: u8) -> bool {
            use nom::character::is_alphanumeric;

            is_alphanumeric(chr) || "-_.!~*'()".contains(char::from(chr))
        }

        pub fn is_reserved(chr: u8) -> bool {
            ";/?:@&=+$,".contains(char::from(chr))
        }
    */

    /*
        pub fn opt_sc<'a>(
            input: &'a [u8],
        ) -> IResult<&'a [u8], Option<&'a [u8]>, VerboseError<&'a [u8]>> {
            use nom::{bytes::complete::tag, combinator::opt};

            opt(tag(";"))(input)
        }

        pub fn opt_amp<'a>(
            input: &'a [u8],
        ) -> IResult<&'a [u8], Option<&'a [u8]>, VerboseError<&'a [u8]>> {
            use nom::{bytes::complete::tag, combinator::opt};

            opt(tag("&"))(input)
        }
    */
}