Merge pull request #14 from nido/master
[racktables-incomplete-works] / wwwroot / inc / interface.php
CommitLineData
b325120a 1<?php
cddbb9fd
DO
2
3# This file is a part of RackTables, a datacenter and server room management
4# framework. See accompanying file "COPYING" for the full copyright and
5# licensing information.
6
e673ee24
DO
7/*
8*
9* This file contains frontend functions for RackTables.
10*
11*/
12
e82deb48 13require_once 'ajax-interface.php';
defd92d8 14require_once 'slb-interface.php';
65e557dd 15
9c0b0016
DO
16// Interface function's special.
17$nextorder['odd'] = 'even';
18$nextorder['even'] = 'odd';
19
52c836b1
DO
20// address allocation type
21$aat = array
22(
23 'regular' => 'Connected',
24 'virtual' => 'Loopback',
25 'shared' => 'Shared',
26 'router' => 'Router',
27);
beb9e88a 28// address allocation code, IPv4 addresses and objects view
52c836b1
DO
29$aac = array
30(
31 'regular' => '',
4318ced5
AA
32 'virtual' => '<span class="aac">L</span>',
33 'shared' => '<span class="aac">S</span>',
34 'router' => '<span class="aac">R</span>',
52c836b1 35);
beb9e88a
DO
36// address allocation code, IPv4 networks view
37$aac2 = array
38(
39 'regular' => '',
40 'virtual' => '<strong>L:</strong>',
29025f8e 41 'shared' => '<strong>S:</strong>',
beb9e88a
DO
42 'router' => '<strong>R:</strong>',
43);
52c836b1 44
0dabdc53
DO
45$vtdecoder = array
46(
47 'ondemand' => '',
54b7ced3
DO
48 'compulsory' => 'P',
49# 'alien' => 'NT',
0dabdc53
DO
50);
51
52$vtoptions = array
53(
54b7ced3
DO
54 'ondemand' => 'auto',
55 'compulsory' => 'permanent',
56# 'alien' => 'never touch',
0dabdc53
DO
57);
58
e5c4506d
DO
59// This may be populated later onsite, report rendering function will use it.
60// See the $systemreport for structure.
61$localreports = array();
d6adad3e 62
9db67d95
DO
63$CodePressMap = array
64(
65 'sql' => 'sql',
66 'php' => 'php',
67 'html' => 'html',
68 'css' => 'css',
69 'js' => 'javascript',
70);
e5c4506d 71
8d4f7d18
DO
72$attrtypes = array
73(
74 'uint' => '[U] unsigned integer',
75 'float' => '[F] floating point',
76 'string' => '[S] string',
86ff26ae
DO
77 'dict' => '[D] dictionary record',
78 'date' => '[T] date'
8d4f7d18
DO
79);
80
a1d72d2e
AA
81$quick_links = NULL; // you can override this in your local.php, but first initialize it with getConfiguredQuickLinks()
82
83function renderQuickLinks()
84{
85 global $quick_links;
86 if (! isset ($quick_links))
87 $quick_links = getConfiguredQuickLinks();
88 echo '<ul class="qlinks">';
89 foreach ($quick_links as $link)
90 echo '<li><a href="' . $link['href'] . '">' . str_replace (' ', '&nbsp;', $link['title']) . '</a></li>';
91 echo '</ul>';
92}
93
f97df464
DO
94function renderInterfaceHTML ($pageno, $tabno, $payload)
95{
96?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
97<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
98<head><title><?php echo getTitle ($pageno); ?></title>
99<?php printPageHeaders(); ?>
100</head>
101<body>
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
AA
106 </div>
107 <div class="menubar"><?php showPathAndSearch ($pageno); ?></div>
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 {
318c48a8 1466 echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter><span";
cd3775e9
DO
1467 $helper_args = array
1468 (
1469 'port' => $port['id'],
f4cfd325 1470 'in_rack' => 'on'
cd3775e9
DO
1471 );
1472 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
9e214652 1473 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
cd3775e9
DO
1474 echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1475 echo "\",\"findlink\",\"${popup_args}\");'";
1476 // end of onclick=
cd3775e9
DO
1477 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1478 echo "\",\"findlink\",\"${popup_args}\");'";
1479 // end of onclick=
1480 echo '>';
1481 // end of <a>
5ccd99a0 1482 printImageHREF ('plug', 'Link this port');
cd3775e9
DO
1483 echo "</span>";
1484 echo " <input type=text name=reservation_comment></td>\n";
e673ee24 1485 }
5bbbeaa2
DO
1486 echo "<td>";
1487 printImageHREF ('save', 'Save changes', TRUE);
1488 echo "</td></form></tr>\n";
e673ee24 1489 }
39b4abd0 1490 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
3153a326 1491 printNewItemTR ($prefs);
e673ee24 1492 echo "</table><br>\n";
a1fc539a
RF
1493 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1494 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1495 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>";
1496 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
dec748f6 1497 printOpFormIntro ('addBulkPorts');
a1fc539a
RF
1498 echo "<tr><td>";
1499 printImageHREF ('add', 'add ports', TRUE);
1500 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1501 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1502 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1503 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1504 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1505 echo "<td>&nbsp;</td><td>";
1506 printImageHREF ('add', 'add ports', TRUE, 110);
1507 echo "</td></tr></form>";
1508 echo "</table><br>\n";
1509 }
f44fdef9
DO
1510 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes')
1511 finishPortlet();
1512 if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes')
1513 return;
e673ee24
DO
1514
1515 startPortlet ('Add/update multiple ports');
7056988c 1516 printOpFormIntro ('addMultiPorts');
f7a3c94a 1517 echo 'Format: <select name=format tabindex=201>';
e673ee24
DO
1518 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1519 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
e673ee24 1520 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
351d4dbf 1521 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
e673ee24
DO
1522 echo "</select>";
1523 echo 'Default port type: ';
cd3775e9 1524 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type', 'tabindex' => 202), $prefs['selected']);
f7a3c94a
DO
1525 echo "<input type=submit value='Parse output' tabindex=204><br>\n";
1526 echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
e673ee24
DO
1527 echo '</form>';
1528 finishPortlet();
1529}
1530
4318ced5 1531function renderIPForObject ($object_id)
e673ee24 1532{
4318ced5 1533 function printNewItemTR ($default_type)
21ee3351
AA
1534 {
1535 global $aat;
4318ced5
AA
1536 printOpFormIntro ('add');
1537 echo "<tr><td>"; // left btn
dec748f6 1538 printImageHREF ('add', 'allocate', TRUE);
21ee3351 1539 echo "</td>";
4318ced5
AA
1540 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n"; // if-name
1541 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n"; // IP
1542 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1543 echo "<td colspan=2>&nbsp;</td>"; // network, routed by
1544 echo '<td>';
1545 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), $default_type); // type
1546 echo "</td><td>&nbsp;</td><td>"; // misc
1547 printImageHREF ('add', 'allocate', TRUE, 103); // right btn
21ee3351
AA
1548 echo "</td></tr></form>";
1549 }
21ee3351
AA
1550 global $aat;
1551 startPortlet ('Allocations');
4318ced5
AA
1552 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1553 echo '<th>&nbsp;</th>';
1554 echo '<th>OS interface</th>';
1555 echo '<th>IP address</th>';
21ee3351 1556 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
4318ced5
AA
1557 {
1558 echo '<th>network</th>';
1559 echo '<th>routed by</th>';
1560 }
1561 echo '<th>type</th>';
1562 echo '<th>misc</th>';
1563 echo '<th>&nbsp</th>';
1564 echo '</tr>';
21ee3351 1565
710ead7e
AA
1566 $alloc_list = ''; // most of the output is stored here
1567 $used_alloc_types = array();
4318ced5 1568 foreach (getObjectIPAllocations ($object_id) as $alloc)
21ee3351 1569 {
710ead7e
AA
1570 if (! isset ($used_alloc_types[$alloc['type']]))
1571 $used_alloc_types[$alloc['type']] = 0;
1572 $used_alloc_types[$alloc['type']]++;
1573
40c9fc94 1574 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
4318ced5 1575 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
710ead7e 1576 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
f3505b35 1577
710ead7e 1578 $alloc_list .= "<td><a href='" .
f3505b35
AA
1579 makeHrefProcess
1580 (
1581 array
1582 (
4318ced5 1583 'op' => 'del',
f3505b35 1584 'ip' => $alloc['addrinfo']['ip'],
f3505b35 1585 )
dec748f6 1586 ) . "'>" .
f3505b35
AA
1587 getImageHREF ('delete', 'Delete this IP address') .
1588 "</a></td>";
40c9fc94 1589 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
710ead7e 1590 $alloc_list .= $rendered_alloc['td_ip'];
21ee3351
AA
1591 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1592 {
710ead7e
AA
1593 $alloc_list .= $rendered_alloc['td_network'];
1594 $alloc_list .= $rendered_alloc['td_routed_by'];
21ee3351 1595 }
710ead7e
AA
1596 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1597 $alloc_list .= $rendered_alloc['td_peers'];
1598 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
f3505b35 1599
710ead7e 1600 $alloc_list .= "</form></tr>\n";
21ee3351 1601 }
710ead7e 1602 asort ($used_alloc_types, SORT_NUMERIC);
a0a5ce54 1603 $most_popular_type = empty ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types));
710ead7e
AA
1604
1605 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1606 echo $alloc_list;
4318ced5 1607 printNewItemTR ($most_popular_type);
710ead7e
AA
1608 if (! $list_on_top)
1609 echo $alloc_list;
21ee3351
AA
1610
1611 echo "</table><br>\n";
1612 finishPortlet();
f3505b35
AA
1613}
1614
08408472
AA
1615// This function is deprecated. Do not rely on its internals,
1616// it will probably be removed in the next major relese.
1617// Use new showError, showWarning, showSuccess functions.
dec748f6 1618// Log array is stored in global $log_messages. Its format is simple: plain ordered array
8ab645cf 1619// with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1cb6adf5 1620function showMessageOrError ()
e673ee24 1621{
a2b16202
AA
1622 global $log_messages;
1623
1624 @session_start();
1625 if (isset ($_SESSION['log']))
1626 {
1627 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1628 unset ($_SESSION['log']);
1629 }
1630 session_commit();
1631
1632 if (empty ($log_messages))
1cb6adf5 1633 return;
8ab645cf
AA
1634 $msginfo = array
1635 (
dec748f6 1636// records 0~99 with success messages
8ab645cf
AA
1637 0 => array ('code' => 'success', 'format' => '%s'),
1638 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1639 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1640 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1641 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
1642 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1643 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1644 26 => array ('code' => 'success', 'format' => 'updated %u records successfully'),
1645 37 => array ('code' => 'success', 'format' => 'added %u records successfully'),
1646 38 => array ('code' => 'success', 'format' => 'removed %u records successfully'),
8ab645cf
AA
1647 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1648 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1649 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1650 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1651 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1652 57 => array ('code' => 'success', 'format' => 'Reset complete'),
8ab645cf 1653 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
8ab645cf
AA
1654 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1655 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1656 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
8ab645cf
AA
1657 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"),
1658 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'),
8628ae44 1659// records 100~199 with fatal error messages
8ab645cf
AA
1660 100 => array ('code' => 'error', 'format' => '%s'),
1661 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
8ab645cf
AA
1662 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1663 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'),
1664 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1665 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1666 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1667 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1668 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1669 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1670 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1671 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1672 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
8ab645cf
AA
1673 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1674 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1675 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
1676 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"),
1677 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"),
1678 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
f0ff4930 1679
8628ae44 1680// records 200~299 with warnings
8ab645cf
AA
1681 200 => array ('code' => 'warning', 'format' => '%s'),
1682 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
e1add254 1683 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
7587edca 1684 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
57777e4a 1685
24d3182a 1686// records 300~399 with notices
8ab645cf 1687 300 => array ('code' => 'neutral', 'format' => '%s'),
24d3182a 1688
8ab645cf
AA
1689 );
1690 // Handle the arguments. Is there any better way to do it?
a2b16202 1691 foreach ($log_messages as $record)
8ab645cf
AA
1692 {
1693 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1694 {
41152018
AA
1695 $prefix = isset ($record['c']) ? $record['c'] . ': ' : '';
1696 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
8ab645cf
AA
1697 continue;
1698 }
1699 if (isset ($record['a']))
1700 switch (count ($record['a']))
baf37d01 1701 {
8ab645cf
AA
1702 case 1:
1703 $msgtext = sprintf
1704 (
1705 $msginfo[$record['c']]['format'],
1706 $record['a'][0]
1707 );
1708 break;
1709 case 2:
1710 $msgtext = sprintf
1711 (
1712 $msginfo[$record['c']]['format'],
1713 $record['a'][0],
1714 $record['a'][1]
1715 );
1716 break;
1717 case 3:
1718 $msgtext = sprintf
1719 (
1720 $msginfo[$record['c']]['format'],
1721 $record['a'][0],
1722 $record['a'][1],
1723 $record['a'][2]
1724 );
1725 break;
1726 case 4:
1727 default:
1728 $msgtext = sprintf
1729 (
1730 $msginfo[$record['c']]['format'],
1731 $record['a'][0],
1732 $record['a'][1],
1733 $record['a'][2],
1734 $record['a'][3]
1735 );
1736 break;
baf37d01 1737 }
8ab645cf
AA
1738 else
1739 $msgtext = $msginfo[$record['c']]['format'];
1740 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
baf37d01 1741 }
a2b16202 1742 $log_messages = array();
e673ee24
DO
1743}
1744
65e557dd
AA
1745// renders two tables: port link status and learned MAC list
1746function renderPortsInfo($object_id)
1747{
03522bd8
AA
1748 try
1749 {
1750 if (permitted (NULL, NULL, 'get_link_status'))
1751 $linkStatus = queryDevice ($object_id, 'getportstatus');
1752 else
1753 showWarning ("You don't have permission to view ports link status");
1754
1755 if (permitted (NULL, NULL, 'get_mac_list'))
1756 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
1757 else
1758 showWarning ("You don't have permission to view learned MAC list");
1759 }
1760 catch (RTGatewayError $e)
1761 {
1762 showError ($e->getMessage());
1763 return;
1764 }
1765
65e557dd
AA
1766 global $nextorder;
1767 echo "<table width='100%'><tr>";
03522bd8 1768 if (! empty ($linkStatus))
65e557dd 1769 {
03522bd8
AA
1770 echo "<td valign='top' width='50%'>";
1771 startPortlet('Link status');
1772 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>";
1773 $order = 'even';
1774 foreach ($linkStatus as $pn => $link)
65e557dd 1775 {
03522bd8 1776 switch ($link['status'])
65e557dd 1777 {
03522bd8
AA
1778 case 'up':
1779 $img_filename = 'link-up.png';
1780 break;
1781 case 'down':
1782 $img_filename = 'link-down.png';
1783 break;
1784 case 'disabled':
1785 $img_filename = 'link-disabled.png';
1786 break;
1787 default:
1788 $img_filename = '1x1t.gif';
1789 }
9f78501e 1790
03522bd8
AA
1791 echo "<tr class='row_$order'>";
1792 $order = $nextorder[$order];
1793 echo '<td>' . $pn;
1794 echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">';
1795 echo '<td>' . $link['status'];
1796 $info = '';
1797 if (isset ($link['speed']))
1798 $info .= $link['speed'];
1799 if (isset ($link['duplex']))
1800 {
1801 if (! empty ($info))
1802 $info .= ', ';
1803 $info .= $link['duplex'];
65e557dd 1804 }
03522bd8
AA
1805 echo '<td>' . $info;
1806 echo '</tr>';
65e557dd 1807 }
03522bd8
AA
1808 echo "</table></td>";
1809 finishPortlet();
65e557dd
AA
1810 }
1811
65e557dd
AA
1812 if (! empty ($macList))
1813 {
1814 echo "<td valign='top' width='50%'>";
1815 $rendered_macs = '';
1816 $mac_count = 0;
1817 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>";
1818 $order = 'even';
1819 foreach ($macList as $pn => $list)
1820 {
1821 $order = $nextorder[$order];
1822 foreach ($list as $item)
1823 {
1824 ++$mac_count;
1825 $rendered_macs .= "<tr class='row_$order'>";
1826 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'];
1827 $rendered_macs .= '<td>' . $item['vid'];
1828 $rendered_macs .= '<td>' . $pn;
1829 $rendered_macs .= '</tr>';
1830 }
1831 }
1832 $rendered_macs .= "</table></td>";
dec748f6 1833
65e557dd
AA
1834 startPortlet("Learned MACs ($mac_count)");
1835 echo $rendered_macs;
1836 finishPortlet();
1837 }
1838
1839 echo "</td></tr></table>";
1840}
1841
e673ee24 1842/*
51c18782 1843The following conditions must be met:
e673ee24
DO
18441. We can mount onto free atoms only. This means: if any record for an atom
1845already exists in RackSpace, it can't be used for mounting.
18462. We can't unmount from 'W' atoms. Operator should review appropriate comments
1847and either delete them before unmounting or refuse to unmount the object.
1848*/
7e1db771 1849function renderRackSpaceForObject ($object_id)
e673ee24 1850{
e673ee24
DO
1851 // Always process occupied racks plus racks chosen by user. First get racks with
1852 // already allocated rackspace...
51c18782 1853 $workingRacksData = getResidentRacksData ($object_id);
e673ee24 1854 // ...and then add those chosen by user (if any).
2135fd83 1855 if (isset($_REQUEST['rackmulti']))
e673ee24 1856 foreach ($_REQUEST['rackmulti'] as $cand_id)
e673ee24
DO
1857 if (!isset ($workingRacksData[$cand_id]))
1858 {
0cc24e9a 1859 $rackData = spotEntity ('rack', $cand_id);
61a1d996 1860 amplifyCell ($rackData);
e673ee24
DO
1861 $workingRacksData[$cand_id] = $rackData;
1862 }
51690ad4 1863
0a7feebb
AD
1864 // Get a list of all of this object's parents,
1865 // then trim the list to only include parents which are racks
1866 $objectParents = getEntityRelatives('parents', 'object', $object_id);
1867 $parentRacks = array();
1868 foreach ($objectParents as $parentData)
1869 if ($parentData['entity_type'] == 'rack')
1870 $parentRacks[] = $parentData['entity_id'];
1871
e673ee24
DO
1872 // Main layout starts.
1873 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
1874
1875 // Left portlet with rack list.
1876 echo "<td class=pcleft height='1%'>";
1877 startPortlet ('Racks');
a8efc03e 1878 $allRacksData = listCells ('rack');
6d42599c
AA
1879
1880 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
1881 if (! isset ($_REQUEST['show_all_racks']) and getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
1882 {
1883 $matching_racks = array();
1884 $object = spotEntity ('object', $object_id);
1885 $matched_tags = array();
1886 foreach ($allRacksData as $rack)
1887 foreach ($object['etags'] as $tag)
1888 if (tagOnChain ($tag, $rack['etags']) or tagOnChain ($tag, $rack['itags']))
1889 {
1890 $matching_racks[$rack['id']] = $rack;
1891 $matched_tags[$tag['id']] = $tag;
1892 break;
1893 }
1894 // add current object's racks even if they dont match filter
1895 foreach ($workingRacksData as $rack_id => $rack)
1896 if (! isset ($matching_racks[$rack_id]))
1897 $matching_racks[$rack_id] = $rack;
1898 // if matching racks found, and rack list is reduced, show 'show all' link
1899 if (count ($matching_racks) and count ($matching_racks) != count ($allRacksData))
1900 {
1901 $filter_text = '';
1902 foreach ($matched_tags as $tag)
1903 $filter_text .= (empty ($filter_text) ? '' : ' or ') . '{' . $tag['tag'] . '}';
1904 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
1905 $href_show_all .= htmlspecialchars('&show_all_racks=1');
1906 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
1907 $allRacksData = $matching_racks;
1908 }
1909 }
1910
4b8d413e 1911 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
61a1d996 1912 foreach ($allRacksData as $rack)
51c18782
DO
1913 if (!array_key_exists ($rack['id'], $workingRacksData))
1914 {
1915 amplifyCell ($rack);
1916 $workingRacksData[$rack['id']] = $rack;
1917 }
1918 foreach (array_keys ($workingRacksData) as $rackId)
1919 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
1920 printOpFormIntro ('updateObjectAllocation');
4b8d413e 1921 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
51c18782 1922 echo "<br><br>";
e673ee24
DO
1923 finishPortlet();
1924 echo "</td>";
1925
1926 // Middle portlet with comment and submit.
1927 echo "<td class=pcleft>";
5c8bf2ba 1928 startPortlet ('Comment (for Rackspace History)');
e673ee24
DO
1929 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
1930 echo "<input type=submit value='Save' name=got_atoms>\n";
51c18782 1931 echo "<br><br>";
e673ee24
DO
1932 finishPortlet();
1933 echo "</td>";
1934
1935 // Right portlet with rendered racks. If this form submit is not final, we have to
1936 // reflect the former state of the grid in current form.
1937 echo "<td class=pcright rowspan=2 height='1%'>";
1938 startPortlet ('Working copy');
65e557dd 1939 addJS ('js/racktables.js');
e673ee24
DO
1940 echo '<table border=0 cellspacing=10 align=center><tr>';
1941 foreach ($workingRacksData as $rack_id => $rackData)
1942 {
1943 // Order is important here: only original allocation is highlighted.
1944 highlightObject ($rackData, $object_id);
1945 markupAtomGrid ($rackData, 'T');
1946 // If we have a form processed, discard user input and show new database
1947 // contents.
51c18782 1948 if (isset ($_REQUEST['rackmulti'][0])) // is an update
e673ee24
DO
1949 mergeGridFormToRack ($rackData);
1950 echo "<td valign=top>";
1951 echo "<center>\n<h2>${rackData['name']}</h2>\n";
1952 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 1953 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
1954 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1955 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1956 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
e673ee24 1957 renderAtomGrid ($rackData);
57c69e9c 1958 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
1959 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1960 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1961 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
0a7feebb
AD
1962 echo "</table>\n<br>\n";
1963 // Determine zero-u checkbox status.
1964 // If form has been submitted, use form data, otherwise use DB data.
dec748f6 1965 if (isset($_REQUEST['op']))
0a7feebb
AD
1966 $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : '';
1967 else
1968 $checked = in_array($rack_id, $parentRacks) ? 'checked' : '';
d141833a 1969 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 1970 echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n";
0a7feebb 1971 echo '</center></td>';
e673ee24
DO
1972 }
1973 echo "</tr></table>";
1974 finishPortlet();
1975 echo "</td>\n";
1976
1977 echo "</form>\n";
1978 echo "</tr></table>\n";
1979}
1980
1981function renderMolecule ($mdata, $object_id)
1982{
1983 // sort data out
1984 $rackpack = array();
1985 global $loclist;
64b95774 1986 foreach ($mdata as $rua)
e673ee24
DO
1987 {
1988 $rack_id = $rua['rack_id'];
1989 $unit_no = $rua['unit_no'];
1990 $atom = $rua['atom'];
1991 if (!isset ($rackpack[$rack_id]))
1992 {
61a1d996
DO
1993 $rackData = spotEntity ('rack', $rack_id);
1994 amplifyCell ($rackData);
e673ee24
DO
1995 for ($i = $rackData['height']; $i > 0; $i--)
1996 for ($locidx = 0; $locidx < 3; $locidx++)
1997 $rackData[$i][$locidx]['state'] = 'F';
1998 $rackpack[$rack_id] = $rackData;
1999 }
2000 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2001 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2002 }
2003 // now we have some racks to render
64b95774 2004 foreach ($rackpack as $rackData)
e673ee24
DO
2005 {
2006 markAllSpans ($rackData);
2007 echo "<table class=molecule cellspacing=0>\n";
2008 echo "<caption>${rackData['name']}</caption>\n";
2009 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
2010 for ($i = $rackData['height']; $i > 0; $i--)
2011 {
4dcd770e 2012 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
e673ee24
DO
2013 for ($locidx = 0; $locidx < 3; $locidx++)
2014 {
2015 $state = $rackData[$i][$locidx]['state'];
65e557dd 2016 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
e673ee24
DO
2017 }
2018 echo "</tr>\n";
2019 }
2020 echo "</table>\n";
2021 }
2022}
2023
23cdc7e9 2024function renderDepot ()
e673ee24 2025{
23cdc7e9 2026 global $pageno, $nextorder;
23cdc7e9
DO
2027 $cellfilter = getCellFilter();
2028 $objects = filterCellList (listCells ('object'), $cellfilter['expression']);
2029
2030 echo "<table border=0 class=objectview>\n";
2031 echo "<tr><td class=pcleft>";
2032
1ebbf889 2033 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
e673ee24 2034 {
4899096d 2035 if (count($objects) > 0)
1ebbf889 2036 {
4899096d
AD
2037 startPortlet ('Objects (' . count ($objects) . ')');
2038 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
b09a8280 2039 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
4899096d 2040 $order = 'odd';
3f8a25d6
DO
2041 # gather IDs of all objects and fetch rackspace info in one pass
2042 $idlist = array();
2043 foreach ($objects as $obj)
2044 $idlist[] = $obj['id'];
2045 $mountinfo = getMountInfo ($idlist);
4899096d
AD
2046 foreach ($objects as $obj)
2047 {
ad3e5e7e 2048 echo "<tr class='row_${order} tdleft' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
4899096d
AD
2049 if (count ($obj['etags']))
2050 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
4318ced5
AA
2051 echo "</td><td>${obj['label']}</td>";
2052 echo "<td>${obj['asset_no']}</td>";
3f8a25d6 2053 $places = array();
b09a8280 2054 if ($obj['container_id'])
86dad907 2055 $places[] = mkA ($obj['container_dname'], 'object', $obj['container_id']);
b09a8280 2056 elseif (! array_key_exists ($obj['id'], $mountinfo))
3f8a25d6 2057 $places[] = 'Unmounted';
4899096d 2058 else
3f8a25d6
DO
2059 foreach ($mountinfo[$obj['id']] as $mi)
2060 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
4318ced5 2061 echo "<td>" . implode (', ', $places) . '</td>';
4899096d
AD
2062 echo '</tr>';
2063 $order = $nextorder[$order];
2064 }
2065 echo '</table>';
2066 finishPortlet();
1ebbf889 2067 }
4899096d
AD
2068 else
2069 echo '<h2>No objects exist</h2>';
e673ee24 2070 }
23cdc7e9
DO
2071
2072 echo "</td><td class=pcright width='25%'>";
2073
95857b5c 2074 renderCellFilterPortlet ($cellfilter, 'object', $objects);
23cdc7e9 2075 echo "</td></tr></table>\n";
e673ee24
DO
2076}
2077
1ebbf889
AA
2078// This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2079// In this case it renders the describing message instead.
2080function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2081{
2082 if (!$cellfilter['is_empty'])
2083 return FALSE;
2084 if (isset ($_REQUEST['show_all_objects']))
2085 return FALSE;
2086 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2087 if (0 == $max || $count <= $max)
2088 return FALSE;
2089
2090 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2091 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2092 $suffix = isset ($count) ? " ($count)" : '';
2093 echo <<<END
2094<p>Please set a filter to display the corresponging $entities_name.
2095<br><a href="$href_show_all">Show all $entities_name$suffix</a>
2096END;
2097 return TRUE;
2098}
2099
e673ee24 2100// History viewer for history-enabled simple dictionaries.
9b8174d7 2101function renderObjectHistory ($object_id)
e673ee24 2102{
e673ee24
DO
2103 $order = 'odd';
2104 global $nextorder;
9b8174d7
AD
2105 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2106 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>';
2107 $result = usePreparedSelectBlade
2108 (
2109 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2110 array ($object_id)
2111 );
e673ee24
DO
2112 while ($row = $result->fetch (PDO::FETCH_NUM))
2113 {
2114 echo "<tr class=row_${order}><td>${row[0]}</td>";
9b8174d7 2115 for ($i = 1; $i <= 6; $i++)
e673ee24
DO
2116 echo "<td>" . $row[$i] . "</td>";
2117 echo "</tr>\n";
2118 $order = $nextorder[$order];
2119 }
2120 echo "</table><br>\n";
2121}
2122
2123function renderRackspaceHistory ()
2124{
4fbb5a00 2125 global $nextorder, $pageno, $tabno;
e673ee24
DO
2126 $order = 'odd';
2127 $history = getRackspaceHistory();
2128 // Show the last operation by default.
2129 if (isset ($_REQUEST['op_id']))
2130 $op_id = $_REQUEST['op_id'];
2131 elseif (isset ($history[0]['mo_id']))
2132 $op_id = $history[0]['mo_id'];
2133 else $op_id = NULL;
dec748f6 2134
e673ee24
DO
2135 $omid = NULL;
2136 $nmid = NULL;
2137 $object_id = 1;
2138 if ($op_id)
2139 list ($omid, $nmid) = getOperationMolecules ($op_id);
2140
2141 // Main layout starts.
2142 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2143
2144 // Left top portlet with old allocation.
2145 echo "<tr><td class=pcleft>";
2146 startPortlet ('Old allocation');
2147 if ($omid)
2148 {
2149 $oldMolecule = getMolecule ($omid);
2150 renderMolecule ($oldMolecule, $object_id);
2151 }
2152 else
2153 echo "nothing";
2154 finishPortlet();
2155
2156 echo '</td><td class=pcright>';
2157
2158 // Right top portlet with new allocation
2159 startPortlet ('New allocation');
2160 if ($nmid)
2161 {
2162 $newMolecule = getMolecule ($nmid);
2163 renderMolecule ($newMolecule, $object_id);
2164 }
2165 else
2166 echo "nothing";
2167 finishPortlet();
737a3f72 2168
e673ee24 2169 echo '</td></tr><tr><td colspan=2>';
737a3f72 2170
e673ee24
DO
2171 // Bottom portlet with list
2172
2173 startPortlet ('Rackspace allocation history');
2174 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
7fa7047a 2175 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
e673ee24
DO
2176 foreach ($history as $row)
2177 {
2178 if ($row['mo_id'] == $op_id)
2179 $class = 'hl';
2180 else
2181 $class = "row_${order}";
4fbb5a00 2182 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
7fa7047a
DO
2183 echo "<td>${row['user_name']}</td><td>";
2184 renderCell (spotEntity ('object', $row['ro_id']));
9c6222ef 2185 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
e673ee24
DO
2186 $order = $nextorder[$order];
2187 }
2188 echo "</table>\n";
2189 finishPortlet();
737a3f72 2190
e673ee24 2191 echo '</td></tr></table>';
e673ee24
DO
2192}
2193
4318ced5 2194function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
d65353ad
DO
2195{
2196 $self = __FUNCTION__;
4318ced5 2197 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
00276508
AA
2198
2199 // scroll page to the highlighted item
2200 if ($target && isset ($_REQUEST['hl_net']))
65e557dd 2201 addAutoScrollScript ("net-$target");
00276508 2202
d65353ad
DO
2203 foreach ($tree as $item)
2204 {
4318ced5
AA
2205 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'))
2206 loadIPAddrList ($item); // necessary to compute router list and address counter
2207
0137d53c
DO
2208 if (isset ($item['id']))
2209 {
1f54e1ba 2210 $decor = array ('indent' => $level);
fec0c8da 2211 if ($item['symbol'] == 'node-collapsed')
4318ced5 2212 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
fec0c8da 2213 elseif ($item['symbol'] == 'node-expanded')
4318ced5
AA
2214 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
2215 $tr_class = '';
21ee3351 2216 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
64347dcf 2217 {
5c717ce5 2218 $decor['tdclass'] = ' highlight';
4318ced5 2219 $tr_class = $decor['tdclass'];
64347dcf 2220 }
4318ced5
AA
2221 echo "<tr valign=top class=\"$tr_class\">";
2222 printIPNetInfoTDs ($item, $decor);
2223
2224 // capacity and usage
2225 echo "<td class=tdcenter>";
2226 echo getRenderedIPNetCapacity ($item);
64347dcf 2227 echo "</td>";
4318ced5
AA
2228
2229 if ($display_routers)
4a47d34b 2230 printRoutersTD (findRouters ($item['addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
0137d53c 2231 echo "</tr>";
fec0c8da 2232 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
4318ced5 2233 $self ($item['kids'], $baseurl, $target, $level + 1);
0137d53c
DO
2234 }
2235 else
2236 {
4318ced5 2237 // non-allocated (spare) IP range
0137d53c 2238 echo "<tr valign=top>";
21ee3351 2239 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
00276508 2240
4318ced5 2241 // capacity and usage
21ee3351 2242 echo "<td class=tdcenter>";
4318ced5 2243 echo getRenderedIPNetCapacity ($item);
21ee3351 2244 echo "</td>";
4318ced5
AA
2245 if ($display_routers)
2246 echo "<td></td>";
21ee3351 2247 echo "</tr>";
21ee3351 2248 }
21ee3351
AA
2249 }
2250}
2251
4318ced5 2252function renderIPSpace()
e673ee24 2253{
4fbb5a00 2254 global $pageno, $tabno;
4318ced5 2255 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
31c941ec 2256 $cellfilter = getCellFilter();
4318ced5
AA
2257 $top = NULL;
2258 $netlist = array();
2259 foreach (listCells ($realm) as $net)
2260 {
2261 if (isset ($top) and IPNetContains ($top, $net))
2262 ;
2263 elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression']))
2264 $top = $net;
1ebbf889 2265 else
4318ced5
AA
2266 continue;
2267 $netlist[$net['id']] = $net;
5388794d 2268 }
21ee3351
AA
2269 $netcount = count ($netlist);
2270 // expand request can take either natural values or "ALL". Zero means no expanding.
2271 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
4318ced5 2272 $tree = prepareIPTree ($netlist, $eid);
21ee3351
AA
2273
2274 echo "<table border=0 class=objectview>\n";
2275 echo "<tr><td class=pcleft>";
4318ced5 2276 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
21ee3351
AA
2277 {
2278 startPortlet ("networks (${netcount})");
2279 echo '<h4>';
4318ced5
AA
2280 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2281 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2282 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2283 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2284 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2285 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2286
21ee3351 2287 if ($eid === 0)
4318ced5 2288 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
21ee3351 2289 elseif ($eid === 'ALL')
4318ced5
AA
2290 echo "expanding all ($auto / $none)";
2291 elseif ($eid === 'NONE')
2292 echo "collapsing all ($all / $auto)";
21ee3351
AA
2293 else
2294 {
4318ced5
AA
2295 $netinfo = spotEntity ($realm, $eid);
2296 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
21ee3351
AA
2297 }
2298 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2299 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
4318ced5 2300 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
21ee3351
AA
2301 echo "<th>routed by</th>";
2302 echo "</tr>\n";
2303 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
4318ced5 2304 renderIPSpaceRecords ($tree, $baseurl, $eid);
21ee3351
AA
2305 echo "</table>\n";
2306 finishPortlet();
2307 }
2308
2309 echo '</td><td class=pcright>';
4318ced5 2310 renderCellFilterPortlet ($cellfilter, 'ipv4net', $netlist);
21ee3351
AA
2311 echo "</td></tr></table>\n";
2312}
2313
4318ced5 2314function renderIPSpaceEditor()
21ee3351 2315{
4318ced5
AA
2316 global $pageno;
2317 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2318 $net_page = $realm; // 'ipv4net', 'ipv6net'
2319 $addrspaceList = listCells ($realm);
93a49e5b
AA
2320 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2321 if (count ($addrspaceList))
21ee3351 2322 {
21ee3351
AA
2323 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2324 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
21ee3351
AA
2325 foreach ($addrspaceList as $netinfo)
2326 {
21ee3351 2327 echo "<tr valign=top><td>";
93a49e5b 2328 if (! isIPNetworkEmpty ($netinfo))
21ee3351
AA
2329 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2330 else
93a49e5b 2331 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
ad3e5e7e 2332 echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>';
1f54e1ba
DO
2333 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2334 if (count ($netinfo['etags']))
2335 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2336 echo '</td><td>';
4318ced5 2337 echo getRenderedIPNetCapacity ($netinfo);
b1e39212 2338 echo '</tr>';
e673ee24 2339 }
04d619d0
DO
2340 echo "</table>";
2341 finishPortlet();
e673ee24 2342 }
93a49e5b
AA
2343}
2344
2345function renderIPNewNetForm ()
2346{
2347 global $pageno;
2348 if ($pageno == 'ipv6space')
2349 {
2350 $realm = 'ipv6net';
3495ec6e 2351 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
93a49e5b
AA
2352 }
2353 else
2354 {
2355 $realm = 'ipv4net';
3495ec6e 2356 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
93a49e5b
AA
2357 }
2358
2359 // IP prefix validator
2360 addJs ('js/live_validation.js');
2361 $regexp = addslashes ($regexp);
2362 addJs (<<<END
2363$(document).ready(function () {
2364 document.add_new_range.range.setAttribute('match', '$regexp');
2365 Validate.init();
2366});
2367END
2368 , TRUE);
dec748f6 2369
93a49e5b
AA
2370 startPortlet ('Add new');
2371 echo '<table border=0 cellpadding=10 align=center>';
2372 // This form requires a name, so JavaScript validator can find it.
2373 // No printOpFormIntro() hence
d0d40671 2374 echo "<form method=post name='add_new_range' action='".makeHrefProcess(array ('op'=>'add'))."'>\n";
93a49e5b
AA
2375 // tags column
2376 echo '<tr><td rowspan=5><h3>assign tags</h3>';
2377 renderNewEntityTags ($realm);
2378 echo '</td>';
2379 // inputs column
2380 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
2381 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>";
2382 echo '<tr><th class=tdright>VLAN</th><td class=tdleft>';
2383 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical', 'tabindex' => 2)) . '</td></tr>';
2384 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=3></td></tr>";
2385 echo '<tr><td class=tdright><input type=checkbox name="is_connected" tabindex=4></td><th class=tdleft>reserve subnet-router anycast address</th></tr>';
2386 echo "<tr><td colspan=2>";
2387 printImageHREF ('CREATE', 'Add a new network', TRUE, 5);
2388 echo '</td></tr>';
2389 echo "</form></table><br><br>\n";
2390 finishPortlet();
e673ee24
DO
2391}
2392
4318ced5 2393function getRenderedIPNetBacktrace ($range)
e673ee24 2394{
4318ced5
AA
2395 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2396 return array();
e673ee24 2397
4318ced5
AA
2398 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2399 $space = "ipv${v}space"; // ipv4space, ipv6space
2400 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
dec748f6 2401
4318ced5
AA
2402 $ret = array();
2403 // Build a backtrace from all parent networks.
2404 $clen = $range['mask'];
2405 $backtrace = array();
2406 $backtrace['&rarr;'] = $range;
2407 $key = '';
2408 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2409 {
2410 $upperinfo = spotEntity ($range['realm'], $upperid);
2411 $clen = $upperinfo['mask'];
2412 $key .= '&uarr;';
2413 $backtrace[$key] = $upperinfo;
2414 }
2415 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2416 {
2417 $link = '<a href="' . makeHref (array (
2418 'page' => $space,
2419 'tab' => 'default',
2420 'clear-cf' => '',
2421 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2422 'hl_net' => 1,
2423 'eid' => $range['id'],
2424 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2425 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2426 }
2427 return $ret;
2428}
2429
2430function renderIPNetwork ($id)
2431{
2432 global $pageno;
2433 $realm = $pageno; // 'ipv4net', 'ipv6net'
2434 $range = spotEntity ($realm, $id);
2435 loadIPAddrList ($range);
2034d968 2436 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
99ab184f
DO
2437 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2438 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2034d968
DO
2439
2440 echo "<tr><td class=pcleft width='50%'>";
646272be
AA
2441
2442 // render summary portlet
2443 $summary = array();
4318ced5 2444 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2b6b0038 2445 $summary = getRenderedIPNetBacktrace ($range) + $summary;
4318ced5 2446 if ($realm == 'ipv4net')
001e61fa 2447 {
4318ced5
AA
2448 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2449 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2450 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
001e61fa 2451 }
dec748f6 2452
11e3af31
DO
2453 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2454 $domainclass = array();
2455 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2456 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
a5f9d1ca 2457 foreach ($range['8021q'] as $item)
11e3af31 2458 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVLANInfo ($item['domain_id'] . '-' . $item['vlan_id'])));
3a4f4023 2459 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findRouters ($range['addrlist'])))
04d619d0 2460 {
646272be
AA
2461 $summary['Routed by'] = '';
2462 foreach ($routers as $rtr)
4318ced5 2463 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
04d619d0 2464 }
646272be
AA
2465 $summary['tags'] = '';
2466 renderEntitySummary ($range, 'summary', $summary);
e1ae3fb4 2467
99ab184f
DO
2468 if (strlen ($range['comment']))
2469 {
2470 startPortlet ('Comment');
2471 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2472 finishPortlet ();
2473 }
2474
4318ced5 2475 renderFilesPortlet ($realm, $id);
2034d968 2476 echo "</td>\n";
e673ee24 2477
2034d968
DO
2478 echo "<td class=pcright>";
2479 startPortlet ('details');
4318ced5
AA
2480 renderIPNetworkAddresses ($range);
2481 finishPortlet();
2482 echo "</td></tr></table>\n";
2483}
e673ee24 2484
4318ced5
AA
2485// Used solely by renderSeparator
2486function renderEmptyIPv6 ($ip_bin, $hl_ip)
2487{
2488 $class = 'tdleft';
2489 if ($ip_bin === $hl_ip)
5c717ce5 2490 $class .= ' highlight';
4318ced5
AA
2491 $fmt = ip6_format ($ip_bin);
2492 echo "<tr class='$class'><td><a class='ancor' name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
0b8d8309
AA
2493 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2494 ? 'editable'
2495 : '';
cc2fa820
AD
2496 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2497 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
4318ced5
AA
2498}
2499
2500// Renders empty table line to shrink empty IPv6 address ranges.
2501// If the range consists of single address, renders the address instead of empty line.
2502// Renders address $hl_ip inside the range.
2503// Used solely by renderIPv6NetworkAddresses
2504function renderSeparator ($first, $last, $hl_ip)
2505{
2506 $self = __FUNCTION__;
2507 if (strcmp ($first, $last) > 0)
2508 return;
2509 if ($first == $last)
2510 renderEmptyIPv6 ($first, $hl_ip);
2511 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2512 { // $hl_ip is inside the range $first - $last
2513 $self ($first, ip_prev ($hl_ip), $hl_ip);
2514 renderEmptyIPv6 ($hl_ip, $hl_ip);
2515 $self (ip_next ($hl_ip), $last, $hl_ip);
2516 }
2517 else
cc2fa820 2518 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
4318ced5
AA
2519}
2520
2521// calculates page number which contains given $ip (used by renderIPv6NetworkAddresses)
2522function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2523{
2524 if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage)
2525 return 0;
2526 $keys = array_keys ($list);
2527 for ($i = 1; $i <= count ($keys); $i++)
2528 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2529 return intval ($i / $maxperpage);
2530 return intval (count ($list) / $maxperpage);
2531}
2532
2533function renderIPNetworkAddresses ($range)
2534{
2535 switch (strlen ($range['ip_bin']))
2536 {
2537 case 4: return renderIPv4NetworkAddresses ($range);
2538 case 16: return renderIPv6NetworkAddresses ($range);
2539 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2540 }
2541}
2542
2543function renderIPv4NetworkAddresses ($range)
2544{
2545 global $pageno, $tabno, $aac2;
2546 $startip = ip4_bin2int ($range['ip_bin']);
2547 $endip = ip4_bin2int (ip_last ($range));
2548
2549 if (isset ($_REQUEST['hl_ip']))
00276508 2550 {
4318ced5
AA
2551 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2552 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
00276508
AA
2553 }
2554
79b57b18
AA
2555 // pager
2556 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2557 $address_count = $endip - $startip + 1;
2558 $page = 0;
446c25c3 2559 $rendered_pager = '';
79b57b18
AA
2560 if ($address_count > $maxperpage && $maxperpage > 0)
2561 {
2562 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2563 if ($numpages = ceil ($address_count / $maxperpage))
2564 {
4318ced5 2565 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
79b57b18
AA
2566 for ($i = 0; $i < $numpages; $i++)
2567 if ($i == $page)
446c25c3 2568 $rendered_pager .= "<b>$i</b> ";
79b57b18 2569 else
4318ced5 2570 $rendered_pager .= "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $range['id'], 'pg' => $i)) . "'>$i</a> ";
79b57b18
AA
2571 }
2572 $startip = $startip + $page * $maxperpage;
2573 $endip = min ($startip + $maxperpage - 1, $endip);
2574 }
2575
446c25c3 2576 echo $rendered_pager;
beb9e88a 2577 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2578 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
e673ee24 2579
4318ced5
AA
2580 markupIPAddrList ($range['addrlist']);
2581 for ($ip = $startip; $ip <= $endip; $ip++)
2582 {
2583 $ip_bin = ip4_int2bin ($ip);
2584 $dottedquad = ip4_format ($ip_bin);
5c717ce5 2585 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
0cd7c0f6
AA
2586 if (isset ($range['addrlist'][$ip_bin]))
2587 $addr = $range['addrlist'][$ip_bin];
2588 else
e673ee24 2589 {
4318ced5 2590 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
2591 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2592 ? 'editable'
2593 : '';
cc2fa820
AD
2594 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
2595 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
b2035dca
DO
2596 continue;
2597 }
68c91b9c
AA
2598 // render IP change history
2599 $title = '';
2600 $history_class = '';
2601 if (isset ($addr['last_log']))
2602 {
2603 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2604 $history_class = 'hover-history underline';
2605 }
4318ced5
AA
2606 $tr_class .= ' ' . $addr['class'];
2607 echo "<tr class='tdleft $tr_class'>";
2608 echo "<td><a class='ancor $history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
0b8d8309 2609 $editable =
cc2fa820 2610 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
0b8d8309
AA
2611 && permitted ('ipaddress', 'properties', 'editAddress')
2612 ? 'editable'
2613 : '';
cc2fa820
AD
2614 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
2615 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
0b8d8309 2616 echo "<td>";
b2035dca 2617 $delim = '';
b2035dca
DO
2618 if ( $addr['reserved'] == 'yes')
2619 {
2d318652 2620 echo "<strong>RESERVED</strong> ";
b2035dca
DO
2621 $delim = '; ';
2622 }
212b565a 2623 foreach ($addr['allocs'] as $ref)
b2035dca 2624 {
beb9e88a 2625 echo $delim . $aac2[$ref['type']];
4318ced5 2626 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
59a83bd8 2627 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
b2035dca
DO
2628 echo "${ref['object_name']}</a>";
2629 $delim = '; ';
2630 }
2631 if ($delim != '')
e0d6e38e 2632 $delim = '<br>';
212b565a
AA
2633 foreach ($addr['vslist'] as $vs_id)
2634 {
2635 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2636 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
212b565a
AA
2637 $delim = '<br>';
2638 }
2639 foreach ($addr['rsplist'] as $rsp_id)
2640 {
2641 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2642 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
212b565a
AA
2643 $delim = '<br>';
2644 }
b2035dca 2645 echo "</td></tr>\n";
4318ced5 2646 }
2727c7df 2647 // end of iteration
a8dc2982
AA
2648 if (permitted (NULL, NULL, 'set_reserve_comment'))
2649 addJS ('js/inplace-edit.js');
e673ee24
DO
2650
2651 echo "</table>";
446c25c3
AA
2652 if (! empty ($rendered_pager))
2653 echo '<p>' . $rendered_pager . '</p>';
21ee3351
AA
2654}
2655
2656function renderIPv6NetworkAddresses ($netinfo)
2657{
2658 global $pageno, $tabno, $aac2;
2659 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2660 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
21ee3351 2661
4318ced5
AA
2662 $hl_ip = NULL;
2663 if (isset ($_REQUEST['hl_ip']))
2664 {
2665 $hl_ip = ip6_parse ($_REQUEST['hl_ip']);
2666 addAutoScrollScript ('ip-' . ip6_format ($hl_ip));
2667 }
21ee3351 2668
21ee3351
AA
2669 $addresses = $netinfo['addrlist'];
2670 ksort ($addresses);
4318ced5 2671 markupIPAddrList ($addresses);
21ee3351
AA
2672
2673 // pager
2674 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2675 if (count ($addresses) > $maxperpage && $maxperpage > 0)
2676 {
2677 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0);
2678 $numpages = ceil (count ($addresses) / $maxperpage);
2679 echo "<center><h3>$numpages pages:</h3>";
2680 for ($i=0; $i<$numpages; $i++)
2681 {
2682 if ($i == $page)
2683 echo "<b>$i</b> ";
2684 else
2685 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> ";
2686 }
2687 echo "</center>";
2688 }
2689
2690 $i = 0;
dec748f6 2691 $interruped = FALSE;
4318ced5
AA
2692 $prev_ip = ip_prev ($netinfo['ip_bin']);
2693 foreach ($addresses as $ip_bin => $addr)
21ee3351
AA
2694 {
2695 if (isset ($page))
2696 {
2697 ++$i;
2698 if ($i <= $maxperpage * $page)
2699 continue;
2700 elseif ($i > $maxperpage * ($page + 1))
2701 {
2702 $interruped = TRUE;
2703 break;
2704 }
2705 }
2706
4318ced5
AA
2707 if ($ip_bin != ip_next ($prev_ip))
2708 renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip);
2709 $prev_ip = $ip_bin;
2710
2711 // render IP change history
2712 $title = '';
2713 $history_class = '';
2714 if (isset ($addr['last_log']))
2715 {
2716 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2717 $history_class = 'hover-history underline';
2718 }
2719
5c717ce5 2720 $tr_class = $addr['class'] . ' tdleft' . ($hl_ip === $ip_bin ? ' highlight' : '');
4318ced5
AA
2721 echo "<tr class='$tr_class'>";
2722 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
2723 $editable =
2724 (empty ($addr['allocs']) || !empty ($addr['name'])
2725 && permitted ('ipaddress', 'properties', 'editAddress')
2726 ? 'editable'
2727 : '');
cc2fa820
AD
2728 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-name'>${addr['name']}</span></td>";
2729 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-comment'>${addr['comment']}</span></td><td>";
21ee3351 2730 $delim = '';
21ee3351
AA
2731 if ( $addr['reserved'] == 'yes')
2732 {
2733 echo "<strong>RESERVED</strong> ";
2734 $delim = '; ';
2735 }
2736 foreach ($addr['allocs'] as $ref)
2737 {
2738 echo $delim . $aac2[$ref['type']];
71066ef1 2739 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
21ee3351
AA
2740 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
2741 echo "${ref['object_name']}</a>";
2742 $delim = '; ';
2743 }
2744 if ($delim != '')
71066ef1
AA
2745 $delim = '<br>';
2746 foreach ($addr['vslist'] as $vs_id)
2747 {
2748 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2749 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
71066ef1
AA
2750 $delim = '<br>';
2751 }
2752 foreach ($addr['rsplist'] as $rsp_id)
21ee3351 2753 {
71066ef1 2754 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 2755 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
71066ef1 2756 $delim = '<br>';
21ee3351
AA
2757 }
2758 echo "</td></tr>\n";
2759 }
2760 if (! $interruped)
4318ced5 2761 renderSeparator (ip_next ($prev_ip), ip_last ($netinfo), $hl_ip);
21ee3351
AA
2762 if (isset ($page))
2763 { // bottom pager
2764 echo "<tr><td colspan=3>";
2765 if ($page > 0)
2766 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page - 1)) . "'><< prev</a> ";
2767 if ($page < $numpages - 1)
2768 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page + 1)) . "'>next >></a> ";
2769 echo "</td></tr>";
2770 }
2771 echo "</table>";
a8dc2982
AA
2772 if (permitted (NULL, NULL, 'set_reserve_comment'))
2773 addJS ('js/inplace-edit.js');
21ee3351
AA
2774}
2775
2776function renderIPNetworkProperties ($id)
e673ee24 2777{
21ee3351
AA
2778 global $pageno;
2779 $netdata = spotEntity ($pageno, $id);
53ef3908 2780 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
e673ee24 2781 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 2782 printOpFormIntro ('editRange');
99ab184f
DO
2783 echo '<tr><td class=tdright><label for=nameinput>Name:</label></td>';
2784 echo "<td class=tdleft><input type=text name=name id=nameinput size=80 maxlength=255 value='";
2785 echo htmlspecialchars ($netdata['name'], ENT_QUOTES, 'UTF-8') . "'></tr>";
2786 echo '<tr><td class=tdright><label for=commentinput>Comment:</label></td>';
2787 echo "<td class=tdleft><textarea name=comment id=commentinput cols=80 rows=25>\n";
2788 echo htmlspecialchars ($netdata['comment'], ENT_QUOTES, 'UTF-8') . "</textarea></tr>";
53ef3908
DO
2789 echo "<tr><td colspan=2 class=tdcenter>";
2790 printImageHREF ('SAVE', 'Save changes', TRUE);
2791 echo "</td></form></tr></table>\n";
93a49e5b
AA
2792
2793 echo '<center>';
2794 if (! isIPNetworkEmpty ($netdata))
2795 echo getOpLink (NULL, 'delete this prefix', 'nodestroy', 'There are ' . count ($netdata['addrlist']) . ' allocations inside');
2796 else
2797 echo getOpLink (array('op'=>'del','id'=>$id), 'delete this prefix', 'destroy');
2798 echo '</center>';
e673ee24
DO
2799}
2800
09a531eb 2801function renderIPAddress ($ip_bin)
e673ee24 2802{
46098972 2803 global $aat, $nextorder;
09a531eb 2804 $address = getIPAddress ($ip_bin);
68225375 2805 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
21ee3351 2806 echo "<tr><td colspan=2 align=center><h1>${address['ip']}</h1></td></tr>\n";
e673ee24 2807
68225375 2808 echo "<tr><td class=pcleft>";
dec748f6 2809
defd92d8 2810 $summary = array();
423c4216 2811 if (strlen ($address['name']))
cc2fa820
AD
2812 $summary['Name'] = $address['name'];
2813 if (strlen ($address['comment']))
2814 $summary['Comment'] = $address['comment'];
defd92d8
AA
2815 $summary['Reserved'] = $address['reserved'];
2816 $summary['Allocations'] = count ($address['allocs']);
4318ced5 2817 if (isset ($address['outpf']))
defd92d8 2818 $summary['Originated NAT connections'] = count ($address['outpf']);
4318ced5 2819 if (isset ($address['inpf']))
defd92d8 2820 $summary['Arriving NAT connections'] = count ($address['inpf']);
defd92d8 2821 renderEntitySummary ($address, 'summary', $summary);
dec748f6 2822
212b565a 2823 // render SLB portlet
4318ced5 2824 if (! empty ($address['vslist']) or ! empty ($address['rsplist']))
212b565a
AA
2825 {
2826 startPortlet ("");
2827 if (! empty ($address['vslist']))
2828 {
2829 printf ("<h2>virtual services (%d):</h2>", count ($address['vslist']));
2830 foreach ($address['vslist'] as $vs_id)
2831 renderSLBEntityCell (spotEntity ('ipv4vs', $vs_id));
2832 }
2833
2834 if (! empty ($address['rsplist']))
2835 {
2836 printf ("<h2>RS pools (%d):</h2>", count ($address['rsplist']));
2837 foreach ($address['rsplist'] as $rsp_id)
2838 renderSLBEntityCell (spotEntity ('ipv4rspool', $rsp_id));
2839 }
2840 finishPortlet();
2841 }
68225375 2842 echo "</td>\n";
e673ee24 2843
68225375 2844 echo "<td class=pcright>";
defd92d8 2845 if (isset ($address['class']) and ! empty ($address['allocs']))
59bebe2b 2846 {
8e700dd1 2847 startPortlet ('allocations');
2d318652
DO
2848 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2849 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2d318652 2850 // render all allocation records for this address the same way
2d318652 2851 foreach ($address['allocs'] as $bond)
59bebe2b 2852 {
4318ced5 2853 $tr_class = "${address['class']} tdleft";
8e700dd1 2854 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
5c717ce5 2855 $tr_class .= ' highlight';
4318ced5
AA
2856 echo "<tr class='$tr_class'>" .
2857 "<td><a href='" . makeHref (array ('page' => 'object', 'object_id' => $bond['object_id'], 'tab' => 'default', 'hl_ip' => $address['ip'])) . "'>${bond['object_name']}</td>" .
2858 "<td>${bond['name']}</td>" .
2859 "<td><strong>" . $aat[$bond['type']] . "</strong></td>" .
2860 "</tr>\n";
59bebe2b
DO
2861 }
2862 echo "</table><br><br>";
2863 finishPortlet();
2864 }
e673ee24 2865
4318ced5 2866 if (! empty ($address['vslist']) or ! empty ($address['rsplist']))
defd92d8 2867 renderSLBTriplets ($address);
5fe1ed76 2868
7419401e
AA
2869 foreach (array ('outpf' => 'departing NAT rules', 'inpf' => 'arriving NAT rules') as $key => $title)
2870 if (! empty ($address[$key]))
2871 {
2872 startPortlet ($title);
2873 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2874 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2875 foreach ($address[$key] as $rule)
2876 {
2877 echo "<tr>";
2878 echo "<td>" . $rule['proto'] . "</td>";
2879 echo "<td>" . getRenderedIPPortPair ($rule['localip'], $rule['localport']) . "</td>";
2880 echo "<td>" . getRenderedIPPortPair ($rule['remoteip'], $rule['remoteport']) . "</td>";
2881 echo "<td>" . $rule['description'] . "</td></tr>";
2882 echo "</tr>";
2883 }
2884 echo "</table>";
2885 finishPortlet();
2886 }
105a3bc8 2887
68225375
DO
2888 echo "</td></tr>";
2889 echo "</table>\n";
e673ee24
DO
2890}
2891
09a531eb 2892function renderIPAddressProperties ($ip_bin)
e673ee24 2893{
09a531eb 2894 $address = getIPAddress ($ip_bin);
21ee3351 2895 echo "<center><h1>${address['ip']}</h1></center>\n";
7056988c 2896
1fbc9fd6 2897 startPortlet ('update');
e673ee24 2898 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 2899 printOpFormIntro ('editAddress');
0186638b
DO
2900 echo '<tr><td class=tdright><label for=id_name>Name:</label></td>';
2901 echo "<td class=tdleft><input type=text name=name id=id_name size=20 value='${address['name']}'></tr>";
cc2fa820
AD
2902 echo '<tr><td class=tdright><label for=id_comment>Comment:</label></td>';
2903 echo "<td class=tdleft><input type=text name=comment id=id_comment size=20 value='${address['comment']}'></tr>";
0186638b
DO
2904 echo '<td class=tdright><label for=id_reserved>Reserved:</label></td>';
2905 echo "<td class=tdleft><input type=checkbox name=reserved id=id_reserved size=20 ";
2d318652 2906 echo ($address['reserved']=='yes') ? 'checked' : '';
f3d274bf 2907 echo "></tr><tr><td class=tdleft>";
53ef3908 2908 printImageHREF ('SAVE', 'Save changes', TRUE);
f3d274bf 2909 echo "</td></form><td class=tdright>";
59a83bd8 2910 if (!strlen ($address['name']) and $address['reserved'] == 'no')
f3d274bf
DO
2911 printImageHREF ('CLEAR gray');
2912 else
2913 {
18a77e3c 2914 printOpFormIntro ('editAddress', array ('name' => '', 'reserved' => '', 'comment' => ''));
f3d274bf
DO
2915 printImageHREF ('CLEAR', 'Release', TRUE);
2916 echo "</form>";
2917 }
2918 echo "</td></tr></table>\n";
1fbc9fd6 2919 finishPortlet();
e673ee24
DO
2920}
2921
09a531eb 2922function renderIPAddressAllocations ($ip_bin)
e673ee24 2923{
4318ced5 2924 function printNewItemTR ()
39b4abd0
DO
2925 {
2926 global $aat;
4318ced5 2927 printOpFormIntro ('add');
39b4abd0 2928 echo "<tr><td>";
9318d2ef 2929 printImageHREF ('add', 'allocate', TRUE);
8d4f7d18 2930 echo "</td><td>";
31babb65 2931 printSelect (getNarrowObjectList ('IPV4OBJ_LISTSRC'), array ('name' => 'object_id', 'tabindex' => 100));
8d4f7d18 2932 echo "</td><td><input type=text tabindex=101 name=bond_name size=10></td><td>";
01abf1de 2933 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102, 'regular'));
9318d2ef 2934 echo "</td><td>";
f5ff50f5 2935 printImageHREF ('add', 'allocate', TRUE, 103);
9318d2ef 2936 echo "</td></form></tr>";
39b4abd0 2937 }
b82cce3f 2938 global $aat;
e673ee24 2939
09a531eb 2940 $address = getIPAddress ($ip_bin);
21ee3351 2941 echo "<center><h1>${address['ip']}</h1></center>\n";
105a3bc8 2942 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2d318652 2943 echo "<tr><th>&nbsp;</th><th>object</th><th>OS interface</th><th>allocation type</th><th>&nbsp;</th></tr>\n";
e673ee24 2944
39b4abd0 2945 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
4318ced5 2946 printNewItemTR();
f74d96c6 2947 if (isset ($address['class']))
e673ee24 2948 {
f74d96c6
DO
2949 $class = $address['class'];
2950 if ($address['reserved'] == 'yes')
2951 echo "<tr class='${class}'><td colspan=3>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td><td>&nbsp;</td></tr>";
2952 foreach ($address['allocs'] as $bond)
2953 {
2954 echo "<tr class='$class'>";
4318ced5 2955 printOpFormIntro ('upd', array ('object_id' => $bond['object_id']));
21ee3351
AA
2956 echo "<td><a href='"
2957 . makeHrefProcess
2958 (