// // Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net). Distributed under GPL version 2. // // using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using SharpPcap; using EQApplicationLayer; namespace EQExtractor2 { public partial class EQExtractor2Form1 : Form { string Version = "EQExtractor2 Version 2.6.0 SVN"; static int PacketsSeen = 0; static long BytesRead = 0; static long CaptureFileSize = 0; string ZoneName; string SpawnNameFilter = ""; bool CoalesceWaypoints = true; GenerateSQLForm SQLForm = new GenerateSQLForm(); LogForm DebugLog = new LogForm(); UserOptions Options = new UserOptions(); StreamWriter SQLStream; StreamWriter PacketDebugStream; EQStreamProcessor StreamProcessor; public EQExtractor2Form1() { InitializeComponent(); DisplayUsageInfo(); Options.PacketDumpViewerProgram.Text = Properties.Settings.Default.TextFileViewer; Options.ShowDebugWindowOnStartup.Checked = Properties.Settings.Default.ShowDebugWindowOnStartup; Options.ShowTimeStamps.Checked = Properties.Settings.Default.DumpTimeStamps; } public void Log(string Message) { DebugLog.ConsoleWindow.Items.Add(Message); DebugLog.ConsoleWindow.SelectedIndex = DebugLog.ConsoleWindow.Items.Count - 1; Application.DoEvents(); } private void device_OnPacketArrival(object sender, SharpPcap.CaptureEventArgs e) { if (e.Packet.LinkLayerType == PacketDotNet.LinkLayers.Ethernet) { PacketDotNet.Packet packet; long TotalPacketSize = e.Packet.Data.Length; BytesRead += TotalPacketSize; ++PacketsSeen; if ((PacketsSeen > 0) && ((PacketsSeen % 10000) == 0)) { DebugLog.ConsoleWindow.SelectedIndex = DebugLog.ConsoleWindow.Items.Count - 1; int Progress = (int)((float)BytesRead / (float)CaptureFileSize * 100); ProgressBar.Value = Progress; Application.DoEvents(); } try { packet = PacketDotNet.Packet.ParsePacket(e.Packet); } catch { return; } var ethernetPacket = (PacketDotNet.EthernetPacket)packet; var udpPacket = PacketDotNet.UdpPacket.GetEncapsulated(packet); if (udpPacket != null) { var ipPacket = (PacketDotNet.IpPacket)udpPacket.ParentPacket; System.Net.IPAddress srcIp = ipPacket.SourceAddress; System.Net.IPAddress dstIp = ipPacket.DestinationAddress; byte[] Payload = udpPacket.PayloadData; Int32 l = udpPacket.Length - udpPacket.Header.GetLength(0); if (l > 0) { Array.Resize(ref Payload, l); StreamProcessor.ProcessPacket(srcIp, dstIp, udpPacket.SourcePort, udpPacket.DestinationPort, Payload, packet.Timeval.Date); } } } } public void WriteSQL(string Message) { SQLStream.WriteLine(Message); } public void PacketDebugLogger(string Message) { PacketDebugStream.WriteLine(Message); } private void DisableAllControls() { foreach (Control c in this.Controls) { if ((c is Button) || (c is TextBox) || (c is MaskedTextBox) || (c is CheckBox)) c.Enabled = false; } } private void EnableAllControls() { foreach (Control c in this.Controls) c.Enabled = true; menuGenerateSQL.Enabled = StreamProcessor.StreamRecognised() && StreamProcessor.SupportsSQLGeneration(); menuDumpAAs.Enabled = StreamProcessor.StreamRecognised(); } private void menuLoadPCAP_Click(object sender, EventArgs e) { if (InputFileOpenDialog.ShowDialog() != DialogResult.OK) return; menuGenerateSQL.Enabled = false; menuPacketDump.Enabled = false; menuViewPackets.Enabled = false; menuDumpAAs.Enabled = false; SharpPcap.OfflinePcapDevice device; try { string CapFile = InputFileOpenDialog.FileName; device = new SharpPcap.OfflinePcapDevice(CapFile); device.Open(); } catch { StatusBar.Text = "Error: File does not exist or not in .pcap format."; Log("Error: File does not exist or not in .pcap format."); return; } StreamProcessor = new EQStreamProcessor(); if (!StreamProcessor.Init(Application.StartupPath, this.Log)) { Log("Fatal error initialising Stream Processor. No decoders could be initialised (mostly likely misplaced patch_XXXX.conf files."); StatusBar.Text = "Fatal error initialising Stream Processor. No decoders could be initialised (mostly likely misplaced patch_XXXX.conf files."; return; } if (Options.EQPacketDebugFilename.Text.Length > 0) { try { PacketDebugStream = new StreamWriter(Options.EQPacketDebugFilename.Text); StreamProcessor.Packets.SetDebugLogHandler(PacketDebugLogger); } catch { Log("Failed to open netcode debug file for writing."); Options.EQPacketDebugFilename.Text = ""; StreamProcessor.Packets.SetDebugLogHandler(null); } } else StreamProcessor.Packets.SetDebugLogHandler(null); StatusBar.Text = "Reading packets from " + InputFileOpenDialog.FileName + ". Please wait..."; device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival); BytesRead = 0; PacketsSeen = 0; DebugLog.ConsoleWindow.Items.Add("-- Capturing from '" + InputFileOpenDialog.FileName); ProgressBar.Value = 0; ProgressBar.Show(); menuFile.Enabled = false; CaptureFileSize = device.FileSize; device.Capture(); device.Close(); Log("End of file reached. Processed " + PacketsSeen + " packets and " + BytesRead + " bytes."); ProgressBar.Hide(); if (Options.EQPacketDebugFilename.Text.Length > 0) PacketDebugStream.Close(); PacketCountLabel.Text = PacketsSeen.ToString(); if (StreamProcessor.Packets.ErrorsInStream) Log("There were errors encountered in the packet stream. Data may be incomplete."); DebugLog.ConsoleWindow.SelectedIndex = DebugLog.ConsoleWindow.Items.Count - 1; menuFile.Enabled = true; StreamProcessor.PCAPFileReadFinished(); menuPacketDump.Enabled = true; menuViewPackets.Enabled = true; Log("Stream recognised as " + StreamProcessor.GetDecoderVersion()); int PPLength = StreamProcessor.VerifyPlayerProfile(); ClientVersionLabel.Text = StreamProcessor.GetDecoderVersion(); if (PPLength == 0) { Log("Unable to find player profile packet, or packet not of correct size."); menuDumpAAs.Enabled = false; menuGenerateSQL.Enabled = false; ClientVersionLabel.ForeColor = Color.Red; ZoneLabel.Text = ""; PacketCountLabel.Text = ""; StatusBar.Text = "Unrecognised EQ Client Version. Press Ctrl-P to dump, or Ctrl-V to view packets."; return; } else { ClientVersionLabel.ForeColor = Color.Green; Log("Found player profile packet of the expected length (" + PPLength + ")."); if(StreamProcessor.SupportsSQLGeneration()) StatusBar.Text = "Client version recognised. Press Ctrl-S to Generate SQL"; else StatusBar.Text = "Client version recognised. *SQL GENERATION NOT SUPPORTED FOR THIS CLIENT*"; } ZoneName = StreamProcessor.GetZoneName(); UInt32 ZoneNumber = StreamProcessor.GetZoneNumber(); Log("Zonename is " + StreamProcessor.GetZoneName()); Log("Zone number is " + ZoneNumber); ZoneLabel.Text = StreamProcessor.GetZoneLongName() + " [" + StreamProcessor.GetZoneName() + "] (" + ZoneNumber.ToString() + ")"; SQLForm.ZoneIDTextBox.Text = ZoneNumber.ToString(); SQLForm.ZoneIDTextBox.Enabled = true; SQLForm.DoorsTextBox.Enabled = true; SQLForm.NPCTypesTextBox.Enabled = true; SQLForm.SpawnEntryTextBox.Enabled = true; SQLForm.SpawnGroupTextBox.Enabled = true; SQLForm.Spawn2TextBox.Enabled = true; SQLForm.GridTextBox.Enabled = true; SQLForm.ObjectTextBox.Enabled = true; SQLForm.GroundSpawnTextBox.Enabled = true; SQLForm.MerchantTextBox.Enabled = true; SQLForm.VersionSelector.Enabled = true; menuGenerateSQL.Enabled = StreamProcessor.SupportsSQLGeneration(); menuPacketDump.Enabled = true; menuViewPackets.Enabled = true; menuDumpAAs.Enabled = true; SQLForm.RecalculateBaseInsertIDs(); StreamProcessor.GenerateZonePointList(); } private void menuGenerateSQL_Click(object sender, EventArgs e) { if (SQLForm.ShowDialog() != DialogResult.OK) return; string SQLFile = SQLForm.FileName; try { SQLStream = new StreamWriter(SQLFile); } catch { Log("Unable to open file " + SQLFile + " for writing."); StatusBar.Text = "Unable to open file " + SQLFile + " for writing."; return; } UInt32 SpawnDBID = Convert.ToUInt32(SQLForm.NPCTypesTextBox.Text); UInt32 SpawnGroupID = Convert.ToUInt32(SQLForm.SpawnGroupTextBox.Text); UInt32 SpawnEntryID = Convert.ToUInt32(SQLForm.SpawnEntryTextBox.Text); UInt32 Spawn2ID = Convert.ToUInt32(SQLForm.Spawn2TextBox.Text); UInt32 GridDBID = Convert.ToUInt32(SQLForm.GridTextBox.Text); UInt32 MerchantDBID = Convert.ToUInt32(SQLForm.MerchantTextBox.Text); int DoorDBID = Convert.ToInt32(SQLForm.DoorsTextBox.Text); UInt32 GroundSpawnDBID = Convert.ToUInt32(SQLForm.GroundSpawnTextBox.Text); UInt32 ObjectDBID = Convert.ToUInt32(SQLForm.ObjectTextBox.Text); UInt32 ZoneID = Convert.ToUInt32(SQLForm.ZoneIDTextBox.Text); SpawnNameFilter = SQLForm.SpawnNameFilter.Text; CoalesceWaypoints = SQLForm.CoalesceWaypoints.Checked; WriteSQL("-- SQL created by " + Version); WriteSQL("--"); WriteSQL("-- Using Decoder: " + StreamProcessor.GetDecoderVersion()); WriteSQL("--"); WriteSQL("-- Packets captured on " + StreamProcessor.GetCaptureStartTime().ToString()); WriteSQL("--"); WriteSQL("-- Change these variables if required"); WriteSQL("--"); WriteSQL("set @StartingNPCTypeID = " + SpawnDBID + ";"); WriteSQL("set @StartingSpawnGroupID = " + SpawnGroupID + ";"); WriteSQL("set @StartingSpawnEntryID = " + SpawnEntryID + ";"); WriteSQL("set @StartingSpawn2ID = " + Spawn2ID + ";"); WriteSQL("set @StartingGridID = " + GridDBID + ";"); WriteSQL("set @StartingMerchantID = " + MerchantDBID + ";"); WriteSQL("set @BaseDoorID = " + DoorDBID + ";"); WriteSQL("set @StartingGroundSpawnID = " + GroundSpawnDBID + ";"); WriteSQL("set @StartingObjectID = " + ObjectDBID + ";"); WriteSQL("--"); WriteSQL("--"); if (SQLForm.ZoneCheckBox.Checked) StreamProcessor.GenerateZoneSQL(this.WriteSQL); if (SQLForm.ZonePointCheckBox.Checked) StreamProcessor.GenerateZonePointSQL(ZoneName, this.WriteSQL); UInt32 SpawnVersion = (UInt32)SQLForm.VersionSelector.Value; if (SQLForm.DoorCheckBox.Checked) { Log("Starting to generate SQL for Doors."); StreamProcessor.GenerateDoorsSQL(ZoneName, DoorDBID, SpawnVersion, this.WriteSQL); Log("Finished generating SQL for Doors."); } Log("Starting to generate SQL for Spawns and/or Grids."); StreamProcessor.GenerateSpawnSQL(SQLForm.SpawnCheckBox.Checked, SQLForm.GridCheckBox.Checked, SQLForm.MerchantCheckBox.Checked, ZoneName, ZoneID, SpawnVersion, SQLForm.UpdateExistingNPCTypesCheckbox.Checked, SQLForm.NPCTypesTintCheckBox.Checked, SpawnNameFilter, CoalesceWaypoints, SQLForm.InvisibleMenCheckBox.Checked, this.WriteSQL); Log("Finished generating SQL for Spawns and/or Grids."); if (SQLForm.GroundSpawnCheckBox.Checked || SQLForm.ObjectCheckBox.Checked) { Log("Starting to generate SQL for Ground Spawns and/or Objects."); StreamProcessor.GenerateObjectSQL(SQLForm.GroundSpawnCheckBox.Checked, SQLForm.ObjectCheckBox.Checked, SpawnVersion, this.WriteSQL); Log("Finished generating SQL for Ground Spawns and/or Objects."); } StatusBar.Text = "SQL written to " + SQLFile; SQLStream.Close(); } private void menuPacketDump_Click(object sender, EventArgs e) { if (PacketDumpFileDialog.ShowDialog() == DialogResult.OK) { StatusBar.Text = "Packet dump in progress. Please wait..."; Log("Packets dump in progress..."); DisableAllControls(); Application.DoEvents(); if (StreamProcessor.DumpPackets(PacketDumpFileDialog.FileName, Properties.Settings.Default.DumpTimeStamps)) { StatusBar.Text = "Packets dumped successfully."; Log("Packets dumped successfully."); } else { StatusBar.Text = "Packet dump failed."; Log("Packet dump failed."); } EnableAllControls(); } } private void menuDumpAAs_Click(object sender, EventArgs e) { if (PacketDumpFileDialog.ShowDialog() == DialogResult.OK) { Log("AA dump in progress..."); DisableAllControls(); if (StreamProcessor.DumpAAs(PacketDumpFileDialog.FileName)) { StatusBar.Text = "AAs dumped successfully."; Log("AAs dumped successfully."); } else { StatusBar.Text = "AA dumped failed."; Log("AA dump failed."); } EnableAllControls(); } } private void menuExit_Click(object sender, EventArgs e) { Close(); } private void menuViewDebugLog_Click(object sender, EventArgs e) { menuViewDebugLog.Checked = DebugLog.Visible; if (!menuViewDebugLog.Checked) { menuViewDebugLog.Checked = true; ShowDebugLog(); } else { menuViewDebugLog.Checked = false; DebugLog.Hide(); } } private void menuViewPackets_Click(object sender, EventArgs e) { DisableAllControls(); Application.DoEvents(); string TextFileViewer = Properties.Settings.Default.TextFileViewer; string TempFileName = Path.GetTempFileName(); if (StreamProcessor.DumpPackets(TempFileName, Properties.Settings.Default.DumpTimeStamps)) { try { System.Diagnostics.Process.Start(TextFileViewer, TempFileName); } catch { StatusBar.Text = "Unable to launch " + TextFileViewer; } } else { StatusBar.Text = "Unexpected error while generating temporary file."; } EnableAllControls(); } private void EQExtractor2Form1_Load(object sender, EventArgs e) { if (Properties.Settings.Default.ShowDebugWindowOnStartup) { ShowDebugLog(); } } private void DisplayUsageInfo() { #if DEBUG Version += " (Debug Build)"; #else Version += " (Release Build)"; #endif Text = Version; Log(Version + " Initialised."); Log(""); Log("Instructions:"); Log("Generate a .pcap file using Wireshark. To do this, park a character in the zone you want to collect in."); Log("Camp to character select. Start Wireshark capturing. Zone your character in and just sit around for a"); Log("while, or go and inspect merchant inventories if you want to collect those. When finished, stop the"); Log("Wireshark capture and save it (File/Save As)."); Log(""); Log("Load the .pcap file into this program by pressing Ctrl-L."); Log("To generate SQL, press Ctrl-S and select the check boxes and set the starting SQL INSERT IDs as required."); Log("Review the generated SQL before sourcing as DELETEs are auto-generated."); Log("Press Ctrl-V to view packets, or Ctrl-D to dump them to a text file."); Log(""); } private void menuOptions_Click(object sender, EventArgs e) { DialogResult d = Options.ShowDialog(); if (d == DialogResult.OK) { Properties.Settings.Default.TextFileViewer = Options.PacketDumpViewerProgram.Text; Properties.Settings.Default.ShowDebugWindowOnStartup = Options.ShowDebugWindowOnStartup.Checked; Properties.Settings.Default.DumpTimeStamps = Options.ShowTimeStamps.Checked; Properties.Settings.Default.Save(); if (Properties.Settings.Default.ShowDebugWindowOnStartup) { if (!DebugLog.Visible) ShowDebugLog(); } else { if (DebugLog.Visible) { DebugLog.Hide(); menuViewDebugLog.Checked = false; } } } else { Options.PacketDumpViewerProgram.Text = Properties.Settings.Default.TextFileViewer; Options.ShowDebugWindowOnStartup.Checked = Properties.Settings.Default.ShowDebugWindowOnStartup; Options.ShowTimeStamps.Checked = Properties.Settings.Default.DumpTimeStamps; } } private void ShowDebugLog() { DebugLog.Left = this.Location.X; DebugLog.Top = this.Location.Y + this.Height; DebugLog.Show(); menuViewDebugLog.Checked = true; this.Focus(); } private void menuView_Popup(object sender, EventArgs e) { menuViewDebugLog.Checked = DebugLog.Visible; } } }