# Test SSDP/UPnP discovery for Yealink phones
param(
    [string]$IP = "172.16.1.29",
    [int]$DiscoveryTimeout = 5
)

# --- Test 1: SSDP M-SEARCH broadcast ---
Write-Host "=== Test 1: SSDP M-SEARCH (broadcast) ===" -ForegroundColor Yellow
Write-Host "  Sending M-SEARCH to 239.255.255.250:1900..." -ForegroundColor DarkGray

$ssdpMessage = @"
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 3
ST: ssdp:all

"@

$ssdpBytes = [System.Text.Encoding]::ASCII.GetBytes($ssdpMessage.Replace("`n", "`r`n"))
$udpClient = New-Object System.Net.Sockets.UdpClient
$udpClient.Client.ReceiveTimeout = ($DiscoveryTimeout * 1000)
$udpClient.Client.SetSocketOption([System.Net.Sockets.SocketOptionLevel]::Socket,
    [System.Net.Sockets.SocketOptionName]::ReuseAddress, $true)

$multicastEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Parse("239.255.255.250"), 1900)
$udpClient.Send($ssdpBytes, $ssdpBytes.Length, $multicastEp) | Out-Null

$responses = @()
$sw = [System.Diagnostics.Stopwatch]::StartNew()
while ($sw.Elapsed.TotalSeconds -lt $DiscoveryTimeout) {
    try {
        $remoteEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0)
        $data = $udpClient.Receive([ref]$remoteEp)
        $response = [System.Text.Encoding]::ASCII.GetString($data)
        $sourceIp = $remoteEp.Address.ToString()

        if ($response -match 'yealink|Yealink|YEALINK|SIP-T') {
            Write-Host "  [YEALINK] Response from $sourceIp" -ForegroundColor Green
            Write-Host $response -ForegroundColor Cyan
            $responses += @{ IP = $sourceIp; Response = $response }
        }
        elseif ($sourceIp -eq $IP) {
            Write-Host "  Response from TARGET $sourceIp" -ForegroundColor Green
            Write-Host $response -ForegroundColor Cyan
            $responses += @{ IP = $sourceIp; Response = $response }
        }
    }
    catch [System.Net.Sockets.SocketException] {
        break  # Timeout
    }
}
$udpClient.Close()
Write-Host "  Received $($responses.Count) Yealink/target responses" -ForegroundColor DarkGray

# --- Test 2: Direct SSDP to the phone's IP ---
Write-Host ""
Write-Host "=== Test 2: Direct SSDP M-SEARCH to $IP ===" -ForegroundColor Yellow

$udpClient2 = New-Object System.Net.Sockets.UdpClient
$udpClient2.Client.ReceiveTimeout = 3000

$directEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Parse($IP), 1900)
$udpClient2.Send($ssdpBytes, $ssdpBytes.Length, $directEp) | Out-Null

try {
    $remoteEp2 = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0)
    $data2 = $udpClient2.Receive([ref]$remoteEp2)
    $response2 = [System.Text.Encoding]::ASCII.GetString($data2)
    Write-Host "  Response from $($remoteEp2.Address):" -ForegroundColor Green
    Write-Host $response2 -ForegroundColor Cyan
}
catch {
    Write-Host "  No response (timeout)" -ForegroundColor DarkYellow
}
$udpClient2.Close()

# --- Test 3: Try fetching UPnP device description if we got a LOCATION header ---
Write-Host ""
Write-Host "=== Test 3: UPnP device description URLs ===" -ForegroundColor Yellow

# Try common UPnP description URLs
$descUrls = @(
    "http://${IP}:1900/description.xml",
    "http://${IP}/description.xml",
    "http://${IP}:49152/description.xml",
    "http://${IP}:5060/description.xml",
    "http://${IP}/DeviceDescription.xml",
    "http://${IP}/upnp/description.xml"
)

# Also extract LOCATION from any SSDP responses
foreach ($r in $responses) {
    if ($r.Response -match 'LOCATION:\s*(http[^\s\r\n]+)') {
        $loc = $Matches[1].Trim()
        if ($descUrls -notcontains $loc) { $descUrls = @($loc) + $descUrls }
    }
}

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
[System.Net.ServicePointManager]::Expect100Continue = $false

