cc7b9aad89d8aecbeee73ec0c96d002bc477b1fd
[public/netxms.git] / src / server / core / netobj.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: netobj.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Class names
27 */
28 static const TCHAR *s_className[]=
29 {
30 _T("Generic"), _T("Subnet"), _T("Node"), _T("Interface"),
31 _T("Network"), _T("Container"), _T("Zone"), _T("ServiceRoot"),
32 _T("Template"), _T("TemplateGroup"), _T("TemplateRoot"),
33 _T("NetworkService"), _T("VPNConnector"), _T("Condition"),
34 _T("Cluster"), _T("PolicyGroup"), _T("PolicyRoot"),
35 _T("AgentPolicy"), _T("AgentPolicyConfig"), _T("NetworkMapRoot"),
36 _T("NetworkMapGroup"), _T("NetworkMap"), _T("DashboardRoot"),
37 _T("Dashboard"), _T("ReportRoot"), _T("ReportGroup"), _T("Report"),
38 _T("BusinessServiceRoot"), _T("BusinessService"), _T("NodeLink"),
39 _T("ServiceCheck"), _T("MobileDevice"), _T("Rack"), _T("AccessPoint"),
40 _T("AgentPolicyLogParser"), _T("Chassis")
41 };
42
43 /**
44 * Default constructor
45 */
46 NetObj::NetObj()
47 {
48 int i;
49
50 m_id = 0;
51 m_dwRefCount = 0;
52 m_mutexProperties = MutexCreate();
53 m_mutexRefCount = MutexCreate();
54 m_mutexACL = MutexCreate();
55 m_rwlockParentList = RWLockCreate();
56 m_rwlockChildList = RWLockCreate();
57 m_status = STATUS_UNKNOWN;
58 m_name[0] = 0;
59 m_comments = NULL;
60 m_isModified = false;
61 m_isDeleted = false;
62 m_isHidden = false;
63 m_isSystem = false;
64 m_maintenanceMode = false;
65 m_maintenanceEventId = 0;
66 m_childList = new ObjectArray<NetObj>(0, 16, false);
67 m_parentList = new ObjectArray<NetObj>(4, 4, false);
68 m_accessList = new AccessList();
69 m_inheritAccessRights = true;
70 m_dwNumTrustedNodes = 0;
71 m_pdwTrustedNodes = NULL;
72 m_pollRequestor = NULL;
73 m_statusCalcAlg = SA_CALCULATE_DEFAULT;
74 m_statusPropAlg = SA_PROPAGATE_DEFAULT;
75 m_fixedStatus = STATUS_WARNING;
76 m_statusShift = 0;
77 m_statusSingleThreshold = 75;
78 m_dwTimeStamp = 0;
79 for(i = 0; i < 4; i++)
80 {
81 m_statusTranslation[i] = i + 1;
82 m_statusThresholds[i] = 80 - i * 20;
83 }
84 m_submapId = 0;
85 m_moduleData = NULL;
86 m_postalAddress = new PostalAddress();
87 m_dashboards = new IntegerArray<UINT32>();
88 }
89
90 /**
91 * Destructor
92 */
93 NetObj::~NetObj()
94 {
95 MutexDestroy(m_mutexProperties);
96 MutexDestroy(m_mutexRefCount);
97 MutexDestroy(m_mutexACL);
98 RWLockDestroy(m_rwlockParentList);
99 RWLockDestroy(m_rwlockChildList);
100 delete m_childList;
101 delete m_parentList;
102 delete m_accessList;
103 safe_free(m_pdwTrustedNodes);
104 safe_free(m_comments);
105 delete m_moduleData;
106 delete m_postalAddress;
107 delete m_dashboards;
108 }
109
110 /**
111 * Get class name for this object
112 */
113 const TCHAR *NetObj::getObjectClassName() const
114 {
115 int c = getObjectClass();
116 return ((c >= 0) && (c < sizeof(s_className) / sizeof(const TCHAR *))) ? s_className[c] : _T("Custom");
117 }
118
119 /**
120 * Get class name for given class ID
121 */
122 const TCHAR *NetObj::getObjectClassName(int objectClass)
123 {
124 return ((objectClass >= 0) && (objectClass < sizeof(s_className) / sizeof(const TCHAR *))) ? s_className[objectClass] : _T("Custom");
125 }
126
127 /**
128 * Create object from database data
129 */
130 bool NetObj::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
131 {
132 return false; // Abstract objects cannot be loaded from database
133 }
134
135 /**
136 * Save object to database
137 */
138 BOOL NetObj::saveToDatabase(DB_HANDLE hdb)
139 {
140 return FALSE; // Abstract objects cannot be saved to database
141 }
142
143 /**
144 * Parameters for DeleteModuleDataCallback and SaveModuleDataCallback
145 */
146 struct ModuleDataDatabaseCallbackParams
147 {
148 UINT32 id;
149 DB_HANDLE hdb;
150 };
151
152 /**
153 * Callback for deleting module data from database
154 */
155 static EnumerationCallbackResult DeleteModuleDataCallback(const TCHAR *key, const void *value, void *data)
156 {
157 return ((ModuleData *)value)->deleteFromDatabase(((ModuleDataDatabaseCallbackParams *)data)->hdb, ((ModuleDataDatabaseCallbackParams *)data)->id) ? _CONTINUE : _STOP;
158 }
159
160 /**
161 * Delete object from database
162 */
163 bool NetObj::deleteFromDatabase(DB_HANDLE hdb)
164 {
165 // Delete ACL
166 bool success = executeQueryOnObject(hdb, _T("DELETE FROM acl WHERE object_id=?"));
167 if (success)
168 success = executeQueryOnObject(hdb, _T("DELETE FROM object_properties WHERE object_id=?"));
169 if (success)
170 success = executeQueryOnObject(hdb, _T("DELETE FROM object_custom_attributes WHERE object_id=?"));
171
172 // Delete events
173 if (success && ConfigReadInt(_T("DeleteEventsOfDeletedObject"), 1))
174 {
175 success = executeQueryOnObject(hdb, _T("DELETE FROM event_log WHERE event_source=?"));
176 }
177
178 // Delete alarms
179 if (success && ConfigReadInt(_T("DeleteAlarmsOfDeletedObject"), 1))
180 {
181 success = DeleteObjectAlarms(m_id, hdb);
182 }
183
184 // Delete module data
185 if (success && (m_moduleData != NULL))
186 {
187 ModuleDataDatabaseCallbackParams data;
188 data.id = m_id;
189 data.hdb = hdb;
190 success = (m_moduleData->forEach(DeleteModuleDataCallback, &data) == _CONTINUE);
191 }
192
193 return success;
194 }
195
196 /**
197 * Load common object properties from database
198 */
199 bool NetObj::loadCommonProperties(DB_HANDLE hdb)
200 {
201 bool success = false;
202
203 // Load access options
204 DB_STATEMENT hStmt = DBPrepare(hdb,
205 _T("SELECT name,status,is_deleted,")
206 _T("inherit_access_rights,last_modified,status_calc_alg,")
207 _T("status_prop_alg,status_fixed_val,status_shift,")
208 _T("status_translation,status_single_threshold,")
209 _T("status_thresholds,comments,is_system,")
210 _T("location_type,latitude,longitude,location_accuracy,")
211 _T("location_timestamp,guid,image,submap_id,country,city,")
212 _T("street_address,postcode,maint_mode,maint_event_id FROM object_properties ")
213 _T("WHERE object_id=?"));
214 if (hStmt != NULL)
215 {
216 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
217 DB_RESULT hResult = DBSelectPrepared(hStmt);
218 if (hResult != NULL)
219 {
220 if (DBGetNumRows(hResult) > 0)
221 {
222 DBGetField(hResult, 0, 0, m_name, MAX_OBJECT_NAME);
223 m_status = DBGetFieldLong(hResult, 0, 1);
224 m_isDeleted = DBGetFieldLong(hResult, 0, 2) ? true : false;
225 m_inheritAccessRights = DBGetFieldLong(hResult, 0, 3) ? true : false;
226 m_dwTimeStamp = DBGetFieldULong(hResult, 0, 4);
227 m_statusCalcAlg = DBGetFieldLong(hResult, 0, 5);
228 m_statusPropAlg = DBGetFieldLong(hResult, 0, 6);
229 m_fixedStatus = DBGetFieldLong(hResult, 0, 7);
230 m_statusShift = DBGetFieldLong(hResult, 0, 8);
231 DBGetFieldByteArray(hResult, 0, 9, m_statusTranslation, 4, STATUS_WARNING);
232 m_statusSingleThreshold = DBGetFieldLong(hResult, 0, 10);
233 DBGetFieldByteArray(hResult, 0, 11, m_statusThresholds, 4, 50);
234 safe_free(m_comments);
235 m_comments = DBGetField(hResult, 0, 12, NULL, 0);
236 m_isSystem = DBGetFieldLong(hResult, 0, 13) ? true : false;
237
238 int locType = DBGetFieldLong(hResult, 0, 14);
239 if (locType != GL_UNSET)
240 {
241 TCHAR lat[32], lon[32];
242
243 DBGetField(hResult, 0, 15, lat, 32);
244 DBGetField(hResult, 0, 16, lon, 32);
245 m_geoLocation = GeoLocation(locType, lat, lon, DBGetFieldLong(hResult, 0, 17), DBGetFieldULong(hResult, 0, 18));
246 }
247 else
248 {
249 m_geoLocation = GeoLocation();
250 }
251
252 m_guid = DBGetFieldGUID(hResult, 0, 19);
253 m_image = DBGetFieldGUID(hResult, 0, 20);
254 m_submapId = DBGetFieldULong(hResult, 0, 21);
255
256 TCHAR country[64], city[64], streetAddress[256], postcode[32];
257 DBGetField(hResult, 0, 22, country, 64);
258 DBGetField(hResult, 0, 23, city, 64);
259 DBGetField(hResult, 0, 24, streetAddress, 256);
260 DBGetField(hResult, 0, 25, postcode, 32);
261 delete m_postalAddress;
262 m_postalAddress = new PostalAddress(country, city, streetAddress, postcode);
263
264 m_maintenanceMode = DBGetFieldLong(hResult, 0, 26) ? true : false;
265 m_maintenanceEventId = DBGetFieldUInt64(hResult, 0, 27);
266
267 success = true;
268 }
269 DBFreeResult(hResult);
270 }
271 DBFreeStatement(hStmt);
272 }
273
274 // Load custom attributes
275 if (success)
276 {
277 hStmt = DBPrepare(hdb, _T("SELECT attr_name,attr_value FROM object_custom_attributes WHERE object_id=?"));
278 if (hStmt != NULL)
279 {
280 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
281 DB_RESULT hResult = DBSelectPrepared(hStmt);
282 if (hResult != NULL)
283 {
284 int i, count;
285 TCHAR *name, *value;
286
287 count = DBGetNumRows(hResult);
288 for(i = 0; i < count; i++)
289 {
290 name = DBGetField(hResult, i, 0, NULL, 0);
291 if (name != NULL)
292 {
293 value = DBGetField(hResult, i, 1, NULL, 0);
294 if (value != NULL)
295 {
296 m_customAttributes.setPreallocated(name, value);
297 }
298 }
299 }
300 DBFreeResult(hResult);
301 }
302 else
303 {
304 success = false;
305 }
306 DBFreeStatement(hStmt);
307 }
308 else
309 {
310 success = false;
311 }
312 }
313
314 // Load associated dashboards
315 if (success)
316 {
317 hStmt = DBPrepare(hdb, _T("SELECT dashboard_id FROM dashboard_associations WHERE object_id=?"));
318 if (hStmt != NULL)
319 {
320 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
321 DB_RESULT hResult = DBSelectPrepared(hStmt);
322 if (hResult != NULL)
323 {
324 int count = DBGetNumRows(hResult);
325 for(int i = 0; i < count; i++)
326 {
327 m_dashboards->add(DBGetFieldULong(hResult, i, 0));
328 }
329 DBFreeResult(hResult);
330 }
331 else
332 {
333 success = false;
334 }
335 DBFreeStatement(hStmt);
336 }
337 else
338 {
339 success = false;
340 }
341 }
342
343 if (success)
344 success = loadTrustedNodes(hdb);
345
346 if (!success)
347 DbgPrintf(4, _T("NetObj::loadCommonProperties() failed for object %s [%ld] class=%d"), m_name, (long)m_id, getObjectClass());
348
349 return success;
350 }
351
352 /**
353 * Callback for saving custom attribute in database
354 */
355 static EnumerationCallbackResult SaveAttributeCallback(const TCHAR *key, const void *value, void *data)
356 {
357 DB_STATEMENT hStmt = (DB_STATEMENT)data;
358 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, key, DB_BIND_STATIC);
359 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, (const TCHAR *)value, DB_BIND_STATIC);
360 return DBExecute(hStmt) ? _CONTINUE : _STOP;
361 }
362
363 /**
364 * Callback for saving module data in database
365 */
366 static EnumerationCallbackResult SaveModuleDataCallback(const TCHAR *key, const void *value, void *data)
367 {
368 return ((ModuleData *)value)->saveToDatabase(((ModuleDataDatabaseCallbackParams *)data)->hdb, ((ModuleDataDatabaseCallbackParams *)data)->id) ? _CONTINUE : _STOP;
369 }
370
371 /**
372 * Save common object properties to database
373 */
374 bool NetObj::saveCommonProperties(DB_HANDLE hdb)
375 {
376 DB_STATEMENT hStmt;
377 if (IsDatabaseRecordExist(hdb, _T("object_properties"), _T("object_id"), m_id))
378 {
379 hStmt = DBPrepare(hdb,
380 _T("UPDATE object_properties SET name=?,status=?,")
381 _T("is_deleted=?,inherit_access_rights=?,")
382 _T("last_modified=?,status_calc_alg=?,status_prop_alg=?,")
383 _T("status_fixed_val=?,status_shift=?,status_translation=?,")
384 _T("status_single_threshold=?,status_thresholds=?,")
385 _T("comments=?,is_system=?,location_type=?,latitude=?,")
386 _T("longitude=?,location_accuracy=?,location_timestamp=?,")
387 _T("guid=?,image=?,submap_id=?,country=?,city=?,")
388 _T("street_address=?,postcode=?,maint_mode=?,maint_event_id=? WHERE object_id=?"));
389 }
390 else
391 {
392 hStmt = DBPrepare(hdb,
393 _T("INSERT INTO object_properties (name,status,is_deleted,")
394 _T("inherit_access_rights,last_modified,status_calc_alg,")
395 _T("status_prop_alg,status_fixed_val,status_shift,status_translation,")
396 _T("status_single_threshold,status_thresholds,comments,is_system,")
397 _T("location_type,latitude,longitude,location_accuracy,location_timestamp,")
398 _T("guid,image,submap_id,country,city,street_address,postcode,maint_mode,")
399 _T("maint_event_id,object_id) ")
400 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
401 }
402 if (hStmt == NULL)
403 return false;
404
405 TCHAR szTranslation[16], szThresholds[16], lat[32], lon[32];
406 for(int i = 0, j = 0; i < 4; i++, j += 2)
407 {
408 _sntprintf(&szTranslation[j], 16 - j, _T("%02X"), (BYTE)m_statusTranslation[i]);
409 _sntprintf(&szThresholds[j], 16 - j, _T("%02X"), (BYTE)m_statusThresholds[i]);
410 }
411 _sntprintf(lat, 32, _T("%f"), m_geoLocation.getLatitude());
412 _sntprintf(lon, 32, _T("%f"), m_geoLocation.getLongitude());
413
414 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_name, DB_BIND_STATIC);
415 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (LONG)m_status);
416 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)(m_isDeleted ? 1 : 0));
417 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (LONG)(m_inheritAccessRights ? 1 : 0));
418 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_dwTimeStamp);
419 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (LONG)m_statusCalcAlg);
420 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (LONG)m_statusPropAlg);
421 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_fixedStatus);
422 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_statusShift);
423 DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, szTranslation, DB_BIND_STATIC);
424 DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, (LONG)m_statusSingleThreshold);
425 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, szThresholds, DB_BIND_STATIC);
426 DBBind(hStmt, 13, DB_SQLTYPE_VARCHAR, m_comments, DB_BIND_STATIC);
427 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, (LONG)(m_isSystem ? 1 : 0));
428 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getType());
429 DBBind(hStmt, 16, DB_SQLTYPE_VARCHAR, lat, DB_BIND_STATIC);
430 DBBind(hStmt, 17, DB_SQLTYPE_VARCHAR, lon, DB_BIND_STATIC);
431 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getAccuracy());
432 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
433 DBBind(hStmt, 20, DB_SQLTYPE_VARCHAR, m_guid);
434 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, m_image);
435 DBBind(hStmt, 22, DB_SQLTYPE_INTEGER, m_submapId);
436 DBBind(hStmt, 23, DB_SQLTYPE_VARCHAR, m_postalAddress->getCountry(), DB_BIND_STATIC);
437 DBBind(hStmt, 24, DB_SQLTYPE_VARCHAR, m_postalAddress->getCity(), DB_BIND_STATIC);
438 DBBind(hStmt, 25, DB_SQLTYPE_VARCHAR, m_postalAddress->getStreetAddress(), DB_BIND_STATIC);
439 DBBind(hStmt, 26, DB_SQLTYPE_VARCHAR, m_postalAddress->getPostCode(), DB_BIND_STATIC);
440 DBBind(hStmt, 27, DB_SQLTYPE_VARCHAR, m_maintenanceMode ? _T("1") : _T("0"), DB_BIND_STATIC);
441 DBBind(hStmt, 28, DB_SQLTYPE_BIGINT, m_maintenanceEventId);
442 DBBind(hStmt, 29, DB_SQLTYPE_INTEGER, m_id);
443
444 bool success = DBExecute(hStmt);
445 DBFreeStatement(hStmt);
446
447 // Save custom attributes
448 if (success)
449 {
450 TCHAR szQuery[512];
451 _sntprintf(szQuery, 512, _T("DELETE FROM object_custom_attributes WHERE object_id=%d"), m_id);
452 success = DBQuery(hdb, szQuery);
453 if (success)
454 {
455 hStmt = DBPrepare(hdb, _T("INSERT INTO object_custom_attributes (object_id,attr_name,attr_value) VALUES (?,?,?)"));
456 if (hStmt != NULL)
457 {
458 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
459 success = (m_customAttributes.forEach(SaveAttributeCallback, hStmt) == _CONTINUE);
460 DBFreeStatement(hStmt);
461 }
462 else
463 {
464 success = false;
465 }
466 }
467 }
468
469 // Save dashboard associations
470 if (success)
471 {
472 TCHAR szQuery[512];
473 _sntprintf(szQuery, 512, _T("DELETE FROM dashboard_associations WHERE object_id=%d"), m_id);
474 success = DBQuery(hdb, szQuery);
475 if (success && (m_dashboards->size() > 0))
476 {
477 hStmt = DBPrepare(hdb, _T("INSERT INTO dashboard_associations (object_id,dashboard_id) VALUES (?,?)"));
478 if (hStmt != NULL)
479 {
480 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
481 for(int i = 0; (i < m_dashboards->size()) && success; i++)
482 {
483 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_dashboards->get(i));
484 success = DBExecute(hStmt);
485 }
486 DBFreeStatement(hStmt);
487 }
488 else
489 {
490 success = false;
491 }
492 }
493 }
494
495 // Save module data
496 if (success && (m_moduleData != NULL))
497 {
498 ModuleDataDatabaseCallbackParams data;
499 data.id = m_id;
500 data.hdb = hdb;
501 success = (m_moduleData->forEach(SaveModuleDataCallback, &data) == _CONTINUE);
502 }
503
504 if (success)
505 success = saveTrustedNodes(hdb);
506
507 return success;
508 }
509
510 /**
511 * Add reference to the new child object
512 */
513 void NetObj::addChild(NetObj *object)
514 {
515 lockChildList(true);
516 if (m_childList->contains(object))
517 {
518 unlockChildList();
519 return; // Already in the child list
520 }
521 m_childList->add(object);
522 unlockChildList();
523 incRefCount();
524 setModified();
525 DbgPrintf(7, _T("NetObj::addChild: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
526 }
527
528 /**
529 * Add reference to parent object
530 */
531 void NetObj::addParent(NetObj *object)
532 {
533 lockParentList(true);
534 if (m_parentList->contains(object))
535 {
536 unlockParentList();
537 return; // Already in the parents list
538 }
539 m_parentList->add(object);
540 unlockParentList();
541 incRefCount();
542 setModified();
543 DbgPrintf(7, _T("NetObj::addParent: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
544 }
545
546 /**
547 * Delete reference to child object
548 */
549 void NetObj::deleteChild(NetObj *object)
550 {
551 int i;
552
553 lockChildList(true);
554 for(i = 0; i < m_childList->size(); i++)
555 if (m_childList->get(i) == object)
556 break;
557
558 if (i == m_childList->size()) // No such object
559 {
560 unlockChildList();
561 return;
562 }
563
564 DbgPrintf(7, _T("NetObj::deleteChild: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
565 m_childList->remove(i);
566 unlockChildList();
567 decRefCount();
568 setModified();
569 }
570
571 /**
572 * Delete reference to parent object
573 */
574 void NetObj::deleteParent(NetObj *object)
575 {
576 int i;
577
578 lockParentList(true);
579 for(i = 0; i < m_parentList->size(); i++)
580 if (m_parentList->get(i) == object)
581 break;
582 if (i == m_parentList->size()) // No such object
583 {
584 unlockParentList();
585 return;
586 }
587
588 DbgPrintf(7, _T("NetObj::deleteParent: this=%s [%d]; object=%s [%d]"), m_name, m_id, object->m_name, object->m_id);
589
590 m_parentList->remove(i);
591 unlockParentList();
592 decRefCount();
593 setModified();
594 }
595
596 /**
597 * Walker callback to call OnObjectDelete for each active object
598 */
599 void NetObj::onObjectDeleteCallback(NetObj *object, void *data)
600 {
601 UINT32 currId = ((NetObj *)data)->getId();
602 if ((object->getId() != currId) && !object->isDeleted())
603 object->onObjectDelete(currId);
604 }
605
606 /**
607 * Prepare object for deletion - remove all references, etc.
608 *
609 * @param initiator pointer to parent object which causes recursive deletion or NULL
610 */
611 void NetObj::deleteObject(NetObj *initiator)
612 {
613 DbgPrintf(4, _T("Deleting object %d [%s]"), m_id, m_name);
614
615 // Prevent object change propagation until it's marked as deleted
616 // (to prevent the object's incorrect appearance in GUI
617 lockProperties();
618 m_isHidden = true;
619 unlockProperties();
620
621 // Notify modules about object deletion
622 CALL_ALL_MODULES(pfPreObjectDelete, (this));
623
624 prepareForDeletion();
625
626 DbgPrintf(5, _T("NetObj::deleteObject(): deleting object %d from indexes"), m_id);
627 NetObjDeleteFromIndexes(this);
628
629 // Delete references to this object from child objects
630 DbgPrintf(5, _T("NetObj::deleteObject(): clearing child list for object %d"), m_id);
631 ObjectArray<NetObj> *deleteList = NULL;
632 lockChildList(true);
633 for(int i = 0; i < m_childList->size(); i++)
634 {
635 NetObj *o = m_childList->get(i);
636 if (o->getParentCount() == 1)
637 {
638 // last parent, delete object
639 if (deleteList == NULL)
640 deleteList = new ObjectArray<NetObj>(16, 16, false);
641 deleteList->add(o);
642 }
643 else
644 {
645 o->deleteParent(this);
646 }
647 decRefCount();
648 }
649 m_childList->clear();
650 unlockChildList();
651
652 // Delete orphaned child objects
653 if (deleteList != NULL)
654 {
655 for(int i = 0; i < deleteList->size(); i++)
656 {
657 NetObj *obj = deleteList->get(i);
658 DbgPrintf(5, _T("NetObj::deleteObject(): calling deleteObject() on %s [%d]"), obj->getName(), obj->getId());
659 obj->deleteObject(this);
660 }
661 delete deleteList;
662 }
663
664 // Remove references to this object from parent objects
665 DbgPrintf(5, _T("NetObj::Delete(): clearing parent list for object %d"), m_id);
666 lockParentList(true);
667 for(int i = 0; i < m_parentList->size(); i++)
668 {
669 // If parent is deletion initiator then this object already
670 // removed from parent's list
671 NetObj *obj = m_parentList->get(i);
672 if (obj != initiator)
673 {
674 obj->deleteChild(this);
675 obj->calculateCompoundStatus();
676 }
677 decRefCount();
678 }
679 m_parentList->clear();
680 unlockParentList();
681
682 lockProperties();
683 m_isHidden = false;
684 m_isDeleted = true;
685 setModified();
686 unlockProperties();
687
688 // Notify all other objects about object deletion
689 DbgPrintf(5, _T("NetObj::deleteObject(): calling onObjectDelete(%d)"), m_id);
690 g_idxObjectById.forEach(onObjectDeleteCallback, this);
691
692 DbgPrintf(4, _T("Object %d successfully deleted"), m_id);
693 }
694
695 /**
696 * Default handler for object deletion notification
697 */
698 void NetObj::onObjectDelete(UINT32 dwObjectId)
699 {
700 }
701
702 /**
703 * Get childs IDs in printable form
704 */
705 const TCHAR *NetObj::dbgGetChildList(TCHAR *szBuffer)
706 {
707 TCHAR *pBuf = szBuffer;
708 *pBuf = 0;
709 lockChildList(false);
710 for(int i = 0; i < m_childList->size(); i++)
711 {
712 _sntprintf(pBuf, 10, _T("%d "), m_childList->get(i)->getId());
713 while(*pBuf)
714 pBuf++;
715 }
716 unlockChildList();
717 if (pBuf != szBuffer)
718 *(pBuf - 1) = 0;
719 return szBuffer;
720 }
721
722 /**
723 * Get parents IDs in printable form
724 */
725 const TCHAR *NetObj::dbgGetParentList(TCHAR *szBuffer)
726 {
727 TCHAR *pBuf = szBuffer;
728 *pBuf = 0;
729 lockParentList(false);
730 for(int i = 0; i < m_parentList->size(); i++)
731 {
732 _sntprintf(pBuf, 10, _T("%d "), m_parentList->get(i)->getId());
733 while(*pBuf)
734 pBuf++;
735 }
736 unlockParentList();
737 if (pBuf != szBuffer)
738 *(pBuf - 1) = 0;
739 return szBuffer;
740 }
741
742 /**
743 * Calculate status for compound object based on childs' status
744 */
745 void NetObj::calculateCompoundStatus(BOOL bForcedRecalc)
746 {
747 if (m_status == STATUS_UNMANAGED)
748 return;
749
750 int mostCriticalAlarm = GetMostCriticalStatusForObject(m_id);
751 int mostCriticalDCI =
752 (getObjectClass() == OBJECT_NODE || getObjectClass() == OBJECT_MOBILEDEVICE || getObjectClass() == OBJECT_CLUSTER || getObjectClass() == OBJECT_ACCESSPOINT) ?
753 ((DataCollectionTarget *)this)->getMostCriticalDCIStatus() : STATUS_UNKNOWN;
754
755 int oldStatus = m_status;
756 int mostCriticalStatus, i, count, iStatusAlg;
757 int nSingleThreshold, *pnThresholds;
758 int nRating[5], iChildStatus, nThresholds[4];
759
760 lockProperties();
761 if (m_statusCalcAlg == SA_CALCULATE_DEFAULT)
762 {
763 iStatusAlg = GetDefaultStatusCalculation(&nSingleThreshold, &pnThresholds);
764 }
765 else
766 {
767 iStatusAlg = m_statusCalcAlg;
768 nSingleThreshold = m_statusSingleThreshold;
769 pnThresholds = m_statusThresholds;
770 }
771 if (iStatusAlg == SA_CALCULATE_SINGLE_THRESHOLD)
772 {
773 for(i = 0; i < 4; i++)
774 nThresholds[i] = nSingleThreshold;
775 pnThresholds = nThresholds;
776 }
777
778 switch(iStatusAlg)
779 {
780 case SA_CALCULATE_MOST_CRITICAL:
781 lockChildList(false);
782 for(i = 0, count = 0, mostCriticalStatus = -1; i < m_childList->size(); i++)
783 {
784 iChildStatus = m_childList->get(i)->getPropagatedStatus();
785 if ((iChildStatus < STATUS_UNKNOWN) &&
786 (iChildStatus > mostCriticalStatus))
787 {
788 mostCriticalStatus = iChildStatus;
789 count++;
790 }
791 }
792 m_status = (count > 0) ? mostCriticalStatus : STATUS_UNKNOWN;
793 unlockChildList();
794 break;
795 case SA_CALCULATE_SINGLE_THRESHOLD:
796 case SA_CALCULATE_MULTIPLE_THRESHOLDS:
797 // Step 1: calculate severity raitings
798 memset(nRating, 0, sizeof(int) * 5);
799 lockChildList(false);
800 for(i = 0, count = 0; i < m_childList->size(); i++)
801 {
802 iChildStatus = m_childList->get(i)->getPropagatedStatus();
803 if (iChildStatus < STATUS_UNKNOWN)
804 {
805 while(iChildStatus >= 0)
806 nRating[iChildStatus--]++;
807 count++;
808 }
809 }
810 unlockChildList();
811
812 // Step 2: check what severity rating is above threshold
813 if (count > 0)
814 {
815 for(i = 4; i > 0; i--)
816 if (nRating[i] * 100 / count >= pnThresholds[i - 1])
817 break;
818 m_status = i;
819 }
820 else
821 {
822 m_status = STATUS_UNKNOWN;
823 }
824 break;
825 default:
826 m_status = STATUS_UNKNOWN;
827 break;
828 }
829
830 // If alarms exist for object, apply alarm severity to object's status
831 if (mostCriticalAlarm != STATUS_UNKNOWN)
832 {
833 if (m_status == STATUS_UNKNOWN)
834 {
835 m_status = mostCriticalAlarm;
836 }
837 else
838 {
839 m_status = max(m_status, mostCriticalAlarm);
840 }
841 }
842
843 // If DCI status is calculated for object apply DCI object's statud
844 if (mostCriticalDCI != STATUS_UNKNOWN)
845 {
846 if (m_status == STATUS_UNKNOWN)
847 {
848 m_status = mostCriticalDCI;
849 }
850 else
851 {
852 m_status = max(m_status, mostCriticalDCI);
853 }
854 }
855
856 // Query loaded modules for object status
857 ENUMERATE_MODULES(pfCalculateObjectStatus)
858 {
859 int moduleStatus = g_pModuleList[__i].pfCalculateObjectStatus(this);
860 if (moduleStatus != STATUS_UNKNOWN)
861 {
862 if (m_status == STATUS_UNKNOWN)
863 {
864 m_status = moduleStatus;
865 }
866 else
867 {
868 m_status = max(m_status, moduleStatus);
869 }
870 }
871 }
872
873 unlockProperties();
874
875 // Cause parent object(s) to recalculate it's status
876 if ((oldStatus != m_status) || bForcedRecalc)
877 {
878 lockParentList(false);
879 for(i = 0; i < m_parentList->size(); i++)
880 m_parentList->get(i)->calculateCompoundStatus();
881 unlockParentList();
882 lockProperties();
883 setModified();
884 unlockProperties();
885 }
886 }
887
888 /**
889 * Load ACL from database
890 */
891 bool NetObj::loadACLFromDB(DB_HANDLE hdb)
892 {
893 bool success = false;
894
895 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT user_id,access_rights FROM acl WHERE object_id=?"));
896 if (hStmt != NULL)
897 {
898 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
899 DB_RESULT hResult = DBSelectPrepared(hStmt);
900 if (hResult != NULL)
901 {
902 int count = DBGetNumRows(hResult);
903 for(int i = 0; i < count; i++)
904 m_accessList->addElement(DBGetFieldULong(hResult, i, 0), DBGetFieldULong(hResult, i, 1));
905 DBFreeResult(hResult);
906 success = true;
907 }
908 DBFreeStatement(hStmt);
909 }
910 return success;
911 }
912
913 /**
914 * ACL enumeration parameters structure
915 */
916 struct SAVE_PARAM
917 {
918 DB_HANDLE hdb;
919 UINT32 dwObjectId;
920 };
921
922 /**
923 * Handler for ACL elements enumeration
924 */
925 static void EnumerationHandler(UINT32 dwUserId, UINT32 dwAccessRights, void *pArg)
926 {
927 TCHAR szQuery[256];
928
929 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("INSERT INTO acl (object_id,user_id,access_rights) VALUES (%d,%d,%d)"),
930 ((SAVE_PARAM *)pArg)->dwObjectId, dwUserId, dwAccessRights);
931 DBQuery(((SAVE_PARAM *)pArg)->hdb, szQuery);
932 }
933
934 /**
935 * Save ACL to database
936 */
937 bool NetObj::saveACLToDB(DB_HANDLE hdb)
938 {
939 TCHAR szQuery[256];
940 bool success = false;
941 SAVE_PARAM sp;
942
943 // Save access list
944 lockACL();
945 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM acl WHERE object_id=%d"), m_id);
946 if (DBQuery(hdb, szQuery))
947 {
948 sp.dwObjectId = m_id;
949 sp.hdb = hdb;
950 m_accessList->enumerateElements(EnumerationHandler, &sp);
951 success = true;
952 }
953 unlockACL();
954 return success;
955 }
956
957 /**
958 * Data for SendModuleDataCallback
959 */
960 struct SendModuleDataCallbackData
961 {
962 NXCPMessage *msg;
963 UINT32 id;
964 };
965
966 /**
967 * Callback for sending module data in NXCP message
968 */
969 static EnumerationCallbackResult SendModuleDataCallback(const TCHAR *key, const void *value, void *data)
970 {
971 ((SendModuleDataCallbackData *)data)->msg->setField(((SendModuleDataCallbackData *)data)->id, key);
972 ((ModuleData *)value)->fillMessage(((SendModuleDataCallbackData *)data)->msg, ((SendModuleDataCallbackData *)data)->id + 1);
973 ((SendModuleDataCallbackData *)data)->id += 0x100000;
974 return _CONTINUE;
975 }
976
977 /**
978 * Fill NXCP message with object's data
979 * Object's properties are locked when this method is called. Method should not do any other locks.
980 * Data required other locks should be filled in fillMessageInternalStage2().
981 */
982 void NetObj::fillMessageInternal(NXCPMessage *pMsg)
983 {
984 pMsg->setField(VID_OBJECT_CLASS, (WORD)getObjectClass());
985 pMsg->setField(VID_OBJECT_ID, m_id);
986 pMsg->setField(VID_GUID, m_guid);
987 pMsg->setField(VID_OBJECT_NAME, m_name);
988 pMsg->setField(VID_OBJECT_STATUS, (WORD)m_status);
989 pMsg->setField(VID_IS_DELETED, (WORD)(m_isDeleted ? 1 : 0));
990 pMsg->setField(VID_IS_SYSTEM, (INT16)(m_isSystem ? 1 : 0));
991 pMsg->setField(VID_MAINTENANCE_MODE, (INT16)(m_maintenanceEventId ? 1 : 0));
992
993 pMsg->setField(VID_INHERIT_RIGHTS, m_inheritAccessRights);
994 pMsg->setField(VID_STATUS_CALCULATION_ALG, (WORD)m_statusCalcAlg);
995 pMsg->setField(VID_STATUS_PROPAGATION_ALG, (WORD)m_statusPropAlg);
996 pMsg->setField(VID_FIXED_STATUS, (WORD)m_fixedStatus);
997 pMsg->setField(VID_STATUS_SHIFT, (WORD)m_statusShift);
998 pMsg->setField(VID_STATUS_TRANSLATION_1, (WORD)m_statusTranslation[0]);
999 pMsg->setField(VID_STATUS_TRANSLATION_2, (WORD)m_statusTranslation[1]);
1000 pMsg->setField(VID_STATUS_TRANSLATION_3, (WORD)m_statusTranslation[2]);
1001 pMsg->setField(VID_STATUS_TRANSLATION_4, (WORD)m_statusTranslation[3]);
1002 pMsg->setField(VID_STATUS_SINGLE_THRESHOLD, (WORD)m_statusSingleThreshold);
1003 pMsg->setField(VID_STATUS_THRESHOLD_1, (WORD)m_statusThresholds[0]);
1004 pMsg->setField(VID_STATUS_THRESHOLD_2, (WORD)m_statusThresholds[1]);
1005 pMsg->setField(VID_STATUS_THRESHOLD_3, (WORD)m_statusThresholds[2]);
1006 pMsg->setField(VID_STATUS_THRESHOLD_4, (WORD)m_statusThresholds[3]);
1007 pMsg->setField(VID_COMMENTS, CHECK_NULL_EX(m_comments));
1008 pMsg->setField(VID_IMAGE, m_image);
1009 pMsg->setField(VID_SUBMAP_ID, m_submapId);
1010 pMsg->setField(VID_NUM_TRUSTED_NODES, m_dwNumTrustedNodes);
1011 if (m_dwNumTrustedNodes > 0)
1012 pMsg->setFieldFromInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
1013 pMsg->setFieldFromInt32Array(VID_DASHBOARDS, m_dashboards);
1014
1015 m_customAttributes.fillMessage(pMsg, VID_NUM_CUSTOM_ATTRIBUTES, VID_CUSTOM_ATTRIBUTES_BASE);
1016
1017 m_geoLocation.fillMessage(*pMsg);
1018
1019 pMsg->setField(VID_COUNTRY, m_postalAddress->getCountry());
1020 pMsg->setField(VID_CITY, m_postalAddress->getCity());
1021 pMsg->setField(VID_STREET_ADDRESS, m_postalAddress->getStreetAddress());
1022 pMsg->setField(VID_POSTCODE, m_postalAddress->getPostCode());
1023
1024 if (m_moduleData != NULL)
1025 {
1026 pMsg->setField(VID_MODULE_DATA_COUNT, (UINT16)m_moduleData->size());
1027 SendModuleDataCallbackData data;
1028 data.msg = pMsg;
1029 data.id = VID_MODULE_DATA_BASE;
1030 m_moduleData->forEach(SendModuleDataCallback, &data);
1031 }
1032 else
1033 {
1034 pMsg->setField(VID_MODULE_DATA_COUNT, (UINT16)0);
1035 }
1036 }
1037
1038 /**
1039 * Fill NXCP message with object's data - stage 2
1040 * Object's properties are not locked when this method is called. Should be
1041 * used only to fill data where properties lock is not enough (like data
1042 * collection configuration).
1043 */
1044 void NetObj::fillMessageInternalStage2(NXCPMessage *pMsg)
1045 {
1046 }
1047
1048 /**
1049 * Fill NXCP message with object's data
1050 */
1051 void NetObj::fillMessage(NXCPMessage *msg)
1052 {
1053 lockProperties();
1054 fillMessageInternal(msg);
1055 unlockProperties();
1056 fillMessageInternalStage2(msg);
1057
1058 lockACL();
1059 m_accessList->fillMessage(msg);
1060 unlockACL();
1061
1062 UINT32 dwId;
1063 int i;
1064
1065 lockParentList(false);
1066 msg->setField(VID_PARENT_CNT, m_parentList->size());
1067 for(i = 0, dwId = VID_PARENT_ID_BASE; i < m_parentList->size(); i++, dwId++)
1068 msg->setField(dwId, m_parentList->get(i)->getId());
1069 unlockParentList();
1070
1071 lockChildList(false);
1072 msg->setField(VID_CHILD_CNT, m_childList->size());
1073 for(i = 0, dwId = VID_CHILD_ID_BASE; i < m_childList->size(); i++, dwId++)
1074 msg->setField(dwId, m_childList->get(i)->getId());
1075 unlockChildList();
1076 }
1077
1078 /**
1079 * Handler for EnumerateSessions()
1080 */
1081 static void BroadcastObjectChange(ClientSession *pSession, void *pArg)
1082 {
1083 if (pSession->isAuthenticated())
1084 pSession->onObjectChange((NetObj *)pArg);
1085 }
1086
1087 /**
1088 * Mark object as modified and put on client's notification queue
1089 * We assume that object is locked at the time of function call
1090 */
1091 void NetObj::setModified(bool notify)
1092 {
1093 if (g_bModificationsLocked)
1094 return;
1095
1096 m_isModified = true;
1097 m_dwTimeStamp = (UINT32)time(NULL);
1098
1099 // Send event to all connected clients
1100 if (notify && !m_isHidden && !m_isSystem)
1101 EnumerateClientSessions(BroadcastObjectChange, this);
1102 }
1103
1104 /**
1105 * Modify object from NXCP message - common wrapper
1106 */
1107 UINT32 NetObj::modifyFromMessage(NXCPMessage *msg)
1108 {
1109 lockProperties();
1110 UINT32 rcc = modifyFromMessageInternal(msg);
1111 setModified();
1112 unlockProperties();
1113 return rcc;
1114 }
1115
1116 /**
1117 * Modify object from NXCP message
1118 */
1119 UINT32 NetObj::modifyFromMessageInternal(NXCPMessage *pRequest)
1120 {
1121 // Change object's name
1122 if (pRequest->isFieldExist(VID_OBJECT_NAME))
1123 pRequest->getFieldAsString(VID_OBJECT_NAME, m_name, MAX_OBJECT_NAME);
1124
1125 // Change object's status calculation/propagation algorithms
1126 if (pRequest->isFieldExist(VID_STATUS_CALCULATION_ALG))
1127 {
1128 m_statusCalcAlg = pRequest->getFieldAsInt16(VID_STATUS_CALCULATION_ALG);
1129 m_statusPropAlg = pRequest->getFieldAsInt16(VID_STATUS_PROPAGATION_ALG);
1130 m_fixedStatus = pRequest->getFieldAsInt16(VID_FIXED_STATUS);
1131 m_statusShift = pRequest->getFieldAsInt16(VID_STATUS_SHIFT);
1132 m_statusTranslation[0] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_1);
1133 m_statusTranslation[1] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_2);
1134 m_statusTranslation[2] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_3);
1135 m_statusTranslation[3] = pRequest->getFieldAsInt16(VID_STATUS_TRANSLATION_4);
1136 m_statusSingleThreshold = pRequest->getFieldAsInt16(VID_STATUS_SINGLE_THRESHOLD);
1137 m_statusThresholds[0] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_1);
1138 m_statusThresholds[1] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_2);
1139 m_statusThresholds[2] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_3);
1140 m_statusThresholds[3] = pRequest->getFieldAsInt16(VID_STATUS_THRESHOLD_4);
1141 }
1142
1143 // Change image
1144 if (pRequest->isFieldExist(VID_IMAGE))
1145 m_image = pRequest->getFieldAsGUID(VID_IMAGE);
1146
1147 // Change object's ACL
1148 if (pRequest->isFieldExist(VID_ACL_SIZE))
1149 {
1150 lockACL();
1151 m_inheritAccessRights = pRequest->getFieldAsBoolean(VID_INHERIT_RIGHTS);
1152 m_accessList->deleteAll();
1153 int count = pRequest->getFieldAsUInt32(VID_ACL_SIZE);
1154 for(int i = 0; i < count; i++)
1155 m_accessList->addElement(pRequest->getFieldAsUInt32(VID_ACL_USER_BASE + i),
1156 pRequest->getFieldAsUInt32(VID_ACL_RIGHTS_BASE + i));
1157 unlockACL();
1158 }
1159
1160 // Change trusted nodes list
1161 if (pRequest->isFieldExist(VID_NUM_TRUSTED_NODES))
1162 {
1163 m_dwNumTrustedNodes = pRequest->getFieldAsUInt32(VID_NUM_TRUSTED_NODES);
1164 m_pdwTrustedNodes = (UINT32 *)realloc(m_pdwTrustedNodes, sizeof(UINT32) * m_dwNumTrustedNodes);
1165 pRequest->getFieldAsInt32Array(VID_TRUSTED_NODES, m_dwNumTrustedNodes, m_pdwTrustedNodes);
1166 }
1167
1168 // Change custom attributes
1169 if (pRequest->isFieldExist(VID_NUM_CUSTOM_ATTRIBUTES))
1170 {
1171 UINT32 i, dwId, dwNumElements;
1172 TCHAR *name, *value;
1173
1174 dwNumElements = pRequest->getFieldAsUInt32(VID_NUM_CUSTOM_ATTRIBUTES);
1175 m_customAttributes.clear();
1176 for(i = 0, dwId = VID_CUSTOM_ATTRIBUTES_BASE; i < dwNumElements; i++)
1177 {
1178 name = pRequest->getFieldAsString(dwId++);
1179 value = pRequest->getFieldAsString(dwId++);
1180 if ((name != NULL) && (value != NULL))
1181 m_customAttributes.setPreallocated(name, value);
1182 }
1183 }
1184
1185 // Change geolocation
1186 if (pRequest->isFieldExist(VID_GEOLOCATION_TYPE))
1187 {
1188 m_geoLocation = GeoLocation(*pRequest);
1189 addLocationToHistory();
1190 }
1191
1192 if (pRequest->isFieldExist(VID_SUBMAP_ID))
1193 {
1194 m_submapId = pRequest->getFieldAsUInt32(VID_SUBMAP_ID);
1195 }
1196
1197 if (pRequest->isFieldExist(VID_COUNTRY))
1198 {
1199 TCHAR buffer[64];
1200 pRequest->getFieldAsString(VID_COUNTRY, buffer, 64);
1201 m_postalAddress->setCountry(buffer);
1202 }
1203
1204 if (pRequest->isFieldExist(VID_CITY))
1205 {
1206 TCHAR buffer[64];
1207 pRequest->getFieldAsString(VID_CITY, buffer, 64);
1208 m_postalAddress->setCity(buffer);
1209 }
1210
1211 if (pRequest->isFieldExist(VID_STREET_ADDRESS))
1212 {
1213 TCHAR buffer[256];
1214 pRequest->getFieldAsString(VID_STREET_ADDRESS, buffer, 256);
1215 m_postalAddress->setStreetAddress(buffer);
1216 }
1217
1218 if (pRequest->isFieldExist(VID_POSTCODE))
1219 {
1220 TCHAR buffer[32];
1221 pRequest->getFieldAsString(VID_POSTCODE, buffer, 32);
1222 m_postalAddress->setPostCode(buffer);
1223 }
1224
1225 // Change dashboard list
1226 if (pRequest->isFieldExist(VID_DASHBOARDS))
1227 {
1228 pRequest->getFieldAsInt32Array(VID_DASHBOARDS, m_dashboards);
1229 }
1230
1231 return RCC_SUCCESS;
1232 }
1233
1234 /**
1235 * Post-modify hook
1236 */
1237 void NetObj::postModify()
1238 {
1239 calculateCompoundStatus(TRUE);
1240 }
1241
1242 /**
1243 * Get rights to object for specific user
1244 *
1245 * @param userId user object ID
1246 */
1247 UINT32 NetObj::getUserRights(UINT32 userId)
1248 {
1249 UINT32 dwRights;
1250
1251 // Admin always has all rights to any object
1252 if (userId == 0)
1253 return 0xFFFFFFFF;
1254
1255 // Non-admin users have no rights to system objects
1256 if (m_isSystem)
1257 return 0;
1258
1259 // Check if have direct right assignment
1260 lockACL();
1261 bool hasDirectRights = m_accessList->getUserRights(userId, &dwRights);
1262 unlockACL();
1263
1264 if (!hasDirectRights)
1265 {
1266 // We don't. If this object inherit rights from parents, get them
1267 if (m_inheritAccessRights)
1268 {
1269 dwRights = 0;
1270 lockParentList(false);
1271 for(int i = 0; i < m_parentList->size(); i++)
1272 dwRights |= m_parentList->get(i)->getUserRights(userId);
1273 unlockParentList();
1274 }
1275 }
1276
1277 return dwRights;
1278 }
1279
1280 /**
1281 * Check if given user has specific rights on this object
1282 *
1283 * @param userId user object ID
1284 * @param requiredRights bit mask of requested right
1285 * @return true if user has all rights specified in requested rights bit mask
1286 */
1287 BOOL NetObj::checkAccessRights(UINT32 userId, UINT32 requiredRights)
1288 {
1289 UINT32 effectiveRights = getUserRights(userId);
1290 return (effectiveRights & requiredRights) == requiredRights;
1291 }
1292
1293 /**
1294 * Drop all user privileges on current object
1295 */
1296 void NetObj::dropUserAccess(UINT32 dwUserId)
1297 {
1298 lockACL();
1299 bool modified = m_accessList->deleteElement(dwUserId);
1300 unlockACL();
1301 if (modified)
1302 {
1303 lockProperties();
1304 setModified();
1305 unlockProperties();
1306 }
1307 }
1308
1309 /**
1310 * Set object's management status
1311 */
1312 void NetObj::setMgmtStatus(BOOL bIsManaged)
1313 {
1314 int oldStatus;
1315
1316 lockProperties();
1317
1318 if ((bIsManaged && (m_status != STATUS_UNMANAGED)) ||
1319 ((!bIsManaged) && (m_status == STATUS_UNMANAGED)))
1320 {
1321 unlockProperties();
1322 return; // Status is already correct
1323 }
1324
1325 oldStatus = m_status;
1326 m_status = (bIsManaged ? STATUS_UNKNOWN : STATUS_UNMANAGED);
1327
1328 // Generate event if current object is a node
1329 if (getObjectClass() == OBJECT_NODE)
1330 PostEvent(bIsManaged ? EVENT_NODE_UNKNOWN : EVENT_NODE_UNMANAGED, m_id, "d", oldStatus);
1331
1332 setModified();
1333 unlockProperties();
1334
1335 // Change status for child objects also
1336 lockChildList(false);
1337 for(int i = 0; i < m_childList->size(); i++)
1338 m_childList->get(i)->setMgmtStatus(bIsManaged);
1339 unlockChildList();
1340
1341 // Cause parent object(s) to recalculate it's status
1342 lockParentList(false);
1343 for(int i = 0; i < m_parentList->size(); i++)
1344 m_parentList->get(i)->calculateCompoundStatus();
1345 unlockParentList();
1346 }
1347
1348 /**
1349 * Check if given object is an our child (possibly indirect, i.e child of child)
1350 *
1351 * @param id object ID to test
1352 */
1353 bool NetObj::isChild(UINT32 id)
1354 {
1355 bool bResult = false;
1356
1357 // Check for our own ID (object ID should never change, so we may not lock object's data)
1358 if (m_id == id)
1359 bResult = true;
1360
1361 // First, walk through our own child list
1362 if (!bResult)
1363 {
1364 lockChildList(false);
1365 for(int i = 0; i < m_childList->size(); i++)
1366 if (m_childList->get(i)->getId() == id)
1367 {
1368 bResult = true;
1369 break;
1370 }
1371 unlockChildList();
1372 }
1373
1374 // If given object is not in child list, check if it is indirect child
1375 if (!bResult)
1376 {
1377 lockChildList(false);
1378 for(int i = 0; i < m_childList->size(); i++)
1379 if (m_childList->get(i)->isChild(id))
1380 {
1381 bResult = true;
1382 break;
1383 }
1384 unlockChildList();
1385 }
1386
1387 return bResult;
1388 }
1389
1390 /**
1391 * Send message to client, who requests poll, if any
1392 * This method is used by Node and Interface class objects
1393 */
1394 void NetObj::sendPollerMsg(UINT32 dwRqId, const TCHAR *pszFormat, ...)
1395 {
1396 if (m_pollRequestor != NULL)
1397 {
1398 va_list args;
1399 TCHAR szBuffer[1024];
1400
1401 va_start(args, pszFormat);
1402 _vsntprintf(szBuffer, 1024, pszFormat, args);
1403 va_end(args);
1404 m_pollRequestor->sendPollerMsg(dwRqId, szBuffer);
1405 }
1406 }
1407
1408 /**
1409 * Add child node objects (direct and indirect childs) to list
1410 */
1411 void NetObj::addChildNodesToList(ObjectArray<Node> *nodeList, UINT32 dwUserId)
1412 {
1413 lockChildList(false);
1414
1415 // Walk through our own child list
1416 for(int i = 0; i < m_childList->size(); i++)
1417 {
1418 NetObj *object = m_childList->get(i);
1419 if (object->getObjectClass() == OBJECT_NODE)
1420 {
1421 // Check if this node already in the list
1422 int j;
1423 for(j = 0; j < nodeList->size(); j++)
1424 if (nodeList->get(j)->getId() == object->getId())
1425 break;
1426 if (j == nodeList->size())
1427 {
1428 object->incRefCount();
1429 nodeList->add((Node *)object);
1430 }
1431 }
1432 else
1433 {
1434 if (object->checkAccessRights(dwUserId, OBJECT_ACCESS_READ))
1435 object->addChildNodesToList(nodeList, dwUserId);
1436 }
1437 }
1438
1439 unlockChildList();
1440 }
1441
1442 /**
1443 * Add child data collection targets (direct and indirect childs) to list
1444 */
1445 void NetObj::addChildDCTargetsToList(ObjectArray<DataCollectionTarget> *dctList, UINT32 dwUserId)
1446 {
1447 lockChildList(false);
1448
1449 // Walk through our own child list
1450 for(int i = 0; i < m_childList->size(); i++)
1451 {
1452 NetObj *object = m_childList->get(i);
1453 if (!object->checkAccessRights(dwUserId, OBJECT_ACCESS_READ))
1454 continue;
1455
1456 if (object->isDataCollectionTarget())
1457 {
1458 // Check if this objects already in the list
1459 int j;
1460 for(j = 0; j < dctList->size(); j++)
1461 if (dctList->get(j)->getId() == object->getId())
1462 break;
1463 if (j == dctList->size())
1464 {
1465 object->incRefCount();
1466 dctList->add((DataCollectionTarget *)object);
1467 }
1468 }
1469 object->addChildDCTargetsToList(dctList, dwUserId);
1470 }
1471
1472 unlockChildList();
1473 }
1474
1475 /**
1476 * Hide object and all its childs
1477 */
1478 void NetObj::hide()
1479 {
1480 lockChildList(false);
1481 for(int i = 0; i < m_childList->size(); i++)
1482 m_childList->get(i)->hide();
1483 unlockChildList();
1484
1485 lockProperties();
1486 m_isHidden = true;
1487 unlockProperties();
1488 }
1489
1490 /**
1491 * Unhide object and all its childs
1492 */
1493 void NetObj::unhide()
1494 {
1495 lockProperties();
1496 m_isHidden = false;
1497 if (!m_isSystem)
1498 EnumerateClientSessions(BroadcastObjectChange, this);
1499 unlockProperties();
1500
1501 lockChildList(false);
1502 for(int i = 0; i < m_childList->size(); i++)
1503 m_childList->get(i)->unhide();
1504 unlockChildList();
1505 }
1506
1507 /**
1508 * Return status propagated to parent
1509 */
1510 int NetObj::getPropagatedStatus()
1511 {
1512 int iStatus;
1513
1514 if (m_statusPropAlg == SA_PROPAGATE_DEFAULT)
1515 {
1516 iStatus = DefaultPropagatedStatus(m_status);
1517 }
1518 else
1519 {
1520 switch(m_statusPropAlg)
1521 {
1522 case SA_PROPAGATE_UNCHANGED:
1523 iStatus = m_status;
1524 break;
1525 case SA_PROPAGATE_FIXED:
1526 iStatus = ((m_status > STATUS_NORMAL) && (m_status < STATUS_UNKNOWN)) ? m_fixedStatus : m_status;
1527 break;
1528 case SA_PROPAGATE_RELATIVE:
1529 if ((m_status > STATUS_NORMAL) && (m_status < STATUS_UNKNOWN))
1530 {
1531 iStatus = m_status + m_statusShift;
1532 if (iStatus < 0)
1533 iStatus = 0;
1534 if (iStatus > STATUS_CRITICAL)
1535 iStatus = STATUS_CRITICAL;
1536 }
1537 else
1538 {
1539 iStatus = m_status;
1540 }
1541 break;
1542 case SA_PROPAGATE_TRANSLATED:
1543 if ((m_status > STATUS_NORMAL) && (m_status < STATUS_UNKNOWN))
1544 {
1545 iStatus = m_statusTranslation[m_status - 1];
1546 }
1547 else
1548 {
1549 iStatus = m_status;
1550 }
1551 break;
1552 default:
1553 iStatus = STATUS_UNKNOWN;
1554 break;
1555 }
1556 }
1557 return iStatus;
1558 }
1559
1560 /**
1561 * Prepare object for deletion. Method should return only
1562 * when object deletion is safe
1563 */
1564 void NetObj::prepareForDeletion()
1565 {
1566 }
1567
1568 /**
1569 * Set object's comments.
1570 * NOTE: pszText should be dynamically allocated or NULL
1571 */
1572 void NetObj::setComments(TCHAR *text)
1573 {
1574 lockProperties();
1575 free(m_comments);
1576 m_comments = text;
1577 setModified();
1578 unlockProperties();
1579 }
1580
1581 /**
1582 * Copy object's comments to NXCP message
1583 */
1584 void NetObj::commentsToMessage(NXCPMessage *pMsg)
1585 {
1586 lockProperties();
1587 pMsg->setField(VID_COMMENTS, CHECK_NULL_EX(m_comments));
1588 unlockProperties();
1589 }
1590
1591 /**
1592 * Load trusted nodes list from database
1593 */
1594 bool NetObj::loadTrustedNodes(DB_HANDLE hdb)
1595 {
1596 DB_RESULT hResult;
1597 TCHAR query[256];
1598 int i, count;
1599
1600 _sntprintf(query, 256, _T("SELECT target_node_id FROM trusted_nodes WHERE source_object_id=%d"), m_id);
1601 hResult = DBSelect(hdb, query);
1602 if (hResult != NULL)
1603 {
1604 count = DBGetNumRows(hResult);
1605 if (count > 0)
1606 {
1607 m_dwNumTrustedNodes = count;
1608 m_pdwTrustedNodes = (UINT32 *)malloc(sizeof(UINT32) * count);
1609 for(i = 0; i < count; i++)
1610 {
1611 m_pdwTrustedNodes[i] = DBGetFieldULong(hResult, i, 0);
1612 }
1613 }
1614 DBFreeResult(hResult);
1615 }
1616 return (hResult != NULL);
1617 }
1618
1619 /**
1620 * Save list of trusted nodes to database
1621 */
1622 bool NetObj::saveTrustedNodes(DB_HANDLE hdb)
1623 {
1624 TCHAR query[256];
1625 UINT32 i;
1626 bool rc = false;
1627
1628 _sntprintf(query, 256, _T("DELETE FROM trusted_nodes WHERE source_object_id=%d"), m_id);
1629 if (DBQuery(hdb, query))
1630 {
1631 for(i = 0; i < m_dwNumTrustedNodes; i++)
1632 {
1633 _sntprintf(query, 256, _T("INSERT INTO trusted_nodes (source_object_id,target_node_id) VALUES (%d,%d)"),
1634 m_id, m_pdwTrustedNodes[i]);
1635 if (!DBQuery(hdb, query))
1636 break;
1637 }
1638 if (i == m_dwNumTrustedNodes)
1639 rc = true;
1640 }
1641 return rc;
1642 }
1643
1644 /**
1645 * Check if given node is in trust list
1646 * Will always return TRUE if system parameter CheckTrustedNodes set to 0
1647 */
1648 bool NetObj::isTrustedNode(UINT32 id)
1649 {
1650 bool rc;
1651
1652 if (g_flags & AF_CHECK_TRUSTED_NODES)
1653 {
1654 UINT32 i;
1655
1656 lockProperties();
1657 for(i = 0, rc = false; i < m_dwNumTrustedNodes; i++)
1658 {
1659 if (m_pdwTrustedNodes[i] == id)
1660 {
1661 rc = true;
1662 break;
1663 }
1664 }
1665 unlockProperties();
1666 }
1667 else
1668 {
1669 rc = true;
1670 }
1671 return rc;
1672 }
1673
1674 /**
1675 * Get list of parent objects for NXSL script
1676 */
1677 NXSL_Array *NetObj::getParentsForNXSL()
1678 {
1679 NXSL_Array *parents = new NXSL_Array;
1680 int index = 0;
1681
1682 lockParentList(false);
1683 for(int i = 0; i < m_parentList->size(); i++)
1684 {
1685 NetObj *obj = m_parentList->get(i);
1686 if ((obj->getObjectClass() == OBJECT_CONTAINER) ||
1687 (obj->getObjectClass() == OBJECT_SERVICEROOT) ||
1688 (obj->getObjectClass() == OBJECT_NETWORK))
1689 {
1690 parents->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, obj)));
1691 }
1692 }
1693 unlockParentList();
1694
1695 return parents;
1696 }
1697
1698 /**
1699 * Get list of child objects for NXSL script
1700 */
1701 NXSL_Array *NetObj::getChildrenForNXSL()
1702 {
1703 NXSL_Array *children = new NXSL_Array;
1704 int index = 0;
1705
1706 lockChildList(false);
1707 for(int i = 0; i < m_childList->size(); i++)
1708 {
1709 NetObj *obj = m_childList->get(i);
1710 if (obj->getObjectClass() == OBJECT_NODE)
1711 {
1712 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, obj)));
1713 }
1714 else if (obj->getObjectClass() == OBJECT_INTERFACE)
1715 {
1716 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass, obj)));
1717 }
1718 else
1719 {
1720 children->set(index++, new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, obj)));
1721 }
1722 }
1723 unlockChildList();
1724
1725 return children;
1726 }
1727
1728 /**
1729 * Get full list of child objects (including both direct and indirect childs)
1730 */
1731 void NetObj::getFullChildListInternal(ObjectIndex *list, bool eventSourceOnly)
1732 {
1733 lockChildList(false);
1734 for(int i = 0; i < m_childList->size(); i++)
1735 {
1736 NetObj *obj = m_childList->get(i);
1737 if (!eventSourceOnly || IsEventSource(obj->getObjectClass()))
1738 list->put(obj->getId(), obj);
1739 obj->getFullChildListInternal(list, eventSourceOnly);
1740 }
1741 unlockChildList();
1742 }
1743
1744 /**
1745 * Get full list of child objects (including both direct and indirect childs).
1746 * Returned array is dynamically allocated and must be deleted by the caller.
1747 *
1748 * @param eventSourceOnly if true, only objects that can be event source will be included
1749 */
1750 ObjectArray<NetObj> *NetObj::getFullChildList(bool eventSourceOnly, bool updateRefCount)
1751 {
1752 ObjectIndex list;
1753 getFullChildListInternal(&list, eventSourceOnly);
1754 return list.getObjects(updateRefCount);
1755 }
1756
1757 /**
1758 * Get list of child objects (direct only). Returned array is
1759 * dynamically allocated and must be deleted by the caller.
1760 *
1761 * @param typeFilter Only return objects with class ID equals given value.
1762 * Set to -1 to disable filtering.
1763 */
1764 ObjectArray<NetObj> *NetObj::getChildList(int typeFilter)
1765 {
1766 lockChildList(false);
1767 ObjectArray<NetObj> *list = new ObjectArray<NetObj>((int)m_childList->size(), 16, false);
1768 for(int i = 0; i < m_childList->size(); i++)
1769 {
1770 if ((typeFilter == -1) || (typeFilter == m_childList->get(i)->getObjectClass()))
1771 list->add(m_childList->get(i));
1772 }
1773 unlockChildList();
1774 return list;
1775 }
1776
1777 /**
1778 * Get list of parent objects (direct only). Returned array is
1779 * dynamically allocated and must be deleted by the caller.
1780 *
1781 * @param typeFilter Only return objects with class ID equals given value.
1782 * Set to -1 to disable filtering.
1783 */
1784 ObjectArray<NetObj> *NetObj::getParentList(int typeFilter)
1785 {
1786 lockParentList(false);
1787 ObjectArray<NetObj> *list = new ObjectArray<NetObj>(m_parentList->size(), 16, false);
1788 for(int i = 0; i < m_parentList->size(); i++)
1789 {
1790 if ((typeFilter == -1) || (typeFilter == m_parentList->get(i)->getObjectClass()))
1791 list->add(m_parentList->get(i));
1792 }
1793 unlockParentList();
1794 return list;
1795 }
1796
1797 /**
1798 * FInd child object by name (with optional class filter)
1799 */
1800 NetObj *NetObj::findChildObject(const TCHAR *name, int typeFilter)
1801 {
1802 NetObj *object = NULL;
1803 lockChildList(false);
1804 for(int i = 0; i < m_childList->size(); i++)
1805 {
1806 NetObj *o = m_childList->get(i);
1807 if (((typeFilter == -1) || (typeFilter == o->getObjectClass())) && !_tcsicmp(name, o->getName()))
1808 {
1809 object = o;
1810 break;
1811 }
1812 }
1813 unlockChildList();
1814 return object;
1815 }
1816
1817 /**
1818 * Called by client session handler to check if threshold summary should
1819 * be shown for this object. Default implementation always returns false.
1820 */
1821 bool NetObj::showThresholdSummary()
1822 {
1823 return false;
1824 }
1825
1826 /**
1827 * Must return true if object is a possible event source
1828 */
1829 bool NetObj::isEventSource()
1830 {
1831 return false;
1832 }
1833
1834 /**
1835 * Must return true if object is a possible data collection target
1836 */
1837 bool NetObj::isDataCollectionTarget()
1838 {
1839 return false;
1840 }
1841
1842 /**
1843 * Get module data
1844 */
1845 ModuleData *NetObj::getModuleData(const TCHAR *module)
1846 {
1847 lockProperties();
1848 ModuleData *data = (m_moduleData != NULL) ? m_moduleData->get(module) : NULL;
1849 unlockProperties();
1850 return data;
1851 }
1852
1853 /**
1854 * Set module data
1855 */
1856 void NetObj::setModuleData(const TCHAR *module, ModuleData *data)
1857 {
1858 lockProperties();
1859 if (m_moduleData == NULL)
1860 m_moduleData = new StringObjectMap<ModuleData>(true);
1861 m_moduleData->set(module, data);
1862 unlockProperties();
1863 }
1864
1865 /**
1866 * Add new location entry
1867 */
1868 void NetObj::addLocationToHistory()
1869 {
1870 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1871 UINT32 startTimestamp;
1872 bool isSamePlace;
1873 DB_RESULT hResult;
1874 if (!isLocationTableExists())
1875 {
1876 DbgPrintf(4, _T("NetObj::addLocationToHistory: Geolocation history table will be created for object %s [%d]"), m_name, m_id);
1877 if (!createLocationHistoryTable(hdb))
1878 {
1879 DbgPrintf(4, _T("NetObj::addLocationToHistory: Error creating geolocation history table for object %s [%d]"), m_name, m_id);
1880 return;
1881 }
1882 }
1883 const TCHAR *query;
1884 switch(g_dbSyntax)
1885 {
1886 case DB_SYNTAX_ORACLE:
1887 query = _T("SELECT * FROM (SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC) WHERE ROWNUM<=1");
1888 break;
1889 case DB_SYNTAX_MSSQL:
1890 query = _T("SELECT TOP 1 latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC");
1891 break;
1892 case DB_SYNTAX_DB2:
1893 query = _T("SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC FETCH FIRST 200 ROWS ONLY");
1894 break;
1895 default:
1896 query = _T("SELECT latitude,longitude,accuracy,start_timestamp FROM gps_history_%d ORDER BY start_timestamp DESC LIMIT 1");
1897 break;
1898 }
1899 TCHAR preparedQuery[256];
1900 _sntprintf(preparedQuery, 256, query, m_id);
1901 DB_STATEMENT hStmt = DBPrepare(hdb, preparedQuery);
1902
1903 if (hStmt == NULL)
1904 goto onFail;
1905
1906 hResult = DBSelectPrepared(hStmt);
1907 if (hResult == NULL)
1908 goto onFail;
1909 if (DBGetNumRows(hResult) > 0)
1910 {
1911 startTimestamp = DBGetFieldULong(hResult, 0, 3);
1912 isSamePlace = m_geoLocation.sameLocation(DBGetFieldDouble(hResult, 0, 0), DBGetFieldDouble(hResult, 0, 1), DBGetFieldLong(hResult, 0, 2));
1913 DBFreeStatement(hStmt);
1914 DBFreeResult(hResult);
1915 }
1916 else
1917 {
1918 isSamePlace = false;
1919 }
1920
1921 if (isSamePlace)
1922 {
1923 TCHAR query[256];
1924 _sntprintf(query, 255, _T("UPDATE gps_history_%d SET end_timestamp = ? WHERE start_timestamp =? "), m_id);
1925 hStmt = DBPrepare(hdb, query);
1926 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
1927 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, startTimestamp);
1928 }
1929 else
1930 {
1931 TCHAR query[256];
1932 _sntprintf(query, 255, _T("INSERT INTO gps_history_%d (latitude,longitude,")
1933 _T("accuracy,start_timestamp,end_timestamp) VALUES (?,?,?,?,?)"), m_id);
1934 hStmt = DBPrepare(hdb, query);
1935
1936 TCHAR lat[32], lon[32];
1937 _sntprintf(lat, 32, _T("%f"), m_geoLocation.getLatitude());
1938 _sntprintf(lon, 32, _T("%f"), m_geoLocation.getLongitude());
1939
1940 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, lat, DB_BIND_STATIC);
1941 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, lon, DB_BIND_STATIC);
1942 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)m_geoLocation.getAccuracy());
1943 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
1944 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (UINT32)m_geoLocation.getTimestamp());
1945 }
1946
1947 if (hStmt == NULL)
1948 goto onFail;
1949
1950 DBExecute(hStmt);
1951 DBFreeStatement(hStmt);
1952 DBConnectionPoolReleaseConnection(hdb);
1953 return;
1954
1955 onFail:
1956 DBFreeStatement(hStmt);
1957 DbgPrintf(4, _T("NetObj::addLocationToHistory(%s [%d]): Failed to add location to history"), m_name, m_id);
1958 DBConnectionPoolReleaseConnection(hdb);
1959 return;
1960 }
1961
1962 /**
1963 * Check if given data table exist
1964 */
1965 bool NetObj::isLocationTableExists()
1966 {
1967 TCHAR table[256];
1968 _sntprintf(table, 256, _T("gps_history_%d"), m_id);
1969 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1970 int rc = DBIsTableExist(hdb, table);
1971 if (rc == DBIsTableExist_Failure)
1972 {
1973 _tprintf(_T("WARNING: call to DBIsTableExist(\"%s\") failed\n"), table);
1974 }
1975 DBConnectionPoolReleaseConnection(hdb);
1976 return rc != DBIsTableExist_NotFound;
1977 }
1978
1979 /**
1980 * Create table for storing geolocation history for this object
1981 */
1982 bool NetObj::createLocationHistoryTable(DB_HANDLE hdb)
1983 {
1984 TCHAR szQuery[256], szQueryTemplate[256];
1985 MetaDataReadStr(_T("LocationHistory"), szQueryTemplate, 255, _T(""));
1986 _sntprintf(szQuery, 256, szQueryTemplate, m_id);
1987 if (!DBQuery(hdb, szQuery))
1988 return false;
1989
1990 return true;
1991 }
1992
1993 /**
1994 * Set status calculation method
1995 */
1996 void NetObj::setStatusCalculation(int method, int arg1, int arg2, int arg3, int arg4)
1997 {
1998 lockProperties();
1999 m_statusCalcAlg = method;
2000 switch(method)
2001 {
2002 case SA_CALCULATE_SINGLE_THRESHOLD:
2003 m_statusSingleThreshold = arg1;
2004 break;
2005 case SA_CALCULATE_MULTIPLE_THRESHOLDS:
2006 m_statusThresholds[0] = arg1;
2007 m_statusThresholds[1] = arg2;
2008 m_statusThresholds[2] = arg3;
2009 m_statusThresholds[3] = arg4;
2010 break;
2011 default:
2012 break;
2013 }
2014 setModified();
2015 unlockProperties();
2016 }
2017
2018 /**
2019 * Set status propagation method
2020 */
2021 void NetObj::setStatusPropagation(int method, int arg1, int arg2, int arg3, int arg4)
2022 {
2023 lockProperties();
2024 m_statusPropAlg = method;
2025 switch(method)
2026 {
2027 case SA_PROPAGATE_FIXED:
2028 m_fixedStatus = arg1;
2029 break;
2030 case SA_PROPAGATE_RELATIVE:
2031 m_statusShift = arg1;
2032 break;
2033 case SA_PROPAGATE_TRANSLATED:
2034 m_statusTranslation[0] = arg1;
2035 m_statusTranslation[1] = arg2;
2036 m_statusTranslation[2] = arg3;
2037 m_statusTranslation[3] = arg4;
2038 break;
2039 default:
2040 break;
2041 }
2042 setModified();
2043 unlockProperties();
2044 }
2045
2046 /**
2047 * Enter maintenance mode
2048 */
2049 void NetObj::enterMaintenanceMode()
2050 {
2051 DbgPrintf(4, _T("Entering maintenance mode for object %s [%d] (%s)"), m_name, m_id, getObjectClassName());
2052
2053 lockChildList(false);
2054 for(int i = 0; i < m_childList->size(); i++)
2055 {
2056 NetObj *object = m_childList->get(i);
2057 if (object->getStatus() != STATUS_UNMANAGED)
2058 object->enterMaintenanceMode();
2059 }
2060 unlockChildList();
2061 }
2062
2063 /**
2064 * Leave maintenance mode
2065 */
2066 void NetObj::leaveMaintenanceMode()
2067 {
2068 DbgPrintf(4, _T("Leaving maintenance mode for object %s [%d] (%s)"), m_name, m_id, getObjectClassName());
2069
2070 lockChildList(false);
2071 for(int i = 0; i < m_childList->size(); i++)
2072 {
2073 NetObj *object = m_childList->get(i);
2074 if (object->getStatus() != STATUS_UNMANAGED)
2075 object->leaveMaintenanceMode();
2076 }
2077 unlockChildList();
2078 }
2079
2080 /**
2081 * Get all custom attributes as NXSL hash map
2082 */
2083 NXSL_Value *NetObj::getCustomAttributesForNXSL() const
2084 {
2085 NXSL_HashMap *map = new NXSL_HashMap();
2086 lockProperties();
2087 StructArray<KeyValuePair> *attributes = m_customAttributes.toArray();
2088 for(int i = 0; i < attributes->size(); i++)
2089 {
2090 KeyValuePair *p = attributes->get(i);
2091 map->set(p->key, new NXSL_Value((const TCHAR *)p->value));
2092 }
2093 unlockProperties();
2094 delete attributes;
2095 return new NXSL_Value(map);
2096 }
2097
2098 /**
2099 * Create NXSL object for this object
2100 */
2101 NXSL_Value *NetObj::createNXSLObject()
2102 {
2103 return new NXSL_Value(new NXSL_Object(&g_nxslNetObjClass, this));
2104 }