- Added Template and TemplateGroup object classes
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 30 Sep 2004 14:33:43 +0000 (14:33 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 30 Sep 2004 14:33:43 +0000 (14:33 +0000)
- Added string to binary conversion for 64-bit integers
- Functions BinToStr() and StrToBin() moved to libnetxms
- MAC address property added to Interface objects
- MAC address change detection added
- Minor bugfixes

44 files changed:
.gitattributes
ChangeLog
configure.ac
include/netxms-version.h
include/netxmsdb.h
include/nms_agent.h
include/nms_common.h
include/nms_cscp.h
include/nms_util.h
include/nxclapi.h
include/nxcscpapi.h
include/nxevent.h
sql/events.in
sql/schema.in
src/agent/core/netinfo.cpp
src/agent/core/nxagentd.h
src/console/win32/ObjectInfoBox.cpp
src/console/win32/globals.cpp
src/libnetxms/Makefile.am
src/libnetxms/icmp.cpp
src/libnetxms/libnetxms.dsp
src/libnetxms/strtoll.c [new file with mode: 0644]
src/libnetxms/strtoull.c [new file with mode: 0644]
src/libnetxms/tools.cpp
src/libnxcl/objects.cpp
src/server/core/datacoll.cpp
src/server/core/db.cpp
src/server/core/dcitem.cpp
src/server/core/dcithreshold.cpp
src/server/core/dcivalue.cpp
src/server/core/interface.cpp
src/server/core/netinfo.cpp
src/server/core/netxmsd.dsp
src/server/core/nms_core.h
src/server/core/nms_dcoll.h
src/server/core/nms_objects.h
src/server/core/node.cpp
src/server/core/objects.cpp
src/server/core/session.cpp
src/server/core/snmp.cpp
src/server/core/template.cpp [new file with mode: 0644]
src/server/core/tools.cpp
src/server/include/nxsrvapi.h
src/server/libnxsrv/agent.cpp

index 3af7361..cf29158 100644 (file)
@@ -294,6 +294,8 @@ src/libnetxms/md5.h -text
 src/libnetxms/netxms.def -text
 src/libnetxms/sha1.cpp -text
 src/libnetxms/sha1.h -text
+src/libnetxms/strtoll.c -text
+src/libnetxms/strtoull.c -text
 src/libnetxms/tools.cpp -text
 src/libnetxms/unicode.cpp -text
 src/libnxcl/Makefile.am -text
@@ -367,6 +369,7 @@ src/server/core/srvroot.cpp -text
 src/server/core/status.cpp -text
 src/server/core/subnet.cpp -text
 src/server/core/syncer.cpp -text
+src/server/core/template.cpp -text
 src/server/core/tools.cpp -text
 src/server/core/users.cpp -text
 src/server/core/watchdog.cpp -text
index e69de29..57ef32c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -0,0 +1,16 @@
+*
+* 0.1.3
+*
+
+- Added 64-bit string-to-binary conversion
+- Added MAC address property to interface objects
+- Added Template and TemplateGroup object classes
+
+
+*
+* 0.1.2
+*
+
+- Added possibility for copying DCIs from one node to other(s)
+- Added server's startup script for RedHat Linux
+- Numerous bug fixes
index a2e64bb..d3c5097 100644 (file)
@@ -1,9 +1,9 @@
-# $Id: configure.ac,v 1.25 2004-09-22 17:38:01 victor Exp $
+# $Id: configure.ac,v 1.26 2004-09-30 14:33:20 victor Exp $
 #
 # Process this file with autoconf to produce a configure script.
 #
 
-AC_INIT([NetXMS], [0.1.0], [NetXMS Team <bugs@netxms.org>])
+AC_INIT([NetXMS], [0.1.3], [NetXMS Team <bugs@netxms.org>])
 AC_CONFIG_AUX_DIR([config])
 AM_CONFIG_HEADER([config.h])
 AM_INIT_AUTOMAKE
@@ -204,7 +204,8 @@ AC_FUNC_STRFTIME
 AC_FUNC_STRTOD
 AC_FUNC_VPRINTF
 
-AC_CHECK_FUNCS([gettimeofday memmove memset strchr strcspn strdup strerror strrchr strtol strtoul])
+AC_CHECK_FUNCS([gettimeofday memmove memset strchr strcspn strdup strerror])
+AC_CHECK_FUNCS([strrchr strtol strtoul strtoll strtoull])
 AC_CHECK_FUNCS([if_nametoindex daemon mmap strerror_r])
 
 # --------------------------------------------------------------------------
index e747c94..7deb226 100644 (file)
@@ -30,8 +30,8 @@
 
 #define NETXMS_VERSION_MAJOR      0
 #define NETXMS_VERSION_MINOR      1
-#define NETXMS_VERSION_BUILD      2 
-#define NETXMS_VERSION_STRING     "0.1.2"
+#define NETXMS_VERSION_BUILD      3 
+#define NETXMS_VERSION_STRING     "0.1.3"
 
 
 #endif
index d4410ab..48955b4 100644 (file)
@@ -23,6 +23,6 @@
 #ifndef _netxms_db_h
 #define _netxms_db_h
 
-#define DB_FORMAT_VERSION      8
+#define DB_FORMAT_VERSION      9
 
 #endif
index 050b12c..fff589a 100644 (file)
@@ -175,12 +175,12 @@ inline void ret_uint64(TCHAR *rbuf, QWORD value)
 #endif   /* LIBNETXMS_INLINE */
 #else    /* __cplusplus */
 
-void LIBNETXMS_EXPORTABLE ret_string(TCHAR *rbuf, TCHAR *value)
-void LIBNETXMS_EXPORTABLE ret_int(TCHAR *rbuf, long value)
-void LIBNETXMS_EXPORTABLE ret_uint(TCHAR *rbuf, unsigned long value)
-void LIBNETXMS_EXPORTABLE ret_double(TCHAR *rbuf, double value)
-void LIBNETXMS_EXPORTABLE ret_int64(TCHAR *rbuf, INT64 value)
-void LIBNETXMS_EXPORTABLE ret_uint64(TCHAR *rbuf, QWORD value)
+void LIBNETXMS_EXPORTABLE ret_string(TCHAR *rbuf, TCHAR *value);
+void LIBNETXMS_EXPORTABLE ret_int(TCHAR *rbuf, long value);
+void LIBNETXMS_EXPORTABLE ret_uint(TCHAR *rbuf, unsigned long value);
+void LIBNETXMS_EXPORTABLE ret_double(TCHAR *rbuf, double value);
+void LIBNETXMS_EXPORTABLE ret_int64(TCHAR *rbuf, INT64 value);
+void LIBNETXMS_EXPORTABLE ret_uint64(TCHAR *rbuf, QWORD value);
 
 #endif   /* __cplusplus */
 
index 1eeb2cd..d6de4ba 100644 (file)
@@ -35,6 +35,7 @@
 #include <ctype.h>
 #include <stdio.h>
 #include <string.h>
+#include <limits.h>
 
 #include <netxms-version.h>
 
 #define INVALID_POINTER_VALUE    ((void *)0xFFFFFFFF)
 #define MAX_DB_STRING            256
 
+#ifndef LLONG_MAX
+#define LLONG_MAX    9223372036854775807
+#endif
+
+#ifndef LLONG_MIN
+#define LLONG_MIN    (-LLONG_MAX - 1)
+#endif
+
+#ifndef ULLONG_MAX
+#define ULLONG_MAX   18446744073709551615
+#endif
+
 
 //
 // Platform dependent includes and defines
index ad22739..cfd60e8 100644 (file)
@@ -372,6 +372,7 @@ typedef struct
 #define VID_DESTINATION_OBJECT_ID   ((DWORD)110)
 #define VID_NUM_ITEMS               ((DWORD)111)
 #define VID_ITEM_LIST               ((DWORD)112)
+#define VID_MAC_ADDR                ((DWORD)113)
 
 // Variable ranges for object's ACL
 #define VID_ACL_USER_BASE           ((DWORD)0x00001000)
@@ -414,10 +415,14 @@ typedef struct
 // Inline functions
 //
 
+#ifdef __cplusplus
+
 inline BOOL IsBinaryMsg(CSCP_MESSAGE *pMsg)
 {
    return ntohs(pMsg->wFlags) & MF_BINARY;
 }
 
+#endif
+
 
 #endif   /* _nms_cscp_h_ */
index 3be01a8..6ef0c9e 100644 (file)
@@ -36,7 +36,6 @@
 
 #include <nms_common.h>
 #include <nms_cscp.h>
-#include <nms_threads.h>
 #include <time.h>
 
 #if HAVE_BYTESWAP_H
@@ -139,8 +138,10 @@ inline void GetSystemTimeAsFileTime(LPFILETIME pFt)
 #define ntohd(x) (x)
 #endif
 
+#ifdef __cplusplus
 extern "C"
 {
+#endif
 #if defined(_WIN32) || !(HAVE_DECL___BSWAP_64)
    QWORD LIBNETXMS_EXPORTABLE __bswap_64(QWORD qwVal);
 #endif
@@ -157,6 +158,9 @@ extern "C"
 
    void LIBNETXMS_EXPORTABLE *nx_memdup(const void *pData, DWORD dwSize);
 
+   void LIBNETXMS_EXPORTABLE BinToStr(BYTE *pData, DWORD dwSize, char *pStr);
+   DWORD LIBNETXMS_EXPORTABLE StrToBin(char *pStr, BYTE *pData, DWORD dwSize);
+
    void LIBNETXMS_EXPORTABLE StrStrip(TCHAR *pszStr);
    BOOL LIBNETXMS_EXPORTABLE MatchString(const TCHAR *pattern, const TCHAR *string, BOOL matchCase);
    TCHAR LIBNETXMS_EXPORTABLE *ExtractWord(TCHAR *line, TCHAR *buffer);
@@ -198,6 +202,16 @@ extern "C"
                                                 int cchByteChar, WCHAR *pWideCharStr, 
                                                 int cchWideChar);
 #endif
+
+#if !(HAVE_STRTOLL)
+   INT64 LIBNETXMS_EXPORTABLE strtoll(const char *nptr, char **endptr, int base);
+#endif
+#if !(HAVE_STRTOULL)
+   QWORD LIBNETXMS_EXPORTABLE strtoull(const char *nptr, char **endptr, int base);
+#endif
+
+#ifdef __cplusplus
 }
