package MSWin32;
###################################################################
#
# STILL NEED USER/GROUP INFO
#
###################################################################

# MSWin32.pm - these are operating system specific routines for
# 	     Microsoft Windows
# 
# Note that we can't use the name "Win32" as that name is already
# used by the ActiveState Perl software.
# 
# Many of the functions calls below are taken from a book called
# _Windows NT Win32 Perl Programming: The Standard Extensions_, by
# Dave Roth.  A most excellent book.  Page numbers in comments
# refer back into this book.
#
# Rules for these subroutines:
# 
#	1.  These subroutines can be called in any order except
#	    for Initialize${OSName}.  That will always be called
#	    before any others.
#	2.  These subroutines can be called in any order...
# 
# This code has only been tested by the authors on a couple NT servers.
# No 9x machines or even an NT workstation.
#
# MSWin32.pm uses 3 binaries you will need access to:
# 
#    from the OS: ipconfig
#    from the NT Resource Kit: rmtshare & sc
# 
# A "feature" is that Network:Bindings is currently just a registry
# dump that should be beautified.
# 
# ==============================================================
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 
# 2 of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be 
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE.  See the GNU General Public License for more details.
# 
# Original source:
#	Copyright (c) 2000 Gary Weimer <weimer@bis.kodak.com>
#	Based upon code by Bruce W. Mohler
#	Code to collect info developed by Alvin Roe <aroe@bis.kodak.com>
# 
# Contributed source:
#	Copyright (c) 1999, 2000 <author)
# 
# ==============================================================
# 
# $Header: /export/home/mohlerb/src/perl/syssumm/remote/RCS/MSWin32.pm,v 1.2 2000/03/14 21:37:20 mohlerb Exp mohlerb $
# 
# $Revision: 1.2 $
#
# $Log: MSWin32.pm,v $
# Revision 1.2  2000/03/14 21:37:20  mohlerb
# changes from Gary Weimer including:
# Minor comment mods; Cleanup perl -w warnings
#
# Revision 1.1  2000/03/08 17:21:53  mohlerb
# Initial revision
#

use common;
# unique to this OS module...
use Win32;
use Win32::NetAdmin qw(GetUsers GroupIsMember UserGetAttributes UserSetAttributes GetDomainController FILTER_NORMAL_ACCOUNT);
use Win32::AdminMisc;
use Win32::TieRegistry( Delimiter=>"/", ArrayValues=>0 );
if ("Compiling" eq 1) {
  # Never executed, but the compiler doesn't know that...
  use Win32API::Registry;
}
use Sys::Hostname;
#use global;

require Exporter;
@ISA = qw(Exporter);
###########################################################################
# the following sub-routines (&) are variables ($) will be 
# visible in a program using this module...
@EXPORT = qw(
	&InitializeMSWin32
);
# 
# Note that you do not need to export the Return* subroutine
# names since they are being called by reference.
# 
###########################################################################

###########################################################################
# Public Global Variables (must be declared above)
###########################################################################


###########################################################################
# Private Global Variables
###########################################################################

# parts of OS version - filled in by InitializeMSWin32()
#$OSVersion = "";
#$OSVersionMajor = "";
#$OSVersionMinor = "";
#$OSBuildNumber = "";
#$OSPlatform = "";
#$OSServicePackNumber = "";


###########################################################################
# Subroutines
###########################################################################

# 
# This subroutine is called before any others.  It's
# reason for existence is to plug in the references to
# subroutines below to actually generate the information.
# 

