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