/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2005 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people
listed in contributors.txt.

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.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "..\..\core\commonheaders.h"

#define IDLEMOD "Idle"
#define IDL_USERIDLECHECK "UserIdleCheck"
#define IDL_IDLEMETHOD    "IdleMethod"
#define IDL_IDLETIME1ST   "IdleTime1st"
#define IDL_IDLEONSAVER   "IdleOnSaver" // IDC_SCREENSAVER
#define IDL_IDLEONFULLSCR "IdleOnFullScr" // IDC_FULLSCREEN
#define IDL_IDLEONLOCK    "IdleOnLock" // IDC_LOCKED
#define IDL_IDLEONTSDC    "IdleOnTerminalDisconnect" //
#define IDL_IDLEPRIVATE   "IdlePrivate" // IDC_IDLEPRIVATE
#define IDL_IDLESTATUSLOCK "IdleStatusLock" // IDC_IDLESTATUSLOCK
#define IDL_AAENABLE      "AAEnable"
#define IDL_AASTATUS      "AAStatus"

#define IdleObject_IsIdle(obj) (obj->state&0x1)
#define IdleObject_SetIdle(obj) (obj->state|=0x1)
#define IdleObject_ClearIdle(obj) (obj->state&=~0x1)

// either use meth 0, 1 or figure out which one
#define IdleObject_UseMethod0(obj) (obj->state&=~0x2)
#define IdleObject_UseMethod1(obj) (obj->state|=0x2)
#define IdleObject_GetMethod(obj) (obj->state&0x2)

#define IdleObject_IdleCheckSaver(obj) (obj->state&0x4)
#define IdleObject_SetSaverCheck(obj) (obj->state|=0x4)

#define IdleObject_IdleCheckWorkstation(obj) (obj->state&0x8)
#define IdleObject_SetWorkstationCheck(obj) (obj->state|=0x8)

#define IdleObject_IsPrivacy(obj) (obj->state&0x10)
#define IdleObject_SetPrivacy(obj) (obj->state|=0x10)

#define IdleObject_SetStatusLock(obj) (obj->state|=0x20)

#define IdleObject_IdleCheckTerminal(obj) (obj->state&0x40)
#define IdleObject_SetTerminalCheck(obj) (obj->state|=0x40)

#define IdleObject_IdleCheckFullScr(obj) (obj->state&0x80)
#define IdleObject_SetFullScrCheck(obj) (obj->state|=0x80)

//#include <Wtsapi32.h>

#ifndef _INC_WTSAPI

#define WTS_CURRENT_SERVER_HANDLE  ((HANDLE)NULL)
#define WTS_CURRENT_SESSION ((DWORD)-1)

typedef enum _WTS_CONNECTSTATE_CLASS {
    WTSActive,              // User logged on to WinStation
    WTSConnected,           // WinStation connected to client
    WTSConnectQuery,        // In the process of connecting to client
    WTSShadow,              // Shadowing another WinStation
    WTSDisconnected,        // WinStation logged on without client
    WTSIdle,                // Waiting for client to connect
    WTSListen,              // WinStation is listening for connection
    WTSReset,               // WinStation is being reset
    WTSDown,                // WinStation is down due to error
    WTSInit,                // WinStation in initialization
} WTS_CONNECTSTATE_CLASS;


typedef enum _WTS_INFO_CLASS {
    WTSInitialProgram, 
    WTSApplicationName, 
    WTSWorkingDirectory, 
    WTSOEMId, 
    WTSSessionId, 
    WTSUserName, 
    WTSWinStationName, 
    WTSDomainName, 
    WTSConnectState, 
    WTSClientBuildNumber, 
    WTSClientName, 
    WTSClientDirectory, 
    WTSClientProductId, 
    WTSClientHardwareId, 
    WTSClientAddress, 
    WTSClientDisplay, 
    WTSClientProtocolType, 
} WTS_INFO_CLASS;

#endif

VOID (WINAPI *_WTSFreeMemory)(PVOID);
BOOL (WINAPI *_WTSQuerySessionInformation)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*);

BOOL bIsWTSApiPresent = FALSE;

