use crate::lang; use crate::Data; use crate::error::{Error, Result}; type Context<'a> = poise::Context<'a, Data, Error>; /// Evaluate a math expression via qalc #[poise::command(slash_command)] pub async fn math( ctx: Context<'_>, #[description = "Ekspresja matematyczn"] equation: String, ) -> Result<()> { if equation.len() > 1000 { ctx.say(lang::L_MATH_TOO_LONG).await?; return Ok(()); } if !equation.is_ascii() { ctx.say(lang::L_MATH_NOT_ASCII).await?; return Ok(()); } let mut depth = 0i32; for c in equation.chars() { match c { '(' | '[' | '{' => depth += 1, ')' | ']' | '}' => depth -= 1, _ => {} } if depth < 0 { ctx.say(lang::L_MATH_UNBALANCED).await?; return Ok(()); } } if depth != 0 { ctx.say(lang::L_MATH_UNBALANCED).await?; return Ok(()); } let dangerous = [ "eval", "exec", "os.", "subprocess", "import", "__", "system", "shutil", "typecast", "shell", "fork", "execve", ]; let lower = equation.to_lowercase(); if dangerous.iter().any(|d| lower.contains(d)) { ctx.say(lang::L_MATH_DANGEROUS).await?; return Ok(()); } let output = match tokio::time::timeout( std::time::Duration::from_secs(5), tokio::process::Command::new("qalc") .arg(&equation) .output(), ) .await { Ok(result) => result.map_err(|e| Error::Custom(lang::fmt_math_qalc_err(&e)))?, Err(_) => { ctx.say(lang::L_MATH_NO_RESULT).await?; return Ok(()); } }; let result = String::from_utf8_lossy(&output.stdout).trim().to_string(); if result.is_empty() { ctx.say(lang::L_MATH_NO_RESULT).await?; } else { ctx.say(lang::fmt_math_result(&result)).await?; } Ok(()) } pub fn commands() -> Vec> { vec![math()] }