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