cd63928e4b3dad7e6bf16939675a2be4ba1d0c52
[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(IDR_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, "ID", LVCFMT_LEFT, 60);
105 m_wndListCtrl.InsertColumn(1, "SNMP Trap ID", LVCFMT_LEFT, 200);
106 m_wndListCtrl.InsertColumn(2, "Event", LVCFMT_LEFT, 200);
107 m_wndListCtrl.InsertColumn(3, "Description", LVCFMT_LEFT, 250);
108
109 PostMessage(WM_COMMAND, ID_VIEW_REFRESH, 0);
110
111 return 0;
112 }
113
114
115 //
116 // WM_DESTROY message handler
117 //
118
119 void CTrapEditor::OnDestroy()
120 {
121 theApp.OnViewDestroy(IDR_TRAP_EDITOR, this);
122 CMDIChildWnd::OnDestroy();
123 }
124
125
126 //
127 // WM_SETFOCUS message handler
128 //
129
130 void CTrapEditor::OnSetFocus(CWnd* pOldWnd)
131 {
132 CMDIChildWnd::OnSetFocus(pOldWnd);
133
134 m_wndListCtrl.SetFocus();
135 }
136
137
138 //
139 // WM_SIZE message handler
140 //
141
142 void CTrapEditor::OnSize(UINT nType, int cx, int cy)
143 {
144 CMDIChildWnd::OnSize(nType, cx, cy);
145
146 m_wndListCtrl.SetWindowPos(NULL, 0, 0, cx, cy, SWP_NOZORDER);
147 }
148
149
150 //
151 // WM_CLOSE message handler
152 //
153
154 void CTrapEditor::OnClose()
155 {
156 DoRequest(NXCUnlockTrapCfg, "Unlocking SNMP trap configuration database...");
157 CMDIChildWnd::OnClose();
158 }
159
160
161 //
162 // WM_COMMAND::ID_VIEW_REFRESH message handler
163 //
164
165 void CTrapEditor::OnViewRefresh()
166 {
167 DWORD i, dwResult;
168
169 if (m_pTrapList != NULL)
170 NXCDestroyTrapList(m_dwNumTraps, m_pTrapList);
171 m_wndListCtrl.DeleteAllItems();
172 dwResult = DoRequestArg2(NXCLoadTrapCfg, &m_dwNumTraps, &m_pTrapList, _T("Loading SNMP trap configuration..."));
173 if (dwResult == RCC_SUCCESS)
174 {
175 for(i = 0; i < m_dwNumTraps; i++)
176 AddItem(i);
177 SortList();
178 }
179 else
180 {
181 theApp.ErrorBox(dwResult, _T("Error loading SNMP trap configuration: %s"));
182 }
183 }
184
185
186 //
187 // Add new item to list
188 //
189
190 int CTrapEditor::AddItem(DWORD dwIndex)
191 {
192 TCHAR szBuffer[32];
193 int iItem;
194
195 _stprintf(szBuffer, _T("%d"), m_pTrapList[dwIndex].dwId);
196 iItem = m_wndListCtrl.InsertItem(dwIndex, szBuffer);
197 if (iItem != -1)
198 {
199 m_wndListCtrl.SetItemData(iItem, m_pTrapList[dwIndex].dwId);
200 UpdateItem(iItem, dwIndex);
201 }
202 return iItem;
203 }
204
205
206 //
207 // Update item in list
208 //
209
210 void CTrapEditor::UpdateItem(int iItem, DWORD dwIndex)
211 {
212 TCHAR szBuffer[1024];
213
214 SNMPConvertOIDToText(m_pTrapList[dwIndex].dwOidLen, m_pTrapList[dwIndex].pdwObjectId,
215 szBuffer, 1024);
216 m_wndListCtrl.SetItemText(iItem, 1, szBuffer);
217 m_wndListCtrl.SetItemText(iItem, 2, NXCGetEventName(m_pTrapList[dwIndex].dwEventCode));
218 m_wndListCtrl.SetItemText(iItem, 3, m_pTrapList[dwIndex].szDescription);
219
220 m_wndListCtrl.SetItem(iItem, 0, LVIF_IMAGE, NULL,
221 NXCGetEventSeverity(m_pTrapList[dwIndex].dwEventCode),
222 0, 0, 0);
223 }
224
225
226 //
227 // WM_CONTEXTMENU message handler
228 //
229
230 void CTrapEditor::OnContextMenu(CWnd* pWnd, CPoint point)
231 {
232 CMenu *pMenu;
233
234 pMenu = theApp.GetContextMenu(11);
235 pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL);
236 }
237
238
239 //
240 // Update status for menu items
241 //
242
243 void CTrapEditor::OnUpdateTrapDelete(CCmdUI* pCmdUI)
244 {
245 pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() > 0);
246 }
247
248 void CTrapEditor::OnUpdateTrapEdit(CCmdUI* pCmdUI)
249 {
250 pCmdUI->Enable(m_wndListCtrl.GetSelectedCount() == 1);
251 }
252
253
254 //
255 // WM_COMMAND::ID_TRAP_NEW message handler
256 //
257
258 void CTrapEditor::OnTrapNew()
259 {
260 DWORD dwResult, dwTrapId;
261
262 dwResult = DoRequestArg1(NXCCreateTrap, &dwTrapId, _T("Creating trap configuration record..."));
263 if (dwResult == RCC_SUCCESS)
264 {
265 m_pTrapList = (NXC_TRAP_CFG_ENTRY *)realloc(m_pTrapList, sizeof(NXC_TRAP_CFG_ENTRY) * (m_dwNumTraps + 1));
266 memset(&m_pTrapList[m_dwNumTraps], 0, sizeof(NXC_TRAP_CFG_ENTRY));
267 m_pTrapList[m_dwNumTraps].dwId = dwTrapId;
268 m_pTrapList[m_dwNumTraps].dwEventCode = EVENT_SNMP_UNMATCHED_TRAP;
269 m_dwNumTraps++;
270 SelectListViewItem(&m_wndListCtrl, AddItem(m_dwNumTraps - 1));
271 PostMessage(WM_COMMAND, ID_TRAP_EDIT);
272 }
273 else
274 {
275 theApp.ErrorBox(dwResult, _T("Error creating trap configuration:\n%s"));
276 }
277 }
278
279
280 //
281 // Worker function for trap deletion
282 //
283
284 static DWORD DeleteTraps(DWORD dwNumTraps, DWORD *pdwDeleteList, CListCtrl *pList)
285 {
286 DWORD i, dwResult = RCC_SUCCESS;
287 LVFINDINFO lvfi;
288 int iItem;
289
290 lvfi.flags = LVFI_PARAM;
291 for(i = 0; i < dwNumTraps; i++)
292 {
293 dwResult = NXCDeleteTrap(pdwDeleteList[i]);
294 if (dwResult == RCC_SUCCESS)
295 {
296 lvfi.lParam = pdwDeleteList[i];
297 iItem = pList->FindItem(&lvfi);
298 if (iItem != -1)
299 pList->DeleteItem(iItem);
300 }
301 else
302 {
303 break;
304 }
305 }
306 return dwResult;
307 }
308
309
310 //
311 // WM_COMMAND::ID_TRAP_DELETE message handler
312 //
313
314 void CTrapEditor::OnTrapDelete()
315 {
316 int iItem;
317 DWORD i, dwNumItems, *pdwDeleteList, dwResult;
318
319 dwNumItems = m_wndListCtrl.GetSelectedCount();
320 if (dwNumItems > 0)
321 {
322 pdwDeleteList = (DWORD *)malloc(sizeof(DWORD) * dwNumItems);
323 iItem = m_wndListCtrl.GetNextItem(-1, LVIS_SELECTED);
324 for(i = 0; (i < dwNumItems) && (iItem != -1); i++)
325 {
326 pdwDeleteList[i] = m_wndListCtrl.GetItemData(iItem);
327 iItem = m_wndListCtrl.GetNextItem(iItem, LVIS_SELECTED);
328 }
329
330 dwResult = DoRequestArg3(DeleteTraps, (void *)dwNumItems, pdwDeleteList,
331 &m_wndListCtrl, _T("Deleting trap configuration record(s)..."));
332 if (dwResult != RCC_SUCCESS)
333 theApp.ErrorBox(dwResult, _T("Error deleting trap configuration record:\n%s"));
334 free(pdwDeleteList);
335 }
336 }
337
338
339 //
340 // WM_COMMAND::ID_TRAP_EDIT message handler
341 //
342
343 void CTrapEditor::OnTrapEdit()
344 {
345 CTrapEditDlg dlg;
346 int iItem;
347 DWORD i, dwIndex, dwTrapId, dwResult;
348
349 if (m_wndListCtrl.GetSelectedCount() == 1)
350 {
351 iItem = m_wndListCtrl.GetNextItem(-1, LVIS_SELECTED);
352 if (iItem != -1)
353 {
354 dwTrapId = m_wndListCtrl.GetItemData(iItem);
355 for(dwIndex = 0; dwIndex < m_dwNumTraps; dwIndex++)
356 if (m_pTrapList[dwIndex].dwId == dwTrapId)
357 break;
358 if (dwIndex < m_dwNumTraps)
359 {
360 // Copy existing record to dialog object for editing
361 memcpy(&dlg.m_trap, &m_pTrapList[dwIndex], sizeof(NXC_TRAP_CFG_ENTRY));
362 dlg.m_trap.pdwObjectId =
363 (DWORD *)nx_memdup(m_pTrapList[dwIndex].pdwObjectId,
364 sizeof(DWORD) * m_pTrapList[dwIndex].dwOidLen);
365 dlg.m_trap.pMaps =
366 (NXC_OID_MAP *)nx_memdup(m_pTrapList[dwIndex].pMaps,
367 sizeof(NXC_OID_MAP) * m_pTrapList[dwIndex].dwNumMaps);
368 for(i = 0; i < m_pTrapList[dwIndex].dwNumMaps; i++)
369 {
370 dlg.m_trap.pMaps[i].pdwObjectId =
371 (DWORD *)nx_memdup(m_pTrapList[dwIndex].pMaps[i].pdwObjectId,
372 sizeof(DWORD) * m_pTrapList[dwIndex].pMaps[i].dwOidLen);
373 }
374
375 // Run dialog and update record list on success
376 if (dlg.DoModal() == IDOK)
377 {
378 // Update record on server
379 dwResult = DoRequestArg1(NXCModifyTrap, &dlg.m_trap, _T("Updating trap configuration..."));
380 if (dwResult == RCC_SUCCESS)
381 {
382 // Clean existing configuration record
383 for(i = 0; i < m_pTrapList[dwIndex].dwNumMaps; i++)
384 safe_free(m_pTrapList[dwIndex].pMaps[i].pdwObjectId);
385 safe_free(m_pTrapList[dwIndex].pMaps);
386 safe_free(m_pTrapList[dwIndex].pdwObjectId);
387
388 // Copy updated record over existing
389 memcpy(&m_pTrapList[dwIndex], &dlg.m_trap, sizeof(NXC_TRAP_CFG_ENTRY));
390
391 // Prevent memory blocks from freeing by dialog destructor
392 dlg.m_trap.pdwObjectId = NULL;
393 dlg.m_trap.dwNumMaps = 0;
394 dlg.m_trap.pMaps = NULL;
395
396 UpdateItem(iItem, dwIndex);
397 SortList();
398 }
399 else
400 {
401 theApp.ErrorBox(dwResult, _T("Error updating trap configuration:\n%s"));
402 }
403 }
404 }
405 }
406 }
407 }
408
409
410 //
411 // Handler for WM_NOTIFY::NM_DBLCLK from IDC_LIST_VIEW
412 //
413
414 void CTrapEditor::OnListViewDblClk(LPNMITEMACTIVATE pNMHDR, LRESULT *pResult)
415 {
416 PostMessage(WM_COMMAND, ID_TRAP_EDIT, 0);
417 }
418
419
420 //
421 // Compare two OIDs
422 //
423
424 static int CompareOID(DWORD *pdwOid1, DWORD *pdwOid2, DWORD dwLen)
425 {
426 DWORD i;
427
428 for(i = 0; i < dwLen; i++)
429 {
430 if (pdwOid1[i] < pdwOid2[i])
431 return -1;
432 if (pdwOid1[i] > pdwOid2[i])
433 return 1;
434 }
435 return 0;
436 }
437
438
439 //
440 // Trap comparision procedure for sorting
441 //
442
443 static int CALLBACK TrapCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
444 {
445 CTrapEditor *pWnd = (CTrapEditor *)lParamSort;
446 NXC_TRAP_CFG_ENTRY *pTrap1, *pTrap2;
447 TCHAR szEvent1[MAX_EVENT_NAME], szEvent2[MAX_EVENT_NAME];
448 int iResult;
449
450 pTrap1 = pWnd->GetTrapById(lParam1);
451 pTrap2 = pWnd->GetTrapById(lParam2);
452
453 switch(pWnd->GetSortMode())
454 {
455 case 0: // ID
456 iResult = COMPARE_NUMBERS(pTrap1->dwId, pTrap2->dwId);
457 break;
458 case 1: // Object ID
459 iResult = CompareOID(pTrap1->pdwObjectId, pTrap2->pdwObjectId,
460 min(pTrap1->dwOidLen, pTrap2->dwOidLen));
461 if (iResult == 0)
462 iResult = COMPARE_NUMBERS(pTrap1->dwOidLen, pTrap2->dwOidLen);
463 break;
464 case 2: // Event
465 NXCGetEventNameEx(pTrap1->dwEventCode, szEvent1, MAX_EVENT_NAME);
466 NXCGetEventNameEx(pTrap2->dwEventCode, szEvent2, MAX_EVENT_NAME);
467 iResult = _tcsicmp(szEvent1, szEvent2);
468 break;
469 case 3: // Description
470 iResult = _tcsicmp(pTrap1->szDescription, pTrap2->szDescription);
471 break;
472 default:
473 iResult = 0;
474 break;
475 }
476
477 return iResult * pWnd->GetSortDir();
478 }
479
480
481 //
482 // Sort trap list
483 //
484
485 void CTrapEditor::SortList()
486 {
487 LVCOLUMN lvc;
488
489 m_wndListCtrl.SortItems(TrapCompareProc, (LPARAM)this);
490 lvc.mask = LVCF_IMAGE | LVCF_FMT;
491 lvc.fmt = LVCFMT_LEFT | LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
492 lvc.iImage = (m_iSortDir == 1) ? m_iSortImageBase : m_iSortImageBase + 1;
493 m_wndListCtrl.SetColumn(m_iSortMode, &lvc);
494 }
495
496
497 //
498 // Get trap structure by id
499 //
500
501 NXC_TRAP_CFG_ENTRY *CTrapEditor::GetTrapById(DWORD dwId)
502 {
503 DWORD i;
504
505 for(i = 0; i < m_dwNumTraps; i++)
506 if (m_pTrapList[i].dwId == dwId)
507 return &m_pTrapList[i];
508 return NULL;
509 }
510
511
512 //
513 // WM_NOTIFY::LVN_COLUMNCLICK message handler
514 //
515
516 void CTrapEditor::OnListViewColumnClick(LPNMLISTVIEW pNMHDR, LRESULT *pResult)
517 {
518 LVCOLUMN lvCol;
519
520 // Unmark old sorting column
521 lvCol.mask = LVCF_FMT;
522 lvCol.fmt = LVCFMT_LEFT;
523 m_wndListCtrl.SetColumn(m_iSortMode, &lvCol);
524
525 // Change current sort mode and resort list
526 if (m_iSortMode == pNMHDR->iSubItem)
527 {
528 // Same column, change sort direction
529 m_iSortDir = -m_iSortDir;
530 }
531 else
532 {
533 // Another sorting column
534 m_iSortMode = pNMHDR->iSubItem;
535 }
536 SortList();
537
538 *pResult = 0;
539 }