sub InitializeMSWin32 ()
{
	print "InitializeMSWin32()...\n" if $main::Debug;

	# initialize $SubroutineSuffix...
	# WhatVersionOfMSWin32();

	# we need the nodename for later on...
	# 
	# Note that this is the Microsoft name for the
	# machine, not the fully qualified domain name
	# used by the TCP/IP stack...
	# 
	$main::NodeName = Win32::NodeName();
	print "\tNodeName is $main::NodeName\n" if $main::Debug;

	# No reason to search for a syslog on a non-UNIX machine

	# plug in appropriate subroutines
	$main::Routines{General}{Vendor} = \&ReturnVendorMSWin32;
	$main::Routines{General}{Model} = \&ReturnModelMSWin32;
	$main::Routines{General}{HostId} = \&ReturnHostIdMSWin32;

	$main::Routines{Hardware}{Processors} = \&ReturnProcessorsMSWin32;
	$main::Routines{Hardware}{Memory} = \&ReturnMemoryMSWin32;
	$main::Routines{Hardware}{Eeprom} = \&ReturnEepromMSWin32;
# 	$main::Routines{Hardware}{Disks} = \&ReturnDisksMSWin32;
# 	$main::Routines{Hardware}{Tapes} = \&ReturnTapesMSWin32;
# 	$main::Routines{Hardware}{StorageManager} = \&ReturnStorageManagerMSWin32;

	$main::Routines{Network}{DomainName} = \&ReturnDomainNameMSWin32;
# 	$main::Routines{Network}{DefaultRouter} = \&ReturnDefaultRouterMSWin32;
	$main::Routines{Network}{NameServer} = \&ReturnNameServerMSWin32;
# 	$main::Routines{Network}{IpAddress} = \&ReturnIpAddressMSWin32;
# 	$main::Routines{Network}{SubnetMask} = \&ReturnSubnetMaskMSWin32;
	$main::Routines{Network}{NetworkInterfaces} = \&ReturnNetworkInterfacesMSWin32;
	$main::Routines{Network}{IpEnableRouter} = \&ReturnIpEnableRouterMSWin32;
	$main::Routines{Network}{Bindings} = \&ReturnBindingsMSWin32;

	$main::Routines{Software}{OsName} = \&ReturnOsNameMSWin32;
	$main::Routines{Software}{OsVersion} = \&ReturnOsVersionMSWin32;
	$main::Routines{Software}{OsRole} = \&ReturnOsRoleMSWin32;
# 	$main::Routines{Software}{NbrOfLicenses} = \&ReturnNbrOfLicensesMSWin32;
	$main::Routines{Software}{Patches} = \&ReturnPatchesMSWin32;
	$main::Routines{Software}{Printers} = \&ReturnPrintersMSWin32;
# 	$main::Routines{Software}{Services} = \&ReturnServicesMSWin32;
	$main::Routines{Software}{ApplicationsInstalled} = \&ReturnApplicationsInstalledMSWin32;
# 	$main::Routines{Software}{RunningLpsched} = \&ReturnRunningLpschedMSWin32;
# 	$main::Routines{Software}{RunningSendmail} = \&ReturnRunningSendmailMSWin32;
# 	$main::Routines{Software}{RunningNFS} = \&ReturnRunningNFSMSWin32;
# 	$main::Routines{Software}{RunningAutomount} = \&ReturnRunningAutomountMSWin32;
# 	$main::Routines{Software}{RunningNIS} = \&ReturnRunningNISMSWin32;
# 	$main::Routines{Software}{RunningNameserver} = \&ReturnRunningNameserverMSWin32;
# 	$main::Routines{Software}{RunningSamba} = \&ReturnRunningSambaMSWin32;
# 	$main::Routines{Software}{RunningAccounting} = \&ReturnRunningAccountingMSWin32;
# 	$main::Routines{Software}{IpAddressResolution} = \&ReturnIpAddressResolutionMSWin32;
	$main::Routines{Software}{GraphicalUserInterface} = \&ReturnGraphicalUserInterfaceMSWin32;
# 	$main::Routines{Software}{FontServer} = \&ReturnFontServerMSWin32;
	$main::Routines{Software}{LocalFileSystems} = \&ReturnLocalFileSystemsMSWin32;
# 	$main::Routines{Software}{RemoteFileSystems} = \&ReturnRemoteFileSystemsMSWin32;
# 	$main::Routines{Software}{Swap} = \&ReturnSwapMSWin32;
	$main::Routines{Software}{Services} = \&ReturnServicesMSWin32;
	$main::Routines{Software}{Users} = \&ReturnUsersMSWin32;
	$main::Routines{Software}{Groups} = \&ReturnGroupsMSWin32;

	RemoveLocalExclusions();

	return;
}


###########################################################################
# Global
###########################################################################

