From e78a1908e5d1a7244911e0ee70a3c59df389fe83 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Sun, 1 Dec 2013 15:05:43 +0100 Subject: [PATCH] Initial GTK version of GridProxy --- .gitignore | 2 + Programs/GridProxyGUI/FilterScroller.cs | 87 +++ Programs/GridProxyGUI/MainWindow.cs | 184 ++++++ Programs/GridProxyGUI/Program.cs | 16 + .../GridProxyGUI/Properties/AssemblyInfo.cs | 23 + Programs/GridProxyGUI/ProxyLogger.cs | 42 ++ Programs/GridProxyGUI/ProxyManager.cs | 510 +++++++++++++++++ Programs/GridProxyGUI/app.config | 3 + Programs/GridProxyGUI/gtk-gui/MainWindow.cs | 422 ++++++++++++++ Programs/GridProxyGUI/gtk-gui/generated.cs | 67 +++ Programs/GridProxyGUI/gtk-gui/gui.stetic | 532 ++++++++++++++++++ Programs/GridProxyGUI/libomv.ico | Bin 0 -> 82726 bytes Programs/GridProxyGUI/libomv.png | Bin 0 -> 17684 bytes prebuild.xml | 56 +- 14 files changed, 1916 insertions(+), 28 deletions(-) create mode 100755 Programs/GridProxyGUI/FilterScroller.cs create mode 100755 Programs/GridProxyGUI/MainWindow.cs create mode 100755 Programs/GridProxyGUI/Program.cs create mode 100755 Programs/GridProxyGUI/Properties/AssemblyInfo.cs create mode 100755 Programs/GridProxyGUI/ProxyLogger.cs create mode 100755 Programs/GridProxyGUI/ProxyManager.cs create mode 100755 Programs/GridProxyGUI/app.config create mode 100755 Programs/GridProxyGUI/gtk-gui/MainWindow.cs create mode 100755 Programs/GridProxyGUI/gtk-gui/generated.cs create mode 100755 Programs/GridProxyGUI/gtk-gui/gui.stetic create mode 100644 Programs/GridProxyGUI/libomv.ico create mode 100644 Programs/GridProxyGUI/libomv.png diff --git a/.gitignore b/.gitignore index 953a1e20..78b54280 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ compile.bat *.csproj *.user +*.userprefs *.sln +*.suo *.cache [Oo]bj/ diff --git a/Programs/GridProxyGUI/FilterScroller.cs b/Programs/GridProxyGUI/FilterScroller.cs new file mode 100755 index 00000000..8c5948e5 --- /dev/null +++ b/Programs/GridProxyGUI/FilterScroller.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using Gtk; +using GridProxyGUI; + +namespace GridProxyGUI +{ + public class UDPFilterItem + { + public bool Enabled; + public string Name; + } + + + public class FilterScroller : ScrolledWindow + { + ListStore store; + + public FilterScroller(Container parent, ListStore store) + { + this.store = store; + + TreeView tvFilterUDP = new TreeView(); + TreeViewColumn cbCol = new TreeViewColumn(); + TreeViewColumn udpCol = new TreeViewColumn(); + + CellRendererToggle cbCell = new CellRendererToggle(); + cbCell.Toggled += new ToggledHandler(cbCell_Toggled); + cbCell.Activatable = true; + cbCol.PackStart(cbCell, true); + cbCol.SetCellDataFunc(cbCell, renderToggleCell); + tvFilterUDP.AppendColumn(cbCol); + + CellRendererText cell = new CellRendererText(); + udpCol.PackStart(cell, true); + udpCol.SetCellDataFunc(cell, renderTextCell); + tvFilterUDP.AppendColumn(udpCol); + + tvFilterUDP.Model = store; + tvFilterUDP.HeadersVisible = false; + tvFilterUDP.Selection.Mode = SelectionMode.Single; + + foreach (var child in new List(parent.Children)) + { + parent.Remove(child); + } + + Add(tvFilterUDP); + ShadowType = ShadowType.EtchedIn; + parent.Add(this); + parent.ShowAll(); + } + + void cbCell_Toggled(object o, ToggledArgs args) + { + TreeIter iter; + if (store.GetIterFromString(out iter, args.Path)) + { + UDPFilterItem item = store.GetValue(iter, 0) as UDPFilterItem; + if (null != item) + { + item.Enabled = !item.Enabled; + store.SetValue(iter, 0, item); + } + } + } + + void renderTextCell(TreeViewColumn column, CellRenderer cell, TreeModel model, TreeIter iter) + { + var item = model.GetValue(iter, 0) as UDPFilterItem; + if (item != null) + { + ((CellRendererText)cell).Text = item.Name; + } + } + + void renderToggleCell(TreeViewColumn column, CellRenderer cell, TreeModel model, TreeIter iter) + { + var item = model.GetValue(iter, 0) as UDPFilterItem; + if (item != null) + { + ((CellRendererToggle)cell).Active = item.Enabled; + } + } + + } +} diff --git a/Programs/GridProxyGUI/MainWindow.cs b/Programs/GridProxyGUI/MainWindow.cs new file mode 100755 index 00000000..cac4de62 --- /dev/null +++ b/Programs/GridProxyGUI/MainWindow.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Gtk; +using GridProxyGUI; +using WinGridProxy; +using OpenMetaverse.Packets; + +public partial class MainWindow : Gtk.Window +{ + ProxyManager proxy = null; + ConcurrentDictionary UDPFilterItems = new ConcurrentDictionary(); + ConcurrentDictionary CapFilterItems = new ConcurrentDictionary(); + ListStore udpStore, capStore; + FilterScroller capScroller; + + public MainWindow() + : base(Gtk.WindowType.Toplevel) + { + Build(); + SetIconFromFile("libomv.png"); + tabsMain.Page = 1; + mainSplit.Position = 600; + txtSummary.ModifyFont(Pango.FontDescription.FromString("monospace bold 9")); + + ProxyLogger.Init(); + + ProxyManager.OnCapabilityAdded += new ProxyManager.CapsAddedHandler(ProxyManager_OnCapabilityAdded); + ProxyManager.OnEventMessageLog += new ProxyManager.EventQueueMessageHandler(ProxyManager_OnEventMessageLog); + ProxyManager.OnMessageLog += new ProxyManager.MessageLogHandler(ProxyManager_OnMessageLog); + } + + void ProxyManager_OnCapabilityAdded(GridProxy.CapInfo cap) + { + Application.Invoke((sender, e) => + { + if (null == capStore) + { + capStore = new ListStore(typeof(UDPFilterItem)); + } + + if (!CapFilterItems.ContainsKey(cap.CapType)) + { + UDPFilterItem item = new UDPFilterItem() { Enabled = true, Name = cap.CapType }; + CapFilterItems[item.Name] = item; + capStore.AppendValues(item); + } + + if (null == capScroller) + { + capScroller = new FilterScroller(containerFilterCap, capStore); + } + }); + } + + void ProxyManager_OnEventMessageLog(GridProxy.CapsRequest req, GridProxy.CapsStage stage) + { + Application.Invoke((sender, e) => + { + if (null == capStore) + { + capStore = new ListStore(typeof(UDPFilterItem)); + } + + if (!CapFilterItems.ContainsKey(req.Info.CapType)) + { + UDPFilterItem item = new UDPFilterItem() { Enabled = true, Name = req.Info.CapType }; + CapFilterItems[item.Name] = item; + capStore.AppendValues(item); + } + else + { + ProxyManager_OnMessageLog(req, GridProxy.CapsStage.Response); + } + + if (null == capScroller) + { + capScroller = new FilterScroller(containerFilterCap, capStore); + } + }); + } + + void ProxyManager_OnMessageLog(GridProxy.CapsRequest req, GridProxy.CapsStage stage) + { + } + + void Logger_OnLogLine(object sender, LogEventArgs e) + { + Gtk.Application.Invoke((sx, ex) => + { + AppendLog(e.Message); + }); + } + + void AppendLog(string msg) + { + var end = txtSummary.Buffer.EndIter; + txtSummary.Buffer.Insert(ref end, msg); + } + + protected void StartPoxy() + { + AppendLog("Starting proxy..." + Environment.NewLine); + ProxyLogger.OnLogLine += new ProxyLogger.Log(Logger_OnLogLine); + proxy = new ProxyManager(txtPort.Text, cbListen.ActiveText, cbLoginURL.ActiveText); + proxy.Start(); + } + + protected void StopProxy() + { + AppendLog("Proxy stopped" + Environment.NewLine); + ProxyLogger.OnLogLine -= new ProxyLogger.Log(Logger_OnLogLine); + if (proxy != null) proxy.Stop(); + proxy = null; + foreach (var child in new List(containerFilterUDP.Children)) + { + containerFilterUDP.Remove(child); + } + } + + protected void OnDeleteEvent(object sender, DeleteEventArgs a) + { + StopProxy(); + Application.Quit(); + a.RetVal = true; + } + + protected void OnExitActionActivated(object sender, EventArgs e) + { + StopProxy(); + Application.Quit(); + } + + protected void OnBtnStartClicked(object sender, EventArgs e) + { + if (btnStart.Label.StartsWith("Start")) + { + btnStart.Label = "Stop Proxy"; + StartPoxy(); + InitProxyFilters(); + } + else if (btnStart.Label.StartsWith("Stop")) + { + btnStart.Label = "Start Proxy"; + StopProxy(); + } + } + + void InitUDPFilters() + { + if (UDPFilterItems.Count > 0) return; + + UDPFilterItems["Login Request"] = new UDPFilterItem() { Enabled = false, Name = "Login Request" }; + UDPFilterItems["Login Response"] = new UDPFilterItem() { Enabled = true, Name = "Login Response" }; + foreach (string name in Enum.GetNames(typeof(PacketType))) + { + if (!string.IsNullOrEmpty(name)) + { + UDPFilterItems[name] = new UDPFilterItem() { Enabled = false, Name = name }; + } + } + } + + void InitProxyFilters() + { + InitUDPFilters(); + + udpStore = new ListStore(typeof(UDPFilterItem)); + List keys = new List(UDPFilterItems.Keys); + keys.Sort((a, b) => { return string.Compare(a.ToLower(), b.ToLower()); }); + + udpStore.AppendValues(UDPFilterItems["Login Request"]); + udpStore.AppendValues(UDPFilterItems["Login Response"]); + + foreach (var key in keys) + { + if (key == "Login Request" || key == "Login Response") continue; + udpStore.AppendValues(UDPFilterItems[key]); + } + + new FilterScroller(containerFilterUDP, udpStore); + } + +} \ No newline at end of file diff --git a/Programs/GridProxyGUI/Program.cs b/Programs/GridProxyGUI/Program.cs new file mode 100755 index 00000000..54a3b100 --- /dev/null +++ b/Programs/GridProxyGUI/Program.cs @@ -0,0 +1,16 @@ +using System; +using Gtk; + +namespace GridProxyGUI +{ + class MainClass + { + public static void Main(string[] args) + { + Application.Init(); + MainWindow win = new MainWindow(); + win.Show(); + Application.Run(); + } + } +} diff --git a/Programs/GridProxyGUI/Properties/AssemblyInfo.cs b/Programs/GridProxyGUI/Properties/AssemblyInfo.cs new file mode 100755 index 00000000..4e11fa57 --- /dev/null +++ b/Programs/GridProxyGUI/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("GridProxyGUI")] +[assembly: AssemblyDescription("GTK Based GUI for Grid Proxy")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany("Open Metaverse Foundation")] +[assembly: AssemblyProduct("Grid Proxy GUI")] +[assembly: AssemblyCopyright("Latif Khalifa")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + +[assembly: AssemblyFileVersionAttribute("1.0")] diff --git a/Programs/GridProxyGUI/ProxyLogger.cs b/Programs/GridProxyGUI/ProxyLogger.cs new file mode 100755 index 00000000..3d9a4de8 --- /dev/null +++ b/Programs/GridProxyGUI/ProxyLogger.cs @@ -0,0 +1,42 @@ +using System; +using log4net; +using log4net.Appender; +using log4net.Core; +using log4net.Config; +using log4net.Layout; + +namespace GridProxyGUI +{ + public class ProxyLogger : AppenderSkeleton + { + public delegate void Log(object sender, LogEventArgs e); + public static event Log OnLogLine; + + public static void Init() + { + var appender = new ProxyLogger(); + appender.Layout = new PatternLayout("%timestamp %-5level %message%newline"); + // appender.AddFilter(new log4net.Filter.LoggerMatchFilter() { LoggerToMatch = "OpenMetaverse" }); + BasicConfigurator.Configure(appender); + } + + protected override void Append(LoggingEvent le) + { + if (OnLogLine != null && le.Level != Level.Debug) + { + OnLogLine(this, new LogEventArgs(string.Format("{0} [{1}] {2}\n", le.TimeStamp, le.Level, le.MessageObject))); + } + } + } + + public class LogEventArgs : EventArgs + { + public string Message { get; set; } + + public LogEventArgs(string msg) + { + this.Message = msg; + } + } +} + diff --git a/Programs/GridProxyGUI/ProxyManager.cs b/Programs/GridProxyGUI/ProxyManager.cs new file mode 100755 index 00000000..bc9f278b --- /dev/null +++ b/Programs/GridProxyGUI/ProxyManager.cs @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the openmetaverse.org nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Reflection; +using GridProxy; +using Nwc.XmlRpc; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenMetaverse; + +namespace WinGridProxy +{ + public class ProxyManager + { + // fired when a new packet arrives + public delegate void PacketLogHandler(Packet packet, Direction direction, IPEndPoint endpoint); + public static event PacketLogHandler OnPacketLog; + + // fired when a message arrives over a known capability + public delegate void MessageLogHandler(CapsRequest req, CapsStage stage); + public static event MessageLogHandler OnMessageLog; + + // handle login request/response data + public delegate void LoginLogHandler(object request, Direction direction); + public static event LoginLogHandler OnLoginResponse; + + // fired when a new Capability is added to the KnownCaps Dictionary + public delegate void CapsAddedHandler(CapInfo cap); + public static event CapsAddedHandler OnCapabilityAdded; + + // Handle messages sent via the EventQueue + public delegate void EventQueueMessageHandler(CapsRequest req, CapsStage stage); + public static event EventQueueMessageHandler OnEventMessageLog; + + private string _Port; + private string _ListenIP; + private string _LoginURI; + + public ProxyFrame Proxy; + + private Assembly openmvAssembly; + + public ProxyManager(string port, string listenIP, string loginUri) + { + openmvAssembly = Assembly.Load("OpenMetaverse"); + if (openmvAssembly == null) throw new Exception("Assembly load exception"); + + _Port = string.Format("--proxy-login-port={0}", port); + + IPAddress remoteIP; // not used + if (IPAddress.TryParse(listenIP, out remoteIP)) + _ListenIP = String.Format("--proxy-client-facing-address={0}", listenIP); + else + _ListenIP = "--proxy-client-facing-address=127.0.0.1"; + + if (String.IsNullOrEmpty(loginUri)) + _LoginURI = "--proxy-remote-login-uri=https://login.agni.lindenlab.com/cgi-bin/login.cgi"; + else + _LoginURI = "--proxy-remote-login-uri=" + loginUri; + + + string[] args = { _Port, _ListenIP, _LoginURI }; + /* + help + proxy-help + proxy-login-port + proxy-client-facing-address + proxy-remote-facing-address + proxy-remote-login-uri + verbose + quiet + */ + + ProxyConfig pc = new ProxyConfig("WinGridProxy", "Jim Radford", args); + + Proxy = new ProxyFrame(args, pc); + + Proxy.proxy.AddLoginRequestDelegate(new XmlRpcRequestDelegate(LoginRequest)); + Proxy.proxy.AddLoginResponseDelegate(new XmlRpcResponseDelegate(LoginResponse)); + + Proxy.proxy.AddCapsDelegate("EventQueueGet", new CapsDelegate(EventQueueGetHandler)); + + // this is so we are informed of any new capabilities that are added to the KnownCaps dictionary + Proxy.proxy.KnownCaps.AddDelegate(OpenMetaverse.DictionaryEventAction.Add, new OpenMetaverse.DictionaryChangeCallback(KnownCapsAddedHandler)); + } + + public void Start() + { + Proxy.proxy.Start(); + } + + public void Stop() + { + Proxy.proxy.Stop(); + } + + public void KnownCapsAddedHandler(OpenMetaverse.DictionaryEventAction action, System.Collections.DictionaryEntry de) + { + if (OnCapabilityAdded != null) + OnCapabilityAdded((CapInfo)de.Value); + } + + private void LoginRequest(object sender, XmlRpcRequestEventArgs e) + { + if (OnLoginResponse != null) + OnLoginResponse(e.m_Request, Direction.Outgoing); + } + + private void LoginResponse(XmlRpcResponse response) + { + if (OnLoginResponse != null) + OnLoginResponse(response, Direction.Incoming); + } + + + internal OpenMetaverse.ObservableDictionary GetCapabilities() + { + return Proxy.proxy.KnownCaps; + } + + internal void AddCapsDelegate(string capsKey, bool add) + { + if (add) + Proxy.proxy.AddCapsDelegate(capsKey, new CapsDelegate(CapsHandler)); + else + Proxy.proxy.RemoveCapRequestDelegate(capsKey, new CapsDelegate(CapsHandler)); + + } + + private bool CapsHandler(CapsRequest req, CapsStage stage) + { + if (OnMessageLog != null) + OnMessageLog(req, stage); + return false; + } + + /// + /// Process individual messages that arrive via the EventQueue and convert each indvidual event into a format + /// suitable for processing by the IMessage system + /// + /// + /// + /// + private bool EventQueueGetHandler(CapsRequest req, CapsStage stage) + { + if (stage == CapsStage.Response && req.Response is OSDMap) + { + OSDMap map = (OSDMap)req.Response; + + if (map.ContainsKey("events")) + { + OSDArray eventsArray = (OSDArray)map["events"]; + + for (int i = 0; i < eventsArray.Count; i++) + { + OSDMap bodyMap = (OSDMap)eventsArray[i]; + if (OnEventMessageLog != null) + { + CapInfo capInfo = new CapInfo(req.Info.URI, req.Info.Sim, bodyMap["message"].AsString()); + CapsRequest capReq = new CapsRequest(capInfo); + capReq.RequestHeaders = req.RequestHeaders; + capReq.ResponseHeaders = req.ResponseHeaders; + capReq.Request = null;// req.Request; + capReq.RawRequest = null;// req.RawRequest; + capReq.RawResponse = OSDParser.SerializeLLSDXmlBytes(bodyMap); + capReq.Response = bodyMap; + + OnEventMessageLog(capReq, CapsStage.Response); + } + } + } + } + return false; + } + + internal void AddUDPDelegate(PacketType packetType, bool add) + { + if (add) + { + Proxy.proxy.AddDelegate(packetType, Direction.Incoming, new PacketDelegate(PacketInHandler)); + Proxy.proxy.AddDelegate(packetType, Direction.Outgoing, new PacketDelegate(PacketOutHandler)); + } + else + { + Proxy.proxy.RemoveDelegate(packetType, Direction.Incoming, new PacketDelegate(PacketInHandler)); + Proxy.proxy.RemoveDelegate(packetType, Direction.Outgoing, new PacketDelegate(PacketOutHandler)); + } + } + + private Packet PacketInHandler(Packet packet, IPEndPoint endPoint) + { + if (OnPacketLog != null) + OnPacketLog(packet, Direction.Incoming, endPoint); + + return packet; + } + + private Packet PacketOutHandler(Packet packet, IPEndPoint endPoint) + { + if (OnPacketLog != null) + OnPacketLog(packet, Direction.Outgoing, endPoint); + + return packet; + } + + internal void InjectPacket(string packetData, bool toSimulator) + { + Direction direction = Direction.Incoming; + string name = null; + string block = null; + object blockObj = null; + Type packetClass = null; + Packet packet = null; + + try + { + foreach (string line in packetData.Split(new[] { '\n' })) + { + Match match; + + if (name == null) + { + match = (new Regex(@"^\s*(in|out)\s+(\w+)\s*$")).Match(line); + if (!match.Success) + { + OpenMetaverse.Logger.Log("expecting direction and packet name, got: " + line, OpenMetaverse.Helpers.LogLevel.Error); + return; + } + + string lineDir = match.Groups[1].Captures[0].ToString(); + string lineName = match.Groups[2].Captures[0].ToString(); + + if (lineDir == "in") + direction = Direction.Incoming; + else if (lineDir == "out") + direction = Direction.Outgoing; + else + { + OpenMetaverse.Logger.Log("expecting 'in' or 'out', got: " + line, OpenMetaverse.Helpers.LogLevel.Error); + return; + } + + name = lineName; + packetClass = openmvAssembly.GetType("OpenMetaverse.Packets." + name + "Packet"); + if (packetClass == null) throw new Exception("Couldn't get class " + name + "Packet"); + ConstructorInfo ctr = packetClass.GetConstructor(new Type[] { }); + if (ctr == null) throw new Exception("Couldn't get suitable constructor for " + name + "Packet"); + packet = (Packet)ctr.Invoke(new object[] { }); + } + else + { + match = (new Regex(@"^\s*\[(\w+)\]\s*$")).Match(line); + if (match.Success) + { + block = match.Groups[1].Captures[0].ToString(); + FieldInfo blockField = packetClass.GetField(block); + if (blockField == null) throw new Exception("Couldn't get " + name + "Packet." + block); + Type blockClass = blockField.FieldType; + if (blockClass.IsArray) + { + blockClass = blockClass.GetElementType(); + ConstructorInfo ctr = blockClass.GetConstructor(new Type[] { }); + if (ctr == null) throw new Exception("Couldn't get suitable constructor for " + blockClass.Name); + blockObj = ctr.Invoke(new object[] { }); + object[] arr = (object[])blockField.GetValue(packet); + object[] narr = (object[])Array.CreateInstance(blockClass, arr.Length + 1); + Array.Copy(arr, narr, arr.Length); + narr[arr.Length] = blockObj; + blockField.SetValue(packet, narr); + //Console.WriteLine("Added block "+block); + } + else + { + blockObj = blockField.GetValue(packet); + } + if (blockObj == null) throw new Exception("Got " + name + "Packet." + block + " == null"); + //Console.WriteLine("Got block " + name + "Packet." + block); + + continue; + } + + if (block == null) + { + OpenMetaverse.Logger.Log("expecting block name, got: " + line, OpenMetaverse.Helpers.LogLevel.Error); + return; + } + + match = (new Regex(@"^\s*(\w+)\s*=\s*(.*)$")).Match(line); + if (match.Success) + { + string lineField = match.Groups[1].Captures[0].ToString(); + string lineValue = match.Groups[2].Captures[0].ToString(); + object fval; + + //FIXME: use of MagicCast inefficient + //if (lineValue == "$Value") + // fval = MagicCast(name, block, lineField, value); + if (lineValue == "$UUID") + fval = UUID.Random(); + else if (lineValue == "$AgentID") + fval = Proxy.AgentID; + else if (lineValue == "$SessionID") + fval = Proxy.SessionID; + else + fval = MagicCast(name, block, lineField, lineValue); + + MagicSetField(blockObj, lineField, fval); + continue; + } + OpenMetaverse.Logger.Log("expecting block name or field, got: " + line, OpenMetaverse.Helpers.LogLevel.Error); + return; + } + } + + if (name == null) + { + + OpenMetaverse.Logger.Log("expecting direction and packet name, got EOF", OpenMetaverse.Helpers.LogLevel.Error); + return; + } + + packet.Header.Reliable = true; + + Proxy.proxy.InjectPacket(packet, direction); + + OpenMetaverse.Logger.Log("Injected " + name, OpenMetaverse.Helpers.LogLevel.Info); + } + catch (Exception e) + { + OpenMetaverse.Logger.Log("failed to injected " + name, OpenMetaverse.Helpers.LogLevel.Error, e); + } + } + + private static void MagicSetField(object obj, string field, object val) + { + Type cls = obj.GetType(); + + FieldInfo fieldInf = cls.GetField(field); + if (fieldInf == null) + { + PropertyInfo prop = cls.GetProperty(field); + if (prop == null) throw new Exception("Couldn't find field " + cls.Name + "." + field); + prop.SetValue(obj, val, null); + //throw new Exception("FIXME: can't set properties"); + } + else + { + fieldInf.SetValue(obj, val); + } + } + + // MagicCast: given a packet/block/field name and a string, convert the string to a value of the appropriate type + private object MagicCast(string name, string block, string field, string value) + { + Type packetClass = openmvAssembly.GetType("OpenMetaverse.Packets." + name + "Packet"); + if (packetClass == null) throw new Exception("Couldn't get class " + name + "Packet"); + + FieldInfo blockField = packetClass.GetField(block); + if (blockField == null) throw new Exception("Couldn't get " + name + "Packet." + block); + Type blockClass = blockField.FieldType; + if (blockClass.IsArray) blockClass = blockClass.GetElementType(); + // Console.WriteLine("DEBUG: " + blockClass.Name); + + FieldInfo fieldField = blockClass.GetField(field); PropertyInfo fieldProp = null; + Type fieldClass = null; + if (fieldField == null) + { + fieldProp = blockClass.GetProperty(field); + if (fieldProp == null) throw new Exception("Couldn't get " + name + "Packet." + block + "." + field); + fieldClass = fieldProp.PropertyType; + } + else + { + fieldClass = fieldField.FieldType; + } + + try + { + if (fieldClass == typeof(byte)) + { + return Convert.ToByte(value); + } + else if (fieldClass == typeof(ushort)) + { + return Convert.ToUInt16(value); + } + else if (fieldClass == typeof(uint)) + { + return Convert.ToUInt32(value); + } + else if (fieldClass == typeof(ulong)) + { + return Convert.ToUInt64(value); + } + else if (fieldClass == typeof(sbyte)) + { + return Convert.ToSByte(value); + } + else if (fieldClass == typeof(short)) + { + return Convert.ToInt16(value); + } + else if (fieldClass == typeof(int)) + { + return Convert.ToInt32(value); + } + else if (fieldClass == typeof(long)) + { + return Convert.ToInt64(value); + } + else if (fieldClass == typeof(float)) + { + return Convert.ToSingle(value); + } + else if (fieldClass == typeof(double)) + { + return Convert.ToDouble(value); + } + else if (fieldClass == typeof(UUID)) + { + return new UUID(value); + } + else if (fieldClass == typeof(bool)) + { + if (value.ToLower() == "true") + return true; + else if (value.ToLower() == "false") + return false; + else + throw new Exception(); + } + else if (fieldClass == typeof(byte[])) + { + return Utils.StringToBytes(value); + } + else if (fieldClass == typeof(Vector3)) + { + Vector3 result; + if (Vector3.TryParse(value, out result)) + return result; + else + throw new Exception(); + } + else if (fieldClass == typeof(Vector3d)) + { + Vector3d result; + if (Vector3d.TryParse(value, out result)) + return result; + else + throw new Exception(); + } + else if (fieldClass == typeof(Vector4)) + { + Vector4 result; + if (Vector4.TryParse(value, out result)) + return result; + else + throw new Exception(); + } + else if (fieldClass == typeof(Quaternion)) + { + Quaternion result; + if (Quaternion.TryParse(value, out result)) + return result; + else + throw new Exception(); + } + else + { + throw new Exception("unsupported field type " + fieldClass); + } + } + catch + { + throw new Exception("unable to interpret " + value + " as " + fieldClass); + } + } + } + + + +} diff --git a/Programs/GridProxyGUI/app.config b/Programs/GridProxyGUI/app.config new file mode 100755 index 00000000..e3656033 --- /dev/null +++ b/Programs/GridProxyGUI/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Programs/GridProxyGUI/gtk-gui/MainWindow.cs b/Programs/GridProxyGUI/gtk-gui/MainWindow.cs new file mode 100755 index 00000000..35fc1354 --- /dev/null +++ b/Programs/GridProxyGUI/gtk-gui/MainWindow.cs @@ -0,0 +1,422 @@ + +// This file has been generated by the GUI designer. Do not modify. + +public partial class MainWindow +{ + private global::Gtk.UIManager UIManager; + private global::Gtk.Action FileAction; + private global::Gtk.Action ExitAction; + private global::Gtk.Action EditAction; + private global::Gtk.Action HelpAction; + private global::Gtk.Action AboutAction; + private global::Gtk.Action RemoveAction; + private global::Gtk.Action SelectAction; + private global::Gtk.Action AllAction; + private global::Gtk.Action AllAction1; + private global::Gtk.Action SelectedAction; + private global::Gtk.Action FindAction; + private global::Gtk.Action OpenSessionAction; + private global::Gtk.Action SaveSessionAction; + private global::Gtk.Action SaveSessionAsAction; + private global::Gtk.VBox vbox1; + private global::Gtk.HBox boxTopMenu; + private global::Gtk.Alignment alignment2; + private global::Gtk.MenuBar menubar1; + private global::Gtk.VSeparator vseparator1; + private global::Gtk.Label label1; + private global::Gtk.ComboBoxEntry cbListen; + private global::Gtk.Label label2; + private global::Gtk.Entry txtPort; + private global::Gtk.Label label3; + private global::Gtk.ComboBoxEntry cbLoginURL; + private global::Gtk.Button btnStart; + private global::Gtk.HPaned mainSplit; + private global::Gtk.ScrolledWindow sessionLogScroller; + private global::Gtk.TreeView treeview1; + private global::Gtk.Notebook tabsMain; + private global::Gtk.ScrolledWindow logFileScroller; + private global::Gtk.TextView txtSummary; + private global::Gtk.Label label4; + private global::Gtk.VBox filterBox; + private global::Gtk.HBox hbox2; + private global::Gtk.Button btnLoadFilters; + private global::Gtk.Button btnSaveFilters; + private global::Gtk.CheckButton cbAutoCheckCaps; + private global::Gtk.HBox hbox3; + private global::Gtk.Frame frameFilterUDP; + private global::Gtk.Alignment containerFilterUDP; + private global::Gtk.Label GtkLabel7; + private global::Gtk.Frame frameFilterCap; + private global::Gtk.Alignment containerFilterCap; + private global::Gtk.Label GtkLabel8; + private global::Gtk.HBox hbox4; + private global::Gtk.CheckButton cbSelectAllUDP; + private global::Gtk.CheckButton cbSelectAllCap; + private global::Gtk.Label label5; + private global::Gtk.Label label6; + + protected virtual void Build () + { + global::Stetic.Gui.Initialize (this); + // Widget MainWindow + this.UIManager = new global::Gtk.UIManager (); + global::Gtk.ActionGroup w1 = new global::Gtk.ActionGroup ("Default"); + this.FileAction = new global::Gtk.Action ("FileAction", global::Mono.Unix.Catalog.GetString ("File"), null, null); + this.FileAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("File"); + w1.Add (this.FileAction, "f"); + this.ExitAction = new global::Gtk.Action ("ExitAction", global::Mono.Unix.Catalog.GetString ("Exit"), null, null); + this.ExitAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Exit"); + w1.Add (this.ExitAction, "q"); + this.EditAction = new global::Gtk.Action ("EditAction", global::Mono.Unix.Catalog.GetString ("Edit"), null, null); + this.EditAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Edit"); + w1.Add (this.EditAction, null); + this.HelpAction = new global::Gtk.Action ("HelpAction", global::Mono.Unix.Catalog.GetString ("Help"), null, null); + this.HelpAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Help"); + w1.Add (this.HelpAction, null); + this.AboutAction = new global::Gtk.Action ("AboutAction", global::Mono.Unix.Catalog.GetString ("About"), null, null); + this.AboutAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("About"); + w1.Add (this.AboutAction, null); + this.RemoveAction = new global::Gtk.Action ("RemoveAction", global::Mono.Unix.Catalog.GetString ("Remove"), null, null); + this.RemoveAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Remove"); + w1.Add (this.RemoveAction, null); + this.SelectAction = new global::Gtk.Action ("SelectAction", global::Mono.Unix.Catalog.GetString ("Select"), null, null); + this.SelectAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Select"); + w1.Add (this.SelectAction, null); + this.AllAction = new global::Gtk.Action ("AllAction", global::Mono.Unix.Catalog.GetString ("All"), null, null); + this.AllAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("All"); + w1.Add (this.AllAction, null); + this.AllAction1 = new global::Gtk.Action ("AllAction1", global::Mono.Unix.Catalog.GetString ("All"), null, null); + this.AllAction1.ShortLabel = global::Mono.Unix.Catalog.GetString ("All"); + w1.Add (this.AllAction1, null); + this.SelectedAction = new global::Gtk.Action ("SelectedAction", global::Mono.Unix.Catalog.GetString ("Selected"), null, null); + this.SelectedAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Selected"); + w1.Add (this.SelectedAction, null); + this.FindAction = new global::Gtk.Action ("FindAction", global::Mono.Unix.Catalog.GetString ("Find"), null, null); + this.FindAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Find (Ctrl-F)"); + w1.Add (this.FindAction, "f"); + this.OpenSessionAction = new global::Gtk.Action ("OpenSessionAction", global::Mono.Unix.Catalog.GetString ("Open Session..."), null, null); + this.OpenSessionAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Open Session..."); + w1.Add (this.OpenSessionAction, "o"); + this.SaveSessionAction = new global::Gtk.Action ("SaveSessionAction", global::Mono.Unix.Catalog.GetString ("Save Session"), null, null); + this.SaveSessionAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Save Session"); + w1.Add (this.SaveSessionAction, "s"); + this.SaveSessionAsAction = new global::Gtk.Action ("SaveSessionAsAction", global::Mono.Unix.Catalog.GetString ("Save Session As..."), null, null); + this.SaveSessionAsAction.ShortLabel = global::Mono.Unix.Catalog.GetString ("Save Session As..."); + w1.Add (this.SaveSessionAsAction, null); + this.UIManager.InsertActionGroup (w1, 0); + this.AddAccelGroup (this.UIManager.AccelGroup); + this.Name = "MainWindow"; + this.Title = global::Mono.Unix.Catalog.GetString ("Grid Proxy"); + this.WindowPosition = ((global::Gtk.WindowPosition)(4)); + this.AllowShrink = true; + // Container child MainWindow.Gtk.Container+ContainerChild + this.vbox1 = new global::Gtk.VBox (); + this.vbox1.Name = "vbox1"; + this.vbox1.Spacing = 6; + // Container child vbox1.Gtk.Box+BoxChild + this.boxTopMenu = new global::Gtk.HBox (); + this.boxTopMenu.Name = "hbox1"; + this.boxTopMenu.Spacing = 6; + this.boxTopMenu.BorderWidth = ((uint)(3)); + // Container child hbox1.Gtk.Box+BoxChild + this.alignment2 = new global::Gtk.Alignment (0.5F, 0.5F, 1F, 1F); + this.alignment2.Name = "alignment2"; + // Container child alignment2.Gtk.Container+ContainerChild + this.UIManager.AddUiFromString (@""); + this.menubar1 = ((global::Gtk.MenuBar)(this.UIManager.GetWidget ("/menubar1"))); + this.menubar1.Name = "menubar1"; + this.alignment2.Add (this.menubar1); + this.boxTopMenu.Add (this.alignment2); + global::Gtk.Box.BoxChild w3 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.alignment2])); + w3.Position = 0; + w3.Expand = false; + w3.Fill = false; + // Container child hbox1.Gtk.Box+BoxChild + this.vseparator1 = new global::Gtk.VSeparator (); + this.vseparator1.Name = "vseparator1"; + this.boxTopMenu.Add (this.vseparator1); + global::Gtk.Box.BoxChild w4 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.vseparator1])); + w4.Position = 1; + w4.Expand = false; + w4.Fill = false; + // Container child hbox1.Gtk.Box+BoxChild + this.label1 = new global::Gtk.Label (); + this.label1.Name = "label1"; + this.label1.LabelProp = global::Mono.Unix.Catalog.GetString ("Listen IP Address:"); + this.boxTopMenu.Add (this.label1); + global::Gtk.Box.BoxChild w5 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.label1])); + w5.Position = 2; + w5.Expand = false; + w5.Fill = false; + // Container child hbox1.Gtk.Box+BoxChild + this.cbListen = global::Gtk.ComboBoxEntry.NewText (); + this.cbListen.AppendText (global::Mono.Unix.Catalog.GetString ("127.0.0.1")); + this.cbListen.AppendText (global::Mono.Unix.Catalog.GetString ("0.0.0.0")); + this.cbListen.WidthRequest = 100; + this.cbListen.Name = "cbListen"; + this.cbListen.Active = 0; + this.boxTopMenu.Add (this.cbListen); + global::Gtk.Box.BoxChild w6 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.cbListen])); + w6.Position = 3; + w6.Expand = false; + w6.Fill = false; + // Container child hbox1.Gtk.Box+BoxChild + this.label2 = new global::Gtk.Label (); + this.label2.Name = "label2"; + this.label2.LabelProp = global::Mono.Unix.Catalog.GetString ("Port"); + this.boxTopMenu.Add (this.label2); + global::Gtk.Box.BoxChild w7 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.label2])); + w7.Position = 4; + w7.Expand = false; + w7.Fill = false; + // Container child hbox1.Gtk.Box+BoxChild + this.txtPort = new global::Gtk.Entry (); + this.txtPort.WidthRequest = 50; + this.txtPort.CanFocus = true; + this.txtPort.Name = "txtPort"; + this.txtPort.Text = global::Mono.Unix.Catalog.GetString ("8080"); + this.txtPort.IsEditable = true; + this.txtPort.MaxLength = 5; + this.txtPort.InvisibleChar = '●'; + this.boxTopMenu.Add (this.txtPort); + global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.txtPort])); + w8.Position = 5; + w8.Expand = false; + // Container child hbox1.Gtk.Box+BoxChild + this.label3 = new global::Gtk.Label (); + this.label3.Name = "label3"; + this.label3.LabelProp = global::Mono.Unix.Catalog.GetString ("Login URL"); + this.boxTopMenu.Add (this.label3); + global::Gtk.Box.BoxChild w9 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.label3])); + w9.Position = 6; + w9.Expand = false; + w9.Fill = false; + // Container child hbox1.Gtk.Box+BoxChild + this.cbLoginURL = global::Gtk.ComboBoxEntry.NewText (); + this.cbLoginURL.AppendText (global::Mono.Unix.Catalog.GetString ("https://login.agni.lindenlab.com/cgi-bin/login.cgi")); + this.cbLoginURL.AppendText (global::Mono.Unix.Catalog.GetString ("https://login.aditi.lindenlab.com/cgi-bin/login.cgi")); + this.cbLoginURL.AppendText (global::Mono.Unix.Catalog.GetString ("http://login.orgrid.org/")); + this.cbLoginURL.WidthRequest = 300; + this.cbLoginURL.Name = "cbLoginURL"; + this.cbLoginURL.Active = 0; + this.boxTopMenu.Add (this.cbLoginURL); + global::Gtk.Box.BoxChild w10 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.cbLoginURL])); + w10.Position = 7; + w10.Expand = false; + w10.Fill = false; + // Container child hbox1.Gtk.Box+BoxChild + this.btnStart = new global::Gtk.Button (); + this.btnStart.CanFocus = true; + this.btnStart.Name = "btnStart"; + this.btnStart.UseUnderline = true; + this.btnStart.Label = global::Mono.Unix.Catalog.GetString ("Start Proxy"); + this.boxTopMenu.Add (this.btnStart); + global::Gtk.Box.BoxChild w11 = ((global::Gtk.Box.BoxChild)(this.boxTopMenu [this.btnStart])); + w11.Position = 8; + w11.Expand = false; + w11.Fill = false; + this.vbox1.Add (this.boxTopMenu); + global::Gtk.Box.BoxChild w12 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.boxTopMenu])); + w12.Position = 0; + w12.Expand = false; + w12.Fill = false; + // Container child vbox1.Gtk.Box+BoxChild + this.mainSplit = new global::Gtk.HPaned (); + this.mainSplit.CanFocus = true; + this.mainSplit.Name = "mainSplit"; + this.mainSplit.Position = 1; + // Container child mainSplit.Gtk.Paned+PanedChild + this.sessionLogScroller = new global::Gtk.ScrolledWindow (); + this.sessionLogScroller.Name = "GtkScrolledWindow1"; + this.sessionLogScroller.ShadowType = ((global::Gtk.ShadowType)(1)); + // Container child GtkScrolledWindow1.Gtk.Container+ContainerChild + this.treeview1 = new global::Gtk.TreeView (); + this.treeview1.CanFocus = true; + this.treeview1.Name = "treeview1"; + this.sessionLogScroller.Add (this.treeview1); + this.mainSplit.Add (this.sessionLogScroller); + global::Gtk.Paned.PanedChild w14 = ((global::Gtk.Paned.PanedChild)(this.mainSplit [this.sessionLogScroller])); + w14.Resize = false; + // Container child mainSplit.Gtk.Paned+PanedChild + this.tabsMain = new global::Gtk.Notebook (); + this.tabsMain.CanFocus = true; + this.tabsMain.Name = "tabsMain"; + this.tabsMain.CurrentPage = 1; + this.tabsMain.EnablePopup = true; + // Container child tabsMain.Gtk.Notebook+NotebookChild + this.logFileScroller = new global::Gtk.ScrolledWindow (); + this.logFileScroller.Name = "logFileScroller"; + this.logFileScroller.ShadowType = ((global::Gtk.ShadowType)(1)); + // Container child logFileScroller.Gtk.Container+ContainerChild + this.txtSummary = new global::Gtk.TextView (); + this.txtSummary.CanFocus = true; + this.txtSummary.Name = "txtSummary"; + this.txtSummary.Editable = false; + this.txtSummary.WrapMode = ((global::Gtk.WrapMode)(2)); + this.logFileScroller.Add (this.txtSummary); + this.tabsMain.Add (this.logFileScroller); + // Notebook tab + this.label4 = new global::Gtk.Label (); + this.label4.Name = "label4"; + this.label4.LabelProp = global::Mono.Unix.Catalog.GetString ("Summary"); + this.tabsMain.SetTabLabel (this.logFileScroller, this.label4); + this.label4.ShowAll (); + // Container child tabsMain.Gtk.Notebook+NotebookChild + this.filterBox = new global::Gtk.VBox (); + this.filterBox.Name = "filterBox"; + this.filterBox.Spacing = 6; + // Container child filterBox.Gtk.Box+BoxChild + this.hbox2 = new global::Gtk.HBox (); + this.hbox2.Name = "hbox2"; + this.hbox2.Spacing = 6; + // Container child hbox2.Gtk.Box+BoxChild + this.btnLoadFilters = new global::Gtk.Button (); + this.btnLoadFilters.CanFocus = true; + this.btnLoadFilters.Name = "btnLoadFilters"; + this.btnLoadFilters.UseUnderline = true; + this.btnLoadFilters.Label = global::Mono.Unix.Catalog.GetString ("Load"); + global::Gtk.Image w17 = new global::Gtk.Image (); + w17.Pixbuf = global::Stetic.IconLoader.LoadIcon (this, "gtk-open", global::Gtk.IconSize.Menu); + this.btnLoadFilters.Image = w17; + this.hbox2.Add (this.btnLoadFilters); + global::Gtk.Box.BoxChild w18 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.btnLoadFilters])); + w18.Position = 0; + w18.Expand = false; + w18.Fill = false; + // Container child hbox2.Gtk.Box+BoxChild + this.btnSaveFilters = new global::Gtk.Button (); + this.btnSaveFilters.CanFocus = true; + this.btnSaveFilters.Name = "btnSaveFilters"; + this.btnSaveFilters.UseUnderline = true; + this.btnSaveFilters.Label = global::Mono.Unix.Catalog.GetString ("Save"); + global::Gtk.Image w19 = new global::Gtk.Image (); + w19.Pixbuf = global::Stetic.IconLoader.LoadIcon (this, "gtk-save", global::Gtk.IconSize.Menu); + this.btnSaveFilters.Image = w19; + this.hbox2.Add (this.btnSaveFilters); + global::Gtk.Box.BoxChild w20 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.btnSaveFilters])); + w20.Position = 1; + w20.Expand = false; + w20.Fill = false; + // Container child hbox2.Gtk.Box+BoxChild + this.cbAutoCheckCaps = new global::Gtk.CheckButton (); + this.cbAutoCheckCaps.CanFocus = true; + this.cbAutoCheckCaps.Name = "cbAutoCheckCaps"; + this.cbAutoCheckCaps.Label = global::Mono.Unix.Catalog.GetString ("Auto Check New Capabilities"); + this.cbAutoCheckCaps.Active = true; + this.cbAutoCheckCaps.DrawIndicator = true; + this.cbAutoCheckCaps.UseUnderline = true; + this.hbox2.Add (this.cbAutoCheckCaps); + global::Gtk.Box.BoxChild w21 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.cbAutoCheckCaps])); + w21.Position = 2; + this.filterBox.Add (this.hbox2); + global::Gtk.Box.BoxChild w22 = ((global::Gtk.Box.BoxChild)(this.filterBox [this.hbox2])); + w22.Position = 0; + w22.Expand = false; + w22.Fill = false; + // Container child filterBox.Gtk.Box+BoxChild + this.hbox3 = new global::Gtk.HBox (); + this.hbox3.Name = "hbox3"; + this.hbox3.Homogeneous = true; + this.hbox3.Spacing = 6; + // Container child hbox3.Gtk.Box+BoxChild + this.frameFilterUDP = new global::Gtk.Frame (); + this.frameFilterUDP.Name = "frameFilterUDP"; + this.frameFilterUDP.ShadowType = ((global::Gtk.ShadowType)(0)); + this.frameFilterUDP.LabelYalign = 0F; + // Container child frameFilterUDP.Gtk.Container+ContainerChild + this.containerFilterUDP = new global::Gtk.Alignment (0F, 0F, 1F, 1F); + this.containerFilterUDP.Name = "containerFilterUDP"; + this.containerFilterUDP.LeftPadding = ((uint)(12)); + this.frameFilterUDP.Add (this.containerFilterUDP); + this.GtkLabel7 = new global::Gtk.Label (); + this.GtkLabel7.Name = "GtkLabel7"; + this.GtkLabel7.LabelProp = global::Mono.Unix.Catalog.GetString ("UDP Packets & Login"); + this.frameFilterUDP.LabelWidget = this.GtkLabel7; + this.hbox3.Add (this.frameFilterUDP); + global::Gtk.Box.BoxChild w24 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.frameFilterUDP])); + w24.Position = 0; + // Container child hbox3.Gtk.Box+BoxChild + this.frameFilterCap = new global::Gtk.Frame (); + this.frameFilterCap.Name = "frameFilterCap"; + this.frameFilterCap.ShadowType = ((global::Gtk.ShadowType)(0)); + this.frameFilterCap.LabelYalign = 0F; + // Container child frameFilterCap.Gtk.Container+ContainerChild + this.containerFilterCap = new global::Gtk.Alignment (0F, 0F, 1F, 1F); + this.containerFilterCap.Name = "containerFilterCap"; + this.containerFilterCap.LeftPadding = ((uint)(12)); + this.frameFilterCap.Add (this.containerFilterCap); + this.GtkLabel8 = new global::Gtk.Label (); + this.GtkLabel8.Name = "GtkLabel8"; + this.GtkLabel8.LabelProp = global::Mono.Unix.Catalog.GetString ("Capabilities & EventQueue Messages"); + this.frameFilterCap.LabelWidget = this.GtkLabel8; + this.hbox3.Add (this.frameFilterCap); + global::Gtk.Box.BoxChild w26 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.frameFilterCap])); + w26.Position = 1; + this.filterBox.Add (this.hbox3); + global::Gtk.Box.BoxChild w27 = ((global::Gtk.Box.BoxChild)(this.filterBox [this.hbox3])); + w27.Position = 1; + // Container child filterBox.Gtk.Box+BoxChild + this.hbox4 = new global::Gtk.HBox (); + this.hbox4.Name = "hbox4"; + this.hbox4.Homogeneous = true; + this.hbox4.Spacing = 6; + // Container child hbox4.Gtk.Box+BoxChild + this.cbSelectAllUDP = new global::Gtk.CheckButton (); + this.cbSelectAllUDP.CanFocus = true; + this.cbSelectAllUDP.Name = "cbSelectAllUDP"; + this.cbSelectAllUDP.Label = global::Mono.Unix.Catalog.GetString ("Select/Uncheck All"); + this.cbSelectAllUDP.DrawIndicator = true; + this.cbSelectAllUDP.UseUnderline = true; + this.hbox4.Add (this.cbSelectAllUDP); + global::Gtk.Box.BoxChild w28 = ((global::Gtk.Box.BoxChild)(this.hbox4 [this.cbSelectAllUDP])); + w28.Position = 0; + // Container child hbox4.Gtk.Box+BoxChild + this.cbSelectAllCap = new global::Gtk.CheckButton (); + this.cbSelectAllCap.CanFocus = true; + this.cbSelectAllCap.Name = "cbSelectAllCap"; + this.cbSelectAllCap.Label = global::Mono.Unix.Catalog.GetString ("Select/Uncheck All"); + this.cbSelectAllCap.DrawIndicator = true; + this.cbSelectAllCap.UseUnderline = true; + this.hbox4.Add (this.cbSelectAllCap); + global::Gtk.Box.BoxChild w29 = ((global::Gtk.Box.BoxChild)(this.hbox4 [this.cbSelectAllCap])); + w29.Position = 1; + this.filterBox.Add (this.hbox4); + global::Gtk.Box.BoxChild w30 = ((global::Gtk.Box.BoxChild)(this.filterBox [this.hbox4])); + w30.PackType = ((global::Gtk.PackType)(1)); + w30.Position = 2; + w30.Expand = false; + w30.Fill = false; + this.tabsMain.Add (this.filterBox); + global::Gtk.Notebook.NotebookChild w31 = ((global::Gtk.Notebook.NotebookChild)(this.tabsMain [this.filterBox])); + w31.Position = 1; + // Notebook tab + this.label5 = new global::Gtk.Label (); + this.label5.Name = "label5"; + this.label5.LabelProp = global::Mono.Unix.Catalog.GetString ("Filters"); + this.tabsMain.SetTabLabel (this.filterBox, this.label5); + this.label5.ShowAll (); + // Notebook tab + global::Gtk.Label w32 = new global::Gtk.Label (); + w32.Visible = true; + this.tabsMain.Add (w32); + this.label6 = new global::Gtk.Label (); + this.label6.Name = "label6"; + this.label6.LabelProp = global::Mono.Unix.Catalog.GetString ("Inspector"); + this.tabsMain.SetTabLabel (w32, this.label6); + this.label6.ShowAll (); + this.mainSplit.Add (this.tabsMain); + this.vbox1.Add (this.mainSplit); + global::Gtk.Box.BoxChild w34 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.mainSplit])); + w34.Position = 1; + this.Add (this.vbox1); + if ((this.Child != null)) { + this.Child.ShowAll (); + } + this.DefaultWidth = 1211; + this.DefaultHeight = 552; + this.Show (); + this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent); + this.ExitAction.Activated += new global::System.EventHandler (this.OnExitActionActivated); + this.btnStart.Clicked += new global::System.EventHandler (this.OnBtnStartClicked); + } +} diff --git a/Programs/GridProxyGUI/gtk-gui/generated.cs b/Programs/GridProxyGUI/gtk-gui/generated.cs new file mode 100755 index 00000000..c8654260 --- /dev/null +++ b/Programs/GridProxyGUI/gtk-gui/generated.cs @@ -0,0 +1,67 @@ + +// This file has been generated by the GUI designer. Do not modify. +namespace Stetic +{ + internal class Gui + { + private static bool initialized; + + internal static void Initialize (Gtk.Widget iconRenderer) + { + if ((Stetic.Gui.initialized == false)) { + Stetic.Gui.initialized = true; + } + } + } + + internal class IconLoader + { + public static Gdk.Pixbuf LoadIcon (Gtk.Widget widget, string name, Gtk.IconSize size) + { + Gdk.Pixbuf res = widget.RenderIcon (name, size, null); + if ((res != null)) { + return res; + } else { + int sz; + int sy; + global::Gtk.Icon.SizeLookup (size, out sz, out sy); + try { + return Gtk.IconTheme.Default.LoadIcon (name, sz, 0); + } catch (System.Exception) { + if ((name != "gtk-missing-image")) { + return Stetic.IconLoader.LoadIcon (widget, "gtk-missing-image", size); + } else { + Gdk.Pixmap pmap = new Gdk.Pixmap (Gdk.Screen.Default.RootWindow, sz, sz); + Gdk.GC gc = new Gdk.GC (pmap); + gc.RgbFgColor = new Gdk.Color (255, 255, 255); + pmap.DrawRectangle (gc, true, 0, 0, sz, sz); + gc.RgbFgColor = new Gdk.Color (0, 0, 0); + pmap.DrawRectangle (gc, false, 0, 0, (sz - 1), (sz - 1)); + gc.SetLineAttributes (3, Gdk.LineStyle.Solid, Gdk.CapStyle.Round, Gdk.JoinStyle.Round); + gc.RgbFgColor = new Gdk.Color (255, 0, 0); + pmap.DrawLine (gc, (sz / 4), (sz / 4), ((sz - 1) + - (sz / 4)), ((sz - 1) + - (sz / 4))); + pmap.DrawLine (gc, ((sz - 1) + - (sz / 4)), (sz / 4), (sz / 4), ((sz - 1) + - (sz / 4))); + return Gdk.Pixbuf.FromDrawable (pmap, pmap.Colormap, 0, 0, 0, 0, sz, sz); + } + } + } + } + } + + internal class ActionGroups + { + public static Gtk.ActionGroup GetActionGroup (System.Type type) + { + return Stetic.ActionGroups.GetActionGroup (type.FullName); + } + + public static Gtk.ActionGroup GetActionGroup (string name) + { + return null; + } + } +} diff --git a/Programs/GridProxyGUI/gtk-gui/gui.stetic b/Programs/GridProxyGUI/gtk-gui/gui.stetic new file mode 100755 index 00000000..d12fba06 --- /dev/null +++ b/Programs/GridProxyGUI/gtk-gui/gui.stetic @@ -0,0 +1,532 @@ + + + + .. + + + + + + + + + Action + <Alt>f + File + File + + + Action + <Primary>q + Exit + Exit + + + + Action + Edit + Edit + + + Action + Help + Help + + + Action + About + About + + + Action + Remove + Remove + + + Action + Select + Select + + + Action + All + All + + + Action + All + All + + + Action + Selected + Selected + + + Action + <Primary>f + Find + Find (Ctrl-F) + + + Action + <Primary>o + Open Session... + Open Session... + + + Action + <Primary>s + Save Session + Save Session + + + Action + Save Session As... + Save Session As... + + + + Grid Proxy + CenterOnParent + True + + + + + 6 + + + + 6 + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + True + False + False + + + + + + + + 1 + True + False + False + + + + + + Listen IP Address: + + + 2 + True + False + False + + + + + + 100 + True + 127.0.0.1 +0.0.0.0 + 0 + + + 3 + True + False + False + + + + + + Port + + + 4 + True + False + False + + + + + + 50 + True + 8080 + True + 5 + + + + 5 + False + False + + + + + + Login URL + + + 6 + True + False + False + + + + + + 300 + True + https://login.agni.lindenlab.com/cgi-bin/login.cgi +https://login.aditi.lindenlab.com/cgi-bin/login.cgi +http://login.orgrid.org/ + 0 + + + 7 + True + False + False + + + + + btnStart + True + TextOnly + Start Proxy + True + + + + 8 + True + False + False + + + + + 0 + True + False + False + + + + + + True + 400 + + + + True + In + + + + None + + + + + + + + False + + + + + + True + 1 + True + + + + In + + + + True + True + False + + Word + + + + + + + + Summary + + + tab + + + + + + 6 + + + + 6 + + + + True + TextAndIcon + stock:gtk-open Menu + Load + True + + + 0 + True + False + False + + + + + + True + TextAndIcon + stock:gtk-save Menu + Save + True + + + 1 + True + False + False + + + + + + True + Auto Check New Capabilities + True + True + True + True + + + 2 + True + + + + + 0 + True + False + False + + + + + + True + 6 + + + + None + 0 + + + + 0 + 0 + 12 + + + + + + + + + UDP Packets & Login + + + label_item + + + + + 0 + False + + + + + + None + 0 + + + + 0 + 0 + 12 + + + + + + + + + Capabilities & EventQueue Messages + + + label_item + + + + + 1 + False + + + + + 1 + True + + + + + + True + 6 + + + + True + Select/Uncheck All + True + True + True + + + 0 + True + + + + + + True + Select/Uncheck All + True + True + True + + + 1 + True + + + + + End + 2 + True + False + False + + + + + 1 + + + + + + Filters + + + tab + + + + + + + + + Inspector + + + tab + + + + + + + 1 + True + + + + + + \ No newline at end of file diff --git a/Programs/GridProxyGUI/libomv.ico b/Programs/GridProxyGUI/libomv.ico new file mode 100644 index 0000000000000000000000000000000000000000..ad64d2c56d26dabf9188b943ef31263a33745079 GIT binary patch literal 82726 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 literal 0 HcmV?d00001 diff --git a/prebuild.xml b/prebuild.xml index 95bf7f72..503da113 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -34,7 +34,7 @@ - + ../bin/ @@ -56,7 +56,7 @@ - + ../bin/ @@ -77,7 +77,7 @@ - + ../bin/ @@ -99,7 +99,7 @@ - + ../bin/ @@ -129,7 +129,7 @@ - + ../bin/ @@ -154,7 +154,7 @@ - + ../bin/ @@ -179,7 +179,7 @@ - + ../../bin/ @@ -207,7 +207,7 @@ - + ../bin/ @@ -229,7 +229,7 @@ - + ../bin/ @@ -252,7 +252,7 @@ - + ../bin/ @@ -279,7 +279,7 @@ - + ../../bin/ @@ -310,7 +310,7 @@ - + ../../bin/ @@ -338,7 +338,7 @@ - + ../../bin/ @@ -361,7 +361,7 @@ - + ../../bin/ @@ -382,7 +382,7 @@ - + ../../../bin/ @@ -403,7 +403,7 @@ - + ../../../bin/ @@ -433,7 +433,7 @@ - + ../../bin/ @@ -494,7 +494,7 @@ - + ../../bin/ @@ -522,7 +522,7 @@ - + ../../bin/ @@ -546,7 +546,7 @@ - + ../../bin/ @@ -580,7 +580,7 @@ - + ../../bin/ @@ -603,7 +603,7 @@ - + ../../bin/ @@ -628,7 +628,7 @@ - + ../../../bin/ @@ -656,7 +656,7 @@ - + ../../../bin/ @@ -684,7 +684,7 @@ - + ../../../bin/ @@ -712,7 +712,7 @@ - + ../../../bin/ @@ -734,7 +734,7 @@ - + ../../../bin/