r4188 update: UI: ability to clear object ports list at one blow
[racktables] / inc / interface.php
1 <?php
2 /*
3 *
4 * This file contains frontend functions for RackTables.
5 *
6 */
7
8 require_once 'ajax-interface.php';
9
10 // Interface function's special.
11 $nextorder['odd'] = 'even';
12 $nextorder['even'] = 'odd';
13
14 // address allocation type
15 $aat = array
16 (
17 'regular' => 'Connected',
18 'virtual' => 'Loopback',
19 'shared' => 'Shared',
20 'router' => 'Router',
21 );
22 // address allocation code, IPv4 addresses and objects view
23 $aac = array
24 (
25 'regular' => '',
26 'virtual' => '<strong>L</strong>',
27 'shared' => '<strong>S</strong>',
28 'router' => '<strong>R</strong>',
29 );
30 // address allocation code, IPv4 networks view
31 $aac2 = array
32 (
33 'regular' => '',
34 'virtual' => '<strong>L:</strong>',
35 'shared' => '<strong>S:</strong>',
36 'router' => '<strong>R:</strong>',
37 );
38
39 $vtdecoder = array
40 (
41 'ondemand' => '',
42 'compulsory' => 'P',
43 # 'alien' => 'NT',
44 );
45
46 $vtoptions = array
47 (
48 'ondemand' => 'auto',
49 'compulsory' => 'permanent',
50 # 'alien' => 'never touch',
51 );
52
53 // Let's have it here, so extensions can add their own images.
54 $image = array();
55 $image['logo']['path'] = 'pix/defaultlogo.png';
56 $image['logo']['width'] = 210;
57 $image['logo']['height'] = 40;
58 $image['rackspace']['path'] = 'pix/racks.png';
59 $image['rackspace']['width'] = 218;
60 $image['rackspace']['height'] = 200;
61 $image['objects']['path'] = 'pix/server.png';
62 $image['objects']['width'] = 218;
63 $image['objects']['height'] = 200;
64 $image['depot']['path'] = 'pix/server.png';
65 $image['depot']['width'] = 218;
66 $image['depot']['height'] = 200;
67 $image['files']['path'] = 'pix/files.png';
68 $image['files']['width'] = 218;
69 $image['files']['height'] = 200;
70 $image['ipv4space']['path'] = 'pix/addressspace.png';
71 $image['ipv4space']['width'] = 218;
72 $image['ipv4space']['height'] = 200;
73 $image['ipv6space']['path'] = 'pix/addressspacev6.png';
74 $image['ipv6space']['width'] = 218;
75 $image['ipv6space']['height'] = 200;
76 $image['ipv4slb']['path'] = 'pix/slb.png';
77 $image['ipv4slb']['width'] = 218;
78 $image['ipv4slb']['height'] = 200;
79 $image['config']['path'] = 'pix/configuration.png';
80 $image['config']['width'] = 218;
81 $image['config']['height'] = 200;
82 $image['reports']['path'] = 'pix/report.png';
83 $image['reports']['width'] = 218;
84 $image['reports']['height'] = 200;
85 $image['8021q']['path'] = 'pix/8021q.png';
86 $image['8021q']['width'] = 218;
87 $image['8021q']['height'] = 200;
88 $image['objectlog']['path'] = 'pix/crystal-mimetypes-shellscript-218x200.png';
89 $image['objectlog']['width'] = 218;
90 $image['objectlog']['height'] = 200;
91 $image['virtual']['path'] = 'pix/virtualresources.png';
92 $image['virtual']['width'] = 218;
93 $image['virtual']['height'] = 200;
94 $image['download']['path'] = 'pix/download.png';
95 $image['download']['width'] = 16;
96 $image['download']['height'] = 16;
97 $image['DOWNLOAD']['path'] = 'pix/download-big.png';
98 $image['DOWNLOAD']['width'] = 32;
99 $image['DOWNLOAD']['height'] = 32;
100 $image['plug']['path'] = 'pix/tango-network-wired.png';
101 $image['plug']['width'] = 16;
102 $image['plug']['height'] = 16;
103 $image['cut']['path'] = 'pix/tango-edit-cut-16x16.png';
104 $image['cut']['width'] = 16;
105 $image['cut']['height'] = 16;
106 $image['Cut']['path'] = 'pix/tango-edit-cut-22x22.png';
107 $image['Cut']['width'] = 22;
108 $image['Cut']['height'] = 22;
109 $image['CUT']['path'] = 'pix/tango-edit-cut-32x32.png';
110 $image['CUT']['width'] = 32;
111 $image['CUT']['height'] = 32;
112 $image['add']['path'] = 'pix/tango-list-add.png';
113 $image['add']['width'] = 16;
114 $image['add']['height'] = 16;
115 $image['ADD']['path'] = 'pix/tango-list-add-big.png';
116 $image['ADD']['width'] = 32;
117 $image['ADD']['height'] = 32;
118 $image['delete']['path'] = 'pix/tango-list-remove.png';
119 $image['delete']['width'] = 16;
120 $image['delete']['height'] = 16;
121 $image['DELETE']['path'] = 'pix/tango-list-remove-32x32.png';
122 $image['DELETE']['width'] = 32;
123 $image['DELETE']['height'] = 32;
124 $image['destroy']['path'] = 'pix/tango-user-trash-16x16.png';
125 $image['destroy']['width'] = 16;
126 $image['destroy']['height'] = 16;
127 $image['nodestroy']['path'] = 'pix/tango-user-trash-16x16-gray.png';
128 $image['nodestroy']['width'] = 16;
129 $image['nodestroy']['height'] = 16;
130 $image['NODESTROY']['path'] = 'pix/tango-user-trash-32x32-gray.png';
131 $image['NODESTROY']['width'] = 32;
132 $image['NODESTROY']['height'] = 32;
133 $image['DESTROY']['path'] = 'pix/tango-user-trash-32x32.png';
134 $image['DESTROY']['width'] = 32;
135 $image['DESTROY']['height'] = 32;
136 $image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
137 $image['nodelete']['width'] = 16;
138 $image['nodelete']['height'] = 16;
139 $image['inservice']['path'] = 'pix/tango-emblem-system.png';
140 $image['inservice']['width'] = 16;
141 $image['inservice']['height'] = 16;
142 $image['notinservice']['path'] = 'pix/tango-dialog-error.png';
143 $image['notinservice']['width'] = 16;
144 $image['notinservice']['height'] = 16;
145 $image['find']['path'] = 'pix/tango-system-search.png';
146 $image['find']['width'] = 16;
147 $image['find']['height'] = 16;
148 $image['next']['path'] = 'pix/tango-go-next.png';
149 $image['next']['width'] = 32;
150 $image['next']['height'] = 32;
151 $image['prev']['path'] = 'pix/tango-go-previous.png';
152 $image['prev']['width'] = 32;
153 $image['prev']['height'] = 32;
154 $image['COMMIT']['path'] = 'pix/tango-go-prev-next-32x32.png';
155 $image['COMMIT']['width'] = 32;
156 $image['COMMIT']['height'] = 32;
157 $image['COMMIT gray']['path'] = 'pix/tango-go-prev-next-gray-32x32.png';
158 $image['COMMIT gray']['width'] = 32;
159 $image['COMMIT gray']['height'] = 32;
160 $image['RECALC']['path'] = 'pix/tango-view-refresh-32x32.png';
161 $image['RECALC']['width'] = 32;
162 $image['RECALC']['height'] = 32;
163 $image['clear']['path'] = 'pix/tango-edit-clear.png';
164 $image['clear']['width'] = 16;
165 $image['clear']['height'] = 16;
166 $image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
167 $image['CLEAR']['width'] = 32;
168 $image['CLEAR']['height'] = 32;
169 $image['CLEAR gray']['path'] = 'pix/tango-edit-clear-gray-32x32.png';
170 $image['CLEAR gray']['width'] = 32;
171 $image['CLEAR gray']['height'] = 32;
172 $image['save']['path'] = 'pix/tango-document-save-16x16.png';
173 $image['save']['width'] = 16;
174 $image['save']['height'] = 16;
175 $image['SAVE']['path'] = 'pix/tango-document-save-32x32.png';
176 $image['SAVE']['width'] = 32;
177 $image['SAVE']['height'] = 32;
178 $image['NOSAVE']['path'] = 'pix/tango-document-save-32x32-gray.png';
179 $image['NOSAVE']['width'] = 32;
180 $image['NOSAVE']['height'] = 32;
181 $image['create']['path'] = 'pix/tango-document-new.png';
182 $image['create']['width'] = 16;
183 $image['create']['height'] = 16;
184 $image['CREATE']['path'] = 'pix/tango-document-new-big.png';
185 $image['CREATE']['width'] = 32;
186 $image['CREATE']['height'] = 32;
187 $image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
188 $image['DENIED']['width'] = 32;
189 $image['DENIED']['height'] = 32;
190 $image['node-collapsed']['path'] = 'pix/node-collapsed.png';
191 $image['node-collapsed']['width'] = 16;
192 $image['node-collapsed']['height'] = 16;
193 $image['node-expanded']['path'] = 'pix/node-expanded.png';
194 $image['node-expanded']['width'] = 16;
195 $image['node-expanded']['height'] = 16;
196 $image['node-expanded-static']['path'] = 'pix/node-expanded-static.png';
197 $image['node-expanded-static']['width'] = 16;
198 $image['node-expanded-static']['height'] = 16;
199 $image['dragons']['path'] = 'pix/mitsudragon.png';
200 $image['dragons']['width'] = 195;
201 $image['dragons']['height'] = 33;
202 $image['LB']['path'] = 'pix/loadbalancer.png';
203 $image['LB']['width'] = 32;
204 $image['LB']['height'] = 32;
205 $image['RS pool']['path'] = 'pix/serverpool.png';
206 $image['RS pool']['width'] = 48;
207 $image['RS pool']['height'] = 16;
208 $image['VS']['path'] = 'pix/servicesign.png';
209 $image['VS']['width'] = 39;
210 $image['VS']['height'] = 62;
211 $image['router']['path'] = 'pix/router.png';
212 $image['router']['width'] = 32;
213 $image['router']['height'] = 32;
214 $image['object']['path'] = 'pix/bracket-16x16.png';
215 $image['object']['width'] = 16;
216 $image['object']['height'] = 16;
217 $image['OBJECT']['path'] = 'pix/bracket-32x32.png';
218 $image['OBJECT']['width'] = 32;
219 $image['OBJECT']['height'] = 32;
220 $image['attach']['path'] = 'pix/tango-mail-attachment-16x16.png';
221 $image['attach']['width'] = 16;
222 $image['attach']['height'] = 16;
223 $image['Attach']['path'] = 'pix/tango-mail-attachment-22x22.png';
224 $image['Attach']['width'] = 22;
225 $image['Attach']['height'] = 22;
226 $image['ATTACH']['path'] = 'pix/tango-mail-attachment-32x32.png';
227 $image['ATTACH']['width'] = 32;
228 $image['ATTACH']['height'] = 32;
229 $image['favorite']['path'] = 'pix/tango-emblem-favorite.png';
230 $image['favorite']['width'] = 16;
231 $image['favorite']['height'] = 16;
232 $image['computer']['path'] = 'pix/tango-computer.png';
233 $image['computer']['width'] = 16;
234 $image['computer']['height'] = 16;
235 $image['empty file']['path'] = 'pix/crystal-file-empty-32x32.png';
236 $image['empty file']['width'] = 32;
237 $image['empty file']['height'] = 32;
238 $image['text file']['path'] = 'pix/crystal-file-text-32x32.png';
239 $image['text file']['width'] = 32;
240 $image['text file']['height'] = 32;
241 $image['image file']['path'] = 'pix/crystal-file-image-32x32.png';
242 $image['image file']['width'] = 32;
243 $image['image file']['height'] = 32;
244 $image['text']['path'] = 'pix/tango-text-x-generic-16x16.png';
245 $image['text']['width'] = 16;
246 $image['text']['height'] = 16;
247 $image['NET']['path'] = 'pix/crystal-network_local-32x32.png';
248 $image['NET']['width'] = 32;
249 $image['NET']['height'] = 32;
250 $image['net']['path'] = 'pix/crystal-network_local-16x16.png';
251 $image['net']['width'] = 16;
252 $image['net']['height'] = 16;
253 $image['USER']['path'] = 'pix/crystal-edit-user-32x32.png';
254 $image['USER']['width'] = 32;
255 $image['USER']['height'] = 32;
256 $image['setfilter']['path'] = 'pix/pgadmin3-viewfiltereddata.png';
257 $image['setfilter']['width'] = 32;
258 $image['setfilter']['height'] = 32;
259 $image['setfilter gray']['path'] = 'pix/pgadmin3-viewfiltereddata-grayscale.png';
260 $image['setfilter gray']['width'] = 32;
261 $image['setfilter gray']['height'] = 32;
262 $image['resetfilter']['path'] = 'pix/pgadmin3-viewdata.png';
263 $image['resetfilter']['width'] = 32;
264 $image['resetfilter']['height'] = 32;
265 $image['resetfilter gray']['path'] = 'pix/pgadmin3-viewdata-grayscale.png';
266 $image['resetfilter gray']['width'] = 32;
267 $image['resetfilter gray']['height'] = 32;
268 $image['knight']['path'] = 'pix/smiley_knight.png';
269 $image['knight']['width'] = 72;
270 $image['knight']['height'] = 33;
271 $image['Zoom']['path'] = 'pix/tango-system-search-22x22.png';
272 $image['Zoom']['width'] = 22;
273 $image['Zoom']['height'] = 22;
274 $image['Zooming']['path'] = 'pix/tango-view-fullscreen-22x22.png';
275 $image['Zooming']['width'] = 22;
276 $image['Zooming']['height'] = 22;
277 $image['UNLOCK']['path'] = 'pix/crystal-actions-unlock-32x32.png';
278 $image['UNLOCK']['width'] = 32;
279 $image['UNLOCK']['height'] = 32;
280 $image['CLOCK']['path'] = 'pix/tango-appointment-32x32.png';
281 $image['CLOCK']['width'] = 32;
282 $image['CLOCK']['height'] = 32;
283 $image['DQUEUE done']['path'] = 'pix/crystal-ok-32x32.png';
284 $image['DQUEUE done']['width'] = 32;
285 $image['DQUEUE done']['height'] = 32;
286 $image['DQUEUE sync_aging']['path'] = 'pix/tango-appointment-32x32.png';
287 $image['DQUEUE sync_aging']['width'] = 32;
288 $image['DQUEUE sync_aging']['height'] = 32;
289 $image['DQUEUE resync_aging']['path'] = 'pix/tango-appointment-32x32.png';
290 $image['DQUEUE resync_aging']['width'] = 32;
291 $image['DQUEUE resync_aging']['height'] = 32;
292 $image['DQUEUE sync_ready']['path'] = 'pix/tango-emblem-system-32x32.png';
293 $image['DQUEUE sync_ready']['width'] = 32;
294 $image['DQUEUE sync_ready']['height'] = 32;
295 $image['DQUEUE resync_ready']['path'] = 'pix/tango-emblem-important-32x32.png';
296 $image['DQUEUE resync_ready']['width'] = 32;
297 $image['DQUEUE resync_ready']['height'] = 32;
298 $image['DQUEUE failed']['path'] = 'pix/tango-emblem-unreadable-32x32.png';
299 $image['DQUEUE failed']['width'] = 32;
300 $image['DQUEUE failed']['height'] = 32;
301 $image['DQUEUE disabled']['path'] = 'pix/tango-emblem-readonly-32x32.png';
302 $image['DQUEUE disabled']['width'] = 32;
303 $image['DQUEUE disabled']['height'] = 32;
304 $image['COPY']['path'] = 'pix/tango-edit-copy-32x32.png';
305 $image['COPY']['width'] = 32;
306 $image['COPY']['height'] = 32;
307 $image['html']['path'] = 'pix/tango-text-html.png';
308 $image['html']['width'] = 16;
309 $image['html']['height'] = 16;
310
311 // This may be populated later onsite, report rendering function will use it.
312 // See the $systemreport for structure.
313 $localreports = array();
314
315 $CodePressMap = array
316 (
317 'sql' => 'sql',
318 'php' => 'php',
319 'html' => 'html',
320 'css' => 'css',
321 'js' => 'javascript',
322 );
323
324 $attrtypes = array
325 (
326 'uint' => '[U] unsigned integer',
327 'float' => '[F] floating point',
328 'string' => '[S] string',
329 'dict' => '[D] dictionary record'
330 );
331
332 // Main menu.
333 function renderIndexItem ($ypageno) {
334 global $page;
335 if (permitted($ypageno)) {
336 $title = isset ($page[$ypageno]['title']) ? $page[$ypageno]['title'] : dynamic_title_decoder ($ypageno);
337 if (is_array ($title))
338 $title = $title['name'];
339 print " <td>\n";
340 print " <h1><a href='".makeHref(array('page'=>$ypageno))."'>".$title."<br>\n";
341 printImageHREF ($ypageno);
342 print "</a></h1>\n";
343 print " </td>\n";
344 } else {
345 print " <td>&nbsp;</td>\n";
346 }
347 }
348
349 function renderIndex ()
350 {
351 global $indexlayout;
352 ?>
353 <table border=0 cellpadding=0 cellspacing=0 width='100%'>
354 <tr>
355 <td>
356 <div style='text-align: center; margin: 10px; '>
357 <table width='100%' cellspacing=0 cellpadding=20 class=mainmenu border=0>
358 <?php
359 foreach ($indexlayout as $row)
360 {
361 echo '<tr>';
362 foreach ($row as $column)
363 if ($column === NULL)
364 echo '<td>&nbsp;</td>';
365 else
366 renderIndexItem ($column);
367 echo '</tr>';
368 }
369 ?>
370 </table>
371 </div>
372 </td>
373 </tr>
374 </table>
375 <?php
376 }
377
378 function renderRackspace ()
379 {
380 $found_racks = array();
381 $rows = array();
382 $cellfilter = getCellFilter();
383 $rackCount = 0;
384 foreach (getRackRows() as $row_id => $row_name) {
385 $rackList = filterCellList (listCells ('rack', $row_id), $cellfilter['expression']);
386 $found_racks = array_merge($found_racks, $rackList);
387 $rows[] = array(
388 'row_id' => $row_id,
389 'row_name' => $row_name,
390 'racks' => $rackList
391 );
392 $rackCount += count($rackList);
393 }
394
395 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
396 renderCellFilterPortlet ($cellfilter, 'rack', $found_racks);
397 echo '</td><td class=pcright>';
398
399 if (! renderEmptyResults($cellfilter, 'racks', $rackCount))
400 {
401 echo '<table border=0 cellpadding=10 cellpadding=1>';
402 // generate thumb gallery
403 global $nextorder;
404 $rackwidth = getRackImageWidth();
405 // Zero value effectively disables the limit.
406 $maxPerRow = getConfigVar ('RACKS_PER_ROW');
407 $order = 'odd';
408 foreach ($rows as $row)
409 {
410 $row_id = $row['row_id'];
411 $row_name = $row['row_name'];
412 $rackList = $row['racks'];
413
414 if (!count ($rackList) and count ($cellfilter['expression']))
415 continue;
416 $rackListIdx = 0;
417 echo "<tr class=row_${order}><th class=tdleft>";
418 echo "<a href='".makeHref(array('page'=>'row', 'row_id'=>$row_id))."${cellfilter['urlextra']}'>";
419 echo "${row_name}</a></th><td><table border=0 cellspacing=5><tr>";
420 if (!count ($rackList))
421 echo "<td>(empty row)</td>";
422 else
423 foreach ($rackList as $rack)
424 {
425 if ($rackListIdx > 0 and $maxPerRow > 0 and $rackListIdx % $maxPerRow == 0)
426 {
427 echo '</tr></table></tr>';
428 echo "<tr class=row_${order}><th class=tdleft>${row_name} (continued)";
429 echo "</th><td><table border=0 cellspacing=5><tr>";
430 }
431 echo "<td align=center><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
432 echo "<img border=0 width=${rackwidth} height=";
433 echo getRackImageHeight ($rack['height']);
434 echo " title='${rack['height']} units'";
435 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
436 echo "<br>${rack['name']}</a></td>";
437 $rackListIdx++;
438 }
439 $order = $nextorder[$order];
440 echo "</tr></table></tr>\n";
441 }
442 echo "</table>\n";
443 }
444 echo "</td></tr></table>\n";
445 }
446
447 function renderRackspaceRowEditor ()
448 {
449 function printNewItemTR ()
450 {
451 printOpFormIntro ('addRow');
452 echo "<tr><td>";
453 printImageHREF ('create', 'Add new row', TRUE);
454 echo "</td><td><input type=text name=name tabindex=100></td><td>";
455 printImageHREF ('create', 'Add new row', TRUE, 101);
456 echo "</td></tr></form>";
457 }
458 startPortlet ('Rows');
459 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
460 echo "<tr><th>&nbsp;</th><th>Name</th><th>&nbsp;</th></tr>\n";
461 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
462 printNewItemTR();
463 foreach (getRackRows() as $row_id => $row_name)
464 {
465 echo "<tr><td>";
466 if ($rc = count (listCells ('rack', $row_id)))
467 printImageHREF ('nodestroy', "${rc} rack(s) here");
468 else
469 {
470 echo "<a href=\"".makeHrefProcess(array('op'=>'delete', 'row_id'=>$row_id))."\">";
471 printImageHREF ('destroy', 'Delete row');
472 echo "</a>";
473 }
474 printOpFormIntro ('updateRow', array ('row_id' => $row_id));
475 echo "</td><td><input type=text name=name value='${row_name}'></td><td>";
476 printImageHREF ('save', 'Save changes', TRUE);
477 echo "</form></td></tr>\n";
478 }
479 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
480 printNewItemTR();
481 echo "</table><br>\n";
482 finishPortlet();
483 }
484
485 function renderRow ($row_id)
486 {
487 $rowInfo = getRackRowInfo ($row_id);
488 $cellfilter = getCellFilter();
489 $rackList = filterCellList (listCells ('rack', $row_id), $cellfilter['expression']);
490 // Main layout starts.
491 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
492
493 // Left portlet with row information.
494 echo "<tr><td class=pcleft>";
495 startPortlet ($rowInfo['name']);
496 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
497 echo "<tr><th width='50%' class=tdright>Racks:</th><td class=tdleft>${rowInfo['count']}</td></tr>\n";
498 echo "<tr><th width='50%' class=tdright>Units:</th><td class=tdleft>${rowInfo['sum']}</td></tr>\n";
499 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
500 renderProgressBar (getRSUforRackRow ($rackList));
501 echo "</td></tr>\n";
502 echo "</table><br>\n";
503 finishPortlet();
504 renderCellFilterPortlet ($cellfilter, 'rack', $rackList, 'row_id', $row_id);
505
506 echo "</td><td class=pcright>";
507
508 global $nextorder;
509 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
510 // Maximum number of racks per row is proportionally less, but at least 1.
511 $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1);
512 $rackListIdx = 0;
513 $order = 'odd';
514 startPortlet ('Racks');
515 echo "<table border=0 cellspacing=5 align='center'><tr>";
516 foreach ($rackList as $rack)
517 {
518 if ($rackListIdx % $maxPerRow == 0)
519 {
520 if ($rackListIdx > 0)
521 echo '</tr>';
522 echo '<tr>';
523 }
524 echo "<td align=center class=row_${order}><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
525 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
526 echo " title='${rack['height']} units'";
527 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
528 echo "<br>${rack['name']}</a></td>";
529 $order = $nextorder[$order];
530 $rackListIdx++;
531 }
532 echo "</tr></table>\n";
533 finishPortlet();
534 echo "</td></tr></table>";
535 }
536
537 // This function renders rack as HTML table.
538 function renderRack ($rack_id, $hl_obj_id = 0)
539 {
540 $rackData = spotEntity ('rack', $rack_id);
541 amplifyCell ($rackData);
542 markAllSpans ($rackData);
543 if ($hl_obj_id > 0)
544 highlightObject ($rackData, $hl_obj_id);
545 markupObjectProblems ($rackData);
546 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
547 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
548 echo "<center><table border=0><tr valign=middle>";
549 echo "<td><h2><a href='".makeHref(array('page'=>'row', 'row_id'=>$rackData['row_id']))."'>${rackData['row_name']}</a> :</h2></td>";
550 // FIXME: use 'bypass'?
551 if ($prev_id != NULL)
552 {
553 echo "<td><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$prev_id))."'>";
554 printImageHREF ('prev', 'previous rack');
555 echo "</a></td>";
556 }
557 echo "<td><h2><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rackData['id']))."'>${rackData['name']}</a></h2></td>";
558 if ($next_id != NULL)
559 {
560 echo "<td><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$next_id))."'>";
561 printImageHREF ('next', 'next rack');
562 echo "</a></td>";
563 }
564 echo "</h2></td></tr></table>\n";
565 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
566 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
567 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
568 addAtomCSS();
569 for ($i = $rackData['height']; $i > 0; $i--)
570 {
571 echo "<tr><th>${i}</th>";
572 for ($locidx = 0; $locidx < 3; $locidx++)
573 {
574 if (isset ($rackData[$i][$locidx]['skipped']))
575 continue;
576 $state = $rackData[$i][$locidx]['state'];
577 echo "<td class='atom state_${state}";
578 if (isset ($rackData[$i][$locidx]['hl']))
579 echo $rackData[$i][$locidx]['hl'];
580 echo "'";
581 if (isset ($rackData[$i][$locidx]['colspan']))
582 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
583 if (isset ($rackData[$i][$locidx]['rowspan']))
584 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
585 echo ">";
586 switch ($state)
587 {
588 case 'T':
589 $objectData = spotEntity ('object', $rackData[$i][$locidx]['object_id']);
590 if (strlen ($objectData['asset_no']))
591 $prefix = "<div title='${objectData['asset_no']}";
592 else
593 $prefix = "<div title='no asset tag";
594 // Don't tell about label, if it matches common name.
595 $body = '';
596 if ($objectData['name'] != $objectData['label'] and strlen ($objectData['label']))
597 $body = ", visible label is \"${objectData['label']}\"";
598 // Display list of child objects, if any
599 $objectChildren = getEntityRelatives ('children', 'object', $objectData['id']);
600 if (count($objectChildren) > 0)
601 {
602 foreach ($objectChildren as $child)
603 $childNames[] = $child['name'];
604 natsort($childNames);
605 $suffix = sprintf(", contains %s'>", implode(', ', $childNames));
606 }
607 else
608 $suffix = "'>";
609 echo $prefix . $body . $suffix;
610 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$objectData['id']))."'>${objectData['dname']}</a></div>";
611 break;
612 case 'A':
613 echo '<div title="This rackspace does not exist">&nbsp;</div>';
614 break;
615 case 'F':
616 echo '<div title="Free rackspace">&nbsp;</div>';
617 break;
618 case 'U':
619 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
620 break;
621 default:
622 echo '<div title="No data">&nbsp;</div>';
623 break;
624 }
625 echo '</td>';
626 }
627 echo "</tr>\n";
628 }
629 echo "</table></center>\n";
630 }
631
632 function renderNewRackForm ($row_id)
633 {
634 startPortlet ('Add one');
635 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
636 echo '<table border=0 align=center>';
637 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
638 if ($defh == 0)
639 $defh = '';
640 echo "<tr><th class=tdright>Rack name (*):</th><td class=tdleft><input type=text name=rack_name tabindex=1></td>";
641 echo "<td rowspan=4>Assign tags:<br>";
642 renderNewEntityTags ('rack');
643 echo "</td></tr>\n";
644 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";
645 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment tabindex=3></td></tr>\n";
646 echo "<tr><td class=submit colspan=2>";
647 printImageHREF ('CREATE', 'Add', TRUE);
648 echo "</td></tr></table></form>";
649 finishPortlet();
650
651 startPortlet ('Add many');
652 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
653 echo '<table border=0 align=center>';
654 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
655 if ($defh == 0)
656 $defh = '';
657 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height2 value='${defh}'></td>";
658 echo "<td rowspan=3 valign=top>Assign tags:<br>";
659 renderNewEntityTags ('rack');
660 echo "</td></tr>\n";
661 echo "<tr><th class=tdright>Rack names (*):</th><td class=tdleft><textarea name=rack_names cols=40 rows=25></textarea></td></tr>\n";
662 echo "<tr><td class=submit colspan=2>";
663 printImageHREF ('CREATE', 'Add', TRUE);
664 echo '</form></table>';
665 finishPortlet();
666 }
667
668 function renderEditObjectForm ($object_id)
669 {
670 global $pageno;
671 $object = spotEntity ('object', $object_id);
672 startPortlet ();
673 printOpFormIntro ('update');
674
675 // static attributes
676 echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
677 echo "<tr><td>&nbsp;</td><th colspan=2><h2>Attributes</h2></th></tr>";
678 // baseline info
679 echo "<tr><td>&nbsp;</td><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
680 if (considerConfiguredConstraint ($object, 'VIRTUAL_OBJ_LISTSRC'))
681 {
682 echo "<input type=hidden name=object_label value=''>\n";
683 echo "<input type=hidden name=object_asset_no value=''>\n";
684 echo "<input type=hidden name=object_barcode value=''>\n";
685 }
686 else
687 {
688 echo "<tr><td>&nbsp;</td><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
689 echo "<tr><td>&nbsp;</td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
690 echo "<tr><td>&nbsp;</td><th class=tdright>Barcode:</th><td class=tdleft><input type=text name=object_barcode value='${object['barcode']}'></td></tr>\n";
691 }
692 // parent selection
693 if (rackObjectTypeMayHaveParent ($object['objtype_id']))
694 {
695 $parents = getEntityRelatives ('parents', 'object', $object_id);
696 foreach ($parents as $link_id => $parent_details)
697 {
698 if (!isset($label))
699 $label = count($parents) > 1 ? 'Containers:' : 'Container:';
700 echo "<tr><td>&nbsp;</td>";
701 echo "<th class=tdright>${label}</th><td class=tdleft>";
702 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$parent_details['entity_id']))."'>${parent_details['name']}</a>";
703 echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
704 echo "<a href='".
705 makeHrefProcess(array(
706 'op'=>'unlinkEntities',
707 'link_id'=>$link_id,
708 'object_id'=>$object_id,
709 'page='=>'object',
710 'tab'=>'edit')).
711 "'>";
712 printImageHREF ('cut', 'Unlink container');
713 echo "</a>";
714 echo "</td></tr>\n";
715 $label = '&nbsp;';
716 }
717 echo "<tr><td>&nbsp;</td>";
718 echo "<th class=tdright>Select container:</th><td class=tdleft>";
719 echo "<span";
720 $helper_args = array ('object_id' => $object_id);
721 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
722 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
723 echo " onclick='window.open(\"" . makeHrefForHelper ('objlist', $helper_args);
724 echo "\",\"findlink\",\"${popup_args}\");'>";
725 printImageHREF ('attach', 'Select a container');
726 echo "</span></td></tr>\n";
727 }
728 // optional attributes
729 $values = getAttrValues ($object_id);
730 echo '<input type=hidden name=num_attrs value=' . count($values) . ">\n";
731 if (count($values) > 0)
732 {
733 $i = 0;
734 foreach ($values as $record)
735 {
736 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
737 echo '<tr><td>';
738 if (strlen ($record['value']))
739 {
740 echo "<a href='".makeHrefProcess(array('op'=>'clearSticker', 'object_id'=>$object_id, 'attr_id'=>$record['id']))."'>";
741 printImageHREF ('clear', 'Clear value');
742 echo '</a>';
743 }
744 else
745 echo '&nbsp;';
746 echo '</td>';
747 echo "<th class=sticker>${record['name']}:</th><td class=tdleft>";
748 switch ($record['type'])
749 {
750 case 'uint':
751 case 'float':
752 case 'string':
753 echo "<input type=text name=${i}_value value='${record['value']}'>";
754 break;
755 case 'dict':
756 $chapter = readChapter ($record['chapter_id'], 'o');
757 $chapter[0] = '-- NOT SET --';
758 $chapter = cookOptgroups ($chapter, $object['objtype_id'], $record['key']);
759 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
760 break;
761 }
762 echo "</td></tr>\n";
763 $i++;
764 }
765 }
766 echo "<tr><td>&nbsp;</td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
767 if ($object['has_problems'] == 'yes')
768 echo ' checked';
769 echo "></td></tr>\n";
770 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
771 echo "<a href='".
772 makeHrefProcess(array('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id)).
773 "' onclick=\"javascript:return confirm('Are you sure you want to delete the object?')\">" . getImageHREF ('destroy', 'Delete object') . "</a>";
774 echo "&nbsp;";
775 echo "<a href='".
776 makeHrefProcess(array ('op'=>'resetObject', 'page' => 'object', 'tab' => 'edit', 'object_id' => $object_id)).
777 "' onclick=\"javascript:return confirm('Are you sure you want to reset most of object properties?')\">" . getImageHREF ('clear', 'Reset (cleanup) object') . "</a>";
778 echo "</td></tr>\n";
779 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
780
781 echo "<tr><th class=submit colspan=3>";
782 printImageHREF ('SAVE', 'Save changes', TRUE);
783 echo "</form></th></tr></table>\n";
784 finishPortlet();
785
786 echo '<table border=0 width=100%><tr><td>';
787 startPortlet ('history');
788 renderHistory ($pageno, $object_id);
789 finishPortlet();
790 echo '</td></tr></table>';
791 }
792
793 // This is a clone of renderEditObjectForm().
794 function renderEditRackForm ($rack_id)
795 {
796 global $pageno;
797 $rack = spotEntity ('rack', $rack_id);
798 amplifyCell ($rack);
799
800 startPortlet ('Rack attributes');
801 printOpFormIntro ('updateRack');
802 echo '<table border=0 align=center>';
803 echo "<tr><th class=tdright>Rack row:</th><td class=tdleft>";
804 printSelect (getRackRows(), array ('name' => 'rack_row_id'), $rack['row_id']);
805 echo "</td></tr>\n";
806 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=rack_name value='${rack['name']}'></td></tr>\n";
807 echo "<tr><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=rack_height value='${rack['height']}'></td></tr>\n";
808 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment value='${rack['comment']}'></td></tr>\n";
809 if (count ($rack['mountedObjects']) == 0)
810 {
811 echo "<tr><th class=tdright>Actions:</th><td class=tdleft><a href='".
812 makeHrefProcess(array('op'=>'deleteRack', 'rack_id'=>$rack_id)).
813 "' onclick=\"javascript:return confirm('Are you sure you want to delete the rack?')\">Delete rack</a></td></tr>\n";
814 }
815 echo "<tr><td class=submit colspan=2>";
816 printImageHREF ('SAVE', 'Save changes', TRUE);
817 echo "</td></tr>\n";
818 echo '</form></table><br>';
819 finishPortlet();
820
821 startPortlet ('History');
822 renderHistory ($pageno, $rack_id);
823 finishPortlet();
824 }
825
826 function printSelect ($optionList, $select_attrs = array(), $selected_id = NULL)
827 {
828 echo getSelect ($optionList, $select_attrs, $selected_id);
829 }
830
831 // Input array keys are OPTION VALUEs and input array values are OPTION text.
832 function getSelect ($optionList, $select_attrs = array(), $selected_id = NULL)
833 {
834 $ret = '';
835 if (!array_key_exists ('name', $select_attrs))
836 return '';
837 // handle two corner cases in a specific way
838 if (count ($optionList) == 0)
839 return '(none)';
840 if (count ($optionList) == 1)
841 {
842 $value = current (array_keys ($optionList));
843 return "<input type=hidden name=${select_attrs['name']} id=${select_attrs['name']} value=${value}>" . current ($optionList);
844 }
845 if (!array_key_exists ('id', $select_attrs))
846 $select_attrs['id'] = $select_attrs['name'];
847 $ret .= '<select';
848 foreach ($select_attrs as $attr_name => $attr_value)
849 $ret .= " ${attr_name}=${attr_value}";
850 $ret .= '>';
851 foreach ($optionList as $dict_key => $dict_value)
852 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>";
853 $ret .= '</select>';
854 return $ret;
855 }
856
857 function printNiftySelect ($groupList, $select_attrs = array(), $selected_id = NULL, $autocomplete = false)
858 {
859 echo getNiftySelect ($groupList, $select_attrs, $selected_id);
860 }
861
862 // Input is a cooked list of OPTGROUPs, each with own sub-list of OPTIONs in the same
863 // format as printSelect() expects.
864 function getNiftySelect ($groupList, $select_attrs, $selected_id = NULL)
865 {
866 // special treatment for ungrouped data
867 if (count ($groupList) == 1 and isset ($groupList['other']))
868 return getSelect ($groupList['other'], $select_attrs, $selected_id);
869 if (!array_key_exists ('name', $select_attrs))
870 return '';
871 if (!array_key_exists ('id', $select_attrs))
872 $select_attrs['id'] = $select_attrs['name'];
873 $ret = '<select';
874 foreach ($select_attrs as $attr_name => $attr_value)
875 $ret .= " ${attr_name}=${attr_value}";
876 $ret .= '>';
877 foreach ($groupList as $groupname => $groupdata)
878 {
879 $ret .= "<optgroup label='${groupname}'>";
880 foreach ($groupdata as $dict_key => $dict_value)
881 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>";
882 $ret .= '</optgroup>';
883 }
884 $ret .= '</select>';
885 return $ret;
886 }
887
888 // used by renderGridForm() and renderRackPage()
889 function renderRackInfoPortlet ($rackData)
890 {
891 startPortlet ('summary');
892 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
893 echo "<tr><th width='50%' class=tdright>Rack row:</th><td class=tdleft>${rackData['row_name']}</td></tr>\n";
894 echo "<tr><th width='50%' class=tdright>Name:</th><td class=tdleft>${rackData['name']}</td></tr>\n";
895 echo "<tr><th width='50%' class=tdright>Height:</th><td class=tdleft>${rackData['height']}</td></tr>\n";
896 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
897 renderProgressBar (getRSUforRack ($rackData));
898 echo "</td></tr>\n";
899 echo "<tr><th width='50%' class=tdright>Objects:</th><td class=tdleft>";
900 echo count ($rackData['mountedObjects']);
901 echo "</td></tr>\n";
902 printTagTRs ($rackData, makeHref(array('page'=>'rackspace', 'tab'=>'default'))."&");
903 if (strlen ($rackData['comment']))
904 echo "<tr><th width='50%' class=tdright>Comment:</th><td class=tdleft>${rackData['comment']}</td></tr>\n";
905 echo '</table>';
906 finishPortlet();
907 }
908
909 // This is a universal editor of rack design/waste.
910 // FIXME: switch to using printOpFormIntro()
911 function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2)
912 {
913 $rackData = spotEntity ('rack', $rack_id);
914 amplifyCell ($rackData);
915 $filter ($rackData);
916 markupObjectProblems ($rackData);
917
918 // Render the result whatever it is.
919 // Main layout.
920 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
921 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
922
923 // Left column with information portlet.
924 echo "<tr><td class=pcleft height='1%' width='50%'>";
925 renderRackInfoPortlet ($rackData);
926 echo "</td>\n";
927 echo "<td class=pcright>";
928
929 // Grid form.
930 startPortlet ($header);
931 addJS ('js/racktables.js');
932 echo "<center>\n";
933 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
934 echo "<tr><th width='10%'>&nbsp;</th>";
935 echo "<th width='20%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
936 echo "<th width='50%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
937 echo "<th width='20%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
938 printOpFormIntro ('updateRack');
939 markupAtomGrid ($rackData, $state2);
940 renderAtomGrid ($rackData);
941 echo "</table></center>\n";
942 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
943 finishPortlet();
944 echo "</td></tr></table>\n";
945 }
946
947 function renderRackDesign ($rack_id)
948 {
949 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
950 }
951
952 function renderRackProblems ($rack_id)
953 {
954 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
955 }
956
957 function startPortlet ($title = '')
958 {
959 echo "<div class=portlet><h2>${title}</h2>";
960 }
961
962 function finishPortlet ()
963 {
964 echo "</div>\n";
965 }
966
967 function renderRackObject ($object_id)
968 {
969 global $nextorder, $aac;
970 $info = spotEntity ('object', $object_id);
971 // FIXME: employ amplifyCell() instead of calling loader functions directly
972 amplifyCell ($info);
973 // Main layout starts.
974 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
975 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
976 // left column with uknown number of portlets
977 echo "<tr><td class=pcleft>";
978 startPortlet ('summary');
979 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
980 if (strlen ($info['name']))
981 echo "<tr><th width='50%' class=tdright>Common name:</th><td class=tdleft>${info['name']}</td></tr>\n";
982 // FIXME: don't call spotEntity() each time, do it once in the beginning.
983 elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
984 echo "<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>\n";
985 echo "<tr><th width='50%' class=tdright>Object type:</th><td class=tdleft><a href='";
986 echo makeHref (array (
987 'page' => 'depot',
988 'tab' => 'default',
989 'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
990 ));
991 echo "'>" . decodeObjectType ($info['objtype_id'], 'o') . '</a></td></tr>';
992 if (strlen ($info['asset_no']))
993 echo "<tr><th width='50%' class=tdright>Asset tag:</th><td class=tdleft>${info['asset_no']}</td></tr>\n";
994 // FIXME: ditto
995 elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
996 echo "<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>\n";
997 if (strlen ($info['label']))
998 echo "<tr><th width='50%' class=tdright>Visible label:</th><td class=tdleft>${info['label']}</td></tr>\n";
999 if (strlen ($info['barcode']))
1000 echo "<tr><th width='50%' class=tdright>Barcode:</th><td class=tdleft>${info['barcode']}</td></tr>\n";
1001 if ($parents = getEntityRelatives ('parents', 'object', $object_id))
1002 {
1003 foreach ($parents as $parent)
1004 {
1005 if (!isset($label))
1006 $label = count($parents) > 1 ? 'Containers:' : 'Container:';
1007 echo "<tr><th width='50%' class=tdright>${label}</th><td class=tdleft>";
1008 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$parent['entity_id']))."'>${parent['name']}</a>";
1009 echo "</td></tr>\n";
1010 $label = '&nbsp;';
1011 }
1012 unset ($label);
1013 }
1014 if ($children = getEntityRelatives ('children', 'object', $object_id))
1015 {
1016 foreach ($children as $child)
1017 {
1018 if (!isset($label))
1019 $label = 'Contains:';
1020 echo "<tr><th width='50%' class=tdright>${label}</th><td class=tdleft>";
1021 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$child['entity_id']))."'>${child['name']}</a>";
1022 echo "</td></tr>\n";
1023 $label = '&nbsp;';
1024 }
1025 }
1026 if ($info['has_problems'] == 'yes')
1027 echo "<tr><td colspan=2 class=msg_error>Has problems</td></tr>\n";
1028 foreach (getAttrValues ($object_id) as $record)
1029 if (strlen ($record['value']))
1030 {
1031 echo "<tr><th width='50%' class=sticker>${record['name']}:</th><td class=sticker>" .
1032 formatAttributeValue ($record) .
1033 "</td></tr>\n";
1034 }
1035 printTagTRs
1036 (
1037 $info,
1038 makeHref
1039 (
1040 array
1041 (
1042 'page'=>'depot',
1043 'tab'=>'default',
1044 'andor' => 'and',
1045 'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
1046 )
1047 )."&"
1048 );
1049 echo "</table><br>\n";
1050 finishPortlet();
1051
1052 if (strlen ($info['comment']))
1053 {
1054 startPortlet ('Comment');
1055 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
1056 finishPortlet ();
1057 }
1058
1059 if (count ($logrecords = getLogRecordsForObject ($_REQUEST['object_id'])))
1060 {
1061 startPortlet ('log records');
1062 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>";
1063 $order = 'odd';
1064 foreach (getLogRecordsForObject ($_REQUEST['object_id']) as $row)
1065 {
1066 echo "<tr class=row_${order} valign=top>";
1067 echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>';
1068 echo '<td class="slbconf rsvtext">' . string_insert_hrefs ($row['content']) . '</td>';
1069 echo '</tr>';
1070 $order = $nextorder[$order];
1071 }
1072 echo '</table>';
1073 finishPortlet();
1074 }
1075
1076 switchportInfoJS ($object_id); // load JS code to make portnames interactive
1077 renderFilesPortlet ('object', $object_id);
1078
1079 if (count ($info['ports']))
1080 {
1081 startPortlet ('ports and links');
1082 $hl_port_id = 0;
1083 if (isset ($_REQUEST['hl_port_id']))
1084 {
1085 assertUIntArg ('hl_port_id');
1086 $hl_port_id = $_REQUEST['hl_port_id'];
1087 addAutoScrollScript ("port-$hl_port_id");
1088 }
1089 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>";
1090 echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>';
1091 echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>';
1092 echo '<th class=tdcenter colspan=2>Remote object and port</th>';
1093 echo '<th class=tdleft>Cable ID</th></tr>';
1094 foreach ($info['ports'] as $port)
1095 {
1096 echo '<tr';
1097 if ($hl_port_id == $port['id'])
1098 echo ' class=port_highlight';
1099 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
1100 echo "><td class='tdleft' NOWRAP><a name='port-${port['id']}' class='interactive-portname nolink $a_class'>${port['name']}</a></td>";
1101 echo "<td class=tdleft>${port['label']}</td>";
1102 echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class=tdleft><tt>${port['l2address']}</tt></td>";
1103 if ($port['remote_object_id'])
1104 {
1105 $remote_object = spotEntity ('object', $port['remote_object_id']);
1106 echo "<td class=tdleft><a href='".makeHref(array('page'=>'object', 'object_id'=>$port['remote_object_id'], 'hl_port_id'=>$port['remote_id']))."'>${remote_object['dname']}</a></td>";
1107 echo "<td class=tdleft>${port['remote_name']}</td>";
1108 echo "<td class='tdleft rsvtext'>${port['cableid']}</td>";
1109 }
1110 elseif (strlen ($port['reservation_comment']))
1111 {
1112 echo "<td class=tdleft><b>Reserved:</b></td>";
1113 echo "<td class='tdleft rsvtext'>${port['reservation_comment']}</td><td>&nbsp;</td>";
1114 }
1115 else
1116 echo '<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>';
1117 echo "</tr>";
1118 }
1119 echo "</table><br>";
1120 finishPortlet();
1121 }
1122
1123 if (count ($info['ipv4']) + count ($info['ipv6']))
1124 {
1125 startPortlet ('IP addresses');
1126 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1127 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1128 echo "<tr><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n";
1129 else
1130 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
1131 $hl_ip_addr = '';
1132 if (isset ($_REQUEST['hl_ipv6_addr']))
1133 {
1134 if ($hl_ipv6 = assertIPv6Arg ('hl_ipv6_addr'))
1135 $hl_ip_addr = $hl_ipv6->format();
1136 }
1137 elseif (isset ($_REQUEST['hl_ipv4_addr']))
1138 $hl_ip_addr = $_REQUEST['hl_ipv4_addr'];
1139 if ($hl_ip_addr)
1140 addAutoScrollScript ("ip-$hl_ip_addr");
1141
1142 // group IP allocations by interface name instead of address family
1143 $allocs_by_iface = array();
1144 foreach (array ('ipv4', 'ipv6') as $ip_v)
1145 foreach ($info[$ip_v] as $dottedquad => $alloc)
1146 $allocs_by_iface[$alloc['osif']][$dottedquad] = $alloc;
1147
1148 // sort allocs array by portnames
1149 foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist)
1150 {
1151 $is_first_row = TRUE;
1152 foreach ($alloclist as $dottedquad => $alloc)
1153 {
1154 if ($alloc['addrinfo']['version'] == 6)
1155 {
1156 $addr_page_name = 'ipv6address';
1157 $ipv6_address = new IPv6Address ($dottedquad);
1158 $dottedquad = $ipv6_address->format();
1159 if ($netid = getIPv6AddressNetworkId ($ipv6_address))
1160 {
1161 $netinfo = spotEntity ('ipv6net', $netid);
1162 loadIPv6AddrList ($netinfo);
1163 }
1164 }
1165 else
1166 {
1167 $addr_page_name = 'ipaddress';
1168 if ($netid = getIPv4AddressNetworkId ($dottedquad))
1169 {
1170 $netinfo = spotEntity ('ipv4net', $netid);
1171 loadIPv4AddrList ($netinfo);
1172 }
1173 }
1174 $address_name = niftyString ($alloc['addrinfo']['name']);
1175 $class = $alloc['addrinfo']['class'];
1176 $secondclass = ($hl_ip_addr == $dottedquad) ? 'tdleft port_highlight' : 'tdleft';
1177 echo "<tr class='${class}' valign=top>";
1178
1179 // display iface name (common cell for both address families)
1180 if ($is_first_row)
1181 {
1182 $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : '';
1183 echo "<td class=tdleft $rowspan>$iface_name</td>";
1184 $is_first_row = FALSE;
1185 }
1186 echo "<td class='${secondclass}'>";
1187 if (NULL !== $netid)
1188 echo "<a name='ip-$dottedquad' href='index.php?page=$addr_page_name&hl_object_id=$object_id&ip=$dottedquad'>${dottedquad}</a>";
1189 else
1190 echo $dottedquad;
1191 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
1192 echo '<small>/' . (NULL === $netid ? '??' : $netinfo['mask']) . '</small>';
1193 echo '&nbsp;' . $aac[$alloc['type']];
1194 if (strlen ($alloc['addrinfo']['name']))
1195 echo ' (' . niftyString ($alloc['addrinfo']['name']) . ')';
1196 echo '</td>';
1197 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1198 {
1199 if (NULL === $netid)
1200 echo '<td class=sparenetwork>N/A</td><td class=sparenetwork>N/A</td>';
1201 else
1202 {
1203 echo "<td class='${secondclass}'>";
1204 renderCell ($netinfo);
1205 echo "</td>";
1206 // filter out self-allocation
1207 $other_routers = array();
1208 foreach (findRouters ($netinfo['addrlist']) as $router)
1209 if ($router['id'] != $object_id)
1210 $other_routers[] = $router;
1211 if (count ($other_routers))
1212 printRoutersTD ($other_routers);
1213 else
1214 echo "<td class='${secondclass}'>&nbsp;</td>";
1215 }
1216 }
1217 // peers
1218 echo "<td class='${secondclass}'>\n";
1219 $prefix = '';
1220 if ($alloc['addrinfo']['reserved'] == 'yes')
1221 {
1222 echo $prefix . '<strong>RESERVED</strong>';
1223 $prefix = '; ';
1224 }
1225 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
1226 {
1227 if ($allocpeer['object_id'] == $object_id)
1228 continue;
1229 echo $prefix . "<a href='" . makeHref (array ('page' => 'object', 'object_id' => $allocpeer['object_id'])) . "'>";
1230 if (isset ($allocpeer['osif']) and strlen ($allocpeer['osif']))
1231 echo $allocpeer['osif'] . '@';
1232 echo $allocpeer['object_name'] . '</a>';
1233 $prefix = '; ';
1234 }
1235 echo "</td></tr>\n";
1236 }
1237 }
1238 echo "</table><br>\n";
1239 finishPortlet();
1240 }
1241
1242 $forwards = $info['nat4'];
1243 if (count($forwards['in']) or count($forwards['out']))
1244 {
1245 startPortlet('NATv4');
1246
1247 if (count($forwards['out']))
1248 {
1249
1250 echo "<h3>locally performed NAT</h3>";
1251
1252 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
1253 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
1254
1255 foreach ($forwards['out'] as $pf)
1256 {
1257 $class = 'trerror';
1258 $osif = '';
1259 if (isset ($alloclist [$pf['localip']]))
1260 {
1261 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
1262 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
1263 }
1264 echo "<tr class='$class'>";
1265 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}<a href='".makeHref(array('page'=>'ipaddress', 'tab'=>'default', 'ip'=>$pf['localip']))."'>${pf['localip']}</a>:${pf['localport']}</td>";
1266 echo "<td class=tdleft><a href='".makeHref(array('page'=>'ipaddress', 'tab'=>'default', 'ip'=>$pf['remoteip']))."'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
1267 $address = getIPv4Address ($pf['remoteip']);
1268 echo "<td class='description'>";
1269 if (count ($address['allocs']))
1270 foreach($address['allocs'] as $bond)
1271 echo "<a href='".makeHref(array('page'=>'object', 'tab'=>'default', 'object_id'=>$bond['object_id']))."'>${bond['object_name']}(${bond['name']})</a> ";
1272 elseif (strlen ($pf['remote_addr_name']))
1273 echo '(' . $pf['remote_addr_name'] . ')';
1274 echo "</td><td class='description'>${pf['description']}</td></tr>";
1275 }
1276 echo "</table><br><br>";
1277 }
1278 if (count($forwards['in']))
1279 {
1280 echo "<h3>arriving NAT connections</h3>";
1281 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
1282 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
1283 foreach ($forwards['in'] as $pf)
1284 {
1285 echo "<tr>";
1286 echo "<td>${pf['proto']}/<a href='".makeHref(array('page'=>'ipaddress', 'tab'=>'default', 'ip'=>$pf['localip']))."'>${pf['localip']}</a>:${pf['localport']}</td>";
1287 echo "<td class='description'><a href='".makeHref(array('page'=>'object', 'tab'=>'default', 'object_id'=>$pf['object_id']))."'>${pf['object_name']}</a>";
1288 echo "</td><td><a href='".makeHref(array('page'=>'ipaddress', 'tab'=>'default', 'ip'=>$pf['remoteip']))."'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
1289 echo "<td class='description'>${pf['description']}</td></tr>";
1290 }
1291 echo "</table><br><br>";
1292 }
1293 finishPortlet();
1294 }
1295
1296 $pools = $info['ipv4rspools'];
1297 if (count ($pools))
1298 {
1299 $order = 'odd';
1300 startPortlet ('Real server pools (' . count ($pools) . ')');
1301 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
1302 echo "<tr><th>VS</th><th>RS pool</th><th>RS</th><th>VS config</th><th>RS config</th><th>Prio</th></tr>\n";
1303 foreach ($pools as $vs_id => $vs_info)
1304 {
1305 echo "<tr valign=top class=row_${order}><td class=tdleft>";
1306 renderCell (spotEntity ('ipv4vs', $vs_id));
1307 echo "</td><td class=tdleft>";
1308 renderCell (spotEntity ('ipv4rspool', $vs_info['pool_id']));
1309 echo '</td><td class=tdleft>' . $vs_info['rscount'] . '</td>';
1310 echo "<td class=slbconf>${vs_info['vsconfig']}</td>";
1311 echo "<td class=slbconf>${vs_info['rsconfig']}</td>";
1312 echo "<td class=slbconf>${vs_info['prio']}</td>";
1313 echo "</tr>\n";
1314 $order = $nextorder[$order];
1315 }
1316 echo "</table>\n";
1317 finishPortlet();
1318 }
1319 echo "</td>\n";
1320
1321 // After left column we have (surprise!) right column with rackspace portlet only.
1322 echo "<td class=pcright>";
1323 if (!considerConfiguredConstraint ($info, 'VIRTUAL_OBJ_LISTSRC'))
1324 {
1325 // rackspace portlet
1326 startPortlet ('rackspace allocation');
1327 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1328 renderRack ($rack_id, $object_id);
1329 echo '<br>';
1330 finishPortlet();
1331 }
1332 echo "</td></tr>";
1333 echo "</table>\n";
1334 }
1335
1336 function renderRackMultiSelect ($sname, $racks, $selected)
1337 {
1338 // Transform the given flat list into a list of groups, each representing a rack row.
1339 $rdata = array();
1340 foreach ($racks as $rack)
1341 if (!isset ($rdata[$rack['row_name']]))
1342 $rdata[$rack['row_name']] = array ($rack['id'] => $rack['name']);
1343 else
1344 $rdata[$rack['row_name']][$rack['id']] = $rack['name'];
1345 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
1346 foreach ($rdata as $optgroup => $racklist)
1347 {
1348 echo "<optgroup label='${optgroup}'>";
1349 foreach ($racklist as $rack_id => $rack_name)
1350 {
1351 echo "<option value=${rack_id}";
1352 if (!(array_search ($rack_id, $selected) === FALSE))
1353 echo ' selected';
1354 echo">${rack_name}</option>\n";
1355 }
1356 }
1357 echo "</select>\n";
1358 }
1359
1360 // This function renders a form for port edition.
1361 function renderPortsForObject ($object_id)
1362 {
1363 $prefs = getPortListPrefs();
1364 function printNewItemTR ($prefs)
1365 {
1366 printOpFormIntro ('addPort');
1367 echo "<tr><td>";
1368 printImageHREF ('add', 'add a port', TRUE);
1369 echo "</td><td class='tdleft'><input type=text size=8 name=port_name tabindex=100></td>\n";
1370 echo "<td><input type=text name=port_label tabindex=101></td><td>";
1371 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 102), $prefs['selected']);
1372 echo "<td><input type=text name=port_l2address tabindex=103 size=18 maxlength=24></td>\n";
1373 echo "<td colspan=3>&nbsp;</td><td>";
1374 printImageHREF ('add', 'add a port', TRUE, 104);
1375 echo "</td></tr></form>";
1376 }
1377 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' || getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' )
1378 startPortlet ('Ports and interfaces');
1379 else
1380 echo '<br>';
1381 $object = spotEntity ('object', $object_id);
1382 amplifyCell ($object);
1383 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1384 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1385 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1386 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1387 printOpFormIntro ('addBulkPorts');
1388 echo "<tr><td>";
1389 printImageHREF ('add', 'add ports', TRUE);
1390 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1391 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1392 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1393 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1394 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1395 echo "<td>&nbsp;</td><td>";
1396 printImageHREF ('add', 'add ports', TRUE, 110);
1397 echo "</td></tr></form>";
1398 echo "</table><br>\n";
1399 }
1400
1401 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1402 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>L2 address</th>";
1403 echo "<th class=tdcenter colspan=2>Cable, Remote object and port</th><th class=tdcenter>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
1404 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1405 printNewItemTR ($prefs);
1406
1407 // clear ports link
1408 echo "<a href='".
1409 makeHrefProcess(array ('op'=>'deleteAll', 'page' => 'object', 'tab' => 'ports', 'object_id' => $object_id)).
1410 "' onclick=\"javascript:return confirm('Are you sure you want to delete all existing ports?')\">" . getImageHREF ('clear', 'Clear port list') . " Clear port list</a>";
1411
1412 if (isset ($_REQUEST['hl_port_id']))
1413 {
1414 assertUIntArg ('hl_port_id');
1415 $hl_port_id = intval ($_REQUEST['hl_port_id']);
1416 addAutoScrollScript ("port-$hl_port_id");
1417 }
1418 switchportInfoJS ($object_id); // load JS code to make portnames interactive
1419 foreach ($object['ports'] as $port)
1420 {
1421 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="port_highlight"' : '';
1422 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
1423 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id'], 'object_id'=>$object_id))."'>";
1424 printImageHREF ('delete', 'Unlink and Delete this port');
1425 echo "</a></td>\n";
1426 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
1427 echo "<td class='tdleft' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=8></td>";
1428 echo "<td><input type=text name=label value='${port['label']}'></td>";
1429 if (!$port['remote_object_id'])
1430 {
1431 echo '<td>';
1432 if ($port['iif_id'] != 1)
1433 echo '<label>' . $port['iif_name'] . ' ';
1434 printSelect (getExistingPortTypeOptions ($port['id']), array ('name' => 'port_type_id'), $port['oif_id']);
1435 if ($port['iif_id'] != 1)
1436 echo '</label>';
1437 echo '</td>';
1438 }
1439 else
1440 {
1441 echo "<input type=hidden name=port_type_id value='${port['oif_id']}'><td class=tdleft>";
1442 echo formatPortIIFOIF ($port) . '</td>';
1443 }
1444 // 18 is enough to fit 6-byte MAC address in its longest form,
1445 // while 24 should be Ok for WWN
1446 echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n";
1447 if ($port['remote_object_id'])
1448 {
1449 $remote_object = spotEntity ('object', $port['remote_object_id']);
1450 echo "<td>${port['cableid']}&nbsp;<a href='".makeHref(array('page'=>'object', 'object_id'=>$port['remote_object_id']))."'>${remote_object['dname']}</a></td>";
1451 echo "<td>${port['remote_name']}<input type=hidden name=reservation_comment value=''></td>";
1452 echo "<td class=tdcenter><a href='".
1453 makeHrefProcess(array(
1454 'op'=>'unlinkPort',
1455 'port_id'=>$port['id'],
1456 'object_id'=>$object_id)).
1457 "'>";
1458 printImageHREF ('cut', 'Unlink this port');
1459 echo "</a></td>";
1460 }
1461 elseif (strlen ($port['reservation_comment']))
1462 {
1463 echo "<td><b>Reserved:</b></td>";
1464 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1465 echo "<td class=tdcenter><a href='".
1466 makeHrefProcess(array(
1467 'op'=>'useup',
1468 'port_id'=>$port['id'],
1469 'object_id'=>$object_id)).
1470 "'>";
1471 printImageHREF ('clear', 'Use up this port');
1472 echo "</a></td>";
1473 }
1474 else
1475 {
1476 //echo "<td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter><a href='javascript:;'";
1477 echo "<td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter><span";
1478 $helper_args = array
1479 (
1480 'port' => $port['id'],
1481 'in_rack' => 'n',
1482 );
1483 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
1484 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
1485 echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1486 echo "\",\"findlink\",\"${popup_args}\");'";
1487 // end of onclick=
1488 $helper_args['in_rack'] = 'y';
1489 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1490 echo "\",\"findlink\",\"${popup_args}\");'";
1491 // end of onclick=
1492 echo '>';
1493 // end of <a>
1494 printImageHREF ('plug', 'Link this port');
1495 echo "</span>";
1496 echo " <input type=text name=reservation_comment></td>\n";
1497 }
1498 echo "<td>";
1499 printImageHREF ('save', 'Save changes', TRUE);
1500 echo "</td></form></tr>\n";
1501 }
1502 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1503 printNewItemTR ($prefs);
1504 echo "</table><br>\n";
1505 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1506 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1507 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1508 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1509 printOpFormIntro ('addBulkPorts');
1510 echo "<tr><td>";
1511 printImageHREF ('add', 'add ports', TRUE);
1512 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1513 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1514 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1515 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1516 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1517 echo "<td>&nbsp;</td><td>";
1518 printImageHREF ('add', 'add ports', TRUE, 110);
1519 echo "</td></tr></form>";
1520 echo "</table><br>\n";
1521 }
1522 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes')
1523 finishPortlet();
1524 if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes')
1525 return;
1526
1527 startPortlet ('Add/update multiple ports');
1528 printOpFormIntro ('addMultiPorts');
1529 echo 'Format: <select name=format tabindex=201>';
1530 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1531 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
1532 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
1533 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
1534 echo "</select>";
1535 echo 'Default port type: ';
1536 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type', 'tabindex' => 202), $prefs['selected']);
1537 echo "<input type=submit value='Parse output' tabindex=204><br>\n";
1538 echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
1539 echo '</form>';
1540 finishPortlet();
1541 }
1542
1543 function renderIPv4ForObject ($object_id)
1544 {
1545 function printNewItemTR ()
1546 {
1547 global $aat;
1548 printOpFormIntro ('addIPv4Allocation');
1549 echo "<tr><td>";
1550 printImageHREF ('add', 'allocate', TRUE);
1551 echo "</td>";
1552 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n";
1553 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n";
1554 echo "<td colspan=2>&nbsp;</td><td>";
1555 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), 'regular');
1556 echo "</td><td>&nbsp;</td><td>";
1557 printImageHREF ('add', 'allocate', TRUE, 103);
1558 echo "</td></tr></form>";
1559 }
1560 $focus = spotEntity ('object', $object_id);
1561 amplifyCell ($focus);
1562 global $aat;
1563 startPortlet ('Allocations');
1564 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1565 echo '<tr><th>&nbsp;</th><th>OS interface</th><th>IP address</th>';
1566 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1567 echo '<th>network</th><th>routed by</th>';
1568 echo '<th>type</th><th>misc</th><th>&nbsp</th></tr>';
1569
1570 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1571 printNewItemTR();
1572 foreach ($focus['ipv4'] as $dottedquad => $alloc)
1573 {
1574 $class = $alloc['addrinfo']['class'];
1575 $netid = getIPv4AddressNetworkId ($dottedquad);
1576 if (NULL !== $netid)
1577 {
1578 $netinfo = spotEntity ('ipv4net', $netid);
1579 loadIPv4AddrList ($netinfo);
1580 }
1581 printOpFormIntro ('updIPv4Allocation', array ('ip' => $dottedquad));
1582 echo "<tr class='$class' valign=top><td><a href='".makeHrefProcess(array('op'=>'delIPv4Allocation', 'ip'=>$dottedquad, 'object_id'=>$object_id))."'>";
1583 printImageHREF ('delete', 'Delete this IPv4 address');
1584 echo "</a></td>";
1585 echo "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10></td><td class=tdleft>";
1586 if (NULL !== $netid)
1587 echo "<a href='".makeHref(array('page'=>'ipaddress', 'ip'=>$dottedquad))."'>${dottedquad}</a>";
1588 else
1589 echo $dottedquad;
1590 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
1591 echo '<small>/' . (NULL === $netid ? '??' : $netinfo['mask']) . '</small>';
1592 if (strlen ($alloc['addrinfo']['name']))
1593 echo ' (' . niftyString ($alloc['addrinfo']['name']) . ')';
1594 echo '</td>';
1595 // FIXME: this a copy-and-paste from renderRackObject()
1596 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1597 {
1598 if (NULL === $netid)
1599 echo '<td class=sparenetwork>N/A</td><td class=sparenetwork>N/A</td>';
1600 else
1601 {
1602 echo '<td>';
1603 renderCell ($netinfo);
1604 echo '</td>';
1605 // filter out self-allocation
1606 $other_routers = array();
1607 foreach (findRouters ($netinfo['addrlist']) as $router)
1608 if ($router['id'] != $object_id)
1609 $other_routers[] = $router;
1610 if (count ($other_routers))
1611 printRoutersTD ($other_routers);
1612 else
1613 echo "<td>&nbsp;</td>";
1614 }
1615 }
1616 echo '<td>';
1617 printSelect ($aat, array ('name' => 'bond_type'), $alloc['type']);
1618 echo "</td><td>";
1619 $prefix = '';
1620 if ($alloc['addrinfo']['reserved'] == 'yes')
1621 {
1622 echo $prefix . '<strong>RESERVED</strong>';
1623 $prefix = '; ';
1624 }
1625 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
1626 {
1627 if ($allocpeer['object_id'] == $object_id)
1628 continue;
1629 echo $prefix . "<a href='".makeHref(array('page'=>'object', 'object_id'=>$allocpeer['object_id']))."'>";
1630 if (isset ($allocpeer['osif']) and strlen ($allocpeer['osif']))
1631 echo $allocpeer['osif'] . '@';
1632 echo $allocpeer['object_name'] . '</a>';
1633 $prefix = '; ';
1634 }
1635 echo "</td><td>";
1636 printImageHREF ('save', 'Save changes', TRUE);
1637 echo "</td></form></tr>\n";
1638 }
1639 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1640 printNewItemTR();
1641
1642 echo "</table><br>\n";
1643 finishPortlet();
1644
1645 }
1646
1647 function renderIPv6ForObject ($object_id)
1648 {
1649 function printNewItemTR ()
1650 {
1651 global $aat;
1652 printOpFormIntro ('addIPv6Allocation');
1653 echo "<tr><td>";
1654 printImageHREF ('add', 'allocate', TRUE);
1655 echo "</td>";
1656 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n";
1657 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n";
1658 echo "<td colspan=2>&nbsp;</td><td>";
1659 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), 'regular');
1660 echo "</td><td>&nbsp;</td><td>";
1661 printImageHREF ('add', 'allocate', TRUE, 103);
1662 echo "</td></tr></form>";
1663 }
1664 $focus = spotEntity ('object', $object_id);
1665 amplifyCell ($focus);
1666 global $aat;
1667 startPortlet ('Allocations');
1668 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1669 echo '<tr><th>&nbsp;</th><th>OS interface</th><th>IP address</th>';
1670 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1671 echo '<th>network</th><th>routed by</th>';
1672 echo '<th>type</th><th>misc</th><th>&nbsp</th></tr>';
1673
1674 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1675 printNewItemTR();
1676 foreach ($focus['ipv6'] as $bin_str => $alloc)
1677 {
1678 $ipv6 = new IPv6Address ($bin_str);
1679 $dottedquad = $ipv6->format();
1680 $class = $alloc['addrinfo']['class'];
1681 $netid = getIPv6AddressNetworkId ($ipv6);
1682 if (NULL !== $netid)
1683 {
1684 $netinfo = spotEntity ('ipv6net', $netid);
1685 loadIPv6AddrList ($netinfo);
1686 }
1687 printOpFormIntro ('updIPv6Allocation', array ('ip' => $dottedquad));
1688 echo "<tr class='$class' valign=top><td><a href='".makeHrefProcess(array('op'=>'delIPv6Allocation', 'ip'=>$dottedquad, 'object_id'=>$object_id))."'>";
1689 printImageHREF ('delete', 'Delete this IPv6 address');
1690 echo "</a></td>";
1691 echo "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10></td><td class=tdleft>";
1692 if (NULL !== $netid)
1693 echo "<a href='index.php?page=ipv6address&ip=$dottedquad'>$dottedquad</a>";
1694 else
1695 echo $dottedquad;
1696 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
1697 echo '<small>/' . (NULL === $netid ? '??' : $netinfo['mask']) . '</small>';
1698 if (strlen ($alloc['addrinfo']['name']))
1699 echo ' (' . niftyString ($alloc['addrinfo']['name']) . ')';
1700 echo '</td>';
1701 // FIXME: this a copy-and-paste from renderRackObject()
1702 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1703 {
1704 if (NULL === $netid)
1705 echo '<td class=sparenetwork>N/A</td><td class=sparenetwork>N/A</td>';
1706 else
1707 {
1708 echo '<td>';
1709 renderCell ($netinfo);
1710 echo '</td>';
1711 // filter out self-allocation
1712 $other_routers = array();
1713 foreach (findRouters ($netinfo['addrlist']) as $router)
1714 if ($router['id'] != $object_id)
1715 $other_routers[] = $router;
1716 if (count ($other_routers))
1717 printRoutersTD ($other_routers);
1718 else
1719 echo "<td>&nbsp;</td>";
1720 }
1721 }
1722 echo '<td>';
1723 printSelect ($aat, array ('name' => 'bond_type'), $alloc['type']);
1724 echo "</td><td>";
1725 $prefix = '';
1726 if ($alloc['addrinfo']['reserved'] == 'yes')
1727 {
1728 echo $prefix . '<strong>RESERVED</strong>';
1729 $prefix = '; ';
1730 }
1731 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
1732 {
1733 if ($allocpeer['object_id'] == $object_id)
1734 continue;
1735 echo $prefix . "<a href='".makeHref(array('page'=>'object', 'object_id'=>$allocpeer['object_id']))."'>";
1736 if (isset ($allocpeer['osif']) and strlen ($allocpeer['osif']))
1737 echo $allocpeer['osif'] . '@';
1738 echo $allocpeer['object_name'] . '</a>';
1739 $prefix = '; ';
1740 }
1741 echo "</td><td>";
1742 printImageHREF ('save', 'Save changes', TRUE);
1743 echo "</td></form></tr>\n";
1744 }
1745 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1746 printNewItemTR();
1747
1748 echo "</table><br>\n";
1749 finishPortlet();
1750
1751 }
1752
1753 // This function is deprecated. Do not rely on its internals,
1754 // it will probably be removed in the next major relese.
1755 // Use new showError, showWarning, showSuccess functions.
1756 // Log structure versions:
1757 // 1: the whole structure is a list of code-message pairs
1758 // 2 and later: there's a "v" field set, which indicates the version
1759 // 2: there's a "m" list set to hold message code and optional arguments
1760 function showMessageOrError ()
1761 {
1762 if (!isset ($_SESSION['log']))
1763 return;
1764 $log = $_SESSION['log'];
1765 switch (TRUE)
1766 {
1767 case !isset ($log['v']):
1768 case $log['v'] == 1:
1769 foreach ($log as $key => $record)
1770 if ($key !== 'v')
1771 echo "<div class=msg_${record['code']}>${record['message']}</div>";
1772 break;
1773 case $log['v'] == 2:
1774 $msginfo = array
1775 (
1776 // records 0~99 with success messages
1777 0 => array ('code' => 'success', 'format' => '%s'),
1778 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with port %s at object %s'),
1779 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1780 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1781 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1782 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1783 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1784 26 => array ('code' => 'success', 'format' => 'updated %u record(s) successfully'),
1785 37 => array ('code' => 'success', 'format' => 'added %u records successfully'),
1786 41 => array ('code' => 'success', 'format' => 'uplink ports reverb queued'),
1787 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1788 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1789 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1790 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1791 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1792 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1793 62 => array ('code' => 'success', 'format' => 'gw: %s'),
1794 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1795 64 => array ('code' => 'success', 'format' => 'Port %s@%s has been assigned to VLAN %u'),
1796 66 => array ('code' => 'success', 'format' => "File sent Ok via handler '%s'"),
1797 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1798 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1799 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
1800 80 => array ('code' => 'success', 'format' => "Added new object '%s'"),
1801 81 => array ('code' => 'success', 'format' => "SNMP: completed '%s' work"),
1802 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"),
1803 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'),
1804 // records 100~199 with fatal error messages
1805 100 => array ('code' => 'error', 'format' => '%s'),
1806 102 => array ('code' => 'error', 'format' => "Error creating user account '%s'"),
1807 104 => array ('code' => 'error', 'format' => "failed updating record '%s'"),
1808 105 => array ('code' => 'error', 'format' => 'default VLAN cannot be changed'),
1809 107 => array ('code' => 'error', 'format' => 'Assertion failed: %s'),
1810 108 => array ('code' => 'error', 'format' => 'Database error: %s'),
1811 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
1812 110 => array ('code' => 'error', 'format' => 'failed adding a record'),
1813 111 => array ('code' => 'error', 'format' => 'failed deleting a record'),
1814 120 => array ('code' => 'error', 'format' => 'Reset failed!'),
1815 127 => array ('code' => 'error', 'format' => 'Added %u real servers and encountered %u errors'),
1816 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1817 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'),
1818 142 => array ('code' => 'error', 'format' => 'executeAutoPorts() failed'),
1819 143 => array ('code' => 'error', 'format' => 'Tried chaining %u tags, but experienced %u errors.'),
1820 144 => array ('code' => 'error', 'format' => "Error deleting tag: '%s'"),
1821 147 => array ('code' => 'error', 'format' => 'failed adding record "%s"'),
1822 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1823 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1824 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1825 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1826 153 => array ('code' => 'error', 'format' => 'Password change failed.'),
1827 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1828 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1829 157 => array ('code' => 'error', 'format' => 'operation not permitted'),
1830 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1831 160 => array ('code' => 'error', 'format' => 'Invalid arguments'),
1832 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1833 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1834 164 => array ('code' => 'error', 'format' => 'Gateway failure: %s.'),
1835 165 => array ('code' => 'error', 'format' => 'Gateway failure: malformed reply.'),
1836 166 => array ('code' => 'error', 'format' => 'gw: %s'),
1837 167 => array ('code' => 'error', 'format' => 'Could not find port %s'),
1838 168 => array ('code' => 'error', 'format' => 'Port %s is a trunk'),
1839 169 => array ('code' => 'error', 'format' => 'Failed to configure %s, connector returned code %u'),
1840 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1841 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1842 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
1843 184 => array ('code' => 'error', 'format' => 'Submitted form is invalid at line %u'),
1844 186 => array ('code' => 'error', 'format' => 'Incomplete form has been ignored. Cheers.'),
1845 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"),
1846 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"),
1847 190 => array ('code' => 'error', 'format' => "Invalid VLAN ID '%s'"),
1848 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
1849
1850 // records 200~299 with warnings
1851 200 => array ('code' => 'warning', 'format' => '%s'),
1852 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1853 202 => array ('code' => 'warning', 'format' => 'gw: %s'),
1854 203 => array ('code' => 'warning', 'format' => 'Port %s seems to be the first in VLAN %u at this switch.'),
1855 204 => array ('code' => 'warning', 'format' => 'Check uplink/downlink configuration for proper operation.'),
1856 205 => array ('code' => 'warning', 'format' => '%u change request(s) have been ignored'),
1857 206 => array ('code' => 'warning', 'format' => 'Rack is not empty'),
1858 207 => array ('code' => 'warning', 'format' => 'Ignored empty request'),
1859
1860 // records 300~399 with notices
1861 300 => array ('code' => 'neutral', 'format' => '%s'),
1862
1863 );
1864 // Handle the arguments. Is there any better way to do it?
1865 foreach ($log['m'] as $record)
1866 {
1867 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1868 {
1869 echo '<div class=msg_neutral>(this message was lost)</div>';
1870 continue;
1871 }
1872 if (isset ($record['a']))
1873 switch (count ($record['a']))
1874 {
1875 case 1:
1876 $msgtext = sprintf
1877 (
1878 $msginfo[$record['c']]['format'],
1879 $record['a'][0]
1880 );
1881 break;
1882 case 2:
1883 $msgtext = sprintf
1884 (
1885 $msginfo[$record['c']]['format'],
1886 $record['a'][0],
1887 $record['a'][1]
1888 );
1889 break;
1890 case 3:
1891 $msgtext = sprintf
1892 (
1893 $msginfo[$record['c']]['format'],
1894 $record['a'][0],
1895 $record['a'][1],
1896 $record['a'][2]
1897 );
1898 break;
1899 case 4:
1900 default:
1901 $msgtext = sprintf
1902 (
1903 $msginfo[$record['c']]['format'],
1904 $record['a'][0],
1905 $record['a'][1],
1906 $record['a'][2],
1907 $record['a'][3]
1908 );
1909 break;
1910 }
1911 else
1912 $msgtext = $msginfo[$record['c']]['format'];
1913 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1914 }
1915 break;
1916 default:
1917 echo '<div class=msg_error>' . __FUNCTION__ . ': internal error</div>';
1918 break;
1919 }
1920 clearMessages();
1921 }
1922
1923 // renders two tables: port link status and learned MAC list
1924 function renderPortsInfo($object_id)
1925 {
1926 global $nextorder;
1927 echo "<table width='100%'><tr>";
1928
1929 if (permitted (NULL, NULL, 'get_link_status'))
1930 {
1931 try
1932 {
1933 $linkStatus = gwRetrieveDeviceConfig ($object_id, 'getportstatus');
1934 }
1935 catch (RackTablesError $e) {}
1936 if (! empty ($linkStatus))
1937 {
1938 echo "<td valign='top' width='50%'>";
1939 startPortlet('Link status');
1940 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th>Link status<th>Link info</tr>";
1941 $order = 'even';
1942 foreach ($linkStatus as $pn => $link)
1943 {
1944 echo "<tr class='row_$order'>";
1945 $order = $nextorder[$order];
1946 echo '<td>' . $pn;
1947 echo '<td>' . $link['status'];
1948 $info = '';
1949 if (isset ($link['speed']))
1950 $info .= $link['speed'];
1951 if (isset ($link['duplex']))
1952 {
1953 if (! empty ($info))
1954 $info .= ', ';
1955 $info .= $link['duplex'];
1956 }
1957 echo '<td>' . $info;
1958 echo '</tr>';
1959 }
1960 echo "</table></td>";
1961 finishPortlet();
1962 }
1963 }
1964
1965 try
1966 {
1967 $macList = sortPortList (gwRetrieveDeviceConfig ($object_id, 'getmaclist'));
1968 }
1969 catch (RackTablesError $e) {}
1970 if (! empty ($macList))
1971 {
1972 echo "<td valign='top' width='50%'>";
1973 $rendered_macs = '';
1974 $mac_count = 0;
1975 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>";
1976 $order = 'even';
1977 foreach ($macList as $pn => $list)
1978 {
1979 $order = $nextorder[$order];
1980 foreach ($list as $item)
1981 {
1982 ++$mac_count;
1983 $rendered_macs .= "<tr class='row_$order'>";
1984 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'];
1985 $rendered_macs .= '<td>' . $item['vid'];
1986 $rendered_macs .= '<td>' . $pn;
1987 $rendered_macs .= '</tr>';
1988 }
1989 }
1990 $rendered_macs .= "</table></td>";
1991
1992 startPortlet("Learned MACs ($mac_count)");
1993 echo $rendered_macs;
1994 finishPortlet();
1995 }
1996
1997 echo "</td></tr></table>";
1998 }
1999
2000 /*
2001 The following conditions must be met:
2002 1. We can mount onto free atoms only. This means: if any record for an atom
2003 already exists in RackSpace, it can't be used for mounting.
2004 2. We can't unmount from 'W' atoms. Operator should review appropriate comments
2005 and either delete them before unmounting or refuse to unmount the object.
2006 */
2007 function renderRackSpaceForObject ($object_id)
2008 {
2009 // Always process occupied racks plus racks chosen by user. First get racks with
2010 // already allocated rackspace...
2011 $workingRacksData = getResidentRacksData ($object_id);
2012 // ...and then add those chosen by user (if any).
2013 if (isset($_REQUEST['rackmulti']))
2014 foreach ($_REQUEST['rackmulti'] as $cand_id)
2015 if (!isset ($workingRacksData[$cand_id]))
2016 {
2017 $rackData = spotEntity ('rack', $cand_id);
2018 amplifyCell ($rackData);
2019 $workingRacksData[$cand_id] = $rackData;
2020 }
2021
2022 // Main layout starts.
2023 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
2024
2025 // Left portlet with rack list.
2026 echo "<td class=pcleft height='1%'>";
2027 startPortlet ('Racks');
2028 $allRacksData = listCells ('rack');
2029 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
2030 foreach ($allRacksData as $rack)
2031 if (!array_key_exists ($rack['id'], $workingRacksData))
2032 {
2033 amplifyCell ($rack);
2034 $workingRacksData[$rack['id']] = $rack;
2035 }
2036 foreach (array_keys ($workingRacksData) as $rackId)
2037 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
2038 printOpFormIntro ('updateObjectAllocation');
2039 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
2040 echo "<br><br>";
2041 finishPortlet();
2042 echo "</td>";
2043
2044 // Middle portlet with comment and submit.
2045 echo "<td class=pcleft>";
2046 startPortlet ('Comment');
2047 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
2048 echo "<input type=submit value='Save' name=got_atoms>\n";
2049 echo "<br><br>";
2050 finishPortlet();
2051 echo "</td>";
2052
2053 // Right portlet with rendered racks. If this form submit is not final, we have to
2054 // reflect the former state of the grid in current form.
2055 echo "<td class=pcright rowspan=2 height='1%'>";
2056 startPortlet ('Working copy');
2057 addJS ('js/racktables.js');
2058 echo '<table border=0 cellspacing=10 align=center><tr>';
2059 foreach ($workingRacksData as $rack_id => $rackData)
2060 {
2061 // Order is important here: only original allocation is highlighted.
2062 highlightObject ($rackData, $object_id);
2063 markupAtomGrid ($rackData, 'T');
2064 // If we have a form processed, discard user input and show new database
2065 // contents.
2066 if (isset ($_REQUEST['rackmulti'][0])) // is an update
2067 mergeGridFormToRack ($rackData);
2068 echo "<td valign=top>";
2069 echo "<center>\n<h2>${rackData['name']}</h2>\n";
2070 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
2071 echo "<tr><th width='10%'>&nbsp;</th>";
2072 echo "<th width='20%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2073 echo "<th width='50%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2074 echo "<th width='20%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
2075 renderAtomGrid ($rackData);
2076 echo "<tr><th width='10%'>&nbsp;</th>";
2077 echo "<th width='20%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2078 echo "<th width='50%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2079 echo "<th width='20%'><a href='javascript:;' oncontextmenu=\"blockToggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']}); return false;\" onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
2080 echo "</table></center>\n";
2081 echo '</td>';
2082 }
2083 echo "</tr></table>";
2084 finishPortlet();
2085 echo "</td>\n";
2086
2087 echo "</form>\n";
2088 echo "</tr></table>\n";
2089 }
2090
2091 function renderMolecule ($mdata, $object_id)
2092 {
2093 // sort data out
2094 $rackpack = array();
2095 global $loclist;
2096 foreach ($mdata as $rua)
2097 {
2098 $rack_id = $rua['rack_id'];
2099 $unit_no = $rua['unit_no'];
2100 $atom = $rua['atom'];
2101 if (!isset ($rackpack[$rack_id]))
2102 {
2103 $rackData = spotEntity ('rack', $rack_id);
2104 amplifyCell ($rackData);
2105 for ($i = $rackData['height']; $i > 0; $i--)
2106 for ($locidx = 0; $locidx < 3; $locidx++)
2107 $rackData[$i][$locidx]['state'] = 'F';
2108 $rackpack[$rack_id] = $rackData;
2109 }
2110 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2111 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2112 }
2113 // now we have some racks to render
2114 addAtomCSS();
2115 foreach ($rackpack as $rackData)
2116 {
2117 markAllSpans ($rackData);
2118 echo "<table class=molecule cellspacing=0>\n";
2119 echo "<caption>${rackData['name']}</caption>\n";
2120 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
2121 for ($i = $rackData['height']; $i > 0; $i--)
2122 {
2123 echo "<tr><th>$i</th>";
2124 for ($locidx = 0; $locidx < 3; $locidx++)
2125 {
2126 $state = $rackData[$i][$locidx]['state'];
2127 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
2128 }
2129 echo "</tr>\n";
2130 }
2131 echo "</table>\n";
2132 }
2133 }
2134
2135 function renderDepot ()
2136 {
2137 global $pageno, $nextorder;
2138 $cellfilter = getCellFilter();
2139 $objects = filterCellList (listCells ('object'), $cellfilter['expression']);
2140
2141 echo "<table border=0 class=objectview>\n";
2142 echo "<tr><td class=pcleft>";
2143
2144 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
2145 {
2146 if (count($objects) > 0)
2147 {
2148 startPortlet ('Objects (' . count ($objects) . ')');
2149 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2150 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Barcode</th><th>Row/Rack</th></tr>';
2151 $order = 'odd';
2152 foreach ($objects as $obj)
2153 {
2154 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $obj['id'])
2155 $secondclass = 'tdleft port_highlight';
2156 else
2157 $secondclass = 'tdleft';
2158 echo "<tr class=row_${order} valign=top><td class='${secondclass}'><a href='".makeHref(array('page'=>'object', 'object_id'=>$obj['id']))."'><strong>${obj['dname']}</strong></a>";
2159 if (count ($obj['etags']))
2160 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
2161 echo "</td><td class='${secondclass}'>${obj['label']}</td>";
2162 echo "<td class='${secondclass}'>${obj['asset_no']}</td>";
2163 echo "<td class='${secondclass}'>${obj['barcode']}</td>";
2164 if ($obj['rack_id'])
2165 echo "<td class='${secondclass}'><a href='".makeHref(array('page'=>'row', 'row_id'=>$obj['row_id']))."'>${obj['Row_name']}</a>/<a href='".makeHref(array('page'=>'rack', 'rack_id'=>$obj['rack_id']))."'>${obj['Rack_name']}</a></td>";
2166 else
2167 echo "<td class='${secondclass}'>Unmounted</td>";
2168 echo '</tr>';
2169 $order = $nextorder[$order];
2170 }
2171 echo '</table>';
2172 finishPortlet();
2173 }
2174 else
2175 echo '<h2>No objects exist</h2>';
2176 }
2177
2178 echo "</td><td class=pcright width='25%'>";
2179
2180 renderCellFilterPortlet ($cellfilter, 'object', $objects);
2181 echo "</td></tr></table>\n";
2182 }
2183
2184 // This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2185 // In this case it renders the describing message instead.
2186 function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2187 {
2188 if (!$cellfilter['is_empty'])
2189 return FALSE;
2190 if (isset ($_REQUEST['show_all_objects']))
2191 return FALSE;
2192 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2193 if (0 == $max || $count <= $max)
2194 return FALSE;
2195
2196 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2197 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2198 $suffix = isset ($count) ? " ($count)" : '';
2199 echo <<<END
2200 <p>Please set a filter to display the corresponging $entities_name.
2201 <br><a href="$href_show_all">Show all $entities_name$suffix</a>
2202 END;
2203 return TRUE;
2204 }
2205
2206 // History viewer for history-enabled simple dictionaries.
2207 function renderHistory ($object_type, $object_id)
2208 {
2209 switch ($object_type)
2210 {
2211 case 'row':
2212 $query = "select ctime, user_name, name, comment from RackRowHistory where id = ? order by ctime";
2213 $header = '<tr><th>change time</th><th>author</th><th>rack row name</th><th>rack row comment</th></tr>';
2214 $extra = 3;
2215 break;
2216 case 'rack':
2217 $query =
2218 "select ctime, user_name, rh.name, rr.name as name, rh.height, rh.comment " .
2219 "from RackHistory as rh left join RackRow as rr on rh.row_id = rr.id " .
2220 "where rh.id = ? order by ctime";
2221 $header = '<tr><th>change time</th><th>author</th><th>rack name</th><th>rack row name</th><th>rack height</th><th>rack comment</th></tr>';
2222 $extra = 5;
2223 break;
2224 case 'object':
2225 $query =
2226 "select ctime, user_name, RackObjectHistory.name as name, label, barcode, asset_no, has_problems, dict_value, comment " .
2227 "from RackObjectHistory inner join Dictionary on objtype_id = dict_key join Chapter on Dictionary.chapter_id = Chapter.id " .
2228 "where Chapter.name = 'RackObjectType' and RackObjectHistory.id=? order by ctime";
2229 $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>has problems?</th><th>object type</th><th>comment</th></tr>';
2230 $extra = 8;
2231 break;
2232 default:
2233 throw new InvalidArgException ('object_type', $object_type);
2234 }
2235 $result = usePreparedSelectBlade ($query, array ($object_id));
2236 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2237 $order = 'odd';
2238 global $nextorder;
2239 echo $header;
2240 while ($row = $result->fetch (PDO::FETCH_NUM))
2241 {
2242 echo "<tr class=row_${order}><td>${row[0]}</td>";
2243 for ($i = 1; $i <= $extra; $i++)
2244 echo "<td>" . $row[$i] . "</td>";
2245 echo "</tr>\n";
2246 $order = $nextorder[$order];
2247 }
2248 echo "</table><br>\n";
2249 }
2250
2251 function renderRackspaceHistory ()
2252 {
2253 global $nextorder, $pageno, $tabno;
2254 $order = 'odd';
2255 $history = getRackspaceHistory();
2256 // Show the last operation by default.
2257 if (isset ($_REQUEST['op_id']))
2258 $op_id = $_REQUEST['op_id'];
2259 elseif (isset ($history[0]['mo_id']))
2260 $op_id = $history[0]['mo_id'];
2261 else $op_id = NULL;
2262
2263 $omid = NULL;
2264 $nmid = NULL;
2265 $object_id = 1;
2266 if ($op_id)
2267 list ($omid, $nmid) = getOperationMolecules ($op_id);
2268
2269 // Main layout starts.
2270 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2271
2272 // Left top portlet with old allocation.
2273 echo "<tr><td class=pcleft>";
2274 startPortlet ('Old allocation');
2275 if ($omid)
2276 {
2277 $oldMolecule = getMolecule ($omid);
2278 renderMolecule ($oldMolecule, $object_id);
2279 }
2280 else
2281 echo "nothing";
2282 finishPortlet();
2283
2284 echo '</td><td class=pcright>';
2285
2286 // Right top portlet with new allocation
2287 startPortlet ('New allocation');
2288 if ($nmid)
2289 {
2290 $newMolecule = getMolecule ($nmid);
2291 renderMolecule ($newMolecule, $object_id);
2292 }
2293 else
2294 echo "nothing";
2295 finishPortlet();
2296
2297 echo '</td></tr><tr><td colspan=2>';
2298
2299 // Bottom portlet with list
2300
2301 startPortlet ('Rackspace allocation history');
2302 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
2303 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
2304 foreach ($history as $row)
2305 {
2306 if ($row['mo_id'] == $op_id)
2307 $class = 'hl';
2308 else
2309 $class = "row_${order}";
2310 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
2311 echo "<td>${row['user_name']}</td><td>";
2312 renderCell (spotEntity ('object', $row['ro_id']));
2313 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
2314 $order = $nextorder[$order];
2315 }
2316 echo "</table>\n";
2317 finishPortlet();
2318
2319 echo '</td></tr></table>';
2320 }
2321
2322 function renderIPv4SpaceRecords ($tree, $baseurl, $target = 0, $knight, $level = 1)
2323 {
2324 $self = __FUNCTION__;
2325 static $vdomlist = NULL;
2326 if ($vdomlist == NULL and getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2327 $vdomlist = getVLANDomainOptions();
2328
2329 // scroll page to the highlighted item
2330 if ($target && isset ($_REQUEST['hl_net']))
2331 addAutoScrollScript ("net-$target");
2332
2333 foreach ($tree as $item)
2334 {
2335 if (getConfigVar ('IPV4_TREE_SHOW_USAGE') == 'yes')
2336 loadIPv4AddrList ($item); // necessary to compute router list and address counter
2337 else
2338 {
2339 $item['addrlist'] = array();
2340 $item['addrc'] = 0;
2341 }
2342 $used = $item['addrc'];
2343 $maxdirect = $item['addrt'];
2344 $maxtotal = binInvMaskFromDec ($item['mask']) + 1;
2345 if (isset ($item['id']))
2346 {
2347 $decor = array ('indent' => $level);
2348 if ($item['symbol'] == 'node-collapsed')
2349 $decor['symbolurl'] = "${baseurl}&eid=" . $item['id'];
2350 elseif ($item['symbol'] == 'node-expanded')
2351 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}" : '');
2352 echo "<tr valign=top>";
2353 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
2354 $decor['tdclass'] .= ' port_highlight';
2355 printIPNetInfoTDs ($item, $decor);
2356 echo "<td class=tdcenter>";
2357 if (getConfigVar ('IPV4_TREE_SHOW_USAGE') == 'yes')
2358 {
2359 renderProgressBar ($maxdirect ? $used/$maxdirect : 0);
2360 echo "<br><small>${used}/${maxdirect}" . ($maxdirect == $maxtotal ? '' : "/${maxtotal}") . '</small>';
2361 }
2362 else
2363 echo "<small>${maxdirect}</small>";
2364 echo "</td>";
2365 if (getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2366 {
2367 echo '<td class=tdleft>';
2368 if (count ($item['8021q']))
2369 {
2370 echo '<ul>';
2371 foreach ($item['8021q'] as $binding)
2372 {
2373 echo '<li><a href="' . makeHref (array ('page' => 'vlan', 'vlan_ck' => $binding['domain_id'] . '-' . $binding['vlan_id'])) . '">';
2374 // FIXME: would formatVLANName() do this?
2375 echo $binding['vlan_id'] . '@' . niftyString ($vdomlist[$binding['domain_id']], 15) . '</a></li>';
2376 }
2377 echo '</ul>';
2378 }
2379 echo '</td>';
2380 }
2381 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
2382 printRoutersTD (findRouters ($item['addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
2383 echo "</tr>";
2384 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
2385 $self ($item['kids'], $baseurl, $target, $knight, $level + 1);
2386 }
2387 else
2388 {
2389 echo "<tr valign=top>";
2390 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
2391 echo "<td class=tdcenter>";
2392 if (getConfigVar ('IPV4_TREE_SHOW_USAGE') == 'yes')
2393 {
2394 renderProgressBar ($used/$maxtotal, 'sparenetwork');
2395 echo "<br><small>${used}/${maxtotal}</small>";
2396 }
2397 else
2398 echo "<small>${maxtotal}</small>";
2399 if (getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2400 echo '</td><td>&nbsp;</td>';
2401 echo "</td><td>&nbsp;</td></tr>";
2402 }
2403 }
2404 }
2405
2406 function renderIPv6SpaceRecords ($tree, $baseurl, $target = 0, $knight, $level = 1)
2407 {
2408 $self = __FUNCTION__;
2409 static $vdomlist = NULL;
2410 if ($vdomlist == NULL and getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2411 $vdomlist = getVLANDomainOptions();
2412
2413 // scroll page to the highlighted item
2414 if ($target && isset ($_REQUEST['hl_net']))
2415 addAutoScrollScript ("net-$target");
2416
2417 foreach ($tree as $item)
2418 {
2419 if (getConfigVar ('IPV4_TREE_SHOW_USAGE') == 'yes')
2420 loadIPv6AddrList ($item); // necessary to compute router list and address counter
2421 else
2422 {
2423 $item['addrlist'] = array();
2424 $item['addrc'] = 0;
2425 }
2426 if (isset ($item['id']))
2427 {
2428 $decor = array ('indent' => $level);
2429 if ($item['symbol'] == 'node-collapsed')
2430 $decor['symbolurl'] = "${baseurl}&eid=" . $item['id'];
2431 elseif ($item['symbol'] == 'node-expanded')
2432 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}#net6id${item['parent_id']}" : '');
2433 echo "<tr valign=top>";
2434 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
2435 $decor['tdclass'] .= ' port_highlight';
2436 printIPNetInfoTDs ($item, $decor);
2437 echo "<td class=tdcenter>";
2438 // show net usage
2439 echo formatIPv6NetUsage ($item['addrc'], $item['mask']);
2440 echo "</td>";
2441 if (getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2442 {
2443 echo '<td class=tdleft>';
2444 if (count ($item['8021q']))
2445 {
2446 echo '<ul>';
2447 foreach ($item['8021q'] as $binding)
2448 {
2449 echo '<li><a href="' . makeHref (array ('page' => 'vlan', 'vlan_ck' => $binding['domain_id'] . '-' . $binding['vlan_id'])) . '">';
2450 // FIXME: would formatVLANName() do this?
2451 echo $binding['vlan_id'] . '@' . niftyString ($vdomlist[$binding['domain_id']], 15) . '</a></li>';
2452 }
2453 echo '</ul>';
2454 }
2455 echo '</td>';
2456 }
2457 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
2458 printRoutersTD (findRouters ($item['addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
2459 echo "</tr>";
2460 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
2461 $self ($item['kids'], $baseurl, $target, $knight, $level + 1);
2462 }
2463 /* do not display spare networks
2464 else
2465 { // display spare networks
2466 echo "<tr valign=top>";
2467 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
2468 echo "<td class=tdcenter>";
2469 echo formatIPv6NetUsage ($item['addrc'], $item['mask']);
2470 if (getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2471 echo '</td><td>&nbsp;</td>';
2472 echo "</td><td>&nbsp;</td></tr>";
2473 }*/
2474 }
2475 }
2476
2477 // if $used is NULL, returns only human-formatted mask.
2478 // Otherwise returns "$used in/of " . human-formatted-mask
2479 function formatIPv6NetUsage ($used, $mask)
2480 {
2481 $prefixes = array
2482 (
2483 0 => '',
2484 3 => 'k',
2485 6 => 'M',
2486 9 => 'G',
2487 12 => 'T',
2488 15 => 'P',
2489 18 => 'E',
2490 21 => 'Z',
2491 24 => 'Y',
2492 );
2493
2494 if ($mask <= 64)
2495 {
2496 $what = '/64 net';
2497 $preposition = 'in';
2498 $mask += 64;
2499 }
2500 else
2501 {
2502 $what = 'IP';
2503 $preposition = 'of';
2504 }
2505 $what .= (0 == $mask % 64 ? '' : 's');
2506 $addrc = isset ($used) ? "$used $preposition " : '';
2507
2508 $dec_order = intval ((128 - $mask) / 10) * 3;
2509 $mult = isset ($prefixes[$dec_order]) ? $prefixes[$dec_order] : '??';
2510
2511 $cnt = 1 << ((128 - $mask) % 10);
2512 if ($cnt == 1 && $mult == '')
2513 $cnt = 'single';
2514
2515 return "<small>${addrc}${cnt}${mult} ${what}</small>";
2516 }
2517
2518 function renderIPv4Space ()
2519 {
2520 global $pageno, $tabno;
2521 $cellfilter = getCellFilter();
2522 $netlist = listCells ('ipv4net');
2523 $allcount = count ($netlist);
2524 $netlist = filterCellList ($netlist, $cellfilter['expression']);
2525 array_walk ($netlist, 'amplifyCell');
2526
2527 $netcount = count ($netlist);
2528 // expand request can take either natural values or "ALL". Zero means no expanding.
2529 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
2530 $tree = prepareIPv4Tree ($netlist, $eid);
2531
2532 echo "<table border=0 class=objectview>\n";
2533 echo "<tr><td class=pcleft>";
2534 if (! renderEmptyResults($cellfilter, 'IPv4 nets', count($tree)))
2535 {
2536 startPortlet ("networks (${netcount})");
2537 echo '<h4>';
2538 if ($eid === 0)
2539 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') .
2540 " (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2541 $cellfilter['urlextra'] . "'>expand all</a>)";
2542 elseif ($eid === 'ALL')
2543 echo "expanding all (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2544 $cellfilter['urlextra'] . "'>auto-collapse</a>)";
2545 else
2546 {
2547 $netinfo = spotEntity ('ipv4net', $eid);
2548 echo "expanding ${netinfo['ip']}/${netinfo['mask']} (<a href='" .
2549 makeHref (array ('page' => $pageno, 'tab' => $tabno)) .
2550 $cellfilter['urlextra'] . "'>auto-collapse</a> / <a href='" .
2551 makeHref (array ('page' => $pageno, 'tab' => $tabno, 'eid' => 'ALL')) .
2552 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>)";
2553 }
2554 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2555 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2556 if (getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2557 echo '<th>VLAN</th>';
2558 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
2559 echo "<th>routed by</th>";
2560 echo "</tr>\n";
2561 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2562 renderIPv4SpaceRecords ($tree, $baseurl, $eid, $netcount == $allcount and getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
2563 echo "</table>\n";
2564 finishPortlet();
2565 }
2566
2567 echo '</td><td class=pcright>';
2568 renderCellFilterPortlet ($cellfilter, 'ipv4net', $netlist);
2569 echo "</td></tr></table>\n";
2570 }
2571
2572 function renderIPv6Space ()
2573 {
2574 global $pageno, $tabno;
2575 $cellfilter = getCellFilter();
2576 $netlist = listCells ('ipv6net');
2577 $allcount = count ($netlist);
2578 $netlist = filterCellList ($netlist, $cellfilter['expression']);
2579 array_walk ($netlist, 'amplifyCell');
2580
2581 $netcount = count ($netlist);
2582 // expand request can take either natural values or "ALL". Zero means no expanding.
2583 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
2584 $tree = prepareIPv6Tree ($netlist, $eid);
2585
2586 echo "<table border=0 class=objectview>\n";
2587 echo "<tr><td class=pcleft>";
2588 if (! renderEmptyResults($cellfilter, 'IPv6 nets', count($tree)))
2589 {
2590 startPortlet ("networks (${netcount})");
2591 echo '<h4>';
2592 if ($eid === 0)
2593 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') .
2594 " (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2595 $cellfilter['urlextra'] . "'>expand all</a>)";
2596 elseif ($eid === 'ALL')
2597 echo "expanding all (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2598 $cellfilter['urlextra'] . "'>auto-collapse</a>)";
2599 else
2600 {
2601 $netinfo = spotEntity ('ipv6net', $eid);
2602 echo "expanding ${netinfo['ip']}/${netinfo['mask']} (<a href='" .
2603 makeHref (array ('page' => $pageno, 'tab' => $tabno)) .
2604 $cellfilter['urlextra'] . "'>auto-collapse</a> / <a href='" .
2605 makeHref (array ('page' => $pageno, 'tab' => $tabno, 'eid' => 'ALL')) .
2606 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>)";
2607 }
2608 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2609 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2610 if (getConfigVar ('IPV4_TREE_SHOW_VLAN') == 'yes')
2611 echo '<th>VLAN</th>';
2612 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
2613 echo "<th>routed by</th>";
2614 echo "</tr>\n";
2615 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2616 renderIPv6SpaceRecords ($tree, $baseurl, $eid, $netcount == $allcount and getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
2617 echo "</table>\n";
2618 finishPortlet();
2619 }
2620
2621 echo '</td><td class=pcright>';
2622 renderCellFilterPortlet ($cellfilter, 'ipv6net', $netlist);
2623 echo "</td></tr></table>\n";
2624 }
2625
2626 function renderSLBDefConfig()
2627 {
2628 $defaults = getSLBDefaults ();
2629 startPortlet ('SLB default configs');
2630 echo '<table cellspacing=0 cellpadding=5 align=center>';
2631 printOpFormIntro ('save');
2632 echo '<tr><th class=tdright>VS config</th><td colspan=2><textarea tabindex=103 name=vsconfig rows=10 cols=80>' . htmlspecialchars($defaults['vs']) . '</textarea></td>';
2633 echo '<td rowspan=2>';
2634 printImageHREF ('SAVE', 'Save changes', TRUE);
2635 echo '</td></tr>';
2636 echo '<tr><th class=tdright>RS config</th><td colspan=2><textarea tabindex=104 name=rsconfig rows=10 cols=80>' . htmlspecialchars($defaults['rs']) . '</textarea></td></tr>';
2637 echo '</form></table>';
2638 finishPortlet();
2639 }
2640
2641 function renderIPv4SLB ()
2642 {
2643 global $page, $nextorder;
2644
2645 startPortlet ('SLB configuration');
2646 echo "<table border=0 width='100%'><tr>";
2647 foreach (array ('ipv4vslist', 'ipv4rsplist', 'rservers', 'lbs') as $pno)
2648 echo "<td><h3><a href='".makeHref(array('page'=>$pno))."'>" . $page[$pno]['title'] . "</a></h3></td>";
2649 echo '</tr></table>';
2650 finishPortlet();
2651
2652 $summary = getSLBSummary();
2653 startPortlet ('SLB tactical overview');
2654 // A single id-keyed array isn't used here to preserve existing
2655 // order of LBs returned by getSLBSummary()
2656 $lblist = array();
2657 $lbdname = array();
2658 foreach ($summary as $vipdata)
2659 foreach (array_keys ($vipdata['lblist']) as $lb_object_id)
2660 if (!in_array ($lb_object_id, $lblist))
2661 {
2662 $oi = spotEntity ('object', $lb_object_id);
2663 $lbdname[$lb_object_id] = $oi['dname'];
2664 $lblist[] = $lb_object_id;
2665 }
2666 if (!count ($summary))
2667 echo 'none configured';
2668 else
2669 {
2670 $order = 'odd';
2671 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2672 echo "<tr valign=top><td>&nbsp;</td>";
2673 foreach ($lblist as $lb_object_id)
2674 {
2675 #echo "<th><a href='".makeHref(array('page'=>'object', 'tab'=>'default', 'object_id'=>$lb_object_id))."'>" . $lbdname[$lb_object_id] . "</a></th>";
2676 echo '<td>';
2677 renderLBCell ($lb_object_id);
2678 echo '</td>';
2679 }
2680 echo "</tr>\n";
2681 foreach ($summary as $vsid => $vsdata)
2682 {
2683 echo "<tr class=row_${order}><td class=tdleft>";
2684 renderCell (spotEntity ('ipv4vs', $vsid));
2685 echo "</td>";
2686 foreach ($lblist as $lb_object_id)
2687 {
2688 echo '<td class=tdleft>';
2689 if (!isset ($vsdata['lblist'][$lb_object_id]))
2690 echo '&nbsp;';
2691 else
2692 {
2693 echo $vsdata['lblist'][$lb_object_id]['size'];
2694 // echo " (<a href='".makeHref(array('page'=>'ipv4rspool', 'pool_id'=>$vsdata['lblist'][$lb_object_id]['id'])). "'>";
2695 // echo $vsdata['lblist'][$lb_object_id]['name'] . '</a>)';
2696 }
2697 echo '</td>';
2698 }
2699 echo "</tr>\n";
2700 $order = $nextorder[$order];
2701 }
2702 echo "</table>\n";
2703 }
2704 finishPortlet ();
2705 }
2706
2707 function renderIPv4SpaceEditor ()
2708 {
2709 // IPv4 validator
2710 addJs ('js/live_validation.js');
2711 $regexp = addslashes ('^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$');
2712 addJs (<<<END
2713 $(document).ready(function () {
2714 document.add_new_range.range.setAttribute('match', '$regexp');
2715 Validate.init();
2716 });
2717 END
2718 , TRUE);
2719
2720 function printNewItemTR ()
2721 {
2722 startPortlet ('Add new');
2723 echo '<table border=0 cellpadding=10 align=center>';
2724 // This form requires a name, so JavaScript validator can find it.
2725 // No printOpFormIntro() hence
2726 echo "<form method=post name='add_new_range' action='".makeHrefProcess()."'>\n";
2727 echo "<input type=hidden name=op value=addIPv4Prefix>\n";
2728 // tags column
2729 echo '<tr><td rowspan=4><h3>assign tags</h3>';
2730 renderNewEntityTags ('ipv4net');
2731 echo '</td>';
2732 // inputs column
2733 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
2734 echo "<th class=tdright>prefix</th><td class=tdleft><input type=text name='range' size=18 class='live-validate' tabindex=1 value='${prefix_value}'></td>";
2735 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=2></td></tr>";
2736 echo "<tr><th class=tdright>connected network</th><td class=tdleft><input type=checkbox name='is_bcast' tabindex=3></td></tr>";
2737 echo "<tr><td colspan=2>";
2738 printImageHREF ('CREATE', 'Add a new network', TRUE, 4);
2739 echo '</td></tr>';
2740 echo "</form></table><br><br>\n";
2741 finishPortlet();
2742 }
2743
2744 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
2745 printNewItemTR();
2746 if (count ($addrspaceList = listCells ('ipv4net')))
2747 {
2748 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2749 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2750 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
2751 array_walk ($addrspaceList, 'amplifyCell');
2752 $tree = prepareIPv4Tree ($addrspaceList, 'ALL');
2753 // this is only called for having "trace" set
2754 treeFromList ($addrspaceList);
2755 foreach ($addrspaceList as $netinfo)
2756 {
2757 $netinfo = peekNode ($tree, $netinfo['trace'], $netinfo['id']);
2758 // now we have all subnets listed in netinfo
2759 loadIPv4AddrList ($netinfo);
2760 $used = $netinfo['addrc'];
2761 $maxdirect = $netinfo['addrt'];
2762 $maxtotal = binInvMaskFromDec ($netinfo['mask']) + 1;
2763 echo "<tr valign=top><td>";
2764 if (count ($netinfo['addrlist']) && getConfigVar ('IPV4_JAYWALK') == 'no')
2765 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2766 else
2767 {
2768 echo "<a href='".makeHrefProcess(array('op'=>'delIPv4Prefix', 'id'=>$netinfo['id']))."'>";
2769 printImageHREF ('destroy', 'Delete this prefix');
2770 echo "</a>";
2771 }
2772 echo '</td><td class=tdleft><a href="' . makeHref (array ('page' => 'ipv4net', 'id' => $netinfo['id'])) . '">';
2773 echo "${netinfo['ip']}/${netinfo['mask']}</a></td>";
2774 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2775 if (count ($netinfo['etags']))
2776 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2777 echo '</td><td>';
2778 renderProgressBar ($maxdirect ? $used/$maxdirect : 0);
2779 echo "<br><small>${used}/${maxdirect}" . ($maxdirect == $maxtotal ? '' : "/${maxtotal}") . '</small></td>';
2780 echo '</tr>';
2781 }
2782 echo "</table>";
2783 finishPortlet();
2784 }
2785 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
2786 printNewItemTR();
2787 }
2788
2789 function renderIPv6SpaceEditor ()
2790 {
2791 // IPv6 validator
2792 addJs ('js/live_validation.js');
2793 $regexp = addslashes ('^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$');
2794 addJs (<<<END
2795 $(document).ready(function () {
2796 document.add_new_range.range.setAttribute('match', '$regexp');
2797 Validate.init();
2798 });
2799 END
2800 , TRUE);
2801
2802 function printNewItemTR ()
2803 {
2804 startPortlet ('Add new');
2805 echo '<table border=0 cellpadding=10 align=center>';
2806 // This form requires a name, so JavaScript validator can find it.
2807 // No printOpFormIntro() hence
2808 echo "<form method=post name='add_new_range' action='".makeHrefProcess()."'>\n";
2809 echo "<input type=hidden name=op value=addIPv6Prefix>\n";
2810 // tags column
2811 echo '<tr><td rowspan=4><h3>assign tags</h3>';
2812 renderNewEntityTags ('ipv4net');
2813 echo '</td>';
2814 // inputs column
2815 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
2816 echo "<th class=tdright>prefix</th><td class=tdleft><input type=text name='range' size=36 class='live-validate' tabindex=1 value='${prefix_value}'></td>";
2817 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=2></td></tr>";
2818 echo "<tr><td colspan=2>";
2819 printImageHREF ('CREATE', 'Add a new network', TRUE, 4);
2820 echo '</td></tr>';
2821 echo "</form></table><br><br>\n";
2822 finishPortlet();
2823 }
2824
2825 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
2826 printNewItemTR();
2827 if (count ($addrspaceList = listCells ('ipv6net')))
2828 {
2829 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2830 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2831 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
2832 array_walk ($addrspaceList, 'amplifyCell');
2833 $tree = prepareIPv6Tree ($addrspaceList, 'ALL');
2834 // this is only called for having "trace" set
2835 treeFromList ($addrspaceList);
2836 foreach ($addrspaceList as $netinfo)
2837 {
2838 $netinfo = peekNode ($tree, $netinfo['trace'], $netinfo['id']);
2839 // now we have all subnets listed in netinfo
2840 loadIPv6AddrList ($netinfo);
2841 echo "<tr valign=top><td>";
2842 if (count ($netinfo['addrlist']) && getConfigVar ('IPV4_JAYWALK') == 'no')
2843 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2844 else
2845 {
2846 echo "<a href='".makeHrefProcess (array ('op' => 'delIPv6Prefix', 'id' => $netinfo['id'])) . "'>";
2847 printImageHREF ('destroy', 'Delete this prefix');
2848 echo "</a>";
2849 }
2850 echo '</td><td class=tdleft><a href="' . makeHref (array ('page' => 'ipv6net', 'id' => $netinfo['id'])) . '">';
2851 echo "${netinfo['ip']}/${netinfo['mask']}</a></td>";
2852 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2853 if (count ($netinfo['etags']))
2854 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2855 echo '</td><td>';
2856 echo formatIPv6NetUsage ($netinfo['addrc'], $netinfo['mask']);
2857 echo '</tr>';
2858 }
2859 echo "</table>";
2860 finishPortlet();
2861 }
2862 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
2863 printNewItemTR();
2864 }
2865
2866 function renderIPv4Network ($id)
2867 {
2868 global $pageno, $tabno, $aac2, $netmaskbylen, $wildcardbylen;
2869
2870 $range = spotEntity ('ipv4net', $id);
2871 amplifyCell ($range);
2872 loadIPv4AddrList ($range);
2873 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2874 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2875 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2876
2877 echo "<tr><td class=pcleft width='50%'>";
2878 startPortlet ('summary');
2879 $total = ($range['ip_bin'] | $range['mask_bin_inv']) - ($range['ip_bin'] & $range['mask_bin']) + 1;
2880 $used = count ($range['addrlist']);
2881 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
2882
2883 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
2884 renderProgressBar ($used/$total);
2885 echo "&nbsp;${used}/${total}</td></tr>\n";
2886
2887 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
2888 {
2889 // Build a backtrace from all parent networks.
2890 $clen = $range['mask'];