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