You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1911 lines
69 KiB
1911 lines
69 KiB
/****************************************************************************/
|
|
/* robosrv.c */
|
|
/* */
|
|
/* RoboServer scalability testing utility source file */
|
|
/* */
|
|
/* Copyright (c) 1999 Microsoft Corporation */
|
|
/****************************************************************************/
|
|
|
|
|
|
#ifdef DBG
|
|
#define _DEBUG
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
#include <winsock2.h>
|
|
#include <commctrl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <process.h>
|
|
#include <time.h>
|
|
#include <tchar.h>
|
|
#include <crtdbg.h>
|
|
#include "resource.h"
|
|
|
|
|
|
#define SIZEOF_ARRAY(a) (sizeof(a)/sizeof((a)[0]))
|
|
|
|
|
|
// These two window messages are for Windows Sockets messages that we request
|
|
// when there are network events
|
|
#define WM_SocketRoboClients WM_APP+0
|
|
#define WM_SocketQueryIdle WM_APP+1
|
|
|
|
// This window message is for inter-thread communication from the canary thread
|
|
// When there is an error, the canary thread sends this message. wParam is
|
|
// a TCHAR pointer that points to the error message to display. lParam is
|
|
// unused and must be set to 0.
|
|
#define WM_DisplayErrorText WM_APP+2
|
|
|
|
#define MAX_ROBOCLIENTS 1000
|
|
#define MAX_RCNAME 84
|
|
#define MAX_STATUS 120
|
|
#define MAX_SCRIPTLEN 100
|
|
#define MAX_EDIT_TEXT_LENGTH 100
|
|
#define MAX_PENDINGINFO 64
|
|
#define MAX_DELAYTEXT 8
|
|
#define MAX_RECV_CLIENT_DATA 128
|
|
#define MAX_NUMBERTEXT 8
|
|
#define MAX_TERMSRVRNAME 100
|
|
#define MAX_DISPLAY_STRING_LENGTH 200
|
|
|
|
#define DEBUG_STRING_LEN 200
|
|
|
|
#define COLUMNONEWIDTH 150
|
|
#define COLUMNTWOWIDTH 135
|
|
#define COLUMNTHREEWIDTH 45
|
|
#define COLUMNFOURWIDTH 150
|
|
|
|
#define STATE_CONNECTED 1
|
|
#define STATE_RUNNING 2
|
|
#define STATE_DISCONNECTED 3
|
|
#define STATE_PENDING_SCRIPT 4
|
|
|
|
#define TIMEBUFSIZE 100
|
|
|
|
#define NUM_TABBED_ITEMS 7
|
|
|
|
const u_short LISTENER_SOCKET = 9877;
|
|
const u_short QUERYIDLE_LISTENER_SOCKET = 9878;
|
|
|
|
|
|
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
|
|
|
|
SOCKET SockInit(u_short port);
|
|
|
|
int DisplayErrorText(TCHAR *psText);
|
|
|
|
int GetRCIndexFromRCItem(int iRightClickedItem);
|
|
|
|
int CALLBACK colcmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
|
|
|
|
int TimedRunScriptOnSelectedItems(HWND hwnd, TCHAR *psScriptName);
|
|
|
|
int SendRunCommand(int iRCIndex);
|
|
|
|
int RunCommandOnSelectedItems(HWND hwnd, TCHAR *psCommandName);
|
|
|
|
int ProcessTimerMessage(HWND hwnd, WPARAM wParam);
|
|
|
|
int MorePendingScripts();
|
|
|
|
UINT_PTR MySetTimer(HWND hwnd, UINT_PTR nTimer, UINT nTimeout);
|
|
|
|
int MyKillTimer(HWND hwnd, UINT_PTR nTimer);
|
|
|
|
int CancelPendingScripts(HWND hwnd);
|
|
|
|
int GetRCIndexFromSocket(SOCKET wParam);
|
|
|
|
int IsDisconnected(TCHAR *psClientName, int *i);
|
|
|
|
int NumberRunningClients();
|
|
|
|
int NumClientsPerSet(HWND hwnd);
|
|
|
|
int GetDelay(HWND hwnd);
|
|
|
|
int GetSetDelay(HWND hwnd);
|
|
|
|
void __cdecl CanaryThread(void *unused);
|
|
|
|
int GetCommandLineArgs(TCHAR *psCommandLine);
|
|
|
|
int LogToLogFile(char *psLogData);
|
|
|
|
int ToAnsi(char *psDest, const TCHAR *psSrc, int nSizeOfBuffer);
|
|
|
|
int CleanUp(HWND hwnd);
|
|
|
|
void FatalErrMsgBox(HINSTANCE hInstance, UINT nMsgId);
|
|
|
|
LRESULT CALLBACK TabProc(HWND hwnd, UINT Msg,
|
|
WPARAM wParam, LPARAM lParam);
|
|
|
|
struct RoboClientData {
|
|
SOCKET sock;
|
|
int state;
|
|
BOOL valid;
|
|
TCHAR psRCName[MAX_RCNAME]; // The name of this connection
|
|
TCHAR psPendingInfo[MAX_PENDINGINFO]; // Will hold the script name
|
|
};
|
|
typedef struct RoboClientData RoboClientData;
|
|
|
|
|
|
// Globals
|
|
RoboClientData g_RCData[MAX_ROBOCLIENTS + 1];
|
|
|
|
// Queryidle socket
|
|
SOCKET g_qidlesock = INVALID_SOCKET;
|
|
// Listener socket
|
|
SOCKET g_listenersocket = INVALID_SOCKET;
|
|
|
|
// Old procedures for dialog items
|
|
LONG_PTR g_OldProc[NUM_TABBED_ITEMS];
|
|
// HWNDs for dialog items
|
|
HWND g_hwnd[NUM_TABBED_ITEMS];
|
|
|
|
TCHAR g_TermSrvrName[MAX_TERMSRVRNAME];
|
|
TCHAR g_DebugString[DEBUG_STRING_LEN];
|
|
char g_DebugStringA[DEBUG_STRING_LEN];
|
|
|
|
int g_iClientNameColumn;
|
|
int g_iStatusColumn;
|
|
int g_iIndexColumn;
|
|
int g_iTimeStartedColumn;
|
|
int g_CurrentSortColumn = -1;
|
|
int g_nNumConnections = 10;
|
|
|
|
UINT_PTR g_nIDTimer = 1;
|
|
|
|
HMENU g_hPopupMenu;
|
|
HANDLE g_hCanaryEvent;
|
|
HWND g_hListView;
|
|
HWND g_hNumRunning;
|
|
HWND g_hTermSrvEditBox;
|
|
HWND g_hQidleStatus;
|
|
HWND g_hErrorText;
|
|
HWND g_hTB;
|
|
BOOL g_bAscending = FALSE;
|
|
|
|
CRITICAL_SECTION g_LogFileCritSect;
|
|
|
|
// WinMain - entry point
|
|
int APIENTRY WinMain(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
static TCHAR szAppName[] = _T("RoboServer");
|
|
HWND hwnd, hGE, hTSEdit, hDelayEdit, hClientsPerSetEdit;
|
|
HWND hSetDelayEdit, hCheckBox;
|
|
MSG msg;
|
|
WNDCLASSEX wndclass;
|
|
DWORD x;
|
|
WORD wVersionRequested;
|
|
WSADATA wsaData;
|
|
int err;
|
|
SOCKET sock;
|
|
LVCOLUMN lvc;
|
|
TCHAR * psCommandLine;
|
|
TCHAR szClientNameColumn[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR szStatusColumn[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR szIndexColumn[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR szStTimeColumn[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR szDisplayString1[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR szDisplayString2[MAX_DISPLAY_STRING_LENGTH];
|
|
INITCOMMONCONTROLSEX iccex;
|
|
|
|
lpCmdLine; // unused parameter
|
|
hPrevInstance; // unused parameter
|
|
|
|
LoadString(hInstance, IDS_CLIENTNAMECOL, szClientNameColumn,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(hInstance, IDS_STATUSCOL, szStatusColumn,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(hInstance, IDS_INDEXCOL, szIndexColumn,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(hInstance, IDS_STARTTIMECOL, szStTimeColumn,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
|
|
wndclass.cbSize = sizeof(wndclass);
|
|
wndclass.style = CS_HREDRAW | CS_VREDRAW;
|
|
wndclass.lpfnWndProc = WndProc;
|
|
wndclass.cbClsExtra = 0;
|
|
wndclass.cbWndExtra = DLGWINDOWEXTRA;
|
|
wndclass.hInstance = hInstance;
|
|
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON));
|
|
if (wndclass.hIcon == 0) {
|
|
FatalErrMsgBox(hInstance, IDS_LOADICONFAILED);
|
|
return -1;
|
|
}
|
|
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
if (wndclass.hCursor == 0) {
|
|
FatalErrMsgBox(hInstance, IDS_LOADCURSORFAILED);
|
|
return -1;
|
|
}
|
|
wndclass.hbrBackground = (HBRUSH) (COLOR_ACTIVEBORDER + 1);
|
|
wndclass.lpszMenuName = NULL;
|
|
wndclass.lpszClassName = szAppName;
|
|
wndclass.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON));
|
|
if (wndclass.hIconSm == 0) {
|
|
FatalErrMsgBox(hInstance, IDS_LOADSMICONFAILED);
|
|
return -1;
|
|
}
|
|
|
|
// Default value for the terminal server to hit
|
|
LoadString(hInstance, IDS_LABTS, szDisplayString1,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
_tcsncpy(g_TermSrvrName, szDisplayString1, SIZEOF_ARRAY(g_TermSrvrName));
|
|
g_TermSrvrName[SIZEOF_ARRAY(g_TermSrvrName) - 1] = 0;
|
|
|
|
psCommandLine = GetCommandLine();
|
|
|
|
if (psCommandLine == 0) {
|
|
FatalErrMsgBox(hInstance, IDS_COMMANDLINEERR);
|
|
return -1;
|
|
}
|
|
|
|
if (GetCommandLineArgs(psCommandLine) != 0)
|
|
return -1;
|
|
|
|
// Initialize common controls
|
|
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS;
|
|
if (InitCommonControlsEx(&iccex) == FALSE) {
|
|
FatalErrMsgBox(hInstance, IDS_INITCOMCTRLFAIL);
|
|
}
|
|
|
|
if (RegisterClassEx(&wndclass) == 0) {
|
|
FatalErrMsgBox(hInstance, IDS_REGWNDCLASSFAIL);
|
|
return -1;
|
|
}
|
|
|
|
hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), 0, NULL);
|
|
|
|
if (hwnd == 0) {
|
|
FatalErrMsgBox(hInstance, IDS_CREATEMAINWNDERR);
|
|
return -1;
|
|
}
|
|
|
|
wVersionRequested = MAKEWORD( 2, 2 );
|
|
|
|
err = WSAStartup( wVersionRequested, &wsaData );
|
|
|
|
if ( err != 0 ) {
|
|
FatalErrMsgBox(hInstance, IDS_WINSOCKERR);
|
|
return -1;
|
|
}
|
|
|
|
// Initialize incoming socket
|
|
sock = SockInit(LISTENER_SOCKET);
|
|
|
|
if (WSAAsyncSelect(sock, hwnd, WM_SocketRoboClients, FD_ACCEPT | FD_CONNECT) != 0) {
|
|
FatalErrMsgBox(hInstance, IDS_WSAASYNCSELERR);
|
|
goto bad;
|
|
}
|
|
|
|
// Initialize queryidle incoming socket
|
|
sock = SockInit(QUERYIDLE_LISTENER_SOCKET);
|
|
|
|
if (WSAAsyncSelect(sock, hwnd, WM_SocketQueryIdle, FD_ACCEPT | FD_CONNECT) != 0) {
|
|
FatalErrMsgBox(hInstance, IDS_WSAASYNCSELERR);
|
|
goto bad;
|
|
}
|
|
|
|
// store the listener socket for later use
|
|
g_listenersocket = sock;
|
|
|
|
memset(g_RCData, 0, sizeof(RoboClientData) * MAX_ROBOCLIENTS);
|
|
|
|
ShowWindow(hwnd, nCmdShow);
|
|
|
|
g_hNumRunning = GetDlgItem(hwnd, IDC_NUMTOTAL);
|
|
g_hQidleStatus = GetDlgItem(hwnd, IDC_STATIC3);
|
|
g_hErrorText = GetDlgItem(hwnd, IDC_ERRORTEXT);
|
|
g_hListView = GetDlgItem(hwnd, IDC_LISTVIEW);
|
|
g_hTermSrvEditBox = GetDlgItem(hwnd, IDC_TERMSRVEDIT);
|
|
g_hTB = GetDlgItem(hwnd, IDC_SLIDER1);
|
|
|
|
hTSEdit = GetDlgItem(hwnd, IDC_TERMSRVEDIT);
|
|
hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT);
|
|
hClientsPerSetEdit = GetDlgItem(hwnd, IDC_CLIENTSPERSET);
|
|
hSetDelayEdit = GetDlgItem(hwnd, IDC_SETDELAY);
|
|
|
|
_ASSERTE(IsWindow(g_hNumRunning));
|
|
_ASSERTE(IsWindow(g_hQidleStatus));
|
|
_ASSERTE(IsWindow(g_hErrorText));
|
|
_ASSERTE(IsWindow(g_hListView));
|
|
_ASSERTE(IsWindow(g_hTermSrvEditBox));
|
|
_ASSERTE(IsWindow(g_hTB));
|
|
_ASSERTE(IsWindow(hTSEdit));
|
|
_ASSERTE(IsWindow(hDelayEdit));
|
|
_ASSERTE(IsWindow(hClientsPerSetEdit));
|
|
_ASSERTE(IsWindow(hSetDelayEdit));
|
|
|
|
lvc.mask = LVCF_TEXT | LVCF_WIDTH;
|
|
|
|
lvc.pszText = szClientNameColumn;
|
|
lvc.cchTextMax = sizeof(szClientNameColumn);
|
|
lvc.cx = COLUMNONEWIDTH;
|
|
g_iClientNameColumn = ListView_InsertColumn(g_hListView, 1, &lvc);
|
|
|
|
lvc.pszText = szStatusColumn;
|
|
lvc.cchTextMax = sizeof(szStatusColumn);
|
|
lvc.cx = COLUMNTWOWIDTH;
|
|
g_iStatusColumn = ListView_InsertColumn(g_hListView, 2, &lvc);
|
|
|
|
lvc.pszText = szIndexColumn;
|
|
lvc.cchTextMax = sizeof(szIndexColumn);
|
|
lvc.cx = COLUMNTHREEWIDTH;
|
|
g_iIndexColumn = ListView_InsertColumn(g_hListView, 3, &lvc);
|
|
|
|
lvc.pszText = szStTimeColumn;
|
|
lvc.cchTextMax = sizeof(szStTimeColumn);
|
|
lvc.cx = COLUMNFOURWIDTH;
|
|
g_iTimeStartedColumn = ListView_InsertColumn(g_hListView, 4, &lvc);
|
|
|
|
LoadString(hInstance, IDS_WELCOME, szDisplayString1,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString1);
|
|
SetWindowText(hTSEdit, g_TermSrvrName);
|
|
SetWindowText(hDelayEdit, _T("30"));
|
|
SetWindowText(hClientsPerSetEdit, _T("10"));
|
|
SetWindowText(hSetDelayEdit, _T("15"));
|
|
|
|
// Initialize Graphic Equalizer
|
|
hGE = GetDlgItem(hwnd, IDC_PROGRESS1);
|
|
_ASSERTE(IsWindow(hGE));
|
|
SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
|
|
SendMessage(hGE, PBM_SETPOS, 8, 0);
|
|
|
|
hGE = GetDlgItem(hwnd, IDC_PROGRESS2);
|
|
_ASSERTE(IsWindow(hGE));
|
|
SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
|
|
SendMessage(hGE, PBM_SETPOS, 7, 0);
|
|
|
|
hGE = GetDlgItem(hwnd, IDC_PROGRESS3);
|
|
_ASSERTE(IsWindow(hGE));
|
|
SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
|
|
SendMessage(hGE, PBM_SETPOS, 6, 0);
|
|
|
|
hGE = GetDlgItem(hwnd, IDC_PROGRESS4);
|
|
_ASSERTE(IsWindow(hGE));
|
|
SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
|
|
SendMessage(hGE, PBM_SETPOS, 6, 0);
|
|
|
|
hGE = GetDlgItem(hwnd, IDC_PROGRESS5);
|
|
_ASSERTE(IsWindow(hGE));
|
|
SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
|
|
SendMessage(hGE, PBM_SETPOS, 7, 0);
|
|
|
|
hGE = GetDlgItem(hwnd, IDC_PROGRESS6);
|
|
_ASSERTE(IsWindow(hGE));
|
|
SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
|
|
SendMessage(hGE, PBM_SETPOS, 8, 0);
|
|
|
|
// Initialize Slider control IDC_SLIDER1 for number of RC connections
|
|
// per client
|
|
{
|
|
TCHAR buffer[6];
|
|
|
|
SendMessage(g_hTB, TBM_SETRANGE, (WPARAM) (BOOL) TRUE,
|
|
(LPARAM) MAKELONG(1, 20));
|
|
SendMessage(g_hTB, TBM_SETTICFREQ, (WPARAM) 1,
|
|
(LPARAM) 0);
|
|
SendMessage(g_hTB, TBM_SETSEL, (WPARAM) (BOOL) TRUE,
|
|
MAKELONG(1, g_nNumConnections));
|
|
// Now set the number to "M"
|
|
_stprintf(buffer, _T("%d"), 20);
|
|
SetWindowText(GetDlgItem(hwnd, IDC_STATIC6), buffer);
|
|
}
|
|
|
|
// make number of connections a command line param
|
|
SendMessage(g_hTB, TBM_SETPOS, (WPARAM) (BOOL) TRUE, (LPARAM) g_nNumConnections);
|
|
|
|
// Initialize check box
|
|
hCheckBox = GetDlgItem(hwnd, IDC_CANARYCHECK);
|
|
_ASSERTE(IsWindow(hCheckBox));
|
|
SendMessage(hCheckBox, BM_SETCHECK, BST_CHECKED, 0);
|
|
|
|
// Clear qidle status
|
|
SetWindowText(g_hQidleStatus, _T(""));
|
|
|
|
g_hPopupMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1));
|
|
if (g_hPopupMenu == 0) {
|
|
LoadString(hInstance, IDS_POPUPMENULOADERR, szDisplayString1,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString1);
|
|
}
|
|
g_hPopupMenu = GetSubMenu(g_hPopupMenu, 0);
|
|
|
|
// Initialize critical section for log file
|
|
InitializeCriticalSection(&g_LogFileCritSect);
|
|
|
|
// Initialize everything required for canary thread, and then create the
|
|
// canary thread first, create auto-reset, doesn't start in signaled state
|
|
// event
|
|
if ((g_hCanaryEvent = CreateEvent(0, FALSE, FALSE, NULL)) == NULL) {
|
|
FatalErrMsgBox(hInstance, IDS_CANARYEVENTERR);
|
|
goto bad;
|
|
}
|
|
if (_beginthread(CanaryThread, 0, hwnd) == -1) {
|
|
FatalErrMsgBox(hInstance, IDS_CANARYTHREADERR);
|
|
goto bad;
|
|
}
|
|
|
|
_ASSERTE(SetFocus(g_hListView) != NULL);
|
|
|
|
// Store old window procedures for controls so that I can subclass them
|
|
// Also, store the HWND of each control for searching
|
|
g_OldProc[0] = SetWindowLongPtr(g_hListView, GWLP_WNDPROC,
|
|
(LONG_PTR) TabProc);
|
|
g_hwnd[0] = g_hListView;
|
|
g_OldProc[1] = SetWindowLongPtr(g_hTB, GWLP_WNDPROC,
|
|
(LONG_PTR) TabProc);
|
|
g_hwnd[1] = g_hTB;
|
|
g_OldProc[2] = SetWindowLongPtr(hCheckBox, GWLP_WNDPROC,
|
|
(LONG_PTR) TabProc);
|
|
g_hwnd[2] = hCheckBox;
|
|
g_OldProc[3] = SetWindowLongPtr(g_hTermSrvEditBox, GWLP_WNDPROC,
|
|
(LONG_PTR) TabProc);
|
|
g_hwnd[3] = g_hTermSrvEditBox;
|
|
g_OldProc[4] = SetWindowLongPtr(hClientsPerSetEdit, GWLP_WNDPROC,
|
|
(LONG_PTR) TabProc);
|
|
g_hwnd[4] = hClientsPerSetEdit;
|
|
g_OldProc[5] = SetWindowLongPtr(hDelayEdit, GWLP_WNDPROC,
|
|
(LONG_PTR) TabProc);
|
|
g_hwnd[5] = hDelayEdit;
|
|
g_OldProc[6] = SetWindowLongPtr(hSetDelayEdit, GWLP_WNDPROC,
|
|
(LONG_PTR) TabProc);
|
|
g_hwnd[6] = hSetDelayEdit;
|
|
|
|
_ASSERTE(g_OldProc[0] != 0);
|
|
_ASSERTE(g_OldProc[1] != 0);
|
|
_ASSERTE(g_OldProc[2] != 0);
|
|
_ASSERTE(g_OldProc[3] != 0);
|
|
_ASSERTE(g_OldProc[4] != 0);
|
|
_ASSERTE(g_OldProc[5] != 0);
|
|
_ASSERTE(g_OldProc[6] != 0);
|
|
|
|
|
|
while(GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
return (int) msg.wParam;
|
|
|
|
bad:
|
|
WSACleanup();
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
// receives window messages and deals with them
|
|
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TCHAR szDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
|
|
switch (iMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
// Close all open connections
|
|
CleanUp(hwnd);
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case ID_RUNSCRIPT_KNOWLEDGEWORKER:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("KnowWkr"));
|
|
break;
|
|
case ID_RUNSCRIPT_KNOWLEDGEWORKERFAST:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("FastKW"));
|
|
break;
|
|
case ID_RUNSCRIPT_ADMINISTRATIVEWORKER:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("AdminWkr"));
|
|
break;
|
|
case ID__RUNSCRIPT_DATA:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("taskwkr"));
|
|
break;
|
|
case ID__RUNSCRIPT_STW:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("stw"));
|
|
break;
|
|
case ID__RUNSCRIPT_HPW:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("hpw"));
|
|
break;
|
|
case ID__RUNSCRIPT_BLANK:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("blank"));
|
|
break;
|
|
case ID__RUNSCRIPT_CONFIGURATIONSCRIPT:
|
|
TimedRunScriptOnSelectedItems(hwnd, _T("config"));
|
|
break;
|
|
case ID__UPDATE:
|
|
RunCommandOnSelectedItems(hwnd, _T("update"));
|
|
break;
|
|
case ID__REBOOT:
|
|
RunCommandOnSelectedItems(hwnd, _T("reboot"));
|
|
break;
|
|
case ID_CANCEL:
|
|
CancelPendingScripts(hwnd);
|
|
break;
|
|
default:
|
|
OutputDebugString(_T("Unhandled WM_COMMAND: "));
|
|
wsprintf(g_DebugString, _T("%d\n"), LOWORD(wParam));
|
|
OutputDebugString(g_DebugString);
|
|
break;
|
|
}
|
|
break;
|
|
case WM_CREATE:
|
|
break;
|
|
case WM_CHAR:
|
|
break;
|
|
case WM_TIMER:
|
|
ProcessTimerMessage(hwnd, wParam);
|
|
return 0;
|
|
case WM_KEYDOWN:
|
|
// NOTE INTENTIONAL FALLTHROUGH!
|
|
case WM_SYSKEYDOWN:
|
|
if (wParam == VK_TAB) {
|
|
SetFocus(g_hwnd[0]);
|
|
}
|
|
break;
|
|
case WM_DisplayErrorText:
|
|
return DisplayErrorText((TCHAR *) wParam);
|
|
case WM_NOTIFY:
|
|
{
|
|
switch (((LPNMHDR) lParam)->code)
|
|
{
|
|
case NM_RCLICK:
|
|
{
|
|
POINT pnt;
|
|
|
|
if (ListView_GetSelectedCount(g_hListView) > 0) {
|
|
GetCursorPos(&pnt);
|
|
|
|
TrackPopupMenu(g_hPopupMenu, 0, pnt.x, pnt.y, 0, hwnd,
|
|
0);
|
|
}
|
|
}
|
|
break;
|
|
case LVN_ODCACHEHINT:
|
|
break;
|
|
case LVN_COLUMNCLICK:
|
|
if (g_CurrentSortColumn ==
|
|
((LPNMLISTVIEW)lParam)->iSubItem)
|
|
g_bAscending = !g_bAscending;
|
|
else
|
|
g_bAscending = TRUE;
|
|
|
|
g_CurrentSortColumn = ((LPNMLISTVIEW)lParam)->iSubItem;
|
|
|
|
if (ListView_SortItems(g_hListView, colcmp,
|
|
((LPNMLISTVIEW)lParam)->iSubItem) == FALSE)
|
|
OutputDebugString(_T("Sort failed"));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
// WM_SocketQueryIdle is the window message that we are going to request
|
|
// for all information that originates from the queryidle utility. This
|
|
// utility will provide information about what user numbers to re-run as
|
|
// well as when retry limits have been exceeded
|
|
|
|
// line protocol (strings are ASCII and null-terminated):
|
|
// queryidle sends "restart xxx", where xxx is the 1-indexed number of the
|
|
// session to be restarted
|
|
// queryidle sends "frqfail xxx", where xxx is the 1-indexed number of
|
|
// the user session for the status line
|
|
case WM_SocketQueryIdle:
|
|
switch (WSAGETSELECTEVENT(lParam))
|
|
{
|
|
case FD_ACCEPT:
|
|
{
|
|
struct sockaddr_in SockAddr;
|
|
int SockAddrLen;
|
|
|
|
g_qidlesock = accept(wParam, (struct sockaddr *) &SockAddr,
|
|
&SockAddrLen);
|
|
|
|
if (g_qidlesock == INVALID_SOCKET) {
|
|
LoadString(NULL, IDS_INVALIDQIDLESOCKET, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
return TRUE;
|
|
}
|
|
|
|
if (WSAAsyncSelect(g_qidlesock, hwnd, WM_SocketQueryIdle,
|
|
FD_CLOSE | FD_READ) != 0) {
|
|
LoadString(NULL, IDS_WSAASYNCQIDLEERR, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
return TRUE;
|
|
}
|
|
|
|
LoadString(NULL, IDS_QIDLECONNEST, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case FD_READ:
|
|
{
|
|
unsigned n;
|
|
char psData[MAX_RECV_CLIENT_DATA];
|
|
|
|
// SetWindowText(g_hQidleStatus, _T("Qidle data received"));
|
|
|
|
n = recv(g_qidlesock, psData, sizeof(psData), 0);
|
|
|
|
if (n != SOCKET_ERROR) {
|
|
if ((n == strlen("restart xxx") + 1) ||
|
|
(n == strlen("idle xxx") + 1)) {
|
|
// get the number of the connection in question (xxx)
|
|
int nUser;
|
|
|
|
// if it's a restart command
|
|
if (strncmp(psData, "restart ", strlen("restart ")) == 0) {
|
|
|
|
nUser = atoi(&psData[8]);
|
|
// restart the given session if it's already running
|
|
if (g_RCData[nUser - 1].state == STATE_RUNNING) {
|
|
SendRunCommand(nUser - 1);
|
|
} else {
|
|
LoadString(NULL, IDS_QIDLEREPORTWEIRDUSER,
|
|
szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
}
|
|
_snprintf(g_DebugStringA, DEBUG_STRING_LEN,
|
|
"Queryidle indicated that"
|
|
" user smc%03d failed.", nUser);
|
|
LogToLogFile(g_DebugStringA);
|
|
break;
|
|
}
|
|
// if it's the frqfail command
|
|
if (strncmp(psData, "frqfail ", strlen("frqfail ")) == 0) {
|
|
|
|
nUser = atoi(&psData[8]);
|
|
// set the status to the fact that xxx
|
|
// is frequently failing
|
|
wsprintf(g_DebugString, _T("User smc%03d has failed ")
|
|
_T("to run correctly for too long and will ")
|
|
_T("be logged off"), nUser);
|
|
SetWindowText(g_hQidleStatus, g_DebugString);
|
|
ToAnsi(g_DebugStringA, g_DebugString, DEBUG_STRING_LEN);
|
|
LogToLogFile(g_DebugStringA);
|
|
break;
|
|
}
|
|
// if it's the idle notification
|
|
if (strncmp(psData, "idle ", strlen("idle ")) == 0) {
|
|
LoadString(NULL, IDS_USERISIDLE, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
// I think this is fixed now, but haven't tested
|
|
nUser = atoi(&psData[5]);
|
|
wsprintf(g_DebugString, szDisplayString,
|
|
nUser);
|
|
SetWindowText(g_hQidleStatus, g_DebugString);
|
|
ToAnsi(g_DebugStringA, g_DebugString, DEBUG_STRING_LEN);
|
|
LogToLogFile(g_DebugStringA);
|
|
break;
|
|
}
|
|
// else display an error
|
|
LoadString(NULL, IDS_QIDLESENTGIBBERISH, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
} else {
|
|
LoadString(NULL, IDS_QIDLESENTWRONGLENGTH,
|
|
szDisplayString, MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
}
|
|
|
|
} else {
|
|
LoadString(NULL, IDS_QIDLESOCKERR, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case FD_CLOSE:
|
|
{
|
|
LoadString(NULL, IDS_QIDLESAYSGOODBYE, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hQidleStatus, szDisplayString);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case WM_SocketRoboClients:
|
|
switch (WSAGETSELECTEVENT(lParam))
|
|
{
|
|
case FD_ACCEPT:
|
|
{
|
|
struct sockaddr_in SockAddr;
|
|
int SockAddrLen, i, iItemIndex;
|
|
HWND hTB;
|
|
TCHAR psSockAppend[9]; // ".(.....)" + 1
|
|
char psNumConnections[2]; // one char null terminated
|
|
TCHAR psIndex[5]; // up to 4 digits + null
|
|
TCHAR psClientName[MAX_RCNAME];
|
|
char psClientNameA[MAX_RCNAME];
|
|
int nSliderPos;
|
|
SOCKET sock;
|
|
struct hostent * he;
|
|
LVITEM lvi;
|
|
|
|
LoadString(NULL, IDS_PROCESSINGCONNREQ, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString);
|
|
|
|
SockAddrLen = sizeof(SockAddr);
|
|
|
|
sock = accept(wParam, (struct sockaddr *) &SockAddr,
|
|
&SockAddrLen);
|
|
|
|
// gethostbyaddr tries to confuse us by taking a char * when
|
|
// it really wants this peculiar sin_addr thing
|
|
// The second argument to this function ("4") is the length of
|
|
// the address.
|
|
he = gethostbyaddr((char *)&SockAddr.sin_addr, 4, AF_INET);
|
|
if (he == NULL) {
|
|
LoadString(NULL, IDS_GETHOSTFAILED, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString);
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(psClientNameA, he->h_name);
|
|
#ifdef UNICODE
|
|
MultiByteToWideChar(CP_ACP, 0, psClientNameA, -1,
|
|
psClientName, MAX_RCNAME);
|
|
#else
|
|
strcpy(psClientName, psClientNameA);
|
|
#endif
|
|
_tcstok(psClientName, _T(".")); // Kill domain
|
|
|
|
// See if there is a disconnected client by that name
|
|
if (IsDisconnected(psClientName, &i)) {
|
|
|
|
// Good--we've found one--remove that list item now
|
|
LVFINDINFO lvfi;
|
|
int iListViewIndex;
|
|
|
|
lvfi.flags = LVFI_STRING;
|
|
lvfi.psz = g_RCData[i].psRCName;
|
|
lvfi.lParam = 0;
|
|
lvfi.vkDirection = 0;
|
|
iListViewIndex = ListView_FindItem(g_hListView, -1, &lvfi);
|
|
if (ListView_DeleteItem(g_hListView, iListViewIndex)
|
|
== FALSE) {
|
|
LoadString(NULL, IDS_COULDNOTDELITEM, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString);
|
|
}
|
|
} else {
|
|
|
|
// Find a spot in our g_RCData array
|
|
for (i = 0; i < MAX_ROBOCLIENTS; i++)
|
|
if (g_RCData[i].valid == FALSE) break;
|
|
}
|
|
|
|
g_RCData[i].valid = TRUE;
|
|
g_RCData[i].sock = sock;
|
|
|
|
LoadString(NULL, IDS_CLIENTCONNECTED, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
wsprintf(g_DebugString, szDisplayString, i + 1);
|
|
SetWindowText(g_hErrorText, g_DebugString);
|
|
|
|
if (g_RCData[i].sock == INVALID_SOCKET) {
|
|
LoadString(NULL, IDS_INVALIDSOCKETFROMACCEPT,
|
|
szDisplayString, MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString);
|
|
g_RCData[i].valid = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
// Send it the number of connections it is to make
|
|
// Determine the position of the slider control
|
|
nSliderPos = (int) SendMessage(g_hTB, TBM_GETPOS, 0, 0);
|
|
psNumConnections[0] = (char) (nSliderPos + '0');
|
|
psNumConnections[1] = 0; // null terminate
|
|
if (send(g_RCData[i].sock, psNumConnections,
|
|
sizeof(psNumConnections), 0) == SOCKET_ERROR) {
|
|
LoadString(NULL, IDS_SENDERRNUMCONN, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString);
|
|
return FALSE;
|
|
}
|
|
|
|
// Add the incoming connection to the list box
|
|
|
|
// this won't append a null if count is less than psClientName,
|
|
// which is bad
|
|
_tcsncpy(g_RCData[i].psRCName, psClientName,
|
|
MAX_RCNAME - _tcslen(_T(" (%d)")) - 1);
|
|
|
|
// clean up display a bit
|
|
_tcstok(g_RCData[i].psRCName, _T("."));
|
|
|
|
// add socket number to entry for multiplexing
|
|
_sntprintf(psSockAppend, 9, _T(" (%d)"), g_RCData[i].sock);
|
|
_tcscat(g_RCData[i].psRCName, psSockAppend);
|
|
|
|
// create the actual list view item
|
|
lvi.mask = LVIF_TEXT | LVIF_PARAM;
|
|
lvi.iItem = (int) SendMessage(g_hListView, LVM_GETITEMCOUNT, 0, 0);
|
|
lvi.iSubItem = 0;
|
|
lvi.pszText = g_RCData[i].psRCName;
|
|
lvi.cchTextMax = sizeof(g_RCData[i].psRCName);
|
|
lvi.lParam = (LPARAM) (char *)g_RCData[i].psRCName;
|
|
iItemIndex = ListView_InsertItem(g_hListView, &lvi);
|
|
|
|
g_RCData[i].state = STATE_CONNECTED;
|
|
LoadString(NULL, IDS_CONNECTED, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, szDisplayString);
|
|
|
|
// set the index field
|
|
wsprintf(psIndex, _T("%03d"), i + 1);
|
|
ListView_SetItemText(g_hListView, iItemIndex, g_iIndexColumn, psIndex);
|
|
|
|
// Now set up notification for this socket
|
|
if (WSAAsyncSelect(g_RCData[i].sock, hwnd,
|
|
WM_SocketRoboClients, FD_CLOSE | FD_READ) !=
|
|
SOCKET_ERROR) {
|
|
return TRUE;
|
|
} else {
|
|
LoadString(NULL, IDS_ERRORCANTRECVNOTIFICATIONS,
|
|
szDisplayString, MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn,
|
|
szDisplayString);
|
|
return TRUE;
|
|
}
|
|
}
|
|
case FD_CONNECT:
|
|
// MessageBox(0, _T("Error"), _T("Received connect unexpectedly"), 0);
|
|
break;
|
|
case FD_CLOSE:
|
|
{
|
|
int i;
|
|
int iListViewIndex;
|
|
LVFINDINFO lvfi;
|
|
TCHAR psNumberText[MAX_NUMBERTEXT];
|
|
|
|
LoadString(NULL, IDS_ROBOCLIDISCON, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, szDisplayString);
|
|
|
|
// find the entry that corresponds to our socket
|
|
i = GetRCIndexFromSocket(wParam);
|
|
|
|
// Find the spot in the ListView that has this Client Name
|
|
lvfi.flags = LVFI_STRING;
|
|
lvfi.psz = g_RCData[i].psRCName;
|
|
lvfi.lParam = 0;
|
|
lvfi.vkDirection = 0;
|
|
iListViewIndex = ListView_FindItem(g_hListView, -1, &lvfi);
|
|
|
|
g_RCData[i].state = STATE_DISCONNECTED;
|
|
|
|
// wsprintf(debugString, "Deleting socket %d from index %d of g_RCData[] (%s)", wParam,
|
|
// i, g_RCData[i].psRCName);
|
|
// SetWindowText(hErrorText, debugString);
|
|
|
|
// Update number running
|
|
wsprintf(psNumberText, _T("%d"), NumberRunningClients());
|
|
SetWindowText(g_hNumRunning, psNumberText);
|
|
|
|
|
|
// Set text of column to "Lost Connection"
|
|
LoadString(NULL, IDS_LOSTCONNECTION, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iListViewIndex,
|
|
g_iStatusColumn, szDisplayString);
|
|
|
|
// Erase the time started column
|
|
ListView_SetItemText(g_hListView, iListViewIndex,
|
|
g_iTimeStartedColumn, _T(""));
|
|
|
|
}
|
|
break;
|
|
case FD_READ:
|
|
{
|
|
int iRCIndex, n, iListViewIndex;
|
|
char psData[MAX_RECV_CLIENT_DATA];
|
|
LVFINDINFO lvfi;
|
|
iRCIndex = GetRCIndexFromSocket(wParam);
|
|
|
|
n = recv(g_RCData[iRCIndex].sock, psData, sizeof(psData), 0);
|
|
|
|
if (n == SOCKET_ERROR) {
|
|
OutputDebugString(_T("FD_READ but SOCKET_ERROR on recv"));
|
|
} else {
|
|
lvfi.flags = LVFI_STRING;
|
|
lvfi.psz = g_RCData[iRCIndex].psRCName;
|
|
lvfi.lParam = 0;
|
|
lvfi.vkDirection = 0;
|
|
iListViewIndex = ListView_FindItem(g_hListView, -1,
|
|
&lvfi);
|
|
if (strncmp(psData, "errorsmclient", (n > 13) ? 13 : n)
|
|
== 0) {
|
|
LoadString(NULL, IDS_SMCLIENTRUNERR, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iListViewIndex,
|
|
g_iStatusColumn, szDisplayString);
|
|
} else if (strncmp(psData, "errorcreate",
|
|
(n > 11) ? 11 : n) == 0) {
|
|
LoadString(NULL, IDS_CREATESCRERR, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iListViewIndex,
|
|
g_iStatusColumn, szDisplayString);
|
|
} else if (strncmp(psData, "success", (n > 11) ? 11 : n) == 0) {
|
|
|
|
SYSTEMTIME startloctime;
|
|
TCHAR psStartTimeDatePart[TIMEBUFSIZE];
|
|
TCHAR psStartTimeTimePart[TIMEBUFSIZE];
|
|
TCHAR psStartTime[TIMEBUFSIZE * 2];
|
|
|
|
GetLocalTime(&startloctime); // set starttime
|
|
|
|
GetDateFormat(0, 0, &startloctime, 0, psStartTimeDatePart, TIMEBUFSIZE);
|
|
GetTimeFormat(0, 0, &startloctime, 0, psStartTimeTimePart, TIMEBUFSIZE);
|
|
|
|
wsprintf(psStartTime, _T("%s %s"), psStartTimeDatePart, psStartTimeTimePart);
|
|
|
|
ListView_SetItemText(g_hListView, iListViewIndex,
|
|
g_iTimeStartedColumn, psStartTime);
|
|
LoadString(NULL, IDS_SCRIPTSTARTED, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iListViewIndex,
|
|
g_iStatusColumn, szDisplayString);
|
|
} else {
|
|
LoadString(NULL, IDS_UNKNOWNROBOTALK, szDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iListViewIndex,
|
|
g_iStatusColumn, szDisplayString);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hwnd, iMsg, wParam, lParam);
|
|
}
|
|
|
|
// The canary architecture works like this: The canary thread (i.e., this
|
|
// function) is spawned when the application initializes, and immediately
|
|
// blocks on g_hCanaryEvent. The main app, when it is time for the canary
|
|
// to run, signals the event. Then the canary blocks on the timer script
|
|
// (called "canary" so it can be a "canary.cmd," a "canary.bat," a
|
|
// "canary.exe," etc.), writes how long it took to a file, and then blocks
|
|
// again.
|
|
void __cdecl CanaryThread(void *unused) {
|
|
HWND hwnd = (HWND) unused;
|
|
HWND hButton;
|
|
int bCheck;
|
|
FILE *fp;
|
|
SYSTEMTIME timelocinit;
|
|
SYSTEMTIME timelocfin;
|
|
FILETIME ftinit;
|
|
FILETIME ftfin;
|
|
ULARGE_INTEGER nInit;
|
|
ULARGE_INTEGER nFin;
|
|
ULARGE_INTEGER nDiffTime;
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR psNumRunning[MAX_NUMBERTEXT];
|
|
TCHAR psTimeDatePart[TIMEBUFSIZE];
|
|
TCHAR psTimeTimePart[TIMEBUFSIZE];
|
|
char psNumRunningA[MAX_NUMBERTEXT];
|
|
char psTimeDatePartA[TIMEBUFSIZE];
|
|
char psTimeTimePartA[TIMEBUFSIZE];
|
|
|
|
hButton = GetDlgItem(hwnd, IDC_CANARYCHECK);
|
|
|
|
for( ; ; ) {
|
|
WaitForSingleObject(g_hCanaryEvent, INFINITE);
|
|
|
|
// Check checkbox to see if "run canary automatically" is on
|
|
// IDC_CANARYCHECK
|
|
bCheck = (int) SendMessage(hButton, BM_GETCHECK, 0, 0);
|
|
if (bCheck != 0) {
|
|
// FUNCTIONALITY CHANGE: Canary delays the delay between
|
|
// multiselect commands before starting
|
|
LoadString(NULL, IDS_CANARYDELAYING, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString,
|
|
0);
|
|
Sleep(GetDelay(hwnd));
|
|
LoadString(NULL, IDS_CANARYSTARTING, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString,
|
|
0);
|
|
// Get the time
|
|
GetLocalTime(&timelocinit);
|
|
// Get number of scripts attempted
|
|
GetWindowText(g_hNumRunning, psNumRunning, MAX_NUMBERTEXT);
|
|
// run the script
|
|
if (_spawnl(_P_WAIT, "canary", "canary", 0) != 0) {
|
|
LoadString(NULL, IDS_CANARYCOULDNTSTART, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SendMessage(hwnd, WM_DisplayErrorText,
|
|
(WPARAM) psDisplayString, 0);
|
|
} else {
|
|
LoadString(NULL, IDS_CANARYFINISHED, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SendMessage(hwnd, WM_DisplayErrorText,
|
|
(WPARAM) psDisplayString, 0);
|
|
}
|
|
// Get the time again
|
|
GetLocalTime(&timelocfin);
|
|
// compute difference
|
|
if ( SystemTimeToFileTime(&timelocinit, &ftinit) &&
|
|
SystemTimeToFileTime(&timelocfin, &ftfin) ) {
|
|
|
|
memcpy(&nInit, &ftinit, sizeof(FILETIME));
|
|
memcpy(&nFin, &ftfin, sizeof(FILETIME));
|
|
// This gives the difference in 100-nanosecond intervals (10^-7 sec).
|
|
nDiffTime.QuadPart = nFin.QuadPart - nInit.QuadPart;
|
|
// Divide by 10^7 to get seconds
|
|
nDiffTime.QuadPart /= 10000000;
|
|
// Get the date and time strings
|
|
GetDateFormat(0, 0, &timelocinit, 0, psTimeDatePart, TIMEBUFSIZE);
|
|
GetTimeFormat(0, 0, &timelocinit, 0, psTimeTimePart, TIMEBUFSIZE);
|
|
// Convert strings to ANSI
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, psTimeDatePart, -1, psTimeDatePartA, TIMEBUFSIZE, 0, 0);
|
|
WideCharToMultiByte(CP_ACP, 0, psTimeTimePart, -1, psTimeTimePartA, TIMEBUFSIZE, 0, 0);
|
|
WideCharToMultiByte(CP_ACP, 0, psNumRunning, -1, psNumRunningA, MAX_NUMBERTEXT, 0, 0);
|
|
#else
|
|
strncpy(psTimeDatePartA, psTimeDatePart, TIMEBUFSIZE);
|
|
strncpy(psTimeTimePartA, psTimeTimePart, TIMEBUFSIZE);
|
|
strncpy(psNumRunningA, psNumRunning, MAX_NUMBERTEXT);
|
|
#endif
|
|
|
|
// open the file
|
|
fp = fopen("canary.csv", "a+t");
|
|
// write the difference to the file
|
|
if (fp != 0) {
|
|
fprintf(fp, "%s %s,%s,%d:%02d\n", psTimeDatePartA, psTimeTimePartA,
|
|
psNumRunningA, (int) nDiffTime.QuadPart / 60, (int) nDiffTime.QuadPart % 60);
|
|
// close the file
|
|
fclose(fp);
|
|
} else {
|
|
LoadString(NULL, IDS_CANARYCOULDNOTOPENFILE, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SendMessage(hwnd, WM_DisplayErrorText,
|
|
(WPARAM) psDisplayString, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// This function displays text in the status line. Returns 0 on success,
|
|
// nonzero on error.
|
|
int DisplayErrorText(TCHAR *psText) {
|
|
SetWindowText(g_hErrorText, psText);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// helper function to find out the index in our data structure from the
|
|
// incoming socket
|
|
int GetRCIndexFromSocket(SOCKET wParam) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_ROBOCLIENTS; i++) {
|
|
if (g_RCData[i].valid == TRUE)
|
|
if (g_RCData[i].sock == wParam)
|
|
break;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
// Initialize the listener socket
|
|
SOCKET SockInit(u_short port) {
|
|
SOCKET listenfd;
|
|
struct sockaddr_in servaddr;
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (listenfd == INVALID_SOCKET) {
|
|
LoadString(NULL, IDS_SOCKETERROR, psDisplayTitleString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(NULL, IDS_SOCKETERROR, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
MessageBox(0, psDisplayString, psDisplayTitleString, 0);
|
|
goto err;
|
|
}
|
|
|
|
memset(&servaddr, 0, sizeof(servaddr));
|
|
servaddr.sin_family = AF_INET;
|
|
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
servaddr.sin_port = htons(port);
|
|
|
|
if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) != 0) {
|
|
LoadString(NULL, IDS_BINDERRTITLE, psDisplayTitleString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(NULL, IDS_BINDERRBODY, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
MessageBox(0, psDisplayString, psDisplayTitleString, 0);
|
|
goto err;
|
|
}
|
|
|
|
if (listen(listenfd, SOMAXCONN) != 0) {
|
|
LoadString(NULL, IDS_LISTENERROR, psDisplayTitleString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(NULL, IDS_LISTENERROR, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
MessageBox(0, psDisplayString, psDisplayTitleString, 0);
|
|
goto err;
|
|
}
|
|
|
|
|
|
return listenfd;
|
|
|
|
err:
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
|
|
// function needed for ListView_SortItems to work. Compares the values
|
|
// in two columns.
|
|
int CALLBACK colcmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamColumn) {
|
|
TCHAR *psz1;
|
|
TCHAR *psz2;
|
|
int i1, i2;
|
|
TCHAR pszClientName[MAX_RCNAME];
|
|
TCHAR pszSubItem1[MAX_RCNAME];
|
|
TCHAR pszSubItem2[MAX_RCNAME];
|
|
|
|
psz1 = (TCHAR *) lParam1;
|
|
psz2 = (TCHAR *) lParam2;
|
|
|
|
if ((lParam1 == 0) || (lParam2 == 0)) {
|
|
OutputDebugString(_T("a null was passed to the sort function"));
|
|
return 0;
|
|
}
|
|
|
|
// Find the item number in the ListView
|
|
for (i1 = 0; i1 < ListView_GetItemCount(g_hListView); i1++) {
|
|
ListView_GetItemText(g_hListView, i1, g_iClientNameColumn,
|
|
pszClientName, MAX_RCNAME);
|
|
if (_tcscmp(psz1, pszClientName) == 0)
|
|
break;
|
|
}
|
|
for (i2 = 0; i2 < ListView_GetItemCount(g_hListView); i2++) {
|
|
ListView_GetItemText(g_hListView, i2, g_iClientNameColumn,
|
|
pszClientName, MAX_RCNAME);
|
|
if (_tcscmp(psz2, pszClientName) == 0)
|
|
break;
|
|
}
|
|
|
|
ListView_GetItemText(g_hListView, i1, (int) lParamColumn, pszSubItem1,
|
|
MAX_RCNAME);
|
|
ListView_GetItemText(g_hListView, i2, (int) lParamColumn, pszSubItem2,
|
|
MAX_RCNAME);
|
|
|
|
if (g_bAscending == TRUE)
|
|
return _tcscmp(pszSubItem1, pszSubItem2);
|
|
else
|
|
return -_tcscmp(pszSubItem1, pszSubItem2);
|
|
|
|
}
|
|
|
|
|
|
// Get the RoboClient index (in our data structure) from an entry in the
|
|
// listview (called an item)
|
|
int GetRCIndexFromRCItem(int iRightClickedItem) {
|
|
int i;
|
|
TCHAR psItemText[MAX_RCNAME];
|
|
|
|
for (i = 0; i < MAX_ROBOCLIENTS; i++) {
|
|
if (g_RCData[i].valid == TRUE) {
|
|
ListView_GetItemText(g_hListView, iRightClickedItem,
|
|
g_iClientNameColumn, psItemText, MAX_RCNAME);
|
|
if (_tcscmp(g_RCData[i].psRCName, psItemText) == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
// Initiates a script run for a particular scriptname passed in
|
|
int TimedRunScriptOnSelectedItems(HWND hwnd, TCHAR *psScriptName) {
|
|
|
|
int iItemIndex;
|
|
int iRCIndex;
|
|
int nTimeout;
|
|
int bCheck;
|
|
HWND hDelayEdit;
|
|
HWND hButton;
|
|
LVITEM lvi;
|
|
TCHAR psDelayText[MAX_DELAYTEXT];
|
|
TCHAR psTempString[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
hButton = GetDlgItem(hwnd, IDC_CANARYCHECK);
|
|
_ASSERTE(IsWindow(hButton));
|
|
|
|
// Loop through all the items in the list, changing the ones
|
|
// that are selected to "Pending" and STATE_PENDING
|
|
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
|
|
iItemIndex++) {
|
|
lvi.iItem = iItemIndex;
|
|
lvi.iSubItem = 0;
|
|
lvi.mask = LVIF_STATE;
|
|
lvi.stateMask = LVIS_SELECTED;
|
|
ListView_GetItem(g_hListView, &lvi);
|
|
if (lvi.state & LVIS_SELECTED) {
|
|
iRCIndex = GetRCIndexFromRCItem(iItemIndex);
|
|
if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) {
|
|
LoadString(NULL, IDS_PENDING, psTempString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
_sntprintf(psDisplayString, MAX_DISPLAY_STRING_LENGTH,
|
|
psTempString, psScriptName);
|
|
ListView_SetItemText(g_hListView, iItemIndex,
|
|
g_iStatusColumn, psDisplayString);
|
|
g_RCData[iRCIndex].state = STATE_PENDING_SCRIPT;
|
|
_tcsncpy(g_RCData[iRCIndex].psPendingInfo, psScriptName,
|
|
MAX_PENDINGINFO);
|
|
} else {
|
|
LoadString(NULL, IDS_CANTRUNDISC, psTempString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex,
|
|
g_iStatusColumn, psTempString);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now, set the timer for all of the items.
|
|
hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT);
|
|
_ASSERTE(IsWindow(hDelayEdit));
|
|
|
|
GetWindowText(hDelayEdit, psDelayText, MAX_DELAYTEXT);
|
|
|
|
nTimeout = _ttoi(psDelayText);
|
|
nTimeout *= 1000;
|
|
|
|
// this should probably be a ui thing rather than a silent sfp-like thing
|
|
if (nTimeout == 0)
|
|
nTimeout = 100; // Don't allow a delay of 0
|
|
|
|
// Only delay if the "Run canary automatically" button is checked
|
|
// Check checkbox to see if "run canary automatically" is on
|
|
// IDC_CANARYCHECK
|
|
bCheck = (int) SendMessage(hButton, BM_GETCHECK, 0, 0);
|
|
if (bCheck != 0) {
|
|
g_nIDTimer = MySetTimer(hwnd, g_nIDTimer, GetSetDelay(hwnd));
|
|
} else {
|
|
g_nIDTimer = MySetTimer(hwnd, g_nIDTimer, 0);
|
|
}
|
|
|
|
SetEvent(g_hCanaryEvent);
|
|
// Fire off a WM_TIMER message immediately for the first guy
|
|
// SendMessage(hwnd, WM_TIMER, g_nIDTimer, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Tell selected roboclients to run batch files such as reboot or update
|
|
int RunCommandOnSelectedItems(HWND hwnd, TCHAR *psCommandName) {
|
|
|
|
char psCommandNameA[MAX_SCRIPTLEN];
|
|
int iItemIndex, iRCIndex;
|
|
LVITEM lvi;
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, psCommandName, -1,
|
|
psCommandNameA, MAX_SCRIPTLEN, 0, 0);
|
|
#else
|
|
strcpy(psCommandNameA, psCommandName);
|
|
#endif
|
|
|
|
// Loop through all the items in the list
|
|
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
|
|
iItemIndex++) {
|
|
lvi.iItem = iItemIndex;
|
|
lvi.iSubItem = 0;
|
|
lvi.mask = LVIF_STATE;
|
|
lvi.stateMask = LVIS_SELECTED;
|
|
ListView_GetItem(g_hListView, &lvi);
|
|
if (lvi.state & LVIS_SELECTED) {
|
|
iRCIndex = GetRCIndexFromRCItem(iItemIndex);
|
|
if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) {
|
|
if (send(g_RCData[iRCIndex].sock, psCommandNameA,
|
|
_tcslen(psCommandName), 0) != SOCKET_ERROR) {
|
|
LoadString(NULL, IDS_COMMANDSENT, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex,
|
|
g_iStatusColumn, psDisplayString);
|
|
} else {
|
|
LoadString(NULL, IDS_SENDERROR, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex,
|
|
g_iStatusColumn, psDisplayString);
|
|
}
|
|
} // else was disconnected
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// main dispatch routine for when a timer message is received
|
|
int ProcessTimerMessage(HWND hwnd, WPARAM wParam) {
|
|
UINT_PTR nTimer = wParam;
|
|
int iItemIndex;
|
|
int iRCIndex;
|
|
TCHAR psNumberText[MAX_NUMBERTEXT];
|
|
|
|
|
|
// I don't know how it happens, but there start to be weird other timers
|
|
// about.
|
|
if (nTimer != g_nIDTimer)
|
|
return 0;
|
|
|
|
|
|
|
|
// For now, find the first pending item in the list and change its status
|
|
// to running
|
|
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
|
|
iItemIndex++) {
|
|
iRCIndex = GetRCIndexFromRCItem(iItemIndex);
|
|
if (g_RCData[iRCIndex].valid) {
|
|
if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT) {
|
|
|
|
// Send the command to the client
|
|
if (SendRunCommand(iRCIndex) == 0) {
|
|
|
|
// Update count
|
|
wsprintf(psNumberText, _T("%d"), NumberRunningClients());
|
|
SetWindowText(g_hNumRunning, psNumberText);
|
|
|
|
// Fix the timer
|
|
// If NumRunning() % NumPerSet() == 0 AND NumRunning != 0,
|
|
// Set the timer to SETDELAY * 60 seconds at the end of
|
|
// running.
|
|
// * NumClientsPerSet was fixed at nonzero when MySetTimer
|
|
// was called initially
|
|
// * Not using MySetTimer here because that does all sorts
|
|
// of unnecessary disables
|
|
if (NumberRunningClients() % NumClientsPerSet(hwnd) == 0) {
|
|
if (NumberRunningClients() != 0) {
|
|
g_nIDTimer = SetTimer(hwnd, g_nIDTimer,
|
|
GetSetDelay(hwnd), 0);
|
|
SetEvent(g_hCanaryEvent); // do the canary thing
|
|
}
|
|
} else {
|
|
// else set the timer to the normal value. It used to be
|
|
// that we would set the timer to the normal value if
|
|
// numrunning % numperset was == 1, but that had buggy
|
|
// behavior when you canceled when there were a couple
|
|
// running and then you ran some more.
|
|
// if (NumberRunningClients() % NumClientsPerSet(hwnd) == 1)
|
|
g_nIDTimer = SetTimer(hwnd, g_nIDTimer,
|
|
GetDelay(hwnd), 0);
|
|
}
|
|
}
|
|
|
|
if (MorePendingScripts() == 0) {
|
|
MyKillTimer(hwnd, g_nIDTimer);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we got here, we need to kill the timer
|
|
MyKillTimer(hwnd, nTimer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Actually send the run command to a particular RC connection.
|
|
// Returns 0 on success, nonzero on error
|
|
int SendRunCommand(int iRCIndex) {
|
|
|
|
TCHAR psEditText[MAX_EDIT_TEXT_LENGTH];
|
|
TCHAR psCommandText[MAX_SCRIPTLEN];
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
char psCommandTextA[MAX_SCRIPTLEN];
|
|
int iItemIndex;
|
|
LVFINDINFO lvfi;
|
|
|
|
lvfi.flags = LVFI_STRING;
|
|
lvfi.psz = g_RCData[iRCIndex].psRCName;
|
|
lvfi.lParam = 0;
|
|
lvfi.vkDirection = 0;
|
|
iItemIndex = ListView_FindItem(g_hListView, -1,
|
|
&lvfi);
|
|
|
|
GetWindowText(g_hTermSrvEditBox, psEditText, MAX_EDIT_TEXT_LENGTH);
|
|
wsprintf(psCommandText, _T("%s/%s/smc%03d"), psEditText,
|
|
g_RCData[iRCIndex].psPendingInfo, iRCIndex + 1);
|
|
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, psCommandText, -1,
|
|
psCommandTextA, MAX_SCRIPTLEN, 0, 0);
|
|
#else
|
|
strcpy(psCommandTextA, psCommandText);
|
|
#endif
|
|
|
|
if (send(g_RCData[iRCIndex].sock, psCommandTextA,
|
|
_tcslen(psCommandText), 0) != SOCKET_ERROR) {
|
|
// if successful, change text to Run command sent
|
|
LoadString(NULL, IDS_RUNCOMMANDSENT, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex,
|
|
g_iStatusColumn, psDisplayString);
|
|
|
|
// change state to RUNNING
|
|
g_RCData[iRCIndex].state = STATE_RUNNING;
|
|
|
|
return 0;
|
|
} else {
|
|
LoadString(NULL, IDS_SENDERROR, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex,
|
|
g_iStatusColumn, psDisplayString);
|
|
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
// In: i, uninitialized integer
|
|
// psClientName, Client to try to find in the list
|
|
// Out: i, RCindex of a disconnected session with name "psClientName"
|
|
// Returns: 1 if found a disconnected item with that name,
|
|
// 0 otherwise
|
|
int IsDisconnected(TCHAR *psClientName, int *iReturnedIndex) {
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_ROBOCLIENTS; i++) {
|
|
if (g_RCData[i].valid == TRUE)
|
|
if (g_RCData[i].state == STATE_DISCONNECTED)
|
|
if (_tcsncmp(psClientName, g_RCData[i].psRCName,
|
|
_tcslen(psClientName)) == 0) {
|
|
*iReturnedIndex = i;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Are there still scripts that will be run in the current command?
|
|
int MorePendingScripts() {
|
|
|
|
int iItemIndex, iRCIndex;
|
|
|
|
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
|
|
iItemIndex++) {
|
|
iRCIndex = GetRCIndexFromRCItem(iItemIndex);
|
|
if (g_RCData[iRCIndex].valid) {
|
|
if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Returns the number of scripts we think have started
|
|
int NumberRunningClients() {
|
|
|
|
int iItemIndex, iRCIndex;
|
|
int nNumberRunning = 0;
|
|
|
|
for (iRCIndex = 0; iRCIndex < MAX_ROBOCLIENTS; iRCIndex += 1) {
|
|
if (g_RCData[iRCIndex].valid) {
|
|
if (g_RCData[iRCIndex].state == STATE_RUNNING)
|
|
nNumberRunning++;
|
|
}
|
|
}
|
|
|
|
return nNumberRunning;
|
|
}
|
|
|
|
|
|
// Cancel all scripts currently pending
|
|
int CancelPendingScripts(HWND hwnd) {
|
|
int iItemIndex, iRCIndex;
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
|
|
iItemIndex++) {
|
|
iRCIndex = GetRCIndexFromRCItem(iItemIndex);
|
|
if (g_RCData[iRCIndex].valid) {
|
|
if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT) {
|
|
g_RCData[iRCIndex].state = STATE_CONNECTED;
|
|
LoadString(NULL, IDS_CANCELCOMMAND, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
ListView_SetItemText(g_hListView, iItemIndex,
|
|
g_iStatusColumn, psDisplayString);
|
|
}
|
|
}
|
|
}
|
|
|
|
MyKillTimer(hwnd, g_nIDTimer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Sets the timer using the Win32 SetTimer, and sets the appropriate menu items
|
|
// to disabled/enabled.
|
|
UINT_PTR MySetTimer(HWND hwnd, UINT_PTR nTimer, UINT nTimeout) {
|
|
|
|
// when we are setting the timer, we're disabling a bunch of things: menu
|
|
// items and edit boxes
|
|
EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKER, MF_GRAYED);
|
|
EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKERFAST, MF_GRAYED);
|
|
// EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_ADMINISTRATIVEWORKER,
|
|
// MF_GRAYED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_DATA, MF_GRAYED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_STW, MF_GRAYED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_BLANK, MF_GRAYED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_CONFIGURATIONSCRIPT,
|
|
MF_GRAYED);
|
|
// EnableMenuItem(g_hPopupMenu, ID__UPDATE, MF_GRAYED);
|
|
EnableMenuItem(g_hPopupMenu, ID__REBOOT, MF_GRAYED);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_TERMSRVEDIT), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_DELAYEDIT), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CLIENTSPERSET), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SETDELAY), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CANARYCHECK), FALSE);
|
|
// and we're enabling "Cancel Pending tasks"
|
|
EnableMenuItem(g_hPopupMenu, ID_CANCEL, MF_ENABLED);
|
|
|
|
// We are also making sure that the number of clients per set, if 0,
|
|
// is set to MAX_ROBOCLIENTS
|
|
if (NumClientsPerSet(hwnd) == 0) {
|
|
HWND hClientsPerSet;
|
|
TCHAR sClientsPerSetText[MAX_NUMBERTEXT];
|
|
|
|
hClientsPerSet = GetDlgItem(hwnd, IDC_CLIENTSPERSET);
|
|
_sntprintf(sClientsPerSetText, MAX_NUMBERTEXT, _T("%d"), MAX_ROBOCLIENTS);
|
|
sClientsPerSetText[MAX_NUMBERTEXT - 1] = 0;
|
|
SetWindowText(hClientsPerSet, sClientsPerSetText);
|
|
}
|
|
|
|
return SetTimer(hwnd, nTimer, nTimeout, 0);
|
|
}
|
|
|
|
|
|
// Kills the timer and sets appropriate menu items disabled or enabled
|
|
int MyKillTimer(HWND hwnd, UINT_PTR nTimer) {
|
|
// When killing the timer, re-enable menu items and edit boxes
|
|
EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKER, MF_ENABLED);
|
|
EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKERFAST, MF_ENABLED);
|
|
// EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_ADMINISTRATIVEWORKER,
|
|
// MF_ENABLED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_DATA, MF_ENABLED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_STW, MF_ENABLED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_BLANK, MF_ENABLED);
|
|
EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_CONFIGURATIONSCRIPT,
|
|
MF_ENABLED);
|
|
// EnableMenuItem(g_hPopupMenu, ID__UPDATE, MF_ENABLED);
|
|
EnableMenuItem(g_hPopupMenu, ID__REBOOT, MF_ENABLED);
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_TERMSRVEDIT), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_DELAYEDIT), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CLIENTSPERSET), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SETDELAY), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CANARYCHECK), TRUE);
|
|
// and disable "Cancel Pending Tasks"
|
|
EnableMenuItem(g_hPopupMenu, ID_CANCEL, MF_GRAYED);
|
|
return KillTimer(hwnd, nTimer);
|
|
}
|
|
|
|
|
|
// Retrieves the delay in the IDC_DELAYEDIT box (turned into milliseconds)
|
|
int GetDelay(HWND hwnd) {
|
|
HWND hDelayEdit;
|
|
int nTimeout;
|
|
TCHAR psDelayText[MAX_DELAYTEXT];
|
|
|
|
hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT);
|
|
_ASSERTE(IsWindow(hDelayEdit));
|
|
|
|
GetWindowText(hDelayEdit, psDelayText, MAX_DELAYTEXT);
|
|
nTimeout = _ttoi(psDelayText);
|
|
nTimeout *= 1000;
|
|
|
|
if (nTimeout == 0)
|
|
nTimeout = 100; // Don't allow a delay of 0
|
|
|
|
return nTimeout;
|
|
}
|
|
|
|
|
|
// Retrieves the number in the IDC_CLIENTSPERSET box
|
|
int NumClientsPerSet(HWND hwnd) {
|
|
HWND hClientsPerSet;
|
|
TCHAR psClientsPerSet[MAX_DELAYTEXT];
|
|
|
|
hClientsPerSet = GetDlgItem(hwnd, IDC_CLIENTSPERSET);
|
|
GetWindowText(hClientsPerSet, psClientsPerSet, MAX_DELAYTEXT);
|
|
|
|
return _ttoi(psClientsPerSet);
|
|
}
|
|
|
|
|
|
// Retrieves the delay in the IDC_SETDELAY box, turned into milliseconds
|
|
int GetSetDelay(HWND hwnd) {
|
|
HWND hSetDelayEdit;
|
|
int nTimeout;
|
|
TCHAR psDelayText[MAX_DELAYTEXT];
|
|
|
|
hSetDelayEdit = GetDlgItem(hwnd, IDC_SETDELAY);
|
|
_ASSERTE(IsWindow(hSetDelayEdit));
|
|
|
|
GetWindowText(hSetDelayEdit, psDelayText, MAX_DELAYTEXT);
|
|
nTimeout = _ttoi(psDelayText);
|
|
nTimeout *= 60000; // minutes to ms
|
|
|
|
if (nTimeout == 0)
|
|
nTimeout = GetDelay(hwnd); // Normal timer
|
|
|
|
return nTimeout;
|
|
}
|
|
|
|
// Takes the command line string as an argument and modifies global variables
|
|
// for the arguments.
|
|
// Pops up a messagebox on error
|
|
int GetCommandLineArgs(TCHAR *psCommandLine) {
|
|
TCHAR *psCurrPtr = psCommandLine;
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
if (*psCurrPtr == '\"') {
|
|
psCurrPtr++; // skip the opening quote
|
|
|
|
// Handle if the first arg is quoted
|
|
while ((*psCurrPtr != 0) && (*psCurrPtr != '\"'))
|
|
psCurrPtr++;
|
|
|
|
// then skip the " character
|
|
if (*psCurrPtr == '\"')
|
|
psCurrPtr++;
|
|
} else {
|
|
// go forward in the array until you get a ' ' or until NULL
|
|
while((*psCurrPtr != 0) && (*psCurrPtr != ' '))
|
|
psCurrPtr++;
|
|
}
|
|
|
|
// skip spaces
|
|
while(*psCurrPtr == ' ')
|
|
psCurrPtr++;
|
|
|
|
// if the character is NULL, return 0 (no args)
|
|
if (*psCurrPtr == 0)
|
|
return 0;
|
|
|
|
while (*psCurrPtr != 0) {
|
|
|
|
// now, check whether the next three are "-s:" and then non-null,
|
|
if (_tcsncmp(psCurrPtr, _T("-s:"), 3) == 0) {
|
|
if ((psCurrPtr[3] == 0) || (psCurrPtr[3] == ' ')) {
|
|
goto SHOWMSGBOX;
|
|
} else {
|
|
TCHAR *psStartOfName = &psCurrPtr[3];
|
|
int namelen = 0;
|
|
|
|
while ((psStartOfName[namelen] != 0) && (psStartOfName[namelen] != ' '))
|
|
namelen++;
|
|
_tcsncpy(g_TermSrvrName, psStartOfName, namelen);
|
|
g_TermSrvrName[namelen] = 0;
|
|
psCurrPtr = &psStartOfName[namelen];
|
|
}
|
|
} else if (_tcsncmp(psCurrPtr, _T("-n:"), 3) == 0) {
|
|
if ((psCurrPtr[3] == 0) || (psCurrPtr[3] == ' ')) {
|
|
goto SHOWMSGBOX;
|
|
} else {
|
|
TCHAR *psStartOfNum = &psCurrPtr[3];
|
|
int numlen = 0;
|
|
|
|
while ((psStartOfNum[numlen] != 0) && (psStartOfNum[numlen] != ' '))
|
|
numlen++;
|
|
g_nNumConnections = _ttoi(psStartOfNum);
|
|
// CHANGE BACK FROM 64 TO 5
|
|
if ((g_nNumConnections < 1) || (g_nNumConnections > 64)) {
|
|
g_nNumConnections = 3;
|
|
goto SHOWMSGBOX;
|
|
}
|
|
|
|
psCurrPtr = &psStartOfNum[numlen];
|
|
}
|
|
} else {
|
|
// error
|
|
goto SHOWMSGBOX;
|
|
}
|
|
|
|
// skip whitespace
|
|
while(*psCurrPtr == ' ')
|
|
psCurrPtr++;
|
|
}
|
|
|
|
return 0;
|
|
|
|
SHOWMSGBOX:
|
|
LoadString(NULL, IDS_COMMANDLINESYNTAX, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(NULL, IDS_COMMANDLINESYNTAXTITLE, psDisplayTitleString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
MessageBox(0, psDisplayString, psDisplayTitleString, 0);
|
|
return -1;
|
|
}
|
|
|
|
|
|
// log information to our global log file
|
|
int LogToLogFile(char *psLogData) {
|
|
FILE *fp;
|
|
SYSTEMTIME logloctime;
|
|
TCHAR psTimeDatePart[TIMEBUFSIZE];
|
|
TCHAR psTimeTimePart[TIMEBUFSIZE];
|
|
char psTimeDatePartA[TIMEBUFSIZE];
|
|
char psTimeTimePartA[TIMEBUFSIZE];
|
|
|
|
// Get the time
|
|
GetLocalTime(&logloctime);
|
|
// Get strings
|
|
GetDateFormat(0, 0, &logloctime, 0, psTimeDatePart, TIMEBUFSIZE);
|
|
GetTimeFormat(0, 0, &logloctime, 0, psTimeTimePart, TIMEBUFSIZE);
|
|
|
|
// Make sure we are in ANSI
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, psTimeDatePart, -1, psTimeDatePartA, TIMEBUFSIZE, 0, 0);
|
|
WideCharToMultiByte(CP_ACP, 0, psTimeTimePart, -1, psTimeTimePartA, TIMEBUFSIZE, 0, 0);
|
|
#else
|
|
strncpy(psTimeDatePartA, psTimeDatePart, TIMEBUFSIZE);
|
|
strncpy(psTimeTimePartA, psTimeTimePart, TIMEBUFSIZE);
|
|
#endif
|
|
|
|
EnterCriticalSection(&g_LogFileCritSect);
|
|
|
|
// open the file
|
|
fp = fopen("log.txt", "a+t");
|
|
// write the information to the file
|
|
if (fp != 0) {
|
|
// First, a timestamp
|
|
fprintf(fp, "%s %s\n", psTimeDatePartA, psTimeTimePartA);
|
|
// Now, the message
|
|
fprintf(fp, "%s\n\n", psLogData);
|
|
// close the file
|
|
fclose(fp);
|
|
} else {
|
|
// error
|
|
}
|
|
|
|
LeaveCriticalSection(&g_LogFileCritSect);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ToAnsi(char *psDest, const TCHAR *psSrc, int nSizeOfBuffer) {
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, psSrc, -1, psDest, nSizeOfBuffer, 0, 0);
|
|
#else
|
|
_strncpy(psDest, psSrc, nSizeOfBuffer);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
// On close, clean up by disabling the listener socket then closing all open
|
|
// connections. This ensures the roboclients will know the roboserver has
|
|
// exited
|
|
int CleanUp(HWND hwnd) {
|
|
int iItemIndex;
|
|
int iRCIndex;
|
|
TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
// Disable listener
|
|
LoadString(NULL, IDS_CLOSINGLISTENER, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, psDisplayString);
|
|
|
|
if (closesocket(g_listenersocket) != 0) {
|
|
LoadString(NULL, IDS_COULDNOTCLOSELISTENER, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(NULL, IDS_COULDNOTCLOSELISTENER, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
MessageBox(hwnd, psDisplayString, psDisplayTitleString, 0);
|
|
}
|
|
|
|
// Set status line to "disconnecting clients..."
|
|
LoadString(NULL, IDS_DISCONNECTINGCLIENTS, psDisplayString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
SetWindowText(g_hErrorText, psDisplayString);
|
|
|
|
// Disconnect all the clients
|
|
for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
|
|
iItemIndex++) {
|
|
iRCIndex = GetRCIndexFromRCItem(iItemIndex);
|
|
if (g_RCData[iRCIndex].valid) {
|
|
if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) {
|
|
shutdown(g_RCData[iRCIndex].sock, SD_BOTH);
|
|
closesocket(g_RCData[iRCIndex].sock);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// This procedure is for the subclassing of all the tabbable controls so that
|
|
// I can tab between them.
|
|
LRESULT CALLBACK TabProc(HWND hwnd, UINT Msg,
|
|
WPARAM wParam, LPARAM lParam) {
|
|
|
|
int i;
|
|
|
|
// Find the id of the hwnd
|
|
for (i = 0; i < NUM_TABBED_ITEMS; i++) {
|
|
if (g_hwnd[i] == hwnd)
|
|
break;
|
|
}
|
|
|
|
switch (Msg) {
|
|
case WM_KEYDOWN:
|
|
if (wParam == VK_TAB) {
|
|
int newItem = (i + (GetKeyState(VK_SHIFT) < 0 ?
|
|
NUM_TABBED_ITEMS - 1 : 1)) % NUM_TABBED_ITEMS;
|
|
// set the focus to the next or previous item
|
|
SetFocus(g_hwnd[newItem]);
|
|
// if the control is before an edit box control, select all the
|
|
// text in the edit control that gets selected
|
|
if ((newItem > 2) && (newItem < 7))
|
|
SendMessage(g_hwnd[newItem], EM_SETSEL, 0, -1);
|
|
}
|
|
break;
|
|
case WM_SETFOCUS:
|
|
break;
|
|
}
|
|
|
|
return CallWindowProc((WNDPROC) g_OldProc[i], hwnd, Msg, wParam, lParam);
|
|
}
|
|
|
|
// Message box on fatal error.
|
|
// IN: current hInstance of string resources
|
|
// ID in StringTable of string to display
|
|
void FatalErrMsgBox(HINSTANCE hInstance, UINT nMsgId) {
|
|
TCHAR szTitleString[MAX_DISPLAY_STRING_LENGTH];
|
|
TCHAR szErrorString[MAX_DISPLAY_STRING_LENGTH];
|
|
|
|
LoadString(hInstance, IDS_FATALERROR, szTitleString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
LoadString(hInstance, nMsgId, szErrorString,
|
|
MAX_DISPLAY_STRING_LENGTH);
|
|
|
|
MessageBox(0, szErrorString, szTitleString, 0);
|
|
}
|