- Implemented package uploading (installation) to server from console
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 16 Jan 2005 22:44:38 +0000 (22:44 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 16 Jan 2005 22:44:38 +0000 (22:44 +0000)
- Implemented "average delta per minute" DCI transformation
- TODO updated

23 files changed:
.gitattributes
TODO
include/nms_cscp.h
include/nms_util.h
include/nxclapi.h
src/agent/core/nxagentd.h
src/console/win32/PackageMgr.cpp [new file with mode: 0644]
src/console/win32/PackageMgr.h [new file with mode: 0644]
src/console/win32/nxcon.clw
src/libnetxms/tools.cpp
src/libnxcl/image.cpp
src/libnxcl/libnxcl.h
src/libnxcl/main.cpp
src/libnxcl/package.cpp
src/libnxcl/session.cpp
src/server/core/Makefile.am
src/server/core/dcitem.cpp
src/server/core/id.cpp
src/server/core/nxcore.dsp
src/server/core/package.cpp [new file with mode: 0644]
src/server/core/session.cpp
src/server/include/nms_core.h
src/server/include/nms_pkg.h [new file with mode: 0644]

index fa3bb45..97f6045 100644 (file)
@@ -306,6 +306,8 @@ src/console/win32/ObjectSearchBox.cpp -text
 src/console/win32/ObjectSearchBox.h -text
 src/console/win32/ObjectSelDlg.cpp -text
 src/console/win32/ObjectSelDlg.h -text
+src/console/win32/PackageMgr.cpp -text
+src/console/win32/PackageMgr.h -text
 src/console/win32/PasswordChangeDlg.cpp -text
 src/console/win32/PasswordChangeDlg.h -text
 src/console/win32/RequestProcessingDlg.cpp -text
@@ -507,6 +509,7 @@ src/server/core/nxcore.dsp -text
 src/server/core/nxcore.dsw -text
 src/server/core/nxcore.h -text
 src/server/core/objects.cpp -text
+src/server/core/package.cpp -text
 src/server/core/rootobj.cpp -text
 src/server/core/session.cpp -text
 src/server/core/snmp.cpp -text
@@ -549,6 +552,7 @@ src/server/include/nms_dcoll.h -text
 src/server/include/nms_events.h -text
 src/server/include/nms_locks.h -text
 src/server/include/nms_objects.h -text
+src/server/include/nms_pkg.h -text
 src/server/include/nms_users.h -text
 src/server/include/nxmodule.h -text
 src/server/include/nxsrvapi.h -text
diff --git a/TODO b/TODO
index f4bc293..70b8b67 100644 (file)
--- a/TODO
+++ b/TODO
@@ -22,6 +22,7 @@ GENERAL:
   event configuration to allow sending of new events
 - View and update agent's configuration from server
 - Add diff() method for DCI thresholds
+- Planned outages (maintenance schedule)
 
 
 SERVER:
@@ -42,6 +43,7 @@ SERVER:
 - Multiple status pollers
 - Housekeeping for DCI
 - Add logging API for database drivers
+- DCI transformation scripts (probably Perl?)
 
 
 CORE AGENT:
@@ -65,9 +67,16 @@ WINDOWS CONSOLE:
 - Add primary IP address selection 
 - Add real-time graphs
 - Fix problem with header colors in event policy editor
+- Play sound on new alarms
+- Add sorting to all list views
 
 
 SUBAGENTS:
 
 - libperl-driven subagent, allow to run perl scripts w/o forking/executing
 - bandwidth meter; data in/out for last N seconds
+
+
+CLIENT LIBRARY:
+
+- Add locks to functions which calls PrepareForSync()/WaitForSync()
index 3d21158..eb50119 100644 (file)
@@ -277,6 +277,7 @@ typedef struct
 #define CMD_INSTALL_PACKAGE         0x006F
 #define CMD_LOCK_PACKAGE_DB         0x0070
 #define CMD_UNLOCK_PACKAGE_DB       0x0071
+#define CMD_ABORT_FILE_TRANSFER     0x0072
 
 
 //
@@ -411,6 +412,7 @@ typedef struct
 #define VID_PACKAGE_ID              ((DWORD)126)
 #define VID_PACKAGE_VERSION         ((DWORD)127)
 #define VID_PLATFORM_NAME           ((DWORD)128)
+#define VID_PACKAGE_NAME            ((DWORD)129)
 
 // Variable ranges for object's ACL
 #define VID_ACL_USER_BASE           ((DWORD)0x00001000)
index 6b2e4a3..4e948db 100644 (file)
@@ -197,6 +197,7 @@ extern "C"
    TCHAR LIBNETXMS_EXPORTABLE *ExtractWord(TCHAR *line, TCHAR *buffer);
    BOOL LIBNETXMS_EXPORTABLE IsValidObjectName(TCHAR *pszName);
    void LIBNETXMS_EXPORTABLE TranslateStr(TCHAR *pszString, TCHAR *pszSubStr, TCHAR *pszReplace);
+   TCHAR LIBNETXMS_EXPORTABLE *GetCleanFileName(TCHAR *pszFileName);
    
    DWORD LIBNETXMS_EXPORTABLE CalculateCRC32(const unsigned char *data, DWORD nbytes);
    void LIBNETXMS_EXPORTABLE CalculateMD5Hash(const unsigned char *data, int nbytes, unsigned char *hash);
index ca7e5af..dec6ff6 100644 (file)
@@ -64,6 +64,7 @@ typedef void * NXC_SESSION;
 #define MAX_STRING_VALUE         256
 #define MAX_AGENT_VERSION_LEN    64
 #define MAX_PLATFORM_NAME_LEN    64
+#define MAX_PACKAGE_NAME_LEN     64
 #define GROUP_FLAG               ((DWORD)0x80000000)
 #define GROUP_EVERYONE           ((DWORD)0x80000000)
 #define INVALID_UID              ((DWORD)0xFFFFFFFF)
@@ -236,6 +237,9 @@ typedef void * NXC_SESSION;
 #define RCC_DCI_NOT_SUPPORTED       ((DWORD)30)
 #define RCC_VERSION_MISMATCH        ((DWORD)31)
 #define RCC_NPI_PARSE_ERROR         ((DWORD)32)
+#define RCC_DUPLICATE_PACKAGE       ((DWORD)33)
+#define RCC_PACKAGE_FILE_EXIST      ((DWORD)34)
+#define RCC_RESOURCE_BUSY           ((DWORD)35)
 
 
 //
@@ -529,9 +533,11 @@ typedef void (* NXC_DEBUG_CALLBACK)(TCHAR *pMsg);
 typedef struct
 {
    DWORD dwId;
+   TCHAR szName[MAX_PACKAGE_NAME_LEN];
    TCHAR szVersion[MAX_AGENT_VERSION_LEN];
    TCHAR szPlatform[MAX_PLATFORM_NAME_LEN];
    TCHAR szFileName[MAX_DB_STRING];
+   TCHAR szDescription[MAX_DB_STRING];
 } NXC_PACKAGE_INFO;
 
 
@@ -982,8 +988,8 @@ DWORD LIBNXCL_EXPORTABLE NXCLockPackageDB(NXC_SESSION hSession);
 DWORD LIBNXCL_EXPORTABLE NXCUnlockPackageDB(NXC_SESSION hSession);
 DWORD LIBNXCL_EXPORTABLE NXCGetPackageList(NXC_SESSION hSession, DWORD *pdwNumPackages, 
                                            NXC_PACKAGE_INFO **ppList);
-DWORD LIBNXCL_EXPORTABLE NXCInstallPackage(NXC_SESSION hSession, TCHAR *pszPkgFile, 
-                                           DWORD *pdwPkgId);
+DWORD LIBNXCL_EXPORTABLE NXCInstallPackage(NXC_SESSION hSession, NXC_PACKAGE_INFO *pInfo,
+                                           TCHAR *pszFullPkgPath);
 DWORD LIBNXCL_EXPORTABLE NXCRemovePackage(NXC_SESSION hSession, DWORD dwPkgId);
 DWORD LIBNXCL_EXPORTABLE NXCParseNPIFile(TCHAR *pszInfoFile, NXC_PACKAGE_INFO *pInfo);
 
index 39a5f3c..4d4aff7 100644 (file)
@@ -33,7 +33,6 @@
 #include "messages.h"
 
 #ifdef _WIN32
-#include <io.h>
 #include <psapi.h>
 #endif
 
diff --git a/src/console/win32/PackageMgr.cpp b/src/console/win32/PackageMgr.cpp
new file mode 100644 (file)
index 0000000..62dc057
--- /dev/null
@@ -0,0 +1,260 @@
+// PackageMgr.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "nxcon.h"
+#include "PackageMgr.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CPackageMgr
+
+IMPLEMENT_DYNCREATE(CPackageMgr, CMDIChildWnd)
+
+CPackageMgr::CPackageMgr()
+{
+   m_pPackageList = NULL;
+   m_dwNumPackages = 0;
+}
+
+CPackageMgr::~CPackageMgr()
+{
+   safe_free(m_pPackageList);
+}
+
+
+BEGIN_MESSAGE_MAP(CPackageMgr, CMDIChildWnd)
+       //{{AFX_MSG_MAP(CPackageMgr)
+       ON_WM_CREATE()
+       ON_WM_DESTROY()
+       ON_COMMAND(ID_VIEW_REFRESH, OnViewRefresh)
+       ON_WM_SIZE()
+       ON_WM_SETFOCUS()
+       ON_WM_CLOSE()
+       ON_COMMAND(ID_PACKAGE_INSTALL, OnPackageInstall)
+       ON_WM_CONTEXTMENU()
+       //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPackageMgr message handlers
+
+BOOL CPackageMgr::PreCreateWindow(CREATESTRUCT& cs) 
+{
+   if (cs.lpszClass == NULL)
+      cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, 
+                                         NULL, 
+                                         GetSysColorBrush(COLOR_WINDOW), 
+                                         AfxGetApp()->LoadIcon(IDI_DATABASE));
+       return CMDIChildWnd::PreCreateWindow(cs);
+}
+
+
+//
+// WM_CREATE message handler
+//
+
+int CPackageMgr::OnCreate(LPCREATESTRUCT lpCreateStruct) 
+{
+   RECT rect;
+
+       if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
+               return -1;
+       
+   theApp.OnViewCreate(IDR_PACKAGE_MGR, this);
+       
+   // Create image list
+   m_imageList.Create(16, 16, ILC_COLOR24 | ILC_MASK, 4, 1);
+   m_imageList.Add(theApp.LoadIcon(IDI_PACKAGE));
+   m_imageList.Add(theApp.LoadIcon(IDI_SORT_UP));
+   m_imageList.Add(theApp.LoadIcon(IDI_SORT_DOWN));
+       
+   // Create list view control
+   GetClientRect(&rect);
+   m_wndListCtrl.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS,
+                        rect, this, IDC_LIST_VIEW);
+   m_wndListCtrl.SetExtendedStyle(LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT |
+                                  LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
+   m_wndListCtrl.SetHoverTime(0x7FFFFFFF);
+   m_wndListCtrl.SetImageList(&m_imageList, LVSIL_SMALL);
+
+   // Setup columns
+   m_wndListCtrl.InsertColumn(0, _T("ID"), LVCFMT_LEFT, 60);
+   m_wndListCtrl.InsertColumn(1, _T("Name"), LVCFMT_LEFT, 150);
+   m_wndListCtrl.InsertColumn(2, _T("Version"), LVCFMT_LEFT, 100);
+   m_wndListCtrl.InsertColumn(3, _T("Platform"), LVCFMT_LEFT, 150);
+   m_wndListCtrl.InsertColumn(4, _T("File"), LVCFMT_LEFT, 200);
+
+   PostMessage(WM_COMMAND, ID_VIEW_REFRESH, 0);
+
+       return 0;
+}
+
+
+//
+// WM_CLOSE message handler
+//
+
+void CPackageMgr::OnClose() 
+{
+   DoRequestArg1(NXCUnlockPackageDB, g_hSession, "Unlocking package database...");
+       CMDIChildWnd::OnClose();
+}
+
+
+//
+// WM_DESTROY message handler
+//
+
+void CPackageMgr::OnDestroy() 
+{
+   theApp.OnViewDestroy(IDR_PACKAGE_MGR, this);
+       CMDIChildWnd::OnDestroy();
+}
+
+
+//
+// WM_SIZE message handler
+//
+
+void CPackageMgr::OnSize(UINT nType, int cx, int cy) 
+{
+       CMDIChildWnd::OnSize(nType, cx, cy);
+       
+   m_wndListCtrl.SetWindowPos(NULL, 0, 0, cx, cy, SWP_NOZORDER);
+}
+
+
+//
+// WM_SETFOCUS message handler
+//
+
+void CPackageMgr::OnSetFocus(CWnd* pOldWnd) 
+{
+       CMDIChildWnd::OnSetFocus(pOldWnd);
+
+   m_wndListCtrl.SetFocus();
+}
+
+
+//
+// WM_COMMAND::ID_VIEW_REFRESH message handler
+//
+
+void CPackageMgr::OnViewRefresh() 
+{
+   DWORD i, dwResult;
+
+   m_wndListCtrl.DeleteAllItems();
+   safe_free(m_pPackageList);
+   dwResult = DoRequestArg3(NXCGetPackageList, g_hSession, &m_dwNumPackages, 
+                            &m_pPackageList, _T("Loading package database..."));
+   if (dwResult == RCC_SUCCESS)
+   {
+      for(i = 0; i < m_dwNumPackages; i++)
+      {
+         AddListItem(&m_pPackageList[i], FALSE);
+      }
+   }
+   else
+   {
+      theApp.ErrorBox(dwResult, _T("Error loading package list from server: %s"));
+   }
+}
+
+
+//
+// Add new item to package list
+//
+
+void CPackageMgr::AddListItem(NXC_PACKAGE_INFO *pInfo, BOOL bSelect)
+{
+   TCHAR szBuffer[64];
+   int iItem;
+
+   _stprintf(szBuffer, _T("%d"), pInfo->dwId);
+   iItem = m_wndListCtrl.InsertItem(0x7FFFFFFF, szBuffer, 0);
+   if (iItem != -1)
+   {
+      m_wndListCtrl.SetItemText(iItem, 1, pInfo->szName);
+      m_wndListCtrl.SetItemText(iItem, 2, pInfo->szVersion);
+      m_wndListCtrl.SetItemText(iItem, 3, pInfo->szPlatform);
+      m_wndListCtrl.SetItemText(iItem, 4, pInfo->szFileName);
+
+      if (bSelect)
+         SelectListViewItem(&m_wndListCtrl, iItem);
+   }
+}
+
+
+//
+// Package installation worker function
+//
+
+static DWORD InstallPackage(TCHAR *pszPkgFile, NXC_PACKAGE_INFO *pInfo)
+{
+   DWORD dwResult;
+   TCHAR *ptr, szDataFile[MAX_PATH];
+
+   // First, parse package information file
+   dwResult = NXCParseNPIFile(pszPkgFile, pInfo);
+   if (dwResult == RCC_SUCCESS)
+   {
+      _tcsncpy(szDataFile, pszPkgFile, MAX_PATH);
+      ptr = _tcsrchr(szDataFile, _T('\\'));
+      ASSERT(ptr != NULL);
+      if (ptr == NULL)  // Normally we should receive full path, so it's just a paranoid check
+         ptr = szDataFile;
+      else
+         ptr++;
+      _tcscpy(ptr, pInfo->szFileName);
+
+      dwResult = NXCInstallPackage(g_hSession, pInfo, szDataFile);
+   }
+
+   return dwResult;
+}
+
+
+//
+// WM_COMMAND::ID_PACKAGE_INSTALL message handler
+//
+
+void CPackageMgr::OnPackageInstall() 
+{
+   CFileDialog dlg(TRUE, _T(".npi"), NULL, OFN_FILEMUSTEXIST, 
+                   _T("NetXMS Package Info Files (*.npi)|*.npi|All Files (*.*)|*.*||"), this);
+   DWORD dwResult;
+   NXC_PACKAGE_INFO info;
+
+   if (dlg.DoModal() == IDOK)
+   {
+      dwResult = DoRequestArg2(InstallPackage, dlg.m_ofn.lpstrFile, &info, _T("Installing package..."));
+      if (dwResult == RCC_SUCCESS)
+      {
+         AddListItem(&info, TRUE);
+      }
+      else
+      {
+         theApp.ErrorBox(dwResult, _T("Unable to install package: %s"));
+      }
+   }
+}
+
+
+//
+// WM_CONTEXTMENU message handler
+//
+
+void CPackageMgr::OnContextMenu(CWnd* pWnd, CPoint point) 
+{
+   CMenu *pMenu;
+
+   pMenu = theApp.GetContextMenu(13);
+   pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, NULL);
+}
diff --git a/src/console/win32/PackageMgr.h b/src/console/win32/PackageMgr.h
new file mode 100644 (file)
index 0000000..d6b7851
--- /dev/null
@@ -0,0 +1,60 @@
+#if !defined(AFX_PACKAGEMGR_H__870772A7_A79F_43FE_ACDB_22C1FCFF6791__INCLUDED_)
+#define AFX_PACKAGEMGR_H__870772A7_A79F_43FE_ACDB_22C1FCFF6791__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// PackageMgr.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CPackageMgr frame
+
+class CPackageMgr : public CMDIChildWnd
+{
+       DECLARE_DYNCREATE(CPackageMgr)
+protected:
+       CPackageMgr();           // protected constructor used by dynamic creation
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+       // ClassWizard generated virtual function overrides
+       //{{AFX_VIRTUAL(CPackageMgr)
+       protected:
+       virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+       //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+       CListCtrl m_wndListCtrl;
+       CImageList m_imageList;
+   DWORD m_dwNumPackages;
+   NXC_PACKAGE_INFO *m_pPackageList;
+       virtual ~CPackageMgr();
+       void AddListItem(NXC_PACKAGE_INFO *pInfo, BOOL bSelect);
+
+       // Generated message map functions
+       //{{AFX_MSG(CPackageMgr)
+       afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+       afx_msg void OnDestroy();
+       afx_msg void OnViewRefresh();
+       afx_msg void OnSize(UINT nType, int cx, int cy);
+       afx_msg void OnSetFocus(CWnd* pOldWnd);
+       afx_msg void OnClose();
+       afx_msg void OnPackageInstall();
+       afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_PACKAGEMGR_H__870772A7_A79F_43FE_ACDB_22C1FCFF6791__INCLUDED_)
index 6d3b7b7..532066c 100644 (file)
@@ -17,20 +17,20 @@ Class9=CMapView
 
 ResourceCount=95
 Resource1=IDD_THRESHOLD (English (U.S.))
