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