Advanced status calculation fully implemented
[public/netxms.git] / src / console / win32 / tools.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Windows Console
4 ** Copyright (C) 2004 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** $module: tools.cpp
21 ** Various tools and helper functions
22 **
23 **/
24
25 #include "stdafx.h"
26 #include "nxcon.h"
27
28
29 //
30 // Format time stamp
31 //
32
33 char *FormatTimeStamp(DWORD dwTimeStamp, char *pszBuffer, int iType)
34 {
35 struct tm *pTime;
36 static char *pFormat[] = { "%d-%b-%Y %H:%M:%S", "%H:%M:%S" };
37
38 pTime = localtime((const time_t *)&dwTimeStamp);
39 strftime(pszBuffer, 32, pFormat[iType], pTime);
40 return pszBuffer;
41 }
42
43
44 //
45 // Get size of a window
46 //
47
48 CSize GetWindowSize(CWnd *pWnd)
49 {
50 RECT rect;
51 CSize size;
52
53 pWnd->GetWindowRect(&rect);
54 size.cx = rect.right - rect.left;
55 size.cy = rect.bottom - rect.top;
56 return size;
57 }
58
59
60 //
61 // Enable or disable dialog item
62 //
63
64 void EnableDlgItem(CDialog *pWnd, int nCtrl, BOOL bEnable)
65 {
66 CWnd *pCtrl;
67
68 pCtrl = pWnd->GetDlgItem(nCtrl);
69 if (pCtrl != NULL)
70 pCtrl->EnableWindow(bEnable);
71 }
72
73
74 //
75 // Check if dialog button is checked
76 //
77
78 BOOL IsButtonChecked(CDialog *pWnd, int nCtrl)
79 {
80 return pWnd->SendDlgItemMessage(nCtrl, BM_GETCHECK) == BST_CHECKED;
81 }
82
83
84 //
85 // Select given item in list view
86 // Will remove selection from all currently selected items and set
87 // LVIS_SELECTED and LVIS_FOCUSED flags to specified item
88 //
89
90 void SelectListViewItem(CListCtrl *pListCtrl, int iItem)
91 {
92 int i;
93
94 i = pListCtrl->GetNextItem(-1, LVIS_SELECTED);
95 while(i != -1)
96 {
97 pListCtrl->SetItemState(i, 0, LVIS_SELECTED | LVIS_FOCUSED);
98 i = pListCtrl->GetNextItem(i, LVIS_SELECTED);
99 }
100 pListCtrl->SetItemState(iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
101 pListCtrl->SetSelectionMark(iItem);
102 }
103
104
105 //
106 // Build full OID for MIB tree leaf
107 //
108
109 void BuildOIDString(SNMP_MIBObject *pNode, TCHAR *pszBuffer)
110 {
111 DWORD dwPos, dwSubIdList[MAX_OID_LEN];
112 int iBufPos = 0;
113 SNMP_MIBObject *pCurr;
114
115 if (pNode->Parent() == NULL)
116 {
117 pszBuffer[0] = 0;
118 }
119 else
120 {
121 for(dwPos = 0, pCurr = pNode; pCurr->Parent() != NULL; pCurr = pCurr->Parent())
122 dwSubIdList[dwPos++] = pCurr->OID();
123 while(dwPos > 0)
124 {
125 sprintf(&pszBuffer[iBufPos], ".%u", dwSubIdList[--dwPos]);
126 iBufPos = strlen(pszBuffer);
127 }
128 }
129 }
130
131
132 //
133 // Build full symbolic OID for MIB tree leaf
134 //
135
136 TCHAR *BuildSymbolicOIDString(SNMP_MIBObject *pNode, DWORD dwInstance)
137 {
138 DWORD dwPos, dwSize;
139 TCHAR *pszBuffer;
140 const TCHAR *pszSubIdList[MAX_OID_LEN];
141 int iBufPos = 0;
142 SNMP_MIBObject *pCurr;
143
144 if (pNode->Parent() == NULL)
145 {
146 pszBuffer = (char *)malloc(4);
147 pszBuffer[0] = 0;
148 }
149 else
150 {
151 for(dwPos = 0, dwSize = 0, pCurr = pNode; pCurr->Parent() != NULL; pCurr = pCurr->Parent())
152 {
153 pszSubIdList[dwPos] = CHECK_NULL(pCurr->Name());
154 dwSize += strlen(pszSubIdList[dwPos]) + 1;
155 dwPos++;
156 }
157 pszBuffer = (char *)malloc(dwSize + 16);
158 for(iBufPos = 0; dwPos > 0;)
159 {
160 iBufPos += sprintf(&pszBuffer[iBufPos], ".%s", pszSubIdList[--dwPos]);
161 }
162 sprintf(&pszBuffer[iBufPos], ".%lu", dwInstance);
163 }
164 return pszBuffer;
165 }
166
167
168 //
169 // Translate given code to text
170 //
171
172 const char *CodeToText(int iCode, CODE_TO_TEXT *pTranslator, const char *pszDefaultText)
173 {
174 int i;
175
176 for(i = 0; pTranslator[i].pszText != NULL; i++)
177 if (pTranslator[i].iCode == iCode)
178 return pTranslator[i].pszText;
179 return pszDefaultText;
180 }
181
182
183 //
184 // Translate UNIX text to MSDOS (i.e. convert LF to CR/LF)
185 //
186
187 char *TranslateUNIXText(const char *pszText)
188 {
189 int n;
190 const char *ptr;
191 char *dptr, *pDst;
192
193 // Count newline characters
194 for(ptr = pszText, n = 0; *ptr != 0; ptr++)
195 if (*ptr == '\n')
196 n++;
197
198 pDst = (char *)malloc(strlen(pszText) + n + 1);
199 for(ptr = pszText, dptr = pDst; *ptr != 0; ptr++)
200 if (*ptr == '\n')
201 {
202 *dptr++ = '\r';
203 *dptr++ = '\n';
204 }
205 else
206 {
207 *dptr++ = *ptr;
208 }
209 *dptr = 0;
210 return pDst;
211 }
212
213
214 //
215 // Load bitmap into image list
216 //
217
218 void LoadBitmapIntoList(CImageList *pImageList, UINT nIDResource, COLORREF rgbMaskColor)
219 {
220 CBitmap bmp;
221
222 bmp.LoadBitmap(nIDResource);
223 pImageList->Add(&bmp, rgbMaskColor);
224 }
225
226
227 //
228 // Find image's index in list by image id
229 //
230
231 int ImageIdToIndex(DWORD dwImageId)
232 {
233 DWORD i;
234
235 for(i = 0; i < g_pSrvImageList->dwNumImages; i++)
236 if (g_pSrvImageList->pImageList[i].dwId == dwImageId)
237 return i;
238 return -1;
239 }
240
241
242 //
243 // Create image list with object images
244 //
245
246 void CreateObjectImageList(void)
247 {
248 HICON hIcon;
249 DWORD i, dwPos;
250 char szFileName[MAX_PATH];
251
252 // Create small (16x16) image list
253 if (g_pObjectSmallImageList != NULL)
254 delete g_pObjectSmallImageList;
255 g_pObjectSmallImageList = new CImageList;
256 g_pObjectSmallImageList->Create(16, 16, ILC_COLOR24 | ILC_MASK, 16, 8);
257
258 // Create normal (32x32) image list
259 if (g_pObjectNormalImageList != NULL)
260 delete g_pObjectNormalImageList;
261 g_pObjectNormalImageList = new CImageList;
262 g_pObjectNormalImageList->Create(32, 32, ILC_COLOR24 | ILC_MASK, 16, 8);
263
264 strcpy(szFileName, g_szWorkDir);
265 strcat(szFileName, WORKDIR_IMAGECACHE);
266 strcat(szFileName, "\\");
267 dwPos = strlen(szFileName);
268
269 for(i = 0; i < g_pSrvImageList->dwNumImages; i++)
270 {
271 sprintf(&szFileName[dwPos], "%08x.ico", g_pSrvImageList->pImageList[i].dwId);
272
273 // Load and add 16x16 image
274 hIcon = (HICON)LoadImage(NULL, szFileName, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
275 g_pObjectSmallImageList->Add(hIcon);
276 DestroyIcon(hIcon);
277
278 // Load and add 32x32 image
279 hIcon = (HICON)LoadImage(NULL, szFileName, IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
280 g_pObjectNormalImageList->Add(hIcon);
281 DestroyIcon(hIcon);
282 }
283 }
284
285
286 //
287 // Get index of class default image
288 //
289
290 int GetClassDefaultImageIndex(int iClass)
291 {
292 DWORD i;
293
294 for(i = 0; i < g_dwDefImgListSize; i++)
295 if (g_pDefImgList[i].dwObjectClass == (DWORD)iClass)
296 return g_pDefImgList[i].iImageIndex;
297 return -1;
298 }
299
300
301 //
302 // Get image index for given object
303 //
304
305 int GetObjectImageIndex(NXC_OBJECT *pObject)
306 {
307 // Check if object has custom image
308 return (pObject->dwImage != IMG_DEFAULT) ?
309 ImageIdToIndex(pObject->dwImage) :
310 GetClassDefaultImageIndex(pObject->iClass);
311 }
312
313
314 //
315 // Create image list with event severity icons
316 //
317
318 CImageList *CreateEventImageList(void)
319 {
320 CImageList *pImageList;
321
322 pImageList = new CImageList;
323 pImageList->Create(16, 16, ILC_COLOR24 | ILC_MASK, 8, 8);
324 pImageList->Add(theApp.LoadIcon(IDI_SEVERITY_NORMAL));
325 pImageList->Add(theApp.LoadIcon(IDI_SEVERITY_WARNING));
326 pImageList->Add(theApp.LoadIcon(IDI_SEVERITY_MINOR));
327 pImageList->Add(theApp.LoadIcon(IDI_SEVERITY_MAJOR));
328 pImageList->Add(theApp.LoadIcon(IDI_SEVERITY_CRITICAL));
329 pImageList->Add(theApp.LoadIcon(IDI_UNKNOWN)); // For alarms
330 pImageList->Add(theApp.LoadIcon(IDI_ACK));
331 return pImageList;
332 }
333
334
335 //
336 // Find action in list by ID
337 //
338
339 NXC_ACTION *FindActionById(DWORD dwActionId)
340 {
341 DWORD i;
342
343 for(i = 0; i < g_dwNumActions; i++)
344 if (g_pActionList[i].dwId == dwActionId)
345 return &g_pActionList[i];
346 return NULL;
347 }
348
349
350 //
351 // Update action list with information received from server
352 //
353
354 void UpdateActions(DWORD dwCode, NXC_ACTION *pAction)
355 {
356 DWORD i;
357 NXC_ACTION *pCurrAction;
358
359 LockActions();
360
361 // Find action with given ID
362 pCurrAction = FindActionById(pAction->dwId);
363
364 // Update action list depending on notification code
365 switch(dwCode)
366 {
367 case NX_NOTIFY_ACTION_CREATED:
368 case NX_NOTIFY_ACTION_MODIFIED:
369 if (pCurrAction == NULL)
370 {
371 i = g_dwNumActions;
372 g_dwNumActions++;
373 g_pActionList = (NXC_ACTION *)realloc(g_pActionList, sizeof(NXC_ACTION) * g_dwNumActions);
374 memcpy(&g_pActionList[i], pAction, sizeof(NXC_ACTION));
375 g_pActionList[i].pszData = strdup(pAction->pszData);
376 }
377 else
378 {
379 // Action with given id already exist, just update it
380 safe_free(pCurrAction->pszData);
381 memcpy(pCurrAction, pAction, sizeof(NXC_ACTION));
382 pCurrAction->pszData = strdup(pAction->pszData);
383 }
384 break;
385 case NX_NOTIFY_ACTION_DELETED:
386 if (pCurrAction != NULL)
387 {
388 for(i = 0; i < g_dwNumActions; i++)
389 if (g_pActionList[i].dwId == pAction->dwId)
390 {
391 g_dwNumActions--;
392 safe_free(g_pActionList[i].pszData);
393 memmove(&g_pActionList[i], &g_pActionList[i + 1],
394 sizeof(NXC_ACTION) * (g_dwNumActions - i));
395 break;
396 }
397 }
398 break;
399 }
400
401 UnlockActions();
402 }
403
404
405 //
406 // Restore placement of MDI child window
407 //
408
409 void RestoreMDIChildPlacement(CMDIChildWnd *pWnd, WINDOWPLACEMENT *pwp)
410 {
411 BOOL bMaximized;
412
413 bMaximized = (pwp->showCmd == SW_SHOWMAXIMIZED);
414 pwp->showCmd = SW_SHOWNORMAL;
415 pWnd->SetWindowPlacement(pwp);
416 if (bMaximized)
417 ::PostMessage(pWnd->GetParent()->m_hWnd, WM_MDIMAXIMIZE, (WPARAM)pWnd->m_hWnd, 0);
418 }
419
420
421 //
422 // Extract parameter from window parameters string
423 //
424
425 BOOL ExtractWindowParam(TCHAR *pszStr, TCHAR *pszParam, TCHAR *pszBuffer, int iSize)
426 {
427 TCHAR *pCurr, szName[32];
428 int iState = 0, iPos;
429 BOOL bResult = FALSE;
430
431 for(pCurr = pszStr, iPos = 0; (*pCurr != 0) && (iState != -1); pCurr++)
432 {
433 switch(iState)
434 {
435 case 0: // Read parameter name
436 if (*pCurr == _T(':'))
437 {
438 szName[iPos] = 0;
439 iPos = 0;
440 if (!_tcscmp(szName, pszParam))
441 {
442 bResult = TRUE;
443 iState = 1;
444 }
445 else
446 {
447 iState = 2;
448 }
449 }
450 else
451 {
452 if (iPos < 31)
453 szName[iPos++] = *pCurr;
454 }
455 break;
456 case 1: // Read value
457 if (*pCurr == _T('\x7F'))
458 {
459 iState = -1; // Finish
460 }
461 else
462 {
463 if (iPos < iSize - 1)
464 pszBuffer[iPos++] = *pCurr;
465 }
466 break;
467 case 2: // Skip value
468 if (*pCurr == _T('\x7F'))
469 iState = 0;
470 break;
471 }
472 }
473 pszBuffer[iPos] = 0;
474 return bResult;
475 }
476
477
478 //
479 // Extract window parameter as DWORD
480 //
481
482 DWORD ExtractWindowParamULong(TCHAR *pszStr, TCHAR *pszParam, DWORD dwDefault)
483 {
484 TCHAR szBuffer[32], *eptr;
485 DWORD dwResult;
486
487 if (ExtractWindowParam(pszStr, pszParam, szBuffer, 32))
488 {
489 dwResult = _tcstoul(szBuffer, &eptr, 0);
490 if (*eptr != 0)
491 dwResult = dwDefault;
492 }
493 else
494 {
495 dwResult = dwDefault;
496 }
497 return dwResult;
498 }
499
500
501 //
502 // Extract window parameter as long
503 //
504
505 long ExtractWindowParamLong(TCHAR *pszStr, TCHAR *pszParam, long nDefault)
506 {
507 TCHAR szBuffer[32], *eptr;
508 long nResult;
509
510 if (ExtractWindowParam(pszStr, pszParam, szBuffer, 32))
511 {
512 nResult = _tcstol(szBuffer, &eptr, 0);
513 if (*eptr != 0)
514 nResult = nDefault;
515 }
516 else
517 {
518 nResult = nDefault;
519 }
520 return nResult;
521 }
522
523
524 //
525 // Constructors for DCIInfo class
526 //
527
528 DCIInfo::DCIInfo()
529 {
530 m_dwNodeId = 0;
531 m_dwItemId = 0;
532 m_iSource = 0;
533 m_iDataType = 0;
534 m_pszParameter = NULL;
535 m_pszDescription = NULL;
536 }
537
538 DCIInfo::DCIInfo(DWORD dwNodeId, NXC_DCI *pItem)
539 {
540 m_dwNodeId = dwNodeId;
541 m_dwItemId = pItem->dwId;
542 m_iSource = pItem->iSource;
543 m_iDataType = pItem->iDataType;
544 m_pszParameter = _tcsdup(pItem->szName);
545 m_pszDescription = _tcsdup(pItem->szDescription);
546 }
547
548
549 //
550 // Destructor for class DCIInfo
551 //
552
553 DCIInfo::~DCIInfo()
554 {
555 safe_free(m_pszParameter);
556 safe_free(m_pszDescription);
557 }
558
559
560 //
561 // Copy menu items from one menu to another
562 //
563
564 void CopyMenuItems(CMenu *pDst, CMenu *pSrc)
565 {
566 DWORD i;
567 TCHAR szBuffer[256];
568 MENUITEMINFO info;
569
570 info.cbSize = sizeof(MENUITEMINFO);
571 for(i = 0; i < pSrc->GetMenuItemCount(); i++)
572 {
573 info.fMask = MIIM_ID | MIIM_TYPE;
574 info.dwTypeData = szBuffer;
575 info.cch = 256;
576 pSrc->GetMenuItemInfo(i, &info, TRUE);
577 pDst->AppendMenu(MF_ENABLED | ((info.fType == MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING),
578 info.wID, info.dwTypeData);
579 }
580 }
581
582
583 //
584 // Create object tools pop-up menu
585 //
586
587 CMenu *CreateToolsSubmenu(TCHAR *pszCurrPath, DWORD *pdwStart)
588 {
589 CMenu *pMenu;
590 TCHAR szName[MAX_DB_STRING], szPath[MAX_DB_STRING];
591 UINT nId;
592 DWORD i;
593 int j;
594
595 pMenu = new CMenu;
596 pMenu->CreatePopupMenu();
597 for(i = *pdwStart, nId = OBJTOOL_MENU_FIRST_ID + *pdwStart; i < g_dwNumObjectTools; i++, nId++)
598 {
599 // Separate item name and path
600 memset(szPath, 0, sizeof(TCHAR) * MAX_DB_STRING);
601 if (_tcsstr(g_pObjectToolList[i].szName, _T("->")) != NULL)
602 {
603 for(j = _tcslen(g_pObjectToolList[i].szName) - 1; j > 0; j--)
604 if ((g_pObjectToolList[i].szName[j] == _T('>')) &&
605 (g_pObjectToolList[i].szName[j - 1] == _T('-')))
606 {
607 _tcscpy(szName, &g_pObjectToolList[i].szName[j + 1]);
608 j--;
609 break;
610 }
611 memcpy(szPath, g_pObjectToolList[i].szName, j * sizeof(TCHAR));
612 }
613 else
614 {
615 _tcscpy(szName, g_pObjectToolList[i].szName);
616 }
617
618 if (!_tcsicmp(szPath, pszCurrPath))
619 {
620 StrStrip(szName);
621 pMenu->AppendMenu(MF_ENABLED | MF_STRING, nId, szName);
622 }
623 else
624 {
625 for(j = _tcslen(pszCurrPath); (szPath[j] == _T(' ')) || (szPath[j] == _T('\t')); j++);
626 if ((*pszCurrPath == 0) ||
627 ((!memicmp(szPath, pszCurrPath, _tcslen(pszCurrPath) * sizeof(TCHAR))) &&
628 (szPath[j] == _T('-')) && (szPath[j + 1] == _T('>'))))
629 {
630 CMenu *pSubMenu;
631 TCHAR *pszName;
632
633 // Submenu of current menu
634 if (*pszCurrPath != 0)
635 j += 2;
636 pszName = &szPath[j];
637 for(; (szPath[j] != 0) && (memcmp(&szPath[j], _T("->"), sizeof(TCHAR) * 2)); j++);
638 szPath[j] = 0;
639 pSubMenu = CreateToolsSubmenu(szPath, &i);
640 nId = OBJTOOL_MENU_FIRST_ID + i;
641 StrStrip(pszName);
642 pMenu->AppendMenu(MF_ENABLED | MF_STRING | MF_POPUP,
643 (UINT)pSubMenu->Detach(), pszName);
644 delete pSubMenu;
645 }
646 else
647 {
648 i--;
649 break;
650 }
651 }
652 }
653 *pdwStart = i;
654 return pMenu;
655 }
656
657
658 //
659 // Copy list of dynamic strings
660 //
661
662 TCHAR **CopyStringList(TCHAR **ppList, DWORD dwSize)
663 {
664 DWORD i;
665 TCHAR **ppDst;
666
667 ppDst = (TCHAR **)malloc(sizeof(TCHAR *) * dwSize);
668 for(i = 0; i < dwSize; i++)
669 ppDst[i] = _tcsdup(ppList[i]);
670 return ppDst;
671 }
672
673
674 //
675 // Destroy list of dynamic strings
676 //
677
678 void DestroyStringList(TCHAR **ppList, DWORD dwSize)
679 {
680 DWORD i;
681
682 for(i = 0; i < dwSize; i++)
683 free(ppList[i]);
684 safe_free(ppList);
685 }