-Resource2=IDD_REQUEST_PROCESSING
+Resource2=IDD_CREATE_TG
 Resource3=IDM_VIEW_SPECIFIC (English (U.S.))
-Resource4=IDD_DCI_COLLECTION
-Resource5=IDD_EDIT_RULE_ALARM
+Resource4=IDA_EPP
+Resource5=IDD_LOGIN
 Class2=CChildView
 Class5=CAboutDlg
 Class6=CControlPanel
 Class8=CMapFrame
 Class10=CLoginDialog
-Resource6=IDD_EDIT_TRAP
+Resource6=IDD_SET_PASSWORD
 Class11=CProgressDialog
-Resource7=IDA_PACKAGE_MGR
+Resource7=IDD_NEW_ACTION
 Class12=CObjectBrowser
-Resource8=IDD_DCI_TRANSFORM
+Resource8=IDD_SELECT_USER
 Class13=CObjectPropDlg
 Resource9=IDD_CP_GENERAL (English (U.S.))
 Resource10=IDA_OBJECT_BROWSER (English (U.S.))
@@ -46,7 +46,7 @@ Resource17=IDD_SET_PASSWORD (English (U.S.))
 Class16=CDebugFrame
 Resource18=IDD_OBJECT_SECURITY (English (U.S.))
 Resource19=IDD_OBJECT_PROPERTIES (English (U.S.))
