takproto 0.4.2

Rust library for TAK (Team Awareness Kit) Protocol - send CoT messages to TAK servers with mTLS support
Documentation
use std::env;
use std::time::{SystemTime, UNIX_EPOCH};
use takproto::proto::{CotEvent, Detail};
use takproto::{TakClient, TlsConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args: Vec<String> = env::args().collect();

    if args.len() < 6 {
        eprintln!(
            "Usage: {} <server_addr> <server_name> <ca_cert> <client_cert> <client_key>",
            args[0]
        );
        std::process::exit(1);
    }

    let server_addr = &args[1];
    let server_name = &args[2];
    let ca_cert_path = &args[3];
    let client_cert_path = &args[4];
    let client_key_path = &args[5];

    let tls_config =
        TlsConfig::new_with_client_cert(ca_cert_path, client_cert_path, client_key_path)?;

    println!("Connecting to TAK server...");
    let mut client = TakClient::connect_tls(server_addr, server_name, tls_config).await?;
    println!("✓ Connected\n");
    println!("🔗 Testing attachment methods for iTAK\n");

    let now_ms = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() as u64;

    // Test 1: <archive/> element (enables attachments)
    println!("Test 1: <archive/> element...");
    let event1 = CotEvent {
        r#type: "b-m-p-s-m".to_string(),
        uid: "TEST-ARCHIVE".to_string(),
        send_time: now_ms,
        start_time: now_ms,
        stale_time: now_ms + 300_000,
        how: "h-e".to_string(),
        lat: 39.377445,
        lon: -76.832160,
        hae: 10.0,
        ce: 9.9,
        le: 9.9,

        detail: Some(Detail {
            xml_detail: r#"<archive/><remarks>Has archive element</remarks>"#.to_string(),
            ..Default::default()
        }),

        ..Default::default()
    };

    client.send_cot_event_xml(event1).await?;
    println!("  ✓ Sent TEST-ARCHIVE\n");

    // Test 2: <link> with archive
    println!("Test 2: <link> inside <archive>...");
    let event2 = CotEvent {
        r#type: "b-m-p-s-m".to_string(),
        uid: "TEST-LINK-ARCHIVE".to_string(),
        send_time: now_ms + 1000,
        start_time: now_ms + 1000,
        stale_time: now_ms + 301_000,
        how: "h-e".to_string(),
        lat: 39.379000,
        lon: -76.833000,
        hae: 10.0,
        ce: 9.9,
        le: 9.9,

        detail: Some(Detail {
            xml_detail: r#"<archive><link uid="TEST-LINK-ARCHIVE" type="b-m-p-s-m" relation="p-p" url="https://www.rust-lang.org" mime="text/html"/></archive><remarks>Link in archive</remarks>"#.to_string(),
            ..Default::default()
        }),

        ..Default::default()
    };

    client.send_cot_event_xml(event2).await?;
    println!("  ✓ Sent TEST-LINK-ARCHIVE\n");

    // Test 3: <fileshare> element (TAK file sharing)
    println!("Test 3: <fileshare> element...");
    let event3 = CotEvent {
        r#type: "b-m-p-s-m".to_string(),
        uid: "TEST-FILESHARE".to_string(),
        send_time: now_ms + 2000,
        start_time: now_ms + 2000,
        stale_time: now_ms + 302_000,
        how: "h-e".to_string(),
        lat: 39.381000,
        lon: -76.835000,
        hae: 10.0,
        ce: 9.9,
        le: 9.9,

        detail: Some(Detail {
            xml_detail: r#"<fileshare filename="report.html" senderUrl="https://www.rust-lang.org" sizeInBytes="1024" sha256="0000000000000000000000000000000000000000000000000000000000000000"/><remarks>Has fileshare</remarks>"#.to_string(),
            ..Default::default()
        }),

        ..Default::default()
    };

    client.send_cot_event_xml(event3).await?;
    println!("  ✓ Sent TEST-FILESHARE\n");

    // Test 4: <attachment> element
    println!("Test 4: <attachment> element...");
    let event4 = CotEvent {
        r#type: "b-m-p-s-m".to_string(),
        uid: "TEST-ATTACHMENT".to_string(),
        send_time: now_ms + 3000,
        start_time: now_ms + 3000,
        stale_time: now_ms + 303_000,
        how: "h-e".to_string(),
        lat: 39.383000,
        lon: -76.837000,
        hae: 10.0,
        ce: 9.9,
        le: 9.9,

        detail: Some(Detail {
            xml_detail: r#"<attachment url="https://www.rust-lang.org" type="text/html" name="Rust Website"/><remarks>Has attachment</remarks>"#.to_string(),
            ..Default::default()
        }),

        ..Default::default()
    };

    client.send_cot_event_xml(event4).await?;
    println!("  ✓ Sent TEST-ATTACHMENT\n");

    // Test 5: Multiple attachment approaches combined
    println!("Test 5: Combined approach...");
    let event5 = CotEvent {
        r#type: "b-m-p-s-m".to_string(),
        uid: "TEST-COMBINED".to_string(),
        send_time: now_ms + 4000,
        start_time: now_ms + 4000,
        stale_time: now_ms + 304_000,
        how: "h-e".to_string(),
        lat: 39.385000,
        lon: -76.839000,
        hae: 10.0,
        ce: 9.9,
        le: 9.9,

        detail: Some(Detail {
            xml_detail: r#"<archive/><link uid="TEST-COMBINED" production_time="2024-01-01T00:00:00Z" type="b-m-p-s-m" parent_callsign="TEST-COMBINED" relation="p-p" url="https://www.rust-lang.org" mime="text/html"/><remarks>Combined: archive + link</remarks>"#.to_string(),
            ..Default::default()
        }),

        ..Default::default()
    };

    client.send_cot_event_xml(event5).await?;
    println!("  ✓ Sent TEST-COMBINED\n");

    // Test 6: Nested in __serverdestination (for proper routing)
    println!("Test 6: With server destination...");
    let event6 = CotEvent {
        r#type: "b-m-p-s-m".to_string(),
        uid: "TEST-SERVERDEST".to_string(),
        send_time: now_ms + 5000,
        start_time: now_ms + 5000,
        stale_time: now_ms + 305_000,
        how: "h-e".to_string(),
        lat: 39.387000,
        lon: -76.841000,
        hae: 10.0,
        ce: 9.9,
        le: 9.9,

        detail: Some(Detail {
            xml_detail: r#"<__serverdestination destinations="*"/><archive/><link uid="TEST-SERVERDEST" type="b-m-p-s-m" relation="p-p" url="https://www.rust-lang.org" mime="text/html"/><remarks>With server routing</remarks>"#.to_string(),
            ..Default::default()
        }),

        ..Default::default()
    };

    client.send_cot_event_xml(event6).await?;
    println!("  ✓ Sent TEST-SERVERDEST\n");

    println!("=== ✅ ALL TESTS SENT ===\n");
    println!("Check iTAK for 6 markers:\n");
    println!("1. TEST-ARCHIVE");
    println!("2. TEST-LINK-ARCHIVE");
    println!("3. TEST-FILESHARE");
    println!("4. TEST-ATTACHMENT");
    println!("5. TEST-COMBINED");
    println!("6. TEST-SERVERDEST\n");

    println!("📎 LOOK FOR:");
    println!("  - Paperclip icon on any markers?");
    println!("  - Attachments section in details?");
    println!("  - Any clickable links?\n");

    println!("Report back which test number(s) show:");
    println!("  a) Paperclip icon");
    println!("  b) Clickable/tappable content");
    println!("  c) Attachment section");

    client.close().await?;
    Ok(())
}