renderLocationFilterPortlet: add JavaScript to toggle children (#841)
[racktables] / wwwroot / inc / interface.php
CommitLineData
b325120a 1<?php
cddbb9fd
DO
2
3# This file is a part of RackTables, a datacenter and server room management
4# framework. See accompanying file "COPYING" for the full copyright and
5# licensing information.
6
e673ee24
DO
7/*
8*
9* This file contains frontend functions for RackTables.
10*
11*/
12
e82deb48 13require_once 'ajax-interface.php';
defd92d8 14require_once 'slb-interface.php';
65e557dd 15
9c0b0016
DO
16// Interface function's special.
17$nextorder['odd'] = 'even';
18$nextorder['even'] = 'odd';
19
52c836b1
DO
20// address allocation type
21$aat = array
22(
23 'regular' => 'Connected',
24 'virtual' => 'Loopback',
25 'shared' => 'Shared',
26 'router' => 'Router',
27);
beb9e88a 28// address allocation code, IPv4 addresses and objects view
52c836b1
DO
29$aac = array
30(
31 'regular' => '',
4318ced5
AA
32 'virtual' => '<span class="aac">L</span>',
33 'shared' => '<span class="aac">S</span>',
34 'router' => '<span class="aac">R</span>',
52c836b1 35);
beb9e88a
DO
36// address allocation code, IPv4 networks view
37$aac2 = array
38(
39 'regular' => '',
40 'virtual' => '<strong>L:</strong>',
29025f8e 41 'shared' => '<strong>S:</strong>',
beb9e88a
DO
42 'router' => '<strong>R:</strong>',
43);
52c836b1 44
0dabdc53
DO
45$vtdecoder = array
46(
47 'ondemand' => '',
54b7ced3
DO
48 'compulsory' => 'P',
49# 'alien' => 'NT',
0dabdc53
DO
50);
51
52$vtoptions = array
53(
54b7ced3
DO
54 'ondemand' => 'auto',
55 'compulsory' => 'permanent',
56# 'alien' => 'never touch',
0dabdc53
DO
57);
58
e5c4506d
DO
59// This may be populated later onsite, report rendering function will use it.
60// See the $systemreport for structure.
61$localreports = array();
d6adad3e 62
9db67d95
DO
63$CodePressMap = array
64(
65 'sql' => 'sql',
66 'php' => 'php',
67 'html' => 'html',
68 'css' => 'css',
69 'js' => 'javascript',
70);
e5c4506d 71
8d4f7d18
DO
72$attrtypes = array
73(
74 'uint' => '[U] unsigned integer',
75 'float' => '[F] floating point',
76 'string' => '[S] string',
86ff26ae
DO
77 'dict' => '[D] dictionary record',
78 'date' => '[T] date'
8d4f7d18
DO
79);
80
a1d72d2e
AA
81$quick_links = NULL; // you can override this in your local.php, but first initialize it with getConfiguredQuickLinks()
82
83function renderQuickLinks()
84{
85 global $quick_links;
86 if (! isset ($quick_links))
87 $quick_links = getConfiguredQuickLinks();
88 echo '<ul class="qlinks">';
89 foreach ($quick_links as $link)
90 echo '<li><a href="' . $link['href'] . '">' . str_replace (' ', '&nbsp;', $link['title']) . '</a></li>';
91 echo '</ul>';
92}
93
f97df464
DO
94function renderInterfaceHTML ($pageno, $tabno, $payload)
95{
96?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
97<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
98<head><title><?php echo getTitle ($pageno); ?></title>
99<?php printPageHeaders(); ?>
100</head>
101<body>
b2937330
AA
102<div class="maintable">
103 <div class="mainheader">
104 <div style="float: right" class=greeting><a href='index.php?page=myaccount&tab=default'><?php global $remote_displayname; echo $remote_displayname ?></a> [ <a href='?logout'>logout</a> ]</div>
a1d72d2e 105 <?php echo getConfigVar ('enterprise') ?> RackTables <a href="http://racktables.org" title="Visit RackTables site"><?php echo CODE_VERSION ?></a><?php renderQuickLinks() ?>
b2937330 106 </div>
d688a63f 107 <div class="menubar"><?php showPathAndSearch ($pageno, $tabno); ?></div>
b2937330
AA
108 <div class="tabbar"><?php showTabs ($pageno, $tabno); ?></div>
109 <div class="msgbar"><?php showMessageOrError(); ?></div>
110 <div class="pagebar"><?php echo $payload; ?></div>
111</div>
f97df464
DO
112</body>
113</html>
114<?php
115}
116
e673ee24 117// Main menu.
f2168c4b
DO
118function renderIndexItem ($ypageno)
119{
120 echo (! permitted ($ypageno)) ? " <td>&nbsp;</td>\n" :
121 " <td>\n" .
122 " <h1><a href='" . makeHref (array ('page' => $ypageno)) . "'>" .
123 getPageName ($ypageno) . "<br>\n" . getImageHREF ($ypageno) .
124 "</a></h1>\n" .
125 " </td>\n";
4b680876
DO
126}
127
e673ee24
DO
128function renderIndex ()
129{
67c5c049 130 global $indexlayout;
e673ee24
DO
131?>
132<table border=0 cellpadding=0 cellspacing=0 width='100%'>
133 <tr>
134 <td>
135 <div style='text-align: center; margin: 10px; '>
a544d2c4 136 <table width='100%' cellspacing=0 cellpadding=20 class=mainmenu border=0>
4b680876 137<?php
67c5c049
DO
138foreach ($indexlayout as $row)
139{
140 echo '<tr>';
141 foreach ($row as $column)
142 if ($column === NULL)
143 echo '<td>&nbsp;</td>';
144 else
145 renderIndexItem ($column);
146 echo '</tr>';
147}
148?>
e673ee24
DO
149 </table>
150 </div>
151 </td>
152 </tr>
153</table>
b325120a 154<?php
e673ee24
DO
155}
156
f3505b35
AA
157function getRenderedAlloc ($object_id, $alloc)
158{
159 $ret = array
160 (
161 'tr_class' => '',
40c9fc94 162 'td_name_suffix' => '',
f3505b35
AA
163 'td_ip' => '',
164 'td_network' => '',
165 'td_routed_by' => '',
166 'td_peers' => '',
167 );
168 $dottedquad = $alloc['addrinfo']['ip'];
4318ced5 169 $ip_bin = $alloc['addrinfo']['ip_bin'];
f3505b35 170
4318ced5
AA
171 $hl_ip_bin = NULL;
172 if (isset ($_REQUEST['hl_ip']))
f3505b35 173 {
4318ced5
AA
174 $hl_ip_bin = ip_parse ($_REQUEST['hl_ip']);
175 addAutoScrollScript ("ip-" . $_REQUEST['hl_ip']);
f3505b35
AA
176 }
177
178 $ret['tr_class'] = $alloc['addrinfo']['class'];
4318ced5 179 if ($hl_ip_bin === $ip_bin)
5c717ce5 180 $ret['tr_class'] .= ' highlight';
dec748f6 181
68c91b9c
AA
182 // render IP change history
183 $ip_title = '';
184 $ip_class = '';
185 if (isset ($alloc['addrinfo']['last_log']))
186 {
187 $log = $alloc['addrinfo']['last_log'];
188 $ip_title = "title='" .
189 htmlspecialchars
190 (
191 $log['user'] . ', ' . formatAge ($log['time']),
192 ENT_QUOTES
193 ) . "'";
194 $ip_class = 'hover-history underline';
195 }
196
f3505b35
AA
197 // render IP address td
198 global $aac;
4318ced5
AA
199 $netinfo = spotNetworkByIP ($ip_bin);
200 $ret['td_ip'] = "<td class='tdleft'>";
201 if (isset ($netinfo))
202 {
203 $title = $dottedquad;
204 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
205 $title .= '/' . $netinfo['mask'];
68c91b9c 206 $ret['td_ip'] .= "<a name='ip-$dottedquad' class='$ip_class' $ip_title href='" .
f3505b35
AA
207 makeHref (
208 array
209 (
4318ced5 210 'page' => 'ipaddress',
f3505b35
AA
211 'hl_object_id' => $object_id,
212 'ip' => $dottedquad,
213 )
4318ced5
AA
214 ) . "'>$title</a>";
215 }
f3505b35 216 else
68c91b9c 217 $ret['td_ip'] .= "<span class='$ip_class' $ip_title>$dottedquad</span>";
4318ced5 218 $ret['td_ip'] .= $aac[$alloc['type']];
f3505b35
AA
219 if (strlen ($alloc['addrinfo']['name']))
220 $ret['td_ip'] .= ' (' . niftyString ($alloc['addrinfo']['name']) . ')';
221 $ret['td_ip'] .= '</td>';
222
223 // render network and routed_by tds
4318ced5
AA
224 $td_class = 'tdleft';
225 if (! isset ($netinfo))
f3505b35
AA
226 {
227 $ret['td_network'] = "<td class='$td_class sparenetwork'>N/A</td>";
228 $ret['td_routed_by'] = $ret['td_network'];
229 }
230 else
231 {
232 $ret['td_network'] = "<td class='$td_class'>" .
233 getOutputOf ('renderCell', $netinfo) . '</td>';
234
98350e52
AA
235 // render "routed by" td
236 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') == 'none'))
237 $ret['td_routed_by'] = '';
f3505b35 238 else
98350e52
AA
239 {
240 loadIPAddrList ($netinfo);
241 $other_routers = array();
242 foreach (findRouters ($netinfo['own_addrlist']) as $router)
243 if ($router['id'] != $object_id)
244 $other_routers[] = $router;
245 if (count ($other_routers))
246 $ret['td_routed_by'] = getOutputOf ('printRoutersTD', $other_routers, $display_routers);
247 else
248 $ret['td_routed_by'] = "<td class='$td_class'>&nbsp;</td>";
249 }
f3505b35 250 }
dec748f6 251
f3505b35
AA
252 // render peers td
253 $ret['td_peers'] = "<td class='$td_class'>";
254 $prefix = '';
255 if ($alloc['addrinfo']['reserved'] == 'yes')
256 {
257 $ret['td_peers'] .= $prefix . '<strong>RESERVED</strong>';
258 $prefix = '; ';
259 }
260 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
261 {
262 if ($allocpeer['object_id'] == $object_id)
263 continue;
264 $ret['td_peers'] .= $prefix . "<a href='" . makeHref (array ('page' => 'object', 'object_id' => $allocpeer['object_id'])) . "'>";
265 if (isset ($allocpeer['osif']) and strlen ($allocpeer['osif']))
266 $ret['td_peers'] .= $allocpeer['osif'] . '@';
267 $ret['td_peers'] .= $allocpeer['object_name'] . '</a>';
268 $prefix = '; ';
269 }
270 $ret['td_peers'] .= '</td>';
271
272 return $ret;
273}
274
e1add254
AD
275function renderLocationFilterPortlet ()
276{
e1add254 277 // Recursive function used to build the location tree
2056822d 278 function renderLocationCheckbox ($subtree, $level = 0)
e1add254
AD
279 {
280 $self = __FUNCTION__;
e1add254 281
2056822d 282 foreach ($subtree as $location_id => $location)
e1add254 283 {
2056822d
AA
284 echo "<tr><td class=tagbox style='padding-left: " . ($level * 16) . "px;'><label>";
285 $checked = (in_array ($location['id'], $_SESSION['locationFilter'])) ? 'checked' : '';
9c88bba9 286 echo "<label><input type=checkbox name='location_id[]' class=${level} value='${location['id']}'${checked} onClick=checkAll(this)>${location['name']}";
2056822d
AA
287 echo "</label></td></tr>\n";
288 if ($location['kidc'])
289 $self ($location['kids'], $level + 1);
e1add254
AD
290 }
291 }
292
9c88bba9
AD
293 addJS(<<<END
294function checkAll(bx) {
295 for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;)
296 if (tbls[i].id == "locationFilter") {
297 var bxs=tbls[i].getElementsByTagName("input");
298 var in_tree = false;
299 for (var j=0; j<bxs.length; j++ ) {
300 if(in_tree == false && bxs[j].value == bx.value)
301 in_tree = true;
302 else if(parseInt(bxs[j].className) <= parseInt(bx.className))
303 in_tree = false;
304 if (bxs[j].type=="checkbox" && in_tree == true)
305 bxs[j].checked = bx.checked;
306 }
307 }
308}
309END
310 ,TRUE);
e1add254
AD
311 startPortlet ('Location filter');
312 echo <<<END
9c88bba9 313<table border=0 align=center cellspacing=0 class="tagtree" id="locationFilter">
e1add254
AD
314 <form method=get>
315 <input type=hidden name=page value=rackspace>
316 <input type=hidden name=tab value=default>
317 <input type=hidden name=changeLocationFilter value=true>
318END;
2056822d
AA
319
320 $locationlist = listCells ('location');
e1add254
AD
321 if (count ($locationlist))
322 {
9c88bba9
AD
323 echo "<tr><td class=tagbox style='padding-left: 0px'><label>";
324 echo "<input type=checkbox name='location' onClick=checkAll(this)> Toggle all";
325 echo "</label></td></tr>\n";
e1add254 326 echo "<tr><td class=tagbox><hr></td></tr>\n";
2056822d 327 renderLocationCheckbox (treeFromList ($locationlist));
e1add254
AD
328 echo "<tr><td class=tagbox><hr></td></tr>\n";
329 echo "<tr><td>";
330 printImageHREF ('setfilter', 'set filter', TRUE);
331 echo "</td></tr>\n";
332 }
333 else
334 {
335 echo "<tr><td class='tagbox sparenetwork'>(no locations exist)</td></tr>\n";
336 echo "<tr><td>";
337 printImageHREF ('setfilter gray');
338 echo "</td></tr>\n";
339 }
340
341 echo "</form></table>\n";
342 finishPortlet ();
343}
344
e673ee24
DO
345function renderRackspace ()
346{
e1add254
AD
347 // Handle the location filter
348 @session_start();
349 if (isset ($_REQUEST['changeLocationFilter']))
350 unset ($_SESSION['locationFilter']);
351 if (isset ($_REQUEST['location_id']))
352 $_SESSION['locationFilter'] = $_REQUEST['location_id'];
353 if (!isset ($_SESSION['locationFilter']))
dec748f6 354 $_SESSION['locationFilter'] = array_keys (listCells ('location')); // Add all locations to the filter
5d6352df 355 session_commit();
e1add254 356
95857b5c
DO
357 $found_racks = array();
358 $rows = array();
a8efc03e 359 $cellfilter = getCellFilter();
1ebbf889 360 $rackCount = 0;
e1add254
AD
361 foreach (getAllRows() as $row_id => $rowInfo)
362 {
95857b5c 363 $rackList = filterCellList (listCells ('rack', $row_id), $cellfilter['expression']);
e1add254
AD
364 $found_racks = array_merge ($found_racks, $rackList);
365 $rows[] = array (
366 'location_id' => $rowInfo['location_id'],
367 'location_name' => $rowInfo['location_name'],
95857b5c 368 'row_id' => $row_id,
e1add254 369 'row_name' => $rowInfo['name'],
95857b5c
DO
370 'racks' => $rackList
371 );
1ebbf889 372 $rackCount += count($rackList);
95857b5c 373 }
1ebbf889 374
95857b5c 375 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
1ebbf889
AA
376
377 if (! renderEmptyResults($cellfilter, 'racks', $rackCount))
e673ee24 378 {
1ebbf889
AA
379 // generate thumb gallery
380 global $nextorder;
381 $rackwidth = getRackImageWidth();
382 // Zero value effectively disables the limit.
383 $maxPerRow = getConfigVar ('RACKS_PER_ROW');
384 $order = 'odd';
e1add254 385 if (count ($rows))
1ebbf889 386 {
e1add254
AD
387 echo '<table border=0 cellpadding=10 class=cooltable>';
388 echo '<tr><th class=tdleft>Location</th><th class=tdleft>Row</th><th class=tdleft>Racks</th></tr>';
389 foreach ($rows as $row)
390 {
391 $location_id = $row['location_id'];
392 $row_id = $row['row_id'];
393 $row_name = $row['row_name'];
394 $rackList = $row['racks'];
395
396 if (($location_id != '' and !in_array ($location_id, $_SESSION['locationFilter'])) or (!count ($rackList) and count ($cellfilter['expression'])))
397 continue;
398 $rackListIdx = 0;
399 echo "<tr class=row_${order}><th class=tdleft>";
c08915c7
AD
400 $locationTree = '';
401 while ($location_id)
402 {
403 $parentLocation = spotEntity ('location', $location_id);
ec459a0b 404 $locationTree = "&raquo; <a href='" .
c08915c7
AD
405 makeHref(array('page'=>'location', 'location_id'=>$parentLocation['id'])) .
406 "${cellfilter['urlextra']}'>${parentLocation['name']}</a> " .
407 $locationTree;
408 $location_id = $parentLocation['parent_id'];
409 }
410 $locationTree = substr ($locationTree, 8);
411 echo $locationTree;
e1add254
AD
412 echo "</th><th class=tdleft><a href='".makeHref(array('page'=>'row', 'row_id'=>$row_id))."${cellfilter['urlextra']}'>${row_name}</a></th>";
413 echo "<th class=tdleft><table border=0 cellspacing=5><tr>";
414 if (!count ($rackList))
415 echo "<td>(empty row)</td>";
416 else
417 foreach ($rackList as $rack)
1ebbf889 418 {
e1add254
AD
419 if ($rackListIdx > 0 and $maxPerRow > 0 and $rackListIdx % $maxPerRow == 0)
420 {
42504426 421 echo '</tr></table></th></tr>';
e1add254
AD
422 echo "<tr class=row_${order}><th class=tdleft></th><th class=tdleft>${row_name} (continued)";
423 echo "</th><th class=tdleft><table border=0 cellspacing=5><tr>";
424 }
425 echo "<td align=center valign=bottom><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
426 echo "<img border=0 width=${rackwidth} height=";
427 echo getRackImageHeight ($rack['height']);
428 echo " title='${rack['height']} units'";
429 echo "src='?module=image&img=minirack&rack_id=${rack['id']}'>";
430 echo "<br>${rack['name']}</a></td>";
431 $rackListIdx++;
1ebbf889 432 }
e1add254 433 $order = $nextorder[$order];
42504426 434 echo "</tr></table></th></tr>\n";
e1add254 435 }
42504426 436 echo "</table>\n";
1ebbf889 437 }
e1add254
AD
438 else
439 echo "<h2>No rows found</h2>\n";
e673ee24 440 }
14ad4f4a
DO
441 echo '</td><td class=pcright width="25%">';
442 renderCellFilterPortlet ($cellfilter, 'rack', $found_racks);
e1add254
AD
443 echo "<br>\n";
444 renderLocationFilterPortlet ();
489a7502 445 echo "</td></tr></table>\n";
e673ee24
DO
446}
447
2056822d 448function renderLocationRowForEditor ($subtree, $level = 0)
e1add254
AD
449{
450 $self = __FUNCTION__;
2056822d
AA
451 foreach ($subtree as $locationinfo)
452 {
453 echo "<tr><td align=left style='padding-left: " . ($locationinfo['kidc'] ? $level : ($level + 1) * 16) . "px;'>";
454 if ($locationinfo['kidc'])
455 printImageHREF ('node-expanded-static');
456 if ($locationinfo['refcnt'] > 0 || $locationinfo['kidc'] > 0)
457 printImageHREF ('nodestroy');
458 else
10f5133a 459 echo getOpLink (array ('op' => 'deleteLocation', 'location_id' => $locationinfo['id']), '', 'destroy', 'Delete location');
2056822d
AA
460 echo '</td><td class=tdleft>';
461 printOpFormIntro ('updateLocation', array ('location_id' => $locationinfo['id']));
462 $parent = isset ($locationinfo['parent_id']) ? $locationinfo['parent_id'] : 0;
463 echo getSelect
464 (
465 array ( $parent => $parent ? htmlspecialchars ($locationinfo['parent_name']) : '-- NONE --'),
466 array ('name' => 'parent_id', 'id' => 'locationid_' . $locationinfo['id'], 'class' => 'locationlist-popup'),
467 $parent,
468 FALSE
469 );
470 echo "</td><td class=tdleft>";
471 echo "<input type=text size=48 name=name value='${locationinfo['name']}'>";
472 echo '</td><td>' . getImageHREF ('save', 'Save changes', TRUE) . "</form></td></tr>\n";
473 if ($locationinfo['kidc'])
474 $self ($locationinfo['kids'], $level + 1);
475 }
e1add254
AD
476}
477
478function renderRackspaceLocationEditor ()
479{
480 addJS
481 (
482<<<END
483function locationeditor_showselectbox(e) {
484 $(this).load('index.php', {module: 'ajax', ac: 'get-location-select', locationid: this.id});
485 $(this).unbind('mousedown', locationeditor_showselectbox);
486}
487$(document).ready(function () {
488 $('select.locationlist-popup').bind('mousedown', locationeditor_showselectbox);
489});
490END
491 , TRUE
492 );
493 function printNewItemTR ()
494 {
e1add254
AD
495 printOpFormIntro ('addLocation');
496 echo "<tr><td>";
497 printImageHREF ('create', 'Add new location', TRUE);
498 echo "</td><td><select name=parent_id tabindex=100>";
499 echo "<option value=0>-- NONE --</option>";
2056822d 500 foreach (listCells ('location') as $location)
e1add254
AD
501 echo "<option value=${location['id']}>${location['name']}</option>";
502 echo "</select></td>";
503 echo "<td><input type=text size=48 name=name tabindex=101></td><td>";
504 printImageHREF ('create', 'Add new location', TRUE, 102);
505 echo "</td></tr></form>\n";
506 }
e1add254
AD
507
508 startPortlet ('Locations');
509 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
510 echo "<tr><th>&nbsp;</th><th>Parent</th><th>Name</th><th>&nbsp;</th></tr>\n";
511 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
512 printNewItemTR();
2056822d 513
1e0f13f3
AD
514 $locations = listCells ('location');
515 renderLocationRowForEditor (treeFromList ($locations));
2056822d 516
e1add254
AD
517 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
518 printNewItemTR();
519 echo "</table><br>\n";
520 finishPortlet();
521}
522
345fd640
AD
523function renderRackspaceRowEditor ()
524{
2056822d 525 function printNewItemTR ($locationlist)
345fd640
AD
526 {
527 printOpFormIntro ('addRow');
7be51fea
DO
528 echo "<tr><td>";
529 printImageHREF ('create', 'Add new row', TRUE);
e1add254
AD
530 echo "</td><td><select name=location_id tabindex=100>";
531 echo "<option value=0>-- NONE --</option>";
532 foreach ($locationlist as $location)
533 echo "<option value=${location['id']}>${location['name']}</option>";
534 echo "</select></td>";
535 echo "<td><input type=text name=name tabindex=101></td><td>";
536 printImageHREF ('create', 'Add new row', TRUE, 102);
7be51fea 537 echo "</td></tr></form>";
345fd640 538 }
2056822d 539 $locationlist = listCells ('location');
e1add254 540
d732e47e 541 startPortlet ('Rows');
345fd640 542 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
e1add254 543 echo "<tr><th>&nbsp;</th><th>Location</th><th>Name</th><th>&nbsp;</th></tr>\n";
345fd640 544 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
2056822d 545 printNewItemTR($locationlist);
e1add254 546 foreach (getAllRows() as $row_id => $rowInfo)
345fd640 547 {
7be51fea 548 echo "<tr><td>";
a8efc03e 549 if ($rc = count (listCells ('rack', $row_id)))
6c18dd08 550 printImageHREF ('nodestroy', "${rc} rack(s) here");
7be51fea 551 else
10f5133a 552 echo getOpLink (array('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row');
c40666f5 553 printOpFormIntro ('updateRow', array ('row_id' => $row_id));
e1add254
AD
554 echo "</td><td>";
555 $selectlist = array();
556 $selectlist['other'][0] = '-- NONE --';
557 foreach ($locationlist as $location_id => $locationdata)
558 $selectlist['other'][$location_id] = $locationdata['name'];
559 printNiftySelect ($selectlist, array ('name' => 'location_id'), $rowInfo['location_id']);
560 echo "</td><td><input type=text name=name value='${rowInfo['name']}'></td><td>";
7be51fea
DO
561 printImageHREF ('save', 'Save changes', TRUE);
562 echo "</form></td></tr>\n";
345fd640
AD
563 }
564 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
2056822d 565 printNewItemTR($locationlist);
345fd640
AD
566 echo "</table><br>\n";
567 finishPortlet();
568}
569
7e1db771 570function renderRow ($row_id)
e673ee24 571{
e16b666c 572 $rowInfo = getRowInfo ($row_id);
a8efc03e
DO
573 $cellfilter = getCellFilter();
574 $rackList = filterCellList (listCells ('rack', $row_id), $cellfilter['expression']);
e673ee24
DO
575 // Main layout starts.
576 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
577
578 // Left portlet with row information.
579 echo "<tr><td class=pcleft>";
a8ce7234 580 startPortlet ($rowInfo['name']);
e673ee24 581 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
58295e8c
AD
582 if ($rowInfo['location_id'])
583 echo "<tr><th width='50%' class=tdright>Location:</th><td class=tdleft>".mkA ($rowInfo['location'], 'location', $rowInfo['location_id'])."</td></tr>\n";
5af82683
DY
584 echo "<tr><th width='50%' class=tdright>Racks:</th><td class=tdleft>${rowInfo['count']}</td></tr>\n";
585 echo "<tr><th width='50%' class=tdright>Units:</th><td class=tdleft>${rowInfo['sum']}</td></tr>\n";
9b8174d7
AD
586 echo "<tr><th width='50%' class=tdright>% used:</th><td class=tdleft>";
587 renderProgressBar (getRSUforRow ($rackList));
114e50af 588 echo "</td></tr>\n";
e673ee24
DO
589 echo "</table><br>\n";
590 finishPortlet();
7f297114 591 renderCellFilterPortlet ($cellfilter, 'rack', $rackList, array ('row_id' => $row_id));
e673ee24 592
6ccfd4bd 593 renderFilesPortlet ('row',$row_id);
48325652 594 echo "</td><td class=pcright>";
e673ee24 595
4fbb5a00 596 global $nextorder;
d5157018 597 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
f5883ec1
DO
598 // Maximum number of racks per row is proportionally less, but at least 1.
599 $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1);
600 $rackListIdx = 0;
e673ee24
DO
601 $order = 'odd';
602 startPortlet ('Racks');
603 echo "<table border=0 cellspacing=5 align='center'><tr>";
64b95774 604 foreach ($rackList as $rack)
e673ee24 605 {
f5883ec1
DO
606 if ($rackListIdx % $maxPerRow == 0)
607 {
608 if ($rackListIdx > 0)
609 echo '</tr>';
610 echo '<tr>';
611 }
9b8174d7 612 $class = ($rack['has_problems'] == 'yes') ? 'error' : $order;
d69e5d6f 613 echo "<td align=center valign=bottom class=row_${class}><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
d5157018 614 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
e673ee24 615 echo " title='${rack['height']} units'";
e696bef6 616 echo "src='?module=image&img=midirack&rack_id=${rack['id']}&scale=" . getConfigVar ('ROW_SCALE') . "'>";
e673ee24
DO
617 echo "<br>${rack['name']}</a></td>";
618 $order = $nextorder[$order];
f5883ec1 619 $rackListIdx++;
e673ee24
DO
620 }
621 echo "</tr></table>\n";
622 finishPortlet();
e673ee24
DO
623 echo "</td></tr></table>";
624}
625
0a7feebb 626// Used by renderRack()
84feb87b 627function printObjectDetailsForRenderRack ($object_id, $hl_obj_id = 0)
0a7feebb
AD
628{
629 $objectData = spotEntity ('object', $object_id);
630 if (strlen ($objectData['asset_no']))
631 $prefix = "<div title='${objectData['asset_no']}";
632 else
633 $prefix = "<div title='no asset tag";
634 // Don't tell about label, if it matches common name.
635 $body = '';
636 if ($objectData['name'] != $objectData['label'] and strlen ($objectData['label']))
637 $body = ", visible label is \"${objectData['label']}\"";
638 // Display list of child objects, if any
639 $objectChildren = getEntityRelatives ('children', 'object', $objectData['id']);
84feb87b 640 $slotInfo = $slotData = $slotTitle = array ();
0a7feebb
AD
641 if (count($objectChildren) > 0)
642 {
643 foreach ($objectChildren as $child)
84feb87b 644 {
0a7feebb 645 $childNames[] = $child['name'];
84feb87b 646 $childData = spotEntity ('object', $child['entity_id']);
ec459a0b 647 $attrData = getAttrValues ($child['entity_id']);
84feb87b
AD
648 if ($attrData['28']) // slot number
649 {
650 $slot = $attrData['28']['value'];
651 $slotInfo[$slot] = $child['name'];
652 $slotData[$slot] = $child['entity_id'];
653 if (strlen ($childData['asset_no']))
654 $slotTitle[$slot] = "<div title='${childData['asset_no']}";
655 else
656 $slotTitle[$slot] = "<div title='no asset tag";
657 if (strlen ($childData['label']) and $childData['label'] != $child['name'])
658 $slotTitle[$slot] .= ", visible label is \"${childData['label']}\"";
659 $slotTitle[$slot] .= "'>";
660 }
661 }
0a7feebb
AD
662 natsort($childNames);
663 $suffix = sprintf(", contains %s'>", implode(', ', $childNames));
664 }
665 else
666 $suffix = "'>";
ad3e5e7e 667 echo "${prefix}${body}${suffix}" . mkA ($objectData['dname'], 'object', $objectData['id']) . '</div>';
84feb87b
AD
668 if (in_array ($objectData['objtype_id'], array (1502,1503))) // server chassis, network chassis
669 {
670 $objAttr = getAttrValues ($objectData['id']);
671 if (isset ($objAttr[2])) // HW type
672 {
673 extractLayout ($objAttr[2]);
674 if (isset ($objAttr[2]['rows']))
675 {
676 $rows = $objAttr[2]['rows'];
677 $cols = $objAttr[2]['cols'];
678 $layout = $objAttr[2]['layout'];
679 echo "<table width='100%' border='1'>";
680 for ($r = 0; $r < $rows; $r++)
681 {
682 echo '<tr>';
683 for ($c = 0; $c < $cols; $c++)
684 {
685 $s = ($r * $cols) + $c + 1;
686 if (isset ($slotData[$s]))
687 {
688 echo "<td class='state_T";
689 if ($slotData[$s] == $hl_obj_id)
690 echo 'h';
691 echo "'>${slotTitle[$s]}";
692 if ($layout == 'V')
693 {
694 $tmp = substr ($slotInfo[$s], 0, 1);
695 foreach (str_split (substr ($slotInfo[$s],1)) as $letter)
696 $tmp .= '<br>' . $letter;
697 $slotInfo[$s] = $tmp;
698 }
699 echo mkA ($slotInfo[$s], 'object', $slotData[$s]);
700 echo '</div></td>';
701 }
702 else
703 echo "<td class='state_F'><div title=\"Free slot\">&nbsp;</div></td>";
704 }
705 echo '</tr>';
706 }
707 echo '</table>';
708 }
709 }
710 }
0a7feebb
AD
711}
712
e673ee24 713// This function renders rack as HTML table.
7e1db771 714function renderRack ($rack_id, $hl_obj_id = 0)
e673ee24 715{
61a1d996
DO
716 $rackData = spotEntity ('rack', $rack_id);
717 amplifyCell ($rackData);
e673ee24
DO
718 markAllSpans ($rackData);
719 if ($hl_obj_id > 0)
720 highlightObject ($rackData, $hl_obj_id);
e673ee24
DO
721 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
722 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
d48d8820 723 echo "<center><table border=0><tr valign=middle>";
ad3e5e7e 724 echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>';
e673ee24 725 if ($prev_id != NULL)
ad3e5e7e
DO
726 echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>';
727 echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>';
e673ee24 728 if ($next_id != NULL)
ad3e5e7e 729 echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>';
d48d8820 730 echo "</h2></td></tr></table>\n";
e673ee24 731 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
d08147d6
DO
732 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
733 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
e673ee24
DO
734 for ($i = $rackData['height']; $i > 0; $i--)
735 {
4dcd770e 736 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
e673ee24
DO
737 for ($locidx = 0; $locidx < 3; $locidx++)
738 {
739 if (isset ($rackData[$i][$locidx]['skipped']))
740 continue;
741 $state = $rackData[$i][$locidx]['state'];
65e557dd 742 echo "<td class='atom state_${state}";
e673ee24
DO
743 if (isset ($rackData[$i][$locidx]['hl']))
744 echo $rackData[$i][$locidx]['hl'];
65e557dd 745 echo "'";
e673ee24
DO
746 if (isset ($rackData[$i][$locidx]['colspan']))
747 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
748 if (isset ($rackData[$i][$locidx]['rowspan']))
749 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
750 echo ">";
751 switch ($state)
752 {
753 case 'T':
84feb87b 754 printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id);
e673ee24
DO
755 break;
756 case 'A':
757 echo '<div title="This rackspace does not exist">&nbsp;</div>';
758 break;
759 case 'F':
760 echo '<div title="Free rackspace">&nbsp;</div>';
761 break;
762 case 'U':
763 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
764 break;
765 default:
766 echo '<div title="No data">&nbsp;</div>';
767 break;
768 }
769 echo '</td>';
770 }
771 echo "</tr>\n";
772 }
0a7feebb
AD
773 echo "</table>\n";
774 // Get a list of all of objects Zero-U mounted to this rack
775 $zeroUObjects = getEntityRelatives('children', 'rack', $rack_id);
a20a4e3c
DO
776 if (count ($zeroUObjects) > 0)
777 {
0a7feebb
AD
778 echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n";
779 echo "<tr><th>Zero-U:</th></tr>\n";
780 foreach ($zeroUObjects as $zeroUObject)
781 {
782 $state = ($zeroUObject['entity_id'] == $hl_obj_id) ? 'Th' : 'T';
783 echo "<tr><td class='atom state_${state}'>";
784 printObjectDetailsForRenderRack($zeroUObject['entity_id']);
785 echo "</td></tr>\n";
786 }
787 echo "</table>\n";
788 }
789 echo "</center>\n";
e673ee24
DO
790}
791
42504426
AD
792function renderRackSortForm ($row_id)
793{
2b8c5aad 794 includeJQueryUI (FALSE);
42504426
AD
795 addJS
796 (
797<<<END
798 $(document).ready(
799 function () {
800 $("#sortRacks").sortable({
801 update : function () {
802 serial = $('#sortRacks').sortable('serialize');
803 $.ajax({
804 url: 'index.php?module=ajax&ac=upd-rack-sort-order',
805 type: 'post',
806 data: serial,
807 });
808 }
809 });
810 }
811 );
812END
813 , TRUE
814 );
815
816 startPortlet ('Racks');
817 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
818 echo "<tr><th>Drag to change order</th></tr>\n";
819 echo "<tr><td><ul class='uflist' id='sortRacks'>\n";
820 foreach (getRacks($row_id) as $rack_id => $rackInfo)
821 echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n";
822 echo "</ul></td></tr></table>\n";
823 finishPortlet();
824}
825
e673ee24
DO
826function renderNewRackForm ($row_id)
827{
9b8174d7
AD
828 $default_height = getConfigVar ('DEFAULT_RACK_HEIGHT');
829 if ($default_height == 0)
830 $default_height = '';
50b4ba85 831 startPortlet ('Add one');
f19c75d6 832 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
e673ee24 833 echo '<table border=0 align=center>';
9b8174d7 834 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name tabindex=1></td>";
72d52730 835 echo "<td rowspan=4>Assign tags:<br>";
a26a6ccc 836 renderNewEntityTags ('rack');
72d52730 837 echo "</td></tr>\n";
9b8174d7 838 echo "<tr><th class=tdright>Height in units (required):</th><td class=tdleft><input type=text name=height1 tabindex=2 value='${default_height}'></td></tr>\n";
9b8174d7 839 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no tabindex=4></td></tr>\n";
f19c75d6
DO
840 echo "<tr><td class=submit colspan=2>";
841 printImageHREF ('CREATE', 'Add', TRUE);
842 echo "</td></tr></table></form>";
406b54bd 843 finishPortlet();
406b54bd 844
50b4ba85 845 startPortlet ('Add many');
f19c75d6 846 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
50b4ba85 847 echo '<table border=0 align=center>';
9b8174d7 848 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>";
72d52730 849 echo "<td rowspan=3 valign=top>Assign tags:<br>";
a26a6ccc 850 renderNewEntityTags ('rack');
72d52730 851 echo "</td></tr>\n";
9b8174d7 852 echo "<tr><th class=tdright>Rack names (required):</th><td class=tdleft><textarea name=names cols=40 rows=25></textarea></td></tr>\n";
f19c75d6
DO
853 echo "<tr><td class=submit colspan=2>";
854 printImageHREF ('CREATE', 'Add', TRUE);
e673ee24
DO
855 echo '</form></table>';
856 finishPortlet();
857}
858
3825c4db 859function renderEditObjectForm()
e673ee24 860{
8dc2a6c8 861 global $pageno, $virtual_obj_types;
3825c4db 862 $object_id = getBypassValue();
fb6e2f57 863 $object = spotEntity ('object', $object_id);
cdd3efe9 864 startPortlet ();
43fb6eaf 865 printOpFormIntro ('update');
cdd3efe9
AD
866
867 // static attributes
e10f583a
DO
868 echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
869 echo "<tr><td>&nbsp;</td><th colspan=2><h2>Attributes</h2></th></tr>";
3825c4db
DO
870 echo '<tr><td>&nbsp;</td><th class=tdright>Type:</th><td class=tdleft>';
871 printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']);
872 echo '</td></tr>';
22bb04da 873 // baseline info
e10f583a 874 echo "<tr><td>&nbsp;</td><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
8dc2a6c8 875 if (in_array($object['objtype_id'], $virtual_obj_types))
0682218d
AD
876 {
877 echo "<input type=hidden name=object_label value=''>\n";
878 echo "<input type=hidden name=object_asset_no value=''>\n";
0682218d
AD
879 }
880 else
881 {
882 echo "<tr><td>&nbsp;</td><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
883 echo "<tr><td>&nbsp;</td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
0682218d
AD
884 }
885 // parent selection
9b8174d7 886 if (objectTypeMayHaveParent ($object['objtype_id']))
0682218d
AD
887 {
888 $parents = getEntityRelatives ('parents', 'object', $object_id);
889 foreach ($parents as $link_id => $parent_details)
890 {
891 if (!isset($label))
892 $label = count($parents) > 1 ? 'Containers:' : 'Container:';
893 echo "<tr><td>&nbsp;</td>";
894 echo "<th class=tdright>${label}</th><td class=tdleft>";
ad3e5e7e 895 echo mkA ($parent_details['name'], 'object', $parent_details['entity_id']);
0682218d 896 echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
10f5133a 897 echo getOpLink (array('op'=>'unlinkEntities', 'link_id'=>$link_id), '', 'cut', 'Unlink container');
0682218d
AD
898 echo "</td></tr>\n";
899 $label = '&nbsp;';
900 }
901 echo "<tr><td>&nbsp;</td>";
902 echo "<th class=tdright>Select container:</th><td class=tdleft>";
903 echo "<span";
904 $helper_args = array ('object_id' => $object_id);
905 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
906 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
907 echo " onclick='window.open(\"" . makeHrefForHelper ('objlist', $helper_args);
908 echo "\",\"findlink\",\"${popup_args}\");'>";
909 printImageHREF ('attach', 'Select a container');
910 echo "</span></td></tr>\n";
911 }
cdd3efe9 912 // optional attributes
a2a7f6f6 913 $i = 0;
e673ee24 914 $values = getAttrValues ($object_id);
2b98d5a2 915 if (count($values) > 0)
e673ee24 916 {
2b98d5a2 917 foreach ($values as $record)
e673ee24 918 {
990fce2a
AA
919 if (! permitted (NULL, NULL, NULL, array (
920 array ('tag' => '$attr_' . $record['id']),
921 array ('tag' => '$any_op'),
922 )))
923 continue;
2b98d5a2
AD
924 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
925 echo '<tr><td>';
59a83bd8 926 if (strlen ($record['value']))
10f5133a 927 echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation');
2b98d5a2
AD
928 else
929 echo '&nbsp;';
930 echo '</td>';
e10f583a 931 echo "<th class=sticker>${record['name']}:</th><td class=tdleft>";
2b98d5a2
AD
932 switch ($record['type'])
933 {
934 case 'uint':
935 case 'float':
936 case 'string':
937 echo "<input type=text name=${i}_value value='${record['value']}'>";
938 break;
939 case 'dict':
7fa7047a 940 $chapter = readChapter ($record['chapter_id'], 'o');
2b98d5a2 941 $chapter[0] = '-- NOT SET --';
f3d274bf 942 $chapter = cookOptgroups ($chapter, $object['objtype_id'], $record['key']);
cd3775e9 943 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
2b98d5a2 944 break;
86ff26ae 945 case 'date':
2a943f85 946 $date_value = $record['value'] ? datetimestrFromTimestamp ($record['value']) : '';
86ff26ae
DO
947 echo "<input type=text name=${i}_value value='${date_value}'>";
948 break;
2b98d5a2
AD
949 }
950 echo "</td></tr>\n";
951 $i++;
e673ee24 952 }
e673ee24 953 }
a2a7f6f6 954 echo '<input type=hidden name=num_attrs value=' . $i . ">\n";
e10f583a
DO
955 echo "<tr><td>&nbsp;</td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
956 if ($object['has_problems'] == 'yes')
957 echo ' checked';
958 echo "></td></tr>\n";
dec748f6 959 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
10f5133a 960 echo getOpLink (array ('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id), '' ,'destroy', 'Delete object', 'need-confirmation');
abd1e9ac 961 echo "&nbsp;";
10f5133a 962 echo getOpLink (array ('op'=>'resetObject'), '' ,'clear', 'Reset (cleanup) object', 'need-confirmation');
abd1e9ac 963 echo "</td></tr>\n";
e10f583a 964 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
cdd3efe9 965
e10f583a 966 echo "<tr><th class=submit colspan=3>";
5bbbeaa2 967 printImageHREF ('SAVE', 'Save changes', TRUE);
cdd3efe9 968 echo "</form></th></tr></table>\n";
e673ee24 969 finishPortlet();
e673ee24 970
cdd3efe9 971 echo '<table border=0 width=100%><tr><td>';
e673ee24 972 startPortlet ('history');
9b8174d7 973 renderObjectHistory ($object_id);
e673ee24 974 finishPortlet();
cdd3efe9 975 echo '</td></tr></table>';
e673ee24
DO
976}
977
e673ee24
DO
978function renderEditRackForm ($rack_id)
979{
0c2b7c4a 980 global $pageno;
61a1d996
DO
981 $rack = spotEntity ('rack', $rack_id);
982 amplifyCell ($rack);
e673ee24 983
9b8174d7 984 startPortlet ('Attributes');
7056988c 985 printOpFormIntro ('updateRack');
e673ee24 986 echo '<table border=0 align=center>';
9b8174d7 987 echo "<tr><td>&nbsp;</td><th class=tdright>Rack row:</th><td class=tdleft>";
e1add254
AD
988 foreach (getAllRows () as $row_id => $rowInfo)
989 $rows[$row_id] = $rowInfo['name'];
990 natcasesort ($rows);
991 printSelect ($rows, array ('name' => 'row_id'), $rack['row_id']);
e673ee24 992 echo "</td></tr>\n";
9b8174d7
AD
993 echo "<tr><td>&nbsp;</td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${rack['name']}'></td></tr>\n";
994 echo "<tr><td>&nbsp;</td><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=height value='${rack['height']}'></td></tr>\n";
9b8174d7
AD
995 echo "<tr><td>&nbsp;</td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no value='${rack['asset_no']}'></td></tr>\n";
996 // optional attributes
997 $values = getAttrValues ($rack_id);
998 $num_attrs = count($values);
42504426 999 $num_attrs = $num_attrs-2; // subtract for the 'height' and 'sort_order' attributes
9b8174d7
AD
1000 echo "<input type=hidden name=num_attrs value=${num_attrs}>\n";
1001 $i = 0;
1002 foreach ($values as $record)
1003 {
1004 // Skip the 'height' attribute as it's already displayed as a required field
42504426
AD
1005 // Also skip the 'sort_order' attribute
1006 if ($record['id'] == 27 or $record['id'] == 29)
9b8174d7
AD
1007 continue;
1008 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
1009 echo '<tr><td>';
1010 if (strlen ($record['value']))
10f5133a 1011 echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation');
9b8174d7
AD
1012 else
1013 echo '&nbsp;';
1014 echo '</td>';
1015 echo "<th class=sticker>${record['name']}:</th><td class=tdleft>";
1016 switch ($record['type'])
1017 {
1018 case 'uint':
1019 case 'float':
1020 case 'string':
1021 echo "<input type=text name=${i}_value value='${record['value']}'>";
1022 break;
1023 case 'dict':
1024 $chapter = readChapter ($record['chapter_id'], 'o');
1025 $chapter[0] = '-- NOT SET --';
1026 $chapter = cookOptgroups ($chapter, 1560, $record['key']);
1027 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
1028 break;
1029 }
1030 echo "</td></tr>\n";
1031 $i++;
1032 }
1033 echo "<tr><td>&nbsp;</td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=has_problems";
1034 if ($rack['has_problems'] == 'yes')
1035 echo ' checked';
1036 echo "></td></tr>\n";
c495997f 1037 if ($rack['isDeletable'])
c8187437 1038 {
dec748f6 1039 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
10f5133a 1040 echo getOpLink (array ('op'=>'deleteRack'), '', 'destroy', 'Delete rack', 'need-confirmation');
9b8174d7 1041 echo "&nbsp;</td></tr>\n";
c8187437 1042 }
9b8174d7
AD
1043 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=comment rows=10 cols=80>${rack['comment']}</textarea></td></tr>";
1044 echo "<tr><td class=submit colspan=3>";
7056988c
DO
1045 printImageHREF ('SAVE', 'Save changes', TRUE);
1046 echo "</td></tr>\n";
e673ee24
DO
1047 echo '</form></table><br>';
1048 finishPortlet();
dec748f6 1049
e673ee24 1050 startPortlet ('History');
9b8174d7 1051 renderObjectHistory ($rack_id);
e673ee24
DO
1052 finishPortlet();
1053}
1054
254673dd
DO
1055// used by renderGridForm() and renderRackPage()
1056function renderRackInfoPortlet ($rackData)
1057{
646272be
AA
1058 $summary = array();
1059 $summary['Rack row'] = $rackData['row_name'];
1060 $summary['Name'] = $rackData['name'];
1061 $summary['Height'] = $rackData['height'];
9b8174d7 1062 if (strlen ($rackData['asset_no']))
646272be 1063 $summary['Asset tag'] = $rackData['asset_no'];
9b8174d7 1064 if ($rackData['has_problems'] == 'yes')
646272be 1065 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
42504426
AD
1066 // Display populated attributes, but skip 'height' since it's already displayed above
1067 // and skip 'sort_order' because it's modified using AJAX
9b8174d7 1068 foreach (getAttrValues ($rackData['id']) as $record)
42504426 1069 if ($record['id'] != 27 && $record['id'] != 29 && strlen ($record['value']))
646272be
AA
1070 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
1071 $summary['% used'] = getProgressBar (getRSUforRack ($rackData));
1072 $summary['Objects'] = count ($rackData['mountedObjects']);
1073 $summary['tags'] = '';
59a83bd8 1074 if (strlen ($rackData['comment']))
646272be
AA
1075 $summary['Comment'] = $rackData['comment'];
1076 renderEntitySummary ($rackData, 'summary', $summary);
254673dd
DO
1077}
1078
e673ee24 1079// This is a universal editor of rack design/waste.
7056988c 1080// FIXME: switch to using printOpFormIntro()
7e1db771 1081function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2)
e673ee24 1082{
61a1d996
DO
1083 $rackData = spotEntity ('rack', $rack_id);
1084 amplifyCell ($rackData);
254673dd 1085 $filter ($rackData);
e673ee24 1086
e673ee24
DO
1087 // Render the result whatever it is.
1088 // Main layout.
1089 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1090 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
1091
1092 // Left column with information portlet.
1093 echo "<tr><td class=pcleft height='1%' width='50%'>";
254673dd 1094 renderRackInfoPortlet ($rackData);
e673ee24 1095 echo "</td>\n";
bb09cca0 1096 echo "<td class=pcright>";
e673ee24
DO
1097
1098 // Grid form.
1099 startPortlet ($header);
65e557dd 1100 addJS ('js/racktables.js');
e673ee24
DO
1101 echo "<center>\n";
1102 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 1103 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
1104 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1105 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1106 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
4fbb5a00 1107 printOpFormIntro ('updateRack');
e673ee24
DO
1108 markupAtomGrid ($rackData, $state2);
1109 renderAtomGrid ($rackData);
1110 echo "</table></center>\n";
1111 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
1112 finishPortlet();
bb09cca0 1113 echo "</td></tr></table>\n";
e673ee24
DO
1114}
1115
1116function renderRackDesign ($rack_id)
1117{
bb09cca0 1118 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
e673ee24
DO
1119}
1120
7e1db771 1121function renderRackProblems ($rack_id)
e673ee24 1122{
bb09cca0 1123 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
e673ee24
DO
1124}
1125
40c9fc94
AA
1126function renderObjectPortRow ($port, $is_highlighted)
1127{
1128 echo '<tr';
1129 if ($is_highlighted)
5c717ce5 1130 echo ' class=highlight';
40c9fc94
AA
1131 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
1132 echo "><td class='tdleft' NOWRAP><a name='port-${port['id']}' class='ancor interactive-portname nolink $a_class'>${port['name']}</a></td>";
1133 echo "<td class=tdleft>${port['label']}</td>";
1134 echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class=tdleft><tt>${port['l2address']}</tt></td>";
1135 if ($port['remote_object_id'])
1136 {
1137 echo "<td class=tdleft>" .
dec748f6 1138 formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL) .
40c9fc94
AA
1139 "</td>";
1140 echo "<td class=tdleft>" . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . "</td>";
0b8d8309
AA
1141 $editable = permitted ('object', 'ports', 'editPort')
1142 ? 'editable'
1143 : '';
1144 echo "<td class=tdleft><span class='rsvtext $editable id-${port['id']} op-upd-reservation-cable'>${port['cableid']}</span></td>";
40c9fc94
AA
1145 }
1146 else
1147 echo implode ('', formatPortReservation ($port)) . '<td></td>';
1148 echo "</tr>";
1149}
1150
9b8174d7 1151function renderObject ($object_id)
e673ee24 1152{
8dc2a6c8 1153 global $nextorder, $virtual_obj_types;
fb6e2f57 1154 $info = spotEntity ('object', $object_id);
94fe6370 1155 amplifyCell ($info);
e673ee24
DO
1156 // Main layout starts.
1157 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1158 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
1159 // left column with uknown number of portlets
1160 echo "<tr><td class=pcleft>";
646272be
AA
1161
1162 // display summary portlet
1163 $summary = array();
59a83bd8 1164 if (strlen ($info['name']))
646272be 1165 $summary['Common name'] = $info['name'];
94fe6370 1166 elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
646272be
AA
1167 $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>');
1168 $summary['Object type'] = '<a href="' . makeHref (array (
341fd895
DO
1169 'page' => 'depot',
1170 'tab' => 'default',
1171 'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
646272be 1172 )) . '">' . decodeObjectType ($info['objtype_id'], 'o') . '</a>';
9b8174d7 1173 if (strlen ($info['label']))
646272be 1174 $summary['Visible label'] = $info['label'];
59a83bd8 1175 if (strlen ($info['asset_no']))
646272be 1176 $summary['Asset tag'] = $info['asset_no'];
d4e8ddeb 1177 elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
646272be
AA
1178 $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>');
1179 $parents = getEntityRelatives ('parents', 'object', $object_id);
1180 if (count ($parents))
0682218d 1181 {
646272be 1182 $fmt_parents = array();
0682218d 1183 foreach ($parents as $parent)
8023ee39
AA
1184 $fmt_parents[] = "<a href='".makeHref(array('page'=>$parent['page'], $parent['id_name'] => $parent['entity_id']))."'>${parent['name']}</a>";
1185 $summary[count($parents) > 1 ? 'Containers' : 'Container'] = implode ('<br>', $fmt_parents);
0682218d 1186 }
646272be
AA
1187 $children = getEntityRelatives ('children', 'object', $object_id);
1188 if (count ($children))
0682218d 1189 {
646272be 1190 $fmt_children = array();
0682218d 1191 foreach ($children as $child)
8023ee39 1192 $fmt_children[] = "<a href='".makeHref(array('page'=>$child['page'], $child['id_name']=>$child['entity_id']))."'>${child['name']}</a>";
dcde9835 1193 $summary['Contains'] = implode ('<br>', $fmt_children);
0682218d 1194 }
e673ee24 1195 if ($info['has_problems'] == 'yes')
646272be 1196 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
8ad59489 1197 foreach (getAttrValues ($object_id) as $record)
4969aa31
DO
1198 if
1199 (
dec748f6 1200 strlen ($record['value']) and
4969aa31
DO
1201 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1202 )
646272be 1203 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
a2c597ea
AA
1204 $summary[] = array (getOutputOf ('printTagTRs',
1205 $info,
1206 makeHref
1207 (
1208 array
1209 (
1210 'page'=>'depot',
1211 'tab'=>'default',
1212 'andor' => 'and',
1213 'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
1214 )
1215 )."&"
1216 ));
646272be 1217 renderEntitySummary ($info, 'summary', $summary);
e673ee24 1218
59a83bd8 1219 if (strlen ($info['comment']))
e673ee24
DO
1220 {
1221 startPortlet ('Comment');
6cc5d6cd 1222 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
e673ee24
DO
1223 finishPortlet ();
1224 }
1225
b5700329
AA
1226 $logrecords = getLogRecordsForObject ($_REQUEST['object_id']);
1227 if (count ($logrecords))
9a90adc4
DO
1228 {
1229 startPortlet ('log records');
1230 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>";
1231 $order = 'odd';
b5700329 1232 foreach ($logrecords as $row)
9a90adc4
DO
1233 {
1234 echo "<tr class=row_${order} valign=top>";
1235 echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>';
0b8d8309 1236 echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES)) . '</td>';
9a90adc4
DO
1237 echo '</tr>';
1238 $order = $nextorder[$order];
1239 }
1240 echo '</table>';
1241 finishPortlet();
1242 }
1243
65e557dd 1244 switchportInfoJS ($object_id); // load JS code to make portnames interactive
e1ae3fb4
AD
1245 renderFilesPortlet ('object', $object_id);
1246
9f75e165 1247 if (count ($info['ports']))
e673ee24 1248 {
0ab782bc 1249 startPortlet ('ports and links');
9f75e165
DO
1250 $hl_port_id = 0;
1251 if (isset ($_REQUEST['hl_port_id']))
e673ee24 1252 {
0cc24e9a 1253 assertUIntArg ('hl_port_id');
9f75e165 1254 $hl_port_id = $_REQUEST['hl_port_id'];
65e557dd 1255 addAutoScrollScript ("port-$hl_port_id");
9f75e165
DO
1256 }
1257 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>";
1258 echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>';
0d59a51c 1259 echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>';
0c7c9f8b
DO
1260 echo '<th class=tdcenter colspan=2>Remote object and port</th>';
1261 echo '<th class=tdleft>Cable ID</th></tr>';
9f75e165 1262 foreach ($info['ports'] as $port)
40c9fc94 1263 callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id']));
fd5edda8 1264 if (permitted (NULL, 'ports', 'set_reserve_comment'))
a8dc2982 1265 addJS ('js/inplace-edit.js');
9f75e165 1266 echo "</table><br>";
e673ee24
DO
1267 finishPortlet();
1268 }
85970da2 1269
21ee3351 1270 if (count ($info['ipv4']) + count ($info['ipv6']))
e673ee24 1271 {
21ee3351 1272 startPortlet ('IP addresses');
e673ee24 1273 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
f0ed1181 1274 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
0b9c98d7 1275 echo "<tr><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n";
83fdf85f
DO
1276 else
1277 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
21ee3351
AA
1278
1279 // group IP allocations by interface name instead of address family
1280 $allocs_by_iface = array();
1281 foreach (array ('ipv4', 'ipv6') as $ip_v)
4318ced5
AA
1282 foreach ($info[$ip_v] as $ip_bin => $alloc)
1283 $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc;
dec748f6 1284
21ee3351
AA
1285 // sort allocs array by portnames
1286 foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist)
1287 {
1288 $is_first_row = TRUE;
f3505b35 1289 foreach ($alloclist as $alloc)
b90c3907 1290 {
40c9fc94 1291 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
f3505b35 1292 echo "<tr class='${rendered_alloc['tr_class']}' valign=top>";
21ee3351 1293
f3505b35 1294 // display iface name, same values are grouped into single cell
21ee3351
AA
1295 if ($is_first_row)
1296 {
1297 $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : '';
40c9fc94 1298 echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>";
21ee3351
AA
1299 $is_first_row = FALSE;
1300 }
f3505b35 1301 echo $rendered_alloc['td_ip'];
21ee3351 1302 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
83fdf85f 1303 {
f3505b35
AA
1304 echo $rendered_alloc['td_network'];
1305 echo $rendered_alloc['td_routed_by'];
21ee3351 1306 }
f3505b35
AA
1307 echo $rendered_alloc['td_peers'];
1308
1309 echo "</tr>\n";
b90c3907 1310 }
e673ee24
DO
1311 }
1312 echo "</table><br>\n";
1313 finishPortlet();
1314 }
1315
94fe6370 1316 $forwards = $info['nat4'];
e673ee24
DO
1317 if (count($forwards['in']) or count($forwards['out']))
1318 {
f28fbe8b 1319 startPortlet('NATv4');
e673ee24
DO
1320
1321 if (count($forwards['out']))
1322 {
1323
f28fbe8b 1324 echo "<h3>locally performed NAT</h3>";
e673ee24 1325
105a3bc8 1326 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1327 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
e673ee24
DO
1328
1329 foreach ($forwards['out'] as $pf)
1330 {
2c817354
DO
1331 $class = 'trerror';
1332 $osif = '';
1333 if (isset ($alloclist [$pf['localip']]))
1334 {
1335 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
1336 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
1337 }
e673ee24 1338 echo "<tr class='$class'>";
7419401e
AA
1339 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1340 echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
4318ced5 1341 $address = getIPAddress (ip4_parse ($pf['remoteip']));
e673ee24 1342 echo "<td class='description'>";
53ef3908
DO
1343 if (count ($address['allocs']))
1344 foreach($address['allocs'] as $bond)
ad3e5e7e 1345 echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' ';
59a83bd8 1346 elseif (strlen ($pf['remote_addr_name']))
f28fbe8b 1347 echo '(' . $pf['remote_addr_name'] . ')';
53ef3908 1348 echo "</td><td class='description'>${pf['description']}</td></tr>";
e673ee24
DO
1349 }
1350 echo "</table><br><br>";
1351 }
1352 if (count($forwards['in']))
1353 {
f28fbe8b 1354 echo "<h3>arriving NAT connections</h3>";
105a3bc8 1355 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1356 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
e673ee24
DO
1357 foreach ($forwards['in'] as $pf)
1358 {
1359 echo "<tr>";
7419401e 1360 echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
ad3e5e7e 1361 echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']);
7419401e 1362 echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
e673ee24
DO
1363 echo "<td class='description'>${pf['description']}</td></tr>";
1364 }
e673ee24
DO
1365 echo "</table><br><br>";
1366 }
1367 finishPortlet();
1368 }
1369
eacc0983 1370 renderSLBTriplets2 ($info);
defd92d8 1371 renderSLBTriplets ($info);
e673ee24
DO
1372 echo "</td>\n";
1373
7056988c 1374 // After left column we have (surprise!) right column with rackspace portlet only.
e673ee24 1375 echo "<td class=pcright>";
8dc2a6c8 1376 if (!in_array($info['objtype_id'], $virtual_obj_types))
0682218d
AD
1377 {
1378 // rackspace portlet
1379 startPortlet ('rackspace allocation');
1380 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1381 renderRack ($rack_id, $object_id);
1382 echo '<br>';
1383 finishPortlet();
1384 }
e673ee24
DO
1385 echo "</td></tr>";
1386 echo "</table>\n";
1387}
1388
1389function renderRackMultiSelect ($sname, $racks, $selected)
1390{
04571888
DO
1391 // Transform the given flat list into a list of groups, each representing a rack row.
1392 $rdata = array();
e673ee24 1393 foreach ($racks as $rack)
d016010a
AD
1394 {
1395 $row_name = ($rack['location_id']) ? $rack['location_name'] . '/' . $rack['row_name'] : $rack['row_name'];
1396 $rdata[$row_name][$rack['id']] = $rack['name'];
1397 }
4fbb5a00 1398 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
04571888 1399 foreach ($rdata as $optgroup => $racklist)
e673ee24 1400 {
04571888
DO
1401 echo "<optgroup label='${optgroup}'>";
1402 foreach ($racklist as $rack_id => $rack_name)
1403 {
1404 echo "<option value=${rack_id}";
1405 if (!(array_search ($rack_id, $selected) === FALSE))
1406 echo ' selected';
1407 echo">${rack_name}</option>\n";
1408 }
e673ee24
DO
1409 }
1410 echo "</select>\n";
1411}
1412
e673ee24 1413// This function renders a form for port edition.
7e1db771 1414function renderPortsForObject ($object_id)
e673ee24 1415{
3153a326
DO
1416 $prefs = getPortListPrefs();
1417 function printNewItemTR ($prefs)
39b4abd0
DO
1418 {
1419 printOpFormIntro ('addPort');
1420 echo "<tr><td>";
f5ff50f5 1421 printImageHREF ('add', 'add a port', TRUE);
65e557dd 1422 echo "</td><td class='tdleft'><input type=text size=8 name=port_name tabindex=100></td>\n";
cd3775e9
DO
1423 echo "<td><input type=text name=port_label tabindex=101></td><td>";
1424 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 102), $prefs['selected']);
1425 echo "<td><input type=text name=port_l2address tabindex=103 size=18 maxlength=24></td>\n";
318c48a8 1426 echo "<td colspan=4>&nbsp;</td><td>";
9318d2ef
DO
1427 printImageHREF ('add', 'add a port', TRUE, 104);
1428 echo "</td></tr></form>";
39b4abd0 1429 }
a1fc539a 1430 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' || getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' )
f44fdef9
DO
1431 startPortlet ('Ports and interfaces');
1432 else
1433 echo '<br>';
9f75e165
DO
1434 $object = spotEntity ('object', $object_id);
1435 amplifyCell ($object);
a1fc539a
RF
1436 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1437 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1438 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1439 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1440 printOpFormIntro ('addBulkPorts');
1441 echo "<tr><td>";
1442 printImageHREF ('add', 'add ports', TRUE);
1443 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1444 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1445 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1446 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1447 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1448 echo "<td>&nbsp;</td><td>";
1449 printImageHREF ('add', 'add ports', TRUE, 110);
1450 echo "</td></tr></form>";
1451 echo "</table><br>\n";
1452 }
dec748f6 1453
e673ee24 1454 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
0d59a51c 1455 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>L2 address</th>";
318c48a8 1456 echo "<th class=tdcenter colspan=2>Remote object and port</th><th>Cable ID</th><th class=tdcenter>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
39b4abd0 1457 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
3153a326 1458 printNewItemTR ($prefs);
45ff9012
AA
1459
1460 // clear ports link
10f5133a 1461 echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation');
45ff9012 1462
00276508
AA
1463 if (isset ($_REQUEST['hl_port_id']))
1464 {
1465 assertUIntArg ('hl_port_id');
1466 $hl_port_id = intval ($_REQUEST['hl_port_id']);
65e557dd 1467 addAutoScrollScript ("port-$hl_port_id");
00276508 1468 }
65e557dd 1469 switchportInfoJS ($object_id); // load JS code to make portnames interactive
9f75e165 1470 foreach ($object['ports'] as $port)
e673ee24 1471 {
5c717ce5 1472 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : '';
7056988c 1473 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
d0d40671 1474 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>";
e673ee24
DO
1475 printImageHREF ('delete', 'Unlink and Delete this port');
1476 echo "</a></td>\n";
65e557dd
AA
1477 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
1478 echo "<td class='tdleft' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=8></td>";
cd3775e9 1479 echo "<td><input type=text name=label value='${port['label']}'></td>";
611170af
AD
1480 if (!$port['remote_object_id'])
1481 {
3153a326
DO
1482 echo '<td>';
1483 if ($port['iif_id'] != 1)
1484 echo '<label>' . $port['iif_name'] . ' ';
cd3775e9 1485 printSelect (getExistingPortTypeOptions ($port['id']), array ('name' => 'port_type_id'), $port['oif_id']);
3153a326
DO
1486 if ($port['iif_id'] != 1)
1487 echo '</label>';
1488 echo '</td>';
611170af
AD
1489 }
1490 else
1491 {
045bab87 1492 echo "<input type=hidden name=port_type_id value='${port['oif_id']}'><td class=tdleft>";
e9d357e1 1493 echo formatPortIIFOIF ($port) . '</td>';
611170af 1494 }
cd3775e9
DO
1495 // 18 is enough to fit 6-byte MAC address in its longest form,
1496 // while 24 should be Ok for WWN
1497 echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n";
e673ee24
DO
1498 if ($port['remote_object_id'])
1499 {
318c48a8 1500 echo "<td>" .
a2ea559e 1501 formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL)) .
5c6225b1
AA
1502 "</td>";
1503 echo "<td> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') .
1504 "<input type=hidden name=reservation_comment value=''></td>";
318c48a8 1505 echo "<td><input type=text name=cable value='${port['cableid']}'></td>";
10f5133a
AA
1506 echo "<td class=tdcenter>";
1507 echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port');
1508 echo "</td>";
e673ee24 1509 }
59a83bd8 1510 elseif (strlen ($port['reservation_comment']))
e673ee24 1511 {
5c6225b1 1512 echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>";
e673ee24 1513 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
318c48a8 1514 echo "<td></td>";
10f5133a
AA
1515 echo "<td class=tdcenter>";
1516 echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port');
1517 echo "</td>";
e673ee24
DO
1518 }
1519 else
1520 {
6b1ca530 1521 $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX');
318c48a8 1522 echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter><span";
cd3775e9
DO
1523 $helper_args = array
1524 (
1525 'port' => $port['id'],
6b1ca530 1526 'in_rack' => ($in_rack == "yes" ? "on" : "")
cd3775e9
DO
1527 );
1528 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
9e214652 1529 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
cd3775e9
DO
1530 echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1531 echo "\",\"findlink\",\"${popup_args}\");'";
1532 // end of onclick=
cd3775e9
DO
1533 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1534 echo "\",\"findlink\",\"${popup_args}\");'";
1535 // end of onclick=
1536 echo '>';
1537 // end of <a>
5ccd99a0 1538 printImageHREF ('plug', 'Link this port');
cd3775e9
DO
1539 echo "</span>";
1540 echo " <input type=text name=reservation_comment></td>\n";
e673ee24 1541 }
5bbbeaa2
DO
1542 echo "<td>";
1543 printImageHREF ('save', 'Save changes', TRUE);
1544 echo "</td></form></tr>\n";
e673ee24 1545 }
39b4abd0 1546 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
3153a326 1547 printNewItemTR ($prefs);
e673ee24 1548 echo "</table><br>\n";
a1fc539a
RF
1549 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1550 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1551 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1552 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
dec748f6 1553 printOpFormIntro ('addBulkPorts');
a1fc539a
RF
1554 echo "<tr><td>";
1555 printImageHREF ('add', 'add ports', TRUE);
1556 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1557 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1558 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1559 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1560 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1561 echo "<td>&nbsp;</td><td>";
1562 printImageHREF ('add', 'add ports', TRUE, 110);
1563 echo "</td></tr></form>";
1564 echo "</table><br>\n";
1565 }
f44fdef9
DO
1566 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes')
1567 finishPortlet();
1568 if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes')
1569 return;
e673ee24
DO
1570
1571 startPortlet ('Add/update multiple ports');
7056988c 1572 printOpFormIntro ('addMultiPorts');
f7a3c94a 1573 echo 'Format: <select name=format tabindex=201>';
e673ee24
DO
1574 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1575 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
e673ee24 1576 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
351d4dbf 1577 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
e673ee24
DO
1578 echo "</select>";
1579 echo 'Default port type: ';
cd3775e9 1580 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type', 'tabindex' => 202), $prefs['selected']);
f7a3c94a
DO
1581 echo "<input type=submit value='Parse output' tabindex=204><br>\n";
1582 echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
e673ee24
DO
1583 echo '</form>';
1584 finishPortlet();
1585}
1586
4318ced5 1587function renderIPForObject ($object_id)
e673ee24 1588{
4318ced5 1589 function printNewItemTR ($default_type)
21ee3351
AA
1590 {
1591 global $aat;
4318ced5
AA
1592 printOpFormIntro ('add');
1593 echo "<tr><td>"; // left btn
dec748f6 1594 printImageHREF ('add', 'allocate', TRUE);
21ee3351 1595 echo "</td>";
4318ced5
AA
1596 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n"; // if-name
1597 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n"; // IP
1598 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1599 echo "<td colspan=2>&nbsp;</td>"; // network, routed by
1600 echo '<td>';
1601 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), $default_type); // type
1602 echo "</td><td>&nbsp;</td><td>"; // misc
1603 printImageHREF ('add', 'allocate', TRUE, 103); // right btn
21ee3351
AA
1604 echo "</td></tr></form>";
1605 }
21ee3351
AA
1606 global $aat;
1607 startPortlet ('Allocations');
4318ced5
AA
1608 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1609 echo '<th>&nbsp;</th>';
1610 echo '<th>OS interface</th>';
1611 echo '<th>IP address</th>';
21ee3351 1612 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
4318ced5
AA
1613 {
1614 echo '<th>network</th>';
1615 echo '<th>routed by</th>';
1616 }
1617 echo '<th>type</th>';
1618 echo '<th>misc</th>';
1619 echo '<th>&nbsp</th>';
1620 echo '</tr>';
21ee3351 1621
710ead7e
AA
1622 $alloc_list = ''; // most of the output is stored here
1623 $used_alloc_types = array();
4318ced5 1624 foreach (getObjectIPAllocations ($object_id) as $alloc)
21ee3351 1625 {
710ead7e
AA
1626 if (! isset ($used_alloc_types[$alloc['type']]))
1627 $used_alloc_types[$alloc['type']] = 0;
1628 $used_alloc_types[$alloc['type']]++;
1629
40c9fc94 1630 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
4318ced5 1631 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
710ead7e 1632 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
f3505b35 1633
10f5133a 1634 $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>";
40c9fc94 1635 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
710ead7e 1636 $alloc_list .= $rendered_alloc['td_ip'];
21ee3351
AA
1637 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1638 {
710ead7e
AA
1639 $alloc_list .= $rendered_alloc['td_network'];
1640 $alloc_list .= $rendered_alloc['td_routed_by'];
21ee3351 1641 }
710ead7e
AA
1642 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1643 $alloc_list .= $rendered_alloc['td_peers'];
1644 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
f3505b35 1645
710ead7e 1646 $alloc_list .= "</form></tr>\n";
21ee3351 1647 }
710ead7e 1648 asort ($used_alloc_types, SORT_NUMERIC);
a0a5ce54 1649 $most_popular_type = empty ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types));
710ead7e
AA
1650
1651 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1652 echo $alloc_list;
4318ced5 1653 printNewItemTR ($most_popular_type);
710ead7e
AA
1654 if (! $list_on_top)
1655 echo $alloc_list;
21ee3351
AA
1656
1657 echo "</table><br>\n";
1658 finishPortlet();
f3505b35
AA
1659}
1660
08408472
AA
1661// This function is deprecated. Do not rely on its internals,
1662// it will probably be removed in the next major relese.
1663// Use new showError, showWarning, showSuccess functions.
dec748f6 1664// Log array is stored in global $log_messages. Its format is simple: plain ordered array
8ab645cf 1665// with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1cb6adf5 1666function showMessageOrError ()
e673ee24 1667{
a2b16202
AA
1668 global $log_messages;
1669
1670 @session_start();
1671 if (isset ($_SESSION['log']))
1672 {
1673 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1674 unset ($_SESSION['log']);
1675 }
1676 session_commit();
1677
1678 if (empty ($log_messages))
1cb6adf5 1679 return;
8ab645cf
AA
1680 $msginfo = array
1681 (
dec748f6 1682// records 0~99 with success messages
8ab645cf
AA
1683 0 => array ('code' => 'success', 'format' => '%s'),
1684 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1685 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1686 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1687 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
1688 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1689 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1690 26 => array ('code' => 'success', 'format' => 'updated %u records successfully'),
1691 37 => array ('code' => 'success', 'format' => 'added %u records successfully'),
1692 38 => array ('code' => 'success', 'format' => 'removed %u records successfully'),
8ab645cf
AA
1693 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1694 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1695 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1696 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1697 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1698 57 => array ('code' => 'success', 'format' => 'Reset complete'),
8ab645cf 1699 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
8ab645cf
AA
1700 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1701 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1702 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
8ab645cf
AA
1703 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"),
1704 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'),
8628ae44 1705// records 100~199 with fatal error messages
8ab645cf
AA
1706 100 => array ('code' => 'error', 'format' => '%s'),
1707 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
8ab645cf
AA
1708 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1709 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'),
1710 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1711 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1712 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1713 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1714 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1715 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1716 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1717 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1718 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
8ab645cf
AA
1719 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1720 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1721 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
1722 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"),
1723 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"),
1724 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
f0ff4930 1725
8628ae44 1726// records 200~299 with warnings
8ab645cf
AA
1727 200 => array ('code' => 'warning', 'format' => '%s'),
1728 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
e1add254 1729 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
7587edca 1730 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
57777e4a 1731
24d3182a 1732// records 300~399 with notices
8ab645cf 1733 300 => array ('code' => 'neutral', 'format' => '%s'),
24d3182a 1734
8ab645cf
AA
1735 );
1736 // Handle the arguments. Is there any better way to do it?
a2b16202 1737 foreach ($log_messages as $record)
8ab645cf
AA
1738 {
1739 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1740 {
41152018
AA
1741 $prefix = isset ($record['c']) ? $record['c'] . ': ' : '';
1742 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
8ab645cf
AA
1743 continue;
1744 }
1745 if (isset ($record['a']))
1746 switch (count ($record['a']))
baf37d01 1747 {
8ab645cf
AA
1748 case 1:
1749 $msgtext = sprintf
1750 (
1751 $msginfo[$record['c']]['format'],
1752 $record['a'][0]
1753 );
1754 break;
1755 case 2:
1756 $msgtext = sprintf
1757 (
1758 $msginfo[$record['c']]['format'],
1759 $record['a'][0],
1760 $record['a'][1]
1761 );
1762 break;
1763 case 3:
1764 $msgtext = sprintf
1765 (
1766 $msginfo[$record['c']]['format'],
1767 $record['a'][0],
1768 $record['a'][1],
1769 $record['a'][2]
1770 );
1771 break;
1772 case 4:
1773 default:
1774 $msgtext = sprintf
1775 (
1776 $msginfo[$record['c']]['format'],
1777 $record['a'][0],
1778 $record['a'][1],
1779 $record['a'][2],
1780 $record['a'][3]
1781 );
1782 break;
baf37d01 1783 }
8ab645cf
AA
1784 else
1785 $msgtext = $msginfo[$record['c']]['format'];
1786 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
baf37d01 1787 }
a2b16202 1788 $log_messages = array();
e673ee24
DO
1789}
1790
65e557dd
AA
1791// renders two tables: port link status and learned MAC list
1792function renderPortsInfo($object_id)
1793{
03522bd8
AA
1794 try
1795 {
1796 if (permitted (NULL, NULL, 'get_link_status'))
1797 $linkStatus = queryDevice ($object_id, 'getportstatus');
1798 else
1799 showWarning ("You don't have permission to view ports link status");
1800
1801 if (permitted (NULL, NULL, 'get_mac_list'))
1802 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
1803 else
1804 showWarning ("You don't have permission to view learned MAC list");
1805 }
1806 catch (RTGatewayError $e)
1807 {
1808 showError ($e->getMessage());
1809 return;
1810 }
1811
65e557dd
AA
1812 global $nextorder;
1813 echo "<table width='100%'><tr>";
03522bd8 1814 if (! empty ($linkStatus))
65e557dd 1815 {
03522bd8
AA
1816 echo "<td valign='top' width='50%'>";
1817 startPortlet('Link status');
1818 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>";
1819 $order = 'even';
1820 foreach ($linkStatus as $pn => $link)
65e557dd 1821 {
03522bd8 1822 switch ($link['status'])
65e557dd 1823 {
03522bd8
AA
1824 case 'up':
1825 $img_filename = 'link-up.png';
1826 break;
1827 case 'down':
1828 $img_filename = 'link-down.png';
1829 break;
1830 case 'disabled':
1831 $img_filename = 'link-disabled.png';
1832 break;
1833 default:
1834 $img_filename = '1x1t.gif';
1835 }
9f78501e 1836
03522bd8
AA
1837 echo "<tr class='row_$order'>";
1838 $order = $nextorder[$order];
1839 echo '<td>' . $pn;
1840 echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">';
1841 echo '<td>' . $link['status'];
1842 $info = '';
1843 if (isset ($link['speed']))
1844 $info .= $link['speed'];
1845 if (isset ($link['duplex']))
1846 {
1847 if (! empty ($info))
1848 $info .= ', ';
1849 $info .= $link['duplex'];
65e557dd 1850 }
03522bd8
AA
1851 echo '<td>' . $info;
1852 echo '</tr>';
65e557dd 1853 }
03522bd8
AA
1854 echo "</table></td>";
1855 finishPortlet();
65e557dd
AA
1856 }
1857
65e557dd
AA
1858 if (! empty ($macList))
1859 {
1860 echo "<td valign='top' width='50%'>";
1861 $rendered_macs = '';
1862 $mac_count = 0;
1863 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>";
1864 $order = 'even';
1865 foreach ($macList as $pn => $list)
1866 {
1867 $order = $nextorder[$order];
1868 foreach ($list as $item)
1869 {
1870 ++$mac_count;
1871 $rendered_macs .= "<tr class='row_$order'>";
1872 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'];
1873 $rendered_macs .= '<td>' . $item['vid'];
1874 $rendered_macs .= '<td>' . $pn;
1875 $rendered_macs .= '</tr>';
1876 }
1877 }
1878 $rendered_macs .= "</table></td>";
dec748f6 1879
65e557dd
AA
1880 startPortlet("Learned MACs ($mac_count)");
1881 echo $rendered_macs;
1882 finishPortlet();
1883 }
1884
1885 echo "</td></tr></table>";
1886}
1887
e673ee24 1888/*
51c18782 1889The following conditions must be met:
e673ee24
DO
18901. We can mount onto free atoms only. This means: if any record for an atom
1891already exists in RackSpace, it can't be used for mounting.
18922. We can't unmount from 'W' atoms. Operator should review appropriate comments
1893and either delete them before unmounting or refuse to unmount the object.
1894*/
7e1db771 1895function renderRackSpaceForObject ($object_id)
e673ee24 1896{
e673ee24
DO
1897 // Always process occupied racks plus racks chosen by user. First get racks with
1898 // already allocated rackspace...
51c18782 1899 $workingRacksData = getResidentRacksData ($object_id);
e673ee24 1900 // ...and then add those chosen by user (if any).
2135fd83 1901 if (isset($_REQUEST['rackmulti']))
e673ee24 1902 foreach ($_REQUEST['rackmulti'] as $cand_id)
e673ee24
DO
1903 if (!isset ($workingRacksData[$cand_id]))
1904 {
0cc24e9a 1905 $rackData = spotEntity ('rack', $cand_id);
61a1d996 1906 amplifyCell ($rackData);
e673ee24
DO
1907 $workingRacksData[$cand_id] = $rackData;
1908 }
51690ad4 1909
0a7feebb
AD
1910 // Get a list of all of this object's parents,
1911 // then trim the list to only include parents which are racks
1912 $objectParents = getEntityRelatives('parents', 'object', $object_id);
1913 $parentRacks = array();
1914 foreach ($objectParents as $parentData)
1915 if ($parentData['entity_type'] == 'rack')
1916 $parentRacks[] = $parentData['entity_id'];
1917
e673ee24
DO
1918 // Main layout starts.
1919 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
1920
1921 // Left portlet with rack list.
1922 echo "<td class=pcleft height='1%'>";
1923 startPortlet ('Racks');
a8efc03e 1924 $allRacksData = listCells ('rack');
6d42599c
AA
1925
1926 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
1927 if (! isset ($_REQUEST['show_all_racks']) and getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
1928 {
1929 $matching_racks = array();
1930 $object = spotEntity ('object', $object_id);
1931 $matched_tags = array();
1932 foreach ($allRacksData as $rack)
1933 foreach ($object['etags'] as $tag)
1934 if (tagOnChain ($tag, $rack['etags']) or tagOnChain ($tag, $rack['itags']))
1935 {
1936 $matching_racks[$rack['id']] = $rack;
1937 $matched_tags[$tag['id']] = $tag;
1938 break;
1939 }
1940 // add current object's racks even if they dont match filter
1941 foreach ($workingRacksData as $rack_id => $rack)
1942 if (! isset ($matching_racks[$rack_id]))
1943 $matching_racks[$rack_id] = $rack;
1944 // if matching racks found, and rack list is reduced, show 'show all' link
1945 if (count ($matching_racks) and count ($matching_racks) != count ($allRacksData))
1946 {
1947 $filter_text = '';
1948 foreach ($matched_tags as $tag)
1949 $filter_text .= (empty ($filter_text) ? '' : ' or ') . '{' . $tag['tag'] . '}';
1950 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
1951 $href_show_all .= htmlspecialchars('&show_all_racks=1');
1952 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
1953 $allRacksData = $matching_racks;
1954 }
1955 }
1956
4b8d413e 1957 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
61a1d996 1958 foreach ($allRacksData as $rack)
51c18782
DO
1959 if (!array_key_exists ($rack['id'], $workingRacksData))
1960 {
1961 amplifyCell ($rack);
1962 $workingRacksData[$rack['id']] = $rack;
1963 }
1964 foreach (array_keys ($workingRacksData) as $rackId)
1965 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
1966 printOpFormIntro ('updateObjectAllocation');
4b8d413e 1967 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
51c18782 1968 echo "<br><br>";
e673ee24
DO
1969 finishPortlet();
1970 echo "</td>";
1971
1972 // Middle portlet with comment and submit.
1973 echo "<td class=pcleft>";
5c8bf2ba 1974 startPortlet ('Comment (for Rackspace History)');
e673ee24
DO
1975 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
1976 echo "<input type=submit value='Save' name=got_atoms>\n";
51c18782 1977 echo "<br><br>";
e673ee24
DO
1978 finishPortlet();
1979 echo "</td>";
1980
1981 // Right portlet with rendered racks. If this form submit is not final, we have to
1982 // reflect the former state of the grid in current form.
1983 echo "<td class=pcright rowspan=2 height='1%'>";
1984 startPortlet ('Working copy');
65e557dd 1985 addJS ('js/racktables.js');
e673ee24
DO
1986 echo '<table border=0 cellspacing=10 align=center><tr>';
1987 foreach ($workingRacksData as $rack_id => $rackData)
1988 {
1989 // Order is important here: only original allocation is highlighted.
1990 highlightObject ($rackData, $object_id);
1991 markupAtomGrid ($rackData, 'T');
1992 // If we have a form processed, discard user input and show new database
1993 // contents.
51c18782 1994 if (isset ($_REQUEST['rackmulti'][0])) // is an update
e673ee24
DO
1995 mergeGridFormToRack ($rackData);
1996 echo "<td valign=top>";
1997 echo "<center>\n<h2>${rackData['name']}</h2>\n";
1998 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 1999 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2000 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2001 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2002 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
e673ee24 2003 renderAtomGrid ($rackData);
57c69e9c 2004 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2005 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2006 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2007 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
0a7feebb
AD
2008 echo "</table>\n<br>\n";
2009 // Determine zero-u checkbox status.
2010 // If form has been submitted, use form data, otherwise use DB data.
dec748f6 2011 if (isset($_REQUEST['op']))
0a7feebb
AD
2012 $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : '';
2013 else
2014 $checked = in_array($rack_id, $parentRacks) ? 'checked' : '';
d141833a 2015 echo "<label for=zerou_${rack_id}>Zero-U:</label> <input type=checkbox ${checked} name=zerou_${rack_id} id=zerou_${rack_id}>\n<br><br>\n";
bd0bfb76 2016 echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n";
0a7feebb 2017 echo '</center></td>';
e673ee24
DO
2018 }
2019 echo "</tr></table>";
2020 finishPortlet();
2021 echo "</td>\n";
2022
2023 echo "</form>\n";
2024 echo "</tr></table>\n";
2025}
2026
2027function renderMolecule ($mdata, $object_id)
2028{
2029 // sort data out
2030 $rackpack = array();
2031 global $loclist;
64b95774 2032 foreach ($mdata as $rua)
e673ee24
DO
2033 {
2034 $rack_id = $rua['rack_id'];
2035 $unit_no = $rua['unit_no'];
2036 $atom = $rua['atom'];
2037 if (!isset ($rackpack[$rack_id]))
2038 {
61a1d996
DO
2039 $rackData = spotEntity ('rack', $rack_id);
2040 amplifyCell ($rackData);
e673ee24
DO
2041 for ($i = $rackData['height']; $i > 0; $i--)
2042 for ($locidx = 0; $locidx < 3; $locidx++)
2043 $rackData[$i][$locidx]['state'] = 'F';
2044 $rackpack[$rack_id] = $rackData;
2045 }
2046 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2047 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2048 }
2049 // now we have some racks to render
64b95774 2050 foreach ($rackpack as $rackData)
e673ee24
DO
2051 {
2052 markAllSpans ($rackData);
2053 echo "<table class=molecule cellspacing=0>\n";
2054 echo "<caption>${rackData['name']}</caption>\n";
2055 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
2056 for ($i = $rackData['height']; $i > 0; $i--)
2057 {
4dcd770e 2058 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
e673ee24
DO
2059 for ($locidx = 0; $locidx < 3; $locidx++)
2060 {
2061 $state = $rackData[$i][$locidx]['state'];
65e557dd 2062 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
e673ee24
DO
2063 }
2064 echo "</tr>\n";
2065 }
2066 echo "</table>\n";
2067 }
2068}
2069
23cdc7e9 2070function renderDepot ()
e673ee24 2071{
23cdc7e9 2072 global $pageno, $nextorder;
23cdc7e9
DO
2073 $cellfilter = getCellFilter();
2074 $objects = filterCellList (listCells ('object'), $cellfilter['expression']);
2075
2076 echo "<table border=0 class=objectview>\n";
2077 echo "<tr><td class=pcleft>";
2078
1ebbf889 2079 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
e673ee24 2080 {
4899096d 2081 if (count($objects) > 0)
1ebbf889 2082 {
4899096d
AD
2083 startPortlet ('Objects (' . count ($objects) . ')');
2084 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
b09a8280 2085 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
4899096d 2086 $order = 'odd';
3f8a25d6
DO
2087 # gather IDs of all objects and fetch rackspace info in one pass
2088 $idlist = array();
2089 foreach ($objects as $obj)
2090 $idlist[] = $obj['id'];
2091 $mountinfo = getMountInfo ($idlist);
4899096d
AD
2092 foreach ($objects as $obj)
2093 {
ad3e5e7e 2094 echo "<tr class='row_${order} tdleft' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
4899096d
AD
2095 if (count ($obj['etags']))
2096 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
4318ced5
AA
2097 echo "</td><td>${obj['label']}</td>";
2098 echo "<td>${obj['asset_no']}</td>";
3f8a25d6 2099 $places = array();
b09a8280 2100 if ($obj['container_id'])
86dad907 2101 $places[] = mkA ($obj['container_dname'], 'object', $obj['container_id']);
b09a8280 2102 elseif (! array_key_exists ($obj['id'], $mountinfo))
3f8a25d6 2103 $places[] = 'Unmounted';
4899096d 2104 else
3f8a25d6
DO
2105 foreach ($mountinfo[$obj['id']] as $mi)
2106 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
4318ced5 2107 echo "<td>" . implode (', ', $places) . '</td>';
4899096d
AD
2108 echo '</tr>';
2109 $order = $nextorder[$order];
2110 }
2111 echo '</table>';
2112 finishPortlet();
1ebbf889 2113 }
4899096d
AD
2114 else
2115 echo '<h2>No objects exist</h2>';
e673ee24 2116 }
23cdc7e9
DO
2117
2118 echo "</td><td class=pcright width='25%'>";
2119
95857b5c 2120 renderCellFilterPortlet ($cellfilter, 'object', $objects);
23cdc7e9 2121 echo "</td></tr></table>\n";
e673ee24
DO
2122}
2123
1ebbf889
AA
2124// This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2125// In this case it renders the describing message instead.
2126function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2127{
2128 if (!$cellfilter['is_empty'])
2129 return FALSE;
2130 if (isset ($_REQUEST['show_all_objects']))
2131 return FALSE;
2132 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2133 if (0 == $max || $count <= $max)
2134 return FALSE;
2135
2136 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2137 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2138 $suffix = isset ($count) ? " ($count)" : '';
2139 echo <<<END
2140<p>Please set a filter to display the corresponging $entities_name.
2141<br><a href="$href_show_all">Show all $entities_name$suffix</a>
2142END;
2143 return TRUE;
2144}
2145
e673ee24 2146// History viewer for history-enabled simple dictionaries.
9b8174d7 2147function renderObjectHistory ($object_id)
e673ee24 2148{
e673ee24
DO
2149 $order = 'odd';
2150 global $nextorder;
9b8174d7
AD
2151 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2152 echo '<tr><th>change time</th><th>author</th><th>name</th><th>visible label</th><th>asset no</th><th>has problems?</th><th>comment</th></tr>';
2153 $result = usePreparedSelectBlade
2154 (
2155 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2156 array ($object_id)
2157 );
e673ee24
DO
2158 while ($row = $result->fetch (PDO::FETCH_NUM))
2159 {
2160 echo "<tr class=row_${order}><td>${row[0]}</td>";
9b8174d7 2161 for ($i = 1; $i <= 6; $i++)
e673ee24
DO
2162 echo "<td>" . $row[$i] . "</td>";
2163 echo "</tr>\n";
2164 $order = $nextorder[$order];
2165 }
2166 echo "</table><br>\n";
2167}
2168
2169function renderRackspaceHistory ()
2170{
4fbb5a00 2171 global $nextorder, $pageno, $tabno;
e673ee24
DO
2172 $order = 'odd';
2173 $history = getRackspaceHistory();
2174 // Show the last operation by default.
2175 if (isset ($_REQUEST['op_id']))
2176 $op_id = $_REQUEST['op_id'];
2177 elseif (isset ($history[0]['mo_id']))
2178 $op_id = $history[0]['mo_id'];
2179 else $op_id = NULL;
dec748f6 2180
e673ee24
DO
2181 $omid = NULL;
2182 $nmid = NULL;
2183 $object_id = 1;
2184 if ($op_id)
2185 list ($omid, $nmid) = getOperationMolecules ($op_id);
2186
2187 // Main layout starts.
2188 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2189
2190 // Left top portlet with old allocation.
2191 echo "<tr><td class=pcleft>";
2192 startPortlet ('Old allocation');
2193 if ($omid)
2194 {
2195 $oldMolecule = getMolecule ($omid);
2196 renderMolecule ($oldMolecule, $object_id);
2197 }
2198 else
2199 echo "nothing";
2200 finishPortlet();
2201
2202 echo '</td><td class=pcright>';
2203
2204 // Right top portlet with new allocation
2205 startPortlet ('New allocation');
2206 if ($nmid)
2207 {
2208 $newMolecule = getMolecule ($nmid);
2209 renderMolecule ($newMolecule, $object_id);
2210 }
2211 else
2212 echo "nothing";
2213 finishPortlet();
737a3f72 2214
e673ee24 2215 echo '</td></tr><tr><td colspan=2>';
737a3f72 2216
e673ee24
DO
2217 // Bottom portlet with list
2218
2219 startPortlet ('Rackspace allocation history');
2220 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
7fa7047a 2221 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
e673ee24
DO
2222 foreach ($history as $row)
2223 {
2224 if ($row['mo_id'] == $op_id)
2225 $class = 'hl';
2226 else
2227 $class = "row_${order}";
4fbb5a00 2228 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
7fa7047a
DO
2229 echo "<td>${row['user_name']}</td><td>";
2230 renderCell (spotEntity ('object', $row['ro_id']));
9c6222ef 2231 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
e673ee24
DO
2232 $order = $nextorder[$order];
2233 }
2234 echo "</table>\n";
2235 finishPortlet();
737a3f72 2236
e673ee24 2237 echo '</td></tr></table>';
e673ee24
DO
2238}
2239
4318ced5 2240function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
d65353ad
DO
2241{
2242 $self = __FUNCTION__;
4318ced5 2243 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
00276508
AA
2244
2245 // scroll page to the highlighted item
2246 if ($target && isset ($_REQUEST['hl_net']))
65e557dd 2247 addAutoScrollScript ("net-$target");
00276508 2248
d65353ad
DO
2249 foreach ($tree as $item)
2250 {
4318ced5
AA
2251 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'))
2252 loadIPAddrList ($item); // necessary to compute router list and address counter
2253
0137d53c
DO
2254 if (isset ($item['id']))
2255 {
1f54e1ba 2256 $decor = array ('indent' => $level);
fec0c8da 2257 if ($item['symbol'] == 'node-collapsed')
4318ced5 2258 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
fec0c8da 2259 elseif ($item['symbol'] == 'node-expanded')
4318ced5
AA
2260 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
2261 $tr_class = '';
21ee3351 2262 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
64347dcf 2263 {
5c717ce5 2264 $decor['tdclass'] = ' highlight';
4318ced5 2265 $tr_class = $decor['tdclass'];
64347dcf 2266 }
4318ced5
AA
2267 echo "<tr valign=top class=\"$tr_class\">";
2268 printIPNetInfoTDs ($item, $decor);
2269
2270 // capacity and usage
2271 echo "<td class=tdcenter>";
2272 echo getRenderedIPNetCapacity ($item);
64347dcf 2273 echo "</td>";
4318ced5
AA
2274
2275 if ($display_routers)
efd8057e 2276 printRoutersTD (findRouters ($item['own_addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
0137d53c 2277 echo "</tr>";
fec0c8da 2278 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
4318ced5 2279 $self ($item['kids'], $baseurl, $target, $level + 1);
0137d53c
DO
2280 }
2281 else
2282 {
4318ced5 2283 // non-allocated (spare) IP range
0137d53c 2284 echo "<tr valign=top>";
21ee3351 2285 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
00276508 2286
4318ced5 2287 // capacity and usage
21ee3351 2288 echo "<td class=tdcenter>";
4318ced5 2289 echo getRenderedIPNetCapacity ($item);
21ee3351 2290 echo "</td>";
4318ced5
AA
2291 if ($display_routers)
2292 echo "<td></td>";
21ee3351 2293 echo "</tr>";
21ee3351 2294 }
21ee3351
AA
2295 }
2296}
2297
4318ced5 2298function renderIPSpace()
e673ee24 2299{
4fbb5a00 2300 global $pageno, $tabno;
4318ced5 2301 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
31c941ec 2302 $cellfilter = getCellFilter();
4318ced5
AA
2303 $top = NULL;
2304 $netlist = array();
2305 foreach (listCells ($realm) as $net)
2306 {
2307 if (isset ($top) and IPNetContains ($top, $net))
2308 ;
2309 elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression']))
2310 $top = $net;
1ebbf889 2311 else
4318ced5
AA
2312 continue;
2313 $netlist[$net['id']] = $net;
5388794d 2314 }
21ee3351
AA
2315 $netcount = count ($netlist);
2316 // expand request can take either natural values or "ALL". Zero means no expanding.
2317 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
4318ced5 2318 $tree = prepareIPTree ($netlist, $eid);
21ee3351
AA
2319
2320 echo "<table border=0 class=objectview>\n";
2321 echo "<tr><td class=pcleft>";
4318ced5 2322 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
21ee3351
AA
2323 {
2324 startPortlet ("networks (${netcount})");
2325 echo '<h4>';
4318ced5
AA
2326 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2327 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2328 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2329 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2330 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2331 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2332
21ee3351 2333 if ($eid === 0)
4318ced5 2334 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
21ee3351 2335 elseif ($eid === 'ALL')
4318ced5
AA
2336 echo "expanding all ($auto / $none)";
2337 elseif ($eid === 'NONE')
2338 echo "collapsing all ($all / $auto)";
21ee3351
AA
2339 else
2340 {
4318ced5
AA
2341 $netinfo = spotEntity ($realm, $eid);
2342 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
21ee3351
AA
2343 }
2344 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2345 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
4318ced5 2346 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
21ee3351
AA
2347 echo "<th>routed by</th>";
2348 echo "</tr>\n";
2349 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
4318ced5 2350 renderIPSpaceRecords ($tree, $baseurl, $eid);
21ee3351
AA
2351 echo "</table>\n";
2352 finishPortlet();
2353 }
2354
2355 echo '</td><td class=pcright>';
4318ced5 2356 renderCellFilterPortlet ($cellfilter, 'ipv4net', $netlist);
21ee3351
AA
2357 echo "</td></tr></table>\n";
2358}
2359
4318ced5 2360function renderIPSpaceEditor()
21ee3351 2361{
4318ced5
AA
2362 global $pageno;
2363 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2364 $net_page = $realm; // 'ipv4net', 'ipv6net'
2365 $addrspaceList = listCells ($realm);
93a49e5b
AA
2366 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2367 if (count ($addrspaceList))
21ee3351 2368 {
21ee3351
AA
2369 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2370 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
21ee3351
AA
2371 foreach ($addrspaceList as $netinfo)
2372 {
21ee3351 2373 echo "<tr valign=top><td>";
93a49e5b 2374 if (! isIPNetworkEmpty ($netinfo))
21ee3351
AA
2375 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2376 else
93a49e5b 2377 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
ad3e5e7e 2378 echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>';
1f54e1ba
DO
2379 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2380 if (count ($netinfo['etags']))
2381 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2382 echo '</td><td>';
4318ced5 2383 echo getRenderedIPNetCapacity ($netinfo);
b1e39212 2384 echo '</tr>';
e673ee24 2385 }
04d619d0
DO
2386 echo "</table>";
2387 finishPortlet();
e673ee24 2388 }
93a49e5b
AA
2389}
2390
2391function renderIPNewNetForm ()
2392{
2393 global $pageno;
2394 if ($pageno == 'ipv6space')
2395 {
2396 $realm = 'ipv6net';
3495ec6e 2397 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
93a49e5b
AA
2398 }
2399 else
2400 {
2401 $realm = 'ipv4net';
3495ec6e 2402 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
93a49e5b
AA
2403 }
2404
2405 // IP prefix validator
10f5133a 2406 addJS ('js/live_validation.js');
93a49e5b 2407 $regexp = addslashes ($regexp);
10f5133a 2408 addJS (<<<END
93a49e5b 2409$(document).ready(function () {
10f5133a 2410 $('form#add' input[name="range"]).attr('match', '$regexp');
93a49e5b
AA
2411 Validate.init();
2412});
2413END
2414 , TRUE);
dec748f6 2415
93a49e5b
AA
2416 startPortlet ('Add new');
2417 echo '<table border=0 cellpadding=10 align=center>';
10f5133a 2418 printOpFormIntro ('add');
93a49e5b
AA
2419 // tags column
2420 echo '<tr><td rowspan=5><h3>assign tags</h3>';
2421 renderNewEntityTags ($realm);
2422 echo '</td>';
2423 // inputs column
2424 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
2425 echo "<th class=tdright>prefix</th><td class=tdleft><input type=text name='range' size=36 class='live-validate' tabindex=1 value='${prefix_value}'></td>";
2426 echo '<tr><th class=tdright>VLAN</th><td class=tdleft>';
2427 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical', 'tabindex' => 2)) . '</td></tr>';
2428 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=3></td></tr>";
2429 echo '<tr><td class=tdright><input type=checkbox name="is_connected" tabindex=4></td><th class=tdleft>reserve subnet-router anycast address</th></tr>';
2430 echo "<tr><td colspan=2>";
2431 printImageHREF ('CREATE', 'Add a new network', TRUE, 5);
2432 echo '</td></tr>';
2433 echo "</form></table><br><br>\n";
2434 finishPortlet();
e673ee24
DO
2435}
2436
4318ced5 2437function getRenderedIPNetBacktrace ($range)
e673ee24 2438{
4318ced5
AA
2439 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2440 return array();
e673ee24 2441
4318ced5
AA
2442 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2443 $space = "ipv${v}space"; // ipv4space, ipv6space
2444 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
dec748f6 2445
4318ced5
AA
2446 $ret = array();
2447 // Build a backtrace from all parent networks.
2448 $clen = $range['mask'];
2449 $backtrace = array();
2450 $backtrace['&rarr;'] = $range;
2451 $key = '';
2452 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2453 {
2454 $upperinfo = spotEntity ($range['realm'], $upperid);
2455 $clen = $upperinfo['mask'];
2456 $key .= '&uarr;';
2457 $backtrace[$key] = $upperinfo;
2458 }
2459 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2460 {
2461 $link = '<a href="' . makeHref (array (
2462 'page' => $space,
2463 'tab' => 'default',
2464 'clear-cf' => '',
2465 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2466 'hl_net' => 1,
2467 'eid' => $range['id'],
2468 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2469 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2470 }
2471 return $ret;
2472}
2473
2474function renderIPNetwork ($id)
2475{
2476 global $pageno;
2477 $realm = $pageno; // 'ipv4net', 'ipv6net'
2478 $range = spotEntity ($realm, $id);
2479 loadIPAddrList ($range);
2034d968 2480 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
99ab184f
DO
2481 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2482 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2034d968
DO
2483
2484 echo "<tr><td class=pcleft width='50%'>";
646272be
AA
2485
2486 // render summary portlet
2487 $summary = array();
4318ced5 2488 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2b6b0038 2489 $summary = getRenderedIPNetBacktrace ($range) + $summary;
4318ced5 2490 if ($realm == 'ipv4net')
001e61fa 2491 {
4318ced5
AA
2492 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2493 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2494 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
001e61fa 2495 }
dec748f6 2496
11e3af31
DO
2497 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2498 $domainclass = array();
2499 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2500 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
a5f9d1ca 2501 foreach ($range['8021q'] as $item)
11e3af31 2502 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVLANInfo ($item['domain_id'] . '-' . $item['vlan_id'])));
3a4f4023 2503 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findRouters ($range['addrlist'])))
04d619d0 2504 {
646272be
AA
2505 $summary['Routed by'] = '';
2506 foreach ($routers as $rtr)
4318ced5 2507 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
04d619d0 2508 }
646272be
AA
2509 $summary['tags'] = '';
2510 renderEntitySummary ($range, 'summary', $summary);
e1ae3fb4 2511
99ab184f
DO
2512 if (strlen ($range['comment']))
2513 {
2514 startPortlet ('Comment');
2515 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2516 finishPortlet ();
2517 }
2518
4318ced5 2519 renderFilesPortlet ($realm, $id);
2034d968 2520 echo "</td>\n";
e673ee24 2521
2034d968
DO
2522 echo "<td class=pcright>";
2523 startPortlet ('details');
4318ced5
AA
2524 renderIPNetworkAddresses ($range);
2525 finishPortlet();
2526 echo "</td></tr></table>\n";
2527}
e673ee24 2528
4318ced5
AA
2529// Used solely by renderSeparator
2530function renderEmptyIPv6 ($ip_bin, $hl_ip)
2531{
2532 $class = 'tdleft';
2533 if ($ip_bin === $hl_ip)
5c717ce5 2534 $class .= ' highlight';
4318ced5
AA
2535 $fmt = ip6_format ($ip_bin);
2536 echo "<tr class='$class'><td><a class='ancor' name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
0b8d8309
AA
2537 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2538 ? 'editable'
2539 : '';
cc2fa820
AD
2540 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2541 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
4318ced5
AA
2542}
2543
2544// Renders empty table line to shrink empty IPv6 address ranges.
2545// If the range consists of single address, renders the address instead of empty line.
2546// Renders address $hl_ip inside the range.
2547// Used solely by renderIPv6NetworkAddresses
2548function renderSeparator ($first, $last, $hl_ip)
2549{
2550 $self = __FUNCTION__;
2551 if (strcmp ($first, $last) > 0)
2552 return;
2553 if ($first == $last)
2554 renderEmptyIPv6 ($first, $hl_ip);
2555 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2556 { // $hl_ip is inside the range $first - $last
2557 $self ($first, ip_prev ($hl_ip), $hl_ip);
2558 renderEmptyIPv6 ($hl_ip, $hl_ip);
2559 $self (ip_next ($hl_ip), $last, $hl_ip);
2560 }
2561 else
cc2fa820 2562 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
4318ced5
AA
2563}
2564
2565// calculates page number which contains given $ip (used by renderIPv6NetworkAddresses)
2566function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2567{
2568 if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage)
2569 return 0;
2570 $keys = array_keys ($list);
2571 for ($i = 1; $i <= count ($keys); $i++)
2572 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2573 return intval ($i / $maxperpage);
2574 return intval (count ($list) / $maxperpage);
2575}
2576
2577function renderIPNetworkAddresses ($range)
2578{
2579 switch (strlen ($range['ip_bin']))
2580 {
2581 case 4: return renderIPv4NetworkAddresses ($range);
2582 case 16: return renderIPv6NetworkAddresses ($range);
2583 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2584 }
2585}
2586
2587function renderIPv4NetworkAddresses ($range)
2588{
2589 global $pageno, $tabno, $aac2;
2590 $startip = ip4_bin2int ($range['ip_bin']);
2591 $endip = ip4_bin2int (ip_last ($range));
2592
2593 if (isset ($_REQUEST['hl_ip']))
00276508 2594 {
4318ced5
AA
2595 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2596 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
00276508
AA
2597 }
2598
79b57b18
AA
2599 // pager
2600 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2601 $address_count = $endip - $startip + 1;
2602 $page = 0;
446c25c3 2603 $rendered_pager = '';
79b57b18
AA
2604 if ($address_count > $maxperpage && $maxperpage > 0)
2605 {
2606 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2607 if ($numpages = ceil ($address_count / $maxperpage))
2608 {
4318ced5 2609 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
79b57b18
AA
2610 for ($i = 0; $i < $numpages; $i++)
2611 if ($i == $page)
446c25c3 2612 $rendered_pager .= "<b>$i</b> ";
79b57b18 2613 else
4318ced5 2614 $rendered_pager .= "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $range['id'], 'pg' => $i)) . "'>$i</a> ";
79b57b18
AA
2615 }
2616 $startip = $startip + $page * $maxperpage;
2617 $endip = min ($startip + $maxperpage - 1, $endip);
2618 }
2619
446c25c3 2620 echo $rendered_pager;
beb9e88a 2621 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2622 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
e673ee24 2623
4318ced5
AA
2624 markupIPAddrList ($range['addrlist']);
2625 for ($ip = $startip; $ip <= $endip; $ip++)
2626 {
2627 $ip_bin = ip4_int2bin ($ip);
2628 $dottedquad = ip4_format ($ip_bin);
5c717ce5 2629 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
0cd7c0f6
AA
2630 if (isset ($range['addrlist'][$ip_bin]))
2631 $addr = $range['addrlist'][$ip_bin];
2632 else
e673ee24 2633 {
4318ced5 2634 echo "<tr class='tdleft $tr_class'><td class=tdleft><a class='ancor' name='ip-$dottedquad' href='" . makeHref(array('page'=>'ipaddress', 'ip' => $dottedquad)) . "'>$dottedquad</a></td>";
0b8d8309
AA
2635 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2636 ? 'editable'
2637 : '';
cc2fa820
AD
2638 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
2639 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
b2035dca
DO
2640 continue;
2641 }
68c91b9c
AA
2642 // render IP change history
2643 $title = '';
2644 $history_class = '';
2645 if (isset ($addr['last_log']))
2646 {
2647 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2648 $history_class = 'hover-history underline';
2649 }
4318ced5
AA
2650 $tr_class .= ' ' . $addr['class'];
2651 echo "<tr class='tdleft $tr_class'>";
2652 echo "<td><a class='ancor $history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
0b8d8309 2653 $editable =
cc2fa820 2654 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
0b8d8309
AA
2655 && permitted ('ipaddress', 'properties', 'editAddress')
2656 ? 'editable'
2657 : '';
cc2fa820
AD
2658 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
2659 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
0b8d8309 2660 echo "<td>";
b2035dca 2661 $delim = '';
b2035dca
DO
2662 if ( $addr['reserved'] == 'yes')
2663 {
2d318652 2664 echo "<strong>RESERVED</strong> ";
b2035dca
DO
2665 $delim = '; ';
2666 }
212b565a 2667 foreach ($addr['allocs'] as $ref)
b2035dca 2668 {
beb9e88a 2669 echo $delim . $aac2[$ref['type']];
4318ced5 2670 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
59a83bd8 2671 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
b2035dca
DO
2672 echo "${ref['object_name']}</a>";
2673 $delim = '; ';
2674 }
2675 if ($delim != '')
e0d6e38e 2676 $delim = '<br>';
212b565a
AA
2677 foreach ($addr['vslist'] as $vs_id)
2678 {
2679 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2680 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
212b565a
AA
2681 $delim = '<br>';
2682 }
eacc0983
AA
2683 foreach ($addr['vsglist'] as $vs_id)
2684 {
2685 $vs = spotEntity ('ipvs', $vs_id);
2686 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
2687 $delim = '<br>';
2688 }
212b565a
AA
2689 foreach ($addr['rsplist'] as $rsp_id)
2690 {
2691 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2692 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
212b565a
AA
2693 $delim = '<br>';
2694 }
b2035dca 2695 echo "</td></tr>\n";
4318ced5 2696 }
2727c7df 2697 // end of iteration
a8dc2982
AA
2698 if (permitted (NULL, NULL, 'set_reserve_comment'))
2699 addJS ('js/inplace-edit.js');
e673ee24
DO
2700
2701 echo "</table>";
446c25c3
AA
2702 if (! empty ($rendered_pager))
2703 echo '<p>' . $rendered_pager . '</p>';
21ee3351
AA
2704}
2705
2706function renderIPv6NetworkAddresses ($netinfo)
2707{
2708 global $pageno, $tabno, $aac2;
2709 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2710 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
21ee3351 2711
4318ced5
AA
2712 $hl_ip = NULL;
2713 if (isset ($_REQUEST['hl_ip']))
2714 {
2715 $hl_ip = ip6_parse ($_REQUEST['hl_ip']);
2716 addAutoScrollScript ('ip-' . ip6_format ($hl_ip));
2717 }
21ee3351 2718
21ee3351
AA
2719 $addresses = $netinfo['addrlist'];
2720 ksort ($addresses);
4318ced5 2721 markupIPAddrList ($addresses);
21ee3351
AA
2722
2723 // pager
2724 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2725 if (count ($addresses) > $maxperpage && $maxperpage > 0)
2726 {
2727 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0);
2728 $numpages = ceil (count ($addresses) / $maxperpage);
2729 echo "<center><h3>$numpages pages:</h3>";
2730 for ($i=0; $i<$numpages; $i++)
2731 {
2732 if ($i == $page)
2733 echo "<b>$i</b> ";
2734 else
2735 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> ";
2736 }
2737 echo "</center>";
2738 }
2739
2740 $i = 0;
dec748f6 2741 $interruped = FALSE;
4318ced5
AA
2742 $prev_ip = ip_prev ($netinfo['ip_bin']);
2743 foreach ($addresses as $ip_bin => $addr)
21ee3351
AA
2744 {
2745 if (isset ($page))
2746 {
2747 ++$i;
2748 if ($i <= $maxperpage * $page)
2749 continue;
2750 elseif ($i > $maxperpage * ($page + 1))
2751 {
2752 $interruped = TRUE;
2753 break;
2754 }
2755 }
2756
4318ced5
AA
2757 if ($ip_bin != ip_next ($prev_ip))
2758 renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip);
2759 $prev_ip = $ip_bin;
2760
2761 // render IP change history
2762 $title = '';
2763 $history_class = '';
2764 if (isset ($addr['last_log']))
2765 {
2766 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2767 $history_class = 'hover-history underline';
2768 }
2769
5c717ce5 2770 $tr_class = $addr['class'] . ' tdleft' . ($hl_ip === $ip_bin ? ' highlight' : '');
4318ced5
AA
2771 echo "<tr class='$tr_class'>";
2772 echo "<td><a class='ancor $history_class' $title name='ip-${addr['ip']}' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $addr['ip'])) . "'>${addr['ip']}</a></td>";
0b8d8309
AA
2773 $editable =
2774 (empty ($addr['allocs']) || !empty ($addr['name'])
2775 && permitted ('ipaddress', 'properties', 'editAddress')
2776 ? 'editable'
2777 : '');
cc2fa820
AD
2778 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-name'>${addr['name']}</span></td>";
2779 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-comment'>${addr['comment']}</span></td><td>";
21ee3351 2780 $delim = '';
21ee3351
AA
2781 if ( $addr['reserved'] == 'yes')
2782 {
2783 echo "<strong>RESERVED</strong> ";
2784 $delim = '; ';
2785 }
2786 foreach ($addr['allocs'] as $ref)
2787 {
2788 echo $delim . $aac2[$ref['type']];
71066ef1 2789 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
21ee3351
AA
2790 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
2791 echo "${ref['object_name']}</a>";
2792 $delim = '; ';
2793 }
2794 if ($delim != '')
71066ef1
AA
2795 $delim = '<br>';
2796 foreach ($addr['vslist'] as $vs_id)
2797 {
2798 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2799 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
71066ef1
AA
2800 $delim = '<br>';
2801 }
eacc0983
AA
2802 foreach ($addr['vsglist'] as $vs_id)
2803 {
2804 $vs = spotEntity ('ipvs', $vs_id);
2805 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
2806 $delim = '<br>';
2807 }
71066ef1 2808 foreach ($addr['rsplist'] as $rsp_id)
21ee3351 2809 {
71066ef1 2810 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2811 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
71066ef1 2812 $delim = '<br>';
21ee3351
AA
2813 }
2814 echo "</td></tr>\n";
2815 }
2816 if (! $interruped)
4318ced5 2817 renderSeparator (ip_next ($prev_ip), ip_last ($netinfo), $hl_ip);
21ee3351
AA
2818 if (isset ($page))
2819 { // bottom pager
2820 echo "<tr><td colspan=3>";
2821 if ($page > 0)
2822 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page - 1)) . "'><< prev</a> ";
2823 if ($page < $numpages - 1)
2824 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page + 1)) . "'>next >></a> ";
2825 echo "</td></tr>";
2826 }
2827 echo "</table>";
a8dc2982
AA
2828 if (permitted (NULL, NULL, 'set_reserve_comment'))
2829 addJS ('js/inplace-edit.js');
21ee3351
AA
2830}
2831
2832function renderIPNetworkProperties ($id)
e673ee24 2833{
21ee3351
AA
2834 global $pageno;
2835 $netdata = spotEntity ($pageno, $id);
53ef3908 2836 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
e673ee24 2837 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 2838 printOpFormIntro ('editRange');
99ab184f
DO
2839 echo '<tr><td class=tdright><label for=nameinput>Name:</label></td>';
2840 echo "<td class=tdleft><input type=text name=name id=nameinput size=80 maxlength=255 value='";
2841 echo htmlspecialchars ($netdata['name'], ENT_QUOTES, 'UTF-8') . "'></tr>";
2842 echo '<tr><td class=tdright><label for=commentinput>Comment:</label></td>';
2843 echo "<td class=tdleft><textarea name=comment id=commentinput cols=80 rows=25>\n";
2844 echo htmlspecialchars ($netdata['comment'], ENT_QUOTES, 'UTF-8') . "</textarea></tr>";
53ef3908
DO
2845 echo "<tr><td colspan=2 class=tdcenter>";
2846 printImageHREF ('SAVE', 'Save changes', TRUE);
2847 echo "</td></form></tr></table>\n";
93a49e5b
AA
2848
2849 echo '<center>';
2850 if (! isIPNetworkEmpty ($netdata))
2851 echo getOpLink (NULL, 'delete this prefix', 'nodestroy', 'There are ' . count ($netdata['addrlist']) . ' allocations inside');
2852 else
2853 echo getOpLink (array('op'=>'del','id'=>$id), 'delete this prefix', 'destroy');
2854 echo '</center>';
e673ee24
DO
2855}
2856
09a531eb 2857function renderIPAddress ($ip_bin)
e673ee24 2858{
46098972 2859 global $aat, $nextorder;
09a531eb 2860 $address = getIPAddress ($ip_bin);
68225375 2861 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
21ee3351 2862 echo "<tr><td colspan=2 align=center><h1>${address['ip']}</h1></td></tr>\n";
e673ee24 2863
68225375 2864 echo "<tr><td class=pcleft>";
dec748f6 2865
defd92d8 2866 $summary = array();
423c4216 2867 if (strlen ($address['name']))
cc2fa820
AD
2868 $summary['Name'] = $address['name'];
2869 if (strlen ($address['comment']))
2870 $summary['Comment'] = $address['comment'];
defd92d8
AA
2871 $summary['Reserved'] = $address['reserved'];
2872 $summary['Allocations'] = count ($address['allocs']);
4318ced5 2873 if (isset ($address['outpf']))
defd92d8 2874 $summary['Originated NAT connections'] = count ($address['outpf']);
4318ced5 2875 if (isset ($address['inpf']))
defd92d8 2876 $summary['Arriving NAT connections'] = count ($address['inpf']);
defd92d8 2877 renderEntitySummary ($address, 'summary', $summary);
dec748f6 2878
212b565a 2879 // render SLB portlet
eacc0983 2880 if (! empty ($address['vslist']) or ! empty ($address['vsglist']) or ! empty ($address['rsplist']))
212b565a
AA
2881 {
2882 startPortlet ("");
eacc0983
AA
2883 if (! empty ($address['vsglist']))
2884 {
2885 printf ("<h2>virtual service groups (%d):</h2>", count ($address['vsglist']));
2886 foreach ($address['vsglist'] as $vsg_id)
2887 renderSLBEntityCell (spotEntity ('ipvs', $vsg_id));
2888 }
2889
212b565a
AA
2890 if (! empty ($address['vslist']))
2891 {
2892 printf ("<h2>virtual services (%d):</h2>", count ($address['vslist']));
2893 foreach ($address['vslist'] as $vs_id)
2894 renderSLBEntityCell (spotEntity ('ipv4vs', $vs_id));
2895 }
2896
2897 if (! empty ($address['rsplist']))
2898 {
2899 printf ("<h2>RS pools (%d):</h2>", count ($address['rsplist']));
2900 foreach ($address['rsplist'] as $rsp_id)
2901 renderSLBEntityCell (spotEntity ('ipv4rspool', $rsp_id));
2902 }
2903 finishPortlet();
2904 }
68225375 2905 echo "</td>\n";
e673ee24 2906
68225375 2907 echo "<td class=pcright>";
defd92d8 2908 if (isset ($address['class']) and ! empty ($address['allocs']))
59bebe2b 2909 {
8e700dd1 2910 startPortlet ('allocations');
2d318652
DO
2911 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2912 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2d318652 2913 // render all allocation records for this address the same way
2d318652 2914 foreach ($address['allocs'] as $bond)
59bebe2b 2915 {
4318ced5 2916 $tr_class = "${address['class']} tdleft";
8e700dd1 2917 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
5c717ce5 2918 $tr_class .= ' highlight';
4318ced5
AA
2919 echo "<tr class='$tr_class'>" .
2920 "<td><a href='" . makeHref (array ('page' => 'object', 'object_id' => $bond['object_id'], 'tab' => 'default', 'hl_ip' => $address['ip'])) . "'>${bond['object_name']}</td>" .
2921 "<td>${bond['name']}</td>" .
2922 "<td><strong>" . $aat[$bond['type']] . "</strong></td>" .
2923 "</tr>\n";
59bebe2b
DO
2924 }
2925 echo "</table><br><br>";
2926 finishPortlet();
2927 }
e673ee24 2928
eacc0983
AA
2929 if (! empty ($address['rsplist']))
2930 {
2931 startPortlet ("RS pools:");
2932 foreach ($address['rsplist'] as $rsp_id)
2933 {
2934 renderSLBEntityCell (spotEntity ('ipv4rspool', $rsp_id));
2935 echo '<br>';
2936 }
2937 finishPortlet();
2938 }
2939
2940 if (! empty ($address['vsglist']))
2941 foreach ($address['vsglist'] as $vsg_id)
2942 renderSLBTriplets2 (spotEntity ('ipvs', $vsg_id), FALSE, $ip_bin);
2943
2944 if (! empty ($address['vslist']))
defd92d8 2945 renderSLBTriplets ($address);
5fe1ed76 2946
7419401e
AA
2947 foreach (array ('outpf' => 'departing NAT rules', 'inpf' => 'arriving NAT rules') as $key => $title)
2948 if (! empty ($address[$key]))
2949 {
2950 startPortlet ($title);
2951 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2952 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2953 foreach ($address[$key] as $rule)
2954 {
2955 echo "<tr>";
2956 echo "<td>" . $rule['proto'] . "</td>";
2957 echo "<td>" . getRenderedIPPortPair ($rule['localip'], $rule['localport']) . "</td>";
2958 echo "<td>" . getRenderedIPPortPair ($rule['remoteip'], $rule['remoteport']) . "</td>";
2959 echo "<td>" . $rule['description'] . "</td></tr>";
2960 echo "</tr>";
2961 }
2962 echo "</table>";
2963 finishPortlet();
2964 }
105a3bc8 2965
68225375
DO
2966 echo "</td></tr>";
2967 echo "</table>\n";
e673ee24
DO
2968}
2969
09a531eb 2970function renderIPAddressProperties ($ip_bin)
e673ee24 2971{
09a531eb 2972 $address = getIPAddress ($ip_bin);
21ee3351 2973 echo "<center><h1>${address['ip']}</h1></center>\n";
7056988c 2974
1fbc9fd6 2975 startPortlet ('update');
e673ee24 2976 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 2977 printOpFormIntro ('editAddress');
0186638b
DO
2978 echo '<tr><td class=tdright><label for=id_name>Name:</label></td>';
2979 echo "<td class=tdleft><input type=text name=name id=id_name size=20 value='${address['name']}'></tr>";
cc2fa820
AD
2980 echo '<tr><td class=tdright><label for=id_comment>Comment:</label></td>';
2981 echo "<td class=tdleft><input type=text name=comment id=id_comment size=20 value='${address['comment']}'></tr>";
0186638b
DO
2982 echo '<td class=tdright><label for=id_reserved>Reserved:</label></td>';
2983 echo "<td class=tdleft><input type=checkbox name=reserved id=id_reserved size=20 ";
2d318652 2984 echo ($address['reserved']=='yes') ? 'checked' : '';
f3d274bf 2985 echo "></tr><tr><td class=tdleft>";
53ef3908 2986 printImageHREF ('SAVE', 'Save changes', TRUE);
f3d274bf 2987 echo "</td></form><td class=tdright>";
59a83bd8 2988 if (!strlen ($address['name']) and $address['reserved'] == 'no')
f3d274bf
DO
2989 printImageHREF ('CLEAR gray');
2990 else
2991 {
18a77e3c 2992 printOpFormIntro ('editAddress', array ('name' => '', 'reserved' => '', 'comment' => ''));
f3d274bf
DO
2993 printImageHREF ('CLEAR', 'Release', TRUE);
2994 echo "</form>";
2995 }
2996 echo "</td></tr></table>\n";
1fbc9fd6 2997 finishPortlet();
e673ee24
DO
2998}
2999
09a531eb 3000function renderIPAddressAllocations ($ip_bin)
e673ee24 3001{
4318ced5 3002 function printNewItemTR ()
39b4abd0
DO
3003 {
3004 global $aat;
4318ced5 3005 printOpFormIntro ('add');
39b4abd0 3006 echo "<tr><td>";
9318d2ef 3007 printImageHREF ('add', 'allocate', TRUE);
8d4f7d18 3008 echo "</td><td>";
31babb65 3009 printSelect (getNarrowObjectList ('IPV4OBJ_LISTSRC'), array ('name' => 'object_id', 'tabindex' => 100));
8d4f7d18 3010 echo "</td><td><input type=text tabindex=101 name=bond_name size=10></td><td>";
01abf1de 3011 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102, 'regular'));
9318d2ef 3012 echo "</td><td>";
f5ff50f5 3013 printImageHREF ('add', 'allocate', TRUE, 103);
9318d2ef 3014 echo "</td></form></tr>";
39b4abd0 3015 }
b82cce3f 3016 global $aat;
e673ee24 3017
09a531eb 3018 $address = getIPAddress ($ip_bin);
21ee3351 3019 echo "<center><h1>${address['ip']}</h1></center>\n";
105a3bc8 3020 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2d318652 3021 echo "<tr><th>&nbsp;</th><th>object</th><th>OS interface</th><th>allocation type</th><th>&nbsp;</th></tr>\n";
e673ee24 3022
39b4abd0 3023 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
4318ced5 3024 printNewItemTR();
f74d96c6 3025 if (isset ($address['class']))
e673ee24 3026 {
f74d96c6
DO
3027 $class = $address['class'];
3028 if ($address['reserved'] == 'yes')
3029 echo "<tr class='${class}'><td colspan=3>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td><td>&nbsp;</td></tr>";
3030 foreach ($address['allocs'] as $bond)
3031 {
3032 echo "<tr class='$class'>";
4318ced5 3033 printOpFormIntro ('upd', array ('object_id' => $bond['object_id']));
10f5133a 3034 echo "<td>" . getOpLink (array ('op' => 'del', 'object_id' => $bond['object_id'] ), '', 'delete', 'Unallocate address') . "</td>";
4318ced5 3035 echo "<td><a href='" . makeHref (array ('page' => 'object', 'object_id' => $bond['object_id'], 'hl_ip' => $address['ip'])) . "'>${bond['object_name']}</td>";
f74d96c6 3036 echo "<td><input type='text' name='bond_name' value='${bond['name']}' size=10></td><td>";
cd3775e9 3037 printSelect ($aat, array ('name' => 'bond_type'), $bond['type']);
f74d96c6
DO
3038 echo "</td><td>";
3039 printImageHREF ('save', 'Save changes', TRUE);
3040 echo "</td></form></tr>\n";
3041 }
e673ee24 3042 }
39b4abd0 3043 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
4318ced5 3044 printNewItemTR();
e673ee24 3045 echo "</table><br><br>";
e673ee24
DO
3046}
3047
7e1db771 3048function renderNATv4ForObject ($object_id)
e673ee24 3049{
9318d2ef
DO
3050 function printNewItemTR ($alloclist)
3051 {
9318d2ef
DO
3052 printOpFormIntro ('addNATv4Rule');
3053 echo "<tr align='center'><td>";
3054 printImageHREF ('add', 'Add new NAT rule', TRUE);
3055 echo '</td><td>';
cd3775e9 3056 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP'), array ('name' => 'proto'));
9318d2ef
DO
3057 echo "<select name='localip' tabindex=1>";
3058
4318ced5 3059 foreach ($alloclist as $ip_bin => $alloc)
9318d2ef 3060 {
4318ced5 3061 $ip = $alloc['addrinfo']['ip'];
43eb71f1
DO
3062 $name = (!isset ($alloc['addrinfo']['name']) or !strlen ($alloc['addrinfo']['name'])) ? '' : (' (' . niftyString ($alloc['addrinfo']['name']) . ')');
3063 $osif = (!isset ($alloc['osif']) or !strlen ($alloc['osif'])) ? '' : ($alloc['osif'] . ': ');
4318ced5 3064 echo "<option value='${ip}'>${osif}${ip}${name}</option>";
9318d2ef
DO
3065 }
3066
3067 echo "</select>:<input type='text' name='localport' size='4' tabindex=2></td>";
3068 echo "<td><input type='text' name='remoteip' id='remoteip' size='10' tabindex=3>";
39106006
DO
3069 echo "<a href='javascript:;' onclick='window.open(\"" . makeHrefForHelper ('inet4list');
3070 echo "\", \"findobjectip\", \"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
9318d2ef
DO
3071 printImageHREF ('find', 'Find object');
3072 echo "</a>";
3073 echo ":<input type='text' name='remoteport' size='4' tabindex=4></td><td></td>";
3074 echo "<td colspan=1><input type='text' name='description' size='20' tabindex=5></td><td>";
f5ff50f5 3075 printImageHREF ('add', 'Add new NAT rule', TRUE, 6);
9318d2ef
DO
3076 echo "</td></tr></form>";
3077 }
dec748f6 3078
94fe6370
DO
3079 $focus = spotEntity ('object', $object_id);
3080 amplifyCell ($focus);
f28fbe8b 3081 echo "<center><h2>locally performed NAT</h2></center>";
e673ee24 3082
105a3bc8 3083 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
d54b9495 3084 echo "<tr><th></th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Comment</th><th>&nbsp;</th></tr>\n";
e673ee24 3085
9318d2ef 3086 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
94fe6370
DO
3087 printNewItemTR ($focus['ipv4']);
3088 foreach ($focus['nat4']['out'] as $pf)
e673ee24 3089 {
2c817354
DO
3090 $class = 'trerror';
3091 $osif = '';
4318ced5
AA
3092 $localip_bin = ip4_parse ($pf['localip']);
3093 if (isset ($focus['ipv4'][$localip_bin]))
2c817354 3094 {
4318ced5
AA
3095 $class = $focus['ipv4'][$localip_bin]['addrinfo']['class'];
3096 $osif = $focus['ipv4'][$localip_bin]['osif'] . ': ';
2c817354 3097 }
e673ee24
DO
3098
3099 echo "<tr class='$class'>";
10f5133a
AA
3100 echo "<td>" . getOpLink (
3101 array (
dec748f6 3102 'op'=>'delNATv4Rule',
4fbb5a00
DY
3103 'localip'=>$pf['localip'],
3104 'localport'=>$pf['localport'],
3105 'remoteip'=>$pf['remoteip'],
3106 'remoteport'=>$pf['remoteport'],
dec748f6 3107 'proto'=>$pf['proto'],
10f5133a
AA
3108 ), '', 'delete', 'Delete NAT rule'
3109 ) . "</td>";
7419401e 3110 echo "<td>${pf['proto']}/${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']);
59a83bd8 3111 if (strlen ($pf['local_addr_name']))
f28fbe8b
DO
3112 echo ' (' . $pf['local_addr_name'] . ')';
3113 echo "</td>";
7419401e 3114 echo "<td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
e673ee24 3115
4318ced5 3116 $address = getIPAddress (ip4_parse ($pf['remoteip']));
e673ee24
DO
3117
3118 echo "<td class='description'>";
53ef3908
DO
3119 if (count ($address['allocs']))
3120 foreach ($address['allocs'] as $bond)
ad3e5e7e 3121 echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' ';
59a83bd8 3122 elseif (strlen ($pf['remote_addr_name']))
f28fbe8b 3123 echo '(' . $pf['remote_addr_name'] . ')';
7056988c
DO
3124 printOpFormIntro
3125 (
3126 'updNATv4Rule',
3127 array
3128 (
3129 'localip' => $pf['localip'],
3130 'localport' => $pf['localport'],
3131 'remoteip' => $pf['remoteip'],
3132 'remoteport' => $pf['remoteport'],
3133 'proto' => $pf['proto']
3134 )
3135 );
3136 echo "</td><td class='description'>";
d54b9495
DO
3137 echo "<input type='text' name='description' value='${pf['description']}'></td><td>";
3138 printImageHREF ('save', 'Save changes', TRUE);
3139 echo "</td></form></tr>";
e673ee24 3140 }
9318d2ef 3141 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
94fe6370 3142 printNewItemTR ($focus['ipv4']);
e673ee24
DO
3143
3144 echo "</table><br><br>";
94fe6370
DO
3145 if (!count ($focus['nat4']))
3146 return;
e673ee24 3147
f28fbe8b 3148 echo "<center><h2>arriving NAT connections</h2></center>";
105a3bc8 3149 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
e673ee24
DO
3150 echo "<tr><th></th><th>Source</th><th>Source objects</th><th>Target</th><th>Description</th></tr>\n";
3151
94fe6370 3152 foreach ($focus['nat4']['in'] as $pf)
e673ee24 3153 {
10f5133a
AA
3154 echo "<tr><td>" . getOpLink (
3155 array(
4fbb5a00
DY
3156 'op'=>'delNATv4Rule',
3157 'localip'=>$pf['localip'],
3158 'localport'=>$pf['localport'],
3159 'remoteip'=>$pf['remoteip'],
3160 'remoteport'=>$pf['remoteport'],
3161 'proto'=>$pf['proto'],
10f5133a
AA
3162 ), '', 'delete', 'Delete NAT rule'
3163 ) . "</td>";
7419401e 3164 echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
ad3e5e7e 3165 echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']);
7419401e 3166 echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
e67