#[macro_use]
extern crate log;
use clap::{Arg, ArgAction, Command};
use directip::mt::MTMessage;
use std::fs::File;
use std::io::{stdin, BufReader, Read, Write};
use std::net::TcpStream;
fn main() -> anyhow::Result<()> {
let cmd = Command::new("DIPCommand")
.author(clap::crate_authors!("\n"))
.version(clap::crate_version!())
.about("Send MT messges")
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.action(ArgAction::Count)
.help("Sets the level of verbosity"),
)
.arg(
Arg::new("dry_run")
.long("dry-run")
.action(ArgAction::SetTrue)
.help("Dump message instead of transmitting it"),
)
.arg(
Arg::new("server")
.long("server")
.required(true)
.takes_value(true)
.help("Destination server host"),
)
.arg(
Arg::new("imei")
.long("imei")
.required(true)
.takes_value(true)
.help("Target IMEI"),
)
.arg(
Arg::new("msg_id")
.long("msg-id")
.value_parser(clap::value_parser!(u32))
.takes_value(true)
.help("Unique client message id"),
)
.arg(
Arg::new("encoding")
.long("encoding")
.value_parser(["ascii", "hex", "binary"])
.default_value("ascii")
.help("Payload encoding"),
)
.arg(
Arg::new("from_file")
.long("from-file")
.action(ArgAction::SetTrue)
.help("Reads payload from a file"),
)
.arg(Arg::new("payload").takes_value(true).help("Payload"))
.after_help(
"Longer explanation to appear after the options when \
displaying the help information from --help or -h",
);
let matches = cmd.get_matches();
let server = matches.get_one::<String>("server").unwrap();
let msg_id = *matches.get_one::<u32>("msg_id").unwrap();
let imei = matches.get_one::<String>("imei").unwrap();
let encoding: &String = matches.get_one("encoding").expect("default");
let from_file = matches.get_one::<bool>("from_file").unwrap_or(&false);
let dry_run = matches.get_one::<bool>("dry_run").unwrap_or(&false);
let payload: Vec<u8> = match matches.get_one::<String>("payload") {
Some(p) => p.clone().into_bytes(),
None => {
let mut buffer = vec![];
let mut stdin = stdin();
stdin.read_to_end(&mut buffer)?;
buffer
}
};
let payload: Vec<u8> = if *from_file {
let path = String::from_utf8(payload).unwrap();
let mut reader = BufReader::new(File::open(path)?);
if matches!(encoding.as_ref(), "binary") {
let mut s = vec![];
reader.read_to_end(&mut s)?;
s
} else {
let mut s = String::new();
reader.read_to_string(&mut s)?;
s.trim_end().into()
}
} else {
payload
};
debug!("Composing MT-Message");
let msg = MTMessage::builder()
.client_msg_id(msg_id)
.imei(imei.as_bytes().try_into().unwrap())
.payload(payload)
.build();
debug!("Composed message: {:?}", msg);
debug!("MTMessage stream: {:02x?}", msg);
if *dry_run {
dbg!(msg);
} else {
debug!("Connecting");
let mut stream = TcpStream::connect(server).unwrap();
debug!("Transmitting");
let n = stream.write(msg.to_vec().as_slice()).unwrap();
info!("Transmitted {} bytes", n);
let mut buffer = [0u8; 56];
let n = stream.read(&mut buffer).unwrap();
info!("Confirmation: {:02x?}", &buffer[..n]);
let response = MTMessage::from_reader(buffer.as_slice())
.expect("Gateway response is not a valid MT-Message");
info!("{}", response.confirmation_message().unwrap());
}
Ok(())
}
#[cfg(test)]
mod test {
use super::MTMessage;
#[test]
fn tmp() {
let msg = MTMessage::builder()
.client_msg_id(999)
.imei([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
.payload("Hello".into())
.build()
.to_vec();
dbg!(msg);
}
}