Only object tools appropriate for current object are now displayed in the menu
authorVictor Kirhenshtein <victor@netxms.org>
Tue, 22 Nov 2005 23:00:29 +0000 (23:00 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 22 Nov 2005 23:00:29 +0000 (23:00 +0000)
14 files changed:
doc/db_format_change.txt
include/nms_cscp.h
include/nxclapi.h
include/nxtools.h
src/console/win32/MainFrm.cpp
src/console/win32/MainFrm.h
src/console/win32/ObjectBrowser.cpp
src/console/win32/comm.cpp
src/console/win32/globals.h
src/console/win32/nxcon.cpp
src/console/win32/tools.cpp
src/libnxcl/objtools.cpp
src/server/core/objtools.cpp
src/server/core/session.cpp

index 2edc186..f940276 100644 (file)
@@ -4,6 +4,8 @@
 
 - Added new column proxy_node to "nodes" table:
        ALTER TABLE nodes ADD proxy_node integer not null
+- Added new column matching_oid to "object_tools" table:
+       ALTER TABLE object_tools ADD matching_oid varchar(255) not null
 
 
 *************
index d7f939b..934b1f1 100644 (file)
@@ -585,6 +585,7 @@ typedef struct
 #define VID_TOOL_TYPE               ((DWORD)196)
 #define VID_TOOL_DATA               ((DWORD)197)
 #define VID_ACL                     ((DWORD)198)
+#define VID_TOOL_OID                ((DWORD)199)
 
 // Variable ranges for object's ACL
 #define VID_ACL_USER_BASE           ((DWORD)0x00001000)
index b1f2657..5f3c6e2 100644 (file)
@@ -1103,6 +1103,7 @@ typedef struct
    WORD wType;
    TCHAR szName[MAX_DB_STRING];
    TCHAR szDescription[MAX_DB_STRING];
+   TCHAR *pszMatchingOID;
    TCHAR *pszData;
 } NXC_OBJECT_TOOL;
 
@@ -1145,6 +1146,7 @@ typedef struct
    DWORD dwFlags;
    TCHAR szName[MAX_DB_STRING];
    TCHAR szDescription[MAX_DB_STRING];
+   TCHAR *pszMatchingOID;
    TCHAR *pszData;
    DWORD *pdwACL;
    DWORD dwACLSize;
@@ -1403,6 +1405,7 @@ DWORD LIBNXCL_EXPORTABLE NXCDeleteObjectTool(NXC_SESSION hSession, DWORD dwToolI
 DWORD LIBNXCL_EXPORTABLE NXCGenerateObjectToolId(NXC_SESSION hSession, DWORD *pdwToolId);
 DWORD LIBNXCL_EXPORTABLE NXCUpdateObjectTool(NXC_SESSION hSession,
                                              NXC_OBJECT_TOOL_DETAILS *pData);
+BOOL LIBNXCL_EXPORTABLE NXCIsAppropriateTool(NXC_OBJECT_TOOL *pTool, NXC_OBJECT *pObject);
 
 DWORD LIBNXCL_EXPORTABLE NXCLoadLPPList(NXC_SESSION hSession, NXC_LPP_LIST **ppList);
 void LIBNXCL_EXPORTABLE NXCDestroyLPPList(NXC_LPP_LIST *pList);
index a00e178..3ed0b0a 100644 (file)
@@ -40,6 +40,9 @@
 // SNMP tool flags
 //
 
+#define TF_REQUIRES_SNMP            ((DWORD)0x00000001)
+#define TF_REQUIRES_AGENT           ((DWORD)0x00000002)
+#define TF_REQUIRES_OID_MATCH       ((DWORD)0x00000004)
 #define TF_SNMP_INDEXED_BY_VALUE    ((DWORD)0x00010000)
 
 
index 28f0f5a..c2071b3 100644 (file)
@@ -213,6 +213,16 @@ void CMainFrame::OnUpdateEventList(WPARAM wParam, LPARAM lParam)
 
 
 //
+// WM_UPDATE_OBJECT_TOOLS message handler
+//
+
+void CMainFrame::OnUpdateObjectTools(WPARAM wParam, LPARAM lParam)
+{
+   DoRequest(LoadObjectTools, _T("Reloading object tools information..."));
+}
+
+
+//
 // Handler for WM_STATE_CHANGE message
 //
 
index 28eaee6..fec5936 100644 (file)
@@ -63,6 +63,7 @@ protected:
    afx_msg void OnAlarmUpdate(WPARAM wParam, LPARAM lParam);
    afx_msg void OnDeploymentInfo(WPARAM wParam, LPARAM lParam);
    afx_msg void OnUpdateEventList(WPARAM wParam, LPARAM lParam);
+   afx_msg void OnUpdateObjectTools(WPARAM wParam, LPARAM lParam);
        DECLARE_MESSAGE_MAP()
 };
 
