tox_core/state_format/
old.rs

1//! Old **Tox State Format (TSF)**. *__Will be deprecated__ when something
2//! better will become available.*
3
4use std::default::Default;
5use nom::{
6    number::complete::{le_u16, be_u16, le_u8, le_u32, le_u64},
7    combinator::rest,
8    bytes::complete::take,
9};
10
11use tox_binary_io::*;
12use tox_crypto::*;
13use tox_packet::dht::packed_node::*;
14use tox_packet::toxid::{NoSpam, NOSPAMBYTES};
15use tox_packet::packed_node::*;
16
17const REQUEST_MSG_LEN: usize = 1024;
18
19/// According to https://zetok.github.io/tox-spec/#sections
20const SECTION_MAGIC: &[u8; 2] = &[0xce, 0x01];
21
22/** NoSpam and Keys section of the new state format.
23
24https://zetok.github.io/tox-spec/#nospam-and-keys-0x01
25*/
26#[derive(Clone, Debug, Eq, PartialEq)]
27pub struct NospamKeys {
28    /// Own `NoSpam`.
29    pub nospam: NoSpam,
30    /// Own `PublicKey`.
31    pub pk: PublicKey,
32    /// Own `SecretKey`.
33    pub sk: SecretKey,
34}
35
36/// Number of bytes of serialized [`NospamKeys`](./struct.NospamKeys.html).
37pub const NOSPAMKEYSBYTES: usize = NOSPAMBYTES + PUBLICKEYBYTES + SECRETKEYBYTES;
38
39impl NospamKeys {
40    /// Generates random `NospamKeys`.
41    pub fn random() -> Self {
42        let nospam = NoSpam::random();
43        let (pk, sk) = gen_keypair();
44        NospamKeys {
45            nospam,
46            pk,
47            sk
48        }
49    }
50}
51
52/** Provided that there's at least [`NOSPAMKEYSBYTES`]
53(./constant.NOSPAMKEYSBYTES.html) de-serializing will not fail.
54*/
55// NoSpam is defined in toxid.rs
56impl FromBytes for NospamKeys {
57    named!(from_bytes<NospamKeys>, do_parse!(
58        tag!([0x01,0x00]) >>
59        tag!(SECTION_MAGIC) >>
60        nospam: call!(NoSpam::from_bytes) >>
61        pk: call!(PublicKey::from_bytes) >>
62        sk: call!(SecretKey::from_bytes) >>
63        (NospamKeys {
64            nospam,
65            pk,
66            sk
67        })
68    ));
69}
70
71impl ToBytes for NospamKeys {
72    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
73        do_gen!(buf,
74            gen_le_u16!(0x0001) >>
75            gen_slice!(SECTION_MAGIC) >>
76            gen_slice!(self.nospam.0) >>
77            gen_slice!(self.pk.as_ref()) >>
78            gen_slice!(self.sk.0)
79        )
80    }
81}
82
83/** Own name, up to [`NAME_LEN`](./constant.NAME_LEN.html) bytes long.
84*/
85#[derive(Clone, Debug, Default, Eq, PartialEq)]
86pub struct Name(pub Vec<u8>);
87
88/// Length in bytes of name. ***Will be moved elsewhere.***
89pub const NAME_LEN: usize = 128;
90
91/** Produces up to [`NAME_LEN`](./constant.NAME_LEN.html) bytes long `Name`.
92    Can't fail.
93*/
94impl FromBytes for Name {
95    named!(from_bytes<Name>, do_parse!(
96        tag!([0x04,0x00]) >>
97        tag!(SECTION_MAGIC) >>
98        name_bytes: rest >>
99        name: value!(name_bytes.to_vec()) >>
100        (Name(name))
101    ));
102}
103
104impl ToBytes for Name {
105    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
106        do_gen!(buf,
107            gen_le_u16!(0x0004) >>
108            gen_slice!(SECTION_MAGIC) >>
109            gen_slice!(self.0.as_slice())
110        )
111    }
112}
113
114/** DHT section of the old state format.
115https://zetok.github.io/tox-spec/#dht-0x02
116Default is empty, no Nodes.
117*/
118#[derive(Clone, Debug, Default, Eq, PartialEq)]
119pub struct DhtState(pub Vec<PackedNode>);
120
121/// Special, magical beginning of DHT section in LE.
122const DHT_MAGICAL: u32 = 0x0159_000d;
123
124/** Special DHT section type encoded in LE.
125
126    https://zetok.github.io/tox-spec/#dht-sections
127*/
128const DHT_SECTION_TYPE: u16 = 0x0004;
129
130/** Yet another magical number in DHT section that needs a check.
131
132https://zetok.github.io/tox-spec/#dht-sections
133*/
134const DHT_2ND_MAGICAL: u16 = 0x11ce;
135
136impl FromBytes for DhtState {
137    named!(from_bytes<DhtState>, do_parse!(
138        tag!([0x02,0x00]) >>
139        tag!(SECTION_MAGIC) >>
140        verify!(le_u32, |value| *value == DHT_MAGICAL) >> // check whether beginning of the section matches DHT magic bytes
141        num_of_bytes: le_u32 >>
142        verify!(le_u16, |value| *value == DHT_SECTION_TYPE) >> // check DHT section type
143        verify!(le_u16, |value| *value == DHT_2ND_MAGICAL) >> // check whether yet another magic number matches
144        nodes: flat_map!(take(num_of_bytes), many0!(PackedNode::from_bytes)) >>
145        (DhtState(nodes))
146    ));
147}
148
149impl ToBytes for DhtState {
150    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
151        let start_idx = buf.1;
152
153        let (buf, idx) = do_gen!(buf,
154            gen_le_u16!(0x0002) >>
155            gen_slice!(SECTION_MAGIC) >>
156            gen_le_u32!(DHT_MAGICAL as u32) >>
157            gen_skip!(4) >>
158            gen_le_u16!(DHT_SECTION_TYPE as u16) >>
159            gen_le_u16!(DHT_2ND_MAGICAL as u16) >>
160            gen_many_ref!(&self.0, |buf, node| PackedNode::to_bytes(node, buf))
161        )?;
162
163        let len = (idx - start_idx - 16) as u32;
164        buf[start_idx + 8..start_idx + 12].copy_from_slice(&u32::to_le_bytes(len));
165        Ok((buf, idx))
166    }
167}
168
169/** Friend state status. Used by [`FriendState`](./struct.FriendState.html).
170
171https://zetok.github.io/tox-spec/#friends-0x03
172
173*/
174#[derive(Copy, Clone, Debug, Eq, PartialEq)]
175pub enum FriendStatus {
176    /// Not a friend. (When this can happen and what does it entail?)
177    NotFriend   = 0,
178    /// Friend was added.
179    Added       = 1,
180    /// Friend request was sent to the friend.
181    FrSent      = 2,
182    /// Friend confirmed.
183    /// (Something like toxcore knowing that friend accepted FR?)
184    Confirmed   = 3,
185    /// Friend has come online.
186    Online      = 4,
187}
188
189impl FromBytes for FriendStatus {
190    named!(from_bytes<FriendStatus>, switch!(le_u8,
191        0 => value!(FriendStatus::NotFriend) |
192        1 => value!(FriendStatus::Added) |
193        2 => value!(FriendStatus::FrSent) |
194        3 => value!(FriendStatus::Confirmed) |
195        4 => value!(FriendStatus::Online)
196    ));
197}
198
199/** User status. Used for both own & friend statuses.
200
201https://zetok.github.io/tox-spec/#userstatus
202
203*/
204#[derive(Clone, Copy, Debug, Eq, PartialEq)]
205pub enum UserWorkingStatus {
206    /// User is `Online`.
207    Online = 0,
208    /// User is `Away`.
209    Away   = 1,
210    /// User is `Busy`.
211    Busy   = 2,
212}
213
214/// Returns `UserWorkingStatus::Online`.
215impl Default for UserWorkingStatus {
216    fn default() -> Self {
217        UserWorkingStatus::Online
218    }
219}
220
221impl FromBytes for UserWorkingStatus {
222    named!(from_bytes<UserWorkingStatus>,
223        switch!(le_u8,
224            0 => value!(UserWorkingStatus::Online) |
225            1 => value!(UserWorkingStatus::Away) |
226            2 => value!(UserWorkingStatus::Busy)
227        )
228    );
229}
230
231/// Length in bytes of UserStatus
232pub const USER_STATUS_LEN: usize = 1;
233
234/// User status section
235#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
236pub struct UserStatus(UserWorkingStatus);
237
238impl FromBytes for UserStatus {
239    named!(from_bytes<UserStatus>, do_parse!(
240        tag!([0x06,0x00]) >>
241        tag!(SECTION_MAGIC) >>
242        user_status : call!(UserWorkingStatus::from_bytes) >>
243        (UserStatus(user_status))
244    ));
245}
246
247impl ToBytes for UserStatus {
248    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
249        do_gen!(buf,
250            gen_le_u16!(0x0006) >>
251            gen_slice!(SECTION_MAGIC) >>
252            gen_le_u8!(self.0 as u8)
253        )
254    }
255}
256
257/** Status message, up to [`STATUS_MSG_LEN`](./constant.STATUS_MSG_LEN.html)
258bytes.
259
260*/
261#[derive(Clone, Debug, Default, Eq, PartialEq)]
262pub struct StatusMsg(pub Vec<u8>);
263
264/// Length in bytes of friend's status message.
265// FIXME: move somewhere else
266pub const STATUS_MSG_LEN: usize = 1007;
267
268impl ToBytes for StatusMsg {
269    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
270        do_gen!(buf,
271            gen_le_u16!(0x0005) >>
272            gen_slice!(SECTION_MAGIC) >>
273            gen_slice!(self.0.as_slice())
274        )
275    }
276}
277
278impl FromBytes for StatusMsg {
279    named!(from_bytes<StatusMsg>, do_parse!(
280        tag!([0x05,0x00]) >>
281        tag!(SECTION_MAGIC) >>
282        status_msg_bytes: rest >>
283        status_msg: value!(status_msg_bytes.to_vec()) >>
284        (StatusMsg(status_msg))
285    ));
286}
287
288/// Contains list in `TcpUdpPackedNode` format.
289#[derive(Clone, Debug, Default, Eq, PartialEq)]
290pub struct TcpRelays(pub Vec<TcpUdpPackedNode>);
291
292impl FromBytes for TcpRelays {
293    named!(from_bytes<TcpRelays>, do_parse!(
294        tag!([0x0a, 0x00]) >>
295        tag!(SECTION_MAGIC) >>
296        nodes: many0!(TcpUdpPackedNode::from_bytes) >>
297        (TcpRelays(nodes))
298    ));
299}
300
301impl ToBytes for TcpRelays {
302    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
303        do_gen!(buf,
304            gen_le_u16!(0x000a) >>
305            gen_slice!(SECTION_MAGIC) >>
306            gen_many_ref!(&self.0, |buf, node| TcpUdpPackedNode::to_bytes(node, buf))
307        )
308    }
309}
310
311/// Contains list in `PackedNode` format.
312#[derive(Clone, Debug, Default, Eq, PartialEq)]
313pub struct PathNodes(pub Vec<TcpUdpPackedNode>);
314
315impl FromBytes for PathNodes {
316    named!(from_bytes<PathNodes>, do_parse!(
317        tag!([0x0b, 0x00]) >>
318        tag!(SECTION_MAGIC) >>
319        nodes: many0!(TcpUdpPackedNode::from_bytes) >>
320        (PathNodes(nodes))
321    ));
322}
323
324impl ToBytes for PathNodes {
325    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
326        do_gen!(buf,
327            gen_le_u16!(0x000b) >>
328            gen_slice!(SECTION_MAGIC) >>
329            gen_many_ref!(&self.0, |buf, node| TcpUdpPackedNode::to_bytes(node, buf))
330        )
331    }
332}
333
334/** Friend state format for a single friend, compatible with what C toxcore
335does with on `GCC x86{,_x64}` platform.
336
337Data that is supposed to be strings (friend request message, friend name,
338friend status message) might, or might not even be a valid UTF-8. **Anything
339using that data should validate whether it's actually correct UTF-8!**
340
341*feel free to add compatibility to what broken C toxcore does on other
342platforms*
343
344https://zetok.github.io/tox-spec/#friends-0x03
345*/
346#[derive(Clone, Debug, Eq, PartialEq)]
347pub struct FriendState {
348    friend_status: FriendStatus,
349    pk: PublicKey,
350    /// Friend request message that is being sent to friend.
351    fr_msg: Vec<u8>,
352    /// Friend's name.
353    name: Name,
354    status_msg: StatusMsg,
355    user_status: UserWorkingStatus,
356    nospam: NoSpam,
357    /// Time when friend was last seen online.
358    last_seen: u64,
359}
360
361/// Number of bytes of serialized [`FriendState`](./struct.FriendState.html).
362pub const FRIENDSTATEBYTES: usize = 1      // "Status"
363    + PUBLICKEYBYTES
364    /* Friend request message      */ + REQUEST_MSG_LEN
365    /* padding1                    */ + 1
366    /* actual size of FR message   */ + 2
367    /* Name;                       */ + NAME_LEN
368    /* actual size of Name         */ + 2
369    /* Status msg;                 */ + STATUS_MSG_LEN
370    /* padding2                    */ + 1
371    /* actual size of status msg   */ + 2
372    /* UserStatus                  */ + 1
373    /* padding3                    */ + 3
374    /* only used for sending FR    */ + NOSPAMBYTES
375    /* last time seen              */ + 8;
376
377impl FromBytes for FriendState {
378    named!(from_bytes<FriendState>, do_parse!(
379        friend_status: call!(FriendStatus::from_bytes) >>
380        pk: call!(PublicKey::from_bytes) >>
381        fr_msg_bytes: take!(REQUEST_MSG_LEN) >>
382        _padding1: take!(1) >>
383        fr_msg_len: be_u16 >>
384        verify!(value!(fr_msg_len), |len| *len <= REQUEST_MSG_LEN as u16) >>
385        fr_msg: value!(fr_msg_bytes[..fr_msg_len as usize].to_vec()) >>
386        name_bytes: take!(NAME_LEN) >>
387        name_len: be_u16 >>
388        verify!(value!(name_len), |len| *len <= NAME_LEN as u16) >>
389        name: value!(Name(name_bytes[..name_len as usize].to_vec())) >>
390        status_msg_bytes: take!(STATUS_MSG_LEN) >>
391        _padding2: take!(1) >>
392        status_msg_len: be_u16 >>
393        verify!(value!(status_msg_len), |len| *len <= STATUS_MSG_LEN as u16) >>
394        status_msg: value!(StatusMsg(status_msg_bytes[..status_msg_len as usize].to_vec())) >>
395        user_status: call!(UserWorkingStatus::from_bytes) >>
396        _padding3: take!(3) >>
397        nospam: call!(NoSpam::from_bytes) >>
398        last_seen: le_u64 >>
399        (FriendState {
400            friend_status,
401            pk,
402            fr_msg,
403            name,
404            status_msg,
405            user_status,
406            nospam,
407            last_seen,
408        })
409    ));
410}
411
412impl ToBytes for FriendState {
413    #[allow(clippy::cognitive_complexity)]
414    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
415        let mut fr_msg_pad = self.fr_msg.clone();
416        let mut name_pad = self.name.0.clone();
417        let mut status_msg_pad = self.status_msg.0.clone();
418        fr_msg_pad.resize(REQUEST_MSG_LEN, 0);
419        name_pad.resize(NAME_LEN, 0);
420        status_msg_pad.resize(STATUS_MSG_LEN, 0);
421
422        do_gen!(buf,
423            gen_le_u8!(self.friend_status as u8) >>
424            gen_slice!(self.pk.as_ref()) >>
425            gen_slice!(fr_msg_pad.as_slice()) >>
426            gen_le_u8!(0) >>
427            gen_be_u16!(self.fr_msg.len() as u16) >>
428            gen_slice!(name_pad.as_slice()) >>
429            gen_be_u16!(self.name.0.len() as u16) >>
430            gen_slice!(status_msg_pad.as_slice()) >>
431            gen_le_u8!(0) >>
432            gen_be_u16!(self.status_msg.0.len() as u16) >>
433            gen_le_u8!(self.user_status as u8) >>
434            gen_le_u8!(0) >>
435            gen_le_u16!(0) >>
436            gen_slice!(self.nospam.0) >>
437            gen_le_u64!(self.last_seen)
438        )
439    }
440}
441
442/** Wrapper struct for `Vec<FriendState>` to ease working with friend lists.
443*/
444#[derive(Clone, Debug, Default, Eq, PartialEq)]
445pub struct Friends(pub Vec<FriendState>);
446
447impl FromBytes for Friends {
448    named!(from_bytes<Friends>, do_parse!(
449        tag!([0x03, 0x00]) >>
450        tag!(SECTION_MAGIC) >>
451        friends: many0!(flat_map!(take(FRIENDSTATEBYTES), FriendState::from_bytes)) >>
452        (Friends(friends))
453    ));
454}
455
456impl ToBytes for Friends {
457    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
458        do_gen!(buf,
459            gen_le_u16!(0x0003) >>
460            gen_slice!(SECTION_MAGIC) >>
461            gen_many_ref!(&self.0, |buf, friend| FriendState::to_bytes(friend, buf))
462        )
463    }
464}
465
466/// End of the state format data.
467#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
468pub struct Eof;
469
470impl FromBytes for Eof {
471    named!(from_bytes<Eof>, do_parse!(
472        tag!([0xff, 0x00]) >>
473        tag!(SECTION_MAGIC) >>
474        (Eof)
475    ));
476}
477
478impl ToBytes for Eof {
479    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
480        do_gen!(buf,
481            gen_le_u16!(0x00ff) >>
482            gen_slice!(SECTION_MAGIC)
483        )
484    }
485}
486
487/** Sections of state format.
488
489https://zetok.github.io/tox-spec/#sections
490*/
491#[derive(Clone, Debug, Eq, PartialEq)]
492pub enum Section {
493    /** Section for [`NoSpam`](../../toxid/struct.NoSpam.html), public and
494    secret keys.
495
496    https://zetok.github.io/tox-spec/#nospam-and-keys-0x01
497    */
498    NospamKeys(NospamKeys),
499    /** Section for DHT-related data – [`DhtState`](./struct.DhtState.html).
500
501    https://zetok.github.io/tox-spec/#dht-0x02
502    */
503    DhtState(DhtState),
504    /** Section for friends data. Contains list of [`Friends`]
505    (./struct.Friends.html).
506
507    https://zetok.github.io/tox-spec/#friends-0x03
508    */
509    Friends(Friends),
510    /** Section for own [`StatusMsg`](./struct.StatusMsg.html).
511
512    https://zetok.github.io/tox-spec/#status-message-0x05
513    */
514    Name(Name),
515    /** Section for own [`StatusMsg`](./struct.StatusMsg.html).
516
517    https://zetok.github.io/tox-spec/#status-message-0x05
518    */
519    StatusMsg(StatusMsg),
520    /** Section for own [`UserStatus`](./enum.UserStatus.html).
521
522    https://zetok.github.io/tox-spec/#status-0x06
523    */
524    UserStatus(UserStatus),
525    /** Section for a list of [`TcpRelays`](./struct.TcpRelays.html).
526
527    https://zetok.github.io/tox-spec/#tcp-relays-0x0a
528    */
529    TcpRelays(TcpRelays),
530    /** Section for a list of [`PathNodes`](./struct.PathNodes.html) for onion
531    routing.
532
533    https://zetok.github.io/tox-spec/#path-nodes-0x0b
534    */
535    PathNodes(PathNodes),
536    /// End of file. https://zetok.github.io/tox-spec/#eof-0xff
537    Eof(Eof),
538}
539
540impl FromBytes for Section {
541    named!(from_bytes<Section>, alt!(
542        map!(NospamKeys::from_bytes, Section::NospamKeys) |
543        map!(DhtState::from_bytes, Section::DhtState) |
544        map!(Friends::from_bytes, Section::Friends) |
545        map!(Name::from_bytes, Section::Name) |
546        map!(StatusMsg::from_bytes, Section::StatusMsg) |
547        map!(UserStatus::from_bytes, Section::UserStatus) |
548        map!(TcpRelays::from_bytes, Section::TcpRelays) |
549        map!(PathNodes::from_bytes, Section::PathNodes) |
550        map!(Eof::from_bytes, Section::Eof)
551    ));
552}
553
554impl ToBytes for Section {
555    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
556        let (buf, start_idx) = buf;
557
558        if buf.len() < start_idx + 4 {
559            return Err(GenError::BufferTooSmall(start_idx + 4));
560        }
561
562        let buf = (buf, start_idx + 4);
563        let (buf, idx) = match *self {
564            Section::NospamKeys(ref p) => p.to_bytes(buf),
565            Section::DhtState(ref p) => p.to_bytes(buf),
566            Section::Friends(ref p) => p.to_bytes(buf),
567            Section::Name(ref p) => p.to_bytes(buf),
568            Section::StatusMsg(ref p) => p.to_bytes(buf),
569            Section::UserStatus(ref p) => p.to_bytes(buf),
570            Section::TcpRelays(ref p) => p.to_bytes(buf),
571            Section::PathNodes(ref p) => p.to_bytes(buf),
572            Section::Eof(ref p) => p.to_bytes(buf),
573        }?;
574
575        let len = (idx - start_idx - 8) as u32;
576        buf[start_idx..start_idx + 4].copy_from_slice(&u32::to_le_bytes(len));
577        Ok((buf, idx))
578    }
579}
580
581/// State Format magic bytes.
582const STATE_MAGIC: &[u8; 4] = &[0x1f, 0x1b, 0xed, 0x15];
583
584/** Tox State sections. Use to manage `.tox` save files.
585
586https://zetok.github.io/tox-spec/#state-format
587*/
588#[derive(Clone, Debug, Eq, PartialEq)]
589pub struct State {
590    sections: Vec<Section>,
591}
592
593impl FromBytes for State {
594    named!(from_bytes<State>, do_parse!(
595        tag!(&[0; 4][..]) >>
596        tag!(STATE_MAGIC) >>
597        sections: many0!(flat_map!(length_data!(map!(le_u32, |len| len + 4)), Section::from_bytes)) >>
598        (State {
599            sections: sections.to_vec(),
600        })
601    ));
602}
603
604impl ToBytes for State {
605    fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
606        do_gen!(buf,
607            gen_slice!([0; 4]) >>
608            gen_slice!(STATE_MAGIC) >>
609            gen_many_ref!(&self.sections, |buf, section| Section::to_bytes(section, buf))
610        )
611    }
612}
613
614#[cfg(test)]
615mod tests {
616    use super::*;
617
618    use tox_packet::ip_port::*;
619
620    encode_decode_test!(
621        tox_crypto::crypto_init().unwrap(),
622        no_spam_keys_encode_decode,
623        NospamKeys::random()
624    );
625
626    encode_decode_test!(
627        tox_crypto::crypto_init().unwrap(),
628        dht_state_encode_decode,
629        DhtState(vec![
630            PackedNode {
631                pk: gen_keypair().0,
632                saddr: "1.2.3.4:1234".parse().unwrap(),
633            },
634            PackedNode {
635                pk: gen_keypair().0,
636                saddr: "1.2.3.5:1235".parse().unwrap(),
637            },
638        ])
639    );
640
641    encode_decode_test!(
642        tox_crypto::crypto_init().unwrap(),
643        friends_encode_decode,
644        Friends(vec![
645            FriendState {
646                friend_status: FriendStatus::Added,
647                pk: gen_keypair().0,
648                fr_msg: b"test msg".to_vec(),
649                name: Name(b"test name".to_vec()),
650                status_msg: StatusMsg(b"test status msg".to_vec()),
651                user_status: UserWorkingStatus::Online,
652                nospam: NoSpam([7; NOSPAMBYTES]),
653                last_seen: 1234,
654            },
655            FriendState {
656                friend_status: FriendStatus::Added,
657                pk: gen_keypair().0,
658                fr_msg: b"test msg2".to_vec(),
659                name: Name(b"test name2".to_vec()),
660                status_msg: StatusMsg(b"test status msg2".to_vec()),
661                user_status: UserWorkingStatus::Online,
662                nospam: NoSpam([8; NOSPAMBYTES]),
663                last_seen: 1235,
664            },
665        ])
666    );
667
668    encode_decode_test!(
669        tox_crypto::crypto_init().unwrap(),
670        friend_state_encode_decode,
671        FriendState {
672            friend_status: FriendStatus::Added,
673            pk: gen_keypair().0,
674            fr_msg: b"test msg".to_vec(),
675            name: Name(b"test name".to_vec()),
676            status_msg: StatusMsg(b"test status msg".to_vec()),
677            user_status: UserWorkingStatus::Online,
678            nospam: NoSpam([7; NOSPAMBYTES]),
679            last_seen: 1234,
680        }
681    );
682
683    encode_decode_test!(
684        tox_crypto::crypto_init().unwrap(),
685        name_encode_decode,
686        Name(vec![0,1,2,3,4])
687    );
688
689    encode_decode_test!(
690        tox_crypto::crypto_init().unwrap(),
691        status_msg_encode_decode,
692        StatusMsg(vec![0,1,2,3,4,5])
693    );
694
695    encode_decode_test!(
696        tox_crypto::crypto_init().unwrap(),
697        eof_encode_decode,
698        Eof
699    );
700
701    encode_decode_test!(
702        tox_crypto::crypto_init().unwrap(),
703        user_status_encode_decode,
704        UserStatus(UserWorkingStatus::Online)
705    );
706
707    encode_decode_test!(
708        tox_crypto::crypto_init().unwrap(),
709        tcp_relays_encode_decode,
710        TcpRelays(vec![
711            TcpUdpPackedNode {
712                pk: gen_keypair().0,
713                ip_port: IpPort {
714                    protocol: ProtocolType::TCP,
715                    ip_addr: "1.2.3.4".parse().unwrap(),
716                    port: 1234,
717                },
718            },
719            TcpUdpPackedNode {
720                pk: gen_keypair().0,
721                ip_port: IpPort {
722                    protocol: ProtocolType::UDP,
723                    ip_addr: "1.2.3.5".parse().unwrap(),
724                    port: 12345,
725                },
726            },
727        ])
728    );
729
730    encode_decode_test!(
731        tox_crypto::crypto_init().unwrap(),
732        path_nodes_encode_decode,
733        PathNodes(vec![
734            TcpUdpPackedNode {
735                pk: gen_keypair().0,
736                ip_port: IpPort {
737                    protocol: ProtocolType::TCP,
738                    ip_addr: "1.2.3.4".parse().unwrap(),
739                    port: 1234,
740                },
741            },
742            TcpUdpPackedNode {
743                pk: gen_keypair().0,
744                ip_port: IpPort {
745                    protocol: ProtocolType::UDP,
746                    ip_addr: "1.2.3.5".parse().unwrap(),
747                    port: 12345,
748                },
749            },
750        ])
751    );
752
753    encode_decode_test!(
754        tox_crypto::crypto_init().unwrap(),
755        state_encode_decode,
756        State {
757            sections: vec![
758                Section::NospamKeys(NospamKeys::random()),
759                Section::DhtState(DhtState(vec![
760                    PackedNode {
761                        pk: gen_keypair().0,
762                        saddr: "1.2.3.4:1234".parse().unwrap(),
763                    },
764                    PackedNode {
765                        pk: gen_keypair().0,
766                        saddr: "1.2.3.5:1235".parse().unwrap(),
767                    },
768                ])),
769                Section::Friends(Friends(vec![
770                    FriendState {
771                        friend_status: FriendStatus::Added,
772                        pk: gen_keypair().0,
773                        fr_msg: b"test msg".to_vec(),
774                        name: Name(b"test name".to_vec()),
775                        status_msg: StatusMsg(b"test status msg".to_vec()),
776                        user_status: UserWorkingStatus::Online,
777                        nospam: NoSpam([7; NOSPAMBYTES]),
778                        last_seen: 1234,
779                    },
780                    FriendState {
781                        friend_status: FriendStatus::Added,
782                        pk: gen_keypair().0,
783                        fr_msg: b"test msg2".to_vec(),
784                        name: Name(b"test name2".to_vec()),
785                        status_msg: StatusMsg(b"test status msg2".to_vec()),
786                        user_status: UserWorkingStatus::Online,
787                        nospam: NoSpam([8; NOSPAMBYTES]),
788                        last_seen: 1235,
789                    },
790                ])),
791                Section::Name(Name(vec![0,1,2,3,4])),
792                Section::StatusMsg(StatusMsg(vec![0,1,2,3,4,5])),
793                Section::UserStatus(UserStatus(UserWorkingStatus::Online)),
794                Section::TcpRelays(TcpRelays(vec![
795                    TcpUdpPackedNode {
796                        pk: gen_keypair().0,
797                        ip_port: IpPort {
798                            protocol: ProtocolType::TCP,
799                            ip_addr: "1.2.3.4".parse().unwrap(),
800                            port: 1234,
801                        },
802                    },
803                    TcpUdpPackedNode {
804                        pk: gen_keypair().0,
805                        ip_port: IpPort {
806                            protocol: ProtocolType::UDP,
807                            ip_addr: "1.2.3.5".parse().unwrap(),
808                            port: 12345,
809                        },
810                    },
811                ])),
812                Section::PathNodes(PathNodes(vec![
813                    TcpUdpPackedNode {
814                        pk: gen_keypair().0,
815                        ip_port: IpPort {
816                            protocol: ProtocolType::TCP,
817                            ip_addr: "1.2.3.4".parse().unwrap(),
818                            port: 1234,
819                        },
820                    },
821                    TcpUdpPackedNode {
822                        pk: gen_keypair().0,
823                        ip_port: IpPort {
824                            protocol: ProtocolType::UDP,
825                            ip_addr: "1.2.3.5".parse().unwrap(),
826                            port: 12345,
827                        },
828                    },
829                ])),
830                Section::Eof(Eof),
831            ],
832        }
833    );
834}