<commit_before>//! Thread-safe connections on IrcStreams.
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
#[cfg(any(feature = "encode", feature = "ssl"))] use std::io::{IoError, IoErrorKind};
#[cfg(feature = "encode")] use encoding::{DecoderTrap, EncoderTrap, Encoding};
#[cfg(feature = "encode")] use encoding::label::encoding_from_whatwg_label;
use data::kinds::{IrcReader, IrcWriter};
use data::message::Message;
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslStream, Tlsv1};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
#[experimental]
pub struct Connection<T: IrcReader, U: IrcWriter> {
    reader: Mutex<T>,
    writer: Mutex<U>,
}

/// A Connection over a buffered NetStream.
pub type NetConnection = Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>>;

impl Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<NetConnection> {
        Connection::connect_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specified server with a given timeout in
    /// milliseconds.
    #[experimental]
    pub fn connect_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<NetConnection> {
        Connection::connect_internal(host, port, Some(timeout_ms))
    }

    /// Creates a thread-safe TCP connection with an optional timeout.
    #[experimental]
    fn connect_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<NetConnection> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        Ok(Connection::new(
            BufferedReader::new(NetStream::UnsecuredTcpStream(socket.clone())),
            BufferedWriter::new(NetStream::UnsecuredTcpStream(socket))
        ))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl(host: &str, port: u16) -> IoResult<NetConnection> {
        Connection::connect_ssl_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specificed server over SSL with a given timeout
    /// in milliseconds. If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<NetConnection> {
        Connection::connect_ssl_internal(host, port, Some(timeout_ms))
    }

    /// Panics because SSL support was not included at compilation.
    #[experimental]
    #[cfg(not(feature = "ssl"))]
    fn connect_ssl_internal(host: &str, port: u16, _: Option<u64>)
    -> IoResult<NetConnection> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Creates a thread-safe TCP connection over SSL with an optional timeout.
    #[experimental]
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<NetConnection> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        let ssl = try!(ssl_to_io(SslContext::new(Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok(Connection::new(
            BufferedReader::new(NetStream::SslTcpStream(ssl_socket.clone())),
            BufferedWriter::new(NetStream::SslTcpSteram(ssl_socket)),
        ))
    }
}

impl<T: IrcReader, U: IrcWriter> Connection<T, U> {
    /// Creates a new connection from an IrcReader and an IrcWriter.
    #[experimental]
    pub fn new(reader: T, writer: U) -> Connection<T, U> {
        Connection {
            reader: Mutex::new(reader),
            writer: Mutex::new(writer),
        }
    }

    /// Sends a Message over this connection.
    #[experimental]
    #[cfg(feature = "encode")]
    pub fn send(&self, message: Message, encoding: &str) -> IoResult<()> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(IoError {
                kind: IoErrorKind::InvalidInput,
                desc: "Failed to find decoder.",
                detail: Some(format!("Invalid decoder: {}", encoding))
            })
        };
        let data = match encoding.encode(message.into_string()[], EncoderTrap::Strict) {
            Ok(data) => data,
            Err(data) => return Err(IoError {
                kind: IoErrorKind::InvalidInput,
                desc: "Failed to decode message.",
                detail: Some(format!("Failed to decode {} as {}.", data, encoding.name())),
            })
        };
        let mut writer = self.writer.lock();
        try!(writer.write(data[]));
        writer.flush()
    }

    /// Sends a message over this connection.
    #[experimental]
    #[cfg(not(feature = "encode"))]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut writer = self.writer.lock();
        try!(writer.write_str(message.into_string()[]));
        writer.flush()
    }

    /// Receives a single line from this connection.
    #[experimental]
    #[cfg(feature = "encoding")]
    pub fn recv(&self, encoding: &str) -> IoResult<String> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(IoError {
                kind: IoErrorKind::InvalidInput,
                desc: "Failed to find decoder.",
                detail: Some(format!("Invalid decoder: {}", encoding))
            })
        };
        self.reader.lock().read_until(b'\n').and_then(|line|
            match encoding.decode(line[], DecoderTrap::Strict) {
                Ok(data) => Ok(data),
                Err(data) => Err(IoError {
                    kind: IoErrorKind::InvalidInput,
                    desc: "Failed to decode message.",
                    detail: Some(format!("Failed to decode {} as {}.", data, encoding.name())),
                })
            }
        )
    }

    /// Receives a single line from this connection.
    #[experimental]
    #[cfg(not(feature = "encoding"))]
    pub fn recv(&self) -> IoResult<String> {
        self.reader.lock().read_line()
    }

    /// Acquires the Reader lock.
    #[experimental]
    pub fn reader<'a>(&'a self) -> MutexGuard<'a, T> {
        self.reader.lock()
    }

    /// Acquires the Writer lock.
    #[experimental]
    pub fn writer<'a>(&'a self) -> MutexGuard<'a, U> {
        self.writer.lock()
    }
}

/// Converts a Result<T, SslError> into an IoResult<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: Result<T, SslError>) -> IoResult<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "An SSL error occurred.",
            detail: Some(format!("{}", e)),
        }),
    }
}

/// An abstraction over different networked streams.
#[experimental]
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Reader for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Writer for NetStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }
}

#[cfg(test)]
mod test {
    use super::Connection;
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;
    #[cfg(feature = "encode")] use encoding::{DecoderTrap, Encoding};
    #[cfg(feature = "encode")] use encoding::all::ISO_8859_15;

    #[test]
    #[cfg(not(feature = "encode"))]
    fn send() {
        let conn = Connection::new(NullReader, MemWriter::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.writer().get_ref().to_vec()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_utf8() {
        let conn = Connection::new(NullReader, MemWriter::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("€ŠšŽžŒœŸ")), "l9"
        ).is_ok());
        let data = ISO_8859_15.decode(conn.stream().value()[], DecoderTrap::Strict).unwrap();
        assert_eq!(data[], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_iso885915() {

    }

    #[test]
    #[cfg(not(feature = "encode"))]
    fn recv() {
        let conn = Connection::new(
            MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec()), NullWriter
        );
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_utf8() {
        let conn = Connection::new(
            MemReader::new(b"PRIVMSG test :Testing!\r\n".to_vec()), NullWriter
        );
        assert_eq!(conn.recv("UTF-8").unwrap()[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_iso885915() {
        let conn = Connection::new(
            MemReader::new({
                let mut vec = Vec::new();
                vec.push_all(b"PRIVMSG test :");
                vec.push_all(&[0xA4, 0xA6, 0xA8, 0xB4, 0xB8, 0xBC, 0xBD, 0xBE]);
                vec.push_all(b"\r\n");
                vec
            }), NullWriter
        );
        assert_eq!(conn.recv("l9").unwrap()[], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }
}
<commit_msg>Fixed encode tests.<commit_after>//! Thread-safe connections on IrcStreams.
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
#[cfg(any(feature = "encode", feature = "ssl"))] use std::io::{IoError, IoErrorKind};
#[cfg(feature = "encode")] use encoding::{DecoderTrap, EncoderTrap, Encoding};
#[cfg(feature = "encode")] use encoding::label::encoding_from_whatwg_label;
use data::kinds::{IrcReader, IrcWriter};
use data::message::Message;
#[cfg(feature = "ssl")] use openssl::ssl::{SslContext, SslStream, Tlsv1};
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;

/// A thread-safe connection.
#[experimental]
pub struct Connection<T: IrcReader, U: IrcWriter> {
    reader: Mutex<T>,
    writer: Mutex<U>,
}

/// A Connection over a buffered NetStream.
pub type NetConnection = Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>>;

impl Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
    /// Creates a thread-safe TCP connection to the specified server.
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<NetConnection> {
        Connection::connect_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specified server with a given timeout in
    /// milliseconds.
    #[experimental]
    pub fn connect_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<NetConnection> {
        Connection::connect_internal(host, port, Some(timeout_ms))
    }

    /// Creates a thread-safe TCP connection with an optional timeout.
    #[experimental]
    fn connect_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<NetConnection> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        Ok(Connection::new(
            BufferedReader::new(NetStream::UnsecuredTcpStream(socket.clone())),
            BufferedWriter::new(NetStream::UnsecuredTcpStream(socket))
        ))
    }

    /// Creates a thread-safe TCP connection to the specified server over SSL.
    /// If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl(host: &str, port: u16) -> IoResult<NetConnection> {
        Connection::connect_ssl_internal(host, port, None)
    }

    /// Creates a thread-safe TCP connection to the specificed server over SSL with a given timeout
    /// in milliseconds. If the library is compiled without SSL support, this method panics.
    #[experimental]
    pub fn connect_ssl_with_timeout(host: &str, port: u16, timeout_ms: u64)
        -> IoResult<NetConnection> {
        Connection::connect_ssl_internal(host, port, Some(timeout_ms))
    }

    /// Panics because SSL support was not included at compilation.
    #[experimental]
    #[cfg(not(feature = "ssl"))]
    fn connect_ssl_internal(host: &str, port: u16, _: Option<u64>)
    -> IoResult<NetConnection> {
        panic!("Cannot connect to {}:{} over SSL without compiling with SSL support.", host, port)
    }

    /// Creates a thread-safe TCP connection over SSL with an optional timeout.
    #[experimental]
    #[cfg(feature = "ssl")]
    fn connect_ssl_internal(host: &str, port: u16, timeout_ms: Option<u64>)
    -> IoResult<NetConnection> {
        let mut socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        socket.set_timeout(timeout_ms);
        let ssl = try!(ssl_to_io(SslContext::new(Tlsv1)));
        let ssl_socket = try!(ssl_to_io(SslStream::new(&ssl, socket)));
        Ok(Connection::new(
            BufferedReader::new(NetStream::SslTcpStream(ssl_socket.clone())),
            BufferedWriter::new(NetStream::SslTcpSteram(ssl_socket)),
        ))
    }
}

impl<T: IrcReader, U: IrcWriter> Connection<T, U> {
    /// Creates a new connection from an IrcReader and an IrcWriter.
    #[experimental]
    pub fn new(reader: T, writer: U) -> Connection<T, U> {
        Connection {
            reader: Mutex::new(reader),
            writer: Mutex::new(writer),
        }
    }

    /// Sends a Message over this connection.
    #[experimental]
    #[cfg(feature = "encode")]
    pub fn send(&self, message: Message, encoding: &str) -> IoResult<()> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(IoError {
                kind: IoErrorKind::InvalidInput,
                desc: "Failed to find decoder.",
                detail: Some(format!("Invalid decoder: {}", encoding))
            })
        };
        let data = match encoding.encode(message.into_string()[], EncoderTrap::Strict) {
            Ok(data) => data,
            Err(data) => return Err(IoError {
                kind: IoErrorKind::InvalidInput,
                desc: "Failed to decode message.",
                detail: Some(format!("Failed to decode {} as {}.", data, encoding.name())),
            })
        };
        let mut writer = self.writer.lock();
        try!(writer.write(data[]));
        writer.flush()
    }

    /// Sends a message over this connection.
    #[experimental]
    #[cfg(not(feature = "encode"))]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut writer = self.writer.lock();
        try!(writer.write_str(message.into_string()[]));
        writer.flush()
    }

    /// Receives a single line from this connection.
    #[experimental]
    #[cfg(feature = "encoding")]
    pub fn recv(&self, encoding: &str) -> IoResult<String> {
        let encoding = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => return Err(IoError {
                kind: IoErrorKind::InvalidInput,
                desc: "Failed to find decoder.",
                detail: Some(format!("Invalid decoder: {}", encoding))
            })
        };
        self.reader.lock().read_until(b'\n').and_then(|line|
            match encoding.decode(line[], DecoderTrap::Strict) {
                Ok(data) => Ok(data),
                Err(data) => Err(IoError {
                    kind: IoErrorKind::InvalidInput,
                    desc: "Failed to decode message.",
                    detail: Some(format!("Failed to decode {} as {}.", data, encoding.name())),
                })
            }
        )
    }

