# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Gather script for Unix wireless info."""

import os
import re
import sys

if __name__ == "__main__":
    try:
        import sigma
    except ImportError:
        sys.path.append(os.path.join(os.pardir, os.pardir))

from sigma.gather import gathering

def get_never_wireless():
    # For server-only platforms (Solaris, HP-UX, AIX) that are unlikely
    # to support wireless capabilities.
    return [(0, "", "")]

def read_trim(pipe):
    return pipe.readline().lstrip().rstrip()

def parse_linux(pipe, interfaces):
    result = []
    line = read_trim(pipe)
    while True:
        if line == "":
            break
        while line != "" and not line.startswith("*"):
            line = read_trim(pipe)
        # Now we are at a line like "*-network".  Skip it.
        line = read_trim(pipe)
        product = None
        logical_name = None
        while line != "" and not line.startswith("*"):
            if line.startswith("product:"):
                dontcare, product = line.split(None, 1)
            elif line.startswith("logical name:"):
                dontcare1, dontcare2, logical_name = line.split(None, 2)
            line = read_trim(pipe)
        if product:
            lproduct = product.lower()
            if "wireless" in lproduct or "wlan" in lproduct:
                active = logical_name in interfaces
                active_str = gathering.boolean_to_active(active)
                result.append((1, product, active_str))
    if result == []:
        return [(0, "", "")]
    else:
        return result
    
# If I write this as a coroutine, then I can't have a try/finally that
# closes the pipe.

# Note that if I run lshw as root, I get usable output from "lshw -C
# network".  It looks like this:
#  *-network
#       description: Ethernet controller
#       product: BCM4401 100Base-T
#       vendor: Broadcom Corporation
#       physical id: 9
#       bus info: pci@01:09.0
#       logical name: eth0
#       version: 01
#       serial: 00:0d:56:4f:61:7d
#       size: 100Mbps
#       clock: 33MHz
#       capabilities: bus_master cap_list mii autonegotiation 100bt-fd 100bt 10bt-fd 10bt ethernet physical
#       configuration: autonegociated=100bt broadcast=yes driver=bcm4400 driverversion=3.0.7 duplex=full ip=10.0.5.52 link=yes multicast=yes
#       resources: iomemory:fe9fe000-fe9fffff irq:3

# If I run "lshw -C network" as non-root, I get plausible but
# nevertheless useless output like the following.  The problem is that
# we have to be able to connect the logical name ("eth0" in this case)
# with the product ("BCM4401 100Base-T" in this case).

#  *-network
#       description: Ethernet controller
#       product: BCM4401 100Base-T
#       vendor: Broadcom Corporation
#       physical id: 9
#       bus info: pci@01:09.0
#       version: 01
#       clock: 33MHz
#       capabilities: bus_master cap_list
#       configuration: driver=bcm4400
#       resources: iomemory:fe9fe000-fe9fffff irq:3
#  *-network
#       description: Ethernet interface
#       physical id: 1
#       logical name: eth0
#       serial: 00:0d:56:4f:61:7d
#       size: 100Mbps
#       capabilities: mii autonegotiation 100bt-fd 100bt 10bt-fd 10bt ethernet physical
#       configuration: autonegociated=100bt broadcast=yes duplex=full ip=10.0.5.52 link=yes multicast=yes

def get_linux():
    lshwbin = gathering.get_thirdparty_exe("lshw")
    pipe = os.popen(lshwbin + " -C network -disable scsi", "r");
    try:
        return parse_linux(pipe, gathering.get_active_interfaces())
    finally: 
        pipe.close()

# Sample output from system_profiler:
# AirPort Card:
#
#     AirPort Card Information:
#
#           Wireless Card Type: AirPort Extreme
#           Wireless Card Locale: USA
#           Wireless Card Firmware Version: 400.17 (3.90.34.0.p11)
#           Current Wireless Network: wireless network not available

def get_osx():
    regex = re.compile(r"\s*([^:]+):\s*(.*[\S])\s*$")
    results = []
    pipe = os.popen("/usr/sbin/system_profiler SPAirPortDataType", "r")
    try:
        for line in pipe:
            m = regex.match(line)
            if m is None:
                continue
            key, value = m.groups()
            if key == "Wireless Card Type":
                type = value
            elif key == "Wireless Card Locale":
                locale = value
            elif key == "Wireless Card Firmware Version":
                firmware = value
            elif key == "Current Wireless Network":
                availb = ("not available" not in value and
                          "currently turned off" not in value)
                avails = gathering.boolean_to_active(availb)
                rec = (1, "%s | %s | %s" % (type, locale, firmware), avails)
                results.append(rec)
                type = locale = firmware = "?"
    finally:
        pipe.close()
    if not results:
        results.append((0, "", ""))
    return results

supported = {
    "SunOS": get_never_wireless,
    "HP-UX": get_never_wireless,
    "AIX": get_never_wireless,
    "Linux": get_linux,
    "Darwin": get_osx,
    }

def Gather(collector):
    if os.name == "nt":
        from sigma.gather import gather_winwirelessnic
        gather_winwirelessnic.Gather(collector)
        return
    if not hasattr(os, "uname"):
        raise RuntimeError("Can't gather wireless info on %s system" % os.name)
    system, node, release, version, machine = os.uname()
    doit = supported.get(system)
    if doit is None:
        raise RuntimeError("Can't gather wireless info on %s system" % system)
    table = collector.table("wirelessnic",
                            ["iswireless", "nicname", "nicstatus"])
    for record in doit():
        table.add(record)

def _test():
    from sigma.gather import gathering
    gathering.test(Gather)

if __name__ == "__main__":
    _test()
