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