    /// Receives a single line from this connection.
    #[experimental]
    #[cfg(not(feature = "encoding"))]
    pub fn recv(&self) -> IoResult<String> {
        self.reader.lock().read_line()
    }

    /// Acquires the Reader lock.
    #[experimental]
    pub fn reader<'a>(&'a self) -> MutexGuard<'a, T> {
        self.reader.lock()
    }

    /// Acquires the Writer lock.
    #[experimental]
    pub fn writer<'a>(&'a self) -> MutexGuard<'a, U> {
        self.writer.lock()
    }
}

/// Converts a Result<T, SslError> into an IoResult<T>.
#[cfg(feature = "ssl")]
fn ssl_to_io<T>(res: Result<T, SslError>) -> IoResult<T> {
    match res {
        Ok(x) => Ok(x),
        Err(e) => Err(IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "An SSL error occurred.",
            detail: Some(format!("{}", e)),
        }),
    }
}

/// An abstraction over different networked streams.
#[experimental]
pub enum NetStream {
    /// An unsecured TcpStream.
    UnsecuredTcpStream(TcpStream),
    /// An SSL-secured TcpStream.
    /// This is only available when compiled with SSL support.
    #[cfg(feature = "ssl")]
    SslTcpStream(SslStream<TcpStream>),
}

impl Reader for NetStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.read(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.read(buf),
        }
    }
}

impl Writer for NetStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self {
            &NetStream::UnsecuredTcpStream(ref mut stream) => stream.write(buf),
            #[cfg(feature = "ssl")]
            &NetStream::SslTcpStream(ref mut stream) => stream.write(buf),
        }
    }
}

#[cfg(test)]
mod test {
    use super::Connection;
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;
    #[cfg(feature = "encode")] use encoding::{DecoderTrap, Encoding};
    #[cfg(feature = "encode")] use encoding::all::{ISO_8859_15, UTF_8};

