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