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