r2206 - try one more art for tree
[racktables] / inc / interface.php
CommitLineData
b325120a 1<?php
e673ee24
DO
2/*
3*
4* This file contains frontend functions for RackTables.
5*
6*/
7
9c0b0016
DO
8// Interface function's special.
9$nextorder['odd'] = 'even';
10$nextorder['even'] = 'odd';
11
52c836b1
DO
12// address allocation type
13$aat = array
14(
15 'regular' => 'Connected',
16 'virtual' => 'Loopback',
17 'shared' => 'Shared',
18 'router' => 'Router',
19);
beb9e88a 20// address allocation code, IPv4 addresses and objects view
52c836b1
DO
21$aac = array
22(
23 'regular' => '',
24 'virtual' => '<strong>L</strong>',
25 'shared' => '<strong>S</strong>',
26 'router' => '<strong>R</strong>',
27);
beb9e88a
DO
28// address allocation code, IPv4 networks view
29$aac2 = array
30(
31 'regular' => '',
32 'virtual' => '<strong>L:</strong>',
33 'router' => '<strong>R:</strong>',
34);
52c836b1 35
7056988c
DO
36// Let's have it here, so extensions can add their own images.
37$image = array();
38$image['error']['path'] = 'pix/error.png';
39$image['error']['width'] = 76;
40$image['error']['height'] = 17;
41$image['logo']['path'] = 'pix/defaultlogo.png';
42$image['logo']['width'] = 210;
43$image['logo']['height'] = 40;
44$image['rackspace']['path'] = 'pix/racks.png';
45$image['rackspace']['width'] = 218;
46$image['rackspace']['height'] = 200;
47$image['objects']['path'] = 'pix/server.png';
48$image['objects']['width'] = 218;
49$image['objects']['height'] = 200;
50$image['ipv4space']['path'] = 'pix/addressspace.png';
51$image['ipv4space']['width'] = 218;
52$image['ipv4space']['height'] = 200;
53$image['ipv4slb']['path'] = 'pix/slb.png';
54$image['ipv4slb']['width'] = 218;
55$image['ipv4slb']['height'] = 200;
56$image['config']['path'] = 'pix/configuration.png';
57$image['config']['width'] = 218;
58$image['config']['height'] = 200;
59$image['reports']['path'] = 'pix/report.png';
60$image['reports']['width'] = 218;
61$image['reports']['height'] = 200;
62$image['useup']['path'] = 'pix/tango-edit-clear.png';
63$image['useup']['width'] = 16;
64$image['useup']['height'] = 16;
65$image['link']['path'] = 'pix/tango-network-wired.png';
66$image['link']['width'] = 16;
67$image['link']['height'] = 16;
68$image['unlink']['path'] = 'pix/tango-edit-clear.png';
69$image['unlink']['width'] = 16;
70$image['unlink']['height'] = 16;
71$image['add']['path'] = 'pix/tango-list-add.png';
72$image['add']['width'] = 16;
73$image['add']['height'] = 16;
74$image['delete']['path'] = 'pix/tango-list-remove.png';
75$image['delete']['width'] = 16;
76$image['delete']['height'] = 16;
77$image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
78$image['nodelete']['width'] = 16;
79$image['nodelete']['height'] = 16;
80$image['grant'] = $image['add'];
81$image['revoke'] = $image['delete'];
82$image['inservice']['path'] = 'pix/tango-emblem-system.png';
83$image['inservice']['width'] = 16;
84$image['inservice']['height'] = 16;
85$image['notinservice']['path'] = 'pix/tango-dialog-error.png';
86$image['notinservice']['width'] = 16;
87$image['notinservice']['height'] = 16;
88$image['blockuser'] = $image['inservice'];
89$image['unblockuser'] = $image['notinservice'];
90$image['find']['path'] = 'pix/tango-system-search.png';
91$image['find']['width'] = 16;
92$image['find']['height'] = 16;
93$image['spacer']['path'] = 'pix/pixel.png';
94$image['spacer']['width'] = 16;
95$image['spacer']['height'] = 16;
96$image['next']['path'] = 'pix/tango-go-next.png';
97$image['next']['width'] = 32;
98$image['next']['height'] = 32;
99$image['prev']['path'] = 'pix/tango-go-previous.png';
100$image['prev']['width'] = 32;
101$image['prev']['height'] = 32;
102$image['clear']['path'] = 'pix/tango-edit-clear.png';
103$image['clear']['width'] = 16;
104$image['clear']['height'] = 16;
61a61189
DO
105$image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
106$image['CLEAR']['width'] = 32;
107$image['CLEAR']['height'] = 32;
7056988c
DO
108$image['save']['path'] = 'pix/tango-document-save.png';
109$image['save']['width'] = 16;
110$image['save']['height'] = 16;
111$image['SAVE']['path'] = 'pix/tango-document-save-big.png';
112$image['SAVE']['width'] = 32;
113$image['SAVE']['height'] = 32;
114$image['create']['path'] = 'pix/tango-document-new.png';
115$image['create']['width'] = 16;
116$image['create']['height'] = 16;
117$image['CREATE']['path'] = 'pix/tango-document-new-big.png';
118$image['CREATE']['width'] = 32;
119$image['CREATE']['height'] = 32;
120$image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
121$image['DENIED']['width'] = 32;
122$image['DENIED']['height'] = 32;
d28d7f4d
DO
123$image['apply']['path'] = 'pix/tango-emblem-system.png';
124$image['apply']['width'] = 16;
125$image['apply']['height'] = 16;
737a3f72
DO
126$image['node-collapsed']['path'] = 'pix/node-collapsed.png';
127$image['node-collapsed']['width'] = 16;
128$image['node-collapsed']['height'] = 16;
129$image['node-expanded']['path'] = 'pix/node-expanded.png';
130$image['node-expanded']['width'] = 16;
131$image['node-expanded']['height'] = 16;
7056988c 132
e5c4506d
DO
133// This may be populated later onsite, report rendering function will use it.
134// See the $systemreport for structure.
135$localreports = array();
136
e673ee24
DO
137// Main menu.
138function renderIndex ()
139{
140 global $root;
141?>
142<table border=0 cellpadding=0 cellspacing=0 width='100%'>
143 <tr>
144 <td>
145 <div style='text-align: center; margin: 10px; '>
146 <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
147 <tr>
148 <td>
b325120a
DO
149 <h1><a href='<?php echo $root; ?>?page=rackspace'>Rackspace<br>
150 <?php printImageHREF ('rackspace'); ?></a></h1>
e673ee24
DO
151 </td>
152 <td>
b325120a
DO
153 <h1><a href='<?php echo $root; ?>?page=objects'>Objects<br>
154 <?php printImageHREF ('objects'); ?></a></h1>
e673ee24
DO
155 </td>
156 <td>
b325120a
DO
157 <h1><a href='<?php echo $root; ?>?page=ipv4space'>IPv4 space<br>
158 <?php printImageHREF ('ipv4space'); ?></a></h1>
e673ee24
DO
159 </td>
160 </tr>
161 </table>
162 <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
163 <tr>
164 <td>
b325120a
DO
165 <h1><a href='<?php echo $root; ?>?page=config'>Configuration<br>
166 <?php printImageHREF ('config'); ?></a></h1>
e673ee24
DO
167 </td>
168 <td>
da95280e 169 <h1><a href='<?php echo $root; ?>?page=reports'>Reports<br>
b325120a 170 <?php printImageHREF ('reports'); ?></a></h1>
e673ee24 171 </td>
ae545907 172 <td>
f973f491
DO
173 <h1><a href='<?php echo $root; ?>?page=ipv4slb'>IPv4 SLB<br>
174 <?php printImageHREF ('ipv4slb'); ?></a></h1>
ae545907 175 </td>
e673ee24
DO
176 </tr>
177 </table>
178 </div>
179 </td>
180 </tr>
181</table>
b325120a 182<?php
e673ee24
DO
183}
184
185function renderRackspace ()
186{
932cf41f 187 $tagfilter = getTagFilter();
094a8e6e 188 $tagfilter_str = getTagFilterStr ($tagfilter);
489a7502
DO
189 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
190 renderTagFilterPortlet ($tagfilter, 'rack');
191 echo '</td><td class=pcright>';
192 echo '<table border=0 cellpadding=10 cellpadding=1>';
e673ee24 193 // generate thumb gallery
489a7502 194 $rackrowList = getRackspace ($tagfilter);
9c0b0016 195 global $root, $nextorder;
d5157018 196 $rackwidth = getRackImageWidth();
e673ee24
DO
197 $order = 'odd';
198 foreach ($rackrowList as $rackrow)
199 {
84466afa 200 echo "<tr class=row_${order}><th class=tdleft>";
a0d54e7e
DO
201 echo "<a href='${root}?page=row&row_id=${rackrow['row_id']}${tagfilter_str}'>";
202 echo "${rackrow['row_name']}</a></th>";
203 $rackList = getRacksForRow ($rackrow['row_id'], $tagfilter);
e673ee24 204 echo "<td><table border=0 cellspacing=5><tr>";
64b95774 205 foreach ($rackList as $rack)
e673ee24
DO
206 {
207 echo "<td align=center><a href='${root}?page=rack&rack_id=${rack['id']}'>";
208 echo "<img border=0 width=${rackwidth} height=";
d5157018 209 echo getRackImageHeight ($rack['height']);
e673ee24 210 echo " title='${rack['height']} units'";
d2ec5490 211 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
e673ee24
DO
212 echo "<br>${rack['name']}</a></td>";
213 }
214 echo "</tr></table></tr>\n";
215 $order = $nextorder[$order];
216 }
217 echo "</table>\n";
489a7502 218 echo "</td></tr></table>\n";
e673ee24
DO
219}
220
d5157018 221function renderRow ($row_id = 0)
e673ee24
DO
222{
223 if ($row_id == 0)
224 {
39a6338a 225 showError ('Invalid row_id', __FUNCTION__);
e673ee24
DO
226 return;
227 }
228 if (($rowInfo = getRackRowInfo ($row_id)) == NULL)
229 {
39a6338a 230 showError ('getRackRowInfo() failed', __FUNCTION__);
e673ee24
DO
231 return;
232 }
a0d54e7e
DO
233 $tagfilter = getTagFilter();
234 $rackList = getRacksForRow ($row_id, $tagfilter);
e673ee24
DO
235 // Main layout starts.
236 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
237
238 // Left portlet with row information.
239 echo "<tr><td class=pcleft>";
a8ce7234 240 startPortlet ($rowInfo['name']);
e673ee24 241 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
e673ee24
DO
242 echo "<tr><th width='50%' class=tdright>Racks:</th><td class=tdleft>${rowInfo['count']}</td></tr>\n";
243 echo "<tr><th width='50%' class=tdright>Units:</th><td class=tdleft>${rowInfo['sum']}</td></tr>\n";
04d619d0 244 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
114e50af
DO
245 renderProgressBar (getRSUforRackRow ($rackList));
246 echo "</td></tr>\n";
e673ee24
DO
247 echo "</table><br>\n";
248 finishPortlet();
249
a0d54e7e 250 echo "</td><td class=pcright rowspan=2>";
e673ee24 251
9c0b0016 252 global $root, $nextorder;
d5157018 253 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
e673ee24
DO
254 $order = 'odd';
255 startPortlet ('Racks');
256 echo "<table border=0 cellspacing=5 align='center'><tr>";
64b95774 257 foreach ($rackList as $rack)
e673ee24
DO
258 {
259 echo "<td align=center class=row_${order}><a href='${root}?page=rack&rack_id=${rack['id']}'>";
d5157018 260 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
e673ee24 261 echo " title='${rack['height']} units'";
d2ec5490 262 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
e673ee24
DO
263 echo "<br>${rack['name']}</a></td>";
264 $order = $nextorder[$order];
265 }
266 echo "</tr></table>\n";
267 finishPortlet();
a0d54e7e 268 echo "</td></tr>";
e673ee24 269
a0d54e7e
DO
270 echo "<tr><td class=pcleft>";
271 renderTagFilterPortlet ($tagfilter, 'rack', 'row_id', $row_id);
e673ee24
DO
272 echo "</td></tr></table>";
273}
274
04f110a0 275function showError ($info = '', $location = 'N/A')
e673ee24
DO
276{
277 global $root;
04f110a0
DO
278 if (preg_match ('/\.php$/', $location))
279 $location = basename ($location);
280 elseif ($location != 'N/A')
281 $location = $location . '()';
282 echo "<div class=msg_error>An error has occured in [${location}]. ";
e673ee24
DO
283 if (empty ($info))
284 echo 'No additional information is available.';
285 else
286 echo "Additional information:<br><p>\n<pre>\n${info}\n</pre></p>";
287 echo "Go back or try starting from <a href='${root}'>index page</a>.<br></div>\n";
288}
289
290// This function renders rack as HTML table.
291function renderRack ($rack_id = 0, $hl_obj_id = 0)
292{
293 if ($rack_id == 0)
294 {
39a6338a 295 showError ('Invalid rack_id', __FUNCTION__);
e673ee24
DO
296 return;
297 }
298 if (($rackData = getRackData ($rack_id)) == NULL)
299 {
39a6338a 300 showError ('getRackData() failed', __FUNCTION__);
e673ee24
DO
301 return;
302 }
303 global $root, $pageno, $tabno;
304 markAllSpans ($rackData);
305 if ($hl_obj_id > 0)
306 highlightObject ($rackData, $hl_obj_id);
307 markupObjectProblems ($rackData);
308 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
309 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
d48d8820
DO
310 echo "<center><table border=0><tr valign=middle>";
311 echo "<td><h2><a href='${root}?page=row&row_id=${rackData['row_id']}'>${rackData['row_name']}</a> :</h2></td>";
e673ee24
DO
312 // FIXME: use 'bypass'?
313 if ($prev_id != NULL)
9803c56c 314 {
d48d8820 315 echo "<td><a href='${root}?page=rack&rack_id=${prev_id}'>";
9803c56c 316 printImageHREF ('prev', 'previous rack');
d48d8820 317 echo "</a></td>";
9803c56c 318 }
d48d8820 319 echo "<td><h2><a href='${root}?page=rack&rack_id=${rackData['id']}'>${rackData['name']}</a></h2></td>";
e673ee24 320 if ($next_id != NULL)
9803c56c 321 {
d48d8820 322 echo "<td><a href='${root}?page=rack&rack_id=${next_id}'>";
f444c095 323 printImageHREF ('next', 'next rack');
d48d8820 324 echo "</a></td>";
9803c56c 325 }
d48d8820 326 echo "</h2></td></tr></table>\n";
1c81a02c
DO
327 if ($rackData['left_is_front'] == 'yes')
328 $markup = array ('left' => 'Front', 'right' => 'Back');
329 else
330 $markup = array ('left' => 'Back', 'right' => 'Front');
e673ee24 331 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
9ddfe309
DO
332 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>${markup['left']}</th>";
333 echo "<th width='50%'>Interior</th><th width='20%'>${markup['right']}</th></tr>\n";
e673ee24
DO
334 for ($i = $rackData['height']; $i > 0; $i--)
335 {
9ddfe309 336 echo '<tr><th>' . ($rackData['bottom_is_unit1'] == 'yes' ? $i : $rackData['height'] - $i + 1) . '</th>';
e673ee24
DO
337 for ($locidx = 0; $locidx < 3; $locidx++)
338 {
339 if (isset ($rackData[$i][$locidx]['skipped']))
340 continue;
341 $state = $rackData[$i][$locidx]['state'];
342 echo "<td class=state_${state}";
343 if (isset ($rackData[$i][$locidx]['hl']))
344 echo $rackData[$i][$locidx]['hl'];
345 if (isset ($rackData[$i][$locidx]['colspan']))
346 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
347 if (isset ($rackData[$i][$locidx]['rowspan']))
348 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
349 echo ">";
350 switch ($state)
351 {
352 case 'T':
353 $objectData = getObjectInfo ($rackData[$i][$locidx]['object_id']);
354 if (!empty ($objectData['asset_no']))
355 $prefix = "<div title='${objectData['asset_no']}";
356 else
357 $prefix = "<div title='no asset tag";
358 // Don't tell about label, if it matches common name.
359 if ($objectData['name'] != $objectData['label'] and !empty ($objectData['label']))
360 $suffix = ", visible label is \"${objectData['label']}\"'>";
361 else
362 $suffix = "'>";
363 echo $prefix . $suffix;
364 echo "<a href='${root}?page=object&object_id=${objectData['id']}'>${objectData['dname']}</a></div>";
365 break;
366 case 'A':
367 echo '<div title="This rackspace does not exist">&nbsp;</div>';
368 break;
369 case 'F':
370 echo '<div title="Free rackspace">&nbsp;</div>';
371 break;
372 case 'U':
373 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
374 break;
375 default:
376 echo '<div title="No data">&nbsp;</div>';
377 break;
378 }
379 echo '</td>';
380 }
381 echo "</tr>\n";
382 }
383 echo "</table></center>\n";
384}
385
e673ee24
DO
386function renderNewRackForm ($row_id)
387{
f19c75d6 388 showMessageOrError();
f19c75d6 389
50b4ba85 390 startPortlet ('Add one');
f19c75d6 391 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
e673ee24 392 echo '<table border=0 align=center>';
b901bf1f
DO
393 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
394 if ($defh == 0)
395 $defh = '';
72d52730
DO
396 echo "<tr><th class=tdright>Rack name (*):</th><td class=tdleft><input type=text name=rack_name tabindex=1></td>";
397 echo "<td rowspan=4>Assign tags:<br>";
398 renderTagSelect();
399 echo "</td></tr>\n";
b8094ae4 400 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height1 tabindex=2 value='${defh}'></td></tr>\n";
4134b5c0 401 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment tabindex=3></td></tr>\n";
f19c75d6
DO
402 echo "<tr><td class=submit colspan=2>";
403 printImageHREF ('CREATE', 'Add', TRUE);
404 echo "</td></tr></table></form>";
406b54bd 405 finishPortlet();
406b54bd 406
50b4ba85 407 startPortlet ('Add many');
f19c75d6 408 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
50b4ba85
DO
409 echo '<table border=0 align=center>';
410 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
411 if ($defh == 0)
412 $defh = '';
72d52730
DO
413 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height2 value='${defh}'></td>";
414 echo "<td rowspan=3 valign=top>Assign tags:<br>";
415 renderTagSelect();
416 echo "</td></tr>\n";
50b4ba85 417 echo "<tr><th class=tdright>Rack names (*):</th><td class=tdleft><textarea name=rack_names cols=40 rows=25></textarea></td></tr>\n";
f19c75d6
DO
418 echo "<tr><td class=submit colspan=2>";
419 printImageHREF ('CREATE', 'Add', TRUE);
e673ee24
DO
420 echo '</form></table>';
421 finishPortlet();
422}
423
424function renderEditObjectForm ($object_id)
425{
426 showMessageOrError();
e673ee24 427
22bb04da 428 global $pageno, $tabno, $root;
e673ee24
DO
429 $object = getObjectInfo ($object_id);
430 if ($object == NULL)
431 {
39a6338a 432 showError ('getObjectInfo() failed', __FUNCTION__);
e673ee24
DO
433 return;
434 }
e673ee24
DO
435 echo '<table border=0 width=100%><tr>';
436
437 echo '<td class=pcleft>';
438 startPortlet ('Static attributes');
43fb6eaf 439 printOpFormIntro ('update');
e673ee24
DO
440 echo '<table border=0 align=center>';
441 echo "<tr><th class=tdright>Type:</th><td class=tdleft>";
442 printSelect (getObjectTypeList(), 'object_type_id', $object['objtype_id']);
443 echo "</td></tr>\n";
22bb04da 444 // baseline info
e673ee24
DO
445 echo "<tr><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
446 echo "<tr><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
447 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
448 echo "<tr><th class=tdright>Barcode:</th><td class=tdleft><input type=text name=object_barcode value='${object['barcode']}'></td></tr>\n";
449 echo "<tr><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
450 if ($object['has_problems'] == 'yes')
451 echo ' checked';
452 echo "></td></tr>\n";
453 echo "<tr><td colspan=2><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
5bbbeaa2
DO
454 echo "<tr><th class=submit colspan=2>";
455 printImageHREF ('SAVE', 'Save changes', TRUE);
456 echo "</td></tr>\n";
e673ee24
DO
457 echo '</form></table><br>';
458 finishPortlet();
459 echo '</td>';
460
22bb04da 461 // stickers
e673ee24
DO
462 echo '<td class=pcright>';
463 startPortlet ('Optional attributes');
464 $values = getAttrValues ($object_id);
e673ee24
DO
465 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
466 echo "<tr><th>&nbsp;</th><th>Attribute</th><th>Value</th><th>&nbsp;</th></tr>\n";
43fb6eaf 467 printOpFormIntro ('updateStickers');
0dfb8a2a
DO
468 echo '<input type=hidden name=num_attrs value=' . count($values) . ">\n";
469
470 $i = 0;
e673ee24
DO
471 foreach ($values as $record)
472 {
0dfb8a2a 473 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
0c4605ab 474 echo '<tr><td>';
ca1fec24 475 if (!empty ($record['value']))
0c4605ab 476 {
22bb04da 477 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=clearSticker&object_id=${object_id}&attr_id=${record['id']}'>";
d48d8820 478 printImageHREF ('clear', 'Clear value');
0c4605ab
DO
479 echo '</a>';
480 }
481 else
d48d8820 482 echo '&nbsp;';
0c4605ab 483 echo '</td>';
e673ee24
DO
484 echo "<td class=tdright>${record['name']}:</td><td class=tdleft>";
485 switch ($record['type'])
486 {
487 case 'uint':
488 case 'float':
489 case 'string':
0dfb8a2a 490 echo "<input type=text name=${i}_value value='${record['value']}'>";
e673ee24
DO
491 break;
492 case 'dict':
493 $chapter = readChapter ($record['chapter_name']);
4c330a14 494 $chapter[0] = '-- NOT SET --';
0dfb8a2a 495 printSelect ($chapter, "${i}_value", $record['key']);
e673ee24
DO
496 break;
497 }
0dfb8a2a
DO
498 echo "</td></tr>\n";
499 $i++;
e673ee24 500 }
5bbbeaa2
DO
501 echo "<tr><td colspan=3>";
502 printImageHREF ('SAVE', 'Save changes', TRUE);
503 echo "</td></tr>\n";
0dfb8a2a 504 echo "</form>";
e673ee24
DO
505 echo "</table>\n";
506 finishPortlet();
507 echo '</td>';
508
509 echo '</tr><tr>';
510
511 echo '<td colspan=2>';
512 startPortlet ('history');
513 renderHistory ($pageno, $object_id);
514 finishPortlet();
515 echo '</td>';
516
517 echo '</tr></table>';
518}
519
520// This is a clone of renderEditObjectForm().
521function renderEditRackForm ($rack_id)
522{
0c2b7c4a
DO
523 showMessageOrError();
524 global $pageno;
e673ee24
DO
525 $rack = getRackData ($rack_id);
526 if ($rack == NULL)
527 {
39a6338a 528 showError ('getRackData() failed', __FUNCTION__);
e673ee24
DO
529 return;
530 }
531
e673ee24 532 startPortlet ('Rack attributes');
7056988c 533 printOpFormIntro ('updateRack');
e673ee24
DO
534 echo '<table border=0 align=center>';
535 echo "<tr><th class=tdright>Rack row:</th><td class=tdleft>";
4c330a14 536 printSelect (readChapter ('RackRow'), 'rack_row_id', $rack['row_id']);
e673ee24
DO
537 echo "</td></tr>\n";
538 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=rack_name value='${rack['name']}'></td></tr>\n";
539 echo "<tr><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=rack_height value='${rack['height']}'></td></tr>\n";
540 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment value='${rack['comment']}'></td></tr>\n";
7056988c
DO
541 echo "<tr><td class=submit colspan=2>";
542 printImageHREF ('SAVE', 'Save changes', TRUE);
543 echo "</td></tr>\n";
e673ee24
DO
544 echo '</form></table><br>';
545 finishPortlet();
546
547 startPortlet ('History');
548 renderHistory ($pageno, $rack_id);
549 finishPortlet();
550}
551
552// This is a helper for creators and editors.
553function printSelect ($rowList, $select_name, $selected_id = 1)
554{
9e7f32a7
DO
555 // First collect all data for OPTGROUPs, then ouput it and dump
556 // the rest of records as is.
557 $optgroup = array();
558 $other = array();
4c330a14 559 foreach ($rowList as $dict_key => $dict_value)
e673ee24 560 {
f0b540a3 561 if (strpos ($dict_value, '%GSKIP%') !== FALSE)
9e7f32a7 562 {
f0b540a3 563 $tmp = explode ('%GSKIP%', $dict_value, 2);
9e7f32a7
DO
564 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
565 }
f0b540a3 566 elseif (strpos ($dict_value, '%GPASS%') !== FALSE)
2613bc1c 567 {
f0b540a3 568 $tmp = explode ('%GPASS%', $dict_value, 2);
2613bc1c
DO
569 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
570 }
9e7f32a7
DO
571 else
572 $other[$dict_key] = $dict_value;
573 }
574 echo "<select name=${select_name}>";
575 if (!count ($optgroup))
576 {
577 foreach ($other as $dict_key => $dict_value)
578 {
579 echo "<option value=${dict_key}";
580 if ($dict_key == $selected_id)
581 echo ' selected';
582 echo ">${dict_value}</option>";
583 }
584 }
585 else
586 {
587 foreach ($optgroup as $groupname => $groupdata)
588 {
589 echo "<optgroup label='${groupname}'>";
590 foreach ($groupdata as $dict_key => $dict_value)
591 {
592 echo "<option value=${dict_key}";
593 if ($dict_key == $selected_id)
594 echo ' selected';
595 echo ">${dict_value}</option>";
596 }
597 echo "</optgroup>\n";
598 }
599 if (count ($other))
600 {
601 echo "<optgroup label='other'>\n";
602 foreach ($other as $dict_key => $dict_value)
603 {
604 echo "<option value=${dict_key}";
605 if ($dict_key == $selected_id)
606 echo ' selected';
607 echo ">${dict_value}</option>";
608 }
609 echo "</optgroup>\n";
610 }
e673ee24
DO
611 }
612 echo "</select>";
613}
614
254673dd
DO
615// used by renderGridForm() and renderRackPage()
616function renderRackInfoPortlet ($rackData)
617{
d9c609c4 618 global $root;
254673dd
DO
619 startPortlet ('summary');
620 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
621 echo "<tr><th width='50%' class=tdright>Rack row:</th><td class=tdleft>${rackData['row_name']}</td></tr>\n";
622 echo "<tr><th width='50%' class=tdright>Name:</th><td class=tdleft>${rackData['name']}</td></tr>\n";
623 echo "<tr><th width='50%' class=tdright>Height:</th><td class=tdleft>${rackData['height']}</td></tr>\n";
04d619d0 624 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
254673dd
DO
625 renderProgressBar (getRSUforRack ($rackData));
626 echo "</td></tr>\n";
627 echo "<tr><th width='50%' class=tdright>Objects:</th><td class=tdleft>";
abef7149 628 echo count (stuffInRackspace ($rackData));
254673dd 629 echo "</td></tr>\n";
e2ac59cf 630 printTagTRs ("${root}?page=rackspace&");
254673dd
DO
631 if (!empty ($rackData['comment']))
632 echo "<tr><th width='50%' class=tdright>Comment:</th><td class=tdleft>${rackData['comment']}</td></tr>\n";
633 echo '</table>';
634 finishPortlet();
635}
636
e673ee24 637// This is a universal editor of rack design/waste.
7056988c 638// FIXME: switch to using printOpFormIntro()
bb09cca0 639function renderGridForm ($rack_id = 0, $filter, $header, $submit, $state1, $state2)
e673ee24
DO
640{
641 if ($rack_id == 0)
642 {
591ff2c4 643 showError ('Invalid rack_id', __FUNCTION__);
e673ee24
DO
644 return;
645 }
646 if (($rackData = getRackData ($rack_id)) == NULL)
647 {
591ff2c4 648 showError ('getRackData() failed', __FUNCTION__);
e673ee24
DO
649 return;
650 }
651
652 global $root, $pageno, $tabno;
254673dd 653 $filter ($rackData);
e673ee24
DO
654 markupObjectProblems ($rackData);
655
656 // Process form submit.
657 if (isset ($_REQUEST['do_update']))
658 {
659 $log[] = processGridForm ($rackData, $state1, $state2);
254673dd
DO
660 printLog ($log);
661 $rackData = getRackData ($rack_id);
662 $filter ($rackData);
663 markupObjectProblems ($rackData);
e673ee24
DO
664 }
665
666 // Render the result whatever it is.
667 // Main layout.
668 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
669 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
670
671 // Left column with information portlet.
672 echo "<tr><td class=pcleft height='1%' width='50%'>";
254673dd 673 renderRackInfoPortlet ($rackData);
e673ee24 674 echo "</td>\n";
bb09cca0 675 echo "<td class=pcright>";
e673ee24
DO
676
677 // Grid form.
678 startPortlet ($header);
679 echo "<center>\n";
680 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
681 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
682 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
9d479d56 683 echo "<form method=post action='${root}?'>\n";
e673ee24
DO
684 echo "<input type=hidden name=page value=${pageno}>\n";
685 echo "<input type=hidden name=tab value=${tabno}>\n";
686 echo "<input type=hidden name=rack_id value=${rack_id}>\n";
687 markupAtomGrid ($rackData, $state2);
688 renderAtomGrid ($rackData);
689 echo "</table></center>\n";
690 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
691 finishPortlet();
bb09cca0 692 echo "</td></tr></table>\n";
e673ee24
DO
693}
694
695function renderRackDesign ($rack_id)
696{
bb09cca0 697 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
e673ee24
DO
698}
699
700function renderRackProblems ($rack_id = 0)
701{
bb09cca0 702 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
e673ee24
DO
703}
704
705function startPortlet ($title = '')
706{
707 echo "<div class=portlet><h2>${title}</h2>";
708}
709
710function finishPortlet ()
711{
712 echo "</div>\n";
713}
714
715function printRefsOfType ($refs, $type, $eq)
716{
717 global $root;
718 $gotone=0;
719 foreach ($refs as $ref)
720 {
721 if ($eq($ref['type'], $type))
722 {
723 if ($gotone) echo ', ';
4b2bf583
DO
724 echo "<a href='${root}?page=object&object_id=${ref['object_id']}'>";
725 if (!empty ($ref['name']))
726 echo $ref['name'] . '@';
727 echo "${ref['object_name']}</a>";
e673ee24
DO
728 $gotone=1;
729 }
730 }
731}
732
733function renderRackObject ($object_id = 0)
734{
52c836b1 735 global $root, $nextorder, $aac;
e673ee24
DO
736 if ($object_id <= 0)
737 {
591ff2c4 738 showError ('Invalid object_id', __FUNCTION__);
e673ee24
DO
739 return;
740 }
741 $info = getObjectInfo ($object_id);
742 if ($info == NULL)
743 {
591ff2c4 744 showError ('getObjectInfo() failed', __FUNCTION__);
e673ee24
DO
745 return;
746 }
747 // Main layout starts.
748 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
749 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
750 // left column with uknown number of portlets
751 echo "<tr><td class=pcleft>";
0ab782bc 752 startPortlet ('summary');
e673ee24
DO
753 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
754 if (!empty ($info['name']))
755 echo "<tr><th width='50%' class=tdright>Common name:</th><td class=tdleft>${info['name']}</td></tr>\n";
9c0b0016 756 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('NAMEFUL_OBJTYPES'))))
a0ec6295 757 echo "<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>\n";
e2ac59cf 758 echo "<tr><th width='50%' class=tdright>Object type:</th>";
8e700dd1 759 echo "<td class=tdleft><a href='${root}?page=objgroup&group_id=${info['objtype_id']}&hl_object_id=${object_id}'>${info['objtype_name']}</a></td></tr>\n";
e673ee24
DO
760 if (!empty ($info['asset_no']))
761 echo "<tr><th width='50%' class=tdright>Asset tag:</th><td class=tdleft>${info['asset_no']}</td></tr>\n";
a6305acc 762 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('REQUIRE_ASSET_TAG_FOR'))))
a0ec6295 763 echo "<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>\n";
e673ee24
DO
764 if (!empty ($info['label']))
765 echo "<tr><th width='50%' class=tdright>Visible label:</th><td class=tdleft>${info['label']}</td></tr>\n";
766 if (!empty ($info['barcode']))
767 echo "<tr><th width='50%' class=tdright>Barcode:</th><td class=tdleft>${info['barcode']}</td></tr>\n";
768 if ($info['has_problems'] == 'yes')
769 echo "<tr><td colspan=2 class=msg_error>Has problems</td></tr>\n";
24cbe8af 770 foreach (getAttrValues ($object_id, TRUE) as $record)
e673ee24 771 if (!empty ($record['value']))
50a954f6 772 echo "<tr><th width='50%' class=opt_attr_th>${record['name']}:</th><td class=tdleft>${record['a_value']}</td></tr>\n";
e2ac59cf 773 printTagTRs ("${root}?page=objgroup&group_id=${info['objtype_id']}&");
e673ee24
DO
774 echo "</table><br>\n";
775 finishPortlet();
776
777 if (!empty ($info['comment']))
778 {
779 startPortlet ('Comment');
6cc5d6cd 780 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
e673ee24
DO
781 finishPortlet ();
782 }
783
784 $ports = getObjectPortsAndLinks ($object_id);
785 if (count ($ports))
786 {
0ab782bc 787 startPortlet ('ports and links');
e673ee24
DO
788 usort($ports, 'sortByName');
789 if ($ports)
790 {
791 $hl_port_id = 0;
792 if (isset ($_REQUEST['hl_port_id']))
793 {
2c6c7645 794 assertUIntArg ('hl_port_id', __FUNCTION__);
e673ee24
DO
795 $hl_port_id = $_REQUEST['hl_port_id'];
796 }
797 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
798 echo "<tr><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
799 echo "<th>Rem. Object</th><th>Rem. port</th></tr>\n";
800 foreach ($ports as $port)
801 {
802 echo '<tr';
803 if ($hl_port_id == $port['id'])
804 echo ' class=port_highlight';
805 echo "><td>${port['name']}</td><td>${port['label']}</td><td>${port['type']}</td>";
806 echo "<td>${port['l2address']}</td>";
807 if ($port['remote_object_id'])
808 {
8e700dd1 809 echo "<td><a href='${root}?page=object&object_id=${port['remote_object_id']}&hl_port_id=${port['remote_id']}'>${port['remote_object_name']}</a></td>";
e673ee24
DO
810 echo "<td>${port['remote_name']}</td>";
811 }
812 elseif (!empty ($port['reservation_comment']))
813 {
814 echo "<td><b>Reserved;</b></td>";
815 echo "<td>${port['reservation_comment']}</td>";
816 }
817 else
818 echo '<td>&nbsp;</td><td>&nbsp;</td>';
819 echo "</tr>\n";
820 }
821 echo "</table><br>\n";
822 }
823 finishPortlet();
824 }
85970da2 825
0ab782bc
DO
826 $alloclist = getObjectIPv4Allocations ($object_id);
827 if (count ($alloclist))
e673ee24 828 {
f28fbe8b 829 startPortlet ('IPv4 addresses');
e673ee24 830 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
f0ed1181 831 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
71287f1c 832 echo "<tr><th>OS interface</th><th>IP address</th><th colspan=2>network</th><th>routed by</th><th>peers</th></tr>\n";
83fdf85f
DO
833 else
834 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
fc0e3978
DO
835 $hl_ipv4_addr = '';
836 if (isset ($_REQUEST['hl_ipv4_addr']))
837 {
838 assertIPv4Arg ('hl_ipv4_addr', __FUNCTION__);
839 $hl_ipv4_addr = $_REQUEST['hl_ipv4_addr'];
840 }
85970da2 841 foreach ($alloclist as $dottedquad => $alloc)
e673ee24 842 {
0ab782bc
DO
843 $address_name = niftyString ($alloc['addrinfo']['name']);
844 $class = $alloc['addrinfo']['class'];
85970da2 845 $secondclass = ($hl_ipv4_addr == $dottedquad) ? 'tdleft port_highlight' : 'tdleft';
83fdf85f 846 $netid = getIPv4AddressNetworkId ($dottedquad);
71287f1c 847 $netinfo = getIPv4NetworkInfo ($netid);
b6b87070 848 loadIPv4AddrList ($netinfo);
83fdf85f
DO
849 echo "<tr class='${class}' valign=top><td class=tdleft>${alloc['osif']}</td><td class='${secondclass}'>";
850 echo "<a href='${root}?page=ipaddress&ip=" . $dottedquad . "&hl_object_id=${object_id}'>${dottedquad}</a>";
f0ed1181 851 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
83fdf85f
DO
852 {
853 if (NULL === $netid)
854 $suffix = '/??';
855 else
83fdf85f 856 echo '<small>/' . $netinfo['mask'] . '</small>';
83fdf85f 857 }
351b1f45 858 echo '&nbsp;' . $aac[$alloc['type']];
83fdf85f
DO
859 if (!empty ($alloc['addrinfo']['name']))
860 echo '(' . niftyString ($alloc['addrinfo']['name']) . ')';
861 echo '</td>';
f0ed1181 862 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
b90c3907 863 {
83fdf85f 864 if (NULL === $netid)
71287f1c 865 echo '<td colspan=2>?</td>';
83fdf85f 866 else
fd30f6e4 867 printIPv4NetInfoTDs ($netinfo, $secondclass);
71287f1c 868 echo "<td class='${secondclass}'>";
83fdf85f 869 // FIXME: These cals are really heavy, replace them with a more appropriate dedicated function.
83fdf85f 870 $newline = '';
b6b87070 871 foreach (findRouters ($netinfo['addrlist']) as $router)
83fdf85f
DO
872 {
873 if ($router['id'] == $object_id)
874 continue;
875 echo $newline . $router['addr'] . ", <a href='${root}?page=object&object_id=${router['id']}&hl_ipv4_addr=${router['addr']}'>";
876 echo (empty ($router['iface']) ? '' : $router['iface'] . '@') . $router['dname'] . '</a>';
877 $routertags = loadRackObjectTags ($router['id']);
878 if (count ($routertags))
351b1f45 879 echo '<br><small>' . serializeTags ($routertags, "${root}?page=objects&tab=default&") . '</small>';
83fdf85f
DO
880 $newline = '<br>';
881 }
882 echo '</td>';
b90c3907 883 }
83fdf85f 884 // peers
0ab782bc 885 echo "<td class='${secondclass}'>\n";
0ab782bc 886 $prefix = '';
2c817354 887 if ($alloc['addrinfo']['reserved'] == 'yes')
e673ee24 888 {
85970da2 889 echo $prefix . '<strong>RESERVED</strong>';
0ab782bc
DO
890 $prefix = '; ';
891 }
892 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
893 {
894 if ($allocpeer['object_id'] == $object_id)
895 continue;
896 echo $prefix . "<a href='${root}?page=object&object_id=${allocpeer['object_id']}'>";
897 if (!empty ($allocpeer['osif']))
898 echo $allocpeer['osif'] . '@';
899 echo $allocpeer['object_name'] . '</a>';
0ab782bc 900 $prefix = '; ';
e673ee24 901 }
e673ee24
DO
902 echo "</td></tr>\n";
903 }
904 echo "</table><br>\n";
905 finishPortlet();
906 }
907
eeb4a5d8 908 $forwards = getNATv4ForObject ($object_id);
e673ee24
DO
909 if (count($forwards['in']) or count($forwards['out']))
910 {
f28fbe8b 911 startPortlet('NATv4');
e673ee24
DO
912
913 if (count($forwards['out']))
914 {
915
f28fbe8b 916 echo "<h3>locally performed NAT</h3>";
e673ee24 917
105a3bc8 918 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 919 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
920
921 foreach ($forwards['out'] as $pf)
922 {
2c817354
DO
923 $class = 'trerror';
924 $osif = '';
925 if (isset ($alloclist [$pf['localip']]))
926 {
927 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
928 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
929 }
e673ee24 930 echo "<tr class='$class'>";
2c817354 931 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
f28fbe8b 932 echo "<td class=tdleft><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
53ef3908 933 $address = getIPv4Address ($pf['remoteip']);
e673ee24 934 echo "<td class='description'>";
53ef3908
DO
935 if (count ($address['allocs']))
936 foreach($address['allocs'] as $bond)
f28fbe8b
DO
937 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
938 elseif (!empty ($pf['remote_addr_name']))
939 echo '(' . $pf['remote_addr_name'] . ')';
53ef3908 940 echo "</td><td class='description'>${pf['description']}</td></tr>";
e673ee24
DO
941 }
942 echo "</table><br><br>";
943 }
944 if (count($forwards['in']))
945 {
f28fbe8b 946 echo "<h3>arriving NAT connections</h3>";
105a3bc8 947 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 948 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
e673ee24
DO
949 foreach ($forwards['in'] as $pf)
950 {
951 echo "<tr>";
952 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
e673ee24 953 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
e673ee24
DO
954 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
955 echo "<td class='description'>${pf['description']}</td></tr>";
956 }
e673ee24
DO
957 echo "</table><br><br>";
958 }
959 finishPortlet();
960 }
961
78e7b769
DO
962 $pools = getRSPoolsForObject ($object_id);
963 if (count ($pools))
964 {
300826cb 965 $order = 'odd';
78e7b769
DO
966 startPortlet ('Real server pools');
967 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
732e4578 968 echo "<tr><th>VS</th><th>RS pool</th><th>RS</th><th>VS config</th><th>RS config</th></tr>\n";
748805bf 969 foreach ($pools as $vs_id => $info)
78e7b769 970 {
300826cb 971 echo "<tr valign=top class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs_id}'>";
748805bf
DO
972 echo buildVServiceName ($info);
973 echo '</a>';
974 if (!empty ($info['name']))
300826cb 975 echo "<br>${info['name']}";
0e692350 976 echo "</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${info['pool_id']}'>";
748805bf 977 echo (empty ($info['pool_name']) ? 'ANONYMOUS' : $info['pool_name']);
732e4578
DO
978 echo '</a></td><td class=tdleft>' . $info['rscount'] . '</td>';
979 echo "<td class=tdleft><pre>${info['vsconfig']}</pre></td>";
980 echo "<td class=tdleft><pre>${info['rsconfig']}</pre></td>";
78e7b769 981 echo "</tr>\n";
300826cb 982 $order = $nextorder[$order];
78e7b769
DO
983 }
984 echo "</table>\n";
985 finishPortlet();
986 }
e673ee24
DO
987 echo "</td>\n";
988
7056988c 989 // After left column we have (surprise!) right column with rackspace portlet only.
e673ee24
DO
990 echo "<td class=pcright>";
991 // rackspace portlet
0ab782bc 992 startPortlet ('rackspace allocation');
e673ee24
DO
993 // FIXME: now we call getRackData() twice
994 $racks = getResidentRacksData ($object_id);
995 foreach ($racks as $rackData)
996 renderRack ($rackData['id'], $object_id);
997 echo '<br>';
998 finishPortlet();
999 echo "</td></tr>";
1000 echo "</table>\n";
1001}
1002
1003function renderRackMultiSelect ($sname, $racks, $selected)
1004{
04571888
DO
1005 // Transform the given flat list into a list of groups, each representing a rack row.
1006 $rdata = array();
e673ee24 1007 foreach ($racks as $rack)
04571888
DO
1008 if (!isset ($rdata[$rack['row_name']]))
1009 $rdata[$rack['row_name']] = array ($rack['id'] => $rack['name']);
1010 else
1011 $rdata[$rack['row_name']][$rack['id']] = $rack['name'];
1012 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementById(\"racks\").submit()'>\n";
1013 foreach ($rdata as $optgroup => $racklist)
e673ee24 1014 {
04571888
DO
1015 echo "<optgroup label='${optgroup}'>";
1016 foreach ($racklist as $rack_id => $rack_name)
1017 {
1018 echo "<option value=${rack_id}";
1019 if (!(array_search ($rack_id, $selected) === FALSE))
1020 echo ' selected';
1021 echo">${rack_name}</option>\n";
1022 }
e673ee24
DO
1023 }
1024 echo "</select>\n";
1025}
1026
1027function showMessageOrError ()
1028{
46f92ff7 1029 if (isset ($_REQUEST['message']))
e673ee24 1030 echo "<div class=msg_success>${_REQUEST['message']}</div>";
46f92ff7 1031 elseif (isset ($_REQUEST['error']))
e673ee24 1032 echo "<div class=msg_error>${_REQUEST['error']}</div>";
46f92ff7
DO
1033 elseif (isset ($_REQUEST['log']))
1034 printLog (unserialize (base64_decode ($_REQUEST['log'])));
e673ee24
DO
1035}
1036
1037// This function renders a form for port edition.
1038function renderPortsForObject ($object_id = 0)
1039{
1040 global $root, $pageno, $tabno;
1041 if ($object_id <= 0)
1042 {
591ff2c4 1043 showError ('Invalid object_id', __FUNCTION__);
e673ee24
DO
1044 return;
1045 }
1046 showMessageOrError();
1047 startPortlet ('Ports and interfaces');
1048 $ports = getObjectPortsAndLinks ($object_id);
1049 usort($ports, 'sortByName');
1050 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1051 echo "<tr><th>&nbsp;</th><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
1052 echo "<th>Rem. object</th><th>Rem. port</th><th>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
1053 foreach ($ports as $port)
1054 {
7056988c 1055 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
e673ee24
DO
1056 echo "<tr><td><a href='${root}process.php?op=delPort&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=$object_id&port_name=${port['name']}'>";
1057 printImageHREF ('delete', 'Unlink and Delete this port');
1058 echo "</a></td>\n";
1059 echo "<td><input type=text name=name value='${port['name']}' size=8></td>";
1060 echo "<td><input type=text name=label value='${port['label']}' size=24></td>";
1061 echo "<td>${port['type']}</td>\n";
1062 echo "<td><input type=text name=l2address value='${port['l2address']}'></td>\n";
1063 if ($port['remote_object_id'])
1064 {
1065 echo "<td><a href='${root}?page=object&object_id=${port['remote_object_id']}'>${port['remote_object_name']}</a></td>";
1066 echo "<td>${port['remote_name']}</td>";
1067 echo "<td><a href='${root}process.php?op=unlinkPort&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=$object_id&port_name=";
1068 echo urlencode ($port['name']);
1069 echo "&remote_port_name=${port['remote_name']}&remote_object_name=${port['remote_object_name']}'>";
1070 printImageHREF ('unlink', 'Unlink this port');
1071 echo "</a></td>";
1072 }
1073 elseif (!empty ($port['reservation_comment']))
1074 {
1075 echo "<td><b>Reserved;</b></td>";
1076 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1077 echo "<td><a href='${root}process.php?op=useup&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=${object_id}'>";
1078 printImageHREF ('useup', 'Use up this port');
1079 echo "</a></td>";
1080 }
1081 else
1082 {
1083 echo "<td>&nbsp;</td><td>&nbsp;</td>";
1084 echo "<td>";
1085 echo "<a href='javascript:;' onclick='window.open(\"${root}link_helper.php?port=${port['id']}&type=${port['type_id']}&object_id=$object_id&port_name=";
1086 echo urlencode ($port['name']);
1087 echo "\",\"findlink\",\"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
1088 printImageHREF ('link', 'Link this port');
1089 echo "</a> <input type=text name=reservation_comment>";
1090 echo "</td>\n";
1091 }
5bbbeaa2
DO
1092 echo "<td>";
1093 printImageHREF ('save', 'Save changes', TRUE);
1094 echo "</td></form></tr>\n";
e673ee24 1095 }
7056988c
DO
1096 printOpFormIntro ('addPort');
1097 echo "<tr><td>";
d48d8820
DO
1098 printImageHREF ('add', '', TRUE, 104);
1099 echo "</td><td><input type=text size=8 name=port_name tabindex=100></td>\n";
e673ee24 1100 echo "<td><input type=text size=24 name=port_label tabindex=101></td>";
e673ee24
DO
1101 echo "<td><select name='port_type_id' tabindex=102>\n";
1102 $types = getPortTypes();
9c0b0016 1103 $default_port_type = getConfigVar ('default_port_type');
e673ee24
DO
1104 foreach ($types as $typeid => $typename)
1105 {
1106 echo "<option value='${typeid}'";
1107 if ($typeid == $default_port_type)
1108 echo " selected";
1109 echo ">${typename}</option>\n";
1110 }
1111 echo "</select></td>";
1112 echo "<td><input type=text name=port_l2address tabindex=103></td>\n";
d48d8820 1113 echo "<td colspan=4>&nbsp;</td></tr></form>";
e673ee24
DO
1114 echo "</table><br>\n";
1115 finishPortlet();
1116
1117 startPortlet ('Add/update multiple ports');
7056988c 1118 printOpFormIntro ('addMultiPorts');
e673ee24 1119 echo 'Format: <select name=format>';
e673ee24
DO
1120 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1121 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
e673ee24 1122 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
351d4dbf 1123 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
e673ee24
DO
1124 echo "</select>";
1125 echo 'Default port type: ';
1126 echo "<select name=port_type>\n";
1127 foreach ($types as $typeid => $typename)
1128 {
1129 echo "<option value='${typeid}'";
1130 if ($typeid == $default_port_type)
1131 echo " selected";
1132 echo ">${typename}</option>\n";
1133 }
1134 echo "</select>";
1135 echo "<input type=submit value='Parse output'><br>\n";
1136 echo "<textarea name=input cols=100 rows=50></textarea><br>\n";
1137 echo '</form>';
1138 finishPortlet();
1139}
1140
72d8ced3 1141function renderIPv4ForObject ($object_id = 0)
e673ee24 1142{
52c836b1 1143 global $root, $pageno, $tabno, $aat;
e673ee24
DO
1144 if ($object_id <= 0)
1145 {
591ff2c4 1146 showError ('Invalid object_id', __FUNCTION__);
e673ee24
DO
1147 return;
1148 }
1149 showMessageOrError();
72d8ced3 1150 startPortlet ('Allocations');
85970da2 1151 $alloclist = getObjectIPv4Allocations ($object_id);
e673ee24 1152 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
79e45b4c
DO
1153 echo '<tr><th>&nbsp;</th><th>OS interface</th><th>IP address</th>';
1154 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1155 echo '<th colspan=2>network</th><th>routed by</th>';
1156 echo '<th>type</th><th>misc</th><th>&nbsp</th></tr>';
85970da2 1157 foreach ($alloclist as $dottedquad => $alloc)
e673ee24 1158 {
85970da2 1159 $class = $alloc['addrinfo']['class'];
79e45b4c
DO
1160 $netid = getIPv4AddressNetworkId ($dottedquad);
1161 $netinfo = getIPv4NetworkInfo ($netid);
b6b87070 1162 loadIPv4AddrList ($netinfo);
85970da2 1163 printOpFormIntro ('updIPv4Allocation', array ('ip' => $dottedquad));
79e45b4c 1164 echo "<tr class='$class' valign=top><td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${dottedquad}&object_id=$object_id'>";
e673ee24
DO
1165 printImageHREF ('delete', 'Delete this IPv4 address');
1166 echo "</a></td>";
85970da2 1167 echo "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10></td>";
79e45b4c
DO
1168 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${dottedquad}'>${dottedquad}</a>";
1169 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
1170 {
1171 if (NULL === $netid)
1172 $suffix = '/??';
1173 else
1174 echo '<small>/' . $netinfo['mask'] . '</small>';
1175 }
1176 echo '&nbsp;' . $aac[$alloc['type']];
1177 if (!empty ($alloc['addrinfo']['name']))
1178 echo '(' . niftyString ($alloc['addrinfo']['name']) . ')';
1179 echo '</td>';
1180 // FIXME: this a copy-and-paste from renderRackObject()
1181 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1182 {
1183 if (NULL === $netid)
1184 echo '<td colspan=2>?</td>';
1185 else
1186 printIPv4NetInfoTDs ($netinfo);
1187 echo "<td class='${secondclass}'>";
1188 // FIXME: These cals are really heavy, replace them with a more appropriate dedicated function.
79e45b4c 1189 $newline = '';
b6b87070 1190 foreach (findRouters ($netinfo['addrlist']) as $router)
79e45b4c
DO
1191 {
1192 if ($router['id'] == $object_id)
1193 continue;
1194 echo $newline . $router['addr'] . ", <a href='${root}?page=object&object_id=${router['id']}&hl_ipv4_addr=${router['addr']}'>";
1195 echo (empty ($router['iface']) ? '' : $router['iface'] . '@') . $router['dname'] . '</a>';
1196 $routertags = loadRackObjectTags ($router['id']);
1197 if (count ($routertags))
1198 echo '<br><small>' . serializeTags ($routertags, "${root}?page=objects&tab=default&") . '</small>';
1199 $newline = '<br>';
1200 }
1201 echo '</td>';
1202 }
1203 echo '<td>';
85970da2 1204 printSelect ($aat, 'bond_type', $alloc['type']);
e673ee24 1205 echo "</td><td>";
85970da2 1206 $prefix = '';
4940e4d5 1207 if ($alloc['addrinfo']['reserved'] == 'yes')
e673ee24 1208 {
85970da2
DO
1209 echo $prefix . '<strong>RESERVED</strong>';
1210 $prefix = '; ';
e673ee24 1211 }
85970da2 1212 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
e673ee24 1213 {
85970da2
DO
1214 if ($allocpeer['object_id'] == $object_id)
1215 continue;
1216 echo $prefix . "<a href='${root}?page=object&object_id=${allocpeer['object_id']}'>";
1217 if (!empty ($allocpeer['osif']))
1218 echo $allocpeer['osif'] . '@';
1219 echo $allocpeer['object_name'] . '</a>';
1220 $prefix = '; ';
e673ee24 1221 }
d54b9495
DO
1222 echo "</td><td>";
1223 printImageHREF ('save', 'Save changes', TRUE);
1224 echo "</td></form></tr>\n";
e673ee24
DO
1225 }
1226
7056988c
DO
1227 printOpFormIntro ('addIPv4Allocation');
1228 echo "<tr><td>";
d54b9495 1229 printImageHREF ('add', 'Allocate new address', TRUE, 99);
7056988c
DO
1230 echo "</td>";
1231 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n";
1232 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n";
79e45b4c 1233 echo "<td colspan=3>&nbsp;</td><td>";
52c836b1 1234 printSelect ($aat, 'bond_type');
7056988c 1235 echo "</td><td colspan=2>&nbsp;</td></tr></form></table><br>\n";
e673ee24
DO
1236 finishPortlet();
1237
1238}
1239
baf37d01
DO
1240// Log structure versions:
1241// 1: the whole structure is a list of code-message pairs
1242// 2 and later: there's a "v" field set, which indicates the version
1243// 2: there's a "m" list set to hold message code and optional arguments
e673ee24
DO
1244function printLog ($log)
1245{
baf37d01
DO
1246 switch (TRUE)
1247 {
1248 case !isset ($log['v']):
ebb5441d 1249 case $log['v'] == 1:
baf37d01 1250 foreach ($log as $key => $record)
ebb5441d 1251 if ($key !== 'v')
baf37d01
DO
1252 echo "<div class=msg_${record['code']}>${record['message']}</div>";
1253 break;
1254 case $log['v'] == 2:
1255 $msginfo = array
1256 (
ebb5441d 1257 0 => array ('code' => 'success', 'format' => 'Success: %s'),
baf37d01
DO
1258 1 => array ('code' => 'success', 'format' => '%u new records done, %u already existed'),
1259 2 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully added.'),
1260 3 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully deleted.'),
1261 4 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully updated'),
1262 5 => array ('code' => 'success', 'format' => 'Port %s was added successfully'),
1263 6 => array ('code' => 'success', 'format' => 'Port %s was updated successfully'),
1264 7 => array ('code' => 'success', 'format' => 'Port %s was deleted successfully'),
1265 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with port %s at object %s'),
1266 9 => array ('code' => 'success', 'format' => 'Port %s was successfully unlinked from %s@%s'),
1267 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1268 11 => array ('code' => 'success', 'format' => 'Reservation removed.'),
1269 12 => array ('code' => 'success', 'format' => 'allocation updated'),
1270 13 => array ('code' => 'success', 'format' => 'allocated'),
1271 14 => array ('code' => 'success', 'format' => 'deallocated'),
1272 15 => array ('code' => 'success', 'format' => 'Reset succeeded.'),
1273 16 => array ('code' => 'success', 'format' => 'Update done'),
1274 17 => array ('code' => 'success', 'format' => 'Update(s) succeeded.'),
1275 18 => array ('code' => 'success', 'format' => 'Load balancer was successfully added'),
1276 19 => array ('code' => 'success', 'format' => 'Load balancer was successfully deleted'),
1277 20 => array ('code' => 'success', 'format' => 'Load balancer info was successfully updated'),
1278 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1279 22 => array ('code' => 'success', 'format' => 'Chained %u tags'),
1280 23 => array ('code' => 'success', 'format' => 'IPv4 prefix successfully added'),
1281 24 => array ('code' => 'success', 'format' => 'IPv4 prefix deleted'),
1282 25 => array ('code' => 'success', 'format' => 'IPv4 prefix updated'),
1283 26 => array ('code' => 'success', 'format' => '%u IP address(es) were successfully updated'),
1284 27 => array ('code' => 'success', 'format' => 'IPv4 address updated'),
1285 28 => array ('code' => 'success', 'format' => 'Virtual service was successfully created'),
1286 29 => array ('code' => 'success', 'format' => 'Virtual service was successfully deleted'),
1287 30 => array ('code' => 'success', 'format' => 'Virtual service was successfully updated'),
1288 31 => array ('code' => 'success', 'format' => 'RS pool was successfully created'),
1289 32 => array ('code' => 'success', 'format' => 'RS pool was successfully deleted'),
1290 33 => array ('code' => 'success', 'format' => 'RS pool was successfully updated'),
1291 34 => array ('code' => 'success', 'format' => 'Real server was successfully added'),
1292 35 => array ('code' => 'success', 'format' => 'Real server was successfully deleted'),
1293 36 => array ('code' => 'success', 'format' => 'Real server was successfully updated'),
1294 37 => array ('code' => 'success', 'format' => 'Successfully added %u real servers'),
1295 38 => array ('code' => 'success', 'format' => '%u real server(s) were successfully (de)activated'),
1296 39 => array ('code' => 'success', 'format' => 'User account %s updated.'),
1297 40 => array ('code' => 'success', 'format' => 'User account %s created.'),
1298 41 => array ('code' => 'success', 'format' => 'User account disabled.'),
1299 42 => array ('code' => 'success', 'format' => 'User account enabled.'),
1300 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1301 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1302 45 => array ('code' => 'success', 'format' => "Attribute '%s' created."),
1303 46 => array ('code' => 'success', 'format' => 'Rename successful.'),
1304 47 => array ('code' => 'success', 'format' => 'Attribute was deleted.'),
1305 48 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1306 49 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1307 50 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1308 51 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1309 52 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1310 53 => array ('code' => 'success', 'format' => 'Chapter was deleted.'),
1311 54 => array ('code' => 'success', 'format' => 'Chapter was updated.'),
1312 55 => array ('code' => 'success', 'format' => 'Chapter was added.'),
1313 56 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1314 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1315 58 => array ('code' => 'success', 'format' => "Successfully deleted tag ."),
1316 59 => array ('code' => 'success', 'format' => "Created tag '%s'."),
1317 60 => array ('code' => 'success', 'format' => "Updated tag '%s'."),
ebb5441d 1318 61 => array ('code' => 'success', 'format' => 'Password changed successfully.'),
24dcb9d8 1319 62 => array ('code' => 'success', 'format' => 'gw: %s'),
f0ff4930
DO
1320 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1321 64 => array ('code' => 'success', 'format' => 'Port %s@%s has been assigned to VLAN %u'),
f19c75d6 1322 65 => array ('code' => 'success', 'format' => "Added new rack '%s'"),
03e6ef01 1323 66 => array ('code' => 'success', 'format' => "File sent Ok via handler '%s'"),
abef7149 1324 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
0c2b7c4a 1325 68 => array ('code' => 'success', 'format' => "Updated rack '%s'"),
f0ff4930 1326
ebb5441d
DO
1327 100 => array ('code' => 'error', 'format' => 'Generic error: %s'),
1328 101 => array ('code' => 'error', 'format' => 'Port name cannot be empty'),
1329 102 => array ('code' => 'error', 'format' => "Error creating user account '%s'"),
1330 103 => array ('code' => 'error', 'format' => 'getHashByID() failed'),
1331 104 => array ('code' => 'error', 'format' => "Error updating user account '%s'"),
1332 105 => array ('code' => 'error', 'format' => 'Error enabling user account.'),
1333 106 => array ('code' => 'error', 'format' => 'Error disabling user account.'),
1334 107 => array ('code' => 'error', 'format' => 'Admin account cannot be disabled'),
1335 108 => array ('code' => 'error', 'format' => '%u failures and %u successfull changes.'),
1336 109 => array ('code' => 'error', 'format' => 'Update failed!'),
1337 110 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1338 111 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1339 112 => array ('code' => 'error', 'format' => 'Error adding chapter.'),
1340 113 => array ('code' => 'error', 'format' => 'Error updating chapter.'),
1341 114 => array ('code' => 'error', 'format' => 'Error deleting chapter.'),
1342 115 => array ('code' => 'error', 'format' => 'Error renaming attribute.'),
1343 116 => array ('code' => 'error', 'format' => 'Error creating attribute.'),
1344 117 => array ('code' => 'error', 'format' => 'Error deleting attribute.'),
1345 118 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1346 119 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1347 120 => array ('code' => 'error', 'format' => 'Reset failed!'),
1348 121 => array ('code' => 'error', 'format' => 'commitUpdateObject() failed'),
1349 122 => array ('code' => 'error', 'format' => 'One or more update(s) failed!'),
1350 123 => array ('code' => 'error', 'format' => 'Cannot process submitted data: unknown format code.'),
1351 124 => array ('code' => 'error', 'format' => 'Error removing reservation!'),
1352 125 => array ('code' => 'error', 'format' => "Update failed with error: '%s'"),
1353 126 => array ('code' => 'error', 'format' => 'addRStoRSPool() failed'),
1354 127 => array ('code' => 'error', 'format' => 'Added %u real servers and encountered %u errors'),
1355 128 => array ('code' => 'error', 'format' => 'commitDeleteRS() failed'),
1356 129 => array ('code' => 'error', 'format' => 'commitDeleteLB() failed'),
1357 130 => array ('code' => 'error', 'format' => 'commitDeleteVS() failed'),
1358 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1359 132 => array ('code' => 'error', 'format' => 'invalid protocol'),
1360 133 => array ('code' => 'error', 'format' => 'commitUpdateRS() failed'),
1361 134 => array ('code' => 'error', 'format' => 'commitUpdateLB() failed'),
1362 135 => array ('code' => 'error', 'format' => 'commitUpdateVS() failed'),
1363 136 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1364 137 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1365 138 => array ('code' => 'error', 'format' => 'commitDeleteRSPool() failed'),
1366 139 => array ('code' => 'error', 'format' => 'commitUpdateRSPool() failed'),
1367 140 => array ('code' => 'error', 'format' => 'Encountered %u errors, (de)activated %u real servers'),
1368 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u IP address(es)'),
1369 142 => array ('code' => 'error', 'format' => 'executeAutoPorts() failed'),
1370 143 => array ('code' => 'error', 'format' => 'Tried chaining %u tags, but experienced %u errors.'),
1371 144 => array ('code' => 'error', 'format' => "Error deleting tag: '%s'"),
1372 145 => array ('code' => 'error', 'format' => "Invalid tag name '%s'"),
1373 146 => array ('code' => 'error', 'format' => "Tag '%s' (or similar name) already exists"),
1374 147 => array ('code' => 'error', 'format' => "Could not create tag '%s' because of error '%s'"),
1375 148 => array ('code' => 'error', 'format' => "Could not update tag '%s' because of error '%s'"),
1376 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1377 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1378 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1379 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1380 153 => array ('code' => 'error', 'format' => 'Password change failed.'),
1381 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1382 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1383 156 => array ('code' => 'error', 'format' => 'getSwitchVLANs() failed'),
e81fb764 1384 157 => array ('code' => 'error', 'format' => 'operation not permitted'),
24dcb9d8
DO
1385 158 => array ('code' => 'error', 'format' => 'Ignoring malformed record #%u in form submit'),
1386 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1387 160 => array ('code' => 'error', 'format' => 'Invalid arguments'),
1388 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1389 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1390 163 => array ('code' => 'error', 'format' => 'Failed to get any response from queryGateway() or the gateway died'),
c030232f 1391 164 => array ('code' => 'error', 'format' => 'Gateway failure: %s.'),
24dcb9d8
DO
1392 165 => array ('code' => 'error', 'format' => 'Gateway failure: malformed reply.'),
1393 166 => array ('code' => 'error', 'format' => 'gw: %s'),
f0ff4930
DO
1394 167 => array ('code' => 'error', 'format' => 'Could not find port %s'),
1395 168 => array ('code' => 'error', 'format' => 'Port %s is a trunk'),
1396 169 => array ('code' => 'error', 'format' => 'Failed to configure %s, connector returned code %u'),
5222f192 1397 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
f19c75d6
DO
1398 171 => array ('code' => 'error', 'format' => "Failed creating rack '%s'. Already exists in this row?"),
1399 172 => array ('code' => 'error', 'format' => 'Malformed request'),
e5c4506d
DO
1400 173 => array ('code' => 'error', 'format' => "Invalid IPv4 prefix '%s'"),
1401 174 => array ('code' => 'error', 'format' => 'Bad IPv4 address'),
1402 175 => array ('code' => 'error', 'format' => 'Invalid netmask'),
1403 176 => array ('code' => 'error', 'format' => 'This network already exists'),
0c2b7c4a 1404 177 => array ('code' => 'error', 'format' => 'commitUpdateRack() failed'),
f0ff4930 1405
24dcb9d8
DO
1406 200 => array ('code' => 'warning', 'format' => 'generic warning: %s'),
1407 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1408 202 => array ('code' => 'warning', 'format' => 'gw: %s'),
f0ff4930
DO
1409 203 => array ('code' => 'warning', 'format' => 'Port %s seems to be the first in VLAN %u at this switch.'),
1410 204 => array ('code' => 'warning', 'format' => 'Check uplink/downlink configuration for proper operation.'),
1411 205 => array ('code' => 'warning', 'format' => '%u change request(s) have been ignored'),
baf37d01
DO
1412 );
1413 // Handle the arguments. Is there any better way to do it?
1414 foreach ($log['m'] as $record)
1415 {
5222f192
DO
1416 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1417 {
1418 echo '<div class=msg_neutral>(this message was lost)</div>';
1419 continue;
1420 }
baf37d01
DO
1421 if (isset ($record['a']))
1422 switch (count ($record['a']))
1423 {
1424 case 1:
1425 $msgtext = sprintf
1426 (
1427 $msginfo[$record['c']]['format'],
1428 $record['a'][0]
1429 );
1430 break;
1431 case 2:
1432 $msgtext = sprintf
1433 (
1434 $msginfo[$record['c']]['format'],
1435 $record['a'][0],
1436 $record['a'][1]
1437 );
1438 break;
1439 case 3:
1440 $msgtext = sprintf
1441 (
1442 $msginfo[$record['c']]['format'],
1443 $record['a'][0],
1444 $record['a'][1],
1445 $record['a'][2]
1446 );
1447 break;
1448 case 4:
1449 default:
1450 $msgtext = sprintf
1451 (
1452 $msginfo[$record['c']]['format'],
1453 $record['a'][0],
1454 $record['a'][1],
1455 $record['a'][2],
1456 $record['a'][3]
1457 );
1458 break;
1459 }
1460 else
1461 $msgtext = $msginfo[$record['c']]['format'];
1462 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1463 }
1464 break;
1465 default:
1466 echo '<div class=msg_error>' . __FUNCTION__ . ': internal error</div>';
1467 break;
1468 }
e673ee24
DO
1469}
1470
1471/*
1472The following conditions must be followed:
14731. We can mount onto free atoms only. This means: if any record for an atom
1474already exists in RackSpace, it can't be used for mounting.
14752. We can't unmount from 'W' atoms. Operator should review appropriate comments
1476and either delete them before unmounting or refuse to unmount the object.
1477*/
1478
1479// We extensively use $_REQUEST in the function.
7056988c 1480// FIXME: move related code into ophandler
e673ee24
DO
1481function renderRackSpaceForObject ($object_id = 0)
1482{
1483 if ($object_id <= 0)
1484 {
591ff2c4 1485 showError ('Invalid object_id', __FUNCTION__);
e673ee24
DO
1486 return;
1487 }
1488 $is_submit = isset ($_REQUEST['got_atoms']);
1489 $is_update = isset ($_REQUEST['rackmulti'][0]);
1490 $info = getObjectInfo ($object_id);
1491 if ($info == NULL)
1492 {
591ff2c4 1493 showError ('getObjectInfo() failed', __FUNCTION__);
e673ee24
DO
1494 return;
1495 }
1496 // Always process occupied racks plus racks chosen by user. First get racks with
1497 // already allocated rackspace...
1498 $workingRacksData = getResidentRacksData ($object_id);
1499 if ($workingRacksData === NULL)
1500 {
1501 print_r ($workingRacksData);
591ff2c4 1502 showError ('getResidentRacksData() failed', __FUNCTION__);
e673ee24
DO
1503 return;
1504 }
1505
1506 // ...and then add those chosen by user (if any).
1507 if ($is_update)
1508 foreach ($_REQUEST['rackmulti'] as $cand_id)
1509 {
1510 if (!isset ($workingRacksData[$cand_id]))
1511 {
1512 $rackData = getRackData ($cand_id);
1513 if ($rackData == NULL)
1514 {
591ff2c4 1515 showError ('getRackData() failed', __FUNCTION__);
e673ee24
DO
1516 return NULL;
1517 }
1518 $workingRacksData[$cand_id] = $rackData;
1519 }
1520 }
1521
1522 // Do it only once...
1523 foreach ($workingRacksData as &$rackData)
1524 applyObjectMountMask ($rackData, $object_id);
1525 // Now we workaround an old caveat: http://bugs.php.net/bug.php?id=37410
1526 unset ($rackData);
1527
1528 // Here we process form submit by trying to save all submitted info to database.
1529 if ($is_submit)
1530 {
1531 $oldMolecule = getMoleculeForObject ($object_id);
1532 $worldchanged = FALSE;
1533 $log = array();
1534 foreach ($workingRacksData as $rack_id => $rackData)
1535 {
1536 $logrecord = processGridForm ($rackData, 'F', 'T', $object_id);
1537 $log[] = $logrecord;
1538 if ($logrecord['code'] != 300)
1539 {
1540 $worldchanged = TRUE;
1541 // Reload our working copy after form processing.
1542 $rackData = getRackData ($rack_id);
1543 if ($rackData == NULL)
4d2e93f2 1544 $log[] = array ('code' => 500, 'message' => 'Working copy update failed in ', __FUNCTION__);
e673ee24
DO
1545 applyObjectMountMask ($rackData, $object_id);
1546 $workingRacksData[$rack_id] = $rackData;
1547 }
1548 }
1549 if ($worldchanged)
1550 {
1551 // Log a record.
1552 $newMolecule = getMoleculeForObject ($object_id);
1553 $oc = count ($oldMolecule);
1554 $nc = count ($newMolecule);
1555 $omid = $oc ? createMolecule ($oldMolecule) : 'NULL';
1556 $nmid = $nc ? createMolecule ($newMolecule) : 'NULL';
1557 global $remote_username;
1558 $comment = empty ($_REQUEST['comment']) ? 'NULL' : "'${_REQUEST['comment']}'";
1559 $query =
1560 "insert into MountOperation(object_id, old_molecule_id, new_molecule_id, user_name, comment) " .
1561 "values (${object_id}, ${omid}, ${nmid}, '${remote_username}', ${comment})";
1562 global $dbxlink;
1563 $result = $dbxlink->query ($query);
1564 if ($result == NULL)
1565 $log[] = array ('code' => 'error', 'message' => 'SQL query failed during history logging.');
1566 else
1567 $log[] = array ('code' => 'success', 'message' => 'History logged.');
1568 }
1569 printLog ($log);
1570 }
1571
1572 // This is the time for rendering.
1573 global $root, $pageno, $tabno;
1574 echo "<form id='racks' action='${root}'>";
1575 echo "<input type=hidden name=page value='${pageno}'>\n";
1576 echo "<input type=hidden name=tab value='${tabno}'>\n";
1577 echo "<input type=hidden name=object_id value='${object_id}'>\n";
1578 // Main layout starts.
1579 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
1580
1581 // Left portlet with rack list.
1582 echo "<td class=pcleft height='1%'>";
1583 startPortlet ('Racks');
1584 $allRacksData = getRacksForRow();
4b8d413e
DO
1585 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
1586 {
1587 foreach (array_keys ($allRacksData) as $rack_id)
1588 {
1589 $rackData = getRackData ($rack_id);
1590 if ($rackData == NULL)
1591 {
1592 showError ('getRackData() failed', __FUNCTION__);
1593 return NULL;
1594 }
1595 $workingRacksData[$rack_id] = $rackData;
1596 }
1597 foreach ($workingRacksData as &$rackData)
1598 applyObjectMountMask ($rackData, $object_id);
1599 unset ($rackData);
1600 }
1601 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
e673ee24
DO
1602 echo "<br>";
1603 echo "<br>";
1604 finishPortlet();
1605 echo "</td>";
1606
1607 // Middle portlet with comment and submit.
1608 echo "<td class=pcleft>";
1609 startPortlet ('Comment');
1610 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
1611 echo "<input type=submit value='Save' name=got_atoms>\n";
1612 echo "<br>";
1613 echo "<br>";
1614 finishPortlet();
1615 echo "</td>";
1616
1617 // Right portlet with rendered racks. If this form submit is not final, we have to
1618 // reflect the former state of the grid in current form.
1619 echo "<td class=pcright rowspan=2 height='1%'>";
1620 startPortlet ('Working copy');
1621 echo '<table border=0 cellspacing=10 align=center><tr>';
1622 foreach ($workingRacksData as $rack_id => $rackData)
1623 {
1624 // Order is important here: only original allocation is highlighted.
1625 highlightObject ($rackData, $object_id);
1626 markupAtomGrid ($rackData, 'T');
1627 // If we have a form processed, discard user input and show new database
1628 // contents.
1629 if (!$is_submit and $is_update)
1630 mergeGridFormToRack ($rackData);
1631 echo "<td valign=top>";
1632 echo "<center>\n<h2>${rackData['name']}</h2>\n";
1633 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
1634 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
1635 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1636 renderAtomGrid ($rackData);
9b7468b7
DO
1637 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
1638 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
e673ee24
DO
1639 echo "</table></center>\n";
1640 echo '</td>';
1641 }
1642 echo "</tr></table>";
1643 finishPortlet();
1644 echo "</td>\n";
1645
1646 echo "</form>\n";
1647 echo "</tr></table>\n";
1648}
1649
1650function renderMolecule ($mdata, $object_id)
1651{
1652 // sort data out
1653 $rackpack = array();
1654 global $loclist;
64b95774 1655 foreach ($mdata as $rua)
e673ee24
DO
1656 {
1657 $rack_id = $rua['rack_id'];
1658 $unit_no = $rua['unit_no'];
1659 $atom = $rua['atom'];
1660 if (!isset ($rackpack[$rack_id]))
1661 {
1662 $rackData = getRackData ($rack_id);
1663 for ($i = $rackData['height']; $i > 0; $i--)
1664 for ($locidx = 0; $locidx < 3; $locidx++)
1665 $rackData[$i][$locidx]['state'] = 'F';
1666 $rackpack[$rack_id] = $rackData;
1667 }
1668 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
1669 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
1670 }
1671 // now we have some racks to render
64b95774 1672 foreach ($rackpack as $rackData)
e673ee24
DO
1673 {
1674 markAllSpans ($rackData);
1675 echo "<table class=molecule cellspacing=0>\n";
1676 echo "<caption>${rackData['name']}</caption>\n";
1677 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1678 for ($i = $rackData['height']; $i > 0; $i--)
1679 {
1680 echo "<tr><th>$i</th>";
1681 for ($locidx = 0; $locidx < 3; $locidx++)
1682 {
1683 $state = $rackData[$i][$locidx]['state'];
1684 echo "<td class=state_${state}>&nbsp;</td>\n";
1685 }
1686 echo "</tr>\n";
1687 }
1688 echo "</table>\n";
1689 }
1690}
1691
1692function renderUnmountedObjectsPortlet ()
1693{
1694 startPortlet ('Unmounted objects');
1695 $objs = getUnmountedObjects();
1696 if ($objs === NULL)
1697 {
591ff2c4 1698 showError ('getUnmountedObjects() failed', __FUNCTION__);
e673ee24
DO
1699 return;
1700 }
1701 global $root, $nextorder;
1702 $order = 'odd';
1703 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
18d94c29 1704 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset number</th><th>Barcode</th></tr>';
e673ee24
DO
1705 foreach ($objs as $obj)
1706 {
1707 echo "<tr class=row_${order}><td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1708 echo "<td>${obj['label']}</td>";
18d94c29
DO
1709 echo "<td>${obj['asset_no']}</td>";
1710 echo "<td>${obj['barcode']}</td></tr>";
e673ee24
DO
1711 $order = $nextorder[$order];
1712 }
1713 echo "</table><br>\n";
1714 finishPortlet();
1715}
1716
1717function renderProblematicObjectsPortlet ()
1718{
1719 startPortlet ('Problematic objects');
1720 $objs = getProblematicObjects();
1721 if ($objs === NULL)
1722 {
591ff2c4 1723 showError ('getProblematicObjects() failed', __FUNCTION__);
e673ee24
DO
1724 return;
1725 }
1726 global $root, $nextorder;
1727 $order = 'odd';
1728 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1729 echo '<tr><th>Type</th><th>Common name</th></tr>';
1730 foreach ($objs as $obj)
1731 {
1732 echo "<tr class=row_${order}><td>${obj['objtype_name']}</td>";
1733 echo "<td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></tr>";
1734 $order = $nextorder[$order];
1735 }
1736 echo "</table><br>\n";
1737 finishPortlet();
1738}
1739
7cc02fc1
DO
1740function renderObjectSpace ()
1741{
105cea6e 1742 global $root, $taglist, $tagtree;
7cc02fc1
DO
1743 echo "<table border=0 class=objectview>\n";
1744 echo "<tr><td class=pcleft width='50%'>";
1745 startPortlet ('View all by type');
1746 $groupInfo = getObjectGroupInfo();
1747 if ($groupInfo === NULL)
1748 {
1749 showError ('getObjectGroupInfo() failed', __FUNCTION__);
1750 return;
1751 }
1752 if (count ($groupInfo) == 0)
1753 echo "No objects exist in DB";
1754 else
1755 {
1756 echo '<div align=left><ul>';
1757 foreach ($groupInfo as $gi)
1758 echo "<li><a href='${root}?page=objgroup&group_id=${gi['id']}'>${gi['name']}</a> (${gi['count']})</li>";
1759 echo '</ul></div>';
1760 }
1761 finishPortlet();
1762
1763 echo '</td><td class=pcright>';
1764
1765 startPortlet ('View all by tag');
1766 if (count ($taglist) == 0)
1767 echo "No tags exist in DB";
1768 else
1769 renderTagCloud ('object');
1770 finishPortlet();
e673ee24
DO
1771 echo "</td></tr></table>\n";
1772}
1773
466dcbe6 1774function renderObjectGroup ()
7cc02fc1
DO
1775{
1776 global $root, $pageno, $tabno, $nextorder, $taglist, $tagtree;
2c6c7645 1777 assertUIntArg ('group_id', __FUNCTION__, TRUE);
7cc02fc1 1778 $group_id = $_REQUEST['group_id'];
a0d54e7e
DO
1779 $tagfilter = getTagFilter();
1780 $tagfilter_str = getTagFilterStr ($tagfilter);
7cc02fc1
DO
1781 echo "<table border=0 class=objectview>\n";
1782 echo "<tr><td class=pcleft width='25%'>";
1783 startPortlet ('change type');
1784 $groupInfo = getObjectGroupInfo();
1785 if ($groupInfo === NULL)
1786 {
1787 showError ('getObjectGroupInfo() failed', __FUNCTION__);
1788 return;
1789 }
1790 if (count ($groupInfo) == 0)
1791 echo "No objects exist in DB";
1792 else
1793 {
1794 echo '<div align=left><ul>';
1795 foreach ($groupInfo as $gi)
1796 {
a0d54e7e 1797 echo "<li><a href='${root}?page=${pageno}&group_id=${gi['id']}${tagfilter_str}'>";
105cea6e
DO
1798 if ($gi['id'] == $group_id)
1799 echo '<strong>';
1800 echo "${gi['name']}</a>";
1801 if ($gi['id'] == $group_id)
1802 echo '</strong>';
1803 echo " (${gi['count']})";
1804 if ($gi['id'] == $group_id)
1805 echo ' &larr;';
1806 echo "</li>";
7cc02fc1
DO
1807 }
1808 echo '</ul></div>';
1809 }
1810 finishPortlet();
1811
1812 echo '</td><td class=pcleft>';
1813
1814 startPortlet ('Objects');
11c8e4be 1815 $objects = getObjectList ($group_id, $tagfilter, getTFMode());
7cc02fc1
DO
1816 if ($objects === NULL)
1817 {
1818 showError ('getObjectList() failed', __FUNCTION__);
1819 return;
1820 }
1821 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1822 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Barcode</th><th>Rack</th></tr>';
1823 $order = 'odd';
1824 foreach ($objects as $obj)
1825 {
8e700dd1
DO
1826 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $obj['id'])
1827 $secondclass = 'tdleft port_highlight';
1828 else
1829 $secondclass = 'tdleft';
1830 echo "<tr class=row_${order}><td class='${secondclass}'><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1831 echo "<td class='${secondclass}'>${obj['label']}</td>";
1832 echo "<td class='${secondclass}'>${obj['asset_no']}</td>";
1833 echo "<td class='${secondclass}'>${obj['barcode']}</td>";
7cc02fc1 1834 if ($obj['rack_id'])
8e700dd1 1835 echo "<td class='${secondclass}'><a href='${root}?page=rack&rack_id=${obj['rack_id']}'>${obj['Rack_name']}</a></td>";
7cc02fc1 1836 else
8e700dd1 1837 echo "<td class='${secondclass}'>Unmounted</td>";
7cc02fc1
DO
1838 echo '</tr>';
1839 $order = $nextorder[$order];
1840 }
1841 echo '</table>';
1842 finishPortlet();
1843
1844 echo "</td><td class=pcright width='25%'>";
1845
a0d54e7e 1846 renderTagFilterPortlet ($tagfilter, 'object', 'group_id', $group_id);
7cc02fc1 1847 echo "</td></tr></table>\n";
e673ee24
DO
1848}
1849
1850function renderEmptyPortsSelect ($port_id, $type_id)
1851{
1852 $ports = getEmptyPortsOfType($type_id);
1853 usort($ports, 'sortEmptyPorts');
1854 foreach ($ports as $port)
1855 {
1856 if ($port_id == $port['Port_id'])
1857 continue;
1858 echo "<option value='${port['Port_id']}' onclick='getElementById(\"remote_port_name\").value=\"${port['Port_name']}\"; getElementById(\"remote_object_name\").value=\"${port['Object_name']}\";'>${port['Object_name']} ${port['Port_name']}</option>\n";
1859 }
1860}
1861
6ef9683b 1862function renderAllIPv4Allocations ()
e673ee24 1863{
6ef9683b 1864 $addresses = getAllIPv4Allocations();
e673ee24
DO
1865 usort($addresses, 'sortObjectAddressesAndNames');
1866 foreach ($addresses as $address)
1867 {
1868 echo "<option value='${address['ip']}' onclick='getElementById(\"ip\").value=\"${address['ip']}\";'>${address['object_name']} ${address['name']} ${address['ip']}</option>\n";
1869 }
1870}
1871
1872// History viewer for history-enabled simple dictionaries.
1873function renderHistory ($object_type, $object_id)
1874{
1875 switch ($object_type)
1876 {
1877 case 'row':
1878 $query = "select ctime, user_name, name, deleted, comment from RackRowHistory where id = ${object_id} order by ctime";
1879 $header = '<tr><th>change time</th><th>author</th><th>rack row name</th><th>is deleted?</th><th>rack row comment</th></tr>';
1880 $extra = 4;
1881 break;
1882 case 'rack':
1883 $query =
1884 "select ctime, user_name, rh.name, rh.deleted, d.dict_value as name, rh.height, rh.comment " .
1885 "from RackHistory as rh left join Dictionary as d on rh.row_id = d.dict_key " .
1886 "natural join Chapter " .
1887 "where chapter_name = 'RackRow' and rh.id = ${object_id} order by ctime";
1888 $header = '<tr><th>change time</th><th>author</th><th>rack name</th><th>is deleted?</th><th>rack row name</th><th>rack height</th><th>rack comment</th></tr>';
1889 $extra = 6;
1890 break;
1891 case 'object':
1892 $query =
1893 "select ctime, user_name, name, label, barcode, asset_no, deleted, has_problems, dict_value, comment " .
1894 "from RackObjectHistory inner join Dictionary on objtype_id = dict_key natural join Chapter " .
1895 "where chapter_name = 'RackObjectType' and id=${object_id} order by ctime";
1896 $header = '<tr><th>change time</th><th>author</th><th>common name</th><th>visible label</th><th>barcode</th><th>asset no</th><th>is deleted?</th><th>has problems?</th><th>object type</th><th>comment</th></tr>';
1897 $extra = 9;
1898 break;
1899 default:
591ff2c4 1900 showError ("Uknown object type '${object_type}'", __FUNCTION__);
e673ee24
DO
1901 return;
1902 }
1903 global $dbxlink;
1904 $result = $dbxlink->query ($query);
1905 if ($result == NULL)
1906 {
591ff2c4 1907 showError ('SQL query failed', __FUNCTION__);
e673ee24
DO
1908 return;
1909 }
1910 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1911 $order = 'odd';
1912 global $nextorder;
1913 echo $header;
1914 while ($row = $result->fetch (PDO::FETCH_NUM))
1915 {
1916 echo "<tr class=row_${order}><td>${row[0]}</td>";
1917 for ($i = 1; $i <= $extra; $i++)
1918 echo "<td>" . $row[$i] . "</td>";
1919 echo "</tr>\n";
1920 $order = $nextorder[$order];
1921 }
1922 echo "</table><br>\n";
1923}
1924
1925function renderRackspaceHistory ()
1926{
1927 global $root, $nextorder, $pageno, $tabno;
1928 $order = 'odd';
1929 $history = getRackspaceHistory();
1930 // Show the last operation by default.
1931 if (isset ($_REQUEST['op_id']))
1932 $op_id = $_REQUEST['op_id'];
1933 elseif (isset ($history[0]['mo_id']))
1934 $op_id = $history[0]['mo_id'];
1935 else $op_id = NULL;
1936
1937 $omid = NULL;
1938 $nmid = NULL;
1939 $object_id = 1;
1940 if ($op_id)
1941 list ($omid, $nmid) = getOperationMolecules ($op_id);
1942
1943 // Main layout starts.
1944 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1945
1946 // Left top portlet with old allocation.
1947 echo "<tr><td class=pcleft>";
1948 startPortlet ('Old allocation');
1949 if ($omid)
1950 {
1951 $oldMolecule = getMolecule ($omid);
1952 renderMolecule ($oldMolecule, $object_id);
1953 }
1954 else
1955 echo "nothing";
1956 finishPortlet();
1957
1958 echo '</td><td class=pcright>';
1959
1960 // Right top portlet with new allocation
1961 startPortlet ('New allocation');
1962 if ($nmid)
1963 {
1964 $newMolecule = getMolecule ($nmid);
1965 renderMolecule ($newMolecule, $object_id);
1966 }
1967 else
1968 echo "nothing";
1969 finishPortlet();
737a3f72 1970
e673ee24 1971 echo '</td></tr><tr><td colspan=2>';
737a3f72 1972
e673ee24
DO
1973 // Bottom portlet with list
1974
1975 startPortlet ('Rackspace allocation history');
1976 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
1977 echo "<tr><th>timestamp</th><th>author</th><th>rack object ID</th><th>rack object type</th><th>rack object name</th><th>comment</th></tr>\n";
1978 foreach ($history as $row)
1979 {
1980 if ($row['mo_id'] == $op_id)
1981 $class = 'hl';
1982 else
1983 $class = "row_${order}";
1984 echo "<tr class=${class}><td><a href='${root}?page=${pageno}&tab=${tabno}&op_id=${row['mo_id']}'>${row['ctime']}</a></td>";
1985 echo "<td>${row['user_name']}</td>";
1986 echo "<td>${row['ro_id']}</td><td>${row['objtype_name']}</td><td>${row['name']}</td><td>${row['comment']}</td>\n";
1987 echo "</tr>\n";
1988 $order = $nextorder[$order];
1989 }
1990 echo "</table>\n";
1991 finishPortlet();
737a3f72 1992
e673ee24 1993 echo '</td></tr></table>';
e673ee24
DO
1994}
1995
737a3f72 1996function renderIPv4SpaceRecords ($tree, $todo, $level = 1, &$tagcache = array())
d65353ad
DO
1997{
1998 $self = __FUNCTION__;
0137d53c 1999 $doing = 1;
737a3f72 2000 $expanded_id = 0;
d65353ad
DO
2001 foreach ($tree as $item)
2002 {
737a3f72
DO
2003 $total = $item['addrt'];
2004 if (!$item['kidc'])
2005 $symbol = 'spacer';
2006 elseif (getConfigVar ('TREE_THRESHOLD') > 0 and $item['kidc'] >= getConfigVar ('TREE_THRESHOLD') and $item['id'] != $expanded_id)
2007 $symbol = 'node-collapsed';
2008 else
2009 $symbol = 'node-expanded';
0137d53c
DO
2010 if (isset ($item['id']))
2011 {
b6b87070
DO
2012 loadIPv4AddrList ($item);
2013 $used = $item['addrc'];
0137d53c 2014 echo "<tr valign=top>";
737a3f72 2015 printIPv4NetInfoTDs ($item, 'tdleft', $level, $symbol);
0137d53c 2016 echo "<td class=tdcenter>";
737a3f72 2017 renderProgressBar ($total ? $used/$total : 0);
0137d53c
DO
2018 echo "<br><small>${used}/${total}</small></td>";
2019 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
b6b87070 2020 printRoutersTD (findRouters ($item['addrlist']), $tagcache);
0137d53c 2021 echo "</tr>";
737a3f72
DO
2022 if ($symbol == 'node-expanded')
2023 $self ($item['kids'], $item['kidc'], $level + 1, $tagcache);
0137d53c
DO
2024 }
2025 else
2026 {
2027 $used = 0;
0137d53c 2028 echo "<tr valign=top>";
737a3f72 2029 printIPv4NetInfoTDs ($item, 'tdleft sparenetwork', $level, $symbol);
0137d53c
DO
2030 echo "<td class=tdcenter>";
2031 renderProgressBar ($used/$total);
2032 echo "<br><small>${used}/${total}</small></td>";
2033 echo "<td>&nbsp;</td></tr>";
2034 }
2035 $doing++;
d65353ad
DO
2036 }
2037}
2038
04d619d0 2039function renderIPv4Space ()
e673ee24 2040{
932cf41f 2041 $tagfilter = getTagFilter();
94a40058
DO
2042 $netlist = getIPv4NetworkList ($tagfilter, getTFMode());
2043 $netcount = count ($netlist);
2044 $tree = treeFromList ($netlist, getConfigVar ('TREE_THRESHOLD'));
2045 unset ($netlist);
1327d9dd 2046 sortTree ($tree, 'IPv4NetworkCmp');
0137d53c 2047 treeApplyFunc ($tree, 'iptree_fill');
737a3f72 2048 treeApplyFunc ($tree, 'countOwnIPv4Addresses');
3630d1fb
DO
2049
2050 echo "<table border=0 class=objectview>\n";
2051 echo "<tr><td class=pcleft>";
1327d9dd 2052 // FIXME: the counter is wrong
94a40058 2053 startPortlet ("networks (${netcount})");
04d619d0 2054 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
57dece2f 2055 echo "<tr><th>prefix</th><th>name/tags</th><th>%% used</th>";
f0ed1181 2056 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
57dece2f
DO
2057 echo "<th>routed by</th>";
2058 echo "</tr>\n";
51b6651a 2059 renderIPv4SpaceRecords ($tree, count ($tree));
e673ee24 2060 echo "</table>\n";
a7fe7729 2061 finishPortlet();
74ccacff 2062 echo '</td><td class=pcright>';
5b7bd02e 2063 renderTagFilterPortlet ($tagfilter, 'ipv4net');
74ccacff 2064 echo "</td></tr></table>\n";
f973f491 2065}
a7fe7729 2066
f973f491
DO
2067function renderIPv4SLB ()
2068{
80e85ea1 2069 global $root, $page, $nextorder;
a7fe7729 2070
6fec9f39 2071 startPortlet ('SLB configuration');
b3c50e6c 2072 echo "<table border=0 width='100%'><tr>";
ee437dab 2073 foreach (array ('ipv4vslist', 'ipv4rsplist', 'rservers', 'lbs') as $pno)
e57dca7f 2074 echo "<td><h3><a href='${root}?page=${pno}'>" . $page[$pno]['title'] . "</a></h3></td>";
b3c50e6c
DO
2075 echo '</tr></table>';
2076 finishPortlet();
2077
c3bdc503 2078 $summary = getSLBSummary();
6fec9f39 2079 startPortlet ('SLB tactical overview');
4cadac8f
DO
2080 // A single id-keyed array isn't used here to preserve existing
2081 // order of LBs returned by getSLBSummary()
c3bdc503
DO
2082 $lblist = array();
2083 $lbdname = array();
4cadac8f 2084 foreach ($summary as $vipdata)
da04825a 2085 foreach (array_keys ($vipdata['lblist']) as $lb_object_id)
c3bdc503
DO
2086 if (!in_array ($lb_object_id, $lblist))
2087 {
2088 $oi = getObjectInfo ($lb_object_id);
2089 $lbdname[$lb_object_id] = $oi['dname'];
2090 $lblist[] = $lb_object_id;
2091 }
2092 if (!count ($summary))
2093 echo 'none configured';
2094 else
2095 {
80e85ea1 2096 $order = 'odd';
c3bdc503 2097 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
a7bc13c8 2098 echo "<tr><th>VS&nbsp;&darr; LB&nbsp;&rarr;</th>";
c3bdc503 2099 foreach ($lblist as $lb_object_id)
71b8bda1 2100 echo "<th><a href='${root}?page=object&tab=default&object_id=${lb_object_id}'>" . $lbdname[$lb_object_id] . "</a></th>";
c3bdc503 2101 echo "</tr>\n";
4cadac8f
DO
2102 foreach ($summary as $vsid => $vsdata)
2103 {
49fb2686 2104 echo "<tr class=row_${order}><td class=tdleft><a href='$root?page=ipv4vs&tab=default&vs_id=${vsid}'>";
8d790216 2105 echo buildVServiceName ($vsdata);
6fec9f39
DO
2106 echo '</a>';
2107 if (!empty ($vsdata['name']))
300826cb 2108 echo "<br>${vsdata['name']}";
6fec9f39 2109 echo "</td>";
4cadac8f 2110 foreach ($lblist as $lb_object_id)
da04825a 2111 {
60fbcece 2112 echo '<td class=tdleft>';
2b4eee17 2113 if (!isset ($vsdata['lblist'][$lb_object_id]))
da04825a
DO
2114 echo '&nbsp;';
2115 else
6fec9f39
DO
2116 {
2117 echo $vsdata['lblist'][$lb_object_id]['size'];
79a9edb4
DO
2118// echo " (<a href='${root}?page=ipv4rsp&pool_id=";
2119// echo $vsdata['lblist'][$lb_object_id]['id'] . "'>";
2120// echo $vsdata['lblist'][$lb_object_id]['name'] . '</a>)';
6fec9f39 2121 }
da04825a
DO
2122 echo '</td>';
2123 }
2124 echo "</tr>\n";
80e85ea1 2125 $order = $nextorder[$order];
4cadac8f 2126 }
c3bdc503
DO
2127 echo "</table>\n";
2128 }
a7fe7729 2129 finishPortlet ();
e673ee24
DO
2130}
2131
04d619d0 2132function renderIPv4SpaceEditor ()
e673ee24
DO
2133{
2134 global $root, $pageno, $tabno;
2135 showMessageOrError();
2a201216 2136
a262e150
DO
2137 // IPv4 validator
2138?>
2139 <script type="text/javascript">
2140 function init() {
2141 document.add_new_range.range.setAttribute('match', "^\\d\\d?\\d?\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\/\\d\\d?$");
2142
2143 Validate.init();
2144 }
2145 window.onload=init;
2146 </script>
2147<?php
2148
4c0653e2 2149 startPortlet ("Add new");
04d619d0 2150 echo '<table border=0 cellpadding=10 align=center>';
7056988c
DO
2151 // This form requires a name, so JavaScript validator can find it.
2152 // No printOpFormIntro() hence
04d619d0 2153 echo "<form method=post name='add_new_range' action='${root}process.php'>\n";
42023f03 2154 echo "<input type=hidden name=op value=addIPv4Prefix>\n";
2a201216
DY
2155 echo "<input type=hidden name=page value='${pageno}'>\n";
2156 echo "<input type=hidden name=tab value='${tabno}'>\n";
04d619d0
DO
2157 // tags column
2158 echo '<tr><td rowspan=4><h3>assign tags</h3>';
5c0bb421 2159 renderTagSelect();
04d619d0
DO
2160 echo '</td>';
2161 // inputs column
2162 echo "<th class=tdright>prefix</th><td class=tdleft><input type=text name='range' size=18 class='live-validate' tabindex=1></td>";
2163 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=2></td></tr>";
2164 echo "<tr><th class=tdright>connected network</th><td class=tdleft><input type=checkbox name='is_bcast' tabindex=3 checked></td></tr>";
2165 echo "<tr><td colspan=2>";
4c0653e2 2166 printImageHREF ('CREATE', 'Add a new network', TRUE, 4);
04d619d0 2167 echo '</td></tr>';
2a201216 2168 echo "</form></table><br><br>\n";
5c0bb421 2169 finishPortlet();
2a201216 2170
b18d26dc 2171 $addrspaceList = getIPv4NetworkList();
04d619d0 2172 if (count ($addrspaceList))
e673ee24 2173 {
04d619d0
DO
2174 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2175 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2176 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>&nbsp;</th></tr>";
2177 foreach ($addrspaceList as $iprange)
e673ee24 2178 {
b6b87070
DO
2179 $netdata = getIPv4NetworkInfo ($iprange['id']);
2180 loadIPv4AddrList ($netdata);
04d619d0 2181 $usedips = count ($netdata['addrlist']);
b6b87070 2182 $totalips = binInvMaskFromDec ($netdata['mask']) + 1;
04d619d0
DO
2183 echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=updIPv4Prefix&id=${iprange['id']}'>";
2184 echo '<tr valign=top><td>';
2185 if ($usedips == 0)
2186 {
2187 echo "<a href='${root}process.php?op=delIPv4Prefix&page=${pageno}&tab=${tabno}&id=${iprange['id']}'>";
2188 printImageHREF ('delete', 'Delete this IP range');
2189 echo "</a>";
2190 }
2191 else
2192 printImageHREF ('nodelete', 'There are IP addresses allocated or reserved');
2193 echo "</td>\n<td class=tdleft>${netdata['ip']}/${netdata['mask']}</td>";
2194 echo "<td><input type=text name=name size=40 value='${netdata['name']}'>";
2195 echo "</td><td>";
2196 printImageHREF ('save', 'Save changes', TRUE);
2197 echo "</td></tr></form>\n";
e673ee24 2198 }
04d619d0
DO
2199 echo "</table>";
2200 finishPortlet();
e673ee24 2201 }
e673ee24
DO
2202}
2203
beb9e88a 2204function renderIPv4Network ($id)
e673ee24 2205{
beb9e88a 2206 global $root, $pageno, $tabno, $aac2;
545478d0
DO
2207 $netmaskbylen = array
2208 (
2209 32 => '255.255.255.255',
2210 31 => '255.255.255.254',
2211 30 => '255.255.255.252',
2212 29 => '255.255.255.248',
2213 28 => '255.255.255.240',
2214 27 => '255.255.255.224',
2215 26 => '255.255.255.192',
2216 25 => '255.255.255.128',
2217 24 => '255.255.255.0',
2218 23 => '255.255.254.0',
2219 22 => '255.255.252.0',
2220 21 => '255.255.248.0',
2221 20 => '255.255.240.0',
2222 19 => '255.255.224.0',
2223 18 => '255.255.192.0',
2224 17 => '255.255.128.0',
2225 16 => '255.255.0.0',
2226 15 => '255.254.0.0',
2227 14 => '255.252.0.0',
2228 13 => '255.248.0.0',
2229 12 => '255.240.0.0',
2230 11 => '255.224.0.0',
2231 10 => '255.192.0.0',
2232 9 => '255.128.0.0',
2233 8 => '255.0.0.0',
2234 7 => '254.0.0.0',
2235 6 => '252.0.0.0',
2236 5 => '248.0.0.0',
2237 4 => '240.0.0.0',
2238 3 => '224.0.0.0',
2239 2 => '192.0.0.0',
2240 1 => '128.0.0.0'
2241 );
2242 $wildcardbylen = array
2243 (
2244 32 => '0.0.0.0',
2245 31 => '0.0.0.1',
2246 30 => '0.0.0.3',
2247 29 => '0.0.0.7',
2248 28 => '0.0.0.15',
2249 27 => '0.0.0.31',
2250 26 => '0.0.0.63',
2251 25 => '0.0.0.127',
2252 24 => '0.0.0.255',
2253 23 => '0.0.1.255',
2254 22 => '0.0.3.255',
2255 21 => '0.0.7.255',
2256 20 => '0.0.15.255',
2257 19 => '0.0.31.255',
2258 18 => '0.0.63.255',
2259 17 => '0.0.127.255',
2260 16 => '0.0.255.25',
2261 15 => '0.1.255.255',
2262 14 => '0.3.255.255',
2263 13 => '0.7.255.255',
2264 12 => '0.15.255.255',
2265 11 => '0.31.255.255',
2266 10 => '0.63.255.255',
2267 9 => '0.127.255.255',
2268 8 => '0.255.255.255',
2269 7 => '1.255.255.255',
2270 6 => '3.255.255.255',
2271 5 => '7.255.255.255',
2272 4 => '15.255.255.255',
2273 3 => '31.255.255.255',
2274 2 => '63.255.255.255',
2275 1 => '127.255.255.255'
2276 );
b901bf1f 2277 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
e673ee24
DO
2278 if (isset($_REQUEST['pg']))
2279 $page = $_REQUEST['pg'];
2280 else
2281 $page=0;
2282
b6b87070
DO
2283 $range = getIPv4NetworkInfo ($id);
2284 loadIPv4AddrList ($range);
2034d968
DO
2285 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2286 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>${range['name']}</h2></td></tr>\n";
2287
2288 echo "<tr><td class=pcleft width='50%'>";
2289 startPortlet ('summary');
2290 $total = ($range['ip_bin'] | $range['mask_bin_inv']) - ($range['ip_bin'] & $range['mask_bin']) + 1;
2291 $used = count ($range['addrlist']);
2292 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
04d619d0
DO
2293
2294 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
2034d968
DO
2295 renderProgressBar ($used/$total);
2296 echo "&nbsp;${used}/${total}</td></tr>\n";
04d619d0 2297
545478d0
DO
2298 echo "<tr><th width='50%' class=tdright>Netmask:</th><td class=tdleft>";
2299 echo $netmaskbylen[$range['mask']];
2300 echo "</td></tr>\n";
04d619d0 2301
545478d0
DO
2302 echo "<tr><th width='50%' class=tdright>Wildcard bits:</th><td class=tdleft>";
2303 echo $wildcardbylen[$range['mask']];
2304 echo "</td></tr>\n";
04d619d0 2305
f3d0cb20 2306 $routers = findRouters ($range['addrlist']);
f0ed1181 2307 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers))
04d619d0 2308 {
57dece2f 2309 echo "<tr><th width='50%' class=tdright>Routed by:</th>";
f3d0cb20 2310 printRoutersTD ($routers);
57dece2f 2311 echo "</tr>\n";
04d619d0
DO
2312 }
2313
e2ac59cf 2314 printTagTRs ("${root}?page=ipv4space&");
2034d968
DO
2315 echo "</table><br>\n";
2316 finishPortlet();
2317 echo "</td>\n";
e673ee24 2318
2034d968
DO
2319 echo "<td class=pcright>";
2320 startPortlet ('details');
e673ee24
DO
2321 $startip = $range['ip_bin'] & $range['mask_bin'];
2322 $endip = $range['ip_bin'] | $range['mask_bin_inv'];
2323 $realstartip = $startip;
2324 $realendip = $endip;
2325 $numpages = 0;
2326 if($endip - $startip > $maxperpage)
2327 {
e673ee24
DO
2328 $numpages = ($endip - $startip)/$maxperpage;
2329 $startip = $startip + $page * $maxperpage;
2330 $endip = $startip + $maxperpage-1;
2331 }
2332 echo "<center>";
b901bf1f
DO
2333 if ($numpages)
2334 echo '<h3>' . long2ip ($startip) . ' ~ ' . long2ip ($endip) . '</h3>';
e673ee24
DO
2335 for ($i=0; $i<$numpages; $i++)
2336 {
2337 if ($i == $page)
2338 echo "<b>$i</b> ";
2339 else
a60e0851 2340 echo "<a href='${root}?page=${pageno}&tab=${tabno}&id=$id&pg=$i'>$i</a> ";
e673ee24
DO
2341 }
2342 echo "</center>";
2343
beb9e88a 2344 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
e673ee24
DO
2345 echo "<tr><th>Address</th><th>Name</th><th>Allocation</th></tr>\n";
2346
2347
b2035dca
DO
2348 for ($ip = $startip; $ip <= $endip; $ip++) :
2349 if (isset ($_REQUEST['hl_ipv4_addr']) and ip2long ($_REQUEST['hl_ipv4_addr']) == $ip)
2350 $secondstyle = 'tdleft port_highlight';
2727c7df 2351 else
b2035dca
DO
2352 $secondstyle = 'tdleft';
2353 if (!isset ($range['addrlist'][$ip]))
e673ee24 2354 {
b2035dca
DO
2355 echo "<tr><td class=tdleft><a href='${root}?page=ipaddress&ip=" . long2ip ($ip) . "'>" . long2ip ($ip);
2356 echo "</a></td><td class='${secondstyle}'>&nbsp;</td><td class='${secondstyle}'>&nbsp;</td></tr>\n";
2357 continue;
2358 }
b2035dca 2359 $addr = $range['addrlist'][$ip];
2d318652 2360 echo "<tr class='${addr['class']}'>";
e673ee24 2361
b2035dca
DO
2362 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
2363 echo "<td class='${secondstyle}'>${addr['name']}</td><td class='${secondstyle}'>";
2364 $delim = '';
2365 $prologue = '';
2366 if ( $addr['reserved'] == 'yes')
2367 {
2d318652 2368 echo "<strong>RESERVED</strong> ";
b2035dca
DO
2369 $delim = '; ';
2370 }
2d318652 2371 foreach ($range['addrlist'][$ip]['allocs'] as $ref)
b2035dca 2372 {
beb9e88a
DO
2373 echo $delim . $aac2[$ref['type']];
2374 echo "<a href='${root}?page=object&object_id=${ref['object_id']}";
b2035dca
DO
2375 echo "&hl_ipv4_addr=${addr['ip']}'>";
2376 echo $ref['name'] . (empty ($ref['name']) ? '' : '@');
2377 echo "${ref['object_name']}</a>";
2378 $delim = '; ';
2379 }
2380 if ($delim != '')
2381 {
6131056c 2382 $delim = '';
b2035dca
DO
2383 $prologue = '<br>';
2384 }
2d318652 2385 foreach ($range['addrlist'][$ip]['lblist'] as $ref)
b2035dca
DO
2386 {
2387 echo $prologue;
602663f4 2388 $prologue = '';
b2035dca
DO
2389 echo "${delim}<a href='${root}?page=object&object_id=${ref['object_id']}'>";
2390 echo "${ref['object_name']}</a>:<a href='${root}?page=ipv4vs&vs_id=${ref['vs_id']}'>";
2391 echo "${ref['vport']}/${ref['proto']}</a>&rarr;";
2392 $delim = '; ';
2393 }
2394 if ($delim != '')
2395 {
2396 $delim = '';
2397 $prologue = '<br>';
e673ee24 2398 }
2d318652 2399 foreach ($range['addrlist'][$ip]['rslist'] as $ref)
b2035dca
DO
2400 {
2401 echo $prologue;
2402 $prologue = '';
2403 echo "${delim}&rarr;${ref['rsport']}@<a href='${root}?page=ipv4rsp&pool_id=${ref['rspool_id']}'>";
2404 echo "${ref['rspool_name']}</a>";
2405 $delim = '; ';
2406 }
2407 echo "</td></tr>\n";
2408 endfor;
2727c7df 2409 // end of iteration
e673ee24
DO
2410
2411 echo "</table>";
2034d968
DO
2412 finishPortlet();
2413 echo "</td></tr></table>\n";
e673ee24
DO
2414}
2415
53ef3908 2416function renderIPv4NetworkProperties ($id)
e673ee24 2417{
e673ee24 2418 showMessageOrError();
53ef3908
DO
2419 $netdata = getIPv4NetworkInfo ($id);
2420 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
e673ee24 2421 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 2422 printOpFormIntro ('editRange');
53ef3908
DO
2423 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${netdata['name']}'></tr>";
2424 echo "<tr><td colspan=2 class=tdcenter>";
2425 printImageHREF ('SAVE', 'Save changes', TRUE);
2426 echo "</td></form></tr></table>\n";
e673ee24
DO
2427}
2428
2d318652 2429function renderIPv4Address ($dottedquad)
e673ee24 2430{
52c836b1 2431 global $root, $aat;
2d318652 2432 $address = getIPv4Address ($dottedquad);
68225375 2433 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2d318652
DO
2434 echo "<tr><td colspan=2 align=center><h1>${dottedquad}</h1></td></tr>\n";
2435 if (!empty ($address['name']))
68225375 2436 echo "<tr><td colspan=2 align=center><h2>${address['name']}</h2></td></tr>\n";
e673ee24 2437
68225375
DO
2438 echo "<tr><td class=pcleft>";
2439 startPortlet ('summary');
2440 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
04d619d0 2441 echo "<tr><th width='50%' class=tdright>Allocations:</th><td class=tdleft>" . count ($address['allocs']) . "</td></tr>\n";
68225375
DO
2442 echo "<tr><th width='50%' class=tdright>Originated NAT connections:</th><td class=tdleft>" . count ($address['outpf']) . "</td></tr>\n";
2443 echo "<tr><th width='50%' class=tdright>Arriving NAT connections:</th><td class=tdleft>" . count ($address['inpf']) . "</td></tr>\n";
04d619d0 2444 echo "<tr><th width='50%' class=tdright>SLB virtual services:</th><td class=tdleft>" . count ($address['lblist']) . "</td></tr>\n";
68225375
DO
2445 echo "<tr><th width='50%' class=tdright>SLB real servers:</th><td class=tdleft>" . count ($address['rslist']) . "</td></tr>\n";
2446 printTagTRs();
2447 echo "</table><br>\n";
2448 finishPortlet();
2449 echo "</td>\n";
e673ee24 2450
68225375 2451 echo "<td class=pcright>";
e673ee24 2452
2d318652 2453 if (!empty ($address['class']))
59bebe2b 2454 {
8e700dd1 2455 startPortlet ('allocations');
2d318652
DO
2456 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2457 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2458 $class = $address['class'];
2459 // render all allocation records for this address the same way
59bebe2b 2460 if ($address['reserved'] == 'yes')
2d318652
DO
2461 echo "<tr class='${class}'><td colspan=2>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td></tr>";
2462 foreach ($address['allocs'] as $bond)
59bebe2b 2463 {
8e700dd1
DO
2464 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
2465 $secondclass = 'tdleft port_highlight';
2466 else
2467 $secondclass = 'tdleft';
2468 echo "<tr class='$class'><td class=tdleft><a href='${root}?page=object&object_id=${bond['object_id']}";
2d318652 2469 echo "&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td><td class='${secondclass}'>${bond['name']}</td><td class='${secondclass}'><strong>";
52c836b1
DO
2470 echo $aat[$bond['type']];
2471 echo "</strong></td></tr>\n";
59bebe2b
DO
2472 }
2473 echo "</table><br><br>";
2474 finishPortlet();
2475 }
e673ee24 2476
f3d0cb20
DO
2477 // FIXME: The returned list is structured differently, than we expect it to be. One of the sides
2478 // must be fixed.
2d318652 2479 if (count ($address['lblist']))
e673ee24 2480 {
2d318652
DO
2481 startPortlet ('Virtual services (' . count ($address['lblist']) . ')');
2482 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
59bebe2b 2483 echo "<tr><th>VS</th><th>name</th></tr>\n";
2d318652 2484 foreach ($address['lblist'] as $vsinfo)
e673ee24 2485 {
2d318652 2486 echo "<tr><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vsinfo['vs_id']}'>";
59bebe2b 2487 echo buildVServiceName ($vsinfo) . "</a></td><td class=tdleft>";
5fe1ed76 2488 echo $vsinfo['name'] . "</td></tr>\n";
e673ee24 2489 }
59bebe2b
DO
2490 echo "</table><br><br>";
2491 finishPortlet();
e673ee24 2492 }
5fe1ed76
DO
2493
2494 if (count ($address['rslist']))
2495 {
2496 startPortlet ('Real servers (' . count ($address['rslist']) . ')');
2d318652 2497 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
53f4b619 2498 echo "<tr><th>&nbsp;</th><th>port</th><th>RS pool</th></tr>\n";
5fe1ed76
DO
2499 foreach ($address['rslist'] as $rsinfo)
2500 {
2501 echo "<tr><td>";
2502 if ($rsinfo['inservice'] == 'yes')
2503 printImageHREF ('inservice', 'in service');
2504 else
2505 printImageHREF ('notinservice', 'NOT in service');
2d318652
DO
2506 echo "</td><td class=tdleft>${rsinfo['rsport']}</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rsinfo['rspool_id']}'>";
2507 echo $rsinfo['rspool_name'] . "</a></td></tr>\n";
5fe1ed76
DO
2508 }
2509 echo "</table><br><br>";
2510 finishPortlet();
2511 }
2512
68225375
DO
2513 if (count ($address['outpf']))
2514 {
105a3bc8 2515 startPortlet ('departing NAT rules');
2d318652 2516 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
105a3bc8
DO
2517 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2518 foreach ($address['outpf'] as $rule)
b62ff880 2519 echo "<tr><td>${rule['proto']}</td><td>${rule['localip']}:${rule['localport']}</td><td>${rule['remoteip']}:${rule['remoteport']}</td><td>${rule['description']}</td></tr>";
105a3bc8 2520 echo "</table>";
68225375
DO
2521 finishPortlet();
2522 }
105a3bc8
DO
2523
2524 if (count ($address['inpf']))
2525 {
2526 startPortlet ('arriving NAT rules');
2d318652 2527 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
105a3bc8
DO
2528 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2529 foreach ($address['inpf'] as $rule)
b62ff880 2530 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
2531 echo "</table>";
2532 finishPortlet();
2533 }
2534
68225375
DO
2535 echo "</td></tr>";
2536 echo "</table>\n";
e673ee24
DO
2537}
2538
2d318652 2539function renderIPv4AddressProperties ($dottedquad)
e673ee24 2540{
e673ee24 2541 showMessageOrError();
2d318652
DO
2542 $address = getIPv4Address ($dottedquad);
2543 echo "<center><h1>$dottedquad</h1></center>\n";
7056988c 2544
1fbc9fd6 2545 startPortlet ('update');
e673ee24 2546 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
7056988c 2547 printOpFormIntro ('editAddress');
2d318652
DO
2548 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${address['name']}'></tr>";
2549 echo "<td class='tdright'>Reserved:</td><td class='tdleft'><input type=checkbox name=reserved size=20 ";
2550 echo ($address['reserved']=='yes') ? 'checked' : '';
53ef3908
DO
2551 echo "></tr><tr><td colspan=2 class='tdcenter'>";
2552 printImageHREF ('SAVE', 'Save changes', TRUE);
2553 echo "</td></form></tr></table>\n";
1fbc9fd6
DO
2554 finishPortlet();
2555 if (empty ($address['name']) and $address['reserved'] == 'no')
2556 return;
7056988c 2557
1fbc9fd6 2558 startPortlet ('release');
7056988c 2559 printOpFormIntro ('editAddress', array ('name' => '', 'reserved' => ''));
1fbc9fd6
DO
2560 echo "<input type=submit value='release'></form>";
2561 finishPortlet();
e673ee24
DO
2562}
2563
2d318652 2564function renderIPv4AddressAllocations ($dottedquad)
e673ee24 2565{
e673ee24 2566 showMessageOrError();
2d318652 2567 global $pageno, $tabno, $root, $aat;
e673ee24 2568
2d318652
DO
2569 $address = getIPv4Address ($dottedquad);
2570 $class = $address['class'];
2571 echo "<center><h1>${dottedquad}</h1></center>\n";
105a3bc8 2572 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2d318652 2573 echo "<tr><th>&nbsp;</th><th>object</th><th>OS interface</th><th>allocation type</th><th>&nbsp;</th></tr>\n";
e673ee24
DO
2574
2575 if ($address['reserved'] == 'yes')
2d318652
DO
2576 echo "<tr class='${class}'><td colspan=3>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td><td>&nbsp;</td></tr>";
2577 foreach ($address['allocs'] as $bond)
e673ee24 2578 {
7056988c
DO
2579 echo "<tr class='$class'>";
2580 printOpFormIntro ('updIPv4Allocation', array ('object_id' => $bond['object_id']));
2d318652 2581 echo "<td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${dottedquad}&object_id=${bond['object_id']}'>";
e673ee24
DO
2582 printImageHREF ('delete', 'Unallocate address');
2583 echo "</a></td>";
2d318652 2584 echo "<td><a href='${root}?page=object&object_id=${bond['object_id']}&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td>";
52c836b1
DO
2585 echo "<td><input type='text' name='bond_name' value='${bond['name']}' size=10></td><td>";
2586 printSelect ($aat, 'bond_type', $bond['type']);
2587 echo "</td><td>";
b4c1ef87
DO
2588 printImageHREF ('save', 'Save changes', TRUE);
2589 echo "</td></form></tr>\n";
e673ee24 2590 }
7056988c 2591 printOpFormIntro ('addIPv4Allocation');
b4c1ef87
DO
2592 echo "<td>";
2593 printImageHREF ('add', 'new allocation', TRUE);
2594 echo "</td><td><select name='object_id'>";
e673ee24 2595
6dbdc7c7 2596 foreach (explode (',', getConfigVar ('IPV4_PERFORMERS')) as $type)
e9132485 2597 foreach (getNarrowObjectList ($type) as $object)
e673ee24 2598 echo "<option value='${object['id']}'>${object['dname']}</option>";
e673ee24 2599
52c836b1
DO
2600 echo "</select></td><td><input type='text' name='bond_name' value='' size=10></td><td>";
2601 printSelect ($aat, 'bond_type');
2602 echo "</td><td>&nbsp;</td></form></tr>";
e673ee24
DO
2603 echo "</table><br><br>";
2604
2605}
2606
eeb4a5d8 2607function renderNATv4ForObject ($object_id = 0)
e673ee24
DO
2608{
2609 global $pageno, $tabno, $root;
2610
2611 $info = getObjectInfo ($object_id);
eeb4a5d8 2612 $forwards = getNATv4ForObject ($object_id);
2c817354 2613 $alloclist = getObjectIPv4Allocations ($object_id);
e673ee24 2614 showMessageOrError();
f28fbe8b 2615 echo "<center><h2>locally performed NAT</h2></center>";
e673ee24 2616
105a3bc8 2617 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
d54b9495 2618 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
DO
2619
2620 foreach ($forwards['out'] as $pf)
2621 {
2c817354
DO
2622 $class = 'trerror';
2623 $osif = '';
2624 if (isset ($alloclist [$pf['localip']]))
2625 {
2626 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
2627 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
2628 }
e673ee24
DO
2629
2630 echo "<tr class='$class'>";
72d8ced3 2631 echo "<td><a href='${root}process.php?op=delNATv4Rule&localip=${pf['localip']}&localport=${pf['localport']}&remoteip=${pf['remoteip']}&remoteport=${pf['remoteport']}&proto=${pf['proto']}&object_id=$object_id&page=${pageno}&tab=${tabno}'>";
4de22e7e
DO
2632 printImageHREF ('delete', 'Delete NAT rule');
2633 echo "</a></td>";
2c817354 2634 echo "<td>${pf['proto']}/${osif}<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}";
f28fbe8b
DO
2635 if (!empty ($pf['local_addr_name']))
2636 echo ' (' . $pf['local_addr_name'] . ')';
2637 echo "</td>";
e673ee24
DO
2638 echo "<td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2639
53ef3908 2640 $address = getIPv4Address ($pf['remoteip']);
e673ee24
DO
2641
2642 echo "<td class='description'>";
53ef3908
DO
2643 if (count ($address['allocs']))
2644 foreach ($address['allocs'] as $bond)
f28fbe8b
DO
2645 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
2646 elseif (!empty ($pf['remote_addr_name']))
2647 echo '(' . $pf['remote_addr_name'] . ')';
7056988c
DO
2648 printOpFormIntro
2649 (
2650 'updNATv4Rule',
2651 array
2652 (
2653 'localip' => $pf['localip'],
2654 'localport' => $pf['localport'],
2655 'remoteip' => $pf['remoteip'],
2656 'remoteport' => $pf['remoteport'],
2657 'proto' => $pf['proto']
2658 )
2659 );
2660 echo "</td><td class='description'>";
d54b9495
DO
2661 echo "<input type='text' name='description' value='${pf['description']}'></td><td>";
2662 printImageHREF ('save', 'Save changes', TRUE);
2663 echo "</td></form></tr>";
e673ee24 2664 }
7056988c 2665 printOpFormIntro ('addNATv4Rule');
d54b9495
DO
2666 echo "<tr align='center'><td>";
2667 printImageHREF ('add', 'Add new NAT rule', TRUE);
2668 echo '</td><td>';
eeb4a5d8 2669 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP'), 'proto');
52c3543f 2670 echo "<select name='localip' tabindex=1>";
e673ee24 2671
2c817354
DO
2672 foreach ($alloclist as $dottedquad => $alloc)
2673 {
2674 $name = empty ($alloc['addrinfo']['name']) ? '' : (' (' . niftyString ($alloc['addrinfo']['name']) . ')');
2675 $osif = empty ($alloc['osif']) ? '' : ($alloc['osif'] . ': ');
2676 echo "<option value='${dottedquad}'>${osif}${dottedquad}${name}</option>";
2677 }
e673ee24 2678
52c3543f
DO
2679 echo "</select>:<input type='text' name='localport' size='4' tabindex=2></td>";
2680 echo "<td><input type='text' name='remoteip' id='remoteip' size='10' tabindex=3>";
4de22e7e
DO
2681 echo "<a href='javascript:;' onclick='window.open(\"${root}/find_object_ip_helper.php\", \"findobjectip\", \"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
2682 printImageHREF ('find', 'Find object');
2683 echo "</a>";
52c3543f 2684 echo ":<input type='text' name='remoteport' size='4' tabindex=4></td><td></td>";
d54b9495 2685 echo "<td colspan=1><input type='text' name='description' size='20' tabindex=5></td><td>&nbsp;</td></tr>";
e673ee24
DO
2686 echo "</form>";
2687
2688 echo "</table><br><br>";
2689
f28fbe8b 2690 echo "<center><h2>arriving NAT connections</h2></center>";
105a3bc8 2691 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
e673ee24
DO
2692 echo "<tr><th></th><th>Source</th><th>Source objects</th><th>Target</th><th>Description</th></tr>\n";
2693
2694 foreach ($forwards['in'] as $pf)
2695 {
72d8ced3 2696 echo "<tr><td><a href='${root}process.php?op=delNATv4Rule&localip=${pf['localip']}&localport=${pf['localport']}&remoteip=${pf['remoteip']}&remoteport=${pf['remoteport']}&proto=${pf['proto']}&object_id=${pf['object_id']}&page=${pageno}&tab=${tabno}'>";
4de22e7e
DO
2697 printImageHREF ('delete', 'Delete NAT rule');
2698 echo "</a></td>";
e673ee24
DO
2699 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
2700 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
2701 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2702 echo "<td class='description'>${pf['description']}</td></tr>";
2703 }
2704
e673ee24 2705 echo "</table><br><br>";
e673ee24
DO
2706}
2707
7056988c 2708// FIXME: move related code away into ophandler(s)
e673ee24
DO
2709function renderAddMultipleObjectsForm ()
2710{
20c901a7 2711 global $root, $pageno, $tabno, $nextorder;
e673ee24
DO
2712
2713 $type_id = array();
7f791d1d 2714 $global_type_id = 0;
e673ee24
DO
2715 $name = array();
2716 $asset_no = array();
ce4d1a79 2717 $keepvalues1 = $keepvalues2 = FALSE;
7f791d1d 2718 $log = array();
e673ee24 2719 // Look for current submit.
7f791d1d 2720 if (isset ($_REQUEST['got_fast_data']))
e673ee24 2721 {
f60bb422 2722 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
ce4d1a79 2723 $keepvalues1 = TRUE;
9c0b0016
DO
2724 $max = getConfigVar ('MASSCOUNT');
2725 for ($i = 0; $i < $max; $i++)
e673ee24
DO
2726 {
2727 if (!isset ($_REQUEST["${i}_object_type_id"]))
2728 {
2729 $log[] = array ('code' => 'error', 'message' => "Submitted form is invalid at line " . $i + 1);
2730 break;
2731 }
2c6c7645
DO
2732 assertUIntArg ("${i}_object_type_id", __FUNCTION__, TRUE);
2733 assertStringArg ("${i}_object_name", __FUNCTION__, TRUE);
2734 assertStringArg ("${i}_object_label", __FUNCTION__, TRUE);
2735 assertStringArg ("${i}_object_asset_no", __FUNCTION__, TRUE);
2736 assertStringArg ("${i}_object_barcode", __FUNCTION__, TRUE);
e673ee24
DO
2737 $type_id[$i] = $_REQUEST["${i}_object_type_id"];
2738 // Save user input for possible rendering.
2739 $name[$i] = $_REQUEST["${i}_object_name"];
2740 $label[$i] = $_REQUEST["${i}_object_label"];
2741 $asset_no[$i] = $_REQUEST["${i}_object_asset_no"];
2742 $barcode[$i] = $_REQUEST["${i}_object_barcode"];
2743
f60bb422 2744 // It's better to skip silently, than to print a notice.
e673ee24
DO
2745 if ($type_id[$i] == 0)
2746 continue;
f60bb422 2747 if (commitAddObject ($name[$i], $label[$i], $barcode[$i], $type_id[$i], $asset_no[$i], $taglist) === TRUE)
e673ee24
DO
2748 $log[] = array ('code' => 'success', 'message' => "Added new object '${name[$i]}'");
2749 else
4d2e93f2 2750 $log[] = array ('code' => 'error', 'message' => __FUNCTION__ . ': commitAddObject() failed');
e673ee24 2751 }
e673ee24 2752 }
7f791d1d
DO
2753 elseif (isset ($_REQUEST['got_very_fast_data']))
2754 {
f60bb422 2755 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
ce4d1a79 2756 $keepvalues2 = TRUE;
2c6c7645
DO
2757 assertUIntArg ('global_type_id', __FUNCTION__, TRUE);
2758 assertStringArg ('namelist', __FUNCTION__, TRUE);
7f791d1d
DO
2759 $global_type_id = $_REQUEST['global_type_id'];
2760 if ($global_type_id == 0)
2761 {
2762 if (!empty ($_REQUEST['namelist']))
2763 $log[] = array ('code' => 'error', 'message' => 'Object type is not selected, check the form below');
2764 else
2765 $log[] = array ('code' => 'error', 'message' => 'Empty form has been ignored. Cheers.');
2766 }
2767 else
2768 {
2769 // The name extractor below was stolen from ophandlers.php:addMultiPorts()
2770 $names1 = explode ('\n', $_REQUEST['namelist']);
2771 $names2 = array();
2772 foreach ($names1 as $line)
2773 {
2774 $parts = explode ('\r', $line);
2775 reset ($parts);
2776 if (empty ($parts[0]))
2777 continue;
2778 else
2779 $names2[] = rtrim ($parts[0]);
2780 }
2781 foreach ($names2 as $cname)
f60bb422 2782 if (commitAddObject ($cname, '', '', $global_type_id, '', $taglist) === TRUE)
7f791d1d
DO
2783 $log[] = array ('code' => 'success', 'message' => "Added new object '${cname}'");
2784 else
2785 $log[] = array ('code' => 'error', 'message' => "Could not add '${cname}'");
2786 }
2787 }
2788 printLog ($log);
e673ee24
DO
2789
2790 // Render a form for the next.
2791 $typelist = getObjectTypeList();
4c330a14 2792 $typelist[0] = 'select type...';
7f791d1d 2793
f60bb422
DO
2794 startPortlet ('Distinct types, same tags');
2795 $max = getConfigVar ('MASSCOUNT');
20c901a7 2796 echo "<form name=fastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
e673ee24 2797 echo '<table border=0 align=center>';
f60bb422
DO
2798 echo "<tr><th>Object type</th><th>Common name</th><th>Visible label</th>";
2799 echo "<th>Asset tag</th><th>Barcode</th><th>Tags</th></tr>\n";
7f791d1d 2800 // If a user forgot to select object type on input, we keep his
e673ee24 2801 // previous input in the form.
9c0b0016 2802 for ($i = 0; $i < $max; $i++)
e673ee24 2803 {
7f791d1d 2804 echo '<tr><td>';
e7ade6bf
DO
2805 // Don't employ DEFAULT_OBJECT_TYPE to avoid creating ghost records for pre-selected empty rows.
2806 printSelect ($typelist, "${i}_object_type_id", 0);
e673ee24
DO
2807 echo '</td>';
2808 echo "<td><input type=text size=30 name=${i}_object_name";
ce4d1a79 2809 if ($keepvalues1 and isset ($name[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
e673ee24
DO
2810 echo " value='${name[$i]}'";
2811 echo "></td>";
2812 echo "<td><input type=text size=30 name=${i}_object_label";
ce4d1a79 2813 if ($keepvalues1 and isset ($label[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
e673ee24
DO
2814 echo " value='${label[$i]}'";
2815 echo "></td>";
2816 echo "<td><input type=text size=20 name=${i}_object_asset_no";
ce4d1a79 2817 if ($keepvalues1 and isset ($asset_no[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
e673ee24
DO
2818 echo " value='${asset_no[$i]}'";
2819 echo "></td>";
2820 echo "<td><input type=text size=10 name=${i}_object_barcode";
ce4d1a79 2821 if ($keepvalues1 and isset ($barcode[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
e673ee24
DO
2822 echo " value='${barcode[$i]}'";
2823 echo "></td>";
f60bb422
DO
2824 if ($i == 0)
2825 {
2826 echo "<td valign=top rowspan=${max}>";
2827 renderTagSelect();
2828 echo "</td>\n";
2829 }
e673ee24 2830 echo "</tr>\n";
e673ee24 2831 }
216c84bb 2832 echo "<tr><td class=submit colspan=5><input type=submit name=got_fast_data value='Go!'></td></tr>\n";
e673ee24
DO
2833 echo "</form></table>\n";
2834 finishPortlet();
7f791d1d 2835
f60bb422 2836 startPortlet ('Same type, same tags');
20c901a7 2837 echo "<form name=veryfastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
f60bb422
DO
2838 echo "<table border=0 align=center><tr><th>names</th><th>type</th></tr>";
2839 echo "<tr><td rowspan=3><textarea name=namelist cols=40 rows=25>\n";
ce4d1a79 2840 if ($keepvalues2 and $global_type_id == 0)
7f791d1d 2841 echo $_REQUEST['namelist'];
f60bb422
DO
2842 echo "</textarea></td><td valign=top>";
2843 printSelect ($typelist, "global_type_id", getConfigVar ('DEFAULT_OBJECT_TYPE'));
2844 echo "</td></tr>";
2845 echo "<tr><th>Tags</th></tr>";
2846 echo "<tr><td valign=top>";
2847 renderTagSelect();
2848 echo "</td></tr>";
2849 echo "<tr><td colspan=2><input type=submit name=got_very_fast_data value='Go!'></td></tr></table>\n";
2850 echo "</form>\n";
7f791d1d 2851 finishPortlet();
e673ee24
DO
2852}
2853
2854function printGreeting ()
2855{
59cd003e 2856 global $remote_username, $accounts, $root;
e673ee24 2857 $account = $accounts[$remote_username];
7056988c
DO
2858 $person = empty ($account['user_realname']) ? $account['user_name'] : $account['user_realname'];
2859 echo "Hello, ${person}. This is RackTables " . CODE_VERSION . ". Click <a href='${root}?logout'>here</a> to logout.";
e673ee24
DO
2860}
2861
2862function renderSearchResults ()
2863{
2864 global $remote_username, $root;
2865 $terms = trim ($_REQUEST['q']);
2866 if (empty ($terms))
2867 {
591ff2c4 2868 showError ('Search string cannot be empty.', __FUNCTION__);
e673ee24
DO
2869 return;
2870 }
54522168 2871 if (!permitted ('objects', 'default'))
e673ee24 2872 {
591ff2c4 2873 showError ('You are not authorized for viewing information about objects.', __FUNCTION__);
e673ee24
DO
2874 return;
2875 }
ea5fc465 2876 $nhits = 0;
e673ee24
DO
2877 // If we search for L2 address, we can either find one or find none.
2878 if
2879 (
2880 preg_match ('/^[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?$/i', $terms) or
2881 preg_match ('/^[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]$/i', $terms) or
ea5fc465
DO
2882 preg_match ('/^[0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9a-f][0-9a-f][0-9a-f][0-9a-f]$/i', $terms) or
2883 // STP bridge ID: bridge priotity + port MAC address. Cut off first 4 chars and look for MAC address.
2884 preg_match ('/^[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]$/i', $terms)
e673ee24
DO
2885 )
2886 // Search for L2 address.
2887 {
3ec29bf4
DO
2888 $terms = str_replace ('.', '', $terms);
2889 $terms = str_replace (':', '', $terms);
ea5fc465 2890 $terms = substr ($terms, -12);
e673ee24
DO
2891 $result = searchByl2address ($terms);
2892 if ($result !== NULL)
2893 {
ea5fc465
DO
2894 $nhits++;
2895 $lasthit = 'port';
2896 $summary['port'][] = $result;
e673ee24 2897 }
e673ee24
DO
2898 }
2899 elseif (preg_match ('/^[0-9][0-9]?[0-9]?\.[0-9]?[0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9]?[0-9]?[0-9]?$/i', $terms))
2900 // Search for IP address.
2901 {
bb0a44e9 2902 if (NULL !== getIPv4AddressNetworkId ($terms))
e673ee24 2903 {
ea5fc465 2904 $nhits++;
f3d0cb20
DO
2905 $lasthit = 'ipv4addressbydq';
2906 $summary['ipv4addressbydq'][] = $terms;
e673ee24 2907 }
e673ee24
DO
2908 }
2909 else
ea5fc465 2910 // Search for objects, addresses, networks, virtual services and RS pools by their description.
e673ee24 2911 {
ea5fc465
DO
2912 $tmp = getObjectSearchResults ($terms);
2913 if (count ($tmp))
e673ee24 2914 {
ea5fc465
DO
2915 $nhits += count ($tmp);
2916 $lasthit = 'object';
2917 $summary['object'] = $tmp;
e673ee24 2918 }
ea5fc465
DO
2919 $tmp = getIPv4AddressSearchResult ($terms);
2920 if (count ($tmp))
e673ee24 2921 {
ea5fc465 2922 $nhits += count ($tmp);
f3d0cb20
DO
2923 $lasthit = 'ipv4addressbydescr';
2924 $summary['ipv4addressbydescr'] = $tmp;
ea5fc465
DO
2925 }
2926 $tmp = getIPv4PrefixSearchResult ($terms);
2927 if (count ($tmp))
2928 {
2929 $nhits += count ($tmp);
2930 $lasthit = 'ipv4network';
2931 $summary['ipv4network'] = $tmp;
2932 }
05411ccd
DO
2933 $tmp = getIPv4RSPoolSearchResult ($terms);
2934 if (count ($tmp))
2935 {
2936 $nhits += count ($tmp);
2937 $lasthit = 'ipv4rspool';
2938 $summary['ipv4rspool'] = $tmp;
2939 }
2940 $tmp = getIPv4VServiceSearchResult ($terms);
2941 if (count ($tmp))
2942 {
2943 $nhits += count ($tmp);
2944 $lasthit = 'ipv4vs';
2945 $summary['ipv4vs'] = $tmp;
2946 }
6a88e734
DO
2947 $tmp = getAccountSearchResult ($terms);
2948 if (count ($tmp))
2949 {
2950 $nhits += count ($tmp);
2951 $lasthit = 'user';
2952 $summary['user'] = $tmp;
2953 }
ea5fc465
DO
2954 }
2955 if ($nhits == 0)
2956 echo "<center><h2>Nothing found for '${terms}'</h2></center>";
2957 elseif ($nhits == 1)
2958 {
2959 $record = current ($summary[$lasthit]);
2960 switch ($lasthit)
2961 {
2962 case 'port':
2963 echo "<script language='Javascript'>document.location='${root}?page=object";
2964 echo "&hl_port_id=" . $record['port_id'];
2965 echo "&object_id=" . $record['object_id'] . "';//</script>";
2966 break;
f3d0cb20
DO
2967 case 'ipv4addressbydq':
2968 $parentnet = getIPv4AddressNetworkId ($record);
2969 if ($parentnet !== NULL)
79a9edb4 2970 echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record}';//</script>";
f3d0cb20
DO
2971 else
2972 echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record}';//</script>";
ea5fc465 2973 break;
f3d0cb20
DO
2974 case 'ipv4addressbydescr':
2975 $parentnet = getIPv4AddressNetworkId ($record['ip']);
2976 if ($parentnet !== NULL)
79a9edb4 2977 echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record['ip']}';//</script>";
f3d0cb20
DO
2978 else
2979 echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record['ip']}';//</script>";
ea5fc465
DO
2980 break;
2981 case 'ipv4network':
2982 echo "<script language='Javascript'>document.location='${root}?page=iprange";
2983 echo "&id=${record['id']}";
2984 echo "';//</script>";
2985 break;
2986 case 'object':
2987 echo "<script language='Javascript'>document.location='${root}?page=object&object_id=${record['id']}';//</script>";
2988 break;
05411ccd 2989 case 'ipv4rspool':
0e692350 2990 echo "<script language='Javascript'>document.location='${root}?page=ipv4rsp&pool_id=${record['pool_id']}';//</script>";
05411ccd
DO
2991 break;
2992 case 'ipv4vs':
49fb2686 2993 echo "<script language='Javascript'>document.location='${root}?page=ipv4vs&vs_id=${record['id']}';//</script>";
05411ccd 2994 break;
6a88e734
DO
2995 case 'user':
2996 echo "<script language='Javascript'>document.location='${root}?page=user&user_id=${record['user_id']}';//</script>";
2997 break;
ea5fc465
DO
2998 }
2999 return;
3000 }
3001 else
3002 {
3003 global $nextorder;
3004 $order = 'odd';
3005 echo "<center><h2>${nhits} result(s) found for '${terms}'</h2></center>";
3006 foreach ($summary as $where => $what)
3007 switch ($where)
e673ee24 3008 {
ea5fc465 3009 case 'object':
06adfe89 3010 startPortlet ("<a href='${root}?page=objects'>Objects</a>");
ea5fc465
DO
3011 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3012 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>barcode</th></tr>';
3013 foreach ($what as $obj)
3014 {
3015 echo "<tr class=row_${order}><td><a href=\"${root}?page=object&object_id=${obj['id']}\">${obj['dname']}</a></td>";
3016 echo "<td>${obj['label']}</td>";
3017 echo "<td>${obj['asset_no']}</td>";
3018 echo "<td>${obj['barcode']}</td></tr>";
3019 $order = $nextorder[$order];
3020 }
3021 echo '</table>';
3022 finishPortlet();
3023 break;
3024 case 'ipv4network':
06adfe89 3025 startPortlet ("<a href='${root}?page=ipv4space'>IPv4 networks</a>");
ea5fc465 3026 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3c41194e 3027 echo '<tr><th>network</th><th>name/tags</th></tr>';
71287f1c 3028 foreach ($what as $netinfo)
ea5fc465 3029 {
71287f1c
DO
3030 echo "<tr class=row_${order} valign=top>";
3031 printIPv4NetInfoTDs ($netinfo);
3032 echo "</tr>\n";
ea5fc465
DO
3033 $order = $nextorder[$order];
3034 }
3035 echo '</table>';
3036 finishPortlet();
3037 break;
f3d0cb20 3038 case 'ipv4addressbydescr':
ea5fc465
DO
3039 startPortlet ('IPv4 addresses');
3040 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
f3d0cb20 3041 // FIXME: address, parent network, routers (if extended view is enabled)
ea5fc465
DO
3042 echo '<tr><th>Address</th><th>Descritpion</th></tr>';
3043 foreach ($what as $addr)
3044 {
f3d0cb20
DO
3045 echo "<tr class=row_${order}><td class=tdleft>";
3046 $parentnet = getIPv4AddressNetworkId ($addr['ip']);
3047 if ($parentnet !== NULL)
3048 echo "<a href='${root}?page=iprange&id=${parentnet}&hl_ipv4_addr=${addr['ip']}'>${addr['ip']}</a></td>";
3049 else
3050 echo "<a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
ea5fc465
DO
3051 echo "<td class=tdleft>${addr['name']}</td></tr>";
3052 $order = $nextorder[$order];
3053 }
3054 echo '</table>';
3055 finishPortlet();
3056 break;
05411ccd 3057 case 'ipv4rspool':
ee437dab 3058 startPortlet ("<a href='${root}?page=ipv4rsplist'>RS pools</a>");
05411ccd
DO
3059 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3060 foreach ($what as $rspool)
3061 {
0e692350 3062 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rspool['pool_id']}'>";
05411ccd
DO
3063 echo buildRSPoolName ($rspool);
3064 echo "</a></td></tr>";
3065 $order = $nextorder[$order];
3066 }
3067 echo '</table>';
3068 finishPortlet();
3069 break;
3070 case 'ipv4vs':
a239e016 3071 startPortlet ("<a href='${root}?page=ipv4vslist'>Virtual services</a>");
05411ccd
DO
3072 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3073 echo '<tr><th>VS</th><th>Descritpion</th></tr>';
3074 foreach ($what as $vs)
3075 {
49fb2686 3076 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs['id']}'>";
05411ccd 3077 echo buildVServiceName ($vs);
6a88e734
DO
3078 echo "</a></td><td class=tdleft>${vs['name']}</td></tr>";
3079 $order = $nextorder[$order];
3080 }
3081 echo '</table>';
3082 finishPortlet();
3083 break;
3084 case 'user':
3085 startPortlet ("<a href='${root}?page=userlist'>Users</a>");
3086 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3087 echo '<tr><th>username</th><th>realname</th></tr>';
3088 foreach ($what as $item)
3089 {
3090 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=user&user_id=${item['user_id']}'>";
3091 echo $item['user_name'];
3092 echo "</a></td><td class=tdleft>${item['user_realname']}</td></tr>";
05411ccd
DO
3093 $order = $nextorder[$order];
3094 }
3095 echo '</table>';
3096 finishPortlet();
3097 break;
e673ee24 3098 }
e673ee24
DO
3099 }
3100}
3101
3102// This function prints a table of checkboxes to aid the user in toggling mount atoms
3103// from one state to another. The first argument is rack data as
3104// produced by getRackData(), the second is the value used for the 'unckecked' state
3105// and the third is the value used for 'checked' state.
3106// Usage contexts:
3107// for mounting an object: printAtomGrid ($data, 'F', 'T')
3108// for changing rack design: printAtomGrid ($data, 'A', 'F')
3109// for adding rack problem: printAtomGrid ($data, 'F', 'U')
3110// for adding object problem: printAtomGrid ($data, 'T', 'W')
3111
3112function renderAtomGrid ($data)
3113{
3114 $rack_id = $data['id'];
3115 for ($unit_no = $data['height']; $unit_no > 0; $unit_no--)
3116 {
3117 echo "<tr><th>${unit_no}</th>";
3118 for ($locidx = 0; $locidx < 3; $locidx++)
3119 {
3120 $state = $data[$unit_no][$locidx]['state'];
3121 echo "<td class=state_${state}";
3122 if (isset ($data[$unit_no][$locidx]['hl']))
3123 echo $data[$unit_no][$locidx]['hl'];
3124 echo ">";
3125 if (!($data[$unit_no][$locidx]['enabled'] === TRUE))
3126 echo '<input type=checkbox disabled>';
3127 else
3128 echo "<input type=checkbox" . $data[$unit_no][$locidx]['checked'] . " name=atom_${rack_id}_${unit_no}_${locidx}>";
3129 echo '</td>';
3130 }
3131 echo "</tr>\n";
3132 }
3133}
3134
59427701 3135function renderUserList ()
e673ee24 3136{
9048d42b 3137 global $nextorder, $accounts, $root, $pageno;
59427701
DO
3138 echo "<table border=0 class=objectview>\n";
3139 echo "<tr><td class=pcleft>";
e673ee24
DO
3140 startPortlet ('User accounts');
3141 echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3142 echo "<tr><th class=tdleft>Username</th><th class=tdleft>Real name</th></tr>";
3143 $order = 'odd';
59427701 3144 $tagfilter = getTagFilter();
11c8e4be 3145 foreach (getUserAccounts ($tagfilter, getTFMode()) as $user)
e673ee24 3146 {
9048d42b
DO
3147 echo "<tr class=row_${order} valign=top><td class=tdleft><a href='${root}?page=user&user_id=${user['user_id']}'>";
3148 echo "${user['user_name']}</a>";
3149 $usertags = loadUserTags ($user['user_id']);
3150 if (count ($usertags))
3151 echo '<br><small>' . serializeTags ($usertags, "${root}?page=${pageno}&tab=default&") . '</small>';
3152 echo "</td><td class=tdleft>${user['user_realname']}</td></li>";
e673ee24
DO
3153 $order = $nextorder[$order];
3154 }
3155 echo '</table>';
3156 finishPortlet();
59427701
DO
3157 echo '</td><td class=pcright>';
3158 renderTagFilterPortlet ($tagfilter, 'user');
3159 echo "</td></tr></table>\n";
e673ee24
DO
3160}
3161
59427701 3162function renderUserListEditor ()
e673ee24
DO
3163{
3164 global $root, $pageno, $tabno, $accounts;
3165 startPortlet ('User accounts');
3166 showMessageOrError();
3167 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
623457f8 3168 echo "<tr><th>status (click to change)</th><th>Username</th><th>Real name</th><th>Password</th><th>&nbsp;</th></tr>\n";
e673ee24
DO
3169 foreach ($accounts as $account)
3170 {
7056988c
DO
3171 printOpFormIntro ('updateUser', array ('user_id' => $account['user_id']));
3172 echo "<tr><td>";
e673ee24
DO
3173 if ($account['user_enabled'] == 'yes' && $account['user_id'] != 1)
3174 {
59427701 3175 echo "<a href='${root}process.php?op=disableUser&page=${pageno}&tab=${tabno}&user_id=${account['user_id']}'>";
e673ee24
DO
3176 printImageHREF ('blockuser', 'disable account');
3177 echo "</a>\n";
3178 }
3179 if ($account['user_enabled'] == 'no' && $account['user_id'] != 1)
3180 {
59427701 3181 echo "<a href='${root}process.php?op=enableUser&page=${pageno}&tab=${tabno}&user_id=${account['user_id']}'>";
e673ee24
DO
3182 printImageHREF ('unblockuser', 'enable account');
3183 echo "</a>\n";
3184 }
3185 // Otherwise skip icon.
3186 echo "</td>";
3187 echo "<td><input type=text name=username value='${account['user_name']}' size=16></td>";
3188 echo "<td><input type=text name=realname value='${account['user_realname']}' size=24></td>";
8e5763a7
DO
3189 echo "<td><input type=password name=password value='${account['user_password_hash']}' size=64></td><td>";
3190 printImageHREF ('save', 'Save changes', TRUE);
3191 echo "</td></form></tr>\n";
e673ee24 3192 }
7056988c 3193 printOpFormIntro ('createUser');
8e5763a7 3194 echo "<td>&nbsp;</td><td><input type=text size=16 name=username tabindex=100></td>\n";
e673ee24 3195 echo "<td><input type=text size=24 name=realname tabindex=101></td>";
8e5763a7
DO
3196 echo "<td><input type=password size=64 name=password tabindex=102></td><td>";
3197 printImageHREF ('create', 'Add new account', TRUE, 103);
3198 echo "</td></tr></form>";
e673ee24
DO
3199 echo "</table><br>\n";
3200 finishPortlet();
3201}
3202
17c32f4c
DO
3203function renderPortMapViewer ()
3204{
3205 renderPortMap (FALSE);
3206}
3207
3208function renderPortMapEditor ()
3209{
3210 renderPortMap (TRUE);
3211}
3212
e673ee24
DO
3213function renderPortMap ($editable = FALSE)
3214{
3215 global $nextorder, $root, $pageno, $tabno;
3216 showMessageOrError();
3217 startPortlet ("Port compatibility map");
3218 $ptlist = getPortTypes();
3219 $pclist = getPortCompat();
3220 $pctable = buildPortCompatMatrixFromList ($ptlist, $pclist);
3221 if ($editable)
7056988c 3222 printOpFormIntro ('save');
e673ee24
DO
3223 echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3224 echo "<tr><th class=vert_th>&nbsp;</th>";
3225 foreach ($ptlist as $name2)
3226 echo "<th>to ${name2}</th>";
3227 echo "</tr>";
3228 // Make a copy to have an independent array pointer.
3229 $ptlistY = $ptlist;
3230 $order = 'odd';
3231 foreach ($ptlistY as $type1 => $name1)
3232 {
3233 echo "<tr class=row_${order}><th class=vert_th style='border-bottom: 0px;'>from $name1</th>";
3234 foreach ($ptlist as $type2 => $name2)
3235 {
92b38217 3236 echo '<td' . ($pctable[$type1][$type2] ? " class=portmap_highlight_$order" : '') . '>';
19acd465 3237 echo '<input type=checkbox' . ($editable ? " name=atom_${type1}_${type2}" : ' disabled');
e673ee24
DO
3238 echo ($pctable[$type1][$type2] ? ' checked' : '') . '></td>';
3239 }
3240 echo "</tr>\n";
3241 $order = $nextorder[$order];
3242 }
3243 echo '</table><br>';
3244 if ($editable)
3245 {
7056988c 3246 printImageHREF ('SAVE', 'Save changes', TRUE);
e673ee24
DO
3247 echo "</form>";
3248 }
3249 finishPortlet();
3250}
3251
3252function renderConfigMainpage ()
3253{
3254 global $pageno, $root;
3255 $children = getDirectChildPages ($pageno);
3256 echo '<ul>';
27ef67da
DO
3257 // FIXME: assume all config kids to have static titles at the moment,
3258 // but use some proper abstract function later.
e673ee24 3259 foreach ($children as $cpageno => $child)
27ef67da 3260 echo "<li><a href='${root}?page=${cpageno}'>" . $child['title'] . "</li>\n";
e673ee24
DO
3261 echo '';
3262 echo '</ul>';
3263}
3264
3265function renderRackPage ($rack_id)
3266{
3267 if ($rack_id == 0)
3268 {
7056988c 3269 showError ('Invalid argument', __FUNCTION__);
e673ee24
DO
3270 return;
3271 }
3272 if (($rackData = getRackData ($rack_id)) == NULL)
3273 {
591ff2c4 3274 showError ('getRackData() failed', __FUNCTION__);
e673ee24
DO
3275 return;
3276 }
3277 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
3278
3279 // Left column with information.
3280 echo "<td class=pcleft>";
254673dd 3281 renderRackInfoPortlet ($rackData);
e673ee24
DO
3282 echo '</td>';
3283
3284 // Right column with rendered rack.
3285 echo '<td>';
3286 startPortlet ('Rack diagram');
3287 renderRack ($rack_id);
3288 finishPortlet();
3289 echo '</td>';
3290
3291 echo '</tr></table>';
3292}
3293
3294function renderDictionary ()
3295{
3296 global $nextorder;
2dd59b15 3297 $dict = getDict (TRUE);
aa28ebdf 3298 echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
aa28ebdf
DO
3299 foreach ($dict as $chapter_no => $chapter)
3300 {
a22ec5b4 3301 $order = 'odd';
83d2fcca 3302 echo "<tr><th>Chapter</th><th>refs</th><th>Word</th></tr>\n";
aa28ebdf
DO
3303 $wc = count ($chapter['word']);
3304 echo "<tr class=row_${order}><td class=tdleft" . ($wc ? " rowspan = ${wc}" : '');
3305 echo "><div title='number=${chapter_no}'>${chapter['name']} (${wc} records)</div></td>";
3306 if (!$wc)
3307 echo "<td colspan=2>none</td>";
3308 else
e673ee24 3309 {
aa28ebdf
DO
3310 $chap_start = TRUE;
3311 foreach ($chapter['word'] as $key => $value)
3312 {
3313 if (!$chap_start)
3314 echo "<tr class=row_${order}>";
3315 else
3316 $chap_start = FALSE;
6bb8e41d
DO
3317 echo '<td>' . ($chapter['refcnt'][$key] ? $chapter['refcnt'][$key] : '&nbsp;') . '</td>';
3318 echo "<td><div title='key=${key}'>${value}</div></td></tr>\n";
aa28ebdf
DO
3319 $order = $nextorder[$order];
3320 }
e673ee24 3321 }
e673ee24 3322 }
2dd59b15 3323 echo "</table>\n<br>";
e673ee24
DO
3324}
3325
3326function renderDictionaryEditor ()
3327{
f632bd28 3328 global $root, $pageno, $tabno, $nextorder;
e673ee24 3329 $dict = getDict();
95d80773 3330 showMessageOrError();
f632bd28
DO
3331 echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3332 foreach ($dict as $chapter_no => $chapter)
e673ee24 3333 {
f632bd28 3334 $order = 'odd';
b2f9fa84 3335 echo "<tr><th>Chapter</th><th>&nbsp;</th><th>Word</th><th>&nbsp;</th></tr>\n";
f632bd28
DO
3336 $wc = count ($chapter['word']);
3337 // One extra span for the new record per each chapter block.
3338 echo "<tr class=row_${order}><td class=tdleft" . ($wc ? ' rowspan = ' . ($wc + 1) : '');
3339 echo "><div title='number=${chapter_no}'>${chapter['name']} (${wc} records)</div></td>";
7056988c
DO
3340 printOpFormIntro ('add', array ('chapter_no' => $chapter['no']));
3341 echo "<td>";
3342 printImageHREF ('add', 'Add new', TRUE);
3343 echo "</td>";
f632bd28 3344 echo "<td class=tdright><input type=text name=dict_value size=32></td>";
7056988c 3345 echo "<td>&nbsp;</td>";
f632bd28 3346 echo '</tr></form>';
b2f9fa84 3347 $order = $nextorder[$order];
e673ee24
DO
3348 foreach ($chapter['word'] as $key => $value)
3349 {
7056988c 3350 printOpFormIntro ('upd', array ('chapter_no' => $chapter['no'], 'dict_key' => $key));
95d80773 3351 echo "<tr class=row_${order}><td>";
f632bd28
DO
3352 // Prevent deleting words currently used somewhere.
3353