- Fixed bugs number 195 and 203
[public/netxms.git] / src / console / win32 / TrapEditor.cpp
1 // TrapEditor.cpp : implementation file
2 //
3
4 #include "stdafx.h"
5 #include "nxcon.h"
6 #include "TrapEditor.h"
7 #include "TrapEditDlg.h"
8 #include <nxsnmp.h>
9
10 #ifdef _DEBUG
11 #define new DEBUG_NEW
12 #undef THIS_FILE
13 static char THIS_FILE[] = __FILE__;
14 #endif
15
16 /////////////////////////////////////////////////////////////////////////////
17 // CTrapEditor
18
19 IMPLEMENT_DYNCREATE(CTrapEditor, CMDIChildWnd)
20
21 CTrapEditor::CTrapEditor()
22 {
23 m_pTrapList = NULL;
24 m_dwNumTraps = 0;
25 m_pImageList = NULL;
26
27 m_iSortMode = theApp.GetProfileInt(_T("TrapEditor"), _T("SortMode"), 0);
28 m_iSortDir = theApp.GetProfileInt(_T("TrapEditor"), _T("SortDir"), 1);
29 }
30
31 CTrapEditor::~CTrapEditor()
32 {
33 theApp.WriteProfileInt(_T("TrapEditor"), _T("SortMode"), m_iSortMode);
34 theApp.WriteProfileInt(_T("TrapEditor"), _T("SortDir"), m_iSortDir);
35
36 if (m_pTrapList != NULL)
37 NXCDestroyTrapList(m_dwNumTraps, m_pTrapList);
38 delete m_pImageList;
39 }
40
41
42 BEGIN_MESSAGE_MAP(CTrapEditor, CMDIChildWnd)
43 //{{AFX_MSG_MAP(CTrapEditor)
44 ON_WM_CREATE()
45 ON_WM_DESTROY()
46 ON_WM_SETFOCUS()
47 ON_WM_SIZE()
48 ON_WM_CLOSE()
49 ON_COMMAND(ID_VIEW_REFRESH, OnViewRefresh)
50 ON_WM_CONTEXTMENU()
51 ON_UPDATE_COMMAND_UI(ID_TRAP_DELETE, OnUpdateTrapDelete)
52 ON_UPDATE_COMMAND_UI(ID_TRAP_EDIT, OnUpdateTrapEdit)
53 ON_COMMAND(ID_TRAP_NEW, OnTrapNew)
54 ON_COMMAND(ID_TRAP_DELETE, OnTrapDelete)
55 ON_COMMAND(ID_TRAP_EDIT, OnTrapEdit)
56 //}}AFX_MSG_MAP
57 ON_NOTIFY(NM_DBLCLK, IDC_LIST_VIEW, OnListViewDblClk)
58 ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_VIEW, OnListViewColumnClick)
59 END_MESSAGE_MAP()
60
61 /////////////////////////////////////////////////////////////////////////////
62 // CTrapEditor message handlers
63
64 BOOL CTrapEditor::PreCreateWindow(CREATESTRUCT& cs)
65 {
66 if (cs.lpszClass == NULL)
67 cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
68 NULL,
69 GetSysColorBrush(COLOR_WINDOW),
70 AfxGetApp()->LoadIcon(IDI_TRAP));
71 return CMDIChildWnd::PreCreateWindow(cs);
72 }
73
74
75 //
76 // WM_CREATE message handler
77 //
78
79 int CTrapEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
80 {
81 RECT rect;
82
83 if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
84 return -1;
85
86 theApp.OnViewCreate(VIEW_TRAP_EDITOR, this);
87
88 // Create image list
89 m_pImageList = CreateEventImageList();
90 m_iSortImageBase = m_pImageList->GetImageCount();
91 m_pImageList->Add(theApp.LoadIcon(IDI_SORT_UP));
92 m_pImageList->Add(theApp.LoadIcon(IDI_SORT_DOWN));
93
94 // Create list view control
95 GetClientRect(&rect);
96 m_wndListCtrl.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS,
97 rect, this, IDC_LIST_VIEW);
98 m_wndListCtrl.SetExtendedStyle(LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT |
99 LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
100 m_wndListCtrl.SetHoverTime(0x7FFFFFFF);
101 m_wndListCtrl.SetImageList(m_pImageList, LVSIL_SMALL);
102
103 // Setup columns
104 m_wndListCtrl.InsertColumn(0, _T("ID"), LVCFMT_LEFT, 60);
105 m_wndListCtrl.InsertColumn(1, _T("SNMP Trap ID"), LVCFMT_LEFT, 200);
106 m_wndListCtrl.InsertColumn(2, _T("Event"), LVCFMT_LEFT, 200);
107 m_wndListCtrl.InsertColumn(3, _T("Description"), LVCFMT_LEFT, 250);
108
109 LoadListCtrlColumns(m_wndListCtrl, _T("TrapEditor"), _T("ListCtrl"));
110
111 PostMessage(WM_COMMAND, ID_VIEW_REFRESH, 0);
112
113 return 0;
114 }
115
116
117 //
118 // WM_DESTROY message handler
119 //
120
121 void CTrapEditor::OnDestroy()
122 {
123 SaveListCtrlColumns(m_wndListCtrl, _T("TrapEditor"), _T("ListCtrl"));
124 theApp.OnViewDestroy(VIEW_TRAP_EDITOR, this);
125 CMDIChildWnd::OnDestroy();
126 }
127
128
129 //
130 // WM_SETFOCUS message handler
131 //
132
133 void CTrapEditor::OnSetFocus(CWnd* pOldWnd)
134 {
135 CMDIChildWnd::OnSetFocus(pOldWnd);
136
137 m_wndListCtrl.SetFocus();
138 }
139
140
141 //
142 // WM_SIZE message handler
143 //
144
145 void CTrapEditor::OnSize(UINT nType, int cx, int cy)
146 {
147 CMDIChildWnd::OnSize(nType, cx, cy);
148
149 m_wndListCtrl.SetWindowPos(NULL, 0, 0, cx, cy, SWP_NOZORDER);
150 }
151
152
153 //
154 // WM_CLOSE message handler
155 //
156
157 void CTrapEditor::OnClose()
158 {
159 DoRequestArg1(NXCUnlockTrapCfg, g_hSession, _T("Unlocking SNMP trap configuration database..."));
160 CMDIChildWnd::OnClose();
161 }
162
163
164 //
165 // WM_COMMAND::ID_VIEW_REFRESH message handler
166 //
167
168 void CTrapEditor::OnViewRefresh()
169 {
170 DWORD i, dwResult;
171
172 if (m_pTrapList != NULL)
173 NXCDestroyTrapList(m_dwNumTraps, m_pTrapList);
174 m_wndListCtrl.DeleteAllItems();
175 dwResult = DoRequestArg3(NXCLoadTrapCfg, g_hSession, &m_dwNumTraps,
176 &m_pTrapList, _T("Loading SNMP trap configuration..."));
177 if (dwResult == RCC_SUCCESS)
178 {
179 for(i = 0; i < m_dwNumTraps; i++)
180 AddItem(i);
181 SortList();
182 }
183 else
184 {
185 theApp.ErrorBox(dwResult, _T("Error loading SNMP trap configuration: %s"));
186 }
187 }
188
189
190 //
191 // Add new item to list
192 //
193
194 int CTrapEditor::AddItem(DWORD dwIndex)
195 {
196 TCHAR szBuffer[32];
197 int iItem;
198
199 _stprintf(szBuffer, _T("%d"), m_pTrapList[dwIndex].dwId);
200 iItem = m_wndListCtrl.InsertItem(dwIndex, szBuffer);
201 if (iItem != -1)
202 {
203 m_wndListCtrl.SetItemData(iItem, m_pTrapList[dwIndex].dwId);
204 UpdateItem(iItem, dwIndex);
205 }
206 return iItem;
207 }
208
209
210 //
211 // Update item in list
212 //
213
214 void CTrapEditor::UpdateItem(int iItem, DWORD dwIndex)
215 {
216 TCHAR szBuffer[1024];
217
218 SNMPConvertOIDToText(m_pTrapList[dwIndex].dwOidLen, m_pTrapList[dwIndex].pdwObjectId,
219 szBuffer, 1024);
220 m_wndListCtrl.SetItemText(iItem, 1, szBuffer);
221 m_wndListCtrl.SetItemText(iItem, 2, NXCGetEventName(g_hSession, m_pTrapList[dwIndex].dwEventCode));
222 m_wndListCtrl.SetItemText(iItem, 3, m_pTrapList[dwIndex].szDescription);
223
224 m_wndListCtrl.SetItem(iItem, 0, LVIF_IMAGE, NULL,
225 NXCGetEventSeverity(g_hSession, m_pTrapList[dwIndex].dwEventCode),
226 0, 0, 0);
227 }
228
229
230 //
231 // WM_CONTEXTMENU message handler
232 //
233
234 void CTrapEditor::OnContextMenu(CWnd* pWnd, CPoint point)
235 {
236 CMenu *pMenu;
237
238 pMenu = theApp.GetContextMenu(11);
239 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL);
240 }
241
242
243 //
244 // Update status for menu items
245 //
246
247 void CTrapEditor::OnUpdateTrapDelete(CCmdUI* pCmdUI)
248 {
249 pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() > 0);
250 }
251
252 void CTrapEditor::OnUpdateTrapEdit(CCmdUI* pCmdUI)
253 {
254 pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() == 1);
255 }
256
257
258 //
259 // WM_COMMAND::ID_TRAP_NEW message handler
260 //
261
262 void CTrapEditor::OnTrapNew()
263 {
264 DWORD dwResult, dwTrapId;
265
266 dwResult = DoRequestArg2(NXCCreateTrap, g_hSession, &dwTrapId, _T("Creating trap configuration record..."));
267 if (dwResult == RCC_SUCCESS)
268 {
269 m_pTrapList = (NXC_TRAP_CFG_ENTRY *)realloc(m_pTrapList, sizeof(NXC_TRAP_CFG_ENTRY) * (m_dwNumTraps + 1));
270 memset(&m_pTrapList[m_dwNumTraps], 0, sizeof(NXC_TRAP_CFG_ENTRY));
271 m_pTrapList[m_dwNumTraps].dwId = dwTrapId;
272 m_pTrapList[m_dwNumTraps].dwEventCode = EVENT_SNMP_UNMATCHED_TRAP;
273 m_dwNumTraps++;
274 SelectListViewItem(&m_wndListCtrl, AddItem(m_dwNumTraps - 1));
275 EditTrap(TRUE);
276 }
277 else
278 {
279 theApp.ErrorBox(dwResult, _T("Error creating trap configuration:\n%s"));
280 }
281 }
282
283
284 //
285 // Worker function for trap deletion
286 //
287
288 static DWORD DeleteTraps(DWORD dwNumTraps, DWORD *pdwDeleteList, CListCtrl *pList)
289 {
290 DWORD i, dwResult = RCC_SUCCESS;
291 LVFINDINFO lvfi;
292 int iItem;
293
294 lvfi.flags = LVFI_PARAM;
295 for(i = 0; i < dwNumTraps; i++)
296 {
297 dwResult = NXCDeleteTrap(g_hSession, pdwDeleteList[i]);
298 if (dwResult == RCC_SUCCESS)
299 {
300 lvfi.lParam = pdwDeleteList[i];
301 iItem = pList->FindItem(&lvfi);
302 if (iItem != -1)
303 pList->DeleteItem(iItem);
304 }
305 else
306 {
307 break;
308 }
309 }
310 return dwResult;
311 }
312
313
314 //
315 // WM_COMMAND::ID_TRAP_DELETE message handler
316 //
317
318 void CTrapEditor::OnTrapDelete()
319 {
320 int iItem;
321 DWORD i, dwNumItems, *pdwDeleteList, dwResult;
322
323 dwNumItems = m_wndListCtrl.GetSelectedCount();
324 if (dwNumItems > 0)
325 {
326 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * dwNumItems);
327 iItem = m_wndListCtrl.GetNextItem(-1, LVIS_SELECTED);
328 for(i = 0; (i < dwNumItems) && (iItem != -1); i++)
329 {
330 pdwDeleteList[i] = m_wndListCtrl.GetItemData(iItem);
331 iItem = m_wndListCtrl.GetNextItem(iItem, LVIS_SELECTED);
332 }
333
334 dwResult = DoRequestArg3(DeleteTraps, (void *)dwNumItems, pdwDeleteList,
335 &m_wndListCtrl, _T("Deleting trap configuration record(s)..."));
336 if (dwResult != RCC_SUCCESS)
337 theApp.ErrorBox(dwResult, _T("Error deleting trap configuration record:\n%s"));
338 free(pdwDeleteList);
339 }
340 }
341
342
343 //
344 // Edit currently selected trap record
345 //
346
347 void CTrapEditor::EditTrap(BOOL bNewTrap)
348 {
349 CTrapEditDlg dlg;
350 int iItem;
351 DWORD i, dwIndex, dwTrapId, dwResult;
352
353 if (m_wndListCtrl.GetSelectedCount() == 1)
354 {
355 iItem = m_wndListCtrl.GetNextItem(-1, LVIS_SELECTED);
356 if (iItem != -1)
357 {
358 dwTrapId = m_wndListCtrl.GetItemData(iItem);
359 for(dwIndex = 0; dwIndex < m_dwNumTraps; dwIndex++)
360 if (m_pTrapList[dwIndex].dwId == dwTrapId)
361 break;
362 if (dwIndex < m_dwNumTraps)
363 {
364 // Copy existing record to dialog object for editing
365 memcpy(&dlg.m_trap, &m_pTrapList[dwIndex], sizeof(NXC_TRAP_CFG_ENTRY));
366 dlg.m_trap.pdwObjectId =
367 (DWORD *)nx_memdup(m_pTrapList[dwIndex].pdwObjectId,
368 sizeof(DWORD) * m_pTrapList[dwIndex].dwOidLen);
369 dlg.m_trap.pMaps =
370 (NXC_OID_MAP *)nx_memdup(m_pTrapList[dwIndex].pMaps,
371 sizeof(NXC_OID_MAP) * m_pTrapList[dwIndex].dwNumMaps);
372 for(i = 0; i < m_pTrapList[dwIndex].dwNumMaps; i++)
373 {
374 if ((m_pTrapList[dwIndex].pMaps[i].dwOidLen & 0x80000000) == 0)
375 dlg.m_trap.pMaps[i].pdwObjectId =
376 (DWORD *)nx_memdup(m_pTrapList[dwIndex].pMaps[i].pdwObjectId,
377 sizeof(DWORD) * m_pTrapList[dwIndex].pMaps[i].dwOidLen);
378 else
379 dlg.m_trap.pMaps[i].pdwObjectId = NULL;
380 }
381
382 // Run dialog and update record list on success
383 if (dlg.DoModal() == IDOK)
384 {
385 // Update record on server
386 dwResult = DoRequestArg2(NXCModifyTrap, g_hSession,
387 &dlg.m_trap, _T("Updating trap configuration..."));
388 if (dwResult == RCC_SUCCESS)
389 {
390 // Clean existing configuration record
391 for(i = 0; i < m_pTrapList[dwIndex].dwNumMaps; i++)
392 safe_free(m_pTrapList[dwIndex].pMaps[i].pdwObjectId);
393 safe_free(m_pTrapList[dwIndex].pMaps);
394 safe_free(m_pTrapList[dwIndex].pdwObjectId);
395
396 // Copy updated record over existing
397 memcpy(&m_pTrapList[dwIndex], &dlg.m_trap, sizeof(NXC_TRAP_CFG_ENTRY));
398
399 // Prevent memory blocks from freeing by dialog destructor
400 dlg.m_trap.pdwObjectId = NULL;
401 dlg.m_trap.dwNumMaps = 0;
402 dlg.m_trap.pMaps = NULL;
403
404 UpdateItem(iItem, dwIndex);
405 SortList();
406 }
407 else
408 {
409 theApp.ErrorBox(dwResult, _T("Error updating trap configuration:\n%s"));
410 }
411 }
412 else /* user press cancel */
413 {
414 if (bNewTrap)
415 PostMessage(WM_COMMAND, ID_TRAP_DELETE, 0);
416 }
417 }
418 }
419 }
420 }
421
422
423 //
424 // WM_COMMAND::ID_TRAP_EDIT message handler
425 //
426
427 void CTrapEditor::OnTrapEdit()
428 {
429 EditTrap(FALSE);
430 }
431
432
433 //
434 // Handler for WM_NOTIFY::NM_DBLCLK from IDC_LIST_VIEW
435 //
436
437 void CTrapEditor::OnListViewDblClk(LPNMITEMACTIVATE pNMHDR, LRESULT *pResult)
438 {
439 PostMessage(WM_COMMAND, ID_TRAP_EDIT, 0);
440 }
441
442
443 //
444 // Compare two OIDs
445 //
446
447 static int CompareOID(DWORD *pdwOid1, DWORD *pdwOid2, DWORD dwLen)
448 {
449 DWORD i;
450
451 for(i = 0; i < dwLen; i++)
452 {
453 if (pdwOid1[i] < pdwOid2[i])
454 return -1;
455 if (pdwOid1[i] > pdwOid2[i])
456 return 1;
457 }
458 return 0;
459 }
460
461
462 //
463 // Trap comparision procedure for sorting
464 //
465
466 static int CALLBACK TrapCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
467 {
468 CTrapEditor *pWnd = (CTrapEditor *)lParamSort;
469 NXC_TRAP_CFG_ENTRY *pTrap1, *pTrap2;
470 TCHAR szEvent1[MAX_EVENT_NAME], szEvent2[MAX_EVENT_NAME];
471 int iResult;
472
473 pTrap1 = pWnd->GetTrapById(lParam1);
474 pTrap2 = pWnd->GetTrapById(lParam2);
475
476 switch(pWnd->GetSortMode())
477 {
478 case 0: // ID
479 iResult = COMPARE_NUMBERS(pTrap1->dwId, pTrap2->dwId);
480 break;
481 case 1: // Object ID
482 iResult = CompareOID(pTrap1->pdwObjectId, pTrap2->pdwObjectId,
483 min(pTrap1->dwOidLen, pTrap2->dwOidLen));
484 if (iResult == 0)
485 iResult = COMPARE_NUMBERS(pTrap1->dwOidLen, pTrap2->dwOidLen);
486 break;
487 case 2: // Event
488 NXCGetEventNameEx(g_hSession, pTrap1->dwEventCode, szEvent1, MAX_EVENT_NAME);
489 NXCGetEventNameEx(g_hSession, pTrap2->dwEventCode, szEvent2, MAX_EVENT_NAME);
490 iResult = _tcsicmp(szEvent1, szEvent2);
491 break;
492 case 3: // Description
493 iResult = _tcsicmp(pTrap1->szDescription, pTrap2->szDescription);
494 break;
495 default:
496 iResult = 0;
497 break;
498 }
499
500 return iResult * pWnd->GetSortDir();
501 }
502
503
504 //
505 // Sort trap list
506 //
507
508 void CTrapEditor::SortList()
509 {
510 LVCOLUMN lvc;
511
512 m_wndListCtrl.SortItems(TrapCompareProc, (LPARAM)this);
513 lvc.mask = LVCF_IMAGE | LVCF_FMT;
514 lvc.fmt = LVCFMT_LEFT | LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
515 lvc.iImage = (m_iSortDir == 1) ? m_iSortImageBase : m_iSortImageBase + 1;
516 m_wndListCtrl.SetColumn(m_iSortMode, &lvc);
517 }
518
519
520 //
521 // Get trap structure by id
522 //
523
524 NXC_TRAP_CFG_ENTRY *CTrapEditor::GetTrapById(DWORD dwId)
525 {
526 DWORD i;
527
528 for(i = 0; i < m_dwNumTraps; i++)
529 if (m_pTrapList[i].dwId == dwId)
530 return &m_pTrapList[i];
531 return NULL;
532 }
533
534
535 //
536 // WM_NOTIFY::LVN_COLUMNCLICK message handler
537 //
538
539 void CTrapEditor::OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult)
540 {
541 LVCOLUMN lvCol;
542
543 // Unmark old sorting column
544 lvCol.mask = LVCF_FMT;
545 lvCol.fmt = LVCFMT_LEFT;
546 m_wndListCtrl.SetColumn(m_iSortMode, &lvCol);
547
548 // Change current sort mode and resort list
549 if (m_iSortMode == pNMHDR->iSubItem)
550 {
551 // Same column, change sort direction
552 m_iSortDir = -m_iSortDir;
553 }
554 else
555 {
556 // Another sorting column
557 m_iSortMode = pNMHDR->iSubItem;
558 }
559 SortList();
560
561 *pResult = 0;
562 }