#
# get rid of all trailing nulls, \n, and \r's
#
sub chopy () {
        $_[$[] =~ s/[\000\n\r]*$//;
        return($_[$[]);
}


# sub WhatVersionOfMSWin32
# {
# 	print "WhatVersionOfMSWin32()...\n" if $main::Debug;
# 
# 	# page 343
# 	my @Version = Win32::GetOSVersion;
# 	$OSServicePackNumber = $Version[0];
# 	$OSVersionMajor = $Version[1];
# 	$OSVersionMinor = $Version[2];
# 	$OSBuildNumber = $Version[3];
# 	$OSPlatform = $Version[4];
# 
# 	# map Platform ID to Platform
# 	if ( $OSPlatform == 1 ) {
# 		$OSPlatform = "Microsoft Windows 95/98";
# 		$OSServicePackNumber = "None";
# 	}
# 	elsif ( $OSPlatform == 2 ) {
# 		$OSPlatform = "Microsoft Windows NT";
# 	}
# 	else {
# 		$OSPlatform = "Microsoft Windows 3.x";
# 		$OSServicePackNumber = "None";
# 	}
# 
# 	print "\tMajor OS version is $OSVersionMajor...\n" if $main::Debug;
# 	print "\tMinor OS version is $OSVersionMinor...\n" if $main::Debug;
# 	print "\tBuild Number is $OSBuildNumber...\n" if $main::Debug;
# 	print "\tPlatform is $OSPlatform...\n" if $main::Debug;
# 	print "\tService pack is $OSServicePackNumber...\n" if $main::Debug;
# 
# 	$SubroutineSuffix = $OSVersionMajor;
# 
# 	return;
# }


###########################################################################
# General
###########################################################################

sub ReturnVendorMSWin32 ($)
{	my $Subcategory = shift;

	# CUSTOMIZE
	return ( "IGNORE" );
}


sub ReturnModelMSWin32 ($)
{	my $Subcategory = shift;

	return ( "IGNORE" );
}


sub ReturnHostIdMSWin32 ($)
{	my $Subcategory = shift;

	return ( "IGNORE" );
}


###########################################################################
# Hardware
###########################################################################

sub ReturnProcessorsMSWin32 ($)
{	my $Subcategory = shift;
	my @Processors = ( );

	my $reg = $Registry->{"LMachine/HARDWARE/DESCRIPTION/System/CentralProcessor/"};
	my ($x, $t1, $t2, $t3, $str);
	foreach $x (keys %{$reg}) {
		$t1 = $reg->{$x."~MHz"};
		$t1 = hex($t1);
		$t2 = $reg->{$x."VendorIdentifier"};
		$t3 = $reg->{$x."Identifier"};
		$str= qq[speed="$t1" vendor="$t2" identifier="$t3"];
		push(@Processors, $str);
		print "Processor-$#Processors: $str\n" if $main::Debug;
	}

	my @Response = ForceMultipleResponses(\@Processors);

	return @Response;
}


sub ReturnMemoryMSWin32 ($)
{	my $Subcategory = shift;
	my $Memory;
	my %temp = Win32::AdminMisc::GetMemoryInfo();
	$Memory  = int(($temp{RAMTotal}) / 1048576) ."MB";

	print "Memory: $Memory\n" if $main::Debug;

	return ( $Memory );
}


sub ReturnEepromMSWin32 ($)
{	my $Subcategory = shift;
	my $reg = $Registry->{"LMachine/HARDWARE/DESCRIPTION/System/"};
	my $date = $reg->{"/SystemBiosDate"};
	my $ver = $reg->{"/SystemBiosVersion"};
	$ver = &chopy($ver);
	my $str = qq[biosdate="$date" biosversion="$ver"];

	print "Eeprom: $str\n" if $main::Debug;
	return ($str);
}


# sub ReturnDisksMSWin32 ($)
# {	my $Subcategory = shift;
# 	my @Controllers = ( );
# 	my $ControllerNbr = -1;
# 	my $CurrentController = -1;
# 	my @Response = ( );
# 
# 	# ...
# 
# 	@Response = ForceMultipleResponses(\@Response);
# 
# 	return @Response;
# }


# sub ReturnTapesMSWin32 ($)
# {	my $Subcategory = shift;
# 	my @Controllers = ( );
# 	my $ControllerNbr = -1;
# 	my $CurrentController = -1;
# 	my @Response = ( );
# 
# 	# ...
# 
# 	@Response = ForceMultipleResponses(\@Response);
# 
# 	return @Response;
# }


# sub ReturnStorageManagerMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( "None" );
# }


###########################################################################
# Network
###########################################################################

sub ReturnDomainNameMSWin32 ($)
{	my $Subcategory = shift;

	my $t1 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters/Hostname"};
	my $t2 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters/Domain"};
	my $DomainName = "$t1.$t2";

	print "DomainName: $DomainName\n" if $main::Debug;
	return $DomainName;
}


# sub ReturnDefaultRouterMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $DefaultRouter );
# }


sub ReturnNameServerMSWin32 ($)
{	my $Subcategory = shift;
	my @Response = split(/\s+/,$Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters/NameServer"});

	print "NameServers: @Response\n" if $main::Debug;
	@Response = ForceMultipleResponses(\@Response);
	return @Response;
}


# sub ReturnIpAddressMSWin32
# {	my $Subcategory = shift;
# 
# 	return ( $IPAddress );
# }


# sub ReturnSubnetMaskMSWin32
# {	my $Subcategory = shift;
# 
# 	return ($SubnetMask);
# }     


sub ReturnNetworkInterfacesMSWin32 ($)
{	my $Subcategory = shift;
	my @Response = ( );

	open (IN, qq[ipconfig /all|]) || warn "Error getting input:\n    $!:\n    ";
	my @ipconfig = <IN>;
	close IN;
	my $ipconfig;

	my @list = keys %{$Registry->{"LMachine/SOFTWARE/Microsoft/Windows NT/CurrentVersion/NetworkCards"}};
	foreach $x (@list){
	    # make some local varibles
	    my $x1 = ""; #device (name)
	    my $x2 = ""; #description
	    my $x3 = ""; #mac address
	    my $x4 = ""; #ip
	    my $x5 = ""; #netmask
	    my $x6 = ""; #dhcp server
	    my $x7 = ""; #wins server(s)
	    my $x8 = ""; #gateway
	    chop ($x);
	    $x1 = $Registry->{"LMachine/SOFTWARE/Microsoft/Windows NT/CurrentVersion/NetworkCards/".$x."/ServiceName"};
	    $x2 = $Registry->{"LMachine/SOFTWARE/Microsoft/Windows NT/CurrentVersion/NetworkCards/".$x."/Description"};
	    if ($Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/".$x1."/Parameters/Tcpip/EnableDHCP"}){
		$go = 1;
		$x4 = "DHCP Assigned";#IP
		$x5 = "DHCP Assigned";#netmask
		$x6 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/". $x1."/Parameters/Tcpip/DHCPServer"};# DHCPServer
		$x7 = "DHCP Assigned";
		$x8 = "DHCP Assigned";
	    }else{
		$go = 0;
		$x4 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/".$x1."/Parameters/Tcpip/IPAddress"};
		$x4 = &chopy($x4);
		$x5 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/".$x1."/Parameters/Tcpip/SubnetMask"};
		$x5 = &chopy($x5);
		$x6 = "N/A";
		$t1 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/NetBT/Adapters/".$x1."/NameServer"};
		$t1 = &chopy($t1);
		$t2 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/NetBT/Adapters/".$x1."/NameServerBackup"};
		$t2 = &chopy($t2);
		$x7 = "Primary:$t1 Secondary:$t2";
		$x8 = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/".$x1."/Parameters/Tcpip/DefaultGateway"};
		$x8 = &chopy($x8);
	    }
	    my $foundit=0;
	    IPCONFIG: foreach $ipconfig (@ipconfig) {
		if ($ipconfig =~ $x1) {
			$foundit = 1;
		} elsif ($foundit && $ipconfig =~ /Physical Address.*:.(.{17})/) {
			$x3 = "$1";
			last IPCONFIG;
		}
	    }

	    my $str = qq[device="$x1" description="$x2" macaddr="$x3" ip="$x4" netmask="$x5" dhcpserver="$x6" winsrv="$x7" gateway="$x8"];

	    push(@Response, $str);
	    print "Interface-$#Response: $str\n" if $main::Debug;
	}

	@Response = ForceMultipleResponses(\@Response);
	return @Response;
}


sub ReturnIpEnableRouterMSWin32 ($)
{	my $Subcategor = shift;
	my $reg = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters/IPEnableRouter"};
	&chopy($reg);

	my $Response = ("Yes","No")[!$reg]; # negate to force 0/1

	print "IpEnableRouter: $Response\n" if $main::Debug;
	return($Response);
}


sub ReturnBindingsMSWin32 ($)
{	my $Subcategor = shift;
	my $Response=$Registry->{"LMachine/SOFTWARE/Microsoft/Ncpa/CurrentVersion/BindfileEx"};

	print "Bindings: $Response\n" if $main::Debug;
	return($Response);
}


# sub AddNetInfo ($)
# {	my $BusHardwareAddress = shift;
# 	my $MACAddress = "";
# 	my $NetworkInterfaceName = "";
# 	my $NICType = "";
# 
# 	return $NICDescription;
# }


###########################################################################
# Software
###########################################################################

sub ReturnOsRoleMSWin32 ($)
{	my $Subcategory = shift;
	my $OsRole;

	my $reg  = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Control/ProductOptions/"};

	if ($reg->{"/ProductType"} eq "WinNT") { # Workstation
		$OsRole = "Workstation";
	}elsif ($reg->{"/ProductType"} eq "LanmanNT"){ #Domain Controller
		if (Win32::AdminMisc::GetPDC() eq Win32::NodeName) {
			$OsRole = "Primary Domain Controller";
		}else{
			$OsRole = "Backup Domain Controller";
		}
	}else {
		$OsRole = "Server";
	}

	print "OsRole: $OsRole\n" if $main::Debug;
	return ("$OsRole");
}


sub ReturnOsNameMSWin32 ($)
{	my $Subcategory = shift;
	my $OsName;

	my $reg  = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Control/ProductOptions/"};

	if ($reg->{"/ProductType"} eq "WinNT") { # Workstation
		$OsName = "Windows NT Workstation";
	}else {
		$OsName = "Windows NT Server";
	}

	my $Suite = $reg->{"/ProductSuite"};
	if ($Suite =~ /^(Terminal Server)/) {
		$OsName = "Windows NT $Suite";
	}elsif ($Suite =~ /^(Enterprise)/) {
		$OsName = "Windows NT $Suite Server";
	}

	print "OsName: $OsName\n" if $main::Debug;
	return ( "$OsName" );
}


sub ReturnOsVersionMSWin32 ($)
{	my $Subcategory = shift;
	my @OSVersion = Win32::GetOSVersion;
	@OSVersion = @OSVersion[1..3]; # major, minor, build
	my $OSVersion = join('.', @OSVersion);

	print "OsVersion: $OSVersion\n" if $main::Debug;
	return ( "$OSVersion" );
}


# sub ReturnNbrOfLicensesMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $NbrOfLicenses );
# }


sub ReturnPatchesMSWin32 ($)
{	my $Subcategory = shift;
	my ($Response) = Win32::GetOSVersion;
	my @Response = ($Response);

	print "Patches-0: $Response\n" if $main::Debug;
	@Response = ForceMultipleResponses(\@Response);
	return @Response;
}


# sub ReturnRunningLpschedMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $Lpsched );
# }


sub ReturnPrintersMSWin32 ($)
{	my $Subcategory = shift;
	my @Response = ( );

	my $reg = $Registry->{"LMachine/System/CurrentControlSet/Control/Print/Printers/"};
	foreach $printer (keys %{$reg}) {
	    if (ord($printer) != ord("/")) {
		my $str = 'name="' . $reg->{"$printer/Name"} .
			'" description="' . $reg->{"$printer/Description"} .
			'" location="' . $reg->{"$printer/Location"} .
			'" port="' . $reg->{"$printer/Port"} .
			'" driver="' . $reg->{"$printer/Printer Driver"} .
			'" sharename="' . $reg->{"$printer/Share Name"} . '"';

		print "Printers-$#Response: $str\n" if $main::Debug;
		push(@Response, $str);
	    }
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


# sub ReturnServicesMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	ruturn XXX;
# }


sub ReturnApplicationsInstalledMSWin32 ($)
{	my $Subcategory = shift;
	my @progs = ();
	my @list = keys %{$Registry->{"LMachine/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/"}};
	my $t1 = "";
        foreach $x (@list) {
                $t1 = $Registry->{"LMachine/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/".$x."DisplayName"};
                if ($t1)  {
                        push (@progs, '"'."$t1".'"');
                } else { # No Display name...
                        $t1 = $Registry->{"LMachine/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/".$x."QuietDisplayName"};
                        if ($t1)  {
                                push (@progs, '"'."$t1".'"');
                        }else{
                                push (@progs, '"'."$x".'"');
                        }
                }
        }

	print "ApplicationsInstalled: @progs\n" if $main::Debug;
	return("@progs");
}


# # 
# # Note that this subroutine has a side-effect of setting
# # a global variable in main:: called EmailAvailable if
# # sendmail is running...
# # 
# 
# sub ReturnRunningSendmailMSWin32 ($)
# {
# 	my $Subcategory = shift;
# 
# 	#...
# 
# # 	# side-effect
# 	$main::EmailAvailable = ( $Sendmail eq "Yes" );
# 	return ( $Sendmail );
# }


# sub ReturnRunningNFSMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $NFSState );
# }


# sub ReturnRunningAutomountMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $Automount );
# }


# sub ReturnRunningNISMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $NISState );
# }


# sub ReturnRunningNameserverMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $Nameserver );
# }


# sub ReturnIpAddressResolutionMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $IPAddressResolution );
# }


# sub ReturnRunningSambaMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ReturnRunningSamba($Subcategory, $PsCommand, $PsArgs, $InetdConfPath);
# }


sub ReturnGraphicalUserInterfaceMSWin32 ($)
{	my $Subcategory = shift;

	return ( "Win32" );
}


# sub ReturnFontServerMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( $FontServer );
# }


sub ReturnLocalFileSystemsMSWin32 ($)
{	my $Subcategory = shift;
	my @Response = ( );

	my @Drives = Win32::AdminMisc::GetDrives(DRIVE_FIXED);
	foreach $x (@Drives) {
		my ($size,$free)=Win32::AdminMisc::GetDriveSpace($x);
		$size  = int($size / 1048576);
		my $used = $size - (int(($free / 1048576)*10)) / 10;
		my %temp = Win32::AdminMisc::GetVolumeInfo($x);
		my $serial = sprintf "%x", $temp{"Serial"};
		$serial =~ s/^(....)(....)/\U$1-\U$2/;
		my $format = $temp{"FileSystemName"};
		my $str = qq[mnt="$x" volname="$temp{Volume}" sn="$serial" format="$temp{FileSystemName}" size="${size}MB" used="${used}MB"];

		push(@Response, $str);
		print "Services-$#Resonse: $str\n" if $main::Debug;
	}

	@Drives = Win32::AdminMisc::GetDrives(DRIVE_CDROM);
	foreach $x (@Drives) {
		my $str=qq[mnt="$x" volname= "N/A" sn="N/A" format= "CD-ROM Drive" size="" used=""];
		push(@Response, $str);
		print "Services-$#Resonse: $str\n" if $main::Debug;
	}

	@Drives = Win32::AdminMisc::GetDrives(DRIVE_REMOVABLE);
	foreach $x (@Drives) {
		my $str=qq[mnt="$x" volname= "N/A" sn="N/A" format= "Removable(Floppy) Drive" size="" used=""];
		push(@Response, $str);
		print "Services-$#Response: $str\n" if $main::Debug;
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnRemoteFileSystemsMSWin32 ($)
{	my $Subcategory = shift;
	my @Response = ( );
	my ($x, $t1, $t2);
	my @list = keys %{$Registry->{"LMachine/System/CurrentControlSet/Services/LanmanServer/Shares/"}};
	foreach $x (@list) {

	    if (ord($x) == ord("/")) {
		$t1 = substr($x, 1);
		$t2 = "\\\\".Win32::NodeName."\\";
		open (IN, qq[rmtshare $t2"$t1"|]) || warn "Error getting input:\n    $!:\n    ";
		my $x1 = "";    # FULL CONTROL
		my $x2 = "";    # CHANGE
		my $x3 = "";    # READ
		my $x4 = "";    # NONE
		while ($in = <IN>){
			chop $in;
			if ($in =~ /^Path *(.*)$/) {
				$t3 = "$1"; # path
				# push is done above
			}elsif ($in =~ /^ *(.*[^ ]) *:  (.*)$/) {
				if ($2 eq "FULL CONTROL") {
					$x1 .= "$1\t";
				}elsif ($2 eq "CHANGE") {
					$x2 .= "$1\t";
				}elsif ($2 eq "READ") {
					$x3 .= "$1\t";
				}elsif ($2 eq "NONE") {
					$x4 .= "$1\t";
				}
			}
		}
		close IN;
		my $str=qq[name="$t1" path="$t3" perms="FullControl:$x1 Change:$x2 Read:$x3 NoAccess:$x4" desc="Not Implemented"];
		push(@Response, $str);
		print "ExportedFileSystems-$#Response: $str\n" if $main::Debug;

	    }
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


# sub ReturnSwapMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	#
# 	# XXX - This is a dummy routine
# 	# 
# 	# The value of $SwapCommand needs to be initialized above.
# 	# 
# 
# 	ReturnSwap($Subcategory, "$SwapCommand");
# }


# sub ReturnRunningAccountingMSWin32 ($)
# {	my $Subcategory = shift;
# 
# 	return ( "Unknown" );
# }


sub ReturnServicesMSWin32 ($)
{	my $Subcategory = shift;
	my @Response;

	my @list = keys %{$Registry->{"LMachine/System/CurrentControlSet/Services/"}};
	my $host = "\\\\".Win32::NodeName;
	my ($name, $dpyName, $sType, $account);
	foreach $x (@list) {
	    chop($x);
	    open (IN, qq[sc $host qc "$x"|]) ||
		warn "Error getting input:\n    $!:\n    ";
	    MYLOOP: while ($in = <IN>) {
		chomp $in;
		if ($in =~ /^\[SC\]/) {  #GetServiceConfig SUCCESS*(.*)$/) 
			last MYLOOP if ($in =~ /fail/);
		}elsif ($in =~ /^SERVICE_NAME: (.*)$/){
			$name = "$1";
		}elsif ($in =~ /^        START_TYPE         : (.)/) {
			if ("$1" eq "0") {
				$sType = "Boot";
			}elsif ("$1" eq "1") {
				$sType = "System";
			}elsif ("$1" eq "2") {
				$sType = "Automatic";
			}elsif ("$1" eq "3") {
				$sType = "Manual";
			}elsif  ("$1" eq "4") {
				$sType = "Disabled";
			}
                }elsif ($in =~ /^        DISPLAY_NAME       : (.*)..$/) {
                        $dpyName = "$1";
                }elsif ($in =~ /^        SERVICE_START_NAME : (.*)..$/) {
                        if (!length($1)) {
                                $account = "N/A";
                        }else{
                                $account = "$1";
                        }
                }else{
                        #Do nothing...
                }

	    }
	    close IN;
	    # store data...
	    if ($sType) {
		$str=qq[name="$name" displayname="$dpyName" starttype="$sType" serviceaccount="$account"];
		push(@Response, $str);
		print "Services-$#Response: $str\n" if $main::Debug;
	    }
	}

	@Response = ForceMultipleResponses(\@Response);
	return @Response;
}


sub ReturnUsersMSWin32 ($)
{	my $Subcategory = shift;
	my @Response;

	my %users;
	my ($user, $password, $passwordage, $privilege, $homeDir);
	my ($comment, $flags, $scriptpath);

	Win32::NetAdmin::GetUsers("", FILTER_NORMAL_ACCOUNT, \%users);

	foreach $user (keys %users) {
		Win32::NetAdmin::UserGetAttributes("", $user, $password,
			$passwordage, $privilege, $homeDir, $comment,
			$flags, $scriptpath);
		my $str=qq[id="$user" name="$users{$user}" home="$homeDir" script="$scriptpath"];
		push(@Response, $str);
		print "Users-$#Response: $str\n" if $main::Debug;
	}


	@Response = ForceMultipleResponses(\@Response);
	return @Response;
}


sub ReturnGroupsMSWin32 ($)
{	my $Subcategory = shift;
	my @Response;

	my (%temp, $group);
	if (Win32::AdminMisc::GetGroups("\\\\".Win32::NodeName, GROUP_TYPE_ALL, \%temp)) {
	    foreach $x (keys %temp) {
		$group = $temp{$x};
		$name = $group->{"name"};
		$type = $group->{"type"};
		$comment = $group->{"comment"};

		@u=();
		$members="";
		if ($type eq "global") {
		    if (Win32::NetAdmin::GroupGetMembers("\\\\".Win32::NodeName, "$x", \@u)) {
			$members="@u";
		    } else {
			warn "Error attempting to get members of global group, $x.\n";
		    }
		} else { #must be local group
		    if (Win32::NetAdmin::LocalGroupGetMembersWithDomain("\\\\".Win32::NodeName, $x, \@u)) {
			$members="@u";
		    } else {
			warn "Error attempting to get members of local group, $x.\n";
		    }
		}

		my $str=qq[name="$name" type="$type" comment="$comment" members="$members"];
		push(@Response, $str);
		print "Groups-$#Response: $str\n" if $main::Debug;
	    }
	}

	@Response = ForceMultipleResponses(\@Response);
	return @Response;
}


###########################################################################
# End of MSWin32.pm
###########################################################################

1;
