use std::io::Error;
use voip_ms::{Client, GetDIDsInfoParams, GetDIDsInfoResponse, SendSMSParams, SendSMSResponse};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
if dry_run_enabled("VOIP_MS_DRY_RUN") {
println!("dry run enabled via VOIP_MS_DRY_RUN=true; skipping API calls and SMS send");
return Ok(());
}
let (username, password) = credentials()?;
let from = std::env::var("VOIP_MS_FROM_DID").map_err(|_| "VOIP_MS_FROM_DID is not set")?;
let to = std::env::var("VOIP_MS_TO").map_err(|_| "VOIP_MS_TO is not set")?;
let message = message()?;
let client = Client::new(username, password);
let dids_response: GetDIDsInfoResponse = client
.get_dids_info(&GetDIDsInfoParams {
did: Some(from.clone()),
..Default::default()
})
.await?;
let did = dids_response
.dids
.unwrap_or_default()
.into_iter()
.find(|did| did.did.as_deref() == Some(from.as_str()))
.ok_or_else(|| Error::other(format!("DID {from} was not found on this account")))?;
if !did.sms_available.unwrap_or(false) {
return Err(Error::other(format!("DID {from} does not have SMS available")).into());
}
if !did.sms_enabled.unwrap_or(false) {
return Err(Error::other(format!(
"SMS is not enabled for DID {from}; enable SMS in voip.ms before running this example"
))
.into());
}
let response: SendSMSResponse = client
.send_sms(&SendSMSParams {
did: Some(from),
dst: Some(to),
message: Some(message),
})
.await?;
println!(
"status: {}",
response.status.as_deref().unwrap_or("(missing)")
);
Ok(())
}
fn credentials() -> Result<(String, String), &'static str> {
let username = std::env::var("VOIP_MS_USERNAME").map_err(|_| "VOIP_MS_USERNAME is not set")?;
let password = std::env::var("VOIP_MS_PASSWORD").map_err(|_| "VOIP_MS_PASSWORD is not set")?;
Ok((username, password))
}
fn message() -> Result<String, &'static str> {
if let Ok(message) = std::env::var("VOIP_MS_MESSAGE")
&& !message.trim().is_empty()
{
return Ok(message);
}
std::env::args()
.nth(1)
.ok_or("set VOIP_MS_MESSAGE or pass the message body as the first argument")
}
fn dry_run_enabled(name: &str) -> bool {
std::env::var(name)
.ok()
.map(|value| {
matches!(
value.trim().to_ascii_lowercase().as_str(),
"1" | "true" | "yes" | "y" | "on"
)
})
.unwrap_or(false)
}