-Resource20=IDD_THRESHOLD
+Resource20=IDA_NETMAP
 Class17=CObjectPreview
 Resource21=IDD_DCI_TRANSFORM (English (U.S.))
 Class18=CToolBox
@@ -59,32 +59,32 @@ Class23=CNodePropsGeneral
 Resource23=IDD_LOGIN (English (U.S.))
 Class24=CObjectPropCaps
 Class25=CObjectPropSheet
-Resource24=IDA_EPP
+Resource24=IDD_SELECT_OBJECT
 Class26=CRequestProcessingDlg
 Resource25=IDD_EDIT_EVENT (English (U.S.))
 Resource26=IDD_PROGRESS (English (U.S.))
-Resource27=IDD_EDIT_RULE_COMMENT
+Resource27=IDA_TRAP_EDITOR
 Resource28=IDD_USER_PROPERTIES (English (U.S.))
 Class27=CObjectPropsGeneral
 Resource29=IDA_ALARM_BROWSER (English (U.S.))
 Class28=CObjectPropsSecurity
 Resource30=IDD_CREATE_NODE (English (U.S.))
-Resource31=IDD_USER_PROPERTIES
-Resource32=IDA_TRAP_EDITOR
+Resource31=IDR_MAINFRAME
+Resource32=IDD_EDIT_RULE_ALARM
 Class29=CUserSelectDlg
-Resource33=IDD_OBJECT_PRESENTATION
+Resource33=IDA_PACKAGE_MGR
 Class30=CUserEditor
 Resource34=IDD_DCI_PROPERTIES
 Class31=CNewUserDlg
-Resource35=IDD_SELECT_OBJECT
-Resource36=IDD_EDIT_TRAP_ARG
+Resource35=IDA_ACTION_EDITOR
+Resource36=IDD_DCI_COLLECTION
 Class32=CUserPropDlg
 Resource37=IDM_CONTEXT (English (U.S.))
-Resource38=IDA_ACTION_EDITOR
+Resource38=IDD_EDIT_RULE_SEVERITY
 Class33=CGroupPropDlg