index d04ea11..f361db8 100644 (file)
@@ -1056,8 +1056,10 @@ void CObjectBrowser::ClearListSelection()
 
 void CObjectBrowser::OnContextMenu(CWnd* pWnd, CPoint point) 
 {
-   CMenu *pMenu;
+   CMenu *pMenu, *pToolsMenu;
    CPoint pt;
+   DWORD dwTemp;
+   BOOL bMenuInserted = FALSE;
 
    pt = point;
    pWnd->ScreenToClient(&pt);
@@ -1071,7 +1073,21 @@ void CObjectBrowser::OnContextMenu(CWnd* pWnd, CPoint point)
       if ((iItem != -1) && (uFlags & LVHT_ONITEM))
       {
          pMenu = theApp.GetContextMenu(1);
+         dwTemp = 0;
+         pToolsMenu = CreateToolsSubmenu(m_pCurrentObject, _T(""), &dwTemp);
+         if (pToolsMenu->GetMenuItemCount() > 0)
+         {
+            pMenu->InsertMenu(14, MF_BYPOSITION | MF_STRING | MF_POPUP,
+                              (UINT)pToolsMenu->GetSafeHmenu(), _T("&Tools"));
+            pToolsMenu->Detach();
+            bMenuInserted = TRUE;
+         }
+         delete pToolsMenu;
          pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL);
+         if (bMenuInserted)
+         {
+            pMenu->DeleteMenu(14, MF_BYPOSITION);
+         }
       }
    }
    else if (pWnd->GetDlgCtrlID() == IDC_TREE_VIEW)
@@ -1085,7 +1101,21 @@ void CObjectBrowser::OnContextMenu(CWnd* pWnd, CPoint point)
          m_wndTreeCtrl.Select(hItem, TVGN_CARET);
 
          pMenu = theApp.GetContextMenu(1);
+         dwTemp = 0;
+         pToolsMenu = CreateToolsSubmenu(m_pCurrentObject, _T(""), &dwTemp);
+         if (pToolsMenu->GetMenuItemCount() > 0)
+         {
+            pMenu->InsertMenu(14, MF_BYPOSITION | MF_STRING | MF_POPUP,
+                              (UINT)pToolsMenu->GetSafeHmenu(), _T("&Tools"));
+            pToolsMenu->Detach();
+            bMenuInserted = TRUE;
+         }
+         delete pToolsMenu;
          pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL);
+         if (bMenuInserted)
+         {
+            pMenu->DeleteMenu(14, MF_BYPOSITION);
+         }
       }
    }
 }
index a2691ba..75b8fb9 100644 (file)
@@ -98,6 +98,25 @@ static int CompareTools(const void *p1, const void *p2)
 
 
 //
+// (Re)load object tools
+//
+
+DWORD LoadObjectTools(void)
+{
+   DWORD dwResult;
+
+   NXCDestroyObjectToolList(g_dwNumObjectTools, g_pObjectToolList);
+   dwResult = NXCGetObjectTools(g_hSession, &g_dwNumObjectTools, &g_pObjectToolList);
+   if (dwResult == RCC_SUCCESS)
+   {
+      // Sort tools in alphabetical order
+      qsort(g_pObjectToolList, g_dwNumObjectTools, sizeof(NXC_OBJECT_TOOL), CompareTools);
+   }
+   return dwResult;
+}
+
+
+//
 // Login thread
 //
 
