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