nectar/
lib.rs

1#![doc = include_str!("../README.md")]
2#![forbid(unsafe_code)]
3
4// RFC 854 `<https://tools.ietf.org/html/rfc854>`
5//
6// Originally based off of https://github.com/jtenner/telnet_codec, which has
7// been archived.
8
9use std::mem;
10
11use bytes::{Buf, BufMut, Bytes, BytesMut};
12use tokio_util::codec::{Decoder, Encoder};
13
14use crate::{
15    constants::{
16        CHARSET, CHARSET_ACCEPTED, CHARSET_REJECTED, CHARSET_REQUEST, CHARSET_TTABLE_REJECTED, DO,
17        DONT, ENVIRON, IAC, LINEMODE, LINEMODE_FORWARD_MASK, LINEMODE_SLC, MODE, NAWS, NOP, SB, SE,
18        WILL, WONT,
19    },
20    env::{decode_env, encode_env_op},
21    error::TelnetError,
22    event::TelnetEvent,
23    linemode::ForwardMaskOption,
24    option::TelnetOption,
25    subnegotiation::{LineModeOption, SubnegotiationType},
26};
27
28/// Various byte or byte sequences used in the Telnet protocol.
29pub mod constants;
30/// Telnet environment options
31pub mod env;
32/// Codec and Io errors that may occur while processing Telnet events.
33pub mod error;
34/// Top-level Telnet events, such as Message, Do, Will, and Subnegotiation.
35pub mod event;
36/// Telnet linemode options
37pub mod linemode;
38/// Telnet options such as `Echo`, `GoAhead`, and `SuppressGoAhead`.
39pub mod option;
40/// Telnet subnegotiation options.
41pub mod subnegotiation;
42
43type Result<T> = std::result::Result<T, TelnetError>;
44
45/// Implements a Tokio codec for the Telnet protocol, along with MUD-specific
46/// extension protocols such as GMCP.
47///
48/// You should never have to interact with this directly.
49#[derive(Debug)]
50pub struct TelnetCodec {
51    /// Whether or not the client has enabled the Suppress Go Ahead option.
52    pub sga: bool,
53    pub max_buffer_length: usize,
54    pub buffer: Vec<u8>,
55    /// If this field is set to false, nectar will generate an event for each
56    /// character instead of each message
57    pub message_mode: bool,
58    /// Attempt to parse unicode when received
59    #[cfg(feature = "unicode")]
60    pub unicode: bool,
61}
62
63impl TelnetCodec {
64    #[must_use]
65    pub fn new(max_buffer_length: usize) -> Self {
66        TelnetCodec {
67            sga: false,
68            max_buffer_length,
69            buffer: Vec::new(),
70            message_mode: true,
71            #[cfg(feature = "unicode")]
72            unicode: false,
73        }
74    }
75}
76
77impl Decoder for TelnetCodec {
78    type Item = TelnetEvent;
79    type Error = TelnetError;
80
81    fn decode(&mut self, buffer: &mut BytesMut) -> Result<Option<Self::Item>> {
82        let mut byte_index = 0;
83
84        if self.sga && !self.buffer.is_empty() {
85            let buf = mem::take(&mut self.buffer);
86            let result = String::from_utf8_lossy(&buf[..]);
87
88            return Ok(Some(TelnetEvent::Message(result.to_string())));
89        }
90
91        if buffer.is_empty() {
92            return Ok(None);
93        }
94
95        if self.sga {
96            return Ok(decode_suppress_go_ahead(&mut byte_index, buffer));
97        }
98
99        Ok(decode_bytes(self, &mut byte_index, buffer))
100    }
101}
102
103impl Encoder<TelnetEvent> for TelnetCodec {
104    type Error = TelnetError;
105
106    fn encode(&mut self, event: TelnetEvent, buffer: &mut BytesMut) -> Result<()> {
107        match event {
108            TelnetEvent::Do(option) => encode_negotiate(DO, option, buffer),
109            TelnetEvent::Dont(option) => encode_negotiate(DONT, option, buffer),
110            TelnetEvent::Will(option) => encode_negotiate(WILL, option, buffer),
111            TelnetEvent::Wont(option) => encode_negotiate(WONT, option, buffer),
112            TelnetEvent::Subnegotiate(sb_type) => encode_sb(sb_type, buffer),
113            TelnetEvent::Message(msg) => encode_message(msg, buffer),
114            TelnetEvent::RawMessage(msg) => encode_raw_message(msg, buffer),
115            _ => {}
116        }
117
118        Ok(())
119    }
120}
121
122#[cfg(feature = "unicode")]
123fn decode_utf8(byte_index: usize, buffer: &mut BytesMut, start: u8) -> Option<TelnetEvent> {
124    let length = match start {
125        0xC2..=0xDF => 2,
126        0xE0..=0xEF => 3,
127        // In theory this should never happen...
128        0xF0..=0xF4 => 4,
129        _ => 1,
130    };
131
132    if length == 1 {
133        buffer.advance(byte_index + 1);
134        Some(TelnetEvent::Unicode(start as char))
135    } else {
136        if let Ok(s) = std::str::from_utf8(&buffer[byte_index..byte_index + length]) {
137            if s.chars().count() != 1 {
138                // Something weird happened here...
139                // Maybe we should disconnect / fail here instead
140
141                buffer.advance(byte_index + length);
142                return Some(TelnetEvent::Nop);
143            }
144
145            // We can unwrap here since we checked it above.
146            let c = s.chars().next().unwrap();
147
148            buffer.advance(byte_index + length);
149            return Some(TelnetEvent::Unicode(c));
150        }
151
152        // We were unable to parse the unicode...
153        // Discard the input and act like nothing happened!
154
155        buffer.advance(byte_index + length);
156        Some(TelnetEvent::Nop)
157    }
158}
159
160fn decode_negotiate(byte_index: usize, buffer: &mut BytesMut, option: u8) -> Option<TelnetEvent> {
161    if byte_index + 2 >= buffer.len() {
162        return None;
163    }
164
165    let byte = buffer[byte_index + 2];
166    buffer.advance(byte_index + 3);
167    match option {
168        WILL => Some(TelnetEvent::Will(byte.into())),
169        WONT => Some(TelnetEvent::Wont(byte.into())),
170        DO => Some(TelnetEvent::Do(byte.into())),
171        DONT => Some(TelnetEvent::Dont(byte.into())),
172        _ => None,
173    }
174}
175
176fn decode_suppress_go_ahead(byte_index: &mut usize, buffer: &mut BytesMut) -> Option<TelnetEvent> {
177    match buffer[0] {
178        IAC => {
179            if 1 >= buffer.len() {
180                return None;
181            }
182
183            match buffer[*byte_index + 1] {
184                IAC => {
185                    buffer.advance(2);
186                    Some(TelnetEvent::Character(IAC))
187                }
188                _ => None,
189            }
190        }
191        _ => None,
192    }
193}
194
195fn decode_negotiate_about_window_size(subvec: &[u8]) -> Option<TelnetEvent> {
196    match subvec.len() {
197        4 => {
198            let result = SubnegotiationType::WindowSize(
199                (u16::from(subvec[0]) << 8) | u16::from(subvec[1]),
200                (u16::from(subvec[2]) << 8) | u16::from(subvec[3]),
201            );
202            Some(TelnetEvent::Subnegotiate(result))
203        }
204        _ => None,
205    }
206}
207
208fn decode_linemode(subvec: &[u8]) -> Option<TelnetEvent> {
209    if subvec.is_empty() {
210        return None;
211    }
212
213    let suboption = match subvec[0] {
214        WILL | WONT | DO | DONT => LineModeOption::ForwardMask(ForwardMaskOption::from(subvec[0])),
215        _ => LineModeOption::from(subvec[0]),
216    };
217
218    match suboption {
219        LineModeOption::SLC(_) => {
220            let slc_data = &subvec[1..];
221
222            // (function, flag, value)
223            let slc_triples = slc_data
224                .chunks_exact(3)
225                .map(|chunk| ((chunk[0], chunk[1]).into(), chunk[2] as char))
226                .collect();
227            Some(TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(LineModeOption::SLC(
228                slc_triples,
229            ))))
230        }
231        LineModeOption::ForwardMask(_) => {
232            let data = &subvec[2..];
233            let option = match subvec[0] {
234                DO => ForwardMaskOption::Do(data.to_vec()),
235                byte => ForwardMaskOption::from(byte),
236            };
237
238            Some(TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(
239                LineModeOption::ForwardMask(option),
240            )))
241        }
242        LineModeOption::Mode(_) => {
243            let mode = subvec[1];
244
245            Some(TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(LineModeOption::Mode(
246                mode,
247            ))))
248        }
249        LineModeOption::Unknown(_, _) => {
250            let data = &subvec[1..];
251            Some(TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(LineModeOption::Unknown(
252                subvec[0],
253                Bytes::from(data.to_vec()),
254            ))))
255        }
256    }
257}
258
259fn decode_charset(subvec: &[u8]) -> Option<TelnetEvent> {
260    if subvec.is_empty() {
261        return None;
262    }
263
264    match subvec[0] {
265        CHARSET_REQUEST => {
266            if subvec.len() == 1 {
267                return None;
268            }
269
270            let separator = subvec[1];
271            let charsets: Vec<_> =
272                subvec[2..].split(|&x| x == separator).map(|x| Bytes::from(x.to_vec())).collect();
273
274            if charsets.is_empty() {
275                return None;
276            }
277
278            let result = SubnegotiationType::CharsetRequest(charsets);
279            Some(TelnetEvent::Subnegotiate(result))
280        }
281        CHARSET_ACCEPTED => {
282            let result = SubnegotiationType::CharsetAccepted(Bytes::from(subvec[1..].to_vec()));
283            Some(TelnetEvent::Subnegotiate(result))
284        }
285        CHARSET_REJECTED => {
286            let result = SubnegotiationType::CharsetRejected;
287            Some(TelnetEvent::Subnegotiate(result))
288        }
289        CHARSET_TTABLE_REJECTED => {
290            let result = SubnegotiationType::CharsetTTableRejected;
291            Some(TelnetEvent::Subnegotiate(result))
292        }
293        _ => None,
294    }
295}
296
297fn decode_unknown(option: u8, subvec: Vec<u8>) -> TelnetEvent {
298    TelnetEvent::Subnegotiate(SubnegotiationType::Unknown(option.into(), Bytes::from(subvec)))
299}
300
301fn decode_next_byte(codec: &mut TelnetCodec, buffer_size: &mut usize, byte: u8) {
302    if buffer_size < &mut codec.max_buffer_length {
303        codec.buffer.push(byte);
304        *buffer_size += 1;
305    }
306}
307
308fn decode_subnegotiation_end(
309    invalid: bool,
310    buffer: &mut BytesMut,
311    subvec: Vec<u8>,
312    option: u8,
313) -> Option<TelnetEvent> {
314    if invalid {
315        None
316    } else {
317        let opt = match option {
318            NAWS => decode_negotiate_about_window_size(&subvec),
319            CHARSET => decode_charset(&subvec),
320            LINEMODE => decode_linemode(&subvec),
321            ENVIRON => decode_env(&subvec),
322            _ => Some(decode_unknown(option, subvec)),
323        };
324
325        if let Some(event) = &opt {
326            buffer.advance(event.len());
327        }
328
329        opt
330    }
331}
332
333fn decode_bytes(
334    codec: &mut TelnetCodec,
335    byte_index: &mut usize,
336    buffer: &mut BytesMut,
337) -> Option<TelnetEvent> {
338    let mut codec_buffer_size = codec.buffer.len();
339
340    loop {
341        if *byte_index >= buffer.len() {
342            return None;
343        }
344
345        // Handle matches against the first byte in the buffer.
346        match buffer[*byte_index] {
347            IAC => {
348                if *byte_index + 1 >= buffer.len() {
349                    return None;
350                }
351
352                // Handle matches against the second byte in the buffer.
353                match buffer[*byte_index + 1] {
354                    IAC => {
355                        if codec.buffer.len() < codec.max_buffer_length {
356                            codec.buffer.push(IAC);
357                            codec_buffer_size += 1;
358                        }
359
360                        *byte_index += 1;
361                    }
362                    DO => return decode_negotiate(*byte_index, buffer, DO),
363                    DONT => return decode_negotiate(*byte_index, buffer, DONT),
364                    WILL => return decode_negotiate(*byte_index, buffer, WILL),
365                    WONT => return decode_negotiate(*byte_index, buffer, WONT),
366                    SB => {
367                        if *byte_index + 2 >= buffer.len() {
368                            buffer.advance(*byte_index + 2);
369                            return None;
370                        }
371
372                        let start = *byte_index;
373                        let opt = buffer[*byte_index + 2];
374
375                        *byte_index += 3;
376
377                        let mut subvec: Vec<u8> = Vec::new();
378                        let mut invalid = false;
379
380                        loop {
381                            if *byte_index > buffer.len() {
382                                buffer.advance(start);
383                                return None;
384                            }
385
386                            // Handle matches against the third byte in the
387                            // buffer. This is for subnegotiation.
388                            match buffer[*byte_index] {
389                                IAC => {
390                                    if *byte_index + 1 > buffer.len() {
391                                        return None;
392                                    }
393
394                                    // Handle matches against the fourth byte in
395                                    // the buffer. This is the final byte in the
396                                    // buffer.
397                                    match buffer[*byte_index + 1] {
398                                        SE => {
399                                            return decode_subnegotiation_end(
400                                                invalid, buffer, subvec, opt,
401                                            )
402                                        }
403                                        IAC => subvec.push(IAC),
404                                        _ => invalid = true,
405                                    }
406
407                                    *byte_index += 1;
408                                }
409                                _ => subvec.push(buffer[*byte_index]),
410                            }
411
412                            *byte_index += 1;
413                        }
414                    }
415                    NOP => *byte_index += 1,
416                    _ => {}
417                }
418            }
419            b'\n' => {
420                let mut codec_buffer = mem::take(&mut codec.buffer);
421                if codec_buffer.ends_with(&[b'\r']) {
422                    codec_buffer.pop();
423                    buffer.advance(*byte_index + 1);
424
425                    let result = String::from_utf8_lossy(&codec_buffer[..]);
426                    return Some(TelnetEvent::Message(result.to_string()));
427                }
428
429                decode_next_byte(codec, &mut codec_buffer_size, buffer[*byte_index]);
430            }
431            #[cfg(not(feature = "unicode"))]
432            c if !codec.message_mode => {
433                let mut codec_buffer = mem::take(&mut codec.buffer);
434                codec_buffer.pop();
435                buffer.advance(*byte_index + 1);
436                return Some(TelnetEvent::Character(c));
437            }
438
439            #[cfg(feature = "unicode")]
440            c if !codec.message_mode => {
441                // Unicode support is compiled in but not enabled,
442                // so just pass characters on as they are
443
444                if !codec.unicode {
445                    let mut codec_buffer = mem::take(&mut codec.buffer);
446                    codec_buffer.pop();
447                    buffer.advance(*byte_index + 1);
448                    return Some(TelnetEvent::Character(c));
449                }
450
451                return decode_utf8(*byte_index, buffer, c);
452            }
453            _ => decode_next_byte(codec, &mut codec_buffer_size, buffer[*byte_index]),
454        };
455
456        *byte_index += 1;
457    }
458}
459
460fn encode_negotiate(opt: u8, subopt: TelnetOption, buf: &mut BytesMut) {
461    buf.reserve(3);
462    buf.put_u8(IAC);
463
464    match opt {
465        DO => buf.put_u8(DO),
466        DONT => buf.put_u8(DONT),
467        WILL => buf.put_u8(WILL),
468        WONT => buf.put_u8(WONT),
469        _ => unreachable!(),
470    }
471
472    buf.put_u8(subopt.into());
473}
474
475fn encode_sb(sb: SubnegotiationType, buffer: &mut BytesMut) {
476    match sb {
477        SubnegotiationType::WindowSize(width, height) => {
478            buffer.reserve(9);
479            buffer.extend([IAC, SB, NAWS]);
480            buffer.put_u16(width);
481            buffer.put_u16(height);
482            buffer.extend([IAC, SE]);
483        }
484        SubnegotiationType::CharsetRequest(charsets) => {
485            let charset_lens = charsets.iter().map(|c| c.len()).sum::<usize>();
486            let spaces = charsets.len().saturating_sub(1);
487
488            buffer.reserve(7 + charset_lens + spaces);
489            let sep = b' ';
490            buffer.extend([IAC, SB, CHARSET, CHARSET_REQUEST, sep]);
491
492            for (i, charset) in charsets.iter().enumerate() {
493                buffer.extend(charset);
494                if i < charsets.len() - 1 {
495                    buffer.put_u8(sep);
496                }
497            }
498
499            buffer.extend([IAC, SE]);
500        }
501        SubnegotiationType::CharsetAccepted(charset) => {
502            buffer.reserve(6 + charset.len());
503            buffer.extend([IAC, SB, CHARSET, CHARSET_ACCEPTED]);
504            buffer.extend(charset);
505            buffer.extend([IAC, SE]);
506        }
507        SubnegotiationType::CharsetRejected => {
508            buffer.reserve(6);
509            buffer.extend([IAC, SB, CHARSET, CHARSET_REJECTED, IAC, SE]);
510        }
511        SubnegotiationType::CharsetTTableRejected => {
512            buffer.reserve(6);
513            buffer.extend([IAC, SB, CHARSET, CHARSET_TTABLE_REJECTED, IAC, SE]);
514        }
515        SubnegotiationType::Environment(op) => {
516            buffer.extend([IAC, SB, ENVIRON]);
517            encode_env_op(op, buffer);
518            buffer.extend([IAC, SE]);
519        }
520        SubnegotiationType::Unknown(option, bytes) => {
521            let mut bytes_buffer_size = bytes.len() + 5;
522
523            for byte in &bytes {
524                if *byte == IAC {
525                    bytes_buffer_size += 1;
526                }
527            }
528
529            buffer.reserve(bytes_buffer_size);
530
531            // IAC SUB OPTION
532            buffer.extend([IAC, SB, option.into()]);
533
534            // Write to the buffer
535            for byte in &bytes {
536                if *byte == IAC {
537                    buffer.extend([IAC, IAC]);
538                } else {
539                    buffer.put_u8(*byte);
540                }
541            }
542
543            // IAC SUBNEGOTIATION END
544            buffer.extend([IAC, SE]);
545        }
546        SubnegotiationType::LineMode(mode) => match mode {
547            LineModeOption::Mode(value) => {
548                buffer.reserve(7);
549                buffer.extend([IAC, SB, LINEMODE, MODE, value, IAC, SE]);
550            }
551            LineModeOption::SLC(values) => {
552                // 4: Subnegotiation begin values.len() * 3: each entry
553                // symbolizes a triple of bytes:
554                // - Function
555                // - Modifiers (acknowledgement, urgency etc.)
556                // - Character 2: Subnegotiation end
557
558                buffer.reserve(6 + values.len() * 3);
559                buffer.extend([IAC, SB, LINEMODE, LINEMODE_SLC]);
560
561                for &(dispatch, char) in &values {
562                    let (first, second) = dispatch.into();
563                    buffer.extend([first, second, char as u8]);
564                }
565
566                buffer.extend([IAC, SE]);
567            }
568            LineModeOption::ForwardMask(ForwardMaskOption::Do(data)) => {
569                // Note: this needs to be 32 bytes in binary mode
570                buffer.reserve(7 + 16);
571
572                buffer.extend([IAC, SB, LINEMODE, DO, LINEMODE_FORWARD_MASK]);
573
574                let iter = data.into_iter().take(16);
575                let zeros = std::iter::repeat(0).take(16 - iter.len());
576
577                buffer.extend(iter.chain(zeros));
578                buffer.extend([IAC, SE]);
579            }
580            LineModeOption::ForwardMask(option) => {
581                buffer.reserve(7);
582                buffer.extend([IAC, SB, LINEMODE, option.into(), LINEMODE_FORWARD_MASK, IAC, SE]);
583            }
584            LineModeOption::Unknown(option, data) => {
585                buffer.reserve(7 + data.len());
586                buffer.extend([IAC, SB, LINEMODE, option]);
587                buffer.extend(data);
588                buffer.extend([IAC, SE]);
589            }
590        },
591    }
592}
593
594fn encode_raw_message(message: String, buffer: &mut BytesMut) {
595    let bytes = Bytes::from(message);
596    let mut bytes_buffer_size = bytes.len();
597
598    for byte in &bytes {
599        if *byte == IAC {
600            bytes_buffer_size += 1;
601        }
602    }
603
604    buffer.reserve(bytes_buffer_size);
605
606    for byte in &bytes {
607        if *byte == IAC {
608            buffer.extend([IAC, IAC]);
609        }
610        buffer.put_u8(*byte);
611    }
612}
613
614fn encode_message(message: String, buffer: &mut BytesMut) {
615    encode_raw_message(message, buffer);
616
617    if !buffer.ends_with(b"\r\n") {
618        buffer.reserve(2);
619        buffer.extend([b'\r', b'\n']);
620    }
621}
622
623#[cfg(test)]
624mod tests {
625    use super::*;
626
627    fn setup() -> (TelnetCodec, BytesMut) {
628        let codec = TelnetCodec::new(16);
629        let buffer = BytesMut::new();
630        (codec, buffer)
631    }
632
633    mod test_decode {
634        use super::*;
635
636        #[test]
637        fn test_sga_true() {
638            let (mut codec, mut buffer) = setup();
639            codec.sga = true;
640
641            // when both the codec's internal buffer, and the input buffer are
642            // empty, there's nothing going on.
643            assert!(codec.decode(&mut buffer).unwrap().is_none());
644
645            // when the codec's internal buffer is not empty, clear it out and
646            // send it as a message
647            codec.buffer.extend([b'h', b'i', b'y', b'a', b' ', 0xf0, 0x9f, 0x98, 0x81]);
648            assert_eq!(
649                codec.decode(&mut buffer).unwrap().unwrap(),
650                TelnetEvent::Message("hiya ๐Ÿ˜".to_string())
651            );
652            assert!(codec.buffer.is_empty());
653
654            // when the codec's internal buffer is empty, and the input buffer
655            // has data, decode as a SuppressGoAhead
656            buffer.extend([IAC]);
657            assert!(codec.decode(&mut buffer).unwrap().is_none());
658            assert!(codec.buffer.is_empty());
659            assert_eq!(buffer.as_ref(), &[IAC]);
660            buffer.extend([IAC]); // Add a second, as two are interpreted as a single IAC
661            assert_eq!(codec.decode(&mut buffer).unwrap().unwrap(), TelnetEvent::Character(IAC));
662            assert!(codec.buffer.is_empty());
663            assert!(buffer.is_empty());
664
665            // Ignore IAC followed by non-IAC
666            buffer.extend([IAC, WILL]);
667            assert!(codec.decode(&mut buffer).unwrap().is_none());
668            assert!(codec.buffer.is_empty());
669            assert_eq!(buffer.as_ref(), &[IAC, WILL]);
670
671            // Ignore non-IAC followed by IAC
672            buffer.extend([WILL, IAC]);
673            assert!(codec.decode(&mut buffer).unwrap().is_none());
674            assert!(codec.buffer.is_empty());
675            assert_eq!(buffer.as_ref(), &[IAC, WILL, WILL, IAC]); // previous stuff is still there
676        }
677
678        mod test_sga_false {
679            use super::*;
680
681            #[test]
682            fn test_buffer_starts_with_newline() {
683                let (mut codec, mut buffer) = setup();
684
685                codec.buffer.extend([b'c', b'o', b'o', b'l', b'!', b'\r']);
686                buffer.extend([b'\n', b'y', b'e', b's']);
687
688                // when the newline completes a \r\n sequence, send the contents
689                // of the codec's internal buffer as a message
690                assert_eq!(
691                    codec.decode(&mut buffer).unwrap().unwrap(),
692                    TelnetEvent::Message("cool!".to_string())
693                );
694                assert!(codec.buffer.is_empty());
695                assert_eq!(buffer.as_ref(), &[b'y', b'e', b's']);
696
697                // When the character does not complete a \r\n sequence, and is
698                // not IAC, append it to the codec's internal buffer, but do not
699                // remove it from the input buffer.
700                assert_eq!(codec.decode(&mut buffer).unwrap(), None);
701                assert_eq!(&codec.buffer, &[b'y', b'e', b's']);
702                assert_eq!(buffer.as_ref(), &[b'y', b'e', b's']);
703            }
704
705            #[test]
706            fn test_overflow() {
707                let (mut codec, mut buffer) = setup();
708
709                buffer.extend([b'a'; 10]);
710                buffer.extend([b'z'; 10]);
711
712                assert!(codec.decode(&mut buffer).unwrap().is_none());
713
714                assert_eq!(&codec.buffer[..=9], &[b'a'; 10]);
715                assert_eq!(&codec.buffer[10..], &[b'z'; 6]);
716
717                assert_eq!(&buffer[..=9], &[b'a'; 10]);
718                assert_eq!(&buffer[10..], &[b'z'; 10]);
719            }
720
721            mod test_iac {
722                use super::*;
723                use crate::constants::ECHO;
724
725                #[test]
726                fn test_double_iac() {
727                    let (mut codec, mut buffer) = setup();
728
729                    // a doubled IAC on the wire is interpreted as a single byte
730                    // of data
731                    buffer.extend([IAC, IAC]);
732                    assert_eq!(codec.decode(&mut buffer).unwrap(), None);
733                    assert_eq!(&codec.buffer, &[IAC]);
734                    assert_eq!(buffer.as_ref(), &[IAC, IAC]);
735                }
736
737                #[test]
738                fn test_do() {
739                    let (mut codec, mut buffer) = setup();
740
741                    buffer.extend([IAC, DO, ECHO]);
742                    assert_eq!(
743                        codec.decode(&mut buffer).unwrap().unwrap(),
744                        TelnetEvent::Do(TelnetOption::Echo)
745                    );
746                    assert!(codec.buffer.is_empty());
747                    assert!(buffer.is_empty());
748                }
749
750                #[test]
751                fn test_dont() {
752                    let (mut codec, mut buffer) = setup();
753
754                    buffer.extend([IAC, DONT, ECHO]);
755                    assert_eq!(
756                        codec.decode(&mut buffer).unwrap().unwrap(),
757                        TelnetEvent::Dont(TelnetOption::Echo)
758                    );
759                    assert!(codec.buffer.is_empty());
760                    assert!(buffer.is_empty());
761                }
762
763                #[test]
764                fn test_will() {
765                    let (mut codec, mut buffer) = setup();
766
767                    buffer.extend([IAC, WILL, ECHO]);
768                    assert_eq!(
769                        codec.decode(&mut buffer).unwrap().unwrap(),
770                        TelnetEvent::Will(TelnetOption::Echo)
771                    );
772                    assert!(codec.buffer.is_empty());
773                    assert!(buffer.is_empty());
774                }
775
776                #[test]
777                fn test_wont() {
778                    let (mut codec, mut buffer) = setup();
779
780                    buffer.extend([IAC, WONT, ECHO]);
781                    assert_eq!(
782                        codec.decode(&mut buffer).unwrap().unwrap(),
783                        TelnetEvent::Wont(TelnetOption::Echo)
784                    );
785                    assert!(codec.buffer.is_empty());
786                    assert!(buffer.is_empty());
787                }
788
789                #[test]
790                fn test_nop() {
791                    let (mut codec, mut buffer) = setup();
792
793                    buffer.extend([IAC, NOP]);
794                    assert_eq!(codec.decode(&mut buffer).unwrap(), None);
795                    assert!(codec.buffer.is_empty());
796                    assert_eq!(buffer.as_ref(), &[IAC, NOP]);
797                }
798
799                #[test]
800                fn test_sb_naws() {
801                    let (mut codec, mut buffer) = setup();
802
803                    buffer.extend([IAC, SB, NAWS, 0x00, 0x50, 0x00, 0x50, IAC, SE]);
804                    assert_eq!(
805                        codec.decode(&mut buffer).unwrap().unwrap(),
806                        TelnetEvent::Subnegotiate(SubnegotiationType::WindowSize(80, 80))
807                    );
808                    assert!(codec.buffer.is_empty());
809                    assert!(buffer.is_empty());
810                }
811
812                #[test]
813                fn test_sb_charset_request() {
814                    let (mut codec, mut buffer) = setup();
815
816                    buffer.extend([IAC, SB, CHARSET, CHARSET_REQUEST, b' ']);
817                    buffer.extend("UTF-8".bytes());
818                    buffer.put_u8(b' ');
819                    buffer.extend("US-ASCII".bytes());
820                    buffer.extend([IAC, SE]);
821
822                    assert_eq!(
823                        codec.decode(&mut buffer).unwrap().unwrap(),
824                        TelnetEvent::Subnegotiate(SubnegotiationType::CharsetRequest(vec![
825                            Bytes::from("UTF-8"),
826                            Bytes::from("US-ASCII")
827                        ]))
828                    );
829                    assert!(codec.buffer.is_empty());
830                    assert!(buffer.is_empty());
831                }
832
833                #[test]
834                fn test_sb_charset_accepted() {
835                    let (mut codec, mut buffer) = setup();
836
837                    buffer.extend([IAC, SB, CHARSET, CHARSET_ACCEPTED]);
838                    buffer.extend("UTF-8".bytes());
839                    buffer.extend([IAC, SE]);
840
841                    assert_eq!(
842                        codec.decode(&mut buffer).unwrap().unwrap(),
843                        TelnetEvent::Subnegotiate(SubnegotiationType::CharsetAccepted(
844                            Bytes::from("UTF-8")
845                        ))
846                    );
847                    assert!(codec.buffer.is_empty());
848                    assert!(buffer.is_empty());
849                }
850
851                #[test]
852                fn test_sb_charset_rejected() {
853                    let (mut codec, mut buffer) = setup();
854
855                    buffer.extend([IAC, SB, CHARSET, CHARSET_REJECTED, IAC, SE]);
856
857                    assert_eq!(
858                        codec.decode(&mut buffer).unwrap().unwrap(),
859                        TelnetEvent::Subnegotiate(SubnegotiationType::CharsetRejected)
860                    );
861                    assert!(codec.buffer.is_empty());
862                    assert!(buffer.is_empty());
863                }
864
865                #[test]
866                fn test_sb_charset_ttable_rejected() {
867                    let (mut codec, mut buffer) = setup();
868
869                    buffer.extend([IAC, SB, CHARSET, CHARSET_TTABLE_REJECTED, IAC, SE]);
870
871                    assert_eq!(
872                        codec.decode(&mut buffer).unwrap().unwrap(),
873                        TelnetEvent::Subnegotiate(SubnegotiationType::CharsetTTableRejected)
874                    );
875                    assert!(codec.buffer.is_empty());
876                    assert!(buffer.is_empty());
877                }
878            }
879        }
880    }
881
882    mod test_encode {
883        use super::*;
884        use crate::{
885            constants::{ECHO, LINEMODE_EDIT, SLC_ABORT, SLC_BRK, SLC_SYNCH},
886            linemode::{Dispatch, SlcFunction},
887        };
888
889        #[test]
890        fn test_message() {
891            let (mut codec, mut buffer) = setup();
892            codec.encode(TelnetEvent::Message("hiya ๐Ÿ˜".to_string()), &mut buffer).unwrap();
893            assert_eq!(buffer.as_ref(), b"hiya \xF0\x9F\x98\x81\r\n");
894
895            let (mut codec, mut buffer) = setup();
896            let msg = "this message is larger than the max buffer length".to_string();
897            assert!(msg.len() > codec.max_buffer_length);
898            codec.encode(TelnetEvent::Message(msg), &mut buffer).unwrap();
899            assert_eq!(buffer.as_ref(), b"this message is larger than the max buffer length\r\n");
900        }
901
902        #[test]
903        #[cfg(feature = "unicode")]
904        fn test_unicode() {
905            let (mut codec, mut buffer) = setup();
906            codec.message_mode = false;
907            codec.unicode = true;
908            codec.sga = false;
909
910            buffer.extend(b"\xC3\xA4");
911
912            let result = codec.decode(&mut buffer);
913
914            assert!(matches!(result, Ok(Some(TelnetEvent::Unicode('รค')))));
915        }
916
917        #[test]
918        fn test_raw_message() {
919            let (mut codec, mut buffer) = setup();
920            codec.encode(TelnetEvent::RawMessage("hiya ๐Ÿ˜".to_string()), &mut buffer).unwrap();
921            assert_eq!(buffer.as_ref(), b"hiya \xF0\x9F\x98\x81");
922        }
923
924        #[test]
925        fn test_do() {
926            let (mut codec, mut buffer) = setup();
927            codec.encode(TelnetEvent::Do(TelnetOption::Echo), &mut buffer).unwrap();
928            assert_eq!(buffer.as_ref(), &[IAC, DO, ECHO]);
929        }
930
931        #[test]
932        fn test_dont() {
933            let (mut codec, mut buffer) = setup();
934            codec.encode(TelnetEvent::Dont(TelnetOption::Echo), &mut buffer).unwrap();
935            assert_eq!(buffer.as_ref(), &[IAC, DONT, ECHO]);
936        }
937
938        #[test]
939        fn test_will() {
940            let (mut codec, mut buffer) = setup();
941            codec.encode(TelnetEvent::Will(TelnetOption::Echo), &mut buffer).unwrap();
942            assert_eq!(buffer.as_ref(), &[IAC, WILL, ECHO]);
943        }
944
945        #[test]
946        fn test_wont() {
947            let (mut codec, mut buffer) = setup();
948            codec.encode(TelnetEvent::Wont(TelnetOption::Echo), &mut buffer).unwrap();
949            assert_eq!(buffer.as_ref(), &[IAC, WONT, ECHO]);
950        }
951
952        #[test]
953        fn test_sb_naws() {
954            let (mut codec, mut buffer) = setup();
955            codec
956                .encode(
957                    TelnetEvent::Subnegotiate(SubnegotiationType::WindowSize(80, 80)),
958                    &mut buffer,
959                )
960                .unwrap();
961            assert_eq!(buffer.as_ref(), &[IAC, SB, NAWS, 0x00, 0x50, 0x00, 0x50, IAC, SE]);
962        }
963
964        #[test]
965        fn test_sb_charset_request() {
966            let (mut codec, mut buffer) = setup();
967            codec
968                .encode(
969                    TelnetEvent::Subnegotiate(SubnegotiationType::CharsetRequest(vec![
970                        Bytes::from("UTF-8"),
971                        Bytes::from("US-ASCII"),
972                    ])),
973                    &mut buffer,
974                )
975                .unwrap();
976            assert_eq!(&buffer.as_ref()[0..=4], &[IAC, SB, CHARSET, CHARSET_REQUEST, b' ']);
977            assert_eq!(&buffer.as_ref()[5..], b"UTF-8 US-ASCII\xFF\xF0" as &[u8]);
978        }
979
980        #[test]
981        fn test_sb_charset_accepted() {
982            let (mut codec, mut buffer) = setup();
983            codec
984                .encode(
985                    TelnetEvent::Subnegotiate(SubnegotiationType::CharsetAccepted(Bytes::from(
986                        "UTF-8",
987                    ))),
988                    &mut buffer,
989                )
990                .unwrap();
991            assert_eq!(&buffer.as_ref()[0..=3], &[IAC, SB, CHARSET, CHARSET_ACCEPTED]);
992            assert_eq!(&buffer.as_ref()[4..], b"UTF-8\xFF\xF0" as &[u8]);
993        }
994
995        #[test]
996        fn test_sb_charset_rejected() {
997            let (mut codec, mut buffer) = setup();
998            codec
999                .encode(TelnetEvent::Subnegotiate(SubnegotiationType::CharsetRejected), &mut buffer)
1000                .unwrap();
1001            assert_eq!(buffer.as_ref(), &[IAC, SB, CHARSET, CHARSET_REJECTED, IAC, SE]);
1002        }
1003
1004        #[test]
1005        fn test_sb_charset_ttable_rejected() {
1006            let (mut codec, mut buffer) = setup();
1007            codec
1008                .encode(
1009                    TelnetEvent::Subnegotiate(SubnegotiationType::CharsetTTableRejected),
1010                    &mut buffer,
1011                )
1012                .unwrap();
1013            assert_eq!(buffer.as_ref(), &[IAC, SB, CHARSET, CHARSET_TTABLE_REJECTED, IAC, SE]);
1014        }
1015
1016        #[test]
1017        fn test_sb_linemode_mode_encode() {
1018            let (mut codec, mut buffer) = setup();
1019            codec
1020                .encode(
1021                    TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(LineModeOption::Mode(
1022                        LINEMODE_EDIT,
1023                    ))),
1024                    &mut buffer,
1025                )
1026                .unwrap();
1027
1028            assert_eq!(buffer.as_ref(), &[IAC, SB, LINEMODE, MODE, LINEMODE_EDIT, IAC, SE]);
1029        }
1030
1031        #[test]
1032        fn test_sb_linemode_mode_decode() {
1033            let (mut codec, mut buffer) = setup();
1034            buffer.extend([IAC, SB, LINEMODE, MODE, LINEMODE_EDIT, IAC, SE]);
1035            let event = codec.decode(&mut buffer).unwrap().unwrap();
1036            match event {
1037                TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(LineModeOption::Mode(
1038                    mode,
1039                ))) => {
1040                    assert_eq!(mode, LINEMODE_EDIT);
1041                }
1042                _ => panic!("Bad decode!"),
1043            };
1044        }
1045
1046        #[test]
1047        fn test_sb_linemode_slc_encode() {
1048            let (mut codec, mut buffer) = setup();
1049            let triples = [
1050                (Dispatch::from((SLC_ABORT, 0)), '0'),
1051                (Dispatch::from((SLC_SYNCH, 0)), '1'),
1052                (Dispatch::from((SLC_BRK, 0)), '2'),
1053            ];
1054
1055            codec
1056                .encode(
1057                    TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(LineModeOption::SLC(
1058                        triples.to_vec(),
1059                    ))),
1060                    &mut buffer,
1061                )
1062                .unwrap();
1063
1064            assert_eq!(
1065                buffer.as_ref(),
1066                &[
1067                    IAC,
1068                    SB,
1069                    LINEMODE,
1070                    LINEMODE_SLC,
1071                    SLC_ABORT,
1072                    0,
1073                    b'0',
1074                    SLC_SYNCH,
1075                    0,
1076                    b'1',
1077                    SLC_BRK,
1078                    0,
1079                    b'2',
1080                    IAC,
1081                    SE
1082                ]
1083            )
1084        }
1085
1086        #[test]
1087        fn test_sb_linemode_unk_decode() {
1088            let (mut codec, mut buffer) = setup();
1089
1090            buffer.extend([IAC, SB, LINEMODE, 123, 1, 2, 3, 4, 5, 6, IAC, SE]);
1091
1092            let event = codec.decode(&mut buffer).unwrap().unwrap();
1093
1094            match event {
1095                TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(
1096                    LineModeOption::Unknown(123, data),
1097                )) => {
1098                    assert_eq!(data.as_ref(), &[1, 2, 3, 4, 5, 6]);
1099                }
1100                _ => panic!("Bad decode!"),
1101            }
1102        }
1103
1104        #[test]
1105        fn test_sb_linemode_unk_encode() {
1106            let (mut codec, mut buffer) = setup();
1107
1108            codec
1109                .encode(
1110                    TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(
1111                        LineModeOption::Unknown(123, [1, 2, 3, 4, 5, 6].to_vec().into()),
1112                    )),
1113                    &mut buffer,
1114                )
1115                .unwrap();
1116
1117            assert_eq!(buffer.as_ref(), &[IAC, SB, LINEMODE, 123, 1, 2, 3, 4, 5, 6, IAC, SE]);
1118        }
1119
1120        #[test]
1121        fn test_sb_linemode_slc_decode() {
1122            let (mut codec, mut buffer) = setup();
1123
1124            buffer.extend([
1125                IAC,
1126                SB,
1127                LINEMODE,
1128                LINEMODE_SLC,
1129                SLC_ABORT,
1130                0,
1131                b'0',
1132                SLC_SYNCH,
1133                0,
1134                b'1',
1135                SLC_BRK,
1136                0,
1137                b'2',
1138                IAC,
1139                SE,
1140            ]);
1141
1142            let event = codec.decode(&mut buffer).unwrap().unwrap();
1143
1144            match event {
1145                TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(LineModeOption::SLC(
1146                    triples,
1147                ))) => {
1148                    assert_eq!(triples.len(), 3);
1149
1150                    const CHARS: [char; 3] = ['0', '1', '2'];
1151                    const FUNCS: [u8; 3] = [SLC_ABORT, SLC_SYNCH, SLC_BRK];
1152
1153                    for (index, &(dispatch, char)) in triples.iter().enumerate() {
1154                        assert_eq!(dispatch.function, SlcFunction::from(FUNCS[index]));
1155                        assert_eq!(char, CHARS[index]);
1156                    }
1157                }
1158                _ => panic!("Bad decode!"),
1159            }
1160        }
1161
1162        #[test]
1163        fn test_sb_linemode_fmask_decode() {
1164            let (mut codec, mut buffer) = setup();
1165            buffer.extend([
1166                IAC,
1167                SB,
1168                LINEMODE,
1169                DO,
1170                LINEMODE_FORWARD_MASK,
1171                0,
1172                0,
1173                0,
1174                0,
1175                0,
1176                0,
1177                0,
1178                0,
1179                0,
1180                0,
1181                0,
1182                0,
1183                0,
1184                0,
1185                0,
1186                123,
1187                IAC,
1188                SE,
1189            ]);
1190
1191            let event = codec.decode(&mut buffer).unwrap().unwrap();
1192
1193            match event {
1194                TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(
1195                    LineModeOption::ForwardMask(ForwardMaskOption::Do(data)),
1196                )) => {
1197                    assert_eq!(data.len(), 16);
1198                    assert_eq!(data[15], 123)
1199                }
1200                _ => panic!("Bad decode!"),
1201            }
1202        }
1203
1204        #[test]
1205        fn test_sb_linemode_fmask_encode() {
1206            let (mut codec, mut buffer) = setup();
1207            codec
1208                .encode(
1209                    TelnetEvent::Subnegotiate(SubnegotiationType::LineMode(
1210                        LineModeOption::ForwardMask(ForwardMaskOption::Do(Vec::with_capacity(16))),
1211                    )),
1212                    &mut buffer,
1213                )
1214                .unwrap();
1215
1216            assert_eq!(
1217                buffer.as_ref(),
1218                &[
1219                    IAC,
1220                    SB,
1221                    LINEMODE,
1222                    DO,
1223                    LINEMODE_FORWARD_MASK,
1224                    0,
1225                    0,
1226                    0,
1227                    0,
1228                    0,
1229                    0,
1230                    0,
1231                    0,
1232                    0,
1233                    0,
1234                    0,
1235                    0,
1236                    0,
1237                    0,
1238                    0,
1239                    0,
1240                    IAC,
1241                    SE
1242                ]
1243            )
1244        }
1245    }
1246}