# Enable unsafe header parsing
$netAssembly = [System.Reflection.Assembly]::GetAssembly([System.Net.Configuration.SettingsSection])
if ($netAssembly) {
    $settingsType = $netAssembly.GetType("System.Net.Configuration.SettingsSectionInternal")
    if ($settingsType) {
        $bf = [System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::GetProperty -bor [System.Reflection.BindingFlags]::NonPublic
        $instance = $settingsType.InvokeMember("Section", $bf, $null, $null, @())
        if ($instance) {
            $field = $settingsType.GetField("useUnsafeHeaderParsing", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance)
            if ($field) { $field.SetValue($instance, $true) }
        }
    }
}

foreach ($url in $descUrls) {
    Write-Host "  Trying: $url" -ForegroundColor DarkGray -NoNewline
    try {
        $req = [System.Net.HttpWebRequest]::Create($url)
        $req.Timeout = 3000
        $req.UserAgent = "UPnP/1.0"
        $resp = $req.GetResponse()
        $reader = New-Object System.IO.StreamReader($resp.GetResponseStream())
        $body = $reader.ReadToEnd()
        $reader.Close()
        $resp.Close()
        Write-Host " -> OK ($($body.Length) chars)" -ForegroundColor Green
        Write-Host $body -ForegroundColor Cyan

        # Save if it looks like XML device description
        if ($body -match 'serialNumber|modelName|manufacturer') {
            Write-Host ""
            Write-Host "  [FOUND] Device description with useful fields!" -ForegroundColor Green
            $body | Out-File "C:\temp\yealink_upnp.xml" -Encoding UTF8
        }
    }
    catch {
        Write-Host " -> FAIL" -ForegroundColor Red
    }
}

# --- Test 4: Try SNMP if available ---
Write-Host ""
Write-Host "=== Test 4: SNMP probe (community: public) ===" -ForegroundColor Yellow
Write-Host "  Trying SNMPv2c GET on common OIDs..." -ForegroundColor DarkGray

# Build a simple SNMPv2c GET request for sysDescr (1.3.6.1.2.1.1.1.0)
# This is a minimal hand-crafted SNMP packet
$snmpGet = [byte[]]@(
    0x30, 0x29,                         # SEQUENCE, length 41
    0x02, 0x01, 0x01,                   # INTEGER: version = 1 (SNMPv2c)
    0x04, 0x06,                         # OCTET STRING: community
    0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, # "public"
    0xA0, 0x1C,                         # GET-REQUEST, length 28
    0x02, 0x04, 0x01, 0x02, 0x03, 0x04, # request-id
    0x02, 0x01, 0x00,                   # error-status: 0
    0x02, 0x01, 0x00,                   # error-index: 0
    0x30, 0x0E,                         # varbind list
    0x30, 0x0C,                         # varbind
    0x06, 0x08,                         # OID
    0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00,  # 1.3.6.1.2.1.1.1.0 (sysDescr)
    0x05, 0x00                          # NULL
)

try {
    $snmpClient = New-Object System.Net.Sockets.UdpClient
    $snmpClient.Client.ReceiveTimeout = 3000
    $snmpEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Parse($IP), 161)
    $snmpClient.Send($snmpGet, $snmpGet.Length, $snmpEp) | Out-Null

    $snmpRemote = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0)
    $snmpData = $snmpClient.Receive([ref]$snmpRemote)
    $snmpResponse = [System.Text.Encoding]::ASCII.GetString($snmpData)
    Write-Host "  SNMP response received ($($snmpData.Length) bytes)" -ForegroundColor Green
    # Try to extract readable text from the response
    $readable = ($snmpData | ForEach-Object { if ($_ -ge 32 -and $_ -le 126) { [char]$_ } else { "." } }) -join ""
    Write-Host "  Readable: $readable" -ForegroundColor Cyan
    $snmpClient.Close()
}
catch {
    Write-Host "  No SNMP response (timeout or blocked)" -ForegroundColor DarkYellow
}
