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