diff options
Diffstat (limited to 'swat/apps')
3 files changed, 726 insertions, 0 deletions
diff --git a/swat/apps/swat/source/class/swat/module/statistics/Fsm.js b/swat/apps/swat/source/class/swat/module/statistics/Fsm.js new file mode 100644 index 0000000000..486463d648 --- /dev/null +++ b/swat/apps/swat/source/class/swat/module/statistics/Fsm.js @@ -0,0 +1,219 @@ +/* + * Copyright: + * (C) 2006 by Derrell Lipman + * All rights reserved + * + * License: + * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ + */ + +/** + * Swat statistics class finite state machine + */ +qx.OO.defineClass("swat.module.statistics.Fsm", swat.module.AbstractModuleFsm, +function() +{ + swat.module.AbstractModuleFsm.call(this); +}); + + +qx.Class._startTimer = function(fsm) +{ + // Create a timer instance to expire in a few seconds + var timer = new qx.client.Timer(5000); + timer.addEventListener("interval", fsm.eventListener, fsm); + fsm.addObject("timer", timer); + timer.start(); +}; + + +qx.Class._stopTimer = function(fsm) +{ + // ... then stop the timer. Get the timer object. + var timer = fsm.getObject("timer"); + + // If it still exists... + if (timer) + { + // ... then dispose of it. + timer.dispose(); + fsm.removeObject("timer"); + } +}; + + +qx.Proto.buildFsm = function(module) +{ + var fsm = module.fsm; + var thisClass = this; + + /* + * State: Idle + * + * Actions upon entry + * - if returning from RPC, display the result + * - start an interval timer to request statistics again in a while + * + * Transition on: + * "interval" on interval_timer + */ + var state = new qx.util.fsm.State( + "State_Idle", + { + "onentry" : + function(fsm, state) + { + // Did we just return from an RPC request? + if (fsm.getPreviousState() == "State_AwaitRpcResult") + { + // Yup. Display the result. We need to get the request object + var request = fsm.getObject("swat.module.fsmUtils.request"); + + // We don't need the request object to be saved any more + fsm.removeObject("swat.module.fsmUtils.request"); + + // Display the result + var gui = swat.module.statistics.Gui.getInstance(); + gui.displayData(module, request.result); + + // Dispose of the request (and result) + request.result = null; + request = null; + + // Restart the timer. + swat.module.statistics.Fsm._startTimer(fsm); + } + }, + + "onexit" : + function(fsm, state) + { + // If we're not coming right back into this state... + if (fsm.getNextState() != "State_Idle") + { + // ... then stop the timer. + swat.module.statistics.Fsm._stopTimer(fsm); + } + }, + + "events" : + { + // If the timer expires, send a new statistics request + "interval" : + { + "timer" : + "Transition_Idle_to_AwaitRpcResult_via_request_statistics" + }, + + // When we get an appear event, start our timer + "appear" : + { + "swat.module.canvas" : + "Transition_Idle_to_Idle_via_appear" + }, + + // When we get a disappear event, stop our timer + "disappear" : + { + "swat.module.canvas" : + "Transition_Idle_to_Idle_via_disappear" + } + } + }); + + // Replace the initial Idle state with this one + fsm.replaceState(state, true); + + /* + * Transition: Idle to AwaitRpcResult + * + * Cause: "interval" on timer + * + * Action: + * Issue a Get Statistics request + */ + var trans = new qx.util.fsm.Transition( + "Transition_Idle_to_AwaitRpcResult_via_request_statistics", + { + "nextState" : + "State_AwaitRpcResult", + + "ontransition" : + function(fsm, event) + { + var rpc = fsm.getObject("swat.module.rpc"); + + rpc.setUrl("/services/"); + rpc.setServiceName("samba.management"); + + var request = + rpc.callAsyncListeners(true, // coalesce failure events + "get_statistics", + true, true); + fsm.addObject("swat.module.fsmUtils.request", request); + } + }); + state.addTransition(trans); + + /* + * Transition: Idle to Idle + * + * Cause: "appear" on canvas + * + * Action: + * Start our timer + */ + var trans = new qx.util.fsm.Transition( + "Transition_Idle_to_Idle_via_appear", + { + "nextState" : + "State_Idle", + + "ontransition" : + function(fsm, event) + { + swat.module.statistics.Fsm._startTimer(fsm); + } + }); + state.addTransition(trans); + + /* + * Transition: Idle to Idle + * + * Cause: "disappear" on canvas + * + * Action: + * Stop our timer + */ + var trans = new qx.util.fsm.Transition( + "Transition_Idle_to_Idle_via_disappear", + { + "nextState" : + "State_Idle", + + "ontransition" : + function(fsm, event) + { + swat.module.statistics.Fsm._stopTimer(fsm); + } + }); + state.addTransition(trans); + + // Add the AwaitRpcResult state and all of its transitions + this.addAwaitRpcResultState(module); + + // Allocate an RPC object + o = new qx.io.remote.Rpc(); + o.setTimeout(10000); + o.addEventListener("completed", fsm.eventListener, fsm); + o.addEventListener("failed", fsm.eventListener, fsm); + o.addEventListener("timeout", fsm.eventListener, fsm); + o.addEventListener("aborted", fsm.eventListener, fsm); + fsm.addObject("swat.module.rpc", o); +}; + + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.util.Return.returnInstance; diff --git a/swat/apps/swat/source/class/swat/module/statistics/Gui.js b/swat/apps/swat/source/class/swat/module/statistics/Gui.js new file mode 100644 index 0000000000..050c488c5c --- /dev/null +++ b/swat/apps/swat/source/class/swat/module/statistics/Gui.js @@ -0,0 +1,464 @@ +/* + * Copyright: + * (C) 2006 by Derrell Lipman + * All rights reserved + * + * License: + * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ + */ + +/** + * Swat statistics class graphical user interface + */ +qx.OO.defineClass("swat.module.statistics.Gui", qx.core.Object, +function() +{ + qx.core.Object.call(this); +}); + + +/* + * The result of our request for statistics is in this form: + * + * rpc: Object + * status: INACTIVE + * smb: Object + * tcons: Array + * 0: Object + * share_name: tmp + * last_use_time: 1167186771 + * client_ip: 127.0.0.1 + * tid: 10928 + * connect_time: 1167186757 + * connections: 1 + * sessions: Array + * 0: Object + * auth_time: 1167186757 + * vuid: 24588 + * last_use_time: 1167186771 + * client_ip: 127.0.0.1 + * connect_time: 1167186757 + * account_name: Administrator + * domain_name: WORKGROUP + * status: RUNNING + * ldap: Object + * status: INACTIVE + * wins: Object + * status: DISABLED + * nbt: Object + * status: RUNNING + * statistics: Object + * total_received: 32 + * total_sent: 4 + * query_count: 0 + * release_count: 0 + * register_count: 0 + * kdc: Object + * status: INACTIVE + * cldap: Object + * status: RUNNING + */ + +/** + * Build the raw graphical user interface. + */ +qx.Proto.buildGui = function(module) +{ + var o; + var fsm = module.fsm; + var canvas = module.canvas; + + canvas.setOverflow("auto"); + + // Create a gui object where we'll put each widget handle that has varying + // data to be displayed. + module.gui = { }; + + var addCaptionedText = function(caption, dest) + { + // Add a row to the destination grid + dest.addRow(); + var row = dest.getRowCount() - 1; + dest.setRowHeight(row, 16); + + // Add the caption + o = new qx.ui.basic.Label(caption); + dest.add(o, 0, row); + + // Add the text field that will contain varying data + o = new qx.ui.basic.Label(""); + dest.add(o, 1, row); + + // Give 'em the varying data label + return o; + }; + + var addGroup = function(legend, top, height, width, left, right, dest) + { + // Add a groupbox + var group = new qx.ui.groupbox.GroupBox(legend); + group.setTop(top); + if (left >= 0) + { + group.setLeft(left); + } + if (right >= 0) + { + group.setRight(right); + } + if (height >= 0) + { + group.setHeight(height); + } + if (typeof(width) == "string" || width >= 0) + { + group.setWidth(width); + } + group.setBackgroundColor("white"); + group.getLegendObject().setBackgroundColor("white"); + + var grid = new qx.ui.layout.GridLayout(); + grid.setLocation(0, 0); + grid.setDimension("100%", "100%"); + grid.setPadding(0, 0); + grid.setRowCount(0); + grid.setColumnCount(2); + grid.setColumnWidth(0, 100); + grid.setColumnWidth(1, 200); + + group.add(grid); + dest.add(group); + + return grid; + }; + + // Add the RPC Service group box and its status + var group = addGroup("RPC Service", 40, 60, "46%", 20, -1, canvas); + module.gui.rpc = + { + status : addCaptionedText("Status:", group) + }; + + // Add the KDC Service group box and its status + var group = addGroup("KDC Service", 40, 60, "46%", -1, 20, canvas); + module.gui.kdc = + { + status : addCaptionedText("Status:", group) + }; + + // Add the LDAP Service group box and its status + var group = addGroup("LDAP Service", 120, 60, "46%", 20, -1, canvas); + module.gui.ldap = + { + status : addCaptionedText("Status:", group) + }; + + // Add the CLDAP Service group box and its status + var group = addGroup("CLDAP Service", 120, 60, "46%", -1, 20, canvas); + module.gui.cldap = + { + status : addCaptionedText("Status:", group) + }; + + // Add the WINS Service group box and its status + var group = addGroup("WINS Service", 200, 60, "46%", 20, -1, canvas); + module.gui.wins = + { + status : addCaptionedText("Status:", group) + }; + + // Add the NBT Service group box and its status, and the statistics + var group = addGroup("NBT Service", 200, 140, "46%", -1, 20, canvas); + module.gui.nbt = + { + status : addCaptionedText("Status:", group), + total_received : addCaptionedText("Total received:", group), + total_sent : addCaptionedText("Total sent:", group), + query_count : addCaptionedText("Query count:", group), + release_count : addCaptionedText("Release count:", group), + register_count : addCaptionedText("Register count:", group) + }; + + // Add the SMB Service group box (sans grid) and its status + var group = new qx.ui.groupbox.GroupBox("SMB Service"); + group.set({ + top: 360, + height: 400, + left: 20, + right: 20 + }); + group.setBackgroundColor("white"); + group.getLegendObject().setBackgroundColor("white"); + + // Create the Status block + o = new qx.ui.basic.Label("Status:"); + o.set({ + top : 0, + left : 0, + width : 100 + }); + group.add(o); + + o = new qx.ui.basic.Label(""); + o.set({ + top : 0, + left : 100, + width : 200 + }); + group.add(o); + + // Add the status and create the table models for sessions and connections + module.gui.smb = + { + status : o, + sessions : new qx.ui.table.SimpleTableModel(), + tcons : new qx.ui.table.SimpleTableModel() + }; + + // Begin the Sessions section + o = new qx.ui.basic.Label("Sessions"); + o.set({ + top : 20, + left : 20 + }); + group.add(o); + + // Set column labels + var tableModel = module.gui.smb.sessions; + tableModel.setColumns([ + "User", + "Client", + "Connected at", + "Authenticated at", + "Last used at", + "VUID" + ]); + tableModel.setData([ ]); + + // Create the table for sessions + var table = new qx.ui.table.Table(tableModel); + table.set({ + top : 40, + left : 20, + right : 20, + height : 160 + }); + table.setMetaColumnCounts([1, -1]); + table.setStatusBarVisible(false); + table.setColumnVisibilityButtonVisible(false); + table.setColumnWidth(0, 260); + table.setColumnWidth(1, 80); + table.setColumnWidth(2, 120); + table.setColumnWidth(3, 120); + table.setColumnWidth(4, 120); + table.setColumnWidth(5, 60); + + // Add the table to the groupbox + group.add(table); + canvas.add(group); + + // Begin the Connections section + o = new qx.ui.basic.Label("Connections"); + o.set({ + top : 220, + left : 20 + }); + group.add(o); + + // Create the table model for tcons + var tableModel = module.gui.smb.tcons; + tableModel.setColumns([ + "Share", + "Client", + "Connected at", + "Last used at", + "TID" + ]); + tableModel.setData([ ]); + + // Create the table for sessions + var table = new qx.ui.table.Table(tableModel); + table.set({ + top : 240, + left : 20, + right : 20, + bottom : 20 + }); + table.setMetaColumnCounts([1, -1]); + table.setStatusBarVisible(false); + table.setColumnVisibilityButtonVisible(false); + table.setColumnWidth(0, 260); + table.setColumnWidth(1, 80); + table.setColumnWidth(2, 120); + table.setColumnWidth(3, 120); + table.setColumnWidth(4, 60); + + // Add the table to the groupbox + group.add(table); + canvas.add(group); + +}; + + +/** + * Populate the graphical user interface with the specified data + * + * @param module {Object} + * The descriptor containing our module-specific information + * + * @result {Object} + * The result returned by SAMBA to our request for statistics. We display + * the data provided by this result. + */ +qx.Proto.displayData = function(module, result) +{ + var gui = module.gui; + + if (result.type == "failed") + { + // Have we already put up the FAILED message? + if (gui.failed) + { + // Yup. + gui.failed.setDisplay(true); + return; + } + + // Create a semi-transparent layover o which to display a failure message + gui.failed = new qx.ui.layout.CanvasLayout(); + gui.failed.set({ + top: 0, + bottom: 0, + left: 0, + right: 0 + }); + gui.failed.setBackgroundColor("white"); + gui.failed.setDisplay(true); // initially displayed + gui.failed.setOpacity(0.7); // semi-transparent + + // Add the failure message + var style = + "color: red;" + + "font-size: large;" + + "font-weight: bold;"; + var o = new qx.ui.basic.Label("<span style='" + style + "'>" + + "Communication with SAMBA failed!", + "</span>"); + o.set({ + top : 0, + left : 20 + }); + gui.failed.add(o); + + // Add the failed layover to the canvas + module.canvas.add(gui.failed); + + return; + } + + // Successful RPC request. + // If the failure message was displayed, we no longer need it. + if (gui.failed) + { + gui.failed.setDisplay(false); + } + + // Create a function for formatting dates + var dateFormat = function(unixepoch) + { + var d = new Date(unixepoch * 1000); + return (d.getFullYear() + "-" + + ("0" + (d.getMonth() + 1)).substr(-2) + "-" + + ("0" + d.getDate()).substr(-2) + " " + + ("0" + d.getHours()).substr(-2) + ":" + + ("0" + d.getMinutes()).substr(-2)); + } + + // Set the status values + gui.rpc.status.setHtml(result.data.rpc.status); + gui.kdc.status.setHtml(result.data.kdc.status); + gui.ldap.status.setHtml(result.data.ldap.status); + gui.cldap.status.setHtml(result.data.cldap.status); + gui.wins.status.setHtml(result.data.wins.status); + gui.nbt.status.setHtml(result.data.nbt.status); + gui.smb.status.setHtml(result.data.smb.status); + + // If the NBT service is running... + if (result.data.nbt.status == "RUNNING") + { + // ... then output the statistics + gui.nbt.total_received.setHtml( + result.data.nbt.statistics.total_received.toString()); + gui.nbt.total_sent.setHtml( + result.data.nbt.statistics.total_sent.toString()); + gui.nbt.query_count.setHtml( + result.data.nbt.statistics.query_count.toString()); + gui.nbt.release_count.setHtml( + result.data.nbt.statistics.release_count.toString()); + gui.nbt.register_count.setHtml( + result.data.nbt.statistics.register_count.toString()); + } + else + { + // otherwise, clear the statistics fields + gui.nbt.total_received.setHtml(""); + gui.nbt.total_sent.setHtml(""); + gui.nbt.query_count.setHtml(""); + gui.nbt.release_count.setHtml(""); + gui.nbt.register_count.setHtml(""); + } + + // Initialize data for sessions list + var rowData = []; + + // If there are any sessions... + if (result.data.smb.sessions instanceof Array) + { + // ... then for each session... + for (var i = 0; i < result.data.smb.sessions.length; i++) + { + // ... add its info to the table data + var sess = result.data.smb.sessions[i]; + rowData.push([ + sess.account_name + "/" + sess.domain_name, + sess.client_ip, + dateFormat(sess.connect_time), + dateFormat(sess.auth_time), + dateFormat(sess.last_use_time), + sess.vuid.toString() + ]); + } + } + + // Whether there were sessions or not, reset the session table data + gui.smb.sessions.setData(rowData); + + // Initialize data for tcons list + var rowData = []; + + // If there are any tcons... + if (result.data.smb.tcons instanceof Array) + { + // ... then for each tcon... + for (var i = 0; i < result.data.smb.tcons.length; i++) + { + // ... add its info to the table data + var conn = result.data.smb.tcons[i]; + rowData.push([ + conn.share_name, + conn.client_ip, + dateFormat(conn.connect_time), + dateFormat(conn.last_use_time), + conn.tid.toString() + ]); + } + } + + // Whether there were tcons or not, reset the tcon table data + gui.smb.tcons.setData(rowData); +}; + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.util.Return.returnInstance; diff --git a/swat/apps/swat/source/class/swat/module/statistics/Statistics.js b/swat/apps/swat/source/class/swat/module/statistics/Statistics.js new file mode 100644 index 0000000000..00adf2f866 --- /dev/null +++ b/swat/apps/swat/source/class/swat/module/statistics/Statistics.js @@ -0,0 +1,43 @@ +/* + * Copyright: + * (C) 2006 by Derrell Lipman + * All rights reserved + * + * License: + * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/ + */ + +/** + * Swat statistics class + */ +qx.OO.defineClass("swat.module.statistics.Statistics", + swat.module.AbstractModule, +function() +{ + swat.module.AbstractModule.call(this); +}); + + +/** + * Create the module's finite state machine and graphical user interface. + * + * This function is called the first time a module is actually selected to + * appear. Creation of the module's actual FSM and GUI have been deferred + * until they were actually needed (now) so we need to create them. + * + * @param module {Object} @see AbstractModule + */ +qx.Proto.initialAppear = function(module) +{ + // Replace the existing (temporary) finite state machine with the real one + swat.module.statistics.Fsm.getInstance().buildFsm(module); + + // Create the real gui + swat.module.statistics.Gui.getInstance().buildGui(module); +}; + + +/** + * Singleton Instance Getter + */ +qx.Class.getInstance = qx.util.Return.returnInstance; |