mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
commit6bc5d1b90eAuthor: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:56:37 2019 +0200 fix fmt commit197d94ad9dMerge:7ce337c686678cAuthor: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:51:16 2019 +0200 Merge remote-tracking branch 'origin/master' into eventlogging commit7ce337c6d0Author: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:44:27 2019 +0200 left-over error logging commit10148d2e43Author: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:03:17 2019 +0200 ignore non-utf8 parts of header fields (add comment why it shouldn't happen) don't throw error if no sql rows are returned commit69dc237ee3Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sun Jul 21 12:56:04 2019 +0200 fix(receive_imf): remove recursive sql call commitdf5464ea80Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 17:05:24 2019 +0200 fix: blocked is an optional value commite4bf9956a5Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 16:50:56 2019 +0200 fix(msg): handle optional in_reply_to commitd353d9d9d8Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 16:17:25 2019 +0200 fix(chat): remove recursive sql usage commit1ad45ed4d6Author: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 15:14:11 2019 +0200 fix rust fmt commit496e980a17Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 14:34:20 2019 +0200 use forked rusqlite commitfa09e46ed9Author: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 12:37:51 2019 +0200 another pace where we might (and in my case did) get invalid utf8 commitd6de420b9aAuthor: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 12:30:48 2019 +0200 fix some string issues, introduce to_string_lossy such that to_string() continues to panic on non-utf8 commit38eb708db8Author: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 01:17:53 2019 +0200 for now make to_string() less strict as we often don't want to crash the whole app just because some non-proper utf8 came in (through a message we can't neccesarily congtrol) commit7a59da5f8fAuthor: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 22:48:39 2019 +0200 fix linting commitf13a1d4a2fAuthor: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 22:46:58 2019 +0200 fix some test flakyness commit7b3a450918Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 22:35:07 2019 +0200 - fix saved_mime test which broke to improper conversion of imf_raw_not_terminated - some cargo.toml updates no clue where they come from - log Message-ID for received messages commit169923b102Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 12:31:22 2019 +0200 formatting commit42688a0622Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 12:24:56 2019 +0200 remove some print statements commit35f3c0edd1Merge:e7a2362f58b1d6Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 10:25:21 2019 +0200 Merge branch 'master' into eventlogging commite7a236264aAuthor: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 23:20:20 2019 +0200 print invalid strings commitaaa5b820d9Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 23:12:35 2019 +0200 cleanup commite7f0745010Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 23:03:57 2019 +0200 reduce direc usage of CString commitc68e7ae14eAuthor: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 22:47:47 2019 +0200 audit use of to_cstring and fix ub commit618087e5a7Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 21:38:52 2019 +0200 fix(imap): body ptr lifetime commit245abb8384Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 19:44:10 2019 +0200 remove debug commita3e1042001Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 18:30:54 2019 +0200 fix some things, add more debugging statements commit7b7ce9348fAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 15:11:57 2019 +0200 fix python lint issues commit7a4808ba0dAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 14:35:54 2019 +0200 cargofmt commit8f240f7153Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 14:03:57 2019 +0200 (dig,hpk) pull out job collection from sql query/lock logic commit7d0b5d8abbAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 12:52:02 2019 +0200 remove print statements and fix a crash commitee317cb1b5Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 11:38:10 2019 +0200 fix some merge issues commit7b736fe635Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 11:16:38 2019 +0200 (dig,hpk) add test and fix for wrong dbs commitc7db15352aMerge:0b371670c5015dAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 09:59:44 2019 +0200 Merge branch 'master' into eventlogging commit0b37167be8Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 00:06:05 2019 +0200 address @dignifiedquire comments commit5cac4b5076Author: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 12:47:22 2019 +0200 remove spurious print commit475a41beb3Author: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 12:31:12 2019 +0200 address @dignifiedquire rustyness comment and fix changelog commitad4be80b4eAuthor: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 10:25:25 2019 +0200 make smtp/imap connect() return bool instead of c-int commit8737c1d142Author: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 09:26:33 2019 +0200 cleanup some parts, add comments commit964fe466ccAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 20:05:41 2019 +0200 wip-commit which passes all tests with proper finalization commit43936e7db7Author: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 16:17:42 2019 +0200 snapshot of my current debugging state commit0e80ce9c39Author: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 12:57:19 2019 +0200 more aggressively skip perform API when threads are closing commitc652bae68aAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 12:06:05 2019 +0200 intermediate wip commit commitbc904a495dAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 11:18:56 2019 +0200 add some logging, and a more precise teardown for online python tests commit8d99444c6aAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 00:22:12 2019 +0200 fix std commit9dab53e0afAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 00:20:54 2019 +0200 rustfmt commit360089ac74Author: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 00:03:49 2019 +0200 remove some debugging commite892c5cf4dAuthor: holger krekel <holger@merlinux.eu> Date: Mon Jul 15 23:31:30 2019 +0200 fix test for events commit9ad4c9a6feAuthor: holger krekel <holger@merlinux.eu> Date: Mon Jul 15 22:51:57 2019 +0200 wip try test that we see INFO events from the core
580 lines
16 KiB
Rust
580 lines
16 KiB
Rust
//! This is a CLI program and a little testing frame. This file must not be
|
|
//! included when using Delta Chat Core as a library.
|
|
//!
|
|
//! Usage: cargo run --example repl --release -- <databasefile>
|
|
//! All further options can be set using the set-command (type ? for help).
|
|
|
|
#[macro_use]
|
|
extern crate deltachat;
|
|
#[macro_use]
|
|
extern crate failure;
|
|
#[macro_use]
|
|
extern crate lazy_static;
|
|
#[macro_use]
|
|
extern crate rusqlite;
|
|
|
|
use std::borrow::Cow::{self, Borrowed, Owned};
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
use std::sync::{Arc, Mutex, RwLock};
|
|
|
|
use deltachat::config;
|
|
use deltachat::constants::*;
|
|
use deltachat::context::*;
|
|
use deltachat::dc_configure::*;
|
|
use deltachat::dc_job::*;
|
|
use deltachat::dc_securejoin::*;
|
|
use deltachat::dc_tools::*;
|
|
use deltachat::oauth2::*;
|
|
use deltachat::types::*;
|
|
use deltachat::x::*;
|
|
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
|
use rustyline::config::OutputStreamType;
|
|
use rustyline::error::ReadlineError;
|
|
use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
|
|
use rustyline::hint::{Hinter, HistoryHinter};
|
|
use rustyline::{
|
|
Cmd, CompletionType, Config, Context as RustyContext, EditMode, Editor, Helper, KeyPress,
|
|
};
|
|
|
|
mod cmdline;
|
|
use self::cmdline::*;
|
|
|
|
// Event Handler
|
|
|
|
unsafe extern "C" fn receive_event(
|
|
_context: &Context,
|
|
event: Event,
|
|
data1: uintptr_t,
|
|
data2: uintptr_t,
|
|
) -> uintptr_t {
|
|
match event {
|
|
Event::GET_STRING => {}
|
|
Event::INFO => {
|
|
/* do not show the event as this would fill the screen */
|
|
println!("{}", to_string(data2 as *const _),);
|
|
}
|
|
Event::SMTP_CONNECTED => {
|
|
println!("[DC_EVENT_SMTP_CONNECTED] {}", to_string(data2 as *const _));
|
|
}
|
|
Event::IMAP_CONNECTED => {
|
|
println!("[DC_EVENT_IMAP_CONNECTED] {}", to_string(data2 as *const _),);
|
|
}
|
|
Event::SMTP_MESSAGE_SENT => {
|
|
println!(
|
|
"[DC_EVENT_SMTP_MESSAGE_SENT] {}",
|
|
to_string(data2 as *const _),
|
|
);
|
|
}
|
|
Event::WARNING => {
|
|
println!("[Warning] {}", to_string(data2 as *const _),);
|
|
}
|
|
Event::ERROR => {
|
|
println!(
|
|
"\x1b[31m[DC_EVENT_ERROR] {}\x1b[0m",
|
|
to_string(data2 as *const _),
|
|
);
|
|
}
|
|
Event::ERROR_NETWORK => {
|
|
println!(
|
|
"\x1b[31m[DC_EVENT_ERROR_NETWORK] first={}, msg={}\x1b[0m",
|
|
data1 as usize,
|
|
to_string(data2 as *const _),
|
|
);
|
|
}
|
|
Event::ERROR_SELF_NOT_IN_GROUP => {
|
|
println!(
|
|
"\x1b[31m[DC_EVENT_ERROR_SELF_NOT_IN_GROUP] {}\x1b[0m",
|
|
to_string(data2 as *const _),
|
|
);
|
|
}
|
|
Event::MSGS_CHANGED => {
|
|
print!(
|
|
"\x1b[33m{{Received DC_EVENT_MSGS_CHANGED({}, {})}}\n\x1b[0m",
|
|
data1 as usize, data2 as usize,
|
|
);
|
|
}
|
|
Event::CONTACTS_CHANGED => {
|
|
print!("\x1b[33m{{Received DC_EVENT_CONTACTS_CHANGED()}}\n\x1b[0m");
|
|
}
|
|
Event::LOCATION_CHANGED => {
|
|
print!(
|
|
"\x1b[33m{{Received DC_EVENT_LOCATION_CHANGED(contact={})}}\n\x1b[0m",
|
|
data1 as usize,
|
|
);
|
|
}
|
|
Event::CONFIGURE_PROGRESS => {
|
|
print!(
|
|
"\x1b[33m{{Received DC_EVENT_CONFIGURE_PROGRESS({} ‰)}}\n\x1b[0m",
|
|
data1 as usize,
|
|
);
|
|
}
|
|
Event::IMEX_PROGRESS => {
|
|
print!(
|
|
"\x1b[33m{{Received DC_EVENT_IMEX_PROGRESS({} ‰)}}\n\x1b[0m",
|
|
data1 as usize,
|
|
);
|
|
}
|
|
Event::IMEX_FILE_WRITTEN => {
|
|
print!(
|
|
"\x1b[33m{{Received DC_EVENT_IMEX_FILE_WRITTEN({})}}\n\x1b[0m",
|
|
to_string(data1 as *const _)
|
|
);
|
|
}
|
|
Event::CHAT_MODIFIED => {
|
|
print!(
|
|
"\x1b[33m{{Received DC_EVENT_CHAT_MODIFIED({})}}\n\x1b[0m",
|
|
data1 as usize,
|
|
);
|
|
}
|
|
_ => {
|
|
print!(
|
|
"\x1b[33m{{Received {:?}({}, {})}}\n\x1b[0m",
|
|
event, data1 as usize, data2 as usize,
|
|
);
|
|
}
|
|
}
|
|
|
|
0
|
|
}
|
|
|
|
// Threads for waiting for messages and for jobs
|
|
|
|
lazy_static! {
|
|
static ref HANDLE: Arc<Mutex<Option<Handle>>> = Arc::new(Mutex::new(None));
|
|
static ref IS_RUNNING: AtomicBool = AtomicBool::new(true);
|
|
}
|
|
|
|
struct Handle {
|
|
handle_imap: Option<std::thread::JoinHandle<()>>,
|
|
handle_mvbox: Option<std::thread::JoinHandle<()>>,
|
|
handle_sentbox: Option<std::thread::JoinHandle<()>>,
|
|
handle_smtp: Option<std::thread::JoinHandle<()>>,
|
|
}
|
|
|
|
macro_rules! while_running {
|
|
($code:block) => {
|
|
if IS_RUNNING.load(Ordering::Relaxed) {
|
|
$code
|
|
} else {
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
|
|
fn start_threads(c: Arc<RwLock<Context>>) {
|
|
if HANDLE.clone().lock().unwrap().is_some() {
|
|
return;
|
|
}
|
|
|
|
println!("Starting threads");
|
|
IS_RUNNING.store(true, Ordering::Relaxed);
|
|
|
|
let ctx = c.clone();
|
|
let handle_imap = std::thread::spawn(move || loop {
|
|
while_running!({
|
|
unsafe {
|
|
dc_perform_imap_jobs(&ctx.read().unwrap());
|
|
dc_perform_imap_fetch(&ctx.read().unwrap());
|
|
}
|
|
while_running!({
|
|
let context = ctx.read().unwrap();
|
|
dc_perform_imap_idle(&context);
|
|
});
|
|
});
|
|
});
|
|
|
|
let ctx = c.clone();
|
|
let handle_mvbox = std::thread::spawn(move || loop {
|
|
while_running!({
|
|
unsafe { dc_perform_mvbox_fetch(&ctx.read().unwrap()) };
|
|
while_running!({
|
|
unsafe { dc_perform_mvbox_idle(&ctx.read().unwrap()) };
|
|
});
|
|
});
|
|
});
|
|
|
|
let ctx = c.clone();
|
|
let handle_sentbox = std::thread::spawn(move || loop {
|
|
while_running!({
|
|
unsafe { dc_perform_sentbox_fetch(&ctx.read().unwrap()) };
|
|
while_running!({
|
|
unsafe { dc_perform_sentbox_idle(&ctx.read().unwrap()) };
|
|
});
|
|
});
|
|
});
|
|
|
|
let ctx = c;
|
|
let handle_smtp = std::thread::spawn(move || loop {
|
|
while_running!({
|
|
unsafe { dc_perform_smtp_jobs(&ctx.read().unwrap()) };
|
|
while_running!({
|
|
unsafe { dc_perform_smtp_idle(&ctx.read().unwrap()) };
|
|
});
|
|
});
|
|
});
|
|
|
|
*HANDLE.clone().lock().unwrap() = Some(Handle {
|
|
handle_imap: Some(handle_imap),
|
|
handle_mvbox: Some(handle_mvbox),
|
|
handle_sentbox: Some(handle_sentbox),
|
|
handle_smtp: Some(handle_smtp),
|
|
});
|
|
}
|
|
|
|
fn stop_threads(context: &Context) {
|
|
if let Some(ref mut handle) = *HANDLE.clone().lock().unwrap() {
|
|
println!("Stopping threads");
|
|
IS_RUNNING.store(false, Ordering::Relaxed);
|
|
|
|
unsafe {
|
|
dc_interrupt_imap_idle(context);
|
|
dc_interrupt_mvbox_idle(context);
|
|
dc_interrupt_sentbox_idle(context);
|
|
dc_interrupt_smtp_idle(context);
|
|
}
|
|
|
|
handle.handle_imap.take().unwrap().join().unwrap();
|
|
handle.handle_mvbox.take().unwrap().join().unwrap();
|
|
handle.handle_sentbox.take().unwrap().join().unwrap();
|
|
handle.handle_smtp.take().unwrap().join().unwrap();
|
|
}
|
|
}
|
|
|
|
// === The main loop
|
|
|
|
struct DcHelper {
|
|
completer: FilenameCompleter,
|
|
highlighter: MatchingBracketHighlighter,
|
|
hinter: HistoryHinter,
|
|
}
|
|
|
|
impl Completer for DcHelper {
|
|
type Candidate = Pair;
|
|
|
|
fn complete(
|
|
&self,
|
|
line: &str,
|
|
pos: usize,
|
|
ctx: &RustyContext<'_>,
|
|
) -> Result<(usize, Vec<Pair>), ReadlineError> {
|
|
self.completer.complete(line, pos, ctx)
|
|
}
|
|
}
|
|
|
|
const IMEX_COMMANDS: [&'static str; 12] = [
|
|
"initiate-key-transfer",
|
|
"get-setupcodebegin",
|
|
"continue-key-transfer",
|
|
"has-backup",
|
|
"export-backup",
|
|
"import-backup",
|
|
"export-keys",
|
|
"import-keys",
|
|
"export-setup",
|
|
"poke",
|
|
"reset",
|
|
"stop",
|
|
];
|
|
|
|
const DB_COMMANDS: [&'static str; 11] = [
|
|
"info",
|
|
"open",
|
|
"close",
|
|
"set",
|
|
"get",
|
|
"oauth2",
|
|
"configure",
|
|
"connect",
|
|
"disconnect",
|
|
"maybenetwork",
|
|
"housekeeping",
|
|
];
|
|
|
|
const CHAT_COMMANDS: [&'static str; 24] = [
|
|
"listchats",
|
|
"listarchived",
|
|
"chat",
|
|
"createchat",
|
|
"createchatbymsg",
|
|
"creategroup",
|
|
"createverified",
|
|
"addmember",
|
|
"removemember",
|
|
"groupname",
|
|
"groupimage",
|
|
"chatinfo",
|
|
"sendlocations",
|
|
"setlocation",
|
|
"dellocations",
|
|
"getlocations",
|
|
"send",
|
|
"sendimage",
|
|
"sendfile",
|
|
"draft",
|
|
"listmedia",
|
|
"archive",
|
|
"unarchive",
|
|
"delchat",
|
|
];
|
|
const MESSAGE_COMMANDS: [&'static str; 8] = [
|
|
"listmsgs",
|
|
"msginfo",
|
|
"listfresh",
|
|
"forward",
|
|
"markseen",
|
|
"star",
|
|
"unstar",
|
|
"delmsg",
|
|
];
|
|
const CONTACT_COMMANDS: [&'static str; 6] = [
|
|
"listcontacts",
|
|
"listverified",
|
|
"addcontact",
|
|
"contactinfo",
|
|
"delcontact",
|
|
"cleanupcontacts",
|
|
];
|
|
const MISC_COMMANDS: [&'static str; 8] = [
|
|
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "help",
|
|
];
|
|
|
|
impl Hinter for DcHelper {
|
|
fn hint(&self, line: &str, pos: usize, ctx: &RustyContext<'_>) -> Option<String> {
|
|
if !line.is_empty() {
|
|
for &cmds in &[
|
|
&IMEX_COMMANDS[..],
|
|
&DB_COMMANDS[..],
|
|
&CHAT_COMMANDS[..],
|
|
&MESSAGE_COMMANDS[..],
|
|
&CONTACT_COMMANDS[..],
|
|
&MISC_COMMANDS[..],
|
|
] {
|
|
if let Some(entry) = cmds.iter().find(|el| el.starts_with(&line[..pos])) {
|
|
if *entry != line && *entry != &line[..pos] {
|
|
return Some(entry[pos..].to_owned());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
self.hinter.hint(line, pos, ctx)
|
|
}
|
|
}
|
|
|
|
static COLORED_PROMPT: &'static str = "\x1b[1;32m> \x1b[0m";
|
|
static PROMPT: &'static str = "> ";
|
|
|
|
impl Highlighter for DcHelper {
|
|
fn highlight_prompt<'p>(&self, prompt: &'p str) -> Cow<'p, str> {
|
|
if prompt == PROMPT {
|
|
Borrowed(COLORED_PROMPT)
|
|
} else {
|
|
Borrowed(prompt)
|
|
}
|
|
}
|
|
|
|
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
|
Owned("\x1b[1m".to_owned() + hint + "\x1b[m")
|
|
}
|
|
|
|
fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
|
|
self.highlighter.highlight(line, pos)
|
|
}
|
|
|
|
fn highlight_char(&self, line: &str, pos: usize) -> bool {
|
|
self.highlighter.highlight_char(line, pos)
|
|
}
|
|
}
|
|
|
|
impl Helper for DcHelper {}
|
|
|
|
fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
|
let mut context = dc_context_new(
|
|
Some(receive_event),
|
|
0 as *mut libc::c_void,
|
|
b"CLI\x00" as *const u8 as *const libc::c_char,
|
|
);
|
|
|
|
unsafe { dc_cmdline_skip_auth() };
|
|
|
|
if args.len() == 2 {
|
|
if 0 == unsafe {
|
|
let a = to_cstring(&args[1]);
|
|
let res = dc_open(&mut context, a, 0 as *const _);
|
|
free(a as *mut _);
|
|
res
|
|
} {
|
|
println!("Error: Cannot open {}.", args[0],);
|
|
}
|
|
} else if args.len() != 1 {
|
|
println!("Error: Bad arguments, expected [db-name].");
|
|
}
|
|
|
|
println!("Delta Chat Core is awaiting your commands.");
|
|
|
|
let ctx = Arc::new(RwLock::new(context));
|
|
|
|
let config = Config::builder()
|
|
.history_ignore_space(true)
|
|
.completion_type(CompletionType::List)
|
|
.edit_mode(EditMode::Emacs)
|
|
.output_stream(OutputStreamType::Stdout)
|
|
.build();
|
|
let h = DcHelper {
|
|
completer: FilenameCompleter::new(),
|
|
highlighter: MatchingBracketHighlighter::new(),
|
|
hinter: HistoryHinter {},
|
|
};
|
|
let mut rl = Editor::with_config(config);
|
|
rl.set_helper(Some(h));
|
|
rl.bind_sequence(KeyPress::Meta('N'), Cmd::HistorySearchForward);
|
|
rl.bind_sequence(KeyPress::Meta('P'), Cmd::HistorySearchBackward);
|
|
if rl.load_history(".dc-history.txt").is_err() {
|
|
println!("No previous history.");
|
|
}
|
|
|
|
loop {
|
|
let p = "> ";
|
|
let readline = rl.readline(&p);
|
|
match readline {
|
|
Ok(line) => {
|
|
// TODO: ignore "set mail_pw"
|
|
rl.add_history_entry(line.as_str());
|
|
let ctx = ctx.clone();
|
|
match unsafe { handle_cmd(line.trim(), ctx) } {
|
|
Ok(ExitResult::Continue) => {}
|
|
Ok(ExitResult::Exit) => break,
|
|
Err(err) => println!("Error: {}", err),
|
|
}
|
|
}
|
|
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
|
|
println!("Exiting...");
|
|
break;
|
|
}
|
|
Err(err) => {
|
|
println!("Error: {}", err);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
rl.save_history(".dc-history.txt")?;
|
|
println!("history saved");
|
|
{
|
|
stop_threads(&ctx.read().unwrap());
|
|
|
|
unsafe {
|
|
let mut ctx = ctx.write().unwrap();
|
|
dc_close(&mut ctx);
|
|
dc_context_unref(&mut ctx);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum ExitResult {
|
|
Continue,
|
|
Exit,
|
|
}
|
|
|
|
unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult, failure::Error> {
|
|
let mut args = line.splitn(2, ' ');
|
|
let arg0 = args.next().unwrap_or_default();
|
|
let arg1 = args.next().unwrap_or_default();
|
|
let arg1_c = if arg1.is_empty() {
|
|
std::ptr::null()
|
|
} else {
|
|
to_cstring(arg1)
|
|
};
|
|
|
|
match arg0 {
|
|
"connect" => {
|
|
start_threads(ctx);
|
|
}
|
|
"disconnect" => {
|
|
stop_threads(&ctx.read().unwrap());
|
|
}
|
|
"smtp-jobs" => {
|
|
if HANDLE.clone().lock().unwrap().is_some() {
|
|
println!("smtp-jobs are already running in a thread.",);
|
|
} else {
|
|
dc_perform_smtp_jobs(&ctx.read().unwrap());
|
|
}
|
|
}
|
|
"imap-jobs" => {
|
|
if HANDLE.clone().lock().unwrap().is_some() {
|
|
println!("imap-jobs are already running in a thread.");
|
|
} else {
|
|
dc_perform_imap_jobs(&ctx.read().unwrap());
|
|
}
|
|
}
|
|
"configure" => {
|
|
start_threads(ctx.clone());
|
|
dc_configure(&ctx.read().unwrap());
|
|
}
|
|
"oauth2" => {
|
|
if let Some(addr) = ctx.read().unwrap().get_config(config::Config::Addr) {
|
|
let oauth2_url = dc_get_oauth2_url(
|
|
&ctx.read().unwrap(),
|
|
&addr,
|
|
"chat.delta:/com.b44t.messenger",
|
|
);
|
|
if oauth2_url.is_none() {
|
|
println!("OAuth2 not available for {}.", &addr);
|
|
} else {
|
|
println!("Open the following url, set mail_pw to the generated token and server_flags to 2:\n{}", oauth2_url.unwrap());
|
|
}
|
|
} else {
|
|
println!("oauth2: set addr first.");
|
|
}
|
|
}
|
|
"clear" => {
|
|
println!("\n\n\n");
|
|
print!("\x1b[1;1H\x1b[2J");
|
|
}
|
|
"getqr" | "getbadqr" => {
|
|
start_threads(ctx.clone());
|
|
let qrstr =
|
|
dc_get_securejoin_qr(&ctx.read().unwrap(), arg1.parse().unwrap_or_default());
|
|
if !qrstr.is_null() && 0 != *qrstr.offset(0isize) as libc::c_int {
|
|
if arg0 == "getbadqr" && strlen(qrstr) > 40 {
|
|
let mut i: libc::c_int = 12i32;
|
|
while i < 22i32 {
|
|
*qrstr.offset(i as isize) = '0' as i32 as libc::c_char;
|
|
i += 1
|
|
}
|
|
}
|
|
println!("{}", to_string(qrstr as *const _));
|
|
let syscmd = dc_mprintf(
|
|
b"qrencode -t ansiutf8 \"%s\" -o -\x00" as *const u8 as *const libc::c_char,
|
|
qrstr,
|
|
);
|
|
system(syscmd);
|
|
free(syscmd as *mut libc::c_void);
|
|
}
|
|
free(qrstr as *mut libc::c_void);
|
|
}
|
|
"joinqr" => {
|
|
start_threads(ctx.clone());
|
|
if !arg0.is_empty() {
|
|
dc_join_securejoin(&ctx.read().unwrap(), arg1_c);
|
|
}
|
|
}
|
|
"exit" => return Ok(ExitResult::Exit),
|
|
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
|
}
|
|
|
|
free(arg1_c as *mut _);
|
|
|
|
Ok(ExitResult::Continue)
|
|
}
|
|
|
|
pub fn main() -> Result<(), failure::Error> {
|
|
let _ = pretty_env_logger::try_init();
|
|
|
|
let args: Vec<String> = std::env::args().collect();
|
|
main_0(args)?;
|
|
|
|
Ok(())
|
|
}
|