Leaked source code of windows server 2003
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

  1. /****************************************************************************/
  2. /* robosrv.c */
  3. /* */
  4. /* RoboServer scalability testing utility source file */
  5. /* */
  6. /* Copyright (c) 1999 Microsoft Corporation */
  7. /****************************************************************************/
  8. #ifdef DBG
  9. #define _DEBUG
  10. #endif
  11. #include <windows.h>
  12. #include <winsock2.h>
  13. #include <commctrl.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <process.h>
  17. #include <time.h>
  18. #include <tchar.h>
  19. #include <crtdbg.h>
  20. #include "resource.h"
  21. #define SIZEOF_ARRAY(a) (sizeof(a)/sizeof((a)[0]))
  22. // These two window messages are for Windows Sockets messages that we request
  23. // when there are network events
  24. #define WM_SocketRoboClients WM_APP+0
  25. #define WM_SocketQueryIdle WM_APP+1
  26. // This window message is for inter-thread communication from the canary thread
  27. // When there is an error, the canary thread sends this message. wParam is
  28. // a TCHAR pointer that points to the error message to display. lParam is
  29. // unused and must be set to 0.
  30. #define WM_DisplayErrorText WM_APP+2
  31. #define MAX_ROBOCLIENTS 1000
  32. #define MAX_RCNAME 84
  33. #define MAX_STATUS 120
  34. #define MAX_SCRIPTLEN 100
  35. #define MAX_EDIT_TEXT_LENGTH 100
  36. #define MAX_PENDINGINFO 64
  37. #define MAX_DELAYTEXT 8
  38. #define MAX_RECV_CLIENT_DATA 128
  39. #define MAX_NUMBERTEXT 8
  40. #define MAX_TERMSRVRNAME 100
  41. #define MAX_DISPLAY_STRING_LENGTH 200
  42. #define DEBUG_STRING_LEN 200
  43. #define COLUMNONEWIDTH 150
  44. #define COLUMNTWOWIDTH 135
  45. #define COLUMNTHREEWIDTH 45
  46. #define COLUMNFOURWIDTH 150
  47. #define STATE_CONNECTED 1
  48. #define STATE_RUNNING 2
  49. #define STATE_DISCONNECTED 3
  50. #define STATE_PENDING_SCRIPT 4
  51. #define TIMEBUFSIZE 100
  52. #define NUM_TABBED_ITEMS 7
  53. const u_short LISTENER_SOCKET = 9877;
  54. const u_short QUERYIDLE_LISTENER_SOCKET = 9878;
  55. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
  56. SOCKET SockInit(u_short port);
  57. int DisplayErrorText(TCHAR *psText);
  58. int GetRCIndexFromRCItem(int iRightClickedItem);
  59. int CALLBACK colcmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
  60. int TimedRunScriptOnSelectedItems(HWND hwnd, TCHAR *psScriptName);
  61. int SendRunCommand(int iRCIndex);
  62. int RunCommandOnSelectedItems(HWND hwnd, TCHAR *psCommandName);
  63. int ProcessTimerMessage(HWND hwnd, WPARAM wParam);
  64. int MorePendingScripts();
  65. UINT_PTR MySetTimer(HWND hwnd, UINT_PTR nTimer, UINT nTimeout);
  66. int MyKillTimer(HWND hwnd, UINT_PTR nTimer);
  67. int CancelPendingScripts(HWND hwnd);
  68. int GetRCIndexFromSocket(SOCKET wParam);
  69. int IsDisconnected(TCHAR *psClientName, int *i);
  70. int NumberRunningClients();
  71. int NumClientsPerSet(HWND hwnd);
  72. int GetDelay(HWND hwnd);
  73. int GetSetDelay(HWND hwnd);
  74. void __cdecl CanaryThread(void *unused);
  75. int GetCommandLineArgs(TCHAR *psCommandLine);
  76. int LogToLogFile(char *psLogData);
  77. int ToAnsi(char *psDest, const TCHAR *psSrc, int nSizeOfBuffer);
  78. int CleanUp(HWND hwnd);
  79. void FatalErrMsgBox(HINSTANCE hInstance, UINT nMsgId);
  80. LRESULT CALLBACK TabProc(HWND hwnd, UINT Msg,
  81. WPARAM wParam, LPARAM lParam);
  82. struct RoboClientData {
  83. SOCKET sock;
  84. int state;
  85. BOOL valid;
  86. TCHAR psRCName[MAX_RCNAME]; // The name of this connection
  87. TCHAR psPendingInfo[MAX_PENDINGINFO]; // Will hold the script name
  88. };
  89. typedef struct RoboClientData RoboClientData;
  90. // Globals
  91. RoboClientData g_RCData[MAX_ROBOCLIENTS + 1];
  92. // Queryidle socket
  93. SOCKET g_qidlesock = INVALID_SOCKET;
  94. // Listener socket
  95. SOCKET g_listenersocket = INVALID_SOCKET;
  96. // Old procedures for dialog items
  97. LONG_PTR g_OldProc[NUM_TABBED_ITEMS];
  98. // HWNDs for dialog items
  99. HWND g_hwnd[NUM_TABBED_ITEMS];
  100. TCHAR g_TermSrvrName[MAX_TERMSRVRNAME];
  101. TCHAR g_DebugString[DEBUG_STRING_LEN];
  102. char g_DebugStringA[DEBUG_STRING_LEN];
  103. int g_iClientNameColumn;
  104. int g_iStatusColumn;
  105. int g_iIndexColumn;
  106. int g_iTimeStartedColumn;
  107. int g_CurrentSortColumn = -1;
  108. int g_nNumConnections = 10;
  109. UINT_PTR g_nIDTimer = 1;
  110. HMENU g_hPopupMenu;
  111. HANDLE g_hCanaryEvent;
  112. HWND g_hListView;
  113. HWND g_hNumRunning;
  114. HWND g_hTermSrvEditBox;
  115. HWND g_hQidleStatus;
  116. HWND g_hErrorText;
  117. HWND g_hTB;
  118. BOOL g_bAscending = FALSE;
  119. CRITICAL_SECTION g_LogFileCritSect;
  120. // WinMain - entry point
  121. int APIENTRY WinMain(HINSTANCE hInstance,
  122. HINSTANCE hPrevInstance,
  123. LPSTR lpCmdLine,
  124. int nCmdShow)
  125. {
  126. static TCHAR szAppName[] = _T("RoboServer");
  127. HWND hwnd, hGE, hTSEdit, hDelayEdit, hClientsPerSetEdit;
  128. HWND hSetDelayEdit, hCheckBox;
  129. MSG msg;
  130. WNDCLASSEX wndclass;
  131. DWORD x;
  132. WORD wVersionRequested;
  133. WSADATA wsaData;
  134. int err;
  135. SOCKET sock;
  136. LVCOLUMN lvc;
  137. TCHAR * psCommandLine;
  138. TCHAR szClientNameColumn[MAX_DISPLAY_STRING_LENGTH];
  139. TCHAR szStatusColumn[MAX_DISPLAY_STRING_LENGTH];
  140. TCHAR szIndexColumn[MAX_DISPLAY_STRING_LENGTH];
  141. TCHAR szStTimeColumn[MAX_DISPLAY_STRING_LENGTH];
  142. TCHAR szDisplayString1[MAX_DISPLAY_STRING_LENGTH];
  143. TCHAR szDisplayString2[MAX_DISPLAY_STRING_LENGTH];
  144. INITCOMMONCONTROLSEX iccex;
  145. lpCmdLine; // unused parameter
  146. hPrevInstance; // unused parameter
  147. LoadString(hInstance, IDS_CLIENTNAMECOL, szClientNameColumn,
  148. MAX_DISPLAY_STRING_LENGTH);
  149. LoadString(hInstance, IDS_STATUSCOL, szStatusColumn,
  150. MAX_DISPLAY_STRING_LENGTH);
  151. LoadString(hInstance, IDS_INDEXCOL, szIndexColumn,
  152. MAX_DISPLAY_STRING_LENGTH);
  153. LoadString(hInstance, IDS_STARTTIMECOL, szStTimeColumn,
  154. MAX_DISPLAY_STRING_LENGTH);
  155. wndclass.cbSize = sizeof(wndclass);
  156. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  157. wndclass.lpfnWndProc = WndProc;
  158. wndclass.cbClsExtra = 0;
  159. wndclass.cbWndExtra = DLGWINDOWEXTRA;
  160. wndclass.hInstance = hInstance;
  161. wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON));
  162. if (wndclass.hIcon == 0) {
  163. FatalErrMsgBox(hInstance, IDS_LOADICONFAILED);
  164. return -1;
  165. }
  166. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  167. if (wndclass.hCursor == 0) {
  168. FatalErrMsgBox(hInstance, IDS_LOADCURSORFAILED);
  169. return -1;
  170. }
  171. wndclass.hbrBackground = (HBRUSH) (COLOR_ACTIVEBORDER + 1);
  172. wndclass.lpszMenuName = NULL;
  173. wndclass.lpszClassName = szAppName;
  174. wndclass.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON));
  175. if (wndclass.hIconSm == 0) {
  176. FatalErrMsgBox(hInstance, IDS_LOADSMICONFAILED);
  177. return -1;
  178. }
  179. // Default value for the terminal server to hit
  180. LoadString(hInstance, IDS_LABTS, szDisplayString1,
  181. MAX_DISPLAY_STRING_LENGTH);
  182. _tcsncpy(g_TermSrvrName, szDisplayString1, SIZEOF_ARRAY(g_TermSrvrName));
  183. g_TermSrvrName[SIZEOF_ARRAY(g_TermSrvrName) - 1] = 0;
  184. psCommandLine = GetCommandLine();
  185. if (psCommandLine == 0) {
  186. FatalErrMsgBox(hInstance, IDS_COMMANDLINEERR);
  187. return -1;
  188. }
  189. if (GetCommandLineArgs(psCommandLine) != 0)
  190. return -1;
  191. // Initialize common controls
  192. iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  193. iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS;
  194. if (InitCommonControlsEx(&iccex) == FALSE) {
  195. FatalErrMsgBox(hInstance, IDS_INITCOMCTRLFAIL);
  196. }
  197. if (RegisterClassEx(&wndclass) == 0) {
  198. FatalErrMsgBox(hInstance, IDS_REGWNDCLASSFAIL);
  199. return -1;
  200. }
  201. hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), 0, NULL);
  202. if (hwnd == 0) {
  203. FatalErrMsgBox(hInstance, IDS_CREATEMAINWNDERR);
  204. return -1;
  205. }
  206. wVersionRequested = MAKEWORD( 2, 2 );
  207. err = WSAStartup( wVersionRequested, &wsaData );
  208. if ( err != 0 ) {
  209. FatalErrMsgBox(hInstance, IDS_WINSOCKERR);
  210. return -1;
  211. }
  212. // Initialize incoming socket
  213. sock = SockInit(LISTENER_SOCKET);
  214. if (WSAAsyncSelect(sock, hwnd, WM_SocketRoboClients, FD_ACCEPT | FD_CONNECT) != 0) {
  215. FatalErrMsgBox(hInstance, IDS_WSAASYNCSELERR);
  216. goto bad;
  217. }
  218. // Initialize queryidle incoming socket
  219. sock = SockInit(QUERYIDLE_LISTENER_SOCKET);
  220. if (WSAAsyncSelect(sock, hwnd, WM_SocketQueryIdle, FD_ACCEPT | FD_CONNECT) != 0) {
  221. FatalErrMsgBox(hInstance, IDS_WSAASYNCSELERR);
  222. goto bad;
  223. }
  224. // store the listener socket for later use
  225. g_listenersocket = sock;
  226. memset(g_RCData, 0, sizeof(RoboClientData) * MAX_ROBOCLIENTS);
  227. ShowWindow(hwnd, nCmdShow);
  228. g_hNumRunning = GetDlgItem(hwnd, IDC_NUMTOTAL);
  229. g_hQidleStatus = GetDlgItem(hwnd, IDC_STATIC3);
  230. g_hErrorText = GetDlgItem(hwnd, IDC_ERRORTEXT);
  231. g_hListView = GetDlgItem(hwnd, IDC_LISTVIEW);
  232. g_hTermSrvEditBox = GetDlgItem(hwnd, IDC_TERMSRVEDIT);
  233. g_hTB = GetDlgItem(hwnd, IDC_SLIDER1);
  234. hTSEdit = GetDlgItem(hwnd, IDC_TERMSRVEDIT);
  235. hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT);
  236. hClientsPerSetEdit = GetDlgItem(hwnd, IDC_CLIENTSPERSET);
  237. hSetDelayEdit = GetDlgItem(hwnd, IDC_SETDELAY);
  238. _ASSERTE(IsWindow(g_hNumRunning));
  239. _ASSERTE(IsWindow(g_hQidleStatus));
  240. _ASSERTE(IsWindow(g_hErrorText));
  241. _ASSERTE(IsWindow(g_hListView));
  242. _ASSERTE(IsWindow(g_hTermSrvEditBox));
  243. _ASSERTE(IsWindow(g_hTB));
  244. _ASSERTE(IsWindow(hTSEdit));
  245. _ASSERTE(IsWindow(hDelayEdit));
  246. _ASSERTE(IsWindow(hClientsPerSetEdit));
  247. _ASSERTE(IsWindow(hSetDelayEdit));
  248. lvc.mask = LVCF_TEXT | LVCF_WIDTH;
  249. lvc.pszText = szClientNameColumn;
  250. lvc.cchTextMax = sizeof(szClientNameColumn);
  251. lvc.cx = COLUMNONEWIDTH;
  252. g_iClientNameColumn = ListView_InsertColumn(g_hListView, 1, &lvc);
  253. lvc.pszText = szStatusColumn;
  254. lvc.cchTextMax = sizeof(szStatusColumn);
  255. lvc.cx = COLUMNTWOWIDTH;
  256. g_iStatusColumn = ListView_InsertColumn(g_hListView, 2, &lvc);
  257. lvc.pszText = szIndexColumn;
  258. lvc.cchTextMax = sizeof(szIndexColumn);
  259. lvc.cx = COLUMNTHREEWIDTH;
  260. g_iIndexColumn = ListView_InsertColumn(g_hListView, 3, &lvc);
  261. lvc.pszText = szStTimeColumn;
  262. lvc.cchTextMax = sizeof(szStTimeColumn);
  263. lvc.cx = COLUMNFOURWIDTH;
  264. g_iTimeStartedColumn = ListView_InsertColumn(g_hListView, 4, &lvc);
  265. LoadString(hInstance, IDS_WELCOME, szDisplayString1,
  266. MAX_DISPLAY_STRING_LENGTH);
  267. SetWindowText(g_hErrorText, szDisplayString1);
  268. SetWindowText(hTSEdit, g_TermSrvrName);
  269. SetWindowText(hDelayEdit, _T("30"));
  270. SetWindowText(hClientsPerSetEdit, _T("10"));
  271. SetWindowText(hSetDelayEdit, _T("15"));
  272. // Initialize Graphic Equalizer
  273. hGE = GetDlgItem(hwnd, IDC_PROGRESS1);
  274. _ASSERTE(IsWindow(hGE));
  275. SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
  276. SendMessage(hGE, PBM_SETPOS, 8, 0);
  277. hGE = GetDlgItem(hwnd, IDC_PROGRESS2);
  278. _ASSERTE(IsWindow(hGE));
  279. SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
  280. SendMessage(hGE, PBM_SETPOS, 7, 0);
  281. hGE = GetDlgItem(hwnd, IDC_PROGRESS3);
  282. _ASSERTE(IsWindow(hGE));
  283. SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
  284. SendMessage(hGE, PBM_SETPOS, 6, 0);
  285. hGE = GetDlgItem(hwnd, IDC_PROGRESS4);
  286. _ASSERTE(IsWindow(hGE));
  287. SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
  288. SendMessage(hGE, PBM_SETPOS, 6, 0);
  289. hGE = GetDlgItem(hwnd, IDC_PROGRESS5);
  290. _ASSERTE(IsWindow(hGE));
  291. SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
  292. SendMessage(hGE, PBM_SETPOS, 7, 0);
  293. hGE = GetDlgItem(hwnd, IDC_PROGRESS6);
  294. _ASSERTE(IsWindow(hGE));
  295. SendMessage(hGE, PBM_SETRANGE, 0, MAKELPARAM(0, 10));
  296. SendMessage(hGE, PBM_SETPOS, 8, 0);
  297. // Initialize Slider control IDC_SLIDER1 for number of RC connections
  298. // per client
  299. {
  300. TCHAR buffer[6];
  301. SendMessage(g_hTB, TBM_SETRANGE, (WPARAM) (BOOL) TRUE,
  302. (LPARAM) MAKELONG(1, 20));
  303. SendMessage(g_hTB, TBM_SETTICFREQ, (WPARAM) 1,
  304. (LPARAM) 0);
  305. SendMessage(g_hTB, TBM_SETSEL, (WPARAM) (BOOL) TRUE,
  306. MAKELONG(1, g_nNumConnections));
  307. // Now set the number to "M"
  308. _stprintf(buffer, _T("%d"), 20);
  309. SetWindowText(GetDlgItem(hwnd, IDC_STATIC6), buffer);
  310. }
  311. // make number of connections a command line param
  312. SendMessage(g_hTB, TBM_SETPOS, (WPARAM) (BOOL) TRUE, (LPARAM) g_nNumConnections);
  313. // Initialize check box
  314. hCheckBox = GetDlgItem(hwnd, IDC_CANARYCHECK);
  315. _ASSERTE(IsWindow(hCheckBox));
  316. SendMessage(hCheckBox, BM_SETCHECK, BST_CHECKED, 0);
  317. // Clear qidle status
  318. SetWindowText(g_hQidleStatus, _T(""));
  319. g_hPopupMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1));
  320. if (g_hPopupMenu == 0) {
  321. LoadString(hInstance, IDS_POPUPMENULOADERR, szDisplayString1,
  322. MAX_DISPLAY_STRING_LENGTH);
  323. SetWindowText(g_hErrorText, szDisplayString1);
  324. }
  325. g_hPopupMenu = GetSubMenu(g_hPopupMenu, 0);
  326. // Initialize critical section for log file
  327. InitializeCriticalSection(&g_LogFileCritSect);
  328. // Initialize everything required for canary thread, and then create the
  329. // canary thread first, create auto-reset, doesn't start in signaled state
  330. // event
  331. if ((g_hCanaryEvent = CreateEvent(0, FALSE, FALSE, NULL)) == NULL) {
  332. FatalErrMsgBox(hInstance, IDS_CANARYEVENTERR);
  333. goto bad;
  334. }
  335. if (_beginthread(CanaryThread, 0, hwnd) == -1) {
  336. FatalErrMsgBox(hInstance, IDS_CANARYTHREADERR);
  337. goto bad;
  338. }
  339. _ASSERTE(SetFocus(g_hListView) != NULL);
  340. // Store old window procedures for controls so that I can subclass them
  341. // Also, store the HWND of each control for searching
  342. g_OldProc[0] = SetWindowLongPtr(g_hListView, GWLP_WNDPROC,
  343. (LONG_PTR) TabProc);
  344. g_hwnd[0] = g_hListView;
  345. g_OldProc[1] = SetWindowLongPtr(g_hTB, GWLP_WNDPROC,
  346. (LONG_PTR) TabProc);
  347. g_hwnd[1] = g_hTB;
  348. g_OldProc[2] = SetWindowLongPtr(hCheckBox, GWLP_WNDPROC,
  349. (LONG_PTR) TabProc);
  350. g_hwnd[2] = hCheckBox;
  351. g_OldProc[3] = SetWindowLongPtr(g_hTermSrvEditBox, GWLP_WNDPROC,
  352. (LONG_PTR) TabProc);
  353. g_hwnd[3] = g_hTermSrvEditBox;
  354. g_OldProc[4] = SetWindowLongPtr(hClientsPerSetEdit, GWLP_WNDPROC,
  355. (LONG_PTR) TabProc);
  356. g_hwnd[4] = hClientsPerSetEdit;
  357. g_OldProc[5] = SetWindowLongPtr(hDelayEdit, GWLP_WNDPROC,
  358. (LONG_PTR) TabProc);
  359. g_hwnd[5] = hDelayEdit;
  360. g_OldProc[6] = SetWindowLongPtr(hSetDelayEdit, GWLP_WNDPROC,
  361. (LONG_PTR) TabProc);
  362. g_hwnd[6] = hSetDelayEdit;
  363. _ASSERTE(g_OldProc[0] != 0);
  364. _ASSERTE(g_OldProc[1] != 0);
  365. _ASSERTE(g_OldProc[2] != 0);
  366. _ASSERTE(g_OldProc[3] != 0);
  367. _ASSERTE(g_OldProc[4] != 0);
  368. _ASSERTE(g_OldProc[5] != 0);
  369. _ASSERTE(g_OldProc[6] != 0);
  370. while(GetMessage(&msg, NULL, 0, 0))
  371. {
  372. TranslateMessage(&msg);
  373. DispatchMessage(&msg);
  374. }
  375. return (int) msg.wParam;
  376. bad:
  377. WSACleanup();
  378. return 0;
  379. }
  380. // receives window messages and deals with them
  381. LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  382. {
  383. TCHAR szDisplayString[MAX_DISPLAY_STRING_LENGTH];
  384. switch (iMsg)
  385. {
  386. case WM_DESTROY:
  387. // Close all open connections
  388. CleanUp(hwnd);
  389. PostQuitMessage(0);
  390. return 0;
  391. case WM_COMMAND:
  392. switch (LOWORD(wParam))
  393. {
  394. case ID_RUNSCRIPT_KNOWLEDGEWORKER:
  395. TimedRunScriptOnSelectedItems(hwnd, _T("KnowWkr"));
  396. break;
  397. case ID_RUNSCRIPT_KNOWLEDGEWORKERFAST:
  398. TimedRunScriptOnSelectedItems(hwnd, _T("FastKW"));
  399. break;
  400. case ID_RUNSCRIPT_ADMINISTRATIVEWORKER:
  401. TimedRunScriptOnSelectedItems(hwnd, _T("AdminWkr"));
  402. break;
  403. case ID__RUNSCRIPT_DATA:
  404. TimedRunScriptOnSelectedItems(hwnd, _T("taskwkr"));
  405. break;
  406. case ID__RUNSCRIPT_STW:
  407. TimedRunScriptOnSelectedItems(hwnd, _T("stw"));
  408. break;
  409. case ID__RUNSCRIPT_HPW:
  410. TimedRunScriptOnSelectedItems(hwnd, _T("hpw"));
  411. break;
  412. case ID__RUNSCRIPT_BLANK:
  413. TimedRunScriptOnSelectedItems(hwnd, _T("blank"));
  414. break;
  415. case ID__RUNSCRIPT_CONFIGURATIONSCRIPT:
  416. TimedRunScriptOnSelectedItems(hwnd, _T("config"));
  417. break;
  418. case ID__UPDATE:
  419. RunCommandOnSelectedItems(hwnd, _T("update"));
  420. break;
  421. case ID__REBOOT:
  422. RunCommandOnSelectedItems(hwnd, _T("reboot"));
  423. break;
  424. case ID_CANCEL:
  425. CancelPendingScripts(hwnd);
  426. break;
  427. default:
  428. OutputDebugString(_T("Unhandled WM_COMMAND: "));
  429. wsprintf(g_DebugString, _T("%d\n"), LOWORD(wParam));
  430. OutputDebugString(g_DebugString);
  431. break;
  432. }
  433. break;
  434. case WM_CREATE:
  435. break;
  436. case WM_CHAR:
  437. break;
  438. case WM_TIMER:
  439. ProcessTimerMessage(hwnd, wParam);
  440. return 0;
  441. case WM_KEYDOWN:
  442. // NOTE INTENTIONAL FALLTHROUGH!
  443. case WM_SYSKEYDOWN:
  444. if (wParam == VK_TAB) {
  445. SetFocus(g_hwnd[0]);
  446. }
  447. break;
  448. case WM_DisplayErrorText:
  449. return DisplayErrorText((TCHAR *) wParam);
  450. case WM_NOTIFY:
  451. {
  452. switch (((LPNMHDR) lParam)->code)
  453. {
  454. case NM_RCLICK:
  455. {
  456. POINT pnt;
  457. if (ListView_GetSelectedCount(g_hListView) > 0) {
  458. GetCursorPos(&pnt);
  459. TrackPopupMenu(g_hPopupMenu, 0, pnt.x, pnt.y, 0, hwnd,
  460. 0);
  461. }
  462. }
  463. break;
  464. case LVN_ODCACHEHINT:
  465. break;
  466. case LVN_COLUMNCLICK:
  467. if (g_CurrentSortColumn ==
  468. ((LPNMLISTVIEW)lParam)->iSubItem)
  469. g_bAscending = !g_bAscending;
  470. else
  471. g_bAscending = TRUE;
  472. g_CurrentSortColumn = ((LPNMLISTVIEW)lParam)->iSubItem;
  473. if (ListView_SortItems(g_hListView, colcmp,
  474. ((LPNMLISTVIEW)lParam)->iSubItem) == FALSE)
  475. OutputDebugString(_T("Sort failed"));
  476. break;
  477. default:
  478. break;
  479. }
  480. }
  481. break;
  482. // WM_SocketQueryIdle is the window message that we are going to request
  483. // for all information that originates from the queryidle utility. This
  484. // utility will provide information about what user numbers to re-run as
  485. // well as when retry limits have been exceeded
  486. // line protocol (strings are ASCII and null-terminated):
  487. // queryidle sends "restart xxx", where xxx is the 1-indexed number of the
  488. // session to be restarted
  489. // queryidle sends "frqfail xxx", where xxx is the 1-indexed number of
  490. // the user session for the status line
  491. case WM_SocketQueryIdle:
  492. switch (WSAGETSELECTEVENT(lParam))
  493. {
  494. case FD_ACCEPT:
  495. {
  496. struct sockaddr_in SockAddr;
  497. int SockAddrLen;
  498. g_qidlesock = accept(wParam, (struct sockaddr *) &SockAddr,
  499. &SockAddrLen);
  500. if (g_qidlesock == INVALID_SOCKET) {
  501. LoadString(NULL, IDS_INVALIDQIDLESOCKET, szDisplayString,
  502. MAX_DISPLAY_STRING_LENGTH);
  503. SetWindowText(g_hQidleStatus, szDisplayString);
  504. return TRUE;
  505. }
  506. if (WSAAsyncSelect(g_qidlesock, hwnd, WM_SocketQueryIdle,
  507. FD_CLOSE | FD_READ) != 0) {
  508. LoadString(NULL, IDS_WSAASYNCQIDLEERR, szDisplayString,
  509. MAX_DISPLAY_STRING_LENGTH);
  510. SetWindowText(g_hQidleStatus, szDisplayString);
  511. return TRUE;
  512. }
  513. LoadString(NULL, IDS_QIDLECONNEST, szDisplayString,
  514. MAX_DISPLAY_STRING_LENGTH);
  515. SetWindowText(g_hQidleStatus, szDisplayString);
  516. return TRUE;
  517. }
  518. break;
  519. case FD_READ:
  520. {
  521. unsigned n;
  522. char psData[MAX_RECV_CLIENT_DATA];
  523. // SetWindowText(g_hQidleStatus, _T("Qidle data received"));
  524. n = recv(g_qidlesock, psData, sizeof(psData), 0);
  525. if (n != SOCKET_ERROR) {
  526. if ((n == strlen("restart xxx") + 1) ||
  527. (n == strlen("idle xxx") + 1)) {
  528. // get the number of the connection in question (xxx)
  529. int nUser;
  530. // if it's a restart command
  531. if (strncmp(psData, "restart ", strlen("restart ")) == 0) {
  532. nUser = atoi(&psData[8]);
  533. // restart the given session if it's already running
  534. if (g_RCData[nUser - 1].state == STATE_RUNNING) {
  535. SendRunCommand(nUser - 1);
  536. } else {
  537. LoadString(NULL, IDS_QIDLEREPORTWEIRDUSER,
  538. szDisplayString,
  539. MAX_DISPLAY_STRING_LENGTH);
  540. SetWindowText(g_hQidleStatus, szDisplayString);
  541. }
  542. _snprintf(g_DebugStringA, DEBUG_STRING_LEN,
  543. "Queryidle indicated that"
  544. " user smc%03d failed.", nUser);
  545. LogToLogFile(g_DebugStringA);
  546. break;
  547. }
  548. // if it's the frqfail command
  549. if (strncmp(psData, "frqfail ", strlen("frqfail ")) == 0) {
  550. nUser = atoi(&psData[8]);
  551. // set the status to the fact that xxx
  552. // is frequently failing
  553. wsprintf(g_DebugString, _T("User smc%03d has failed ")
  554. _T("to run correctly for too long and will ")
  555. _T("be logged off"), nUser);
  556. SetWindowText(g_hQidleStatus, g_DebugString);
  557. ToAnsi(g_DebugStringA, g_DebugString, DEBUG_STRING_LEN);
  558. LogToLogFile(g_DebugStringA);
  559. break;
  560. }
  561. // if it's the idle notification
  562. if (strncmp(psData, "idle ", strlen("idle ")) == 0) {
  563. LoadString(NULL, IDS_USERISIDLE, szDisplayString,
  564. MAX_DISPLAY_STRING_LENGTH);
  565. // I think this is fixed now, but haven't tested
  566. nUser = atoi(&psData[5]);
  567. wsprintf(g_DebugString, szDisplayString,
  568. nUser);
  569. SetWindowText(g_hQidleStatus, g_DebugString);
  570. ToAnsi(g_DebugStringA, g_DebugString, DEBUG_STRING_LEN);
  571. LogToLogFile(g_DebugStringA);
  572. break;
  573. }
  574. // else display an error
  575. LoadString(NULL, IDS_QIDLESENTGIBBERISH, szDisplayString,
  576. MAX_DISPLAY_STRING_LENGTH);
  577. SetWindowText(g_hQidleStatus, szDisplayString);
  578. } else {
  579. LoadString(NULL, IDS_QIDLESENTWRONGLENGTH,
  580. szDisplayString, MAX_DISPLAY_STRING_LENGTH);
  581. SetWindowText(g_hQidleStatus, szDisplayString);
  582. }
  583. } else {
  584. LoadString(NULL, IDS_QIDLESOCKERR, szDisplayString,
  585. MAX_DISPLAY_STRING_LENGTH);
  586. SetWindowText(g_hQidleStatus, szDisplayString);
  587. }
  588. return TRUE;
  589. }
  590. break;
  591. case FD_CLOSE:
  592. {
  593. LoadString(NULL, IDS_QIDLESAYSGOODBYE, szDisplayString,
  594. MAX_DISPLAY_STRING_LENGTH);
  595. SetWindowText(g_hQidleStatus, szDisplayString);
  596. return TRUE;
  597. }
  598. break;
  599. }
  600. break;
  601. case WM_SocketRoboClients:
  602. switch (WSAGETSELECTEVENT(lParam))
  603. {
  604. case FD_ACCEPT:
  605. {
  606. struct sockaddr_in SockAddr;
  607. int SockAddrLen, i, iItemIndex;
  608. HWND hTB;
  609. TCHAR psSockAppend[9]; // ".(.....)" + 1
  610. char psNumConnections[2]; // one char null terminated
  611. TCHAR psIndex[5]; // up to 4 digits + null
  612. TCHAR psClientName[MAX_RCNAME];
  613. char psClientNameA[MAX_RCNAME];
  614. int nSliderPos;
  615. SOCKET sock;
  616. struct hostent * he;
  617. LVITEM lvi;
  618. LoadString(NULL, IDS_PROCESSINGCONNREQ, szDisplayString,
  619. MAX_DISPLAY_STRING_LENGTH);
  620. SetWindowText(g_hErrorText, szDisplayString);
  621. SockAddrLen = sizeof(SockAddr);
  622. sock = accept(wParam, (struct sockaddr *) &SockAddr,
  623. &SockAddrLen);
  624. // gethostbyaddr tries to confuse us by taking a char * when
  625. // it really wants this peculiar sin_addr thing
  626. // The second argument to this function ("4") is the length of
  627. // the address.
  628. he = gethostbyaddr((char *)&SockAddr.sin_addr, 4, AF_INET);
  629. if (he == NULL) {
  630. LoadString(NULL, IDS_GETHOSTFAILED, szDisplayString,
  631. MAX_DISPLAY_STRING_LENGTH);
  632. SetWindowText(g_hErrorText, szDisplayString);
  633. return FALSE;
  634. }
  635. strcpy(psClientNameA, he->h_name);
  636. #ifdef UNICODE
  637. MultiByteToWideChar(CP_ACP, 0, psClientNameA, -1,
  638. psClientName, MAX_RCNAME);
  639. #else
  640. strcpy(psClientName, psClientNameA);
  641. #endif
  642. _tcstok(psClientName, _T(".")); // Kill domain
  643. // See if there is a disconnected client by that name
  644. if (IsDisconnected(psClientName, &i)) {
  645. // Good--we've found one--remove that list item now
  646. LVFINDINFO lvfi;
  647. int iListViewIndex;
  648. lvfi.flags = LVFI_STRING;
  649. lvfi.psz = g_RCData[i].psRCName;
  650. lvfi.lParam = 0;
  651. lvfi.vkDirection = 0;
  652. iListViewIndex = ListView_FindItem(g_hListView, -1, &lvfi);
  653. if (ListView_DeleteItem(g_hListView, iListViewIndex)
  654. == FALSE) {
  655. LoadString(NULL, IDS_COULDNOTDELITEM, szDisplayString,
  656. MAX_DISPLAY_STRING_LENGTH);
  657. SetWindowText(g_hErrorText, szDisplayString);
  658. }
  659. } else {
  660. // Find a spot in our g_RCData array
  661. for (i = 0; i < MAX_ROBOCLIENTS; i++)
  662. if (g_RCData[i].valid == FALSE) break;
  663. }
  664. g_RCData[i].valid = TRUE;
  665. g_RCData[i].sock = sock;
  666. LoadString(NULL, IDS_CLIENTCONNECTED, szDisplayString,
  667. MAX_DISPLAY_STRING_LENGTH);
  668. wsprintf(g_DebugString, szDisplayString, i + 1);
  669. SetWindowText(g_hErrorText, g_DebugString);
  670. if (g_RCData[i].sock == INVALID_SOCKET) {
  671. LoadString(NULL, IDS_INVALIDSOCKETFROMACCEPT,
  672. szDisplayString, MAX_DISPLAY_STRING_LENGTH);
  673. SetWindowText(g_hErrorText, szDisplayString);
  674. g_RCData[i].valid = FALSE;
  675. return FALSE;
  676. }
  677. // Send it the number of connections it is to make
  678. // Determine the position of the slider control
  679. nSliderPos = (int) SendMessage(g_hTB, TBM_GETPOS, 0, 0);
  680. psNumConnections[0] = (char) (nSliderPos + '0');
  681. psNumConnections[1] = 0; // null terminate
  682. if (send(g_RCData[i].sock, psNumConnections,
  683. sizeof(psNumConnections), 0) == SOCKET_ERROR) {
  684. LoadString(NULL, IDS_SENDERRNUMCONN, szDisplayString,
  685. MAX_DISPLAY_STRING_LENGTH);
  686. SetWindowText(g_hErrorText, szDisplayString);
  687. return FALSE;
  688. }
  689. // Add the incoming connection to the list box
  690. // this won't append a null if count is less than psClientName,
  691. // which is bad
  692. _tcsncpy(g_RCData[i].psRCName, psClientName,
  693. MAX_RCNAME - _tcslen(_T(" (%d)")) - 1);
  694. // clean up display a bit
  695. _tcstok(g_RCData[i].psRCName, _T("."));
  696. // add socket number to entry for multiplexing
  697. _sntprintf(psSockAppend, 9, _T(" (%d)"), g_RCData[i].sock);
  698. _tcscat(g_RCData[i].psRCName, psSockAppend);
  699. // create the actual list view item
  700. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  701. lvi.iItem = (int) SendMessage(g_hListView, LVM_GETITEMCOUNT, 0, 0);
  702. lvi.iSubItem = 0;
  703. lvi.pszText = g_RCData[i].psRCName;
  704. lvi.cchTextMax = sizeof(g_RCData[i].psRCName);
  705. lvi.lParam = (LPARAM) (char *)g_RCData[i].psRCName;
  706. iItemIndex = ListView_InsertItem(g_hListView, &lvi);
  707. g_RCData[i].state = STATE_CONNECTED;
  708. LoadString(NULL, IDS_CONNECTED, szDisplayString,
  709. MAX_DISPLAY_STRING_LENGTH);
  710. ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn, szDisplayString);
  711. // set the index field
  712. wsprintf(psIndex, _T("%03d"), i + 1);
  713. ListView_SetItemText(g_hListView, iItemIndex, g_iIndexColumn, psIndex);
  714. // Now set up notification for this socket
  715. if (WSAAsyncSelect(g_RCData[i].sock, hwnd,
  716. WM_SocketRoboClients, FD_CLOSE | FD_READ) !=
  717. SOCKET_ERROR) {
  718. return TRUE;
  719. } else {
  720. LoadString(NULL, IDS_ERRORCANTRECVNOTIFICATIONS,
  721. szDisplayString, MAX_DISPLAY_STRING_LENGTH);
  722. ListView_SetItemText(g_hListView, iItemIndex, g_iStatusColumn,
  723. szDisplayString);
  724. return TRUE;
  725. }
  726. }
  727. case FD_CONNECT:
  728. // MessageBox(0, _T("Error"), _T("Received connect unexpectedly"), 0);
  729. break;
  730. case FD_CLOSE:
  731. {
  732. int i;
  733. int iListViewIndex;
  734. LVFINDINFO lvfi;
  735. TCHAR psNumberText[MAX_NUMBERTEXT];
  736. LoadString(NULL, IDS_ROBOCLIDISCON, szDisplayString,
  737. MAX_DISPLAY_STRING_LENGTH);
  738. SetWindowText(g_hErrorText, szDisplayString);
  739. // find the entry that corresponds to our socket
  740. i = GetRCIndexFromSocket(wParam);
  741. // Find the spot in the ListView that has this Client Name
  742. lvfi.flags = LVFI_STRING;
  743. lvfi.psz = g_RCData[i].psRCName;
  744. lvfi.lParam = 0;
  745. lvfi.vkDirection = 0;
  746. iListViewIndex = ListView_FindItem(g_hListView, -1, &lvfi);
  747. g_RCData[i].state = STATE_DISCONNECTED;
  748. // wsprintf(debugString, "Deleting socket %d from index %d of g_RCData[] (%s)", wParam,
  749. // i, g_RCData[i].psRCName);
  750. // SetWindowText(hErrorText, debugString);
  751. // Update number running
  752. wsprintf(psNumberText, _T("%d"), NumberRunningClients());
  753. SetWindowText(g_hNumRunning, psNumberText);
  754. // Set text of column to "Lost Connection"
  755. LoadString(NULL, IDS_LOSTCONNECTION, szDisplayString,
  756. MAX_DISPLAY_STRING_LENGTH);
  757. ListView_SetItemText(g_hListView, iListViewIndex,
  758. g_iStatusColumn, szDisplayString);
  759. // Erase the time started column
  760. ListView_SetItemText(g_hListView, iListViewIndex,
  761. g_iTimeStartedColumn, _T(""));
  762. }
  763. break;
  764. case FD_READ:
  765. {
  766. int iRCIndex, n, iListViewIndex;
  767. char psData[MAX_RECV_CLIENT_DATA];
  768. LVFINDINFO lvfi;
  769. iRCIndex = GetRCIndexFromSocket(wParam);
  770. n = recv(g_RCData[iRCIndex].sock, psData, sizeof(psData), 0);
  771. if (n == SOCKET_ERROR) {
  772. OutputDebugString(_T("FD_READ but SOCKET_ERROR on recv"));
  773. } else {
  774. lvfi.flags = LVFI_STRING;
  775. lvfi.psz = g_RCData[iRCIndex].psRCName;
  776. lvfi.lParam = 0;
  777. lvfi.vkDirection = 0;
  778. iListViewIndex = ListView_FindItem(g_hListView, -1,
  779. &lvfi);
  780. if (strncmp(psData, "errorsmclient", (n > 13) ? 13 : n)
  781. == 0) {
  782. LoadString(NULL, IDS_SMCLIENTRUNERR, szDisplayString,
  783. MAX_DISPLAY_STRING_LENGTH);
  784. ListView_SetItemText(g_hListView, iListViewIndex,
  785. g_iStatusColumn, szDisplayString);
  786. } else if (strncmp(psData, "errorcreate",
  787. (n > 11) ? 11 : n) == 0) {
  788. LoadString(NULL, IDS_CREATESCRERR, szDisplayString,
  789. MAX_DISPLAY_STRING_LENGTH);
  790. ListView_SetItemText(g_hListView, iListViewIndex,
  791. g_iStatusColumn, szDisplayString);
  792. } else if (strncmp(psData, "success", (n > 11) ? 11 : n) == 0) {
  793. SYSTEMTIME startloctime;
  794. TCHAR psStartTimeDatePart[TIMEBUFSIZE];
  795. TCHAR psStartTimeTimePart[TIMEBUFSIZE];
  796. TCHAR psStartTime[TIMEBUFSIZE * 2];
  797. GetLocalTime(&startloctime); // set starttime
  798. GetDateFormat(0, 0, &startloctime, 0, psStartTimeDatePart, TIMEBUFSIZE);
  799. GetTimeFormat(0, 0, &startloctime, 0, psStartTimeTimePart, TIMEBUFSIZE);
  800. wsprintf(psStartTime, _T("%s %s"), psStartTimeDatePart, psStartTimeTimePart);
  801. ListView_SetItemText(g_hListView, iListViewIndex,
  802. g_iTimeStartedColumn, psStartTime);
  803. LoadString(NULL, IDS_SCRIPTSTARTED, szDisplayString,
  804. MAX_DISPLAY_STRING_LENGTH);
  805. ListView_SetItemText(g_hListView, iListViewIndex,
  806. g_iStatusColumn, szDisplayString);
  807. } else {
  808. LoadString(NULL, IDS_UNKNOWNROBOTALK, szDisplayString,
  809. MAX_DISPLAY_STRING_LENGTH);
  810. ListView_SetItemText(g_hListView, iListViewIndex,
  811. g_iStatusColumn, szDisplayString);
  812. }
  813. }
  814. }
  815. break;
  816. }
  817. break;
  818. }
  819. return DefWindowProc(hwnd, iMsg, wParam, lParam);
  820. }
  821. // The canary architecture works like this: The canary thread (i.e., this
  822. // function) is spawned when the application initializes, and immediately
  823. // blocks on g_hCanaryEvent. The main app, when it is time for the canary
  824. // to run, signals the event. Then the canary blocks on the timer script
  825. // (called "canary" so it can be a "canary.cmd," a "canary.bat," a
  826. // "canary.exe," etc.), writes how long it took to a file, and then blocks
  827. // again.
  828. void __cdecl CanaryThread(void *unused) {
  829. HWND hwnd = (HWND) unused;
  830. HWND hButton;
  831. int bCheck;
  832. FILE *fp;
  833. SYSTEMTIME timelocinit;
  834. SYSTEMTIME timelocfin;
  835. FILETIME ftinit;
  836. FILETIME ftfin;
  837. ULARGE_INTEGER nInit;
  838. ULARGE_INTEGER nFin;
  839. ULARGE_INTEGER nDiffTime;
  840. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  841. TCHAR psNumRunning[MAX_NUMBERTEXT];
  842. TCHAR psTimeDatePart[TIMEBUFSIZE];
  843. TCHAR psTimeTimePart[TIMEBUFSIZE];
  844. char psNumRunningA[MAX_NUMBERTEXT];
  845. char psTimeDatePartA[TIMEBUFSIZE];
  846. char psTimeTimePartA[TIMEBUFSIZE];
  847. hButton = GetDlgItem(hwnd, IDC_CANARYCHECK);
  848. for( ; ; ) {
  849. WaitForSingleObject(g_hCanaryEvent, INFINITE);
  850. // Check checkbox to see if "run canary automatically" is on
  851. // IDC_CANARYCHECK
  852. bCheck = (int) SendMessage(hButton, BM_GETCHECK, 0, 0);
  853. if (bCheck != 0) {
  854. // FUNCTIONALITY CHANGE: Canary delays the delay between
  855. // multiselect commands before starting
  856. LoadString(NULL, IDS_CANARYDELAYING, psDisplayString,
  857. MAX_DISPLAY_STRING_LENGTH);
  858. SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString,
  859. 0);
  860. Sleep(GetDelay(hwnd));
  861. LoadString(NULL, IDS_CANARYSTARTING, psDisplayString,
  862. MAX_DISPLAY_STRING_LENGTH);
  863. SendMessage(hwnd, WM_DisplayErrorText, (WPARAM) psDisplayString,
  864. 0);
  865. // Get the time
  866. GetLocalTime(&timelocinit);
  867. // Get number of scripts attempted
  868. GetWindowText(g_hNumRunning, psNumRunning, MAX_NUMBERTEXT);
  869. // run the script
  870. if (_spawnl(_P_WAIT, "canary", "canary", 0) != 0) {
  871. LoadString(NULL, IDS_CANARYCOULDNTSTART, psDisplayString,
  872. MAX_DISPLAY_STRING_LENGTH);
  873. SendMessage(hwnd, WM_DisplayErrorText,
  874. (WPARAM) psDisplayString, 0);
  875. } else {
  876. LoadString(NULL, IDS_CANARYFINISHED, psDisplayString,
  877. MAX_DISPLAY_STRING_LENGTH);
  878. SendMessage(hwnd, WM_DisplayErrorText,
  879. (WPARAM) psDisplayString, 0);
  880. }
  881. // Get the time again
  882. GetLocalTime(&timelocfin);
  883. // compute difference
  884. if ( SystemTimeToFileTime(&timelocinit, &ftinit) &&
  885. SystemTimeToFileTime(&timelocfin, &ftfin) ) {
  886. memcpy(&nInit, &ftinit, sizeof(FILETIME));
  887. memcpy(&nFin, &ftfin, sizeof(FILETIME));
  888. // This gives the difference in 100-nanosecond intervals (10^-7 sec).
  889. nDiffTime.QuadPart = nFin.QuadPart - nInit.QuadPart;
  890. // Divide by 10^7 to get seconds
  891. nDiffTime.QuadPart /= 10000000;
  892. // Get the date and time strings
  893. GetDateFormat(0, 0, &timelocinit, 0, psTimeDatePart, TIMEBUFSIZE);
  894. GetTimeFormat(0, 0, &timelocinit, 0, psTimeTimePart, TIMEBUFSIZE);
  895. // Convert strings to ANSI
  896. #ifdef UNICODE
  897. WideCharToMultiByte(CP_ACP, 0, psTimeDatePart, -1, psTimeDatePartA, TIMEBUFSIZE, 0, 0);
  898. WideCharToMultiByte(CP_ACP, 0, psTimeTimePart, -1, psTimeTimePartA, TIMEBUFSIZE, 0, 0);
  899. WideCharToMultiByte(CP_ACP, 0, psNumRunning, -1, psNumRunningA, MAX_NUMBERTEXT, 0, 0);
  900. #else
  901. strncpy(psTimeDatePartA, psTimeDatePart, TIMEBUFSIZE);
  902. strncpy(psTimeTimePartA, psTimeTimePart, TIMEBUFSIZE);
  903. strncpy(psNumRunningA, psNumRunning, MAX_NUMBERTEXT);
  904. #endif
  905. // open the file
  906. fp = fopen("canary.csv", "a+t");
  907. // write the difference to the file
  908. if (fp != 0) {
  909. fprintf(fp, "%s %s,%s,%d:%02d\n", psTimeDatePartA, psTimeTimePartA,
  910. psNumRunningA, (int) nDiffTime.QuadPart / 60, (int) nDiffTime.QuadPart % 60);
  911. // close the file
  912. fclose(fp);
  913. } else {
  914. LoadString(NULL, IDS_CANARYCOULDNOTOPENFILE, psDisplayString,
  915. MAX_DISPLAY_STRING_LENGTH);
  916. SendMessage(hwnd, WM_DisplayErrorText,
  917. (WPARAM) psDisplayString, 0);
  918. }
  919. }
  920. }
  921. }
  922. }
  923. // This function displays text in the status line. Returns 0 on success,
  924. // nonzero on error.
  925. int DisplayErrorText(TCHAR *psText) {
  926. SetWindowText(g_hErrorText, psText);
  927. return 0;
  928. }
  929. // helper function to find out the index in our data structure from the
  930. // incoming socket
  931. int GetRCIndexFromSocket(SOCKET wParam) {
  932. int i;
  933. for (i = 0; i < MAX_ROBOCLIENTS; i++) {
  934. if (g_RCData[i].valid == TRUE)
  935. if (g_RCData[i].sock == wParam)
  936. break;
  937. }
  938. return i;
  939. }
  940. // Initialize the listener socket
  941. SOCKET SockInit(u_short port) {
  942. SOCKET listenfd;
  943. struct sockaddr_in servaddr;
  944. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  945. TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
  946. listenfd = socket(AF_INET, SOCK_STREAM, 0);
  947. if (listenfd == INVALID_SOCKET) {
  948. LoadString(NULL, IDS_SOCKETERROR, psDisplayTitleString,
  949. MAX_DISPLAY_STRING_LENGTH);
  950. LoadString(NULL, IDS_SOCKETERROR, psDisplayString,
  951. MAX_DISPLAY_STRING_LENGTH);
  952. MessageBox(0, psDisplayString, psDisplayTitleString, 0);
  953. goto err;
  954. }
  955. memset(&servaddr, 0, sizeof(servaddr));
  956. servaddr.sin_family = AF_INET;
  957. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  958. servaddr.sin_port = htons(port);
  959. if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) != 0) {
  960. LoadString(NULL, IDS_BINDERRTITLE, psDisplayTitleString,
  961. MAX_DISPLAY_STRING_LENGTH);
  962. LoadString(NULL, IDS_BINDERRBODY, psDisplayString,
  963. MAX_DISPLAY_STRING_LENGTH);
  964. MessageBox(0, psDisplayString, psDisplayTitleString, 0);
  965. goto err;
  966. }
  967. if (listen(listenfd, SOMAXCONN) != 0) {
  968. LoadString(NULL, IDS_LISTENERROR, psDisplayTitleString,
  969. MAX_DISPLAY_STRING_LENGTH);
  970. LoadString(NULL, IDS_LISTENERROR, psDisplayString,
  971. MAX_DISPLAY_STRING_LENGTH);
  972. MessageBox(0, psDisplayString, psDisplayTitleString, 0);
  973. goto err;
  974. }
  975. return listenfd;
  976. err:
  977. return INVALID_SOCKET;
  978. }
  979. // function needed for ListView_SortItems to work. Compares the values
  980. // in two columns.
  981. int CALLBACK colcmp(LPARAM lParam1, LPARAM lParam2, LPARAM lParamColumn) {
  982. TCHAR *psz1;
  983. TCHAR *psz2;
  984. int i1, i2;
  985. TCHAR pszClientName[MAX_RCNAME];
  986. TCHAR pszSubItem1[MAX_RCNAME];
  987. TCHAR pszSubItem2[MAX_RCNAME];
  988. psz1 = (TCHAR *) lParam1;
  989. psz2 = (TCHAR *) lParam2;
  990. if ((lParam1 == 0) || (lParam2 == 0)) {
  991. OutputDebugString(_T("a null was passed to the sort function"));
  992. return 0;
  993. }
  994. // Find the item number in the ListView
  995. for (i1 = 0; i1 < ListView_GetItemCount(g_hListView); i1++) {
  996. ListView_GetItemText(g_hListView, i1, g_iClientNameColumn,
  997. pszClientName, MAX_RCNAME);
  998. if (_tcscmp(psz1, pszClientName) == 0)
  999. break;
  1000. }
  1001. for (i2 = 0; i2 < ListView_GetItemCount(g_hListView); i2++) {
  1002. ListView_GetItemText(g_hListView, i2, g_iClientNameColumn,
  1003. pszClientName, MAX_RCNAME);
  1004. if (_tcscmp(psz2, pszClientName) == 0)
  1005. break;
  1006. }
  1007. ListView_GetItemText(g_hListView, i1, (int) lParamColumn, pszSubItem1,
  1008. MAX_RCNAME);
  1009. ListView_GetItemText(g_hListView, i2, (int) lParamColumn, pszSubItem2,
  1010. MAX_RCNAME);
  1011. if (g_bAscending == TRUE)
  1012. return _tcscmp(pszSubItem1, pszSubItem2);
  1013. else
  1014. return -_tcscmp(pszSubItem1, pszSubItem2);
  1015. }
  1016. // Get the RoboClient index (in our data structure) from an entry in the
  1017. // listview (called an item)
  1018. int GetRCIndexFromRCItem(int iRightClickedItem) {
  1019. int i;
  1020. TCHAR psItemText[MAX_RCNAME];
  1021. for (i = 0; i < MAX_ROBOCLIENTS; i++) {
  1022. if (g_RCData[i].valid == TRUE) {
  1023. ListView_GetItemText(g_hListView, iRightClickedItem,
  1024. g_iClientNameColumn, psItemText, MAX_RCNAME);
  1025. if (_tcscmp(g_RCData[i].psRCName, psItemText) == 0)
  1026. break;
  1027. }
  1028. }
  1029. return i;
  1030. }
  1031. // Initiates a script run for a particular scriptname passed in
  1032. int TimedRunScriptOnSelectedItems(HWND hwnd, TCHAR *psScriptName) {
  1033. int iItemIndex;
  1034. int iRCIndex;
  1035. int nTimeout;
  1036. int bCheck;
  1037. HWND hDelayEdit;
  1038. HWND hButton;
  1039. LVITEM lvi;
  1040. TCHAR psDelayText[MAX_DELAYTEXT];
  1041. TCHAR psTempString[MAX_DISPLAY_STRING_LENGTH];
  1042. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  1043. hButton = GetDlgItem(hwnd, IDC_CANARYCHECK);
  1044. _ASSERTE(IsWindow(hButton));
  1045. // Loop through all the items in the list, changing the ones
  1046. // that are selected to "Pending" and STATE_PENDING
  1047. for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
  1048. iItemIndex++) {
  1049. lvi.iItem = iItemIndex;
  1050. lvi.iSubItem = 0;
  1051. lvi.mask = LVIF_STATE;
  1052. lvi.stateMask = LVIS_SELECTED;
  1053. ListView_GetItem(g_hListView, &lvi);
  1054. if (lvi.state & LVIS_SELECTED) {
  1055. iRCIndex = GetRCIndexFromRCItem(iItemIndex);
  1056. if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) {
  1057. LoadString(NULL, IDS_PENDING, psTempString,
  1058. MAX_DISPLAY_STRING_LENGTH);
  1059. _sntprintf(psDisplayString, MAX_DISPLAY_STRING_LENGTH,
  1060. psTempString, psScriptName);
  1061. ListView_SetItemText(g_hListView, iItemIndex,
  1062. g_iStatusColumn, psDisplayString);
  1063. g_RCData[iRCIndex].state = STATE_PENDING_SCRIPT;
  1064. _tcsncpy(g_RCData[iRCIndex].psPendingInfo, psScriptName,
  1065. MAX_PENDINGINFO);
  1066. } else {
  1067. LoadString(NULL, IDS_CANTRUNDISC, psTempString,
  1068. MAX_DISPLAY_STRING_LENGTH);
  1069. ListView_SetItemText(g_hListView, iItemIndex,
  1070. g_iStatusColumn, psTempString);
  1071. }
  1072. }
  1073. }
  1074. // Now, set the timer for all of the items.
  1075. hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT);
  1076. _ASSERTE(IsWindow(hDelayEdit));
  1077. GetWindowText(hDelayEdit, psDelayText, MAX_DELAYTEXT);
  1078. nTimeout = _ttoi(psDelayText);
  1079. nTimeout *= 1000;
  1080. // this should probably be a ui thing rather than a silent sfp-like thing
  1081. if (nTimeout == 0)
  1082. nTimeout = 100; // Don't allow a delay of 0
  1083. // Only delay if the "Run canary automatically" button is checked
  1084. // Check checkbox to see if "run canary automatically" is on
  1085. // IDC_CANARYCHECK
  1086. bCheck = (int) SendMessage(hButton, BM_GETCHECK, 0, 0);
  1087. if (bCheck != 0) {
  1088. g_nIDTimer = MySetTimer(hwnd, g_nIDTimer, GetSetDelay(hwnd));
  1089. } else {
  1090. g_nIDTimer = MySetTimer(hwnd, g_nIDTimer, 0);
  1091. }
  1092. SetEvent(g_hCanaryEvent);
  1093. // Fire off a WM_TIMER message immediately for the first guy
  1094. // SendMessage(hwnd, WM_TIMER, g_nIDTimer, 0);
  1095. return 0;
  1096. }
  1097. // Tell selected roboclients to run batch files such as reboot or update
  1098. int RunCommandOnSelectedItems(HWND hwnd, TCHAR *psCommandName) {
  1099. char psCommandNameA[MAX_SCRIPTLEN];
  1100. int iItemIndex, iRCIndex;
  1101. LVITEM lvi;
  1102. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  1103. #ifdef UNICODE
  1104. WideCharToMultiByte(CP_ACP, 0, psCommandName, -1,
  1105. psCommandNameA, MAX_SCRIPTLEN, 0, 0);
  1106. #else
  1107. strcpy(psCommandNameA, psCommandName);
  1108. #endif
  1109. // Loop through all the items in the list
  1110. for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
  1111. iItemIndex++) {
  1112. lvi.iItem = iItemIndex;
  1113. lvi.iSubItem = 0;
  1114. lvi.mask = LVIF_STATE;
  1115. lvi.stateMask = LVIS_SELECTED;
  1116. ListView_GetItem(g_hListView, &lvi);
  1117. if (lvi.state & LVIS_SELECTED) {
  1118. iRCIndex = GetRCIndexFromRCItem(iItemIndex);
  1119. if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) {
  1120. if (send(g_RCData[iRCIndex].sock, psCommandNameA,
  1121. _tcslen(psCommandName), 0) != SOCKET_ERROR) {
  1122. LoadString(NULL, IDS_COMMANDSENT, psDisplayString,
  1123. MAX_DISPLAY_STRING_LENGTH);
  1124. ListView_SetItemText(g_hListView, iItemIndex,
  1125. g_iStatusColumn, psDisplayString);
  1126. } else {
  1127. LoadString(NULL, IDS_SENDERROR, psDisplayString,
  1128. MAX_DISPLAY_STRING_LENGTH);
  1129. ListView_SetItemText(g_hListView, iItemIndex,
  1130. g_iStatusColumn, psDisplayString);
  1131. }
  1132. } // else was disconnected
  1133. }
  1134. }
  1135. return 0;
  1136. }
  1137. // main dispatch routine for when a timer message is received
  1138. int ProcessTimerMessage(HWND hwnd, WPARAM wParam) {
  1139. UINT_PTR nTimer = wParam;
  1140. int iItemIndex;
  1141. int iRCIndex;
  1142. TCHAR psNumberText[MAX_NUMBERTEXT];
  1143. // I don't know how it happens, but there start to be weird other timers
  1144. // about.
  1145. if (nTimer != g_nIDTimer)
  1146. return 0;
  1147. // For now, find the first pending item in the list and change its status
  1148. // to running
  1149. for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
  1150. iItemIndex++) {
  1151. iRCIndex = GetRCIndexFromRCItem(iItemIndex);
  1152. if (g_RCData[iRCIndex].valid) {
  1153. if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT) {
  1154. // Send the command to the client
  1155. if (SendRunCommand(iRCIndex) == 0) {
  1156. // Update count
  1157. wsprintf(psNumberText, _T("%d"), NumberRunningClients());
  1158. SetWindowText(g_hNumRunning, psNumberText);
  1159. // Fix the timer
  1160. // If NumRunning() % NumPerSet() == 0 AND NumRunning != 0,
  1161. // Set the timer to SETDELAY * 60 seconds at the end of
  1162. // running.
  1163. // * NumClientsPerSet was fixed at nonzero when MySetTimer
  1164. // was called initially
  1165. // * Not using MySetTimer here because that does all sorts
  1166. // of unnecessary disables
  1167. if (NumberRunningClients() % NumClientsPerSet(hwnd) == 0) {
  1168. if (NumberRunningClients() != 0) {
  1169. g_nIDTimer = SetTimer(hwnd, g_nIDTimer,
  1170. GetSetDelay(hwnd), 0);
  1171. SetEvent(g_hCanaryEvent); // do the canary thing
  1172. }
  1173. } else {
  1174. // else set the timer to the normal value. It used to be
  1175. // that we would set the timer to the normal value if
  1176. // numrunning % numperset was == 1, but that had buggy
  1177. // behavior when you canceled when there were a couple
  1178. // running and then you ran some more.
  1179. // if (NumberRunningClients() % NumClientsPerSet(hwnd) == 1)
  1180. g_nIDTimer = SetTimer(hwnd, g_nIDTimer,
  1181. GetDelay(hwnd), 0);
  1182. }
  1183. }
  1184. if (MorePendingScripts() == 0) {
  1185. MyKillTimer(hwnd, g_nIDTimer);
  1186. }
  1187. return 0;
  1188. }
  1189. }
  1190. }
  1191. // If we got here, we need to kill the timer
  1192. MyKillTimer(hwnd, nTimer);
  1193. return 0;
  1194. }
  1195. // Actually send the run command to a particular RC connection.
  1196. // Returns 0 on success, nonzero on error
  1197. int SendRunCommand(int iRCIndex) {
  1198. TCHAR psEditText[MAX_EDIT_TEXT_LENGTH];
  1199. TCHAR psCommandText[MAX_SCRIPTLEN];
  1200. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  1201. char psCommandTextA[MAX_SCRIPTLEN];
  1202. int iItemIndex;
  1203. LVFINDINFO lvfi;
  1204. lvfi.flags = LVFI_STRING;
  1205. lvfi.psz = g_RCData[iRCIndex].psRCName;
  1206. lvfi.lParam = 0;
  1207. lvfi.vkDirection = 0;
  1208. iItemIndex = ListView_FindItem(g_hListView, -1,
  1209. &lvfi);
  1210. GetWindowText(g_hTermSrvEditBox, psEditText, MAX_EDIT_TEXT_LENGTH);
  1211. wsprintf(psCommandText, _T("%s/%s/smc%03d"), psEditText,
  1212. g_RCData[iRCIndex].psPendingInfo, iRCIndex + 1);
  1213. #ifdef UNICODE
  1214. WideCharToMultiByte(CP_ACP, 0, psCommandText, -1,
  1215. psCommandTextA, MAX_SCRIPTLEN, 0, 0);
  1216. #else
  1217. strcpy(psCommandTextA, psCommandText);
  1218. #endif
  1219. if (send(g_RCData[iRCIndex].sock, psCommandTextA,
  1220. _tcslen(psCommandText), 0) != SOCKET_ERROR) {
  1221. // if successful, change text to Run command sent
  1222. LoadString(NULL, IDS_RUNCOMMANDSENT, psDisplayString,
  1223. MAX_DISPLAY_STRING_LENGTH);
  1224. ListView_SetItemText(g_hListView, iItemIndex,
  1225. g_iStatusColumn, psDisplayString);
  1226. // change state to RUNNING
  1227. g_RCData[iRCIndex].state = STATE_RUNNING;
  1228. return 0;
  1229. } else {
  1230. LoadString(NULL, IDS_SENDERROR, psDisplayString,
  1231. MAX_DISPLAY_STRING_LENGTH);
  1232. ListView_SetItemText(g_hListView, iItemIndex,
  1233. g_iStatusColumn, psDisplayString);
  1234. return -1;
  1235. }
  1236. }
  1237. // In: i, uninitialized integer
  1238. // psClientName, Client to try to find in the list
  1239. // Out: i, RCindex of a disconnected session with name "psClientName"
  1240. // Returns: 1 if found a disconnected item with that name,
  1241. // 0 otherwise
  1242. int IsDisconnected(TCHAR *psClientName, int *iReturnedIndex) {
  1243. int i;
  1244. for (i = 0; i < MAX_ROBOCLIENTS; i++) {
  1245. if (g_RCData[i].valid == TRUE)
  1246. if (g_RCData[i].state == STATE_DISCONNECTED)
  1247. if (_tcsncmp(psClientName, g_RCData[i].psRCName,
  1248. _tcslen(psClientName)) == 0) {
  1249. *iReturnedIndex = i;
  1250. return 1;
  1251. }
  1252. }
  1253. return 0;
  1254. }
  1255. // Are there still scripts that will be run in the current command?
  1256. int MorePendingScripts() {
  1257. int iItemIndex, iRCIndex;
  1258. for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
  1259. iItemIndex++) {
  1260. iRCIndex = GetRCIndexFromRCItem(iItemIndex);
  1261. if (g_RCData[iRCIndex].valid) {
  1262. if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT)
  1263. return 1;
  1264. }
  1265. }
  1266. return 0;
  1267. }
  1268. // Returns the number of scripts we think have started
  1269. int NumberRunningClients() {
  1270. int iItemIndex, iRCIndex;
  1271. int nNumberRunning = 0;
  1272. for (iRCIndex = 0; iRCIndex < MAX_ROBOCLIENTS; iRCIndex += 1) {
  1273. if (g_RCData[iRCIndex].valid) {
  1274. if (g_RCData[iRCIndex].state == STATE_RUNNING)
  1275. nNumberRunning++;
  1276. }
  1277. }
  1278. return nNumberRunning;
  1279. }
  1280. // Cancel all scripts currently pending
  1281. int CancelPendingScripts(HWND hwnd) {
  1282. int iItemIndex, iRCIndex;
  1283. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  1284. for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
  1285. iItemIndex++) {
  1286. iRCIndex = GetRCIndexFromRCItem(iItemIndex);
  1287. if (g_RCData[iRCIndex].valid) {
  1288. if (g_RCData[iRCIndex].state == STATE_PENDING_SCRIPT) {
  1289. g_RCData[iRCIndex].state = STATE_CONNECTED;
  1290. LoadString(NULL, IDS_CANCELCOMMAND, psDisplayString,
  1291. MAX_DISPLAY_STRING_LENGTH);
  1292. ListView_SetItemText(g_hListView, iItemIndex,
  1293. g_iStatusColumn, psDisplayString);
  1294. }
  1295. }
  1296. }
  1297. MyKillTimer(hwnd, g_nIDTimer);
  1298. return 0;
  1299. }
  1300. // Sets the timer using the Win32 SetTimer, and sets the appropriate menu items
  1301. // to disabled/enabled.
  1302. UINT_PTR MySetTimer(HWND hwnd, UINT_PTR nTimer, UINT nTimeout) {
  1303. // when we are setting the timer, we're disabling a bunch of things: menu
  1304. // items and edit boxes
  1305. EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKER, MF_GRAYED);
  1306. EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKERFAST, MF_GRAYED);
  1307. // EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_ADMINISTRATIVEWORKER,
  1308. // MF_GRAYED);
  1309. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_DATA, MF_GRAYED);
  1310. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_STW, MF_GRAYED);
  1311. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_BLANK, MF_GRAYED);
  1312. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_CONFIGURATIONSCRIPT,
  1313. MF_GRAYED);
  1314. // EnableMenuItem(g_hPopupMenu, ID__UPDATE, MF_GRAYED);
  1315. EnableMenuItem(g_hPopupMenu, ID__REBOOT, MF_GRAYED);
  1316. EnableWindow(GetDlgItem(hwnd, IDC_TERMSRVEDIT), FALSE);
  1317. EnableWindow(GetDlgItem(hwnd, IDC_DELAYEDIT), FALSE);
  1318. EnableWindow(GetDlgItem(hwnd, IDC_CLIENTSPERSET), FALSE);
  1319. EnableWindow(GetDlgItem(hwnd, IDC_SETDELAY), FALSE);
  1320. EnableWindow(GetDlgItem(hwnd, IDC_CANARYCHECK), FALSE);
  1321. // and we're enabling "Cancel Pending tasks"
  1322. EnableMenuItem(g_hPopupMenu, ID_CANCEL, MF_ENABLED);
  1323. // We are also making sure that the number of clients per set, if 0,
  1324. // is set to MAX_ROBOCLIENTS
  1325. if (NumClientsPerSet(hwnd) == 0) {
  1326. HWND hClientsPerSet;
  1327. TCHAR sClientsPerSetText[MAX_NUMBERTEXT];
  1328. hClientsPerSet = GetDlgItem(hwnd, IDC_CLIENTSPERSET);
  1329. _sntprintf(sClientsPerSetText, MAX_NUMBERTEXT, _T("%d"), MAX_ROBOCLIENTS);
  1330. sClientsPerSetText[MAX_NUMBERTEXT - 1] = 0;
  1331. SetWindowText(hClientsPerSet, sClientsPerSetText);
  1332. }
  1333. return SetTimer(hwnd, nTimer, nTimeout, 0);
  1334. }
  1335. // Kills the timer and sets appropriate menu items disabled or enabled
  1336. int MyKillTimer(HWND hwnd, UINT_PTR nTimer) {
  1337. // When killing the timer, re-enable menu items and edit boxes
  1338. EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKER, MF_ENABLED);
  1339. EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_KNOWLEDGEWORKERFAST, MF_ENABLED);
  1340. // EnableMenuItem(g_hPopupMenu, ID_RUNSCRIPT_ADMINISTRATIVEWORKER,
  1341. // MF_ENABLED);
  1342. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_DATA, MF_ENABLED);
  1343. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_STW, MF_ENABLED);
  1344. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_BLANK, MF_ENABLED);
  1345. EnableMenuItem(g_hPopupMenu, ID__RUNSCRIPT_CONFIGURATIONSCRIPT,
  1346. MF_ENABLED);
  1347. // EnableMenuItem(g_hPopupMenu, ID__UPDATE, MF_ENABLED);
  1348. EnableMenuItem(g_hPopupMenu, ID__REBOOT, MF_ENABLED);
  1349. EnableWindow(GetDlgItem(hwnd, IDC_TERMSRVEDIT), TRUE);
  1350. EnableWindow(GetDlgItem(hwnd, IDC_DELAYEDIT), TRUE);
  1351. EnableWindow(GetDlgItem(hwnd, IDC_CLIENTSPERSET), TRUE);
  1352. EnableWindow(GetDlgItem(hwnd, IDC_SETDELAY), TRUE);
  1353. EnableWindow(GetDlgItem(hwnd, IDC_CANARYCHECK), TRUE);
  1354. // and disable "Cancel Pending Tasks"
  1355. EnableMenuItem(g_hPopupMenu, ID_CANCEL, MF_GRAYED);
  1356. return KillTimer(hwnd, nTimer);
  1357. }
  1358. // Retrieves the delay in the IDC_DELAYEDIT box (turned into milliseconds)
  1359. int GetDelay(HWND hwnd) {
  1360. HWND hDelayEdit;
  1361. int nTimeout;
  1362. TCHAR psDelayText[MAX_DELAYTEXT];
  1363. hDelayEdit = GetDlgItem(hwnd, IDC_DELAYEDIT);
  1364. _ASSERTE(IsWindow(hDelayEdit));
  1365. GetWindowText(hDelayEdit, psDelayText, MAX_DELAYTEXT);
  1366. nTimeout = _ttoi(psDelayText);
  1367. nTimeout *= 1000;
  1368. if (nTimeout == 0)
  1369. nTimeout = 100; // Don't allow a delay of 0
  1370. return nTimeout;
  1371. }
  1372. // Retrieves the number in the IDC_CLIENTSPERSET box
  1373. int NumClientsPerSet(HWND hwnd) {
  1374. HWND hClientsPerSet;
  1375. TCHAR psClientsPerSet[MAX_DELAYTEXT];
  1376. hClientsPerSet = GetDlgItem(hwnd, IDC_CLIENTSPERSET);
  1377. GetWindowText(hClientsPerSet, psClientsPerSet, MAX_DELAYTEXT);
  1378. return _ttoi(psClientsPerSet);
  1379. }
  1380. // Retrieves the delay in the IDC_SETDELAY box, turned into milliseconds
  1381. int GetSetDelay(HWND hwnd) {
  1382. HWND hSetDelayEdit;
  1383. int nTimeout;
  1384. TCHAR psDelayText[MAX_DELAYTEXT];
  1385. hSetDelayEdit = GetDlgItem(hwnd, IDC_SETDELAY);
  1386. _ASSERTE(IsWindow(hSetDelayEdit));
  1387. GetWindowText(hSetDelayEdit, psDelayText, MAX_DELAYTEXT);
  1388. nTimeout = _ttoi(psDelayText);
  1389. nTimeout *= 60000; // minutes to ms
  1390. if (nTimeout == 0)
  1391. nTimeout = GetDelay(hwnd); // Normal timer
  1392. return nTimeout;
  1393. }
  1394. // Takes the command line string as an argument and modifies global variables
  1395. // for the arguments.
  1396. // Pops up a messagebox on error
  1397. int GetCommandLineArgs(TCHAR *psCommandLine) {
  1398. TCHAR *psCurrPtr = psCommandLine;
  1399. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  1400. TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
  1401. if (*psCurrPtr == '\"') {
  1402. psCurrPtr++; // skip the opening quote
  1403. // Handle if the first arg is quoted
  1404. while ((*psCurrPtr != 0) && (*psCurrPtr != '\"'))
  1405. psCurrPtr++;
  1406. // then skip the " character
  1407. if (*psCurrPtr == '\"')
  1408. psCurrPtr++;
  1409. } else {
  1410. // go forward in the array until you get a ' ' or until NULL
  1411. while((*psCurrPtr != 0) && (*psCurrPtr != ' '))
  1412. psCurrPtr++;
  1413. }
  1414. // skip spaces
  1415. while(*psCurrPtr == ' ')
  1416. psCurrPtr++;
  1417. // if the character is NULL, return 0 (no args)
  1418. if (*psCurrPtr == 0)
  1419. return 0;
  1420. while (*psCurrPtr != 0) {
  1421. // now, check whether the next three are "-s:" and then non-null,
  1422. if (_tcsncmp(psCurrPtr, _T("-s:"), 3) == 0) {
  1423. if ((psCurrPtr[3] == 0) || (psCurrPtr[3] == ' ')) {
  1424. goto SHOWMSGBOX;
  1425. } else {
  1426. TCHAR *psStartOfName = &psCurrPtr[3];
  1427. int namelen = 0;
  1428. while ((psStartOfName[namelen] != 0) && (psStartOfName[namelen] != ' '))
  1429. namelen++;
  1430. _tcsncpy(g_TermSrvrName, psStartOfName, namelen);
  1431. g_TermSrvrName[namelen] = 0;
  1432. psCurrPtr = &psStartOfName[namelen];
  1433. }
  1434. } else if (_tcsncmp(psCurrPtr, _T("-n:"), 3) == 0) {
  1435. if ((psCurrPtr[3] == 0) || (psCurrPtr[3] == ' ')) {
  1436. goto SHOWMSGBOX;
  1437. } else {
  1438. TCHAR *psStartOfNum = &psCurrPtr[3];
  1439. int numlen = 0;
  1440. while ((psStartOfNum[numlen] != 0) && (psStartOfNum[numlen] != ' '))
  1441. numlen++;
  1442. g_nNumConnections = _ttoi(psStartOfNum);
  1443. // CHANGE BACK FROM 64 TO 5
  1444. if ((g_nNumConnections < 1) || (g_nNumConnections > 64)) {
  1445. g_nNumConnections = 3;
  1446. goto SHOWMSGBOX;
  1447. }
  1448. psCurrPtr = &psStartOfNum[numlen];
  1449. }
  1450. } else {
  1451. // error
  1452. goto SHOWMSGBOX;
  1453. }
  1454. // skip whitespace
  1455. while(*psCurrPtr == ' ')
  1456. psCurrPtr++;
  1457. }
  1458. return 0;
  1459. SHOWMSGBOX:
  1460. LoadString(NULL, IDS_COMMANDLINESYNTAX, psDisplayString,
  1461. MAX_DISPLAY_STRING_LENGTH);
  1462. LoadString(NULL, IDS_COMMANDLINESYNTAXTITLE, psDisplayTitleString,
  1463. MAX_DISPLAY_STRING_LENGTH);
  1464. MessageBox(0, psDisplayString, psDisplayTitleString, 0);
  1465. return -1;
  1466. }
  1467. // log information to our global log file
  1468. int LogToLogFile(char *psLogData) {
  1469. FILE *fp;
  1470. SYSTEMTIME logloctime;
  1471. TCHAR psTimeDatePart[TIMEBUFSIZE];
  1472. TCHAR psTimeTimePart[TIMEBUFSIZE];
  1473. char psTimeDatePartA[TIMEBUFSIZE];
  1474. char psTimeTimePartA[TIMEBUFSIZE];
  1475. // Get the time
  1476. GetLocalTime(&logloctime);
  1477. // Get strings
  1478. GetDateFormat(0, 0, &logloctime, 0, psTimeDatePart, TIMEBUFSIZE);
  1479. GetTimeFormat(0, 0, &logloctime, 0, psTimeTimePart, TIMEBUFSIZE);
  1480. // Make sure we are in ANSI
  1481. #ifdef UNICODE
  1482. WideCharToMultiByte(CP_ACP, 0, psTimeDatePart, -1, psTimeDatePartA, TIMEBUFSIZE, 0, 0);
  1483. WideCharToMultiByte(CP_ACP, 0, psTimeTimePart, -1, psTimeTimePartA, TIMEBUFSIZE, 0, 0);
  1484. #else
  1485. strncpy(psTimeDatePartA, psTimeDatePart, TIMEBUFSIZE);
  1486. strncpy(psTimeTimePartA, psTimeTimePart, TIMEBUFSIZE);
  1487. #endif
  1488. EnterCriticalSection(&g_LogFileCritSect);
  1489. // open the file
  1490. fp = fopen("log.txt", "a+t");
  1491. // write the information to the file
  1492. if (fp != 0) {
  1493. // First, a timestamp
  1494. fprintf(fp, "%s %s\n", psTimeDatePartA, psTimeTimePartA);
  1495. // Now, the message
  1496. fprintf(fp, "%s\n\n", psLogData);
  1497. // close the file
  1498. fclose(fp);
  1499. } else {
  1500. // error
  1501. }
  1502. LeaveCriticalSection(&g_LogFileCritSect);
  1503. return 0;
  1504. }
  1505. int ToAnsi(char *psDest, const TCHAR *psSrc, int nSizeOfBuffer) {
  1506. #ifdef UNICODE
  1507. WideCharToMultiByte(CP_ACP, 0, psSrc, -1, psDest, nSizeOfBuffer, 0, 0);
  1508. #else
  1509. _strncpy(psDest, psSrc, nSizeOfBuffer);
  1510. #endif
  1511. return 0;
  1512. }
  1513. // On close, clean up by disabling the listener socket then closing all open
  1514. // connections. This ensures the roboclients will know the roboserver has
  1515. // exited
  1516. int CleanUp(HWND hwnd) {
  1517. int iItemIndex;
  1518. int iRCIndex;
  1519. TCHAR psDisplayString[MAX_DISPLAY_STRING_LENGTH];
  1520. TCHAR psDisplayTitleString[MAX_DISPLAY_STRING_LENGTH];
  1521. // Disable listener
  1522. LoadString(NULL, IDS_CLOSINGLISTENER, psDisplayString,
  1523. MAX_DISPLAY_STRING_LENGTH);
  1524. SetWindowText(g_hErrorText, psDisplayString);
  1525. if (closesocket(g_listenersocket) != 0) {
  1526. LoadString(NULL, IDS_COULDNOTCLOSELISTENER, psDisplayString,
  1527. MAX_DISPLAY_STRING_LENGTH);
  1528. LoadString(NULL, IDS_COULDNOTCLOSELISTENER, psDisplayString,
  1529. MAX_DISPLAY_STRING_LENGTH);
  1530. MessageBox(hwnd, psDisplayString, psDisplayTitleString, 0);
  1531. }
  1532. // Set status line to "disconnecting clients..."
  1533. LoadString(NULL, IDS_DISCONNECTINGCLIENTS, psDisplayString,
  1534. MAX_DISPLAY_STRING_LENGTH);
  1535. SetWindowText(g_hErrorText, psDisplayString);
  1536. // Disconnect all the clients
  1537. for (iItemIndex = 0; iItemIndex < ListView_GetItemCount(g_hListView);
  1538. iItemIndex++) {
  1539. iRCIndex = GetRCIndexFromRCItem(iItemIndex);
  1540. if (g_RCData[iRCIndex].valid) {
  1541. if (g_RCData[iRCIndex].state != STATE_DISCONNECTED) {
  1542. shutdown(g_RCData[iRCIndex].sock, SD_BOTH);
  1543. closesocket(g_RCData[iRCIndex].sock);
  1544. }
  1545. }
  1546. }
  1547. return 0;
  1548. }
  1549. // This procedure is for the subclassing of all the tabbable controls so that
  1550. // I can tab between them.
  1551. LRESULT CALLBACK TabProc(HWND hwnd, UINT Msg,
  1552. WPARAM wParam, LPARAM lParam) {
  1553. int i;
  1554. // Find the id of the hwnd
  1555. for (i = 0; i < NUM_TABBED_ITEMS; i++) {
  1556. if (g_hwnd[i] == hwnd)
  1557. break;
  1558. }
  1559. switch (Msg) {
  1560. case WM_KEYDOWN:
  1561. if (wParam == VK_TAB) {
  1562. int newItem = (i + (GetKeyState(VK_SHIFT) < 0 ?
  1563. NUM_TABBED_ITEMS - 1 : 1)) % NUM_TABBED_ITEMS;
  1564. // set the focus to the next or previous item
  1565. SetFocus(g_hwnd[newItem]);
  1566. // if the control is before an edit box control, select all the
  1567. // text in the edit control that gets selected
  1568. if ((newItem > 2) && (newItem < 7))
  1569. SendMessage(g_hwnd[newItem], EM_SETSEL, 0, -1);
  1570. }
  1571. break;
  1572. case WM_SETFOCUS:
  1573. break;
  1574. }
  1575. return CallWindowProc((WNDPROC) g_OldProc[i], hwnd, Msg, wParam, lParam);
  1576. }
  1577. // Message box on fatal error.
  1578. // IN: current hInstance of string resources
  1579. // ID in StringTable of string to display
  1580. void FatalErrMsgBox(HINSTANCE hInstance, UINT nMsgId) {
  1581. TCHAR szTitleString[MAX_DISPLAY_STRING_LENGTH];
  1582. TCHAR szErrorString[MAX_DISPLAY_STRING_LENGTH];
  1583. LoadString(hInstance, IDS_FATALERROR, szTitleString,
  1584. MAX_DISPLAY_STRING_LENGTH);
  1585. LoadString(hInstance, nMsgId, szErrorString,
  1586. MAX_DISPLAY_STRING_LENGTH);
  1587. MessageBox(0, szErrorString, szTitleString, 0);
  1588. }