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