corrade-vassal – Rev 1

Subversion Repositories:
Rev:
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(@"\[(?<Type>\w+|\w+\[\])\]|\((?<Enum>.*)\)|\s-- (?<Header>\w+|\w+ \[\]) --\s|(?<BlockSep>\s\*\*\*\s)|(?<Tag>\s<\w+>\s|\s<\/\w+>\s)|(?<BlockCounter>\s\w+\[\d+\]\s)|(?<UUID>[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<FileFilter> GetFileFilters()
    {
        List<FileFilter> filters = new List<FileFilter>();

        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);
    }

}