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