<commit_before>#!python
from __future__ import print_function
import os
import sys
import socket
import time
import ctypes as c
import json

if sys.platform != "win32":
	# simple sanity check
	raise RuntimeError("This script requires Windows NT with Terminal Services.")

import servicemanager as sm
import win32api as Api
from win32con import *
from win32gui import *
from win32ts import *
from win32security import *
import win32service
import win32serviceutil

SERVER_URL = "http://equal.cluenet.org/rwho/server.php"

## Windows native types and constants

# generic types
UINT				= c.c_uint
WORD				= c.c_uint16
DWORD				= c.c_uint32
WCHAR				= c.c_wchar
HANDLE				= DWORD
HWND				= HANDLE

# window messages
WM_WTSSESSION_CHANGE		= 0x2B1

# WM_WTSSESSION_CHANGE events
WTS_CONSOLE_CONNECT		= 0x1
WTS_CONSOLE_DISCONNECT		= 0x2
WTS_REMOTE_CONNECT		= 0x3
WTS_REMOTE_DISCONNECT		= 0x4
WTS_SESSION_LOGON		= 0x5
WTS_SESSION_LOGOFF		= 0x6
WTS_SESSION_LOCK		= 0x7
WTS_SESSION_UNLOCK		= 0x8
WTS_SESSION_REMOTE_CONTROL	= 0x9

# http://msdn.microsoft.com/en-us/library/aa383860(v=vs.85).aspx
WTS_CONNECTSTATE_CLASS	= DWORD # enum
WTSActive		= 0
WTSConnected		= 1
WTSConnectQuery		= 2
WTSShadow		= 3
WTSDisconnected		= 4
WTSIdle			= 5
WTSListen		= 6
WTSReset		= 7
WTSDown			= 8
WTSInit			= 9

# http://msdn.microsoft.com/en-us/library/aa383861(v=vs.85).aspx
WTS_INFO_CLASS		= DWORD # enum
WTSSessionInfo		= 24

# include <winsta.h>
# http://msdn.microsoft.com/en-us/library/cc248871(PROT.10).aspx
WINSTATIONNAME_LENGTH		= 32
USERNAME_LENGTH			= 20
DOMAIN_LENGTH			= 17

class LARGE_INTEGER(c.Structure):
	_fields_ = (
		("HighPart",	DWORD),
		("LowPart",	DWORD),
	)

class FILETIME(c.Structure):
	_fields_ = (
		("dwHighDateTime",	DWORD),
		("dwLowDateTime",	DWORD),
	)

class WTSINFO(c.Structure):
	# http://msdn.microsoft.com/en-us/library/bb736370(v=vs.85).aspx
	_fields_ = (
		("State",			WTS_CONNECTSTATE_CLASS),
		("SessionId",			DWORD),
		("IncomingBytes",		DWORD),
		("OutgoingBytes",		DWORD),
		("IncomingFrames",		DWORD),
		("OutgoingFrames",		DWORD),
		("IncomingCompressedBytes",	DWORD),
		("OutgoingCompressedBytes",	DWORD),
		("WinStationName",		WCHAR * (WINSTATIONNAME_LENGTH+1)),
		("Domain",			WCHAR * (DOMAIN_LENGTH+1)),
		("UserName",			WCHAR * (USERNAME_LENGTH+1)),
		("ConnectTime",			FILETIME),
		("DisconnectTime",		FILETIME),
		("LastInputTime",		FILETIME),
		("LogonTime",			FILETIME),
		("CurrentTime",			FILETIME),
	)

## Windows native functions

def _wtsapi_WTSQuerySessionInformation(hServer, sessionID, infoClass):
	ppBuffer = DWORD(0)
	pBytesReturned = DWORD(0)

	res = c.windll.wtsapi32.WTSQuerySessionInformationW(
		HANDLE(hServer), DWORD(sessionID), WTS_INFO_CLASS(infoClass),
		c.byref(ppBuffer), c.byref(pBytesReturned))

	if res:
		return (ppBuffer, pBytesReturned)
	else:
		print("WTSQuerySessionInformationW: error %r" % Api.GetLastError())
		return (0, 0)

def WTSQuerySessionInformation_SessionInfo(hServer, sessionId):
	# only supported starting with Server 2008 & Vista SP1
	buf, bufsize = _wtsapi_WTSQuerySessionInformation(hServer, sessionId, WTSSessionInfo)
	if bufsize:
		return buf, c.cast(buf.value, c.POINTER(WTSINFO)).contents
	else:
		return None

def SetTimer(hWnd, IDEvent, elapse):
	IDEvent = UINT(IDEvent)
	if c.windll.user32.SetTimer(HWND(hWnd), c.byref(IDEvent), UINT(elapse), None):
		return IDEvent.value
	else:
		return False

def UnixTimeFromFileTime(ftime):
	return (((ftime.dwHighDateTime << 32) | ftime.dwLowDateTime) - 116444736000000000) / 10000000.0

def collect_session_info():
	hServer = WTS_CURRENT_SERVER_HANDLE
	#hServer = WTSOpenServer("...")
	for sess in WTSEnumerateSessions(hServer):
		print("session", sess)

		if sess["State"] != WTSActive:
			# skip inactive (disconnected) sessions
			continue

		sessionId = sess["SessionId"]
		user = WTSQuerySessionInformation(hServer, sessionId, WTSUserName)
		if not user:
			print("skipping (null user)")<commit_msg>agent-win32: fix exception on WinXP<commit_after>#!python
from __future__ import print_function
import os
import sys
import socket
import time
import ctypes as c
import json

