mod activity_manager;
mod cli;
mod config;
mod explorer;
mod filetransfer;
mod host;
mod support;
mod system;
mod ui;
mod utils;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_regex;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate magic_crypt;
use std::env;
use std::path::Path;
use std::time::Duration;
use self::activity_manager::{ActivityManager, NextActivity};
use self::cli::{Args, ArgsSubcommands, RemoteArgs, RunOpts, Task};
use self::system::logging::{self, LogLevel};
const APP_NAME: &str = env!("CARGO_PKG_NAME");
const APP_BUILD_DATE: &str = env!("VERGEN_BUILD_TIMESTAMP");
const APP_GIT_BRANCH: &str = env!("VERGEN_GIT_BRANCH");
const APP_GIT_HASH: &str = env!("VERGEN_GIT_SHA");
const TERMSCP_VERSION: &str = env!("CARGO_PKG_VERSION");
const TERMSCP_AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
type MainResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
#[inline]
fn git_hash() -> &'static str {
APP_GIT_HASH[0..8].as_ref()
}
fn main() -> MainResult<()> {
let args: Args = argh::from_env();
let run_opts: RunOpts = match parse_args(args) {
Ok(opts) => opts,
Err(err) => {
eprintln!("{err}");
return Err(err.into());
}
};
if let Err(err) = logging::init(run_opts.log_level) {
eprintln!("Failed to initialize logging: {err}");
}
info!(
"{APP_NAME} v{TERMSCP_VERSION} ({APP_GIT_BRANCH}, {git_hash}, {APP_BUILD_DATE}) - Developed by {TERMSCP_AUTHORS}",
git_hash = git_hash()
);
info!("Starting activity manager...");
run(run_opts)
}
fn parse_args(args: Args) -> Result<RunOpts, String> {
let run_opts = match args.nested {
Some(ArgsSubcommands::Update(_)) => RunOpts::update(),
Some(ArgsSubcommands::LoadTheme(args)) => RunOpts::import_theme(args.theme),
Some(ArgsSubcommands::Config(_)) => RunOpts::config(),
None => {
let mut run_opts: RunOpts = RunOpts::default();
if args.version {
run_opts.task = Task::Version;
return Ok(run_opts);
}
if args.debug {
run_opts.log_level = LogLevel::Trace;
} else if args.quiet {
run_opts.log_level = LogLevel::Off;
}
if args.wno_keyring {
run_opts.keyring = false;
}
run_opts.ticks = Duration::from_millis(args.ticks);
match RemoteArgs::try_from(&args) {
Err(err) => return Err(err),
Ok(remote) => {
run_opts.remote = remote;
}
}
run_opts.task = if run_opts.remote.remote.is_none() {
Task::Activity(NextActivity::Authentication)
} else {
Task::Activity(NextActivity::FileTransfer)
};
if let Some(localdir) = run_opts.remote.local_dir.as_deref() {
if let Err(err) = env::set_current_dir(localdir) {
return Err(format!("Bad working directory argument: {err}"));
}
}
run_opts
}
};
Ok(run_opts)
}
fn run(run_opts: RunOpts) -> MainResult<()> {
match run_opts.task {
Task::ImportTheme(theme) => run_import_theme(&theme),
Task::InstallUpdate => run_install_update(),
Task::Activity(activity) => {
run_activity(activity, run_opts.ticks, run_opts.remote, run_opts.keyring)
}
Task::Version => print_version(),
}
}
fn print_version() -> MainResult<()> {
println!(
"{APP_NAME} v{TERMSCP_VERSION} ({APP_GIT_BRANCH}, {git_hash}, {APP_BUILD_DATE}) - Developed by {TERMSCP_AUTHORS}",
git_hash = git_hash()
);
Ok(())
}
fn run_import_theme(theme: &Path) -> MainResult<()> {
match support::import_theme(theme) {
Ok(_) => {
println!("Theme has been successfully imported!");
Ok(())
}
Err(err) => {
eprintln!("{err}");
Err(err.into())
}
}
}
fn run_install_update() -> MainResult<()> {
match support::install_update() {
Ok(msg) => {
println!("{msg}");
Ok(())
}
Err(err) => {
eprintln!("Could not install update: {err}");
Err(err.into())
}
}
}
fn run_activity(
activity: NextActivity,
ticks: Duration,
remote_args: RemoteArgs,
keyring: bool,
) -> MainResult<()> {
let mut manager: ActivityManager = match ActivityManager::new(ticks, keyring) {
Ok(m) => m,
Err(err) => {
eprintln!("Could not start activity manager: {err}");
return Err(err.into());
}
};
if let Err(err) = manager.configure_remote_args(remote_args) {
eprintln!("{err}");
return Err(err.into());
}
manager.run(activity);
Ok(())
}