diff --git a/installer/src/main.rs b/installer/src/main.rs index de785b8..a975056 100644 --- a/installer/src/main.rs +++ b/installer/src/main.rs @@ -73,6 +73,16 @@ enum UtilSubCommand { WingtechStartTelnet(WingtechArgs), /// Root the Wingtech and launch adb. WingtechStartAdb(WingtechArgs), + /// Send a file to the TP-Link device over telnet. + /// + /// Before running this utility, you need to make telnet accessible with `installer util + /// tplink-start-telnet`. + TplinkSendFile(TplinkSendFile), + /// Send a file to the Wingtech device over telnet. + /// + /// Before running this utility, you need to make telnet accessible with `installer util + /// wingtech-start-telnet`. + WingtechSendFile(WingtechSendFile), } #[derive(Parser, Debug)] @@ -82,6 +92,28 @@ struct TplinkStartTelnet { admin_ip: String, } +#[derive(Parser, Debug)] +struct TplinkSendFile { + /// IP address for TP-Link admin interface, if custom. + #[arg(long, default_value = "192.168.0.1")] + admin_ip: String, + /// Local path to the file to send. + local_path: String, + /// Remote path where the file should be stored on the device. + remote_path: String, +} + +#[derive(Parser, Debug)] +struct WingtechSendFile { + /// IP address for Wingtech admin interface, if custom. + #[arg(long, default_value = "192.168.1.1")] + admin_ip: String, + /// Local path to the file to send. + local_path: String, + /// Remote path where the file should be stored on the device. + remote_path: String, +} + #[derive(Parser, Debug)] struct WingtechArgs { /// IP address for Wingtech admin interface, if custom. @@ -134,6 +166,12 @@ async fn run() -> Result<(), Error> { UtilSubCommand::TplinkStartTelnet(options) => { tplink::start_telnet(&options.admin_ip).await?; } + UtilSubCommand::TplinkSendFile(options) => { + util::send_file(&options.admin_ip, &options.local_path, &options.remote_path).await?; + } + UtilSubCommand::WingtechSendFile(options) => { + util::send_file(&options.admin_ip, &options.local_path, &options.remote_path).await?; + } UtilSubCommand::WingtechStartTelnet(args) => wingtech::start_telnet(&args.admin_ip, &args.admin_password).await.context("\nFailed to start telnet on the Wingtech CT2MHS01")?, UtilSubCommand::WingtechStartAdb(args) => wingtech::start_adb(&args.admin_ip, &args.admin_password).await.context("\nFailed to start adb on the Wingtech CT2MHS01")?, } diff --git a/installer/src/util.rs b/installer/src/util.rs index 1f7ce86..1974d90 100644 --- a/installer/src/util.rs +++ b/installer/src/util.rs @@ -1,8 +1,9 @@ use std::io::Write; use std::net::SocketAddr; +use std::str::FromStr; use std::time::Duration; -use anyhow::{Result, bail}; +use anyhow::{Context, Result, bail}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpStream; use tokio::time::{sleep, timeout}; @@ -88,3 +89,19 @@ pub async fn telnet_send_file(addr: SocketAddr, filename: &str, payload: &[u8]) println!("ok"); Ok(()) } + +pub async fn send_file(admin_ip: &str, local_path: &str, remote_path: &str) -> Result<()> { + let file_content = std::fs::read(local_path) + .with_context(|| format!("Failed to read local file: {}", local_path))?; + + println!("Connecting to {admin_ip}"); + let addr = SocketAddr::from_str(&format!("{admin_ip}:23")) + .with_context(|| format!("Invalid IP address: {}", admin_ip))?; + + telnet_send_file(addr, remote_path, &file_content) + .await + .with_context(|| format!("Failed to send file {} to {}", local_path, remote_path))?; + + println!("Successfully sent {} to {}", local_path, remote_path); + Ok(()) +}