    #[test]
    #[cfg(not(feature = "encode"))]
    fn send() {
        let conn = Connection::new(NullReader, MemWriter::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))
        ).is_ok());
        let data = String::from_utf8(conn.writer().get_ref().to_vec()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_utf8() {
        let conn = Connection::new(NullReader, MemWriter::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("€ŠšŽžŒœŸ")), "UTF-8"
        ).is_ok());
        let data = UTF_8.decode(conn.writer().get_ref(), DecoderTrap::Strict).unwrap();
        assert_eq!(data[], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn send_iso885915() {
        let conn = Connection::new(NullReader, MemWriter::new());
        assert!(conn.send(
            Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("€ŠšŽžŒœŸ")), "l9"
        ).is_ok());
        let data = ISO_8859_15.decode(conn.writer().get_ref(), DecoderTrap::Strict).unwrap();
        assert_eq!(data[], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }

    #[test]
    #[cfg(not(feature = "encode"))]
    fn recv() {
        let conn = Connection::new(
            MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec()), NullWriter
        );
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_utf8() {
        let conn = Connection::new(
            MemReader::new(b"PRIVMSG test :Testing!\r\n".to_vec()), NullWriter
        );
        assert_eq!(conn.recv("UTF-8").unwrap()[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    #[cfg(feature = "encode")]
    fn recv_iso885915() {
        let conn = Connection::new(
            MemReader::new({
                let mut vec = Vec::new();
                vec.push_all(b"PRIVMSG test :");
                vec.push_all(&[0xA4, 0xA6, 0xA8, 0xB4, 0xB8, 0xBC, 0xBD, 0xBE]);
                vec.push_all(b"\r\n");
                vec
            }), NullWriter
        );
        assert_eq!(conn.recv("l9").unwrap()[], "PRIVMSG test :€ŠšŽžŒœŸ\r\n");
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serenity;
extern crate rand;
extern crate typemap;
extern crate stalch;
extern crate seximal;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;

use serenity::framework::StandardFramework;

const PREFIX: &str = "f>";
const WESTMANN: UserId = UserId(229154015626264577);
const MEMES: ChannelId = ChannelId(306454829738491904);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("lfalchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2017")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, _msg, args) {
    ctx.set_game(Game::playing(&args.join(" ")));
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }.unwrap();
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(args.join(" ") + "\n") {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }.unwrap();
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }.unwrap();
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

struct Handler;

fn main() {
    println!("{} in {}", WESTMANN, MEMES);

    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler);

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("seximal", seximal)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        eprintln!("{} in {}: image: {}", msg.channel_id.0, msg.author.id.0, msg.attachments.iter().any(|a| a.width.is_some()));
        if msg.channel_id == MEMES && msg.author.id == WESTMANN && msg.attachments.iter().any(|a| a.width.is_some()) {
            msg.channel_id.say("Den er gammel!").unwrap();
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "mc", "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "wt", "thunder", "tankspil";; "Jeg hader World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Communism is the ultimate goal of socialism.");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Some(d) = operation.parse::<f64>().ok() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    Ok(stack.push(res))
}

fn stalch_run<'a>(s: String) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<commit_msg>Add seticon<commit_after>#[macro_use]
extern crate serenity;
extern crate rand;
extern crate typemap;
extern crate stalch;
extern crate seximal;
extern crate hyper;
extern crate base64;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::io::Read;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;
use serenity::CACHE;

use serenity::framework::StandardFramework;

const PREFIX: &str = "f]";
const WESTMANN: UserId = UserId(229154015626264577);
const FALCH: UserId = UserId(165877785544491008);
const MEMES: ChannelId = ChannelId(306454829738491904);
const FALCHATS: GuildId = GuildId(189120762659995648);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("falchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2018")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, msg, args) {
    if msg.author.id == FALCH {
        ctx.set_game(Game::playing(&args.join(" ")));
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(seticon(_ctx, msg, args) {
    let s = args.join("/");

    if msg.author.id == FALCH {
        let img = {
            let client = hyper::Client::new();
            let mut resp = client.get(&format!("http://dev.lfalch.com/{}.png", s)).send()?;
            if !resp.status.is_success() {
                msg.reply("No success")?;
                return Ok(());
            }

            let mut v = Vec::new();

            resp.read_to_end(&mut v)?;

            let b64 = base64::encode(&v);
            let ext = "png";

            format!("data:image/{};base64,{}", ext, b64)
        };

        FALCHATS.edit(|e| e.icon(Some(&img)))?;
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(args.join(" ") + "\n") {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }?;
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

struct Handler;

fn main() {
    println!("{} in {}", WESTMANN, MEMES);

    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler);

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("seximal", seximal)
        .on("seticon", seticon)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        eprintln!("{} in {}: image: {}", msg.channel_id.0, msg.author.id.0, msg.attachments.iter().any(|a| a.width.is_some()));
        if msg.channel_id == MEMES && msg.author.id == WESTMANN && msg.attachments.iter().any(|a| a.width.is_some()) {
            msg.channel_id.say("Den er gammel!").unwrap();
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "mc", "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "wt", "thunder", "tankspil";; "Jeg hader World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Communism is the ultimate goal of socialism.");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Some(d) = operation.parse::<f64>().ok() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    Ok(stack.push(res))
}

fn stalch_run<'a>(s: String) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<|endoftext|>


<commit_before>#![feature(globs)]
extern crate rgtk;

use rgtk::*;
use rgtk::gtk::signals;

fn main() {
    gtk::init();

    let width = 1242;
    let height = 768;
    let sidebar_width = ((width as f32) * 0.32) as i32;
    let content_width = width - sidebar_width;
    let top_height = ((height as f32) * 0.8) as i32;

    let mut window = gtk::Window::new(gtk::window_type::TopLevel).unwrap();
    window.set_title("SolidOak");
    window.set_window_position(gtk::window_position::Center);
    window.set_default_size(width, height);

    window.connect(signals::DeleteEvent::new(|_| {
        gtk::main_quit();
        true
    }));

    let project_pane = gtk::TreeView::new().unwrap();
    let rusti_pane = gtk::TextView::new().unwrap();
    project_pane.set_size_request(sidebar_width, top_height);
    let mut vbox_1 = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    vbox_1.pack_start(&project_pane, false, true, 0);
    vbox_1.pack_start(&rusti_pane, true, true, 0);

    let editor_pane = gtk::TextView::new().unwrap();
    let build_pane = gtk::TextView::new().unwrap();
    editor_pane.set_size_request(content_width, top_height);
    let mut vbox_2 = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    vbox_2.pack_start(&editor_pane, false, true, 0);
    vbox_2.pack_start(&build_pane, true, true, 0);

    let mut hbox = gtk::Box::new(gtk::orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&vbox_1, false, true, 0);
    hbox.pack_start(&vbox_2, true, true, 0);
    window.add(&hbox);

    window.show_all();
    gtk::main();
}
<commit_msg>Add project buttons<commit_after>#![feature(globs)]
extern crate rgtk;

use rgtk::*;
use rgtk::gtk::signals;

fn main() {
    gtk::init();

    let width = 1242;
    let height = 768;
    let sidebar_width = ((width as f32) * 0.32) as i32;
    let content_width = width - sidebar_width;
    let top_height = ((height as f32) * 0.8) as i32;

    let mut window = gtk::Window::new(gtk::window_type::TopLevel).unwrap();
    window.set_title("SolidOak");
    window.set_window_position(gtk::window_position::Center);
    window.set_default_size(width, height);

    window.connect(signals::DeleteEvent::new(|_| {
        gtk::main_quit();
        true
    }));

    let new_project_button = gtk::Button::new_with_label("New Project").unwrap();
    let import_button = gtk::Button::new_with_label("Import").unwrap();
    let rename_button = gtk::Button::new_with_label("Rename").unwrap();
    let remove_button = gtk::Button::new_with_label("Remove").unwrap();

    let mut project_buttons = gtk::Box::new(gtk::orientation::Horizontal, 0).unwrap();
    project_buttons.set_size_request(sidebar_width, -1);
    project_buttons.add(&new_project_button);
    project_buttons.add(&import_button);
    project_buttons.add(&rename_button);
    project_buttons.add(&remove_button);

    let project_tree = gtk::TreeView::new().unwrap();

    let mut project_pane = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    project_pane.set_size_request(sidebar_width, top_height);
    project_pane.pack_start(&project_buttons, false, true, 0);
    project_pane.pack_start(&project_tree, true, true, 0);

    let rusti_pane = gtk::TextView::new().unwrap();
    let mut vbox_1 = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    vbox_1.pack_start(&project_pane, false, true, 0);
    vbox_1.pack_start(&rusti_pane, true, true, 0);

    let editor_pane = gtk::TextView::new().unwrap();
    let build_pane = gtk::TextView::new().unwrap();
    editor_pane.set_size_request(content_width, top_height);
    let mut vbox_2 = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    vbox_2.pack_start(&editor_pane, false, true, 0);
    vbox_2.pack_start(&build_pane, true, true, 0);

    let mut hbox = gtk::Box::new(gtk::orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&vbox_1, false, true, 0);
    hbox.pack_start(&vbox_2, true, true, 0);
    window.add(&hbox);

    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS+CONNECT
//   FIXED A STINKER OF A BUG!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
    let mut i = 0;
    let mut x = 0;
    let mut request = String::new();

    let srch = needle.as_bytes();

    if srch.len() == 0
    {
        return request;
    }

    while buf[i] as char != '\0'
    {
        if buf[i] as char == srch[0] as char
        {
            while x < srch.len() && buf[i] as char  == srch[x] as char
            {
                i = i + 1;
                x = x + 1;
            }
            break;
        } else {
            i = i + 1;
        }
    }

    if x == srch.len()
    {
        //println!("match");
        let mut end = i;
        while buf[end] as char != byte as char && buf[end] as char != '\n'
        {
            end = end + 1;

        }

        for y in (i..end)
        {
            request.push(buf[y] as char);
        }
    }

    return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn get_with_content_length(mut instream: &TcpStream, mut outstream: &TcpStream, total: usize) {
    let mut current = 0;
    let mut buf = [0u8; CHUNK];

    while current < total
    {
        let bytes = outstream.read(&mut buf). unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent <= 0
            {
                break;
            }
            chunk = chunk + sent;
            current = current + chunk;
        }
    }
}

fn get_with_no_content_length(mut instream: &TcpStream, mut outstream: &TcpStream)
{
    loop {
        let mut buf = [0u8; CHUNK];

        let bytes = outstream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break; // please!!!
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk = chunk + sent;
        }
    }
}

fn http_connect_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_options_request(mut instream: TcpStream)
{
    let allow = "GET,POST,HEAD,CONNECT,OPTIONS";

    let code: String = "HTTP/1.1 200 OK\r\n".to_string();
    let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

    let response = format!("{}{}", code, request);

    instream.write(response.as_bytes()).unwrap();
}

fn http_head_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("xHEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", hdr.resource, hdr.hostname);

    outstream.write(query.as_bytes()).unwrap();
}

fn http_post_request(mut instream: TcpStream, headers: Header)
{

    let bogus_fix = &format!("{}:{}", headers.hostname, 80);
    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", headers.resource, headers.hostname, headers.content, headers.length);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    let mut buf = [0u8; CHUNK];
    let mut current = 0;

    while current < headers.length
    {
        let bytes = instream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = outstream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk += sent;
            current = current + chunk;
        }
    }

    let terminate = "\r\n\r\n";

    outstream.write(terminate.as_bytes()).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_get_request(instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", headers.resource, headers.hostname);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    if headers.length > 0
    {
        get_with_content_length(&instream, &outstream, headers.length);
    }
    else
    {
        get_with_no_content_length(&instream, &outstream);
    }
}

fn req_resource(buf: [u8;REQUEST_LEN]) -> String
{
    let mut i = 0;
    let bytes = buf;
    let mut request: String = String::new();

    while bytes[i] as char != '\0'
    {
        request.push(bytes[i] as char);
        i += 1;
    }

    return request;
}

fn req_content(buf: [u8;REQUEST_LEN]) -> String
{
    let content = substr(buf, "Content-Type: ", '\r' as u8);

    return content;
}

fn req_hostname(buf: [u8;REQUEST_LEN]) -> String
{
    let hostname: String = substr(buf, "http://", '/' as u8);

    return hostname;
}

fn req_length(buf: [u8;REQUEST_LEN]) -> usize
{
    let request: String = substr(buf, "Content-Length: ", '\r' as u8);
    if ! request.is_empty()
    {
        return request.trim().parse().unwrap();
    }

    return 0;
}

struct Header {
    pub hostname: String,
    pub resource: String,
        pub content: String,
        pub length: usize,
        pub method: String,
}

impl Header {

pub fn new() -> Header
{
    let hostname = String::new();
    let resource = String::new();
    let content  = String::new();
    let method   = String::new();
    let length   = 0;

    let h = Header
        { hostname: hostname, resource: resource , content: content, length: length, method: method};

    return h;
}

}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{

    if headers.hostname.is_empty()
    {
        headers.hostname = req_hostname(buffer);
    }

    if headers.resource.is_empty()
    {
        headers.resource = req_resource(buffer);
    }

    if headers.content.is_empty()
    {
        headers.content = req_content(buffer);
    }

    if headers.length == 0
    {
        headers.length = req_length(buffer);
    }

    if headers.hostname.is_empty() || headers.resource.is_empty() || headers.method.is_empty()
    {
        return false;
    }

    return true;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
    let mut have_method = false;
    let mut byte = [0u8;1];
    let mut byte_count = 0;

    while ! have_method && byte_count < 16
    {
        instream.read(&mut byte).unwrap();
        if byte[0] as char != ' '
        {
            headers.method.push(byte[0] as char);
        }

        if byte[0] as char == ' '
        {
            have_method = true;
        }

        byte_count += 1;
    }

    if byte_count == 16 || headers.method.is_empty()
    {
        return;
    }

     loop
     {
	  let mut buffer = [0u8; REQUEST_LEN];
          let mut byte = [0u8; 1];
          let mut len = 0;

          while byte[0] as char != '\n'
          {
              let bytes = instream.read(&mut byte).unwrap();
              buffer[len] = byte[0];
              len += bytes;
          }

          buffer[len] = 0;

          if check_headers(buffer, headers) && len == 2
          {
              return;
          }
     }
}

fn proxy(stream: TcpStream) {
    let mut headers: Header = Header::new();
    request_headers(&stream, &mut headers);

    match headers.method.as_ref() {
            "GET" =>
            {
                http_get_request(stream, headers);
            }

            "POST" =>
            {
                http_post_request(stream, headers);
            }

            "HEAD" =>
            {
                http_head_request(stream, headers);
            }

            "CONNECT" =>
            {
                http_connect_request(stream, headers);
            }

            "OPTIONS" =>
            {
                http_options_request(stream);
            }

            _ =>
            {
                println!("REQUEST UNKNOWN");
            }
        }
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let host = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(host).unwrap();

    let pool = ThreadPool::new(threads);

    for stream in listener.incoming()
    {
        match stream
        {
            Ok(stream) =>
            {
                pool.execute(move || { proxy(stream); });
            }

            Err(_) =>
            {
                println!("NET error");
                1 << 7;
            }
        }
    }

    drop (listener);
}

fn main () {
    let threads = 128;
    let port: u16 = 9999;

    proxy_time(port, threads);
    println!("Blocking all badness");

}

<commit_msg>The rain...i<commit_after>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS+CONNECT
//   FIXED A STINKER OF A BUG!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
    let mut i = 0;
    let mut x = 0;
    let mut request = String::new();

    let srch = needle.as_bytes();

    if srch.len() == 0
    {
        return request;
    }

    while buf[i] as char != '\0'
    {
        if buf[i] as char == srch[0] as char
        {
            while x < srch.len() && buf[i] as char  == srch[x] as char
            {
                i = i + 1;
                x = x + 1;
            }
            break;
        } else {
            i = i + 1;
        }
    }

    if x == srch.len()
    {
        //println!("match");
        let mut end = i;
        while buf[end] as char != byte as char && buf[end] as char != '\n'
        {
            end = end + 1;

        }

        for y in (i..end)
        {
            request.push(buf[y] as char);
        }
    }

    return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn get_with_content_length(mut instream: &TcpStream, mut outstream: &TcpStream, total: usize) {
    let mut current = 0;
    let mut buf = [0u8; CHUNK];

    while current < total
    {
        let bytes = outstream.read(&mut buf). unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent <= 0
            {
                break;
            }
            chunk = chunk + sent;
            current = current + chunk;
        }
    }
}

fn get_with_no_content_length(mut instream: &TcpStream, mut outstream: &TcpStream)
{
    loop {
        let mut buf = [0u8; CHUNK];

        let bytes = outstream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break; // please!!!
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk = chunk + sent;
        }
    }
}

fn http_connect_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_options_request(mut instream: TcpStream)
{
    let allow = "GET,POST,HEAD,CONNECT,OPTIONS";

    let code: String = "HTTP/1.1 200 OK\r\n".to_string();
    let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

    let response = format!("{}{}", code, request);

    instream.write(response.as_bytes()).unwrap();
}

fn http_head_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("xHEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", hdr.resource, hdr.hostname);

    outstream.write(query.as_bytes()).unwrap();
}

fn http_post_request(mut instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);
    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", headers.resource, headers.hostname, headers.content, headers.length);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    let mut buf = [0u8; CHUNK];
    let mut current = 0;

    while current < headers.length
    {
        let bytes = instream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = outstream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk += sent;
            current = current + chunk;
        }
    }

    let terminate = "\r\n\r\n";

    outstream.write(terminate.as_bytes()).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_get_request(instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", headers.resource, headers.hostname);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    if headers.length > 0
    {
        get_with_content_length(&instream, &outstream, headers.length);
    }
    else
    {
        get_with_no_content_length(&instream, &outstream);
    }
}

fn req_resource(buf: [u8;REQUEST_LEN]) -> String
{
    let mut i = 0;
    let bytes = buf;
    let mut request: String = String::new();

    while bytes[i] as char != '\0'
    {
        request.push(bytes[i] as char);
        i += 1;
    }

    return request;
}

fn req_content(buf: [u8;REQUEST_LEN]) -> String
{
    let content = substr(buf, "Content-Type: ", '\r' as u8);

    return content;
}

fn req_hostname(buf: [u8;REQUEST_LEN]) -> String
{
    let hostname: String = substr(buf, "http://", '/' as u8);

    return hostname;
}

fn req_length(buf: [u8;REQUEST_LEN]) -> usize
{
    let request: String = substr(buf, "Content-Length: ", '\r' as u8);
    if ! request.is_empty()
    {
        return request.trim().parse().unwrap();
    }

    return 0;
}

struct Header {
    pub hostname: String,
    pub resource: String,
    pub content: String,
    pub length: usize,
    pub method: String,
}

impl Header {

pub fn new() -> Header
{
    let hostname = String::new();
    let resource = String::new();
    let content  = String::new();
    let method   = String::new();
    let length   = 0;

    let h = Header
        { hostname: hostname, resource: resource , content: content, length: length, method: method};

    return h;
}

}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{

    if headers.hostname.is_empty()
    {
        headers.hostname = req_hostname(buffer);
    }

    if headers.resource.is_empty()
    {
        headers.resource = req_resource(buffer);
    }

    if headers.content.is_empty()
    {
        headers.content = req_content(buffer);
    }

    if headers.length == 0
    {
        headers.length = req_length(buffer);
    }

    if headers.hostname.is_empty() || headers.resource.is_empty() || headers.method.is_empty()
    {
        return false;
    }

    return true;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
    let mut have_method = false;
    let mut byte = [0u8;1];
    let mut byte_count = 0;

    while ! have_method && byte_count < 16
    {
        instream.read(&mut byte).unwrap();
        if byte[0] as char != ' '
        {
            headers.method.push(byte[0] as char);
        }

        if byte[0] as char == ' '
        {
            have_method = true;
        }

        byte_count += 1;
    }

    if byte_count == 16 || headers.method.is_empty()
    {
        return;
    }

     loop
     {
	  let mut buffer = [0u8; REQUEST_LEN];
          let mut byte = [0u8; 1];
          let mut len = 0;

          while byte[0] as char != '\n'
          {
              let bytes = instream.read(&mut byte).unwrap();
              buffer[len] = byte[0];
              len += bytes;
          }

          buffer[len] = 0;

          if check_headers(buffer, headers) && len == 2
          {
              return;
          }
     }
}

fn proxy(stream: TcpStream) {
    let mut headers: Header = Header::new();
    request_headers(&stream, &mut headers);

    match headers.method.as_ref() {
            "GET" =>
            {
                http_get_request(stream, headers);
            }

            "POST" =>
            {
                http_post_request(stream, headers);
            }

            "HEAD" =>
            {
                http_head_request(stream, headers);
            }

            "CONNECT" =>
            {
                http_connect_request(stream, headers);
            }

            "OPTIONS" =>
            {
                http_options_request(stream);
            }

            _ =>
            {
                println!("REQUEST UNKNOWN");
            }
        }
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let host = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(host).unwrap();

    let pool = ThreadPool::new(threads);

    for stream in listener.incoming()
    {
        match stream
        {
            Ok(stream) =>
            {
                pool.execute(move || { proxy(stream); });
            }

            Err(_) =>
            {
                println!("NET error");
                1 << 7;
            }
        }
    }

    drop (listener);
}

fn main () {
    let threads = 128;
    let port: u16 = 9999;

    proxy_time(port, threads);
    println!("Blocking all badness");

}

<|endoftext|>


<commit_before>#![recursion_limit = "1024"] // error_chain

extern crate websocket;
extern crate env_logger;
#[macro_use]
extern crate log;
#[macro_use]
extern crate error_chain;
extern crate url;
extern crate clap;

use std::thread;
use std::io::{stdin,stdout};

use websocket::{Message, Sender, Receiver, DataFrame};
use websocket::message::Type;
use websocket::client::request::Url;
use websocket::Client;

use std::borrow::Borrow;
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Write, Read};

