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