static BOOL bModuleInitialized = FALSE;

BOOL InitWTSAPI()
{
	HMODULE hDll = LoadLibraryA("wtsapi32.dll");
	if (hDll) {
		_WTSFreeMemory = (VOID (WINAPI *)(PVOID))GetProcAddress(hDll, "WTSFreeMemory");
		_WTSQuerySessionInformation = (BOOL (WINAPI *)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*))GetProcAddress(hDll, "WTSQuerySessionInformationW");
		
		if (_WTSFreeMemory && _WTSQuerySessionInformation) return 1;
	}
	return 0;
}

BOOL IsTerminalDisconnected()
{
	PVOID pBuffer = NULL;
	DWORD pBytesReturned = 0;
	BOOL result = FALSE;

	if ( !bIsWTSApiPresent)
		return FALSE;

	if (_WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState, &pBuffer, &pBytesReturned)) {
		if (*(PDWORD)pBuffer == WTSDisconnected)
			result = TRUE;
	}
	else bIsWTSApiPresent = FALSE;

	if (pBuffer)
		_WTSFreeMemory(pBuffer);
	return result;
}

typedef struct {
	UINT_PTR hTimer;
	unsigned int useridlecheck;
	unsigned int state;
	unsigned int minutes;	// user setting, number of minutes of inactivity to wait for
	POINT mousepos;
	unsigned int mouseidle;
	int aastatus;
	int idleType;
}
	IdleObject;

static const WORD aa_Status[] = {ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH};

static IdleObject gIdleObject;
static HANDLE hIdleEvent;
static BOOL (WINAPI * MyGetLastInputInfo)(PLASTINPUTINFO);

void CALLBACK IdleTimer(HWND hwnd, UINT umsg, UINT_PTR idEvent, DWORD dwTime);

static void IdleObject_ReadSettings(IdleObject * obj)
{
	obj->useridlecheck = DBGetContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, 0);
	obj->minutes = DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, 10);
	obj->aastatus = !DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? 0 : DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0);
	if (DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, 0)) IdleObject_UseMethod1(obj);
	else IdleObject_UseMethod0(obj);
	if (DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, 0)) IdleObject_SetSaverCheck(obj);
	if (DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONFULLSCR, 0)) IdleObject_SetFullScrCheck(obj);
	if (DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, 0)) IdleObject_SetWorkstationCheck(obj);
	if (DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, 0)) IdleObject_SetPrivacy(obj);
	if (DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, 0)) IdleObject_SetStatusLock(obj);
	if (DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONTSDC, 0)) IdleObject_SetTerminalCheck(obj);
}

static void IdleObject_Create(IdleObject * obj)
{
	ZeroMemory(obj, sizeof(IdleObject));
	obj->hTimer=SetTimer(NULL, 0, 2000, IdleTimer);
	IdleObject_ReadSettings(obj);
}

static void IdleObject_Destroy(IdleObject * obj)
{
	if (IdleObject_IsIdle(obj))
		NotifyEventHooks(hIdleEvent, 0, 0);
	IdleObject_ClearIdle(obj);
	KillTimer(NULL, obj->hTimer);
}

static int IdleObject_IsUserIdle(IdleObject * obj)
{
	DWORD dwTick;
	if (IdleObject_GetMethod(obj)) {
		CallService(MS_SYSTEM_GETIDLE, 0, (LPARAM)&dwTick);
		return GetTickCount() - dwTick > (obj->minutes * 60 * 1000);
	}
	
	if (MyGetLastInputInfo != NULL) {
		LASTINPUTINFO ii;
		ZeroMemory(&ii, sizeof(ii));
		ii.cbSize=sizeof(ii);
		if (MyGetLastInputInfo(&ii)) 
			return GetTickCount() - ii.dwTime > (obj->minutes * 60 * 1000);
	}
	else {
		POINT pt;
		GetCursorPos(&pt);
		if (pt.x != obj->mousepos.x || pt.y != obj->mousepos.y) {
			obj->mousepos=pt;
			obj->mouseidle=0;
		}
		else obj->mouseidle += 2;

		if (obj->mouseidle)
			return obj->mouseidle * 1000 >= (obj->minutes * 60 * 1000);
	}
	return FALSE;
}