-Resource39=IDD_SELECT_EVENT
-Resource40=IDA_ALARM_BROWSER
-Resource41=IDM_VIEW_SPECIFIC
+Resource39=IDA_GRAPH
+Resource40=IDD_EDIT_RULE_COMMENT
+Resource41=IDM_CONTEXT
 Resource42=IDD_SELECT_OBJECT (English (U.S.))
 Class34=CPasswordChangeDlg
 Class35=CNodeSummary
@@ -100,55 +100,55 @@ Class41=CGraphFrame
 Class42=CDCIThresholdsPage
 Resource46=IDA_MDI_DEFAULT (English (U.S.))
 Resource47=IDD_OBJECT_CAPS (English (U.S.))
-Resource48=IDM_CONTEXT
+Resource48=IDM_VIEW_SPECIFIC
 Class43=CThresholdDlg
 Resource49=IDD_SELECT_USER (English (U.S.))
-Resource50=IDD_NEW_ACTION
+Resource50=IDD_OBJECT_NODE_GENERAL
 Class44=CMIBBrowserDlg
 Class45=CEventPolicyEditor
 Class46=CRuleList
 Class47=CRuleHeader
 Resource51=IDR_MAINFRAME (English (U.S.))
-Resource52=IDD_CREATE_TG
+Resource52=IDD_NEW_USER
 Class48=CObjectSelDlg
-Resource53=IDD_ABOUTBOX
-Resource54=IDD_MIB_BROWSER
+Resource53=IDD_ACTION_PROPERTIES
+Resource54=IDA_EVENT_EDITOR
 Class49=CRuleCommentDlg
-Resource55=IDD_NEW_USER
+Resource55=IDD_EDIT_TRAP_ARG
 Class50=CEventSelDlg
-Resource56=IDD_CREATE_NODE
+Resource56=IDD_OBJECT_SECURITY
 Resource57=IDD_REQUEST_PROCESSING (English (U.S.))
-Resource58=IDD_DATA_QUERY
+Resource58=IDD_GROUP_PROPERTIES
 Resource59=IDD_ABOUTBOX (English (U.S.))
 Resource60=IDD_MIB_BROWSER (English (U.S.))
 Class51=CObjectPropsPresentation
 Resource61=IDD_OBJECT_PRESENTATION (English (U.S.))
-Resource62=IDD_DCI_THRESHOLDS
+Resource62=IDA_ALARM_BROWSER
 Class52=CRuleSeverityDlg
-Resource63=IDD_EDIT_RULE_SEVERITY
+Resource63=IDD_ABOUTBOX
 Class53=CRuleAlarmDlg
 Class54=CAlarmBrowser
 Resource64=IDD_SELECT_EVENT (English (U.S.))
-Resource65=IDD_ACTION_PROPERTIES
+Resource65=IDD_OBJECT_CAPS
 Resource66=IDD_NEW_ACTION (English (U.S.))
 Resource67=IDD_DCI_COLLECTION (English (U.S.))
 Resource68=IDD_NEW_USER (English (U.S.))
 Class55=CConsolePropsGeneral
 Class56=CActionEditor
-Resource69=IDA_GRAPH
-Resource70=IDD_SELECT_ACTION
+Resource69=IDD_CP_GENERAL
+Resource70=IDD_REQUEST_PROCESSING
 Class57=CNewActionDlg
-Resource71=IDA_EVENT_EDITOR
+Resource71=IDD_OBJECT_PRESENTATION
 Class58=CEditActionDlg
-Resource72=IDA_MDI_DEFAULT
+Resource72=IDD_THRESHOLD
 Class59=CActionSelDlg
-Resource73=IDD_SET_PASSWORD
+Resource73=IDA_OBJECT_BROWSER
 Resource74=IDD_EDIT_RULE_COMMENT (English (U.S.))
 Resource75=IDD_EDIT_RULE_ALARM (English (U.S.))
-Resource76=IDD_OBJECT_GENERAL
+Resource76=IDD_CREATE_TEMPLATE
 Class60=CCreateObjectDlg
 Class61=CCreateContainerDlg
-Resource77=IDD_CREATE_TEMPLATE
+Resource77=IDD_USER_PROPERTIES
 Class62=CCreateNodeDlg
 Resource78=IDA_EPP (English (U.S.))
 Resource79=IDD_CREATE_CONTAINER (English (U.S.))
@@ -158,27 +158,27 @@ Resource81=IDD_ACTION_PROPERTIES (English (U.S.))
 Class64=CPollNodeDlg
 Resource82=IDD_POLL_NODE (English (U.S.))
 Class65=CNodePoller
-Resource83=IDR_MAINFRAME
-Resource84=IDA_NETMAP
+Resource83=IDD_DCI_THRESHOLDS
+Resource84=IDD_SELECT_EVENT
 Class66=CCreateTemplateDlg
 Class67=CCreateTGDlg
-Resource85=IDD_SELECT_USER
-Resource86=IDD_LOGIN
+Resource85=IDD_EDIT_TRAP
+Resource86=IDD_SELECT_ACTION
 Class68=CTrapEditor
-Resource87=IDA_OBJECT_BROWSER
-Resource88=IDD_EDIT_EVENT
-Resource89=IDD_GROUP_PROPERTIES
+Resource87=IDD_MIB_BROWSER
+Resource88=IDD_CREATE_CONTAINER
+Resource89=IDA_MDI_DEFAULT
 Class69=CDataQueryDlg
-Resource90=IDD_CP_GENERAL
+Resource90=IDD_EDIT_EVENT
 Class70=CTrapEditDlg
-Resource91=IDD_OBJECT_NODE_GENERAL
+Resource91=IDD_CREATE_NODE
 Class71=CTrapParamDlg
-Resource92=IDD_OBJECT_CAPS
-Resource93=IDD_CREATE_CONTAINER
+Resource92=IDD_DCI_TRANSFORM
+Resource93=IDD_OBJECT_GENERAL
 Class72=CGraphPropDlg
 Class73=CColorSelector
 Class74=CPackageMgr
-Resource94=IDD_OBJECT_SECURITY
+Resource94=IDD_DATA_QUERY
 Resource95=IDD_GRAPH_PROPERTIES
 
 [CLS:CConsoleApp]
index 442003e..fecd9d4 100644 (file)
@@ -607,3 +607,18 @@ QWORD LIBNETXMS_EXPORTABLE FileSize(TCHAR *pszFileName)
    return (QWORD)fileInfo.st_size;
 #endif
 }
+
+
+//
+// Get pointer to clean file name (without path specification)
+//
+
+TCHAR LIBNETXMS_EXPORTABLE *GetCleanFileName(TCHAR *pszFileName)
+{
+   TCHAR *ptr;
+
+   ptr = pszFileName + _tcslen(pszFileName);
+   while((ptr >= pszFileName) && (*ptr != _T('/')) && (*ptr != _T('\\')) && (*ptr != _T(':')))
+      ptr--;
+   return (ptr + 1);
+}
index 215d91a..265c612 100644 (file)
 
 #include "libnxcl.h"
 
-#if defined(_WIN32) && !defined(UNDER_CE)
-#include <io.h>
-#endif
-
 
 //
 // Download image file from server
index 2f96174..5b70914 100644 (file)
@@ -133,6 +133,7 @@ public:
    CSCP_MESSAGE *WaitForRawMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut = 0);
    DWORD WaitForRCC(DWORD dwRqId);
    DWORD CreateRqId(void) { return m_dwMsgId++; }
