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