static bool IsWorkstationLocked (void)
{
	bool rc = false;

	if (openInputDesktop != NULL) {
		HDESK hDesk = openInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP);
		if (hDesk == NULL)
			rc = true;
		else if (closeDesktop != NULL)
			closeDesktop(hDesk);
	}
	return rc;
}

static bool IsScreenSaverRunning(void)
{
	BOOL rc = FALSE;
	SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &rc, FALSE);
	return rc != 0;
}

bool IsFullScreen(void) 
{
	RECT rcScreen = {0};

	rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
	rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);

	if (MyMonitorFromWindow)
	{
		HMONITOR hMon = MyMonitorFromWindow(cli.hwndContactList, MONITOR_DEFAULTTONEAREST);
		MONITORINFO mi;
		mi.cbSize = sizeof(mi);
		if (MyGetMonitorInfo(hMon, &mi))
			rcScreen = mi.rcMonitor;
	}

	HWND hWndDesktop = GetDesktopWindow();
	HWND hWndShell = GetShellWindow();

	// check foregroundwindow
	HWND hWnd = GetForegroundWindow();
	if (hWnd && hWnd != hWndDesktop && hWnd != hWndShell) 
	{
		TCHAR tszClassName[128] = _T("");
		GetClassName(hWnd, tszClassName, SIZEOF(tszClassName));
		if (_tcscmp(tszClassName, _T("WorkerW")))
		{
			RECT rect, rectw, recti;
			GetWindowRect(hWnd, &rectw);

			GetClientRect(hWnd, &rect);
			ClientToScreen(hWnd, (LPPOINT)&rect);
			ClientToScreen(hWnd, (LPPOINT)&rect.right);
			
			if (EqualRect(&rect, &rectw) && IntersectRect(&recti, &rect, &rcScreen) && 
				EqualRect(&recti, &rcScreen))
				return true;
		}
	}

	return false;
}

static void IdleObject_Tick(IdleObject * obj)
{
	bool idle = false;
	int  idleType = 0, flags = 0;

	if (obj->useridlecheck && IdleObject_IsUserIdle(obj)) {
		idleType = 1; idle = true; 
	}
	else if (IdleObject_IdleCheckSaver(obj) && IsScreenSaverRunning()) {
		idleType = 2; idle = true; 
	}
	else if (IdleObject_IdleCheckFullScr(obj) && IsFullScreen()) {
		idleType = 5; idle = true; 
	}
	else if (IdleObject_IdleCheckWorkstation(obj) && IsWorkstationLocked()) {
		idleType = 3; idle = true; 
	}
	else if (IdleObject_IdleCheckTerminal(obj) && IsTerminalDisconnected()) {
		idleType = 4; idle = true; 
	}

	if (IdleObject_IsPrivacy(obj))
		flags |= IDF_PRIVACY;

	if ( !IdleObject_IsIdle(obj) && idle) {
		IdleObject_SetIdle(obj);
		obj->idleType = idleType;
		NotifyEventHooks(hIdleEvent, 0, IDF_ISIDLE | flags);
	}
	if (IdleObject_IsIdle(obj) && !idle) {
		IdleObject_ClearIdle(obj);
		obj->idleType = 0;
		NotifyEventHooks(hIdleEvent, 0, flags);
}	}

void CALLBACK IdleTimer(HWND, UINT, UINT_PTR idEvent, DWORD)
{
	if (gIdleObject.hTimer == idEvent)
		IdleObject_Tick(&gIdleObject);
}

int IdleGetStatusIndex(WORD status)
{
    int j;
    for (j = 0; j < SIZEOF(aa_Status); j++)
        if (aa_Status[j] == status)
			  return j;

    return 0;
}