+   DWORD SendFile(DWORD dwRqId, TCHAR *pszFileName);
 
    void CallEventHandler(DWORD dwEvent, DWORD dwCode, void *pArg);
 
index 953274c..ca5f4b9 100644 (file)
@@ -150,9 +150,12 @@ const TCHAR LIBNXCL_EXPORTABLE *NXCGetErrorText(DWORD dwError)
       _T("Invalid trap configuration record ID"),
       _T("Requested data collection item is not supported by agent"),
       _T("Client and server versions mismatch"),
-      _T("Error parsing package information file")
+      _T("Error parsing package information file"),
+      _T("Package with specified properties already installed on server"),
+      _T("Package file already exist on server"),
+      _T("Server resource busy")
    };
-   return ((dwError >= 0) && (dwError <= RCC_NPI_PARSE_ERROR)) ? pszErrorText[dwError] : _T("Unknown error code");
+   return ((dwError >= 0) && (dwError <= RCC_RESOURCE_BUSY)) ? pszErrorText[dwError] : _T("Unknown error code");
 }
 
 
index 6af2646..38f2d6e 100644 (file)
@@ -95,6 +95,9 @@ DWORD LIBNXCL_EXPORTABLE NXCGetPackageList(NXC_SESSION hSession, DWORD *pdwNumPa
             {
                *ppList = (NXC_PACKAGE_INFO *)realloc(*ppList, sizeof(NXC_PACKAGE_INFO) * (*pdwNumPackages + 1));
                (*ppList)[*pdwNumPackages].dwId = dwPkgId;
+               pResponce->GetVariableStr(VID_PACKAGE_NAME, 
+                                         (*ppList)[*pdwNumPackages].szName, 
+                                         MAX_PACKAGE_NAME);
                pResponce->GetVariableStr(VID_FILE_NAME, 
                                          (*ppList)[*pdwNumPackages].szFileName, 
                                          MAX_DB_STRING);
@@ -104,6 +107,9 @@ DWORD LIBNXCL_EXPORTABLE NXCGetPackageList(NXC_SESSION hSession, DWORD *pdwNumPa
                pResponce->GetVariableStr(VID_PACKAGE_VERSION, 
                                          (*ppList)[*pdwNumPackages].szVersion, 
                                          MAX_AGENT_VERSION_LEN);
+               pResponce->GetVariableStr(VID_DESCRIPTION, 
+                                         (*ppList)[*pdwNumPackages].szDescription, 
+                                         MAX_DB_STRING);
                (*pdwNumPackages)++;
             }
             delete pResponce;
@@ -147,9 +153,52 @@ DWORD LIBNXCL_EXPORTABLE NXCRemovePackage(NXC_SESSION hSession, DWORD dwPkgId)
 // Install package to server
 //
 
-DWORD LIBNXCL_EXPORTABLE NXCInstallPackage(NXC_SESSION hSession, TCHAR *pszPkgFile, DWORD *pdwPkgId)
+DWORD LIBNXCL_EXPORTABLE NXCInstallPackage(NXC_SESSION hSession, NXC_PACKAGE_INFO *pInfo,
+                                           TCHAR *pszFullPkgPath)
 {
-   return 0;
+   CSCPMessage msg, *pResponce;
+   DWORD dwRqId, dwResult;
+
+   dwRqId = ((NXCL_Session *)hSession)->CreateRqId();
+
+   msg.SetCode(CMD_INSTALL_PACKAGE);
+   msg.SetId(dwRqId);
+   msg.SetVariable(VID_PACKAGE_NAME, pInfo->szName);
+   msg.SetVariable(VID_DESCRIPTION, pInfo->szDescription);
+   msg.SetVariable(VID_FILE_NAME, pInfo->szFileName);
+   msg.SetVariable(VID_PLATFORM_NAME, pInfo->szPlatform);
+   msg.SetVariable(VID_PACKAGE_VERSION, pInfo->szVersion);
+   ((NXCL_Session *)hSession)->SendMsg(&msg);
+
+   pResponce = ((NXCL_Session *)hSession)->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId);
+   if (pResponce != NULL)
+   {
+      dwResult = pResponce->GetVariableLong(VID_RCC);
+      if (dwResult == RCC_SUCCESS)
+      {
+         // Get id assigned to installed package and
+         // update provided package information structure
+         pInfo->dwId = pResponce->GetVariableLong(VID_PACKAGE_ID);
+      }
+      delete pResponce;
+   }
+   else
+   {
+      dwResult = RCC_TIMEOUT;
+   }
+
+   // If everything is OK, send package file to server
+   if (dwResult == RCC_SUCCESS)
+   {
+      dwResult = ((NXCL_Session *)hSession)->SendFile(dwRqId, pszFullPkgPath);
+      if (dwResult == RCC_SUCCESS)
+      {
+         // Wait for final confirmation
+         dwResult = ((NXCL_Session *)hSession)->WaitForRCC(dwRqId);
+      }
+   }
+
+   return dwResult;
 }
 
 
@@ -184,6 +233,7 @@ DWORD LIBNXCL_EXPORTABLE NXCParseNPIFile(TCHAR *pszInfoFile, NXC_PACKAGE_INFO *p
 
          if (!_tcscmp(szTag, _T("NAME")))
          {
+            _tcsncpy(pInfo->szName, ptr, MAX_PACKAGE_NAME_LEN);
          }
          else if (!_tcscmp(szTag, _T("PLATFORM")))
          {
@@ -195,9 +245,11 @@ DWORD LIBNXCL_EXPORTABLE NXCParseNPIFile(TCHAR *pszInfoFile, NXC_PACKAGE_INFO *p
          }
          else if (!_tcscmp(szTag, _T("DESCRIPTION")))
          {
+            _tcsncpy(pInfo->szDescription, ptr, MAX_DB_STRING);
          }
          else if (!_tcscmp(szTag, _T("FILE")))
          {
+            _tcsncpy(pInfo->szFileName, GetCleanFileName(ptr), MAX_DB_STRING);
          }
          else
          {
index ee6d9b3..006bf62 100644 (file)
@@ -748,3 +748,13 @@ DWORD NXCL_Session::LoadUserDB(void)
 
    return dwRetCode;
 }
+
+
+//
+// Send file to server
+//
+
+DWORD NXCL_Session::SendFile(DWORD dwRqId, TCHAR *pszFileName)
+{
+   return SendFileOverCSCP(m_hSocket, dwRqId, pszFileName) ? RCC_SUCCESS : RCC_IO_ERROR;
+}
index e630687..f678a87 100644 (file)
@@ -1,7 +1,7 @@
 INCLUDES=-I@top_srcdir@/include -I@top_srcdir@/src/server/include
 
 lib_LTLIBRARIES = libnxcore.la
-libnxcore_la_SOURCES = acl.cpp actions.cpp admin.cpp alarm.cpp client.cpp config.cpp container.cpp datacoll.cpp dbwrite.cpp dcitem.cpp dcithreshold.cpp dcivalue.cpp debug.cpp discovery.cpp email.cpp entirenet.cpp epp.cpp events.cpp evproc.cpp hk.cpp id.cpp image.cpp interface.cpp locks.cpp main.cpp modules.cpp netinfo.cpp netobj.cpp node.cpp nortel.cpp np.cpp objects.cpp rootobj.cpp session.cpp snmp.cpp snmptrap.cpp status.cpp subnet.cpp syncer.cpp template.cpp tools.cpp uniroot.cpp users.cpp watchdog.cpp
+libnxcore_la_SOURCES = acl.cpp actions.cpp admin.cpp alarm.cpp client.cpp config.cpp container.cpp datacoll.cpp dbwrite.cpp dcitem.cpp dcithreshold.cpp dcivalue.cpp debug.cpp discovery.cpp email.cpp entirenet.cpp epp.cpp events.cpp evproc.cpp hk.cpp id.cpp image.cpp interface.cpp locks.cpp main.cpp modules.cpp netinfo.cpp netobj.cpp node.cpp nortel.cpp np.cpp objects.cpp package.cpp rootobj.cpp session.cpp snmp.cpp snmptrap.cpp status.cpp subnet.cpp syncer.cpp template.cpp tools.cpp uniroot.cpp users.cpp watchdog.cpp
 libnxcore_la_LDFLAGS = -version-info $(LIBNXCORE_LIBRARY_VERSION)
 
 EXTRA_DIST = \
index ab62010..1d5d03d 100644 (file)
@@ -553,6 +553,8 @@ void DCItem::Transform(ItemValue &value, long nElapsedTime)
                break;
          }
          break;
+      case DCM_AVERAGE_PER_MINUTE:
+         nElapsedTime /= 60;  // Convert to minutes
       case DCM_AVERAGE_PER_SECOND:
          // Check elapsed time to prevent divide-by-zero exception
          if (nElapsedTime == 0)
@@ -576,9 +578,9 @@ void DCItem::Transform(ItemValue &value, long nElapsedTime)
                value = ((double)value - (double)m_prevRawValue) / (double)nElapsedTime;
                break;
             case DCI_DT_STRING:
-               // I don't see any meaning in "average delta per second" for string
+               // I don't see any meaning in "average delta per second (minute)" for string
                // values, so result will be 0 if there are no difference between
-               // two values, and 1 otherwise
+               // current and previous values, and 1 otherwise
                value = (long)((strcmp((const TCHAR *)value, (const TCHAR *)m_prevRawValue) == 0) ? 0 : 1);
                break;
             default:
@@ -586,8 +588,6 @@ void DCItem::Transform(ItemValue &value, long nElapsedTime)
                break;
          }
          break;
-      case DCM_AVERAGE_PER_MINUTE:
-         break;
       default:    // Default is no transformation
          break;
    }
