getting basic irc

master
lza_menace 2 years ago
parent 18d5970a1b
commit 84ba83fe5c

1
Cargo.lock generated

@ -2875,6 +2875,7 @@ dependencies = [
"egui",
"json",
"libtor",
"native-tls",
"regex",
"reqwest",
"rodio",

@ -13,4 +13,5 @@ reqwest = { version = "0.11.12", features = ["blocking", "json", "stream", "sock
egui = "0.19.0"
rodio = "0.16.0"
regex = "1.6.0"
json = "0.12.4"
json = "0.12.4"
native-tls = "0.2"

@ -0,0 +1,59 @@
:CTCPServ!services@services.oftc.net PRIVMSG wowboombox :VERSION:reflection.oftc.net NOTICE AUTH :*** Looking up your hostname...
:reflection.oftc.net NOTICE AUTH :*** Checking Ident
:reflection.oftc.net NOTICE AUTH :*** Couldn't look up your hostname
:reflection.oftc.net NOTICE AUTH :*** No Ident response
:reflection.oftc.net 001 wowboombox :Welcome to the OFTC Internet Relay Chat Network wowboombox
:reflection.oftc.net 002 wowboombox :Your host is reflection.oftc.net[64.86.243.183/6667], running version hybrid-7.2.2+oftc1.7.3
:reflection.oftc.net 003 wowboombox :This server was created Aug 9 2022 at 01:16:38
:reflection.oftc.net 004 wowboombox reflection.oftc.net hybrid-7.2.2+oftc1.7.3 CDGPRSabcdfgijklnorsuwxyz bciklmnopstvzeIMRS bkloveI
:reflection.oftc.net 005 wowboombox CALLERID CASEMAPPING=rfc1459 DEAF=D KICKLEN=160 MODES=4 NICKLEN=30 PREFIX=(ov)@+ STATUSMSG=@+ TOPICLEN=391 NETWORK=OFTC MAXLIST=beI:100 MAXTARGETS=1 CHANTYPES=# :are supported by this server
:reflection.oftc.net 005 wowboombox CHANLIMIT=#:250 CHANNELLEN=50 CHANMODES=eIqb,k,l,cimnpstzMRS AWAYLEN=160 KNOCK ELIST=CMNTU SAFELIST EXCEPTS=e INVEX=I :are supported by this server
:reflection.oftc.net 042 wowboombox 8L3AADHMZ :your unique ID
:reflection.oftc.net 251 wowboombox :There are 32 users and 30389 invisible on 19 servers
:reflection.oftc.net 252 wowboombox 20 :IRC Operators online
:reflection.oftc.net 253 wowboombox 18 :unknown connection(s)
:reflection.oftc.net 254 wowboombox 4069 :channels formed
:reflection.oftc.net 255 wowboombox :I have 1432 clients and 1 servers
:reflection.oftc.net 265 wowboombox :Current local users: 1432 Max: 2049
:reflection.oftc.net 266 wowboombox :Current global users: 30421 Max: 31889
:reflection.oftc.net 250 wowboombox :Highest connection count: 2050 (2049 clients) (149498 connections received)
:reflection.oftc.net 375 wowboombox :- reflection.oftc.net Message of the Day -
:reflection.oftc.net 372 wowboombox :- O
:reflection.oftc.net 372 wowboombox :- \ The Open and Free
:reflection.oftc.net 372 wowboombox :- O Technology Community
:reflection.oftc.net 372 wowboombox :- /| https://www.oftc.net
:reflection.oftc.net 372 wowboombox :- O-O O
:reflection.oftc.net 372 wowboombox :-
:reflection.oftc.net 372 wowboombox :- Welcome to the OFTC IRC Network.
:reflection.oftc.net 372 wowboombox :-
:reflection.oftc.net 372 wowboombox :- The Open and Free Technology Community was founded at the
:reflection.oftc.net 372 wowboombox :- end of 2001 by a group of experienced members of the Open
:reflection.oftc.net 372 wowboombox :- Source and Free Software communities; it is aimed at
:reflection.oftc.net 372 wowboombox :- providing these communities with better communication,
:reflection.oftc.net 372 wowboombox :- development, and support infrastructure. Our goal is to
:reflection.oftc.net 372 wowboombox :- provide stable services to members of the community in any
:reflection.oftc.net 372 wowboombox :- part of the world, while listening closely to their needs
:reflection.oftc.net 372 wowboombox :- and desires.
:reflection.oftc.net 372 wowboombox :-
:reflection.oftc.net 372 wowboombox :- We are not a general purpose chat platform, but a topical
:reflection.oftc.net 372 wowboombox :- network intent on providing the open source and free
:reflection.oftc.net 372 wowboombox :- software communities a means to cooperate and communicate.
:reflection.oftc.net 372 wowboombox :- As such, illegal and off-topic activity, such as warez
:reflection.oftc.net 372 wowboombox :- trading, will result in being barred from access.
:reflection.oftc.net 372 wowboombox :-
:reflection.oftc.net 372 wowboombox :- OFTC honors your privacy. To operate the network, we store
:reflection.oftc.net 372 wowboombox :- and process information about IRC connections, nicknames,
:reflection.oftc.net 372 wowboombox :- and channels. Our Privacy Policy explains what we do with
:reflection.oftc.net 372 wowboombox :- that data, and what your rights are. By connecting, you
:reflection.oftc.net 372 wowboombox :- accept these terms: https://www.oftc.net/Privacy_Policy/
:reflection.oftc.net 372 wowboombox :-
:reflection.oftc.net 372 wowboombox :- If you require assistance with using the OFTC IRC network,
:reflection.oftc.net 372 wowboombox :- stop by in channel #oftc, or email support@oftc.net with
:reflection.oftc.net 372 wowboombox :- details. For help with non-IRC questions please refer to
:reflection.oftc.net 372 wowboombox :- the respective channels and project homepages.
:reflection.oftc.net 372 wowboombox :-
:reflection.oftc.net 372 wowboombox :- Thanks and enjoy your stay! The OFTC team.
:reflection.oftc.net 376 wowboombox :End of /MOTD command.
:wowboombox!~wowboombo@47.209.29.77 MODE wowboombox :+i
:CTCPServ!services@services.oftc.net PRIVMSG wowboombox :VERSION
PING :reflection.oftc.net

@ -6,17 +6,20 @@ use egui::TextStyle::*;
use crate::player::Player;
use crate::tor::GuiTor;
use crate::stats::Market;
use crate::irc::Client as IRCClient;
use libtor::Error as libtorError;
pub struct App {
pub player: Player,
pub market: Market,
pub irc: IRCClient,
pub tor_required: bool,
pub tor_started: bool,
pub tor_connected: bool,
pub to_data: String,
pub show_irc: bool,
pub irc_message: String,
pub irc_connected: bool,
pub show_market_data: bool
}
@ -25,11 +28,13 @@ impl Default for App {
Self {
player: Player::default(),
market: Market::new(),
irc: IRCClient::new("wowboombox".to_owned()),
tor_started: false,
tor_required: true,
tor_connected: false,
show_market_data: false,
show_irc: false,
irc_connected: false,
to_data: "".to_owned(),
irc_message: "".to_owned()
}
@ -67,6 +72,7 @@ impl eframe::App for App {
ui.checkbox(&mut self.tor_required, "Require Tor");
if (self.tor_connected && self.tor_required) || (! self.tor_required) {
ui.checkbox(&mut self.show_market_data, "Show Market Data");
ui.checkbox(&mut self.show_irc, "Show IRC");
}
});
@ -91,6 +97,14 @@ impl eframe::App for App {
}
}
}
// IRC
if self.show_irc && ! self.irc_connected {
self.irc.run().expect("wtf mate");
self.irc_connected = true;
} else if self.show_irc {
ui.label(self.irc.read_irc_log());
}
if self.show_market_data {
egui::ComboBox::from_label("Pick currency base.")
.selected_text(format!("{}", self.market.denomination))

@ -0,0 +1,315 @@
// Copyright © 2019 Matthew Geary
// [This program is licensed under the "MIT License"]
// Please see the file LICENSE in the source
// distribution of this software for license terms.
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::io::{Read, Write};
use std::collections::HashMap;
use std::net::TcpStream;
use std::str;
use std::thread;
///! A simple IRC client written in Rust.
/// Returns a TcpStream connected to the desired server, with the given nickname
///
/// # Arguments
///
/// * `nick` - A string that holds the desired user nickname.
/// # `server` - A string that holds the desired irc server
///
/// # Example
///
/// `let stream = connect(nick.to_owned(), server.to_owned()).unwrap();`
///
fn connect(nick: String) -> std::io::Result<TcpStream> {
// https://doc.rust-lang.org/std/net/struct.TcpStream.html
let send_stream = TcpStream::connect("irc.oftc.net:6667")?;
// let send_stream = connector.connect("irc.oftc.net", send_stream).expect("could not connect via tls");
// https://tools.ietf.org/html/rfc1459#section-4.1.1
// https://github.com/hoodie/concatenation_benchmarks-rs
let nick_string = format!("{}\r\n", &nick);
let user_string = format!("{} * * {}\n\r", &nick, &nick);
send_cmd(&send_stream, "USER", user_string)?;
send_cmd(&send_stream, "NICK", nick_string)?;
// send_cmd(&send_stream.get_ref(), "JOIN", "#wownero-music".to_owned())?;
Ok(send_stream)
}
/// Writes a command to a given TcpStream
///
/// # Arguments
///
/// * `stream` - A mutable reference to a TcpStream
/// # `server` - A string that holds the desired message
///
/// # Example
///
/// `send_cmd(&send_stream, "QUIT", "\r\n".to_string())?;`
///
fn send_cmd(mut stream: &TcpStream, cmd: &str, msg: String) -> Result<usize, std::io::Error> {
let mut cmd = cmd.to_string();
cmd.push_str(" ");
cmd.push_str(&msg);
println!("sending: {}", cmd.trim());
stream.write(cmd.as_bytes())
}
/// Loops to recieve data from a TcpStream
///
/// # Arguments
///
/// * `stream` - A mutable reference to a TcpStream
///
/// # Example
///
/// The following example demonstrates how to set up a threaded TcpStream with one
/// stream reference listening and one receiving.
/// ```
/// let send_stream = connect(nick.to_owned(), server.to_owned())?;
/// let recv_stream = send_stream.try_clone()?;
/// thread::spawn(move || receive(&recv_stream).expect("error setting up recv_stream"));
/// ```
///
fn receive(mut stream: &TcpStream) -> std::io::Result<()> {
loop {
let mut buffer = Vec::new();
let mut temp = [1];
for _ in 0..512 {
stream.read_exact(&mut temp)?;
match temp[0] {
0x1 => continue, // start of heading
0xD => continue, // carriage return
0xA => break, // line feed
_ => buffer.push(temp[0]),
}
}
let res_string = str::from_utf8(&buffer[..]);
match res_string {
Ok(r) => {
if !res_string.unwrap().is_empty() {
let mut f = OpenOptions::new()
.append(true)
.open("irc.log")
.unwrap();
if let Err(e) = writeln!(f, "{}", r.to_string()) {
eprintln!("[!] Failed to write to file: {}", e);
}
}
}
Err(error) => eprintln!("error while reading from tcp stream: {}", error),
}
}
}
/// A client struct holds nickname, server, and command information as well as
/// implementing functions to connect to a server and issue commands.
pub struct Client {
/// A user must have a nickname
nick: String,
/// Storing command data in a hashmap will supply the
/// user with accurate feedback
commands: HashMap<String, String>,
}
impl Client {
/// Returns a Client with the given nickname and server
/// as well as a hashmap built with command data
///
/// # Arguments
///
/// * `nick` - A string holding the desired nickname
/// * `server` - A string holding the desired server
///
/// # Example
///
/// `let client = Client::new(nick, server);`
///
pub fn new(nick: String) -> Client {
let mut commands = HashMap::new();
commands.insert("/quit".to_string(), "Command: /quit".to_string());
commands.insert(
"/join".to_string(),
"Command: /join Parameters: <channel>".to_string(),
);
commands.insert(
"/part".to_string(),
"Command: /part Parameters: <channel>".to_string(),
);
commands.insert(
"/nick".to_string(),
"Command: /nick Parameters: <nickname>".to_string(),
);
commands.insert(
"/msg".to_string(),
"Command: /msg Parameters: <receiver>".to_string(),
);
commands.insert(
"/topic".to_string(),
"Command: /topic Parameters: <channel> [<topic>]".to_string(),
);
commands.insert(
"/list".to_string(),
"Command: /list Parameters: <channel>".to_string(),
);
commands.insert(
"/names".to_string(),
"Command: /names Parameters: <channel>".to_string(),
);
Client {
nick,
commands,
}
}
/// Returns an option specifying whether the given
/// command/message is valid. If the message is not valid,
/// the function prints information about the command to
/// the user and returns None.
///
/// # Arguments
///
/// * `params` - The minimum number of params needed for the command
/// * `msg` - The msg to verify
///
/// # Example
///
/// if let None = self.verify(2, &msg) {
/// continue
/// }
///
pub fn verify(&self, params: usize, msg: &[&str]) -> Option<()> {
if msg.len() < params {
let msg = self.commands.get(msg[0].trim()).unwrap();
println!("{}", msg);
return None;
}
Some(())
}
pub fn read_irc_log(&self) -> String {
let mut s: String = String::new();
let f = std::fs::File::open("irc.log"); // ("unable to open irc log");
if f.is_err() { return "".to_owned() }
let _ = f.unwrap().read_to_string(&mut s);
return s;
}
/// Creates a send and recv TcpStream (with the same socket)
/// spins recv to its own thread
/// main thread takes user input and matches it to commands
/// after commands and processed and messages verified,
/// the send stream is used to send command/message combinations.
pub fn run(&self) -> std::io::Result<()> {
let send_stream = connect(self.nick.to_owned())?;
let recv_stream = send_stream.try_clone()?;
// https://doc.rust-lang.org/nightly/std/thread/
thread::spawn(move || receive(&recv_stream).expect("error setting up recv_stream"));
Ok(())
// Read the input.
// loop {
// let mut msg = String::new();
// match io::stdin().read_line(&mut msg) {
// Ok(_) => {
// // https://users.rust-lang.org/t/how-to-split-a-string-by-and-then-print-first-or-last-component/23042
// let mut msg: Vec<&str> = msg.trim().split(' ').collect();
// let cmd: &str = msg[0].trim();
// match cmd {
// "help" => {
// self.commands
// .iter()
// .for_each(|(_, val)| println!("{}", val));
// }
// "/quit" => {
// send_cmd(&send_stream, "QUIT", "\r\n".to_string())?;
// println!("Quitting...");
// return Ok(());
// }
// "/join" => {
// if self.verify(2, &msg).is_none() {
// continue;
// }
// let msg = format!("{}\r\n", msg[1].trim());
// send_cmd(&send_stream, "JOIN", msg)?;
// }
// "/part" => {
// if self.verify(2, &msg).is_none() {
// continue;
// }
// let msg = format!("{}\r\n", msg[1].trim());
// send_cmd(&send_stream, "PART", msg)?;
// }
// "/nick" => {
// if self.verify(2, &msg).is_none() {
// continue;
// }
// let msg = format!("{}\r\n", msg[1].trim());
// send_cmd(&send_stream, "NICK", msg)?;
// }
// "/msg" => {
// if self.verify(2, &msg).is_none() {
// continue;
// }
// let receiver = msg[1].trim();
// msg.remove(0);
// msg.remove(0);
// let mut text = String::new();
// msg.iter().for_each(|word| {
// text.push_str(word);
// text.push_str(" ")
// });
// let text = text.trim();
// let msg = format!("{} :{:?}\r\n", receiver, text);
// send_cmd(&send_stream, "PRIVMSG", msg)?;
// }
// "/list" => {
// let target = if msg.len() > 1 { msg[1].trim() } else { "" };
// let msg = format!("{}\r\n", target);
// send_cmd(&send_stream, "LIST", msg)?;
// }
// "/names" => {
// let target = if msg.len() > 1 { msg[1].trim() } else { "" };
// let msg = format!("{}\r\n", target);
// send_cmd(&send_stream, "NAMES", msg)?;
// }
// "/topic" => {
// if self.verify(3, &msg).is_none() {
// continue;
// }
// let msg = format!("{} {}\r\n", msg[1].trim(), msg[2].trim());
// send_cmd(&send_stream, "NAMES", msg)?;
// }
// _ => {
// println!("Unrecognized command: {}", msg[0]);
// }
// }
// }
// Err(error) => eprintln!("error while reading user input: {}", error),
// }
// }
}
}
// Parse command line arguments and use them create and run a client
// fn main() {
// // Process the arguments.
// let args: Vec<String> = std::env::args().collect();
// let mut nick: String;
// let mut server: String;
// match args.len() {
// 3 => server = args[2].to_owned(),
// 2 => server = "irc.freenode.net".to_string(),
// _ => usage(),
// }
// nick = args[1].to_owned();
// let client = Client::new(nick, server);
// client.run().expect("Client Error");
// }

@ -8,6 +8,7 @@ mod app;
mod player;
mod tor;
mod stats;
mod irc;
// "http://wowradiod6mhb4ignjqy5ghf5l42yh2yeumgeq3yi7gn7yqy3efhe5ad.onion"
// "http://wowradiof5wx62w4avdk5fwbvcoea2z4ul2q3awffn5vmfaa3vhlgiid.onion"