- Implemented interface for SMS drivers
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 17 Feb 2005 22:10:29 +0000 (22:10 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 17 Feb 2005 22:10:29 +0000 (22:10 +0000)
- In "nodes" table all flag fields is_xxx replaced by node_flags field

13 files changed:
include/netxmsdb.h
include/nxevent.h
sql/events.in
sql/schema.in
src/console/Makefile.am
src/server/core/Makefile.am
src/server/core/email.cpp
src/server/core/main.cpp
src/server/core/node.cpp
src/server/core/sms.cpp
src/server/include/nms_core.h
src/server/libnxsrv/messages.mc
src/server/tools/nxdbmgr/upgrade.cpp

index 2e9213b..6bdffc8 100644 (file)
@@ -23,6 +23,6 @@
 #ifndef _netxms_db_h
 #define _netxms_db_h
 
-#define DB_FORMAT_VERSION      20
+#define DB_FORMAT_VERSION      21
 
 #endif
index 592dd68..fc3ae91 100644 (file)
@@ -84,6 +84,7 @@
 #define EVENT_SERVICE_UNKNOWN    27
 #define EVENT_NODE_DOWN          28
 #define EVENT_NODE_UP            29
+#define EVENT_SMS_FAILURE        30
 
 #define EVENT_SNMP_UNMATCHED_TRAP   500
 #define EVENT_SNMP_COLD_START       501
index 25b30ad..749dde4 100644 (file)
@@ -312,6 +312,15 @@ INSERT INTO event_cfg (event_code,event_name,severity,flags,message,description)
                '   2) Service object ID#0D0A' CONCAT
                '   3) Service type'
        );