index 6c4a0a1..5c70e57 100644 (file)
@@ -27,7 +27,7 @@
 // Constants
 //
 
-#define NUMBER_OF_GROUPS   13
+#define NUMBER_OF_GROUPS   14
 
 
 //
 static MUTEX m_mutexTableAccess;
 static DWORD m_dwFreeIdTable[NUMBER_OF_GROUPS] = { 10, 1, FIRST_USER_EVENT_ID, 1, 1, 
                                                    1000, 1, 0x80000000,
-                                                   1, 1, 0x80000001, 1, 1 };
+                                                   1, 1, 0x80000001, 1, 1, 1 };
 static DWORD m_dwIdLimits[NUMBER_OF_GROUPS] = { 0xFFFFFFFE, 0xFFFFFFFE, 0x7FFFFFFF, 0x7FFFFFFF, 
                                                 0x7FFFFFFF, 0xFFFFFFFE, 0x7FFFFFFF, 0xFFFFFFFF,
                                                 0x7FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFE, 0xFFFFFFFE,
-                                                0xFFFFFFFE
+                                                0xFFFFFFFE, 0xFFFFFFFE
                                               };
 static QWORD m_qwFreeEventId = 1;
 static char *m_pszGroupNames[] =
@@ -58,7 +58,8 @@ static char *m_pszGroupNames[] =
    "Users",
    "User Groups",
    "Alarms",
-   "Alarm Notes"
+   "Alarm Notes",
+   "Packages"
 };
 
 
@@ -245,6 +246,16 @@ BOOL InitIdTable(void)
       DBFreeResult(hResult);
    }
 
+   // Get first available package id
+   hResult = DBSelect(g_hCoreDB, "SELECT max(pkg_id) FROM agent_pkg");
+   if (hResult != NULL)
+   {
+      if (DBGetNumRows(hResult) > 0)
+         m_dwFreeIdTable[IDG_PACKAGE] = max(m_dwFreeIdTable[IDG_PACKAGE], 
+                                            DBGetFieldULong(hResult, 0, 0) + 1);
+      DBFreeResult(hResult);
+   }
+
    return TRUE;
 }
 
index 6c15fc7..071d560 100644 (file)
@@ -230,6 +230,10 @@ SOURCE=.\objects.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\package.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\rootobj.cpp
 # End Source File
 # Begin Source File
@@ -342,6 +346,10 @@ SOURCE=..\include\nms_objects.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\include\nms_pkg.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\..\include\nms_threads.h
 # End Source File
 # Begin Source File
diff --git a/src/server/core/package.cpp b/src/server/core/package.cpp
new file mode 100644 (file)
index 0000000..644918b
--- /dev/null
@@ -0,0 +1,69 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004, 2005 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: package.cpp
+**
+**/
+
+#include "nxcore.h"
+
+
+//
+// Check if package with specific parameters already installed
+//
+
+BOOL IsPackageInstalled(TCHAR *pszName, TCHAR *pszVersion, TCHAR *pszPlatform)
+{
+   DB_RESULT hResult;
+   TCHAR szQuery[1024], *pszEscName, *pszEscVersion, *pszEscPlatform;
+   BOOL bResult = FALSE;
+
+   pszEscName = EncodeSQLString(pszName);
+   pszEscVersion = EncodeSQLString(pszVersion);
+   pszEscPlatform = EncodeSQLString(pszPlatform);
+   _sntprintf(szQuery, 1024, _T("SELECT pkg_id FROM agent_pkg WHERE "
+                                "pkg_name='%s' AND version='%s' AND platform='%s'"),
+              pszEscName, pszEscVersion, pszEscPlatform);
+   free(pszEscName);
+   free(pszEscVersion);
+   free(pszEscPlatform);
+
+   hResult = DBSelect(g_hCoreDB, szQuery);
+   if (hResult != NULL)
+   {
+      bResult = (DBGetNumRows(hResult) > 0);
+      DBFreeResult(hResult);
+   }
+   return bResult;
+}
+
+
+//
+// Check if package file with given name exist
+//
+
+BOOL IsPackageFileExist(TCHAR *pszFileName)
+{
+   TCHAR szFullPath[MAX_PATH];
+
+   _tcscpy(szFullPath, g_szDataDir);
+   _tcscat(szFullPath, DDIR_PACKAGES);
+   _tcscat(szFullPath, FS_PATH_SEPARATOR);
+   _tcscat(szFullPath, pszFileName);
+   return (_taccess(szFullPath, 0) == 0);
+}
index 3f9b013..b3026a5 100644 (file)
@@ -35,6 +35,8 @@
 #define TRAP_UPDATE     2
 #define TRAP_DELETE     3
 
+#define RAW_MSG_SIZE    262144
+
 
 //
 // Externals
@@ -183,6 +185,8 @@ ClientSession::ClientSession(SOCKET hSocket, DWORD dwHostAddr)
    m_dwOpenDCIListSize = 0;
    m_pOpenDCIList = NULL;
    m_ppEPPRuleList = NULL;
+   m_hCurrFile = -1;
+   m_dwFileRqId = 0;
 }
 
 