+#endif
 
 #endif   /* _nms_util_h_ */
index 7170bd8..e2b525f 100644 (file)
@@ -68,6 +68,7 @@ typedef unsigned long HREQUEST;
 #define OBJECT_STATUS_COUNT      9
 #define MAX_RCPT_ADDR_LEN        256
 #define MAX_EMAIL_SUBJECT_LEN    256
+#define MAC_ADDR_LENGTH          6
 
 
 //
@@ -108,6 +109,8 @@ typedef unsigned long HREQUEST;
 #define OBJECT_CONTAINER      5
 #define OBJECT_ZONE           6
 #define OBJECT_SERVICEROOT    7
+#define OBJECT_TEMPLATE       8
+#define OBJECT_TEMPLATE_GROUP 9
 
 
 //
@@ -537,6 +540,7 @@ typedef struct
          DWORD dwIpNetMask;   // Ip netmask.
          DWORD dwIfIndex;     // Interface index.
          DWORD dwIfType;      // Interface type
+         BYTE bMacAddr[MAC_ADDR_LENGTH];
       } iface;
       struct
       {
index b06dfdc..b71ff17 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef _nxcscpapi_h_
 #define _nxcscpapi_h_
 
+#include <nms_threads.h>
+
 
 #ifdef _WIN32
 #ifdef LIBNXCSCP_EXPORTS
index f581389..217b374 100644 (file)
@@ -77,5 +77,6 @@
 #define EVENT_THREAD_HANGS       20
 #define EVENT_THREAD_RUNNING     21
 #define EVENT_SMTP_FAILURE       22
+#define EVENT_MAC_ADDR_CHANGED   23
 
 #endif
index a80ddcc..3d18bd4 100644 (file)
@@ -234,6 +234,19 @@ INSERT INTO events (event_id,name,severity,flags,message,description) VALUES
                '   3) Recipient address#0D#0A' CONCAT
                '   4) Mail subject'
        );
+INSERT INTO events (event_id,name,severity,flags,message,description) VALUES
+       (
+               EVENT_MAC_ADDR_CHANGED, 'SYS_MAC_ADDR_CHANGED', 
+               EVENT_SEVERITY_WARNING, 1,
+               'MAC address for interface %3 changed from %4 to %5',
+               'Generated when server detects change of interface#27s MAC address.#0D#0A' CONCAT
+               'Parameters:#0D#0A' CONCAT
+               '   1) Interface object ID#0D#0A' CONCAT
+               '   2) Interface index#0D#0A' CONCAT
+               '   3) Interface name#0D#0A' CONCAT
+               '   4) Old MAC address#0D#0A' CONCAT
+               '   5) New MAC address'
+       );
 
 
 /*
index 33321d6..f46670b 100644 (file)
@@ -148,6 +148,7 @@ CREATE TABLE interfaces
        if_type integer,
        if_index integer,
        image_id integer,
+       mac_addr varchar(15),
        PRIMARY KEY(id)
 );
 
index b1c6e48..031f3bc 100644 (file)
@@ -76,6 +76,7 @@ LONG H_InterfaceList(char *cmd, char *arg, NETXMS_VALUES_LIST *value)
    IP_ADAPTER_INFO *pBuffer, *pInfo;
    LONG iResult = SYSINFO_RC_SUCCESS;
    char szAdapterName[MAX_OBJECT_NAME], szBuffer[256];
+   char szMacAddr[MAX_ADAPTER_ADDRESS_LENGTH * 2 + 1];
    IP_ADDR_STRING *pAddr;
 
    if (GetAdaptersInfo(NULL, &dwSize) != ERROR_BUFFER_OVERFLOW)
@@ -110,13 +111,15 @@ LONG H_InterfaceList(char *cmd, char *arg, NETXMS_VALUES_LIST *value)
             strncpy(szAdapterName, pInfo->AdapterName, MAX_OBJECT_NAME);
          }
 
+         BinToStr(pInfo->Address, pInfo->AddressLength, szMacAddr);
+
          // Compose result string for each ip address
          for(pAddr = &pInfo->IpAddressList; pAddr != NULL; pAddr = pAddr->Next)
          {
-            sprintf(szBuffer, "%d %s/%d %d %s", pInfo->Index, 
+            sprintf(szBuffer, "%d %s/%d %d %s %s", pInfo->Index, 
                     pAddr->IpAddress.String, 
                     BitsInMask(inet_addr(pAddr->IpMask.String)),
-                    pInfo->Type, szAdapterName);
+                    pInfo->Type, szMacAddr, szAdapterName);
             NxAddResultString(value, szBuffer);
          }
       }
index 63dbd90..e30cf51 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <nms_common.h>
 #include <nms_util.h>
+#include <nms_threads.h>
 #include <nms_agent.h>
 #include <nms_cscp.h>
 #include <stdio.h>
@@ -48,7 +49,7 @@
 #else
 #define DEBUG_SUFFIX
 #endif
-#define AGENT_VERSION_STRING  NETXMS_VERSION_STRING ".1-alpha1" DEBUG_SUFFIX
+#define AGENT_VERSION_STRING  NETXMS_VERSION_STRING DEBUG_SUFFIX
 
 
 //
index c58c6df..026daf2 100644 (file)
@@ -148,6 +148,11 @@ void CObjectInfoBox::OnPaint()
                                  "Unknown" : g_szInterfaceTypes[m_pCurrObject->iface.dwIfType]);
             dc.TextOut(X_MARGIN, cy, szBuffer, strlen(szBuffer));
             cy += step;
+
+            strcpy(szBuffer, "MAC: ");
+            BinToStr(m_pCurrObject->iface.bMacAddr, MAC_ADDR_LENGTH, &szBuffer[5]);
+            dc.TextOut(X_MARGIN, cy, szBuffer, strlen(szBuffer));
+            cy += step;
             break;
          default:
             break;
index 8d6fb8e..b04d7cf 100644 (file)
@@ -65,7 +65,8 @@ CImageList *g_pObjectNormalImageList = NULL;
 
 char *g_szStatusText[] = { "NORMAL", "WARNING", "MINOR", "MAJOR", "CRITICAL", "UNKNOWN", "UNMANAGED", "DISABLED", "TESTING" };
 char *g_szStatusTextSmall[] = { "Normal", "Warning", "Minor", "Major", "Critical", "Unknown", "Unmanaged", "Disabled", "Testing" };
-char *g_szObjectClass[] = { "Generic", "Subnet", "Node", "Interface", "Network", "Container", "Zone", "ServiceRoot" };
+char *g_szObjectClass[] = { "Generic", "Subnet", "Node", "Interface", "Network", 
+                            "Container", "Zone", "ServiceRoot", "Template", "TemplateGroup" };
 char *g_szActionType[] = { "Execute", "Remote", "E-Mail", "SMS" };
 char *g_szInterfaceTypes[] = {
    "Unknown",
index 57ec906..99e92a1 100644 (file)
@@ -1,5 +1,5 @@
 INCLUDES=-I@top_srcdir@/include
 
 lib_LTLIBRARIES = libnetxms.la
-libnetxms_la_SOURCES = config.cpp dload.cpp hash.cpp icmp.cpp inline.cpp main.cpp md5.cpp sha1.cpp tools.cpp unicode.cpp
+libnetxms_la_SOURCES = config.cpp dload.cpp hash.cpp icmp.cpp inline.cpp main.cpp md5.cpp sha1.cpp strtoll.c strtoull.c tools.cpp unicode.cpp
 libnetxms_la_LDFLAGS = -version-info $(LIBNETXMS_LIBRARY_VERSION)
index 6631a5d..4bdc504 100644 (file)
@@ -21,6 +21,7 @@
 **/
 
 #include "libnetxms.h"
+#include <nms_threads.h>
 
 
 //
index d9e5b22..dec68ef 100644 (file)
@@ -138,6 +138,14 @@ SOURCE=.\sha1.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\strtoll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strtoull.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\tools.cpp
 # End Source File
 # Begin Source File
