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