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