error_chain! {
    foreign_links {
        ::std::io::Error, Io;
        log::SetLoggerError, Log;
        ::url::ParseError, Url;
        ::websocket::result::WebSocketError, Ws;
        ::std::env::VarError, Ev;
    }
    errors {
        InvalidSpecifier(t : String) {
            description("invalid specifier")
            display("Invalid client or server specifier `{}`", t)
        }
    }
}

// Initialize logger with default "info" log level:
fn init_logger() -> Result<()> {
    let mut builder = env_logger::LogBuilder::new();
    builder.filter(None, log::LogLevelFilter::Info);
    if ::std::env::var("RUST_LOG").is_ok() {
       builder.parse(&::std::env::var("RUST_LOG")?);
    }
    builder.init()?;
    Ok(())
}

struct SenderWrapper<T: Sender> (T);

impl<T: Sender> ::std::io::Write for SenderWrapper<T> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        let message = Message::binary(buf);
        let ret;
        let len = buf.len();
        if len > 0 {
            debug!("Sending message of {} bytes", len);
            ret = self.0.send_message(&message);
        } else {
            // Interpret zero length buffer is request
            // to close communication

            debug!("Sending the closing message");
            ret = self.0.send_message(&Message::close());
        }
        ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;
        Ok(len)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        Ok(())
    }
}