@@ -248,22 +267,7 @@ static DWORD WINAPI LoginThread(void *pArg)
    if (dwResult == RCC_SUCCESS)
    {
       SetInfoText(hWnd, "Loading object tools information...");
-      dwResult = NXCGetObjectTools(g_hSession, &g_dwNumObjectTools, &g_pObjectToolList);
-      if (dwResult == RCC_SUCCESS)
-      {
-         // Sort tools in alphabetical order and create pop-up menu
-         qsort(g_pObjectToolList, g_dwNumObjectTools, sizeof(NXC_OBJECT_TOOL), CompareTools);
-         i = 0;
-         g_pObjectToolsMenu = CreateToolsSubmenu(_T(""), &i);
-
-         // Insert tools submenu into various menus
-         theApp.GetContextMenu(1)->InsertMenu(14, MF_BYPOSITION | MF_STRING | MF_POPUP,
-                                              (UINT)g_pObjectToolsMenu->GetSafeHmenu(),
-                                              _T("&Tools"));
-         InsertMenu(GetSubMenu(theApp.m_hObjectBrowserMenu, LAST_APP_MENU - 1),
-                    18, MF_BYPOSITION | MF_STRING | MF_POPUP,
-                    (UINT)g_pObjectToolsMenu->GetSafeHmenu(), _T("&Tools"));
-      }
+      dwResult = LoadObjectTools();
    }
 
    // Disconnect if some of post-login operations was failed
index 08c9c02..c2ef044 100644 (file)
@@ -110,6 +110,7 @@ extern CConsoleApp theApp;
 #define WM_NETXMS_EVENT          (WM_USER + 116)
 #define WM_SYSLOG_RECORD         (WM_USER + 117)
 #define WM_UPDATE_EVENT_LIST     (WM_USER + 118)
+#define WM_UPDATE_OBJECT_TOOLS   (WM_USER + 119)
 
 
 //
