commit 3c206e92f19e0e32cef7e1bf7bcc05da4fcd46c2
parent 0c8c32dd422262823632c96d5932145738c90edb
Author: Strange <StrangeGuy6228@protonmail.com>
Date: Fri, 22 Mar 2024 18:42:39 +0530
added d and D for downlaoding and downloading_and_view ing using curl and xdg_open [linux] + make linux will build --release and cp to /opt [requires sudo]
Diffstat:
| M | Makefile | | | 8 | +++++++- |
| M | src/main.rs | | | 981 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
2 files changed, 756 insertions(+), 233 deletions(-)
diff --git a/Makefile b/Makefile
@@ -33,5 +33,11 @@ rsync:
rsync --recursive --times --compress --progress dist/ dkf:/home/dkf/dist/downloads-bhcli
deploy: build-darwin cross-compile-windows build-linux rsync
+
+linux:
+ cargo build --release
+ @echo "Copying binary to /opt requires sudo privileges."
+ @echo "Ensure /opt is added to your \$$PATH variable to use bhcli globally from any path."
+ sudo cp target/release/bhcli /opt
-.PHONY: build-darwin process-windows cross-compile-windows rsync
+.PHONY: build-darwin process-windows cross-compile-windows rsync linux
diff --git a/src/main.rs b/src/main.rs
@@ -1,12 +1,9 @@
-mod util;
-mod lechatphp;
mod bhc;
+mod lechatphp;
+mod util;
+use crate::lechatphp::LoginErr;
use anyhow::{anyhow, Context};
-use std::process;
-use log::LevelFilter;
-use log4rs::append::file::FileAppender;
-use log4rs::encode::pattern::PatternEncoder;
use chrono::{DateTime, Datelike, NaiveDateTime, Utc};
use clap::Parser;
use clipboard::ClipboardContext;
@@ -21,13 +18,18 @@ use crossterm::{
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
+use http::StatusCode;
use lazy_static::lazy_static;
use linkify::LinkFinder;
+use log::LevelFilter;
+use log4rs::append::file::FileAppender;
+use log4rs::encode::pattern::PatternEncoder;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use regex::Regex;
use reqwest::blocking::multipart;
use reqwest::blocking::Client;
+use reqwest::redirect::Policy;
use rodio::{source::Source, Decoder, OutputStream};
use select::document::Document;
use select::predicate::{Attr, Name};
@@ -35,13 +37,13 @@ use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::io::Cursor;
use std::io::{self, Write};
-use std::sync::{Arc, MutexGuard};
+use std::process;
+use std::process::Command;
use std::sync::Mutex;
+use std::sync::{Arc, MutexGuard};
use std::thread;
use std::time::Duration;
use std::time::Instant;
-use http::StatusCode;
-use reqwest::redirect::Policy;
use tui::layout::Rect;
use tui::style::Color as tuiColor;
use tui::{
@@ -54,7 +56,6 @@ use tui::{
};
use unicode_width::UnicodeWidthStr;
use util::StatefulList;
-use crate::lechatphp::LoginErr;
const LANG: &str = "en";
const SEND_TO_ALL: &str = "s *";
@@ -65,7 +66,7 @@ const SOUND1: &[u8] = include_bytes!("sound1.mp3");
const DKF_URL: &str = "http://dkforestseeaaq2dqz2uflmlsybvnq2irzn4ygyvu53oazyorednviid.onion";
const BHCLI_BLOG_URL: &str =
"http://dkforestseeaaq2dqz2uflmlsybvnq2irzn4ygyvu53oazyorednviid.onion/bhcli";
-const BAN_IMPOSTERS: bool = true;
+// const BAN_IMPOSTERS: bool = true;
const SERVER_DOWN_500_ERR: &str = "500 Internal Server Error, server down";
const SERVER_DOWN_ERR: &str = "502 Bad Gateway, server down";
const KICKED_ERR: &str = "You have been kicked";
@@ -77,7 +78,7 @@ const CAPTCHA_USED_ERR: &str = "Captcha already used or timed out";
const UNKNOWN_ERR: &str = "Unknown error";
const N0TR1V: &str = "n0tr1v";
const STUXNET: &str = "STUXNET";
-const FAGGOT: &str = "faggot";
+// const FAGGOT: &str = "faggot";
const DNMX_URL: &str = "http://hxuzjtocnzvv5g2rtg2bhwkcbupmk7rclb6lly3fo4tvqkk5oyrv3nid.onion";
lazy_static! {
@@ -221,7 +222,7 @@ struct LeChatPHPClient {
is_muted: Arc<Mutex<bool>>,
show_sys: bool,
display_guest_view: bool,
- display_member_view: bool,
+ display_member_view: bool,
display_hidden_msgs: bool,
tx: crossbeam_channel::Sender<PostType>,
rx: Arc<Mutex<crossbeam_channel::Receiver<PostType>>>,
@@ -236,30 +237,31 @@ impl LeChatPHPClient {
let mut attempt = 0;
loop {
match self.login() {
- Err(e) => {
- match e {
- LoginErr::KickedErr | LoginErr::RegErr | LoginErr::NicknameErr | LoginErr::UnknownErr => {
- log::error!("{}", e);
+ Err(e) => match e {
+ LoginErr::KickedErr
+ | LoginErr::RegErr
+ | LoginErr::NicknameErr
+ | LoginErr::UnknownErr => {
+ log::error!("{}", e);
+ break;
+ }
+ LoginErr::CaptchaFailedSolveErr => {
+ log::error!("{}", e);
+ continue;
+ }
+ LoginErr::CaptchaWgErr | LoginErr::CaptchaUsedErr => {}
+ LoginErr::ServerDownErr | LoginErr::ServerDown500Err => {
+ log::error!("{}", e);
+ }
+ LoginErr::Reqwest(err) => {
+ if err.is_connect() {
+ log::error!("{}\nIs tor proxy enabled ?", err);
break;
- },
- LoginErr::CaptchaFailedSolveErr => {
- log::error!("{}", e);
- continue;
- },
- LoginErr::CaptchaWgErr | LoginErr::CaptchaUsedErr => {},
- LoginErr::ServerDownErr | LoginErr::ServerDown500Err => {
- log::error!("{}", e);
- },
- LoginErr::Reqwest(err) => {
- if err.is_connect() {
- log::error!("{}\nIs tor proxy enabled ?", err);
- break;
- } else if err.is_timeout() {
- log::error!("timeout: {}", err);
- } else {
- log::error!("{}", err);
- }
- },
+ } else if err.is_timeout() {
+ log::error!("timeout: {}", err);
+ } else {
+ log::error!("{}", err);
+ }
}
},
Ok(()) => {
@@ -269,7 +271,7 @@ impl LeChatPHPClient {
Ok(ExitSignal::Terminate) => return,
Err(e) => log::error!("{:?}", e),
}
- },
+ }
}
attempt += 1;
if max_retry > 0 && attempt > max_retry {
@@ -295,7 +297,8 @@ impl LeChatPHPClient {
let send_to = self.config.keepalive_send_to.clone();
thread::spawn(move || loop {
let clb = || {
- tx.send(PostType::Post("<keepalive>".to_owned(), send_to.clone())).unwrap();
+ tx.send(PostType::Post("<keepalive>".to_owned(), send_to.clone()))
+ .unwrap();
tx.send(PostType::DeleteLast).unwrap();
};
let timeout = after(Duration::from_secs(60 * 75));
@@ -323,11 +326,16 @@ impl LeChatPHPClient {
let url = format!("{}?action=post&session={}", &full_url, &session);
thread::spawn(move || loop {
// select! macro fucks all the LSP, therefore the code gymnastic here
- let clb = |v: Result<PostType, crossbeam_channel::RecvError>| {
- match v {
- Ok(post_type_recv) => post_msg(&client, post_type_recv, &full_url, session.clone(), &url, &last_post_tx),
- Err(_) => return,
- }
+ let clb = |v: Result<PostType, crossbeam_channel::RecvError>| match v {
+ Ok(post_type_recv) => post_msg(
+ &client,
+ post_type_recv,
+ &full_url,
+ session.clone(),
+ &url,
+ &last_post_tx,
+ ),
+ Err(_) => return,
};
let rx = rx.lock().unwrap();
select! {
@@ -364,8 +372,21 @@ impl LeChatPHPClient {
let source = Decoder::new_mp3(Cursor::new(SOUND1)).unwrap();
let mut should_notify = false;
- if let Err(err) = get_msgs(&client, &base_url, &page_php, &session, &username, &tx, &users, &sig,
- &messages_updated_tx, &members_tag, &datetime_fmt, &messages, &mut should_notify) {
+ if let Err(err) = get_msgs(
+ &client,
+ &base_url,
+ &page_php,
+ &session,
+ &username,
+ &tx,
+ &users,
+ &sig,
+ &messages_updated_tx,
+ &members_tag,
+ &datetime_fmt,
+ &messages,
+ &mut should_notify,
+ ) {
log::error!("{}", err);
};
@@ -481,13 +502,11 @@ impl LeChatPHPClient {
if self.chat_type == ClientType::BHC {
//let mut resp_txt = self.client.get(&self.config.url).send().unwrap().text().unwrap();
let mut resp_txt = match self.client.get(&self.config.url).send() {
- Ok(response) => {
- match response.text() {
- Ok(text) => text,
- Err(err) => {
- println!("Error: {}\nCheck Your Tor Connection", err);
- process::exit(0);
- }
+ Ok(response) => match response.text() {
+ Ok(text) => text,
+ Err(err) => {
+ println!("Error: {}\nCheck Your Tor Connection", err);
+ process::exit(0);
}
},
Err(err) => {
@@ -497,17 +516,52 @@ impl LeChatPHPClient {
};
let doc = Document::from(resp_txt.as_str());
if let Some(meta) = doc.find(Name("meta")).next() {
- let meta_content = meta.attr("content").context("meta content not found").unwrap().to_owned();
+ let meta_content = meta
+ .attr("content")
+ .context("meta content not found")
+ .unwrap()
+ .to_owned();
let index_url = META_REFRESH_RGX.captures(&meta_content).unwrap()[1].to_owned();
- resp_txt = self.client.get(format!("{}/{}", &self.config.url, index_url)).send().unwrap().text().unwrap();
+ resp_txt = self
+ .client
+ .get(format!("{}/{}", &self.config.url, index_url))
+ .send()
+ .unwrap()
+ .text()
+ .unwrap();
}
let doc = Document::from(resp_txt.as_str());
- let form_action = doc.find(Name("form")).next().unwrap().attr("action").context("form action not found").unwrap().to_owned();
- let captcha_url = doc.find(Name("img")).next().unwrap().attr("src").context("img src not found").unwrap().to_owned();
+ let form_action = doc
+ .find(Name("form"))
+ .next()
+ .unwrap()
+ .attr("action")
+ .context("form action not found")
+ .unwrap()
+ .to_owned();
+ let captcha_url = doc
+ .find(Name("img"))
+ .next()
+ .unwrap()
+ .attr("src")
+ .context("img src not found")
+ .unwrap()
+ .to_owned();
- let captcha_bytes = self.client.get(format!("{}/{}", &self.config.url, captcha_url)).send().unwrap().bytes().unwrap();
+ let captcha_bytes = self
+ .client
+ .get(format!("{}/{}", &self.config.url, captcha_url))
+ .send()
+ .unwrap()
+ .bytes()
+ .unwrap();
let img = image::load_from_memory(&captcha_bytes).unwrap();
- let img_buf = image::imageops::resize(&img, img.width(), img.height(), image::imageops::FilterType::Nearest);
+ let img_buf = image::imageops::resize(
+ &img,
+ img.width(),
+ img.height(),
+ image::imageops::FilterType::Nearest,
+ );
// Save captcha as file on disk
img_buf.save("captcha.gif").unwrap();
termage::display_image("captcha.gif", img.width(), img.height());
@@ -517,22 +571,46 @@ impl LeChatPHPClient {
io::stdout().flush().unwrap();
io::stdin().read_line(&mut captcha_input).unwrap();
trim_newline(&mut captcha_input);
- let params = vec![("input", captcha_input), ("submit", "Enter+Chat".to_owned())];
- let resp = self.client.post(format!("{}/{}", &self.config.url, form_action)).form(¶ms).send().unwrap();
+ let params = vec![
+ ("input", captcha_input),
+ ("submit", "Enter+Chat".to_owned()),
+ ];
+ let resp = self
+ .client
+ .post(format!("{}/{}", &self.config.url, form_action))
+ .form(¶ms)
+ .send()
+ .unwrap();
if resp.status() != StatusCode::SEE_OTHER {
return Err(LoginErr::CaptchaWgErr);
}
- self.config.page_php = resp.headers().get("location").map(|v| v.to_str().unwrap()).unwrap_or(&self.config.page_php).to_string();
+ self.config.page_php = resp
+ .headers()
+ .get("location")
+ .map(|v| v.to_str().unwrap())
+ .unwrap_or(&self.config.page_php)
+ .to_string();
}
self.session = Some(lechatphp::login(
- &self.client, &self.config.url, &self.config.page_php, &self.base_client.username,
- &self.base_client.password, &self.guest_color, self.manual_captcha)?);
+ &self.client,
+ &self.config.url,
+ &self.config.page_php,
+ &self.base_client.username,
+ &self.base_client.password,
+ &self.guest_color,
+ self.manual_captcha,
+ )?);
Ok(())
}
fn logout(&mut self) -> anyhow::Result<()> {
if let Some(session) = &self.session {
- lechatphp::logout(&self.client, &self.config.url, &self.config.page_php, session)?;
+ lechatphp::logout(
+ &self.client,
+ &self.config.url,
+ &self.config.page_php,
+ session,
+ )?;
self.session = None;
}
Ok(())
@@ -573,106 +651,357 @@ impl LeChatPHPClient {
});
}
- fn handle_input(&mut self, events: &Events, app: &mut App, messages: &Arc<Mutex<Vec<Message>>>, users: &Arc<Mutex<Users>>) -> Result<(), ExitSignal> {
+ fn handle_input(
+ &mut self,
+ events: &Events,
+ app: &mut App,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ users: &Arc<Mutex<Users>>,
+ ) -> Result<(), ExitSignal> {
match events.next() {
- Ok(Event::NeedLogin) => return Err(ExitSignal::NeedLogin),
- Ok(Event::Terminate) => return Err(ExitSignal::Terminate),
+ Ok(Event::NeedLogin) => return Err(ExitSignal::NeedLogin),
+ Ok(Event::Terminate) => return Err(ExitSignal::Terminate),
Ok(Event::Input(evt)) => self.handle_event(app, messages, users, evt),
_ => Ok(()),
}
}
- fn handle_event(&mut self, app: &mut App, messages: &Arc<Mutex<Vec<Message>>>, users: &Arc<Mutex<Users>>, event: event::Event) -> Result<(), ExitSignal> {
+ fn handle_event(
+ &mut self,
+ app: &mut App,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ users: &Arc<Mutex<Users>>,
+ event: event::Event,
+ ) -> Result<(), ExitSignal> {
match event {
event::Event::Resize(_cols, _rows) => Ok(()),
- event::Event::FocusGained => Ok(()),
- event::Event::FocusLost => Ok(()),
- event::Event::Paste(_) => Ok(()),
- event::Event::Key(key_event) => self.handle_key_event(app, messages, users, key_event),
- event::Event::Mouse(mouse_event) => self.handle_mouse_event(app, mouse_event),
+ event::Event::FocusGained => Ok(()),
+ event::Event::FocusLost => Ok(()),
+ event::Event::Paste(_) => Ok(()),
+ event::Event::Key(key_event) => self.handle_key_event(app, messages, users, key_event),
+ event::Event::Mouse(mouse_event) => self.handle_mouse_event(app, mouse_event),
}
}
- fn handle_key_event(&mut self, app: &mut App, messages: &Arc<Mutex<Vec<Message>>>, users: &Arc<Mutex<Users>>, key_event: KeyEvent) -> Result<(), ExitSignal> {
+ fn handle_key_event(
+ &mut self,
+ app: &mut App,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ users: &Arc<Mutex<Users>>,
+ key_event: KeyEvent,
+ ) -> Result<(), ExitSignal> {
if app.input_mode != InputMode::Normal {
self.last_key_event = None;
}
match app.input_mode {
- InputMode::LongMessage => self.handle_long_message_mode_key_event(app, key_event, messages),
- InputMode::Normal => self.handle_normal_mode_key_event(app, key_event, messages),
- InputMode::Editing |
- InputMode::EditingErr => self.handle_editing_mode_key_event(app, key_event, users),
+ InputMode::LongMessage => {
+ self.handle_long_message_mode_key_event(app, key_event, messages)
+ }
+ InputMode::Normal => self.handle_normal_mode_key_event(app, key_event, messages),
+ InputMode::Editing | InputMode::EditingErr => {
+ self.handle_editing_mode_key_event(app, key_event, users)
+ }
}
}
- fn handle_long_message_mode_key_event(&mut self, app: &mut App, key_event: KeyEvent, messages: &Arc<Mutex<Vec<Message>>>) -> Result<(), ExitSignal> {
+ fn handle_long_message_mode_key_event(
+ &mut self,
+ app: &mut App,
+ key_event: KeyEvent,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ ) -> Result<(), ExitSignal> {
match key_event {
- KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::NONE, .. } |
- KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::NONE, .. } => self.handle_long_message_mode_key_event_esc(app),
- KeyEvent { code: KeyCode::Char('d'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_long_message_mode_key_event_ctrl_d(app, messages),
+ KeyEvent {
+ code: KeyCode::Enter,
+ modifiers: KeyModifiers::NONE,
+ ..
+ }
+ | KeyEvent {
+ code: KeyCode::Esc,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_long_message_mode_key_event_esc(app),
+ KeyEvent {
+ code: KeyCode::Char('d'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_long_message_mode_key_event_ctrl_d(app, messages),
_ => {}
}
Ok(())
}
- fn handle_normal_mode_key_event(&mut self, app: &mut App, key_event: KeyEvent, messages: &Arc<Mutex<Vec<Message>>>) -> Result<(), ExitSignal> {
+ fn handle_normal_mode_key_event(
+ &mut self,
+ app: &mut App,
+ key_event: KeyEvent,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ ) -> Result<(), ExitSignal> {
match key_event {
- KeyEvent { code: KeyCode::Char('/'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_slash(app),
- KeyEvent { code: KeyCode::Char('j'), modifiers: KeyModifiers::NONE, .. } |
- KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_down(app),
- KeyEvent { code: KeyCode::Char('k'), modifiers: KeyModifiers::NONE, .. } |
- KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_up(app),
- KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_enter(app, messages),
- KeyEvent { code: KeyCode::Backspace, modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_backspace(app, messages),
- KeyEvent { code: KeyCode::Char('y'), modifiers: KeyModifiers::NONE, .. } |
- KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_normal_mode_key_event_yank(app),
- KeyEvent { code: KeyCode::Char('Y'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_yank_link(app),
- KeyEvent { code: KeyCode::Char('d'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_debug(app),
- KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_debug2(app),
- KeyEvent { code: KeyCode::Char('m'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_toggle_mute(),
- KeyEvent { code: KeyCode::Char('S'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_toggle_sys(),
- KeyEvent { code: KeyCode::Char('M'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_toggle_member_view(),
- KeyEvent { code: KeyCode::Char('G'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_toggle_guest_view(),
- KeyEvent { code: KeyCode::Char('H'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_toggle_hidden(),
- KeyEvent { code: KeyCode::Char('i'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_input_mode(app),
- KeyEvent { code: KeyCode::Char('Q'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_logout()?,
- KeyEvent { code: KeyCode::Char('q'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_exit()?,
- KeyEvent { code: KeyCode::Char('t'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_tag(app),
- KeyEvent { code: KeyCode::Char('p'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_pm(app),
- KeyEvent { code: KeyCode::Char('k'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_normal_mode_key_event_kick(app),
- KeyEvent { code: KeyCode::Char('w'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_normal_mode_key_event_warn(app),
- KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::CONTROL, .. } |
- KeyEvent { code: KeyCode::PageUp, modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_page_up(app),
- KeyEvent { code: KeyCode::Char('d'), modifiers: KeyModifiers::CONTROL, .. } |
- KeyEvent { code: KeyCode::PageDown, modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_page_down(app),
- KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_esc(app),
- KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::SHIFT, .. } => self.handle_normal_mode_key_event_shift_u(app),
- KeyEvent { code: KeyCode::Char('g'), modifiers: KeyModifiers::NONE, .. } => self.handle_normal_mode_key_event_g(app),
+ KeyEvent {
+ code: KeyCode::Char('/'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_slash(app),
+ KeyEvent {
+ code: KeyCode::Char('j'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ }
+ | KeyEvent {
+ code: KeyCode::Down,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_down(app),
+ KeyEvent {
+ code: KeyCode::Char('k'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ }
+ | KeyEvent {
+ code: KeyCode::Up,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_up(app),
+ KeyEvent {
+ code: KeyCode::Enter,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_enter(app, messages),
+ KeyEvent {
+ code: KeyCode::Backspace,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_backspace(app, messages),
+ KeyEvent {
+ code: KeyCode::Char('y'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ }
+ | KeyEvent {
+ code: KeyCode::Char('c'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_normal_mode_key_event_yank(app),
+ KeyEvent {
+ code: KeyCode::Char('Y'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_yank_link(app),
+
+ //straneEdit
+ KeyEvent {
+ code: KeyCode::Char('D'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_download_link(app),
+
+ //StrangeEdit
+ KeyEvent {
+ code: KeyCode::Char('d'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_download_and_view(app),
+
+ // KeyEvent {
+ // code: KeyCode::Char('d'),
+ // modifiers: KeyModifiers::NONE,
+ // ..
+ // } => self.handle_normal_mode_key_event_debug(app),
+ // KeyEvent {
+ // code: KeyCode::Char('D'),
+ // modifiers: KeyModifiers::SHIFT,
+ // ..
+ // } => self.handle_normal_mode_key_event_debug2(app),
+ KeyEvent {
+ code: KeyCode::Char('m'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_toggle_mute(),
+ KeyEvent {
+ code: KeyCode::Char('S'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_toggle_sys(),
+ KeyEvent {
+ code: KeyCode::Char('M'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_toggle_member_view(),
+ KeyEvent {
+ code: KeyCode::Char('G'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_toggle_guest_view(),
+ KeyEvent {
+ code: KeyCode::Char('H'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_toggle_hidden(),
+ KeyEvent {
+ code: KeyCode::Char('i'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_input_mode(app),
+ KeyEvent {
+ code: KeyCode::Char('Q'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_logout()?,
+ KeyEvent {
+ code: KeyCode::Char('q'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_exit()?,
+ KeyEvent {
+ code: KeyCode::Char('t'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_tag(app),
+ KeyEvent {
+ code: KeyCode::Char('p'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_pm(app),
+ KeyEvent {
+ code: KeyCode::Char('k'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_normal_mode_key_event_kick(app),
+ KeyEvent {
+ code: KeyCode::Char('w'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_normal_mode_key_event_warn(app),
+ KeyEvent {
+ code: KeyCode::Char('u'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ }
+ | KeyEvent {
+ code: KeyCode::PageUp,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_page_up(app),
+ KeyEvent {
+ code: KeyCode::Char('d'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ }
+ | KeyEvent {
+ code: KeyCode::PageDown,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_page_down(app),
+ KeyEvent {
+ code: KeyCode::Esc,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_esc(app),
+ KeyEvent {
+ code: KeyCode::Char('u'),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_normal_mode_key_event_shift_u(app),
+ KeyEvent {
+ code: KeyCode::Char('g'),
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_normal_mode_key_event_g(app),
_ => {}
}
self.last_key_event = Some(key_event.code);
Ok(())
}
- fn handle_editing_mode_key_event(&mut self, app: &mut App, key_event: KeyEvent, users: &Arc<Mutex<Users>>) -> Result<(), ExitSignal> {
+ fn handle_editing_mode_key_event(
+ &mut self,
+ app: &mut App,
+ key_event: KeyEvent,
+ users: &Arc<Mutex<Users>>,
+ ) -> Result<(), ExitSignal> {
app.input_mode = InputMode::Editing;
match key_event {
- KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_enter(app)?,
- KeyEvent { code: KeyCode::Tab, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_tab(app, users),
- KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_editing_mode_key_event_ctrl_c(app),
- KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_editing_mode_key_event_ctrl_a(app),
- KeyEvent { code: KeyCode::Char('e'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_editing_mode_key_event_ctrl_e(app),
- KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_editing_mode_key_event_ctrl_f(app),
- KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_editing_mode_key_event_ctrl_b(app),
- KeyEvent { code: KeyCode::Char('v'), modifiers: KeyModifiers::CONTROL, .. } => self.handle_editing_mode_key_event_ctrl_v(app),
- KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_left(app),
- KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_right(app),
- KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_down(app),
- KeyEvent { code: KeyCode::Char(c), modifiers: KeyModifiers::NONE, .. } |
- KeyEvent { code: KeyCode::Char(c), modifiers: KeyModifiers::SHIFT, .. } => self.handle_editing_mode_key_event_shift_c(app, c),
- KeyEvent { code: KeyCode::Backspace, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_backspace(app),
- KeyEvent { code: KeyCode::Delete, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_delete(app),
- KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::NONE, .. } => self.handle_editing_mode_key_event_esc(app),
+ KeyEvent {
+ code: KeyCode::Enter,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_enter(app)?,
+ KeyEvent {
+ code: KeyCode::Tab,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_tab(app, users),
+ KeyEvent {
+ code: KeyCode::Char('c'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_editing_mode_key_event_ctrl_c(app),
+ KeyEvent {
+ code: KeyCode::Char('a'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_editing_mode_key_event_ctrl_a(app),
+ KeyEvent {
+ code: KeyCode::Char('e'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_editing_mode_key_event_ctrl_e(app),
+ KeyEvent {
+ code: KeyCode::Char('f'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_editing_mode_key_event_ctrl_f(app),
+ KeyEvent {
+ code: KeyCode::Char('b'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_editing_mode_key_event_ctrl_b(app),
+ KeyEvent {
+ code: KeyCode::Char('v'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => self.handle_editing_mode_key_event_ctrl_v(app),
+ KeyEvent {
+ code: KeyCode::Left,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_left(app),
+ KeyEvent {
+ code: KeyCode::Right,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_right(app),
+ KeyEvent {
+ code: KeyCode::Down,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_down(app),
+ KeyEvent {
+ code: KeyCode::Char(c),
+ modifiers: KeyModifiers::NONE,
+ ..
+ }
+ | KeyEvent {
+ code: KeyCode::Char(c),
+ modifiers: KeyModifiers::SHIFT,
+ ..
+ } => self.handle_editing_mode_key_event_shift_c(app, c),
+ KeyEvent {
+ code: KeyCode::Backspace,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_backspace(app),
+ KeyEvent {
+ code: KeyCode::Delete,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_delete(app),
+ KeyEvent {
+ code: KeyCode::Esc,
+ modifiers: KeyModifiers::NONE,
+ ..
+ } => self.handle_editing_mode_key_event_esc(app),
_ => {}
}
Ok(())
@@ -683,12 +1012,20 @@ impl LeChatPHPClient {
app.input_mode = InputMode::Normal;
}
- fn handle_long_message_mode_key_event_ctrl_d(&mut self, app: &mut App, messages: &Arc<Mutex<Vec<Message>>>) {
+ fn handle_long_message_mode_key_event_ctrl_d(
+ &mut self,
+ app: &mut App,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ ) {
if let Some(idx) = app.items.state.selected() {
if let Some(item) = app.items.items.get(idx) {
- self.post_msg(PostType::Clean(item.date.to_owned(), item.text.text())).unwrap();
+ self.post_msg(PostType::Clean(item.date.to_owned(), item.text.text()))
+ .unwrap();
let mut messages = messages.lock().unwrap();
- if let Some(pos) = messages.iter().position(|m| m.date == item.date && m.text == item.text) {
+ if let Some(pos) = messages
+ .iter()
+ .position(|m| m.date == item.date && m.text == item.text)
+ {
messages[pos].hide = !messages[pos].hide;
}
app.long_message = None;
@@ -704,7 +1041,7 @@ impl LeChatPHPClient {
fn handle_normal_mode_key_event_down(&mut self, app: &mut App) {
app.items.next()
}
-
+
fn handle_normal_mode_key_event_slash(&mut self, app: &mut App) {
app.items.unselect();
app.input = "/".to_owned();
@@ -712,13 +1049,18 @@ impl LeChatPHPClient {
app.input_mode = InputMode::Editing;
}
- fn handle_normal_mode_key_event_enter(&mut self, app: &mut App, messages: &Arc<Mutex<Vec<Message>>>) {
+ fn handle_normal_mode_key_event_enter(
+ &mut self,
+ app: &mut App,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ ) {
if let Some(idx) = app.items.state.selected() {
if let Some(item) = app.items.items.get(idx) {
// If we have a filter, <enter> will "jump" to the message
- if !app.filter.is_empty(){
+ if !app.filter.is_empty() {
let idx = messages
- .lock().unwrap()
+ .lock()
+ .unwrap()
.iter()
.enumerate()
.find(|(_, e)| e.date == item.date)
@@ -733,11 +1075,18 @@ impl LeChatPHPClient {
}
}
- fn handle_normal_mode_key_event_backspace(&mut self, app: &mut App, messages: &Arc<Mutex<Vec<Message>>>) {
+ fn handle_normal_mode_key_event_backspace(
+ &mut self,
+ app: &mut App,
+ messages: &Arc<Mutex<Vec<Message>>>,
+ ) {
if let Some(idx) = app.items.state.selected() {
if let Some(item) = app.items.items.get(idx) {
let mut messages = messages.lock().unwrap();
- if let Some(pos) = messages.iter().position(|m| m.date == item.date && m.text == item.text) {
+ if let Some(pos) = messages
+ .iter()
+ .position(|m| m.date == item.date && m.text == item.text)
+ {
if item.deleted {
messages.remove(pos);
} else {
@@ -754,14 +1103,11 @@ impl LeChatPHPClient {
if let Some(upload_link) = &item.upload_link {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
let mut out = format!("{}{}", self.config.url, upload_link);
- if let Some((_, _, msg)) =
- get_message(&item.text, &self.config.members_tag)
- {
+ if let Some((_, _, msg)) = get_message(&item.text, &self.config.members_tag) {
out = format!("{} {}", msg, out);
}
ctx.set_contents(out).unwrap();
- } else if let Some((_, _, msg)) =
- get_message(&item.text, &self.config.members_tag)
+ } else if let Some((_, _, msg)) = get_message(&item.text, &self.config.members_tag)
{
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
ctx.set_contents(msg).unwrap();
@@ -777,7 +1123,8 @@ impl LeChatPHPClient {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
let out = format!("{}{}", self.config.url, upload_link);
ctx.set_contents(out).unwrap();
- } else if let Some((_, _, msg)) = get_message(&item.text, &self.config.members_tag) {
+ } else if let Some((_, _, msg)) = get_message(&item.text, &self.config.members_tag)
+ {
let finder = LinkFinder::new();
let links: Vec<_> = finder.links(msg.as_str()).collect();
if let Some(link) = links.get(0) {
@@ -789,22 +1136,116 @@ impl LeChatPHPClient {
}
}
- fn handle_normal_mode_key_event_debug(&mut self, app: &mut App) {
+ //StrangeEdit
+ fn handle_normal_mode_key_event_download_link(&mut self, app: &mut App) {
if let Some(idx) = app.items.state.selected() {
if let Some(item) = app.items.items.get(idx) {
- log::error!("{:?}", item.text.text());
+ if let Some(upload_link) = &item.upload_link {
+ let url = format!("{}{}", self.config.url, upload_link);
+ let _ = Command::new("curl")
+ .args([
+ "--socks5",
+ "localhost:9050",
+ "--socks5-hostname",
+ "localhost:9050",
+ &url,
+ ])
+ .arg("-o")
+ .arg("download.img")
+ .output()
+ .expect("Failed to execute curl command");
+ } else if let Some((_, _, msg)) = get_message(&item.text, &self.config.members_tag)
+ {
+ let finder = LinkFinder::new();
+ let links: Vec<_> = finder.links(msg.as_str()).collect();
+ if let Some(link) = links.first() {
+ let url = link.as_str();
+ let _ = Command::new("curl")
+ .args([
+ "--socks5",
+ "localhost:9050",
+ "--socks5-hostname",
+ "localhost:9050",
+ url,
+ ])
+ .arg("-o")
+ .arg("download.img")
+ .output()
+ .expect("Failed to execute curl command");
+ }
+ }
}
}
}
- fn handle_normal_mode_key_event_debug2(&mut self, app: &mut App) {
+ //strageEdit
+ fn handle_normal_mode_key_event_download_and_view(&mut self, app: &mut App) {
if let Some(idx) = app.items.state.selected() {
if let Some(item) = app.items.items.get(idx) {
- log::error!("{:?} {:?}", item.text, item.upload_link);
+ if let Some(upload_link) = &item.upload_link {
+ let url = format!("{}{}", self.config.url, upload_link);
+ let _ = Command::new("curl")
+ .args([
+ "--socks5",
+ "localhost:9050",
+ "--socks5-hostname",
+ "localhost:9050",
+ &url,
+ ])
+ .arg("-o")
+ .arg("download.img")
+ .output()
+ .expect("Failed to execute curl command");
+
+ let _ = Command::new("xdg-open")
+ .arg("./download.img")
+ .output()
+ .expect("Failed to execute sxiv command");
+ } else if let Some((_, _, msg)) = get_message(&item.text, &self.config.members_tag)
+ {
+ let finder = LinkFinder::new();
+ let links: Vec<_> = finder.links(msg.as_str()).collect();
+ if let Some(link) = links.first() {
+ let url = link.as_str();
+ let _ = Command::new("curl")
+ .args([
+ "--socks5",
+ "localhost:9050",
+ "--socks5-hostname",
+ "localhost:9050",
+ url,
+ ])
+ .arg("-o")
+ .arg("download.img")
+ .output()
+ .expect("Failed to execute curl command");
+
+ let _ = Command::new("sxiv")
+ .arg("./download.img")
+ .output()
+ .expect("Failed to execute sxiv command");
+ }
+ }
}
}
}
+ // fn handle_normal_mode_key_event_debug(&mut self, app: &mut App) {
+ // if let Some(idx) = app.items.state.selected() {
+ // if let Some(item) = app.items.items.get(idx) {
+ // log::error!("{:?}", item.text.text());
+ // }
+ // }
+ // }
+
+ // fn handle_normal_mode_key_event_debug2(&mut self, app: &mut App) {
+ // if let Some(idx) = app.items.state.selected() {
+ // if let Some(item) = app.items.items.get(idx) {
+ // log::error!("{:?} {:?}", item.text, item.upload_link);
+ // }
+ // }
+ // }
+
fn handle_normal_mode_key_event_toggle_mute(&mut self) {
let mut is_muted = self.is_muted.lock().unwrap();
*is_muted = !*is_muted;
@@ -851,11 +1292,9 @@ impl LeChatPHPClient {
fn handle_normal_mode_key_event_tag(&mut self, app: &mut App) {
if let Some(idx) = app.items.state.selected() {
let text = &app.items.items.get(idx).unwrap().text;
- if let Some(username) = get_username(
- &self.base_client.username,
- &text,
- &self.config.members_tag,
- ) {
+ if let Some(username) =
+ get_username(&self.base_client.username, &text, &self.config.members_tag)
+ {
if text.text().starts_with(&app.members_tag) {
app.input = format!("/m @{} ", username);
} else {
@@ -1031,26 +1470,27 @@ impl LeChatPHPClient {
},
None => SEND_TO_ALL,
}
- .to_owned();
+ .to_owned();
let msg = match captures.get(3) {
Some(msg_match) => msg_match.as_str().to_owned(),
None => "".to_owned(),
};
self.post_msg(PostType::Upload(file_path, send_to, msg))
.unwrap();
- }
- else if input.starts_with("!warn") {
+ } else if input.starts_with("!warn") {
// StrangeEdit
let msg: String = input
.find('@')
.map(|index| input[index..].to_string())
.unwrap_or_else(String::new);
- let end_msg = format!("This is your warning - {}, will be kicked next !rules",msg);
+ let end_msg = format!(
+ "This is your warning - {}, will be kicked next !rules",
+ msg
+ );
// log::error!("The Strange end_msg is :{}",end_msg);
- self.post_msg(PostType::Post(end_msg,None)).unwrap();
- }
- else {
+ self.post_msg(PostType::Post(end_msg, None)).unwrap();
+ } else {
if input.starts_with("/") && !input.starts_with("/me ") {
app.input_idx = input.len();
app.input = input;
@@ -1072,9 +1512,9 @@ impl LeChatPHPClient {
let mut prefix = "";
if parts.len() == 1
&& ((parts[0] == "/kick" || parts[0] == "/k")
- || parts[0] == "/pm"
- || parts[0] == "/ignore"
- || parts[0] == "/unignore")
+ || parts[0] == "/pm"
+ || parts[0] == "/ignore"
+ || parts[0] == "/unignore")
{
should_autocomplete = true;
} else if user_prefix.starts_with("@") {
@@ -1240,7 +1680,9 @@ fn autocomplete_username(users: &Arc<Mutex<Users>>, prefix: &str) -> Option<Stri
let users = users.lock().unwrap();
let all_users = users.all();
let prefix_lower = prefix.to_lowercase();
- let filtered = all_users.iter().find(|(_, name)| name.to_lowercase().starts_with(&prefix_lower));
+ let filtered = all_users
+ .iter()
+ .find(|(_, name)| name.to_lowercase().starts_with(&prefix_lower));
Some(filtered?.1.to_owned())
}
@@ -1281,7 +1723,10 @@ enum RetryErr {
Exit,
}
-fn retry_fn<F>(mut clb: F) where F: FnMut() -> anyhow::Result<RetryErr> {
+fn retry_fn<F>(mut clb: F)
+where
+ F: FnMut() -> anyhow::Result<RetryErr>,
+{
loop {
match clb() {
Ok(RetryErr::Retry) => continue,
@@ -1289,21 +1734,37 @@ fn retry_fn<F>(mut clb: F) where F: FnMut() -> anyhow::Result<RetryErr> {
Err(err) => {
log::error!("{}", err);
continue;
- },
+ }
}
}
}
-fn post_msg(client: &Client, post_type_recv: PostType, full_url: &str, session: String, url: &str, last_post_tx: &crossbeam_channel::Sender<()>) {
+fn post_msg(
+ client: &Client,
+ post_type_recv: PostType,
+ full_url: &str,
+ session: String,
+ url: &str,
+ last_post_tx: &crossbeam_channel::Sender<()>,
+) {
let mut should_reset_keepalive_timer = false;
retry_fn(|| -> anyhow::Result<RetryErr> {
let post_type = post_type_recv.clone();
let resp_text = client.get(url).send()?.text()?;
let doc = Document::from(resp_text.as_str());
- let nc = doc.find(Attr("name", "nc")).next().context("nc not found")?;
+ let nc = doc
+ .find(Attr("name", "nc"))
+ .next()
+ .context("nc not found")?;
let nc_value = nc.attr("value").context("nc value not found")?.to_owned();
- let postid = doc.find(Attr("name", "postid")).next().context("failed to get postid")?;
- let postid_value = postid.attr("value").context("failed to get postid value")?.to_owned();
+ let postid = doc
+ .find(Attr("name", "postid"))
+ .next()
+ .context("failed to get postid")?;
+ let postid_value = postid
+ .attr("value")
+ .context("failed to get postid value")?
+ .to_owned();
let mut params: Vec<(&str, String)> = vec![
("lang", LANG.to_owned()),
("nc", nc_value.to_owned()),
@@ -1392,10 +1853,7 @@ fn post_msg(client: &Client, post_type_recv: PostType, full_url: &str, session:
("what", "all".to_owned()),
]);
} else {
- params.extend(vec![
- ("sendto", "".to_owned()),
- ("what", "last".to_owned()),
- ]);
+ params.extend(vec![("sendto", "".to_owned()), ("what", "last".to_owned())]);
}
}
PostType::Upload(file_path, send_to, msg) => {
@@ -1409,13 +1867,14 @@ fn post_msg(client: &Client, post_type_recv: PostType, full_url: &str, session:
.text("message", msg)
.text("sendto", send_to.to_owned())
.text("what", "purge".to_owned())
- .file("file", file_path) {
+ .file("file", file_path)
+ {
Ok(f) => f,
Err(e) => {
log::error!("{:?}", e);
return Ok(RetryErr::Exit);
- },
- }
+ }
+ },
);
}
PostType::Clean(_, _) => {}
@@ -1442,7 +1901,11 @@ fn post_msg(client: &Client, post_type_recv: PostType, full_url: &str, session:
fn parse_date(date: &str, datetime_fmt: &str) -> NaiveDateTime {
let now = Utc::now();
let date_fmt = format!("%Y-{}", datetime_fmt);
- NaiveDateTime::parse_from_str(format!("{}-{}", now.year(), date).as_str(), date_fmt.as_str()).unwrap()
+ NaiveDateTime::parse_from_str(
+ format!("{}-{}", now.year(), date).as_str(),
+ date_fmt.as_str(),
+ )
+ .unwrap()
}
fn get_msgs(
@@ -1455,12 +1918,15 @@ fn get_msgs(
users: &Arc<Mutex<Users>>,
sig: &Arc<Mutex<Sig>>,
messages_updated_tx: &crossbeam_channel::Sender<()>,
- members_tag:&str,
+ members_tag: &str,
datetime_fmt: &str,
messages: &Arc<Mutex<Vec<Message>>>,
- should_notify: &mut bool) -> anyhow::Result<()>
-{
- let url = format!("{}/{}?action=view&session={}&lang={}", base_url, page_php, session, LANG);
+ should_notify: &mut bool,
+) -> anyhow::Result<()> {
+ let url = format!(
+ "{}/{}?action=view&session={}&lang={}",
+ base_url, page_php, session, LANG
+ );
let resp_text = client.get(url).send()?.text()?;
let resp_text = resp_text.replace("<br>", "\n");
let doc = Document::from(resp_text.as_str());
@@ -1474,7 +1940,16 @@ fn get_msgs(
};
{
let messages = messages.lock().unwrap();
- process_new_messages(&new_messages, &messages, datetime_fmt, members_tag, username, should_notify, tx, sig);
+ process_new_messages(
+ &new_messages,
+ &messages,
+ datetime_fmt,
+ members_tag,
+ username,
+ should_notify,
+ tx,
+ sig,
+ );
// Build messages vector. Tag deleted messages.
update_messages(new_messages, messages, datetime_fmt);
// Notify new messages has arrived.
@@ -1491,15 +1966,21 @@ fn get_msgs(
}
fn process_new_messages(
- new_messages: &Vec<Message>, messages: &MutexGuard<Vec<Message>>,
- datetime_fmt: &str, members_tag: &str, username: &str, should_notify: &mut bool,
+ new_messages: &Vec<Message>,
+ messages: &MutexGuard<Vec<Message>>,
+ datetime_fmt: &str,
+ members_tag: &str,
+ username: &str,
+ should_notify: &mut bool,
tx: &crossbeam_channel::Sender<PostType>,
- sig: &Arc<Mutex<Sig>>) {
+ sig: &Arc<Mutex<Sig>>,
+) {
if let Some(last_known_msg) = messages.get(0) {
let last_known_msg_parsed_dt = parse_date(&last_known_msg.date, datetime_fmt);
- let filtered = new_messages
- .iter()
- .filter(|new_msg| last_known_msg_parsed_dt <= parse_date(&new_msg.date, datetime_fmt) && !(new_msg.date == last_known_msg.date && last_known_msg.text == new_msg.text));
+ let filtered = new_messages.iter().filter(|new_msg| {
+ last_known_msg_parsed_dt <= parse_date(&new_msg.date, datetime_fmt)
+ && !(new_msg.date == last_known_msg.date && last_known_msg.text == new_msg.text)
+ });
for new_msg in filtered {
if let Some((from, to_opt, msg)) = get_message(&new_msg.text, &members_tag) {
// Process new messages
@@ -1521,7 +2002,11 @@ fn process_new_messages(
}
}
-fn update_messages(new_messages: Vec<Message>, mut messages: MutexGuard<Vec<Message>>, datetime_fmt: &str) {
+fn update_messages(
+ new_messages: Vec<Message>,
+ mut messages: MutexGuard<Vec<Message>>,
+ datetime_fmt: &str,
+) {
let mut old_msg_ptr = 0;
for new_msg in new_messages.into_iter() {
loop {
@@ -1568,7 +2053,12 @@ fn update_messages(new_messages: Vec<Message>, mut messages: MutexGuard<Vec<Mess
messages.truncate(1000);
}
-fn n0tr1v_only_process_msg(from: &str, msg: &str, tx: &crossbeam_channel::Sender<PostType>, sig: &Arc<Mutex<Sig>>) {
+fn n0tr1v_only_process_msg(
+ from: &str,
+ msg: &str,
+ tx: &crossbeam_channel::Sender<PostType>,
+ sig: &Arc<Mutex<Sig>>,
+) {
// !bhcli filters
if msg == "!bhcli" {
let msg = format!("@{} -> {}", from, BHCLI_BLOG_URL).to_owned();
@@ -1602,10 +2092,16 @@ fn delete_message(
]);
let clean_resp_txt = client.post(full_url).form(¶ms).send()?.text()?;
let doc = Document::from(clean_resp_txt.as_str());
- let nc = doc.find(Attr("name", "nc")).next().context("nc not found")?;
+ let nc = doc
+ .find(Attr("name", "nc"))
+ .next()
+ .context("nc not found")?;
let nc_value = nc.attr("value").context("nc value not found")?.to_owned();
let msgs = extract_messages(&doc)?;
- if let Some(msg) = msgs.iter().find(|m| m.date == date && m.text.text() == text) {
+ if let Some(msg) = msgs
+ .iter()
+ .find(|m| m.date == date && m.text.text() == text)
+ {
let msg_id = msg.id.context("msg id not found")?;
params.extend(vec![
("nc", nc_value.to_owned()),
@@ -1684,10 +2180,10 @@ impl ChatClient {
c.config.datetime_fmt = params.datetime_fmt.unwrap_or("%m-%d %H:%M:%S".to_owned());
c.config.members_tag = params.members_tag.unwrap_or("[M] ".to_owned());
c.config.keepalive_send_to = None;
- },
+ }
ClientType::Dan => {
c.config = LeChatPHPConfig::new_dans_chat_config();
- },
+ }
ClientType::BHC => {
c.config = LeChatPHPConfig::new_black_hat_chat_config();
}
@@ -1852,9 +2348,7 @@ fn ask_username(username: Option<String>) -> String {
}
fn ask_password(password: Option<String>) -> String {
- password.unwrap_or_else(|| {
- rpassword::prompt_password("Password: ").unwrap()
- })
+ password.unwrap_or_else(|| rpassword::prompt_password("Password: ").unwrap())
}
#[derive(Debug, Clone, PartialEq)]
@@ -1971,9 +2465,11 @@ fn main() -> anyhow::Result<()> {
let config = log4rs::config::Config::builder()
.appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile)))
- .build(log4rs::config::Root::builder()
- .appender("logfile")
- .build(LevelFilter::Error))?;
+ .build(
+ log4rs::config::Root::builder()
+ .appender("logfile")
+ .build(LevelFilter::Error),
+ )?;
log4rs::init_config(config)?;
@@ -2062,35 +2558,41 @@ fn get_message(root: &StyledText, members_tag: &str) -> Option<(String, Option<S
_ => return None,
};
return Some((from, None, msg));
- },
+ }
StyledText::Text(t) => {
if t == &members_tag {
let from = match children.get(children.len() - 2)? {
- StyledText::Styled(_, children) => match children.get(children.len() - 1)? {
- StyledText::Text(t) => t.to_owned(),
- _ => return None,
- },
+ StyledText::Styled(_, children) => {
+ match children.get(children.len() - 1)? {
+ StyledText::Text(t) => t.to_owned(),
+ _ => return None,
+ }
+ }
_ => return None,
};
return Some((from, None, msg));
} else if t == "[" {
let from = match children.get(children.len() - 2)? {
- StyledText::Styled(_, children) => match children.get(children.len() - 1)? {
- StyledText::Text(t) => t.to_owned(),
- _ => return None,
- },
+ StyledText::Styled(_, children) => {
+ match children.get(children.len() - 1)? {
+ StyledText::Text(t) => t.to_owned(),
+ _ => return None,
+ }
+ }
_ => return None,
};
let to = match children.get(2)? {
- StyledText::Styled(_, children) => match children.get(children.len() - 1)? {
- StyledText::Text(t) => Some(t.to_owned()),
- _ => return None,
- },
+ StyledText::Styled(_, children) => {
+ match children.get(children.len() - 1)? {
+ StyledText::Text(t) => Some(t.to_owned()),
+ _ => return None,
+ }
+ }
_ => return None,
};
return Some((from, to, msg));
}
- },
+ }
_ => return None,
}
}
@@ -2115,7 +2617,13 @@ struct Message {
}
impl Message {
- fn new(id: Option<usize>, typ: MessageType, date: String, upload_link: Option<String>, text: StyledText) -> Self {
+ fn new(
+ id: Option<usize>,
+ typ: MessageType,
+ date: String,
+ upload_link: Option<String>,
+ text: StyledText,
+ ) -> Self {
Self {
id,
typ,
@@ -2215,22 +2723,22 @@ fn process_node(e: select::node::Node, mut color: tuiColor) -> (StyledText, Opti
color = parse_color(color_match);
}
}
- },
+ }
Some("font") => {
if let Some(color_str) = e.attr("color") {
color = parse_color(color_str);
}
- },
+ }
Some("a") => {
color = tuiColor::White;
if let (Some("attachement"), Some(href)) = (e.attr("class"), e.attr("href")) {
upload_link = Some(href.to_owned());
}
- },
+ }
Some("style") => {
return (StyledText::None, None);
- },
- _ => {},
+ }
+ _ => {}
}
let mut children_texts: Vec<StyledText> = vec![];
let children = e.children();
@@ -2472,7 +2980,12 @@ fn render_long_message(f: &mut Frame<CrosstermBackend<io::Stdout>>, app: &mut Ap
}
}
-fn render_help_txt(f: &mut Frame<CrosstermBackend<io::Stdout>>, app: &mut App, r: Rect, curr_user: &str) {
+fn render_help_txt(
+ f: &mut Frame<CrosstermBackend<io::Stdout>>,
+ app: &mut App,
+ r: Rect,
+ curr_user: &str,
+) {
let (mut msg, style) = match app.input_mode {
InputMode::Normal => (
vec![
@@ -2620,9 +3133,13 @@ fn render_messages(
}
}
-
if app.filter != "" {
- if !m.text.text().to_lowercase().contains(&app.filter.to_lowercase()) {
+ if !m
+ .text
+ .text()
+ .to_lowercase()
+ .contains(&app.filter.to_lowercase())
+ {
return None;
}
}
@@ -2634,8 +3151,8 @@ fn render_messages(
let mut rows = vec![];
let date_style = match (m.deleted, m.hide) {
(false, true) => Style::default().fg(tuiColor::Gray),
- (false, _) => Style::default().fg(tuiColor::DarkGray),
- (true, _) => Style::default().fg(tuiColor::Red),
+ (false, _) => Style::default().fg(tuiColor::DarkGray),
+ (true, _) => Style::default().fg(tuiColor::Red),
};
let mut spans_vec = vec![Span::styled(m.date.clone(), date_style)];
let show_sys_sep = app.show_sys && m.typ == MessageType::SysMsg;
@@ -2661,7 +3178,7 @@ fn render_messages(
let style = match (m.deleted, m.hide) {
(true, _) => Style::default().bg(tuiColor::Rgb(30, 0, 0)),
(_, true) => Style::default().bg(tuiColor::Rgb(20, 20, 20)),
- _ => Style::default(),
+ _ => Style::default(),
};
Some(ListItem::new(rows).style(style))
})
@@ -2805,9 +3322,9 @@ impl Events {
if event::poll(timeout).unwrap() {
let evt = event::read().unwrap();
match evt {
- CEvent::FocusGained => {},
- CEvent::FocusLost => {},
- CEvent::Paste(_) => {},
+ CEvent::FocusGained => {}
+ CEvent::FocusLost => {}
+ CEvent::Paste(_) => {}
CEvent::Resize(_, _) => tx.send(Event::Input(evt)).unwrap(),
CEvent::Key(_) => tx.send(Event::Input(evt)).unwrap(),
CEvent::Mouse(mouse_event) => {