struct ReceiverWrapper<T: Receiver<DataFrame>> (T);

impl<T:Receiver<DataFrame>> ::std::io::Read for ReceiverWrapper<T> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let ret = self.0.recv_message();
        let msg : Message = ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;

        match msg.opcode {
            Type::Close => {
                Ok(0)
            }
            Type::Ping => {
                // Sender used to be in a separate thread with a channel
                // now there's no channel, so trickier to combine ping replies
                // and usual data exchange
                unimplemented!();
            }
            _ => {
                let msgpayload : &[u8] = msg.payload.borrow();
                let len = msgpayload.len();
                debug!("Received message of {} bytes", len);

                assert!(buf.len() >= len);

                buf[0..len].copy_from_slice(msgpayload);

                Ok(len)
            }
        }
    }
}

struct Peer<R, W>
    where R : Read + Send + 'static, W: Write + Send + 'static
{
    reader: R,
    writer: W,
}

type IPeer = Peer<Box<Read+Send>, Box<Write+Send>>;

struct DataExchangeSession<R1, R2, W1, W2>
    where R1 : Read  + Send + 'static,
          R2 : Read  + Send + 'static,
          W1 : Write + Send + 'static,
          W2 : Write + Send + 'static,
{
    peer1: Peer<R1, W1>,
    peer2: Peer<R2, W2>,
}

impl<R1,R2,W1,W2> DataExchangeSession<R1,R2,W1,W2>
    where R1 : Read  + Send + 'static,
          R2 : Read  + Send + 'static,
          W1 : Write + Send + 'static,
          W2 : Write + Send + 'static,
{
    fn data_exchange(self) -> Result<()> {

        let mut reader1 = self.peer1.reader;
        let mut writer1 = self.peer1.writer;
        let mut reader2 = self.peer2.reader;
        let mut writer2 = self.peer2.writer;

        let receive_loop = thread::spawn(move || -> Result<()> {
            // Actual data transfer happens here
            ::std::io::copy(&mut reader1, &mut writer2)?;
            writer2.write(b"")?; // signal close
            Ok(())
        });

        // Actual data transfer happens here
        ::std::io::copy(&mut reader2, &mut writer1)?;
        writer1.write(b"")?; // Signal close

        debug!("Waiting for receiver side to exit");

        receive_loop.join().map_err(|x|format!("{:?}",x))?
    }
}

fn get_websocket_peer(urlstr: &str) -> Result<
        Peer<
            ReceiverWrapper<websocket::client::Receiver<websocket::WebSocketStream>>,
            SenderWrapper<websocket::client::Sender<websocket::WebSocketStream>>>
        > {
    let url = Url::parse(urlstr)?;

    info!("Connecting to {}", url);

    let request = Client::connect(url)?;

    let response = request.send()?; // Send the request and retrieve a response

    info!("Validating response...");

    response.validate()?; // Validate the response

    info!("Successfully connected");

    let (sender, receiver) = response.begin().split();

    let peer = Peer {
        reader : ReceiverWrapper(receiver),
        writer : SenderWrapper(sender),
    };
    Ok(peer)
}

fn get_tcp_peer(addr: &str) -> Result<
        Peer<
            ::std::net::TcpStream,
            ::std::net::TcpStream,
        >> {
    let sock = ::std::net::TcpStream::connect(addr)?;

    let peer = Peer {
        reader : sock.try_clone()?,
        writer : sock.try_clone()?,
    };
    info!("Connected to TCP {}", addr);
    Ok(peer)
}

fn get_stdio_peer() -> Result<Peer<std::io::Stdin, std::io::Stdout>> {
    Ok(
        Peer {
            reader : stdin(),
            writer : stdout(),
        }
    )
}

impl<R,W> Peer<R,W>
    where R : Read + Send + 'static, W: Write + Send + 'static
{
    fn upcast(self) -> IPeer  {
        Peer {
            reader: Box::new(self.reader) as Box<Read +Send>,
            writer: Box::new(self.writer) as Box<Write+Send>,
        }
    }
}

fn get_peer_by_spec(specifier: &str, server: bool) -> Result<IPeer> {
    let _ = server;
    match specifier {
        x if x == "-"               => Ok(get_stdio_peer()?.upcast()),
        x if x.starts_with("ws:")   => Ok(get_websocket_peer(x)?.upcast()),
        x if x.starts_with("wss:")  => Ok(get_websocket_peer(x)?.upcast()),
        x if x.starts_with("tcp:")  => Ok(get_tcp_peer(&x[4..])?.upcast()),
        x => Err(ErrorKind::InvalidSpecifier(x.to_string()).into()),
    }
}

fn try_main() -> Result<()> {
    //env_logger::init()?;
    init_logger()?;

    // setup command line arguments
    let matches = ::clap::App::new("websocat")
        .version("0.1")
        .author("Vitaly \"_Vi\" Shukela <vi0oss@gmail.com>")
        .about("Exchange binary data between binary websocket and something.\nSocat analogue with websockets.")
        .arg(::clap::Arg::with_name("spec1")
             .help("First specifier.")
             .required(true)
             .index(1))
        .arg(::clap::Arg::with_name("spec2")
             .help("Second specifier.")
             .required(true)
             .index(2))
        .after_help(r#"
Specifiers can be:
  ws[s]://<rest of websocket URL>    Connect to websocket
  tcp:<socket address>               Connect to TCP
  -                                  stdin/stdout
  (more to be implemented)

Examples:
  websocat - wss://myserver/mysocket
    Connect stdin/stdout to secure web socket once.
    Like netcat, but for websocket.
    Currently it is the only working example.
  websocat ws://localhost:1234/ tcp:localhost:1235
    Connect both to websocket and to TCP and exchange data.
"#)
        .get_matches();

    let spec1  = matches.value_of("spec1") .ok_or("no listener_spec" )?;
    let spec2 = matches.value_of("spec2").ok_or("no connector_spec")?;

    let des = DataExchangeSession {
        peer1 : get_peer_by_spec(spec1,  true )?,
        peer2 : get_peer_by_spec(spec2, false)?,
    };

    des.data_exchange()?;

    debug!("Exited");
    Ok(())
}

fn main() {
    if let Err(x) = try_main() {
        let _ = writeln!(::std::io::stderr(), "{:?}", x);
    }
}

<commit_msg>Refactor on the way to server mode<commit_after>#![recursion_limit = "1024"] // error_chain

extern crate websocket;
extern crate env_logger;
#[macro_use]
extern crate log;
#[macro_use]
extern crate error_chain;
extern crate url;
extern crate clap;

use std::thread;
use std::io::{stdin,stdout};

use websocket::{Message, Sender, Receiver, DataFrame};
use websocket::message::Type;
use websocket::client::request::Url;
use websocket::Client;

use std::borrow::Borrow;
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Write, Read};

