r1181 + an ugly, but working VLAN implementation for the real world :)
[racktables] / inc / functions.php
CommitLineData
e673ee24
DO
1<?
2/*
3*
4* This file is a library of computational functions for RackTables.
5*
6*/
7
8$loclist[0] = 'front';
9$loclist[1] = 'interior';
10$loclist[2] = 'rear';
11$loclist['front'] = 0;
12$loclist['interior'] = 1;
13$loclist['rear'] = 2;
14$template[0] = array (TRUE, TRUE, TRUE);
15$template[1] = array (TRUE, TRUE, FALSE);
16$template[2] = array (FALSE, TRUE, TRUE);
17$template[3] = array (TRUE, FALSE, FALSE);
18$template[4] = array (FALSE, TRUE, FALSE);
19$template[5] = array (FALSE, FALSE, TRUE);
20$templateWidth[0] = 3;
21$templateWidth[1] = 2;
22$templateWidth[2] = 2;
23$templateWidth[3] = 1;
24$templateWidth[4] = 1;
25$templateWidth[5] = 1;
26
27// Objects of some types should be explicitly shown as
28// anonymous (labelless). This function is a single place where the
29// decision about displayed name is made.
30function displayedName ($objectData)
31{
32 if ($objectData['name'] != '')
33 return $objectData['name'];
34 else
35 switch ($objectData['objtype_id'])
36 {
37 case TYPE_SERVER:
38 case TYPE_SWITCH:
39 case TYPE_ROUTER:
40 return "ANONYMOUS " . $objectData['objtype_name'];
41 default:
42 return "[${objectData['objtype_name']}]";
43 }
44}
45
46// This function finds height of solid rectangle of atoms, which are all
47// assigned to the same object. Rectangle base is defined by specified
48// template.
49function rectHeight ($rackData, $startRow, $template_idx)
50{
51 $height = 0;
52 // The first met object_id is used to match all the folowing IDs.
53 $object_id = 0;
54 global $template;
55 do
56 {
57 for ($locidx = 0; $locidx < 3; $locidx++)
58 {
59 // At least one value in template is TRUE, but the following block
60 // can meet 'skipped' atoms. Let's ensure we have something after processing
61 // the first row.
62 if ($template[$template_idx][$locidx])
63 {
64 if (isset ($rackData[$startRow - $height][$locidx]['skipped']))
65 break 2;
66 if ($rackData[$startRow - $height][$locidx]['state'] != 'T')
67 break 2;
68 if ($object_id == 0)
69 $object_id = $rackData[$startRow - $height][$locidx]['object_id'];
70 if ($object_id != $rackData[$startRow - $height][$locidx]['object_id'])
71 break 2;
72 }
73 }
74 // If the first row can't offer anything, bail out.
75 if ($height == 0 and $object_id == 0)
76 break;
77 $height++;
78 }
79 while ($startRow - $height > 0);
80// echo "for startRow==${startRow} and template==(${template[0]}, ${template[1]}, ${template[2]}) height==${height}<br>\n";
81 return $height;
82}
83
84// This function marks atoms to be avoided by rectHeight() and assigns rowspan/colspan
85// attributes.
86function markSpan (&$rackData, $startRow, $maxheight, $template_idx)
87{
88 global $template, $templateWidth;
89 $colspan = 0;
90 for ($height = 0; $height < $maxheight; $height++)
91 {
92 for ($locidx = 0; $locidx < 3; $locidx++)
93 {
94 if ($template[$template_idx][$locidx])
95 {
96 // Add colspan/rowspan to the first row met and mark the following ones to skip.
97 if ($colspan != 0)
98 $rackData[$startRow - $height][$locidx]['skipped'] = TRUE;
99 else
100 {
101 $colspan = $templateWidth[$template_idx];
102 if ($colspan > 1)
103 $rackData[$startRow - $height][$locidx]['colspan'] = $colspan;
104 if ($maxheight > 1)
105 $rackData[$startRow - $height][$locidx]['rowspan'] = $maxheight;
106 }
107 }
108 }
109 }
110 return;
111}
112
113// This function finds rowspan/solspan/skipped atom attributes for renderRack()
114// What we actually have to do is to find all possible rectangles for each objects
115// and then find the widest of those with the maximal square.
116function markAllSpans (&$rackData = NULL)
117{
118 if ($rackData == NULL)
119 {
120 showError ('Invalid rackData in markupAllSpans()');
121 return;
122 }
123 for ($i = $rackData['height']; $i > 0; $i--)
124 {
125 // calculate height of 6 possible span templates (array is presorted by width descending)
126 global $template;
127 for ($j = 0; $j < 6; $j++)
128 $height[$j] = rectHeight ($rackData, $i, $j);
129 // find the widest rectangle of those with maximal height
130 $maxheight = max ($height);
131 if ($maxheight > 0)
132 {
133 $best_template_index = 0;
134 for ($j = 0; $j < 6; $j++)
135 if ($height[$j] == $maxheight)
136 {
137 $best_template_index = $j;
138 break;
139 }
140 // distribute span marks
141 markSpan ($rackData, $i, $maxheight, $best_template_index);
142 }
143 }
144}
145
146function delRow ($row_id = 0)
147{
148 if ($row_id == 0)
149 {
150 showError ('Not all required args to delRow() are present.');
151 return;
152 }
153 if (!isset ($_REQUEST['confirmed']) || $_REQUEST['confirmed'] != 'true')
154 {
155 echo "Press <a href='?op=del_row&row_id=${row_id}&confirmed=true'>here</a> to confirm rack row deletion.";
156 return;
157 }
158 global $dbxlink;
159 echo 'Deleting rack row information: ';
160 $result = $dbxlink->query ("update RackRow set deleted = 'yes' where id=${row_id} limit 1");
161 if ($result->rowCount() != 1)
162 {
163 showError ('Marked ' . $result.rowCount() . ' rows as deleted, but expected 1');
164 return;
165 }
166 echo 'OK<br>';
167 recordHistory ('RackRow', "id = ${row_id}");
168 echo "Information was deleted. You may return to <a href='?op=list_rows&editmode=on'>rack row list</a>.";
169}
170
171function delRack ($rack_id = 0)
172{
173 if ($rack_id == 0)
174 {
175 showError ('Not all required args to delRack() are present.');
176 return;
177 }
178 if (!isset ($_REQUEST['confirmed']) || $_REQUEST['confirmed'] != 'true')
179 {
180 echo "Press <a href='?op=del_rack&rack_id=${rack_id}&confirmed=true'>here</a> to confirm rack deletion.";
181 return;
182 }
183 global $dbxlink;
184 echo 'Deleting rack information: ';
185 $result = $dbxlink->query ("update Rack set deleted = 'yes' where id=${rack_id} limit 1");
186 if ($result->rowCount() != 1)
187 {
188 showError ('Marked ' . $result.rowCount() . ' rows as deleted, but expected 1');
189 return;
190 }
191 echo 'OK<br>';
192 recordHistory ('Rack', "id = ${rack_id}");
193 echo "Information was deleted. You may return to <a href='?op=list_racks&editmode=on'>rack list</a>.";
194}
195
196function delObject ($object_id = 0)
197{
198 if ($object_id == 0)
199 {
200 showError ('Not all required args to delObject() are present.');
201 return;
202 }
203 if (!isset ($_REQUEST['confirmed']) || $_REQUEST['confirmed'] != 'true')
204 {
205 echo "Press <a href='?op=del_object&object_id=${object_id}&confirmed=true'>here</a> to confirm object deletion.";
206 return;
207 }
208 global $dbxlink;
209 echo 'Deleting object information: ';
210 $result = $dbxlink->query ("update RackObject set deleted = 'yes' where id=${object_id} limit 1");
211 if ($result->rowCount() != 1)
212 {
213 showError ('Marked ' . $result.rowCount() . ' rows as deleted, but expected 1');
214 return;
215 }
216 echo 'OK<br>';
217 recordHistory ('RackObject', "id = ${object_id}");
218 echo "Information was deleted. You may return to <a href='?op=list_objects&editmode=on'>object list</a>.";
219}
220
221// We can mount 'F' atoms and unmount our own 'T' atoms.
222function applyObjectMountMask (&$rackData, $object_id)
223{
224 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
225 for ($locidx = 0; $locidx < 3; $locidx++)
226 switch ($rackData[$unit_no][$locidx]['state'])
227 {
228 case 'F':
229 $rackData[$unit_no][$locidx]['enabled'] = TRUE;
230 break;
231 case 'T':
232 $rackData[$unit_no][$locidx]['enabled'] = ($rackData[$unit_no][$locidx]['object_id'] == $object_id);
233 break;
234 default:
235 $rackData[$unit_no][$locidx]['enabled'] = FALSE;
236 }
237}
238
239// Design change means transition between 'F' and 'A' and back.
240function applyRackDesignMask (&$rackData)
241{
242 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
243 for ($locidx = 0; $locidx < 3; $locidx++)
244 switch ($rackData[$unit_no][$locidx]['state'])
245 {
246 case 'F':
247 case 'A':
248 $rackData[$unit_no][$locidx]['enabled'] = TRUE;
249 break;
250 default:
251 $rackData[$unit_no][$locidx]['enabled'] = FALSE;
252 }
253}
254
255// The same for 'F' and 'U'.
256function applyRackProblemMask (&$rackData)
257{
258 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
259 for ($locidx = 0; $locidx < 3; $locidx++)
260 switch ($rackData[$unit_no][$locidx]['state'])
261 {
262 case 'F':
263 case 'U':
264 $rackData[$unit_no][$locidx]['enabled'] = TRUE;
265 break;
266 default:
267 $rackData[$unit_no][$locidx]['enabled'] = FALSE;
268 }
269}
270
271// This mask should allow toggling 'T' and 'W' on object's rackspace.
272function applyObjectProblemMask (&$rackData)
273{
274 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
275 for ($locidx = 0; $locidx < 3; $locidx++)
276 switch ($rackData[$unit_no][$locidx]['state'])
277 {
278 case 'T':
279 case 'W':
280 $rackData[$unit_no][$locidx]['enabled'] = ($rackData[$unit_no][$locidx]['object_id'] == $object_id);
281 break;
282 default:
283 $rackData[$unit_no][$locidx]['enabled'] = FALSE;
284 }
285}
286
287// This function highlights specified object (and removes previous highlight).
288function highlightObject (&$rackData, $object_id)
289{
290 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
291 for ($locidx = 0; $locidx < 3; $locidx++)
292 if
293 (
294 $rackData[$unit_no][$locidx]['state'] == 'T' and
295 $rackData[$unit_no][$locidx]['object_id'] == $object_id
296 )
297 $rackData[$unit_no][$locidx]['hl'] = 'h';
298 else
299 unset ($rackData[$unit_no][$locidx]['hl']);
300}
301
302// This function marks atoms to selected or not depending on their current state.
303function markupAtomGrid (&$data, $checked_state)
304{
305 for ($unit_no = $data['height']; $unit_no > 0; $unit_no--)
306 for ($locidx = 0; $locidx < 3; $locidx++)
307 {
308 if (!($data[$unit_no][$locidx]['enabled'] === TRUE))
309 continue;
310 if ($data[$unit_no][$locidx]['state'] == $checked_state)
311 $data[$unit_no][$locidx]['checked'] = ' checked';
312 else
313 $data[$unit_no][$locidx]['checked'] = '';
314 }
315}
316
317// This function is almost a clone of processGridForm(), but doesn't save anything to database
318// Return value is the changed rack data.
319// Here we assume that correct filter has already been applied, so we just
320// set or unset checkbox inputs w/o changing atom state.
321function mergeGridFormToRack (&$rackData)
322{
323 $rack_id = $rackData['id'];
324 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
325 for ($locidx = 0; $locidx < 3; $locidx++)
326 {
327 if ($rackData[$unit_no][$locidx]['enabled'] != TRUE)
328 continue;
329 $inputname = "atom_${rack_id}_${unit_no}_${locidx}";
330 if (isset ($_REQUEST[$inputname]) and $_REQUEST[$inputname] == 'on')
331 $rackData[$unit_no][$locidx]['checked'] = ' checked';
332 else
333 $rackData[$unit_no][$locidx]['checked'] = '';
334 }
335}
336
337function binMaskFromDec ($maskL)
338{
339 $binmask=0;
340 for ($i=0; $i<$maskL; $i++)
341 {
342 $binmask*=2;
343 $binmask+=1;
344 }
345 for ($i=$maskL; $i<32; $i++)
346 {
347 $binmask*=2;
348 }
349 return $binmask;
350}
351
352function binInvMaskFromDec ($maskL)
353{
354 $binmask=0;
355 for ($i=0; $i<$maskL; $i++)
356 {
357 $binmask*=2;
358 }
359 for ($i=$maskL; $i<32; $i++)
360 {
361 $binmask*=2;
362 $binmask+=1;
363 }
364 return $binmask;
365}
366
2a201216 367function addRange ($range='', $name='')
e673ee24 368{
2a201216
DY
369 // $range is in x.x.x.x/x format, split into ip/mask vars
370 $rangeArray = explode('/', $range);
371 $ip = $rangeArray[0];
372 $mask = $rangeArray[1];
373
e673ee24
DO
374 $ipL = ip2long($ip);
375 $maskL = ip2long($mask);
376 if ($ipL == -1 || $ipL === FALSE)
377 return 'Bad ip address';
378 if ($mask < 32 && $mask > 0)
379 $maskL = $mask;
380 else
381 {
382 $maskB = decbin($maskL);
383 if (strlen($maskB)!=32)
384 return 'Bad mask';
385 $ones=0;
386 $zeroes=FALSE;
387 foreach( str_split ($maskB) as $digit)
388 {
389 if ($digit == '0')
390 $zeroes = TRUE;
391 if ($digit == '1')
392 {
393 $ones++;
394 if ($zeroes == TRUE)
395 return 'Bad mask';
396 }
397 }
398 $maskL = $ones;
399 }
400 $binmask = binMaskFromDec($maskL);
401 $ipL = $ipL & $binmask;
402
403 $query =
404 "select ".
405 "id, ip, mask, name ".
406 "from IPRanges ";
407
408
409 global $dbxlink;
410
411 $result = $dbxlink->query ($query);
412
413 while ($row = $result->fetch (PDO::FETCH_ASSOC))
414 {
415 $otherip = $row['ip'];
416 $othermask = binMaskFromDec($row['mask']);
417// echo "checking $otherip & $othermask ".($otherip & $othermask)." == $ipL & $othermask ".($ipL & $othermask)." ".decbin($otherip)." ".decbin($othermask)." ".decbin($otherip & $othermask)." ".decbin($ipL)." ".decbin($othermask)." ".decbin($ipL & $othermask)."\n";
418// echo "checking $otherip & $binmask ".($otherip & $binmask)." == $ipL & $binmask ".($ipL & $binmask)." ".decbin($otherip)." ".decbin($binmask)." ".decbin($otherip & $binmask)." ".decbin($ipL)." ".decbin($binmask)." ".decbin($ipL & $binmask)."\n";
419// echo "\n";
420// flush();
421 if (($otherip & $othermask) == ($ipL & $othermask))
422 return "This subnet intersects with ".long2ip($row['ip'])."/${row['mask']}";
423 if (($otherip & $binmask) == ($ipL & $binmask))
424 return "This subnet intersects with ".long2ip($row['ip'])."/${row['mask']}";
425 }
426 $result->closeCursor();
427 $query =
428 "insert into IPRanges set ip=".sprintf('%u', $ipL).", mask='$maskL', name='$name'";
429 $result = $dbxlink->exec ($query);
430 return '';
431}
432
433function getIPRange ($id = 0)
434{
435 global $dbxlink;
436 $query =
437 "select ".
438 "id as IPRanges_id, ".
439 "INET_NTOA(ip) as IPRanges_ip, ".
440 "ip as IPRanges_ip_bin, ".
441 "mask as IPRanges_mask, ".
442 "name as IPRanges_name ".
443 "from IPRanges ".
444 "where id = '$id'";
445 $result = $dbxlink->query ($query);
446 if ($result == NULL)
447 {
448 return NULL;
449 }
450 else
451 {
452 $ret=array();
453 if ($row = $result->fetch (PDO::FETCH_ASSOC))
454 {
455 $ret['id'] = $row['IPRanges_id'];
456 $ret['ip'] = $row['IPRanges_ip'];
457 $ret['ip_bin'] = ip2long($ret['ip']);
458 $ret['mask_bin'] = binMaskFromDec($row['IPRanges_mask']);
459 $ret['mask_bin_inv'] = binInvMaskFromDec($row['IPRanges_mask']);
460 $ret['name'] = $row['IPRanges_name'];
461 $ret['mask'] = $row['IPRanges_mask'];
462 $ret['addrlist'] = array();
463
464 $result->closeCursor();
465 $query =
466 "select ".
467 "IPAddress.ip as ip_bin, ".
468 "INET_NTOA(IPAddress.ip) as ip, ".
469 "IPAddress.name as name, ".
470 "IPAddress.reserved as reserved, ".
471 "IPBonds.object_id as object_id, ".
472 "RackObject.name as object_name, ".
473 "IPBonds.name as bond_name, ".
474 "IPBonds.type as bond_type ".
475 "from IPAddress left join ".
476 "(IPBonds join RackObject on IPBonds.object_id = RackObject.id) ".
477 "on IPAddress.ip = IPBonds.ip ".
478 "where IPAddress.ip >= '".sprintf('%u', ($ret['ip_bin'] & $ret['mask_bin']))."' and ".
479 "IPAddress.ip <= '".sprintf('%u', ($ret['ip_bin'] | ($ret['mask_bin_inv']) ))."' ".
480 "having (reserved='yes' or name != '' or IPAddress.name != '' or object_id is not NULL) ".
481 "order by IPAddress.ip, IPBonds.type, RackObject.name";
482 $res_list=$dbxlink->query ($query);
483 $prev_ip=0;
484 if ($res_list != NULL)
485 {
486 while ($row1 = $res_list->fetch (PDO::FETCH_ASSOC))
487 {
488 if ($prev_ip != $row1['ip'])
489 {
490 $refcount=0;
491 $count=ip2long($row1['ip']);
492 $ret['addrlist'][$count]['name'] = $row1['name'];
493 $ret['addrlist'][$count]['reserved'] = $row1['reserved'];
494 $ret['addrlist'][$count]['ip'] = $row1['ip'];
495 $ret['addrlist'][$count]['ip_bin'] = ip2long($row1['ip']);
496 $prev_ip = $ret['addrlist'][$count]['ip'];
497 $ret['addrlist'][$count]['references'] = array();
498 }
499
500 if ($row1['bond_type'])
501 {
502 $ret['addrlist'][$count]['references'][$refcount]['type'] = $row1['bond_type'];
503 $ret['addrlist'][$count]['references'][$refcount]['name'] = $row1['bond_name'];
504 $ret['addrlist'][$count]['references'][$refcount]['object_id'] = $row1['object_id'];
505 $ret['addrlist'][$count]['references'][$refcount]['object_name'] = $row1['object_name'];
506 $refcount++;
507 }
508 }
509 $res_list->closeCursor();
510 }
511 }
512 }
513 return $ret;
514}
515
516function getIPAddress ($ip=0)
517{
518 $ret = array();
519 $ret['range'] = getIPRange($ip);
520 $ret['bonds'] = array();
521 $ret['outpf'] = array();
522 $ret['inpf'] = array();
523 $ret['exists'] = 0;
524 $ret['reserved'] = 'no';
525 global $dbxlink;
526 $query =
527 "select ".
528 "ip, name, reserved ".
529 "from IPAddress ".
530 "where ip = INET_ATON('$ip')";
531 $result = $dbxlink->query ($query);
532 if ($result == NULL)
533 {
534 return NULL;
535 }
536 else
537 {
538 if ($row = $result->fetch (PDO::FETCH_ASSOC))
539 {
540 $ret['exists'] = 1;
541 $ret['ip_bin'] = $row['ip'];
542 $ret['ip'] = $ip;
543 $ret['name'] = $row['name'];
544 $ret['reserved'] = $row['reserved'];
545 }
546 $result->fetch (PDO::FETCH_ASSOC);
547 }
548 $result->closeCursor();
549
550 if ($ret['exists'] == 1)
551 {
552 $query =
553 "select ".
554 "IPBonds.object_id as object_id, ".
555 "IPBonds.name as name, ".
556 "IPBonds.type as type, ".
557 "RackObject.name as object_name ".
558 "from IPBonds join RackObject on IPBonds.object_id=RackObject.id ".
559 "where IPBonds.ip=INET_ATON('$ip') ".
560 "order by RackObject.id, IPBonds.name";
561 $result1 = $dbxlink->query ($query);
562 $count=0;
563 while ($row = $result1->fetch (PDO::FETCH_ASSOC))
564 {
565 $ret['bonds'][$count]['object_id'] = $row['object_id'];
566 $ret['bonds'][$count]['name'] = $row['name'];
567 $ret['bonds'][$count]['type'] = $row['type'];
568 $ret['bonds'][$count]['object_name'] = $row['object_name'];
569 $count++;
570 }
571 $result1->closeCursor();
572
573
574 }
575
576 return $ret;
577}
578
579function bindIpToObject ($ip='', $object_id=0, $name='', $type='')
580{
581 global $dbxlink;
582
583 $range = getRangeByIp($ip);
584
585 if (!$range)
586 return 'Non-existant ip address. Try adding IP range first';
587
588 $address = getIPAddress($ip);
589
590 if ($address['exists'] == 0)
591 {
592 $query =
593 "insert into IPAddress set ip=INET_ATON('$ip')";
594 $dbxlink->exec ($query);
595 }
596
597 $query =
598 "insert into IPBonds set ip=INET_ATON('$ip'), object_id='$object_id', name='$name', type='$type'";
599 $result = $dbxlink->exec ($query);
600 return '';
601}
602
603// This function looks up 'has_problems' flag for 'T' atoms
604// and modifies 'hl' key. May be, this should be better done
605// in getRackData(). We don't honour 'skipped' key, because
606// the function is also used for thumb creation.
607function markupObjectProblems (&$rackData)
608{
609 for ($i = $rackData['height']; $i > 0; $i--)
610 for ($locidx = 0; $locidx < 3; $locidx++)
611 if ($rackData[$i][$locidx]['state'] == 'T')
612 {
613 $object = getObjectInfo ($rackData[$i][$locidx]['object_id']);
614 if ($object['has_problems'] == 'yes')
615 {
616 // Object can be already highlighted.
617 if (isset ($rackData[$i][$locidx]['hl']))
618 $rackData[$i][$locidx]['hl'] = $rackData[$i][$locidx]['hl'] . 'w';
619 else
620 $rackData[$i][$locidx]['hl'] = 'w';
621 }
622 }
623}
624
625function search_cmpObj ($a, $b)
626{
627 return ($a['score'] > $b['score'] ? -1 : 1);
628}
629
630// This function performs search and then calculates score for each result.
631// Given previous search results in $objects argument, it adds new results
632// to the array and updates score for existing results, if it is greater than
633// existing score.
634function mergeSearchResults (&$objects, $terms, $fieldname)
635{
636 global $dbxlink;
637 $query =
638 "select name, label, asset_no, barcode, ro.id, dict_key as objtype_id, " .
639 "dict_value as objtype_name, asset_no from RackObject as ro inner join Dictionary " .
640 "on objtype_id = dict_key natural join Chapter where chapter_name = 'RackObjectType' and ";
641 $count = 0;
642 foreach (explode (' ', $terms) as $term)
643 {
644 if ($count) $query .= ' or ';
645 $query .= "${fieldname} like '%$term%'";
646 $count++;
647 }
648 $query .= "";
649 $result = $dbxlink->query($query);
650 if ($result == NULL)
651 {
652 showError ("SQL query failed in mergeSearchResults()");
653 return NULL;
654 }
655// FIXME: this dead call was executed 4 times per 1 object search!
656// $typeList = getObjectTypeList();
657 $clist = array ('id', 'name', 'label', 'asset_no', 'barcode', 'objtype_id', 'objtype_name');
658 while ($row = $result->fetch(PDO::FETCH_ASSOC))
659 {
660 foreach ($clist as $cname)
661 $object[$cname] = $row[$cname];
662 $object['score'] = 0;
663 $object['dname'] = displayedName ($object);
664 unset ($object['objtype_id']);
665 foreach (explode (' ', $terms) as $term)
666 if (strstr ($object['name'], $term))
667 $object['score'] += 1;
668 unset ($object['name']);
669 if (!isset ($objects[$row['id']]))
670 $objects[$row['id']] = $object;
671 elseif ($objects[$row['id']]['score'] < $object['score'])
672 $objects[$row['id']]['score'] = $object['score'];
673 }
674 return $objects;
675}
676
677function getSearchResults ($terms)
678{
679 $objects = array();
680 mergeSearchResults ($objects, $terms, 'name');
681 mergeSearchResults ($objects, $terms, 'label');
682 mergeSearchResults ($objects, $terms, 'asset_no');
683 mergeSearchResults ($objects, $terms, 'barcode');
684 if (count ($objects) == 1)
685 usort ($objects, 'search_cmpObj');
686 return $objects;
687}
688
689// This function removes all colons and dots from a string.
690function l2addressForDatabase ($string)
691{
692 if (empty ($string))
693 return 'NULL';
694 $pieces = explode (':', $string);
695 // This workaround is for SunOS ifconfig.
696 foreach ($pieces as &$byte)
697 if (strlen ($byte) == 1)
698 $byte = '0' . $byte;
699 // And this workaround is for PHP.
700 unset ($byte);
701 $string = implode ('', $pieces);
702 $pieces = explode ('.', $string);
703 $string = implode ('', $pieces);
704 $string = strtoupper ($string);
705 return "'$string'";
706}
707
708function l2addressFromDatabase ($string)
709{
710 switch (strlen ($string))
711 {
712 case 12: // Ethernet
713 case 16: // FireWire
714 $ret = implode (':', str_split ($string, 2));
715 break;
716 default:
717 $ret = $string;
718 break;
719 }
720 return $ret;
721}
722
723// The following 2 functions return previous and next rack IDs for
724// a given rack ID. The order of racks is the same as in renderRackspace()
725// or renderRow().
726function getPrevIDforRack ($row_id = 0, $rack_id = 0)
727{
728 if ($row_id <= 0 or $rack_id <= 0)
729 {
730 showError ('Invalid arguments passed to getPrevIDforRack()');
731 return NULL;
732 }
733 $rackList = getRacksForRow ($row_id);
734 doubleLink ($rackList);
735 if (isset ($rackList[$rack_id]['prev_key']))
736 return $rackList[$rack_id]['prev_key'];
737 return NULL;
738}
739
740function getNextIDforRack ($row_id = 0, $rack_id = 0)
741{
742 if ($row_id <= 0 or $rack_id <= 0)
743 {
744 showError ('Invalid arguments passed to getNextIDforRack()');
745 return NULL;
746 }
747 $rackList = getRacksForRow ($row_id);
748 doubleLink ($rackList);
749 if (isset ($rackList[$rack_id]['next_key']))
750 return $rackList[$rack_id]['next_key'];
751 return NULL;
752}
753
754// This function finds previous and next array keys for each array key and
755// modifies its argument accordingly.
756function doubleLink (&$array)
757{
758 $prev_key = NULL;
759 foreach (array_keys ($array) as $key)
760 {
761 if ($prev_key)
762 {
763 $array[$key]['prev_key'] = $prev_key;
764 $array[$prev_key]['next_key'] = $key;
765 }
766 $prev_key = $key;
767 }
768}
769
770// After applying usort() to a rack list we will lose original array keys.
771// This function restores the keys so they are equal to rack IDs.
772function restoreRackIDs ($racks)
773{
774 $ret = array();
775 foreach ($racks as $rack)
776 $ret[$rack['id']] = $rack;
777 return $ret;
778}
779
780function sortTokenize ($a, $b)
781{
782 $aold='';
783 while ($a != $aold)
784 {
785 $aold=$a;
786 $a = ereg_replace('[^a-zA-Z0-9]',' ',$a);
787 $a = ereg_replace('([0-9])([a-zA-Z])','\\1 \\2',$a);
788 $a = ereg_replace('([a-zA-Z])([0-9])','\\1 \\2',$a);
789 }
790
791 $bold='';
792 while ($b != $bold)
793 {
794 $bold=$b;
795 $b = ereg_replace('[^a-zA-Z0-9]',' ',$b);
796 $b = ereg_replace('([0-9])([a-zA-Z])','\\1 \\2',$b);
797 $b = ereg_replace('([a-zA-Z])([0-9])','\\1 \\2',$b);
798 }
799
800
801
802 $ar = explode(' ', $a);
803 $br = explode(' ', $b);
804 for ($i=0; $i<count($ar) && $i<count($br); $i++)
805 {
806 $ret = 0;
807 if (is_numeric($ar[$i]) and is_numeric($br[$i]))
808 $ret = ($ar[$i]==$br[$i])?0:($ar[$i]<$br[$i]?-1:1);
809 else
810 $ret = strcasecmp($ar[$i], $br[$i]);
811 if ($ret != 0)
812 return $ret;
813 }
814 if ($i<count($ar))
815 return 1;
816 if ($i<count($br))
817 return -1;
818 return 0;
819}
820
821function sortByName ($a, $b)
822{
823 return sortTokenize($a['name'], $b['name']);
824}
825
826function eq ($a, $b)
827{
828 return $a==$b;
829}
830
831function neq ($a, $b)
832{
833 return $a!=$b;
834}
835
836function countRefsOfType ($refs, $type, $eq)
837{
838 $count=0;
839 foreach ($refs as $ref)
840 {
841 if ($eq($ref['type'], $type))
842 $count++;
843 }
844 return $count;
845}
846
847function sortEmptyPorts ($a, $b)
848{
849 $objname_cmp = sortTokenize($a['Object_name'], $b['Object_name']);
850 if ($objname_cmp == 0)
851 {
852 return sortTokenize($a['Port_name'], $b['Port_name']);
853 }
854 return $objname_cmp;
855}
856
857function sortObjectAddressesAndNames ($a, $b)
858{
859 $objname_cmp = sortTokenize($a['object_name'], $b['object_name']);
860 if ($objname_cmp == 0)
861 {
862 $objname_cmp = sortTokenize($a['port_name'], $b['port_name']);
863 if ($objname_cmp == 0)
864 {
865 sortTokenize($a['ip'], $b['ip']);
866 }
867 return $objname_cmp;
868 }
869 return $objname_cmp;
870}
871
872
873
874function sortAddresses ($a, $b)
875{
876 $name_cmp = sortTokenize($a['name'], $b['name']);
877 if ($name_cmp == 0)
878 {
879 return sortTokenize($a['ip'], $b['ip']);
880 }
881 return $name_cmp;
882}
883
884// This function expands port compat list into a matrix.
885function buildPortCompatMatrixFromList ($portTypeList, $portCompatList)
886{
887 $matrix = array();
888 // Create type matrix and markup compatible types.
889 foreach (array_keys ($portTypeList) as $type1)
890 foreach (array_keys ($portTypeList) as $type2)
891 $matrix[$type1][$type2] = FALSE;
892 foreach ($portCompatList as $pair)
893 $matrix[$pair['type1']][$pair['type2']] = TRUE;
894 return $matrix;
895}
896
897function newPortForwarding($object_id, $localip, $localport, $remoteip, $remoteport, $proto, $description)
898{
899 global $dbxlink;
900
901 $range = getRangeByIp($localip);
902 if (!$range)
903 return "$localip: Non existant ip";
904
905 $range = getRangeByIp($remoteip);
906 if (!$range)
907 return "$remoteip: Non existant ip";
908
909 if ( ($localport <= 0) or ($localport >= 65536) )
910 return "$localport: invaild port";
911
912 if ( ($remoteport <= 0) or ($remoteport >= 65536) )
913 return "$remoteport: invaild port";
914
915 $query =
916 "insert into PortForwarding set object_id='$object_id', localip=INET_ATON('$localip'), remoteip=INET_ATON('$remoteip'), localport='$localport', remoteport='$remoteport', proto='$proto', description='$description'";
917 $result = $dbxlink->exec ($query);
918
919 return '';
920}
921
922function deletePortForwarding($object_id, $localip, $localport, $remoteip, $remoteport, $proto)
923{
924 global $dbxlink;
925
926 $query =
927 "delete from PortForwarding where object_id='$object_id' and localip=INET_ATON('$localip') and remoteip=INET_ATON('$remoteip') and localport='$localport' and remoteport='$remoteport' and proto='$proto'";
928 $result = $dbxlink->exec ($query);
929 return '';
930}
931
932function updatePortForwarding($object_id, $localip, $localport, $remoteip, $remoteport, $proto, $description)
933{
934 global $dbxlink;
935
936 $query =
937 "update PortForwarding set description='$description' where object_id='$object_id' and localip=INET_ATON('$localip') and remoteip=INET_ATON('$remoteip') and localport='$localport' and remoteport='$remoteport' and proto='$proto'";
938 $result = $dbxlink->exec ($query);
939 return '';
940}
941
942function getObjectForwards($object_id)
943{
944 global $dbxlink;
945
946 $ret = array();
947 $ret['out'] = array();
948 $ret['in'] = array();
949 $query =
950 "select ".
951 "dict_value as proto, ".
952 "proto as proto_bin, ".
953 "INET_NTOA(localip) as localip, ".
954 "localport, ".
955 "INET_NTOA(remoteip) as remoteip, ".
956 "remoteport, ".
957 "description ".
958 "from PortForwarding inner join Dictionary on proto = dict_key natural join Chapter ".
959 "where object_id='$object_id' and chapter_name = 'Protocols' ".
960 "order by localip, localport, proto, remoteip, remoteport";
961 $result2 = $dbxlink->query ($query);
962 $count=0;
963 while ($row = $result2->fetch (PDO::FETCH_ASSOC))
964 {
965 $ret['out'][$count]['proto'] = $row['proto'];
966 $ret['out'][$count]['proto_bin'] = $row['proto_bin'];
967 $ret['out'][$count]['localip'] = $row['localip'];
968 $ret['out'][$count]['localport'] = $row['localport'];
969 $ret['out'][$count]['remoteip'] = $row['remoteip'];
970 $ret['out'][$count]['remoteport'] = $row['remoteport'];
971 $ret['out'][$count]['description'] = $row['description'];
972 $count++;
973 }
974 $result2->closeCursor();
975
976 $query =
977 "select ".
978 "dict_value as proto, ".
979 "proto as proto_bin, ".
980 "INET_NTOA(localip) as localip, ".
981 "localport, ".
982 "INET_NTOA(remoteip) as remoteip, ".
983 "remoteport, ".
984 "PortForwarding.object_id as object_id, ".
985 "RackObject.name as object_name, ".
986 "description ".
987 "from ((PortForwarding join IPBonds on remoteip=ip) join RackObject on PortForwarding.object_id=RackObject.id) inner join Dictionary on proto = dict_key natural join Chapter ".
988 "where IPBonds.object_id='$object_id' and chapter_name = 'Protocols' ".
989 "order by remoteip, remoteport, proto, localip, localport";
990 $result3 = $dbxlink->query ($query);
991 $count=0;
992 while ($row = $result3->fetch (PDO::FETCH_ASSOC))
993 {
994 $ret['in'][$count]['proto'] = $row['proto'];
995 $ret['in'][$count]['proto_bin'] = $row['proto_bin'];
996 $ret['in'][$count]['localport'] = $row['localport'];
997 $ret['in'][$count]['localip'] = $row['localip'];
998 $ret['in'][$count]['remoteport'] = $row['remoteport'];
999 $ret['in'][$count]['remoteip'] = $row['remoteip'];
1000 $ret['in'][$count]['object_id'] = $row['object_id'];
1001 $ret['in'][$count]['object_name'] = $row['object_name'];
1002 $ret['in'][$count]['description'] = $row['description'];
1003 $count++;
1004 }
1005 $result3->closeCursor();
1006
1007 return $ret;
1008}
1009
c31cd72c
DO
1010// This function returns an array of single element of object's FQDN attribute,
1011// if FQDN is set. Otherwise an array of all 'regular' IP addresses of the
1012// object is returned (which may appear 0 and more elements long).
1013// FIXME: attribute id for FQDN
1014function findAllEndpoints ($object_id)
1015{
1016 $values = getAttrValues ($object_id);
1017 foreach ($values as $record)
1018 if ($record['id'] == 3 && !empty ($record['value']))
1019 return array ($record['value']);
1020 $addresses = getObjectAddresses ($object_id);
1021 $regular = array();
1022 foreach ($addresses as $idx => $address)
1023 if ($address['type'] == 'regular')
fa8112d1 1024 $regular[] = $address['ip'];
c31cd72c
DO
1025 return $regular;
1026}
1027
e673ee24 1028?>