diff --git a/src/libnetxms/strtoll.c b/src/libnetxms/strtoll.c
new file mode 100644 (file)
index 0000000..87e062b
--- /dev/null
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if !(HAVE_STRTOLL)
+
+#include "libnetxms.h"
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a long long.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+
+INT64 LIBNETXMS_EXPORTABLE strtoll(const char *nptr, char **endptr, int base)
+{
+       const char *s;
+       INT64 acc, cutoff;
+       int c;
+       int neg, any, cutlim;
+
+       /*
+        * Skip white space and pick up leading +/- sign if any.
+        * If base is 0, allow 0x for hex and 0 for octal, else
+        * assume decimal; if base is already 16, allow 0x.
+        */
+       s = nptr;
+       do {
+               c = (unsigned char) *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else {
+               neg = 0;
+               if (c == '+')
+                       c = *s++;
+       }
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+
+       /*
+        * Compute the cutoff value between legal numbers and illegal
+        * numbers.  That is the largest legal value, divided by the
+        * base.  An input number that is greater than this value, if
+        * followed by a legal input character, is too big.  One that
+        * is equal to this value may be valid or not; the limit
+        * between valid and invalid numbers is then based on the last
+        * digit.  For instance, if the range for long longs is
+        * [-9223372036854775808..9223372036854775807] and the input base
+        * is 10, cutoff will be set to 922337203685477580 and cutlim to
+        * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+        * accumulated a value > 922337203685477580, or equal but the
+        * next digit is > 7 (or 8), the number is too big, and we will
+        * return a range error.
+        *
+        * Set any if any `digits' consumed; make it negative to indicate
+        * overflow.
+        */
+       cutoff = neg ? LLONG_MIN : LLONG_MAX;
+       cutlim = (int)(cutoff % base);
+       cutoff /= base;
+       if (neg) {
+               if (cutlim > 0) {
+                       cutlim -= base;
+                       cutoff += 1;
+               }
+               cutlim = -cutlim;
+       }
+       for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0)
+                       continue;
+               if (neg) {
+                       if (acc < cutoff || (acc == cutoff && c > cutlim)) {
+                               any = -1;
+                               acc = LLONG_MIN;
+                               errno = ERANGE;
+                       } else {
+                               any = 1;
+                               acc *= base;
+                               acc -= c;
+                       }
+               } else {
+                       if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+                               any = -1;
+                               acc = LLONG_MAX;
+                               errno = ERANGE;
+                       } else {
+                               any = 1;
+                               acc *= base;
+                               acc += c;
+                       }
+               }
+       }
+       if (endptr != 0)
+               *endptr = (char *) (any ? s - 1 : nptr);
+       return (acc);
+}
+
+#endif   /* !(HAVE_STRTOLL) */
diff --git a/src/libnetxms/strtoull.c b/src/libnetxms/strtoull.c
new file mode 100644 (file)
index 0000000..ea67272
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if !(HAVE_STRTOULL)
+
+#include "libnetxms.h"
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an 64 bit unsigned integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+
+QWORD LIBNETXMS_EXPORTABLE strtoull(const char *nptr, char **endptr, int base)
+{
+       const char *s;
+       QWORD acc, cutoff;
+       int c;
+       int neg, any, cutlim;
+
+       /*
+        * See strtoq for comments as to the logic used.
+        */
+       s = nptr;
+       do {
+               c = (unsigned char) *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else { 
+               neg = 0;
+               if (c == '+')
+                       c = *s++;
+       }
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+
+       cutoff = ULLONG_MAX / (QWORD)base;
+       cutlim = (int)(ULLONG_MAX % (QWORD)base);
+       for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0)
+                       continue;
+               if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+                       any = -1;
+                       acc = ULLONG_MAX;
+                       errno = ERANGE;
+               } else {
+                       any = 1;
+                       acc *= (QWORD)base;
+                       acc += c;
+               }
+       }
+       if (neg && any > 0)
+               acc = ~acc + 1;
+       if (endptr != 0)
+               *endptr = (char *) (any ? s - 1 : nptr);
+       return (acc);
+}
+
+#endif   /* !(HAVE_STRTOULL) */
index caf2b1f..d6b3877 100644 (file)
@@ -419,3 +419,42 @@ BOOL LIBNETXMS_EXPORTABLE IsValidObjectName(TCHAR *pszName)
    static TCHAR szValidCharacters[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_- @()./");
    return (pszName[0] != 0) && (_tcsspn(pszName, szValidCharacters) == _tcslen(pszName));
 }
+
+
+//
+// Convert byte array to text representation
+//
+
+void LIBNETXMS_EXPORTABLE BinToStr(BYTE *pData, DWORD dwSize, char *pStr)
+{
+   DWORD i;
+   char *pCurr;
+
+   for(i = 0, pCurr = pStr; i < dwSize; i++)
+   {
+      *pCurr++ = bin2hex(pData[i] >> 4);
+      *pCurr++ = bin2hex(pData[i] & 15);
+   }
+   *pCurr = 0;
+}
+
+
+//
+// Convert string of hexadecimal digits to byte array
+//
+
+DWORD LIBNETXMS_EXPORTABLE StrToBin(char *pStr, BYTE *pData, DWORD dwSize)
+{
+   DWORD i;
+   char *pCurr;
+
+   memset(pData, 0, dwSize);
+   for(i = 0, pCurr = pStr; (i < dwSize) && (*pCurr != 0); i++)
+   {
+      pData[i] = hex2bin(*pCurr) << 4;
+      pCurr++;
+      pData[i] |= hex2bin(*pCurr);
+      pCurr++;
+   }
+   return i;
+}
index fb9da7f..8b45ceb 100644 (file)
@@ -191,6 +191,7 @@ static NXC_OBJECT *NewObjectFromMsg(CSCPMessage *pMsg)
          pObject->iface.dwIpNetMask = pMsg->GetVariableLong(VID_IP_NETMASK);
          pObject->iface.dwIfIndex = pMsg->GetVariableLong(VID_IF_INDEX);
          pObject->iface.dwIfType = pMsg->GetVariableLong(VID_IF_TYPE);
+         pMsg->GetVariableBinary(VID_MAC_ADDR, pObject->iface.bMacAddr, MAC_ADDR_LENGTH);
          break;
       case OBJECT_NODE:
          pObject->node.dwFlags = pMsg->GetVariableLong(VID_FLAGS);