@@ -283,12 +284,19 @@ BOOL ExtractWindowParam(TCHAR *pszStr, TCHAR *pszParam, TCHAR *pszBuffer, int iS
 long ExtractWindowParamLong(TCHAR *pszStr, TCHAR *pszParam, long nDefault);
 DWORD ExtractWindowParamULong(TCHAR *pszStr, TCHAR *pszParam, DWORD dwDefault);
 void CopyMenuItems(CMenu *pDst, CMenu *pSrc);
-CMenu *CreateToolsSubmenu(TCHAR *pszCurrPath, DWORD *pdwStart);
 TCHAR **CopyStringList(TCHAR **ppList, DWORD dwSize);
 void DestroyStringList(TCHAR **ppList, DWORD dwSize);
 
 
 //
+// Object tools functions
+//
+
+DWORD LoadObjectTools(void);
+CMenu *CreateToolsSubmenu(NXC_OBJECT *pObject, TCHAR *pszCurrPath, DWORD *pdwStart);
+
+
+//
 // Action functions
 //
 
index dc7ca2e..3ce7f86 100644 (file)
@@ -871,6 +871,7 @@ void CConsoleApp::EventHandler(DWORD dwEvent, DWORD dwCode, void *pArg)
                m_pMainWnd->PostMessage(WM_UPDATE_EVENT_LIST);
                break;
             case NX_NOTIFY_OBJTOOLS_CHANGED:
+               m_pMainWnd->PostMessage(WM_UPDATE_OBJECT_TOOLS);
                break;
             case NX_NOTIFY_NEW_ALARM:
             case NX_NOTIFY_ALARM_DELETED:
index f14bba7..881712f 100644 (file)
@@ -584,7 +584,7 @@ void CopyMenuItems(CMenu *pDst, CMenu *pSrc)
 // Create object tools pop-up menu
 //
 
-CMenu *CreateToolsSubmenu(TCHAR *pszCurrPath, DWORD *pdwStart)
+CMenu *CreateToolsSubmenu(NXC_OBJECT *pObject, TCHAR *pszCurrPath, DWORD *pdwStart)
 {
    CMenu *pMenu;
    TCHAR szName[MAX_DB_STRING], szPath[MAX_DB_STRING];
@@ -596,57 +596,60 @@ CMenu *CreateToolsSubmenu(TCHAR *pszCurrPath, DWORD *pdwStart)
    pMenu->CreatePopupMenu();
    for(i = *pdwStart, nId = OBJTOOL_MENU_FIRST_ID + *pdwStart; i < g_dwNumObjectTools; i++, nId++)
    {
-      // Separate item name and path
-      memset(szPath, 0, sizeof(TCHAR) * MAX_DB_STRING);
-      if (_tcsstr(g_pObjectToolList[i].szName, _T("->")) != NULL)
+      if (NXCIsAppropriateTool(&g_pObjectToolList[i], pObject))
       {
-         for(j = _tcslen(g_pObjectToolList[i].szName) - 1; j > 0; j--)
-            if ((g_pObjectToolList[i].szName[j] == _T('>')) &&
-                (g_pObjectToolList[i].szName[j - 1] == _T('-')))
-            {
-               _tcscpy(szName, &g_pObjectToolList[i].szName[j + 1]);
-               j--;
-               break;
-            }
-         memcpy(szPath, g_pObjectToolList[i].szName, j * sizeof(TCHAR));
-      }
-      else
-      {
-         _tcscpy(szName, g_pObjectToolList[i].szName);
-      }
+         // Separate item name and path
+         memset(szPath, 0, sizeof(TCHAR) * MAX_DB_STRING);
+         if (_tcsstr(g_pObjectToolList[i].szName, _T("->")) != NULL)
+         {
+            for(j = _tcslen(g_pObjectToolList[i].szName) - 1; j > 0; j--)
+               if ((g_pObjectToolList[i].szName[j] == _T('>')) &&
+                   (g_pObjectToolList[i].szName[j - 1] == _T('-')))
+               {
+                  _tcscpy(szName, &g_pObjectToolList[i].szName[j + 1]);
+                  j--;
+                  break;
+               }
+            memcpy(szPath, g_pObjectToolList[i].szName, j * sizeof(TCHAR));
+         }
+         else
+         {
+            _tcscpy(szName, g_pObjectToolList[i].szName);
+         }
 
-      if (!_tcsicmp(szPath, pszCurrPath))
-      {
-         StrStrip(szName);
-         pMenu->AppendMenu(MF_ENABLED | MF_STRING, nId, szName);
-      }
-      else
-      {
-         for(j = _tcslen(pszCurrPath); (szPath[j] == _T(' ')) || (szPath[j] == _T('\t')); j++);
-         if ((*pszCurrPath == 0) ||
-             ((!memicmp(szPath, pszCurrPath, _tcslen(pszCurrPath) * sizeof(TCHAR))) &&
-              (szPath[j] == _T('-')) && (szPath[j + 1] == _T('>'))))
+         if (!_tcsicmp(szPath, pszCurrPath))
          {
-            CMenu *pSubMenu;
-            TCHAR *pszName;
-
-            // Submenu of current menu
-            if (*pszCurrPath != 0)
-               j += 2;
-            pszName = &szPath[j];
-            for(; (szPath[j] != 0) && (memcmp(&szPath[j], _T("->"), sizeof(TCHAR) * 2)); j++);
-            szPath[j] = 0;
-            pSubMenu = CreateToolsSubmenu(szPath, &i);
-            nId = OBJTOOL_MENU_FIRST_ID + i;
-            StrStrip(pszName);
-            pMenu->AppendMenu(MF_ENABLED | MF_STRING | MF_POPUP,
-                              (UINT)pSubMenu->Detach(), pszName);
-            delete pSubMenu;
+            StrStrip(szName);
+            pMenu->AppendMenu(MF_ENABLED | MF_STRING, nId, szName);
          }
          else
          {
-            i--;
-            break;
+            for(j = _tcslen(pszCurrPath); (szPath[j] == _T(' ')) || (szPath[j] == _T('\t')); j++);
+            if ((*pszCurrPath == 0) ||
+                ((!memicmp(szPath, pszCurrPath, _tcslen(pszCurrPath) * sizeof(TCHAR))) &&
+                 (szPath[j] == _T('-')) && (szPath[j + 1] == _T('>'))))
+            {
+               CMenu *pSubMenu;
+               TCHAR *pszName;
+
+               // Submenu of current menu
+               if (*pszCurrPath != 0)
+                  j += 2;
+               pszName = &szPath[j];
+               for(; (szPath[j] != 0) && (memcmp(&szPath[j], _T("->"), sizeof(TCHAR) * 2)); j++);
+               szPath[j] = 0;
+               pSubMenu = CreateToolsSubmenu(pObject, szPath, &i);
+               nId = OBJTOOL_MENU_FIRST_ID + i;
+               StrStrip(pszName);
+               pMenu->AppendMenu(MF_ENABLED | MF_STRING | MF_POPUP,
+                                 (UINT)pSubMenu->Detach(), pszName);
+               delete pSubMenu;
+            }
+            else
+            {
+               i--;
+               break;
+            }
          }
       }
    }
index 6fb55a6..b5f43e8 100644 (file)
@@ -60,6 +60,7 @@ DWORD LIBNXCL_EXPORTABLE NXCGetObjectTools(NXC_SESSION hSession, DWORD *pdwNumTo
             (*ppToolList)[i].pszData = pResponse->GetVariableStr(dwId + 3);
             (*ppToolList)[i].dwFlags = pResponse->GetVariableLong(dwId + 4);
             pResponse->GetVariableStr(dwId + 5, (*ppToolList)[i].szDescription, MAX_DB_STRING);
+            (*ppToolList)[i].pszMatchingOID = pResponse->GetVariableStr(dwId + 6);
          }
       }
       delete pResponse;
@@ -83,7 +84,10 @@ void LIBNXCL_EXPORTABLE NXCDestroyObjectToolList(DWORD dwNumTools, NXC_OBJECT_TO
    if (pList != NULL)
    {
       for(i = 0; i < dwNumTools; i++)
+      {
          safe_free(pList[i].pszData);
+         safe_free(pList[i].pszMatchingOID);
+      }
       free(pList);
    }
 }
@@ -245,6 +249,7 @@ DWORD LIBNXCL_EXPORTABLE NXCGetObjectToolDetails(NXC_SESSION hSession, DWORD dwT
          (*ppData)->pszData = pResponse->GetVariableStr(VID_TOOL_DATA);
          pResponse->GetVariableStr(VID_NAME, (*ppData)->szName, MAX_DB_STRING);
          pResponse->GetVariableStr(VID_DESCRIPTION, (*ppData)->szDescription, MAX_DB_STRING);
+         (*ppData)->pszMatchingOID = pResponse->GetVariableStr(VID_TOOL_OID);
          (*ppData)->dwACLSize = pResponse->GetVariableLong(VID_ACL_SIZE);
          (*ppData)->pdwACL = (DWORD *)malloc(sizeof(DWORD) * (*ppData)->dwACLSize);
          pResponse->GetVariableInt32Array(VID_ACL, (*ppData)->dwACLSize, (*ppData)->pdwACL);
@@ -282,6 +287,8 @@ void LIBNXCL_EXPORTABLE NXCDestroyObjectToolDetails(NXC_OBJECT_TOOL_DETAILS *pDa
 {
    if (pData != NULL)
    {
+      safe_free(pData->pszData);
+      safe_free(pData->pszMatchingOID);
       safe_free(pData->pColList);
       safe_free(pData->pdwACL);
       free(pData);
@@ -364,3 +371,42 @@ DWORD LIBNXCL_EXPORTABLE NXCUpdateObjectTool(NXC_SESSION hSession,
 
    return ((NXCL_Session *)hSession)->WaitForRCC(dwRqId);
 }
+
+
+//
+// Check if given object tool is appropriate for given node
+//
+
+BOOL LIBNXCL_EXPORTABLE NXCIsAppropriateTool(NXC_OBJECT_TOOL *pTool, NXC_OBJECT *pObject)
+{
+   BOOL bResult;
+
+   if (pObject == NULL)
+      return FALSE;
+
+   if (pObject->iClass == OBJECT_NODE)
+   {
+      bResult = TRUE;
+
+      if ((pTool->dwFlags & TF_REQUIRES_SNMP) && (!(pObject->node.dwFlags & NF_IS_SNMP)))
+         bResult = FALSE;
+      if ((pTool->dwFlags & TF_REQUIRES_AGENT) &&
+          (!(pObject->node.dwFlags & NF_IS_NATIVE_AGENT)))
+         bResult = FALSE;
+      if (pTool->dwFlags & TF_REQUIRES_OID_MATCH)
+      {
+         TCHAR *pszPattern;
+
+         pszPattern = CHECK_NULL_EX(pTool->pszMatchingOID);
+         if (*pszPattern == 0)
+            pszPattern = _T("*");
+         if (!MatchString(pszPattern, pObject->node.szObjectId, TRUE))
+            bResult = FALSE;
+      }
+   }
+   else
+   {
+      bResult = FALSE;
+   }
+   return bResult;
+}
index 8b97275..cedbfa5 100644 (file)
@@ -503,7 +503,7 @@ DWORD UpdateObjectToolFromMessage(CSCPMessage *pMsg)
    DB_RESULT hResult;
    BOOL bUpdate = FALSE;
    TCHAR *pszName, *pszData, *pszDescription, *pszTmp;
-   TCHAR szBuffer[MAX_DB_STRING], szQuery[4096];
+   TCHAR szBuffer[MAX_DB_STRING], szQuery[4096], szOID[MAX_DB_STRING];
    DWORD i, dwToolId, dwAclSize, *pdwAcl;
    int nType;
 
@@ -529,14 +529,18 @@ DWORD UpdateObjectToolFromMessage(CSCPMessage *pMsg)
    nType = pMsg->GetVariableShort(VID_TOOL_TYPE);
    if (bUpdate)
       _sntprintf(szQuery, 4096, _T("UPDATE object_tools SET tool_name='%s',tool_type=%d,"
-                                   "tool_data='%s',description='%s',flags=%d WHERE tool_id=%d"),
+                                   "tool_data='%s',description='%s',flags=%d,"
+                                   "matching_oid='%s' WHERE tool_id=%d"),
                 pszName, nType, pszData, pszDescription,
-                pMsg->GetVariableLong(VID_FLAGS), dwToolId);
+                pMsg->GetVariableLong(VID_FLAGS),
+                pMsg->GetVariableStr(VID_TOOL_OID, szOID, MAX_DB_STRING), dwToolId);
    else
       _sntprintf(szQuery, 4096, _T("INSERT INTO object_tools (tool_id,tool_name,tool_type,"
-                                   "tool_data,description,flags) VALUES (%d,'%s',%d,'%s','%s',%d)"),
+                                   "tool_data,description,flags,matching_oid) VALUES "
+                                   "(%d,'%s',%d,'%s','%s',%d,'%s')"),
                 dwToolId, pszName, nType, pszData,
-                pszDescription, pMsg->GetVariableLong(VID_FLAGS));
+                pszDescription, pMsg->GetVariableLong(VID_FLAGS),
+                pMsg->GetVariableStr(VID_TOOL_OID, szOID, MAX_DB_STRING));
    free(pszName);
    free(pszDescription);
    free(pszData);
index 96e5e27..bbe4a5b 100644 (file)
@@ -5039,7 +5039,7 @@ void ClientSession::SendObjectTools(DWORD dwRqId)
       }
       DBFreeResult(hResult);
 
