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