index bfee0cc..35e823c 100644 (file)
@@ -47,7 +47,7 @@ static THREAD_RESULT THREAD_CALL DataCollector(void *pArg)
    while(!ShutdownInProgress())
    {
       pItem = (DCItem *)m_pItemQueue->GetOrBlock();
-      pNode = pItem->RelatedNode();
+      pNode = (Node *)pItem->RelatedNode();
       if (pNode != NULL)
       {
          switch(pItem->DataSource())
index 782b047..bcb1eb6 100644 (file)
@@ -219,6 +219,25 @@ DWORD DBGetFieldULong(DB_RESULT hResult, int iRow, int iColumn)
 
 
 //
+// Get field's value as unsigned 64-bit int
+//
+
+QWORD DBGetFieldUQuad(DB_RESULT hResult, int iRow, int iColumn)
+{
+   INT64 iVal;
+   QWORD qwVal;
+   char *szVal;
+
+   szVal = DBGetField(hResult, iRow, iColumn);
+   if (szVal == NULL)
+      return 0;
+   iVal = strtoll(szVal, NULL, 10);
+   memcpy(&qwVal, &iVal, sizeof(INT64));   // To prevent possible conversion
+   return qwVal;
+}
+
+
+//
 // Get field's value as signed long
 //
 
@@ -232,6 +251,19 @@ long DBGetFieldLong(DB_RESULT hResult, int iRow, int iColumn)
 
 
 //
+// Get field's value as signed 64-bit int
+//
+
+INT64 DBGetFieldQuad(DB_RESULT hResult, int iRow, int iColumn)
+{
+   char *szVal;
+
+   szVal = DBGetField(hResult, iRow, iColumn);
+   return szVal == NULL ? 0 : strtoll(szVal, NULL, 10);
+}
+
+
+//
 // Get field's value as double
 //
 
@@ -319,6 +351,24 @@ DWORD DBGetFieldAsyncULong(DB_ASYNC_RESULT hResult, int iColumn)
 
 
 //
+// Get field's value as unsigned 64-bit int from asynchronous SELECT result
+//
+
+QWORD DBGetFieldAsyncUQuad(DB_ASYNC_RESULT hResult, int iColumn)
+{
+   INT64 iVal;
+   QWORD qwVal;
+   char szBuffer[64];
+
+   if (DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL)
+      return 0;
+   iVal = strtoll(szBuffer, NULL, 10);
+   memcpy(&qwVal, &iVal, sizeof(INT64));   // To prevent possible conversion
+   return qwVal;
+}
+
+
+//
 // Get field's value as signed long from asynchronous SELECT result
 //
 
@@ -331,6 +381,18 @@ long DBGetFieldAsyncLong(DB_RESULT hResult, int iColumn)
 
 
 //
+// Get field's value as signed 64-bit int from asynchronous SELECT result
+//
+
+INT64 DBGetFieldAsyncQuad(DB_RESULT hResult, int iColumn)
+{
+   char szBuffer[64];
+   
+   return DBGetFieldAsync(hResult, iColumn, szBuffer, 64) == NULL ? 0 : strtoll(szBuffer, NULL, 10);
+}
+
+
+//
 // Get field's value as signed long from asynchronous SELECT result
 //
 
index c4f97c8..20a56cf 100644 (file)
@@ -95,7 +95,7 @@ DCItem::DCItem(const DCItem *pSrc)
 // delta_calculation,transformation,template_id,description
 //
 
-DCItem::DCItem(DB_RESULT hResult, int iRow, Node *pNode)
+DCItem::DCItem(DB_RESULT hResult, int iRow, Template *pNode)
 {
    m_dwId = DBGetFieldULong(hResult, iRow, 0);
    strncpy(m_szName, DBGetField(hResult, iRow, 1), MAX_ITEM_NAME);
@@ -125,7 +125,7 @@ DCItem::DCItem(DB_RESULT hResult, int iRow, Node *pNode)
 //
 
 DCItem::DCItem(DWORD dwId, char *szName, int iSource, int iDataType, 
-               int iPollingInterval, int iRetentionTime, Node *pNode)
+               int iPollingInterval, int iRetentionTime, Template *pNode)
 {
    m_dwId = dwId;
    m_dwTemplateId = 0;
index 18e31b4..a7c8267 100644 (file)
@@ -113,10 +113,10 @@ void Threshold::UpdateBinaryValueFromString(void)
          m_value.dwUInt = strtoul(m_pszValueStr, NULL, 0);
          break;
       case DCI_DT_INT64:
-         /* TODO: add 64-bit string to binary conversion */
+         m_value.iInt64 = strtoll(m_pszValueStr, NULL, 0);
          break;
       case DCI_DT_UINT64:
-         /* TODO: add 64-bit string to binary conversion */
+         m_value.qwUInt64 = strtoull(m_pszValueStr, NULL, 0);
          break;
       case DCI_DT_FLOAT:
          m_value.dFloat = strtod(m_pszValueStr, NULL);
index 433653d..4648d26 100644 (file)
@@ -44,12 +44,11 @@ ItemValue::ItemValue()
 
 ItemValue::ItemValue(const char *pszValue)
 {
-   /* TODO: add 64-bit conversion !!! */
    strncpy(m_szString, pszValue, MAX_DB_STRING);
    m_iInt32 = strtol(m_szString, NULL, 0);
-   m_iInt64 = 0;
+   m_iInt64 = strtoll(m_szString, NULL, 0);
    m_dwInt32 = strtoul(m_szString, NULL, 0);
-   m_qwInt64 = 0;
+   m_qwInt64 = strtoull(m_szString, NULL, 0);
    m_dFloat = strtod(m_szString, NULL);
 }
 
index 0f0bbc0..0c236f9 100644 (file)
@@ -48,6 +48,7 @@ Interface::Interface(DWORD dwAddr, DWORD dwNetMask)
    m_dwIpNetMask = dwNetMask;
    m_dwIfIndex = 1;
    m_dwIfType = IFTYPE_OTHER;
+   memset(m_bMacAddr, 0, MAC_ADDR_LENGTH);
 }
 
 
@@ -63,6 +64,7 @@ Interface::Interface(char *szName, DWORD dwIndex, DWORD dwAddr, DWORD dwNetMask,
    m_dwIfType = dwType;
    m_dwIpAddr = dwAddr;
    m_dwIpNetMask = dwNetMask;
+   memset(m_bMacAddr, 0, MAC_ADDR_LENGTH);
 }
 
 
@@ -88,7 +90,7 @@ BOOL Interface::CreateFromDB(DWORD dwId)
    BOOL bResult = FALSE;
 
    sprintf(szQuery, "SELECT id,name,status,ip_addr,ip_netmask,if_type,if_index,node_id,"
-                    "image_id,is_deleted FROM interfaces WHERE id=%d", dwId);
+                    "image_id,is_deleted,mac_addr FROM interfaces WHERE id=%d", dwId);
    hResult = DBSelect(g_hCoreDB, szQuery);
    if (hResult == NULL)
       return FALSE;     // Query failed
@@ -105,6 +107,7 @@ BOOL Interface::CreateFromDB(DWORD dwId)
       dwNodeId = DBGetFieldULong(hResult, 0, 7);
       m_dwImageId = DBGetFieldULong(hResult, 0, 8);
       m_bIsDeleted = DBGetFieldLong(hResult, 0, 9);
+      StrToBin(DBGetField(hResult, 0, 10), m_bMacAddr, MAC_ADDR_LENGTH);
 
       // Link interface to node
       if (!m_bIsDeleted)
@@ -146,7 +149,7 @@ BOOL Interface::CreateFromDB(DWORD dwId)
 
 BOOL Interface::SaveToDB(void)
 {
-   char szQuery[1024];
+   char szQuery[1024], szMacStr[16];
    BOOL bNewObject = TRUE;
    DWORD dwNodeId;
    DB_RESULT hResult;
@@ -171,18 +174,19 @@ BOOL Interface::SaveToDB(void)
       dwNodeId = 0;
 
    // Form and execute INSERT or UPDATE query
+   BinToStr(m_bMacAddr, MAC_ADDR_LENGTH, szMacStr);
    if (bNewObject)
       sprintf(szQuery, "INSERT INTO interfaces (id,name,status,is_deleted,ip_addr,"
-                       "ip_netmask,node_id,if_type,if_index,image_id) "
-                       "VALUES (%ld,'%s',%d,%d,%ld,%ld,%ld,%ld,%ld,%ld)",
+                       "ip_netmask,node_id,if_type,if_index,image_id,mac_addr) "
+                       "VALUES (%ld,'%s',%d,%d,%ld,%ld,%ld,%ld,%ld,%ld,'%s')",
               m_dwId, m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr, m_dwIpNetMask, dwNodeId,
-              m_dwIfType, m_dwIfIndex, m_dwImageId);
+              m_dwIfType, m_dwIfIndex, m_dwImageId, szMacStr);
    else
       sprintf(szQuery, "UPDATE interfaces SET name='%s',status=%d,is_deleted=%d,"
                        "ip_addr=%ld,ip_netmask=%ld,node_id=%ld,if_type=%ld,"
-                       "if_index=%ld,image_id=%ld WHERE id=%ld",
+                       "if_index=%ld,image_id=%ld,mac_addr='%s' WHERE id=%ld",
               m_szName, m_iStatus, m_bIsDeleted, m_dwIpAddr, m_dwIpNetMask, dwNodeId,
-              m_dwIfType, m_dwIfIndex, m_dwImageId, m_dwId);
+              m_dwIfType, m_dwIfIndex, m_dwImageId, szMacStr, m_dwId);
    DBQuery(g_hCoreDB, szQuery);
 
    // Save access list
@@ -260,4 +264,5 @@ void Interface::CreateMessage(CSCPMessage *pMsg)
    pMsg->SetVariable(VID_IF_INDEX, m_dwIfIndex);
    pMsg->SetVariable(VID_IF_TYPE, m_dwIfType);
    pMsg->SetVariable(VID_IP_NETMASK, m_dwIpNetMask);
+   pMsg->SetVariable(VID_MAC_ADDR, m_bMacAddr, MAC_ADDR_LENGTH);
 }
index aabb33e..5a6937f 100644 (file)
@@ -57,7 +57,7 @@
 // Convert string representation of MAC address to binary form
 //
 
