renderDepot: objects with problems are colored red (#1137)
[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 {
ec788aba
AD
2192 $problem = ($obj['has_problems'] == 'yes') ? 'has_problems' : '';
2193 echo "<tr class='row_${order} tdleft ${problem}' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
4899096d
AD
2194 if (count ($obj['etags']))
2195 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
4318ced5
AA
2196 echo "</td><td>${obj['label']}</td>";
2197 echo "<td>${obj['asset_no']}</td>";
3f8a25d6 2198 $places = array();
cae81598
AD
2199 if (array_key_exists ($obj['id'], $containerinfo))
2200 foreach ($containerinfo[$obj['id']] as $ci)
20506de3 2201 $places[] = mkA ($ci['container_dname'], 'object', $ci['container_id']);
cae81598 2202 if (array_key_exists ($obj['id'], $mountinfo))
3f8a25d6
DO
2203 foreach ($mountinfo[$obj['id']] as $mi)
2204 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
cae81598
AD
2205 if (! count ($places))
2206 $places[] = 'Unmounted';
4318ced5 2207 echo "<td>" . implode (', ', $places) . '</td>';
4899096d
AD
2208 echo '</tr>';
2209 $order = $nextorder[$order];
2210 }
2211 echo '</table>';
2212 finishPortlet();
1ebbf889 2213 }
e673ee24 2214 }
23cdc7e9
DO
2215
2216 echo "</td><td class=pcright width='25%'>";
2217
95857b5c 2218 renderCellFilterPortlet ($cellfilter, 'object', $objects);
23cdc7e9 2219 echo "</td></tr></table>\n";
e673ee24
DO
2220}
2221
1ebbf889
AA
2222// This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2223// In this case it renders the describing message instead.
2224function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2225{
2226 if (!$cellfilter['is_empty'])
2227 return FALSE;
2228 if (isset ($_REQUEST['show_all_objects']))
2229 return FALSE;
2230 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2231 if (0 == $max || $count <= $max)
2232 return FALSE;
2233
2234 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2235 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2236 $suffix = isset ($count) ? " ($count)" : '';
2237 echo <<<END
2238<p>Please set a filter to display the corresponging $entities_name.
2239<br><a href="$href_show_all">Show all $entities_name$suffix</a>
2240END;
2241 return TRUE;
2242}
2243
e673ee24 2244// History viewer for history-enabled simple dictionaries.
9b8174d7 2245function renderObjectHistory ($object_id)
e673ee24 2246{
e673ee24
DO
2247 $order = 'odd';
2248 global $nextorder;
9b8174d7
AD
2249 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2250 echo '<tr><th>change time</th><th>author</th><th>name</th><th>visible label</th><th>asset no</th><th>has problems?</th><th>comment</th></tr>';
2251 $result = usePreparedSelectBlade
2252 (
2253 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2254 array ($object_id)
2255 );
e673ee24
DO
2256 while ($row = $result->fetch (PDO::FETCH_NUM))
2257 {
2258 echo "<tr class=row_${order}><td>${row[0]}</td>";
9b8174d7 2259 for ($i = 1; $i <= 6; $i++)
e673ee24
DO
2260 echo "<td>" . $row[$i] . "</td>";
2261 echo "</tr>\n";
2262 $order = $nextorder[$order];
2263 }
2264 echo "</table><br>\n";
2265}
2266
2267function renderRackspaceHistory ()
2268{
4fbb5a00 2269 global $nextorder, $pageno, $tabno;
e673ee24
DO
2270 $order = 'odd';
2271 $history = getRackspaceHistory();
2272 // Show the last operation by default.
2273 if (isset ($_REQUEST['op_id']))
2274 $op_id = $_REQUEST['op_id'];
2275 elseif (isset ($history[0]['mo_id']))
2276 $op_id = $history[0]['mo_id'];
2277 else $op_id = NULL;
dec748f6 2278
e673ee24
DO
2279 $omid = NULL;
2280 $nmid = NULL;
2281 $object_id = 1;
2282 if ($op_id)
2283 list ($omid, $nmid) = getOperationMolecules ($op_id);
2284
2285 // Main layout starts.
2286 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2287
2288 // Left top portlet with old allocation.
2289 echo "<tr><td class=pcleft>";
2290 startPortlet ('Old allocation');
2291 if ($omid)
2292 {
2293 $oldMolecule = getMolecule ($omid);
2294 renderMolecule ($oldMolecule, $object_id);
2295 }
2296 else
2297 echo "nothing";
2298 finishPortlet();
2299
2300 echo '</td><td class=pcright>';
2301
2302 // Right top portlet with new allocation
2303 startPortlet ('New allocation');
2304 if ($nmid)
2305 {
2306 $newMolecule = getMolecule ($nmid);
2307 renderMolecule ($newMolecule, $object_id);
2308 }
2309 else
2310 echo "nothing";
2311 finishPortlet();
737a3f72 2312
e673ee24 2313 echo '</td></tr><tr><td colspan=2>';
737a3f72 2314
e673ee24
DO
2315 // Bottom portlet with list
2316
2317 startPortlet ('Rackspace allocation history');
2318 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
7fa7047a 2319 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
e673ee24
DO
2320 foreach ($history as $row)
2321 {
2322 if ($row['mo_id'] == $op_id)
2323 $class = 'hl';
2324 else
2325 $class = "row_${order}";
4fbb5a00 2326 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
7fa7047a
DO
2327 echo "<td>${row['user_name']}</td><td>";
2328 renderCell (spotEntity ('object', $row['ro_id']));
9c6222ef 2329 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
e673ee24
DO
2330 $order = $nextorder[$order];
2331 }
2332 echo "</table>\n";
2333 finishPortlet();
737a3f72 2334
e673ee24 2335 echo '</td></tr></table>';
e673ee24
DO
2336}
2337
4318ced5 2338function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
d65353ad
DO
2339{
2340 $self = __FUNCTION__;
4318ced5 2341 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
00276508
AA
2342
2343 // scroll page to the highlighted item
2344 if ($target && isset ($_REQUEST['hl_net']))
65e557dd 2345 addAutoScrollScript ("net-$target");
00276508 2346
d65353ad
DO
2347 foreach ($tree as $item)
2348 {
4318ced5
AA
2349 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'))
2350 loadIPAddrList ($item); // necessary to compute router list and address counter
2351
0137d53c
DO
2352 if (isset ($item['id']))
2353 {
1f54e1ba 2354 $decor = array ('indent' => $level);
fec0c8da 2355 if ($item['symbol'] == 'node-collapsed')
4318ced5 2356 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
fec0c8da 2357 elseif ($item['symbol'] == 'node-expanded')
4318ced5
AA
2358 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
2359 $tr_class = '';
21ee3351 2360 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
64347dcf 2361 {
5c717ce5 2362 $decor['tdclass'] = ' highlight';
4318ced5 2363 $tr_class = $decor['tdclass'];
64347dcf 2364 }
4318ced5
AA
2365 echo "<tr valign=top class=\"$tr_class\">";
2366 printIPNetInfoTDs ($item, $decor);
2367
2368 // capacity and usage
2369 echo "<td class=tdcenter>";
2370 echo getRenderedIPNetCapacity ($item);
64347dcf 2371 echo "</td>";
4318ced5
AA
2372
2373 if ($display_routers)
efd8057e 2374 printRoutersTD (findRouters ($item['own_addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
0137d53c 2375 echo "</tr>";
fec0c8da 2376 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
4318ced5 2377 $self ($item['kids'], $baseurl, $target, $level + 1);
0137d53c
DO
2378 }
2379 else
2380 {
4318ced5 2381 // non-allocated (spare) IP range
0137d53c 2382 echo "<tr valign=top>";
21ee3351 2383 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
00276508 2384
4318ced5 2385 // capacity and usage
21ee3351 2386 echo "<td class=tdcenter>";
4318ced5 2387 echo getRenderedIPNetCapacity ($item);
21ee3351 2388 echo "</td>";
4318ced5
AA
2389 if ($display_routers)
2390 echo "<td></td>";
21ee3351 2391 echo "</tr>";
21ee3351 2392 }
21ee3351
AA
2393 }
2394}
2395
4318ced5 2396function renderIPSpace()
e673ee24 2397{
4fbb5a00 2398 global $pageno, $tabno;
4318ced5 2399 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
31c941ec 2400 $cellfilter = getCellFilter();
21ee3351 2401
b99b4167
AA
2402 // expand request can take either natural values or "ALL". Zero means no expanding.
2403 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
2404
21ee3351
AA
2405 echo "<table border=0 class=objectview>\n";
2406 echo "<tr><td class=pcleft>";
950dfa1f
AA
2407
2408 $netlist = array();
b99b4167 2409 if (! ($cellfilter['is_empty'] && ! $eid && renderEmptyResults($cellfilter, 'IP nets', getEntitiesCount ($realm))))
21ee3351 2410 {
950dfa1f
AA
2411 $top = NULL;
2412 foreach (listCells ($realm) as $net)
21ee3351 2413 {
950dfa1f
AA
2414 if (isset ($top) and IPNetContains ($top, $net))
2415 ;
2416 elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression']))
2417 $top = $net;
2418 else
2419 continue;
2420 $netlist[$net['id']] = $net;
2421 }
2422 $netcount = count ($netlist);
950dfa1f
AA
2423 $tree = prepareIPTree ($netlist, $eid);
2424
2425 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
2426 {
2427 startPortlet ("networks (${netcount})");
2428 echo '<h4>';
2429 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2430 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2431 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2432 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2433 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2434 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2435
2436 if ($eid === 0)
2437 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
2438 elseif ($eid === 'ALL')
2439 echo "expanding all ($auto / $none)";
2440 elseif ($eid === 'NONE')
2441 echo "collapsing all ($all / $auto)";
2442 else
2443 {
2444 $netinfo = spotEntity ($realm, $eid);
2445 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
2446 }
2447 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2448 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2449 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
2450 echo "<th>routed by</th>";
2451 echo "</tr>\n";
2452 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2453 renderIPSpaceRecords ($tree, $baseurl, $eid);
2454 echo "</table>\n";
2455 finishPortlet();
21ee3351 2456 }
21ee3351
AA
2457 }
2458
2459 echo '</td><td class=pcright>';
950dfa1f 2460 renderCellFilterPortlet ($cellfilter, $realm, $netlist);
21ee3351
AA
2461 echo "</td></tr></table>\n";
2462}
2463
4318ced5 2464function renderIPSpaceEditor()
21ee3351 2465{
4318ced5
AA
2466 global $pageno;
2467 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2468 $net_page = $realm; // 'ipv4net', 'ipv6net'
2469 $addrspaceList = listCells ($realm);
93a49e5b
AA
2470 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2471 if (count ($addrspaceList))
21ee3351 2472 {
21ee3351
AA
2473 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2474 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
21ee3351
AA
2475 foreach ($addrspaceList as $netinfo)
2476 {
21ee3351 2477 echo "<tr valign=top><td>";
93a49e5b 2478 if (! isIPNetworkEmpty ($netinfo))
21ee3351
AA
2479 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2480 else
93a49e5b 2481 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
ad3e5e7e 2482 echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>';
1f54e1ba
DO
2483 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2484 if (count ($netinfo['etags']))
2485 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2486 echo '</td><td>';
4318ced5 2487 echo getRenderedIPNetCapacity ($netinfo);
b1e39212 2488 echo '</tr>';
e673ee24 2489 }
04d619d0
DO
2490 echo "</table>";
2491 finishPortlet();
e673ee24 2492 }
93a49e5b
AA
2493}
2494
2495function renderIPNewNetForm ()
2496{
2497 global $pageno;
2498 if ($pageno == 'ipv6space')
2499 {
2500 $realm = 'ipv6net';
3495ec6e 2501 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
93a49e5b
AA
2502 }
2503 else
2504 {
2505 $realm = 'ipv4net';
3495ec6e 2506 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
93a49e5b
AA
2507 }
2508
2509 // IP prefix validator
10f5133a 2510 addJS ('js/live_validation.js');
93a49e5b 2511 $regexp = addslashes ($regexp);
10f5133a 2512 addJS (<<<END
93a49e5b 2513$(document).ready(function () {
b895e6b4 2514 $('form#add input[name="range"]').attr('match', '$regexp');
93a49e5b
AA
2515 Validate.init();
2516});
2517END
2518 , TRUE);
dec748f6 2519
93a49e5b 2520 startPortlet ('Add new');
10f5133a 2521 printOpFormIntro ('add');
e7b84015
AB
2522 echo '<table border=0 cellpadding=5 cellspacing=0 align=center>';
2523
93a49e5b
AA
2524 // inputs column
2525 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
e7b84015
AB
2526 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>";
2527 echo '<tr><th class=tdright>VLAN:</th><td class=tdleft>';
93a49e5b 2528 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical', 'tabindex' => 2)) . '</td></tr>';
e7b84015
AB
2529 echo "<tr><th class=tdright>Name:</th><td class=tdleft><input type=text name='name' size='20' tabindex=3></td></tr>";
2530 echo '<tr><th class=tdright>Tags:</th><td class="tdleft">';
2531 printTagsPicker ();
2532 echo '</td></tr>';
2533 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
2534 echo "<tr><td colspan=2>";
2535 printImageHREF ('CREATE', 'Add a new network', TRUE, 5);
2536 echo '</td></tr>';
e7b84015 2537 echo "</table></form><br><br>\n";
93a49e5b 2538 finishPortlet();
e673ee24
DO
2539}
2540
4318ced5 2541function getRenderedIPNetBacktrace ($range)
e673ee24 2542{
4318ced5
AA
2543 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2544 return array();
e673ee24 2545
4318ced5
AA
2546 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2547 $space = "ipv${v}space"; // ipv4space, ipv6space
2548 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
dec748f6 2549
4318ced5
AA
2550 $ret = array();
2551 // Build a backtrace from all parent networks.
2552 $clen = $range['mask'];
2553 $backtrace = array();
2554 $backtrace['&rarr;'] = $range;
2555 $key = '';
2556 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2557 {
2558 $upperinfo = spotEntity ($range['realm'], $upperid);
2559 $clen = $upperinfo['mask'];
2560 $key .= '&uarr;';
2561 $backtrace[$key] = $upperinfo;
2562 }
2563 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2564 {
2565 $link = '<a href="' . makeHref (array (
2566 'page' => $space,
2567 'tab' => 'default',
2568 'clear-cf' => '',
2569 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2570 'hl_net' => 1,
2571 'eid' => $range['id'],
2572 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2573 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2574 }
2575 return $ret;
2576}
2577
2578function renderIPNetwork ($id)
2579{
2580 global $pageno;
2581 $realm = $pageno; // 'ipv4net', 'ipv6net'
2582 $range = spotEntity ($realm, $id);
2583 loadIPAddrList ($range);
2034d968 2584 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
99ab184f
DO
2585 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2586 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2034d968
DO
2587
2588 echo "<tr><td class=pcleft width='50%'>";
646272be
AA
2589
2590 // render summary portlet
2591 $summary = array();
4318ced5 2592 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2b6b0038 2593 $summary = getRenderedIPNetBacktrace ($range) + $summary;
4318ced5 2594 if ($realm == 'ipv4net')
001e61fa 2595 {
4318ced5
AA
2596 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2597 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2598 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
001e61fa 2599 }
dec748f6 2600
11e3af31
DO
2601 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2602 $domainclass = array();
2603 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2604 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
a5f9d1ca 2605 foreach ($range['8021q'] as $item)
11e3af31 2606 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVLANInfo ($item['domain_id'] . '-' . $item['vlan_id'])));
3a4f4023 2607 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findRouters ($range['addrlist'])))
04d619d0 2608 {
646272be
AA
2609 $summary['Routed by'] = '';
2610 foreach ($routers as $rtr)
4318ced5 2611 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
04d619d0 2612 }
646272be
AA
2613 $summary['tags'] = '';
2614 renderEntitySummary ($range, 'summary', $summary);
e1ae3fb4 2615
99ab184f
DO
2616 if (strlen ($range['comment']))
2617 {
2618 startPortlet ('Comment');
2619 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2620 finishPortlet ();
2621 }
2622
4318ced5 2623 renderFilesPortlet ($realm, $id);
2034d968 2624 echo "</td>\n";
e673ee24 2625
2034d968
DO
2626 echo "<td class=pcright>";
2627 startPortlet ('details');
4318ced5
AA
2628 renderIPNetworkAddresses ($range);
2629 finishPortlet();
2630 echo "</td></tr></table>\n";
2631}
e673ee24 2632
4318ced5
AA
2633// Used solely by renderSeparator
2634function renderEmptyIPv6 ($ip_bin, $hl_ip)
2635{
2636 $class = 'tdleft';
2637 if ($ip_bin === $hl_ip)
5c717ce5 2638 $class .= ' highlight';
4318ced5 2639 $fmt = ip6_format ($ip_bin);
235124a6 2640 echo "<tr class='$class'><td><a name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
0b8d8309
AA
2641 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2642 ? 'editable'
2643 : '';
cc2fa820
AD
2644 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2645 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
4318ced5
AA
2646}
2647
2648// Renders empty table line to shrink empty IPv6 address ranges.
2649// If the range consists of single address, renders the address instead of empty line.
2650// Renders address $hl_ip inside the range.
2651// Used solely by renderIPv6NetworkAddresses
2652function renderSeparator ($first, $last, $hl_ip)
2653{
2654 $self = __FUNCTION__;
2655 if (strcmp ($first, $last) > 0)
2656 return;
2657 if ($first == $last)
2658 renderEmptyIPv6 ($first, $hl_ip);
2659 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2660 { // $hl_ip is inside the range $first - $last
2661 $self ($first, ip_prev ($hl_ip), $hl_ip);
2662 renderEmptyIPv6 ($hl_ip, $hl_ip);
2663 $self (ip_next ($hl_ip), $last, $hl_ip);
2664 }
2665 else
cc2fa820 2666 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
4318ced5
AA
2667}
2668
75e7c0c6 2669// calculates page number that contains given $ip (used by renderIPv6NetworkAddresses)
4318ced5
AA
2670function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2671{
2672 if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage)
2673 return 0;
2674 $keys = array_keys ($list);
2675 for ($i = 1; $i <= count ($keys); $i++)
2676 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2677 return intval ($i / $maxperpage);
2678 return intval (count ($list) / $maxperpage);
2679}
2680
2681function renderIPNetworkAddresses ($range)
2682{
2683 switch (strlen ($range['ip_bin']))
2684 {
2685 case 4: return renderIPv4NetworkAddresses ($range);
2686 case 16: return renderIPv6NetworkAddresses ($range);
2687 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2688 }
2689}
2690
2691function renderIPv4NetworkAddresses ($range)
2692{
2693 global $pageno, $tabno, $aac2;
2694 $startip = ip4_bin2int ($range['ip_bin']);
2695 $endip = ip4_bin2int (ip_last ($range));
2696
2697 if (isset ($_REQUEST['hl_ip']))
00276508 2698 {
4318ced5
AA
2699 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2700 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
00276508
AA
2701 }
2702
79b57b18
AA
2703 // pager
2704 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2705 $address_count = $endip - $startip + 1;
2706 $page = 0;
446c25c3 2707 $rendered_pager = '';
79b57b18
AA
2708 if ($address_count > $maxperpage && $maxperpage > 0)
2709 {
2710 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2711 if ($numpages = ceil ($address_count / $maxperpage))
2712 {
4318ced5 2713 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
79b57b18
AA
2714 for ($i = 0; $i < $numpages; $i++)
2715 if ($i == $page)
446c25c3 2716 $rendered_pager .= "<b>$i</b> ";
79b57b18 2717 else
4318ced5 2718 $rendered_pager .= "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $range['id'], 'pg' => $i)) . "'>$i</a> ";
79b57b18
AA
2719 }
2720 $startip = $startip + $page * $maxperpage;
2721 $endip = min ($startip + $maxperpage - 1, $endip);
2722 }
2723
446c25c3 2724 echo $rendered_pager;
beb9e88a 2725 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2726 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
e673ee24 2727
4318ced5
AA
2728 markupIPAddrList ($range['addrlist']);
2729 for ($ip = $startip; $ip <= $endip; $ip++)
2730 {
2731 $ip_bin = ip4_int2bin ($ip);
2732 $dottedquad = ip4_format ($ip_bin);
5c717ce5 2733 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
0cd7c0f6
AA
2734 if (isset ($range['addrlist'][$ip_bin]))
2735 $addr = $range['addrlist'][$ip_bin];
2736 else
e673ee24 2737 {
235124a6 2738 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
2739 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2740 ? 'editable'
2741 : '';
cc2fa820
AD
2742 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
2743 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
b2035dca
DO
2744 continue;
2745 }
68c91b9c
AA
2746 // render IP change history
2747 $title = '';
2748 $history_class = '';
2749 if (isset ($addr['last_log']))
2750 {
2751 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2752 $history_class = 'hover-history underline';
2753 }
4318ced5
AA
2754 $tr_class .= ' ' . $addr['class'];
2755 echo "<tr class='tdleft $tr_class'>";
235124a6 2756 echo "<td><a class='$history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
0b8d8309 2757 $editable =
cc2fa820 2758 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
0b8d8309
AA
2759 && permitted ('ipaddress', 'properties', 'editAddress')
2760 ? 'editable'
2761 : '';
cc2fa820
AD
2762 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
2763 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
0b8d8309 2764 echo "<td>";
b2035dca 2765 $delim = '';
b2035dca
DO
2766 if ( $addr['reserved'] == 'yes')
2767 {
2d318652 2768 echo "<strong>RESERVED</strong> ";
b2035dca
DO
2769 $delim = '; ';
2770 }
212b565a 2771 foreach ($addr['allocs'] as $ref)
b2035dca 2772 {
beb9e88a 2773 echo $delim . $aac2[$ref['type']];
4318ced5 2774 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
59a83bd8 2775 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
b2035dca
DO
2776 echo "${ref['object_name']}</a>";
2777 $delim = '; ';
2778 }
2779 if ($delim != '')
e0d6e38e 2780 $delim = '<br>';
212b565a
AA
2781 foreach ($addr['vslist'] as $vs_id)
2782 {
2783 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2784 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
212b565a
AA
2785 $delim = '<br>';
2786 }
eacc0983
AA
2787 foreach ($addr['vsglist'] as $vs_id)
2788 {
2789 $vs = spotEntity ('ipvs', $vs_id);
2790 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
2791 $delim = '<br>';
2792 }
212b565a
AA
2793 foreach ($addr['rsplist'] as $rsp_id)
2794 {
2795 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2796 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
212b565a
AA
2797 $delim = '<br>';
2798 }
b2035dca 2799 echo "</td></tr>\n";
4318ced5 2800 }
2727c7df 2801 // end of iteration
a8dc2982
AA
2802 if (permitted (NULL, NULL, 'set_reserve_comment'))
2803 addJS ('js/inplace-edit.js');
e673ee24
DO
2804
2805 echo "</table>";
446c25c3
AA
2806 if (! empty ($rendered_pager))
2807 echo '<p>' . $rendered_pager . '</p>';
21ee3351
AA
2808}
2809
2810function renderIPv6NetworkAddresses ($netinfo)
2811{
2812 global $pageno, $tabno, $aac2;
2813 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2814 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
21ee3351 2815
4318ced5
AA
2816 $hl_ip = NULL;
2817 if (isset ($_REQUEST['hl_ip']))
2818 {
2819 $hl_ip = ip6_parse ($_REQUEST['hl_ip']);
2820 addAutoScrollScript ('ip-' . ip6_format ($hl_ip));
2821 }
21ee3351 2822
21ee3351
AA
2823 $addresses = $netinfo['addrlist'];
2824 ksort ($addresses);
4318ced5 2825 markupIPAddrList ($addresses);
21ee3351
AA
2826
2827 // pager
2828 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2829 if (count ($addresses) > $maxperpage && $maxperpage > 0)
2830 {
2831 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0);
2832 $numpages = ceil (count ($addresses) / $maxperpage);
2833 echo "<center><h3>$numpages pages:</h3>";
2834 for ($i=0; $i<$numpages; $i++)
2835 {
2836 if ($i == $page)
2837 echo "<b>$i</b> ";
2838 else
2839 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> ";
2840 }
2841 echo "</center>";
2842 }
2843
2844 $i = 0;
dec748f6 2845 $interruped = FALSE;
4318ced5
AA
2846 $prev_ip = ip_prev ($netinfo['ip_bin']);
2847 foreach ($addresses as $ip_bin => $addr)
21ee3351
AA
2848 {
2849 if (isset ($page))
2850 {
2851 ++$i;
2852 if ($i <= $maxperpage * $page)
2853 continue;
2854 elseif ($i > $maxperpage * ($page + 1))
2855 {
2856 $interruped = TRUE;
2857 break;
2858 }
2859 }
2860
4318ced5
AA
2861 if ($ip_bin != ip_next ($prev_ip))
2862 renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip);
2863 $prev_ip = $ip_bin;
2864
2865 // render IP change history
2866 $title = '';
2867 $history_class = '';
2868 if (isset ($addr['last_log']))
2869 {
2870 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2871 $history_class = 'hover-history underline';
2872 }
2873
5c717ce5 2874 $tr_class = $addr['class'] . ' tdleft' . ($hl_ip === $ip_bin ? ' highlight' : '');
4318ced5 2875 echo "<tr class='$tr_class'>";
235124a6 2876 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
2877 $editable =
2878 (empty ($addr['allocs']) || !empty ($addr['name'])
2879 && permitted ('ipaddress', 'properties', 'editAddress')
2880 ? 'editable'
2881 : '');
cc2fa820
AD
2882 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-name'>${addr['name']}</span></td>";
2883 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-comment'>${addr['comment']}</span></td><td>";
21ee3351 2884 $delim = '';
21ee3351
AA
2885 if ( $addr['reserved'] == 'yes')
2886 {
2887 echo "<strong>RESERVED</strong> ";
2888 $delim = '; ';
2889 }
2890 foreach ($addr['allocs'] as $ref)
2891 {
2892 echo $delim . $aac2[$ref['type']];
71066ef1 2893 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
21ee3351
AA
2894 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
2895 echo "${ref['object_name']}</a>";
2896 $delim = '; ';
2897 }
2898 if ($delim != '')
71066ef1
AA
2899 $delim = '<br>';
2900 foreach ($addr['vslist'] as $vs_id)
2901 {
2902 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2903 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
71066ef1
AA
2904 $delim = '<br>';
2905 }
eacc0983
AA
2906 foreach ($addr['vsglist'] as $vs_id)
2907 {
2908 $vs = spotEntity ('ipvs', $vs_id);
2909 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
2910 $delim = '<br>';
2911 }
71066ef1 2912 foreach ($addr['rsplist'] as $rsp_id)
21ee3351 2913 {
71066ef1 2914 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2915 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
71066ef1 2916 $delim = '<br>';
21ee3351
AA
2917 }
2918 echo "</td></tr>\n";
2919 }
2920 if (! $interruped)
4318ced5 2921 renderSeparator (ip_next ($prev_ip), ip_last ($netinfo), $hl_ip);
21ee3351
AA
2922 if (isset ($page))
2923 { // bottom pager
2924 echo "<tr><td colspan=3>";
2925 if ($page > 0)
2926 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page - 1)) . "'><< prev</a> ";
2927 if ($page < $numpages - 1)
2928 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page + 1)) . "'>next >></a> ";
2929 echo "</td></tr>";
2930 }
2931 echo "</table>";
a8dc2982
AA
2932 if (permitted (NULL, NULL, 'set_reserve_comment'))
2933 addJS ('js/inplace-edit.js');
21ee3351
AA
2934}
2935
2936function renderIPNetworkProperties ($id)
e673ee24 2937{
21ee3351
AA
2938 global $pageno;
2939 $netdata = spotEntity ($pageno, $id);
53ef3908 2940 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
7056988c 2941 printOpFormIntro ('editRange');
e7b84015
AB
2942 echo "<table border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2943 echo '<tr><th class=tdright><label for=nameinput>Name:</label></th>';
99ab184f
DO
2944 echo "<td class=tdleft><input type=text name=name id=nameinput size=80 maxlength=255 value='";
2945 echo htmlspecialchars ($netdata['name'], ENT_QUOTES, 'UTF-8') . "'></tr>";
e7b84015
AB
2946 echo "<tr><th class=tdright>Tags:</th><td class=tdleft>";
2947 printTagsPicker ();
2948 echo "</td></tr>\n";
2949 echo '<tr><th class=tdright><label for=commentinput>Comment:</label></th>';
99ab184f
DO
2950 echo "<td class=tdleft><textarea name=comment id=commentinput cols=80 rows=25>\n";
2951 echo htmlspecialchars ($netdata['comment'], ENT_QUOTES, 'UTF-8') . "</textarea></tr>";
53ef3908
DO
2952 echo "<tr><td colspan=2 class=tdcenter>";
2953 printImageHREF ('SAVE', 'Save changes', TRUE);
e7b84015 2954 echo "</td></tr></table></form>\n";
93a49e5b
AA
2955
2956 echo '<center>';
2957 if (! isIPNetworkEmpty ($netdata))
2958 echo getOpLink (NULL, 'delete this prefix', 'nodestroy', 'There are ' . count ($netdata['addrlist']) . ' allocations inside');
2959 else
2960 echo getOpLink (array('op'=>'del','id'=>$id), 'delete this prefix', 'destroy');
2961 echo '</center>';
e673ee24
DO
2962}
2963
09a531eb 2964function renderIPAddress ($ip_bin)
e673ee24 2965{
46098972 2966 global $aat, $nextorder;
09a531eb 2967 $address = getIPAddress ($ip_bin);
68225375 2968 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
21ee3351 2969 echo "<tr><td colspan=2 align=center><h1>${address['ip']}</h1></td></tr>\n";
e673ee24 2970
68225375 2971 echo "<tr><td class=pcleft>";
dec748f6 2972
defd92d8 2973 $summary = array();
423c4216 2974 if (strlen ($address['name']))
cc2fa820
AD
2975 $summary['Name'] = $address['name'];
2976 if (strlen ($address['comment']))
2977 $summary['Comment'] = $address['comment'];
defd92d8
AA
2978 $summary['Reserved'] = $address['reserved'];
2979 $summary['Allocations'] = count ($address['allocs']);
4318ced5 2980 if (isset ($address['outpf']))
defd92d8 2981 $summary['Originated NAT connections'] = count ($address['outpf']);
4318ced5 2982 if (isset ($address['inpf']))
defd92d8 2983 $summary['Arriving NAT connections'] = count ($address['inpf']);
defd92d8 2984 renderEntitySummary ($address, 'summary', $summary);
dec748f6 2985
212b565a 2986 // render SLB portlet
eacc0983 2987 if (! empty ($address['vslist']) or ! empty ($address['vsglist']) or ! empty ($address['rsplist']))
212b565a
AA
2988 {
2989 startPortlet ("");
eacc0983
AA
2990 if (! empty ($address['vsglist']))
2991 {
2992 printf ("<h2>virtual service groups (%d):</h2>", count ($address['vsglist']));
2993 foreach ($address['vsglist'] as $vsg_id)
2994 renderSLBEntityCell (spotEntity ('ipvs', $vsg_id));
2995 }
2996
212b565a
AA
2997 if (! empty ($address['vslist']))
2998 {
2999 printf ("<h2>virtual services (%d):</h2>", count ($address['vslist']));
3000 foreach ($address['vslist'] as $vs_id)
3001 renderSLBEntityCell (spotEntity ('ipv4vs', $vs_id));
3002 }
3003
3004 if (! empty ($address['rsplist']))
3005 {
3006 printf ("<h2>RS pools (%d):</h2>", count ($address['rsplist']));
3007 foreach ($address['rsplist'] as $rsp_id)
3008 renderSLBEntityCell (spotEntity ('ipv4rspool', $rsp_id));
3009 }
3010 finishPortlet();
3011 }
68225375 3012 echo "</td>\n";
e673ee24 3013
68225375 3014 echo "<td class=pcright>";
defd92d8 3015 if (isset ($address['class']) and ! empty ($address['allocs']))
59bebe2b 3016 {
8e700dd1 3017 startPortlet ('allocations');
2d318652
DO
3018 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
3019 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2d318652 3020 // render all allocation records for this address the same way
2d318652 3021 foreach ($address['allocs'] as $bond)
59bebe2b 3022 {
4318ced5 3023 $tr_class = "${address['class']} tdleft";
8e700dd1 3024 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
5c717ce5 3025 $tr_class .= ' highlight';
4318ced5
AA
3026 echo "<tr class='$tr_class'>" .
3027 "<td><a href='" . makeHref (array ('page' => 'object', 'object_id' => $bond['object_id'], 'tab' => 'default', 'hl_ip' => $address['ip'])) . "'>${bond['object_name']}</td>" .
3028 "<td>${bond['name']}</td>" .
3029 "<td><strong>" . $aat[$bond['type']] . "</strong></td>" .
3030 "</tr>\n";
59bebe2b
DO
3031 }
3032 echo "</table><br><br>";
3033 finishPortlet();
3034 }
e673ee24 3035
eacc0983
AA
3036 if (! empty ($address['rsplist']))
3037 {
3038 startPortlet ("RS pools:");
3039 foreach ($address['rsplist'] as $rsp_id)
3040 {
3041 renderSLBEntityCell (spotEntity ('ipv4rspool', $rsp_id));
3042 echo '<br>';
3043 }
3044 finishPortlet();
3045 }
3046
3047 if (! empty ($address['vsglist']))
3048 foreach ($address['vsglist'] as $vsg_id)
3049 renderSLBTriplets2 (spotEntity ('ipvs', $vsg_id), FALSE, $ip_bin);
3050
3051 if (! empty ($address['vslist']))
defd92d8 3052 renderSLBTriplets ($address);
5fe1ed76 3053
7419401e
AA
3054 foreach (array ('outpf' => 'departing NAT rules', 'inpf' => 'arriving NAT rules') as $key => $title)
3055 if (! empty ($address[$key]))
3056 {
3057 startPortlet ($title);
3058 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
3059 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
3060 foreach ($address[$key] as $rule)
3061 {
3062 echo "<tr>";
3063 echo "<td>" . $rule['proto'] . "</td>";
3064 echo "<td>" . getRenderedIPPortPair ($rule['localip'], $rule['localport']) . "</td>";
3065 echo "<td>" . getRenderedIPPortPair ($rule['remoteip'], $rule['remoteport']) . "</td>";
3066 echo "<td>" . $rule['description'] . "</td></tr>";
3067 echo "</tr>";
3068 }
3069 echo "</table>";
3070 finishPortlet();
3071 }
105a3bc8 3072
68225375
DO
3073 echo "</td></tr>";
3074 echo "</table>\n";
e673ee24
DO
3075}
3076
09a531eb 3077function renderIPAddressProperties ($ip_bin)
e673ee24 3078{
09a531eb 3079 $address = getIPAddress ($ip_bin);
21ee3351 3080 echo "<center><h1>${address['ip']}</h1></center>\n";
7056988c 3081
1fbc9fd6 3082 startPortlet ('update');
e673ee24 3083 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 3084 printOpFormIntro ('editAddress');
0186638b
DO
3085 echo '<tr><td class=tdright><label for=id_name>Name:</label></td>';
3086 echo "<td class=tdleft><input type=text name=name id=id_name size=20 value='${address['name']}'></tr>";
cc2fa820
AD
3087 echo '<tr><td class=tdright><label for=id_comment>Comment:</label></td>';
3088 echo "<td class=tdleft><input type=text name=comment id=id_comment size=20 value='${address['comment']}'></tr>";
0186638b
DO
3089 echo '<td class=tdright><label for=id_reserved>Reserved:</label></td>';
3090 echo "<td class=tdleft><input type=checkbox name=reserved id=id_reserved size=20 ";
2d318652 3091 echo ($address['reserved']=='yes') ? 'checked' : '';
f3d274bf 3092 echo "></tr><tr><td class=tdleft>";
53ef3908 3093 printImageHREF ('SAVE', 'Save changes', TRUE);
f3d274bf 3094 echo "</td></form><td class=tdright>";
59a83bd8 3095 if (!strlen ($address['name']) and $address['reserved'] == 'no')
f3d274bf
DO
3096 printImageHREF ('CLEAR gray');
3097 else
3098 {
18a77e3c 3099 printOpFormIntro ('editAddress', array ('name' => '', 'reserved' => '', 'comment' => ''));
f3d274bf
DO
3100 printImageHREF ('CLEAR', 'Release', TRUE);
3101 echo "</form>";
3102 }
3103 echo "</td></tr></table>\n";
1fbc9fd6 3104 finishPortlet();
e673ee24
DO
3105}
3106
09a531eb 3107function renderIPAddressAllocations ($ip_bin)
e673ee24 3108{
4318ced5 3109 function printNewItemTR ()
39b4abd0
DO
3110 {
3111 global $aat;
4318ced5 3112 printOpFormIntro ('add');
39b4abd0 3113 echo "<tr><td>";
9318d2ef 3114 printImageHREF ('add', 'allocate', TRUE);
8d4f7d18 3115 echo "</td><td>";
31babb65 3116 printSelect (getNarrowObjectList ('IPV4OBJ_LISTSRC'), array ('name' => 'object_id', 'tabindex' => 100));
8d4f7d18 3117 echo "</td><td><input type=text tabindex=101 name=bond_name size=10></td><td>";
01abf1de 3118 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102, 'regular'));
9318d2ef 3119 echo "</td><td>";
f5ff50f5 3120 printImageHREF ('add', 'allocate', TRUE, 103);
9318d2ef 3121 echo "</td></form></tr>";
39b4abd0 3122 }
b82cce3f 3123 global $aat;
e673ee24 3124
09a531eb 3125 $address = getIPAddress ($ip_bin);
21ee3351 3126 echo "<center><h1>${address['ip']}</h1></center>\n";
105a3bc8 3127 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2d318652 3128 echo "<tr><th>&nbsp;</th><th>object</th><th>OS interface</th><th>allocation type</th><th>&nbsp;</th></tr>\n";
e673ee24 3129
39b4abd0 3130 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
4318ced5 3131 printNewItemTR();
f74d96c6 3132 if (isset ($address['class']))
e673ee24 3133 {
f74d96c6
DO
3134 $class = $address['class'];
3135 if ($address['reserved'] == 'yes')
3136 echo "<tr class='${class}'><td colspan=3>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td><td>&nbsp;</td></tr>";
3137 foreach ($address['allocs'] as $bond)
3138 {
3139 echo "<tr class='$class'>";
4318ced5 3140 printOpFormIntro ('upd', array ('object_id' => $bond['object_id']));
10f5133a 3141 echo "<td>" . getOpLink (array ('op' => 'del', 'object_id' => $bond['object_id'] ), '', 'delete', 'Unallocate address') . "</td>";
4318ced5 3142 echo "<td><a href='" . makeHref (array ('page' => 'object', 'object_id' => $bond['object_id'], 'hl_ip' => $address['ip'])) . "'>${bond['object_name']}</td>";
f74d96c6 3143 echo "<td><input type='text' name='bond_name' value='${bond['name']}' size=10></td><td>";
cd3775e9 3144 printSelect ($aat, array ('name' => 'bond_type'), $bond['type']);
f74d96c6
DO
3145 echo "</td><td>";
3146 printImageHREF ('save', 'Save changes', TRUE);
3147 echo "</td></form></tr>\n";
3148 }
e673ee24 3149 }
39b4abd0 3150 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
4318ced5 3151 printNewItemTR();
e673ee24 3152 echo "</table><br><br>";
e673ee24
DO
3153}
3154
7e1db771 3155function renderNATv4ForObject ($object_id)
e673ee24 3156{
9318d2ef
DO
3157 function printNewItemTR ($alloclist)
3158 {
9318d2ef
DO
3159 printOpFormIntro ('addNATv4Rule');
3160 echo "<tr align='center'><td>";
3161 printImageHREF ('add', 'Add new NAT rule', TRUE);
3162 echo '</td><td>';
9067c07f 3163 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP', 'ALL' => 'ALL'), array ('name' => 'proto'));
9318d2ef
DO
3164 echo &q