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