error_chain! {
    foreign_links {
        ::std::io::Error, Io;
        log::SetLoggerError, Log;
        ::url::ParseError, Url;
        ::websocket::result::WebSocketError, Ws;
        ::std::env::VarError, Ev;
    }
    errors {
        InvalidSpecifier(t : String) {
            description("invalid specifier")
            display("Invalid client or server specifier `{}`", t)
        }
    }
}

// Initialize logger with default "info" log level:
fn init_logger() -> Result<()> {
    let mut builder = env_logger::LogBuilder::new();
    builder.filter(None, log::LogLevelFilter::Info);
    if ::std::env::var("RUST_LOG").is_ok() {
       builder.parse(&::std::env::var("RUST_LOG")?);
    }
    builder.init()?;
    Ok(())
}

struct SenderWrapper<T: Sender> (T);

impl<T: Sender> ::std::io::Write for SenderWrapper<T> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        let message = Message::binary(buf);
        let ret;
        let len = buf.len();
        if len > 0 {
            debug!("Sending message of {} bytes", len);
            ret = self.0.send_message(&message);
        } else {
            // Interpret zero length buffer is request
            // to close communication

            debug!("Sending the closing message");
            ret = self.0.send_message(&Message::close());
        }
        ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;
        Ok(len)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        Ok(())
    }
}

struct ReceiverWrapper<T: Receiver<DataFrame>> (T);

impl<T:Receiver<DataFrame>> ::std::io::Read for ReceiverWrapper<T> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let ret = self.0.recv_message();
        let msg : Message = ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;

        match msg.opcode {
            Type::Close => {
                Ok(0)
            }
            Type::Ping => {
                // Sender used to be in a separate thread with a channel
                // now there's no channel, so trickier to combine ping replies
                // and usual data exchange
                unimplemented!();
            }
            _ => {
                let msgpayload : &[u8] = msg.payload.borrow();
                let len = msgpayload.len();
                debug!("Received message of {} bytes", len);

                assert!(buf.len() >= len);

                buf[0..len].copy_from_slice(msgpayload);

                Ok(len)
            }
        }
    }
}

struct Peer<R, W>
    where R : Read + Send + 'static, W: Write + Send + 'static
{
    reader: R,
    writer: W,
}

type IPeer = Peer<Box<Read+Send>, Box<Write+Send>>;

struct DataExchangeSession<R1, R2, W1, W2>
    where R1 : Read  + Send + 'static,
          R2 : Read  + Send + 'static,
          W1 : Write + Send + 'static,
          W2 : Write + Send + 'static,
{
    peer1: Peer<R1, W1>,
    peer2: Peer<R2, W2>,
}

impl<R1,R2,W1,W2> DataExchangeSession<R1,R2,W1,W2>
    where R1 : Read  + Send + 'static,
          R2 : Read  + Send + 'static,
          W1 : Write + Send + 'static,
          W2 : Write + Send + 'static,
{
    fn data_exchange(self) -> Result<()> {

        let mut reader1 = self.peer1.reader;
        let mut writer1 = self.peer1.writer;
        let mut reader2 = self.peer2.reader;
        let mut writer2 = self.peer2.writer;

        let receive_loop = thread::spawn(move || -> Result<()> {
            // Actual data transfer happens here
            ::std::io::copy(&mut reader1, &mut writer2)?;
            writer2.write(b"")?; // signal close
            Ok(())
        });

        // Actual data transfer happens here
        ::std::io::copy(&mut reader2, &mut writer1)?;
        writer1.write(b"")?; // Signal close

        debug!("Waiting for receiver side to exit");

        receive_loop.join().map_err(|x|format!("{:?}",x))?
    }
}

fn get_websocket_peer(urlstr: &str) -> Result<
        Peer<
            ReceiverWrapper<websocket::client::Receiver<websocket::WebSocketStream>>,
            SenderWrapper<websocket::client::Sender<websocket::WebSocketStream>>>
        > {
    let url = Url::parse(urlstr)?;

    info!("Connecting to {}", url);

    let request = Client::connect(url)?;

    let response = request.send()?; // Send the request and retrieve a response

    info!("Validating response...");

    response.validate()?; // Validate the response

    info!("Successfully connected");

    let (sender, receiver) = response.begin().split();

    let peer = Peer {
        reader : ReceiverWrapper(receiver),
        writer : SenderWrapper(sender),
    };
    Ok(peer)
}

fn get_tcp_peer(addr: &str) -> Result<
        Peer<
            ::std::net::TcpStream,
            ::std::net::TcpStream,
        >> {
    let sock = ::std::net::TcpStream::connect(addr)?;

    let peer = Peer {
        reader : sock.try_clone()?,
        writer : sock.try_clone()?,
    };
    info!("Connected to TCP {}", addr);
    Ok(peer)
}

fn get_stdio_peer() -> Result<Peer<std::io::Stdin, std::io::Stdout>> {
    Ok(
        Peer {
            reader : stdin(),
            writer : stdout(),
        }
    )
}

impl<R,W> Peer<R,W>
    where R : Read + Send + 'static, W: Write + Send + 'static
{
    fn upcast(self) -> IPeer  {
        Peer {
            reader: Box::new(self.reader) as Box<Read +Send>,
            writer: Box::new(self.writer) as Box<Write+Send>,
        }
    }
}

trait Server
{
    fn start_serving(&self, spec: &str, once: bool) {

    }
}

enum Spec {
    Server(Box<Server + Send>),
    Client(IPeer)
}

fn get_peer_by_spec(specifier: &str) -> Result<Spec> {
    use Spec::{Server,Client};
    match specifier {
        x if x == "-"               => Ok(Client(get_stdio_peer()?.upcast())),
        x if x.starts_with("ws:")   => Ok(Client(get_websocket_peer(x)?.upcast())),
        x if x.starts_with("wss:")  => Ok(Client(get_websocket_peer(x)?.upcast())),
        x if x.starts_with("tcp:")  => Ok(Client(get_tcp_peer(&x[4..])?.upcast())),
        x => Err(ErrorKind::InvalidSpecifier(x.to_string()).into()),
    }
}

fn try_main() -> Result<()> {
    //env_logger::init()?;
    init_logger()?;

    // setup command line arguments
    let matches = ::clap::App::new("websocat")
        .version("0.1")
        .author("Vitaly \"_Vi\" Shukela <vi0oss@gmail.com>")
        .about("Exchange binary data between binary websocket and something.\nSocat analogue with websockets.")
        .arg(::clap::Arg::with_name("spec1")
             .help("First specifier.")
             .required(true)
             .index(1))
        .arg(::clap::Arg::with_name("spec2")
             .help("Second specifier.")
             .required(true)
             .index(2))
        .after_help(r#"
Specifiers can be:
  ws[s]://<rest of websocket URL>    Connect to websocket
  tcp:<socket address>               Connect to TCP
  tcp-l:<socer address>
  -                                  stdin/stdout
  (more to be implemented)

Examples:
  websocat - wss://myserver/mysocket
    Connect stdin/stdout to secure web socket once.
    Like netcat, but for websocket.
  websocat ws://localhost:1234/ tcp:localhost:1235
    Connect both to websocket and to TCP and exchange data.
  websocat tcp-l::::9559 ws://echo.websocket.org/
    Listen TCPv6 port 9959 on address :: and forward
    all connections to a public loopback websocket

Specify listening part first, unless you want websocat to serve once.
"#)
        .get_matches();

    let spec1  = matches.value_of("spec1") .ok_or("no listener_spec" )?;
    let spec2 = matches.value_of("spec2").ok_or("no connector_spec")?;

    let spec1_ = get_peer_by_spec(spec1)?;

    match spec1_ {
        Spec::Server(x) => {
            unimplemented!();
        }
        Spec::Client(p1) => {
            let spec2_ = get_peer_by_spec(spec2)?;

            match spec2_ {
                Spec::Server(x) => {
                    unimplemented!();
                }
                Spec::Client(p2) => {
                    let des = DataExchangeSession {
                        peer1 : p1,
                        peer2 : p2,
                    };

                    des.data_exchange()?;
                }
            }
        }
    }

    debug!("Exited");
    Ok(())
}

fn main() {
    if let Err(x) = try_main() {
        let _ = writeln!(::std::io::stderr(), "{:?}", x);
    }
}

<|endoftext|>


<commit_before>extern crate pnet;

use std::io;
use std::thread;
use std::time::Duration;
use std::net::Ipv4Addr;
use std::net::AddrParseError;

use pnet::datalink::{self, NetworkInterface};
use pnet::datalink::Channel;
use pnet::packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use pnet::packet::arp::MutableArpPacket;
use pnet::util::{MacAddr, ParseMacAddrErr};
use pnet::packet::ethernet::{EtherTypes, EtherType};
use pnet::packet::MutablePacket;
use pnet::packet::arp::{ArpHardwareTypes, ArpOperations, ArpOperation};

fn send_arp_request_packet() {
    let interfaces = datalink::interfaces();

    // Get en1 interface in osx.
    let interfaces_name_match = |iface: &NetworkInterface| iface.name == "en1";
    let interface = interfaces.into_iter().filter(interfaces_name_match).next().unwrap();

    let(mut tx, mut rx) = match datalink::channel(&interface, Default::default()) {
        Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("Unknown channel type"),
        Err(e) => panic!("Error happened {}", e),
    };

    /// ethernet_packet = Ethernet {
    ///     destination: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
    ///     source: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     ethertype: [0x08, 0x06], // Arp(0x0806)
    ///     payload: arp_packet
    /// }
    ///
    /// arp_packet = Arp {
    ///     hardware_type: [0x00, 0x01],
    ///     protocol_type: [0x08, 0x00], // Ipv4(0x0800)
    ///     hw_addr_len: [0x06],
    ///     proto_addr_len: [0x04],
    ///     operation: [0x00, 0x01], // Request(0x0001)
    ///     sender_hw_addr: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     sender_proto_addr: [0xc0, 0xa8, 0x00, 0x66], // Ipv4(192.168.0.102)
    ///     target_hw_addr: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], // Broadcast
    ///     target_proto_addr: [0xc0, 0xa8, 0x00, 0x65], // // Ipv4(192.168.0.101)
    ///     payload: [],
    /// }

    let buffer: &[u8] = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b, 0x08, 0x06,
                         0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b, 0xc0, 0xa8, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01];
    let ethernet_packet = EthernetPacket::new(&buffer);
    tx.send_to(&ethernet_packet.unwrap(), Some(interface));
}

