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