using GridProxyGUI; using System; using System.Collections.Generic; using System.Collections.Concurrent; using Gtk; using OpenMetaverse.Packets; using Logger = OpenMetaverse.Logger; using System.Timers; using System.Text.RegularExpressions; public partial class MainWindow : Gtk.Window { ProxyManager proxy = null; MessageScroller messages; PluginsScroller plugins; // stats tracking int PacketCounter; int CapsInCounter; int CapsInBytes; int CapsOutCounter; int CapsOutBytes; int PacketsInCounter; int PacketsInBytes; int PacketsOutCounter; int PacketsOutBytes; Timer StatsTimer; public MainWindow() : base(Gtk.WindowType.Toplevel) { Build(); LoadSavedSettings(); ProxyLogger.Init(); ProxyLogger.OnLogLine += new ProxyLogger.Log(Logger_OnLogLine); tabsMain.Page = 0; string font; if (PlatformDetection.IsMac) { txtSummary.ModifyFont(Pango.FontDescription.FromString("monospace bold")); font = "monospace"; IgeMacIntegration.IgeMacMenu.GlobalKeyHandlerEnabled = true; IgeMacIntegration.IgeMacMenu.MenuBar = menuMain; MenuItem quit = new MenuItem("Quit"); quit.Activated += (object sender, EventArgs e) => OnExitActionActivated(sender, e); IgeMacIntegration.IgeMacMenu.QuitMenuItem = quit; menuMain.Hide(); menuSeparator.Hide(); } else { txtSummary.ModifyFont(Pango.FontDescription.FromString("monospace bold 9")); font = "monospace 9"; } btnLoadPlugin.Sensitive = false; txtPort.TextInserted += (object o, TextInsertedArgs args) => { if (args.Length != 1) return; if (!char.IsDigit(args.Text[0])) { txtPort.DeleteText(args.Position - 1, args.Position); } }; InitProxyFilters(); txtRequest.ModifyFont(Pango.FontDescription.FromString(font)); CreateTags(txtRequest.Buffer); txtRequestRaw.ModifyFont(Pango.FontDescription.FromString(font)); txtRequestNotation.ModifyFont(Pango.FontDescription.FromString(font)); txtResponse.ModifyFont(Pango.FontDescription.FromString(font)); CreateTags(txtResponse.Buffer); txtResponseRaw.ModifyFont(Pango.FontDescription.FromString(font)); txtResponseNotation.ModifyFont(Pango.FontDescription.FromString(font)); sessionLogScroller.Add(messages = new MessageScroller(this)); scrolledwindowPlugin.Add(plugins = new PluginsScroller()); messages.CursorChanged += messages_CursorChanged; StatsTimer = new Timer(1000.0); StatsTimer.Elapsed += StatsTimer_Elapsed; StatsTimer.Enabled = true; ProxyManager.OnLoginResponse += ProxyManager_OnLoginResponse; ProxyManager.OnPacketLog += ProxyManager_OnPacketLog; ProxyManager.OnCapabilityAdded += new ProxyManager.CapsAddedHandler(ProxyManager_OnCapabilityAdded); ProxyManager.OnEventMessageLog += new ProxyManager.EventQueueMessageHandler(ProxyManager_OnEventMessageLog); ProxyManager.OnMessageLog += new ProxyManager.MessageLogHandler(ProxyManager_OnMessageLog); } void StatsTimer_Elapsed(object sender, ElapsedEventArgs e) { Application.Invoke((xsender, xe) => { lblUDPIn.Text = string.Format("Packets In {0} ({1} bytes)", PacketsInCounter, PacketsInBytes); lblUDPOut.Text = string.Format("Packets Out {0} ({1} bytes)", PacketsOutCounter, PacketsOutBytes); lblUDPTotal.Text = string.Format("Packets Total {0} ({1} bytes)", PacketsInCounter + PacketsOutCounter, PacketsInBytes + PacketsOutBytes); lblCapIn.Text = string.Format("Caps In {0} ({1} bytes)", CapsInCounter, CapsInBytes); lblCapOut.Text = string.Format("Caps Out {0} ({1} bytes)", CapsOutCounter, CapsOutBytes); lblCapTotal.Text = string.Format("Caps Total {0} ({1} bytes)", CapsInCounter + CapsOutCounter, CapsInBytes + CapsOutBytes); }); } void ProxyManager_OnLoginResponse(object request, GridProxy.Direction direction) { Application.Invoke((xsender, xe) => { string loginType; if (request is Nwc.XmlRpc.XmlRpcRequest) { loginType = "Login Request"; } else { loginType = "Login Response"; } if (UDPFilterItems.ContainsKey(loginType) && UDPFilterItems[loginType].Enabled) { PacketCounter++; SessionLogin sessionLogin = new SessionLogin(request, direction, cbLoginURL.ActiveText, request.GetType().Name + " " + loginType); sessionLogin.Columns = new string[] { PacketCounter.ToString(), sessionLogin.TimeStamp.ToString("HH:mm:ss.fff"), sessionLogin.Protocol, sessionLogin.Name, sessionLogin.Length.ToString(), sessionLogin.Host, sessionLogin.ContentType }; messages.AddSession(sessionLogin); } }); } void ProxyManager_OnPacketLog(Packet packet, GridProxy.Direction direction, System.Net.IPEndPoint endpoint) { Application.Invoke((xsender, xe) => { PacketCounter++; if (direction == GridProxy.Direction.Incoming) { PacketsInCounter++; PacketsInBytes += packet.Length; } else { PacketsOutCounter++; PacketsOutBytes += packet.Length; } SessionPacket sessionPacket = new SessionPacket(packet, direction, endpoint, PacketDecoder.InterpretOptions(packet.Header) + " Seq: " + packet.Header.Sequence.ToString() + " Freq:" + packet.Header.Frequency.ToString()); sessionPacket.Columns = new string[] { PacketCounter.ToString(), sessionPacket.TimeStamp.ToString("HH:mm:ss.fff"), sessionPacket.Protocol, sessionPacket.Name, sessionPacket.Length.ToString(), sessionPacket.Host, sessionPacket.ContentType }; messages.AddSession(sessionPacket); }); } void ProxyManager_OnCapabilityAdded(GridProxy.CapInfo cap) { Application.Invoke((sender, e) => { if (!CapFilterItems.ContainsKey(cap.CapType)) { FilterItem item = new FilterItem() { Name = cap.CapType, Type = ItemType.Cap }; item.FilterItemChanged += item_FilterItemChanged; item.Enabled = true; CapFilterItems[item.Name] = item; capStore.AppendValues(item); } }); } void ProxyManager_OnEventMessageLog(GridProxy.CapsRequest req, GridProxy.CapsStage stage) { Application.Invoke((sender, e) => { if (!CapFilterItems.ContainsKey(req.Info.CapType)) { FilterItem item = new FilterItem() { Enabled = true, Name = req.Info.CapType, Type = ItemType.EQ }; item.FilterItemChanged += item_FilterItemChanged; CapFilterItems[item.Name] = item; capStore.AppendValues(item); } ProxyManager_OnMessageLog(req, GridProxy.CapsStage.Response); }); } void ProxyManager_OnMessageLog(GridProxy.CapsRequest req, GridProxy.CapsStage stage) { Application.Invoke((sender, e) => { if (CapFilterItems.ContainsKey(req.Info.CapType)) { var filter = CapFilterItems[req.Info.CapType]; if (!filter.Enabled) return; PacketCounter++; int size = 0; if (req.RawRequest != null) { size += req.RawRequest.Length; } if (req.RawResponse != null) { size += req.RawResponse.Length; } GridProxy.Direction direction; if (stage == GridProxy.CapsStage.Request) { CapsOutCounter++; CapsOutBytes += req.Request.ToString().Length; direction = GridProxy.Direction.Outgoing; } else { CapsInCounter++; CapsInBytes += req.Response.ToString().Length; direction = GridProxy.Direction.Incoming; } string proto = filter.Type.ToString(); Session capsSession = null; if (filter.Type == ItemType.Cap) { capsSession = new SessionCaps(req.RawRequest, req.RawResponse, req.RequestHeaders, req.ResponseHeaders, direction, req.Info.URI, req.Info.CapType, proto, req.FullUri); } else { capsSession = new SessionEvent(req.RawResponse, req.ResponseHeaders, req.Info.URI, req.Info.CapType, proto); } capsSession.Columns = new string[] { PacketCounter.ToString(), capsSession.TimeStamp.ToString("HH:mm:ss.fff"), capsSession.Protocol, capsSession.Name, capsSession.Length.ToString(), capsSession.Host, capsSession.ContentType }; messages.AddSession(capsSession); } }); } 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); try { proxy = new ProxyManager(txtPort.Text, cbListen.ActiveText, cbLoginURL.ActiveText); proxy.Start(); btnLoadPlugin.Sensitive = true; ApplyProxyFilters(); } catch (Exception ex) { Logger.Log("Failed to start proxy: " + ex.Message, OpenMetaverse.Helpers.LogLevel.Error); try { proxy.Stop(); } catch { } btnStart.Label = "Start Proxy"; proxy = null; } } protected void StopProxy() { AppendLog("Proxy stopped" + Environment.NewLine); if (proxy != null) proxy.Stop(); proxy = null; plugins.Store.Clear(); btnLoadPlugin.Sensitive = false; } protected void OnDeleteEvent(object sender, DeleteEventArgs a) { StopProxy(); SaveSettings(); a.RetVal = true; } protected void OnExitActionActivated(object sender, EventArgs e) { StopProxy(); SaveSettings(); } protected void OnBtnStartClicked(object sender, EventArgs e) { if (btnStart.Label.StartsWith("Start")) { btnStart.Label = "Stop Proxy"; StartPoxy(); } else if (btnStart.Label.StartsWith("Stop")) { btnStart.Label = "Start Proxy"; StopProxy(); } } void SetAllToggles(bool on, ListStore store) { if (null == store) return; store.Foreach((model, path, iter) => { var item = model.GetValue(iter, 0) as FilterItem; if (null != item) { item.Enabled = on; model.SetValue(iter, 0, item); } return false; }); } protected void OnCbSelectAllUDPToggled(object sender, EventArgs e) { SetAllToggles(cbSelectAllUDP.Active, udpStore); } protected void OnCbSelectAllCapToggled(object sender, EventArgs e) { SetAllToggles(cbSelectAllCap.Active, capStore); } protected void OnCbAutoScrollToggled(object sender, EventArgs e) { messages.AutoScroll = cbAutoScroll.Active; } void messages_CursorChanged(object sender, EventArgs e) { var tv = (TreeView)sender; var paths = tv.Selection.GetSelectedRows(); TreeIter iter; if (paths.Length == 1 && tv.Model.GetIter(out iter, paths[0])) { var item = tv.Model.GetValue(iter, 0) as Session; if (item != null) { ColorizePacket(txtRequest.Buffer, item.ToPrettyString(GridProxy.Direction.Outgoing)); txtRequestRaw.Buffer.Text = item.ToRawString(GridProxy.Direction.Outgoing); txtRequestNotation.Buffer.Text = item.ToStringNotation(GridProxy.Direction.Outgoing); ColorizePacket(txtResponse.Buffer, item.ToPrettyString(GridProxy.Direction.Incoming)); txtResponseRaw.Buffer.Text = item.ToRawString(GridProxy.Direction.Incoming); txtResponseNotation.Buffer.Text = item.ToStringNotation(GridProxy.Direction.Incoming); SetVisibility(); } } } void SetVisibility() { tabsMain.Page = 2; var w1 = vboxInspector.Children.GetValue(0) as Widget; var w2 = vboxInspector.Children.GetValue(1) as Widget; if (w1 == null || w2 == null) return; // check if request is empry if (txtRequest.Buffer.Text.Trim().Length < 3 && txtRequestRaw.Buffer.Text.Trim().Length < 3) { w1.Hide(); } else { w1.Show(); } // check if request is empry if (txtResponse.Buffer.Text.Trim().Length < 3 && txtResponseRaw.Buffer.Text.Trim().Length < 3) { w2.Hide(); } else { w2.Show(); } } void CreateTags(TextBuffer buffer) { TextTag tag = buffer.TagTable.Lookup("bold"); if (tag == null) { tag = new TextTag("bold"); tag.Weight = Pango.Weight.Bold; buffer.TagTable.Add(tag); } tag = buffer.TagTable.Lookup("type"); if (tag == null) { tag = new TextTag("type"); tag.ForegroundGdk = new Gdk.Color(43, 145, 175); buffer.TagTable.Add(tag); } tag = buffer.TagTable.Lookup("header"); if (tag == null) { tag = new TextTag("header"); tag.ForegroundGdk = new Gdk.Color(0, 96, 0); tag.BackgroundGdk = new Gdk.Color(206, 226, 252); buffer.TagTable.Add(tag); } tag = buffer.TagTable.Lookup("block"); if (tag == null) { tag = new TextTag("block"); tag.ForegroundGdk = new Gdk.Color(255, 215, 0); buffer.TagTable.Add(tag); } tag = buffer.TagTable.Lookup("tag"); if (tag == null) { tag = new TextTag("tag"); tag.ForegroundGdk = new Gdk.Color(255, 255, 255); tag.BackgroundGdk = new Gdk.Color(40, 40, 40); buffer.TagTable.Add(tag); } tag = buffer.TagTable.Lookup("counter"); if (tag == null) { tag = new TextTag("counter"); tag.ForegroundGdk = new Gdk.Color(0, 64, 0); buffer.TagTable.Add(tag); } tag = buffer.TagTable.Lookup("UUID"); if (tag == null) { tag = new TextTag("UUID"); tag.ForegroundGdk = new Gdk.Color(148, 0, 211); buffer.TagTable.Add(tag); } } void ColorizePacket(TextBuffer buffer, string text) { if (!text.StartsWith("Message Type:") && !text.StartsWith("Packet Type:")) { buffer.Text = text; return; } buffer.Text = string.Empty; text = text.Replace("\r", ""); TextIter iter = buffer.StartIter; Regex typesRegex = new Regex(@"\[(?\w+|\w+\[\])\]|\((?.*)\)|\s-- (?
\w+|\w+ \[\]) --\s|(?\s\*\*\*\s)|(?\s<\w+>\s|\s<\/\w+>\s)|(?\s\w+\[\d+\]\s)|(?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})", RegexOptions.ExplicitCapture); MatchCollection matches = typesRegex.Matches(text); int pos = 0; if (matches.Count == 0) { buffer.Text = text; } foreach (Match match in matches) { string tag = "bold"; buffer.Insert(ref iter, text.Substring(pos, match.Index - pos)); pos += match.Index - pos; if (!String.IsNullOrEmpty(match.Groups["Type"].Value)) { tag = "type"; } else if (!String.IsNullOrEmpty(match.Groups["Enum"].Value)) { tag = "type"; } else if (!String.IsNullOrEmpty(match.Groups["Header"].Value)) { tag = "header"; } else if (!String.IsNullOrEmpty(match.Groups["BlockSep"].Value)) { tag = "block"; } else if (!String.IsNullOrEmpty(match.Groups["Tag"].Value)) { tag = "tag"; } else if (!String.IsNullOrEmpty(match.Groups["BlockCounter"].Value)) { tag = "counter"; } else if (!String.IsNullOrEmpty(match.Groups["UUID"].Value)) { tag = "UUID"; } buffer.InsertWithTagsByName(ref iter, text.Substring(pos, match.Length), tag); pos += match.Length; } } List GetFileFilters() { List filters = new List(); FileFilter filter = new FileFilter(); filter.Name = "Grid Proxy Compressed (*.gpz)"; filter.AddPattern("*.gpz"); filters.Add(filter); filter = new FileFilter(); filter.Name = "All Files (*.*)"; filter.AddPattern("*.*"); filters.Add(filter); return filters; } public void RedrawFilters() { containerFilterCap.QueueDraw(); containerFilterUDP.QueueDraw(); } protected void OnOpenActionActivated(object sender, EventArgs e) { var od = new Gtk.FileChooserDialog(null, "Open Session", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept); foreach (var filter in GetFileFilters()) od.AddFilter(filter); if (od.Run() == (int)ResponseType.Accept) { OpenSession(od.Filename); } od.Destroy(); } protected void OnSaveAsActionActivated(object sender, EventArgs e) { var od = new Gtk.FileChooserDialog(null, "Save Session", this, FileChooserAction.Save, "Cancel", ResponseType.Cancel, "Save", ResponseType.Accept); foreach (var filter in GetFileFilters()) od.AddFilter(filter); if (od.Run() == (int)ResponseType.Accept) { SessionFileName = od.Filename; if (string.IsNullOrEmpty(System.IO.Path.GetExtension(SessionFileName))) { SessionFileName += ".gpz"; } SaveSession(); } od.Destroy(); } protected void OnSaveActionActivated(object sender, EventArgs e) { if (string.IsNullOrEmpty(SessionFileName)) { OnSaveAsActionActivated(sender, e); } else { SaveSession(); } } protected void OnAboutActionActivated(object sender, EventArgs e) { var about = new GridProxyGUI.About(); about.SkipTaskbarHint = about.SkipPagerHint = true; about.Run(); about.Destroy(); } protected void OnBtnLoadPluginClicked(object sender, EventArgs e) { if (proxy == null) return; plugins.LoadPlugin(proxy.Proxy); } }