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