-static void StrToMac(char *pszStr, BYTE *pBuffer)
+void StrToMac(char *pszStr, BYTE *pBuffer)
 {
    DWORD byte1, byte2, byte3, byte4, byte5, byte6;
 
index d3b52e0..10613d0 100644 (file)
@@ -243,6 +243,10 @@ SOURCE=.\syncer.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\template.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\tools.cpp
 # End Source File
 # Begin Source File
@@ -271,6 +275,10 @@ SOURCE=..\include\local_admin.h
 # End Source File
 # Begin Source File
 
+SOURCE="..\..\..\include\netxms-version.h"
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\..\include\netxmsdb.h
 # End Source File
 # Begin Source File
@@ -345,6 +353,10 @@ SOURCE=..\..\..\include\nximage.h
 
 SOURCE=..\..\..\include\nxqueue.h
 # End Source File
+# Begin Source File
+
+SOURCE=..\include\nxsrvapi.h
+# End Source File
 # End Group
 # Begin Group "Resource Files"
 
index 1862324..347f38c 100644 (file)
@@ -363,12 +363,16 @@ DB_ASYNC_RESULT DBAsyncSelect(DB_HANDLE hConn, char *szQuery);
 BOOL DBFetch(DB_ASYNC_RESULT hResult);
 char *DBGetField(DB_RESULT hResult, int iRow, int iColumn);
 long DBGetFieldLong(DB_RESULT hResult, int iRow, int iColumn);
-double DBGetFieldDouble(DB_RESULT hResult, int iRow, int iColumn);
 DWORD DBGetFieldULong(DB_RESULT hResult, int iRow, int iColumn);
+INT64 DBGetFieldQuad(DB_RESULT hResult, int iRow, int iColumn);
+QWORD DBGetFieldUQuad(DB_RESULT hResult, int iRow, int iColumn);
+double DBGetFieldDouble(DB_RESULT hResult, int iRow, int iColumn);
 char *DBGetFieldAsync(DB_ASYNC_RESULT hResult, int iColumn, char *pBuffer, int iBufSize);
 long DBGetFieldAsyncLong(DB_RESULT hResult, int iColumn);
-double DBGetFieldAsyncDouble(DB_RESULT hResult, int iColumn);
 DWORD DBGetFieldAsyncULong(DB_ASYNC_RESULT hResult, int iColumn);
+INT64 DBGetFieldAsyncQuad(DB_RESULT hResult, int iColumn);
+QWORD DBGetFieldAsyncUQuad(DB_ASYNC_RESULT hResult, int iColumn);
+double DBGetFieldAsyncDouble(DB_RESULT hResult, int iColumn);
 int DBGetNumRows(DB_RESULT hResult);
 void DBFreeResult(DB_RESULT hResult);
 void DBFreeAsyncResult(DB_ASYNC_RESULT hResult);
@@ -386,6 +390,7 @@ BOOL SnmpEnumerate(DWORD dwAddr, const char *szCommunity, const char *szRootOid,
                    void (* pHandler)(DWORD, const char *, variable_list *, void *), 
                    void *pUserArg, BOOL bVerbose);
 void OidToStr(oid *pOid, int iOidLen, char *szBuffer, DWORD dwBufferSize);
+void StrToMac(char *pszStr, BYTE *pBuffer);
 
 ARP_CACHE *GetLocalArpCache(void);
 ARP_CACHE *SnmpGetArpCache(DWORD dwAddr, const char *szCommunity);
@@ -405,9 +410,6 @@ NetObj *PollNewNode(DWORD dwIpAddr, DWORD dwNetMask, DWORD dwFlags, TCHAR *pszNa
 void EnumerateClientSessions(void (*pHandler)(ClientSession *, void *), void *pArg);
 void NotifyClient(ClientSession *pSession, void *pArg);
 
-void BinToStr(BYTE *pData, DWORD dwSize, char *pStr);
-DWORD StrToBin(char *pStr, BYTE *pData, DWORD dwSize);
-
 void GetSysInfoStr(char *pszBuffer);
 DWORD GetLocalIpAddr(void);
 
index a0e12d9..72dc597 100644 (file)
@@ -135,7 +135,7 @@ public:
 // Data collection item class
 //
 
-class Node;
+class Template;
 
 class DCItem
 {
@@ -154,7 +154,7 @@ private:
    DWORD m_dwTemplateId;      // Related template's id
    DWORD m_dwNumThresholds;
    Threshold **m_ppThresholdList;
-   Node *m_pNode;             // Pointer to node object this item related to
+   Template *m_pNode;             // Pointer to node or template object this item related to
    char *m_pszFormula;        // Transformation formula
    MUTEX m_hMutex;
    DWORD m_dwCacheSize;       // Number of items in cache
@@ -170,9 +170,9 @@ private:
 public:
    DCItem();
    DCItem(const DCItem *pItem);
-   DCItem(DB_RESULT hResult, int iRow, Node *pNode);
+   DCItem(DB_RESULT hResult, int iRow, Template *pNode);
    DCItem(DWORD dwId, char *szName, int iSource, int iDataType, 
-          int iPollingInterval, int iRetentionTime, Node *pNode);
+          int iPollingInterval, int iRetentionTime, Template *pNode);
    ~DCItem();
 
    BOOL SaveToDB(void);
@@ -183,7 +183,7 @@ public:
    int DataSource(void) { return m_iSource; }
    int DataType(void) { return m_iDataType; }
    const char *Name(void) { return m_szName; }
-   Node *RelatedNode(void) { return m_pNode; }
+   Template *RelatedNode(void) { return m_pNode; }
 
    BOOL ReadyForPolling(time_t currTime) 
    { 
index e4e2b45..d12731f 100644 (file)
@@ -163,6 +163,43 @@ public:
 
 
 //
+// Node template class
+//
+
+class Template : public NetObj
+{
+protected:
+   DWORD m_dwNumItems;     // Number of data collection items
+   DCItem **m_ppItems;     // Data collection items
+   DWORD m_dwDCILockStatus;
+
+   void LoadItemsFromDB(void);
+   void DestroyItems(void);
+
+public:
+   Template();
+   virtual ~Template();
+
+   virtual int Type(void) { return OBJECT_NODE; }
+
+   virtual BOOL SaveToDB(void);
+   virtual BOOL DeleteFromDB(void);
+   virtual BOOL CreateFromDB(DWORD dwId);
+
+   BOOL AddItem(DCItem *pItem);
+   BOOL UpdateItem(DWORD dwItemId, CSCPMessage *pMsg, DWORD *pdwNumMaps, 
+                   DWORD **ppdwMapIndex, DWORD **ppdwMapId);
+   BOOL DeleteItem(DWORD dwItemId);
+   int GetItemType(DWORD dwItemId);
+   const DCItem *GetItemById(DWORD dwItemId);
+   BOOL LockDCIList(DWORD dwSessionId);
+   BOOL UnlockDCIList(DWORD dwSessionId);
+   void SendItemsToClient(ClientSession *pSession, DWORD dwRqId);
+   BOOL IsLockedBySession(DWORD dwSessionId) { return m_dwDCILockStatus == dwSessionId; }
+};
+
+
+//
 // Interface class
 //
 
@@ -172,6 +209,7 @@ protected:
    DWORD m_dwIfIndex;
    DWORD m_dwIfType;
    DWORD m_dwIpNetMask;
+   BYTE m_bMacAddr[MAC_ADDR_LENGTH];
 
 public:
    Interface();
@@ -184,8 +222,11 @@ public:
    virtual BOOL DeleteFromDB(void);
    virtual BOOL CreateFromDB(DWORD dwId);
 
+   void SetMacAddr(BYTE *pbNewMac) { memcpy(m_bMacAddr, pbNewMac, MAC_ADDR_LENGTH); Modify(); }
+
    DWORD IpNetMask(void) { return m_dwIpNetMask; }
    DWORD IfIndex(void) { return m_dwIfIndex; }
+   const BYTE *MacAddr(void) { return m_bMacAddr; }
 
    void StatusPoll(ClientSession *pSession, DWORD dwRqId);
    virtual void CreateMessage(CSCPMessage *pMsg);
@@ -196,7 +237,7 @@ public:
 // Node
 //
 
-class Node : public NetObj
+class Node : public Template
 {
 protected:
    DWORD m_dwFlags;
@@ -215,9 +256,6 @@ protected:
    int m_iNativeAgentFails;
    MUTEX m_hPollerMutex;
    MUTEX m_hAgentAccessMutex;
-   DWORD m_dwNumItems;     // Number of data collection items
-   DCItem **m_ppItems;     // Data collection items
-   DWORD m_dwDCILockStatus;
    AgentConnection *m_pAgentConnection;
 
    void PollerLock(void) { MutexLock(m_hPollerMutex, INFINITE); }
@@ -226,9 +264,6 @@ protected:
    void AgentLock(void) { MutexLock(m_hAgentAccessMutex, INFINITE); }
    void AgentUnlock(void) { MutexUnlock(m_hAgentAccessMutex); }
 
-   void LoadItemsFromDB(void);
-   void DestroyItems(void);
-
 public:
    Node();
    Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags);
@@ -247,12 +282,13 @@ public:
    BOOL IsNativeAgent(void) { return m_dwFlags & NF_IS_NATIVE_AGENT ? TRUE : FALSE; }
    BOOL IsBridge(void) { return m_dwFlags & NF_IS_BRIDGE ? TRUE : FALSE; }
    BOOL IsRouter(void) { return m_dwFlags & NF_IS_ROUTER ? TRUE : FALSE; }
-   BOOL IsLocalManagenet(void) { return m_dwFlags & NF_IS_LOCAL_MGMT ? TRUE : FALSE; }
+   BOOL IsLocalManagement(void) { return m_dwFlags & NF_IS_LOCAL_MGMT ? TRUE : FALSE; }
 
    const char *ObjectId(void) { return m_szObjectId; }
 
    void AddInterface(Interface *pInterface) { AddChild(pInterface); pInterface->AddParent(this); }
-   void CreateNewInterface(DWORD dwAddr, DWORD dwNetMask, char *szName = NULL, DWORD dwIndex = 0, DWORD dwType = 0);
+   void CreateNewInterface(DWORD dwAddr, DWORD dwNetMask, char *szName = NULL, 
+                           DWORD dwIndex = 0, DWORD dwType = 0, BYTE *pbMacAddr = NULL);
    void DeleteInterface(Interface *pInterface);
 
    BOOL NewNodePoll(DWORD dwNetMask);
@@ -270,17 +306,6 @@ public:
 
    virtual void CalculateCompoundStatus(void);
 
-   BOOL AddItem(DCItem *pItem);
-   BOOL UpdateItem(DWORD dwItemId, CSCPMessage *pMsg, DWORD *pdwNumMaps, 
-                   DWORD **ppdwMapIndex, DWORD **ppdwMapId);
-   BOOL DeleteItem(DWORD dwItemId);
-   int GetItemType(DWORD dwItemId);
-   const DCItem *GetItemById(DWORD dwItemId);
-   BOOL LockDCIList(DWORD dwSessionId);
-   BOOL UnlockDCIList(DWORD dwSessionId);
-   void SendItemsToClient(ClientSession *pSession, DWORD dwRqId);
-   BOOL IsLockedBySession(DWORD dwSessionId) { return m_dwDCILockStatus == dwSessionId; }
-
    BOOL ConnectToAgent(void);
    DWORD GetItemFromSNMP(const char *szParam, DWORD dwBufSize, char *szBuffer);
    DWORD GetItemFromAgent(const char *szParam, DWORD dwBufSize, char *szBuffer);
@@ -418,6 +443,21 @@ public:
 
 
 //
+// Template group object
+//
+
+class TemplateGroup : public Container
+{
+public:
+   TemplateGroup() : Container() { }
+   TemplateGroup(char *pszName, char *pszDescription) : Container(pszName, 0, pszDescription) { }
+   virtual ~TemplateGroup() { }
+
+   virtual int Type(void) { return OBJECT_TEMPLATE_GROUP; }
+};
+
+
+//
 // Object index structure
 //
 
index 37d83e0..4d1c765 100644 (file)
@@ -1,6 +1,6 @@
 /* 
 ** NetXMS - Network Management System
-** Copyright (C) 2003 Victor Kirhenshtein
+** Copyright (C) 2003, 2004 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
@@ -28,7 +28,7 @@
 //
 
 Node::Node()
-     :NetObj()
+     :Template()
 {
    m_dwFlags = 0;
    m_dwDiscoveryFlags = 0;
@@ -46,10 +46,7 @@ Node::Node()
    m_iNativeAgentFails = 0;
    m_hPollerMutex = MutexCreate();
    m_hAgentAccessMutex = MutexCreate();
-   m_dwNumItems = 0;
-   m_ppItems = NULL;
    m_pAgentConnection = NULL;
-   m_dwDCILockStatus = INVALID_INDEX;
 }
 
 
@@ -58,7 +55,7 @@ Node::Node()
 //
 
 Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags)
-     :NetObj()
+     :Template()
 {
    m_dwIpAddr = dwAddr;
    m_dwFlags = dwFlags;
@@ -78,10 +75,7 @@ Node::Node(DWORD dwAddr, DWORD dwFlags, DWORD dwDiscoveryFlags)
    m_iNativeAgentFails = 0;
    m_hPollerMutex = MutexCreate();
    m_hAgentAccessMutex = MutexCreate();
-   m_dwNumItems = 0;
-   m_ppItems = NULL;
    m_pAgentConnection = NULL;
-   m_dwDCILockStatus = INVALID_INDEX;
 }
 
 
@@ -93,29 +87,12 @@ Node::~Node()
 {
    MutexDestroy(m_hPollerMutex);
    MutexDestroy(m_hAgentAccessMutex);
-   DestroyItems();
    if (m_pAgentConnection != NULL)
       delete m_pAgentConnection;
 }
 
 
 //
-// Destroy all related data collection items
-//
-
-void Node::DestroyItems(void)
-{
-   DWORD i;
-
-   for(i = 0; i < m_dwNumItems; i++)
-      delete m_ppItems[i];
-   safe_free(m_ppItems);
-   m_dwNumItems = 0;
-   m_ppItems = NULL;
-}
-
-
-//
 // Create object from database data
 //
 
@@ -228,37 +205,6 @@ BOOL Node::CreateFromDB(DWORD dwId)
 
 
 //
-// Load data collection items from database
-//
-
-void Node::LoadItemsFromDB(void)
-{
-   char szQuery[256];
-   DB_RESULT hResult;
-
-   sprintf(szQuery, "SELECT item_id,name,source,datatype,polling_interval,retention_time,"
-                    "status,delta_calculation,transformation,template_id,description "
-                    "FROM items WHERE node_id=%d", m_dwId);
-   hResult = DBSelect(g_hCoreDB, szQuery);
-
-   if (hResult != 0)
-   {
-      int i, iRows;
-
-      iRows = DBGetNumRows(hResult);
-      if (iRows > 0)
-      {
-         m_dwNumItems = iRows;
-         m_ppItems = (DCItem **)malloc(sizeof(DCItem *) * iRows);
-         for(i = 0; i < iRows; i++)
-            m_ppItems[i] = new DCItem(hResult, i, this);
-      }
-      DBFreeResult(hResult);
-   }
-}
-
-
-//
 // Save object to database
 //
 
@@ -342,7 +288,7 @@ BOOL Node::DeleteFromDB(void)
    char szQuery[256];
    BOOL bSuccess;
 
-   bSuccess = NetObj::DeleteFromDB();
+   bSuccess = Template::DeleteFromDB();
    if (bSuccess)
    {
       sprintf(szQuery, "DELETE FROM nodes WHERE id=%ld", m_dwId);
@@ -399,7 +345,8 @@ BOOL Node::NewNodePoll(DWORD dwNetMask)
                                pIfList->pInterfaces[i].dwIpNetMask,
                                pIfList->pInterfaces[i].szName,
                                pIfList->pInterfaces[i].dwIndex,
-                               pIfList->pInterfaces[i].dwType);
+                               pIfList->pInterfaces[i].dwType,
+                               pIfList->pInterfaces[i].bMacAddr);
          DestroyInterfaceList(pIfList);
       }
       else
@@ -510,7 +457,8 @@ Interface *Node::FindInterface(DWORD dwIndex, DWORD dwHostAddr)
 // Create new interface
 //
 
-void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName, DWORD dwIndex, DWORD dwType)
+void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName, 
+                              DWORD dwIndex, DWORD dwType, BYTE *pbMacAddr)
 {
    Interface *pInterface;
    Subnet *pSubnet;
@@ -520,6 +468,8 @@ void Node::CreateNewInterface(DWORD dwIpAddr, DWORD dwNetMask, char *szName, DWO
       pInterface = new Interface(szName, dwIndex, dwIpAddr, dwNetMask, dwType);
    else
       pInterface = new Interface(dwIpAddr, dwNetMask);
+   if (pbMacAddr != NULL)
+      pInterface->SetMacAddr(pbMacAddr);
 
    // Insert to objects' list and generate event
    NetObjInsert(pInterface, TRUE);
@@ -718,7 +668,7 @@ void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId)
             }
          }
 
-      // Add new interfaces
+      // Add new interfaces and check configuration of existing
       for(j = 0; j < pIfList->iNumEntries; j++)
       {
          for(i = 0; i < m_dwChildCount; i++)
@@ -729,7 +679,21 @@ void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId)
                if ((pIfList->pInterfaces[j].dwIndex == pInterface->IfIndex()) &&
                    (pIfList->pInterfaces[j].dwIpAddr == pInterface->IpAddr()) &&
                    (pIfList->pInterfaces[j].dwIpNetMask == pInterface->IpNetMask()))
+               {
+                  // Existing interface, check configuration
+                  if (memcmp(pIfList->pInterfaces[j].bMacAddr, pInterface->MacAddr(), MAC_ADDR_LENGTH))
+                  {
+                     char szOldMac[16], szNewMac[16];
+
+                     BinToStr((BYTE *)pInterface->MacAddr(), MAC_ADDR_LENGTH, szOldMac);
+                     BinToStr(pIfList->pInterfaces[j].bMacAddr, MAC_ADDR_LENGTH, szNewMac);
+                     PostEvent(EVENT_MAC_ADDR_CHANGED, m_dwId, "ddsss",
+                               pInterface->Id(), pInterface->IfIndex(),
+                               pInterface->Name(), szOldMac, szNewMac);
+                     pInterface->SetMacAddr(pIfList->pInterfaces[j].bMacAddr);
+                  }
                   break;
+               }
             }
          if (i == m_dwChildCount)
          {
@@ -740,7 +704,8 @@ void Node::ConfigurationPoll(ClientSession *pSession, DWORD dwRqId)
                                pIfList->pInterfaces[j].dwIpNetMask,
                                pIfList->pInterfaces[j].szName,
                                pIfList->pInterfaces[j].dwIndex,
-                               pIfList->pInterfaces[j].dwType);
+                               pIfList->pInterfaces[j].dwType,
+                               pIfList->pInterfaces[j].bMacAddr);
             bHasChanges = TRUE;
          }
       }
@@ -886,92 +851,6 @@ void Node::QueueItemsForPolling(Queue *pPollerQueue)
 
 
 //
-// Add item to node
-//
-
-BOOL Node::AddItem(DCItem *pItem)
-{
-   DWORD i;
-   BOOL bResult = FALSE;
-
-   Lock();
-   // Check if that item exists
-   for(i = 0; i < m_dwNumItems; i++)
-      if (m_ppItems[i]->Id() == pItem->Id())
-         break;   // Item with specified id already exist
-   
-   if (i == m_dwNumItems)     // Add new item
-   {
-      m_dwNumItems++;
-      m_ppItems = (DCItem **)realloc(m_ppItems, sizeof(DCItem *) * m_dwNumItems);
-      m_ppItems[i] = pItem;
-      m_ppItems[i]->SetLastPollTime(0);    // Cause item to be polled immediatelly
-      m_ppItems[i]->SetStatus(ITEM_STATUS_ACTIVE);
-      m_ppItems[i]->SetBusyFlag(FALSE);
-      Modify();
-      bResult = TRUE;
-   }
-
-   Unlock();
-   return bResult;
-}
-
-
-//
-// Delete item from node
-//
-
-BOOL Node::DeleteItem(DWORD dwItemId)
-{
-   DWORD i;
-   BOOL bResult = FALSE;
-
-   Lock();
-   // Check if that item exists
-   for(i = 0; i < m_dwNumItems; i++)
-      if (m_ppItems[i]->Id() == dwItemId)
-      {
-         // Destroy item
-         m_ppItems[i]->DeleteFromDB();
-         delete m_ppItems[i];
-         m_dwNumItems--;
-         memmove(&m_ppItems[i], &m_ppItems[i + 1], sizeof(DCItem *) * (m_dwNumItems - i));
-         bResult = TRUE;
-         break;
-      }
-
-   Unlock();
-   return bResult;
-}
-
-
-//
-// Modify data collection item from CSCP message
-//
-
-BOOL Node::UpdateItem(DWORD dwItemId, CSCPMessage *pMsg, DWORD *pdwNumMaps, 
-                      DWORD **ppdwMapIndex, DWORD **ppdwMapId)
-{
-   DWORD i;
-   BOOL bResult = FALSE;
-
-   Lock();
-   // Check if that item exists
-   for(i = 0; i < m_dwNumItems; i++)
-      if (m_ppItems[i]->Id() == dwItemId)
-      {
-         m_ppItems[i]->UpdateFromMessage(pMsg, pdwNumMaps, ppdwMapIndex, ppdwMapId);
-         bResult = TRUE;
-         m_bIsModified = TRUE;
-         break;
-      }
-
-   Unlock();
-   return bResult;
-}
-
-
-//
 // Create CSCP message with object's data
 //
 
@@ -1015,114 +894,3 @@ DWORD Node::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
 
    return NetObj::ModifyFromMessage(pRequest, TRUE);
 }
-
-
-//
-// Lock data collection items list
-//
-
-BOOL Node::LockDCIList(DWORD dwSessionId)
-{
-   BOOL bSuccess = FALSE;
-
-   Lock();
-   if (m_dwDCILockStatus == INVALID_INDEX)
-   {
-      m_dwDCILockStatus = dwSessionId;
-      bSuccess = TRUE;
-   }
-   Unlock();
-   return bSuccess;
-}
-
-
-//
-// Unlock data collection items list
-//
-
-BOOL Node::UnlockDCIList(DWORD dwSessionId)
-{
-   BOOL bSuccess = FALSE;
-
-   Lock();
-   if (m_dwDCILockStatus == dwSessionId)
-   {
-      m_dwDCILockStatus = INVALID_INDEX;
-      bSuccess = TRUE;
-   }
-   Unlock();
-   return bSuccess;
-}
-
-
-//
-// Send DCI list to client
-//
-
-void Node::SendItemsToClient(ClientSession *pSession, DWORD dwRqId)
-{
-   CSCPMessage msg;
-   DWORD i;
-
-   // Prepare message
-   msg.SetId(dwRqId);
-   msg.SetCode(CMD_NODE_DCI);
-
-   // Walk through items list
-   for(i = 0; i < m_dwNumItems; i++)
-   {
-      m_ppItems[i]->CreateMessage(&msg);
-      pSession->SendMessage(&msg);
-      msg.DeleteAllVariables();
-   }
-
-   // Send end-of-list indicator
-   msg.SetCode(CMD_NODE_DCI_LIST_END);
-   pSession->SendMessage(&msg);
-}
-
-
-//
-// Get DCI item's type
-//
-
-int Node::GetItemType(DWORD dwItemId)
-{
-   DWORD i;
-   int iType = -1;
-
-   Lock();
-   // Check if that item exists
-   for(i = 0; i < m_dwNumItems; i++)
-      if (m_ppItems[i]->Id() == dwItemId)
-      {
-         iType = m_ppItems[i]->DataType();
-         break;
-      }
-
-   Unlock();
-   return iType;
-}
-
-
-//
-// Get item by it's id
-//
-
-const DCItem *Node::GetItemById(DWORD dwItemId)
-{
-   DWORD i;
-   DCItem *pItem = NULL;
-
-   Lock();
-   // Check if that item exists
-   for(i = 0; i < m_dwNumItems; i++)
-      if (m_ppItems[i]->Id() == dwItemId)
-      {
-         pItem = m_ppItems[i];
-         break;
-      }
-
-   Unlock();
-   return pItem;
-}
index c116ff6..714c702 100644 (file)
@@ -571,7 +571,8 @@ void DumpObjects(void)
    char *pBuffer;
    CONTAINER_CATEGORY *pCat;
    static char *objTypes[]={ "Generic", "Subnet", "Node", "Interface",
-                             "Network", "Container", "Zone", "ServiceRoot" };
+                             "Network", "Container", "Zone", "ServiceRoot",
+                             "Template", "TemplateGroup" };
 
    pBuffer = (char *)malloc(128000);
    MutexLock(g_hMutexIdIndex, INFINITE);
@@ -593,7 +594,7 @@ void DumpObjects(void)
             printf("   IsSNMP: %d IsAgent: %d IsLocal: %d OID: %s\n",
                    ((Node *)(g_pIndexById[i].pObject))->IsSNMPSupported(),
                    ((Node *)(g_pIndexById[i].pObject))->IsNativeAgent(),
-                   ((Node *)(g_pIndexById[i].pObject))->IsLocalManagenet(),
+                   ((Node *)(g_pIndexById[i].pObject))->IsLocalManagement(),
                    ((Node *)(g_pIndexById[i].pObject))->ObjectId());
             break;
          case OBJECT_SUBNET:
index 3287fa7..6a168da 100644 (file)
@@ -1841,8 +1841,7 @@ void ClientSession::GetCollectedData(CSCPMessage *pRequest)
                      break;
                   case DCI_DT_INT64:
                   case DCI_DT_UINT64:
-                     /* TODO: add 64-bit conversion */
-                     pCurr->value.qwInt64 = htonl(DBGetFieldAsyncULong(hResult, 1));
+                     pCurr->value.qwInt64 = htonq(DBGetFieldAsyncUQuad(hResult, 1));
                      break;
                   case DCI_DT_FLOAT:
                      pCurr->value.dFloat = htond(DBGetFieldAsyncDouble(hResult, 1));
index 6f23bc0..b3534aa 100644 (file)
@@ -340,7 +340,7 @@ static void HandlerIpAddr(DWORD dwAddr, const char *szCommunity, variable_list *
 INTERFACE_LIST *SnmpGetInterfaceList(DWORD dwAddr, const char *szCommunity)
 {
    long i, iNumIf;
-   char szOid[128];
+   char szOid[128], szBuffer[256];
    INTERFACE_LIST *pIfList = NULL;
 
    // Get number of interfaces
@@ -374,6 +374,14 @@ INTERFACE_LIST *SnmpGetInterfaceList(DWORD dwAddr, const char *szCommunity)
                    &pIfList->pInterfaces[i].dwType, sizeof(DWORD),
                    FALSE, FALSE))
          continue;
+
+      // MAC address
+      sprintf(szOid, ".1.3.6.1.2.1.2.2.1.6.%d", pIfList->pInterfaces[i].dwIndex);
+      memset(szBuffer, 0, MAC_ADDR_LENGTH);
+      if (!SnmpGet(dwAddr, szCommunity, szOid, NULL, 0,
+                   szBuffer, 256, FALSE, TRUE))
+         continue;
+      memcpy(pIfList->pInterfaces[i].bMacAddr, szBuffer, MAC_ADDR_LENGTH);
    }
 
    // Interface IP address'es and netmasks
diff --git a/src/server/core/template.cpp b/src/server/core/template.cpp
new file mode 100644 (file)
index 0000000..9015162
--- /dev/null
@@ -0,0 +1,335 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004 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: template.cpp
+**
+**/
+
+#include "nms_core.h"
+
+
+//
+// Template object constructor
+//
+
+Template::Template()
+{
+   m_dwNumItems = 0;
+   m_ppItems = NULL;
+   m_dwDCILockStatus = INVALID_INDEX;
+}
+
+
+//
+// Destructor
+//
+
+Template::~Template()
+{
+   DestroyItems();
+}
+
+
+//
+// Destroy all related data collection items
+//
+
+void Template::DestroyItems(void)
+{
+   DWORD i;
+
+   for(i = 0; i < m_dwNumItems; i++)
+      delete m_ppItems[i];
+   safe_free(m_ppItems);
+   m_dwNumItems = 0;
+   m_ppItems = NULL;
+}
+
+
+//
+// Create object from database data
+//
+
+BOOL Template::CreateFromDB(DWORD dwId)
+{
+   return FALSE;
+}
+
+
+//
+// Save object to database
+//
+
+BOOL Template::SaveToDB(void)
+{
+   return FALSE;
+}
+
+
+//
+// Delete object from database
+//
+
+BOOL Template::DeleteFromDB(void)
+{
+   char szQuery[256];
+   BOOL bSuccess;
+
+   bSuccess = NetObj::DeleteFromDB();
+   if (bSuccess)
+   {
+      if (Type() == OBJECT_TEMPLATE)
+      {
+         sprintf(szQuery, "DELETE FROM dct WHERE template_id=%ld", m_dwId);
+         QueueSQLRequest(szQuery);
+      }
+      sprintf(szQuery, "DELETE FROM items WHERE node_id=%ld", m_dwId);
+      QueueSQLRequest(szQuery);
+      sprintf(szQuery, "UPDATE items SET template_id=0 WHERE template_id=%ld", m_dwId);
+      QueueSQLRequest(szQuery);
+   }
+   return bSuccess;
+}
+
+
+//
+// Load data collection items from database
+//
+
+void Template::LoadItemsFromDB(void)
+{
+   char szQuery[256];
+   DB_RESULT hResult;
+
+   sprintf(szQuery, "SELECT item_id,name,source,datatype,polling_interval,retention_time,"
+                    "status,delta_calculation,transformation,template_id,description "
+                    "FROM items WHERE node_id=%d", m_dwId);
+   hResult = DBSelect(g_hCoreDB, szQuery);
+
+   if (hResult != 0)
+   {
+      int i, iRows;
+
+      iRows = DBGetNumRows(hResult);
+      if (iRows > 0)
+      {
+         m_dwNumItems = iRows;
+         m_ppItems = (DCItem **)malloc(sizeof(DCItem *) * iRows);
+         for(i = 0; i < iRows; i++)
+            m_ppItems[i] = new DCItem(hResult, i, this);
+      }
+      DBFreeResult(hResult);
+   }
+}
+
+
+//
+// Add item to node
+//
+
+BOOL Template::AddItem(DCItem *pItem)
+{
+   DWORD i;
+   BOOL bResult = FALSE;
+
+   Lock();
+   // Check if that item exists
+   for(i = 0; i < m_dwNumItems; i++)
+      if (m_ppItems[i]->Id() == pItem->Id())
+         break;   // Item with specified id already exist
+   
+   if (i == m_dwNumItems)     // Add new item
+   {
+      m_dwNumItems++;
+      m_ppItems = (DCItem **)realloc(m_ppItems, sizeof(DCItem *) * m_dwNumItems);
+      m_ppItems[i] = pItem;
+      m_ppItems[i]->SetLastPollTime(0);    // Cause item to be polled immediatelly
+      m_ppItems[i]->SetStatus(ITEM_STATUS_ACTIVE);
+      m_ppItems[i]->SetBusyFlag(FALSE);
+      Modify();
+      bResult = TRUE;
+   }
+
+   Unlock();
+   return bResult;
+}
+
+
+//
+// Delete item from node
+//
+
+BOOL Template::DeleteItem(DWORD dwItemId)
+{
+   DWORD i;
+   BOOL bResult = FALSE;
+
+   Lock();
+   // Check if that item exists
+   for(i = 0; i < m_dwNumItems; i++)
+      if (m_ppItems[i]->Id() == dwItemId)
+      {
+         // Destroy item
+         m_ppItems[i]->DeleteFromDB();
+         delete m_ppItems[i];
+         m_dwNumItems--;
+         memmove(&m_ppItems[i], &m_ppItems[i + 1], sizeof(DCItem *) * (m_dwNumItems - i));
+         bResult = TRUE;
+         break;
+      }
+
+   Unlock();
+   return bResult;
+}
+
+
+//
+// Modify data collection item from CSCP message
+//
+
+BOOL Template::UpdateItem(DWORD dwItemId, CSCPMessage *pMsg, DWORD *pdwNumMaps, 
+                          DWORD **ppdwMapIndex, DWORD **ppdwMapId)
+{
+   DWORD i;
+   BOOL bResult = FALSE;
+
+   Lock();
+   // Check if that item exists
+   for(i = 0; i < m_dwNumItems; i++)
+      if (m_ppItems[i]->Id() == dwItemId)
+      {
+         m_ppItems[i]->UpdateFromMessage(pMsg, pdwNumMaps, ppdwMapIndex, ppdwMapId);
+         bResult = TRUE;
+         m_bIsModified = TRUE;
+         break;
+      }
+
+   Unlock();
+   return bResult;
+}
+
+
+//
+// Lock data collection items list
+//
+
+BOOL Template::LockDCIList(DWORD dwSessionId)
+{
+   BOOL bSuccess = FALSE;
+
+   Lock();
+   if (m_dwDCILockStatus == INVALID_INDEX)
+   {
+      m_dwDCILockStatus = dwSessionId;
+      bSuccess = TRUE;
+   }
+   Unlock();
+   return bSuccess;
+}
+
+
+//
+// Unlock data collection items list
+//
+
+BOOL Template::UnlockDCIList(DWORD dwSessionId)
+{
+   BOOL bSuccess = FALSE;
+
+   Lock();
+   if (m_dwDCILockStatus == dwSessionId)
+   {
+      m_dwDCILockStatus = INVALID_INDEX;
+      bSuccess = TRUE;
+   }
+   Unlock();
+   return bSuccess;
+}
+
+
+//
+// Send DCI list to client
+//
+
+void Template::SendItemsToClient(ClientSession *pSession, DWORD dwRqId)
+{
+   CSCPMessage msg;
+   DWORD i;
+
+   // Prepare message
+   msg.SetId(dwRqId);
+   msg.SetCode(CMD_NODE_DCI);
+
+   // Walk through items list
+   for(i = 0; i < m_dwNumItems; i++)
+   {
+      m_ppItems[i]->CreateMessage(&msg);
+      pSession->SendMessage(&msg);
+      msg.DeleteAllVariables();
+   }
+
+   // Send end-of-list indicator
+   msg.SetCode(CMD_NODE_DCI_LIST_END);
+   pSession->SendMessage(&msg);
+}
+
+
+//
+// Get DCI item's type
+//
+
+int Template::GetItemType(DWORD dwItemId)
+{
+   DWORD i;
+   int iType = -1;
+
+   Lock();
+   // Check if that item exists
+   for(i = 0; i < m_dwNumItems; i++)
+      if (m_ppItems[i]->Id() == dwItemId)
+      {
+         iType = m_ppItems[i]->DataType();
+         break;
+      }
+
+   Unlock();
+   return iType;
+}
+
+
+//
+// Get item by it's id
+//
+
+const DCItem *Template::GetItemById(DWORD dwItemId)
+{
+   DWORD i;
+   DCItem *pItem = NULL;
+
+   Lock();
+   // Check if that item exists
+   for(i = 0; i < m_dwNumItems; i++)
+      if (m_ppItems[i]->Id() == dwItemId)
+      {
+         pItem = m_ppItems[i];
+         break;
+      }
+
+   Unlock();
+   return pItem;
+}
index e993034..e574195 100644 (file)
@@ -90,45 +90,6 @@ void CleanInterfaceList(INTERFACE_LIST *pIfList)
 
 
 //
-// Convert byte array to text representation
-//
-
-void BinToStr(BYTE *pData, DWORD dwSize, char *pStr)
-{
-   DWORD i;
-   char *pCurr;
-
-   for(i = 0, pCurr = pStr; i < dwSize; i++)
-   {
-      *pCurr++ = bin2hex(pData[i] >> 4);
-      *pCurr++ = bin2hex(pData[i] & 15);
-   }
-   *pCurr = 0;
-}
-
-
-//
-// Convert string of hexadecimal digits to byte array
-//
-
-DWORD StrToBin(char *pStr, BYTE *pData, DWORD dwSize)
-{
-   DWORD i;
-   char *pCurr;
-
-   memset(pData, 0, dwSize);
-   for(i = 0, pCurr = pStr; (i < dwSize) && (*pCurr != 0); i++)
-   {
-      pData[i] = hex2bin(*pCurr) << 4;
-      pCurr++;
-      pData[i] |= hex2bin(*pCurr);
-      pCurr++;
-   }
-   return i;
-}
-
-
-//
 // Get system information string
 //
 
index 9e08118..24065f1 100644 (file)
@@ -51,7 +51,7 @@ typedef struct
 {
    DWORD dwIndex;       // Interface index
    DWORD dwIpAddr;
-   BYTE bMacAddr[6];
+   BYTE bMacAddr[MAC_ADDR_LENGTH];
 } ARP_ENTRY;
 
 
@@ -77,6 +77,7 @@ typedef struct
    DWORD dwType;
    DWORD dwIpAddr;
    DWORD dwIpNetMask;
+   BYTE bMacAddr[MAC_ADDR_LENGTH];
    int iNumSecondary;      // Number of secondary IP's on this interface
 } INTERFACE_INFO;
 
index bc813ce..7dcccc5 100644 (file)
@@ -380,6 +380,15 @@ INTERFACE_LIST *AgentConnection::GetInterfaceList(void)
             pBuf = pChar + 1;
          }
 
+         // MAC address
+         pChar = _tcschr(pBuf, ' ');
+         if (pChar != NULL)
+         {
+            *pChar = 0;
+            StrToBin(pBuf, pIfList->pInterfaces[i].bMacAddr, MAC_ADDR_LENGTH);
+            pBuf = pChar + 1;
+         }
+
          // Name
          _tcsncpy(pIfList->pInterfaces[i].szName, pBuf, MAX_OBJECT_NAME - 1);
       }