static INT_PTR CALLBACK IdleOptsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
	case WM_INITDIALOG:
	{
		int j;
		int method = DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, 0);
		TranslateDialogDefault(hwndDlg);
		CheckDlgButton(hwndDlg, IDC_IDLESHORT, DBGetContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, 0) ? BST_CHECKED : BST_UNCHECKED);
		CheckDlgButton(hwndDlg, IDC_IDLEONWINDOWS, method == 0 ? BST_CHECKED : BST_UNCHECKED);
		CheckDlgButton(hwndDlg, IDC_IDLEONMIRANDA, method ? BST_CHECKED : BST_UNCHECKED);
		CheckDlgButton(hwndDlg, IDC_SCREENSAVER, DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, 0) ? BST_CHECKED : BST_UNCHECKED);
		CheckDlgButton(hwndDlg, IDC_FULLSCREEN, DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONFULLSCR, 0) ? BST_CHECKED : BST_UNCHECKED);
		CheckDlgButton(hwndDlg, IDC_LOCKED, DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, 0) ? BST_CHECKED : BST_UNCHECKED);
		CheckDlgButton(hwndDlg, IDC_IDLEPRIVATE, DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, 0) ? BST_CHECKED : BST_UNCHECKED);
		CheckDlgButton(hwndDlg, IDC_IDLESTATUSLOCK, DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, 0) ? BST_CHECKED : BST_UNCHECKED);
		if ( !bIsWTSApiPresent)
			EnableWindow(GetDlgItem(hwndDlg, IDC_IDLETERMINAL), FALSE);
		else
			CheckDlgButton(hwndDlg, IDC_IDLETERMINAL, DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONTSDC, 0) ? BST_CHECKED : BST_UNCHECKED);
		SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_IDLE1STTIME), 0);
		SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETRANGE32, 1, 60);
		SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, 10), 0));
		SendDlgItemMessage(hwndDlg, IDC_IDLE1STTIME, EM_LIMITTEXT, (WPARAM)2, 0);

      CheckDlgButton(hwndDlg, IDC_AASHORTIDLE, DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? BST_CHECKED:BST_UNCHECKED);
		for (j = 0; j < SIZEOF(aa_Status); j++)
			SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_ADDSTRING, 0, (LPARAM)cli.pfnGetStatusModeDescription(aa_Status[j], 0));

		j = IdleGetStatusIndex((WORD)(DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0)));
		SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_SETCURSEL, j, 0);
		SendMessage(hwndDlg, WM_USER+2, 0, 0);
		return TRUE;
	}
	case WM_USER+2:
	{
		BOOL checked = IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED;
		EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONWINDOWS), checked);
		EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONMIRANDA), checked);
		EnableWindow(GetDlgItem(hwndDlg, IDC_IDLE1STTIME), checked);
		EnableWindow(GetDlgItem(hwndDlg, IDC_AASTATUS), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE) == BST_CHECKED?1:0);
		EnableWindow(GetDlgItem(hwndDlg, IDC_IDLESTATUSLOCK), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE) == BST_CHECKED?1:0);
		break;
	}
	case WM_NOTIFY:
	{
		NMHDR * hdr = (NMHDR *)lParam;
		if (hdr && hdr->code == PSN_APPLY) {
			int method = IsDlgButtonChecked(hwndDlg, IDC_IDLEONWINDOWS) == BST_CHECKED;
			int mins = SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_GETPOS, 0, 0);
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, (BYTE)(HIWORD(mins) == 0 ? LOWORD(mins) : 10));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, (BYTE)(method ? 0 : 1));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SCREENSAVER) == BST_CHECKED));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONFULLSCR, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_FULLSCREEN) == BST_CHECKED));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_LOCKED) == BST_CHECKED));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONTSDC, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLETERMINAL) == BST_CHECKED));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLEPRIVATE) == BST_CHECKED));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE) == BST_CHECKED?1:0));
			DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESTATUSLOCK) == BST_CHECKED?1:0));
			{
				int curSel = SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_GETCURSEL, 0, 0);
				if (curSel != CB_ERR) {
					DBWriteContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, (WORD)(aa_Status[curSel]));
				}
			}
			// destroy any current idle and reset settings.
			IdleObject_Destroy(&gIdleObject);
			IdleObject_Create(&gIdleObject);
		}
		break;
	}
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDC_IDLE1STTIME:
		{
			int min;
			if ((HWND)lParam != GetFocus() || HIWORD(wParam) != EN_CHANGE) return FALSE;
			min=GetDlgItemInt(hwndDlg, IDC_IDLE1STTIME, NULL, FALSE);
			if (min == 0 && GetWindowTextLength(GetDlgItem(hwndDlg, IDC_IDLE1STTIME)))
				SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) 1, 0));
			break;
		}
		case IDC_IDLESHORT:
		case IDC_AASHORTIDLE:
			SendMessage(hwndDlg, WM_USER+2, 0, 0);
			break;

		case IDC_AASTATUS:
			if (HIWORD(wParam) != CBN_SELCHANGE)
				return TRUE;
		}
		SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
		break;
	}
	return FALSE;
}

