# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Gather script for I/O ports."""

import os
import platform
import logging
if os.name == "nt":
    from win32com.client import GetObject
    import winreg as _winreg

logger = logging.getLogger("gather.gather_devport")

basicos = platform.uname()[0]
if basicos in [ "Microsoft", "Microsoft Windows" ]:
    basicos = "Windows"
if basicos != "Windows":
    raise Exception("Can't get device port info on this operating system: %r" %
                    basicos)


def get_usbhub_keys(basekey):
    valList = []
    try:
        x = _winreg.ConnectRegistry(None,  _winreg.HKEY_LOCAL_MACHINE)
        try:
            root = _winreg.OpenKey(x, basekey)
            try:
                try:
                    nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(root)
                    for i in range(nsubkeys):
                        try:
                            subkeyname = _winreg.EnumKey(root, i)
                        except OSError as err:
                            continue 
                        valList.append(subkeyname)
                finally:
                    _winreg.CloseKey(root)
            except:
                pass
        finally:
            _winreg.CloseKey(x)
    except:
        pass
    return valList

def get_hub_info(key, name):
    try:
        x = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
        try:
            y = _winreg.OpenKey(x, key)
            try:
                val = _winreg.QueryValueEx(y, name)
                if val != None:
                    return val[0]
                else:
                    return None
            finally:
                _winreg.CloseKey(y)
        finally:
            _winreg.CloseKey(x)
    except OSError:
        return None

def Gather(collector):
    # write header to output
    table = collector.table("devport", ["devtype", "devname", "devid"])
    try:
        objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_ParallelPort")
        for item in objItems:
            devname = item.Properties_("Name").Value
            devid = item.Properties_("PNPDeviceID").Value
            table.add(("parallel_port", devname, devid))
    except:
        logger.exception("devport gather: getting parallel port info failed")

    try:
        objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_SerialPort")
        for item in objItems:
            devname = item.Properties_("Name").Value
            devid = item.Properties_("PNPDeviceID").Value
            table.add(("serial_port", devname, devid))
    except:
        logger.exception("devport gather: getting serial port info failed")

    try:
        objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_InfraredDevice")
        for item in objItems:
            devname = item.Properties_("Name").Value
            devid = item.Properties_("PNPDeviceID").Value
            table.add(("infrared_port", devname, devid))
    except:
        logger.exception("devport gather: getting infrared device info failed")

    try:
        objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_USBHub")
        for item in objItems:
            devname = item.Properties_("Name").Value
            devid = item.Properties_("PNPDeviceID").Value
            table.add(("usb_hub", devname, devid))
    except:
        # Windows 2000 does not have Win32_USBHub class available, try registry
        try:
            basekeylist = ["System\\CurrentControlSet\\Enum\\USB\\ROOT_HUB", "System\\CurrentControlSet\\Enum\\USB\\ROOT_HUB20"]
            for abasekey in basekeylist:
                hubs = get_usbhub_keys(abasekey)
                for ahub in hubs:
                    devid, devname = "", ""
                    keyname = "%s\\%s" % (abasekey, ahub)
                    idlist = get_hub_info(keyname, "HardwareID")
                    for anid in idlist:
                        devid = "%s\\%s" % (anid, ahub)
                        if anid == "USB\\ROOT_HUB" or anid == "USB\\ROOT_HUB20":
                            break
                    devname = get_hub_info(keyname, "DeviceDesc")
                    if devid != "" and devid != None:
                        table.add(("usb_hub", devname, devid))
        except:
            logger.exception("devport gather: getting USB hub info failed")


    try:
        objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_USBController")
        for item in objItems:
            devname = item.Properties_("Name").Value
            devid = item.Properties_("PNPDeviceID").Value
            table.add(("usb_controller", devname, devid))
    except:
        logger.exception("devport gather: getting USB controller info failed")

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

if __name__ == "__main__":
    _test()
