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