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