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