Template is unsaved. Click here to save it
');
51 | console.log('a');
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | DESTDIR ?=
2 | prefix ?= /usr/local
3 | docdir ?= $(prefix)/share/doc/RackTables
4 | datadir ?= $(prefix)/share
5 | # Default values reproduce the layout present in tar.gz, which concurs with
6 | # the default values of $racktables_gwdir and $racktables_staticdir. But
7 | # once the latter are patched for a shared deploy, it is enough to execute
8 | # "make install" with appropriate arguments to split the filesystem.
9 | staticdir ?= $(datadir)/RackTables/wwwroot
10 | applibdir ?= $(datadir)/RackTables/wwwroot/inc
11 | indexdir ?= $(datadir)/RackTables/wwwroot
12 | scriptdir ?= $(datadir)/RackTables
13 |
14 | INSTALL := install
15 | INSTALL_DATA := $(INSTALL) -m 644
16 | INSTALL_DIR := $(INSTALL) -m 755 -d
17 | INSTALL_PROGRAM := $(INSTALL) -m 755
18 |
19 | install-docs: COPYING ChangeLog LICENSE README
20 | $(INSTALL_DIR) $(DESTDIR)$(docdir)
21 | $(INSTALL_DATA) $^ $(DESTDIR)$(docdir)
22 |
23 | install-helpers: scripts gateways
24 | $(INSTALL_DIR) $(DESTDIR)$(scriptdir)
25 | cp -r $^ $(DESTDIR)$(scriptdir)
26 | find $(DESTDIR)$(scriptdir)/scripts -type d -a -name '.git' -exec rm -rf \{\} \; -prune
27 | find $(DESTDIR)$(scriptdir)/gateways -type d -a -name '.git' -exec rm -rf \{\} \; -prune
28 |
29 | install-static: wwwroot/css wwwroot/js wwwroot/pix
30 | $(INSTALL_DIR) $(DESTDIR)$(staticdir)
31 | cp -r $^ $(DESTDIR)$(staticdir)
32 | find $(DESTDIR)$(staticdir) -type d -a -name '.git' -exec rm -rf \{\} \; -prune
33 |
34 | install-applib: wwwroot/inc
35 | $(INSTALL_DIR) $(DESTDIR)$(applibdir)/inc
36 | $(INSTALL_DATA) wwwroot/inc/*.php $(DESTDIR)$(applibdir)
37 |
38 | install-index: wwwroot/index.php
39 | $(INSTALL_DIR) $(DESTDIR)$(indexdir)
40 | $(INSTALL_DATA) wwwroot/index.php $(DESTDIR)$(indexdir)
41 |
42 | install: install-helpers install-static install-applib install-index
43 |
--------------------------------------------------------------------------------
/wwwroot/js/slb_editor.js:
--------------------------------------------------------------------------------
1 | $(document).ready (function () {
2 | // popup form for port/ip config update
3 | $('.slb-checks.editable li').click (function (e) {
4 | if (e.target.tagName != 'LI')
5 | return true;
6 | // clone form into new_form, re-setting all selectbox values which are cleared by clone()
7 | var old_form = $(this).find('form');
8 | var new_form = old_form.clone();
9 | new_form.find('select').each (function (i, elem) {
10 | var corresponding = old_form.find('select[name="' + $(this).attr('name') + '"]');
11 | if (corresponding.length)
12 | $(this).val(corresponding.val());
13 | });
14 | var form = $('').addClass ('popup-box').appendTo ('body').append (new_form);
15 | // confirmation box on port/vip deletion
16 | $('a.del-used-slb').click (function (e) {
17 | return confirm ('This entity is used. Please confirm the deletion');
18 | });
19 |
20 | $(this).thumbPopup (form, { event: e });
21 | return false;
22 | });
23 |
24 | // confirmation box on triplet deletion
25 | $('form#del input').click (function (e) {
26 | return confirm ('Please confirm the deletion of triplet');
27 | });
28 |
29 | // new triplet form stage1 handler
30 | var forms = $('form#addLink');
31 | forms.submit (function() { return false });
32 | forms.find('input[name="submit"]').click (function (e) {
33 | var form = $(this).parents('form');
34 | $.ajax ({
35 | type: 'POST',
36 | url: 'index.php',
37 | data: {
38 | 'module': 'ajax',
39 | 'ac': 'get-slb-form',
40 | 'form': form.serialize(),
41 | 'action': form.attr('action')
42 | },
43 | 'success': function (data) {
44 | form.replaceWith (data);
45 | }
46 | });
47 |
48 | return false;
49 | });
50 | });
51 |
52 | function slb_config_preview (e, object_id, vs_id, rspool_id) {
53 | $.ajax ({
54 | type: 'POST',
55 | url: 'index.php',
56 | data: {
57 | module: 'ajax',
58 | ac: 'triplet-preview',
59 | object_id: object_id,
60 | vs_id: vs_id,
61 | rspool_id: rspool_id
62 | },
63 | success: function (data) {
64 | var div = $('
').addClass('popup-box').appendTo('body');
65 | div.html(data);
66 | $(this).thumbPopup (div, { event: e });
67 | }
68 | });
69 | }
70 |
--------------------------------------------------------------------------------
/README.Fedora:
--------------------------------------------------------------------------------
1 | RUNNING RACKTABLES ON A FEDORA SYSTEM
2 | =====================================
3 |
4 | Most files in Fedora package of RackTables application reside in the
5 | /usr/share/RackTables directory regardless of package version. It is
6 | assumed, that this directory is never directly used in httpd's "document
7 | root" setting. Instead a symlink or a PHP "require" construct should be
8 | used for the index.php (and ONLY index.php) file based on some other
9 | directory, which is actually used as wwwroot. This greatly improves
10 | security and allows for the two use cases described below.
11 |
12 | 1. Single RackTables instance per server. By default the application
13 | expects its configuration file (secret.php) in /etc/RackTables directory,
14 | which is a part of the RPM. In a fresh installation the files is missing,
15 | no MySQL database is setup and there is no symlink.
16 |
17 | Setting up the symlink is simple: one needs to decide on the URL of the
18 | RackTables system and map it to filesystem path. For example, the commands
19 | below are likely to enable access through "http://localhost/racktables/":
20 |
21 | # mkdir /var/www/html/racktables
22 | # ln -s /usr/share/RackTables/wwwroot/index.php /var/www/html/racktables
23 |
24 | After that opening the URL in a browser will bring up RackTables installer,
25 | which will fill in /etc/RackTables/secret.php file and the contents of the
26 | MySQL database. After that the setup is complete.
27 |
28 |
29 | 2. Multiple RackTables instances per server. The application is designed
30 | to be able to serve many independent MySQL databases with the same
31 | codebase, but different configuration files. This requires a separate
32 | config directory per each instance. Each of the directories will feature
33 | an own secret.php file configured for its own MySQL database.
34 |
35 | For example, 3 virtual hosts should provide an independent RackTables
36 | application each. It is assumed, that httpd is already configured for the
37 | virtual hosts using respective directories:
38 |
39 | /var/www/vhosts/racktables.example1.com
40 | /var/www/vhosts/racktables.example2.com
41 | /var/www/vhosts/racktables.example3.com
42 |
43 | The configuration directories could be:
44 |
45 | # mkdir /etc/RackTables/example[123]
46 |
47 | The "wwwroot" directories will require a short PHP wrapper file each. The
48 | wrappers will differ only in the value of $racktables_confdir setting:
49 |
50 | # cat > /var/www/vhosts/racktables.example1.com/index.php <<
57 | EOF
58 |
59 | Once the wrapper files are installed, setup of each instance must be
60 | completed independently through the HTTP installer. Once this is done,
61 | every instance can be independently maintained, backed up and even deleted.
62 |
--------------------------------------------------------------------------------
/wwwroot/js/racktables.js:
--------------------------------------------------------------------------------
1 | // JavaScript functions
2 |
3 | // Used for (un)checking an entire row of rackspace atoms
4 | function toggleRowOfAtoms (rackId, rowId) {
5 | var checkboxId;
6 | var toSet;
7 | toSet = null;
8 | for (var i=0; i<=2; i++) {
9 | checkboxId = "atom_" + rackId + "_" + rowId + "_" + i;
10 |
11 | // Abort if the box is disabled
12 | if (document.getElementById(checkboxId).disabled == true) continue;
13 |
14 | // Box isn't disabled, toggle it
15 | if (toSet == null) {
16 | toSet = !document.getElementById(checkboxId).checked;
17 | }
18 | document.getElementById(checkboxId).checked = toSet;
19 | }
20 | }
21 |
22 | // Used for (un)checking an entire column of rackspace atoms
23 | function toggleColumnOfAtoms (rackId, columnId, numRows) {
24 | var checkboxId;
25 | var toSet;
26 | toSet = null;
27 | for (var i=1; i \$op_help,
20 | 'port:i' => \$op_port,
21 | 'connect-timeout:i' => \$op_connect_timeout,
22 | 'timeout:i' => \$op_timeout,
23 | 'prompt-delay:f' => \$op_delay,
24 | 'prompt:s' => \$op_prompt,
25 | );
26 | if ($op_help) {
27 | &display_help;
28 | exit;
29 | }
30 | my $op_host = $ARGV[0];
31 | defined $op_host or die "ERROR: please specify remote host (-h for help)";
32 | defined $op_prompt or die "ERROR: please specify prompt regexp (-h for help)";
33 | my $prompt_re = qr/$op_prompt/;
34 |
35 | sub display_help {
36 | print <new (
54 | Host => $op_host,
55 | Port => $port,
56 | Timeout => $op_connect_timeout,
57 | );
58 |
59 | use IO::Select;
60 | my $sel = new IO::Select($session);
61 |
62 | my $buff = '';
63 | my $nohang_read;
64 | until ($session->eof) {
65 | # read output from the device
66 | eval {
67 | $buff .= $session->get (Timeout => $nohang_read ? 0 : $op_timeout, Errmode => $nohang_read ? 'return' : 'die');
68 | };
69 | if ($@) {
70 | # check if there is something else in
71 | if (defined ) {
72 | die $@;
73 | }
74 | else {
75 | last; # no more input, seems like session was closed remotely by our last command
76 | }
77 | }
78 | $nohang_read = 0;
79 | print $1 if ($buff =~ s/(.*\n)//s);
80 |
81 | next unless ($buff =~ $prompt_re);
82 | # send pending commands to the device
83 | if ($op_delay and IO::Select->select ($sel, undef, undef, $op_delay)) {
84 | # something is received, no prompt detection at this time
85 | # set NOHANG options for next reading, cause it can be telnet control sequence
86 | $nohang_read = 1;
87 | }
88 | elsif (defined ($_ = )) {
89 | # replace all CR and LF symbols with single trailing LF
90 | s/[\015\012]//g;
91 | $session->put($_ . "\012");
92 | }
93 | else {
94 | # no more commands in input
95 | last;
96 | }
97 | }
98 | print $buff;
99 |
--------------------------------------------------------------------------------
/gateways/ucssdk:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
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 | # This script provides an online stdin/stdout interface to the list of an UCS
8 | # domain components. This is done through Python UcsSdk interfacing with the UCS
9 | # manager (domain controller) instance, a virtual service provided by physical
10 | # UCS Fabric Interconnect switches. The list is output in a text format and is
11 | # eventually available as PHP array through queryDevice() RackTables function.
12 | #
13 | # Script stdin is a multiline text in the following format:
14 | #
15 | # login
16 | # getmo
17 | #
18 | # Script stdout is also a multiline text consisting of OK/ERR lines optionally
19 | # preceded with other content. In the case of enumeration the content is a
20 | # series of COLUMNS and ROW lines with CSV data.
21 |
22 | import sys
23 | try:
24 | from UcsSdk import *
25 | handle = UcsHandle()
26 | except Exception, err:
27 | sys.stderr.write('UCS Python SDK is missing\n')
28 | sys.exit(2)
29 |
30 | loggedin = 0
31 | for line in sys.stdin:
32 | words = line.split()
33 | if len(words) == 0:
34 | continue
35 | elif len(words) >= 1 and words[0] == "help":
36 | print "HELP: login "
37 | print "HELP: Immediately try to log into specified UCS manager instance with given credentials."
38 | print "HELP: getmo"
39 | print "HELP: Retrieve lists of managed objects and output as a set of tables (requires active login)."
40 | print "OK"
41 | # endif "help"
42 | elif len(words) == 4 and words[0] == "login":
43 | try:
44 | if loggedin == 1:
45 | print "INFO Closing previous connection..."
46 | handle.Logout()
47 | if (handle.Login(words[1], words[2], words[3]) == False):
48 | loggedin = 0
49 | print "ERR could not log into " + words[1]
50 | sys.exit(0)
51 | loggedin = 1
52 | print "OK logged into " + words[1]
53 | except Exception, err:
54 | loggedin = 0
55 | print "ERR could not log into " + words[1]
56 | # endif "login"
57 | elif len(words) == 1 and words[0] == "getmo":
58 | if (loggedin != 1):
59 | print "ERR not logged in"
60 | else:
61 | try:
62 | print "COLUMNS type,serial,DN,model,OOB"
63 | for mo in handle.GetManagedObject(None, NetworkElement.ClassId()):
64 | print "ROW NetworkElement," + mo.Serial + "," + mo.Dn + "," + mo.Model + "," + mo.OobIfIp
65 | print "COLUMNS type,serial,DN,model"
66 | for ch in handle.GetManagedObject(None, EquipmentChassis.ClassId()):
67 | print "ROW EquipmentChassis," + ch.Serial + "," + ch.Dn + "," + ch.Model
68 | print "COLUMNS type,serial,DN,model,assigned,slot"
69 | for bl in handle.GetManagedObject(None, ComputeBlade.ClassId()):
70 | print "ROW ComputeBlade," + bl.Serial + "," + bl.Dn + "," + bl.Model + "," + bl.AssignedToDn + "," + bl.SlotId
71 | print "OK enumeration complete"
72 | except Exception, err:
73 | print "ERR exception occured, logging out"
74 | loggedin = 0
75 | # endif "getmo"
76 | else:
77 | print "ERR command not supported (type \"help\" for help)"
78 | # endfor
79 | sys.exit(0)
80 |
81 |
--------------------------------------------------------------------------------
/wwwroot/inc/pre-init.php:
--------------------------------------------------------------------------------
1 | PDO::ERRMODE_EXCEPTION,
61 | PDO::MYSQL_ATTR_INIT_COMMAND => 'set names "utf8"',
62 | );
63 | if (isset ($pdo_bufsize))
64 | $drvoptions[PDO::MYSQL_ATTR_MAX_BUFFER_SIZE] = $pdo_bufsize;
65 | try
66 | {
67 | $dbxlink = new PDO ($pdo_dsn, $db_username, $db_password, $drvoptions);
68 | }
69 | catch (PDOException $e)
70 | {
71 | throw new RackTablesError ("Database connection failed:\n\n" . $e->getMessage(), RackTablesError::INTERNAL);
72 | }
73 | }
74 |
75 | // tries to guess the existance of the file before the php's include using the same searching method.
76 | // in addition to calling file_exists, searches the current file's directory if the path is not looks
77 | // like neither absolute nor relative.
78 | function fileSearchExists ($filename)
79 | {
80 | if (! preg_match ('@^(\.+)?/@', $filename))
81 | {
82 | $this_file_dir = dirname (__FILE__);
83 | if (file_exists ($this_file_dir . '/' . $filename))
84 | return TRUE;
85 | }
86 | return file_exists ($filename);
87 | }
88 |
89 | ?>
90 |
--------------------------------------------------------------------------------
/wwwroot/inc/caching.php:
--------------------------------------------------------------------------------
1 | = $creation_ts && // not modified since
29 | (! $expire || $client_time + $expire >= $server_time) // expiration timeout is not set, or not expired
30 | );
31 | $last_modified = $creation_ts > 0 ? $creation_ts : ($client_time > 0 ? $client_time : $server_time);
32 |
33 | header ("Cache-Control: private, max-age=$expire, pre-check=$expire");
34 | if ($result)
35 | header ('Last-Modified: ' . gmdate (DATE_RFC1123, $last_modified), TRUE, 304);
36 | else
37 | header ('Last-Modified: ' . gmdate (DATE_RFC1123, $last_modified));
38 | return $result;
39 | }
40 |
41 | function HTTPDateToUnixTime ($string)
42 | {
43 | //Written per RFC 2616 3.3.1 - Full Date
44 | //http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html
45 | $month_number = array
46 | (
47 | 'Jan' => 1,
48 | 'Feb' => 2,
49 | 'Mar' => 3,
50 | 'Apr' => 4,
51 | 'May' => 5,
52 | 'Jun' => 6,
53 | 'Jul' => 7,
54 | 'Aug' => 8,
55 | 'Sep' => 9,
56 | 'Oct' => 10,
57 | 'Nov' => 11,
58 | 'Dec' => 12,
59 | );
60 |
61 | $formats = array();
62 | # RFC2616 dictates exchanged timestamps to be in GMT TZ, and RFC822
63 | # (which RFC1123 relies on) explicitly defines, that "GMT" is equivalent
64 | # to "-0000" and "+0000".
65 | $formats['rfc1123'] = '/^(Sun|Mon|Tue|Wed|Thu|Fri|Sat), (\d{2}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d{2}):(\d{2}):(\d{2}) (?:GMT|[-+]0000)$/';
66 | $formats['rfc850'] = '/^(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday), (\d{2})-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{2}) (\d{2}):(\d{2}):(\d{2}) (?:GMT|[-+]0000)$/';
67 | $formats['asctime'] = '/^(Sun|Mon|Tue|Wed|Thu|Fri|Sat) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{2}|\d{1}) (\d{2}):(\d{2}):(\d{2}) (\d{4})$/';
68 |
69 | $matches = array();
70 | if (preg_match ($formats['rfc1123'], $string, $matches))
71 | {
72 | $hours = $matches[5];
73 | $minutes = $matches[6];
74 | $seconds = $matches[7];
75 | $month = $month_number[$matches[3]];
76 | $day = $matches[2];
77 | $year = $matches[4];
78 | }
79 | elseif (preg_match ($formats['rfc850'], $string, $matches))
80 | {
81 | $hours = $matches[5];
82 | $minutes = $matches[6];
83 | $seconds = $matches[7];
84 | $month = $month_number[substr($matches[3],0,3)];
85 | $day = $matches[2];
86 | $year = $matches[4];
87 | }
88 | elseif (preg_match ($formats['asctime'], $string, $matches))
89 | {
90 | $hours = $matches[4];
91 | $minutes = $matches[5];
92 | $seconds = $matches[6];
93 | $month = $month_number[$matches[2]];
94 | $day = $matches[3];
95 | $year = $matches[7];
96 | }
97 | else
98 | return false;
99 | return gmmktime ($hours, $minutes, $seconds, $month, $day, $year);
100 | }
101 |
102 | ?>
103 |
--------------------------------------------------------------------------------
/wwwroot/js/tag-cb.js:
--------------------------------------------------------------------------------
1 | var tag_cb = new function () { // singletone class
2 |
3 | var self = this;
4 | this.enableNegation = function() { enableNegation = true; };
5 | var enableNegation = false;
6 |
7 | // called from interface.php:renderCellFilterPortlet() if SHRINK_TAG_TREE_ON_CLICK is set
8 | this.enableSubmitOnClick = function() { enableSubmitOnClick = true; };
9 | var enableSubmitOnClick = false;
10 |
11 | this.setTagShortList = function(list) { tagShortList = list; };
12 | var tagShortList = {};
13 |
14 | $(document).ready (function () {
15 | if (! enableNegation)
16 | return;
17 | $('.tag-cb').click(function (event) {
18 | cbClick(event, false);
19 | });
20 | $('.tag-cb').closest('label')
21 | .mousedown(function(){return false})
22 | .click(function (event) {
23 | cbClick(event, true);
24 | return false;
25 | });
26 | $('input[name=andor]').click(function (event) {
27 | if ($('.tag-cb:checked').size() != 0 && event.target.value == 'and') {
28 | $(event.target).closest('form')[0].submit();
29 | }
30 | });
31 | });
32 |
33 | // this is a handler for both checkbox click and label click
34 | // suppresses the default action, sets cb checked state and brings input focus on int
35 | // changes the name of checkbox if it is negated
36 | // submits form if this feature is enabled, and filter combination function is 'and'
37 | function cbClick (event, bInvert) {
38 | event.stopImmediatePropagation();
39 | var td = $(event.target).closest('td');
40 | var cb = td.find('.tag-cb');
41 | if (cb.length != 1)
42 | return;
43 | var tagId = cb.attr('value');
44 | var checked = cb.attr('checked');
45 | if (bInvert)
46 | checked = ! checked;
47 | if (event.ctrlKey && ! td.hasClass('inverted') && checked) {
48 | var name = cb.attr('name');
49 | if (name.match(/^cf([tp]\[\])$/))
50 | cb.attr('name', 'nf' + RegExp.$1);
51 | td.addClass ('inverted');
52 | }
53 | else {
54 | var name = cb.attr('name');
55 | if (name.match(/^nf([tp]\[\])$/))
56 | cb.attr('name', 'cf' + RegExp.$1);
57 | td.removeClass('inverted');
58 | }
59 | if (bInvert)
60 | cb.attr('checked', checked ? 'checked' : '');
61 | cb.focus();
62 |
63 | if (enableSubmitOnClick) {
64 | var and_check = $('input[name=andor][value=and]')[0];
65 | if (and_check.checked)
66 | $(event.target).closest('form')[0].submit();
67 | }
68 | }
69 |
70 | this.compactTreeMode = function() {
71 | // reconfigure toggle link
72 | var link = $('a.toggleTreeMode')[0];
73 | if ($(link).filter(':visible')) {
74 | $(link).after('');
75 | }
76 | link.onclick = function () {self.fullTreeMode(); return false;};
77 | $(link).html('show full tree').show();
78 |
79 | $('.tagtree').addClass('compact'); // disable hierachical padding
80 |
81 | var separator = false; // next visible row is separator
82 | var bPrevSeparator = true; // prev visible row was separator
83 | $('input.tag-cb').each(function (i, item) {
84 | var tr = $(item).closest('tr');
85 |
86 | if ($(item).hasClass('root'))
87 | separator = true;
88 |
89 | if (! item.checked && ! tagShortList[item.value]) {
90 | tr.hide();
91 | return;
92 | }
93 |
94 | if (separator && ! bPrevSeparator) { // do not draw two separators together or very first separator
95 | tr.addClass('separator');
96 | bPrevSeparator = true;
97 | }
98 | else {
99 | tr.removeClass('separator');
100 | bPrevSeparator = false;
101 | }
102 | separator = false;
103 | });
104 | }
105 |
106 | this.fullTreeMode = function() {
107 | // reconfigure toggle link
108 | var link = $('a.toggleTreeMode')[0];
109 | link.onclick = function () {self.compactTreeMode(); return false;};
110 | $(link).html('show compact tree').show();
111 |
112 | $('.tagtree').removeClass('compact'); // restore hierachical padding
113 |
114 | var bPrevSeparator = true; // prev visible row was separator
115 | $('input.tag-cb').each(function (i, item) { // // do not draw two separators together or very first separator
116 | var tr = $(item).closest('tr');
117 | tr.removeClass('separator');
118 |
119 | var separator = $(item).hasClass('root');
120 | if (separator && ! bPrevSeparator)
121 | tr.addClass('separator');
122 | bPrevSeparator = separator;
123 |
124 | tr.show();
125 | });
126 | }
127 |
128 | };
129 |
--------------------------------------------------------------------------------
/tests/GetChildrenListTest.php:
--------------------------------------------------------------------------------
1 | 1, 'dict_value' => 'unit test object type'));
26 | self::$objtype_id = lastInsertID ();
27 | commitSupplementOPC (self::$objtype_id, self::$objtype_id);
28 | self::$first_object_id = $parent_object_id = commitAddObject ('unit test object 0', NULL, self::$objtype_id, NULL);
29 | for ($i=1; $i<=self::$num_children; $i++)
30 | {
31 | $child_object_id = commitAddObject ("unit test object ${i}", NULL, self::$objtype_id, NULL);
32 | commitLinkEntities ('object', $parent_object_id, 'object', $child_object_id);
33 | $parent_object_id = $child_object_id;
34 | }
35 | self::$last_object_id = $parent_object_id;
36 |
37 | // add sample tags
38 | usePreparedInsertBlade ('TagTree', array ('tag' => 'unit test tag 0'));
39 | self::$first_tag_id = $parent_tag_id = lastInsertID ();
40 | for ($i=1; $i<=self::$num_children; $i++)
41 | {
42 | usePreparedInsertBlade ('TagTree', array ('parent_id' => $parent_tag_id, 'tag' => "unit test tag ${i}"));
43 | $parent_tag_id = lastInsertID ();
44 | }
45 | self::$last_tag_id = $parent_tag_id;
46 | }
47 |
48 | public static function tearDownAfterClass ()
49 | {
50 | usePreparedExecuteBlade ('SET foreign_key_checks=0');
51 |
52 | // remove sample locations
53 | usePreparedExecuteBlade
54 | (
55 | 'DELETE FROM Object WHERE id BETWEEN ? AND ?',
56 | array (self::$first_location_id, self::$last_location_id)
57 | );
58 | usePreparedExecuteBlade
59 | (
60 | "DELETE FROM EntityLink WHERE parent_entity_type='location' AND child_entity_type='location' " .
61 | 'AND ((parent_entity_id BETWEEN ? AND ?) OR (child_entity_id BETWEEN ? AND ?))',
62 | array
63 | (
64 | self::$first_location_id, self::$last_location_id,
65 | self::$first_location_id, self::$last_location_id
66 | )
67 | );
68 |
69 | // remove sample objects
70 | usePreparedExecuteBlade
71 | (
72 | 'DELETE FROM Object WHERE id BETWEEN ? AND ?',
73 | array (self::$first_object_id, self::$last_object_id)
74 | );
75 | usePreparedExecuteBlade
76 | (
77 | "DELETE FROM EntityLink WHERE parent_entity_type='object' AND child_entity_type='object' " .
78 | 'AND ((parent_entity_id BETWEEN ? AND ?) OR (child_entity_id BETWEEN ? AND ?))',
79 | array
80 | (
81 | self::$first_object_id, self::$last_object_id,
82 | self::$first_object_id, self::$last_object_id
83 | )
84 | );
85 | commitReduceOPC (self::$objtype_id, self::$objtype_id);
86 | usePreparedDeleteBlade ('Dictionary', array ('dict_key' => self::$objtype_id));
87 |
88 | // remove sample tags
89 | usePreparedExecuteBlade
90 | (
91 | 'DELETE FROM TagTree WHERE id BETWEEN ? AND ?',
92 | array (self::$first_tag_id, self::$last_tag_id)
93 | );
94 | }
95 |
96 | public function testGetLocationChildrenList ()
97 | {
98 | $children = getLocationChildrenList (self::$first_location_id);
99 | $this->assertCount (self::$num_children, $children);
100 | }
101 |
102 | public function testGetObjectChildrenList ()
103 | {
104 | $children = getObjectContentsList (self::$first_object_id);
105 | $this->assertCount (self::$num_children, $children);
106 | }
107 |
108 | public function testGetTagChildrenList ()
109 | {
110 | $children = getTagChildrenList (self::$first_tag_id);
111 | $this->assertCount (self::$num_children, $children);
112 | }
113 | }
114 | ?>
115 |
--------------------------------------------------------------------------------
/wwwroot/js/inplace-edit.js:
--------------------------------------------------------------------------------
1 | (function ($) { //unnamed singletone class
2 |
3 | var editMode = false;
4 | var visible_pen = $();
5 | var stop_propagation = false;
6 | var waiting_response = false;
7 | var editable_filter = 'span.editable';
8 |
9 | var span = null;
10 | var group = null;
11 | var input = null;
12 | var btn = null;
13 |
14 | $(document).ready (function() {
15 | $(editable_filter).each (function (i, iSpan) {
16 | var container = $('
')
17 | .mouseover(onSpanMouseOver);
18 | $(iSpan)
19 | .after (container)
20 | .detach()
21 | .appendTo (container);
22 | container
23 | .append
24 | (
25 | $(' ')
26 | .click(onPencilClick)
27 | );
28 | });
29 | $('body').mouseover(onBodyMouseOver);
30 | });
31 |
32 | function onSpanMouseOver (event) {
33 | if (editMode)
34 | return;
35 | stop_propagation = true;
36 | var pen = $(event.target).closest('.edit-container').find('.edit-btn');
37 | if (! visible_pen.length || visible_pen[0] != pen[0]) {
38 | visible_pen.hide();
39 | visible_pen = pen;
40 | visible_pen.show();
41 | }
42 | }
43 |
44 | function onBodyMouseOver () {
45 | if (!editMode && !stop_propagation) {
46 | visible_pen.hide();
47 | visible_pen = $();
48 | }
49 | stop_propagation = false;
50 | }
51 |
52 | function hideEditForm () {
53 | input = null;
54 | btn = null;
55 | group.remove();
56 | span.show();
57 | editMode = false;
58 | };
59 |
60 | function onPencilClick (event) {
61 | // hide original plain text comment
62 | span = $(event.target).closest('.edit-container').find(editable_filter);
63 | var width = span[0].offsetWidth + 50;
64 | if (width < 150)
65 | width = 150;
66 | span.hide();
67 |
68 | // hide pencil
69 | onBodyMouseOver();
70 | editMode = true;
71 |
72 | // construct editor form
73 | group = $(' ');
74 | input = $(' ')
75 | .val(span.html().replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'))
76 | .css('width', '' + width + 'px')
77 | .keydown(
78 | function (event) {
79 | var code = event.keyCode ? event.keyCode : event.which;
80 | if (code == 13)
81 | onFormSubmit();
82 | else if (code == 27)
83 | hideEditForm();
84 | })
85 | .appendTo(group);
86 | group.append(' ');
87 | btn = $(' ')
88 | .css('cursor', 'pointer')
89 | .click( onFormSubmit )
90 | .appendTo(group);
91 | span.after(group);
92 | input[0].focus();
93 | doSetCaretPosition (input[0], input[0].value.length);
94 |
95 | group.click(function(event) { event.stopPropagation(); });
96 | $('body').one('click',
97 | function (event) {
98 | if (! waiting_response)
99 | hideEditForm();
100 | onSpanMouseOver(event);
101 | });
102 | event.stopPropagation(); // prevent the initial click to immediately close edit form
103 | }
104 |
105 | function doSetCaretPosition (input, iCaretPos) {
106 | if (input.setSelectionRange) {
107 | input.setSelectionRange(iCaretPos, iCaretPos);
108 | }
109 | else if (input.createTextRange) {
110 | var range = input.createTextRange();
111 | range.moveEnd("character", iCaretPos);
112 | range.moveStart("character", iCaretPos);
113 | range.select();
114 | }
115 | }
116 |
117 | function onFormSubmit () {
118 | var text = input.val();
119 | input.attr('disabled', 'true');
120 | btn.replaceWith(' ');
121 | waiting_response = true;
122 |
123 | var data = {
124 | 'module': 'ajax',
125 | 'text': text
126 | };
127 | var list = span[0].className.split (/\s+/);
128 | for (var i in list) {
129 | var cn = list[i];
130 | var m;
131 | if (m = cn.match (/^(.+?)-(.*)/)) {
132 | data[m[1]] = m[2];
133 | }
134 | }
135 | if (! ('ac' in data))
136 | data['ac'] = data['op'];
137 |
138 | $.ajax({
139 | type: 'POST',
140 | url: 'index.php',
141 | data: data,
142 | success: function(data, textStatus, XMLHttpRequest) {
143 | if (data == 'OK')
144 | span.html(text);
145 | else
146 | alert ('Error updating port: ' + data);
147 | },
148 | error: function(jqXHR, textStatus, errorThrown) {
149 | alert ('Error updating port: ' + textStatus);
150 | },
151 | complete: function() {
152 | hideEditForm();
153 | waiting_response = false;
154 | }
155 | });
156 | }
157 |
158 | })(jQuery);
159 |
--------------------------------------------------------------------------------
/gateways/sshnokey:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | # This file is a part of RackTables, a datacenter and server room management
3 | # framework. See accompanying file "COPYING" for the full copyright and
4 | # licensing information.
5 | #
6 | # NOTE: Logging in via ssh using a password, whilst better then doing
7 | # the same via telnet/netcat, is still a bad idea when your network is
8 | # not properly secured. If you try to login to a compromised system
9 | # using a password, this password is now in the hands of the attackers.
10 | #
11 | # If possible, use the public key authenticated version instead. In case
12 | # that is not an option, consider different passwords for every system.
13 | #
14 | # To summerise, treat this as a slighhtly-better telnet client and make
15 | # sure the network this runs in is secure.
16 |
17 | use strict;
18 | use Getopt::Long;
19 | use Net::Telnet;
20 | use Net::OpenSSH;
21 |
22 | # fetch command-line parameters
23 | my $op_help;
24 | my $op_port;
25 | my $op_username;
26 | my $op_password;
27 | my $op_connect_timeout = 2;
28 | my $op_timeout = 10;
29 | my $op_prompt;
30 | my $op_delay = 0.01;
31 | GetOptions (
32 | 'h' => \$op_help,
33 | 'port:i' => \$op_port,
34 | 'connect-timeout:i' => \$op_connect_timeout,
35 | 'timeout:i' => \$op_timeout,
36 | 'prompt-delay:f' => \$op_delay,
37 | 'prompt:s' => \$op_prompt,
38 | 'username:s' => \$op_username,
39 | 'password:s' => \$op_password
40 | );
41 | if ($op_help) {
42 | &display_help;
43 | exit;
44 | }
45 | my $op_host = $ARGV[0];
46 | defined $op_host or die "ERROR: please specify remote host (-h for help)";
47 | defined $op_prompt or die "ERROR: please specify prompt regexp (-h for help)";
48 | my $prompt_re = qr/$op_prompt/;
49 |
50 | sub display_help {
51 | print <new(
70 | $op_host,
71 | 'port' => $op_port,
72 | 'user' => $op_username,
73 | 'password' => $op_password
74 | );
75 | $ssh->error and
76 | die "Couldn't establish SSH connection: ". $ssh->error;
77 |
78 | my ($pty, $pid) = $ssh->open2pty({stderr_to_stdout => 1})
79 | or die "unable to start remote shell: " . $ssh->error;
80 |
81 | my $session = Net::Telnet->new (
82 | Fhopen => $pty,
83 | # Host => $op_host,
84 | # Port => $port,
85 | # Timeout => $op_connect_timeout,
86 | Prompt => "/$op_prompt/",
87 | Telnetmode => 0,
88 | Cmd_remove_mode => 1,
89 | Output_record_separator => "\r"
90 | );
91 |
92 | #$session->cmd("term len 0");
93 |
94 |
95 | use IO::Select;
96 | my $sel = new IO::Select($session);
97 |
98 | my $buff = '';
99 | my $nohang_read;
100 | until ($session->eof) {
101 | # read output from the device
102 | eval {
103 | $buff .= $session->get (Timeout => $nohang_read ? 0 : $op_timeout, Errmode => $nohang_read ? 'return' : 'die');
104 | };
105 | if ($@) {
106 | # check if there is something else in
107 | if (defined ) {
108 | die $@;
109 | }
110 | else {
111 | last; # no more input, seems like session was closed remotely by our last command
112 | }
113 | }
114 | $nohang_read = 0;
115 | print $1 if ($buff =~ s/(.*\n)//s);
116 |
117 | next unless ($buff =~ $prompt_re);
118 | # send pending commands to the device
119 | if ($op_delay and IO::Select->select ($sel, undef, undef, $op_delay)) {
120 | # something is received, no prompt detection at this time
121 | # set NOHANG options for next reading, cause it can be telnet control sequence
122 | $nohang_read = 1;
123 | }
124 | elsif (defined ($_ = )) {
125 | # replace all CR and LF symbols with single trailing LF
126 | s/[\015\012]//g;
127 | $session->put($_ . "\012");
128 | }
129 | else {
130 | # no more commands in input
131 | last;
132 | }
133 | }
134 | print $buff;
135 |
--------------------------------------------------------------------------------
/tests/LinkTriggerTest.php:
--------------------------------------------------------------------------------
1 | fetchColumn ();
29 |
30 | // add sample data
31 | // - set port a & b's type to 1000Base-T
32 | // - set port c's type to the incompatible one
33 | self::$object_id = commitAddObject ('unit test object', NULL, 4, NULL);
34 | self::$porta = commitAddPort (self::$object_id, 'test porta', '1-24', NULL, NULL);
35 | self::$portb = commitAddPort (self::$object_id, 'test portb', '1-24', NULL, NULL);
36 | self::$portc = commitAddPort (self::$object_id, 'test portc', self::$portc_type, NULL, NULL);
37 | }
38 |
39 | public static function tearDownAfterClass ()
40 | {
41 | // restore AUTOPORTS_CONFIG to original setting
42 | if (self::$autoports_config_var != '')
43 | setConfigVar ('AUTOPORTS_CONFIG', self::$autoports_config_var);
44 |
45 | // remove sample data
46 | commitDeleteObject (self::$object_id);
47 | }
48 |
49 | public function tearDown ()
50 | {
51 | // delete any links created during the test
52 | usePreparedExecuteBlade
53 | (
54 | 'DELETE FROM Link WHERE porta IN (?,?,?) OR portb IN (?,?,?)',
55 | array (self::$porta, self::$portb, self::$portc, self::$porta, self::$portb, self::$portc)
56 | );
57 | }
58 |
59 | /**
60 | * @expectedException PDOException
61 | */
62 | public function testCreateLinkToSelf ()
63 | {
64 | usePreparedInsertBlade
65 | (
66 | 'Link',
67 | array ('porta' => self::$porta, 'portb' => self::$porta)
68 | );
69 | }
70 |
71 | /**
72 | * @expectedException PDOException
73 | */
74 | public function testUpdateLinkToSelf ()
75 | {
76 | usePreparedInsertBlade
77 | (
78 | 'Link',
79 | array ('porta' => self::$porta, 'portb' => self::$portb)
80 | );
81 | usePreparedUpdateBlade
82 | (
83 | 'Link',
84 | array ('porta' => self::$porta, 'portb' => self::$porta),
85 | array ('porta' => self::$porta, 'portb' => self::$portb)
86 | );
87 | }
88 |
89 | public function testCreateLinkWithPortAGreaterThanPortB ()
90 | {
91 | usePreparedInsertBlade
92 | (
93 | 'Link',
94 | array ('porta' => self::$portb, 'portb' => self::$porta)
95 | );
96 | $result = usePreparedSelectBlade
97 | (
98 | 'SELECT COUNT(*) FROM Link WHERE porta=? AND portb=?',
99 | array (self::$porta, self::$portb)
100 | );
101 | $this->assertEquals ($result->fetchColumn (), 1);
102 | }
103 |
104 | public function testUpdateLinkWithPortAGreaterThanPortB ()
105 | {
106 | usePreparedInsertBlade
107 | (
108 | 'Link',
109 | array ('porta' => self::$porta, 'portb' => self::$portb)
110 | );
111 | usePreparedUpdateBlade
112 | (
113 | 'Link',
114 | array ('porta' => self::$portb, 'portb' => self::$porta),
115 | array ('porta' => self::$porta, 'portb' => self::$portb)
116 | );
117 | $result = usePreparedSelectBlade
118 | (
119 | 'SELECT COUNT(*) FROM Link WHERE porta=? AND portb=?',
120 | array (self::$porta, self::$portb)
121 | );
122 | $this->assertEquals ($result->fetchColumn (), 1);
123 | }
124 |
125 | /**
126 | * @expectedException PDOException
127 | */
128 | public function testCreateLinkBetweenIncompatiblePorts ()
129 | {
130 | usePreparedInsertBlade
131 | (
132 | 'Link',
133 | array ('porta' => self::$porta, 'portb' => self::$portc)
134 | );
135 | }
136 |
137 | /**
138 | * @expectedException PDOException
139 | */
140 | public function testUpdateLinkBetweenIncompatiblePorts ()
141 | {
142 | usePreparedInsertBlade
143 | (
144 | 'Link',
145 | array ('porta' => self::$porta, 'portb' => self::$portb)
146 | );
147 | usePreparedUpdateBlade
148 | (
149 | 'Link',
150 | array ('porta' => self::$porta, 'portb' => self::$portc),
151 | array ('porta' => self::$porta, 'portb' => self::$portb)
152 | );
153 | }
154 | }
155 | ?>
156 |
--------------------------------------------------------------------------------
/wwwroot/js/jquery.thumbhover.js:
--------------------------------------------------------------------------------
1 | // This library is based on jquery.thumbhover.js from unknown author.
2 | // Far and away modified for using in RackTables.
3 | // Usage: jquery_object_a.thumbPopup(jquery_object_b, [options])
4 | // after that call, object_b will be hidden
5 | // object_a, when hovered, will show object_b floating and moving by the cursor.
6 | // When clicked on object_a, object_b will stay visible until outside click
7 | (function($) {
8 | $.fn.thumbPopup = function(popup, options)
9 | {
10 | //Combine the passed in options with the default settings
11 | var settings = jQuery.extend({
12 | //popupId: "thumbPopup",
13 | cursorTopOffset: 15,
14 | cursorLeftOffset: 15,
15 | event: null, // if set, the popup will be displayed immediately, and no mouse handlers will be binded to target
16 | showFreezeHint: true
17 | }, options);
18 |
19 | var freezeHint = null;
20 | var timeout_id = null;
21 | var hintHeight = 0;
22 | if (! freezeHint && settings.showFreezeHint && settings.event == null) {
23 | freezeHint = $('
').html('click to freeze').css('position', 'absolute').css('border', '1px solid black').css('background-color', 'white').appendTo('body');
24 | hintHeight = freezeHint[0].offsetHeight;
25 | freezeHint.hide();
26 | }
27 |
28 | if (! popup.length)
29 | return false;
30 | popup.css("position", "absolute").hide();
31 | $(this).css("cursor", "pointer");
32 |
33 | //Attach hover events that manage the popup
34 | if (settings.event != null)
35 | {
36 | setPopup (settings.event);
37 | stickPopup (settings.event);
38 | }
39 | else {
40 | $(this)
41 | .bind('mouseenter', setPopup)
42 | .bind('mousemove', updatePopupPosition)
43 | .bind('mouseleave', hidePopup)
44 | .click(stickPopup);
45 | }
46 |
47 | function stickPopup(event) {
48 | popup.data("sticked", true);
49 | if (freezeHint)
50 | freezeHint.hide();
51 | $('body').bind('click', function(event) {
52 | if (! (event.target == popup[0] || $(event.target).parents().filter(popup).length))
53 | {
54 | popup.data("sticked", false);
55 | hidePopup (event);
56 | }
57 | return true;
58 | });
59 | return false;
60 | }
61 |
62 | function ShowFreezeHint() {
63 | freezeHint.show();
64 | }
65 |
66 | function setPopup(event) {
67 | if (popup.data("sticked"))
68 | return;
69 | popup.data("hovered", true);
70 | updatePopupPosition(event);
71 | $(popup).show();
72 | }
73 |
74 | function updatePopupPosition(event) {
75 | var windowSize = getWindowSize();
76 | var popupSize = getPopupSize();
77 | var bPopupShownAbove = windowSize.height + windowSize.scrollTop < event.pageY + popupSize.height + settings.cursorTopOffset;
78 | if (freezeHint) {
79 | var deltaHint = bPopupShownAbove ? 20 : - 5 - hintHeight;
80 | freezeHint.hide();
81 | freezeHint.css('top', event.pageY + deltaHint).css('left', event.pageX);
82 | clearTimeout(timeout_id);
83 | timeout_id = setTimeout(ShowFreezeHint, 1000);
84 | }
85 | if (popup.data("sticked"))
86 | return;
87 | var left;
88 | if (windowSize.width + windowSize.scrollLeft < event.pageX + popupSize.width + settings.cursorLeftOffset){
89 | left = event.pageX - popupSize.width - settings.cursorLeftOffset;
90 | } else {
91 | left = event.pageX + settings.cursorLeftOffset;
92 | }
93 | // center pop-up if it does not fit entirely into window
94 | if (
95 | left < windowSize.scrollLeft ||
96 | left + popupSize.width > windowSize.scrollLeft + windowSize.width
97 | ) {
98 | left = (windowSize.width - popupSize.width) / 2;
99 | }
100 | $(popup).css("left", left);
101 |
102 | if (bPopupShownAbove) {
103 | $(popup).css("top", event.pageY - popupSize.height - settings.cursorTopOffset);
104 | } else {
105 | $(popup).css("top", event.pageY + settings.cursorTopOffset);
106 | }
107 | }
108 |
109 | function hidePopup(event) {
110 | popup.data("hovered", false);
111 | if (freezeHint) {
112 | freezeHint.hide();
113 | clearTimeout(timeout_id);
114 | }
115 | if (popup.data("sticked"))
116 | return;
117 | $(popup).hide();
118 | if (settings.event != null)
119 | $(popup).remove();
120 | }
121 |
122 | function getWindowSize() {
123 | return {
124 | scrollLeft: $(window).scrollLeft(),
125 | scrollTop: $(window).scrollTop(),
126 | width: $(window).width(),
127 | height: $(window).height()
128 | };
129 | }
130 |
131 | function getPopupSize() {
132 | return {
133 | width: $(popup).width(),
134 | height: $(popup).height()
135 | };
136 | }
137 |
138 | //Return original selection for chaining
139 | return this;
140 | };
141 | })(jQuery);
142 |
--------------------------------------------------------------------------------
/wwwroot/js/codemirror/htmlmixed.js:
--------------------------------------------------------------------------------
1 | CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
2 | var htmlMode = CodeMirror.getMode(config, {name: "xml",
3 | htmlMode: true,
4 | multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
5 | multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
6 | var cssMode = CodeMirror.getMode(config, "css");
7 |
8 | var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
9 | scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
10 | mode: CodeMirror.getMode(config, "javascript")});
11 | if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
12 | var conf = scriptTypesConf[i];
13 | scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
14 | }
15 | scriptTypes.push({matches: /./,
16 | mode: CodeMirror.getMode(config, "text/plain")});
17 |
18 | function html(stream, state) {
19 | var tagName = state.htmlState.tagName;
20 | var style = htmlMode.token(stream, state.htmlState);
21 | if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
22 | // Script block: mode to change to depends on type attribute
23 | var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
24 | scriptType = scriptType ? scriptType[1] : "";
25 | if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
26 | for (var i = 0; i < scriptTypes.length; ++i) {
27 | var tp = scriptTypes[i];
28 | if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
29 | if (tp.mode) {
30 | state.token = script;
31 | state.localMode = tp.mode;
32 | state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
33 | }
34 | break;
35 | }
36 | }
37 | } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
38 | state.token = css;
39 | state.localMode = cssMode;
40 | state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
41 | }
42 | return style;
43 | }
44 | function maybeBackup(stream, pat, style) {
45 | var cur = stream.current();
46 | var close = cur.search(pat), m;
47 | if (close > -1) stream.backUp(cur.length - close);
48 | else if (m = cur.match(/<\/?$/)) {
49 | stream.backUp(cur.length);
50 | if (!stream.match(pat, false)) stream.match(cur);
51 | }
52 | return style;
53 | }
54 | function script(stream, state) {
55 | if (stream.match(/^<\/\s*script\s*>/i, false)) {
56 | state.token = html;
57 | state.localState = state.localMode = null;
58 | return html(stream, state);
59 | }
60 | return maybeBackup(stream, /<\/\s*script\s*>/,
61 | state.localMode.token(stream, state.localState));
62 | }
63 | function css(stream, state) {
64 | if (stream.match(/^<\/\s*style\s*>/i, false)) {
65 | state.token = html;
66 | state.localState = state.localMode = null;
67 | return html(stream, state);
68 | }
69 | return maybeBackup(stream, /<\/\s*style\s*>/,
70 | cssMode.token(stream, state.localState));
71 | }
72 |
73 | return {
74 | startState: function() {
75 | var state = htmlMode.startState();
76 | return {token: html, localMode: null, localState: null, htmlState: state};
77 | },
78 |
79 | copyState: function(state) {
80 | if (state.localState)
81 | var local = CodeMirror.copyState(state.localMode, state.localState);
82 | return {token: state.token, localMode: state.localMode, localState: local,
83 | htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
84 | },
85 |
86 | token: function(stream, state) {
87 | return state.token(stream, state);
88 | },
89 |
90 | indent: function(state, textAfter) {
91 | if (!state.localMode || /^\s*<\//.test(textAfter))
92 | return htmlMode.indent(state.htmlState, textAfter);
93 | else if (state.localMode.indent)
94 | return state.localMode.indent(state.localState, textAfter);
95 | else
96 | return CodeMirror.Pass;
97 | },
98 |
99 | innerMode: function(state) {
100 | return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
101 | }
102 | };
103 | }, "xml", "javascript", "css");
104 |
105 | CodeMirror.defineMIME("text/html", "htmlmixed");
106 |
--------------------------------------------------------------------------------
/tests/ObjectCircularReferenceTest.php:
--------------------------------------------------------------------------------
1 | 1, 'dict_value' => 'unit test object type'));
16 | self::$objtype_id = lastInsertID ();
17 | commitSupplementOPC (self::$objtype_id, self::$objtype_id);
18 | self::$objecta_id = commitAddObject ('unit test object a', NULL, self::$objtype_id, NULL);
19 | self::$objectb_id = commitAddObject ('unit test object b', NULL, self::$objtype_id, NULL);
20 | self::$objectc_id = commitAddObject ('unit test object c', NULL, self::$objtype_id, NULL);
21 | self::$locationa_id = commitAddObject ('unit test location a', NULL, 1562, NULL);
22 | self::$locationb_id = commitAddObject ('unit test location b', NULL, 1562, NULL);
23 | self::$locationc_id = commitAddObject ('unit test location c', NULL, 1562, NULL);
24 | }
25 |
26 | public static function tearDownAfterClass ()
27 | {
28 | // remove sample data
29 | commitDeleteObject (self::$objecta_id);
30 | commitDeleteObject (self::$objectb_id);
31 | commitDeleteObject (self::$objectc_id);
32 | commitReduceOPC (self::$objtype_id, self::$objtype_id);
33 | usePreparedDeleteBlade ('Dictionary', array ('dict_key' => self::$objtype_id));
34 | commitDeleteObject (self::$locationa_id);
35 | commitDeleteObject (self::$locationb_id);
36 | commitDeleteObject (self::$locationc_id);
37 | }
38 |
39 | public function tearDown ()
40 | {
41 | // delete any links created during the test
42 | usePreparedExecuteBlade
43 | (
44 | "DELETE FROM EntityLink WHERE parent_entity_type='location' AND child_entity_type='location' " .
45 | 'AND (parent_entity_id IN (?,?,?) OR child_entity_id IN (?,?,?))',
46 | array
47 | (
48 | self::$locationa_id, self::$locationb_id, self::$locationc_id,
49 | self::$locationa_id, self::$locationb_id, self::$locationc_id
50 | )
51 | );
52 | usePreparedExecuteBlade
53 | (
54 | "DELETE FROM EntityLink WHERE parent_entity_type='object' AND child_entity_type='object' " .
55 | 'AND (parent_entity_id IN (?,?,?) OR child_entity_id IN (?,?,?))',
56 | array
57 | (
58 | self::$objecta_id, self::$objectb_id, self::$objectc_id,
59 | self::$objecta_id, self::$objectb_id, self::$objectc_id
60 | )
61 | );
62 | }
63 |
64 | /**
65 | * @expectedException RackTablesError
66 | */
67 | public function testCreateObjectCircularReference ()
68 | {
69 | // set A as the parent of B, and B as the parent of C
70 | commitLinkEntities ('object', self::$objecta_id, 'object', self::$objectb_id);
71 | commitLinkEntities ('object', self::$objectb_id, 'object', self::$objectc_id);
72 | // setting C as the parent of A should fail
73 | commitLinkEntities ('object', self::$objectc_id, 'object', self::$objecta_id);
74 | }
75 |
76 | /**
77 | * @expectedException RackTablesError
78 | */
79 | public function testUpdateObjectCircularReference ()
80 | {
81 | // set A as the parent of B, and B as the parent of C
82 | commitLinkEntities ('object', self::$objecta_id, 'object', self::$objectb_id);
83 | commitLinkEntities ('object', self::$objectb_id, 'object', self::$objectc_id);
84 | // reversing the link between B and C should fail
85 | commitUpdateEntityLink
86 | (
87 | 'object', self::$objectb_id, 'object', self::$objectc_id,
88 | 'object', self::$objectc_id, 'object', self::$objectb_id
89 | );
90 | }
91 |
92 | /**
93 | * @expectedException RackTablesError
94 | */
95 | public function testCreateLocationCircularReference ()
96 | {
97 | // set A as the parent of B, and B as the parent of C
98 | commitLinkEntities ('location', self::$locationa_id, 'location', self::$locationb_id);
99 | commitLinkEntities ('location', self::$locationb_id, 'location', self::$locationc_id);
100 | // setting C as the parent of A should fail
101 | commitLinkEntities ('location', self::$locationc_id, 'location', self::$locationa_id);
102 | }
103 |
104 | /**
105 | * @expectedException RackTablesError
106 | */
107 | public function testUpdateLocationCircularReference ()
108 | {
109 | // set A as the parent of B, and B as the parent of C
110 | commitLinkEntities ('location', self::$locationa_id, 'location', self::$locationb_id);
111 | commitLinkEntities ('location', self::$locationb_id, 'location', self::$locationc_id);
112 | // reversing the link between B and C should fail
113 | commitUpdateEntityLink
114 | (
115 | 'location', self::$locationb_id, 'location', self::$locationc_id,
116 | 'location', self::$locationc_id, 'location', self::$locationb_id
117 | );
118 | }
119 | }
120 | ?>
121 |
--------------------------------------------------------------------------------
/wwwroot/js/live_validation.js:
--------------------------------------------------------------------------------
1 | // This file has been downloaded from the following URL:
2 | // http://www.openjs.com/scripts/forms/live_validation/
3 | // (Live Validator 1.00.A Beta)
4 | // It was declared as released under BSD license at that moment.
5 | // The content below is a verbatim copy.
6 |
7 | var Validate = {
8 | elements:[],
9 | //Some General purpose functions
10 | hasClass:function(ele,cls) {
11 | return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
12 | },
13 | addClass:function (ele,cls) {
14 | if (!this.hasClass(ele,cls)) ele.className += " "+cls;
15 | },
16 | removeClass:function (ele,cls) {
17 | if (this.hasClass(ele,cls)) {
18 | var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
19 | ele.className=ele.className.replace(reg,' ');
20 | }
21 | },
22 | stopEvent:function(e) {
23 | //e.cancelBubble is supported by IE - this will kill the bubbling process.
24 | e.cancelBubble = true;
25 | e.returnValue = false;
26 | //e.stopPropagation works in Mozilla.
27 | if (e.stopPropagation) {
28 | e.stopPropagation();
29 | e.preventDefault();
30 | }
31 | },
32 | success:function(ele) {
33 | this.removeClass(ele,"validation-error");
34 | this.addClass(ele,"validation-success");
35 | },
36 | failure:function(ele) {
37 | this.removeClass(ele,"validation-success");
38 | this.addClass(ele,"validation-error");
39 | },
40 | //Logic starts here...
41 | //Deny keyboard input for some specific chars.
42 | validateKeys : function(e,ele) {
43 | //Find Which key is pressed
44 | if (e.keyCode) code = e.keyCode;
45 | else if (e.which) code = e.which;
46 | var character = String.fromCharCode(code);
47 |
48 | //We need only valid keypresses - not stuff like shift, Enter, Backspace etc.
49 | if( e.ctrlKey ||
50 | code == 46 //Delete Key
51 | ) return;
52 | if(e.shiftKey) {
53 | if(!(code >= 37 && code <= 40)) return; //Up,Down,Right and Left - same keycode as %,&,' and (
54 | } else {
55 | if(!(code >= 41 && code <= 126)) return;
56 | }
57 |
58 | if(ele.getAttribute("allowedkeys")) {
59 | var allowed_chars = new RegExp(ele.getAttribute("allowedkeys"));
60 | if(!allowed_chars.test(character)) { //If a character was entered that is not allowed.
61 | this.stopEvent(e);
62 | }
63 | }
64 | },
65 | //See if the match is made - this is called on every keyup event.
66 | testMatch : function(ele) {
67 | if(ele.getAttribute("match")) {
68 | var match_reg = new RegExp(ele.getAttribute("match"));
69 | if(match_reg.test(ele.value)) this.success(ele);
70 | else {
71 | this.failure(ele);
72 | return false;//Don't continue if it is a faluire
73 | }
74 | }
75 | if(ele.getAttribute("equals")) {
76 | if(ele.value == eval(ele.getAttribute("equals"))) this.success(ele);//Yes I know, 'evil eval'.
77 | else {
78 | this.failure(ele);
79 | return false;
80 | }
81 | }
82 | if(ele.getAttribute("istrue")) {
83 | if(eval(ele.getAttribute("istrue"))) this.success(ele);//Again, eval.
84 | else {
85 | this.failure(ele);
86 | return false;
87 | }
88 | }
89 | return true;
90 | },
91 | //Show error message on form submission
92 | attachForm : function(form_id) {
93 | var ths = this;//Closure
94 | $(form_id).onsubmit=function(e) {
95 | if(!e) var e = window.event;
96 | var ele = this;
97 | var err = 0;
98 | for(var i=0,len=ths.elements.length; i${path_to_secret_php}). " .
35 | "The configuration file is usually generated by RackTables installer, which " .
36 | "can be launched here .",
37 | RackTablesError::MISCONFIGURED
38 | );
39 |
40 | connectDB();
41 | transformRequestData();
42 | $configCache = loadConfigDefaults();
43 | $tab['reports']['local'] = getConfigVar ('enterprise');
44 |
45 | if (getConfigVar ('DB_VERSION') != CODE_VERSION)
46 | {
47 | echo 'This Racktables installation seems to be ' .
48 | 'just upgraded to version ' . CODE_VERSION . ', while the '.
49 | 'database version is ' . getConfigVar ('DB_VERSION') . '. No user will be ' .
50 | 'either authenticated or shown any page until the upgrade is ' .
51 | "finished. Follow this link and " .
52 | 'authenticate as administrator to finish the upgrade.
';
53 | exit (1);
54 | }
55 |
56 | if (!mb_internal_encoding ('UTF-8'))
57 | throw new RackTablesError ('Failed setting multibyte string encoding to UTF-8', RackTablesError::INTERNAL);
58 |
59 | $rackCodeCache = loadScript ('RackCodeCache');
60 | if ($rackCodeCache == NULL or !strlen ($rackCodeCache))
61 | {
62 | $rackCode = getRackCode (loadScript ('RackCode'));
63 | saveScript ('RackCodeCache', base64_encode (serialize ($rackCode)));
64 | }
65 | else
66 | {
67 | $rackCode = unserialize (base64_decode ($rackCodeCache));
68 | if ($rackCode === FALSE) // invalid cache
69 | {
70 | saveScript ('RackCodeCache', '');
71 | $rackCode = getRackCode (loadScript ('RackCode'));
72 | }
73 | }
74 |
75 | // avoid notices being thrown
76 | date_default_timezone_set (getConfigVar ('DATETIME_ZONE'));
77 |
78 | // Depending on the 'result' value the 'load' carries either the
79 | // parse tree or error message. The latter case is a bug, because
80 | // RackCode saving function was supposed to validate its input.
81 | if ($rackCode['result'] != 'ACK')
82 | throw new RackTablesError ($rackCode['load'], RackTablesError::INTERNAL);
83 | $rackCode = $rackCode['load'];
84 | // Only call buildPredicateTable() once and save the result, because it will remain
85 | // constant during one execution for constraints processing.
86 | $pTable = buildPredicateTable ($rackCode);
87 | // Constraints parse trees aren't cached in the database, so the least to keep
88 | // things running is to maintain application cache for them.
89 | $entityCache = array();
90 | // used by getExplicitTagsOnly()
91 | $tagRelCache = array();
92 |
93 | $taglist = getTagList();
94 | $tagtree = treeFromList ($taglist);
95 |
96 | $auto_tags = array();
97 | if (! isCLIMode() && isset ($_SERVER['REMOTE_ADDR']))
98 | $auto_tags[] = array ('tag' => '$client_' . $_SERVER['REMOTE_ADDR']);
99 |
100 | // Initial chain for the current user.
101 | $user_given_tags = array();
102 |
103 | // list of regexps used in findAutoTagWarnings to check RackCode.
104 | // add your regexps here to suppress 'Martian autotag' warnings
105 | $user_defined_atags = array();
106 |
107 | // This also can be modified in local.php.
108 | $pageheaders = array
109 | (
110 | 100 => " ",
111 | );
112 | addCSS ('css/pi.css');
113 |
114 | if (!isset ($script_mode) or $script_mode !== TRUE)
115 | {
116 | // A successful call to authenticate() always generates autotags and somethimes
117 | // even given/implicit tags. It also sets remote_username and remote_displayname.
118 | authenticate();
119 | // Authentication passed.
120 | // Note that we don't perform autorization here, so each 1st level page
121 | // has to do it in its way, e.g. by calling authorize() after fixContext().
122 | }
123 | elseif (! isset ($remote_username))
124 | {
125 | // Some functions require remote_username to be set to something to act correctly,
126 | // even though they don't use the value itself.
127 | $admin_account = spotEntity ('user', 1);
128 | if (isCLIMode() && FALSE !== $env_user = getenv('USER'))
129 | // use USER env var if we are in CLI mode
130 | $remote_username = $env_user;
131 | else
132 | $remote_username = $admin_account['user_name'];
133 | unset ($env_user);
134 | unset ($admin_account);
135 | }
136 |
137 | $virtual_obj_types = explode (',', getConfigVar ('VIRTUAL_OBJ_LISTSRC'));
138 |
139 | alterConfigWithUserPreferences();
140 | $op = '';
141 |
142 | // load additional plugins
143 | ob_start();
144 | foreach (glob("$racktables_plugins_dir/*.php") as $filename)
145 | require_once $filename;
146 | // display plugins output if it contains something but newlines
147 | $tmp = ob_get_clean();
148 | if ($tmp != '' and ! preg_match ("/^\n+$/D", $tmp))
149 | echo $tmp;
150 | unset ($tmp);
151 |
152 | // These will be filled in by fixContext()
153 | $expl_tags = array();
154 | $impl_tags = array();
155 | // Initial chain for the current target.
156 | $target_given_tags = array();
157 |
158 | callHook ('initFinished');
159 |
160 | ?>
161 |
--------------------------------------------------------------------------------
/scripts/syncdomain.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | \n";
14 | echo "\t\t--vdid=\n";
15 | echo "\t\t--mode=pull\n";
16 | echo "\t\t--mode=pullall\n";
17 | echo "\t\t--mode=push\n";
18 | echo "\t\t[--max=]\n";
19 | echo "\t\t[--verbose]\n";
20 | echo "\t\t[--nolock]\n";
21 | echo "\t\t[--stderr]\n";
22 | exit (1);
23 | }
24 |
25 | define ('PML_VERBOSE', 1 << 0); // display message only if --verbose option specified
26 | define ('PML_NOTICE', 1 << 1); // the message is informational, do not write to STDERR
27 | function print_message_line($text, $flags = 0)
28 | {
29 | global $options;
30 | if (! array_key_exists ('verbose', $options) and $flags & PML_VERBOSE)
31 | return;
32 | $buff = date (DATE_RFC1123) . ": ${text}\n";
33 | echo $buff;
34 | if (array_key_exists ('stderr', $options) and ! ($flags & PML_NOTICE))
35 | fwrite (STDERR, $buff);
36 | }
37 |
38 | $options = getopt ('', array ('vdid:', 'max::', 'mode:', 'verbose', 'nolock', 'stderr'));
39 | if (!array_key_exists ('mode', $options))
40 | usage();
41 |
42 | switch ($options['mode'])
43 | {
44 | case 'pullall':
45 | $do_push = FALSE;
46 | break;
47 | case 'pull':
48 | $do_push = FALSE;
49 | break;
50 | case 'push':
51 | $do_push = TRUE;
52 | break;
53 | default:
54 | usage();
55 | }
56 |
57 | $max = array_fetch ($options, 'max', 0);
58 | $nolock = array_key_exists ('nolock', $options);
59 |
60 | $switch_list = array();
61 | if (! isset ($options['vdid']))
62 | $switch_list = getVLANSwitches();
63 | else
64 | try
65 | {
66 | $mydomain = getVLANDomain ($options['vdid']);
67 | foreach ($mydomain['switchlist'] as $switch)
68 | $switch_list[] = $switch['object_id'];
69 | }
70 | catch (RackTablesError $e)
71 | {
72 | print_message_line ("Cannot load domain data with ID ${options['vdid']}");
73 | print_message_line ($e->getMessage());
74 | exit (1);
75 | }
76 |
77 | $todo = array
78 | (
79 | 'pull' => array ('sync_ready', 'resync_ready'),
80 | 'push' => array ('sync_ready', 'resync_ready'),
81 | 'pullall' => array ('sync_ready', 'resync_ready', 'sync_aging', 'resync_aging', 'done'),
82 | );
83 |
84 | if (! $nolock)
85 | {
86 | $domain_key = isset ($options['vdid']) ? $options['vdid'] : 0;
87 | $filename = '/var/tmp/RackTables-syncdomain-' . $domain_key . '.pid';
88 | if (FALSE === $fp = @fopen ($filename, 'c+'))
89 | {
90 | print_message_line ("Failed to open ${filename}");
91 | exit (1);
92 | }
93 | $wouldblock = 0;
94 | if (! flock ($fp, LOCK_EX|LOCK_NB, $wouldblock) || $wouldblock)
95 | {
96 | $current_time = time();
97 | $stat = fstat ($fp);
98 | if (! isset ($stat['mtime']))
99 | {
100 | print_message_line ("Failed to obtain mtime of ${filename}");
101 | exit (1);
102 | }
103 | $pidfile_mtime = $stat['mtime'];
104 | if ($current_time < $pidfile_mtime)
105 | {
106 | print_message_line ("Warning: pidfile ${filename} mtime is in future!");
107 | exit (1);
108 | }
109 | // don't indicate failure unless the pidfile is 15 minutes or more old
110 | if ($current_time < $pidfile_mtime + 15 * 60)
111 | exit (0);
112 | print_message_line ("Failed to lock ${filename}, already locked by PID " . trim (fgets ($fp, 10)));
113 | exit (1);
114 | }
115 |
116 | ftruncate ($fp, 0);
117 | fwrite ($fp, getmypid() . "\n");
118 | // don't close $fp yet: we need to keep an flock
119 | }
120 |
121 | // fetch all the needed data from DB (preparing for DB connection loss)
122 | $switch_queue = array();
123 | foreach ($switch_list as $object_id)
124 | {
125 | $cell = spotEntity ('object', $object_id);
126 | $new_disabled = ! considerConfiguredConstraint ($cell, 'SYNC_802Q_LISTSRC');
127 | $queue = detectVLANSwitchQueue (getVLANSwitchInfo ($object_id));
128 | if ($queue == 'disabled' xor $new_disabled)
129 | usePreparedExecuteBlade
130 | (
131 | 'UPDATE VLANSwitch SET out_of_sync="yes", last_error_ts=NOW(), last_errno=? WHERE object_id=?',
132 | array ($new_disabled ? E_8021Q_SYNC_DISABLED : E_8021Q_NOERROR, $object_id)
133 | );
134 | elseif (in_array ($queue, $todo[$options['mode']]))
135 | $switch_queue[] = $cell;
136 | }
137 |
138 | // YOU SHOULD NOT USE DB FUNCTIONS BELOW IN THE PARENT PROCESS
139 | // THE PARENT'S DB CONNECTION IS LOST DUE TO RECONNECTING IN THE CHILD
140 | $fork_slots = getConfigVar ('SYNCDOMAIN_MAX_PROCESSES');
141 | $do_fork = ($fork_slots > 1) and extension_loaded ('pcntl');
142 | if ($fork_slots > 1 and ! $do_fork)
143 | throw new RackTablesError ('PHP extension \'pcntl\' not found, can not use childs', RackTablesError::MISCONFIGURED);
144 | $switches_working = 0;
145 | $switchesdone = 0;
146 | foreach ($switch_queue as $object)
147 | {
148 | if ($do_fork)
149 | {
150 | // wait for the next free slot
151 | while ($fork_slots <= $switches_working)
152 | {
153 | pcntl_waitpid (-1, $wait_status);
154 | --$switches_working;
155 | }
156 | $i_am_child = (0 === $fork_res = pcntl_fork());
157 | }
158 | if (! $do_fork or $i_am_child)
159 | {
160 | try
161 | {
162 | // make a separate DB connection for correct concurrent transactions handling
163 | if ($i_am_child)
164 | connectDB();
165 | $portsdone = exec8021QDeploy ($object['id'], $do_push);
166 | $flags = PML_NOTICE;
167 | if (! $portsdone)
168 | $flags |= PML_VERBOSE;
169 | print_message_line ("Done '${object['dname']}': ${portsdone}", $flags);
170 | }
171 | catch (RackTablesError $e)
172 | {
173 | print_message_line ("FAILED '${object['dname']}': " . $e->getMessage());
174 | }
175 | if ($i_am_child)
176 | exit (0);
177 | }
178 | if (isset ($fork_res) and $fork_res > 0)
179 | ++$switches_working;
180 |
181 | if (++$switchesdone == $max)
182 | {
183 | print_message_line ("Maximum of ${max} items reached, terminating", PML_NOTICE|PML_VERBOSE);
184 | break;
185 | }
186 | }
187 |
188 | // wait for all childs to exit
189 | while ($switches_working > 0)
190 | {
191 | --$switches_working;
192 | pcntl_waitpid (-1, $wait_status);
193 | }
194 |
195 | if (! $nolock)
196 | {
197 | flock ($fp, LOCK_UN); // explicitly unlock file as PHP 5.3.2 made it mandatory
198 | if (FALSE === unlink ($filename))
199 | {
200 | print_message_line ("Failed removing pidfile ${filename}");
201 | exit (1);
202 | }
203 | }
204 | exit (0);
205 | ?>
206 |
--------------------------------------------------------------------------------
/wwwroot/css/jquery.contextmenu.css:
--------------------------------------------------------------------------------
1 | /* Classic Windows Theme (default) */
2 | /* =============================== */
3 | .context-menu-theme-default {
4 | border:2px outset white;
5 | background-color:#D4D0C8;
6 | }
7 | .context-menu-theme-default .context-menu-item {
8 | text-align:left;
9 | cursor:pointer;
10 | padding:4px 28px 4px 16px;
11 | color:black;
12 | font-family:Tahoma,Arial;
13 | font-size:11px;
14 | }
15 | .context-menu-theme-default .context-menu-separator {
16 | margin:4px 2px;
17 | font-size:0px;
18 | border-top:1px solid #808080;
19 | border-bottom:1px solid white;
20 | }
21 | .context-menu-theme-default .context-menu-item-disabled {
22 | color:#808080;
23 | }
24 | .context-menu-theme-default .context-menu-item .context-menu-item-inner {
25 | background:none no-repeat fixed 999px 999px; /* Make sure icons don't appear */
26 | }
27 | .context-menu-theme-default .context-menu-item-hover {
28 | background-color:#0A246A;
29 | color:white;
30 | }
31 | .context-menu-theme-default .context-menu-item-disabled-hover {
32 | background-color:#0A246A;
33 | }
34 |
35 | /* Windows XP Theme */
36 | /* ================ */
37 | .context-menu-theme-xp {
38 | border:1px solid #666;
39 | padding:1px;
40 | background:#F9F8F7 repeat-y top left;
41 | }
42 | .context-menu-theme-xp .context-menu-separator {
43 | margin:4px 2px;
44 | font-size:0px;
45 | border-top:1px solid #808080;
46 | border-bottom:1px solid white;
47 | }
48 | .context-menu-theme-xp .context-menu-item {
49 | text-align:left;
50 | color:black;
51 | font-family:arial;
52 | font-size:11px;
53 | cursor:pointer;
54 | }
55 | .context-menu-theme-xp .context-menu-item .context-menu-item-inner {
56 | background:none no-repeat 2px center;
57 | padding:4px 10px 4px 30px;
58 | }
59 | .context-menu-theme-xp .context-menu-item-hover .context-menu-item-inner {
60 | background:#B6BDD2 none no-repeat 2px center;
61 | padding:3px 9px 3px 29px;
62 | border:1px solid #0A246A;
63 | }
64 |
65 | /* Windows Vista Theme */
66 | /* =================== */
67 | .context-menu-theme-vista {
68 | background:#FAFAFA repeat-y left top;
69 | border:1px solid #868686;
70 | }
71 | .context-menu-theme-vista .context-menu-item {
72 | text-align:left;
73 | cursor:pointer;
74 | color:black;
75 | font-family:Tahoma,Arial;
76 | font-size:11px;
77 | }
78 | .context-menu-theme-vista .context-menu-separator {
79 | margin:0px 0px 0px 32px;
80 | font-size:0px;
81 | border-top:1px solid #C5C5C5;
82 | border-bottom:1px solid #F5F5F5;
83 | }
84 | .context-menu-theme-vista .context-menu-item-hover {
85 | background:transparent repeat-x left center;
86 | border:1px solid #D7D0B3;
87 | }
88 | .context-menu-theme-vista .context-menu-item .context-menu-item-inner {
89 | padding:4px 16px 4px 35px;
90 | margin-left:1px;
91 | background-color:none;
92 | background-repeat:no-repeat;
93 | background-position:3px center;
94 | background-image:none;
95 | }
96 | .context-menu-theme-vista .context-menu-item-hover .context-menu-item-inner {
97 | padding:3px 15px 3px 35px;
98 | margin-left:0px;
99 | }
100 | .context-menu-theme-vista .context-menu-item-disabled {
101 | color:#A7A7A7;
102 | }
103 |
104 | /* OSX Theme */
105 | /* ========= */
106 | .context-menu-theme-osx {
107 | background-color:white;
108 | opacity: .93;
109 | filter: alpha(opacity=93);
110 | zoom:1.0;
111 | border:1px solid #b2b2b2;
112 | }
113 | .context-menu-theme-osx .context-menu-item {
114 | text-align:left;
115 | cursor:pointer;
116 | color:black;
117 | font-family:Lucida Grande,Arial;
118 | font-weight:700;
119 | font-size:12px;
120 | opacity: 1.0;
121 | filter: alpha(opacity=100);
122 | z-index:1;
123 | }
124 | .context-menu-theme-osx .context-menu-separator {
125 | margin:5px 1px 4px 1px;
126 | font-size:0px;
127 | border-top:1px solid #e4e4e4;
128 | }
129 | .context-menu-theme-osx .context-menu-item-hover {
130 | background-color:#1C44F2;
131 | color:white;
132 | }
133 | .context-menu-theme-osx .context-menu-item .context-menu-item-inner {
134 | padding:2px 10px 2px 22px;
135 | background-color:none;
136 | background-repeat:no-repeat;
137 | background-position:4px center;
138 | background-image:none;
139 | }
140 | .context-menu-theme-osx .context-menu-item-disabled {
141 | color:#939393;
142 | }
143 |
144 | /* Linux Human Theme */
145 | /* ================= */
146 | .context-menu-theme-human {
147 | background:#F9F5F2;
148 | border:1px solid #963;
149 | }
150 | .context-menu-theme-human .context-menu-item {
151 | text-align:left;
152 | cursor:pointer;
153 | color:black;
154 | font-family:Helvetica,DejaVu Sans,Arial;
155 | font-size:12px;
156 | line-height:20px;
157 | height:28px;
158 | border:1px solid #F9F5F2;
159 | border-left:0;
160 | border-right:0;
161 | }
162 | .context-menu-theme-human .context-menu-separator {
163 | margin:0px 0px 0px 32px;
164 | font-size:0px;
165 | border-top:1px solid #C5C5C5;
166 | border-bottom:1px solid #F5F5F5;
167 | }
168 | .context-menu-theme-human .context-menu-item-hover {
169 | background:transparent repeat-x left center;
170 | border-color:#963;
171 | }
172 | .context-menu-theme-human .context-menu-item .context-menu-item-inner {
173 | padding:4px 16px 4px 35px;
174 | margin-left:0px;
175 | background-color:none;
176 | background-repeat:no-repeat;
177 | background-position:3px center;
178 | background-image:none;
179 | }
180 | .context-menu-theme-human .context-menu-item-hover .context-menu-item-inner {
181 | }
182 | .context-menu-theme-human .context-menu-item-disabled {
183 | color:#A7A7A7;
184 | }
185 |
186 | /* Gloss Theme */
187 | /* =========== */
188 | .context-menu-theme-gloss {
189 | background:#f4f4f4 repeat-y left center;
190 | border:1px solid #f4f4f4;
191 | padding:1px;
192 | padding-right:0;
193 | }
194 | .context-menu-theme-gloss .context-menu-item {
195 | text-align:left;
196 | cursor:pointer;
197 | color:black;
198 | font-family:Helvetica,DejaVu Sans,Arial;
199 | font-size:12px;
200 | line-height:20px;
201 | height:27px;
202 | border:1px solid transparent;
203 | }
204 | .context-menu-theme-gloss .context-menu-separator {
205 | margin:0px 0px 0px 32px;
206 | font-size:0px;
207 | border-top:1px solid #C5C5C5;
208 | border-bottom:1px solid #F5F5F5;
209 | }
210 | .context-menu-theme-gloss .context-menu-item-hover {
211 | background:transparent repeat-x left center;
212 | color:#fff;
213 | border-color:#000;
214 | border-radius: 3px;
215 | -webkit-border-radius: 3px;
216 | -moz-border-radius: 3px;
217 | }
218 | .context-menu-theme-gloss .context-menu-item .context-menu-item-inner {
219 | padding:4px 16px 4px 35px;
220 | margin-left:0px;
221 | background-color:none;
222 | background-repeat:no-repeat;
223 | background-position:3px center;
224 | background-image:none;
225 | }
226 | .context-menu-theme-gloss .context-menu-item-hover .context-menu-item-inner {
227 | }
228 | .context-menu-theme-gloss .context-menu-item-disabled {
229 | color:#A7A7A7;
230 | }
231 |
232 | .context-menu-theme-gloss-cyan .context-menu-item-hover {
233 | border-color:#00c;
234 | }
235 |
236 | .context-menu-theme-gloss-semitransparent .context-menu-item-hover {
237 | border-color:#00c;
238 | background-color:#30f;
239 | }
240 |
241 |
--------------------------------------------------------------------------------
/wwwroot/js/codemirror/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 500px;
7 | width:100%;
8 | }
9 | .CodeMirror-scroll {
10 | /* Set scrolling behaviour here */
11 | overflow: auto;
12 | }
13 |
14 | /* PADDING */
15 |
16 | .CodeMirror-lines {
17 | padding: 4px 0; /* Vertical padding around content */
18 | }
19 | .CodeMirror pre {
20 | padding: 0 4px; /* Horizontal padding of content */
21 | }
22 |
23 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
24 | background-color: white; /* The little square between H and V scrollbars */
25 | }
26 |
27 | /* GUTTER */
28 |
29 | .CodeMirror-gutters {
30 | border-right: 1px solid #ddd;
31 | background-color: #f7f7f7;
32 | white-space: nowrap;
33 | }
34 | .CodeMirror-linenumbers {}
35 | .CodeMirror-linenumber {
36 | padding: 0 3px 0 5px;
37 | min-width: 20px;
38 | text-align: right;
39 | color: #999;
40 | -moz-box-sizing: content-box;
41 | box-sizing: content-box;
42 | }
43 |
44 | /* CURSOR */
45 |
46 | .CodeMirror div.CodeMirror-cursor {
47 | border-left: 1px solid black;
48 | z-index: 3;
49 | }
50 | /* Shown when moving in bi-directional text */
51 | .CodeMirror div.CodeMirror-secondarycursor {
52 | border-left: 1px solid silver;
53 | }
54 | .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
55 | width: auto;
56 | border: 0;
57 | background: #7e7;
58 | z-index: 1;
59 | }
60 | /* Can style cursor different in overwrite (non-insert) mode */
61 | .CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
62 |
63 | .cm-tab { display: inline-block; }
64 |
65 | .CodeMirror-ruler {
66 | border-left: 1px solid #ccc;
67 | position: absolute;
68 | }
69 |
70 | /* DEFAULT THEME */
71 |
72 | .cm-s-default .cm-keyword {color: #708;}
73 | .cm-s-default .cm-atom {color: #219;}
74 | .cm-s-default .cm-number {color: #164;}
75 | .cm-s-default .cm-def {color: #00f;}
76 | .cm-s-default .cm-variable {color: black;}
77 | .cm-s-default .cm-variable-2 {color: #05a;}
78 | .cm-s-default .cm-variable-3 {color: #085;}
79 | .cm-s-default .cm-property {color: black;}
80 | .cm-s-default .cm-operator {color: blue;}
81 | .cm-s-default .cm-comment {color: #a50;}
82 | .cm-s-default .cm-string {color: #a11;}
83 | .cm-s-default .cm-string-2 {color: #f50;}
84 | .cm-s-default .cm-meta {color: #555;}
85 | .cm-s-default .cm-qualifier {color: #555;}
86 | .cm-s-default .cm-builtin {color: #30a;}
87 | .cm-s-default .cm-bracket {color: #997;}
88 | .cm-s-default .cm-tag {color: orange;}
89 | .cm-s-default .cm-attribute {color: #00c;}
90 | .cm-s-default .cm-header {color: blue;}
91 | .cm-s-default .cm-quote {color: #090;}
92 | .cm-s-default .cm-hr {color: #999;}
93 | .cm-s-default .cm-link {color: #00c;}
94 |
95 | .cm-negative {color: #d44;}
96 | .cm-positive {color: #292;}
97 | .cm-header, .cm-strong {font-weight: bold;}
98 | .cm-em {font-style: italic;}
99 | .cm-link {text-decoration: underline;}
100 |
101 | .cm-s-default .cm-error {color: #f00;}
102 | .cm-invalidchar {color: #f00;}
103 |
104 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
105 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
106 | .CodeMirror-activeline-background {background: #e8f2ff;}
107 |
108 | /* STOP */
109 |
110 | /* The rest of this file contains styles related to the mechanics of
111 | the editor. You probably shouldn't touch them. */
112 |
113 | .CodeMirror {
114 | line-height: 1;
115 | position: relative;
116 | overflow: hidden;
117 | background: white;
118 | color: black;
119 | }
120 |
121 | .CodeMirror-scroll {
122 | /* 30px is the magic margin used to hide the element's real scrollbars */
123 | /* See overflow: hidden in .CodeMirror */
124 | margin-bottom: -30px; margin-right: -30px;
125 | padding-bottom: 30px;
126 | height: 100%;
127 | outline: none; /* Prevent dragging from highlighting the element */
128 | position: relative;
129 | -moz-box-sizing: content-box;
130 | box-sizing: content-box;
131 | }
132 | .CodeMirror-sizer {
133 | position: relative;
134 | border-right: 30px solid transparent;
135 | -moz-box-sizing: content-box;
136 | box-sizing: content-box;
137 | }
138 |
139 | /* The fake, visible scrollbars. Used to force redraw during scrolling
140 | before actuall scrolling happens, thus preventing shaking and
141 | flickering artifacts. */
142 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
143 | position: absolute;
144 | z-index: 6;
145 | display: none;
146 | }
147 | .CodeMirror-vscrollbar {
148 | right: 0; top: 0;
149 | overflow-x: hidden;
150 | overflow-y: scroll;
151 | }
152 | .CodeMirror-hscrollbar {
153 | bottom: 0; left: 0;
154 | overflow-y: hidden;
155 | overflow-x: scroll;
156 | }
157 | .CodeMirror-scrollbar-filler {
158 | right: 0; bottom: 0;
159 | }
160 | .CodeMirror-gutter-filler {
161 | left: 0; bottom: 0;
162 | }
163 |
164 | .CodeMirror-gutters {
165 | position: absolute; left: 0; top: 0;
166 | padding-bottom: 30px;
167 | z-index: 3;
168 | }
169 | .CodeMirror-gutter {
170 | white-space: normal;
171 | height: 100%;
172 | -moz-box-sizing: content-box;
173 | box-sizing: content-box;
174 | padding-bottom: 30px;
175 | margin-bottom: -32px;
176 | display: inline-block;
177 | /* Hack to make IE7 behave */
178 | *zoom:1;
179 | *display:inline;
180 | }
181 | .CodeMirror-gutter-elt {
182 | position: absolute;
183 | cursor: default;
184 | z-index: 4;
185 | }
186 |
187 | .CodeMirror-lines {
188 | cursor: text;
189 | }
190 | .CodeMirror pre {
191 | /* Reset some styles that the rest of the page might have set */
192 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
193 | border-width: 0;
194 | background: transparent;
195 | font-family: inherit;
196 | font-size: inherit;
197 | margin: 0;
198 | white-space: pre;
199 | word-wrap: normal;
200 | line-height: inherit;
201 | color: inherit;
202 | z-index: 2;
203 | position: relative;
204 | overflow: visible;
205 | }
206 | .CodeMirror-wrap pre {
207 | word-wrap: break-word;
208 | white-space: pre-wrap;
209 | word-break: normal;
210 | }
211 |
212 | .CodeMirror-linebackground {
213 | position: absolute;
214 | left: 0; right: 0; top: 0; bottom: 0;
215 | z-index: 0;
216 | }
217 |
218 | .CodeMirror-linewidget {
219 | position: relative;
220 | z-index: 2;
221 | overflow: auto;
222 | }
223 |
224 | .CodeMirror-widget {}
225 |
226 | .CodeMirror-wrap .CodeMirror-scroll {
227 | overflow-x: hidden;
228 | }
229 |
230 | .CodeMirror-measure {
231 | position: absolute;
232 | width: 100%;
233 | height: 0;
234 | overflow: hidden;
235 | visibility: hidden;
236 | }
237 | .CodeMirror-measure pre { position: static; }
238 |
239 | .CodeMirror div.CodeMirror-cursor {
240 | position: absolute;
241 | visibility: hidden;
242 | border-right: none;
243 | width: 0;
244 | }
245 | .CodeMirror-focused div.CodeMirror-cursor {
246 | visibility: visible;
247 | }
248 |
249 | .CodeMirror-selected { background: #d9d9d9; }
250 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
251 |
252 | .cm-searching {
253 | background: #ffa;
254 | background: rgba(255, 255, 0, .4);
255 | }
256 |
257 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
258 | .CodeMirror span { *vertical-align: text-bottom; }
259 |
260 | @media print {
261 | /* Hide the cursor when printing */
262 | .CodeMirror div.CodeMirror-cursor {
263 | visibility: hidden;
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/wwwroot/js/portinfo.js:
--------------------------------------------------------------------------------
1 | if (enabled_elements == null)
2 | enabled_elements = [];
3 | enabled_elements_count = enabled_elements.length;
4 | port_cmenu_items = [];
5 | wait_count = 0;
6 | bk_event = null;
7 | port_clicked = null;
8 |
9 | (function () {
10 | var menu_item_candidates = {
11 | link: {'Show links status': {onclick: menuItemClicked, className: 'itemname-link'}},
12 | conf: {'Show ports configuration': {onclick: menuItemClicked, className: 'itemname-conf'}},
13 | mac: {'Show device learned MACs': {onclick: menuItemClicked, className: 'itemname-mac'}},
14 | portmac: {'Show port learned MACs': {onclick: menuItemClicked, className: 'itemname-portmac'}}
15 | };
16 | var portinfo_enabled = false;
17 | for (var i in enabled_elements) {
18 | var name = enabled_elements[i];
19 | port_cmenu_items.push(menu_item_candidates[name]);
20 | if (menu_item_candidates[name] != null && name.match (/^(link|conf|mac)$/))
21 | portinfo_enabled = true;
22 | }
23 | if (portinfo_enabled) {
24 | port_cmenu_items.unshift($.contextMenu.separator);
25 | port_cmenu_items.unshift({'Show all info': {onclick: showAllClicked, className: 'itemname-all'}});
26 | }
27 | })();
28 |
29 | function showAllClicked(menuItem, menu) {
30 | for (var i in enabled_elements) {
31 | var name = enabled_elements[i];
32 | if (name.match (/^(link|conf|mac)$/)) {
33 | port_clicked = this;
34 | menuItemClicked($('.context-menu-item.itemname-' + name)[0], menu);
35 | }
36 | }
37 | }
38 |
39 | $(document).ready(function () {
40 | // create global object port_cmenu
41 | if (port_cmenu_items.length) {
42 | port_cmenu = $.contextMenu.create(port_cmenu_items, {theme:'vista'});
43 | // add popup button after every portname
44 | $('.interactive-portname.port-menu').after('');
45 | $('
').hide().addClass('cursor-shadow').css('position', 'absolute').css('width', 16).css('height', 16).css("background-image", "url(index.php?module=chrome&uri=pix/ajax-loader.gif").appendTo('body');
46 |
47 | // bind popup menu to every link with class port-popup
48 | $('a.port-popup').bind('click', function(e){port_cmenu.show(this,e);return false;});
49 | $('body').bind('mouseup', rememberCursorPosition);
50 | }
51 | });
52 |
53 | function disableMenuItem(menuItem) {
54 | setTimeout (function() {
55 | if (! $(menuItem).hasClass($.contextMenu.disabledItemClassName)) {
56 | $(menuItem).addClass($.contextMenu.disabledItemClassName);
57 | if (--enabled_elements_count <= 0) {
58 | $('.context-menu-item.itemname-all').addClass($.contextMenu.disabledItemClassName);
59 | }
60 | }
61 | }, 50);
62 | }
63 |
64 | function setItemIcon(menuItem, iconName) {
65 | var iconURL;
66 | if (iconName == 'wait')
67 | iconURL = 'index.php?module=chrome&uri=pix/ajax-loader.gif';
68 | else if (iconName == 'ok')
69 | iconURL = 'index.php?module=chrome&uri=pix/checkbox_yes.png';
70 | else
71 | iconURL = '';
72 | $(menuItem).children('.' + $.contextMenu.innerDivClassName).css("background-image", "url(" + iconURL + ")");
73 | }
74 |
75 | function menuItemClicked(menuItem, menu) {
76 | if (!port_clicked)
77 | port_clicked = this;
78 | // if the item is already disabled, do not react on click
79 | if ($(menuItem).hasClass($.contextMenu.disabledItemClassName))
80 | return;
81 |
82 | // determine the typename of menuItem ('link', 'mac' or 'conf')
83 | var matches = menuItem.className.match(/itemname-([^ ]+)/);
84 | if (! matches)
85 | return;
86 | var type = matches[1];
87 | var per_port_cmd = type == 'portmac';
88 | var portnameElem = $(port_clicked).siblings('.interactive-portname')[0];
89 | port_clicked = null;
90 |
91 | var bSuccessIcon = false;
92 | $.ajax({
93 | async: true,
94 | beforeSend: function(XMLHttpRequest) {
95 | if (++wait_count > 0) {
96 | cursor_shadow = $('.cursor-shadow');
97 | $('body').bind('mousemove', waitCursorMove);
98 | if (bk_event)
99 | waitCursorMove(bk_event);
100 | }
101 | setItemIcon(menuItem, 'wait');
102 | },
103 | complete: function(XMLHttpRequest, textStatus) {
104 | if (--wait_count <= 0) {
105 | $('.cursor-shadow').hide();
106 | $('body').unbind('mousemove', waitCursorMove);
107 | $('body').unbind('click', rememberCursorPosition);
108 | }
109 | if (! bSuccessIcon)
110 | setItemIcon(menuItem, '');
111 | },
112 | type: 'GET',
113 | url: 'index.php',
114 | data: {
115 | 'module': 'ajax',
116 | 'ac': 'get-port-' + type,
117 | 'object_id': getQueryString('object_id'),
118 | 'port_name': getPortName(portnameElem)
119 | },
120 | dataType: 'json',
121 | success: function(data, textStatus, XMLHttpRequest) {
122 | if (! data)
123 | return;
124 | bSuccessIcon = true;
125 |
126 | if (per_port_cmd)
127 | setItemIcon(menuItem, '');
128 | else
129 | setItemIcon(menuItem, 'ok');
130 |
131 | if (type == 'link')
132 | applyLinkData(data);
133 | else if (type == 'mac' || type == 'portmac')
134 | applyMacData(data);
135 | else if (type == 'conf')
136 | applyConfData(data);
137 | }
138 | });
139 | if (!per_port_cmd)
140 | disableMenuItem(menuItem);
141 | }
142 |
143 | function rememberCursorPosition(event) {
144 | bk_event = event;
145 | }
146 |
147 | function waitCursorMove(event) {
148 | cursor_shadow.css("left", event.pageX + 15).css("top", event.pageY + 15).show();
149 | }
150 |
151 | function applyLinkData(data) {
152 | var seen_portnames = {};
153 | $('.interactive-portname').each(function() {
154 | var portname = getPortName (this);
155 | var item = data[portname];
156 | if (item != null) {
157 | var prepended;
158 | if (item['inline'])
159 | prepended = $(' ').addClass('port-link').html(item['inline']).insertBefore(this);
160 | if (item['popup'] && prepended) {
161 | if (! seen_portnames[portname])
162 | seen_portnames[portname] = $('
').addClass('popup-box').html(item['popup']).appendTo('body');
163 | prepended.thumbPopup(seen_portnames[portname]);
164 | }
165 | }
166 | });
167 | }
168 |
169 | function applyMacData(data) {
170 | var seen_portnames = {};
171 | $('.interactive-portname').each(function() {
172 | var portname = getPortName (this);
173 | var item = data[portname];
174 | if (item != null) {
175 | var prepended;
176 | if (item['inline'])
177 | {
178 | var obj = $(this).parent().find('.mac-count');
179 | if (!obj.length)
180 | appended = $('
').addClass('mac-count').html(item['inline']).appendTo($(this).parent());
181 | else
182 | appended = obj.html(item['inline']);
183 | }
184 | if (item['popup'] && appended) {
185 | var obj = $("[id='maclist-popup-"+portname+"']");
186 | if (! obj.size())
187 | obj = $('
').addClass('popup-box mac-list').attr('id', 'maclist-popup-'+portname).html(item['popup']).appendTo('body');
188 | else
189 | obj.html(item['popup']);
190 | appended.thumbPopup(obj);
191 | }
192 | }
193 | });
194 | }
195 |
196 | function applyConfData(data) {
197 | var seen_portnames = {};
198 | $('.interactive-portname').each(function() {
199 | var portname = getPortName (this);
200 | var item = data[portname];
201 | if (item != null) {
202 | if (! seen_portnames[portname])
203 | seen_portnames[portname] = $('
').addClass('popup-box port-config').html(item['popup']).appendTo('body');
204 | $(this).thumbPopup(seen_portnames[portname]);
205 | }
206 | });
207 | }
208 |
209 | function getPortName (element) {
210 | if (element.type == 'text')
211 | return $(element).val();
212 | else
213 | return $(element).html();
214 | }
215 |
--------------------------------------------------------------------------------
/wwwroot/js/jquery.optionTree.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery optionTree Plugin
3 | * version: 1.3
4 | * @requires jQuery v1.3 or later
5 | *
6 | * Dual licensed under the MIT and GPL licenses:
7 | * http://www.opensource.org/licenses/mit-license.php
8 | * http://www.gnu.org/licenses/gpl.html
9 | *
10 | * @version $Id: jquery.optionTree.js 13 2011-03-31 08:51:59Z kkotowicz $
11 | * @author Krzysztof Kotowicz
12 | * @see http://code.google.com/p/jquery-option-tree/
13 | * @see http://blog.kotowicz.net/search/label/option
14 | */
15 |
16 | /**
17 | * Converts passed JSON option tree into dynamically created elements allowing you to
18 | * choose nested options.
19 | *
20 | * @param String tree options tree
21 | * @param array options additional options (optional)
22 | */
23 | (function($){
24 | $.fn.optionTree = function(tree, options) {
25 |
26 | options = $.extend({
27 | choose: 'Choose...', // string with text or function that will be passed current level and returns a string
28 | show_multiple: false, // show multiple values (if true takes number of items as size, or number (eg. 12) to show fixed size)
29 | preselect: {},
30 | loading_image: '', // show an ajax loading graphics (animated gif) while loading ajax (eg. /ajax-loader.gif)
31 | select_class: '',
32 | tabindex: '',
33 | leaf_class: 'final',
34 | empty_value: '', // what value to set the input to if no valid option was selected
35 | on_each_change: false, // URL to lazy load (JSON, 'id' parameter will be added) or function. See default_lazy_load
36 | set_value_on: 'leaf', // leaf - sets input value only when choosing leaf node. 'each' - sets value on each level change.
37 | // makes sense only then indexed=true
38 | indexed: false,
39 | preselect_only_once: false // if true, once preselected items will be chosen, the preselect list is cleared. This is to allow
40 | // changing the higher level options without automatically changing lower levels when a whole subtree is in preselect list
41 | }, options || {});
42 |
43 | var cleanName = function (name) {
44 | return name.replace(/_*$/, '');
45 | };
46 |
47 | var removeNested = function (name) {
48 | $("select[name^='"+ name + "']").remove();
49 | };
50 |
51 | var setValue = function(name, value) {
52 | $("input[name='" + cleanName(name) + "']").val(value).change();
53 | };
54 |
55 | // default lazy loading function
56 | var default_lazy_load = function(value) {
57 | var input = this;
58 | if ( options.loading_image !== '' ) {
59 | // show loading animation
60 | $(" ")
61 | .attr('src', options.loading_image)
62 | .attr('class', 'optionTree-loader')
63 | .insertAfter(input);
64 | }
65 |
66 | $.getJSON(options.lazy_load, {id: value}, function(tree) {
67 | $('.optionTree-loader').remove();
68 | var prop;
69 | for (prop in tree) {
70 | if (tree.hasOwnProperty(prop)) { // tree not empty
71 | $(input).optionTree(tree, options);
72 | return;
73 | }
74 | }
75 | // tree empty, call value switch
76 | $(input).optionTree(value, options);
77 | });
78 | };
79 |
80 | if (typeof options.on_each_change === 'string') { // URL given as an onchange
81 | options.lazy_load = options.on_each_change;
82 | options.on_each_change = default_lazy_load;
83 | }
84 |
85 | var isPreselectedFor = function(clean, v) {
86 | if (!options.preselect || !options.preselect[clean]) {
87 | return false;
88 | }
89 |
90 | if ($.isArray(options.preselect[clean])) {
91 | return $.inArray(v, options.preselect[clean]) !== -1;
92 | }
93 |
94 | return (options.preselect[clean] === v);
95 | };
96 |
97 | return this.each(function() {
98 | var name = $(this).attr('name') + "_";
99 |
100 | // remove all dynamic options of lower levels
101 | removeNested(name);
102 |
103 | if (typeof tree === "object") { // many options exists for current nesting level
104 |
105 | // create select element with all the options
106 | // and bind onchange event to recursively call this function
107 |
108 | var $select = $("").attr('name',name)
109 | .change(function() {
110 | if (this.options[this.selectedIndex].value !== '') {
111 | if ($.isFunction(options.on_each_change)) {
112 | removeNested(name + '_');
113 | options.on_each_change.apply(this, [this.options[this.selectedIndex].value, tree]);
114 | } else {
115 | // call with value as a first parameter
116 | $(this).optionTree(tree[this.options[this.selectedIndex].value], options);
117 | }
118 | if (options.set_value_on === 'each') {
119 | setValue(name, this.options[this.selectedIndex].value);
120 | }
121 | } else {
122 | removeNested(name + '_');
123 | setValue(name, options.empty_value);
124 | }
125 | });
126 |
127 | var text_to_choose = '';
128 |
129 | if (jQuery.isFunction(options.choose)) {
130 | var level = $(this).siblings().andSelf().filter('select').length;
131 | text_to_choose = options.choose.apply(this, [level]);
132 | } else if ( options.choose !== '' ) {
133 | text_to_choose = options.choose;
134 | }
135 |
136 | // if show multiple -> show open select
137 | var count_tree_objects = 0;
138 | if ( text_to_choose !== '' ) {
139 | // we have a default value
140 | count_tree_objects++;
141 | }
142 | if (options.show_multiple > 1) {
143 | count_tree_objects = options.show_multiple;
144 | } else if (options.show_multiple === true) {
145 | $.each(tree, function() {
146 | count_tree_objects++;
147 | });
148 | }
149 | if ( count_tree_objects > 1 ){
150 | $select.attr('size', count_tree_objects);
151 | }
152 |
153 | if ($(this).is('input')) {
154 | $select.insertBefore(this);
155 | } else {
156 | $select.insertAfter(this);
157 | }
158 |
159 | if (options.select_class) {
160 | $select.addClass(options.select_class);
161 | }
162 |
163 | if (options.tabindex) {
164 | $select.attr('tabindex', options.tabindex);
165 | }
166 |
167 | if ( text_to_choose !== '' ) {
168 | $("").html(text_to_choose).val('').appendTo($select);
169 | }
170 |
171 | var foundPreselect = false;
172 | $.each(tree, function(k, v) {
173 | var label, value;
174 | if (options.indexed) {
175 | label = v;
176 | value = k;
177 | } else {
178 | label = value = k;
179 | }
180 | var o = $(" ").html(label)
181 | .attr('value', value);
182 | var clean = cleanName(name);
183 | if (options.leaf_class && typeof value !== 'object') { // this option is a leaf node
184 | o.addClass(options.leaf_class);
185 | }
186 |
187 | o.appendTo($select);
188 | if (isPreselectedFor(clean, value)) {
189 | o.get(0).selected = true;
190 | foundPreselect = true;
191 | }
192 | });
193 |
194 | if (foundPreselect) {
195 | $select.change();
196 | }
197 |
198 | if (!foundPreselect && options.preselect_only_once) { // clear preselect on first not-found level
199 | options.preselect[cleanName(name)] = null;
200 | }
201 |
202 | } else if (options.set_value_on === 'leaf') { // single option is selected by the user (function called via onchange event())
203 | if (options.indexed) {
204 | setValue(name, this.options[this.selectedIndex].value);
205 | } else {
206 | setValue(name, tree);
207 | }
208 | }
209 | });
210 |
211 | };
212 | }(jQuery));
213 |
--------------------------------------------------------------------------------
/wwwroot/inc/triggers.php:
--------------------------------------------------------------------------------
1 | 'AP7902J',
25 | 1152 => 'AP7930J',
26 | 1153 => 'AP7932J',
27 | // 120V input
28 | 1154 => 'AP7900',
29 | 1155 => 'AP7901',
30 | 1156 => 'AP7902',
31 | 1157 => 'AP7930',
32 | 1158 => 'AP7931',
33 | 1159 => 'AP7932',
34 | // 208V input
35 | 1160 => 'AP7911',
36 | 1161 => 'AP7940',
37 | 1162 => 'AP7941',
38 | // 208V 3 phases input
39 | 1163 => 'AP7960',
40 | 1164 => 'AP7961',
41 | 1165 => 'AP7968',
42 | 1166 => 'AP7990',
43 | 1167 => 'AP7991',
44 | 1168 => 'AP7998',
45 | // 230V input
46 | 1137 => 'AP7920',
47 | 1138 => 'AP7921',
48 | 1139 => 'AP7922',
49 | 1140 => 'AP7950',
50 | 1141 => 'AP7951',
51 | 1142 => 'AP7952',
52 | 1143 => 'AP7953',
53 | 1144 => 'AP7954',
54 | // 400V 3 phases input
55 | 1154 => 'AP7957',
56 | );
57 |
58 | // This trigger is on when any of the (get_mac_list, get_link_status) ops permitted
59 | function trigger_liveports ()
60 | {
61 | $breed = detectDeviceBreed (getBypassValue());
62 | foreach (array ('getportstatus', 'getmaclist') as $command)
63 | if
64 | (
65 | validBreedFunction ($breed, $command) and
66 | permitted (NULL, 'liveports', $command)
67 | )
68 | return 'std';
69 | return '';
70 | }
71 |
72 | // SNMP port finder tab trigger. At the moment we decide on showing it
73 | // for pristine switches/PDUs only. Once a user has begun
74 | // filling the data in, we stop showing the tab.
75 | function trigger_snmpportfinder ()
76 | {
77 |
78 | $object = spotEntity ('object', getBypassValue());
79 | switch ($object['objtype_id'])
80 | {
81 | case 7: // any router
82 | case 8: // or switch
83 | case 965: // or wireless device would suffice
84 | return $object['nports'] ? '' : 'attn';
85 | case 2: // but only selected PDUs
86 | if ($object['nports'])
87 | return '';
88 | global $known_APC_SKUs;
89 | return checkTypeAndAttribute
90 | (
91 | $object['id'],
92 | 2, // PDU
93 | 2, // HW type
94 | array_keys ($known_APC_SKUs)
95 | ) ? 'attn' : '';
96 | default:
97 | return '';
98 | }
99 | }
100 |
101 | function trigger_isloadbalancer ()
102 | {
103 | return considerConfiguredConstraint (spotEntity ('object', getBypassValue()), 'IPV4LB_LISTSRC') ? 'std' : '';
104 | }
105 |
106 | function trigger_ip ()
107 | {
108 | if (count (getObjectIPAllocationList (getBypassValue())))
109 | return 'std';
110 | // Only hide the tab, if there are no addresses allocated.
111 | return considerConfiguredConstraint (spotEntity ('object', getBypassValue()), 'IPV4OBJ_LISTSRC') ? 'std' : '';
112 | }
113 |
114 | function trigger_natv4 ()
115 | {
116 | if (!count (getObjectIPv4AllocationList (getBypassValue())))
117 | return '';
118 | return considerConfiguredConstraint (spotEntity ('object', getBypassValue()), 'IPV4NAT_LISTSRC') ? 'std' : '';
119 | }
120 |
121 | function trigger_autoports ()
122 | {
123 | $object = spotEntity ('object', getBypassValue());
124 | amplifyCell ($object);
125 | if (count ($object['ports']))
126 | return '';
127 | return count (getAutoPorts ($object['objtype_id'])) ? 'attn' : '';
128 | }
129 |
130 | function trigger_tags ()
131 | {
132 | global $taglist;
133 | return count ($taglist) ? 'std' : '';
134 | }
135 |
136 | function trigger_passwdchange ()
137 | {
138 | global $user_auth_src;
139 | return $user_auth_src == 'database' ? 'std' : '';
140 | }
141 |
142 | function trigger_localreports ()
143 | {
144 | global $localreports;
145 | return count ($localreports) ? 'std' : '';
146 | }
147 |
148 | function trigger_file_editText ()
149 | {
150 | $fileInfo = spotEntity ('file', getBypassValue());
151 | return ($fileInfo['type'] == 'text/plain') ? 'std' : '';
152 | }
153 |
154 | function trigger_rackspace ()
155 | {
156 | global $virtual_obj_types;
157 |
158 | // Hide the tab if the object type is virtual
159 | $object = spotEntity ('object', getBypassValue());
160 | if (in_array($object['objtype_id'], $virtual_obj_types))
161 | return '';
162 |
163 | $rackspace = getRackspaceStats();
164 | if ($rackspace['Racks'] > 0) return 'std';
165 | return '';
166 | }
167 |
168 | function trigger_ports ()
169 | {
170 | // Hide the tab if the object type exists in the exclusion config option
171 | if (considerConfiguredConstraint (spotEntity ('object', getBypassValue()), 'PORT_EXCLUSION_LISTSRC'))
172 | return '';
173 |
174 | return 'std';
175 | }
176 |
177 | // Offer the generic VLAN setup tab for every object that already
178 | // has a VLAN domain associated or at least can have one (in the latter
179 | // case additionally heat the tab, if no domain is set.
180 | function trigger_object_8021qorder ()
181 | {
182 | if (NULL !== getVLANSwitchInfo (getBypassValue()))
183 | return 'std';
184 | if (!count (getVLANDomainOptions()) or !count (getVSTOptions()))
185 | return '';
186 | if (considerConfiguredConstraint (spotEntity ('object', getBypassValue()), 'VLANSWITCH_LISTSRC'))
187 | return 'attn';
188 | return '';
189 | }
190 |
191 | function trigger_8021q_configured ()
192 | {
193 | if (!count (getVLANDomainOptions()) or !count (getVSTOptions()))
194 | return '';
195 | return 'std';
196 | }
197 |
198 | // implement similar logic for IPv4 networks
199 | function trigger_ipv4net_vlanconfig ()
200 | {
201 | if (!count (getVLANDomainOptions())) // no domains -- no VLANs to bind with
202 | return '';
203 | $netinfo = spotEntity ('ipv4net', getBypassValue());
204 | if ($netinfo['vlanc'])
205 | return 'std';
206 | elseif (considerConfiguredConstraint ($netinfo, 'VLANIPV4NET_LISTSRC'))
207 | return 'attn';
208 | else
209 | return '';
210 | }
211 |
212 | // implement similar logic for IPv6 networks
213 | function trigger_ipv6net_vlanconfig ()
214 | {
215 | if (!count (getVLANDomainOptions())) // no domains -- no VLANs to bind with
216 | return '';
217 | $netinfo = spotEntity ('ipv6net', getBypassValue());
218 | if ($netinfo['vlanc'])
219 | return 'std';
220 | elseif (considerConfiguredConstraint ($netinfo, 'VLANIPV4NET_LISTSRC'))
221 | return 'attn';
222 | else
223 | return '';
224 | }
225 |
226 | function trigger_vlan_ipv4net ()
227 | {
228 | $vlan_info = getVLANInfo (getBypassValue());
229 | return count ($vlan_info['ipv4nets']) ? 'std' : 'attn';
230 | }
231 |
232 | function trigger_vlan_ipv6net ()
233 | {
234 | $vlan_info = getVLANInfo (getBypassValue());
235 | return count ($vlan_info['ipv6nets']) ? 'std' : 'attn';
236 | }
237 |
238 | function trigger_object_8021qports ()
239 | {
240 | if (NULL === getVLANSwitchInfo (getBypassValue()))
241 | return '';
242 | return count (getStored8021QConfig (getBypassValue(), 'desired')) ? 'std' : '';
243 | }
244 |
245 | function trigger_object_8021qsync ()
246 | {
247 | if (NULL === $vswitch = getVLANSwitchInfo (getBypassValue()))
248 | return '';
249 | return $vswitch['out_of_sync'] == 'yes' ? 'attn' : 'std';
250 | }
251 |
252 | function trigger_LiveCDP ()
253 | {
254 | return trigger_anyDP ('getcdpstatus', 'CDP_RUNNERS_LISTSRC');
255 | }
256 |
257 | function trigger_LiveLLDP ()
258 | {
259 | return trigger_anyDP ('getlldpstatus', 'LLDP_RUNNERS_LISTSRC');
260 | }
261 |
262 | function trigger_anyDP ($command, $constraint)
263 | {
264 | if
265 | (
266 | validBreedFunction (detectDeviceBreed (getBypassValue()), $command) and
267 | considerConfiguredConstraint (spotEntity ('object', getBypassValue()), $constraint)
268 | )
269 | return 'std';
270 | return '';
271 | }
272 |
273 | // tease rules editor tab, when the VST has no rules
274 | function trigger_vst_editrules()
275 | {
276 | $vst = spotEntity ('vst', getBypassValue());
277 | return $vst['rulec'] ? 'std' : 'attn';
278 | }
279 |
280 | function triggerIPAddressLog ()
281 | {
282 | $ip_bin = getBypassValue();
283 | switch (strlen ($ip_bin))
284 | {
285 | case 4:
286 | $result = usePreparedSelectBlade ("SELECT COUNT(id) FROM IPv4Log WHERE ip = ?", array (ip4_bin2db ($ip_bin)));
287 | break;
288 | case 16:
289 | $result = usePreparedSelectBlade ("SELECT COUNT(id) FROM IPv6Log WHERE ip = ?", array ($ip_bin));
290 | break;
291 | }
292 | if ($row = $result->fetch(PDO::FETCH_NUM))
293 | if ($row[0] > 0)
294 | return 'std';
295 | return '';
296 | }
297 |
298 | function triggerCactiGraphs ()
299 | {
300 | if (! count (getCactiServers()))
301 | return '';
302 | if
303 | (
304 | count (getCactiGraphsForObject (getBypassValue())) or
305 | considerConfiguredConstraint (spotEntity ('object', getBypassValue()), 'CACTI_LISTSRC')
306 | )
307 | return 'std';
308 | else
309 | return '';
310 | }
311 |
312 | function triggerMuninGraphs()
313 | {
314 | if (! count (getMuninServers()))
315 | return '';
316 | if
317 | (
318 | count (getMuninGraphsForObject (getBypassValue())) or
319 | considerConfiguredConstraint (spotEntity ('object', getBypassValue()), 'MUNIN_LISTSRC')
320 | )
321 | return 'std';
322 | else
323 | return '';
324 | }
325 |
326 | function trigger_ucs()
327 | {
328 | return checkTypeAndAttribute
329 | (
330 | getBypassValue(),
331 | 1787, # management interface
332 | 30, # mgmt type
333 | array (1788) # UCS Manager
334 | ) ? 'std' : '';
335 | }
336 |
337 | function triggerPatchCableHeapsConfigured()
338 | {
339 | return count (getPatchCableHeapSummary()) ? 'std' : '';
340 | }
341 |
342 | ?>
343 |
--------------------------------------------------------------------------------
/wwwroot/index.php:
--------------------------------------------------------------------------------
1 | construct,
75 | # and the latter is accessed as a standalone URL and can reply with any
76 | # Content-type. Hence "image" module indicates failures with internally
77 | # built images, and "download" can return a full-fledged "permission
78 | # denied" or "exception" HTML page instead of the file requested.
79 | require_once 'inc/init.php'; // for authentication check
80 | require_once 'inc/solutions.php';
81 | try
82 | {
83 | dispatchImageRequest();
84 | }
85 | catch (Exception $e)
86 | {
87 | ob_clean();
88 | throw ($e instanceof RTImageError) ? $e : new RTImageError;
89 | }
90 | break;
91 |
92 | case 'svg':
93 | require_once 'inc/init.php';
94 | require_once 'inc/solutions.php';
95 | header ('Content-Type: image/svg+xml');
96 | echo '' . "\n";
97 | echo '' . "\n";
98 | try
99 | {
100 | genericAssertion ('view', 'string');
101 | if (! array_key_exists ($_REQUEST['view'], $svghandler))
102 | throw new InvalidRequestArgException ('view', $_REQUEST['view'], 'undefined view');
103 | if (! is_callable ($svghandler[$_REQUEST['view']]))
104 | throw new RackTablesError ('missing handler function', RackTablesError::INTERNAL);
105 | call_user_func ($svghandler[$_REQUEST['view']]);
106 | }
107 | catch (RTPermissionDenied $e)
108 | {
109 | ob_clean();
110 | printSVGMessageBar ('permission denied', array ('fill' => 'white'), array ('fill' => 'black', 'stroke' => 'gray'));
111 | }
112 | catch (InvalidRequestArgException $e)
113 | {
114 | ob_clean();
115 | printSVGMessageBar ('malformed HTTP request', array(), array ('fill' => 'yellow', 'stroke' => 'black'));
116 | }
117 | catch (EntityNotFoundException $e)
118 | {
119 | ob_clean();
120 | printSVGMessageBar ('no such record', array(), array ('fill' => 'yellow', 'stroke' => 'black'));
121 | }
122 | catch (RackTablesError $e)
123 | {
124 | ob_clean();
125 | printSVGMessageBar ('RT error: ' . $e->getMessage(), array(), array ('fill' => 'red', 'stroke' => 'black'));
126 | }
127 | catch (Exception $e)
128 | {
129 | ob_clean();
130 | printSVGMessageBar ('unknown error', array(), array ('fill' => 'red', 'stroke' => 'black'));
131 | }
132 | break;
133 |
134 | case 'progressbar':
135 | # Unlike images (and like static content), progress bars are processed
136 | # without a permission check, but only for authenticated users.
137 | require_once 'inc/init.php';
138 | require_once 'inc/solutions.php';
139 | try
140 | {
141 | genericAssertion ('done', 'uint0');
142 | // 'progressbar's never change, make browser cache the result
143 | if (checkCachedResponse (0, CACHE_DURATION))
144 | break;
145 | renderProgressBarImage ($_REQUEST['done']);
146 | }
147 | catch (Exception $e)
148 | {
149 | ob_clean();
150 | throw ($e instanceof RTImageError) ? $e : new RTImageError ('pbar_error');
151 | }
152 | break;
153 |
154 | case 'progressbar4':
155 | # Unlike images (and like static content), progress bars are processed
156 | # without a permission check, but only for authenticated users.
157 | require_once 'inc/init.php';
158 | require_once 'inc/solutions.php';
159 | try
160 | {
161 | renderProgressBar4Image ($_REQUEST['px1'], $_REQUEST['px2'], $_REQUEST['px3']);
162 | }
163 | catch (Exception $e)
164 | {
165 | ob_clean();
166 | throw ($e instanceof RTImageError) ? $e : new RTImageError ('pbar_error');
167 | }
168 | break;
169 |
170 | case 'ajax':
171 | require_once 'inc/init.php';
172 | require_once 'inc/ajax-interface.php';
173 | require_once 'inc/solutions.php';
174 | try
175 | {
176 | genericAssertion ('ac', 'string');
177 | $ac = $_REQUEST['ac'];
178 | if (isset ($ajaxhandler[$ac]))
179 | $ajaxhandler[$ac]();
180 | else
181 | {
182 | ob_clean();
183 | echo "NAK\nMalformed request";
184 | }
185 | }
186 | catch (RTPermissionDenied $e)
187 | {
188 | ob_clean();
189 | # FIXME: the remote client could be expecting JSON data instead
190 | echo "NAK\nPermission denied";
191 | }
192 | catch (Exception $e)
193 | {
194 | ob_clean();
195 | echo "NAK\nRuntime exception: ". $e->getMessage();
196 | }
197 | break;
198 |
199 | case 'redirect':
200 | // Include init after ophandlers/snmp, not before, so local.php can redefine things.
201 | require_once 'inc/ophandlers.php';
202 | // snmp.php is an exception, it is treated by a special hack
203 | if (isset ($_REQUEST['op']) and $_REQUEST['op'] == 'querySNMPData')
204 | require_once 'inc/snmp.php';
205 | require_once 'inc/init.php';
206 | try
207 | {
208 | genericAssertion ('op', 'string');
209 | $op = $_REQUEST['op'];
210 | prepareNavigation();
211 | $location = buildRedirectURL();
212 | // FIXME: find a better way to handle this error
213 | if ($op == 'addFile' && !isset($_FILES['file']['error']))
214 | throw new RackTablesError ('File upload error, check upload_max_filesize in php.ini', RackTablesError::MISCONFIGURED);
215 | fixContext();
216 | if
217 | (
218 | !isset ($ophandler[$pageno][$tabno][$op]) or
219 | ! is_callable ($ophandler[$pageno][$tabno][$op])
220 | )
221 | throw new RackTablesError ("Invalid navigation data for '${pageno}-${tabno}-${op}'", RackTablesError::INTERNAL);
222 | // We have a chance to handle an error before starting HTTP header.
223 | if (!isset ($delayauth["${pageno}-${tabno}-${op}"]))
224 | assertPermission();
225 | # Call below does the job of bypass argument assertion, if such is required,
226 | # so the ophandler function doesn't have to re-assert this portion of its
227 | # arguments. And it would be even better to pass returned value to ophandler,
228 | # so it is not necessary to remember the name of bypass in it.
229 | getBypassValue();
230 | if (strlen ($redirect_to = call_user_func ($ophandler[$pageno][$tabno][$op])))
231 | $location = $redirect_to;
232 | }
233 | // known "soft" failures require a short error message
234 | catch (InvalidRequestArgException $e)
235 | {
236 | ob_clean();
237 | showError ($e->getMessage());
238 | }
239 | catch (RTDatabaseError $e)
240 | {
241 | ob_clean();
242 | showError ('Database error: ' . $e->getMessage());
243 | }
244 | catch (RTPermissionDenied $e)
245 | {
246 | ob_clean();
247 | showError ('Operation not permitted');
248 | }
249 | redirectUser ($location);
250 | // any other error requires no special handling and will be caught outside
251 | break;
252 |
253 | case 'popup':
254 | require_once 'inc/popup.php';
255 | require_once 'inc/init.php';
256 | renderPopupHTML();
257 | break;
258 |
259 | case 'upgrade':
260 | require_once 'inc/config.php'; // for CODE_VERSION
261 | require_once 'inc/dictionary.php';
262 | require_once 'inc/functions.php'; // for ip translation functions
263 | require_once 'inc/upgrade.php';
264 | renderUpgraderHTML();
265 | break;
266 |
267 | case 'installer':
268 | require_once 'inc/dictionary.php';
269 | require_once 'inc/config.php';
270 | require_once 'inc/install.php';
271 | renderInstallerHTML();
272 | break;
273 |
274 | default:
275 | throw new InvalidRequestArgException ('module', $requestedModule);
276 | }
277 | ob_end_flush();
278 | }
279 | catch (Exception $e)
280 | {
281 | ob_end_clean();
282 | printException ($e);
283 | }
284 | ?>
285 |
--------------------------------------------------------------------------------
/wwwroot/inc/ajax-interface.php:
--------------------------------------------------------------------------------
1 | $link_info)
21 | {
22 | $link_info = $linkStatus[$portname];
23 | switch ($link_info['status'])
24 | {
25 | case 'up':
26 | $img_filename = 'link-up.png';
27 | break;
28 | case 'down':
29 | $img_filename = 'link-down.png';
30 | break;
31 | case 'disabled':
32 | $img_filename = 'link-disabled.png';
33 | break;
34 | }
35 |
36 | $hidden_lines = array();
37 | $hidden_lines[] = $portname . ': ' . $link_info['status'];
38 | if (isset ($link_info['speed']))
39 | $hidden_lines[] = 'Speed: ' . $link_info['speed'];
40 | if (isset ($link_info['duplex']))
41 | $hidden_lines[] = 'Duplex: ' . $link_info['duplex'];
42 | if (count ($hidden_lines))
43 | $result[$portname]['popup'] = implode (' ', $hidden_lines);
44 | $visible_part = " ";
45 | $result[$portname]['inline'] = $visible_part;
46 | }
47 | // put empty pictures for not-found ports
48 | $object = spotEntity ('object', $object_id);
49 | amplifyCell ($object);
50 | foreach ($object['ports'] as $port)
51 | if (! isset ($result[$port['name']]))
52 | $result[$port['name']]['inline'] = " ";
53 | return $result;
54 | }
55 |
56 | // retrieves MAC address list from switch and formats results to dynamic-HTML
57 | // returns array which could be packed into json and passed to client's browser
58 | function formatPortMacHints ($object_id)
59 | {
60 | $result = array();
61 | if ($_REQUEST['ac'] == 'get-port-portmac')
62 | {
63 | $port_name = $_REQUEST['port_name'];
64 | $ports = reduceSubarraysToColumn (getObjectPortsAndLinks($_REQUEST['object_id']), 'name');
65 | $macList = in_array($port_name, $ports) ?
66 | queryDevice ($object_id, 'getportmaclist', array ($port_name)) :
67 | array();
68 | }
69 | else
70 | $macList = queryDevice ($object_id, 'getmaclist');
71 | foreach ($macList as $portname => $list)
72 | {
73 | $list = $macList[$portname];
74 | $visible_part = count ($list) . ' MACs';
75 | $result[$portname]['inline'] = $visible_part;
76 | if (count ($list))
77 | {
78 | $hidden_part = 'MAC VID ';
79 | foreach ($list as $mac)
80 | $hidden_part .= '' . $mac['mac'] . ' ' . $mac['vid'] . ' ';
81 | $result[$portname]['popup'] = $hidden_part;
82 | }
83 | }
84 | return $result;
85 | }
86 |
87 | // retrieves port configs from switch and formats results to dynamic-HTML
88 | // returns array which could be packed into json and passed to client's browser
89 | function formatPortConfigHints ($object_id, $R = NULL)
90 | {
91 | $result = array();
92 | if (! isset ($R))
93 | $R = getRunning8021QConfig ($object_id);
94 | foreach ($R['portconfig'] as $portname => $portconfig)
95 | {
96 | $hidden_part = '';
97 | foreach ($portconfig as $line)
98 | $hidden_part .= '' . htmlentities ($line['line']) . ' ';
99 | $result[$portname]['popup'] = $hidden_part;
100 | }
101 | return $result;
102 | }
103 |
104 | // returns html-formatted span tag with last changed in title
105 | // takes 3 args:
106 | // log_item - array with keys 'user', 'time'. Could be empty
107 | // text - the text placed into the span
108 | // html_class - the additional css class
109 | function formatLoggedSpan ($log_item, $text, $html_class = '')
110 | {
111 | $title = '';
112 | if (! empty ($log_item))
113 | {
114 | $html_class = trim ($html_class . ' hover-history');
115 | $title = htmlspecialchars ($log_item['user'] . ', ' . formatAge ($log_item['time']), ENT_QUOTES);
116 | }
117 | return "$text ";
121 | }
122 |
123 | function getTagSelectAJAX()
124 | {
125 | global $taglist;
126 | $options = array();
127 | $selected_id = '';
128 | if (! isset($_REQUEST['tagid']))
129 | $options['error'] = "Sorry, param 'tagid' is empty. Reload page and try again";
130 | elseif (! preg_match("/tagid_(\d+)/i", $_REQUEST['tagid'], $m))
131 | $options['error'] = "Sorry, wrong format tagid:'".$_REQUEST['tagid']."'. Reload page and try again";
132 | else
133 | {
134 | $current_tag_id = $m[1];
135 | $selected_id = $taglist[$current_tag_id]['parent_id'];
136 | echo $selected_id;
137 | $options[0] = '-- NONE --';
138 | foreach ($taglist as $tag_id => $taginfo)
139 | if (! in_array ($current_tag_id, $taginfo['trace']) && $current_tag_id != $tag_id)
140 | $options[$tag_id] = $taginfo['tag'];
141 | }
142 | foreach ($options as $tag_id => $value)
143 | echo "' . htmlspecialchars ($value) . ' ';
146 | }
147 |
148 | function getLocationSelectAJAX()
149 | {
150 | $locationlist = listCells ('location');
151 | $locationtree = treeFromList ($locationlist); // adds ['trace'] keys into $locationlist items
152 | $options = array ();
153 | $selected_id = '';
154 | if (! isset($_REQUEST['locationid']))
155 | $options['error'] = "Sorry, param 'locationid' is empty. Reload page and try again";
156 | elseif (! preg_match("/locationid_(\d+)/i", $_REQUEST['locationid'], $m))
157 | $options['error'] = "Sorry, wrong format locationid:'".$_REQUEST['locationid']."'. Reload page and try again";
158 | else
159 | {
160 | $current_location_id = $m[1];
161 | $selected_id = $locationlist[$current_location_id]['parent_id'];
162 | echo $selected_id;
163 | echo "-- NONE -- ";
164 | }
165 | foreach ($locationtree as $location)
166 | {
167 | if ($location['id'] == $current_location_id)
168 | continue;
169 | echo "${location['name']} ";
173 | if ($location['kidc'] > 0)
174 | printLocationChildrenSelectOptions ($location, 0, $selected_id, $current_location_id);
175 | }
176 | }
177 |
178 | function verifyCodeAJAX()
179 | {
180 | global $pageno, $tabno;
181 | $pageno = 'perms';
182 | $tabno = 'edit';
183 | fixContext();
184 | assertPermission();
185 | genericAssertion ('code', 'string');
186 | $result = getRackCode (dos2unix ($_REQUEST['code']));
187 | if ($result['result'] == 'ACK')
188 | echo "ACK\n";
189 | else
190 | echo "NAK\n" . $result['load'];
191 | }
192 |
193 | // echoes JSON-encoded text
194 | function getPortInfoAJAX()
195 | {
196 | $funcmap = array
197 | (
198 | 'get-port-link' => 'formatPortLinkHints',
199 | 'get-port-mac' => 'formatPortMacHints',
200 | 'get-port-portmac' => 'formatPortMacHints',
201 | 'get-port-conf' => 'formatPortConfigHints',
202 | );
203 | $opmap = array
204 | (
205 | 'get-port-link' => 'get_link_status',
206 | 'get-port-mac' => 'get_mac_list',
207 | 'get-port-portmac' => 'get_port_mac_list',
208 | 'get-port-conf' => 'get_port_conf',
209 | );
210 | genericAssertion ('object_id', 'uint');
211 | fixContext (spotEntity ('object', $_REQUEST['object_id']));
212 | assertPermission ('object', 'liveports', $opmap[$_REQUEST['ac']]);
213 | echo json_encode ($funcmap[$_REQUEST['ac']] ($_REQUEST['object_id']));
214 | }
215 |
216 | function updatePortRsvAJAX()
217 | {
218 | global $sic;
219 | assertUIntArg ('id');
220 | assertStringArg ('text', TRUE);
221 | $port_info = getPortInfo ($sic['id']);
222 | fixContext (spotEntity ('object', $port_info['object_id']));
223 | assertPermission ('object', 'ports', 'editPort');
224 | if ($port_info['linked'])
225 | throw new RackTablesError ('Cant update port comment: port is already linked');
226 | if (! isset ($port_info['reservation_comment']))
227 | $port_info['reservation_comment'] = '';
228 | if ($port_info['reservation_comment'] !== $sic['text'])
229 | commitUpdatePortComment ($sic['id'], $sic['text']);
230 | echo 'OK';
231 | }
232 |
233 | function updateIPNameAJAX()
234 | {
235 | global $sic;
236 | assertStringArg ('text', TRUE);
237 | $ip_bin = assertIPArg ('id');
238 | $addr = getIPAddress ($ip_bin);
239 | if (! empty ($addr['allocs']) && empty ($addr['name']))
240 | throw new RackTablesError ('Cant update IP name: address is allocated');
241 | $net = spotNetworkByIP ($ip_bin);
242 | if (isset ($net))
243 | fixContext ($net);
244 | assertPermission ('ipaddress', 'properties', 'editAddress');
245 | $reserved = (empty ($sic['text']) ? 'no' : $addr['reserved']); // unset reservation if user clears name
246 | $comment = (empty ($addr['comment']) ? '' : $addr['comment']);
247 | updateAddress ($ip_bin, $sic['text'], $reserved, $comment);
248 | echo 'OK';
249 | }
250 |
251 | function updateIPCommentAJAX()
252 | {
253 | global $sic;
254 | assertStringArg ('text', TRUE);
255 | $ip_bin = assertIPArg ('id');
256 | $addr = getIPAddress ($ip_bin);
257 | $net = spotNetworkByIP ($ip_bin);
258 | if (isset ($net))
259 | fixContext ($net);
260 | assertPermission ('ipaddress', 'properties', 'editAddress');
261 | updateAddress ($ip_bin, $addr['name'], $addr['reserved'], $sic['text']);
262 | echo 'OK';
263 | }
264 |
265 | function updateCableIdAJAX()
266 | {
267 | global $sic;
268 | assertUIntArg ('id');
269 | assertStringArg ('text', TRUE);
270 | $port_info = getPortInfo ($sic['id']);
271 | fixContext (spotEntity ('object', $port_info['object_id']));
272 | assertPermission ('object', 'ports', 'editPort');
273 | if (! $port_info['linked'])
274 | throw new RackTablesError ('Cant update cable ID: port is not linked');
275 | if ($port_info['reservation_comment'] !== $sic['text'])
276 | commitUpdatePortLink ($sic['id'], $sic['text']);
277 | echo 'OK';
278 | }
279 |
280 | function updateRackSortOrderAJAX()
281 | {
282 | updateRackSortOrder ($_REQUEST['racks']);
283 | echo 'OK';
284 | }
285 |
286 | function getNetUsageAJAX()
287 | {
288 | assertStringArg ('net_id');
289 | list ($ip, $mask) = explode ('/', $_REQUEST['net_id']);
290 | $ip_bin = ip_parse ($ip);
291 | $net = spotNetworkByIP ($ip_bin, $mask + 1);
292 | if (! isset ($net) or $net['mask'] != $mask)
293 | $net = constructIPRange ($ip_bin, $mask);
294 | loadIPAddrList ($net);
295 | echo getRenderedIPNetCapacity ($net);
296 | }
297 |
298 | ?>
299 |
--------------------------------------------------------------------------------
/wwwroot/js/jquery.contextmenu.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c)2005-2009 Matt Kruse (javascripttoolbox.com)
3 | *
4 | * Dual licensed under the MIT and GPL licenses.
5 | * This basically means you can use this code however you want for
6 | * free, but don't claim to have written it yourself!
7 | * Donations always accepted: http://www.JavascriptToolbox.com/donate/
8 | *
9 | * Please do not link to the .js files on javascripttoolbox.com from
10 | * your site. Copy the files locally to your server instead.
11 | *
12 | */
13 | /**
14 | * jquery.contextmenu.js
15 | * jQuery Plugin for Context Menus
16 | * http://www.JavascriptToolbox.com/lib/contextmenu/
17 | *
18 | * Copyright (c) 2008 Matt Kruse (javascripttoolbox.com)
19 | * Dual licensed under the MIT and GPL licenses.
20 | *
21 | * @version 1.1
22 | * @history 1.1 2010-01-25 Fixed a problem with 1.4 which caused undesired show/hide animations
23 | * @history 1.0 2008-10-20 Initial Release
24 | * @todo slideUp doesn't work in IE - because of iframe?
25 | * @todo Hide all other menus when contextmenu is shown?
26 | * @todo More themes
27 | * @todo Nested context menus
28 | */
29 | ;(function($){
30 | $.contextMenu = {
31 | shadow:true,
32 | shadowOffset:0,
33 | shadowOffsetX:5,
34 | shadowOffsetY:5,
35 | shadowWidthAdjust:-3,
36 | shadowHeightAdjust:-3,
37 | shadowOpacity:.2,
38 | shadowClass:'context-menu-shadow',
39 | shadowColor:'black',
40 |
41 | offsetX:0,
42 | offsetY:0,
43 | appendTo:'body',
44 | direction:'down',
45 | constrainToScreen:true,
46 |
47 | showTransition:'show',
48 | hideTransition:'hide',
49 | showSpeed:null,
50 | hideSpeed:null,
51 | showCallback:null,
52 | hideCallback:null,
53 |
54 | className:'context-menu',
55 | itemClassName:'context-menu-item',
56 | itemHoverClassName:'context-menu-item-hover',
57 | disabledItemClassName:'context-menu-item-disabled',
58 | disabledItemHoverClassName:'context-menu-item-disabled-hover',
59 | separatorClassName:'context-menu-separator',
60 | innerDivClassName:'context-menu-item-inner',
61 | themePrefix:'context-menu-theme-',
62 | theme:'default',
63 |
64 | separator:'context-menu-separator', // A specific key to identify a separator
65 | target:null, // The target of the context click, to be populated when triggered
66 | menu:null, // The jQuery object containing the HTML object that is the menu itself
67 | shadowObj:null, // Shadow object
68 | bgiframe:null, // The iframe object for IE6
69 | shown:false, // Currently being shown?
70 | useIframe:/*@cc_on @*//*@if (@_win32) true, @else @*/false,/*@end @*/ // This is a better check than looking at userAgent!
71 |
72 | // Create the menu instance
73 | create: function(menu,opts) {
74 | var cmenu = $.extend({},this,opts); // Clone all default properties to created object
75 |
76 | // If a selector has been passed in, then use that as the menu
77 | if (typeof menu=="string") {
78 | cmenu.menu = $(menu);
79 | }
80 | // If a function has been passed in, call it each time the menu is shown to create the menu
81 | else if (typeof menu=="function") {
82 | cmenu.menuFunction = menu;
83 | }
84 | // Otherwise parse the Array passed in
85 | else {
86 | cmenu.menu = cmenu.createMenu(menu,cmenu);
87 | }
88 | if (cmenu.menu) {
89 | cmenu.menu.css({display:'none'});
90 | $(cmenu.appendTo).append(cmenu.menu);
91 | }
92 |
93 | // Create the shadow object if shadow is enabled
94 | if (cmenu.shadow) {
95 | cmenu.createShadow(cmenu); // Extracted to method for extensibility
96 | if (cmenu.shadowOffset) { cmenu.shadowOffsetX = cmenu.shadowOffsetY = cmenu.shadowOffset; }
97 | }
98 | $('body').bind('contextmenu',function(){cmenu.hide();}); // If right-clicked somewhere else in the document, hide this menu
99 | return cmenu;
100 | },
101 |
102 | // Create an iframe object to go behind the menu
103 | createIframe: function() {
104 | return $('');
105 | },
106 |
107 | // Accept an Array representing a menu structure and turn it into HTML
108 | createMenu: function(menu,cmenu) {
109 | var className = cmenu.className;
110 | $.each(cmenu.theme.split(","),function(i,n){className+=' '+cmenu.themePrefix+n});
111 | var $t = $('').click(function(){cmenu.hide(); return false;}); // We wrap a table around it so width can be flexible
112 | var $tr = $(' ');
113 | var $td = $(' ');
114 | var $div = $('
');
115 |
116 | // Each menu item is specified as either:
117 | // title:function
118 | // or title: { property:value ... }
119 | for (var i=0; i