-      hResult = DBSelect(g_hCoreDB, _T("SELECT tool_id,tool_name,tool_type,tool_data,flags,description FROM object_tools"));
+      hResult = DBSelect(g_hCoreDB, _T("SELECT tool_id,tool_name,tool_type,tool_data,flags,description,matching_oid FROM object_tools"));
       if (hResult != NULL)
       {
          dwNumTools = DBGetNumRows(hResult);
@@ -5087,6 +5087,8 @@ void ClientSession::SendObjectTools(DWORD dwRqId)
                msg.SetVariable(dwId + 5, pszStr);
                free(pszStr);
 
+               msg.SetVariable(dwId + 6, DBGetField(hResult, i, 6));
+
                dwNumMsgRec++;
                dwId += 10;
             }
@@ -5131,7 +5133,7 @@ void ClientSession::SendObjectToolDetails(CSCPMessage *pRequest)
    if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_TOOLS)
    {
       dwToolId = pRequest->GetVariableLong(VID_TOOL_ID);
-      _stprintf(szQuery, _T("SELECT tool_name,tool_type,tool_data,description,flags FROM object_tools WHERE tool_id=%d"), dwToolId);
+      _stprintf(szQuery, _T("SELECT tool_name,tool_type,tool_data,description,flags,matching_oid FROM object_tools WHERE tool_id=%d"), dwToolId);
       hResult = DBSelect(g_hCoreDB, szQuery);
       if (hResult != NULL)
       {
@@ -5156,6 +5158,7 @@ void ClientSession::SendObjectToolDetails(CSCPMessage *pRequest)
             free(pszStr);
 
             msg.SetVariable(VID_FLAGS, DBGetFieldULong(hResult, 0, 4));
+            msg.SetVariable(VID_TOOL_OID, DBGetField(hResult, 0, 5));
             DBFreeResult(hResult);
 
             // Access list