callScript: clear output variables before appending
[racktables-incomplete-works] / wwwroot / inc / interface-lib.php
CommitLineData
ca8aa8e9
DO
1<?php
2
cddbb9fd
DO
3# This file is a part of RackTables, a datacenter and server room management
4# framework. See accompanying file "COPYING" for the full copyright and
5# licensing information.
6
d3535346
DO
7define ('TAGNAME_REGEXP', '/^[\p{L}0-9]([. _~-]?[\p{L}0-9])*$/u');
8define ('AUTOTAGNAME_REGEXP', '/^\$[\p{L}0-9]([. _~-]?[\p{L}0-9])*$/u');
9
ca8aa8e9
DO
10// Let's have it here, so extensions can add their own images.
11$image = array();
ca8aa8e9
DO
12$image['rackspace']['path'] = 'pix/racks.png';
13$image['rackspace']['width'] = 218;
14$image['rackspace']['height'] = 200;
15$image['objects']['path'] = 'pix/server.png';
16$image['objects']['width'] = 218;
17$image['objects']['height'] = 200;
18$image['depot']['path'] = 'pix/server.png';
19$image['depot']['width'] = 218;
20$image['depot']['height'] = 200;
21$image['files']['path'] = 'pix/files.png';
22$image['files']['width'] = 218;
23$image['files']['height'] = 200;
24$image['ipv4space']['path'] = 'pix/addressspace.png';
25$image['ipv4space']['width'] = 218;
26$image['ipv4space']['height'] = 200;
27$image['ipv6space']['path'] = 'pix/addressspacev6.png';
28$image['ipv6space']['width'] = 218;
29$image['ipv6space']['height'] = 200;
30$image['ipv4slb']['path'] = 'pix/slb.png';
31$image['ipv4slb']['width'] = 218;
32$image['ipv4slb']['height'] = 200;
33$image['config']['path'] = 'pix/configuration.png';
34$image['config']['width'] = 218;
35$image['config']['height'] = 200;
36$image['reports']['path'] = 'pix/report.png';
37$image['reports']['width'] = 218;
38$image['reports']['height'] = 200;
39$image['8021q']['path'] = 'pix/8021q.png';
40$image['8021q']['width'] = 218;
41$image['8021q']['height'] = 200;
42$image['objectlog']['path'] = 'pix/crystal-mimetypes-shellscript-218x200.png';
43$image['objectlog']['width'] = 218;
44$image['objectlog']['height'] = 200;
45$image['virtual']['path'] = 'pix/virtualresources.png';
46$image['virtual']['width'] = 218;
47$image['virtual']['height'] = 200;
48$image['download']['path'] = 'pix/download.png';
49$image['download']['width'] = 16;
50$image['download']['height'] = 16;
51$image['DOWNLOAD']['path'] = 'pix/download-big.png';
52$image['DOWNLOAD']['width'] = 32;
53$image['DOWNLOAD']['height'] = 32;
54$image['plug']['path'] = 'pix/tango-network-wired.png';
55$image['plug']['width'] = 16;
56$image['plug']['height'] = 16;
57$image['cut']['path'] = 'pix/tango-edit-cut-16x16.png';
58$image['cut']['width'] = 16;
59$image['cut']['height'] = 16;
60$image['Cut']['path'] = 'pix/tango-edit-cut-22x22.png';
61$image['Cut']['width'] = 22;
62$image['Cut']['height'] = 22;
75a01117
DO
63$image['Cut gray']['path'] = 'pix/tango-edit-cut-22x22-gray.png';
64$image['Cut gray']['width'] = 22;
65$image['Cut gray']['height'] = 22;
ca8aa8e9
DO
66$image['CUT']['path'] = 'pix/tango-edit-cut-32x32.png';
67$image['CUT']['width'] = 32;
68$image['CUT']['height'] = 32;
69$image['add']['path'] = 'pix/tango-list-add.png';
70$image['add']['width'] = 16;
71$image['add']['height'] = 16;
72$image['ADD']['path'] = 'pix/tango-list-add-big.png';
73$image['ADD']['width'] = 32;
74$image['ADD']['height'] = 32;
75$image['delete']['path'] = 'pix/tango-list-remove.png';
76$image['delete']['width'] = 16;
77$image['delete']['height'] = 16;
78$image['DELETE']['path'] = 'pix/tango-list-remove-32x32.png';
79$image['DELETE']['width'] = 32;
80$image['DELETE']['height'] = 32;
81$image['destroy']['path'] = 'pix/tango-user-trash-16x16.png';
82$image['destroy']['width'] = 16;
83$image['destroy']['height'] = 16;
84$image['nodestroy']['path'] = 'pix/tango-user-trash-16x16-gray.png';
85$image['nodestroy']['width'] = 16;
86$image['nodestroy']['height'] = 16;
87$image['NODESTROY']['path'] = 'pix/tango-user-trash-32x32-gray.png';
88$image['NODESTROY']['width'] = 32;
89$image['NODESTROY']['height'] = 32;
90$image['DESTROY']['path'] = 'pix/tango-user-trash-32x32.png';
91$image['DESTROY']['width'] = 32;
92$image['DESTROY']['height'] = 32;
93$image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
94$image['nodelete']['width'] = 16;
95$image['nodelete']['height'] = 16;
96$image['inservice']['path'] = 'pix/tango-emblem-system.png';
97$image['inservice']['width'] = 16;
98$image['inservice']['height'] = 16;
99$image['notinservice']['path'] = 'pix/tango-dialog-error.png';
100$image['notinservice']['width'] = 16;
101$image['notinservice']['height'] = 16;
102$image['find']['path'] = 'pix/tango-system-search.png';
103$image['find']['width'] = 16;
104$image['find']['height'] = 16;
105$image['next']['path'] = 'pix/tango-go-next.png';
106$image['next']['width'] = 32;
107$image['next']['height'] = 32;
108$image['prev']['path'] = 'pix/tango-go-previous.png';
109$image['prev']['width'] = 32;
110$image['prev']['height'] = 32;
111$image['COMMIT']['path'] = 'pix/tango-go-prev-next-32x32.png';
112$image['COMMIT']['width'] = 32;
113$image['COMMIT']['height'] = 32;
114$image['COMMIT gray']['path'] = 'pix/tango-go-prev-next-gray-32x32.png';
115$image['COMMIT gray']['width'] = 32;
116$image['COMMIT gray']['height'] = 32;
117$image['RECALC']['path'] = 'pix/tango-view-refresh-32x32.png';
118$image['RECALC']['width'] = 32;
119$image['RECALC']['height'] = 32;
120$image['clear']['path'] = 'pix/tango-edit-clear.png';
121$image['clear']['width'] = 16;
122$image['clear']['height'] = 16;
123$image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
124$image['CLEAR']['width'] = 32;
125$image['CLEAR']['height'] = 32;
126$image['CLEAR gray']['path'] = 'pix/tango-edit-clear-gray-32x32.png';
127$image['CLEAR gray']['width'] = 32;
128$image['CLEAR gray']['height'] = 32;
129$image['save']['path'] = 'pix/tango-document-save-16x16.png';
130$image['save']['width'] = 16;
131$image['save']['height'] = 16;
132$image['SAVE']['path'] = 'pix/tango-document-save-32x32.png';
133$image['SAVE']['width'] = 32;
134$image['SAVE']['height'] = 32;
135$image['NOSAVE']['path'] = 'pix/tango-document-save-32x32-gray.png';
136$image['NOSAVE']['width'] = 32;
137$image['NOSAVE']['height'] = 32;
138$image['create']['path'] = 'pix/tango-document-new.png';
139$image['create']['width'] = 16;
140$image['create']['height'] = 16;
141$image['CREATE']['path'] = 'pix/tango-document-new-big.png';
142$image['CREATE']['width'] = 32;
143$image['CREATE']['height'] = 32;
144$image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
145$image['DENIED']['width'] = 32;
146$image['DENIED']['height'] = 32;
147$image['node-collapsed']['path'] = 'pix/node-collapsed.png';
148$image['node-collapsed']['width'] = 16;
149$image['node-collapsed']['height'] = 16;
150$image['node-expanded']['path'] = 'pix/node-expanded.png';
151$image['node-expanded']['width'] = 16;
152$image['node-expanded']['height'] = 16;
153$image['node-expanded-static']['path'] = 'pix/node-expanded-static.png';
154$image['node-expanded-static']['width'] = 16;
155$image['node-expanded-static']['height'] = 16;
156$image['dragons']['path'] = 'pix/mitsudragon.png';
157$image['dragons']['width'] = 195;
158$image['dragons']['height'] = 33;
159$image['LB']['path'] = 'pix/loadbalancer.png';
160$image['LB']['width'] = 32;
161$image['LB']['height'] = 32;
162$image['RS pool']['path'] = 'pix/serverpool.png';
163$image['RS pool']['width'] = 48;
164$image['RS pool']['height'] = 16;
165$image['VS']['path'] = 'pix/servicesign.png';
166$image['VS']['width'] = 39;
167$image['VS']['height'] = 62;
168$image['router']['path'] = 'pix/router.png';
169$image['router']['width'] = 32;
170$image['router']['height'] = 32;
171$image['object']['path'] = 'pix/bracket-16x16.png';
172$image['object']['width'] = 16;
173$image['object']['height'] = 16;
174$image['OBJECT']['path'] = 'pix/bracket-32x32.png';
175$image['OBJECT']['width'] = 32;
176$image['OBJECT']['height'] = 32;
177$image['attach']['path'] = 'pix/tango-mail-attachment-16x16.png';
178$image['attach']['width'] = 16;
179$image['attach']['height'] = 16;
180$image['Attach']['path'] = 'pix/tango-mail-attachment-22x22.png';
181$image['Attach']['width'] = 22;
182$image['Attach']['height'] = 22;
183$image['ATTACH']['path'] = 'pix/tango-mail-attachment-32x32.png';
184$image['ATTACH']['width'] = 32;
185$image['ATTACH']['height'] = 32;
186$image['favorite']['path'] = 'pix/tango-emblem-favorite.png';
187$image['favorite']['width'] = 16;
188$image['favorite']['height'] = 16;
189$image['computer']['path'] = 'pix/tango-computer.png';
190$image['computer']['width'] = 16;
191$image['computer']['height'] = 16;
192$image['empty file']['path'] = 'pix/crystal-file-empty-32x32.png';
193$image['empty file']['width'] = 32;
194$image['empty file']['height'] = 32;
195$image['text file']['path'] = 'pix/crystal-file-text-32x32.png';
196$image['text file']['width'] = 32;
197$image['text file']['height'] = 32;
198$image['image file']['path'] = 'pix/crystal-file-image-32x32.png';
199$image['image file']['width'] = 32;
200$image['image file']['height'] = 32;
201$image['text']['path'] = 'pix/tango-text-x-generic-16x16.png';
202$image['text']['width'] = 16;
203$image['text']['height'] = 16;
204$image['NET']['path'] = 'pix/crystal-network_local-32x32.png';
205$image['NET']['width'] = 32;
206$image['NET']['height'] = 32;
207$image['net']['path'] = 'pix/crystal-network_local-16x16.png';
208$image['net']['width'] = 16;
209$image['net']['height'] = 16;
210$image['USER']['path'] = 'pix/crystal-edit-user-32x32.png';
211$image['USER']['width'] = 32;
212$image['USER']['height'] = 32;
213$image['setfilter']['path'] = 'pix/pgadmin3-viewfiltereddata.png';
214$image['setfilter']['width'] = 32;
215$image['setfilter']['height'] = 32;
216$image['setfilter gray']['path'] = 'pix/pgadmin3-viewfiltereddata-grayscale.png';
217$image['setfilter gray']['width'] = 32;
218$image['setfilter gray']['height'] = 32;
219$image['resetfilter']['path'] = 'pix/pgadmin3-viewdata.png';
220$image['resetfilter']['width'] = 32;
221$image['resetfilter']['height'] = 32;
222$image['resetfilter gray']['path'] = 'pix/pgadmin3-viewdata-grayscale.png';
223$image['resetfilter gray']['width'] = 32;
224$image['resetfilter gray']['height'] = 32;
225$image['knight']['path'] = 'pix/smiley_knight.png';
226$image['knight']['width'] = 72;
227$image['knight']['height'] = 33;
228$image['Zoom']['path'] = 'pix/tango-system-search-22x22.png';
229$image['Zoom']['width'] = 22;
230$image['Zoom']['height'] = 22;
231$image['Zooming']['path'] = 'pix/tango-view-fullscreen-22x22.png';
232$image['Zooming']['width'] = 22;
233$image['Zooming']['height'] = 22;
234$image['UNLOCK']['path'] = 'pix/crystal-actions-unlock-32x32.png';
235$image['UNLOCK']['width'] = 32;
236$image['UNLOCK']['height'] = 32;
237$image['CLOCK']['path'] = 'pix/tango-appointment-32x32.png';
238$image['CLOCK']['width'] = 32;
239$image['CLOCK']['height'] = 32;
240$image['DQUEUE done']['path'] = 'pix/crystal-ok-32x32.png';
241$image['DQUEUE done']['width'] = 32;
242$image['DQUEUE done']['height'] = 32;
243$image['DQUEUE sync_aging']['path'] = 'pix/tango-appointment-32x32.png';
244$image['DQUEUE sync_aging']['width'] = 32;
245$image['DQUEUE sync_aging']['height'] = 32;
246$image['DQUEUE resync_aging']['path'] = 'pix/tango-appointment-32x32.png';
247$image['DQUEUE resync_aging']['width'] = 32;
248$image['DQUEUE resync_aging']['height'] = 32;
249$image['DQUEUE sync_ready']['path'] = 'pix/tango-emblem-system-32x32.png';
250$image['DQUEUE sync_ready']['width'] = 32;
251$image['DQUEUE sync_ready']['height'] = 32;
252$image['DQUEUE resync_ready']['path'] = 'pix/tango-emblem-important-32x32.png';
253$image['DQUEUE resync_ready']['width'] = 32;
254$image['DQUEUE resync_ready']['height'] = 32;
255$image['DQUEUE failed']['path'] = 'pix/tango-emblem-unreadable-32x32.png';
256$image['DQUEUE failed']['width'] = 32;
257$image['DQUEUE failed']['height'] = 32;
258$image['DQUEUE disabled']['path'] = 'pix/tango-emblem-readonly-32x32.png';
259$image['DQUEUE disabled']['width'] = 32;
260$image['DQUEUE disabled']['height'] = 32;
d60c7760
AA
261$image['copy']['path'] = 'pix/tango-edit-copy-16x16.png';
262$image['copy']['width'] = 16;
263$image['copy']['height'] = 16;
ca8aa8e9
DO
264$image['COPY']['path'] = 'pix/tango-edit-copy-32x32.png';
265$image['COPY']['width'] = 32;
266$image['COPY']['height'] = 32;
267$image['html']['path'] = 'pix/tango-text-html.png';
268$image['html']['width'] = 16;
269$image['html']['height'] = 16;
270
646272be
AA
271$page_by_realm = array();
272$page_by_realm['object'] = 'depot';
273$page_by_realm['rack'] = 'rackspace';
274$page_by_realm['ipv4net'] = 'ipv4space';
275$page_by_realm['ipv6net'] = 'ipv6space';
e2f674be
AA
276$page_by_realm['ipv4vs'] = 'ipv4slb';
277$page_by_realm['ipv4rspool'] = 'ipv4slb';
646272be
AA
278$page_by_realm['file'] = 'files';
279$page_by_realm['user'] = 'userlist';
280
ca8aa8e9
DO
281function printSelect ($optionList, $select_attrs = array(), $selected_id = NULL)
282{
283 echo getSelect ($optionList, $select_attrs, $selected_id);
284}
285
286// Input array keys are OPTION VALUEs and input array values are OPTION text.
c4ad9ac0 287function getSelect ($optionList, $select_attrs = array(), $selected_id = NULL, $treat_single_special = TRUE)
ca8aa8e9
DO
288{
289 $ret = '';
290 if (!array_key_exists ('name', $select_attrs))
291 return '';
292 // handle two corner cases in a specific way
293 if (count ($optionList) == 0)
294 return '(none)';
c4ad9ac0 295 if (count ($optionList) == 1 && $treat_single_special)
ca8aa8e9
DO
296 {
297 foreach ($optionList as $key => $value) { break; }
298 return "<input type=hidden name=${select_attrs['name']} id=${select_attrs['name']} value=${key}>" . $value;
299 }
300 if (!array_key_exists ('id', $select_attrs))
301 $select_attrs['id'] = $select_attrs['name'];
302 $ret .= '<select';
303 foreach ($select_attrs as $attr_name => $attr_value)
304 $ret .= " ${attr_name}=${attr_value}";
305 $ret .= '>';
306 foreach ($optionList as $dict_key => $dict_value)
307 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>";
308 $ret .= '</select>';
309 return $ret;
310}
311
312function printNiftySelect ($groupList, $select_attrs = array(), $selected_id = NULL, $autocomplete = false)
313{
314 echo getNiftySelect ($groupList, $select_attrs, $selected_id);
315}
316
317// Input is a cooked list of OPTGROUPs, each with own sub-list of OPTIONs in the same
318// format as printSelect() expects.
7232ef01
AD
319// If tree is true, hierarchical drop-boxes are used, otherwise optgroups are used.
320function getNiftySelect ($groupList, $select_attrs, $selected_id = NULL, $tree = false)
ca8aa8e9
DO
321{
322 // special treatment for ungrouped data
323 if (count ($groupList) == 1 and isset ($groupList['other']))
324 return getSelect ($groupList['other'], $select_attrs, $selected_id);
325 if (!array_key_exists ('name', $select_attrs))
326 return '';
327 if (!array_key_exists ('id', $select_attrs))
328 $select_attrs['id'] = $select_attrs['name'];
7232ef01 329 if ($tree)
ca8aa8e9 330 {
2f06f6be
DO
331 # it is safe to call many times for the same file
332 addJS ('js/jquery.optionTree.js');
7232ef01
AD
333 $ret = "<input type=hidden name=${select_attrs['name']}>\n";
334 $ret .= "<script type='text/javascript'>\n";
335 $ret .= "\$(function() {\n";
336 $ret .= " var option_tree = {\n";
337 foreach ($groupList as $groupname => $groupdata)
338 {
339 $ret .= " '${groupname}': {";
340 foreach ($groupdata as $dict_key => $dict_value)
341 $ret .= "\"${dict_value}\":'${dict_key}', ";
342 $ret .= "},\n";
343 }
344 $ret .= " };\n";
30dce055 345 $ret .= " var options = {empty_value: '', choose: 'select...'};\n";
7232ef01
AD
346 $ret .= " \$('input[name=${select_attrs['name']}]').optionTree(option_tree, options);\n";
347 $ret .= "});\n";
348 $ret .= "</script>\n";
349 }
350 else
351 {
352 $ret = '<select';
353 foreach ($select_attrs as $attr_name => $attr_value)
354 $ret .= " ${attr_name}=${attr_value}";
355 $ret .= ">\n";
356 foreach ($groupList as $groupname => $groupdata)
357 {
358 $ret .= "<optgroup label='${groupname}'>\n";
359 foreach ($groupdata as $dict_key => $dict_value)
360 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>\n";
361 $ret .= "</optgroup>\n";
362 }
363 $ret .= "</select>\n";
ca8aa8e9 364 }
ca8aa8e9
DO
365 return $ret;
366}
367
16d86b28
DO
368function getOptionTree ($tree_name, $tree_options, $tree_config = array())
369{
77b5137a
DO
370 function serializeJSArray ($options)
371 {
372 $tmp = array();
373 foreach ($options as $key => $value)
374 $tmp[] = "'${key}': \"${value}\"";
375 return '{' . implode (', ', $tmp) . "}\n";
376 }
377 function serializeJSTree ($tree_options)
16d86b28
DO
378 {
379 $self = __FUNCTION__;
380 $tmp = array();
77b5137a
DO
381 # Leaves on the PHP tree are stored "value => label" way,
382 # non-leaves are stored "label => array" way, and the JS
383 # tree is always built "label => value" or "label => array"
384 # way, hence a structure transform is required.
385 foreach ($tree_options as $key => $value)
386 $tmp[] = is_array ($value) ?
1b655fac
AA
387 '"' . str_replace ('"', '\"', $key) . '": ' . $self ($value) :
388 '"' . str_replace ('"', '\"', $value) . '": "' . str_replace ('"', '\"', $key) . '"';
16d86b28
DO
389 return '{' . implode (', ', $tmp) . "}\n";
390 }
391
392 $default_config = array
393 (
394 'choose' => 'select...',
395 'empty_value' => '',
396 );
397 foreach ($tree_config as $cfgoption_name => $cfgoption_value)
398 $default_config[$cfgoption_name] = $cfgoption_value;
399 # it is safe to call many times for the same file
400 addJS ('js/jquery.optionTree.js');
401 $ret = "<input type=hidden name=${tree_name}>\n";
402 $ret .= "<script type='text/javascript'>\n";
403 $ret .= "\$(function() {\n";
77b5137a 404 $ret .= " var option_tree = " . serializeJSTree ($tree_options) . ";\n";
16d86b28
DO
405 $ret .= " var options = " . serializeJSArray ($default_config) . ";\n";
406 $ret .= " \$('input[name=${tree_name}]').optionTree(option_tree, options);\n";
407 $ret .= "});\n";
408 $ret .= "</script>\n";
409 return $ret;
410}
411
ca8aa8e9
DO
412function printImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
413{
414 echo getImageHREF ($tag, $title, $do_input, $tabindex);
415}
416
417// this would be better called mkIMG(), make "IMG" HTML element
418function getImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
419{
420 global $image;
421 if (!isset ($image[$tag]))
422 $tag = 'error';
423 $img = $image[$tag];
19f22ad8 424 $img['path'] = '?module=chrome&uri=' . $img['path'];
ca8aa8e9
DO
425 if ($do_input == TRUE)
426 return
427 "<input type=image name=submit class=icon " .
428 "src='${img['path']}' " .
429 "border=0 " .
430 ($tabindex ? "tabindex=${tabindex}" : '') .
431 (!strlen ($title) ? '' : " title='${title}'") . // JT: Add title to input hrefs too
432 ">";
433 else
434 return
435 "<img " .
436 "src='${img['path']}' " .
437 "width=${img['width']} " .
438 "height=${img['height']} " .
439 "border=0 " .
440 (!strlen ($title) ? '' : "title='${title}'") .
441 ">";
442}
443
967e3845
DO
444function dos2unix ($text)
445{
446 return str_replace ("\r\n", "\n", $text);
447}
448
449function escapeString ($value, $do_db_escape = FALSE)
450{
451 $ret = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
452 if ($do_db_escape)
453 {
454 global $dbxlink;
455 $ret = substr ($dbxlink->quote ($ret), 1, -1);
456 }
457 return $ret;
458}
459
460function transformRequestData()
461{
462 global $sic;
463 // Magic quotes feature is deprecated, but just in case the local system
464 // still has it activated, reverse its effect.
dbd20c7e
AA
465 $do_magic_quotes = (function_exists ('get_magic_quotes_gpc') and get_magic_quotes_gpc());
466 $seen_keys = array();
467
967e3845
DO
468 // Escape any globals before we ever try to use them, but keep a copy of originals.
469 $sic = array();
4675424f
AA
470 // walk through merged GET and POST instead of REQUEST array because it
471 // can contain cookies with data which could not be decoded from UTF-8
4675424f 472 foreach (array_merge($_GET, $_POST) as $key => $value)
967e3845 473 {
5a7dc9e7
AA
474 if (is_array ($value))
475 $_REQUEST[$key] = $value;
476 else
477 {
478 $value = dos2unix ($value);
479 if ($do_magic_quotes)
480 $value = stripslashes ($value);
481 $_REQUEST[$key] = escapeString ($value);
482 }
483 $sic[$key] = $value;
dbd20c7e 484 $seen_keys[$key] = 1;
967e3845
DO
485 }
486
dbd20c7e
AA
487 // delete cookie information from the $_REQUEST array
488 foreach (array_keys ($_REQUEST) as $key)
489 if (! isset ($seen_keys[$key]))
490 unset ($_REQUEST[$key]);
491
967e3845
DO
492 if (isset ($_SERVER['PHP_AUTH_USER']))
493 $_SERVER['PHP_AUTH_USER'] = escapeString ($_SERVER['PHP_AUTH_USER']);
494 if (isset ($_SERVER['REMOTE_USER']))
495 $_SERVER['REMOTE_USER'] = escapeString ($_SERVER['REMOTE_USER']);
496}
497
ca6698d8
AA
498// JS scripts should be included through this function.
499// They automatically appear in the <head> of your page.
500// $data is a JS filename, or JS code w/o tags around, if $inline = TRUE
501// Scripts are included in the order of adding within the same group, and groups are sorted alphabetically.
502function addJS ($data, $inline = FALSE, $group = 'default')
503{
504 static $javascript = array();
505 static $seen_filenames = array();
506
507 if (! isset ($data))
508 {
509 ksort ($javascript);
510 return $javascript;
511 }
512 // Add jquery.js and racktables.js the first time a Javascript file is added.
513 if (empty($javascript))
514 {
515 $javascript = array
516 (
517 'a_core' => array
518 (
519 array('type' => 'file', 'script' => 'js/jquery-1.4.4.min.js'),
520 array('type' => 'file', 'script' => 'js/racktables.js'),
521 ),
522 );
523
524 // initialize core js filelist
525 foreach ($javascript as $group_name => $group_array)
526 foreach ($group_array as $item)
527 if ($item['type'] == 'file')
528 $seen_filenames[$item['script']] = 1;
529 }
530
531 if ($inline)
532 $javascript[$group][] = array
533 (
534 'type' => 'inline',
535 'script' => $data,
536 );
537 elseif (! isset ($seen_filenames[$data]))
538 {
539 $javascript[$group][] = array
540 (
541 'type' => 'file',
542 'script' => $data,
543 );
544 $seen_filenames[$data] = 1;
545 }
546}
547
548// CSS styles should be included through this function.
549// They automatically appear in the <head> of your page.
550// $data is a CSS filename, or CSS code w/o tags around, if $inline = TRUE
551// Styles are included in the order of adding.
552function addCSS ($data, $inline = FALSE)
553{
554 static $styles = array();
555 static $seen_filenames = array();
556
557 if (! isset ($data))
558 return $styles;
559 if ($inline)
560 $styles[] = array
561 (
562 'type' => 'inline',
563 'style' => $data,
564 );
565 elseif (! isset ($seen_filenames[$data]))
566 {
567 $styles[] = array
568 (
569 'type' => 'file',
570 'style' => $data,
571 );
572 $seen_filenames[$data] = 1;
573 }
574}
575
4318ced5
AA
576function getRenderedIPNetCapacity ($range)
577{
578 switch (strlen ($range['ip_bin']))
579 {
580 case 4: return getRenderedIPv4NetCapacity ($range);
581 case 16: return getRenderedIPv6NetCapacity ($range);
582 default: throw new InvalidArgException ('range["ip_bin"]', $range['ip_bin'], "Invalid binary IP");
583 }
584}
585
586function getRenderedIPv4NetCapacity ($range)
587{
588 $class = 'net-usage';
589 if (isset ($range['addrc']))
590 {
591 // full mode
f59e175c 592 // $a is "aquamarine zone", $b is "gray zone"
4318ced5 593 $total = ip4_range_size ($range);
f59e175c
AA
594 $a_total = getIPv4OwnRangeSize ($range);
595 $a_used = $range['own_addrc'];
596 $b_total = $total - $a_total;
597 $b_used = $range['addrc'] - $a_used;
4318ced5
AA
598
599 // generate link to progress bar image
600 $width = 100;
601 if ($total > 0)
602 {
603 $px_a = round ($a_total / $total * $width);
604 $px1 = round ($a_used / $total * $width);
605 $px2 = $px_a - $px1;
606 $px3 = round ($b_used / $total * $width);
607 if ($px3 + $px1 + $px2 > $width)
608 $px3 = $width - $px1 - $px2;
609 }
610 else
611 $px1 = $px2 = $px3 = 0;
612
4318ced5
AA
613 $title_items = array();
614 $title2_items = array();
615 if ($a_total)
616 {
617 $title_items[] = "$a_used / $a_total";
618 $title2_items[] = sprintf ("%d%% used", $a_used / $a_total * 100);
619 }
620 if ($b_total)
621 {
622 $title_items[] = ($b_used ? "$b_used / " : "") . $b_total;
623 $title2_items[] = sprintf ("%d%% not allocated", $b_total / $total * 100);
624 }
625 $title = implode (', ', $title_items);
626 $title2 = implode (', ', $title2_items);
627 $text = "<img width='$width' height=10 border=0 title='$title2' src='?module=progressbar4&px1=$px1&px2=$px2&px3=$px3'>" .
628 " <small class='title'>$title</small>";
629 }
630 else
631 {
632 // fast mode
633 $class .= ' pending';
634 addJS ('js/net-usage.js');
635
636 $free_text = '';
637 if (isset ($range['kidc']) and $range['kidc'] > 0)
638 {
639 $free_masks = array_keys ($range['spare_ranges']);
640 sort ($free_masks, SORT_NUMERIC);
641 if ($mask = array_shift ($free_masks))
642 {
643 $cnt = count ($range['spare_ranges'][$mask]);
644 $free_text = ', ' . ($cnt > 1 ? "<small>${cnt}x</small>" : "") . "/$mask free";
645 }
646 }
647 $text = ip4_range_size ($range) . $free_text;
648 }
649
650 $div_id = $range['ip'] . '/' . $range['mask'];
651
652 return "<div class=\"$class\" id=\"$div_id\">" . $text . "</div>";
653}
654
655function getRenderedIPv6NetCapacity ($range)
656{
657 $div_id = $range['ip'] . '/' . $range['mask'];
658 $class = 'net-usage';
659 if (isset ($range['addrc']))
660 $used = $range['addrc'];
661 else
662 {
663 $used = NULL;
664 $class .= ' pending';
665 addJS ('js/net-usage.js');
666 }
667
668 static $prefixes = array
669 (
670 0 => '',
671 3 => 'k',
672 6 => 'M',
673 9 => 'G',
674 12 => 'T',
675 15 => 'P',
676 18 => 'E',
677 21 => 'Z',
678 24 => 'Y',
679 );
680
681 if ($range['mask'] <= 64)
682 {
683 $what = 'net';
684 $preposition = 'in';
685 $range['mask'] += 64;
686 }
687 else
688 {
689 $what = 'IP';
690 $preposition = 'of';
691 }
692 $what .= (0 == $range['mask'] % 64 ? '' : 's');
693 $addrc = isset ($used) ? "$used $preposition " : '';
694
695 $dec_order = intval ((128 - $range['mask']) / 10) * 3;
696 $mult = isset ($prefixes[$dec_order]) ? $prefixes[$dec_order] : '??';
697
698 $cnt = 1 << ((128 - $range['mask']) % 10);
699 if ($cnt == 1 && $mult == '')
700 $cnt = '1';
701
702 return "<div class=\"$class\" id=\"$div_id\">" . "{$addrc}${cnt}${mult} ${what}" . "</div>";
703}
704
ca6698d8
AA
705// print part of HTML HEAD block
706function printPageHeaders ()
707{
708 global $pageheaders;
709 ksort ($pageheaders);
710 foreach ($pageheaders as $s)
711 echo $s . "\n";
712
713 // add CSS styles
714 foreach (addCSS (NULL) as $item)
715 if ($item['type'] == 'inline')
716 echo '<style type="text/css">' . "\n" . trim ($item['style'], "\r\n") . "\n</style>\n";
717 elseif ($item['type'] == 'file')
718 echo "<link rel=stylesheet type='text/css' href='?module=chrome&uri=${item['style']}' />\n";
719
720 // add JS scripts
721 foreach (addJS (NULL) as $group_name => $js_list)
722 foreach ($js_list as $item)
723 if ($item['type'] == 'inline')
724 echo '<script type="text/javascript">' . "\n" . trim ($item['script'], "\r\n") . "\n</script>\n";
725 elseif ($item['type'] == 'file')
726 echo "<script type='text/javascript' src='?module=chrome&uri=${item['script']}'></script>\n";
727}
728
d3535346
DO
729function validTagName ($s, $allow_autotag = FALSE)
730{
731 if (1 == preg_match (TAGNAME_REGEXP, $s))
732 return TRUE;
733 if ($allow_autotag and 1 == preg_match (AUTOTAGNAME_REGEXP, $s))
734 return TRUE;
735 return FALSE;
736}
737
0dc380e9
AA
738function cmpTags ($a, $b)
739{
740 global $taglist;
741 if (isset ($a['id']) && isset ($b['id']))
742 {
c09cdace
AA
743 $a_root = array_first ($taglist[$a['id']]['trace']);
744 $b_root = array_first ($taglist[$b['id']]['trace']);
745 if ($a_root < $b_root)
746 return -1;
747 elseif ($a_root > $b_root)
748 return 1;
0dc380e9
AA
749 }
750 elseif (isset ($a['id']))
751 return -1;
752 elseif (isset ($b['id']))
753 return 1;
c09cdace
AA
754
755 return strcmp ($a['tag'], $b['tag']);
0dc380e9
AA
756}
757
221327e3
DO
758function serializeTags ($chain, $baseurl = '')
759{
760 $tmp = array();
0dc380e9 761 usort ($chain, 'cmpTags');
221327e3 762 foreach ($chain as $taginfo)
30bb83bd 763 {
d3ee17b7
AA
764 if ($baseurl == '')
765 $tmp[] = $taginfo['tag'];
30bb83bd 766 else
d3ee17b7 767 {
30bb83bd 768 $title = '';
d3ee17b7
AA
769 if (isset ($taginfo['user']) and isset ($taginfo['time']))
770 $title = 'title="' . htmlspecialchars ($taginfo['user'] . ', ' . formatAge ($taginfo['time']), ENT_QUOTES) . '"';
771 $tmp[] = "<a $title href='${baseurl}cft[]=${taginfo['id']}'>" . $taginfo['tag'] . "</a>";
772 }
30bb83bd 773 }
221327e3
DO
774 return implode (', ', $tmp);
775}
776
2030a7f2
AA
777function startPortlet ($title = '')
778{
779 echo "<div class=portlet><h2>${title}</h2>";
780}
781
782function finishPortlet ()
783{
784 echo "</div>\n";
785}
786
a1d72d2e
AA
787function getPageName ($page_code)
788{
789 global $page;
790 $title = isset ($page[$page_code]['title']) ? $page[$page_code]['title'] : dynamic_title_decoder ($page_code);
791 if (is_array ($title))
792 $title = $title['name'];
793 return $title;
794}
795
646272be
AA
796function printTagTRs ($cell, $baseurl = '')
797{
798 if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' and count ($cell['etags']))
799 {
800 echo "<tr><th width='50%' class=tagchain>Explicit tags:</th><td class=tagchain>";
801 echo serializeTags ($cell['etags'], $baseurl) . "</td></tr>\n";
802 }
803 if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' and count ($cell['itags']))
804 {
805 echo "<tr><th width='50%' class=tagchain>Implicit tags:</th><td class=tagchain>";
806 echo serializeTags ($cell['itags'], $baseurl) . "</td></tr>\n";
807 }
808 if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' and count ($cell['atags']))
809 {
810 echo "<tr><th width='50%' class=tagchain>Automatic tags:</th><td class=tagchain>";
811 echo serializeTags ($cell['atags']) . "</td></tr>\n";
812 }
813}
814
ec143409
AA
815// stub function to override it by chain-connected hooks
816function modifyEntitySummary ($cell, $summary)
817{
818 return $summary;
819}
820
646272be
AA
821// renders 'summary' portlet, which persist on default tab of every realm page.
822// $values is a tricky array.
823// if its value is a string, it is treated as right td inner html, and the key is treated as left th text, colon appends there automatically.
defd92d8 824// 'tags' key has a special meaning: instead of value, the result of printTagTRs call is appended to output
646272be
AA
825// if the value is a single-element array, its value rendered as-is instead of <tr> tag and all its contents.
826// if the value is an array, its first 2 items are treated as left and right contents of row, no colon is appended. Used to enable non-unique titles
827function renderEntitySummary ($cell, $title, $values = array())
828{
829 global $page_by_realm;
54f3cd0a 830 // allow plugins to override summary table
ec143409 831 $values = callHook ('modifyEntitySummary', $cell, $values);
54f3cd0a 832
646272be
AA
833 startPortlet ($title);
834 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
835 foreach ($values as $name => $value)
836 {
837 if (is_array ($value) and count ($value) == 1)
838 {
839 $value = array_shift ($value);
840 echo $value;
841 continue;
842 }
843 if (is_array ($value))
844 {
845 $name = array_shift ($value);
846 $value = array_shift ($value);
847 }
848 elseif (! is_array ($value))
849 $name .= ':';
850 $class = 'tdright';
851 $m = array();
852 if (preg_match('/^\{(.*?)\}(.*)/', $name, $m))
853 {
854 $class .= ' ' . $m[1];
855 $name = $m[2];
856 }
857 if ($name == 'tags:')
858 {
859 $baseurl = '';
860 if (isset ($page_by_realm[$cell['realm']]))
861 $baseurl = makeHref(array('page'=>$page_by_realm[$cell['realm']], 'tab'=>'default'))."&";
862 printTagTRs ($cell, $baseurl);
863 }
864 else
865 echo "<tr><th width='50%' class='$class'>$name</th><td class=tdleft>$value</td></tr>";
866 }
867 echo "</table>\n";
868 finishPortlet();
869}
870
93a49e5b
AA
871function getOpLink ($params, $title, $img_name = '', $comment = '', $class = '')
872{
873 if (isset ($params))
874 $ret = '<a href="' . makeHrefProcess ($params) . '"';
875 else
876 {
877 $ret = '<a href="#" onclick="return false;"';
878 $class .= ' noclick';
879 }
880 if (! empty ($comment))
881 $ret .= ' title="' . htmlspecialchars ($comment, ENT_QUOTES) . '"';
882 $class = trim ($class);
883 if (! empty ($class))
884 $ret .= ' class="' . htmlspecialchars ($class, ENT_QUOTES) . '"';
885 if (! empty ($comment))
886 $ret .= 'title="' . htmlspecialchars($comment, ENT_QUOTES) . '"';
887 $ret .= '>';
888 if (! empty ($img_name))
889 {
890 $ret .= getImageHREF ($img_name, $comment);
891 if (! empty ($title))
892 $ret .= ' ';
893 }
894 $ret .= $title . '</a>';
895 return $ret;
896}
897
4318ced5
AA
898function renderProgressBar ($percentage = 0, $theme = '', $inline = FALSE)
899{
900 echo getProgressBar ($percentage, $theme, $inline);
901}
902
903function getProgressBar ($percentage = 0, $theme = '', $inline = FALSE)
904{
905 $done = ((int) ($percentage * 100));
906 if (! $inline)
907 $src = "?module=progressbar&done=$done" . (empty ($theme) ? '' : "&theme=${theme}");
908 else
909 {
910 $bk_request = $_REQUEST;
911 $_REQUEST['theme'] = $theme;
912 $src = 'data:image/png;base64,' . chunk_split (base64_encode (getOutputOf ('renderProgressBarImage', $done)));
913 $_REQUEST = $bk_request;
914 header ('Content-type: text/html');
915 }
916 $ret = "<img width=100 height=10 border=0 title='${done}%' src='$src'>";
917 return $ret;
918}
919
0dc380e9
AA
920function renderNetVLAN ($cell)
921{
922 if (! empty ($cell['8021q']))
923 {
924 $seen = array();
925 foreach ($cell['8021q'] as $vlan_info)
926 $seen[$vlan_info['vlan_id']] = $vlan_info['domain_id'] . '-' . $vlan_info['vlan_id'];
927 echo '<div class="vlan"><strong><small>VLAN' . (count ($seen) > 1 ? 'S' : '') . '</small> ';
928 $links = array();
929 foreach ($seen as $vlan_id => $vlan_ck)
930 $links[] = '<a href="' . makeHref (array ('page' => 'vlan', 'vlan_ck' => $vlan_ck)) . '">' . $vlan_id . '</a>';
931 echo implode (', ', $links);
932 echo '</strong></div>';
933 }
934}
935
ca8aa8e9 936?>