fn send_arp_reply_packet(gateway: Ipv4Addr, source_mac: MacAddr, target_ip: Ipv4Addr, target_mac: MacAddr) {
    let interfaces = datalink::interfaces();

    // Get en1 interface in osx.
    let interfaces_name_match = |iface: &NetworkInterface| iface.name == "en1";
    let interface = interfaces.into_iter().filter(interfaces_name_match).next().unwrap();

    let(mut tx, mut rx) = match datalink::channel(&interface, Default::default()) {
        Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("Unknown channel type"),
        Err(e) => panic!("Error happened {}", e),
    };

    /// ethernet_packet = Ethernet {
    ///     destination: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
    ///     source: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     ethertype: [0x08, 0x06], // Arp(0x0806)
    ///     payload: arp_packet
    /// }
    ///
    /// arp_packet = Arp {
    ///     hardware_type: [0x00, 0x01],
    ///     protocol_type: [0x08, 0x00], // Ipv4(0x0800)
    ///     hw_addr_len: [0x06],
    ///     proto_addr_len: [0x04],
    ///     operation: [0x00, 0x02], // Reply(0x0002)
    ///     sender_hw_addr: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     sender_proto_addr: [0xc0, 0xa8, 0x00, 0x66], // Ipv4(192.168.0.102)
    ///     target_hw_addr: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], // Broadcast
    ///     target_proto_addr: [0xc0, 0xa8, 0x00, 0x65], // // Ipv4(192.168.0.101)
    ///     payload: [],
    /// }

    let buffer: &[u8] = &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    let mut ethernet_packet = MutableEthernetPacket::new(&mut buffer).unwrap();
    ethernet_packet.set_destination(target_mac);
    ethernet_packet.set_source(source_mac);
    ethernet_packet.set_ethertype(EtherTypes::Arp);

    let mut arp_packet = MutableArpPacket::new(ethernet_packet.payload_mut()).unwrap();
    arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
    arp_packet.set_protocol_type(EtherTypes::Arp);
    arp_packet.set_hw_addr_len(6);
    arp_packet.set_proto_addr_len(4);
    arp_packet.set_operation(ArpOperations::Reply);
    arp_packet.set_sender_hw_addr(source_mac);
    arp_packet.set_sender_proto_addr(gateway);
    arp_packet.set_target_hw_addr(target_mac);
    arp_packet.set_target_proto_addr(target_ip);

    tx.send_to(&arp_packet, Some(interface));
}

fn send_gratitious_arp_request() {
    // TODO:
}

fn main() {
    // let mut mac_addr = String::new();
    // io::stdin().read_line(&mut mac_addr).expect("Failed to read input");

    // let mac_addr: Result<MacAddr, ParseMacAddrErr> = mac_addr.trim().parse();
    // println!("Mac address is {:?}", mac_addr);

    // let mut ip_addr = String::new();
    // io::stdin().read_line(&mut ip_addr).expect("Failed to read input");

    // let ip_addr: Result<Ipv4Addr, AddrParseError> = ip_addr.trim().parse();
    // println!("Ip address is {:?}", ip_addr);

    // Get the following
    //   1. src - gateway_ip (gateway)
    //   2. hwsrc - my_mac  (source-mac)
    //   3. dst - target_ip  (target-ip)
    //   4. hwdst - target_mac  (target-mac)
    //
    // Ethernet
    //   1. src - my_mac
    //   2. dst - target_mac

    // // loop {
    // //     send_arp_reply_packet();
    // //     thread::sleep(Duration::new(2, 0));
    // // }
    let gateway: Result<Ipv4Addr, AddrParseError> = "127.0.0.1".parse();
    let target_ip: Result<Ipv4Addr, AddrParseError> = "127.0.0.1".parse();
    let source_mac: Result<MacAddr, ParseMacAddrErr> = "ef::ef::ef::ef::ef::ef".parse();
    let target_mac: Result<MacAddr, ParseMacAddrErr> = "ef::ef::ef::ef::ef::ef".parse();
    send_arp_reply_packet(gateway.unwrap(), source_mac.unwrap(), target_ip.unwrap(), target_mac.unwrap());
}
<commit_msg>Use data link layer channel for sending packet<commit_after>extern crate pnet;

use std::io;
use std::thread;
use std::time::Duration;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::AddrParseError;

use pnet::datalink::{self, NetworkInterface};
use pnet::datalink::Channel;
use pnet::packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use pnet::packet::arp::MutableArpPacket;
use pnet::util::{MacAddr, ParseMacAddrErr};
use pnet::packet::ethernet::{EtherTypes, EtherType};
use pnet::packet::MutablePacket;
use pnet::packet::arp::{ArpHardwareTypes, ArpOperations, ArpOperation};
use pnet::transport::transport_channel;
use pnet::transport::TransportProtocol::Ipv4;
use pnet::transport::TransportChannelType::Layer4;
use pnet::packet::ip::IpNextHeaderProtocols;

fn send_arp_reply_packet(gateway: Ipv4Addr, source_mac: MacAddr, target_ip: Ipv4Addr, target_mac: MacAddr) {
    let interfaces = datalink::interfaces();

    // Get en1 interface in osx.
    let interfaces_name_match = |iface: &NetworkInterface| iface.name == "en1";
    let interface = interfaces.into_iter().filter(interfaces_name_match).next().unwrap();

    let(mut tx, mut rx) = match datalink::channel(&interface, Default::default()) {
        Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("Unknown channel type"),
        Err(e) => panic!("Error happened {}", e),
    };

    /// ethernet_packet = Ethernet {
    ///     destination: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
    ///     source: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     ethertype: [0x08, 0x06], // Arp(0x0806)
    ///     payload: arp_packet
    /// }
    ///
    /// arp_packet = Arp {
    ///     hardware_type: [0x00, 0x01],
    ///     protocol_type: [0x08, 0x00], // Ipv4(0x0800)
    ///     hw_addr_len: [0x06],
    ///     proto_addr_len: [0x04],
    ///     operation: [0x00, 0x02], // Reply(0x0002)
    ///     sender_hw_addr: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     sender_proto_addr: [0xc0, 0xa8, 0x00, 0x66], // Ipv4(192.168.0.102)
    ///     target_hw_addr: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], // Broadcast
    ///     target_proto_addr: [0xc0, 0xa8, 0x00, 0x65], // Ipv4(192.168.0.101)
    ///     payload: [],
    /// }

    let mut buffer: &mut [u8] = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    let mut ethernet_packet = MutableEthernetPacket::new(&mut buffer).unwrap();
    ethernet_packet.set_destination(target_mac);
    ethernet_packet.set_source(source_mac);
    ethernet_packet.set_ethertype(EtherTypes::Arp);

    let mut arp_buffer: &mut [u8] = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    let mut arp_packet = MutableArpPacket::new(&mut arp_buffer).unwrap();

    arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
    arp_packet.set_protocol_type(EtherTypes::Arp);
    arp_packet.set_hw_addr_len(6);
    arp_packet.set_proto_addr_len(4);
    arp_packet.set_operation(ArpOperations::Reply);
    arp_packet.set_sender_hw_addr(source_mac);
    arp_packet.set_sender_proto_addr(gateway);
    arp_packet.set_target_hw_addr(target_mac);
    arp_packet.set_target_proto_addr(target_ip);

    ethernet_packet.set_payload(arp_packet.packet_mut());

    tx.send_to(&ethernet_packet.to_immutable(), Some(interface));
}

