Author: verifier Date: Mon Jun 23 11:53:51 2008 New Revision: 8817 Added: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.Designer.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.resx freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelPark.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventSessionCrash.cs Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/EventWatcher.csproj freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/Program.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitch.EventSocket.Test/Program.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/ChannelEvent.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelAnswer.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelApplication.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelBridge.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelCreate.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelDestroy.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecute.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecuteComplete.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelHangup.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOriginate.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOutgoing.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelProgress.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelState.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnbridge.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnpark.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventCodec.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmf.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmfStatus.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelInfo.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Commands/Originate.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventManager.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventParser.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventSocket.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Events/EventBase.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/FreeSwitch.EventSocket.csproj freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PartyInfo.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PlainEventMsg.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresence.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceIn.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceOut.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceProbe.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventRoster.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaExpire.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaRegister.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/SipEvent.cs freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/StringParser.cs Log: Completed EventWatcher, added ToString to most of the events (now showing relevant info). Recoded EventParser to be thread safe. EventParser/EventSocket now queues up all incoming data and parses it as soon as possible (true async handling) Added: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.Designer.cs ============================================================================== --- (empty file) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.Designer.cs Mon Jun 23 11:53:51 2008 @@ -0,0 +1,129 @@ +namespace EventWatcher +{ + partial class ChannelWatcher + { + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.tv = new System.Windows.Forms.TreeView(); + this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel(); + this.tb = new System.Windows.Forms.RichTextBox(); + this.toolStrip1.SuspendLayout(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.SuspendLayout(); + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel1}); + this.toolStrip1.Location = new System.Drawing.Point(0, 0); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(961, 25); + this.toolStrip1.TabIndex = 3; + this.toolStrip1.Text = "toolStrip1"; + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 25); + this.splitContainer1.Name = "splitContainer1"; + this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.tb); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tv); + this.splitContainer1.Size = new System.Drawing.Size(961, 622); + this.splitContainer1.SplitterDistance = 307; + this.splitContainer1.TabIndex = 4; + // + // tv + // + this.tv.Dock = System.Windows.Forms.DockStyle.Fill; + this.tv.FullRowSelect = true; + this.tv.Location = new System.Drawing.Point(0, 0); + this.tv.Name = "tv"; + this.tv.ShowLines = false; + this.tv.ShowPlusMinus = false; + this.tv.ShowRootLines = false; + this.tv.Size = new System.Drawing.Size(961, 311); + this.tv.TabIndex = 2; + // + // toolStripLabel1 + // + this.toolStripLabel1.Name = "toolStripLabel1"; + this.toolStripLabel1.Size = new System.Drawing.Size(37, 22); + this.toolStripLabel1.Text = "Rensa"; + this.toolStripLabel1.Click += new System.EventHandler(this.toolStripLabel1_Click); + // + // tb + // + this.tb.Dock = System.Windows.Forms.DockStyle.Fill; + this.tb.Location = new System.Drawing.Point(0, 0); + this.tb.Name = "tb"; + this.tb.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.ForcedBoth; + this.tb.Size = new System.Drawing.Size(961, 307); + this.tb.TabIndex = 0; + this.tb.Text = ""; + this.tb.WordWrap = false; + // + // ChannelWatcher + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(961, 647); + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.toolStrip1); + this.Name = "ChannelWatcher"; + this.Text = "ChannelWatcher"; + this.Load += new System.EventHandler(this.ChannelWatcher_Load); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.ToolStripLabel toolStripLabel1; + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.TreeView tv; + private System.Windows.Forms.RichTextBox tb; + + } +} \ No newline at end of file Added: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.cs ============================================================================== --- (empty file) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.cs Mon Jun 23 11:53:51 2008 @@ -0,0 +1,160 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using FreeSwitch.EventSocket; + +namespace EventWatcher +{ + public partial class ChannelWatcher : Form + { + private EventManager _mgr = new EventManager(); + private Color _currentColor = 0; + StringBuilder sb = new StringBuilder(); + + public ChannelWatcher() + { + InitializeComponent(); + } + + private void ChannelWatcher_Load(object sender, EventArgs e) + { + _mgr.Start("localhost"); + _mgr.Subscribe(Event.All); + _mgr.EventReceived += OnPreSwitchEvent; + ClearTb(); + // AddText("bajs"); + } + + private void OnPreSwitchEvent(EventBase theEvent) + { + if (tv.InvokeRequired) + BeginInvoke((MethodInvoker)delegate { OnSwitchEvent(theEvent); }); + else + OnSwitchEvent(theEvent); + } + + private void ClearTb() + { + /* +{\rtf1\ansi\ansicpg1252\deff0\deflang1053 + {\colortbl ;\red128\green0\blue0;\red0\green128\blue0;\red0\green0\blue255;\red0\green0\blue255;} + {\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}} +\viewkind4\uc1\pard\f0\fs17 Hello\cf1\b <\cf3\b0 (Wor"ld")\cf1\b >\cf0\b0 \par +} + */ + sb.Length = 0; + sb.Append( + @"{\rtf1\ansi\ansicpg1252\deff0\deflang1053" + + @"{\colortbl ;\red0\green0\blue0;\red128\green0\blue0;\red0\green128\blue0;\red0\green0\blue255;\red0\green0\blue255;}" + + @"{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}" + + @"\viewkind4\uc1\pard\f0\fs20\par \par}"); + tb.Rtf = sb.ToString(); + } + + public enum Color + { + None, + Black, + Red, + Green, + Blue + } + + + + [DllImport("user32.dll")] + public static extern bool LockWindowUpdate(IntPtr hWndLock); + + private void AddText(string text) + { + text = text.Replace("\\", "\\\\").Replace("{", "\\{").Replace("}", "\\}"); + string colored = string.Empty; + bool inQ = false; + bool bold = false; + foreach (char ch in text) + { + Color color = Color.None; + if (inQ) + { + if (ch == '"') + { + inQ = false; + color = Color.Black; + } + } + else if (char.IsLetter(ch)) + color = Color.Black; + else if (Char.IsDigit(ch)) + color = Color.Blue; + else if (ch == '"') + { + inQ = true; + color = Color.Green; + } + else + { + bold = true; + color = Color.Red; + } + + if (color != Color.None) + SetColor(ref colored, color, bold); + + if (ch == ')') + colored += ' '; + colored += ch; + if (ch == ')') + colored += ' '; + } + sb.Length = sb.Length - 5; + sb.AppendLine(colored); + sb.Append("\\par\\par}"); + LockWindowUpdate(tb.Handle); + tb.Rtf = sb.ToString(); + tb.SelectionStart = tb.Text.Length; + tb.ScrollToCaret(); + LockWindowUpdate(IntPtr.Zero); + //ScrollToEnd(tb); + + } + + private void SetColor(ref string text, Color color, bool bold) + { + if (color != _currentColor) + { + text += "\\cf" + (int) color; + //if (bold) + // text += "\\b"; + text += " "; + _currentColor = color; + } + } + + private void OnSwitchEvent(EventBase theEvent) + { + AddText(theEvent.ToString()); + + ChannelEvent evt = theEvent as ChannelEvent; + if (evt == null) + return; + + TreeNode node = tv.Nodes[evt.UniqueId]; + if (node == null) + { + tv.Nodes.Add(evt.UniqueId, evt.ToString()); + node = tv.Nodes[evt.UniqueId]; + node.Tag = evt; + node.ToolTipText = evt.ToString().Replace(".", "\r\n"); + } + node.Nodes.Add(new TreeNode(evt.ToString())); + } + + private void toolStripLabel1_Click(object sender, EventArgs e) + { + tv.Nodes.Clear(); + ClearTb(); + } + } +} \ No newline at end of file Added: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.resx ============================================================================== --- (empty file) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/ChannelWatcher.resx Mon Jun 23 11:53:51 2008 @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>17, 17</value> + </metadata> +</root> \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/EventWatcher.csproj ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/EventWatcher.csproj (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/EventWatcher.csproj Mon Jun 23 11:53:51 2008 @@ -40,6 +40,12 @@ <Compile Include="Call.cs" /> <Compile Include="CallManager.cs" /> <Compile Include="CallStateEvent.cs" /> + <Compile Include="ChannelWatcher.cs"> + <SubType>Form</SubType> + </Compile> + <Compile Include="ChannelWatcher.Designer.cs"> + <DependentUpon>ChannelWatcher.cs</DependentUpon> + </Compile> <Compile Include="Extension.cs" /> <Compile Include="Form1.cs"> <SubType>Form</SubType> @@ -52,6 +58,10 @@ </Compile> <Compile Include="Program.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <EmbeddedResource Include="ChannelWatcher.resx"> + <SubType>Designer</SubType> + <DependentUpon>ChannelWatcher.cs</DependentUpon> + </EmbeddedResource> <EmbeddedResource Include="Form1.resx"> <SubType>Designer</SubType> <DependentUpon>Form1.cs</DependentUpon> Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/Program.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/Program.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/EventWatcher/Program.cs Mon Jun 23 11:53:51 2008 @@ -14,7 +14,7 @@ { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new Form1()); + Application.Run(new ChannelWatcher()); } } } \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitch.EventSocket.Test/Program.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitch.EventSocket.Test/Program.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitch.EventSocket.Test/Program.cs Mon Jun 23 11:53:51 2008 @@ -1,8 +1,7 @@ using System; -using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; -using System.Reflection; -using System.Text; +using System.Threading; namespace FreeSwitch.EventSocket.Test { @@ -10,18 +9,70 @@ { static void Main(string[] args) { - EventManager mgr = new EventManager(); + /*EventManager mgr = new EventManager(); mgr.Subscribe(Events.GetChannelEvents()); mgr.Start("localhost"); Console.ReadLine(); + */ + Program p = new Program(); + p.Test(); - string buffer = File.ReadAllText("..\\..\\..\\watcherRaw.log"); - int bufLen = buffer.Length; + } + + private int _counter; + private EventParser _parser; + Random _rand = new Random((int)DateTime.Now.Ticks); + + public void Test() + { + _parser = new EventParser(); + string text = File.ReadAllText("C:\\mymsgs.txt"); + Thread[] threads = new Thread[5]; + for (int i = 0; i < 5; ++i) + threads[i] = new Thread(FeedStream); + + while (StreamFeeder(ref text)) ; + //Parse(text); +/* + Parse(File.ReadAllText("C:\\events1.txt")); + Parse(File.ReadAllText("C:\\events2.txt")); + Parse(File.ReadAllText("C:\\events3.txt")); +*/ + } + + public void FeedStream() + { + + } + public bool StreamFeeder(ref string text) + { + int length; + if (text.Length < 5) + length = text.Length; + else + length = _rand.Next(text.Length / 2); + + string myText = text.Substring(0, length); + Parse(myText); + text = text.Remove(0, length); + return text.Length > 0; + } + + public void Parse(string text) + { + _parser.Append(text); + PlainEventMsg msg = _parser.ParseOne(); + while (msg != null) + { + ++_counter; + + NameValueCollection pars = msg.ParseBody(true); + Console.WriteLine(pars["event-name"]); + + msg = _parser.ParseOne(); + } - EventParser ep = new EventParser(buffer); - //int cnt = 0; - EventSocket es = new EventSocket(); - es.Setup(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/ChannelEvent.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/ChannelEvent.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/ChannelEvent.cs Mon Jun 23 11:53:51 2008 @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class ChannelEvent : EventBase @@ -62,5 +58,12 @@ return true; } + + public override string ToString() + { + return + "ChannelEvent(" + _uniqueId + " [" + _callDirection + "] " + _answerState + + ", channelInfo{" + _channelInfo + "})"; + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelAnswer.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelAnswer.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelAnswer.cs Mon Jun 23 11:53:51 2008 @@ -2,5 +2,9 @@ { public class EventChannelAnswer : EventChannelState { + public override string ToString() + { + return "ChannelAnswer." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelApplication.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelApplication.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelApplication.cs Mon Jun 23 11:53:51 2008 @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelApplication : EventChannelState { + public override string ToString() + { + return "ChannelApplication." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelBridge.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelBridge.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelBridge.cs Mon Jun 23 11:53:51 2008 @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelBridge : EventChannelState { + public override string ToString() + { + return "ChannelBridge." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelCreate.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelCreate.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelCreate.cs Mon Jun 23 11:53:51 2008 @@ -2,5 +2,9 @@ { public class EventChannelCreate : ChannelEvent { + public override string ToString() + { + return "ChannelCreate." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelDestroy.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelDestroy.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelDestroy.cs Mon Jun 23 11:53:51 2008 @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelDestroy : EventChannelState { + public override string ToString() + { + return "ChannelDestroy." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecute.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecute.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecute.cs Mon Jun 23 11:53:51 2008 @@ -28,5 +28,10 @@ return true; } + + public override string ToString() + { + return "EventChannelExecute(" + _appName + ", '" + _arguments + "')." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecuteComplete.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecuteComplete.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelExecuteComplete.cs Mon Jun 23 11:53:51 2008 @@ -28,6 +28,11 @@ return true; } + + public override string ToString() + { + return "ExecuteComplete(" + _appName + ", '" + _arguments + "')." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelHangup.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelHangup.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelHangup.cs Mon Jun 23 11:53:51 2008 @@ -33,6 +33,10 @@ return true; } + public override string ToString() + { + return "ChannelHangup(" + _hangupCause + ")." + base.ToString(); + } } public enum HangupCause Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOriginate.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOriginate.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOriginate.cs Mon Jun 23 11:53:51 2008 @@ -1,11 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelOriginate : ChannelEvent { - + public override string ToString() + { + return "ChannelOriginate." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOutgoing.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOutgoing.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelOutgoing.cs Mon Jun 23 11:53:51 2008 @@ -1,11 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelOutgoing : EventChannelState { - + public override string ToString() + { + return "ChannelOutgoing." + base.ToString(); + } } } Added: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelPark.cs ============================================================================== --- (empty file) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelPark.cs Mon Jun 23 11:53:51 2008 @@ -0,0 +1,10 @@ +namespace FreeSwitch.EventSocket +{ + public class EventChannelPark : EventChannelState + { + public override string ToString() + { + return "ChannelPark." + base.ToString(); + } + } +} Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelProgress.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelProgress.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelProgress.cs Mon Jun 23 11:53:51 2008 @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelProgress : EventChannelState { + public override string ToString() + { + return "ChannelProgress" + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelState.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelState.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelState.cs Mon Jun 23 11:53:51 2008 @@ -2,8 +2,15 @@ { public class EventChannelState : ChannelEvent { - private PartyInfo _caller = new PartyInfo(); - private PartyInfo _originator = new PartyInfo(); + private const string Yes = "yes"; + private const string CallerTag = "caller-"; + private const string OriginatorTag = "originator-"; + private const string OriginateeTag = "originatee-"; + private const string OtherLegTag = "other-leg-"; + private const string ScreenBitTag = "screen-bit"; + private PartyInfo _caller = PartyInfo.Empty; + private PartyInfo _originator = PartyInfo.Empty; + private PartyInfo _otherLeg = PartyInfo.Empty; private bool _screenBit = false; /// <summary> @@ -34,30 +41,58 @@ set { _screenBit = value; } } + /// <summary> + /// Other leg of call. + /// </summary> + public PartyInfo OtherLeg + { + get { return _otherLeg; } + set { _otherLeg = value; } + } + public override bool ParseCommand(string name, string value) { - if (name == "screen-bit") + if (name == ScreenBitTag) { - ScreenBit = value == "yes"; + ScreenBit = value == Yes; return true; } - else if (name.Length > 11 && name.Substring(0, 11) == "originator-" - || name.Length > 11 && name.Substring(0, 11) == "originatee-") + else if (name.Length > 11 && name.Substring(0, 11) == OriginatorTag + || name.Length > 11 && name.Substring(0, 11) == OriginateeTag) { - if (_originator == null) + if (_originator == PartyInfo.Empty) _originator = new PartyInfo(); return _originator.Parse(name.Substring(11), value); } - else if (name.Length > 7 && name.Substring(0, 7) == "caller-") + else if (name.Length > 7 && name.Substring(0, 7) == CallerTag) { - if (_caller == null) + if (_caller == PartyInfo.Empty) _caller = new PartyInfo(); return _caller.Parse(name.Substring(7), value); } + else if (name.Length > 10 && name.Substring(0, 10) == OtherLegTag) + { + if (_otherLeg == PartyInfo.Empty) + _otherLeg = new PartyInfo(); + + return _otherLeg.Parse(name.Substring(10), value); + } else return base.ParseCommand(name, value); } + + public override string ToString() + { + string temp = "ChannelState("; + if (Caller != PartyInfo.Empty) + temp += " Caller{" + Caller + "}"; + if (Originator != PartyInfo.Empty) + temp += " Originator{" + Originator + "}"; + if (OtherLeg != PartyInfo.Empty) + temp += " OtherLeg{" + OtherLeg + "}"; + return temp + ")." + base.ToString(); + } } } \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnbridge.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnbridge.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnbridge.cs Mon Jun 23 11:53:51 2008 @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelUnbridge : EventChannelState { + public override string ToString() + { + return "ChannelUnbridge." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnpark.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnpark.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventChannelUnpark.cs Mon Jun 23 11:53:51 2008 @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class EventChannelUnpark : EventChannelState { + public override string ToString() + { + return "ChannelUnpark." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventCodec.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventCodec.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventCodec.cs Mon Jun 23 11:53:51 2008 @@ -2,5 +2,9 @@ { public class EventCodec : EventChannelState { + public override string ToString() + { + return "Codec." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmf.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmf.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmf.cs Mon Jun 23 11:53:51 2008 @@ -31,5 +31,10 @@ return base.ParseCommand(name, value); } + + public override string ToString() + { + return "Dtmf(" + _digit + ")." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmfStatus.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmfStatus.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventDtmfStatus.cs Mon Jun 23 11:53:51 2008 @@ -27,5 +27,10 @@ return base.ParseCommand(name, value); } + + public override string ToString() + { + return "DtmfStatus." + base.ToString(); + } } } Added: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventSessionCrash.cs ============================================================================== --- (empty file) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelEvents/EventSessionCrash.cs Mon Jun 23 11:53:51 2008 @@ -0,0 +1,10 @@ +namespace FreeSwitch.EventSocket.ChannelEvents +{ + public class EventSessionCrash : ChannelEvent + { + public override string ToString() + { + return "SessionCrash." + base.ToString(); + } + } +} Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelInfo.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelInfo.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/ChannelInfo.cs Mon Jun 23 11:53:51 2008 @@ -9,8 +9,10 @@ SoftExecute, // Channel is in a passive transmit state Execute, // Channel is executing it's dialplan ExchangeMedia, // Channel is exchanging media + Park, ConsumeMedia, // Channel is consuming media Hibernate, // Channel is in a sleep state + Reset, Hangup, // Channel is flagged for hangup and ready to end Done, // Channel is ready to be destroyed and out of the state machine Unknown @@ -21,9 +23,9 @@ { private ChannelState _state; private int _stateNumber; - private string _profile; - private string _address; - private string _hostName; + private string _profile = string.Empty; + private string _address = string.Empty; + private string _hostName = string.Empty; private string _protocol = string.Empty; private string _readCodecName; private int _readCodecRate; @@ -209,10 +211,12 @@ case "CS_SOFT_EXECUTE": return ChannelState.SoftExecute; case "CS_EXECUTE": return ChannelState.Execute; case "CS_EXCHANGE_MEDIA": return ChannelState.ExchangeMedia; + case "CS_PARK": return ChannelState.Park; case "CS_CONSUME_MEDIA": return ChannelState.ConsumeMedia; case "CS_HIBERNATE": return ChannelState.Hibernate; case "CS_HANGUP": return ChannelState.Hangup; case "CS_DONE": return ChannelState.Done; + case "CS_RESET": return ChannelState.Reset; default: return ChannelState.Unknown; } } @@ -221,5 +225,10 @@ { return "Unknown"; } + + public override string ToString() + { + return _address + "@" + _hostName + ": " + _state; + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Commands/Originate.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Commands/Originate.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Commands/Originate.cs Mon Jun 23 11:53:51 2008 @@ -25,6 +25,7 @@ private readonly IList<ChannelVariable> _variables = new List<ChannelVariable>(); private string _callerIdName = null; private string _callerIdNumber = null; + private bool _varsAdded = false; public Originate() {} @@ -73,9 +74,13 @@ { get { - _variables.Add(new ChannelVariable("origination_caller_id_name", CallerIdName ?? _caller.Extension)); - if (!string.IsNullOrEmpty(_callerIdNumber)) - _variables.Add(new ChannelVariable("origination_caller_id_number", _callerIdNumber)); + if (!_varsAdded) + { + _variables.Add(new ChannelVariable("origination_caller_id_name", CallerIdName ?? _caller.Extension)); + if (!string.IsNullOrEmpty(_callerIdNumber)) + _variables.Add(new ChannelVariable("origination_caller_id_number", _callerIdNumber)); + _varsAdded = true; + } string variables = string.Empty; foreach (ChannelVariable var in _variables) Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventManager.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventManager.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventManager.cs Mon Jun 23 11:53:51 2008 @@ -13,8 +13,8 @@ { private readonly EventSocket _socket = new EventSocket(); public event EventHandler EventReceived; - private EventsWriter _writer; - private TextWriter _myWriter; + private readonly EventsWriter _writer; + private readonly TextWriter _rawLog; public string Password { set { _socket.Password = value; } @@ -22,13 +22,14 @@ public EventManager() { - _writer = MyWriter; - _myWriter = new StreamWriter(new FileStream("C:\\temp\\WatcherRow.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite)); + _writer = RawWriter; + _rawLog = new StreamWriter(new FileStream("C:\\temp\\WatcherRaw.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite)); } - private void MyWriter(string text) + private void RawWriter(string text) { - _myWriter.Write(text); + _rawLog.Write(text); + _rawLog.Flush(); } @@ -68,7 +69,7 @@ protected void OnMessage(PlainEventMsg msg) { - NameValueCollection parameters = msg.BodyToNameValue(true); + NameValueCollection parameters = msg.ParseBody(true); string eventName = parameters["event-name"]; if (eventName == null) return; Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventParser.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventParser.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventParser.cs Mon Jun 23 11:53:51 2008 @@ -1,99 +1,190 @@ -using EventSocketParser; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; namespace FreeSwitch.EventSocket { public class EventParser { - private PlainEventMsg _msg; - private readonly StringParser _parser; + private static readonly char[] BugWorkaround = {'C', 'o', 'n', 't', 'e', 'n', 't', '-'}; + private readonly StringBuilder _text = new StringBuilder(); + private readonly Queue<string> _piecesToAppend = new Queue<string>(); - public EventParser(string text) + public string Text { - _parser = new StringParser(text); + get { return _text.ToString(); } } - public PlainEventMsg ParseMessage() + internal static void ParseHeaders(PlainEventMsg msg, string header) { - _parser.ClearSavedPositions(); - _msg = new PlainEventMsg(); - - // Save pos if we cant parse the whole message - _parser.SavePos(); - - ReadHeader(); - if (!_msg.ValidateHeader()) - { - _parser.RestorePos(); - return null; - } - - // skip empty line between body and header - _parser.ReadLine(true); - - // we got no body. - if (_msg.ContentLength == -1) - return _msg; - - // Unfortunately, \n\n doesnt appear after all content. - if (_msg.ContentLength != 0) - _msg.Body = _parser.Read(_msg.ContentLength); - else - _msg.Body = _parser.ReadToEmptyLine(); - - // assume that we have not got a complete packet yet. - if (!_msg.Validate()) - { - _parser.RestorePos(); - return null; - } - - return _msg; - } - - public bool ReadHeader() - { - // skip empty lines - while (!_parser.EOF && _parser.PeekWord(true, true) == string.Empty) - _parser.ReadLine(false); - - if (_parser.EOF) - return false; - - string name = _parser.Read(':', true); + StringParser parser = new StringParser(header); + string name = parser.Read(':', true); while (name != string.Empty) { switch (name) { case "Content-Length": - _msg.ContentLength = int.Parse(_parser.ReadLine(true)); + msg.ContentLength = int.Parse(parser.ReadLine(true)); break; case "Content-Type": - _msg.ContentType = _parser.ReadLine(true); + msg.ContentType = parser.ReadLine(true); break; case "Reply-Text": - _msg.Body = _parser.ReadLine(); + msg.Body = parser.ReadLine(true); break; } // empty line == end of header - if (_parser.EOL) + if (parser.EOL) break; - name = _parser.Read(':', true); + name = parser.Read(':', true); } + } + /* + private int IsLineBreaks(int pos) + { + if (pos > 0 && Text[pos] == '\n' && Text[pos - 1] == '\n') + return 1; + if (pos > 3 && Text[pos] == '\n' && Text[pos - 1] == '\r' + && Text[pos - 2] == '\n' && Text[pos - 3] == '\r') + return 3; + return 0; + } + */ + public void Clear() + { + lock (Text) + _text.Length = 0; + } - return _msg.ContentType != string.Empty; + private void IgnoreLineBreaks(ref int i) + { + while (i < Text.Length && (Text[i] == '\n' || Text[i] == '\r')) + ++i; } - public void Append(string value) + /// <summary> + /// + /// </summary> + /// <returns></returns> + /// <exception cref="InvalidDataException">If parsing failed due to invalid format.</exception> + public PlainEventMsg ParseOne() { - _parser.RemoveUsedContent(); - _parser.Append(value); + // Move queue to text + lock (_piecesToAppend) + { + while (_piecesToAppend.Count > 0) + _text.Append(_piecesToAppend.Dequeue()); + } + + PlainEventMsg plainEvent; + lock (Text) + { + int i = 0; + + // find complete header + bool found = false; + for (; i < Text.Length - 1; ++i) + { + if (Text[i] == '\n' && Text[i+1] == '\n') + { + found = true; + break; + } + } + if (!found) + return null; + + // extract header + char[] chars = new char[i]; + Text.CopyTo(0, chars, 0, i); + string headers = new string(chars); +#if DEBUG + Console.WriteLine("===================================="); + Console.WriteLine("Headers: "); + Console.WriteLine(headers); +#endif + IgnoreLineBreaks(ref i); + + plainEvent = new PlainEventMsg(); + ParseHeaders(plainEvent, headers); + + // we got a body? + if (plainEvent.ContentLength > 0) + { + // Start of Empty header bugfix + // FS seems to send a header with content-length without sending an actual body + // this will eat that kind of header. + if (Text.Length >= BugWorkaround.Length + i) + { + found = true; + for (int index = 0; index < BugWorkaround.Length; ++index) + { + if (Text[index + i] != BugWorkaround[index]) + { + found = false; + break; + } + } + if (found) + { + Text.Remove(0, i); + Console.WriteLine("Removing empty content header."); + return null; + } + } + // end of bugfix. + + // not enough data for body. + if (plainEvent.ContentLength + i > Text.Length) + return null; + + // extract body + chars = new char[plainEvent.ContentLength]; + Text.CopyTo(i, chars, 0, plainEvent.ContentLength); + plainEvent.Body = new string(chars); + + // check for errors. + int pos = plainEvent.Body.IndexOf("\n\n"); + if (pos < plainEvent.Body.Length - 2) + { + Console.WriteLine("Fucked up event"); + Console.WriteLine("Header"); + Console.WriteLine(headers); + Console.WriteLine("Body"); + Console.WriteLine(plainEvent.Body); + Console.WriteLine("=========================== EVERYTHING in _text =============================="); + Console.WriteLine(Text); + throw new InvalidDataException("Fucked up event: " + Text); + } + +#if DEBUG + Console.WriteLine("Body:"); + Console.WriteLine(plainEvent.Body); +#endif + if (plainEvent.Body.Length < plainEvent.ContentLength) + throw new InvalidDataException("Body contents are too small!"); + + // Move forward to next header + i += plainEvent.ContentLength; + IgnoreLineBreaks(ref i); + } + + + // remove header( + body) from buffer + Text.Remove(0, i); + } + + return plainEvent; } - public void Clear() + + public void Append(string text) { - _parser.Clear(); + lock (_piecesToAppend) + _piecesToAppend.Enqueue(text); } } } \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventSocket.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventSocket.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/EventSocket.cs Mon Jun 23 11:53:51 2008 @@ -24,18 +24,30 @@ private bool _autoConnect = true; private Events _events; private string _hostName; - private readonly EventParser _parser = new EventParser(string.Empty); + private readonly EventParser _parser = new EventParser(); public event DataHandler DataReceived; private string _password = "ClueCon"; private int _port = 8021; - private object _lockobj = new object(); + private readonly object _lockobj = new object(); private readonly byte[] _readBuffer = new byte[8192]; - private string _temp = string.Empty; - private Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + private Socket _socket; private NetworkStream _stream; private Timer _timer; private bool _authed = false; const int RetryTimeout = 5000; + private bool _parsing = false; + + public EventSocket() + { + CreateSocket(); + } + + private void CreateSocket() + { + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _socket.NoDelay = true; + _socket.ReceiveBufferSize = 65535; + } public string Password { @@ -112,15 +124,18 @@ private void OnReadCompleted(IAsyncResult ar) { - int bytesRead; + string inbuffer; try { - bytesRead = _stream.EndRead(ar); + int bytesRead = _stream.EndRead(ar); if (bytesRead == 0) { HandleDisconnect(); return; } + inbuffer = Encoding.ASCII.GetString(_readBuffer, 0, bytesRead); + _parser.Append(inbuffer); + BeginRead(); } catch (IOException) { @@ -129,14 +144,22 @@ return; } - string text = Encoding.ASCII.GetString(_readBuffer, 0, bytesRead); if (DataReceived != null) - DataReceived(text); - _temp += text; - _parser.Append(text); - ParseMessages(); + DataReceived(inbuffer); - _stream.BeginRead(_readBuffer, 0, _readBuffer.Length, OnReadCompleted, null); + try + { + ParseMessages(); + } + catch (InvalidDataException) + { + HandleDisconnect(); + } + catch (ArgumentException) + { + Console.WriteLine(_parser.Text); + HandleDisconnect(); + } } /// <summary> @@ -176,39 +199,56 @@ _stream.Write(bytes, 0, bytes.Length); } + static readonly object locker = new object(); private void ParseMessages() { - PlainEventMsg msg = _parser.ParseMessage(); - while (msg != null) + + lock (locker) { - if (msg.ContentType == "auth/request") - { - AuthCommand cmd = new AuthCommand(_password); - cmd.ReplyReceived += OnAuthed; - _commands.Enqueue(cmd); - Write(cmd + "\n\n"); - } - else if (msg.ContentType == "command/reply" - || msg.ContentType == "api/response") + if (_parsing) + return; + _parsing = true; + } + + try + { + PlainEventMsg msg = _parser.ParseOne(); + while (msg != null) { - if (_commands.Count > 0) + if (msg.ContentType == "auth/request") { - CmdBase cmd = _commands.Dequeue(); - cmd.HandleReply(cmd.CreateReply(msg.Body)); + AuthCommand cmd = new AuthCommand(_password); + cmd.ReplyReceived += OnAuthed; + _commands.Enqueue(cmd); + Write(cmd + "\n\n"); + } + else if (msg.ContentType == "command/reply" + || msg.ContentType == "api/response") + { + if (_commands.Count > 0) + { + CmdBase cmd = _commands.Dequeue(); + cmd.HandleReply(cmd.CreateReply(msg.Body.Trim())); + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Got command reply or api response, but no actual command/api: " + msg.Body); + Console.ForegroundColor = ConsoleColor.Gray; + } } else { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Got command reply or api response, but no actual command/api: " + msg.Body); - Console.ForegroundColor = ConsoleColor.Gray; + if (MessageReceived != null) + MessageReceived(msg); } - } - else - { - if (MessageReceived != null) - MessageReceived(msg); - } - msg = _parser.ParseMessage(); + msg = _parser.ParseOne(); + } + } + finally + { + lock (locker) + _parsing = false; } } @@ -223,7 +263,7 @@ _parser.Clear(); _authed = false; _socket.Close(); - _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + CreateSocket(); if (_stream != null) { _stream.Dispose(); Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Events/EventBase.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Events/EventBase.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/Events/EventBase.cs Mon Jun 23 11:53:51 2008 @@ -155,5 +155,10 @@ } return true; } + + public override string ToString() + { + return "Base(" + m_name + ")"; + } } } \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/FreeSwitch.EventSocket.csproj ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/FreeSwitch.EventSocket.csproj (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/FreeSwitch.EventSocket.csproj Mon Jun 23 11:53:51 2008 @@ -43,10 +43,12 @@ <Compile Include="ChannelEvents\EventChannelBridge.cs" /> <Compile Include="ChannelEvents\ChannelEvent.cs" /> <Compile Include="ChannelEvents\EventChannelAnswer.cs" /> + <Compile Include="ChannelEvents\EventChannelPark.cs" /> <Compile Include="ChannelEvents\EventChannelProgress.cs" /> <Compile Include="ChannelEvents\EventChannelUnbridge.cs" /> <Compile Include="ChannelEvents\EventChannelUnpark.cs" /> <Compile Include="ChannelEvents\EventCodec.cs" /> + <Compile Include="ChannelEvents\EventSessionCrash.cs" /> <Compile Include="ChannelInfo.cs" /> <Compile Include="Commands\AnyCommand.cs"> </Compile> Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PartyInfo.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PartyInfo.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PartyInfo.cs Mon Jun 23 11:53:51 2008 @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { public class PartyInfo { - private string m_userName = string.Empty; + public static PartyInfo Empty = new PartyInfo(); + private string _userName = string.Empty; private string m_dialplan = string.Empty; private string m_callerIdName = string.Empty; private string m_callerIdNumber = string.Empty; @@ -14,14 +11,14 @@ private string m_uniqueId = string.Empty; private string m_source = string.Empty; private string m_context = string.Empty; - private string m_channelName = string.Empty; + private string _channelName = string.Empty; private bool m_screenBit; private bool m_privacyHideName; private bool m_privacyHideNumber; public PartyInfo() { - m_userName = string.Empty; + _userName = string.Empty; m_dialplan = string.Empty; m_callerIdName = string.Empty; } @@ -70,8 +67,8 @@ public string ChannelName { - get { return m_channelName; } - set { m_channelName = value; } + get { return _channelName; } + set { _channelName = value; } } public bool ScreenBit @@ -94,8 +91,8 @@ public string UserName { - get { return m_userName; } - set { m_userName = value; } + get { return _userName; } + set { _userName = value; } } public bool Parse(string name, string value) @@ -103,7 +100,7 @@ switch (name) { case "username": - m_userName = value; + _userName = value; break; case "dialplan": Dialplan = value; @@ -146,5 +143,11 @@ } + public override string ToString() + { + return _channelName + "(" + CallerIdName + "/" + CallerIdNumber + ") id: "+UniqueId+", destination: " + DestinationNumber; + + } + } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PlainEventMsg.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PlainEventMsg.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/PlainEventMsg.cs Mon Jun 23 11:53:51 2008 @@ -1,6 +1,5 @@ using System; using System.Collections.Specialized; -using EventSocketParser; namespace FreeSwitch.EventSocket { @@ -50,7 +49,7 @@ } - public NameValueCollection BodyToNameValue(bool urlDecodeValues) + public NameValueCollection ParseBody(bool urlDecodeValues) { NameValueCollection items = new NameValueCollection(); StringParser parser = new StringParser(_body); @@ -64,7 +63,7 @@ { items.Add(name.ToLower(), Uri.UnescapeDataString(value)); } - catch (UriFormatException) + catch (UriFormatException) { // add the value unformatted items.Add(name.ToLower(), value); @@ -77,4 +76,4 @@ return items; } } -} +} \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresence.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresence.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresence.cs Mon Jun 23 11:53:51 2008 @@ -10,7 +10,7 @@ //private string _expires; //not "presencein/register", "presenceout/register" private string _eventType = string.Empty; private string _login = string.Empty; - private EventChannelState _channelState; + private EventChannelState _channelState = new EventChannelState(); public string Login { @@ -71,6 +71,7 @@ * */ public override bool ParseCommand(string name, string value) { + bool res = _channelState.ParseCommand(name, value); switch (name) { case "status": @@ -87,6 +88,7 @@ break; default: + if (name.Length > 7 && name.Substring(0, 7) == "caller-") { if (Caller == null) @@ -98,15 +100,16 @@ if (base.ParseCommand(name, value)) return true; else - { - if (_channelState == null) - _channelState = new EventChannelState(); - return _channelState.ParseCommand(name, value); - } + return res; } } return true; } + + public override string ToString() + { + return "Presence(" + _login + ", " + _status + ")." + _channelState + "." + base.ToString(); + } } } \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceIn.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceIn.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceIn.cs Mon Jun 23 11:53:51 2008 @@ -2,5 +2,9 @@ { public class EventPresenceIn : EventPresence { + public override string ToString() + { + return "PresenceIn." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceOut.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceOut.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceOut.cs Mon Jun 23 11:53:51 2008 @@ -2,7 +2,11 @@ { public class EventPresenceOut : EventPresence { - + public override string ToString() + { + return "PresenceOut." + base.ToString(); + } + } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceProbe.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceProbe.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventPresenceProbe.cs Mon Jun 23 11:53:51 2008 @@ -6,5 +6,11 @@ { class EventPresenceProbe : EventPresence { + public override string ToString() + { + return "PresenceProbe." + base.ToString(); + } + } + } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventRoster.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventRoster.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventRoster.cs Mon Jun 23 11:53:51 2008 @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace FreeSwitch.EventSocket { class EventRoster : SipEvent Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaExpire.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaExpire.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaExpire.cs Mon Jun 23 11:53:51 2008 @@ -59,5 +59,10 @@ return true; } + + public override string ToString() + { + return "SofiaExpire(" + _userName + "@" + _domain + ")." + base.ToString(); + } } } Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaRegister.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaRegister.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/EventSofiaRegister.cs Mon Jun 23 11:53:51 2008 @@ -88,5 +88,12 @@ } return true; } + + public override string ToString() + { + return "SofiaRegister(" + _user + "@" + _domain + ", " + _expires + ")." + base.ToString(); + } } + + } \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/SipEvent.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/SipEvent.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/SipEvents/SipEvent.cs Mon Jun 23 11:53:51 2008 @@ -35,5 +35,10 @@ } return true; } + + public override string ToString() + { + return "Sip(" + _from + ")." + base.ToString(); + } } } \ No newline at end of file Modified: freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/StringParser.cs ============================================================================== --- freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/StringParser.cs (original) +++ freeswitch/trunk/scripts/contrib/verifier/EventSocket/trunk/FreeSwitchEventSocket/StringParser.cs Mon Jun 23 11:53:51 2008 @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace EventSocketParser +namespace FreeSwitch.EventSocket { internal class StringParser { @@ -44,12 +44,8 @@ public void RestorePos() { - _pos = _savedPositions.Pop(); - } - - public void RemoveSavedPos() - { - _savedPositions.Pop(); + if (_savedPositions.Count > 0) + _pos = _savedPositions.Pop(); } public void ClearSavedPositions() @@ -59,17 +55,19 @@ private bool IsEOF(int pos) { - return pos >= _text.Length - 1; + return pos >= _text.Length; } public bool IsEmptyLine(bool skipWhitespaces) { if (EOF) return false; - else if (_pos == _text.Length - 1) + else if (_pos < _text.Length - 1) return _text[_pos] == '\n'; - else + else if (_pos < _text.Length - 2) return _text[_pos] == '\r' && _text[_pos + 1] == '\n'; + + return false; } public string PeekWord(bool skipWS, bool stopAtEOL) @@ -126,10 +124,10 @@ int endpos = _pos; _pos = pos; - // Move to after new line chars - if (_text[_pos] == '\r') - _pos += 2; - else + // Move to after new line chars + if (!EOF && _text[_pos] == '\r') + ++_pos; + if (!EOF && _text[_pos] == '\n') ++_pos; // .. and the result is line without whitespaces at the end and without new line chars. @@ -196,6 +194,9 @@ private int TrimEnd() { + if (EOF) + return _pos; + int pos = _pos; while (IsWS(_text[pos])) --pos; @@ -216,7 +217,9 @@ private bool IsEOL() { - if (_text[_pos] == '\r' && _text[_pos + 1] == '\n') + if (EOF) + return true; + if (_text[_pos] == '\r') return true; else if (_text[_pos] == '\n') return true;