+INSERT INTO event_cfg (event_code,event_name,severity,flags,message,description) VALUES
+       (
+               EVENT_SMS_FAILURE, 'SYS_SMS_FAILURE', 
+               EVENT_SEVERITY_WARNING, 1,
+               'Unable to send SMS to phone %1',
+               'Generated when server is unable to send SMS.#0D#0A' CONCAT
+               'Parameters:#0D#0A' CONCAT
+               '   1) Phone number'
+       );
 
 
 /*
index 3bb919d..bbbf28e 100644 (file)
@@ -97,12 +97,7 @@ CREATE TABLE nodes
        status integer,
        is_deleted integer not null,
        primary_ip varchar(15),
-       is_snmp integer,
-       is_agent integer,
-       is_bridge integer,
-       is_router integer,
-       is_local_mgmt integer,
-       is_ospf integer,
+       node_flags integer,
        snmp_version integer,
        community varchar(32),
        snmp_oid varchar(255),
index b0150ab..6f56ccc 100644 (file)
@@ -8,4 +8,4 @@
 # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
 # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
-SUBDIRS = win32 win32starter
+SUBDIRS = win32 win32starter nxav cmdline
index 88a421a..ff9f7ab 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 correlate.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 netsrv.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_SOURCES = acl.cpp actions.cpp admin.cpp alarm.cpp client.cpp config.cpp container.cpp correlate.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 netsrv.cpp node.cpp nortel.cpp np.cpp objects.cpp package.cpp rootobj.cpp session.cpp sms.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 b13cf6d..eea9408 100644 (file)
@@ -68,6 +68,7 @@ static char m_szSmtpServer[MAX_PATH] = "localhost";
 static WORD m_wSmtpPort = 25;
 static char m_szFromAddr[MAX_PATH] = "netxms@localhost";
 static Queue *m_pMailerQueue = NULL;
+static THREAD m_hThread = INVALID_THREAD_HANDLE;
 
 
 //
@@ -309,7 +310,7 @@ void InitMailer(void)
 
    m_pMailerQueue = new Queue;
 
-   ThreadCreate(MailerThread, 0, NULL);
+   m_hThread = ThreadCreateEx(MailerThread, 0, NULL);
 }
 
 
@@ -321,6 +322,9 @@ void ShutdownMailer(void)
 {
    m_pMailerQueue->Clear();
    m_pMailerQueue->Put(INVALID_POINTER_VALUE);
+   if (m_hThread != INVALID_THREAD_HANDLE)
+      ThreadJoin(m_hThread);
+   delete m_pMailerQueue;
 }
 
 
index 1676cc8..a58f60a 100644 (file)
@@ -252,8 +252,9 @@ BOOL NXCORE_EXPORTABLE Initialize(void)
    if (!InitIdTable())
       return FALSE;
 
-   // Initialize mailer
+   // Initialize mailer and SMS sender
    InitMailer();
+   InitSMSSender();
 
    // Load users from database
    if (!LoadUsers())
@@ -360,6 +361,7 @@ void NXCORE_EXPORTABLE Shutdown(void)
       g_pEventQueue->Put(INVALID_POINTER_VALUE);
 
    ShutdownMailer();
+   ShutdownSMSSender();
 
    ThreadSleep(3);     // Give other threads a chance to terminate in a safe way
    DbgPrintf(AF_DEBUG_MISC, "All threads was notified, continue with shutdown");
index d5fc5ba..747fd45 100644 (file)
@@ -120,9 +120,9 @@ BOOL Node::CreateFromDB(DWORD dwId)
    NetObj *pObject;
    BOOL bResult = FALSE;
 
-   _sntprintf(szQuery, 512, "SELECT name,status,primary_ip,is_snmp,is_agent,is_bridge,"
-                            "is_router,is_ospf,snmp_version,discovery_flags,auth_method,secret,"
-                            "agent_port,status_poll_type,community,snmp_oid,is_local_mgmt,"
+   _sntprintf(szQuery, 512, "SELECT name,status,primary_ip,node_flags,"
+                            "snmp_version,discovery_flags,auth_method,secret,"
+                            "agent_port,status_poll_type,community,snmp_oid,"
                             "image_id,is_deleted,description,node_type,agent_version,"
                             "platform_name,poller_node_id FROM nodes WHERE id=%d", dwId);
    hResult = DBSelect(g_hCoreDB, szQuery);
@@ -139,39 +139,25 @@ BOOL Node::CreateFromDB(DWORD dwId)
    strncpy(m_szName, DBGetField(hResult, 0, 0), MAX_OBJECT_NAME);
    m_iStatus = DBGetFieldLong(hResult, 0, 1);
    m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 2);
-
-   // Flags
-   if (DBGetFieldLong(hResult, 0, 3))
-      m_dwFlags |= NF_IS_SNMP;
-   if (DBGetFieldLong(hResult, 0, 4))
-      m_dwFlags |= NF_IS_NATIVE_AGENT;
-   if (DBGetFieldLong(hResult, 0, 5))
-      m_dwFlags |= NF_IS_BRIDGE;
-   if (DBGetFieldLong(hResult, 0, 6))
-      m_dwFlags |= NF_IS_ROUTER;
-   if (DBGetFieldLong(hResult, 0, 7))
-      m_dwFlags |= NF_IS_OSPF;
-   if (DBGetFieldLong(hResult, 0, 16))
-      m_dwFlags |= NF_IS_LOCAL_MGMT;
-
-   m_iSNMPVersion = DBGetFieldLong(hResult, 0, 8);
-   m_dwDiscoveryFlags = DBGetFieldULong(hResult, 0, 9);
-   m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 10);
-   strncpy(m_szSharedSecret, DBGetField(hResult, 0, 11), MAX_SECRET_LENGTH);
-   m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 12);
-   m_iStatusPollType = DBGetFieldLong(hResult, 0, 13);
-   strncpy(m_szCommunityString, DBGetField(hResult, 0, 14), MAX_COMMUNITY_LENGTH);
-   strncpy(m_szObjectId, DBGetField(hResult, 0, 15), MAX_OID_LEN * 4);
-   m_dwImageId = DBGetFieldULong(hResult, 0, 17);
-   m_bIsDeleted = DBGetFieldLong(hResult, 0, 18);
-   m_pszDescription = _tcsdup(CHECK_NULL_EX(DBGetField(hResult, 0, 19)));
+   m_dwFlags = DBGetFieldULong(hResult, 0, 3);
+   m_iSNMPVersion = DBGetFieldLong(hResult, 0, 4);
+   m_dwDiscoveryFlags = DBGetFieldULong(hResult, 0, 5);
+   m_wAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 6);
+   strncpy(m_szSharedSecret, DBGetField(hResult, 0, 7), MAX_SECRET_LENGTH);
+   m_wAgentPort = (WORD)DBGetFieldLong(hResult, 0, 8);
+   m_iStatusPollType = DBGetFieldLong(hResult, 0, 9);
+   strncpy(m_szCommunityString, DBGetField(hResult, 0, 10), MAX_COMMUNITY_LENGTH);
+   strncpy(m_szObjectId, DBGetField(hResult, 0, 11), MAX_OID_LEN * 4);
+   m_dwImageId = DBGetFieldULong(hResult, 0, 12);
+   m_bIsDeleted = DBGetFieldLong(hResult, 0, 13);
+   m_pszDescription = _tcsdup(CHECK_NULL_EX(DBGetField(hResult, 0, 14)));
    DecodeSQLString(m_pszDescription);
-   m_dwNodeType = DBGetFieldULong(hResult, 0, 20);
-   _tcsncpy(m_szAgentVersion, CHECK_NULL_EX(DBGetField(hResult, 0, 21)), MAX_AGENT_VERSION_LEN);
+   m_dwNodeType = DBGetFieldULong(hResult, 0, 15);
+   _tcsncpy(m_szAgentVersion, CHECK_NULL_EX(DBGetField(hResult, 0, 16)), MAX_AGENT_VERSION_LEN);
    DecodeSQLString(m_szAgentVersion);
-   _tcsncpy(m_szPlatformName, CHECK_NULL_EX(DBGetField(hResult, 0, 22)), MAX_PLATFORM_NAME_LEN);
+   _tcsncpy(m_szPlatformName, CHECK_NULL_EX(DBGetField(hResult, 0, 17)), MAX_PLATFORM_NAME_LEN);
    DecodeSQLString(m_szPlatformName);
-   m_dwPollerNode = DBGetFieldULong(hResult, 0, 23);
+   m_dwPollerNode = DBGetFieldULong(hResult, 0, 18);
 
    DBFreeResult(hResult);
 
@@ -262,42 +248,30 @@ BOOL Node::SaveToDB(void)
    if (bNewObject)
       snprintf(szQuery, 4096,
                "INSERT INTO nodes (id,name,status,is_deleted,primary_ip,"
-               "is_snmp,is_agent,is_bridge,is_router,snmp_version,community,"
-               "discovery_flags,status_poll_type,agent_port,auth_method,secret,"
-               "snmp_oid,is_local_mgmt,image_id,description,node_type,"
-               "agent_version,platform_name,poller_node_id,is_ospf)"
-               " VALUES (%d,'%s',%d,%d,'%s',%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,"
-               "'%s','%s',%d,%ld,'%s',%ld,'%s','%s',%ld,%d)",
+               "node_flags,snmp_version,community,discovery_flags,status_poll_type,"
+               "agent_port,auth_method,secret,snmp_oid,image_id,"
+               "description,node_type,agent_version,platform_name,"
+               "poller_node_id) VALUES (%ld,'%s',%d,%d,'%s',%ld,%d,'%s',%ld,%d,%d,%d,"
+               "'%s','%s',%ld,'%s',%ld,'%s','%s',%ld)",
                m_dwId, m_szName, m_iStatus, m_bIsDeleted, 
-               IpToStr(m_dwIpAddr, szIpAddr),
-               m_dwFlags & NF_IS_SNMP ? 1 : 0,
-               m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
-               m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
-               m_dwFlags & NF_IS_ROUTER ? 1 : 0,
+               IpToStr(m_dwIpAddr, szIpAddr), m_dwFlags,
                m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, m_iStatusPollType,
-               m_wAgentPort,m_wAuthMethod,m_szSharedSecret, m_szObjectId,
-               m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0, m_dwImageId,
-               pszEscDescr, m_dwNodeType, pszEscVersion, pszEscPlatform, 
-               m_dwPollerNode, m_dwFlags & NF_IS_OSPF ? 1 : 0);
+               m_wAgentPort, m_wAuthMethod, m_szSharedSecret, m_szObjectId,
+               m_dwImageId, pszEscDescr, m_dwNodeType, pszEscVersion, pszEscPlatform, 
+               m_dwPollerNode);
    else
       snprintf(szQuery, 4096,
                "UPDATE nodes SET name='%s',status=%d,is_deleted=%d,primary_ip='%s',"
-               "is_snmp=%d,is_agent=%d,is_bridge=%d,is_router=%d,snmp_version=%d,"
-               "community='%s',discovery_flags=%d,status_poll_type=%d,agent_port=%d,"
-               "auth_method=%d,secret='%s',snmp_oid='%s',is_local_mgmt=%d,"
-               "image_id=%ld,description='%s',node_type=%ld,agent_version='%s',"
-               "platform_name='%s',poller_node_id=%ld,is_ospf=%d WHERE id=%ld",
+               "node_flags=%ld,snmp_version=%d,community='%s',discovery_flags=%d,"
+               "status_poll_type=%d,agent_port=%d,auth_method=%d,secret='%s',"
+               "snmp_oid='%s',image_id=%ld,description='%s',node_type=%ld,"
+               "agent_version='%s',platform_name='%s',poller_node_id=%ld WHERE id=%ld",
                m_szName, m_iStatus, m_bIsDeleted, 
                IpToStr(m_dwIpAddr, szIpAddr), 
-               m_dwFlags & NF_IS_SNMP ? 1 : 0,
-               m_dwFlags & NF_IS_NATIVE_AGENT ? 1 : 0,
-               m_dwFlags & NF_IS_BRIDGE ? 1 : 0,
-               m_dwFlags & NF_IS_ROUTER ? 1 : 0,
-               m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, 
+               m_dwFlags, m_iSNMPVersion, m_szCommunityString, m_dwDiscoveryFlags, 
                m_iStatusPollType, m_wAgentPort, m_wAuthMethod, m_szSharedSecret, 
-               m_szObjectId, m_dwFlags & NF_IS_LOCAL_MGMT ? 1 : 0, m_dwImageId, 
-               pszEscDescr, m_dwNodeType, pszEscVersion, pszEscPlatform,
-               m_dwPollerNode, m_dwFlags & NF_IS_OSPF ? 1 : 0, m_dwId);
+               m_szObjectId, m_dwImageId, pszEscDescr, m_dwNodeType, 
+               pszEscVersion, pszEscPlatform, m_dwPollerNode, m_dwId);
    bResult = DBQuery(g_hCoreDB, szQuery);
    free(pszEscDescr);
    free(pszEscVersion);
index 0647efc..a75ba27 100644 (file)
 #include "nxcore.h"
 
 
+//
+// SMS structure
+//
+
+typedef struct
+{
+   char szRcpt[MAX_RCPT_ADDR_LEN];
+   char szText[160];
+} SMS;
+
+
 //
 // Static data
 //
 
 static Queue *m_pMsgQueue;
+static BOOL (* m_DrvSendMsg)(TCHAR *, TCHAR *);
+static void (* m_DrvUnload)(void);
+static THREAD m_hThread = INVALID_THREAD_HANDLE;
+
+
+//
+// Sender thread
+//
+
+static THREAD_RESULT THREAD_CALL SenderThread(void *pArg)
+{
+   SMS *pMsg;
+
+   while(1)
+   {
+      pMsg = (SMS *)m_pMsgQueue->GetOrBlock();
+      if (pMsg == INVALID_POINTER_VALUE)
+         break;
+
+      if (!m_DrvSendMsg(pMsg->szRcpt, pMsg->szText))
+         PostEvent(EVENT_SMS_FAILURE, g_dwMgmtNode, "s", pMsg->szRcpt);
+
+      free(pMsg);
+   }
+   return THREAD_OK;
+}
 
 
 //
@@ -48,14 +85,29 @@ void InitSMSSender(void)
       hModule = DLOpen(szDriver, szErrorText);
       if (hModule != NULL)
       {
-         BOOL (* ModuleInit)(NXMODULE *);
+         BOOL (* DrvInit)(TCHAR *);
 
-         ModuleInit = (BOOL (*)(NXMODULE *))DLGetSymbolAddr(hModule, "NetXMSModuleInit", szErrorText);
-         if (ModuleInit != NULL)
+         DrvInit = (BOOL (*)(TCHAR *))DLGetSymbolAddr(hModule, "SMSDriverInit", szErrorText);
+         m_DrvSendMsg = (BOOL (*)(TCHAR *, TCHAR *))DLGetSymbolAddr(hModule, "SMSDriverSend", szErrorText);
+         m_DrvUnload = (void (*)(void))DLGetSymbolAddr(hModule, "SMSDriverUnload", szErrorText);
+         if ((DrvInit != NULL) && (m_DrvSendMsg != NULL) && (m_DrvUnload != NULL))
          {
-            m_pMsgQueue = new Queue;
-
-            ThreadCreate(SenderThread, 0, NULL);
+            if (DrvInit(szDrvConfig))
+            {
+               m_pMsgQueue = new Queue;
+
+               m_hThread = ThreadCreateEx(SenderThread, 0, NULL);
+            }
+            else
+            {
+               WriteLog(MSG_SMSDRV_INIT_FAILED, EVENTLOG_ERROR_TYPE, "s", szDriver);
+               DLClose(hModule);
+            }
+         }
+         else
+         {
+            WriteLog(MSG_SMSDRV_NO_ENTRY_POINTS, EVENTLOG_ERROR_TYPE, "s", szDriver);
+            DLClose(hModule);
          }
       }
       else
@@ -68,27 +120,29 @@ void InitSMSSender(void)
 
 
 //
-// Shutdown mailer
+// Shutdown SMS sender
 //
 
 void ShutdownSMSSender(void)
 {
    m_pMsgQueue->Clear();
    m_pMsgQueue->Put(INVALID_POINTER_VALUE);
+   if (m_hThread != INVALID_THREAD_HANDLE)
+      ThreadJoin(m_hThread);
+   delete m_pMsgQueue;
 }
 
 
 //
-// Post e-mail to queue
+// Post SMS to queue
 //
 
-void NXCORE_EXPORTABLE PostMail(char *pszRcpt, char *pszSubject, char *pszText)
+void NXCORE_EXPORTABLE PostSMS(TCHAR *pszRcpt, TCHAR *pszText)
 {
-   MAIL_ENVELOPE *pEnvelope;
+   SMS *pMsg;
 
-   pEnvelope = (MAIL_ENVELOPE *)malloc(sizeof(MAIL_ENVELOPE));
-   strncpy(pEnvelope->szRcptAddr, pszRcpt, MAX_RCPT_ADDR_LEN);
-   strncpy(pEnvelope->szSubject, pszSubject, MAX_EMAIL_SUBJECT_LEN);
-   pEnvelope->pszText = strdup(pszText);
-   m_pMailerQueue->Put(pEnvelope);
+   pMsg = (SMS *)malloc(sizeof(SMS));
+   _tcsncpy(pMsg->szRcpt, pszRcpt, MAX_RCPT_ADDR_LEN);
+   _tcsncpy(pMsg->szText, pszText, 160);
+   m_pMsgQueue->Put(pMsg);
 }
index dbfeff0..6644352 100644 (file)
@@ -447,6 +447,10 @@ void InitMailer(void);
 void ShutdownMailer(void);
 void NXCORE_EXPORTABLE PostMail(char *pszRcpt, char *pszSubject, char *pszText);
 
+void InitSMSSender(void);
+void ShutdownSMSSender(void);
+void NXCORE_EXPORTABLE PostSMS(TCHAR *pszRcpt, TCHAR *pszText);
+
 void GetAccelarVLANIfList(DWORD dwVersion, DWORD dwIpAddr, const TCHAR *pszCommunity, INTERFACE_LIST *pIfList);
 
 void InitTraps(void);
index b558423..ebeac64 100644 (file)
@@ -458,4 +458,16 @@ Language=English
 Failed to load network service object with id %1 from database
 .
 
+MessageId=
+SymbolicName=MSG_SMSDRV_NO_ENTRY_POINTS
+Language=English
+Unable to find all required exportable functions in SMS driver "%1"
+.
+
+MessageId=
+SymbolicName=MSG_SMSDRV_INIT_FAILED
+Language=English
+SMS driver "%1" initialization failed
+.
+
 ;#endif
index 4b9cee2..e836a9b 100644 (file)
@@ -80,9 +80,29 @@ static BOOL CreateConfigParam(TCHAR *pszName, TCHAR *pszValue, int iVisible, int
 
 static BOOL H_UpgradeFromV20(void)
 {
+   static TCHAR m_szBatch[] =
+      "INSERT INTO event_cfg (event_code,event_name,severity,flags,message,description)" 
+         " VALUES (30,'SYS_SMS_FAILURE',1,1,'Unable to send SMS to phone %1',"
+                  "'Generated when server is unable to send SMS.#0D#0A"
+                  "   Parameters:#0D#0A   1) Phone number')\n"
+      "ALTER TABLE nodes ADD node_flags integer\n"
+      "<END>";
+   static TCHAR m_szBatch2[] =
+      "ALTER TABLE nodes DROP COLUMN is_snmp\n"
+      "ALTER TABLE nodes DROP COLUMN is_agent\n"
+      "ALTER TABLE nodes DROP COLUMN is_bridge\n"
+      "ALTER TABLE nodes DROP COLUMN is_router\n"
+      "ALTER TABLE nodes DROP COLUMN is_local_mgmt\n"
+      "ALTER TABLE nodes DROP COLUMN is_ospf\n"
+      "<END>";
+   static DWORD m_dwFlag[] = { NF_IS_SNMP, NF_IS_NATIVE_AGENT, NF_IS_BRIDGE,
+                               NF_IS_ROUTER, NF_IS_LOCAL_MGMT, NF_IS_OSPF };
    DB_RESULT hResult;
+   int i, j, iNumRows;
+   DWORD dwFlags;
+   TCHAR szQuery[256];
 
-   if (!SQLQuery(_T("ALTER TABLE nodes ADD node_flags integer")))
+   if (!SQLBatch(m_szBatch))
       if (!g_bIgnoreErrors)
          return FALSE;
 
@@ -91,6 +111,22 @@ static BOOL H_UpgradeFromV20(void)
                           "is_local_mgmt,is_ospf FROM nodes"));
    if (hResult != NULL)
    {
+      iNumRows = DBGetNumRows(hResult);
+      for(i = 0; i < iNumRows; i++)
+      {
+         dwFlags = 0;
+         for(j = 1; j <= 6; j++)
+            if (DBGetFieldLong(hResult, i, j))
+               dwFlags |= m_dwFlag[j];
+         _sntprintf(szQuery, 256, _T("UPDATE nodes SET node_flags=%ld WHERE id=%ld"),
+                    dwFlags, DBGetFieldULong(hResult, i, 0));
+         if (!SQLQuery(m_szBatch))
+            if (!g_bIgnoreErrors)
+            {
+               DBFreeResult(hResult);
+               return FALSE;
+            }
+      }
       DBFreeResult(hResult);
    }
    else
@@ -99,6 +135,10 @@ static BOOL H_UpgradeFromV20(void)
          return FALSE;
    }
 
+   if (!SQLBatch(m_szBatch2))
+      if (!g_bIgnoreErrors)
+         return FALSE;
+
    if (!SQLQuery(_T("UPDATE config SET var_value='21' WHERE var_name='DBFormatVersion'")))
       if (!g_bIgnoreErrors)
          return FALSE;