fn main() {
    // let mut mac_addr = String::new();
    // io::stdin().read_line(&mut mac_addr).expect("Failed to read input");

    // let mac_addr: Result<MacAddr, ParseMacAddrErr> = mac_addr.trim().parse();
    // println!("Mac address is {:?}", mac_addr);

    // let mut ip_addr = String::new();
    // io::stdin().read_line(&mut ip_addr).expect("Failed to read input");

    // let ip_addr: Result<Ipv4Addr, AddrParseError> = ip_addr.trim().parse();
    // println!("Ip address is {:?}", ip_addr);

    // Get the following
    //   1. src - gateway_ip (gateway)
    //   2. hwsrc - my_mac  (source-mac)
    //   3. dst - target_ip  (target-ip)
    //   4. hwdst - target_mac  (target-mac)
    //
    // Ethernet
    //   1. src - my_mac
    //   2. dst - target_mac

    loop {
        let gateway: Result<Ipv4Addr, AddrParseError> = "192.168.1.104".parse();
        let target_ip: Result<Ipv4Addr, AddrParseError> = "192.168.1.101".parse();
        let source_mac: Result<MacAddr, ParseMacAddrErr> = "28:CF:E9:5E:8A:7B".parse();
        let target_mac: Result<MacAddr, ParseMacAddrErr> = "F8:CF:C5:81:C7:74".parse();

        send_arp_reply_packet(gateway.unwrap(), source_mac.unwrap(), target_ip.unwrap(), target_mac.unwrap());
        // thread::sleep(Duration::new(5, 0));
        break;
    }
}
<|endoftext|>


<commit_before><commit_msg>Convert frame_samples into bytes<commit_after><|endoftext|>


<commit_before>use std::io;

fn main() {
    let mut w = String::new();
    let mut k = String::new();

    println!("Type in a message to write");
    io::stdin().read_line(&mut w).expect("Error!");

    println!("Type in a key");
    io::stdin().read_line(&mut k).expect("Error!");

    let k: i32 = match k.trim().parse() {
        Ok(x) => x,
        Err(_) => 0
    };

    println!("Your translated string is\n{:?}", encsr(w.trim(), k));
}

fn key_v(starting: &str, key: i32) -> Vec<char> {
    let k: i32 = key;
    let s = starting;

    let s_v: Vec<char> = s.chars().collect();
    let mut new_v: Vec<char> = Vec::new();

    let mut i: i32 = k-1;

    while i < (s_v.len() as i32) {
        new_v.push(s_v[(i as usize)]);
        i += 1;
    }

    let mut new_i = 0;
    while new_i <= k-2 {
        new_v.push(s_v[(new_i as usize)]);
        new_i += 1;
    }

    return new_v;
}

fn l_to_n(l: char) -> i16 {
    match l {
        'A' => 0,
        'B' => 1,
        'C' => 2,
        'D' => 3,
        'E' => 4,
        'F' => 5,
        'G' => 6,
        'H' => 7,
        'I' => 8,
        'J' => 9,
        'K' => 10,
        'L' => 11,
        'M' => 12,
        'N' => 13,
        'O' => 14,
        'P' => 15,
        'Q' => 16,
        'R' => 17,
        'S' => 18,
        'T' => 19,
        'U' => 20,
        'V' => 21,
        'W' => 22,
        'X' => 23,
        'Y' => 24,
        'Z' => 25,
        _ => 30
    }
}

fn encsr_w(word: &str, key: i32) -> String {
    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut index_v: Vec<i16> = Vec::new();

    for l in word.to_uppercase().chars() {
        index_v.push(l_to_n(l));
    }

    let mut new_w_v: Vec<char> = Vec::new();

    for i in index_v {
        new_w_v.push(key_v[(i as usize)]);
    }

    let s: String = new_w_v.into_iter().collect();

    return s;
}

fn decsr_w(word: &str, key: i32) -> String {

    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut pos_v: Vec<i16> = Vec::new();
    let mut cur_i: i16 = 0;

    for c in word.to_uppercase().chars() {
        while cur_i < (key_v.len() as i16) - 1 {
            if c == key_v[(cur_i as usize)] {
                pos_v.push(cur_i);
                cur_i = 0;
                break;
            }
            cur_i += 1
        }
    }

    let c_vec: Vec<char> = starting.chars().collect();
    let mut fin_v: Vec<char> = Vec::new();

    for p in pos_v {
        fin_v.push(c_vec[(p as usize)]);
    }

    let s: String = fin_v.into_iter().collect();
    return s;
}

fn encsr(word: &str, key: i32) -> Vec<String> {
    let sp_w: Vec<&str> = word.split(" ").collect();
    let mut w_v: Vec<String> = Vec::new();

    for cur_w in sp_w {
        w_v.push(encsr_w(cur_w, key));
    }

    return w_v;
}
<commit_msg>Implement decsr<commit_after>use std::io;

fn main() {
    let mut w = String::new();
    let mut k = String::new();

    println!("Type in a message to write");
    io::stdin().read_line(&mut w).expect("Error!");

    println!("Type in a key");
    io::stdin().read_line(&mut k).expect("Error!");

    let k: i32 = match k.trim().parse() {
        Ok(x) => x,
        Err(_) => 0
    };

    println!("Your translated string is\n{:?}", encsr(w.trim(), k));

    // let try_al: Vec<String> = decsr(encsr("Hello World", 10), 10);
    // for s in try_al {
    //     println!("{:?}", s);
    // }
}

fn key_v(starting: &str, key: i32) -> Vec<char> {
    let k: i32 = key;
    let s = starting;

    let s_v: Vec<char> = s.chars().collect();
    let mut new_v: Vec<char> = Vec::new();

    let mut i: i32 = k-1;

    while i < (s_v.len() as i32) {
        new_v.push(s_v[(i as usize)]);
        i += 1;
    }

    let mut new_i = 0;
    while new_i <= k-2 {
        new_v.push(s_v[(new_i as usize)]);
        new_i += 1;
    }

    return new_v;
}

fn l_to_n(l: char) -> i16 {
    match l {
        'A' => 0,
        'B' => 1,
        'C' => 2,
        'D' => 3,
        'E' => 4,
        'F' => 5,
        'G' => 6,
        'H' => 7,
        'I' => 8,
        'J' => 9,
        'K' => 10,
        'L' => 11,
        'M' => 12,
        'N' => 13,
        'O' => 14,
        'P' => 15,
        'Q' => 16,
        'R' => 17,
        'S' => 18,
        'T' => 19,
        'U' => 20,
        'V' => 21,
        'W' => 22,
        'X' => 23,
        'Y' => 24,
        'Z' => 25,
        _ => 30
    }
}

fn encsr_w(word: &str, key: i32) -> String {
    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut index_v: Vec<i16> = Vec::new();

    for l in word.to_uppercase().chars() {
        index_v.push(l_to_n(l));
    }

    let mut new_w_v: Vec<char> = Vec::new();

    for i in index_v {
        new_w_v.push(key_v[(i as usize)]);
    }

    let s: String = new_w_v.into_iter().collect();

    return s;
}

fn decsr_w(word: &str, key: i32) -> String {

    let starting = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let key_v = key_v(starting, key);

    let mut pos_v: Vec<i16> = Vec::new();
    let mut cur_i: i16 = 0;

    for c in word.to_uppercase().chars() {
        while cur_i < (key_v.len() as i16) - 1 {
            if c == key_v[(cur_i as usize)] {
                pos_v.push(cur_i);
                cur_i = 0;
                break;
            }
            cur_i += 1
        }
    }

    let c_vec: Vec<char> = starting.chars().collect();
    let mut fin_v: Vec<char> = Vec::new();

    for p in pos_v {
        fin_v.push(c_vec[(p as usize)]);
    }

    let s: String = fin_v.into_iter().collect();
    return s;
}

fn encsr(word: &str, key: i32) -> Vec<String> {
    let sp_w: Vec<&str> = word.split(" ").collect();
    let mut w_v: Vec<String> = Vec::new();

    for cur_w in sp_w {
        w_v.push(encsr_w(cur_w, key));
    }

    return w_v
}

fn decsr(enc: Vec<String>, key: i32) -> Vec<String> {
    let mut fin_v: Vec<String> = Vec::new();

    for pt in enc {
        fin_v.push(decsr_w(pt.trim(), key));
    }

    return fin_v;
}
<|endoftext|>