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