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