css bugfix: removed invalid list-type li style
[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']);
be28528c 687 $slotRows = $slotCols = $slotInfo = $slotData = $slotTitle = 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] .= "'>";
721 }
722 }
0a7feebb
AD
723 natsort($childNames);
724 $suffix = sprintf(", contains %s'>", implode(', ', $childNames));
725 }
726 else
727 $suffix = "'>";
ad3e5e7e 728 echo "${prefix}${body}${suffix}" . mkA ($objectData['dname'], 'object', $objectData['id']) . '</div>';
84feb87b
AD
729 if (in_array ($objectData['objtype_id'], array (1502,1503))) // server chassis, network chassis
730 {
731 $objAttr = getAttrValues ($objectData['id']);
732 if (isset ($objAttr[2])) // HW type
733 {
734 extractLayout ($objAttr[2]);
735 if (isset ($objAttr[2]['rows']))
736 {
737 $rows = $objAttr[2]['rows'];
738 $cols = $objAttr[2]['cols'];
739 $layout = $objAttr[2]['layout'];
740 echo "<table width='100%' border='1'>";
741 for ($r = 0; $r < $rows; $r++)
742 {
743 echo '<tr>';
744 for ($c = 0; $c < $cols; $c++)
745 {
746 $s = ($r * $cols) + $c + 1;
747 if (isset ($slotData[$s]))
748 {
be28528c 749 if ($slotData[$s] >= 0)
84feb87b 750 {
be28528c
M
751 for ($lr = 0; $lr < $slotRows[$s]; $lr++)
752 for ($lc = 0; $lc < $slotCols[$s]; $lc++)
753 {
754 $skip = ($lr * $cols) + $lc;
755 if ($skip > 0)
756 $slotData[$s + $skip] = -1;
757 }
758 echo '<td';
759 if ($slotRows[$s] > 1)
760 echo " rowspan=$slotRows[$s]";
761 if ($slotCols[$s] > 1)
762 echo " colspan=$slotCols[$s]";
763 echo " class='state_T";
764 if ($slotData[$s] == $hl_obj_id)
765 echo 'h';
766 echo "'>${slotTitle[$s]}";
767 if ($layout == 'V')
768 {
769 $tmp = substr ($slotInfo[$s], 0, 1);
770 foreach (str_split (substr ($slotInfo[$s], 1)) as $letter)
771 $tmp .= '<br>' . $letter;
772 $slotInfo[$s] = $tmp;
773 }
774 echo mkA ($slotInfo[$s], 'object', $slotData[$s]);
775 echo '</div></td>';
84feb87b 776 }
84feb87b
AD
777 }
778 else
779 echo "<td class='state_F'><div title=\"Free slot\">&nbsp;</div></td>";
780 }
781 echo '</tr>';
782 }
783 echo '</table>';
784 }
785 }
786 }
0a7feebb
AD
787}
788
e673ee24 789// This function renders rack as HTML table.
7e1db771 790function renderRack ($rack_id, $hl_obj_id = 0)
e673ee24 791{
61a1d996
DO
792 $rackData = spotEntity ('rack', $rack_id);
793 amplifyCell ($rackData);
e673ee24
DO
794 markAllSpans ($rackData);
795 if ($hl_obj_id > 0)
796 highlightObject ($rackData, $hl_obj_id);
e673ee24
DO
797 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
798 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
d48d8820 799 echo "<center><table border=0><tr valign=middle>";
ad3e5e7e 800 echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>';
e673ee24 801 if ($prev_id != NULL)
ad3e5e7e
DO
802 echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>';
803 echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>';
e673ee24 804 if ($next_id != NULL)
ad3e5e7e 805 echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>';
d48d8820 806 echo "</h2></td></tr></table>\n";
e673ee24 807 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
d08147d6
DO
808 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
809 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
e673ee24
DO
810 for ($i = $rackData['height']; $i > 0; $i--)
811 {
4dcd770e 812 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
e673ee24
DO
813 for ($locidx = 0; $locidx < 3; $locidx++)
814 {
815 if (isset ($rackData[$i][$locidx]['skipped']))
816 continue;
817 $state = $rackData[$i][$locidx]['state'];
65e557dd 818 echo "<td class='atom state_${state}";
e673ee24
DO
819 if (isset ($rackData[$i][$locidx]['hl']))
820 echo $rackData[$i][$locidx]['hl'];
65e557dd 821 echo "'";
e673ee24
DO
822 if (isset ($rackData[$i][$locidx]['colspan']))
823 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
824 if (isset ($rackData[$i][$locidx]['rowspan']))
825 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
826 echo ">";
827 switch ($state)
828 {
829 case 'T':
84feb87b 830 printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id);
e673ee24
DO
831 break;
832 case 'A':
833 echo '<div title="This rackspace does not exist">&nbsp;</div>';
834 break;
835 case 'F':
836 echo '<div title="Free rackspace">&nbsp;</div>';
837 break;
838 case 'U':
839 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
840 break;
841 default:
842 echo '<div title="No data">&nbsp;</div>';
843 break;
844 }
845 echo '</td>';
846 }
847 echo "</tr>\n";
848 }
0a7feebb
AD
849 echo "</table>\n";
850 // Get a list of all of objects Zero-U mounted to this rack
851 $zeroUObjects = getEntityRelatives('children', 'rack', $rack_id);
a20a4e3c
DO
852 if (count ($zeroUObjects) > 0)
853 {
0a7feebb
AD
854 echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n";
855 echo "<tr><th>Zero-U:</th></tr>\n";
856 foreach ($zeroUObjects as $zeroUObject)
857 {
858 $state = ($zeroUObject['entity_id'] == $hl_obj_id) ? 'Th' : 'T';
859 echo "<tr><td class='atom state_${state}'>";
860 printObjectDetailsForRenderRack($zeroUObject['entity_id']);
861 echo "</td></tr>\n";
862 }
863 echo "</table>\n";
864 }
865 echo "</center>\n";
e673ee24
DO
866}
867
42504426
AD
868function renderRackSortForm ($row_id)
869{
b090b2da
RQ
870 includeJQueryUI (false);
871 $js = <<<JSTXT
872 $(document).ready(
873 function () {
874 $("#sortRacks").sortable({
875 update : function () {
876 serial = $('#sortRacks').sortable('serialize');
877 $.ajax({
878 url: 'index.php?module=ajax&ac=upd-rack-sort-order',
879 type: 'post',
880 data: serial,
881 });
882 }
883 });
884 }
42504426 885 );
b090b2da
RQ
886JSTXT;
887 addJS($js, true);
42504426
AD
888
889 startPortlet ('Racks');
890 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
891 echo "<tr><th>Drag to change order</th></tr>\n";
892 echo "<tr><td><ul class='uflist' id='sortRacks'>\n";
893 foreach (getRacks($row_id) as $rack_id => $rackInfo)
894 echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n";
895 echo "</ul></td></tr></table>\n";
896 finishPortlet();
897}
898
e673ee24
DO
899function renderNewRackForm ($row_id)
900{
9b8174d7
AD
901 $default_height = getConfigVar ('DEFAULT_RACK_HEIGHT');
902 if ($default_height == 0)
903 $default_height = '';
50b4ba85 904 startPortlet ('Add one');
f19c75d6 905 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
e673ee24 906 echo '<table border=0 align=center>';
9b8174d7 907 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name tabindex=1></td>";
72d52730 908 echo "<td rowspan=4>Assign tags:<br>";
a26a6ccc 909 renderNewEntityTags ('rack');
72d52730 910 echo "</td></tr>\n";
9b8174d7 911 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 912 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no tabindex=4></td></tr>\n";
f19c75d6
DO
913 echo "<tr><td class=submit colspan=2>";
914 printImageHREF ('CREATE', 'Add', TRUE);
915 echo "</td></tr></table></form>";
406b54bd 916 finishPortlet();
406b54bd 917
50b4ba85 918 startPortlet ('Add many');
f19c75d6 919 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
50b4ba85 920 echo '<table border=0 align=center>';
9b8174d7 921 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>";
72d52730 922 echo "<td rowspan=3 valign=top>Assign tags:<br>";
a26a6ccc 923 renderNewEntityTags ('rack');
72d52730 924 echo "</td></tr>\n";
9b8174d7 925 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
926 echo "<tr><td class=submit colspan=2>";
927 printImageHREF ('CREATE', 'Add', TRUE);
e673ee24
DO
928 echo '</form></table>';
929 finishPortlet();
930}
931
3825c4db 932function renderEditObjectForm()
e673ee24 933{
8dc2a6c8 934 global $pageno, $virtual_obj_types;
3825c4db 935 $object_id = getBypassValue();
fb6e2f57 936 $object = spotEntity ('object', $object_id);
cdd3efe9 937 startPortlet ();
43fb6eaf 938 printOpFormIntro ('update');
cdd3efe9
AD
939
940 // static attributes
e10f583a
DO
941 echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
942 echo "<tr><td>&nbsp;</td><th colspan=2><h2>Attributes</h2></th></tr>";
3825c4db
DO
943 echo '<tr><td>&nbsp;</td><th class=tdright>Type:</th><td class=tdleft>';
944 printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']);
945 echo '</td></tr>';
22bb04da 946 // baseline info
e10f583a 947 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";
8dc2a6c8 948 if (in_array($object['objtype_id'], $virtual_obj_types))
0682218d
AD
949 {
950 echo "<input type=hidden name=object_label value=''>\n";
951 echo "<input type=hidden name=object_asset_no value=''>\n";
0682218d
AD
952 }
953 else
954 {
955 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";
956 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
AD
957 }
958 // parent selection
9b8174d7 959 if (objectTypeMayHaveParent ($object['objtype_id']))
0682218d
AD
960 {
961 $parents = getEntityRelatives ('parents', 'object', $object_id);
962 foreach ($parents as $link_id => $parent_details)
963 {
964 if (!isset($label))
965 $label = count($parents) > 1 ? 'Containers:' : 'Container:';
966 echo "<tr><td>&nbsp;</td>";
967 echo "<th class=tdright>${label}</th><td class=tdleft>";
ad3e5e7e 968 echo mkA ($parent_details['name'], 'object', $parent_details['entity_id']);
0682218d 969 echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
10f5133a 970 echo getOpLink (array('op'=>'unlinkEntities', 'link_id'=>$link_id), '', 'cut', 'Unlink container');
0682218d
AD
971 echo "</td></tr>\n";
972 $label = '&nbsp;';
973 }
974 echo "<tr><td>&nbsp;</td>";
975 echo "<th class=tdright>Select container:</th><td class=tdleft>";
597896f6
AA
976 echo getPopupLink ('objlist', array ('object_id' => $object_id), 'findlink', 'attach', 'Select a container');
977 echo "</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{
597896f6
AA
1198 $tr_class = $is_highlighted ? 'class=highlight' : '';
1199 echo "<tr $tr_class>";
40c9fc94 1200 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
597896f6 1201 echo "<td class='tdleft' NOWRAP><a name='port-${port['id']}' class='ancor interactive-portname nolink $a_class'>${port['name']}</a></td>";
40c9fc94
AA
1202 echo "<td class=tdleft>${port['label']}</td>";
1203 echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class=tdleft><tt>${port['l2address']}</tt></td>";
597896f6
AA
1204 if (! $port['linked'])
1205 echo implode ('', formatPortReservation ($port)) . '<td></td>';
1206 else
1207 {
a7390942 1208 $editable = permitted ('object', 'ports', 'editPort')? 'editable' : '';
597896f6
AA
1209 $sep = '';
1210 foreach ($port['links'] as $linkinfo)
a7390942 1211 {
a4b6536a 1212 $trace_link = ($sep == '') ? '&nbsp;' . getPopupLink ('traceroute', array ('port' => $port['id']), 'findlink', 'find', '', 'Trace this port') : '';
597896f6
AA
1213 echo $sep;
1214 $sep = "</tr>\n<tr $tr_class><td colspan=4></td>";
1215 echo '<td class=tdleft>'.formatLoggedSpan ($port['last_log'], formatPortLink ($linkinfo['remote_object_id'], $linkinfo['remote_object_name'], $linkinfo['remote_id'], NULL)).'</td>';
a4b6536a 1216 echo '<td class=tdleft>'.formatLoggedSpan ($port['last_log'], $linkinfo['remote_name'], 'underline').$trace_link.'</td>';
597896f6 1217 echo "<td class=tdleft><span class='rsvtext $editable id-".$linkinfo['link_id']." op-upd-reservation-cable'>".$linkinfo['cableid'].'</span></td>';
a7390942 1218 }
40c9fc94 1219 }
597896f6 1220 echo "</tr>\n";
40c9fc94
AA
1221}
1222
9b8174d7 1223function renderObject ($object_id)
e673ee24 1224{
8dc2a6c8 1225 global $nextorder, $virtual_obj_types;
fb6e2f57 1226 $info = spotEntity ('object', $object_id);
94fe6370 1227 amplifyCell ($info);
e673ee24
DO
1228 // Main layout starts.
1229 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1230 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
1231 // left column with uknown number of portlets
1232 echo "<tr><td class=pcleft>";
646272be
AA
1233
1234 // display summary portlet
1235 $summary = array();
59a83bd8 1236 if (strlen ($info['name']))
646272be 1237 $summary['Common name'] = $info['name'];
94fe6370 1238 elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
646272be
AA
1239 $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>');
1240 $summary['Object type'] = '<a href="' . makeHref (array (
341fd895
DO
1241 'page' => 'depot',
1242 'tab' => 'default',
1243 'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
646272be 1244 )) . '">' . decodeObjectType ($info['objtype_id'], 'o') . '</a>';
9b8174d7 1245 if (strlen ($info['label']))
646272be 1246 $summary['Visible label'] = $info['label'];
59a83bd8 1247 if (strlen ($info['asset_no']))
646272be 1248 $summary['Asset tag'] = $info['asset_no'];
d4e8ddeb 1249 elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
646272be
AA
1250 $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>');
1251 $parents = getEntityRelatives ('parents', 'object', $object_id);
1252 if (count ($parents))
0682218d 1253 {
646272be 1254 $fmt_parents = array();
0682218d 1255 foreach ($parents as $parent)
8023ee39
AA
1256 $fmt_parents[] = "<a href='".makeHref(array('page'=>$parent['page'], $parent['id_name'] => $parent['entity_id']))."'>${parent['name']}</a>";
1257 $summary[count($parents) > 1 ? 'Containers' : 'Container'] = implode ('<br>', $fmt_parents);
0682218d 1258 }
646272be
AA
1259 $children = getEntityRelatives ('children', 'object', $object_id);
1260 if (count ($children))
0682218d 1261 {
646272be 1262 $fmt_children = array();
0682218d 1263 foreach ($children as $child)
8023ee39 1264 $fmt_children[] = "<a href='".makeHref(array('page'=>$child['page'], $child['id_name']=>$child['entity_id']))."'>${child['name']}</a>";
dcde9835 1265 $summary['Contains'] = implode ('<br>', $fmt_children);
0682218d 1266 }
e673ee24 1267 if ($info['has_problems'] == 'yes')
646272be 1268 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
8ad59489 1269 foreach (getAttrValues ($object_id) as $record)
4969aa31
DO
1270 if
1271 (
dec748f6 1272 strlen ($record['value']) and
4969aa31
DO
1273 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1274 )
646272be 1275 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
a2c597ea
AA
1276 $summary[] = array (getOutputOf ('printTagTRs',
1277 $info,
1278 makeHref
1279 (
1280 array
1281 (
1282 'page'=>'depot',
1283 'tab'=>'default',
1284 'andor' => 'and',
1285 'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
1286 )
1287 )."&"
1288 ));
a7390942 1289 renderEntitySummary ($info, 'Summary', $summary);
e673ee24 1290
59a83bd8 1291 if (strlen ($info['comment']))
e673ee24
DO
1292 {
1293 startPortlet ('Comment');
6cc5d6cd 1294 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
e673ee24
DO
1295 finishPortlet ();
1296 }
1297
b5700329
AA
1298 $logrecords = getLogRecordsForObject ($_REQUEST['object_id']);
1299 if (count ($logrecords))
9a90adc4
DO
1300 {
1301 startPortlet ('log records');
1302 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>";
1303 $order = 'odd';
b5700329 1304 foreach ($logrecords as $row)
9a90adc4
DO
1305 {
1306 echo "<tr class=row_${order} valign=top>";
1307 echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>';
0b8d8309 1308 echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES)) . '</td>';
9a90adc4
DO
1309 echo '</tr>';
1310 $order = $nextorder[$order];
1311 }
1312 echo '</table>';
1313 finishPortlet();
1314 }
1315
65e557dd 1316 switchportInfoJS ($object_id); // load JS code to make portnames interactive
e1ae3fb4
AD
1317 renderFilesPortlet ('object', $object_id);
1318
9f75e165 1319 if (count ($info['ports']))
e673ee24 1320 {
a7390942 1321 startPortlet ('Ports and links');
9f75e165
DO
1322 $hl_port_id = 0;
1323 if (isset ($_REQUEST['hl_port_id']))
e673ee24 1324 {
0cc24e9a 1325 assertUIntArg ('hl_port_id');
9f75e165 1326 $hl_port_id = $_REQUEST['hl_port_id'];
65e557dd 1327 addAutoScrollScript ("port-$hl_port_id");
9f75e165 1328 }
597896f6 1329 echo getPopupLink ('traceroute', array ('object_id' => $object_id), 'findlink', 'find', 'Trace all port links');
a7390942 1330 echo "<table border=0 cellspacing=0 cellpadding='5' align='center' class='widetable'>";
9f75e165 1331 echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>';
0d59a51c 1332 echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>';
0c7c9f8b 1333 echo '<th class=tdcenter colspan=2>Remote object and port</th>';
a7390942 1334 echo "<th class=tdleft>Cable ID</th></tr>\n";
9f75e165 1335 foreach ($info['ports'] as $port)
40c9fc94 1336 callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id']));
fd5edda8 1337 if (permitted (NULL, 'ports', 'set_reserve_comment'))
a8dc2982 1338 addJS ('js/inplace-edit.js');
9f75e165 1339 echo "</table><br>";
e673ee24
DO
1340 finishPortlet();
1341 }
85970da2 1342
21ee3351 1343 if (count ($info['ipv4']) + count ($info['ipv6']))
e673ee24 1344 {
21ee3351 1345 startPortlet ('IP addresses');
e673ee24 1346 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
f0ed1181 1347 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
0b9c98d7 1348 echo "<tr><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n";
83fdf85f
DO
1349 else
1350 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
21ee3351
AA
1351
1352 // group IP allocations by interface name instead of address family
1353 $allocs_by_iface = array();
1354 foreach (array ('ipv4', 'ipv6') as $ip_v)
4318ced5
AA
1355 foreach ($info[$ip_v] as $ip_bin => $alloc)
1356 $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc;
dec748f6 1357
21ee3351
AA
1358 // sort allocs array by portnames
1359 foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist)
1360 {
1361 $is_first_row = TRUE;
f3505b35 1362 foreach ($alloclist as $alloc)
b90c3907 1363 {
40c9fc94 1364 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
f3505b35 1365 echo "<tr class='${rendered_alloc['tr_class']}' valign=top>";
21ee3351 1366
f3505b35 1367 // display iface name, same values are grouped into single cell
21ee3351
AA
1368 if ($is_first_row)
1369 {
1370 $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : '';
40c9fc94 1371 echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>";
21ee3351
AA
1372 $is_first_row = FALSE;
1373 }
f3505b35 1374 echo $rendered_alloc['td_ip'];
21ee3351 1375 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
83fdf85f 1376 {
f3505b35
AA
1377 echo $rendered_alloc['td_network'];
1378 echo $rendered_alloc['td_routed_by'];
21ee3351 1379 }
f3505b35
AA
1380 echo $rendered_alloc['td_peers'];
1381
1382 echo "</tr>\n";
b90c3907 1383 }
e673ee24
DO
1384 }
1385 echo "</table><br>\n";
1386 finishPortlet();
1387 }
1388
94fe6370 1389 $forwards = $info['nat4'];
e673ee24
DO
1390 if (count($forwards['in']) or count($forwards['out']))
1391 {
f28fbe8b 1392 startPortlet('NATv4');
e673ee24
DO
1393
1394 if (count($forwards['out']))
1395 {
1396
f28fbe8b 1397 echo "<h3>locally performed NAT</h3>";
e673ee24 1398
105a3bc8 1399 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1400 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
1401
1402 foreach ($forwards['out'] as $pf)
1403 {
2c817354
DO
1404 $class = 'trerror';
1405 $osif = '';
1406 if (isset ($alloclist [$pf['localip']]))
1407 {
1408 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
1409 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
1410 }
e673ee24 1411 echo "<tr class='$class'>";
7419401e
AA
1412 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1413 echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
4318ced5 1414 $address = getIPAddress (ip4_parse ($pf['remoteip']));
e673ee24 1415 echo "<td class='description'>";
53ef3908
DO
1416 if (count ($address['allocs']))
1417 foreach($address['allocs'] as $bond)
ad3e5e7e 1418 echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' ';
59a83bd8 1419 elseif (strlen ($pf['remote_addr_name']))
f28fbe8b 1420 echo '(' . $pf['remote_addr_name'] . ')';
53ef3908 1421 echo "</td><td class='description'>${pf['description']}</td></tr>";
e673ee24
DO
1422 }
1423 echo "</table><br><br>";
1424 }
1425 if (count($forwards['in']))
1426 {
f28fbe8b 1427 echo "<h3>arriving NAT connections</h3>";
105a3bc8 1428 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1429 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
e673ee24
DO
1430 foreach ($forwards['in'] as $pf)
1431 {
1432 echo "<tr>";
7419401e 1433 echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
ad3e5e7e 1434 echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']);
7419401e 1435 echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
e673ee24
DO
1436 echo "<td class='description'>${pf['description']}</td></tr>";
1437 }
e673ee24
DO
1438 echo "</table><br><br>";
1439 }
1440 finishPortlet();
1441 }
1442
eacc0983 1443 renderSLBTriplets2 ($info);
defd92d8 1444 renderSLBTriplets ($info);
e673ee24
DO
1445 echo "</td>\n";
1446
7056988c 1447 // After left column we have (surprise!) right column with rackspace portlet only.
e673ee24 1448 echo "<td class=pcright>";
8dc2a6c8 1449 if (!in_array($info['objtype_id'], $virtual_obj_types))
0682218d
AD
1450 {
1451 // rackspace portlet
1452 startPortlet ('rackspace allocation');
1453 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1454 renderRack ($rack_id, $object_id);
1455 echo '<br>';
1456 finishPortlet();
1457 }
e673ee24
DO
1458 echo "</td></tr>";
1459 echo "</table>\n";
1460}
1461
1462function renderRackMultiSelect ($sname, $racks, $selected)
1463{
04571888
DO
1464 // Transform the given flat list into a list of groups, each representing a rack row.
1465 $rdata = array();
e673ee24 1466 foreach ($racks as $rack)
d016010a 1467 {
7b6ae79a
AD
1468 $trail = getLocationTrail ($rack['location_id'], FALSE);
1469 if(!empty ($trail))
1470 $row_name = $trail . ' : ' . $rack['row_name'];
1471 else
1472 $row_name = $rack['row_name'];
d016010a
AD
1473 $rdata[$row_name][$rack['id']] = $rack['name'];
1474 }
4fbb5a00 1475 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
acfc0d89
AA
1476 $row_names = array_keys ($rdata);
1477 natsort ($row_names);
1478 foreach ($row_names as $optgroup)
e673ee24 1479 {
04571888 1480 echo "<optgroup label='${optgroup}'>";
acfc0d89 1481 foreach ($rdata[$optgroup] as $rack_id => $rack_name)
04571888
DO
1482 {
1483 echo "<option value=${rack_id}";
1484 if (!(array_search ($rack_id, $selected) === FALSE))
1485 echo ' selected';
1486 echo">${rack_name}</option>\n";
1487 }
e673ee24
DO
1488 }
1489 echo "</select>\n";
1490}
1491
e673ee24 1492// This function renders a form for port edition.
7e1db771 1493function renderPortsForObject ($object_id)
e673ee24 1494{
3153a326
DO
1495 $prefs = getPortListPrefs();
1496 function printNewItemTR ($prefs)
39b4abd0
DO
1497 {
1498 printOpFormIntro ('addPort');
1499 echo "<tr><td>";
f5ff50f5 1500 printImageHREF ('add', 'add a port', TRUE);
65e557dd 1501 echo "</td><td class='tdleft'><input type=text size=8 name=port_name tabindex=100></td>\n";
a7390942 1502 echo "<td><input type=text name=port_label tabindex=101></td><td class=tdleft>";
cd3775e9
DO
1503 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 102), $prefs['selected']);
1504 echo "<td><input type=text name=port_l2address tabindex=103 size=18 maxlength=24></td>\n";
318c48a8 1505 echo "<td colspan=4>&nbsp;</td><td>";
9318d2ef
DO
1506 printImageHREF ('add', 'add a port', TRUE, 104);
1507 echo "</td></tr></form>";
39b4abd0 1508 }
a1fc539a 1509 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' || getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' )
f44fdef9
DO
1510 startPortlet ('Ports and interfaces');
1511 else
1512 echo '<br>';
9f75e165
DO
1513 $object = spotEntity ('object', $object_id);
1514 amplifyCell ($object);
a1fc539a
RF
1515 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1516 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1517 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>";
1518 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1519 printOpFormIntro ('addBulkPorts');
1520 echo "<tr><td>";
1521 printImageHREF ('add', 'add ports', TRUE);
1522 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1523 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1524 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1525 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1526 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
a7390942 1527 echo "<td>";
a1fc539a
RF
1528 printImageHREF ('add', 'add ports', TRUE, 110);
1529 echo "</td></tr></form>";
1530 echo "</table><br>\n";
1531 }
dec748f6 1532
a7390942 1533 // clear ports link
597896f6 1534 echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', 'Delete all existing ports', 'need-confirmation');
a7390942
AD
1535
1536 // link patch panels link
1537 if ($object['objtype_id'] == 9)
1538 {
597896f6
AA
1539 echo '<span style="margin-left: 2em">';
1540 echo getPopupLink ('patchpanellist', array ('object_id' => $object_id), 'findlink', 'plug', 'Link to another patch panel');
1541 echo '</span>';
a7390942
AD
1542 }
1543
597896f6
AA
1544 echo '<span style="margin-left: 2em">';
1545 echo getPopupLink ('traceroute', array ('object_id' => $object_id), 'findlink', 'find', 'Trace all port links');
1546 echo '</span>';
a7390942
AD
1547
1548 echo "<table border=0 cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
0d59a51c 1549 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>";
a7390942 1550 echo "<th class=tdleft colspan=2>Remote object and port</th><th class=tdleft>Cable ID</th><th class=tdleft>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
39b4abd0 1551 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
3153a326 1552 printNewItemTR ($prefs);
45ff9012 1553
00276508
AA
1554 if (isset ($_REQUEST['hl_port_id']))
1555 {
1556 assertUIntArg ('hl_port_id');
1557 $hl_port_id = intval ($_REQUEST['hl_port_id']);
65e557dd 1558 addAutoScrollScript ("port-$hl_port_id");
00276508 1559 }
65e557dd 1560 switchportInfoJS ($object_id); // load JS code to make portnames interactive
9f75e165 1561 foreach ($object['ports'] as $port)
e673ee24 1562 {
5c717ce5 1563 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : '';
7056988c 1564 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
d0d40671 1565 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>";
e673ee24
DO
1566 printImageHREF ('delete', 'Unlink and Delete this port');
1567 echo "</a></td>\n";
65e557dd 1568 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
a4b6536a 1569 echo "<td class='tdleft' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=8></td>";
cd3775e9 1570 echo "<td><input type=text name=label value='${port['label']}'></td>";
68dc69cc
AA
1571 echo '<td class=tdleft>';
1572 if (count ($port['links']) <= 1)
611170af 1573 {
3153a326
DO
1574 if ($port['iif_id'] != 1)
1575 echo '<label>' . $port['iif_name'] . ' ';
cd3775e9 1576 printSelect (getExistingPortTypeOptions ($port['id']), array ('name' => 'port_type_id'), $port['oif_id']);
3153a326
DO
1577 if ($port['iif_id'] != 1)
1578 echo '</label>';
611170af
AD
1579 }
1580 else
1581 {
597896f6 1582 echo "<input type=hidden name=port_type_id value='${port['oif_id']}'>";
68dc69cc 1583 echo formatPortIIFOIF ($port);
611170af 1584 }
68dc69cc 1585 echo '</td>';
cd3775e9
DO
1586 // 18 is enough to fit 6-byte MAC address in its longest form,
1587 // while 24 should be Ok for WWN
1588 echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n";
597896f6
AA
1589 if ($port['linked'])
1590 {
1591 $sep = '';
1592 foreach ($port['links'] as $linkinfo)
a7390942 1593 {
a4b6536a 1594 $trace_link = ($sep == '') ? '&nbsp;' . getPopupLink ('traceroute', array ('port' => $port['id']), 'findlink', 'find', '', 'Trace this port') : '';
597896f6
AA
1595 echo $sep;
1596 $sep = '<td>' . getImageHREF ('save', 'Save changes', TRUE) . "</td></form></tr>\n";
1597 $sep .= getOpFormIntro ('editPort', array ('port_id' => $port['id'], 'name' => $port['name'], 'link_id' => $linkinfo['link_id']));
1598 $sep .= "<tr $tr_class><td colspan=4>&nbsp;</td><td class=tdleft>";
1599
1600 echo "<input type=hidden name=reservation_comment value=''>";
1601 echo "<input type=hidden name=link_id value='".$linkinfo['link_id']."'>";
1602 echo '<td class=tdleft>'.formatLoggedSpan ($port['last_log'], formatPortLink ($linkinfo['remote_object_id'], $linkinfo['remote_object_name'], $linkinfo['remote_id'], NULL)).'</td>';
a4b6536a 1603 echo '<td class=tdleft>'.formatLoggedSpan ($port['last_log'], $linkinfo['remote_name'], 'underline').$trace_link.'</td>';
597896f6
AA
1604 echo "<td><input type=text name=cable value='".$linkinfo['cableid']."'></td>";
1605 echo '<td class=tdcenter>';
1606 echo getPopupLink ('portlist', array ('port' => $port['id'], 'in_rack' => 'on'), 'findlink', 'plug', '', 'Link this port');
1607 echo '<span style="margin-left: 2em">';
1608 echo getOpLink (array ('op'=>'unlinkPort', 'link_id'=>$linkinfo['link_id'], 'object_id'=>$object_id), '', 'cut', 'Unlink this port');
1609 echo '</span></td>';
a7390942 1610 }
e673ee24 1611 }
59a83bd8 1612 elseif (strlen ($port['reservation_comment']))
e673ee24 1613 {
a7390942 1614 echo "<td class=tdleft>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>";
e673ee24 1615 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
318c48a8 1616 echo "<td></td>";
10f5133a
AA
1617 echo "<td class=tdcenter>";
1618 echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port');
1619 echo "</td>";
e673ee24
DO
1620 }
1621 else
1622 {
6b1ca530 1623 $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX');
318c48a8 1624 echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter><span";
cd3775e9
DO
1625 $helper_args = array
1626 (
1627 'port' => $port['id'],
6b1ca530 1628 'in_rack' => ($in_rack == "yes" ? "on" : "")
cd3775e9
DO
1629 );
1630 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
9e214652 1631 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
cd3775e9 1632 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
a7390942 1633 echo "\",\"findlink\",\"${popup_args}\");'>";
5ccd99a0 1634 printImageHREF ('plug', 'Link this port');
a7390942
AD
1635 echo "</span>&nbsp;<input type=text name=reservation_comment></td>\n";
1636 }
597896f6
AA
1637
1638 echo '<td>';
1639 printImageHREF ('save', 'Save changes', TRUE);
1640 echo "</td></form></tr>\n";
e673ee24 1641 }
39b4abd0 1642 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
3153a326 1643 printNewItemTR ($prefs);
e673ee24 1644 echo "</table><br>\n";
a1fc539a
RF
1645 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1646 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1647 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>";
1648 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
dec748f6 1649 printOpFormIntro ('addBulkPorts');
a1fc539a
RF
1650 echo "<tr><td>";
1651 printImageHREF ('add', 'add ports', TRUE);
1652 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1653 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1654 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1655 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1656 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1657 echo "<td>&nbsp;</td><td>";
1658 printImageHREF ('add', 'add ports', TRUE, 110);
1659 echo "</td></tr></form>";
1660 echo "</table><br>\n";
1661 }
597896f6
AA
1662 finishPortlet();
1663
f44fdef9
DO
1664 if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes')
1665 return;
e673ee24
DO
1666
1667 startPortlet ('Add/update multiple ports');
7056988c 1668 printOpFormIntro ('addMultiPorts');
f7a3c94a 1669 echo 'Format: <select name=format tabindex=201>';
e673ee24
DO
1670 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1671 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
e673ee24 1672 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
351d4dbf 1673 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
e673ee24
DO
1674 echo "</select>";
1675 echo 'Default port type: ';
cd3775e9 1676 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type', 'tabindex' => 202), $prefs['selected']);
f7a3c94a
DO
1677 echo "<input type=submit value='Parse output' tabindex=204><br>\n";
1678 echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
e673ee24
DO
1679 echo '</form>';
1680 finishPortlet();
1681}
1682
4318ced5 1683function renderIPForObject ($object_id)
e673ee24 1684{
4318ced5 1685 function printNewItemTR ($default_type)
21ee3351
AA
1686 {
1687 global $aat;
4318ced5
AA
1688 printOpFormIntro ('add');
1689 echo "<tr><td>"; // left btn
dec748f6 1690 printImageHREF ('add', 'allocate', TRUE);
21ee3351 1691 echo "</td>";
4318ced5
AA
1692 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n"; // if-name
1693 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n"; // IP
1694 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1695 echo "<td colspan=2>&nbsp;</td>"; // network, routed by
1696 echo '<td>';
1697 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), $default_type); // type
1698 echo "</td><td>&nbsp;</td><td>"; // misc
1699 printImageHREF ('add', 'allocate', TRUE, 103); // right btn
21ee3351
AA
1700 echo "</td></tr></form>";
1701 }
21ee3351
AA
1702 global $aat;
1703 startPortlet ('Allocations');
4318ced5
AA
1704 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1705 echo '<th>&nbsp;</th>';
1706 echo '<th>OS interface</th>';
1707 echo '<th>IP address</th>';
21ee3351 1708 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
4318ced5
AA
1709 {
1710 echo '<th>network</th>';
1711 echo '<th>routed by</th>';
1712 }
1713 echo '<th>type</th>';
1714 echo '<th>misc</th>';
1715 echo '<th>&nbsp</th>';
1716 echo '</tr>';
21ee3351 1717
710ead7e
AA
1718 $alloc_list = ''; // most of the output is stored here
1719 $used_alloc_types = array();
4318ced5 1720 foreach (getObjectIPAllocations ($object_id) as $alloc)
21ee3351 1721 {
710ead7e
AA
1722 if (! isset ($used_alloc_types[$alloc['type']]))
1723 $used_alloc_types[$alloc['type']] = 0;
1724 $used_alloc_types[$alloc['type']]++;
1725
40c9fc94 1726 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
4318ced5 1727 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
710ead7e 1728 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
f3505b35 1729
10f5133a 1730 $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>";
40c9fc94 1731 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
710ead7e 1732 $alloc_list .= $rendered_alloc['td_ip'];
21ee3351
AA
1733 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1734 {
710ead7e
AA
1735 $alloc_list .= $rendered_alloc['td_network'];
1736 $alloc_list .= $rendered_alloc['td_routed_by'];
21ee3351 1737 }
710ead7e
AA
1738 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1739 $alloc_list .= $rendered_alloc['td_peers'];
1740 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
f3505b35 1741
710ead7e 1742 $alloc_list .= "</form></tr>\n";
21ee3351 1743 }
710ead7e 1744 asort ($used_alloc_types, SORT_NUMERIC);
a0a5ce54 1745 $most_popular_type = empty ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types));
710ead7e
AA
1746
1747 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1748 echo $alloc_list;
4318ced5 1749 printNewItemTR ($most_popular_type);
710ead7e
AA
1750 if (! $list_on_top)
1751 echo $alloc_list;
21ee3351
AA
1752
1753 echo "</table><br>\n";
1754 finishPortlet();
f3505b35
AA
1755}
1756
08408472
AA
1757// This function is deprecated. Do not rely on its internals,
1758// it will probably be removed in the next major relese.
1759// Use new showError, showWarning, showSuccess functions.
dec748f6 1760// Log array is stored in global $log_messages. Its format is simple: plain ordered array
8ab645cf 1761// with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1cb6adf5 1762function showMessageOrError ()
e673ee24 1763{
a2b16202
AA
1764 global $log_messages;
1765
1766 @session_start();
1767 if (isset ($_SESSION['log']))
1768 {
1769 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1770 unset ($_SESSION['log']);
1771 }
1772 session_commit();
1773
1774 if (empty ($log_messages))
1cb6adf5 1775 return;
8ab645cf
AA
1776 $msginfo = array
1777 (
dec748f6 1778// records 0~99 with success messages
8ab645cf
AA
1779 0 => array ('code' => 'success', 'format' => '%s'),
1780 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1781 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1782 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1783 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
1784 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1785 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1786 26 => array ('code' => 'success', 'format' => 'updated %u records successfully'),
1787 37 => array ('code' => 'success', 'format' => 'added %u records successfully'),
1788 38 => array ('code' => 'success', 'format' => 'removed %u records successfully'),
8ab645cf
AA
1789 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1790 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1791 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1792 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1793 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1794 57 => array ('code' => 'success', 'format' => 'Reset complete'),
8ab645cf 1795 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
8ab645cf
AA
1796 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1797 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1798 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
8ab645cf
AA
1799 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"),
1800 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'),
8628ae44 1801// records 100~199 with fatal error messages
8ab645cf
AA
1802 100 => array ('code' => 'error', 'format' => '%s'),
1803 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
8ab645cf
AA
1804 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1805 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'),
1806 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1807 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1808 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1809 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1810 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1811 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1812 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1813 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1814 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
8ab645cf
AA
1815 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1816 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1817 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
1818 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"),
1819 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"),
1820 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
f0ff4930 1821
8628ae44 1822// records 200~299 with warnings
8ab645cf
AA
1823 200 => array ('code' => 'warning', 'format' => '%s'),
1824 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
e1add254 1825 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
7587edca 1826 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
57777e4a 1827
24d3182a 1828// records 300~399 with notices
8ab645cf 1829 300 => array ('code' => 'neutral', 'format' => '%s'),
24d3182a 1830
8ab645cf
AA
1831 );
1832 // Handle the arguments. Is there any better way to do it?
a2b16202 1833 foreach ($log_messages as $record)
8ab645cf
AA
1834 {
1835 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1836 {
41152018
AA
1837 $prefix = isset ($record['c']) ? $record['c'] . ': ' : '';
1838 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
8ab645cf
AA
1839 continue;
1840 }
1841 if (isset ($record['a']))
1842 switch (count ($record['a']))
baf37d01 1843 {
8ab645cf
AA
1844 case 1:
1845 $msgtext = sprintf
1846 (
1847 $msginfo[$record['c']]['format'],
1848 $record['a'][0]
1849 );
1850 break;
1851 case 2:
1852 $msgtext = sprintf
1853 (
1854 $msginfo[$record['c']]['format'],
1855 $record['a'][0],
1856 $record['a'][1]
1857 );
1858 break;
1859 case 3:
1860 $msgtext = sprintf
1861 (
1862 $msginfo[$record['c']]['format'],
1863 $record['a'][0],
1864 $record['a'][1],
1865 $record['a'][2]
1866 );
1867 break;
1868 case 4:
1869 default:
1870 $msgtext = sprintf
1871 (
1872 $msginfo[$record['c']]['format'],
1873 $record['a'][0],
1874 $record['a'][1],
1875 $record['a'][2],
1876 $record['a'][3]
1877 );
1878 break;
baf37d01 1879 }
8ab645cf
AA
1880 else
1881 $msgtext = $msginfo[$record['c']]['format'];
1882 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
baf37d01 1883 }
a2b16202 1884 $log_messages = array();
e673ee24
DO
1885}
1886
65e557dd
AA
1887// renders two tables: port link status and learned MAC list
1888function renderPortsInfo($object_id)
1889{
03522bd8
AA
1890 try
1891 {
1892 if (permitted (NULL, NULL, 'get_link_status'))
1893 $linkStatus = queryDevice ($object_id, 'getportstatus');
1894 else
1895 showWarning ("You don't have permission to view ports link status");
1896
1897 if (permitted (NULL, NULL, 'get_mac_list'))
1898 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
1899 else
1900 showWarning ("You don't have permission to view learned MAC list");
1901 }
1902 catch (RTGatewayError $e)
1903 {
1904 showError ($e->getMessage());
1905 return;
1906 }
1907
65e557dd
AA
1908 global $nextorder;
1909 echo "<table width='100%'><tr>";
03522bd8 1910 if (! empty ($linkStatus))
65e557dd 1911 {
03522bd8
AA
1912 echo "<td valign='top' width='50%'>";
1913 startPortlet('Link status');
1914 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>";
1915 $order = 'even';
1916 foreach ($linkStatus as $pn => $link)
65e557dd 1917 {
03522bd8 1918 switch ($link['status'])
65e557dd 1919 {
03522bd8
AA
1920 case 'up':
1921 $img_filename = 'link-up.png';
1922 break;
1923 case 'down':
1924 $img_filename = 'link-down.png';
1925 break;
1926 case 'disabled':
1927 $img_filename = 'link-disabled.png';
1928 break;
1929 default:
1930 $img_filename = '1x1t.gif';
1931 }
9f78501e 1932
03522bd8
AA
1933 echo "<tr class='row_$order'>";
1934 $order = $nextorder[$order];
1935 echo '<td>' . $pn;
1936 echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">';
1937 echo '<td>' . $link['status'];
1938 $info = '';
1939 if (isset ($link['speed']))
1940 $info .= $link['speed'];
1941 if (isset ($link['duplex']))
1942 {
1943 if (! empty ($info))
1944 $info .= ', ';
1945 $info .= $link['duplex'];
65e557dd 1946 }
03522bd8
AA
1947 echo '<td>' . $info;
1948 echo '</tr>';
65e557dd 1949 }
03522bd8
AA
1950 echo "</table></td>";
1951 finishPortlet();
65e557dd
AA
1952 }
1953
65e557dd
AA
1954 if (! empty ($macList))
1955 {
1956 echo "<td valign='top' width='50%'>";
1957 $rendered_macs = '';
1958 $mac_count = 0;
1959 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>";
1960 $order = 'even';
1961 foreach ($macList as $pn => $list)
1962 {
1963 $order = $nextorder[$order];
1964 foreach ($list as $item)
1965 {
1966 ++$mac_count;
1967 $rendered_macs .= "<tr class='row_$order'>";
1968 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'];
1969 $rendered_macs .= '<td>' . $item['vid'];
1970 $rendered_macs .= '<td>' . $pn;
1971 $rendered_macs .= '</tr>';
1972 }
1973 }
1974 $rendered_macs .= "</table></td>";
dec748f6 1975
65e557dd
AA
1976 startPortlet("Learned MACs ($mac_count)");
1977 echo $rendered_macs;
1978 finishPortlet();
1979 }
1980
1981 echo "</td></tr></table>";
1982}
1983
e673ee24 1984/*
51c18782 1985The following conditions must be met:
e673ee24
DO
19861. We can mount onto free atoms only. This means: if any record for an atom
1987already exists in RackSpace, it can't be used for mounting.
19882. We can't unmount from 'W' atoms. Operator should review appropriate comments
1989and either delete them before unmounting or refuse to unmount the object.
1990*/
7e1db771 1991function renderRackSpaceForObject ($object_id)
e673ee24 1992{
e673ee24
DO
1993 // Always process occupied racks plus racks chosen by user. First get racks with
1994 // already allocated rackspace...
51c18782 1995 $workingRacksData = getResidentRacksData ($object_id);
e673ee24 1996 // ...and then add those chosen by user (if any).
2135fd83 1997 if (isset($_REQUEST['rackmulti']))
e673ee24 1998 foreach ($_REQUEST['rackmulti'] as $cand_id)
e673ee24
DO
1999 if (!isset ($workingRacksData[$cand_id]))
2000 {
0cc24e9a 2001 $rackData = spotEntity ('rack', $cand_id);
61a1d996 2002 amplifyCell ($rackData);
e673ee24
DO
2003 $workingRacksData[$cand_id] = $rackData;
2004 }
51690ad4 2005
0a7feebb
AD
2006 // Get a list of all of this object's parents,
2007 // then trim the list to only include parents which are racks
2008 $objectParents = getEntityRelatives('parents', 'object', $object_id);
2009 $parentRacks = array();
2010 foreach ($objectParents as $parentData)
2011 if ($parentData['entity_type'] == 'rack')
2012 $parentRacks[] = $parentData['entity_id'];
2013
e673ee24
DO
2014 // Main layout starts.
2015 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
2016
2017 // Left portlet with rack list.
2018 echo "<td class=pcleft height='1%'>";
2019 startPortlet ('Racks');
a8efc03e 2020 $allRacksData = listCells ('rack');
6d42599c
AA
2021
2022 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
2023 if (! isset ($_REQUEST['show_all_racks']) and getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
2024 {
2025 $matching_racks = array();
2026 $object = spotEntity ('object', $object_id);
2027 $matched_tags = array();
2028 foreach ($allRacksData as $rack)
2029 foreach ($object['etags'] as $tag)
2030 if (tagOnChain ($tag, $rack['etags']) or tagOnChain ($tag, $rack['itags']))
2031 {
2032 $matching_racks[$rack['id']] = $rack;
2033 $matched_tags[$tag['id']] = $tag;
2034 break;
2035 }
2036 // add current object's racks even if they dont match filter
2037 foreach ($workingRacksData as $rack_id => $rack)
2038 if (! isset ($matching_racks[$rack_id]))
2039 $matching_racks[$rack_id] = $rack;
2040 // if matching racks found, and rack list is reduced, show 'show all' link
2041 if (count ($matching_racks) and count ($matching_racks) != count ($allRacksData))
2042 {
2043 $filter_text = '';
2044 foreach ($matched_tags as $tag)
2045 $filter_text .= (empty ($filter_text) ? '' : ' or ') . '{' . $tag['tag'] . '}';
2046 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2047 $href_show_all .= htmlspecialchars('&show_all_racks=1');
2048 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
2049 $allRacksData = $matching_racks;
2050 }
2051 }
2052
4b8d413e 2053 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
61a1d996 2054 foreach ($allRacksData as $rack)
51c18782
DO
2055 if (!array_key_exists ($rack['id'], $workingRacksData))
2056 {
2057 amplifyCell ($rack);
2058 $workingRacksData[$rack['id']] = $rack;
2059 }
2060 foreach (array_keys ($workingRacksData) as $rackId)
2061 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
2062 printOpFormIntro ('updateObjectAllocation');
4b8d413e 2063 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
51c18782 2064 echo "<br><br>";
e673ee24
DO
2065 finishPortlet();
2066 echo "</td>";
2067
2068 // Middle portlet with comment and submit.
2069 echo "<td class=pcleft>";
5c8bf2ba 2070 startPortlet ('Comment (for Rackspace History)');
e673ee24
DO
2071 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
2072 echo "<input type=submit value='Save' name=got_atoms>\n";
51c18782 2073 echo "<br><br>";
e673ee24
DO
2074 finishPortlet();
2075 echo "</td>";
2076
2077 // Right portlet with rendered racks. If this form submit is not final, we have to
2078 // reflect the former state of the grid in current form.
2079 echo "<td class=pcright rowspan=2 height='1%'>";
2080 startPortlet ('Working copy');
e8b94513 2081 includeJQueryUI (false);
65e557dd 2082 addJS ('js/racktables.js');
c82023ad 2083 addJS ('js/bulkselector.js');
e673ee24
DO
2084 echo '<table border=0 cellspacing=10 align=center><tr>';
2085 foreach ($workingRacksData as $rack_id => $rackData)
2086 {
2087 // Order is important here: only original allocation is highlighted.
2088 highlightObject ($rackData, $object_id);
2089 markupAtomGrid ($rackData, 'T');
2090 // If we have a form processed, discard user input and show new database
2091 // contents.
51c18782 2092 if (isset ($_REQUEST['rackmulti'][0])) // is an update
e673ee24
DO
2093 mergeGridFormToRack ($rackData);
2094 echo "<td valign=top>";
2095 echo "<center>\n<h2>${rackData['name']}</h2>\n";
e8b94513 2096 echo "<table class=rack id=selectableRack border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 2097 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2098 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2099 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2100 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
e673ee24 2101 renderAtomGrid ($rackData);
57c69e9c 2102 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2103 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2104 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2105 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
0a7feebb
AD
2106 echo "</table>\n<br>\n";
2107 // Determine zero-u checkbox status.
2108 // If form has been submitted, use form data, otherwise use DB data.
dec748f6 2109 if (isset($_REQUEST['op']))
0a7feebb
AD
2110 $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : '';
2111 else
2112 $checked = in_array($rack_id, $parentRacks) ? 'checked' : '';
d141833a 2113 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 2114 echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n";
0a7feebb 2115 echo '</center></td>';
e673ee24
DO
2116 }
2117 echo "</tr></table>";
2118 finishPortlet();
2119 echo "</td>\n";
2120
2121 echo "</form>\n";
2122 echo "</tr></table>\n";
2123}
2124
2125function renderMolecule ($mdata, $object_id)
2126{
2127 // sort data out
2128 $rackpack = array();
2129 global $loclist;
64b95774 2130 foreach ($mdata as $rua)
e673ee24
DO
2131 {
2132 $rack_id = $rua['rack_id'];
2133 $unit_no = $rua['unit_no'];
2134 $atom = $rua['atom'];
2135 if (!isset ($rackpack[$rack_id]))
2136 {
61a1d996
DO
2137 $rackData = spotEntity ('rack', $rack_id);
2138 amplifyCell ($rackData);
e673ee24
DO
2139 for ($i = $rackData['height']; $i > 0; $i--)
2140 for ($locidx = 0; $locidx < 3; $locidx++)
2141 $rackData[$i][$locidx]['state'] = 'F';
2142 $rackpack[$rack_id] = $rackData;
2143 }
2144 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2145 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2146 }
2147 // now we have some racks to render
64b95774 2148 foreach ($rackpack as $rackData)
e673ee24
DO
2149 {
2150 markAllSpans ($rackData);
2151 echo "<table class=molecule cellspacing=0>\n";
2152 echo "<caption>${rackData['name']}</caption>\n";
2153 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
2154 for ($i = $rackData['height']; $i > 0; $i--)
2155 {
4dcd770e 2156 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
e673ee24
DO
2157 for ($locidx = 0; $locidx < 3; $locidx++)
2158 {
2159 $state = $rackData[$i][$locidx]['state'];
65e557dd 2160 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
e673ee24
DO
2161 }
2162 echo "</tr>\n";
2163 }
2164 echo "</table>\n";
2165 }
2166}
2167
23cdc7e9 2168function renderDepot ()
e673ee24 2169{
23cdc7e9 2170 global $pageno, $nextorder;
23cdc7e9
DO
2171 $cellfilter = getCellFilter();
2172 $objects = filterCellList (listCells ('object'), $cellfilter['expression']);
2173
2174 echo "<table border=0 class=objectview>\n";
2175 echo "<tr><td class=pcleft>";
2176
1ebbf889 2177 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
e673ee24 2178 {
4899096d 2179 if (count($objects) > 0)
1ebbf889 2180 {
4899096d
AD
2181 startPortlet ('Objects (' . count ($objects) . ')');
2182 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
b09a8280 2183 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
4899096d 2184 $order = 'odd';
3f8a25d6
DO
2185 # gather IDs of all objects and fetch rackspace info in one pass
2186 $idlist = array();
2187 foreach ($objects as $obj)
2188 $idlist[] = $obj['id'];
2189 $mountinfo = getMountInfo ($idlist);
4899096d
AD
2190 foreach ($objects as $obj)
2191 {
ad3e5e7e 2192 echo "<tr class='row_${order} tdleft' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
4899096d
AD
2193 if (count ($obj['etags']))
2194 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
4318ced5
AA
2195 echo "</td><td>${obj['label']}</td>";
2196 echo "<td>${obj['asset_no']}</td>";
3f8a25d6 2197 $places = array();
b09a8280 2198 if ($obj['container_id'])
86dad907 2199 $places[] = mkA ($obj['container_dname'], 'object', $obj['container_id']);
b09a8280 2200 elseif (! array_key_exists ($obj['id'], $mountinfo))
3f8a25d6 2201 $places[] = 'Unmounted';
4899096d 2202 else
3f8a25d6
DO
2203 foreach ($mountinfo[$obj['id']] as $mi)
2204 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
4318ced5 2205 echo "<td>" . implode (', ', $places) . '</td>';
4899096d
AD
2206 echo '</tr>';
2207 $order = $nextorder[$order];
2208 }
2209 echo '</table>';
2210 finishPortlet();
1ebbf889 2211 }
4899096d
AD
2212 else
2213 echo '<h2>No objects exist</h2>';
e673ee24 2214 }
23cdc7e9
DO
2215
2216 echo "</td><td class=pcright width='25%'>";
2217
95857b5c 2218 renderCellFilterPortlet ($cellfilter, 'object', $objects);
23cdc7e9 2219 echo "</td></tr></table>\n";
e673ee24
DO
2220}
2221
1ebbf889
AA
2222// This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2223// In this case it renders the describing message instead.
2224function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2225{
2226 if (!$cellfilter['is_empty'])
2227 return FALSE;
2228 if (isset ($_REQUEST['show_all_objects']))
2229 return FALSE;
2230 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2231 if (0 == $max || $count <= $max)
2232 return FALSE;
2233
2234 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2235 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2236 $suffix = isset ($count) ? " ($count)" : '';
2237 echo <<<END
2238<p>Please set a filter to display the corresponging $entities_name.
2239<br><a href="$href_show_all">Show all $entities_name$suffix</a>
2240END;
2241 return TRUE;
2242}
2243
e673ee24 2244// History viewer for history-enabled simple dictionaries.
9b8174d7 2245function renderObjectHistory ($object_id)
e673ee24 2246{
e673ee24
DO
2247 $order = 'odd';
2248 global $nextorder;
9b8174d7
AD
2249 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2250 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>';
2251 $result = usePreparedSelectBlade
2252 (
2253 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2254 array ($object_id)
2255 );
e673ee24
DO
2256 while ($row = $result->fetch (PDO::FETCH_NUM))
2257 {
2258 echo "<tr class=row_${order}><td>${row[0]}</td>";
9b8174d7 2259 for ($i = 1; $i <= 6; $i++)
e673ee24
DO
2260 echo "<td>" . $row[$i] . "</td>";
2261 echo "</tr>\n";
2262 $order = $nextorder[$order];
2263 }
2264 echo "</table><br>\n";
2265}
2266
2267function renderRackspaceHistory ()
2268{
4fbb5a00 2269 global $nextorder, $pageno, $tabno;
e673ee24
DO
2270 $order = 'odd';
2271 $history = getRackspaceHistory();
2272 // Show the last operation by default.
2273 if (isset ($_REQUEST['op_id']))
2274 $op_id = $_REQUEST['op_id'];
2275 elseif (isset ($history[0]['mo_id']))
2276 $op_id = $history[0]['mo_id'];
2277 else $op_id = NULL;
dec748f6 2278
e673ee24
DO
2279 $omid = NULL;
2280 $nmid = NULL;
2281 $object_id = 1;
2282 if ($op_id)
2283 list ($omid, $nmid) = getOperationMolecules ($op_id);
2284
2285 // Main layout starts.
2286 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2287
2288 // Left top portlet with old allocation.
2289 echo "<tr><td class=pcleft>";
2290 startPortlet ('Old allocation');
2291 if ($omid)
2292 {
2293 $oldMolecule = getMolecule ($omid);
2294 renderMolecule ($oldMolecule, $object_id);
2295 }
2296 else
2297 echo "nothing";
2298 finishPortlet();
2299
2300 echo '</td><td class=pcright>';
2301
2302 // Right top portlet with new allocation
2303 startPortlet ('New allocation');
2304 if ($nmid)
2305 {
2306 $newMolecule = getMolecule ($nmid);
2307 renderMolecule ($newMolecule, $object_id);
2308 }
2309 else
2310 echo "nothing";
2311 finishPortlet();
737a3f72 2312
e673ee24 2313 echo '</td></tr><tr><td colspan=2>';
737a3f72 2314
e673ee24
DO
2315 // Bottom portlet with list
2316
2317 startPortlet ('Rackspace allocation history');
2318 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
7fa7047a 2319 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
e673ee24
DO
2320 foreach ($history as $row)
2321 {
2322 if ($row['mo_id'] == $op_id)
2323 $class = 'hl';
2324 else
2325 $class = "row_${order}";
4fbb5a00 2326 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
7fa7047a
DO
2327 echo "<td>${row['user_name']}</td><td>";
2328 renderCell (spotEntity ('object', $row['ro_id']));
9c6222ef 2329 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
e673ee24
DO
2330 $order = $nextorder[$order];
2331 }
2332 echo "</table>\n";
2333 finishPortlet();
737a3f72 2334
e673ee24 2335 echo '</td></tr></table>';
e673ee24
DO
2336}
2337
4318ced5 2338function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
d65353ad
DO
2339{
2340 $self = __FUNCTION__;
4318ced5 2341 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
00276508
AA
2342
2343 // scroll page to the highlighted item
2344 if ($target && isset ($_REQUEST['hl_net']))
65e557dd 2345 addAutoScrollScript ("net-$target");
00276508 2346
d65353ad
DO
2347 foreach ($tree as $item)
2348 {
4318ced5
AA
2349 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'))
2350 loadIPAddrList ($item); // necessary to compute router list and address counter
2351
0137d53c
DO
2352 if (isset ($item['id']))
2353 {
1f54e1ba 2354 $decor = array ('indent' => $level);
fec0c8da 2355 if ($item['symbol'] == 'node-collapsed')
4318ced5 2356 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
fec0c8da 2357 elseif ($item['symbol'] == 'node-expanded')
4318ced5
AA
2358 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
2359 $tr_class = '';
21ee3351 2360 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
64347dcf 2361 {
5c717ce5 2362 $decor['tdclass'] = ' highlight';
4318ced5 2363 $tr_class = $decor['tdclass'];
64347dcf 2364 }
4318ced5
AA
2365 echo "<tr valign=top class=\"$tr_class\">";
2366 printIPNetInfoTDs ($item, $decor);
2367
2368 // capacity and usage
2369 echo "<td class=tdcenter>";
2370 echo getRenderedIPNetCapacity ($item);
64347dcf 2371 echo "</td>";
4318ced5
AA
2372
2373 if ($display_routers)
efd8057e 2374 printRoutersTD (findRouters ($item['own_addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
0137d53c 2375 echo "</tr>";
fec0c8da 2376 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
4318ced5 2377 $self ($item['kids'], $baseurl, $target, $level + 1);
0137d53c
DO
2378 }
2379 else
2380 {
4318ced5 2381 // non-allocated (spare) IP range
0137d53c 2382 echo "<tr valign=top>";
21ee3351 2383 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
00276508 2384
4318ced5 2385 // capacity and usage
21ee3351 2386 echo "<td class=tdcenter>";
4318ced5 2387 echo getRenderedIPNetCapacity ($item);
21ee3351 2388 echo "</td>";
4318ced5
AA
2389 if ($display_routers)
2390 echo "<td></td>";
21ee3351 2391 echo "</tr>";
21ee3351 2392 }
21ee3351
AA
2393 }
2394}
2395
4318ced5 2396function renderIPSpace()
e673ee24 2397{
4fbb5a00 2398 global $pageno, $tabno;
4318ced5 2399 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
31c941ec 2400 $cellfilter = getCellFilter();
4318ced5
AA
2401 $top = NULL;
2402 $netlist = array();
2403 foreach (listCells ($realm) as $net)
2404 {
2405 if (isset ($top) and IPNetContains ($top, $net))
2406 ;
2407 elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression']))
2408 $top = $net;
1ebbf889 2409 else
4318ced5
AA
2410 continue;
2411 $netlist[$net['id']] = $net;
5388794d 2412 }
21ee3351
AA
2413 $netcount = count ($netlist);
2414 // expand request can take either natural values or "ALL". Zero means no expanding.
2415 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
4318ced5 2416 $tree = prepareIPTree ($netlist, $eid);
21ee3351
AA
2417
2418 echo "<table border=0 class=objectview>\n";
2419 echo "<tr><td class=pcleft>";
4318ced5 2420 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
21ee3351
AA
2421 {
2422 startPortlet ("networks (${netcount})");
2423 echo '<h4>';
4318ced5
AA
2424 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2425 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2426 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2427 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2428 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2429 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2430
21ee3351 2431 if ($eid === 0)
4318ced5 2432 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
21ee3351 2433 elseif ($eid === 'ALL')
4318ced5
AA
2434 echo "expanding all ($auto / $none)";
2435 elseif ($eid === 'NONE')
2436 echo "collapsing all ($all / $auto)";
21ee3351
AA
2437 else
2438 {
4318ced5
AA
2439 $netinfo = spotEntity ($realm, $eid);
2440 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
21ee3351
AA
2441 }
2442 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2443 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
4318ced5 2444 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
21ee3351
AA
2445 echo "<th>routed by</th>";
2446 echo "</tr>\n";
2447 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
4318ced5 2448 renderIPSpaceRecords ($tree, $baseurl, $eid);
21ee3351
AA
2449 echo "</table>\n";
2450 finishPortlet();
2451 }
2452
2453 echo '</td><td class=pcright>';
4318ced5 2454 renderCellFilterPortlet ($cellfilter, 'ipv4net', $netlist);
21ee3351
AA
2455 echo "</td></tr></table>\n";
2456}
2457
4318ced5 2458function renderIPSpaceEditor()
21ee3351 2459{
4318ced5
AA
2460 global $pageno;
2461 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2462 $net_page = $realm; // 'ipv4net', 'ipv6net'
2463 $addrspaceList = listCells ($realm);
93a49e5b
AA
2464 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2465 if (count ($addrspaceList))
21ee3351 2466 {
21ee3351
AA
2467 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2468 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
21ee3351
AA
2469 foreach ($addrspaceList as $netinfo)
2470 {
21ee3351 2471 echo "<tr valign=top><td>";
93a49e5b 2472 if (! isIPNetworkEmpty ($netinfo))
21ee3351
AA
2473 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2474 else
93a49e5b 2475 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
ad3e5e7e 2476 echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>';
1f54e1ba
DO
2477 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2478 if (count ($netinfo['etags']))
2479 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2480 echo '</td><td>';
4318ced5 2481 echo getRenderedIPNetCapacity ($netinfo);
b1e39212 2482 echo '</tr>';
e673ee24 2483 }
04d619d0
DO
2484 echo "</table>";
2485 finishPortlet();
e673ee24 2486 }
93a49e5b
AA
2487}
2488
2489function renderIPNewNetForm ()
2490{
2491 global $pageno;
2492 if ($pageno == 'ipv6space')
2493 {
2494 $realm = 'ipv6net';
3495ec6e 2495 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
93a49e5b
AA
2496 }
2497 else
2498 {
2499 $realm = 'ipv4net';
3495ec6e 2500 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
93a49e5b
AA
2501 }
2502
2503 // IP prefix validator
10f5133a 2504 addJS ('js/live_validation.js');
93a49e5b 2505 $regexp = addslashes ($regexp);
10f5133a 2506 addJS (<<<END
93a49e5b 2507$(document).ready(function () {
10f5133a 2508 $('form#add' input[name="range"]).attr('match', '$regexp');
93a49e5b
AA
2509 Validate.init();
2510});
2511END
2512 , TRUE);
dec748f6 2513
93a49e5b
AA
2514 startPortlet ('Add new');
2515 echo '<table border=0 cellpadding=10 align=center>';
10f5133a 2516 printOpFormIntro ('add');
93a49e5b
AA
2517 // tags column
2518 echo '<tr><td rowspan=5><h3>assign tags</h3>';
2519 renderNewEntityTags ($realm);
2520 echo '</td>';
2521 // inputs column
2522 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
2523 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>";
2524 echo '<tr><th class=tdright>VLAN</th><td class=tdleft>';
2525 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical', 'tabindex' => 2)) . '</td></tr>';
2526 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=3></td></tr>";
9a3f2f34
DO
2527 echo '<tr><td class=tdright><input type=checkbox name="is_connected" id="is_connected" tabindex=4></td>';
2528 echo '<th class=tdleft><label for="is_connected">reserve subnet-router anycast address</label></th></tr>';
93a49e5b
AA
2529 echo "<tr><td colspan=2>";
2530 printImageHREF ('CREATE', 'Add a new network', TRUE, 5);
2531 echo '</td></tr>';
2532 echo "</form></table><br><br>\n";
2533 finishPortlet();
e673ee24
DO
2534}
2535
4318ced5 2536function getRenderedIPNetBacktrace ($range)
e673ee24 2537{
4318ced5
AA
2538 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2539 return array();
e673ee24 2540
4318ced5
AA
2541 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2542 $space = "ipv${v}space"; // ipv4space, ipv6space
2543 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
dec748f6 2544
4318ced5
AA
2545 $ret = array();
2546 // Build a backtrace from all parent networks.
2547 $clen = $range['mask'];
2548 $backtrace = array();
2549 $backtrace['&rarr;'] = $range;
2550 $key = '';
2551 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2552 {
2553 $upperinfo = spotEntity ($range['realm'], $upperid);
2554 $clen = $upperinfo['mask'];
2555 $key .= '&uarr;';
2556 $backtrace[$key] = $upperinfo;
2557 }
2558 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2559 {
2560 $link = '<a href="' . makeHref (array (
2561 'page' => $space,
2562 'tab' => 'default',
2563 'clear-cf' => '',
2564 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2565 'hl_net' => 1,
2566 'eid' => $range['id'],
2567 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2568 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2569 }
2570 return $ret;
2571}
2572
2573function renderIPNetwork ($id)
2574{
2575 global $pageno;
2576 $realm = $pageno; // 'ipv4net', 'ipv6net'
2577 $range = spotEntity ($realm, $id);
2578 loadIPAddrList ($range);
2034d968 2579 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
99ab184f
DO
2580 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2581 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2034d968
DO
2582
2583 echo "<tr><td class=pcleft width='50%'>";
646272be
AA
2584
2585 // render summary portlet
2586 $summary = array();
4318ced5 2587 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2b6b0038 2588 $summary = getRenderedIPNetBacktrace ($range) + $summary;
4318ced5 2589 if ($realm == 'ipv4net')
001e61fa 2590 {
4318ced5
AA
2591 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2592 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2593 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
001e61fa 2594 }
dec748f6 2595
11e3af31
DO
2596 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2597 $domainclass = array();
2598 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2599 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
a5f9d1ca 2600 foreach ($range['8021q'] as $item)
11e3af31 2601 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVLANInfo ($item['domain_id'] . '-' . $item['vlan_id'])));
3a4f4023 2602 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findRouters ($range['addrlist'])))
04d619d0 2603 {
646272be
AA
2604 $summary['Routed by'] = '';
2605 foreach ($routers as $rtr)
4318ced5 2606 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
04d619d0 2607 }
646272be
AA
2608 $summary['tags'] = '';
2609 renderEntitySummary ($range, 'summary', $summary);
e1ae3fb4 2610
99ab184f
DO
2611 if (strlen ($range['comment']))
2612 {
2613 startPortlet ('Comment');
2614 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2615 finishPortlet ();
2616 }
2617
4318ced5 2618 renderFilesPortlet ($realm, $id);
2034d968 2619 echo "</td>\n";
e673ee24 2620
2034d968
DO
2621 echo "<td class=pcright>";
2622 startPortlet ('details');
4318ced5
AA
2623 renderIPNetworkAddresses ($range);
2624 finishPortlet();
2625 echo "</td></tr></table>\n";
2626}
e673ee24 2627
4318ced5
AA
2628// Used solely by renderSeparator
2629function renderEmptyIPv6 ($ip_bin, $hl_ip)
2630{
2631 $class = 'tdleft';
2632 if ($ip_bin === $hl_ip)
5c717ce5 2633 $class .= ' highlight';
4318ced5
AA
2634 $fmt = ip6_format ($ip_bin);
2635 echo "<tr class='$class'><td><a class='ancor' name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
0b8d8309
AA
2636 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2637 ? 'editable'
2638 : '';
cc2fa820
AD
2639 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2640 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
4318ced5
AA
2641}
2642
2643// Renders empty table line to shrink empty IPv6 address ranges.
2644// If the range consists of single address, renders the address instead of empty line.
2645// Renders address $hl_ip inside the range.
2646// Used solely by renderIPv6NetworkAddresses
2647function renderSeparator ($first, $last, $hl_ip)
2648{
2649 $self = __FUNCTION__;
2650 if (strcmp ($first, $last) > 0)
2651 return;
2652 if ($first == $last)
2653 renderEmptyIPv6 ($first, $hl_ip);
2654 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2655 { // $hl_ip is inside the range $first - $last
2656 $self ($first, ip_prev ($hl_ip), $hl_ip);
2657 renderEmptyIPv6 ($hl_ip, $hl_ip);
2658 $self (ip_next ($hl_ip), $last, $hl_ip);
2659 }
2660 else
cc2fa820 2661 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
4318ced5
AA
2662}
2663
2664// calculates page number which contains given $ip (used by renderIPv6NetworkAddresses)
2665function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2666{
2667 if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage)
2668 return 0;
2669 $keys = array_keys ($list);
2670 for ($i = 1; $i <= count ($keys); $i++)
2671 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2672 return intval ($i / $maxperpage);
2673 return intval (count ($list) / $maxperpage);
2674}
2675
2676function renderIPNetworkAddresses ($range)
2677{
2678 switch (strlen ($range['ip_bin']))
2679 {
2680 case 4: return renderIPv4NetworkAddresses ($range);
2681 case 16: return renderIPv6NetworkAddresses ($range);
2682 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2683 }
2684}
2685
2686function renderIPv4NetworkAddresses ($range)
2687{
2688 global $pageno, $tabno, $aac2;
2689 $startip = ip4_bin2int ($range['ip_bin']);
2690 $endip = ip4_bin2int (ip_last ($range));
2691
2692 if (isset ($_REQUEST['hl_ip']))
00276508 2693 {
4318ced5
AA
2694 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2695 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
00276508
AA
2696 }
2697
79b57b18
AA
2698 // pager
2699 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2700 $address_count = $endip - $startip + 1;
2701 $page = 0;
446c25c3 2702 $rendered_pager = '';
79b57b18
AA
2703 if ($address_count > $maxperpage && $maxperpage > 0)
2704 {
2705 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2706 if ($numpages = ceil ($address_count / $maxperpage))
2707 {
4318ced5 2708 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
79b57b18
AA
2709 for ($i = 0; $i < $numpages; $i++)
2710 if ($i == $page)
446c25c3 2711 $rendered_pager .= "<b>$i</b> ";
79b57b18 2712 else
4318ced5 2713 $rendered_pager .= "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $range['id'], 'pg' => $i)) . "'>$i</a> ";
79b57b18
AA
2714 }
2715 $startip = $startip + $page * $maxperpage;
2716 $endip = min ($startip + $maxperpage - 1, $endip);
2717 }
2718
446c25c3 2719 echo $rendered_pager;
beb9e88a 2720 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2721 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
e673ee24 2722
4318ced5
AA
2723 markupIPAddrList ($range['addrlist']);
2724 for ($ip = $startip; $ip <= $endip; $ip++)
2725 {
2726 $ip_bin = ip4_int2bin ($ip);
2727 $dottedquad = ip4_format ($ip_bin);
5c717ce5 2728 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
0cd7c0f6
AA
2729 if (isset ($range['addrlist'][$ip_bin]))
2730 $addr = $range['addrlist'][$ip_bin];
2731 else
e673ee24 2732 {
4318ced5 2733 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
2734 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2735 ? 'editable'
2736 : '';
cc2fa820
AD
2737 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
2738 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
b2035dca
DO
2739 continue;
2740 }
68c91b9c
AA
2741 // render IP change history
2742 $title = '';
2743 $history_class = '';
2744 if (isset ($addr['last_log']))
2745 {
2746 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2747 $history_class = 'hover-history underline';
2748 }
4318ced5
AA
2749 $tr_class .= ' ' . $addr['class'];
2750 echo "<tr class='tdleft $tr_class'>";
2751 echo "<td><a class='ancor $history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
0b8d8309 2752 $editable =
cc2fa820 2753 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
0b8d8309
AA
2754 && permitted ('ipaddress', 'properties', 'editAddress')
2755 ? 'editable'
2756 : '';
cc2fa820
AD
2757 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
2758 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
0b8d8309 2759 echo "<td>";
b2035dca 2760 $delim = '';
b2035dca
DO
2761 if ( $addr['reserved'] == 'yes')
2762 {
2d318652 2763 echo "<strong>RESERVED</strong> ";
b2035dca
DO
2764 $delim = '; ';
2765 }
212b565a 2766 foreach ($addr['allocs'] as $ref)
b2035dca 2767 {
beb9e88a 2768 echo $delim . $aac2[$ref['type']];
4318ced5 2769 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
59a83bd8 2770 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
b2035dca
DO
2771 echo "${ref['object_name']}</a>";
2772 $delim = '; ';
2773 }
2774 if ($delim != '')
e0d6e38e 2775 $delim = '<br>';
212b565a
AA
2776 foreach ($addr['vslist'] as $vs_id)
2777 {
2778 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2779 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
212b565a
AA
2780 $delim = '<br>';
2781 }
eacc0983
AA
2782 foreach ($addr['vsglist'] as $vs_id)
2783 {
2784 $vs = spotEntity ('ipvs', $vs_id);
2785 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
2786 $delim = '<br>';
2787 }
212b565a
AA
2788 foreach ($addr['rsplist'] as $rsp_id)
2789 {
2790 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2791 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
212b565a
AA
2792 $delim = '<br>';
2793 }
b2035dca 2794 echo "</td></tr>\n";
4318ced5 2795 }
2727c7df 2796 // end of iteration
a8dc2982
AA
2797 if (permitted (NULL, NULL, 'set_reserve_comment'))
2798 addJS ('js/inplace-edit.js');
e673ee24
DO
2799
2800 echo "</table>";
446c25c3
AA
2801 if (! empty ($rendered_pager))
2802 echo '<p>' . $rendered_pager . '</p>';
21ee3351
AA
2803}
2804
2805function renderIPv6NetworkAddresses ($netinfo)
2806{
2807 global $pageno, $tabno, $aac2;
2808 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2809 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
21ee3351 2810
4318ced5
AA
2811 $hl_ip = NULL;
2812 if (isset ($_REQUEST['hl_ip']))
2813 {
2814 $hl_ip = ip6_parse ($_REQUEST['hl_ip']);
2815 addAutoScrollScript ('ip-' . ip6_format ($hl_ip));
2816 }
21ee3351 2817
21ee3351
AA
2818 $addresses = $netinfo['addrlist'];
2819 ksort ($addresses);
4318ced5 2820 markupIPAddrList ($addresses);
21ee3351
AA
2821
2822 // pager
2823 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2824 if (count ($addresses) > $maxperpage && $maxperpage > 0)
2825 {
2826 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0);
2827 $numpages = ceil (count ($addresses) / $maxperpage);
2828 echo "<center><h3>$numpages pages:</h3>";
2829 for ($i=0; $i<$numpages; $i++)
2830 {
2831 if ($i == $page)
2832 echo "<b>$i</b> ";
2833 else
2834 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> ";
2835 }
2836 echo "</center>";
2837 }
2838
2839 $i = 0;
dec748f6 2840 $interruped = FALSE;
4318ced5
AA
2841 $prev_ip = ip_prev ($netinfo['ip_bin']);
2842 foreach ($addresses as $ip_bin => $addr)
21ee3351
AA
2843 {
2844 if (isset ($page))
2845 {
2846 ++$i;
2847 if ($i <= $maxperpage * $page)
2848 continue;
2849 elseif ($i > $maxperpage * ($page + 1))
2850 {
2851 $interruped = TRUE;
2852 break;
2853 }
2854 }
2855
4318ced5
AA
2856 if ($ip_bin != ip_next ($prev_ip))
2857 renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip);
2858 $prev_ip = $ip_bin;
2859
2860 // render IP change history
2861 $title = '';
2862 $history_class = '';
2863 if (isset ($addr['last_log']))
2864 {
2865 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2866 $history_class = 'hover-history underline';
2867 }
2868
5c717ce5 2869 $tr_class = $addr['class'] . ' tdleft' . ($hl_ip === $ip_bin ? ' highlight' : '');
4318ced5
AA
2870 echo "<tr class='$tr_class'>";
2871 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
2872 $editable =
2873 (empty ($addr['allocs']) || !empty ($addr['name'])
2874 && permitted ('ipaddress', 'properties', 'editAddress')
2875 ? 'editable'
2876 : '');
cc2fa820
AD
2877 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-name'>${addr['name']}</span></td>";
2878 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-comment'>${addr['comment']}</span></td><td>";
21ee3351 2879 $delim = '';
21ee3351
AA
2880 if ( $addr['reserved'] == 'yes')
2881 {
2882 echo "<strong>RESERVED</strong> ";
2883 $delim = '; ';
2884 }
2885 foreach ($addr['allocs'] as $ref)
2886 {
2887 echo $delim . $aac2[$ref['type']];
71066ef1 2888 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
21ee3351
AA
2889 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
2890 echo "${ref['object_name']}</a>";
2891 $delim = '; ';
2892 }
2893 if ($delim != '')
71066ef1
AA
2894 $delim = '<br>';
2895 foreach ($addr['vslist'] as $vs_id)
2896 {
2897 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2898 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
71066ef1
AA
2899 $delim = '<br>';
2900 }
eacc0983
AA
2901 foreach ($addr['vsglist'] as $vs_id)
2902 {
2903 $vs = spotEntity ('ipvs', $vs_id);
2904 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
2905 $delim = '<br>';
2906 }
71066ef1 2907 foreach ($addr['rsplist'] as $rsp_id)
21ee3351 2908 {
71066ef1 2909 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2910 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
71066ef1 2911 $delim = '<br>';
21ee3351
AA
2912 }
2913 echo "</td></tr>\n";
2914 }
2915 if (! $interruped)
4318ced5 2916 renderSeparator (ip_next ($prev_ip), ip_last ($netinfo), $hl_ip);
21ee3351
AA
2917 if (isset ($page))
2918 { // bottom pager
2919 echo "<tr><td colspan=3>";
2920 if ($page > 0)
2921 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page - 1)) . "'><< prev</a> ";
2922 if ($page < $numpages - 1)
2923 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page + 1)) . "'>next >></a> ";
2924 echo "</td></tr>";
2925 }
2926 echo "</table>";
a8dc2982
AA
2927 if (permitted (NULL, NULL, 'set_reserve_comment'))
2928 addJS ('js/inplace-edit.js');
21ee3351
AA
2929}
2930
2931function renderIPNetworkProperties ($id)
e673ee24 2932{
21ee3351
AA
2933 global $pageno;
2934 $netdata = spotEntity ($pageno, $id);
53ef3908 2935 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
e673ee24 2936 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 2937 printOpFormIntro ('editRange');
99ab184f
DO
2938 echo '<tr><td class=tdright><label for=nameinput>Name:</label></td>';
2939 echo "<td class=tdleft><input type=text name=name id=nameinput size=80 maxlength=255 value='";
2940 echo htmlspecialchars ($netdata['name'], ENT_QUOTES, 'UTF-8') . "'></tr>";
2941 echo '<tr><td class=tdright><label for=commentinput>Comment:</label></td>';
2942 echo "<td class=tdleft><textarea name=comment id=commentinput cols=80 rows=25>\n";
2943 echo htmlspecialchars ($netdata['comment'], ENT_QUOTES, 'UTF-8') . "</textarea></tr>";
53ef3908
DO
2944 echo "<tr><td colspan=2 class=tdcenter>";
2945 printImageHREF ('SAVE', 'Save changes', TRUE);
2946 echo "</td></form></tr></table>\n";
93a49e5b
AA
2947
2948 echo '<center>';
2949 if (! isIPNetworkEmpty ($netdata))
2950 echo getOpLink (NULL, 'delete this prefix', 'nodestroy', 'There are ' . count ($netdata['addrlist']) . ' allocations inside');
2951 else
2952 echo getOpLink (array('op'=>'del','id'=>$id), 'delete this prefix', 'destroy');
2953 echo '</center>';
e673ee24
DO
2954}
2955
09a531eb 2956function renderIPAddress ($ip_bin)
e673ee24 2957{
46098972 2958 global $aat, $nextorder;
09a531eb 2959 $address = getIPAddress ($ip_bin);
68225375 2960 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
21ee3351 2961 echo "<tr><td colspan=2 align=center><h1>${address['ip']}</h1></td></tr>\n";
e673ee24 2962
68225375 2963 echo "<tr><td class=pcleft>";
dec748f6 2964
defd92d8 2965 $summary = array();
423c4216 2966 if (strlen ($address['name']))
cc2fa820
AD
2967 $summary['Name'] = $address['name'];
2968 if (strlen ($address['comment']))
2969 $summary['Comment'] = $address['comment'];
defd92d8
AA
2970 $summary['Reserved'] = $address['reserved'];
2971 $summary['Allocations'] = count ($address['allocs']);
4318ced5 2972 if (isset ($address['outpf']))
defd92d8 2973 $summary['Originated NAT connections'] = count ($address['outpf']);
4318ced5 2974 if (isset ($address['inpf']))
defd92d8 2975 $summary['Arriving NAT connections'] = count ($address['inpf']);
defd92d8 2976 renderEntitySummary ($address, 'summary', $summary);
dec748f6 2977
212b565a 2978 // render SLB portlet
eacc0983 2979 if (! empty ($address['vslist']) or ! empty ($address['vsglist']) or ! empty ($address['rsplist']))
212b565a
AA
2980 {
2981 startPortlet ("");
eacc0983
AA
2982 if (! empty ($address['vsglist']))
2983 {
2984 printf ("<h2>virtual service groups (%d):</h2>", count ($address['vsglist']));
2985 foreach ($address['vsglist'] as $vsg_id)
2986 renderSLBEntityCell (spotEntity ('ipvs', $vsg_id));
2987 }
2988
212b565a
AA
2989 if (! empty ($address['vslist']))
2990 {
2991 printf ("<h2>virtual services (%d):</h2>", count ($address['vslist']));
2992 foreach ($address['vslist'] as $vs_id)
2993 renderSLBEntityCell (spotEntity ('ipv4vs', $vs_id));
2994 }
2995
2996 if (! empty ($address['rsplist']))
2997 {
2998 printf ("<h2>RS pools (%d):</h2>", count ($address['rsplist']));
2999 foreach ($address['rsplist'] as $rsp_id)
3000 renderSLBEntityCell (spotEntity ('ipv4rspool', $rsp_id));
3001 }
3002 finishPortlet();
3003 }
68225375 3004 echo "</td>\n";
e673ee24 3005
68225375 3006 echo "<td class=pcright>";
defd92d8 3007 if (isset ($address['class']) and ! empty ($address['allocs']))
59bebe2b 3008 {
8e700dd1 3009 startPortlet ('allocations');
2d318652
DO
3010 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
3011 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2d318652 3012 // render all allocation records for this address the same way
2d318652 3013 foreach ($address['allocs'] as $bond)
59bebe2b 3014 {
4318ced5 3015 $tr_class = "${address['class']} tdleft";
8e700dd1 3016 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
5c717ce5 3017 $tr_class .= ' highlight';
4318ced5
AA
3018 echo "<tr class='$tr_class'>" .
3019 "<td><a href='" . makeHref (array ('page' => 'object', 'object_id' => $bond['object_id'], 'tab' => 'default', 'hl_ip' => $address['ip'])) . "'>${bond['object_name']}</td>" .
3020 "<td>${bond['name']}</td>" .
3021 "<td><strong>" . $aat[$bond['type']] . "</strong></td>" .
3022 "</tr>\n";
59bebe2b
DO
3023 }
3024 echo "</table><br><br>";
3025 finishPortlet();
3026 }
e673ee24 3027
eacc0983
AA
3028 if (! empty ($address['rsplist']))
3029 {
3030 startPortlet ("RS pools:");
3031 foreach ($address['rsplist'] as $rsp_id)
3032 {
3033 renderSLBEntityCell (spotEntity ('ipv4rspool', $rsp_id));
3034 echo '<br>';
3035 }
3036 finishPortlet();
3037 }
3038
3039 if (! empty ($address['vsglist']))
3040 foreach ($address['vsglist'] as $vsg_id)
3041 renderSLBTriplets2 (spotEntity ('ipvs', $vsg_id), FALSE, $ip_bin);
3042
3043 if (! empty ($address['vslist']))
defd92d8 3044 renderSLBTriplets ($address);
5fe1ed76 3045
7419401e
AA
3046 foreach (array ('outpf' => 'departing NAT rules', 'inpf' => 'arriving NAT rules') as $key => $title)
3047 if (! empty ($address[$key]))
3048 {
3049 startPortlet ($title);
3050 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
3051 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
3052 foreach ($address[$key] as $rule)
3053 {
3054 echo "<tr>";
3055 echo "<td>" . $rule['proto'] . "</td>";
3056 echo "<td>" . getRenderedIPPortPair ($rule['localip'], $rule['localport']) . "</td>";
3057 echo "<td>" . getRenderedIPPortPair ($rule['remoteip'], $rule['remoteport']) . "</td>";
3058 echo "<td>" . $rule['description'] . "</td></tr>";
3059 echo "</tr>";
3060 }
3061 echo "</table>";
3062 finishPortlet();
3063 }
105a3bc8 3064
68225375
DO
3065 echo "</td></tr>";
3066 echo "</table>\n";
e673ee24
DO
3067}
3068
09a531eb 3069function renderIPAddressProperties ($ip_bin)
e673ee24 3070{
09a531eb 3071 $address = getIPAddress ($ip_bin);
21ee3351 3072 echo "<center><h1>${address['ip']}</h1></center>\n";
7056988c 3073
1fbc9fd6 3074 startPortlet ('update');
e673ee24 3075 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 3076 printOpFormIntro ('editAddress');
0186638b
DO
3077 echo '<tr><td class=tdright><label for=id_name>Name:</label></td>';
3078 echo "<td class=tdleft><input type=text name=name id=id_name size=20 value='${address['name']}'></tr>";
cc2fa820
AD
3079 echo '<tr><td class=tdright><label for=id_comment>Comment:</label></td>';
3080 echo "<td class=tdleft><input type=text name=comment id=id_comment size=20 value='${address['comment']}'></tr>";
0186638b
DO
3081 echo '<td class=tdright><label for=id_reserved>Reserved:</label></td>';
3082 echo "<td class=tdleft><input type=checkbox name=reserved id=id_reserved size=20 ";
2d318652 3083 echo ($address['reserved']=='yes') ? 'checked' : '';
f3d274bf 3084 echo "></tr><tr><td class=tdleft>";
53ef3908 3085 printImageHREF ('SAVE', 'Save changes', TRUE);
f3d274bf 3086 echo "</td></form><td class=tdright>";
59a83bd8 3087 if (!strlen ($address['name']) and $address['reserved'] == 'no')
f3d274bf
DO
3088 printImageHREF ('CLEAR gray');
3089 else
3090 {
18a77e3c 3091 printOpFormIntro ('editAddress', array ('name' => '', 'reserved' => '', 'comment' => ''));
f3d274bf
DO
3092 printImageHREF ('CLEAR', 'Release', TRUE);
3093 echo "</form>";
3094 }
3095 echo "</td></tr></table>\n";
1fbc9fd6 3096 finishPortlet();
e673ee24
DO
3097}
3098
09a531eb 3099function renderIPAddressAllocations ($ip_bin)
e673ee24 3100{
4318ced5 3101 function printNewItemTR ()
39b4abd0
DO
3102 {
3103 global $aat;
4318ced5 3104 printOpFormIntro ('add');
39b4abd0 3105 echo "<tr><td>";
9318d2ef 3106 printImageHREF ('add', 'allocate', TRUE);
8d4f7d18 3107 echo "</td><td>";
31babb65 3108 printSelect (getNarrowObjectList ('IPV4OBJ_LISTSRC'), array ('name' => 'object_id', 'tabindex' => 100));
8d4f7d18 3109 echo "</td><td><input type=text tabindex=101 name=bond_name size=10></td><td>";
01abf1de 3110 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102, 'regular'));
9318d2ef 3111 echo "</td><td>";
f5ff50f5 3112 printImageHREF ('add', 'allocate', TRUE, 103);
9318d2ef 3113 echo "</td></form></tr>";
39b4abd0 3114 }
b82cce3f 3115 global $aat;
e673ee24 3116
09a531eb 3117 $address = getIPAddress ($ip_bin);
21ee3351 3118 echo "<center><h1>${address['ip']}</h1></center>\n";
105a3bc8 3119 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2d318652 3120 echo "<tr><th>&nbsp;</th><th>object</th><th>OS interface</th><th>allocation type</th><th>&nbsp;</th></tr>\n";
e673ee24 3121
39b4abd0 3122 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
4318ced5 3123 printNewItemTR();
f74d96c6 3124 if (isset ($address['class']))
e673ee24 3125 {
f74d96c6
DO
3126 $class = $address['class'];
3127 if ($address['reserved'] == 'yes')
3128 echo "<tr class='${class}'><td colspan=3>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td><td>&nbsp;</td></tr>";
3129 foreach ($address['allocs'] as $bond)
3130 {
3131 echo "<tr class='$class'>";
4318ced5 3132 printOpFormIntro ('upd', array ('object_id' => $bond['object_id']));
10f5133a 3133 echo "<td>" . getOpLink (array ('op' => 'del', 'object_id' => $bond['object_id'] ), '', 'delete', 'Unallocate address') . "</td>";
4318ced5 3134 echo "<td><a href='" . makeHref (array ('page' => 'object', 'object_id' => $bond['object_id'], 'hl_ip' => $address['ip'])) . "'>${bond['object_name']}</td>";
f74d96c6 3135 echo "<td><input type='text' name='bond_name' value='${bond['name']}' size=10></td><td>";
cd3775e9 3136 printSelect ($aat, array ('name' => 'bond_type'), $bond['type']);
f74d96c6
DO
3137 echo "</td><td>";
3138 printImageHREF ('save', 'Save changes', TRUE);
3139 echo "</td></form></tr>\n";
3140 }
e673ee24 3141 }
39b4abd0 3142 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
4318ced5 3143 printNewItemTR();
e673ee24 3144 echo "</table><br><br>";
e673ee24
DO
3145}
3146
7e1db771 3147function renderNATv4ForObject ($object_id)
e673ee24 3148{
9318d2ef
DO
3149 function printNewItemTR ($alloclist)
3150 {
9318d2ef
DO
3151 printOpFormIntro ('addNATv4Rule');
3152 echo "<tr align='center'><td>";
3153 printImageHREF ('add', 'Add new NAT rule', TRUE);
3154 echo '</td><td>';
cd3775e9 3155 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP'), array ('name' => 'proto'));
9318d2ef
DO
3156 echo "<select name='localip' tabindex=1>";
3157