@@ -255,22 +259,29 @@ void ClientSession::ReadThread(void)
 {
    CSCP_MESSAGE *pRawMsg;
    CSCPMessage *pMsg;
+   TCHAR szBuffer[256];
    int iErr;
    DWORD i;
    NetObj *pObject;
+   WORD wFlags;
 
    // Initialize raw message receiving function
    RecvCSCPMessage(0, NULL, m_pMsgBuffer, 0);
 
-   pRawMsg = (CSCP_MESSAGE *)malloc(65536);
+   pRawMsg = (CSCP_MESSAGE *)malloc(RAW_MSG_SIZE);
    while(1)
    {
-      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, 65536)) <= 0)
+      if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE)) <= 0)
          break;
 
       // Check if message is too large
       if (iErr == 1)
+      {
+         DebugPrintf("Received message %s is too large (%d bytes)\n",
+                     CSCPMessageCodeName(ntohs(pRawMsg->wCode), szBuffer),
+                     ntohl(pRawMsg->dwSize));
          continue;
+      }
 
       // Check that actual received packet size is equal to encoded in packet
       if ((int)ntohl(pRawMsg->dwSize) != iErr)
@@ -279,9 +290,77 @@ void ClientSession::ReadThread(void)
          continue;   // Bad packet, wait for next
       }
 
-      // Create message object from raw message
-      pMsg = new CSCPMessage(pRawMsg);
-      m_pMessageQueue->Put(pMsg);
+      // Special handling for raw messages
+      wFlags = ntohs(pRawMsg->wFlags);
+      if (wFlags & MF_BINARY)
+      {
+         // Convert message header to host format
+         pRawMsg->dwId = ntohl(pRawMsg->dwId);
+         pRawMsg->wCode = ntohs(pRawMsg->wCode);
+         pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
+         DebugPrintf("Received raw message %s\n", CSCPMessageCodeName(pRawMsg->wCode, szBuffer));
+
+         if ((pRawMsg->wCode == CMD_FILE_DATA) || 
+             (pRawMsg->wCode == CMD_ABORT_FILE_TRANSFER))
+         {
+            if ((m_hCurrFile != -1) && (m_dwFileRqId == pRawMsg->dwId))
+            {
+               if (pRawMsg->wCode == CMD_FILE_DATA)
+               {
+                  if (write(m_hCurrFile, pRawMsg->df, pRawMsg->dwNumVars) == (int)pRawMsg->dwNumVars)
+                  {
+                     if (wFlags & MF_EOF)
+                     {
+                        CSCPMessage msg;
+
+                        close(m_hCurrFile);
+                        m_hCurrFile = -1;
+                  
+                        msg.SetCode(CMD_REQUEST_COMPLETED);
+                        msg.SetId(pRawMsg->dwId);
+                        msg.SetVariable(VID_RCC, RCC_SUCCESS);
+                        SendMessage(&msg);
+
+                        OnFileUpload(TRUE);
+                     }
+                  }
+                  else
+                  {
+                     // I/O error
+                     CSCPMessage msg;
+
+                     close(m_hCurrFile);
+                     m_hCurrFile = -1;
+               
+                     msg.SetCode(CMD_REQUEST_COMPLETED);
+                     msg.SetId(pRawMsg->dwId);
+                     msg.SetVariable(VID_RCC, RCC_IO_ERROR);
+                     SendMessage(&msg);
+
+                     OnFileUpload(FALSE);
+                  }
+               }
+               else
+               {
+                  // Abort current file transfer because of client's problem
+                  close(m_hCurrFile);
+                  m_hCurrFile = -1;
+               
+                  OnFileUpload(FALSE);
+               }
+            }
+            else
+            {
+               DebugPrintf("Out of state message (ID: %d)\n", pRawMsg->dwId);
+            }
+         }
+      }
+      else
+      {
+         // Create message object from raw message
+         pMsg = new CSCPMessage(pRawMsg);
+         m_pMessageQueue->Put(pMsg);
+      }
    }
    if (iErr < 0)
       WriteLog(MSG_SESSION_CLOSED, EVENTLOG_WARNING_TYPE, "e", WSAGetLastError());
@@ -300,6 +379,14 @@ void ClientSession::ReadThread(void)
    ThreadJoin(m_hProcessingThread);
    ThreadJoin(m_hUpdateThread);
 
+   // Abort current file upload operation, if any
+   if (m_hCurrFile != -1)
+   {
+      close(m_hCurrFile);
+      m_hCurrFile = -1;
+      OnFileUpload(FALSE);
+   }
+
    // Remove all locks created by this session
    RemoveAllSessionLocks(m_dwIndex);
    for(i = 0; i < m_dwOpenDCIListSize; i++)
@@ -626,6 +713,9 @@ void ClientSession::ProcessingThread(void)
          case CMD_GET_PACKAGE_LIST:
             SendAllPackages(pMsg->GetId());
             break;
+         case CMD_INSTALL_PACKAGE:
+            InstallPackage(pMsg);
+            break;
          default:
             // Pass message to loaded modules
             for(i = 0; i < g_dwNumModules; i++)
@@ -649,6 +739,34 @@ void ClientSession::ProcessingThread(void)
 
 
 //
+// Process received file
+//
+
+void ClientSession::OnFileUpload(BOOL bSuccess)
+{
+   // Do processing specific to command initiated file upload
+   switch(m_dwUploadCommand)
+   {
+      case CMD_INSTALL_PACKAGE:
+         if (!bSuccess)
+         {
+            TCHAR szQuery[256];
+
+            _sntprintf(szQuery, 256, _T("DELETE FROM agent_pkg WHERE pkg_id=%ld"), m_dwUploadData);
+            DBQuery(g_hCoreDB, szQuery);
+         }
+         break;
+      default:
+         break;
+   }
+
+   // Remove received file in case of failure
+   if (!bSuccess)
+      _tunlink(m_szCurrFileName);
+}
+
+
+//
 // Send server information to client
 //
 