if sys.platform != "win32":
	# simple sanity check
	raise RuntimeError("This script requires Windows NT with Terminal Services.")

import servicemanager as sm
import win32api as Api
from win32con import *
from win32gui import *
from win32ts import *
from win32security import *
import win32service
import win32serviceutil

SERVER_URL = "http://equal.cluenet.org/rwho/server.php"

## Windows native types and constants

# generic types
UINT				= c.c_uint
WORD				= c.c_uint16
DWORD				= c.c_uint32
WCHAR				= c.c_wchar
HANDLE				= DWORD
HWND				= HANDLE

# window messages
WM_WTSSESSION_CHANGE		= 0x2B1

# WM_WTSSESSION_CHANGE events
WTS_CONSOLE_CONNECT		= 0x1
WTS_CONSOLE_DISCONNECT		= 0x2
WTS_REMOTE_CONNECT		= 0x3
WTS_REMOTE_DISCONNECT		= 0x4
WTS_SESSION_LOGON		= 0x5
WTS_SESSION_LOGOFF		= 0x6
WTS_SESSION_LOCK		= 0x7
WTS_SESSION_UNLOCK		= 0x8
WTS_SESSION_REMOTE_CONTROL	= 0x9

# http://msdn.microsoft.com/en-us/library/aa383860(v=vs.85).aspx
WTS_CONNECTSTATE_CLASS	= DWORD # enum
WTSActive		= 0
WTSConnected		= 1
WTSConnectQuery		= 2
WTSShadow		= 3
WTSDisconnected		= 4
WTSIdle			= 5
WTSListen		= 6
WTSReset		= 7
WTSDown			= 8
WTSInit			= 9

# http://msdn.microsoft.com/en-us/library/aa383861(v=vs.85).aspx
WTS_INFO_CLASS		= DWORD # enum
WTSSessionInfo		= 24

# include <winsta.h>
# http://msdn.microsoft.com/en-us/library/cc248871(PROT.10).aspx
WINSTATIONNAME_LENGTH		= 32
USERNAME_LENGTH			= 20
DOMAIN_LENGTH			= 17

class LARGE_INTEGER(c.Structure):
	_fields_ = (
		("HighPart",	DWORD),
		("LowPart",	DWORD),
	)

class FILETIME(c.Structure):
	_fields_ = (
		("dwHighDateTime",	DWORD),
		("dwLowDateTime",	DWORD),
	)

class WTSINFO(c.Structure):
	# http://msdn.microsoft.com/en-us/library/bb736370(v=vs.85).aspx
	_fields_ = (
		("State",			WTS_CONNECTSTATE_CLASS),
		("SessionId",			DWORD),
		("IncomingBytes",		DWORD),
		("OutgoingBytes",		DWORD),
		("IncomingFrames",		DWORD),
		("OutgoingFrames",		DWORD),
		("IncomingCompressedBytes",	DWORD),
		("OutgoingCompressedBytes",	DWORD),
		("WinStationName",		WCHAR * (WINSTATIONNAME_LENGTH+1)),
		("Domain",			WCHAR * (DOMAIN_LENGTH+1)),
		("UserName",			WCHAR * (USERNAME_LENGTH+1)),
		("ConnectTime",			FILETIME),
		("DisconnectTime",		FILETIME),
		("LastInputTime",		FILETIME),
		("LogonTime",			FILETIME),
		("CurrentTime",			FILETIME),
	)

## Windows native functions

def _wtsapi_WTSQuerySessionInformation(hServer, sessionID, infoClass):
	ppBuffer = DWORD(0)
	pBytesReturned = DWORD(0)

	res = c.windll.wtsapi32.WTSQuerySessionInformationW(
		HANDLE(hServer), DWORD(sessionID), WTS_INFO_CLASS(infoClass),
		c.byref(ppBuffer), c.byref(pBytesReturned))

	if res:
		return (ppBuffer, pBytesReturned)
	else:
		print("WTSQuerySessionInformationW: error %r" % Api.GetLastError())
		return (0, 0)

def WTSQuerySessionInformation_SessionInfo(hServer, sessionId):
	# only supported starting with Server 2008 & Vista SP1
	buf, bufsize = _wtsapi_WTSQuerySessionInformation(hServer, sessionId, WTSSessionInfo)
	if bufsize:
		return buf, c.cast(buf.value, c.POINTER(WTSINFO)).contents
	else:
		return None, None

def SetTimer(hWnd, IDEvent, elapse):
	IDEvent = UINT(IDEvent)
	if c.windll.user32.SetTimer(HWND(hWnd), c.byref(IDEvent), UINT(elapse), None):
		return IDEvent.value
	else:
		return False

def UnixTimeFromFileTime(ftime):
	return (((ftime.dwHighDateTime << 32) | ftime.dwLowDateTime) - 116444736000000000) / 10000000.0

def collect_session_info():
	hServer = WTS_CURRENT_SERVER_HANDLE
	#hServer = WTSOpenServer("...")
	for sess in WTSEnumerateSessions(hServer):
		print("session", sess)

		if sess["State"] != WTSActive:
			# skip inactive (disconnected) sessions
			continue

		sessionId = sess["SessionId"]
		user = WTSQuerySessionInformation(hServer, sessionId, WTSUserName)
		if not user:
			print("skipping (null user)")
{'fraction_non_alphanumeric': 0.11673003802281369, 'fraction_numerical': 0.034727503168567805, 'mean_word_length': 4.946495855312736, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1031582', 'n_tokens_mistral': 3394, 'n_tokens_neox': 3025, 'n_words': 618}