Merge pull request #43 from rafaeldriutti/master
[racktables-incomplete-works] / wwwroot / inc / interface-lib.php
1 <?php
2
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
7 // Let's have it here, so extensions can add their own images.
8 $image = array();
9 $image['rackspace']['path'] = 'pix/racks.png';
10 $image['rackspace']['width'] = 218;
11 $image['rackspace']['height'] = 200;
12 $image['objects']['path'] = 'pix/server.png';
13 $image['objects']['width'] = 218;
14 $image['objects']['height'] = 200;
15 $image['depot']['path'] = 'pix/server.png';
16 $image['depot']['width'] = 218;
17 $image['depot']['height'] = 200;
18 $image['files']['path'] = 'pix/files.png';
19 $image['files']['width'] = 218;
20 $image['files']['height'] = 200;
21 $image['ipv4space']['path'] = 'pix/addressspace.png';
22 $image['ipv4space']['width'] = 218;
23 $image['ipv4space']['height'] = 200;
24 $image['ipv6space']['path'] = 'pix/addressspacev6.png';
25 $image['ipv6space']['width'] = 218;
26 $image['ipv6space']['height'] = 200;
27 $image['ipv4slb']['path'] = 'pix/slb.png';
28 $image['ipv4slb']['width'] = 218;
29 $image['ipv4slb']['height'] = 200;
30 $image['config']['path'] = 'pix/configuration.png';
31 $image['config']['width'] = 218;
32 $image['config']['height'] = 200;
33 $image['reports']['path'] = 'pix/report.png';
34 $image['reports']['width'] = 218;
35 $image['reports']['height'] = 200;
36 $image['8021q']['path'] = 'pix/8021q.png';
37 $image['8021q']['width'] = 218;
38 $image['8021q']['height'] = 200;
39 $image['objectlog']['path'] = 'pix/crystal-mimetypes-shellscript-218x200.png';
40 $image['objectlog']['width'] = 218;
41 $image['objectlog']['height'] = 200;
42 $image['virtual']['path'] = 'pix/virtualresources.png';
43 $image['virtual']['width'] = 218;
44 $image['virtual']['height'] = 200;
45 $image['download']['path'] = 'pix/download.png';
46 $image['download']['width'] = 16;
47 $image['download']['height'] = 16;
48 $image['DOWNLOAD']['path'] = 'pix/download-big.png';
49 $image['DOWNLOAD']['width'] = 32;
50 $image['DOWNLOAD']['height'] = 32;
51 $image['plug']['path'] = 'pix/tango-network-wired.png';
52 $image['plug']['width'] = 16;
53 $image['plug']['height'] = 16;
54 $image['cut']['path'] = 'pix/tango-edit-cut-16x16.png';
55 $image['cut']['width'] = 16;
56 $image['cut']['height'] = 16;
57 $image['Cut']['path'] = 'pix/tango-edit-cut-22x22.png';
58 $image['Cut']['width'] = 22;
59 $image['Cut']['height'] = 22;
60 $image['Cut gray']['path'] = 'pix/tango-edit-cut-22x22-gray.png';
61 $image['Cut gray']['width'] = 22;
62 $image['Cut gray']['height'] = 22;
63 $image['CUT']['path'] = 'pix/tango-edit-cut-32x32.png';
64 $image['CUT']['width'] = 32;
65 $image['CUT']['height'] = 32;
66 $image['add']['path'] = 'pix/tango-list-add.png';
67 $image['add']['width'] = 16;
68 $image['add']['height'] = 16;
69 $image['ADD']['path'] = 'pix/tango-list-add-big.png';
70 $image['ADD']['width'] = 32;
71 $image['ADD']['height'] = 32;
72 $image['delete']['path'] = 'pix/tango-list-remove.png';
73 $image['delete']['width'] = 16;
74 $image['delete']['height'] = 16;
75 $image['DELETE']['path'] = 'pix/tango-list-remove-32x32.png';
76 $image['DELETE']['width'] = 32;
77 $image['DELETE']['height'] = 32;
78 $image['destroy']['path'] = 'pix/tango-user-trash-16x16.png';
79 $image['destroy']['width'] = 16;
80 $image['destroy']['height'] = 16;
81 $image['nodestroy']['path'] = 'pix/tango-user-trash-16x16-gray.png';
82 $image['nodestroy']['width'] = 16;
83 $image['nodestroy']['height'] = 16;
84 $image['NODESTROY']['path'] = 'pix/tango-user-trash-32x32-gray.png';
85 $image['NODESTROY']['width'] = 32;
86 $image['NODESTROY']['height'] = 32;
87 $image['DESTROY']['path'] = 'pix/tango-user-trash-32x32.png';
88 $image['DESTROY']['width'] = 32;
89 $image['DESTROY']['height'] = 32;
90 $image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
91 $image['nodelete']['width'] = 16;
92 $image['nodelete']['height'] = 16;
93 $image['inservice']['path'] = 'pix/tango-emblem-system.png';
94 $image['inservice']['width'] = 16;
95 $image['inservice']['height'] = 16;
96 $image['notinservice']['path'] = 'pix/tango-dialog-error.png';
97 $image['notinservice']['width'] = 16;
98 $image['notinservice']['height'] = 16;
99 $image['find']['path'] = 'pix/tango-system-search.png';
100 $image['find']['width'] = 16;
101 $image['find']['height'] = 16;
102 $image['next']['path'] = 'pix/tango-go-next.png';
103 $image['next']['width'] = 32;
104 $image['next']['height'] = 32;
105 $image['prev']['path'] = 'pix/tango-go-previous.png';
106 $image['prev']['width'] = 32;
107 $image['prev']['height'] = 32;
108 $image['COMMIT']['path'] = 'pix/tango-go-prev-next-32x32.png';
109 $image['COMMIT']['width'] = 32;
110 $image['COMMIT']['height'] = 32;
111 $image['COMMIT gray']['path'] = 'pix/tango-go-prev-next-gray-32x32.png';
112 $image['COMMIT gray']['width'] = 32;
113 $image['COMMIT gray']['height'] = 32;
114 $image['RECALC']['path'] = 'pix/tango-view-refresh-32x32.png';
115 $image['RECALC']['width'] = 32;
116 $image['RECALC']['height'] = 32;
117 $image['clear']['path'] = 'pix/tango-edit-clear.png';
118 $image['clear']['width'] = 16;
119 $image['clear']['height'] = 16;
120 $image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
121 $image['CLEAR']['width'] = 32;
122 $image['CLEAR']['height'] = 32;
123 $image['CLEAR gray']['path'] = 'pix/tango-edit-clear-gray-32x32.png';
124 $image['CLEAR gray']['width'] = 32;
125 $image['CLEAR gray']['height'] = 32;
126 $image['save']['path'] = 'pix/tango-document-save-16x16.png';
127 $image['save']['width'] = 16;
128 $image['save']['height'] = 16;
129 $image['SAVE']['path'] = 'pix/tango-document-save-32x32.png';
130 $image['SAVE']['width'] = 32;
131 $image['SAVE']['height'] = 32;
132 $image['NOSAVE']['path'] = 'pix/tango-document-save-32x32-gray.png';
133 $image['NOSAVE']['width'] = 32;
134 $image['NOSAVE']['height'] = 32;
135 $image['create']['path'] = 'pix/tango-document-new.png';
136 $image['create']['width'] = 16;
137 $image['create']['height'] = 16;
138 $image['CREATE']['path'] = 'pix/tango-document-new-big.png';
139 $image['CREATE']['width'] = 32;
140 $image['CREATE']['height'] = 32;
141 $image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
142 $image['DENIED']['width'] = 32;
143 $image['DENIED']['height'] = 32;
144 $image['node-collapsed']['path'] = 'pix/node-collapsed.png';
145 $image['node-collapsed']['width'] = 16;
146 $image['node-collapsed']['height'] = 16;
147 $image['node-expanded']['path'] = 'pix/node-expanded.png';
148 $image['node-expanded']['width'] = 16;
149 $image['node-expanded']['height'] = 16;
150 $image['node-expanded-static']['path'] = 'pix/node-expanded-static.png';
151 $image['node-expanded-static']['width'] = 16;
152 $image['node-expanded-static']['height'] = 16;
153 $image['dragons']['path'] = 'pix/mitsudragon.png';
154 $image['dragons']['width'] = 195;
155 $image['dragons']['height'] = 33;
156 $image['LB']['path'] = 'pix/loadbalancer.png';
157 $image['LB']['width'] = 32;
158 $image['LB']['height'] = 32;
159 $image['RS pool']['path'] = 'pix/serverpool.png';
160 $image['RS pool']['width'] = 48;
161 $image['RS pool']['height'] = 16;
162 $image['VS']['path'] = 'pix/servicesign.png';
163 $image['VS']['width'] = 39;
164 $image['VS']['height'] = 62;
165 $image['router']['path'] = 'pix/router.png';
166 $image['router']['width'] = 32;
167 $image['router']['height'] = 32;
168 $image['object']['path'] = 'pix/bracket-16x16.png';
169 $image['object']['width'] = 16;
170 $image['object']['height'] = 16;
171 $image['OBJECT']['path'] = 'pix/bracket-32x32.png';
172 $image['OBJECT']['width'] = 32;
173 $image['OBJECT']['height'] = 32;
174 $image['LOCATION']['path'] = 'pix/tango-internet-32x32.png';
175 $image['LOCATION']['width'] = 32;
176 $image['LOCATION']['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;
261 $image['copy']['path'] = 'pix/tango-edit-copy-16x16.png';
262 $image['copy']['width'] = 16;
263 $image['copy']['height'] = 16;
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 $image['pencil']['path'] = 'pix/pencil-icon.png';
271 $image['pencil']['width'] = 12;
272 $image['pencil']['height'] = 12;
273
274 $page_by_realm = array();
275 $page_by_realm['object'] = 'depot';
276 $page_by_realm['rack'] = 'rackspace';
277 $page_by_realm['ipv4net'] = 'ipv4space';
278 $page_by_realm['ipv6net'] = 'ipv6space';
279 $page_by_realm['ipv4vs'] = 'ipv4slb';
280 $page_by_realm['ipv4rspool'] = 'ipv4slb';
281 $page_by_realm['file'] = 'files';
282 $page_by_realm['user'] = 'userlist';
283
284 function printSelect ($optionList, $select_attrs = array(), $selected_id = NULL)
285 {
286 echo getSelect ($optionList, $select_attrs, $selected_id);
287 }
288
289 // Input array keys are OPTION VALUEs and input array values are OPTION text.
290 function getSelect ($optionList, $select_attrs = array(), $selected_id = NULL, $treat_single_special = TRUE)
291 {
292 $ret = '';
293 if (!array_key_exists ('name', $select_attrs))
294 return '';
295 // handle two corner cases in a specific way
296 if (count ($optionList) == 0)
297 return '(none)';
298 if (count ($optionList) == 1 && $treat_single_special)
299 {
300 foreach ($optionList as $key => $value)
301 break;
302 return "<input type=hidden name=${select_attrs['name']} id=${select_attrs['name']} value=${key}>" . $value;
303 }
304 if (!array_key_exists ('id', $select_attrs))
305 $select_attrs['id'] = $select_attrs['name'];
306 $ret .= '<select';
307 foreach ($select_attrs as $attr_name => $attr_value)
308 $ret .= " ${attr_name}=${attr_value}";
309 $ret .= '>';
310 foreach ($optionList as $dict_key => $dict_value)
311 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>";
312 $ret .= '</select>';
313 return $ret;
314 }
315
316 function printNiftySelect ($groupList, $select_attrs = array(), $selected_id = NULL, $autocomplete = false)
317 {
318 echo getNiftySelect ($groupList, $select_attrs, $selected_id);
319 }
320
321 // Input is a cooked list of OPTGROUPs, each with own sub-list of OPTIONs in the same
322 // format as printSelect() expects.
323 // If tree is true, hierarchical drop-boxes are used, otherwise optgroups are used.
324 function getNiftySelect ($groupList, $select_attrs, $selected_id = NULL, $tree = false)
325 {
326 // special treatment for ungrouped data
327 if (count ($groupList) == 1 and isset ($groupList['other']))
328 return getSelect ($groupList['other'], $select_attrs, $selected_id);
329 if (!array_key_exists ('name', $select_attrs))
330 return '';
331 if (!array_key_exists ('id', $select_attrs))
332 $select_attrs['id'] = $select_attrs['name'];
333 if ($tree)
334 {
335 # it is safe to call many times for the same file
336 addJS ('js/jquery.optionTree.js');
337 $ret = "<input type=hidden name=${select_attrs['name']}>\n";
338 $ret .= "<script type='text/javascript'>\n";
339 $ret .= "\$(function() {\n";
340 $ret .= " var option_tree = {\n";
341 foreach ($groupList as $groupname => $groupdata)
342 {
343 $ret .= " '${groupname}': {";
344 foreach ($groupdata as $dict_key => $dict_value)
345 $ret .= "\"${dict_value}\":'${dict_key}', ";
346 $ret .= "},\n";
347 }
348 $ret .= " };\n";
349 $ret .= " var options = {empty_value: '', choose: 'select...'};\n";
350 $ret .= " \$('input[name=${select_attrs['name']}]').optionTree(option_tree, options);\n";
351 $ret .= "});\n";
352 $ret .= "</script>\n";
353 }
354 else
355 {
356 $ret = '<select';
357 foreach ($select_attrs as $attr_name => $attr_value)
358 $ret .= " ${attr_name}=${attr_value}";
359 $ret .= ">\n";
360 foreach ($groupList as $groupname => $groupdata)
361 {
362 $ret .= "<optgroup label='${groupname}'>\n";
363 foreach ($groupdata as $dict_key => $dict_value)
364 $ret .= "<option value='${dict_key}'" . ($dict_key == $selected_id ? ' selected' : '') . ">${dict_value}</option>\n";
365 $ret .= "</optgroup>\n";
366 }
367 $ret .= "</select>\n";
368 }
369 return $ret;
370 }
371
372 function getOptionTree ($tree_name, $tree_options, $tree_config = array())
373 {
374 function serializeJSArray ($options)
375 {
376 $tmp = array();
377 foreach ($options as $key => $value)
378 $tmp[] = "'${key}': \"${value}\"";
379 return '{' . implode (', ', $tmp) . "}\n";
380 }
381 function serializeJSTree ($tree_options)
382 {
383 $self = __FUNCTION__;
384 $tmp = array();
385 # Leaves on the PHP tree are stored "value => label" way,
386 # non-leaves are stored "label => array" way, and the JS
387 # tree is always built "label => value" or "label => array"
388 # way, hence a structure transform is required.
389 foreach ($tree_options as $key => $value)
390 $tmp[] = is_array ($value) ?
391 '"' . str_replace ('"', '\"', $key) . '": ' . $self ($value) :
392 '"' . str_replace ('"', '\"', $value) . '": "' . str_replace ('"', '\"', $key) . '"';
393 return '{' . implode (', ', $tmp) . "}\n";
394 }
395
396 $default_config = array
397 (
398 'choose' => 'select...',
399 'empty_value' => '',
400 );
401 foreach ($tree_config as $cfgoption_name => $cfgoption_value)
402 $default_config[$cfgoption_name] = $cfgoption_value;
403 # it is safe to call many times for the same file
404 addJS ('js/jquery.optionTree.js');
405 $ret = "<input type=hidden name=${tree_name}>\n";
406 $ret .= "<script type='text/javascript'>\n";
407 $ret .= "\$(function() {\n";
408 $ret .= " var option_tree = " . serializeJSTree ($tree_options) . ";\n";
409 $ret .= " var options = " . serializeJSArray ($default_config) . ";\n";
410 $ret .= " \$('input[name=${tree_name}]').optionTree(option_tree, options);\n";
411 $ret .= "});\n";
412 $ret .= "</script>\n";
413 return $ret;
414 }
415
416 function printImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
417 {
418 echo getImageHREF ($tag, $title, $do_input, $tabindex);
419 }
420
421 // this would be better called mkIMG(), make "IMG" HTML element
422 function getImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
423 {
424 global $image;
425 if (!isset ($image[$tag]))
426 $tag = 'error';
427 $img = $image[$tag];
428 $img['path'] = '?module=chrome&uri=' . $img['path'];
429 if ($do_input == TRUE)
430 return
431 "<input type=image name=submit class=icon " .
432 "src='${img['path']}' " .
433 "border=0 " .
434 ($tabindex ? "tabindex=${tabindex}" : '') .
435 (!strlen ($title) ? '' : " title='${title}'") . // JT: Add title to input hrefs too
436 ">";
437 else
438 return
439 "<img " .
440 "src='${img['path']}' " .
441 "width=${img['width']} " .
442 "height=${img['height']} " .
443 "border=0 " .
444 (!strlen ($title) ? '' : "title='${title}'") .
445 ">";
446 }
447
448 function escapeString ($value, $do_db_escape = FALSE)
449 {
450 $ret = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
451 if ($do_db_escape)
452 {
453 global $dbxlink;
454 $ret = substr ($dbxlink->quote ($ret), 1, -1);
455 }
456 return $ret;
457 }
458
459 function transformRequestData()
460 {
461 global $sic;
462 // Magic quotes feature is deprecated, but just in case the local system
463 // still has it activated, reverse its effect.
464 $do_magic_quotes = (function_exists ('get_magic_quotes_gpc') and get_magic_quotes_gpc());
465 $seen_keys = array();
466
467 // Escape any globals before we ever try to use them, but keep a copy of originals.
468 $sic = array();
469 // walk through merged GET and POST instead of REQUEST array because it
470 // can contain cookies with data which could not be decoded from UTF-8
471 foreach (($_POST + $_GET) as $key => $value)
472 {
473 if (is_array ($value))
474 $_REQUEST[$key] = $value;
475 else
476 {
477 $value = dos2unix ($value);
478 if ($do_magic_quotes)
479 $value = stripslashes ($value);
480 $_REQUEST[$key] = escapeString ($value);
481 }
482 $sic[$key] = $value;
483 $seen_keys[$key] = 1;
484 }
485
486 // delete cookie information from the $_REQUEST array
487 foreach (array_keys ($_REQUEST) as $key)
488 if (! isset ($seen_keys[$key]))
489 unset ($_REQUEST[$key]);
490
491 if (isset ($_SERVER['PHP_AUTH_USER']))
492 $_SERVER['PHP_AUTH_USER'] = escapeString ($_SERVER['PHP_AUTH_USER']);
493 if (isset ($_SERVER['REMOTE_USER']))
494 $_SERVER['REMOTE_USER'] = escapeString ($_SERVER['REMOTE_USER']);
495 }
496
497 // JS scripts should be included through this function.
498 // They automatically appear in the <head> of your page.
499 // $data is a JS filename, or JS code w/o tags around, if $inline = TRUE
500 // Scripts are included in the order of adding within the same group, and groups are sorted alphabetically.
501 function addJS ($data, $inline = FALSE, $group = 'default')
502 {
503 static $javascript = array();
504 static $seen_filenames = array();
505
506 if (! isset ($data))
507 {
508 ksort ($javascript);
509 return $javascript;
510 }
511 // Add jquery.js and racktables.js the first time a Javascript file is added.
512 if (empty($javascript))
513 {
514 $javascript = array
515 (
516 'a_core' => array
517 (
518 array('type' => 'file', 'script' => 'js/jquery-1.4.4.min.js'),
519 array('type' => 'file', 'script' => 'js/racktables.js'),
520 ),
521 );
522
523 // initialize core js filelist
524 foreach ($javascript as $group_name => $group_array)
525 foreach ($group_array as $item)
526 if ($item['type'] == 'file')
527 $seen_filenames[$item['script']] = 1;
528 }
529
530 if ($inline)
531 $javascript[$group][] = array
532 (
533 'type' => 'inline',
534 'script' => $data,
535 );
536 elseif (! isset ($seen_filenames[$data]))
537 {
538 $javascript[$group][] = array
539 (
540 'type' => 'file',
541 'script' => $data,
542 );
543 $seen_filenames[$data] = 1;
544 }
545 }
546
547 // CSS styles should be included through this function.
548 // They automatically appear in the <head> of your page.
549 // $data is a CSS filename, or CSS code w/o tags around, if $inline = TRUE
550 // Styles are included in the order of adding.
551 function addCSS ($data, $inline = FALSE)
552 {
553 static $styles = array();
554 static $seen_filenames = array();
555
556 if (! isset ($data))
557 return $styles;
558 if ($inline)
559 $styles[] = array
560 (
561 'type' => 'inline',
562 'style' => $data,
563 );
564 elseif (! isset ($seen_filenames[$data]))
565 {
566 $styles[] = array
567 (
568 'type' => 'file',
569 'style' => $data,
570 );
571 $seen_filenames[$data] = 1;
572 }
573 }
574
575 function getRenderedIPNetCapacity ($range)
576 {
577 switch (strlen ($range['ip_bin']))
578 {
579 case 4: return getRenderedIPv4NetCapacity ($range);
580 case 16: return getRenderedIPv6NetCapacity ($range);
581 default: throw new InvalidArgException ('range["ip_bin"]', $range['ip_bin'], "Invalid binary IP");
582 }
583 }
584
585 function getRenderedIPv4NetCapacity ($range)
586 {
587 $class = 'net-usage';
588 if (isset ($range['addrc']))
589 {
590 // full mode
591 // $a is "aquamarine zone", $b is "gray zone"
592 $total = ip4_range_size ($range);
593
594 // compute $a_total: own range size, without subranges
595 if ($range['kidc'] == 0)
596 $a_total = $total;
597 else
598 {
599 $a_total = 0;
600 foreach ($range['spare_ranges'] as $mask => $spare_list)
601 $a_total = bcadd ($a_total, bcmul (count ($spare_list), ip4_mask_size ($mask)), 0);
602 }
603 $a_used = $range['own_addrc'];
604 $b_total = bcsub ($total, $a_total, 0);
605 $b_used = $range['addrc'] - $a_used;
606
607 // generate link to progress bar image
608 $width = 100;
609 if ($total != 0)
610 {
611 $px_a = round (bcdiv ($a_total, $total, 4) * $width);
612 $px1 = round (bcdiv ($a_used, $total, 4) * $width);
613 $px2 = $px_a - $px1;
614 $px3 = round (bcdiv ($b_used, $total, 4) * $width);
615 if ($px3 + $px1 + $px2 > $width)
616 $px3 = $width - $px1 - $px2;
617 }
618 else
619 $px1 = $px2 = $px3 = 0;
620
621 $title_items = array();
622 $title2_items = array();
623 if ($a_total != 0)
624 {
625 $title_items[] = "$a_used / $a_total";
626 $title2_items[] = sprintf ("%d%% used", bcdiv ($a_used, $a_total, 4) * 100);
627 }
628 if ($b_total != 0)
629 {
630 $title_items[] = ($b_used ? "$b_used / " : "") . $b_total;
631 $title2_items[] = sprintf ("%d%% sub-allocated", bcdiv ($b_total, $total, 4) * 100);
632 }
633 $title = implode (', ', $title_items);
634 $title2 = implode (', ', $title2_items);
635 $text = "<img width='$width' height=10 border=0 title='$title2' src='?module=progressbar4&px1=$px1&px2=$px2&px3=$px3'>" .
636 " <small class='title'>$title</small>";
637 }
638 else
639 {
640 // fast mode
641 $class .= ' pending';
642 addJS ('js/net-usage.js');
643
644 $free_text = '';
645 if (isset ($range['kidc']) and $range['kidc'] > 0)
646 {
647 $free_masks = array_keys ($range['spare_ranges']);
648 sort ($free_masks, SORT_NUMERIC);
649 if ($mask = array_shift ($free_masks))
650 {
651 $cnt = count ($range['spare_ranges'][$mask]);
652 $free_text = ', ' . ($cnt > 1 ? "<small>${cnt}x</small>" : "") . "/$mask free";
653 }
654 }
655 $text = ip4_range_size ($range) . $free_text;
656 }
657
658 $div_id = $range['ip'] . '/' . $range['mask'];
659
660 return "<div class=\"$class\" id=\"$div_id\">" . $text . "</div>";
661 }
662
663 function getRenderedIPv6NetCapacity ($range)
664 {
665 $div_id = $range['ip'] . '/' . $range['mask'];
666 $class = 'net-usage';
667 if (isset ($range['addrc']))
668 $used = $range['addrc'];
669 else
670 {
671 $used = NULL;
672 $class .= ' pending';
673 addJS ('js/net-usage.js');
674 }
675
676 static $prefixes = array
677 (
678 0 => '',
679 3 => 'k',
680 6 => 'M',
681 9 => 'G',
682 12 => 'T',
683 15 => 'P',
684 18 => 'E',
685 21 => 'Z',
686 24 => 'Y',
687 );
688
689 if ($range['mask'] <= 64)
690 {
691 $what = 'net';
692 $preposition = 'in';
693 $range['mask'] += 64;
694 }
695 else
696 {
697 $what = 'IP';
698 $preposition = 'of';
699 }
700 $what .= (0 == $range['mask'] % 64 ? '' : 's');
701 $addrc = isset ($used) ? "$used $preposition " : '';
702
703 $dec_order = intval ((128 - $range['mask']) / 10) * 3;
704 $mult = isset ($prefixes[$dec_order]) ? $prefixes[$dec_order] : '??';
705
706 $cnt = 1 << ((128 - $range['mask']) % 10);
707 if ($cnt == 1 && $mult == '')
708 $cnt = '1';
709
710 return "<div class=\"$class\" id=\"$div_id\">" . "{$addrc}${cnt}${mult} ${what}" . "</div>";
711 }
712
713 // print part of HTML HEAD block
714 function printPageHeaders ()
715 {
716 global $pageheaders;
717 ksort ($pageheaders);
718 foreach ($pageheaders as $s)
719 echo $s . "\n";
720
721 // add CSS styles
722 foreach (addCSS (NULL) as $item)
723 if ($item['type'] == 'inline')
724 echo '<style type="text/css">' . "\n" . trim ($item['style'], "\r\n") . "\n</style>\n";
725 elseif ($item['type'] == 'file')
726 echo "<link rel=stylesheet type='text/css' href='?module=chrome&uri=${item['style']}' />\n";
727
728 // add JS scripts
729 foreach (addJS (NULL) as $group_name => $js_list)
730 foreach ($js_list as $item)
731 if ($item['type'] == 'inline')
732 echo '<script type="text/javascript">' . "\n" . trim ($item['script'], "\r\n") . "\n</script>\n";
733 elseif ($item['type'] == 'file')
734 echo "<script type='text/javascript' src='?module=chrome&uri=${item['script']}'></script>\n";
735 }
736
737 function cmpTags ($a, $b)
738 {
739 global $taglist;
740 if (isset ($a['id']) && isset ($b['id']))
741 {
742 $a_root = array_first ($taglist[$a['id']]['trace']);
743 $b_root = array_first ($taglist[$b['id']]['trace']);
744 if ($a_root < $b_root)
745 return -1;
746 elseif ($a_root > $b_root)
747 return 1;
748 }
749 elseif (isset ($a['id']))
750 return -1;
751 elseif (isset ($b['id']))
752 return 1;
753
754 return strcmp ($a['tag'], $b['tag']);
755 }
756
757 function getTagClassName ($tagid)
758 {
759 global $taglist;
760
761 $class = '';
762 foreach ($taglist[$tagid]['trace'] as $parent)
763 $class .= 'tag-' . $parent . ' ';
764 $class .= 'tag-' . $tagid . ' etag-' . $tagid;
765
766 return $class;
767 }
768
769 function serializeTags ($chain, $baseurl = '')
770 {
771 $tmp = array();
772 usort ($chain, 'cmpTags');
773 foreach ($chain as $taginfo)
774 {
775 $title = '';
776 if (isset ($taginfo['user']) and isset ($taginfo['time']))
777 $title = 'title="' . htmlspecialchars ($taginfo['user'] . ', ' . formatAge ($taginfo['time']), ENT_QUOTES) . '"';
778
779 $class = '';
780 if (isset ($taginfo['id']))
781 $class = 'class="' . getTagClassName ($taginfo['id']) . '"';
782
783 $href = '';
784 if ($baseurl == '')
785 $tag = 'span';
786 else
787 {
788 $tag = 'a';
789 $href = "href='${baseurl}cft[]=${taginfo['id']}'";
790 }
791 $tmp[] = "<$tag $href $title $class>" . $taginfo['tag'] . "</$tag>";
792 }
793 return implode (', ', $tmp);
794 }
795
796 function startPortlet ($title = '')
797 {
798 echo "<div class=portlet><h2>${title}</h2>";
799 }
800
801 function finishPortlet ()
802 {
803 echo "</div>\n";
804 }
805
806 function getPageName ($page_code)
807 {
808 global $page;
809 $title = isset ($page[$page_code]['title']) ? $page[$page_code]['title'] : callHook ('dynamic_title_decoder' ,$page_code);
810 if (is_array ($title))
811 $title = $title['name'];
812 return $title;
813 }
814
815 function printTagTRs ($cell, $baseurl = '')
816 {
817 if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' and count ($cell['etags']))
818 {
819 echo "<tr><th width='50%' class=tagchain>Explicit tags:</th><td class=tagchain>";
820 echo serializeTags ($cell['etags'], $baseurl) . "</td></tr>\n";
821 }
822 if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' and count ($cell['itags']))
823 {
824 echo "<tr><th width='50%' class=tagchain>Implicit tags:</th><td class=tagchain>";
825 echo serializeTags ($cell['itags'], $baseurl) . "</td></tr>\n";
826 }
827 if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' and count ($cell['atags']))
828 {
829 echo "<tr><th width='50%' class=tagchain>Automatic tags:</th><td class=tagchain>";
830 echo serializeTags ($cell['atags']) . "</td></tr>\n";
831 }
832 }
833
834 // stub function to override it by chain-connected hooks
835 function modifyEntitySummary ($cell, $summary)
836 {
837 return $summary;
838 }
839
840 // renders 'summary' portlet, which persist on default tab of every realm page.
841 // $values is a tricky array.
842 // 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.
843 // 'tags' key has a special meaning: instead of value, the result of printTagTRs call is appended to output
844 // if the value is a single-element array, its value rendered as-is instead of <tr> tag and all its contents.
845 // 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
846 function renderEntitySummary ($cell, $title, $values = array())
847 {
848 global $page_by_realm;
849 // allow plugins to override summary table
850 $values = callHook ('modifyEntitySummary', $cell, $values);
851
852 startPortlet ($title);
853 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
854 foreach ($values as $name => $value)
855 {
856 if (is_array ($value) and count ($value) == 1)
857 {
858 $value = array_shift ($value);
859 echo $value;
860 continue;
861 }
862 if (is_array ($value))
863 {
864 $name = array_shift ($value);
865 $value = array_shift ($value);
866 }
867 elseif (! is_array ($value))
868 $name .= ':';
869 $class = 'tdright';
870 $m = array();
871 if (preg_match('/^\{(.*?)\}(.*)/', $name, $m))
872 {
873 $class .= ' ' . $m[1];
874 $name = $m[2];
875 }
876 if ($name == 'tags:')
877 {
878 $baseurl = '';
879 if (isset ($page_by_realm[$cell['realm']]))
880 $baseurl = makeHref(array('page'=>$page_by_realm[$cell['realm']], 'tab'=>'default'))."&";
881 printTagTRs ($cell, $baseurl);
882 }
883 else
884 echo "<tr><th width='50%' class='$class'>$name</th><td class=tdleft>$value</td></tr>";
885 }
886 echo "</table>\n";
887 finishPortlet();
888 }
889
890 function getOpLink ($params, $title, $img_name = '', $comment = '', $class = '')
891 {
892 if (isset ($params))
893 $ret = '<a href="' . makeHrefProcess ($params) . '"';
894 else
895 {
896 $ret = '<a href="#" onclick="return false;"';
897 $class .= ' noclick';
898 }
899 if (! empty ($comment))
900 $ret .= ' title="' . htmlspecialchars ($comment, ENT_QUOTES) . '"';
901 $class = trim ($class);
902 if (! empty ($class))
903 $ret .= ' class="' . htmlspecialchars ($class, ENT_QUOTES) . '"';
904 if (! empty ($comment))
905 $ret .= 'title="' . htmlspecialchars($comment, ENT_QUOTES) . '"';
906 $ret .= '>';
907 if (! empty ($img_name))
908 {
909 $ret .= getImageHREF ($img_name, $comment);
910 if (! empty ($title))
911 $ret .= ' ';
912 }
913 if (FALSE !== strpos ($class, 'need-confirmation'))
914 addJS ('js/racktables.js');
915 $ret .= $title . '</a>';
916 return $ret;
917 }
918
919 function renderProgressBar ($percentage = 0, $theme = '', $inline = FALSE)
920 {
921 echo getProgressBar ($percentage, $theme, $inline);
922 }
923
924 function getProgressBar ($percentage = 0, $theme = '', $inline = FALSE)
925 {
926 $done = ((int) ($percentage * 100));
927 if (! $inline)
928 $src = "?module=progressbar&done=$done" . (empty ($theme) ? '' : "&theme=${theme}");
929 else
930 {
931 $bk_request = $_REQUEST;
932 $_REQUEST['theme'] = $theme;
933 $src = 'data:image/png;base64,' . chunk_split (base64_encode (getOutputOf ('renderProgressBarImage', $done)));
934 $_REQUEST = $bk_request;
935 header ('Content-type: text/html');
936 }
937 $ret = "<img width=100 height=10 border=0 title='${done}%' src='$src'>";
938 return $ret;
939 }
940
941 function renderNetVLAN ($cell)
942 {
943 if (empty ($cell['8021q']))
944 return;
945 $links = array();
946 foreach ($cell['8021q'] as $vi)
947 $links[] = mkA ($vi['vlan_id'], 'vlan', "${vi['domain_id']}-${vi['vlan_id']}");
948 $noun = count ($cell['8021q']) > 1 ? 'VLANs' : 'VLAN';
949 echo "<div class='vlan'><strong><small>${noun}</small> " . implode (', ', $links) . '</strong></div>';
950 }
951
952 function includeJQueryUI ($do_css = TRUE)
953 {
954 addJS ('js/jquery-ui-1.8.21.min.js');
955 if ($do_css)
956 addCSS ('css/jquery-ui-1.8.22.redmond.css');
957 }
958
959 function getRenderedIPPortPair ($ip, $port = NULL)
960 {
961 return "<a href=\"" .
962 makeHref (array ('page' => 'ipaddress', 'tab'=>'default', 'ip' => $ip)) .
963 "\">" . $ip . "</a>" .
964 (isset ($port) ? ":" . $port : "");
965 }
966
967 // Print common operation form prologue, include bypass argument, if
968 // appropriate, and some extra hidden inputs, if requested.
969 // Use special encoding for upload forms
970 function printOpFormIntro ($opname, $extra = array(), $upload = FALSE)
971 {
972 global $pageno, $tabno, $page;
973
974 echo "<form method=post id=${opname} name=${opname} action='?module=redirect&page=${pageno}&tab=${tabno}&op=${opname}'";
975 if ($upload)
976 echo " enctype='multipart/form-data'";
977 echo ">";
978 fillBypassValues ($pageno, $extra);
979 foreach ($extra as $inputname => $inputvalue)
980 printf ('<input type=hidden name="%s" value="%s">', htmlspecialchars ($inputname, ENT_QUOTES), htmlspecialchars ($inputvalue, ENT_QUOTES));
981 }
982
983
984 // Display hrefs for all of a file's parents. If scissors are requested,
985 // prepend cutting button to each of them.
986 function serializeFileLinks ($links, $scissors = FALSE)
987 {
988 $comma = '';
989 $ret = '';
990 foreach ($links as $link_id => $li)
991 {
992 $cell = spotEntity ($li['entity_type'], $li['entity_id']);
993 $ret .= $comma;
994 if ($scissors)
995 $ret .= getOpLink (array('op'=>'unlinkFile', 'link_id'=>$link_id), '', 'cut', 'Unlink file') . ' ';
996 $ret .= mkCellA ($cell);
997 $comma = '<br>';
998 }
999 return $ret;
1000 }
1001
1002 ?>