@@ -3532,7 +3650,7 @@ void ClientSession::SendAllPackages(DWORD dwRqId)
    {
       if (m_dwFlags & CSF_PACKAGE_DB_LOCKED)
       {
-         hResult = DBAsyncSelect(g_hCoreDB, "SELECT pkg_id,version,platform,pkg_file FROM agent_pkg");
+         hResult = DBAsyncSelect(g_hCoreDB, "SELECT pkg_id,version,platform,pkg_file,pkg_name,description FROM agent_pkg");
          if (hResult != NULL)
          {
             msg.SetVariable(VID_RCC, RCC_SUCCESS);
@@ -3548,6 +3666,10 @@ void ClientSession::SendAllPackages(DWORD dwRqId)
                msg.SetVariable(VID_PACKAGE_VERSION, DBGetFieldAsync(hResult, 1, szBuffer, MAX_DB_STRING));
                msg.SetVariable(VID_PLATFORM_NAME, DBGetFieldAsync(hResult, 2, szBuffer, MAX_DB_STRING));
                msg.SetVariable(VID_FILE_NAME, DBGetFieldAsync(hResult, 3, szBuffer, MAX_DB_STRING));
+               msg.SetVariable(VID_PACKAGE_NAME, DBGetFieldAsync(hResult, 4, szBuffer, MAX_DB_STRING));
+               DBGetFieldAsync(hResult, 5, szBuffer, MAX_DB_STRING);
+               DecodeSQLString(szBuffer);
+               msg.SetVariable(VID_DESCRIPTION, szBuffer);
                SendMessage(&msg);
                msg.DeleteAllVariables();
             }
@@ -3577,3 +3699,110 @@ void ClientSession::SendAllPackages(DWORD dwRqId)
    if (!bSuccess)
       SendMessage(&msg);
 }
+
+
+//
+// Install package to server
+//
+
+void ClientSession::InstallPackage(CSCPMessage *pRequest)
+{
+   CSCPMessage msg;
+   TCHAR szPkgName[MAX_PACKAGE_NAME_LEN], szDescription[MAX_DB_STRING];
+   TCHAR szPkgVersion[MAX_AGENT_VERSION_LEN], szFileName[MAX_DB_STRING];
+   TCHAR szPlatform[MAX_PLATFORM_NAME_LEN], *pszCleanFileName, *pszEscDescr;
+   TCHAR szQuery[2048];
+
+   // Prepare responce message
+   msg.SetCode(CMD_REQUEST_COMPLETED);
+   msg.SetId(pRequest->GetId());
+
+   if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_PACKAGES)
+   {
+      if (m_dwFlags & CSF_PACKAGE_DB_LOCKED)
+      {
+         pRequest->GetVariableStr(VID_PACKAGE_NAME, szPkgName, MAX_PACKAGE_NAME_LEN);
+         pRequest->GetVariableStr(VID_DESCRIPTION, szDescription, MAX_DB_STRING);
+         pRequest->GetVariableStr(VID_FILE_NAME, szFileName, MAX_DB_STRING);
+         pRequest->GetVariableStr(VID_PACKAGE_VERSION, szPkgVersion, MAX_AGENT_VERSION_LEN);
+         pRequest->GetVariableStr(VID_PLATFORM_NAME, szPlatform, MAX_PLATFORM_NAME_LEN);
+
+         // Remove possible path specification from file name
+         pszCleanFileName = GetCleanFileName(szFileName);
+
+         if (IsValidObjectName(pszCleanFileName) && 
+             IsValidObjectName(szPkgName) &&
+             IsValidObjectName(szPkgVersion) &&
+             IsValidObjectName(szPlatform))
+         {
+            // Check if same package already exist
+            if (!IsPackageInstalled(szPkgName, szPkgVersion, szPlatform))
+            {
+               // Check for duplicate file name
+               if (!IsPackageFileExist(pszCleanFileName))
+               {
+                  // Prepare for file receive
+                  if (m_hCurrFile == -1)
+                  {
+                     _tcscpy(m_szCurrFileName, g_szDataDir);
+                     _tcscat(m_szCurrFileName, DDIR_PACKAGES);
+                     _tcscat(m_szCurrFileName, FS_PATH_SEPARATOR);
+                     _tcscat(m_szCurrFileName, pszCleanFileName);
+                     m_hCurrFile = _topen(m_szCurrFileName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
+                     if (m_hCurrFile != -1)
+                     {
+                        m_dwFileRqId = pRequest->GetId();
+                        m_dwUploadCommand = CMD_INSTALL_PACKAGE;
+                        m_dwUploadData = CreateUniqueId(IDG_PACKAGE);
+                        msg.SetVariable(VID_RCC, RCC_SUCCESS);
+                        msg.SetVariable(VID_PACKAGE_ID, m_dwUploadData);
+
+                        // Create record in database
+                        pszEscDescr = EncodeSQLString(szDescription);
+                        _sntprintf(szQuery, 2048, _T("INSERT INTO agent_pkg (pkg_id,pkg_name,"
+                                                     "version,description,platform,pkg_file) "
+                                                     "VALUES (%ld,'%s','%s','%s','%s','%s')"),
+                                   m_dwUploadData, szPkgName, szPkgVersion, pszEscDescr,
+                                   szPlatform, pszCleanFileName);
+                        free(pszEscDescr);
+                        DBQuery(g_hCoreDB, szQuery);
+                     }
+                     else
+                     {
+                        msg.SetVariable(VID_RCC, RCC_IO_ERROR);
+                     }
+                  }
+                  else
+                  {
+                     msg.SetVariable(VID_RCC, RCC_RESOURCE_BUSY);
+                  }
+               }
+               else
+               {
+                  msg.SetVariable(VID_RCC, RCC_PACKAGE_FILE_EXIST);
+               }
+            }
+            else
+            {
+               msg.SetVariable(VID_RCC, RCC_DUPLICATE_PACKAGE);
+            }
+         }
+         else
+         {
+            msg.SetVariable(VID_RCC, RCC_INVALID_OBJECT_NAME);
+         }
+      }
+      else
+      {
+         msg.SetVariable(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
+      }
+   }
+   else
+   {
+      // Current user has no rights for package management
+      msg.SetVariable(VID_RCC, RCC_ACCESS_DENIED);
+   }
+
+   // Send responce
+   SendMessage(&msg);
+}
index 9e82f21..8729e14 100644 (file)
@@ -80,6 +80,7 @@
 #include "nms_objects.h"
 #include "messages.h"
 #include "nms_locks.h"
+#include "nms_pkg.h"
 
 
 //
@@ -132,6 +133,7 @@ typedef void * HSNMPSESSION;
 #define IDG_USER_GROUP        10
 #define IDG_ALARM             11
 #define IDG_ALARM_NOTE        12
+#define IDG_PACKAGE           13
 
 
 //
@@ -245,12 +247,17 @@ private:
    MUTEX m_mutexSendActions;
    MUTEX m_mutexPollerInit;
    DWORD m_dwHostAddr;        // IP address of connected host (network byte order)
-   char m_szUserName[256];    // String in form login_name@host
+   TCHAR m_szUserName[256];   // String in form login_name@host
    DWORD m_dwOpenDCIListSize; // Number of open DCI lists
    DWORD *m_pOpenDCIList;     // List of nodes with DCI lists open
    DWORD m_dwNumRecordsToUpload; // Number of records to be uploaded
    DWORD m_dwRecordsUploaded;
    EPRule **m_ppEPPRuleList;   // List of loaded EPP rules
+   int m_hCurrFile;
+   DWORD m_dwFileRqId;
+   DWORD m_dwUploadCommand;
+   DWORD m_dwUploadData;
+   TCHAR m_szCurrFileName[MAX_PATH];
 
    static THREAD_RESULT THREAD_CALL ReadThreadStarter(void *);
    static THREAD_RESULT THREAD_CALL WriteThreadStarter(void *);
@@ -270,6 +277,7 @@ private:
          ((dwRequiredAccess & m_dwSystemAccess) ? TRUE : FALSE);
    }
 
+   void OnFileUpload(BOOL bSuccess);
    void DebugPrintf(char *szFormat, ...);
    void SendServerInfo(DWORD dwRqId);
    void Login(CSCPMessage *pRequest);
@@ -324,6 +332,7 @@ private:
    void SendAllTraps(DWORD dwRqId);
    void LockPackageDB(DWORD dwRqId, BOOL bLock);
    void SendAllPackages(DWORD dwRqId);
+   void InstallPackage(CSCPMessage *pRequest);
 
 public:
    ClientSession(SOCKET hSocket, DWORD dwHostAddr);
diff --git a/src/server/include/nms_pkg.h b/src/server/include/nms_pkg.h
new file mode 100644 (file)
index 0000000..de6a696
--- /dev/null
@@ -0,0 +1,34 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004, 2005 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: nms_pkg.h
+**
+**/
+
+#ifndef _nms_pkg_h_
+#define _nms_pkg_h_
+
+//
+// Package functions
+//
+
+BOOL IsPackageInstalled(TCHAR *pszName, TCHAR *pszVersion, TCHAR *pszPlatform);
+BOOL IsPackageFileExist(TCHAR *pszFileName);
+
+
+#endif   /* _nms_pkg_h_ */