static int IdleOptInit(WPARAM wParam, LPARAM)
{
	OPTIONSDIALOGPAGE odp = { 0 };
	odp.cbSize = sizeof(odp);
	odp.position = 100000000;
	odp.hInstance = hMirandaInst;
	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_IDLE);
	odp.pszGroup = LPGEN("Status");
	odp.pszTitle = LPGEN("Idle");
	odp.pfnDlgProc = IdleOptsDlgProc;
	odp.flags = ODPF_BOLDGROUPS;
	Options_AddPage(wParam, &odp);
	return 0;
}

static INT_PTR IdleGetInfo(WPARAM, LPARAM lParam)
{
	MIRANDA_IDLE_INFO *mii = (MIRANDA_IDLE_INFO*)lParam;
	if ( !mii || (mii->cbSize != sizeof(MIRANDA_IDLE_INFO) && mii->cbSize != MIRANDA_IDLE_INFO_SIZE_1))
		return 1;

	mii->idleTime = gIdleObject.minutes;
	mii->privacy = gIdleObject.state&0x10;
	mii->aaStatus = gIdleObject.aastatus;
	mii->aaLock = gIdleObject.state&0x20;

	if (mii->cbSize == sizeof(MIRANDA_IDLE_INFO))
		mii->idleType = gIdleObject.idleType;
	return 0;
}

static int IdleModernOptInit(WPARAM wParam, LPARAM)
{
	static const int iBoldControls[] =
	{
		IDC_TXT_TITLE1, IDC_TXT_TITLE2, IDC_TXT_TITLE3, 
		MODERNOPT_CTRL_LAST
	};

	MODERNOPTOBJECT obj = {0};
	obj.cbSize = sizeof(obj);
	obj.hInstance = hMirandaInst;
	obj.dwFlags = MODEROPT_FLG_TCHAR | MODEROPT_FLG_NORESIZE;
	obj.iSection = MODERNOPT_PAGE_STATUS;
	obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
	obj.iBoldControls = (int*)iBoldControls;
	obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_IDLE);
	obj.pfnDlgProc = IdleOptsDlgProc;
//	obj.lpzClassicGroup = "Status";
//	obj.lpzClassicPage = "Messages";
	obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
	CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
	return 0;
}

int LoadIdleModule(void)
{
	bModuleInitialized = TRUE;

	bIsWTSApiPresent = InitWTSAPI();
	MyGetLastInputInfo=(BOOL (WINAPI *)(LASTINPUTINFO*))GetProcAddress(GetModuleHandleA("user32"), "GetLastInputInfo");
	hIdleEvent=CreateHookableEvent(ME_IDLE_CHANGED);
	IdleObject_Create(&gIdleObject);
	CreateServiceFunction(MS_IDLE_GETIDLEINFO, IdleGetInfo);
	HookEvent(ME_OPT_INITIALISE, IdleOptInit);
	HookEvent(ME_MODERNOPT_INITIALIZE, IdleModernOptInit);
	return 0;
}

void UnloadIdleModule()
{
	if ( !bModuleInitialized) return;

	IdleObject_Destroy(&gIdleObject);
	DestroyHookableEvent(hIdleEvent);
	hIdleEvent=NULL;
}