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