using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Threading;
using Microsoft.Win32;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using System.Security;
using System.Net;
using System.Net.Mail;
using System.Net.Http;
using System.Net.Mime;
using System.ComponentModel;
using System.Globalization;
//using NAudio;
//using NAudio.Wave;
//using WaveLib;
using Traysoft.AddTapi;


namespace VR2
{
    public class EmailServerSetting
    {
        public string emailServer;
        public ushort emailPort;
        public string emailAddr;
        public string emailPassword;
        public bool emailSSL;

        public EmailServerSetting()
        {
            emailServer = "";
            emailAddr = "";
            emailPassword = "";
            emailPort = 25;
            emailSSL = false;
        }
    }

    public class TAPICDR
    {
        public DateTime CallStartTime;
        public DateTime CallConnectedTime;
        public DateTime CallEndTime;
        public string CallerID;
        public string CallerIDName;
        public string CalledID;
        public string CalledIDName;
        public int CallDir;
        public bool CallDone;
        public bool CallConnected;
        public string CallGuid;
        public string UniqueID;
        public bool Reversed;

        public TAPICDR()
        {
            CallStartTime = CallConnectedTime = CallEndTime = DateTime.Now;
            CallerID = "";
            CallerIDName = "";
            CalledID = "";
            CalledIDName = "";
            CallDir = 0;
            CallDone = false;
            CallConnected = false;
            CallGuid = "";
            UniqueID = "";
            Reversed = false;
        }
    }

    public class VR2Channel
    {
        public int ChanIndex;
        public string CallerIP;
        public string CallerID;
        public string CalleeIP;
        public string CalleeID;
        public DateTime InitTime;
        public DateTime ConnectTime;
        public DateTime EndTime;
        public string UniqueID;
        public string AudioFile;
        public int AudioFileNum;
        public int Reason;
        public int CallDir;
        public bool CallConnected;
        public int ChanStatus;
        public string DTMFStr;
        public string ChanName;

        //Additional SIP Info If Needed
        public string OrgSIPInvite;
        public string OrgSIPResponse;
        public string ExtraSIPHeaders;
        public string SIPCallID;

        public int CallerAudioCodec;
        public int CalleeAudioCodec;
        public string CallerRTPAddr;
        public string CalleeRTPAddr;

        public bool ModTag;

        public VR2Channel()
        {
            ChanIndex = -1;
            ChanName = "";
            Reset();
        }

        public void Reset()
        {
            ChanStatus = 0;

            CallerIP = "";
            CallerID = "";
            CalleeIP = "";
            CalleeID = "";

            UniqueID = "";
            AudioFile = "";
            AudioFileNum = 0;
            Reason = 0;
            CallDir = 0;
            CallConnected = false;

            ModTag = false;

            InitTime = DateTime.Now;
            ConnectTime = DateTime.Now;
            EndTime = DateTime.Now;

            DTMFStr = "";

            OrgSIPInvite = "";
            OrgSIPResponse = "";
            ExtraSIPHeaders = "";
            SIPCallID = "";

            CallerAudioCodec = 0;
            CalleeAudioCodec = 0;
            CallerRTPAddr = "";
            CalleeRTPAddr = "";
        }

        public static string GetSIPHeaderValue(string SIPMsg, string headerName)
        {
            string ret = "";

            if (SIPMsg.Length == 0) return ret;

            int idx = SIPMsg.IndexOf(headerName);

            if (idx >= 0)
            {
                string temp = SIPMsg.Substring(idx + headerName.Length);
                for (int i = 0; i < temp.Length; i++)
                {
                    if (temp[i] != '\r' && temp[i] != '\n')
                    {
                        ret += temp[i];
                    }
                    else
                        break;
                }
            }

            return ret.Trim();
        }
    }

    public class VR2Event
    {
        public int EventID;
        public int ChanID;
        public string[] Params;

        public VR2Event()
        {
            EventID = 0;
            ChanID = 0;
            Params = new string[20];
            for (int i = 0; i < 20; i++)
            {
                Params[i] = "";
            }
        }
    }

    public class DBServerSetting
    {
        public SqlConnection myConn;

        public int authType; //0 = SQL Authentication, 1 = Windows Authentication
        public int dbType; //0 = 2005 Express, 1 = 2005, 2 = 2000
        public string sDBServer;
        public string sDBName;
        public string sUserName;
        public string sPassword;
        public string CallLogTableName;
        public string ChannelStatusTableName;

        public DBServerSetting()
        {
            myConn = null;
            authType = 0;
            dbType = 0;
            sDBServer = "";
            sDBName = "VR2";
            sUserName = "sa";
            sPassword = "";
            CallLogTableName = "calls";
            ChannelStatusTableName = "channels";
        }

        public void CopyFrom(DBServerSetting db_set)
        {
            dbType = db_set.dbType;
            authType = db_set.authType;
            sDBServer = db_set.sDBServer;
            sDBName = db_set.sDBName;
            sUserName = db_set.sUserName;
            sPassword = db_set.sPassword;
        }

        public string GetConnStr()
        {
            string connStr = "Data Source=";

            if (sUserName.Length == 0)
                sUserName = "sa";

            if (dbType == 0)
            {
                if (sDBServer.Length == 0)
                {
                    connStr += ".\\SQLEXPRESS;Initial Catalog=";
                }
                else
                {
                    connStr += sDBServer + "\\SQLEXPRESS;Initial Catalog=";
                }
            }
            else if (dbType >= 1)
            {
                connStr += sDBServer + ";Initial Catalog=";
            }

            if (sDBName.Length == 0)
            {
                connStr += "digilog;";
            }
            else
            {
                connStr += sDBName + ";";
            }

            if (authType == 0)
            {
                connStr += "User Id=" + sUserName + ";";
                connStr += "Password=" + sPassword + ";";
            }
            else
            {
                connStr += "Trusted_Connection=Yes;"; // or Integrated Security=SSPI
            }

            return connStr;
        }

        public bool ConnectDB()
        {
            //string connStr = "Data Source=.\\SQLEXPRESS;Initial Catalog=digilog;User Id=sa;Password=12345678";
            string connStr = GetConnStr();

            myConn = new SqlConnection(connStr);
            try
            {
                myConn.Open();
            }
            catch (Exception e)
            {
                myConn = null;
                //Console.WriteLine(e.ToString());
                VRAPIASM.VRAPIEnv.Log(1, e.ToString());
                return false;
            }

            return true;
        }

        public bool DisconnectDB()
        {
            if (myConn != null)
            {
                try
                {
                    myConn.Close();
                }
                catch (Exception)
                {
                }
                myConn = null;
            }
            return true;
        }

        public bool IsDBConnected()
        {
            return myConn != null;
        }


        static bool TableExists(string tableNameAndSchema, string connectionString)
        {
            bool ret = false;
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                string checkTable = String.Format("IF OBJECT_ID('{0}', 'U') IS NOT NULL SELECT 'true' ELSE SELECT 'false'", tableNameAndSchema);
                SqlCommand command = new SqlCommand(checkTable, connection);
                command.CommandType = System.Data.CommandType.Text;
                connection.Open();
                ret = Convert.ToBoolean(command.ExecuteScalar());
                connection.Close();
                return ret;
            }
        }

        public void TestTables()
        {
            if (!TableExists(CallLogTableName, GetConnStr()))
            {
                SqlCommand catCMD = myConn.CreateCommand();
                catCMD.CommandText = "CREATE TABLE " + CallLogTableName + "(ID bigint IDENTITY(1,1), ChanID INT NOT NULL, Succeed tinyint NULL, CallerIP varchar(80) NULL, CallerID varchar(80) NULL, CallerName varchar(80) NULL, CalleeIP varchar(80) NULL, CalleeID varchar(80) NULL, CalleeName varchar(80) NULL, TimeInit datetime NULL, TimeBegin datetime NULL, TimeEnd datetime NULL, Duration INT NULL, UniqueID varchar(150) NULL, RecordPath varchar(250) NULL, RecordFileNum int NULL, DIR TINYINT, DTMF varchar(100), VRType tinyint, ChanName varchar(100), PAssertedIdentity varchar(100), PChargingVector varchar(100), RemotePartyID varchar(100), SIPReason varchar(100), SIPDate varchar(100), CallerSIPUserAgent varchar(100), CalledSIPUserAgent varchar(100), SIPCallID varchar(200), AcceptLanguage varchar(100), XCaller varchar(100), LastSIPResponseCode varchar(100), CallerAudioCodec INT, CalledAudioCodec INT, CallerRTPAddr varchar(100), CalledRTPAddr varchar(100), ExtraInfo1 varchar(200), ExtraInfo2 varchar(200), ExtraInfo3 varchar(200))";
                catCMD.ExecuteNonQuery();
            }

            if (!TableExists(ChannelStatusTableName, GetConnStr()))
            {
                SqlCommand catCMD = myConn.CreateCommand();
                catCMD.CommandText = "CREATE TABLE " + ChannelStatusTableName + "(ChanID SmallInt, CallerIP varchar(80) NULL, CallerID varchar(80) NULL, CalleeIP varchar(80) NULL, CalleeID varchar(80) NULL, TimeInit datetime NULL, TimeBegin datetime NULL, TimeEnd datetime NULL, UniqueID varchar(150) NULL, RecordPath varchar(250) NULL, DIR TINYINT, CallConnected TINYINT, ChanStatus TINYINT, ChanName varchar(100))";
                catCMD.ExecuteNonQuery();
            }
        }

        /*
         * vb.net to check if a table exists
         * Shared Function TableExists(tableNameAndSchema As String) As Boolean   Using connection As New SqlConnection(connectionString)      Dim checkTable As String = [String].Format("IF OBJECT_ID('{0}', 'U') IS NOT NULL SELECT 'true' ELSE SELECT 'false'", tableNameAndSchema)            Dim command As New SqlCommand(checkTable, connection)      command.CommandType = CommandType.Text      connection.Open()       Return Convert.ToBoolean(command.ExecuteScalar())   End UsingEnd Function
         */

        //vb.net to check if a database exists
        /*
        Public Shared Function CheckDatabaseExists(ByVal server As String, ByVal database As String) As Boolean
        Dim connString As String = ("Data Source="  _
                    + (server + ";Initial Catalog=master;Integrated Security=True;"))
        Dim cmdText As String = ("select * from master.dbo.sysdatabases where name=\'"  _
                    + (database + "\'"))
        Dim bRet As Boolean = false
        Using sqlConnection As SqlConnection = New SqlConnection(connString)
        sqlConnection.Open
        Using sqlCmd As SqlCommand = New SqlCommand(cmdText, sqlConnection)
        Using reader As SqlDataReader = sqlCmd.ExecuteReader
        bRet = reader.HasRows
        End Using
        End Using
        End Using
        Return bRet
        End Function 
        */
    }

    public class VR2WavProcessWrap
    {
        public string fn;
        public int type; //1 = mp3, 2 = gsm, 3 = encode wav only
        public int encode;
    }

    public class VR2WavWorkProcess
    {
        public Thread workThread;
        public Queue<VR2WavProcessWrap> fnList;
        bool isExiting;


        public VR2WavWorkProcess()
        {
            fnList = new Queue<VR2WavProcessWrap>();
            workThread = new Thread(Run);
            isExiting = false;
        }

        public void StartConvert()
        {
            isExiting = false;
            workThread.Start(this);
        }

        public void StopConvert()
        {
            isExiting = true;
            workThread.Join();
        }

        public void AddJob(string fn, int type, int encode)
        {
            VR2WavProcessWrap wrap = new VR2WavProcessWrap();
            wrap.fn = fn;
            wrap.type = type;
            wrap.encode = encode;
            lock (fnList)
            {
                fnList.Enqueue(wrap);
            }
        }

        //code from digilog worked for lame.exe
        public void mciConvertWavMP3(string lamePath, string fileName, bool waitFlag)
        {
            //maxLen is in ms (1000 = 1 second) 
            string mp3fileName = fileName.Replace(".wav", ".mp3");
            string outfile = "--priority 0 \"" + fileName + "\" \"" + mp3fileName + "\"";
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
            psi.FileName = "\"" + lamePath + "\"";
            psi.Arguments = outfile;
            //psi.WorkingDirectory=pworkingDir; 
            psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized;
            System.Diagnostics.Process p = System.Diagnostics.Process.Start(psi);
            if (waitFlag)
            {
                p.WaitForExit();
                // wait for exit of called application 
            }
        }

        public static string GetFileNameOnly(string sFileName)
        {
            FileInfo fi = new FileInfo(sFileName);
            string ext = fi.Extension;
            string fn = fi.Name;
            string fn1 = "";
            for (int i = 0; i < fn.Length - ext.Length; i++)
            {
                fn1 += fn[i];
            }
            return fn1;
        }

        public static string getFileExtension(string fileName)
        {
            /*
            string extension = "";
            char[] arr = fileName.ToCharArray();
            int index = 0;
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] == '.')
                {
                    index = i; //get the last dot in the string 
                }
            }
            for (int x = index + 1; x < arr.Length; x++)//build the new string 
            {
                extension = extension + arr[x];
            }

            return extension;
            */
            FileInfo fi = new FileInfo(fileName);
            return fi.Extension;
        }

        static void Run(object obj)
        {
            Queue<VR2WavProcessWrap> fnList = new Queue<VR2WavProcessWrap>();
            VR2WavWorkProcess wav_process = (VR2WavWorkProcess)obj;
            while (!wav_process.isExiting)
            {
                //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 1");
                lock (wav_process.fnList)
                {
                    while (wav_process.fnList.Count > 0)
                    {
                        fnList.Enqueue(wav_process.fnList.Dequeue());
                    }                    
                }
                //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 2 " + fnList.Count.ToString());

                if (fnList.Count == 0)
                {
                    Thread.Sleep(500);
                }
                else
                {
                    while (fnList.Count > 0)
                    {
                        VR2WavProcessWrap wrap = fnList.Dequeue();
                        string fn1 = "";
                        string outfile = "";

                        Thread.Sleep(500); //Wait 500ms for host app(thread) to finishing writing wav and xml

                        //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 3 " + wrap.fn);

                        if (wrap.type == 0)
                        {
                            fn1 = wrap.fn;
                            goto encode_here;
                        }
                        if (wrap.type == 1)
                        {
                            if (wrap.fn.Contains(".wav"))
                                fn1 = wrap.fn.Replace(".wav", ".mp3");
                            else //already mp3
                            {
                                fn1 = wrap.fn;
                                goto encode_here;
                            }
                        }
                        else if (wrap.type == 2)
                            fn1 = wrap.fn.Replace(".wav", "_gsm.wav");
                        else if (wrap.type == 3)
                            fn1 = wrap.fn.Replace(".wav", ".wzp");
                        else
                            continue;

                        //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 4 " + fn1);

                        /*if (wrap.type == 1)
                        {
                            string tempPath = Application.StartupPath + "\\temp\\";

                            string fname = GetFileNameOnly(wrap.fn);
                            string fext = getFileExtension(wrap.fn);
                            string fnwav = tempPath + fname + "~" + fext;

                            try
                            {

                                using (WaveFileReader wfr = new WaveFileReader(wrap.fn))
                                {
                                    //env.LOG_Trace(1, "Wav2MP3 2");
                                    NAudio.Wave.WaveFormat newFormat = new NAudio.Wave.WaveFormat(16000, wfr.WaveFormat.BitsPerSample, wfr.WaveFormat.Channels);
                                    //env.LOG_Trace(1, "Wav2MP3 3");
                                    using (NAudio.Wave.WaveFileWriter wfw = new NAudio.Wave.WaveFileWriter(fnwav, newFormat))
                                    {
                                        //env.LOG_Trace(1, "Wav2MP3 4");
                                        using (NAudio.Wave.WaveFormatConversionStream conversionStream = new NAudio.Wave.WaveFormatConversionStream(newFormat, wfr))
                                        {
                                            //env.LOG_Trace(1, "Wav2MP3 5");
                                            conversionStream.Position = 0;
                                            byte[] buffer = new byte[1024];
                                            while (conversionStream.Position < conversionStream.Length)
                                            {
                                                //env.LOG_Trace(1, "Wav2MP3 6");
                                                int bytesRead = conversionStream.Read(buffer, 0, 1024);
                                                if (bytesRead > 0)
                                                {
                                                    wfw.Write(buffer, 0, bytesRead);
                                                }
                                                else
                                                {
                                                    break;
                                                }
                                            }
                                            wfw.Close();
                                            //env.LOG_Trace(1, "Wav2MP3 7");

                                        }
                                    }


                                }

                            }
                            catch (Exception)
                            {
                            }

                            //env.LOG_Trace(1, "Wav2MP3 8");

                            //if ( File.Exists(textBoxOutFile.Text) && (MessageBox.Show(this, "Override the existing file?", "File exists", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) )
                            //{
                            //    return;
                            //}
                            try
                            {
                                bool Compressing = true;
                                try
                                {
                                    //env.LOG_Trace(1, "Wav2MP3 9");

                                    WaveLib.WaveStream InStr = new WaveLib.WaveStream(fnwav);
                                    Yeti.MMedia.Mp3.Mp3WriterConfig m_Config = new Yeti.MMedia.Mp3.Mp3WriterConfig(InStr.Format); ;
                                    //env.LOG_Trace(1, "Wav2MP3 10");

                                    try
                                    {
                                        //env.LOG_Trace(1, "Wav2MP3 11");

                                        Yeti.MMedia.Mp3.Mp3Writer writer = new Yeti.MMedia.Mp3.Mp3Writer(new FileStream(fn1, FileMode.Create), m_Config);

                                        //env.LOG_Trace(1, "Wav2MP3 12");

                                        try
                                        {
                                            byte[] buff = new byte[writer.OptimalBufferSize];
                                            int read = 0;
                                            int actual = 0;
                                            //long total = InStr.Length;
                                            //Cursor.Current = Cursors.WaitCursor;
                                            try
                                            {
                                                //env.LOG_Trace(1, "Wav2MP3 13");

                                                while ((read = InStr.Read(buff, 0, buff.Length)) > 0)
                                                {
                                                    //Application.DoEvents();
                                                    writer.Write(buff, 0, read);
                                                    actual += read;
                                                    //progressBar.Value = (int)(((long)actual * 100) / total);
                                                    //toolTip1.SetToolTip(progressBar, string.Format("{0}% compresssed", progressBar.Value));
                                                    //this.Text = string.Format("Audio Compress - {0}% compresssed", progressBar.Value);
                                                    //Application.DoEvents();

                                                    //env.LOG_Trace(1, "Wav2MP3 14");

                                                }
                                                //toolTip1.SetToolTip(progressBar, "Done");
                                                //this.Text = "Audio Compress - Done";
                                            }
                                            finally
                                            {
                                                //Cursor.Current = Cursors.Default;
                                            }
                                        }
                                        finally
                                        {
                                            writer.Close();
                                            //env.LOG_Trace(1, "Wav2MP3 15");

                                        }
                                    }
                                    finally
                                    {
                                        InStr.Close();
                                        //env.LOG_Trace(1, "Wav2MP3 16");

                                    }
                                }
                                finally
                                {
                                    Compressing = false;
                                    //RefreshControls();
                                }
                            }
                            catch (Exception e1)
                            {
                                //LOG_Trace(1, "Wav2MP3 err:" + e1.ToString());
                            }

                            File.Delete(fnwav);
                            //env.LOG_Trace(1, "Wav2MP3 17");

                        }
                        else*/
                        if (wrap.type == 2 || wrap.type == 1)
                        {

                            if (wrap.type == 1)
                                outfile = "--preset phone \"" + wrap.fn + "\" \"" + fn1 + "\"";
                            //outfile = "\"" + wrap.fn + "\" \"" + fn1 + "\"";
                            else if (wrap.type == 2)
                                outfile = "\"" + wrap.fn + "\" -g \"" + fn1 + "\"";

                            //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 5 " + outfile);

                            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
                            if (wrap.type == 1)
                                psi.FileName = "\"" + Application.StartupPath + "\\lame.exe" + "\"";
                            else if (wrap.type == 2)
                                psi.FileName = "\"" + Application.StartupPath + "\\sox.exe" + "\"";

                            //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 6 " + psi.FileName);

                            psi.Arguments = outfile;

                            //psi.WorkingDirectory = Application.StartupPath; 
                            //psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                            psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized;
                            //psi.UseShellExecute = false;
                            //psi.CreateNoWindow = true;

                            //If you provide a value for the Password property, the UseShellExecute property must be false, 
                            //or an InvalidOperationException will be thrown when the Process.Start(ProcessStartInfo) method is called. 
                            if (VR2Main.MainObj.UserName.Length > 0 && VR2Main.MainObj.Password != null /*&& VR2Main.MainObj.Domain.Length > 0*/)
                            {
                                psi.UserName = VR2Main.MainObj.UserName;
                                psi.Password = VR2Main.MainObj.Password;
                                psi.Domain = VR2Main.MainObj.Domain;
                            }

                            try
                            {
                                System.Diagnostics.Process p = System.Diagnostics.Process.Start(psi);
                                //if (waitFlag)
                                p.WaitForExit(); // wait for exit of called application 
                                //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 7 ");
                            }
                            catch (Exception ex)
                            {
                                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                                continue;
                                //VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 8 ");
                            }
                        }
                        else if (wrap.type == 3)
                        {
                            GTAPIASM.GTEncode.FileEncode(wrap.fn, fn1);
                        }

                    encode_here:
                        if (wrap.encode == 1)
                        {
                            if (wrap.type == 0)
                            {
                                string fn2 = fn1.Replace(".wav", ".wzp");
                                GTAPIASM.GTEncode.FileEncode(fn1, fn2);
                                File.Delete(fn1);
                                fn1 = fn2;
                            }
                            else if (wrap.type == 1)
                            {
                                string fn2 = fn1.Replace(".mp3", ".mzp");
                                GTAPIASM.GTEncode.FileEncode(fn1, fn2);
                                File.Delete(fn1);
                                fn1 = fn2;
                            }
                            else if (wrap.type == 2)
                            {
                                string fn2 = fn1.Replace(".wav", ".wzp");
                                GTAPIASM.GTEncode.FileEncode(fn1, fn2);
                                File.Delete(fn1);
                                fn1 = fn2;
                            }
                            else if (wrap.type == 3)
                            {
                            }
                        }

                        if (File.Exists(fn1))
                        {
                            VRAPIASM.VRAPIEnv.Log(1, "VR2WavWorkProcess.Run 9 " + wrap.fn + "," + fn1);

                            //successfully converted
                            if(wrap.fn != fn1)
                                File.Delete(wrap.fn);

                            if (wrap.type == 1 || wrap.type == 2 || wrap.type == 3 || wrap.encode == 1) //mp3 or encode to wzp
                            {
                                try
                                {
                                    string xmlFileName = wrap.fn.Replace(".wav", ".xml");

                                    //In the IP recording. It is very possible that
                                    //when called IDLE event, the xml file is still not available.
                                    //So that's why here I put check and try
                                    //I have seen a couple of times crashing here:
                                    
                                    if (!File.Exists(xmlFileName))
                                    {
                                        Thread.Sleep(500);
                                        if (!File.Exists(xmlFileName))
                                        {
                                            Thread.Sleep(500);
                                            if (!File.Exists(xmlFileName))
                                            {
                                                Thread.Sleep(500);
                                                if (!File.Exists(xmlFileName))
                                                {
                                                    Thread.Sleep(500);
                                                }
                                            }
                                        }
                                    }
                                    XmlDocument xmlDoc = new XmlDocument();
                                    xmlDoc.Load(xmlFileName);
                                    XmlElement root = xmlDoc.DocumentElement;
                                    XmlNode tmpNode = root.SelectSingleNode("//CALL/RECORD/PATH");
                                    tmpNode.InnerText = fn1;
                                    xmlDoc.Save(xmlFileName);
                                }
                                catch (Exception ex)
                                {
                                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                                }
                            }

                        }
                    }
                }

            }

        }
    }

    public class RTPPBXExten
    {
        public string Name;
        public string Number;
        public string IPAddr;

        public RTPPBXExten()
        {
            Name = "";
            Number = "";
            IPAddr = "";
        }
    }

    public class IDMap
    {
        public string OrgID;
        public string RepID;
    }

    public class VR2Main
    {
        public int VRType;
        public string AudioRootFolder;
        public string AudioFileName;
        public int AudioFormat;
        public int AudioEncode;
        public string LogFileName;
        public short LogLevel;
        public string VoIPProtocol;
        public ushort VoIPPort;
        public string VoIPNIC;
        public string DumpFileName;
        public int PromiscuousMode;
        public int ChannelCount;
        public int[] DeviceType;
        public string VRLicKey;
        public string VRLicMAC;
        public Thread mainThread;
        public bool isExiting;
        public VR2Manager manager;
        public ushort managerPort;
        public static VR2Main MainObj;
        public Queue<VR2Event> event_queue;
        public VR2WavWorkProcess wav_work;
        public SamsungCDRProcess ss_cdr_work;

        public List<TAPICDR> TapiCalls;

        public int FilterType; //0 == IP Addr, 1 == ID, 2 == MAC Addr
        public string[] Filters;

        public int ExcludeType; //0 == IP Addr, 1 == ID, 2 == MAC Addr
        public string[] Excludes;

        public int EnableRTSrv;

        public string[] RTPPBX;
        public RTPPBXExten[] RTPExten;

        public bool IgnorePossibleSameCall;
        public bool Recording;
        public bool RecordCallLegs;
        public bool CreateXML;
        public bool UsePacketTime;
        public string RecordPauseKey;
        public int RecordPauseOpt;
        public bool RecordOnlyAfterAnswer;

        public int WriteCallPcapFile;

        public string SIPHeadersInXML;
        public string ExtenPattern;
        public bool RecordStereo;

        public int AddWavDateTime;
        public string AddWavDateTimeFmt;

        public int NoAudioSeconds;
        public int KeepRecordMaxDays;
        public int FIFOSpaceInMB;

        public string TAPIMonitorLines;
        public int TAPIRestartHours;
        public int TAPIIsClosing;

        public int MaxWavSeconds;

        //Credential
        public string UserName;
        public SecureString Password;
        public string Domain;

        public VRAPIASM.VRAPIEnv.VR_CB_Call_Offered m_pCallOffered;
        public VRAPIASM.VRAPIEnv.VR_CB_Call_Connected m_pCallConnected;
        public VRAPIASM.VRAPIEnv.VR_CB_Call_Idle m_pCallIdle;
        public VRAPIASM.VRAPIEnv.VR_CB_Call_DTMF m_pCallDTMF;
        public VRAPIASM.VRAPIEnv.VR_CB_Fatal_Error m_pFatalError;
        public VRAPIASM.VRAPIEnv.VR_CB_Set_ChanName m_pSetChanName;
        public VRAPIASM.VRAPIEnv.VR_CB_Call_Info m_pCallInfo;
        public VRAPIASM.VRAPIEnv.VR_CB_Call_SIP_Info m_pCallSIPInfo;

        public VRAPIASM.VRAPIEnv.VR_CB_Call_Offered m_pCallOffered1;

        public VRAPIASM.VRAPIEnv.VR_CB_GetWavFileName m_pGetWavFileName;


        public int MaxChanNum;
        public VR2Channel[] Channels;

        public DBServerSetting db_set;

        public EmailServerSetting email_set;
        public string[] emails;
        public string[] NotifyRecordingEmails;
        public string NotifyRecordingScript;
        public string NotifyXMLServiceURI;

        public IDMap[] idMaps;

        public string SamsungPBXCDRIP;
        public ushort SamsungPBXCDRPort;

        public string BIBRecordingTrunk;
        public string BIBIncomingTrunk;
        public string BIBOutgoingTrunk;

        public bool updateChanStatusToDB;

        public int TimerCount;
        public int minuteCount;
        public int tapiCount;

        public int totalCallCount; //total invite for new calls, but removed 401 & 407
        public int succCallCount;  //total succussfully finished call, no matter it is connected or not
        public int connCallCount;  //total connacted call count
        public int failedCallCount; //failed call count

        public VR2Main()
        {
            VRType = 0;
            AudioRootFolder = Application.StartupPath + "\\Records\\";
            AudioFileName = "";
            AudioFormat = 0;
            AudioEncode = 0;
            LogFileName = Application.StartupPath + "\\vr2.log";
            LogLevel = 0;
            DeviceType = new int[10];
            for (int i = 0; i < 10; i++)
            {
                DeviceType[i] = -1;
            }
            mainThread = new Thread(Run);
            isExiting = false;
            managerPort = 1376;
            VRLicKey = "";
            VRLicMAC = "";
            VoIPProtocol = "SIP";
            VoIPPort = 0;
            VoIPNIC = "";
            PromiscuousMode = 1;
            DumpFileName = "";

            MainObj = this;

            event_queue = new Queue<VR2Event>();
            TapiCalls = new List<TAPICDR>();

            manager = null;

            FilterType = 0;
            Filters = null;

            ExcludeType = 0;
            Excludes = null;

            EnableRTSrv = 0;

            RTPPBX = null;
            RTPExten = null;

            IgnorePossibleSameCall = false;
            Recording = true;
            RecordCallLegs = false;
            CreateXML = true;
            UsePacketTime = false;

            RecordStereo = false;

            AddWavDateTime = 1;
            AddWavDateTimeFmt = "";

        RecordPauseKey = "";
            RecordPauseOpt = 0;

            SIPHeadersInXML = "";
            ExtenPattern = "";

            RecordOnlyAfterAnswer = false;

            NoAudioSeconds = 0;
            KeepRecordMaxDays = 0;
            FIFOSpaceInMB = 0;

            UserName = "";
            Password = null;
            Domain = "";

            TAPIMonitorLines = "";
            TAPIRestartHours = 0;
            TAPIIsClosing = 0;

            MaxWavSeconds = 3600 * 12;

            m_pCallOffered = new VRAPIASM.VRAPIEnv.VR_CB_Call_Offered(cbCallOffered);
            m_pCallConnected = new VRAPIASM.VRAPIEnv.VR_CB_Call_Connected(cbCallConnected);
            m_pCallIdle = new VRAPIASM.VRAPIEnv.VR_CB_Call_Idle(cbCallIdle);
            m_pCallDTMF = new VRAPIASM.VRAPIEnv.VR_CB_Call_DTMF(cbCallDTMF);
            m_pFatalError = new VRAPIASM.VRAPIEnv.VR_CB_Fatal_Error(cbFatalError);
            m_pSetChanName = new VRAPIASM.VRAPIEnv.VR_CB_Set_ChanName(cbSetChanName);
            m_pCallInfo = new VRAPIASM.VRAPIEnv.VR_CB_Call_Info(cbCallInfo);
            m_pCallSIPInfo = new VRAPIASM.VRAPIEnv.VR_CB_Call_SIP_Info(cbCallSIPInfo);
            m_pGetWavFileName = new VRAPIASM.VRAPIEnv.VR_CB_GetWavFileName(cbGetWavFileName);

            m_pCallOffered1 = null;

            MaxChanNum = 0;
            Channels = null;

            db_set = null;
            email_set = new EmailServerSetting();

            idMaps = null;

            SamsungPBXCDRIP = "";
            SamsungPBXCDRPort = 0;

            updateChanStatusToDB = false;

            TimerCount = 0;
            minuteCount = 0;
            tapiCount = 0;

            Directory.CreateDirectory(Application.StartupPath + "\\temp\\");

            wav_work = new VR2WavWorkProcess();
            ss_cdr_work = new SamsungCDRProcess();

            totalCallCount = 0;
            succCallCount = 0;
            connCallCount = 0;

            NotifyRecordingScript = "";
            NotifyXMLServiceURI = "";
        }

        ~VR2Main()
        {
            MainObj = null;
        }

        static void Run(object obj)
        {
            VR2Main host = (VR2Main)obj;

            while (!host.isExiting)
            {
                host.timerTick();
                Thread.Sleep(200);
            }

        }

        public void StartManager()
        {
            manager = new VR2Manager(this);
            manager.Start(managerPort, "", 200);

            if(IsLicensed())
                ss_cdr_work.vr2m = manager;
        }

        public void StopManager()
        {
            manager.Stop();
            manager = null;
        }

        public void EverySecondProcess()
        {
            if (SamsungPBXCDRIP.Length > 0 && SamsungPBXCDRPort > 0)
            {
                if (!isExiting && ss_cdr_work.isExiting)
                {
                    ss_cdr_work.StopProcess();
                    Thread.Sleep(500);
                    ss_cdr_work.StartProcess();
                }
            }

        }

        public void Every5SecondsProcess()
        {
            if (SamsungPBXCDRIP.Length > 0 && SamsungPBXCDRPort > 0)
            {
                lock (ss_cdr_work)
                {
                    bool opt;

                    do
                    {
                        opt = false;
                        foreach (SamsungCDR cdr in ss_cdr_work.cdrList)
                        {
                            TimeSpan ts = DateTime.Now - cdr.ReceivedTime;

                            if (ts.TotalSeconds > 60)
                            {
                                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::Every2SecondsProcess remove " + cdr.EXT + " " + cdr.FG + " " + cdr.DIALED_DIGIT + " from Samsung cdr list.");
                                ss_cdr_work.cdrList.Remove(cdr);
                                opt = true;
                                break;
                            }

                        }
                    } while (opt);
                }
            }
        }

        public void Every2SecondsProcess()
        {
            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main::Every2SecondsProcess enter");
            if (db_set == null || !updateChanStatusToDB)
                return;

            //in the case that DB is down and can't be accessed, this attempt to connection will really take
            //long time(20 seconds), so the GUI is frozen. The best way is to jsut give up.
            if (!db_set.IsDBConnected())
                return;

            string sqlstr = "";

            lock (this)
            {
                for (int i = 0; i < MaxChanNum; i++)
                {
                    VR2Channel chan = Channels[i];
                    if (chan.ModTag && updateChanStatusToDB)
                    {
                        try
                        {
                            sqlstr += UpdateChannelToDB(chan);
                        }
                        catch (Exception ex)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                        }
                    }
                }

                if (sqlstr.Length > 0) //not empty string
                {
                    try
                    {
                        SqlCommand catCMD = db_set.myConn.CreateCommand();
                        catCMD.CommandTimeout = 3;
                        catCMD.CommandText = sqlstr;
                        if (catCMD.ExecuteNonQuery() == 1)
                        {
                        }
                    }
                    catch (Exception ex)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "SQL:" + sqlstr);
                        VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                        return;
                    }
                }
            }
            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main::Every2SecondsProcess leave");
        }

        public void EveryMinuteProcess()
        {
            minuteCount++;

            if (minuteCount % 60 == 0)
            {
                //every hour
                VRAPIASM.VRAPIEnv.Log(4, "Memory used before collection: " + GC.GetTotalMemory(false).ToString());
                GC.Collect();
                VRAPIASM.VRAPIEnv.Log(4, "Memory used after full collection: " + GC.GetTotalMemory(false).ToString());

                if (TAPIRestartHours > 0)
                {
                    tapiCount++;
                    if (tapiCount == TAPIRestartHours)
                    {
                        tapiCount = 0;
                        RestartTAPIConnection();
                    }
                }
            }

            if(minuteCount % (60 * 24) == 0)
            {
                ////////////////////////////////////////
                //One day
                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::EveryMinuteProcess everyday enter"); 
                
                CleanUpDB();

                minuteCount = 0;

                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::EveryMinuteProcess everyday leave");
            }

            lock (TapiCalls)
            {
                //First trying to find out if there is a call like that already in the cdr list

                bool opt;

                do
                {
                    opt = false;
                    foreach (TAPICDR cdr in TapiCalls)
                    {
                        TimeSpan ts = DateTime.Now - cdr.CallEndTime;
                        if (cdr.CallDone)
                        {
                            if (ts.TotalMinutes >= 2)
                            {
                                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::EveryMinuteProcess remove " + cdr.CallerID + " " + cdr.CalledID + " " + cdr.UniqueID + " from TAPI cdr list.");
                                TapiCalls.Remove(cdr);
                                opt = true;
                                break;
                            }
                        }
                        else if(ts.TotalHours >= 12) //12 hours not closing, dead calls, remove it from list
                        {
                            VRAPIASM.VRAPIEnv.Log(1, "VR2Main::EveryMinuteProcess remove " + cdr.CallerID + " " + cdr.CalledID + " " + cdr.UniqueID + " from TAPI cdr list because it has been 12 hours in list.");
                            TapiCalls.Remove(cdr);
                            opt = true;
                            break;
                        }
                    }
                } while (opt);

                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::EveryMinuteProcess TAPI List Size: " + TapiCalls.Count.ToString());
            }
        }

        private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 
     
        public static DateTime UnixTimeToDateTime(string text) 
        { 
            double seconds = double.Parse(text, CultureInfo.InvariantCulture); 
            return Epoch.AddSeconds(seconds).ToLocalTime(); 
        }

        public bool PatternMatch(string pattern, string s1)
        {
            int idx = 0;
            int j = 0;
            for (j = 0; j < s1.Length && idx < pattern.Length; j++)
            {
                if (pattern[idx] == '*')
                {
                    if (idx < pattern.Length - 1)
                    {
                        if (s1[j] != pattern[idx + 1])
                        {
                            continue;
                        }
                        else
                        {
                            idx += 2;
                            continue;
                        }
                    }
                    else
                        return true;
                }
                else if (pattern[idx] == '?')
                {
                    idx++;
                    continue;
                }
                else
                {
                    if (s1[j] != pattern[idx])
                    {
                        return false;
                    }
                    else
                    {
                        idx++;
                    }
                }
            }

            if (j == s1.Length && idx == pattern.Length)
                return true;
            else
                return false;

        }

        public bool IsExtension(string addr)
        {
            string extn = "";

            if (addr == "PBX") return false;

            if (addr.Contains("sip:"))
            {
                //it is a sip address
                extn = GTAPIASM.GTAPIEnv.GetSIPAddressInfo(1, addr);
            }
            else
            {
                if (addr.IndexOf("DCS Line ") == 0)
                    extn = addr.Substring(9);
                else
                    extn = addr;
            }

            char[] delimiters = new char[] { ';', ',', '|', ' ' };
            string[] Patterns = ExtenPattern.Split(delimiters, StringSplitOptions.None);

            foreach (string pt in Patterns)
            {
                if (PatternMatch(pt, extn))
                    return true;
            }

            return false;
        }

        public bool CorrectSamsungCDRCallInfo(int evt, int ChanIndex, ref string CallerIP, ref string CallerID, ref string CalleeIP, ref string CalleeID, string UniqueID, ref int CallDir)
        {
            bool ret = false;
            if (SamsungPBXCDRIP.Length > 0 && SamsungPBXCDRPort > 0)
            {
                lock (ss_cdr_work)
                {
                    if (ss_cdr_work.cdrList.Count > 0)
                    {
                        for (int i = ss_cdr_work.cdrList.Count - 1; i >= 0; i--)
                        {
                            SamsungCDR cdr = ss_cdr_work.cdrList[i];

                            if (cdr.FG[0] == 'I' || cdr.FG[0] == 'A')
                            {
                                if (cdr.EXT == CallerID)
                                {
                                    CallerID = cdr.CLIP_NUMBER; // cdr.CLIP_NAME + "<sip:" + cdr.CLIP_NUMBER + "@" + CallerIP + ">";
                                    CalleeID = cdr.EXT; // cdr.DIALED_DIGIT + "<sip:" + cdr.EXT + "@" + CalleeIP + ">";
                                    CallDir = 0;
                                    ret = true;
                                    VRAPIASM.VRAPIEnv.Log(4, "CorrectSamsungCDRCallInfo corrected incoming call1:" + CallerID + " " + CalleeID);
                                    break;
                                }
                                else if (cdr.EXT == CalleeID)
                                {
                                    CallerID = cdr.CLIP_NUMBER; //cdr.CLIP_NAME + "<sip:" + cdr.CLIP_NUMBER + "@" + CalleeIP + ">";
                                    CalleeID = cdr.EXT; // cdr.DIALED_DIGIT + "<sip:" + cdr.EXT + "@" + CallerIP + ">";
                                    CallDir = 0;
                                    ret = true;
                                    VRAPIASM.VRAPIEnv.Log(4, "CorrectSamsungCDRCallInfo corrected incoming call2:" + CallerID + " " + CalleeID);
                                    break;
                                }
                            }
                            else if (cdr.FG[0] == 'O')
                            {
                                if (cdr.EXT == CallerID)
                                {
                                    CallerID = cdr.EXT; // "<sip:" + cdr.EXT + "@" + CallerIP + ">";
                                    CalleeID = cdr.DIALED_DIGIT; // cdr.DIALED_DIGIT + "<sip:" + cdr.DIALED_DIGIT + "@" + CalleeIP + ">";
                                    CallDir = 1;
                                    ret = true;
                                    VRAPIASM.VRAPIEnv.Log(4, "CorrectSamsungCDRCallInfo corrected outgoing call1:" + CallerID + " " + CalleeID);
                                    break;
                                }
                                else if (cdr.EXT == CalleeID)
                                {
                                    CallerID = cdr.EXT; // "<sip:" + cdr.EXT + "@" + CalleeIP + ">";
                                    CalleeID = cdr.DIALED_DIGIT; // cdr.DIALED_DIGIT + "<sip:" + cdr.DIALED_DIGIT + "@" + CallerIP + ">";
                                    CallDir = 1;
                                    ret = true;
                                    VRAPIASM.VRAPIEnv.Log(4, "CorrectSamsungCDRCallInfo corrected outgoing call2:" + CallerID + " " + CalleeID);
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            return ret;
        }

        public bool CorrectTAPICallInfo(int evt, int ChanIndex, ref string CallerIP, ref string CallerID, ref string CalleeIP, ref string CalleeID, string UniqueID, ref int CallDir)
        {
            bool ret = false;
            RTPPBXExten rtpCallerExten = null;
            RTPPBXExten rtpCalleeExten = null;

            string keyInfo1 = "";
            string keyInfo2 = "";
            
            if(CallerID == "PBX" && CalleeID != "PBX") keyInfo2 = CalleeID;
            if(CallerID != "PBX" && CalleeID == "PBX") keyInfo1 = CallerID;

            if (CallerID.Contains("sip:")) keyInfo1 = GTAPIASM.GTAPIEnv.GetSIPAddressInfo(1, CallerID);
            if (CalleeID.Contains("sip:")) keyInfo2 = GTAPIASM.GTAPIEnv.GetSIPAddressInfo(1, CalleeID);

            VRAPIASM.VRAPIEnv.Log(4, "CorrectTAPICallInfo keyInfo1: " + keyInfo1 + " keyInfo2: " + keyInfo2);

            if (keyInfo1 == "" && keyInfo2 == "") return ret;

            //Need to find out the correct RTP info for the call, then use it when correcting it
            if(RTPExten != null)
            {
                foreach(RTPPBXExten extn in RTPExten)
                {
                    if(extn.Number == keyInfo1)
                    {
                        rtpCallerExten = extn;
                    }
                    else if(extn.Number == keyInfo2)
                    {
                        rtpCalleeExten = extn;
                        break;
                    }
                }
            }


            int runcnt = 0;
            bool corrected = false;

            lock (TapiCalls)
            {
                //if (evt == 0) //call offered
                {
                    VRAPIASM.VRAPIEnv.Log(4, "CorrectTAPICallInfo TapiCalls.Count: " + TapiCalls.Count);

                run_again:
                    foreach (TAPICDR cdr in TapiCalls)
                    {

                        VRAPIASM.VRAPIEnv.Log(4, "CorrectTAPICallInfo cdr: uniqueid(" + cdr.UniqueID + ") guid(" + cdr.CallGuid + ") CallerID(" + cdr.CallerID + ") CalledID(" + cdr.CalledID + ") done:" + cdr.CallDone.ToString());

                        //skip the cdr which has done in the first round
                        if (runcnt == 0 && cdr.CallDone /*&& (evt == 0 || evt == 1)*/) continue; 

                        if (cdr.UniqueID == UniqueID)
                        {
                            if (cdr.CallerID.Length > 0 && cdr.CallerID != "Unavail")
                                CallerID = cdr.CallerID;

                            if (cdr.CalledID.Length > 0 && cdr.CalledID != "Unavail")
                                CalleeID = cdr.CalledID;

                            if (IsExtension(CallerID) && IsExtension(CalleeID))
                                CallDir = 2;
                            else
                                CallDir = cdr.CallDir;

                            VRAPIASM.VRAPIEnv.Log(4, "Matched Call Corrected: " + CallerID + " " + CalleeID + " " + CallDir.ToString() + " event id: " + evt.ToString());

                            ret = corrected = true;

                            break;
                        }
                    }

                    if (keyInfo1.Length > 0 && !corrected)
                    {
                        foreach (TAPICDR cdr in TapiCalls)
                        {
                            //skip the cdr which has done in the first round
                            if (runcnt == 0 && cdr.CallDone /*&& (evt == 0 || evt == 1)*/) continue; 

                            TimeSpan ts1 = DateTime.Now - cdr.CallConnectedTime;
                            TimeSpan ts2 = DateTime.Now - cdr.CallStartTime;

                            if (/*(ts1.TotalSeconds < 2 || ts2.TotalSeconds < 2) &&*/ (cdr.CallerID.Contains(keyInfo1) || cdr.CalledID.Contains(keyInfo1)))
                            {
                                //the correct match
                                cdr.UniqueID = UniqueID;

                                if (cdr.CallerID.Contains(keyInfo1))
                                {
                                    if (rtpCallerExten != null)
                                    {
                                        CallerID = rtpCallerExten.Name + "<sip:" + rtpCallerExten.Number + "@" + rtpCallerExten.IPAddr + ">";
                                        VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR Caller ID updated from " + cdr.CallerID + " to " + CallerID + " in event id: " + evt.ToString());
                                        cdr.CallerID = CallerID;
                                    }
                                    else
                                    {
                                        if (cdr.CallerID.Length > 0 && cdr.CallerID != "Unavail")
                                            CallerID = cdr.CallerID;
                                    }
                                }
                                else
                                {
                                    if (cdr.CallerID.Length > 0 && cdr.CallerID != "Unavail")
                                        CallerID = cdr.CallerID;
                                }

                                if (cdr.CalledID.Contains(keyInfo1))
                                {
                                    if (rtpCallerExten != null)
                                    {
                                        CalleeID = rtpCallerExten.Name + "<sip:" + rtpCallerExten.Number + "@" + rtpCallerExten.IPAddr + ">";
                                        VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR Callee ID updated from " + cdr.CalledID + " to " + CalleeID + " in event id: " + evt.ToString());
                                        cdr.CalledID = CalleeID;
                                    }
                                    else
                                    {
                                        if (cdr.CalledID.Length > 0 && cdr.CalledID != "Unavail")
                                            CalleeID = cdr.CalledID;
                                    }
                                }
                                else
                                {
                                    if (cdr.CalledID.Length > 0 && cdr.CalledID != "Unavail")
                                        CalleeID = cdr.CalledID; //maybe here should keep original keyInfo2 if it is sip calls
                                }

                                if (IsExtension(CallerID) && IsExtension(CalleeID))
                                    CallDir = 2;
                                else
                                    CallDir = cdr.CallDir;

                                VRAPIASM.VRAPIEnv.Log(4, "Found Call Corrected: " + CallerID + " " + CalleeID + " " + CallDir.ToString() + " event id: " + evt.ToString());

                                ret = corrected = true;

                                break;
                            }

                        }
                    }

                    if (keyInfo2.Length > 0 && !corrected)
                    {
                        foreach (TAPICDR cdr in TapiCalls)
                        {
                            //skip the cdr which has done in the first round
                            if (runcnt == 0 && cdr.CallDone /*&& (evt == 0 || evt == 1)*/) continue; 

                            TimeSpan ts1 = DateTime.Now - cdr.CallConnectedTime;
                            TimeSpan ts2 = DateTime.Now - cdr.CallStartTime;

                            if (/*(ts1.TotalSeconds < 2 || ts2.TotalSeconds < 2) &&*/ (cdr.CallerID.Contains(keyInfo2) || cdr.CalledID.Contains(keyInfo2)))
                            {
                                //the correct match
                                cdr.UniqueID = UniqueID;

                                if (cdr.CallerID.Contains(keyInfo2))
                                {
                                    if (rtpCalleeExten != null)
                                    {
                                        CallerID = rtpCalleeExten.Name + "<sip:" + rtpCalleeExten.Number + "@" + rtpCalleeExten.IPAddr + ">";
                                        VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR Caller ID updated from " + cdr.CallerID + " to " + CallerID + " in event id: " + evt.ToString());
                                        cdr.CallerID = CallerID;
                                    }
                                    else
                                    {
                                        if (cdr.CallerID.Length > 0 && cdr.CallerID != "Unavail")
                                            CallerID = cdr.CallerID;
                                    }
                                }
                                else
                                {
                                    if (cdr.CallerID.Length > 0 && cdr.CallerID != "Unavail")
                                        CallerID = cdr.CallerID;
                                }

                                if (cdr.CalledID.Contains(keyInfo2))
                                {
                                    if (rtpCalleeExten != null)
                                    {
                                        CalleeID = rtpCalleeExten.Name + "<sip:" + rtpCalleeExten.Number + "@" + rtpCalleeExten.IPAddr + ">";
                                        VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR Called ID updated from " + cdr.CalledID + " to " + CalleeID + " in event id: " + evt.ToString());
                                        cdr.CalledID = CalleeID;
                                    }
                                    else
                                    {
                                        if (cdr.CalledID.Length > 0 && cdr.CalledID != "Unavail")
                                            CalleeID = cdr.CalledID;
                                    }
                                }
                                else
                                {
                                    if (cdr.CalledID.Length > 0 && cdr.CalledID != "Unavail")
                                        CalleeID = cdr.CalledID; //maybe here should keep original keyInfo2 if it is sip calls
                                }

                                if (IsExtension(CallerID) && IsExtension(CalleeID))
                                    CallDir = 2;
                                else
                                    CallDir = cdr.CallDir;

                                VRAPIASM.VRAPIEnv.Log(4, "Found Call Corrected: " + CallerID + " " + CalleeID + " " + CallDir.ToString() + " in event id: " + evt.ToString());

                                ret = corrected = true;

                                break;
                            }

                        }
                    }

                    //skip the cdr which has done in the first round
                    if (runcnt == 0 && !corrected /*&& (evt == 0 || evt == 1)*/)
                    {
                        runcnt = 1;
                        goto run_again;
                    }
                }

            }

            return ret;
        }

        public string postXMLData(string destinationUrl, XmlDocument Sendingxml)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(destinationUrl);
            byte[] bytes;
            bytes = System.Text.Encoding.UTF8.GetBytes(Sendingxml.ToString());
            request.ContentType = "text/xml; encoding=utf-8";
            request.ContentLength = bytes.Length;
            request.Method = "POST";
            request.Timeout = 60000; //6 seconds
            Stream requestStream = request.GetRequestStream();
            requestStream.Write(bytes, 0, bytes.Length);
            requestStream.Close();
            HttpWebResponse response;
            response = (HttpWebResponse)request.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                Stream responseStream = response.GetResponseStream();
                string responseStr = new StreamReader(responseStream).ReadToEnd();
                return responseStr;
            }
            return null;
        }

        public static void postXMLAndAudioFile(string destinationUrl, string audioFilePath, string caller, string called, string dateOfCall, int duration, string xmlFilePath)
        {
            //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 1");

            // Create a new instance of HttpClient
            using (HttpClient httpClient = new HttpClient())
            {
                // Create a new instance of MultipartFormDataContent
                using (MultipartFormDataContent content = new MultipartFormDataContent())
                {
                    //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 2");

                    // Read the audio file into a byte array
                    byte[] fileBytes = File.ReadAllBytes(audioFilePath);

                    // Create a ByteArrayContent from the byte array
                    var fileContent = new ByteArrayContent(fileBytes);

                    //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 2-1");

                    // Add the ByteArrayContent to the MultipartFormDataContent with a specific name
                    content.Add(fileContent, "audio", Path.GetFileName(audioFilePath));

                    // Add caller information
                    content.Add(new StringContent(caller), "caller");

                    //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 2-2");

                    // Add called information
                    content.Add(new StringContent(called), "called");

                    //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 2-3");

                    // Add date of call information
                    content.Add(new StringContent(dateOfCall), "time");

                    //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 2-4");

                    // Add date of call information
                    content.Add(new StringContent(duration.ToString()), "duration");

                    //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 2-5");

                    // Read the XML file into a byte array
                    byte[] xmlFileBytes = File.ReadAllBytes(xmlFilePath);

                    // Create a ByteArrayContent from the byte array
                    var xmlFileContent = new ByteArrayContent(xmlFileBytes);

                    // Add the XML ByteArrayContent to the MultipartFormDataContent with a specific name
                    content.Add(xmlFileContent, "xml", Path.GetFileName(xmlFilePath));

                    try
                    {
                        //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 3");

                        HttpResponseMessage response = httpClient.PostAsync(destinationUrl, content).Result;

                        //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 4");

                        // Ensure the response is successful
                        response.EnsureSuccessStatusCode();

                       // VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 5");

                        // Read the response content synchronously
                        string responseBody = response.Content.ReadAsStringAsync().Result;

                        //VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 6 " + responseBody);

                        // Output the response
                        VRAPIASM.VRAPIEnv.Log(4, "Post[" + destinationUrl + "] Response: " + responseBody);
                    }
                    catch (HttpRequestException e)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, destinationUrl + " failed: " + e.Message);
                    }

                    /*
                    // Make a POST request to the RESTful API endpoint
                    using (var response = await httpClient.PostAsync(destinationUrl, content))
                    {
                        VRAPIASM.VRAPIEnv.Log(4, "postXMLAndAudioFile 3");

                        // Check if the request was successful
                        if (response.IsSuccessStatusCode)
                        {
                            // Read and display the response from the API
                            string apiResponse = await response.Content.ReadAsStringAsync();

                            VRAPIASM.VRAPIEnv.Log(4, destinationUrl + " Response: " + apiResponse);
                        }
                        else
                        {
                            // Display error message if request was not successful
                            VRAPIASM.VRAPIEnv.Log(4, destinationUrl + " Failed: " + response.StatusCode);
                        }
                    }*/
                }
            }
        }

        public void SendEmailRecordingNotify(VR2Channel chan, int wt)
        {
            //email notify, or/and script notify

            VRAPIASM.VRAPIEnv.Log(4, "Notification URI:[" + NotifyXMLServiceURI + "] Notification Script:[" + NotifyRecordingScript + "]");

            if (email_set.emailAddr.Length > 0 && email_set.emailServer.Length > 0 && NotifyRecordingEmails.Length > 0)
            {
                try
                {
                    MailMessage myMail = new MailMessage(email_set.emailAddr, email_set.emailAddr);
                    myMail.Subject = "VoIP Recorder V2 Recording Notification";

                    myMail.Body = "Caller: " + chan.CallerID + "\r\n";
                    myMail.Body += "Called: " + chan.CalleeID + "\r\n";
                    myMail.Body += "Start: " + chan.InitTime + "\r\n";
                    myMail.Body += "Connect: " + chan.ConnectTime + "\r\n";
                    myMail.Body += "End: " + chan.EndTime + "\r\n";
                    myMail.Body += "DTMF: " + chan.DTMFStr + "\r\n";

                    for (int i = 0; i < NotifyRecordingEmails.Length; i++)
                    {
                        MailAddress bcc = new MailAddress(NotifyRecordingEmails[i]);
                        myMail.Bcc.Add(bcc);
                    }

                    if (wt == 1)
                    {
                        int lpcnt = 0;
                        while (!File.Exists(chan.AudioFile) && lpcnt < 3)
                        {
                            Thread.Sleep(2000);
                            lpcnt++;
                        }
                    }

                    if (File.Exists(chan.AudioFile))
                        myMail.Attachments.Add(new Attachment(chan.AudioFile));

                    SmtpClient smtp_client = new SmtpClient(email_set.emailServer, email_set.emailPort);

                    smtp_client.UseDefaultCredentials = false;
                    smtp_client.Credentials = new NetworkCredential(email_set.emailAddr, email_set.emailPassword);
                    smtp_client.EnableSsl = email_set.emailSSL;

                    // Set the method that is called back when the send operation ends.
                    smtp_client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);


                    //string userState = "test message1";
                    smtp_client.SendAsync(myMail, this);
                }
                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.Message);
                }

            }

            if (NotifyRecordingScript.Length > 0)
            {
                //VRAPIASM.VRAPIEnv.Log(4, "SendEmailRecordingNotify 2");

                if (wt == 1)
                {
                    int lpcnt = 0;
                    while (!File.Exists(chan.AudioFile) && lpcnt < 3)
                    {
                        Thread.Sleep(2000);
                        lpcnt++;
                    }
                }

                String xmlDoc = "";

                try
                {
                    if (chan.AudioFile.Contains(".wav"))
                        xmlDoc = chan.AudioFile.Replace(".wav", ".xml");
                    else if (chan.AudioFile.Contains(".mp3"))
                        xmlDoc = chan.AudioFile.Replace(".mp3", ".xml");
                    else if (chan.AudioFile.Contains(".raw"))
                        xmlDoc = chan.AudioFile.Replace(".raw", ".xml");
                    else if (chan.AudioFile.Contains(".au"))
                        xmlDoc = chan.AudioFile.Replace(".au", ".xml");
                    else
                        xmlDoc = chan.AudioFile + ".xml";

                    if (wt == 1)
                    {
                        int lpcnt = 0;
                        while (!File.Exists(xmlDoc) && lpcnt < 3)
                        {
                            Thread.Sleep(2000);
                            lpcnt++;
                        }
                    }

                    System.Diagnostics.Process process = new System.Diagnostics.Process();
                    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();

                    bool bScript = false;

                    if (NotifyRecordingScript.ToLower().EndsWith(".py"))
                    {
                        startInfo.FileName = "python.exe";
                        bScript = true;
                    }
                    else if (NotifyRecordingScript.ToLower().EndsWith(".php"))
                    {
                        startInfo.FileName = "php";
                        bScript = true;
                    }
                    else if (NotifyRecordingScript.ToLower().EndsWith(".pl"))
                    {
                        startInfo.FileName = "perl";
                        bScript = true;
                    }
                    else if (NotifyRecordingScript.ToLower().EndsWith(".js"))
                    {
                        startInfo.FileName = "node";
                        bScript = true;
                    }
                    else if (NotifyRecordingScript.ToLower().EndsWith(".rb"))
                    {
                        startInfo.FileName = "ruby";
                        bScript = true;
                    }
                    else if (NotifyRecordingScript.ToLower().EndsWith(".lua"))
                    {
                        startInfo.FileName = "lua";
                        bScript = true;
                    }
                    else if (NotifyRecordingScript.ToLower().EndsWith(".tcl"))
                    {
                        startInfo.FileName = "tclsh";
                        bScript = true;
                    }
                    else if (NotifyRecordingScript.ToLower().EndsWith(".exe") || NotifyRecordingScript.ToLower().EndsWith(".bat") || NotifyRecordingScript.ToLower().EndsWith(".vbs") || NotifyRecordingScript.ToLower().EndsWith(".ps1"))
                    {
                        startInfo.FileName = NotifyRecordingScript;
                        bScript = false;
                    }
                    else
                    {
                        startInfo.FileName = NotifyRecordingScript;
                        bScript = false;
                    }

                    if (bScript)
                        startInfo.Arguments = "\"" + NotifyRecordingScript + "\" \"" + GTAPIASM.GTAPIEnv.GetSIPAddressInfo(1, chan.CallerID) + "\" \"" + GTAPIASM.GTAPIEnv.GetSIPAddressInfo(1, chan.CalleeID) + "\" \"" + chan.ConnectTime.ToString("yyyy-MM-dd HH:mm:ss") + "\" \"" + chan.EndTime.ToString("yyyy-MM-dd HH:mm:ss") + "\" \"" + chan.AudioFile + "\" \"" + xmlDoc + "\"";
                    else
                        startInfo.Arguments = "\"" + GTAPIASM.GTAPIEnv.GetSIPAddressInfo(1, chan.CallerID) + "\" \"" + GTAPIASM.GTAPIEnv.GetSIPAddressInfo(1, chan.CalleeID) + "\" \"" + chan.ConnectTime.ToString("yyyy-MM-dd HH:mm:ss") + "\" \"" + chan.EndTime.ToString("yyyy-MM-dd HH:mm:ss") + "\" \"" + chan.AudioFile + "\" \"" + xmlDoc + "\"";

                    startInfo.UseShellExecute = false;  // Do not use the operating system shell to start the process
                    startInfo.RedirectStandardOutput = true; // Redirect standard output for reading
                    startInfo.RedirectStandardError = true;  // Redirect standard error for reading
                    startInfo.CreateNoWindow = true;    // Do not create a new window
                    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

                    process.StartInfo = startInfo;
                    process.Start();

                    // Read the standard output and error
                    string output = process.StandardOutput.ReadToEnd();
                    string error = process.StandardError.ReadToEnd();

                    process.WaitForExit();

                    // Output the results
                    VRAPIASM.VRAPIEnv.Log(4, "Running Script Output:" + output);

                    if (!string.IsNullOrEmpty(error))
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "Error:" + error);
                    }
                }
                catch(Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.Message);
                }
            }

            if (NotifyXMLServiceURI.Length > 0)
            {
                //VRAPIASM.VRAPIEnv.Log(4, "SendEmailRecordingNotify 3");

                if (wt == 1)
                {
                    int lpcnt = 0;
                    while (!File.Exists(chan.AudioFile) && lpcnt < 3)
                    {
                        Thread.Sleep(2000);
                        lpcnt++;
                    }
                }

                /*XmlDocument xmlDoc = new XmlDocument();

                try
                {
                    if(chan.AudioFile.Contains(".wav"))
                        xmlDoc.Load(chan.AudioFile.Replace(".wav", ".xml"));
                    else if(chan.AudioFile.Contains(".mp3"))
                        xmlDoc.Load(chan.AudioFile.Replace(".mp3", ".xml"));
                    else if(chan.AudioFile.Contains(".raw"))
                        xmlDoc.Load(chan.AudioFile.Replace(".raw", ".xml"));
                    else if(chan.AudioFile.Contains(".au"))
                        xmlDoc.Load(chan.AudioFile.Replace(".au", ".xml"));
                    else
                        xmlDoc.Load(chan.AudioFile + ".xml");

                    postXMLData(NotifyXMLServiceURI, xmlDoc);
                }
                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.Message);
                }*/

                String xmlDoc = "";

                try
                {
                    if (chan.AudioFile.Contains(".wav"))
                        xmlDoc = chan.AudioFile.Replace(".wav", ".xml");
                    else if (chan.AudioFile.Contains(".mp3"))
                        xmlDoc = chan.AudioFile.Replace(".mp3", ".xml");
                    else if (chan.AudioFile.Contains(".raw"))
                        xmlDoc = chan.AudioFile.Replace(".raw", ".xml");
                    else if (chan.AudioFile.Contains(".au"))
                        xmlDoc = chan.AudioFile.Replace(".au", ".xml");
                    else
                        xmlDoc = chan.AudioFile + ".xml";

                    TimeSpan interval = chan.EndTime - chan.ConnectTime;
                    int seconds = (int)interval.TotalSeconds;

                    if (wt == 1)
                    {
                        int lpcnt = 0;
                        while (!File.Exists(xmlDoc) && lpcnt < 3)
                        {
                            Thread.Sleep(2000);
                            lpcnt++;
                        }
                    }

                    postXMLAndAudioFile(NotifyXMLServiceURI, chan.AudioFile, chan.CallerID, chan.CalleeID, chan.ConnectTime.ToString("yyyy-MM-dd HH:mm:ss"), seconds, xmlDoc);
                }
                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.Message);
                }
                
            }
        }

        public void timerTick()
        {
            if (manager != null)
            {
                //VRAPIASM.VRAPIEnv.Log(4, "VR2Main::timerTick before calling ProcessEvents");
                manager.ProcessEvents();
                //VRAPIASM.VRAPIEnv.Log(4, "VR2Main::timerTick after calling ProcessEvents");
            }

            TimerCount++;

            if (TimerCount % 5 == 0)
                EverySecondProcess();

            if (TimerCount % 10 == 0)
                Every2SecondsProcess();

            if (TimerCount % 25 == 0)
                Every5SecondsProcess();

            if (TimerCount % 300 == 0)
            {
                EveryMinuteProcess();
                TimerCount = 0;
            }

            VR2Event evt = null;
            string evtArg = "";

            lock (this)
            {
                while (event_queue.Count > 0)
                {
                    evt = event_queue.Dequeue();
                    if (evt != null)
                    {
                        switch (evt.EventID)
                        {
                            case 1:
                                evtArg = evt.ChanID.ToString() + "|";
                                for(int i=0; i<8; i++)
                                {
                                    evtArg += evt.Params[i] + "|";
                                }

                                //VRAPIASM.VRAPIEnv.Log(4, "cbCallOffered event dequeued!");
                                manager.SendEvent(IntPtr.Zero, "CallOffered", evtArg);

                                break;
                            case 2:
                                evtArg = evt.ChanID.ToString() + "|";
                                for (int i = 0; i < 9; i++)
                                {
                                    evtArg += evt.Params[i] + "|";
                                }

                                //VRAPIASM.VRAPIEnv.Log(4, "cbCallConnected event dequeued!");
                                manager.SendEvent(IntPtr.Zero, "CallConnected", evtArg);

                                break;
                            case 3:
                                //VRAPIASM.VRAPIEnv.Log(4, "cbCallIdle event dequeued! caller id:" + evt.Params[1]);

                                evtArg = evt.ChanID.ToString() + "|";
                                for (int i = 0; i < 13; i++)
                                {
                                    evtArg += evt.Params[i] + "|";
                                }

                                manager.SendEvent(IntPtr.Zero, "CallIdle", evtArg);

                                VR2Channel chan = new VR2Channel();
                                chan.ChanIndex = evt.ChanID;

                                chan.CallerIP = evt.Params[0];
                                chan.CallerID = evt.Params[1];
                                chan.CalleeIP = evt.Params[2];
                                chan.CalleeID = evt.Params[3];

                                try
                                {
                                    chan.InitTime = UnixTimeToDateTime(evt.Params[4]);
                                    chan.ConnectTime = UnixTimeToDateTime(evt.Params[5]);
                                    try
                                    {
                                        if (Convert.ToInt32(evt.Params[6]) == 0)
                                            chan.EndTime = chan.InitTime;
                                        else
                                            chan.EndTime = UnixTimeToDateTime(evt.Params[6]);
                                    }
                                    catch (Exception)
                                    {
                                        chan.EndTime = chan.InitTime;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    VRAPIASM.VRAPIEnv.Log(1, "Exception in CallIdle event: " + ex.ToString());
                                }

                                chan.UniqueID = evt.Params[7];
                                chan.AudioFile = evt.Params[8];
                                try
                                {
                                    chan.AudioFileNum = Convert.ToInt32(evt.Params[9]);
                                }
                                catch (Exception)
                                {
                                    chan.AudioFileNum = 0;
                                }

                                try
                                {
                                    chan.Reason = Convert.ToInt32(evt.Params[10]);
                                }
                                catch (Exception)
                                {
                                    chan.Reason = 0;
                                }

                                try
                                {
                                    chan.CallDir = Convert.ToInt32(evt.Params[11]);
                                }
                                catch (Exception)
                                {
                                    chan.CallDir = 0;
                                }

                                chan.DTMFStr = evt.Params[12];
                                chan.CallConnected = evt.Params[13] == "1";

                                chan.ChanName = Channels[chan.ChanIndex].ChanName;

                                chan.OrgSIPInvite = Channels[chan.ChanIndex].OrgSIPInvite;
                                chan.OrgSIPResponse = Channels[chan.ChanIndex].OrgSIPResponse;
                                chan.ExtraSIPHeaders = Channels[chan.ChanIndex].ExtraSIPHeaders;
                                chan.SIPCallID = Channels[chan.ChanIndex].SIPCallID;

                                chan.CallerAudioCodec = Channels[chan.ChanIndex].CallerAudioCodec;
                                chan.CalleeAudioCodec = Channels[chan.ChanIndex].CalleeAudioCodec;
                                chan.CallerRTPAddr = Channels[chan.ChanIndex].CallerRTPAddr;
                                chan.CalleeRTPAddr = Channels[chan.ChanIndex].CalleeRTPAddr;

                                //VRAPIASM.VRAPIEnv.Log(1, "AudioFormat in CallIdle is " + AudioFormat.ToString());
                                //Audio Format Process
                                try
                                {
                                    if (chan.Reason != 401 && chan.Reason != 407 && chan.AudioFile.Length > 0 && File.Exists(chan.AudioFile))
                                    {
                                        SendEmailRecordingNotify(chan, 1);

                                        FileInfo finfo = new FileInfo(chan.AudioFile);
                                        if (finfo != null)
                                        {
                                            if (finfo.Length > 100)
                                            {
                                                if (AudioFormat == 0 && AudioEncode == 1)
                                                {
                                                    wav_work.AddJob(chan.AudioFile, 0, AudioEncode);
                                                    chan.AudioFile = chan.AudioFile.Replace(".wav", ".wzp");
                                                }
                                                else if (AudioFormat == 1 && chan.AudioFile.Contains(".mp3") && AudioEncode == 1)
                                                {
                                                    wav_work.AddJob(chan.AudioFile, 1, AudioEncode);
                                                    chan.AudioFile = chan.AudioFile.Replace(".mp3", ".mzp");
                                                }
                                                else if (AudioFormat == 1 && chan.AudioFile.Contains(".wav"))
                                                {
                                                    wav_work.AddJob(chan.AudioFile, 1, AudioEncode);
                                                    if (AudioEncode == 1)
                                                    {
                                                        chan.AudioFile = chan.AudioFile.Replace(".wav", ".mzp");
                                                    }
                                                    else
                                                    {
                                                        chan.AudioFile = chan.AudioFile.Replace(".wav", ".mp3");
                                                    }
                                                    //VRAPIASM.VRAPIEnv.Log(1, "wav_work.AddJob called 1");
                                                }
                                                else if (AudioFormat == 2 && chan.AudioFile.Contains(".wav")) //needs gsm
                                                {
                                                    //gsm is still using gzp file.
                                                    wav_work.AddJob(chan.AudioFile, 2, AudioEncode);

                                                    if (AudioEncode == 1)
                                                        chan.AudioFile = chan.AudioFile.Replace(".wav", "_gsm.wzp");
                                                    else
                                                        chan.AudioFile = chan.AudioFile.Replace(".wav", "_gsm.wav");
                                                    //else
                                                    //chan.AudioFile = chan.AudioFile.Replace(".wav", ".gsm");
                                                    //VRAPIASM.VRAPIEnv.Log(1, "wav_work.AddJob called 2");
                                                }
                                                else if (AudioFormat == 3 && chan.AudioFile.Contains(".wav")) //need to encode to wzp file
                                                {
                                                    wav_work.AddJob(chan.AudioFile, 3, 0);
                                                    chan.AudioFile = chan.AudioFile.Replace(".wav", ".wzp");
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        SendEmailRecordingNotify(chan, 0);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                                }

                                try
                                {
                                    if(chan.Reason != 401 && chan.Reason != 407)
                                        SaveCallDataToDB(chan);
                                }
                                catch (Exception ex)
                                {
                                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                                }

                                //VRAPIASM.VRAPIEnv.Log(4, "cbCallIdle event ends!");

                                break;
                            case 4:
                                evtArg = evt.ChanID.ToString() + "|";
                                for (int i = 0; i < 2; i++)
                                {
                                    evtArg += evt.Params[i] + "|";
                                }

                                manager.SendEvent(IntPtr.Zero, "CallDTMF", evtArg);
                                //VRAPIASM.VRAPIEnv.Log(4, "CallDTMF event ends!");
                                break;
                            case 5:
                                evtArg = evt.ChanID.ToString() + "|";
                                for (int i = 0; i < 7; i++)
                                {
                                    evtArg += evt.Params[i] + "|";
                                }

                                manager.SendEvent(IntPtr.Zero, "CallInfo", evtArg);
                                //VRAPIASM.VRAPIEnv.Log(4, "CallInfo event ends!");
                                break;
                            case 6:
                                {
                                    if (email_set.emailAddr.Length > 0 && email_set.emailServer.Length > 0 && emails.Length > 0)
                                    {
                                        int ChanIndex = evt.ChanID;
                                        int ErrorLevel = 0;
                                        int ErrorCode = 0;
                                        string ErrorMsg = evt.Params[2];
                                        int reserved = 0;

                                        try
                                        {
                                            ErrorLevel = Convert.ToInt32(evt.Params[0]);
                                        }
                                        catch (Exception)
                                        {
                                        }

                                        try
                                        {
                                            ErrorCode = Convert.ToInt32(evt.Params[1]);
                                        }
                                        catch (Exception)
                                        {
                                        }

                                        try
                                        {
                                            reserved = Convert.ToInt32(evt.Params[3]);
                                        }
                                        catch (Exception)
                                        {
                                        }

                                        try
                                        {
                                            MailMessage myMail = new MailMessage(email_set.emailAddr, email_set.emailAddr);
                                            myMail.Subject = "VoiceRecorder V2 System Error Notification";

                                            myMail.Body = "Error Code: " + ErrorCode.ToString() + "\r\n";
                                            myMail.Body += "Error Message: " + ErrorMsg + "\r\n";

                                            for(int i=0; i<emails.Length; i++)
                                            {
			                                    MailAddress bcc = new MailAddress(emails[i]);
			                                    myMail.Bcc.Add(bcc);
                                            }

                                            SmtpClient smtp_client = new SmtpClient(email_set.emailServer, email_set.emailPort);

                                            smtp_client.UseDefaultCredentials = false;
                                            smtp_client.Credentials = new NetworkCredential(email_set.emailAddr, email_set.emailPassword);
                                            smtp_client.EnableSsl = email_set.emailSSL;

                                            // Set the method that is called back when the send operation ends.
                                            smtp_client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);

                                            //string userState = "test message1";
                                            smtp_client.SendAsync(myMail, this);
                                        }
                                        catch (Exception ex)
                                        {
                                            VRAPIASM.VRAPIEnv.Log(1, ex.Message);
                                        }

                                        //VRAPIASM.VRAPIEnv.Log(4, "VR2Main timerTick() error event ends!");

                                    }
                                }
                                break;
                            case 15: //set chan name

                                break;
                            case 16: //SIP Message Text
                                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::timerTick Received SIP Text:[" + evt.Params[6] + "]");
                                break;
                            case 17: //New Call, call offered case for original SIP INVITE message for extra info
                                //VRAPIASM.VRAPIEnv.Log(4, "VR2Main::timerTick Received SIP INVITE:[" + evt.Params[10] + "]");
                                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::timerTick Received SIP INVITE Additional Headers:" + evt.Params[8]);
                                break;
                            case 18: //Connected Call
                                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::timerTick Received SIP OK Additional Headers:" + evt.Params[8]);
                                break;
                            case 19: //Disconnected Call
                                VRAPIASM.VRAPIEnv.Log(4, "VR2Main::timerTick Received SIP BYE Additional Headers:" + evt.Params[8]);
                                break;
                        }
                    }
                }

            }
        }

        private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
        {
            // Get the unique identifier for this asynchronous operation.
            //VR2Main mainObj = (VR2Main)e.UserState;

            try
            {
                if (e.Cancelled)
                {
                    VRAPIASM.VRAPIEnv.Log(1, "Email Notification Send canceled.");
                }
                if (e.Error != null)
                {
                    VRAPIASM.VRAPIEnv.Log(1, "Email Notification Send Error:" + e.Error.ToString());
                }
                else
                {
                    VRAPIASM.VRAPIEnv.Log(4, "Email Notification Send Succeeded!");
                }
            }
            catch (Exception)
            {

            }
        }



        public static bool GetBooleanFromXMLNode(XmlNode tmpNode)
        {
            if (tmpNode != null)
            {
                if (tmpNode.InnerText.Trim().ToUpper() == "TRUE")
                    return true;
                else
                {
                    if (tmpNode.InnerText.Trim() == "1")
                        return true;
                    else
                        return false;
                }
            }

            return false;
        }

        public bool LoadEmailNetConfigFromXML(XmlDocument xmlDoc)
        {
            XmlElement root = xmlDoc.DocumentElement;
            XmlNode tmpNode = null;
            try
            {
                tmpNode = root.SelectSingleNode("//VoiceRecorder/SMTPServer/Server");
                if (tmpNode != null)
                    email_set.emailServer = tmpNode.InnerText;

                tmpNode = root.SelectSingleNode("//VoiceRecorder/SMTPServer/Port");
                if (tmpNode != null)
                {
                    try
                    {
                        email_set.emailPort = Convert.ToUInt16(tmpNode.InnerText);
                    }
                    catch (Exception)
                    {
                        email_set.emailPort = 0;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/SMTPServer/EmailAddr");
                if (tmpNode != null)
                   email_set.emailAddr = tmpNode.InnerText;

                tmpNode = root.SelectSingleNode("//VoiceRecorder/SMTPServer/Password");
                if (tmpNode != null)
                    email_set.emailPassword = tmpNode.InnerText;

                email_set.emailSSL = GetBooleanFromXMLNode(root.SelectSingleNode("//VoiceRecorder/SMTPServer/SSL"));

            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }

            return true;
        }

        public int LoadAvayaConfigFromXML(string xmlFileName)
        {
           XmlDocument xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.Load(xmlFileName);
            }
            catch (Exception)
            {
                return 0;
            }

            XmlElement root = xmlDoc.DocumentElement;

            try
            {
                XmlNode tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/CDRPort");
                if (tmpNode != null)
                {
                    VRAPIASM.VRAPIEnv.VR_SetAvayaCDRPort(Convert.ToUInt16(tmpNode.InnerText.Trim()));
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/CDRPortType");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().ToUpper() == "TCP")
                        VRAPIASM.VRAPIEnv.VR_SetAvayaCDRProtocol(0);
                    else
                        VRAPIASM.VRAPIEnv.VR_SetAvayaCDRProtocol(1);
                }

                int i;
                for (i = 0; i < 80; i++)
                {
                    string nodename = "//VoiceRecorder/AvayaCDR/Trunks/Trunk" + i.ToString();
                    tmpNode = root.SelectSingleNode(nodename);
                    if (tmpNode != null)
                    {
                        VRAPIASM.VRAPIEnv.VR_SetAvayaSIPTrunkID(i, tmpNode.InnerText.Trim());
                    }
                    else
                    {
                        break;
                    }
                }
                VRAPIASM.VRAPIEnv.VR_SetAvayaSIPTrunkCount(i);

                int TimePos1 = 1;
                int TimePos2 = 4;
                int CondPos1 = 11;
                int CondPos2 = 11;

                int CallerPos1 = 37;
                int CallerPos2 = 41;
                int CalleePos1 = 21;
                int CalleePos2 = 35;


                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/TimePos1");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            TimePos1 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/TimePos2");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            TimePos2 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/CondPos1");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            CondPos1 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/CondPos2");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            CondPos2 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/CallerPos1");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            CallerPos1 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/CallerPos2");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            CallerPos2 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/CalleePos1");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            CalleePos1 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        } 
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AvayaCDR/Pos/CalleePos2");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            CalleePos2 = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception)
                        {
                        } 
                    }
                }

                VRAPIASM.VRAPIEnv.VR_SetAvayaCDRFormat(TimePos1, TimePos2, CondPos1, CondPos2, CallerPos1, CallerPos2, CalleePos1, CalleePos2);

            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                return 0;
            }

            return 1;               

        }

        public int LoadConfigFromXML(string xmlFileName)
        {
            XmlDocument xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.Load(xmlFileName);
            }
            catch (Exception)
            {
                return 0;
            }

            XmlElement root = xmlDoc.DocumentElement;

            try
            {
                XmlNode tmpNode = root.SelectSingleNode("//VoiceRecorder/Type");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            VRType = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception ex1)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AudioRootFolder");
                if (tmpNode != null)
                {
                    AudioRootFolder = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AudioFileName");
                if (tmpNode != null)
                {
                    AudioFileName = tmpNode.InnerText.Trim();
                }      

                tmpNode = root.SelectSingleNode("//VoiceRecorder/AudioFileFormat");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            AudioFormat = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception ex1)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/EncryptAudioFile");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            AudioEncode = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception ex1)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/Credential");
                if (tmpNode != null)
                {
                    try
                    {
                        string sCredential = tmpNode.InnerText.Trim();
                        if (sCredential.Length > 0)
                        {
                            char[] delimiters = new char[] { ';', ',' };
                            string[] members = sCredential.Split(delimiters, StringSplitOptions.None);
                            if (members.Length == 3)
                            {
                                UserName = members[0];
                                Password = new SecureString();
                                for (int j = 0; j < members[1].Length; j++)
                                {
                                    Password.AppendChar(members[1][j]);
                                }
                                Domain = members[2];
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/Filters");
                if (tmpNode != null)
                {
                    try
                    {
                        string sFilters = tmpNode.InnerText.Trim();
                        if (sFilters.Length > 0)
                        {
                            char[] delimiters = new char[] { ';', ',' };
                            string[] members = sFilters.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                            if (members.Length >= 2)
                            {
                                try
                                {
                                    FilterType = Convert.ToInt32(members[0]);
                                }
                                catch (Exception ex1)
                                {
                                    VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                                }

                                Filters = new string[members.Length - 1];
                                for (int j = 1; j < members.Length; j++)
                                {
                                    Filters[j - 1] = members[j];
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/Excludes");
                if (tmpNode != null)
                {
                    try
                    {
                        string sExcludes = tmpNode.InnerText.Trim();
                        if (sExcludes.Length > 0)
                        {
                            char[] delimiters = new char[] { ';', ',' };
                            string[] members = sExcludes.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                            if (members.Length >= 2)
                            {
                                try
                                {
                                    ExcludeType = Convert.ToInt32(members[0]);
                                }
                                catch (Exception ex1)
                                {
                                    VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                                }

                                Excludes = new string[members.Length - 1];
                                for (int j = 1; j < members.Length; j++)
                                {
                                    Excludes[j - 1] = members[j];
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/LogLevel");
                if (tmpNode != null)
                {
                    LogLevel = Convert.ToInt16(tmpNode.InnerText.Trim());
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/LogFileName");
                if (tmpNode != null)
                {
                    LogFileName = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/ChannelCount");
                if (tmpNode != null)
                {    
                    try
                    {
                        ChannelCount = Convert.ToInt32(tmpNode.InnerText.Trim());
                    }
                    catch (Exception ex1)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/LicKey");
                if (tmpNode != null)
                {
                    VRLicKey = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/LicMAC");
                if (tmpNode != null)
                {
                    VRLicMAC = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/ManagerPort");
                if (tmpNode != null)
                {
                    try
                    {
                        managerPort = Convert.ToUInt16(tmpNode.InnerText.Trim());
                    }
                    catch (Exception)
                    {
                        managerPort = 1376;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/KeepRecordMaxDays");
                if (tmpNode != null)
                {
                    try
                    {
                        KeepRecordMaxDays = Convert.ToInt32(tmpNode.InnerText.Trim());
                    }
                    catch (Exception)
                    {
                        KeepRecordMaxDays = 0;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/FIFOSpaceInMB");
                if (tmpNode != null)
                {
                    try
                    {
                        FIFOSpaceInMB = Convert.ToInt32(tmpNode.InnerText.Trim());
                    }
                    catch (Exception)
                    {
                        FIFOSpaceInMB = 0;
                    }
                }

                for (int i = 1; i <= 10; i++)
                {
                    String NodeName = "//VoiceRecorder/OptiLogix/Devices/Device" + i.ToString();
                    tmpNode = root.SelectSingleNode(NodeName);
                    if (tmpNode != null)
                    {
                        NodeName += "/DeviceType";
                        tmpNode = root.SelectSingleNode(NodeName);
                        if (tmpNode != null)
                        {
                            if (tmpNode.InnerText.Trim().Length > 0)
                            {
                                try
                                {
                                    DeviceType[i - 1] = Convert.ToInt32(tmpNode.InnerText.Trim());
                                }
                                catch (Exception ex1)
                                {
                                    VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                                }
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/EnableRTSrv");
                if (tmpNode != null)
                {
                    try
                    {
                        EnableRTSrv = Convert.ToInt32(tmpNode.InnerText.Trim());
                    }
                    catch (Exception)
                    {
                        EnableRTSrv = 0;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/MaxWavLengthInSeconds");
                if (tmpNode != null)
                {
                    try
                    {
                        MaxWavSeconds = Convert.ToInt32(tmpNode.InnerText.Trim());
                    }
                    catch (Exception)
                    {
                        MaxWavSeconds = 43200;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/Enabled");
                if (tmpNode != null)
                {
                    if (GetBooleanFromXMLNode(tmpNode))
                    {
                        db_set = new DBServerSetting();

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/DBType");
                        if (tmpNode != null)
                        {
                            try
                            {
                                db_set.dbType = Convert.ToInt32(tmpNode.InnerText);
                            }
                            catch (Exception ex1)
                            {
                                VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                            }
                        }

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/DBServer");
                        if (tmpNode != null)
                            db_set.sDBServer = tmpNode.InnerText;

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/DBName");
                        if (tmpNode != null)
                            db_set.sDBName = tmpNode.InnerText;

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/AuthType");
                        if (tmpNode != null)
                        {
                            try
                            {
                                db_set.authType = Convert.ToInt32(tmpNode.InnerText);
                            }
                            catch (Exception ex1)
                            {
                                VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                            }
                        }

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/UserName");
                        if (tmpNode != null)
                            db_set.sUserName = tmpNode.InnerText;

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/Password");
                        if (tmpNode != null)
                            db_set.sPassword = tmpNode.InnerText;

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/CallLogTableName");
                        if (tmpNode != null)
                        {
                            if(tmpNode.InnerText.Length > 0)
                                db_set.CallLogTableName = tmpNode.InnerText;
                        }

                        tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/ChannelStatusTableName");
                        if (tmpNode != null)
                        {
                            if (tmpNode.InnerText.Length > 0)
                                db_set.ChannelStatusTableName = tmpNode.InnerText;
                        }

                    }
                    else
                    {
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/Database/UpdateChannelStatusToDB");
                if (tmpNode != null)
                {
                    if (GetBooleanFromXMLNode(tmpNode))
                    {
                        updateChanStatusToDB = true;
                    }
                }


                //////////////////////////////////////////////////
                //PCBest VoIP Recorder Special Config Items///////
                //////////////////////////////////////////////////

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/Protocol");
                if (tmpNode != null)
                {
                    VoIPProtocol = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/Port");
                if (tmpNode != null)
                {
                    if(tmpNode.InnerText.Trim().Length > 0)
                        VoIPPort = Convert.ToUInt16(tmpNode.InnerText.Trim());
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/NIC");
                if (tmpNode != null)
                {
                    VoIPNIC = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/DumpFile");
                if (tmpNode != null)
                {
                    DumpFileName = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/PromiscuousMode");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            PromiscuousMode = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception ex1)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/WriteCallPcapFile");
                if (tmpNode != null)
                {
                    if (tmpNode.InnerText.Trim().Length > 0)
                    {
                        try
                        {
                            WriteCallPcapFile = Convert.ToInt32(tmpNode.InnerText.Trim());
                        }
                        catch (Exception ex1)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                        }
                    }
                }

                if (VoIPProtocol.ToUpper() == "RTP")
                {
                    tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/RTP/PBXAddr");
                    if (tmpNode != null)
                    {
                        string PBXAddr = tmpNode.InnerText.Trim();
                        if (PBXAddr.Length > 0)
                        {
                            char[] delimiters = new char[] { ';', ',' };
                            string[] members = PBXAddr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                            if (members.Length >= 1)
                            {
                                RTPPBX = new string[members.Length];
                                for (int j = 0; j < members.Length; j++)
                                {
                                    RTPPBX[j] = members[j];
                                }
                            }
                        }
                    }

                    tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/RTP/ExtenAddr");
                    if (tmpNode != null)
                    {
                        string ExtenAddr = tmpNode.InnerText.Trim();
                        if (ExtenAddr.Length > 0)
                        {
                            char[] delimiters = new char[] { ';' };
                            string[] members = ExtenAddr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                            if (members.Length >= 1)
                            {
                                RTPExten = new RTPPBXExten[members.Length];
                                for (int j = 0; j < members.Length; j++)
                                {
                                    RTPExten[j] = new RTPPBXExten();
                                    char[] delimiters1 = new char[] { ',' };
                                    string[] members1 = members[j].Split(delimiters1, StringSplitOptions.RemoveEmptyEntries);
                                    if (members1.Length >= 3)
                                    {
                                        RTPExten[j].Name = members1[0];
                                        RTPExten[j].Number = members1[1];
                                        RTPExten[j].IPAddr = members1[2];
                                    }
                                    else
                                    {
                                        RTPExten[j].Name = "";
                                        RTPExten[j].Number = "";
                                        RTPExten[j].IPAddr = "";
                                    }
                                }
                            }
                        }
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/IgnorePossibleSameCall");
                if (tmpNode != null)
                {
                    if (GetBooleanFromXMLNode(tmpNode))
                    {
                        IgnorePossibleSameCall = true;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/Recording");
                if (tmpNode != null)
                {
                    if (!GetBooleanFromXMLNode(tmpNode))
                    {
                        Recording = false;
                    }
                    else
                        Recording = true;
                }
                else
                    Recording = true;

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/RecordCallLegs");
                if (tmpNode != null)
                {
                    RecordCallLegs = GetBooleanFromXMLNode(tmpNode);
                }
                else
                    RecordCallLegs = false;

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/RecordStereo");
                if (tmpNode != null)
                {
                    RecordStereo = GetBooleanFromXMLNode(tmpNode);
                }
                else
                    RecordStereo = false;


                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/XMLCallInfo");
                if (tmpNode != null)
                {
                    if (!GetBooleanFromXMLNode(tmpNode))
                    {
                        CreateXML = false;
                    }
                    else
                        CreateXML = true;
                }
                else
                    CreateXML = true;	

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/UsePacketTime");
                if (tmpNode != null)
                {
                    if (!GetBooleanFromXMLNode(tmpNode))
                    {
                        UsePacketTime = false;
                    }
                    else
                        UsePacketTime = true;
                }
                else
                    UsePacketTime = false;

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/RecordPauseDTMFKey");
                if (tmpNode != null)
                {
                    RecordPauseKey = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/RecordPauseOption");
                if (tmpNode != null)
                {
                    string inp = tmpNode.InnerText.Trim();
                    if(inp.Length > 0)
                    {
                        try
                        {
                            RecordPauseOpt = Convert.ToInt32(inp);
                        }
                        catch(Exception excp)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, excp.ToString());
                        }
                    }
                }
                

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/SIPHeadersInXML");
                if (tmpNode != null)
                {
                    SIPHeadersInXML = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/ExtenPattern");
                if (tmpNode != null)
                {
                    ExtenPattern = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/RecordOnlyAfterAnswer");
                if (tmpNode != null)
                {
                    if (!GetBooleanFromXMLNode(tmpNode))
                    {
                         RecordOnlyAfterAnswer = false;
                    }
                    else
                         RecordOnlyAfterAnswer = true;
                }
                else
                    RecordOnlyAfterAnswer = false;
                

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/NoAudioSeconds");
                if (tmpNode != null)
                {
                    try
                    {
                        NoAudioSeconds = Convert.ToInt32(tmpNode.InnerText.Trim());
                    }
                    catch (Exception ex1)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                    }
                }

                TAPIMonitorLines = "";
                tmpNode = root.SelectSingleNode("//VoiceRecorder/TAPI/MonitorLines");
                if (tmpNode != null)
                {
                    try
                    {
                        TAPIMonitorLines = tmpNode.InnerText.Trim();
                    }
                    catch (Exception)
                    {
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/AddDateTimeAnnouncement");
                if (tmpNode != null)
                {
                    AddWavDateTime = Convert.ToInt32(tmpNode.InnerText.Trim());
                }
                else
                    AddWavDateTime = 0;

                tmpNode = root.SelectSingleNode("//VoiceRecorder/VoIP/AddDateTimeAnnouncementFmt");
                if (tmpNode != null)
                {
                    AddWavDateTimeFmt = tmpNode.InnerText.Trim();
                }
                else
                    AddWavDateTimeFmt = "";

                TAPIRestartHours = 0;
                tmpNode = root.SelectSingleNode("//VoiceRecorder/TAPI/RestartHours");
                if (tmpNode != null)
                {
                    try
                    {
                        TAPIRestartHours = Convert.ToInt32(tmpNode.InnerText.Trim());
                    }
                    catch (Exception ex1)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex1.ToString());
                    }
                }

                LoadEmailNetConfigFromXML(xmlDoc);

                tmpNode = root.SelectSingleNode("//VoiceRecorder/NotifyEmails");
                if (tmpNode != null)
                {
                    try
                    {
                        string sEmails = tmpNode.InnerText.Trim();
                        if (sEmails.Length > 0)
                        {
                            char[] delimiters = new char[] { ';', ',' };
                            emails = sEmails.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                        }
                    }
                    catch (Exception ex)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/NotifyRecordingEmails");
                if (tmpNode != null)
                {
                    try
                    {
                        string sEmails = tmpNode.InnerText.Trim();
                        if (sEmails.Length > 0)
                        {
                            char[] delimiters = new char[] { ';', ',' };
                            NotifyRecordingEmails = sEmails.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                        }
                    }
                    catch (Exception ex)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/NotifyRecordingScript");
                if (tmpNode != null)
                {
                    try
                    {
                        NotifyRecordingScript = tmpNode.InnerText.Trim();
                    }
                    catch (Exception ex)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/NotifyXMLServiceURI");
                if (tmpNode != null)
                {
                    try
                    {
                        NotifyXMLServiceURI = tmpNode.InnerText.Trim();
                    }
                    catch (Exception ex)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                    }
                }       

                tmpNode = root.SelectSingleNode("//VoiceRecorder/IDMaps");
                if (tmpNode != null)
                {
                    try
                    {
                        string sIDMaps = tmpNode.InnerText.Trim();
                        if (sIDMaps.Length > 0)
                        {
                            char[] delimiters = new char[] { ';' };
                            string[] members = sIDMaps.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                            if (members.Length > 0)
                            {
                                idMaps = new IDMap[members.Length];
                                for (int j = 0; j < members.Length; j++)
                                {
                                    idMaps[j] = new IDMap();
                                    char[] delimiters1 = new char[] { ',' };
                                    string[] members1 = members[j].Split(delimiters1, StringSplitOptions.RemoveEmptyEntries);
                                    if (members1.Length == 2)
                                    {
                                        idMaps[j].OrgID = members1[0];
                                        idMaps[j].RepID = members1[1];
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/SamsungCDR/ServerIPAddr");
                if (tmpNode != null)
                {
                    try
                    {
                        SamsungPBXCDRIP = tmpNode.InnerText.Trim();
                    }
                    catch (Exception)
                    {
                        SamsungPBXCDRIP = "";
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/SamsungCDR/ServerPort");
                if (tmpNode != null)
                {
                    try
                    {
                        SamsungPBXCDRPort = Convert.ToUInt16(tmpNode.InnerText.Trim());
                    }
                    catch (Exception)
                    {
                        SamsungPBXCDRPort = 0;
                    }
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/CiscoBIB/RecordingTrunk");
                if (tmpNode != null)
                {
                    BIBRecordingTrunk = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/CiscoBIB/IncomingTrunk");
                if (tmpNode != null)
                {
                    BIBIncomingTrunk = tmpNode.InnerText.Trim();
                }

                tmpNode = root.SelectSingleNode("//VoiceRecorder/CiscoBIB/OutgoingTrunk");
                if (tmpNode != null)
                {
                    BIBOutgoingTrunk = tmpNode.InnerText.Trim();
                }

            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                return 0;
            }

            return 1;
        }

        public static int cbCallOffered(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, uint CallTime, string UniqueID, string AudioFile, int CallDir)
        {
            //VRAPIASM.VRAPIEnv.Log(4, "Channel " + ChanIndex.ToString() + " got cbCallOffered, caller " + CallerID + " called " + CalleeID);

            try
            {
                if (VR2Main.MainObj != null)
                {
                    if (VR2Main.MainObj.VRType == 0)  //only IP recorder to call this function
                    {
                        bool a = VR2Main.MainObj.CorrectTAPICallInfo(0, ChanIndex, ref CallerIP, ref CallerID, ref CalleeIP, ref CalleeID, UniqueID, ref CallDir);
                        bool b = VR2Main.MainObj.CorrectSamsungCDRCallInfo(0, ChanIndex, ref CallerIP, ref CallerID, ref CalleeIP, ref CalleeID, UniqueID, ref CallDir);
                        if (a || b)
                        {
                            VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 0, CallerID, IntPtr.Zero);
                            VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 1, CalleeID, IntPtr.Zero);
                            VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 2, CallDir.ToString(), IntPtr.Zero);
                        }

                        if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                        {
                            VR2Event evt = new VR2Event();
                            evt.EventID = 1;
                            evt.ChanID = ChanIndex;
                            evt.Params[0] = CallerIP;
                            evt.Params[1] = CallerID;
                            evt.Params[2] = CalleeIP;
                            evt.Params[3] = CalleeID;
                            evt.Params[4] = CallTime.ToString();
                            evt.Params[5] = UniqueID;
                            evt.Params[6] = AudioFile;
                            evt.Params[7] = CallDir.ToString();

                            lock (VR2Main.MainObj)
                            {
                                VR2Main.MainObj.event_queue.Enqueue(evt);

                                VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                                chan.Reset();

                                chan.CallerIP = CallerIP;
                                chan.CallerID = CallerID;
                                chan.CalleeIP = CalleeIP;
                                chan.CalleeID = CalleeID;
                                chan.InitTime = DateTime.Now;
                                chan.UniqueID = UniqueID;
                                chan.AudioFile = AudioFile;
                                chan.CallDir = CallDir;
                                chan.ChanStatus = 1;
                                chan.ModTag = true;

                                VR2Main.MainObj.totalCallCount++;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }

            if(VR2Main.MainObj.m_pCallOffered1 != null)
                VR2Main.MainObj.m_pCallOffered1(ChanIndex, CallerIP, CallerID, CalleeIP, CalleeID, CallTime, UniqueID, AudioFile, CallDir);

            return 0;
        }

        public static void cbCallConnected(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, uint InitTime, uint ConnectTime, string UniqueID, string AudioFile, int CallDir)
        {
            //VRAPIASM.VRAPIEnv.Log(4, "Channel " + ChanIndex.ToString() + " got cbCallConnected");

            try
            {
                if (VR2Main.MainObj != null)
                {
                    if (VR2Main.MainObj.VRType == 0)  //only IP recorder to call this function
                    {
                        bool a = VR2Main.MainObj.CorrectTAPICallInfo(1, ChanIndex, ref CallerIP, ref CallerID, ref CalleeIP, ref CalleeID, UniqueID, ref CallDir);
                        bool b = VR2Main.MainObj.CorrectSamsungCDRCallInfo(0, ChanIndex, ref CallerIP, ref CallerID, ref CalleeIP, ref CalleeID, UniqueID, ref CallDir);
                        if (a || b)
                        {
                            VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 0, CallerID, IntPtr.Zero);
                            VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 1, CalleeID, IntPtr.Zero);
                            VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 2, CallDir.ToString(), IntPtr.Zero);
                        }

                        if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                        {
                            VR2Event evt = new VR2Event();
                            evt.EventID = 2;
                            evt.ChanID = ChanIndex;
                            evt.Params[0] = CallerIP;
                            evt.Params[1] = CallerID;
                            evt.Params[2] = CalleeIP;
                            evt.Params[3] = CalleeID;
                            evt.Params[4] = InitTime.ToString();
                            evt.Params[5] = ConnectTime.ToString();
                            evt.Params[6] = UniqueID;
                            evt.Params[7] = AudioFile;
                            evt.Params[8] = CallDir.ToString();

                            lock (VR2Main.MainObj)
                            {
                                VR2Main.MainObj.event_queue.Enqueue(evt);

                                VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                                chan.CallerIP = CallerIP;
                                chan.CallerID = CallerID;
                                chan.CalleeIP = CalleeIP;
                                chan.CalleeID = CalleeID;
                                chan.ConnectTime = DateTime.Now;
                                if (InitTime == ConnectTime)
                                {
                                    //some recording like DST
                                    //doesn't have CallOffered event, and call init time
                                    //is always same as call connected time
                                    chan.InitTime = DateTime.Now;
                                }

                                chan.UniqueID = UniqueID;
                                chan.AudioFile = AudioFile;
                                chan.CallDir = CallDir;
                                chan.ChanStatus = 2;
                                chan.CallConnected = true;
                                chan.ModTag = true;

                                VR2Main.MainObj.connCallCount++;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }
        }

        public static void cbCallIdle(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, uint InitTime, uint ConnectTime, uint EndTime, string UniqueID, string AudioFile, int AudioFileNum, int Reason, int CallDir, string DTMFStr, int Codec)
        {
            //VRAPIASM.VRAPIEnv.Log(4, "Channel " + ChanIndex.ToString() + " got cbCallIdle");
            if (VR2Main.MainObj != null)
            {
                if (VR2Main.MainObj.VRType == 0) //only IP recorder to call this function
                {
                    bool a = VR2Main.MainObj.CorrectTAPICallInfo(2, ChanIndex, ref CallerIP, ref CallerID, ref CalleeIP, ref CalleeID, UniqueID, ref CallDir);
                    bool b = VR2Main.MainObj.CorrectSamsungCDRCallInfo(0, ChanIndex, ref CallerIP, ref CallerID, ref CalleeIP, ref CalleeID, UniqueID, ref CallDir);
                    if (a || b)
                    {
                        VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 0, CallerID, IntPtr.Zero);
                        VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 1, CalleeID, IntPtr.Zero);
                        VRAPIASM.VRAPIEnv.SetChannelType(ChanIndex, 2, CallDir.ToString(), IntPtr.Zero);
                    }
                }
            }
            
            string logInfo = "cbCallIdle ";
            logInfo += "CH:" + ChanIndex.ToString() + " ";
            logInfo += "CallerIP:" + CallerIP + " ";
            logInfo += "CallerID:" + CallerID + " ";
            logInfo += "CalleeIP:" + CalleeIP + " ";
            logInfo += "CalleeID:" + CalleeID + " ";
            logInfo += "UniqueID:" + UniqueID + " ";
            logInfo += "AudioFile:" + AudioFile + " ";
            if(Reason == 999999)
                logInfo += "Reason: CALLER CANCEL ";
            else
                logInfo += "Reason:" + Reason.ToString() + " ";
            logInfo += "CallDir:" + CallDir.ToString() + " ";
            logInfo += "DTMFStr:" + DTMFStr + " ";

            VRAPIASM.VRAPIEnv.Log(4, logInfo);

            if (AudioFile.Length > 0)
            {
                if (!File.Exists(AudioFile))
                {
                    VRAPIASM.VRAPIEnv.Log(1, AudioFile + " does not exist! Reset the audio filename to empty string!");
                    AudioFile = "";
                    AudioFileNum = 0;
                }
                else
                {
                    FileInfo finfo = new FileInfo(AudioFile);
                    if (finfo.Length < 200)
                    {
                        //too small, pretty much not very useful!
                        VRAPIASM.VRAPIEnv.Log(1, AudioFile + " size < 200 bytes! Reset the audio filename to empty string and delete the file!");
                        File.Delete(AudioFile);
                        AudioFile = "";
                        AudioFileNum = 0;
                    }
                }
            }

            try
            {
                if (VR2Main.MainObj != null)
                {
                    if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                    {
                        VR2Event evt = new VR2Event();
                        evt.EventID = 3;
                        evt.ChanID = ChanIndex;
                        evt.Params[0] = CallerIP;
                        evt.Params[1] = CallerID;
                        evt.Params[2] = CalleeIP;
                        evt.Params[3] = CalleeID;
                        evt.Params[4] = InitTime.ToString();
                        evt.Params[5] = ConnectTime.ToString();
                        evt.Params[6] = EndTime.ToString();

                        evt.Params[7] = UniqueID;
                        evt.Params[8] = AudioFile;
                        evt.Params[9] = AudioFileNum.ToString();

                        evt.Params[10] = Reason.ToString();

                        evt.Params[11] = CallDir.ToString();
                        evt.Params[12] = DTMFStr;
                        evt.Params[14] = Codec.ToString();

                        lock (VR2Main.MainObj)
                        {
                            VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                            evt.Params[13] = chan.CallConnected ? "1" : "0";
                            VR2Main.MainObj.event_queue.Enqueue(evt);

                            chan.CallerIP = CallerIP;
                            chan.CallerID = CallerID;
                            chan.CalleeIP = CalleeIP;
                            chan.CalleeID = CalleeID;
                            chan.EndTime = DateTime.Now;
                            chan.UniqueID = UniqueID;
                            chan.AudioFile = AudioFile;
                            chan.AudioFileNum = AudioFileNum;
                            chan.CallDir = CallDir;
                            chan.ChanStatus = 0;
                            chan.DTMFStr = DTMFStr;

                            chan.ModTag = true;

                            if ((Reason == 401 || Reason == 407) && !chan.CallConnected)
                            {
                                VR2Main.MainObj.totalCallCount--;
                            }
                            else
                            {
                                VR2Main.MainObj.succCallCount++;
                                if (!chan.CallConnected)
                                    VR2Main.MainObj.failedCallCount++;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }
        }

        public static void cbCallDTMF(int ChanIndex, string KeyPressed, string DTMFStr)
        {
            try
            {
                if (VR2Main.MainObj != null)
                {
                    if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                    {
                        VR2Event evt = new VR2Event();
                        evt.EventID = 4;
                        evt.ChanID = ChanIndex;
                        evt.Params[0] = KeyPressed;
                        evt.Params[1] = DTMFStr;

                        lock (VR2Main.MainObj)
                        {
                            VR2Main.MainObj.event_queue.Enqueue(evt);

                            VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                            chan.DTMFStr = DTMFStr;

                            chan.ModTag = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }

        }

        public static void cbSetChanName(int ChanIndex, string ChanName)
        {
            try
            {
                if (VR2Main.MainObj != null)
                {
                    if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                    {
                        //VR2Event evt = new VR2Event();
                        //evt.EventID = 15;
                        //evt.ChanID = ChanIndex;
                        //evt.Params[0] = ChanName;

                        lock (VR2Main.MainObj)
                        {
                            //VR2Main.MainObj.event_queue.Enqueue(evt);

                            VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];
                            chan.ChanName = ChanName;
                            chan.ModTag = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }
        }

        public static string RemoveSpecialCharacters(string str)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < str.Length; i++)
            {
                if ((str[i] >= '0' && str[i] <= '9')
                    || (str[i] >= 'A' && str[i] <= 'z'
                        || (str[i] == '-' || str[i] == '_')))
                {
                    sb.Append(str[i]);
                }
            }

            return sb.ToString();
        }

        public static string RemoveInvalidCharsForFileName(string filename)
        {
            return string.Concat(filename.Split(Path.GetInvalidFileNameChars()));
        }

        public static string ReplaceInvalidCharsForFileName(string filename)
        {
            return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));
        }

        public static string cbGetWavFileName(int ChanIndex, string UniqueID, string CallerID, string CalleeID)
        {
            string fn = "";

            VRAPIASM.VRAPIEnv.Log(4, "cbGetWavFileName CallerID:" + CallerID + " CalleeID:" + CalleeID);

            try
            {
                if (VR2Main.MainObj != null)
                {
                    if (VR2Main.MainObj.AudioFileName.Length > 0)
                    {
                        string Year = DateTime.Now.Year.ToString();
                        string Month = DateTime.Now.Month.ToString("D2");
                        string Day = DateTime.Now.Day.ToString("D2");

                        string DateT = DateTime.Now.ToString("yyyyMMdd-HHmmss");

                        CallerID = GetSIPAddressInfo(1, CallerID);
                        if (CallerID.Length == 0)
                            CallerID = "UnknownCaller";
                        else
                        {
                            CallerID = RemoveInvalidCharsForFileName(CallerID);
                            CallerID = RemoveSpecialCharacters(CallerID);
                        }

                        CalleeID = GetSIPAddressInfo(1, CalleeID);
                        if (CalleeID.Length == 0)
                            CalleeID = "UnknownCalled";
                        else
                        {
                            CalleeID = RemoveInvalidCharsForFileName(CalleeID);
                            CalleeID = RemoveSpecialCharacters(CalleeID);
                        }

                        fn = VR2Main.MainObj.AudioFileName;

                        Random rnd = new Random();

                        fn = fn.Replace("caller", CallerID);
                        fn = fn.Replace("called", CalleeID);
                        fn = fn.Replace("datetime", DateT);
                        fn = fn.Replace("randnum", rnd.Next(100000, 999999).ToString());

                        if (!Directory.Exists(VR2Main.MainObj.AudioRootFolder))
                            Directory.CreateDirectory(VR2Main.MainObj.AudioRootFolder);

                        string dir1 = VR2Main.MainObj.AudioRootFolder + "\\" + Year;
                        if (!Directory.Exists(dir1))
                            Directory.CreateDirectory(dir1);

                        dir1 = VR2Main.MainObj.AudioRootFolder + "\\" + Year + "\\" + Month;
                        if (!Directory.Exists(dir1))
                            Directory.CreateDirectory(dir1);

                        dir1 = VR2Main.MainObj.AudioRootFolder + "\\" + Year + "\\" + Month + "\\" + Day;
                        if (!Directory.Exists(dir1))
                            Directory.CreateDirectory(dir1);

                        fn = VR2Main.MainObj.AudioRootFolder + "\\" + Year + "\\" + Month + "\\" + Day + "\\" + fn;
                        fn = fn.ToLower();
                        if (VR2Main.MainObj.AudioFormat == 1 && fn.Contains(".wav")) //mp3
                        {
                            fn = fn.Replace(".wav", ".mp3");
                        }

                        VRAPIASM.VRAPIEnv.Log(4, "Made filename:" + fn);
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                return "";
            }

            return fn;
        }

        public static void cbCallSIPInfo(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, string UniqueID, string RequestURI, string ContactAddr, string s1, string s2, string SIPCallID, string SIPMsg)
        {
            if (s1 == "SIP MESSAGE TEXT")
            {
                //put the message in s2 to somewhere for process later.
                //better not do anything here in VR2 low level process for dealing with recording
                try
                {
                    if (VR2Main.MainObj != null)
                    {
                        if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                        {
                            VR2Event evt = new VR2Event();
                            evt.EventID = 16;
                            evt.ChanID = ChanIndex;
                            evt.Params[0] = CallerIP;
                            evt.Params[1] = CallerID;
                            evt.Params[2] = CalleeIP;
                            evt.Params[3] = CalleeID;
                            evt.Params[4] = UniqueID;
                            evt.Params[5] = SIPMsg;
                            evt.Params[6] = s2;


                            lock (VR2Main.MainObj)
                            {
                                VR2Main.MainObj.event_queue.Enqueue(evt);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                }
            }
            else if (s1 == "NEW CALL") //SIP offered INVITE case
            {
                try
                {
                    if (VR2Main.MainObj != null)
                    {
                        if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                        {
                            VR2Event evt = new VR2Event();
                            evt.EventID = 17;
                            evt.ChanID = ChanIndex;
                            evt.Params[0] = CallerIP;
                            evt.Params[1] = CallerID;
                            evt.Params[2] = CalleeIP;
                            evt.Params[3] = CalleeID;
                            evt.Params[4] = UniqueID;
                            evt.Params[5] = RequestURI;
                            evt.Params[6] = ContactAddr;
                            evt.Params[7] = s1;
                            evt.Params[8] = s2;
                            evt.Params[9] = SIPCallID;
                            evt.Params[10] = SIPMsg;


                            lock (VR2Main.MainObj)
                            {
                                VR2Main.MainObj.event_queue.Enqueue(evt);

                                VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                                chan.CallerIP = CallerIP;
                                chan.CallerID = CallerID;
                                chan.CalleeIP = CalleeIP;
                                chan.CalleeID = CalleeID;
                                chan.UniqueID = UniqueID;
                                //chan.AudioFile = AudioFile;
                                //chan.CallDir = CallDir;
                                chan.SIPCallID = SIPCallID;
                                chan.OrgSIPInvite = SIPMsg;
                                chan.ExtraSIPHeaders = s2;

                                chan.ModTag = true;
                            }
                        }
                    }
                }

                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                }
            }
            else if (s1 == "CALL CONNECTED") //SIP OK case
            {
                try
                {
                    if (VR2Main.MainObj != null)
                    {
                        if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                        {
                            VR2Event evt = new VR2Event();
                            evt.EventID = 18;
                            evt.ChanID = ChanIndex;
                            evt.Params[0] = CallerIP;
                            evt.Params[1] = CallerID;
                            evt.Params[2] = CalleeIP;
                            evt.Params[3] = CalleeID;
                            evt.Params[4] = UniqueID;
                            evt.Params[5] = RequestURI;
                            evt.Params[6] = ContactAddr;
                            evt.Params[7] = s1;
                            evt.Params[8] = s2;
                            evt.Params[9] = SIPCallID;
                            evt.Params[10] = SIPMsg;


                            lock (VR2Main.MainObj)
                            {
                                VR2Main.MainObj.event_queue.Enqueue(evt);

                                VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                                chan.CallerIP = CallerIP;
                                chan.CallerID = CallerID;
                                chan.CalleeIP = CalleeIP;
                                chan.CalleeID = CalleeID;
                                chan.UniqueID = UniqueID;
                                //chan.AudioFile = AudioFile;
                                //chan.CallDir = CallDir;
                                chan.SIPCallID = SIPCallID;
                                chan.OrgSIPResponse = SIPMsg;

                                char[] delimiters = new char[] { ';', ',', '|', ' ' };
                                string[] parameters = s2.Split(delimiters, StringSplitOptions.None);
                                //VRAPIASM.VRAPIEnv.Log(4, "cbCallSIPInfo CALL CONNECTED " + parameters.Length.ToString());
                                if (parameters.Length >= 4)
                                {
                                    chan.CallerAudioCodec = Convert.ToInt32(parameters[0]);
                                    chan.CalleeAudioCodec = Convert.ToInt32(parameters[1]);
                                    chan.CallerRTPAddr = parameters[2];
                                    chan.CalleeRTPAddr = parameters[3];
                                    //VRAPIASM.VRAPIEnv.Log(4, "cbCallSIPInfo CALL CONNECTED " + chan.CallerAudioCodec.ToString() + " " + chan.CalleeAudioCodec.ToString());
                                }

                                chan.ModTag = true;
                            }
                        }
                    }
                }

                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                }
            }
            else if (s1 == "CALL IDLE") //SIP BYE case
            {
                try
                {
                    if (VR2Main.MainObj != null)
                    {
                        if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                        {
                            VR2Event evt = new VR2Event();
                            evt.EventID = 19;
                            evt.ChanID = ChanIndex;
                            evt.Params[0] = CallerIP;
                            evt.Params[1] = CallerID;
                            evt.Params[2] = CalleeIP;
                            evt.Params[3] = CalleeID;
                            evt.Params[4] = UniqueID;
                            evt.Params[5] = RequestURI;
                            evt.Params[6] = ContactAddr;
                            evt.Params[7] = s1;
                            evt.Params[8] = s2;
                            evt.Params[9] = SIPCallID;
                            evt.Params[10] = SIPMsg;


                            lock (VR2Main.MainObj)
                            {
                                VR2Main.MainObj.event_queue.Enqueue(evt);

                                VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                                chan.CallerIP = CallerIP;
                                chan.CallerID = CallerID;
                                chan.CalleeIP = CalleeIP;
                                chan.CalleeID = CalleeID;
                                chan.UniqueID = UniqueID;
                                //chan.AudioFile = AudioFile;
                                //chan.CallDir = CallDir;
                                chan.SIPCallID = SIPCallID;

                                char[] delimiters = new char[] { ';', ',', '|', ' ' };
                                string[] parameters = s2.Split(delimiters, StringSplitOptions.None);
                                if (parameters.Length >= 4)
                                {
                                    chan.CallerAudioCodec = Convert.ToInt32(parameters[0]);
                                    chan.CalleeAudioCodec = Convert.ToInt32(parameters[1]);
                                    chan.CallerRTPAddr = parameters[2];
                                    chan.CalleeRTPAddr = parameters[3];
                                }

                                chan.ModTag = true;
                            }
                        }
                    }
                }

                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                }
            }


        }

        public static void cbCallInfo(int ChanIndex, string CallerIP, string CallerID, string CalleeIP, string CalleeID, string UniqueID, string AudioFile, int CallDir)
        {
            try
            {
                if (VR2Main.MainObj != null)
                {
                    if (ChanIndex >= 0 && ChanIndex < VR2Main.MainObj.MaxChanNum)
                    {
                        VR2Event evt = new VR2Event();
                        evt.EventID = 5;
                        evt.ChanID = ChanIndex;
                        evt.Params[0] = CallerIP;
                        evt.Params[1] = CallerID;
                        evt.Params[2] = CalleeIP;
                        evt.Params[3] = CalleeID;
                        evt.Params[4] = UniqueID;
                        evt.Params[5] = AudioFile;
                        evt.Params[6] = CallDir.ToString();


                        lock (VR2Main.MainObj)
                        {
                            VR2Main.MainObj.event_queue.Enqueue(evt);

                            VR2Channel chan = VR2Main.MainObj.Channels[ChanIndex];

                            chan.CallerIP = CallerIP;
                            chan.CallerID = CallerID;
                            chan.CalleeIP = CalleeIP;
                            chan.CalleeID = CalleeID;
                            chan.UniqueID = UniqueID;
                            chan.AudioFile = AudioFile;
                            chan.CallDir = CallDir;

                            chan.ModTag = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }
        }

        /*
        public static string cbGetFileName(int ChanIndex, string UniqueID, string CallerID, string CalleeID)
        {
            //you should generate unique file name for recording. Supply with full path.
            string filepath = "c:\\temp\\vr2\\" + UniqueID + ".wav";
        }
        */

        public static void cbFatalError(int ErrorLevel, int ErrorCode, int ChanIndex, string ErrorMsg, int reserved)
        {
            try
            {
                if (VR2Main.MainObj != null)
                {
                    VR2Event evt = new VR2Event();
                    evt.EventID = 6;
                    evt.ChanID = ChanIndex;
                    evt.Params[0] = ErrorLevel.ToString();
                    evt.Params[1] = ErrorCode.ToString();
                    evt.Params[2] = ErrorMsg.ToString();
                    evt.Params[3] = reserved.ToString();

                    lock (VR2Main.MainObj)
                    {
                        VR2Main.MainObj.event_queue.Enqueue(evt);
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }
        }

        public void Start(string xmlConfigFile)
        {
            LoadConfigFromXML(xmlConfigFile);

            VRAPIASM.VRAPIEnv.InitCapture(VRType);
            VRAPIASM.VRAPIEnv.SetAudioRootFolder(AudioRootFolder);
            VRAPIASM.VRAPIEnv.SetAudioFileFormat(AudioFormat);
            VRAPIASM.VRAPIEnv.SetLogFileName(LogFileName);
            VRAPIASM.VRAPIEnv.SetLogLevel(LogLevel);

            if(VRLicKey.Length > 0)
                VRAPIASM.VRAPIEnv.SetLicenseKey(VRLicKey);
            if(VRLicMAC.Length > 0)
                VRAPIASM.VRAPIEnv.SetLicenseMAC(VRLicMAC);

            VRAPIASM.VRAPIEnv.SetChannelCount(ChannelCount);
            VRAPIASM.VRAPIEnv.SetProtocol(VoIPProtocol);

            if (VoIPPort > 0)
                VRAPIASM.VRAPIEnv.SetPort(VoIPPort);

            if (DumpFileName.Length > 0)
            {
                VRAPIASM.VRAPIEnv.SetDumpFile(DumpFileName);
            }
            else if (VoIPNIC.Length > 0)
            {
                if (VoIPNIC.Contains(".pcap") || VoIPNIC.Contains(".cap"))
                {
                    VRAPIASM.VRAPIEnv.SetPCAPFile(VoIPNIC);
                }
                else
                {
                    try
                    {
                        short NicIndex = Convert.ToInt16(VoIPNIC);
                        if (NicIndex >= 0 && NicIndex < 32)
                        {
                            VRAPIASM.VRAPIEnv.SetNIC(NicIndex);
                        }
                    }
                    catch (Exception e1)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, e1.ToString());
                    }
                }
            }

            VRAPIASM.VRAPIEnv.SetPromiscuousMode(PromiscuousMode);

            if (Filters != null)
            {
                if (FilterType == 0 || FilterType == 1 || FilterType == 2)
                {
                    VRAPIASM.VRAPIEnv.SetFilterType(FilterType);
                    VRAPIASM.VRAPIEnv.SetFilterCount(Filters.Length);
                    for (int i = 0; i < Filters.Length; i++)
                    {
                        VRAPIASM.VRAPIEnv.SetFilterItem(i, Filters[i]);
                    }
                }
            }

            if (Excludes != null)
            {
                if (ExcludeType == 0 || ExcludeType == 1 || ExcludeType == 2)
                {
                    VRAPIASM.VRAPIEnv.SetExcludeType(ExcludeType);
                    VRAPIASM.VRAPIEnv.SetExcludeCount(Excludes.Length);
                    for (int i = 0; i < Excludes.Length; i++)
                    {
                        VRAPIASM.VRAPIEnv.SetExcludeItem(i, Excludes[i]);
                    }
                }
            }

            VRAPIASM.VRAPIEnv.SetCB_Call_Offered(m_pCallOffered);
            VRAPIASM.VRAPIEnv.SetCB_Call_Connected(m_pCallConnected);
            VRAPIASM.VRAPIEnv.SetCB_Call_Idle(m_pCallIdle);
            VRAPIASM.VRAPIEnv.SetCB_Call_DTMF(m_pCallDTMF);
            VRAPIASM.VRAPIEnv.SetCB_Fatal_Error(m_pFatalError);
            VRAPIASM.VRAPIEnv.SetCB_Set_ChanName(m_pSetChanName);
            VRAPIASM.VRAPIEnv.SetCB_Call_Info(m_pCallInfo);
            VRAPIASM.VRAPIEnv.SetCB_Call_SIP_Info(m_pCallSIPInfo);

            if (AudioFileName.Length > 0)
                VRAPIASM.VRAPIEnv.SetCB_GetWAVFileName(m_pGetWavFileName);

            if(KeepRecordMaxDays > 0)
            {
                VRAPIASM.VRAPIEnv.SetMaxDays(KeepRecordMaxDays);
            }

            if (FIFOSpaceInMB > 0)
            {
                VRAPIASM.VRAPIEnv.SetFIFOSpace(FIFOSpaceInMB);
            }


            if (EnableRTSrv >= 1)
            {
                VRAPIASM.VRAPIEnv.EnableRTSrv(EnableRTSrv);
            }

            if (MaxWavSeconds >= 1800)
            {
                VRAPIASM.VRAPIEnv.SetMaxWavSeconds(MaxWavSeconds);
            }


            if (VoIPProtocol.ToUpper() == "RTP")
            {
                if (RTPPBX != null)
                {
                    VRAPIASM.VRAPIEnv.SetRTPPBXCount(RTPPBX.Length);
                    for (int i = 0; i < RTPPBX.Length; i++)
                    {
                        VRAPIASM.VRAPIEnv.SetRTPPBXAddr(i, RTPPBX[i]);
                    }
                }

                if (RTPExten != null)
                {
                    VRAPIASM.VRAPIEnv.SetRTPExtenCount(RTPExten.Length);
                    for (int i = 0; i < RTPExten.Length; i++)
                    {
                        VRAPIASM.VRAPIEnv.SetRTPExten(i, RTPExten[i].Name, RTPExten[i].Number, RTPExten[i].IPAddr);
                    }
                }
            }

            if (IgnorePossibleSameCall)
            {
                VRAPIASM.VRAPIEnv.SetIgnorePossibleSameCall(1);
            }

            if (!Recording)
            {
                VRAPIASM.VRAPIEnv.SetRecording(0);
            }

            if (RecordCallLegs)
            {
                VRAPIASM.VRAPIEnv.SetRecordCallLegs(1);
            }

            if (RecordStereo)
            {
                VRAPIASM.VRAPIEnv.SetRecordStereo(1);
            }

            VRAPIASM.VRAPIEnv.EnableAddingDateAndTimeInAudio(AddWavDateTime);
            VRAPIASM.VRAPIEnv.SetAddingDateAndTimeInAudioText(AddWavDateTimeFmt);

            if (!CreateXML)
            {
                VRAPIASM.VRAPIEnv.SetEnableXML(0);
            }

            if (UsePacketTime)
            {
                VRAPIASM.VRAPIEnv.SetUsePacketTime(1);
            }

            if (RecordPauseKey.Length > 0)
            {
                VRAPIASM.VRAPIEnv.SetPauseDTMFStr(RecordPauseKey);
            }

            if (SIPHeadersInXML.Length > 0)
            {
                VRAPIASM.VRAPIEnv.RecordSIPHeadersInXML(SIPHeadersInXML);
            }

            if (WriteCallPcapFile > 0)
            {
                VRAPIASM.VRAPIEnv.EnableSaveCallPcapFile(WriteCallPcapFile);
            }

            if(SamsungPBXCDRIP.Length > 0 && SamsungPBXCDRPort > 0)
            {
                //VRAPIASM.VRAPIEnv.SetSamsungCDRInfo(SamsungPBXCDRIP, SamsungPBXCDRPort);
                ss_cdr_work.SamsungPBXIPAddr = SamsungPBXCDRIP;
                ss_cdr_work.SamsungPBXPort = SamsungPBXCDRPort;
                ss_cdr_work.StartProcess();
            }

            if (ExtenPattern.Length > 0)
            {
                VRAPIASM.VRAPIEnv.SetExtenPattern(ExtenPattern);
            }

            if (RecordOnlyAfterAnswer)
            {
                VRAPIASM.VRAPIEnv.SetRecordOnlyAfterAnswer(true);
            }

            if (NoAudioSeconds > 0)
            {
                VRAPIASM.VRAPIEnv.SetNoAudioSeconds(NoAudioSeconds);
            }

            //the following code is for IP recording and Avaya only
            LoadAvayaConfigFromXML(xmlConfigFile);

            if (BIBRecordingTrunk.Length > 0)
            {
                VRAPIASM.VRAPIEnv.SetCiscoBIBRecordingTrunkName(BIBRecordingTrunk);
            }

            if (BIBIncomingTrunk.Length > 0)
            {
                VRAPIASM.VRAPIEnv.SetCiscoBIBIncomingTrunkName(BIBIncomingTrunk);
            }

            if (BIBOutgoingTrunk.Length > 0)
            {
                VRAPIASM.VRAPIEnv.SetCiscoBIBOutgoingTrunkName(BIBOutgoingTrunk);
            }

            //the following code is for OptiLogix board only
            for (int i = 0; i < 10; i++)
            {
                if (DeviceType[i] >= 0 && DeviceType[i] != 8 && DeviceType[i] != 20)
                    VRAPIASM.VRAPIEnv.SetDeviceType(i, DeviceType[i], "", IntPtr.Zero);
            }

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 1");

            VRAPIASM.VRAPIEnv.StartCapture();

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 2");

            MaxChanNum = VRAPIASM.VRAPIEnv.GetChannelCount();

            Channels = new VR2Channel[MaxChanNum];

            for (int i = 0; i < MaxChanNum; i++)
            {
                Channels[i] = new VR2Channel();
                Channels[i].ChanIndex = i;

                if (RecordPauseOpt != 0)
                    VRAPIASM.VRAPIEnv.SetPauseOption(i, RecordPauseOpt);
            }

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 3");

            //Start DB
            try
            {
                if (db_set != null)
                {
                    //If DB is not available and it is trying to connect to DB
                    //It might take 20 seconds to start, and slow down the GUI interface
                    if (db_set.ConnectDB())
                    {
                        //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 3-1");
                        db_set.TestTables();
                        //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 3-2");
                        ResetChannelsTable();
                        //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 3-3");
                    }
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 4");

            StartManager(); //need this line before mainThread.Start, otherwise Run function may need to use manager class

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 5");

            isExiting = false;
            mainThread.Start(this);

            if (VRAPIASM.VRAPIEnv.IsLicensed() != 0)
            {
                VRAPIASM.VRAPIEnv.Log(4, "Licensed Software");
            }
            else
            {
                VRAPIASM.VRAPIEnv.Log(1, "NOT Licensed Software. ONLY record first 30 seconds of each call!");
            }


            wav_work.StartConvert();

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 6");

            StartTAPIConnection();

            //VRAPIASM.VRAPIEnv.Log(4, "VR2Main.Start Place holder 7");
        }

        public void RestartTAPIConnection()
        {
            VRAPIASM.VRAPIEnv.Log(1, "Will call RestartTAPIConnection!");
            //CloseTAPIConnection();
            //Thread.Sleep(500);
            //StartTAPIConnection();
        }

        public void StartTAPIConnection()
        {
            //TAPI
            TAPIIsClosing = 0;

            if (TAPIMonitorLines.Length > 0)
            {
                // Set the serial number if you purchased AddTapi.NET
                TapiApp.SerialNumber = "2CBCI9C-CKU828D-38QTN3C-7PW22";
                // Initialize AddTapi
                TapiApp.Initialize("VR2");
                VRAPIASM.VRAPIEnv.Log(4, "TapiApp.Initialized!");
                // Subscribe to events from AddTapi
                TapiApp.TapiError += OnTapiError;
                TapiApp.LineAdded += OnLineAdded;
                TapiApp.LineClosed += OnLineClosed;
                TapiApp.LineRemoved += OnLineRemoved;
                TapiApp.IncomingCall += OnIncomingCall;
                TapiApp.OutgoingCall += OnOutgoingCall;
                TapiApp.CallConnected += OnCallConnected;
                TapiApp.CallDisconnected += OnCallDisconnected;
                TapiApp.LineDeviceState += OnLineDeviceState;

                foreach (TapiLine line in TapiApp.Lines)
                {
                    if (TAPIMonitorLines.Contains(line.Name + ";"))
                    {
                        // Check if the line is already open
                        if (line.IsOpen)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, "Already monitoring line " + line.Name);
                            continue;
                        }
                        // Open selected line
                        try
                        {
                            line.RingsToAnswer = 0;
                            line.Open(true, null);
                            VRAPIASM.VRAPIEnv.Log(4, "Started monitoring line " + line.Name);
                        }
                        catch (TapiException exc)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, "TapiException! " + exc.Message);
                        }
                        catch (Exception exc)
                        {
                            VRAPIASM.VRAPIEnv.Log(1, "Exception! " + exc.Message);
                        }
                    }
                }
            }
        }

        public bool IsLicensed()
        {
            return VRAPIASM.VRAPIEnv.IsLicensed() != 0;
        }

        public void CloseTAPIConnection()
        {
            // Close selected line
            TAPIIsClosing = 1;
            foreach (TapiLine line in TapiApp.Lines)
            {
                if (TAPIMonitorLines.Contains(line.Name + ";"))
                {
                    // Check if the line is already open
                    try
                    {
                        if (line.IsOpen)
                        {
                            line.Close();
                        }
                        VRAPIASM.VRAPIEnv.Log(4, "Stopped monitoring line " + line.Name);
                    }
                    catch (TapiException exc)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "TapiException! " + exc.Message);
                    }
                    catch (Exception exc)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "Exception! " + exc.Message);
                    }

                }
            }

            try
            {
                TapiApp.Shutdown();
                VRAPIASM.VRAPIEnv.Log(4, "TapiApp.Shutdown!");
            }
            catch (TapiException exc)
            {
                VRAPIASM.VRAPIEnv.Log(1, "TapiException! " + exc.Message);
            }
            catch (Exception exc)
            {
                VRAPIASM.VRAPIEnv.Log(1, "Exception! " + exc.Message);
            }

            TAPIIsClosing = 0;
        }

        public void Stop()
        {
            ////////////////////////
            //close TAPI line first
            CloseTAPIConnection();

            isExiting = true;

            wav_work.StopConvert();

            if (SamsungPBXCDRIP.Length > 0 && SamsungPBXCDRPort > 0)
            {
                ss_cdr_work.StopProcess();
            }

            mainThread.Join();

            StopManager();

            try
            {
                if (db_set != null)
                {
                    db_set.DisconnectDB();
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
            }

            VRAPIASM.VRAPIEnv.StopCapture();
            VRAPIASM.VRAPIEnv.FreeCapture();           
        }

        public static DateTime GetDotNetDateTime(string s)
        {
            string temp = "";
            temp += s[0];
            temp += s[1];
            temp += s[2];
            temp += s[3];
            int dtYear = 2000;

            try
            {
                dtYear = Convert.ToInt32(temp);
            }
            catch (Exception)
            {
            }

            temp = "";
            temp += s[5];
            temp += s[6];
            int dtMonth = 1;

            try
            {
                dtMonth = Convert.ToInt32(temp);
            }
            catch (Exception)
            {
            }

            temp = "";
            temp += s[8];
            temp += s[9];
            int dtDay = 1;
            try
            {
                dtDay = Convert.ToInt32(temp);
            }
            catch (Exception)
            {
            }

            temp = "";
            temp += s[11];
            temp += s[12];
            int dtHour = 1;

            try
            {
                dtHour = Convert.ToInt32(temp);
            }
            catch (Exception)
            {
            }

            temp = "";
            temp += s[14];
            temp += s[15];
            int dtMinute = 1;

            try
            {
                dtMinute = Convert.ToInt32(temp);
            }
            catch (Exception)
            {
            }

            temp = "";
            temp += s[17];
            temp += s[18];
            int dtSecond = 1;

            try
            {
                dtSecond = Convert.ToInt32(temp);
            }
            catch (Exception)
            {
            }

            DateTime dt = new DateTime(dtYear, dtMonth, dtDay, dtHour, dtMinute, dtSecond);
            return dt;
        }


        public static string GetSQLDateTime(DateTime dt)
        {
            return dt.ToString("yyyy-MM-ddTHH:mm:ss");
            /*
            string sret = "";
            sret += dt.Year.ToString() + "-" + dt.Month.ToString() + "-" + dt.Day.ToString() + " ";
            sret += dt.Hour.ToString() + ":" + dt.Minute.ToString() + ":" + dt.Second.ToString();
            return sret;
             */
        }

        public bool CleanUpDB()
        {
            if (KeepRecordMaxDays > 0 && db_set != null)
            {
                DateTime dt = DateTime.Now;
                dt = dt.AddDays(-KeepRecordMaxDays);

                if (!db_set.IsDBConnected())
                {
                    if (!db_set.ConnectDB())
                        return false;
                }

                string commandStr = "DELETE FROM " + db_set.CallLogTableName + " WHERE TimeEnd < '" + GetSQLDateTime(dt) + "'";
                //VRAPIASM.VRAPIEnv.Log(4, "SQL: " + commandStr);

                try
                {
                    SqlCommand myComm = new SqlCommand(commandStr, db_set.myConn);
                    myComm.CommandTimeout = 5;
                    int rowAffected = myComm.ExecuteNonQuery();
                    if (rowAffected > 0)
                    {
                        VRAPIASM.VRAPIEnv.Log(4, "Deleted " + rowAffected.ToString() + " rows in TABLE: " + db_set.CallLogTableName);
                    }
                }
                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, "SQL:" + commandStr);
                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                    db_set.DisconnectDB();
                    return false;
                }

            }

            return true;
        }

        public string RemoveIPPort(string s)
        {
            string ret = s;
            if (s.Contains(":"))
            {
                int po = s.LastIndexOf(":");
                if (po != 0)
                {
                    ret = s.Substring(0, po);
                }
            }
            return ret;
        }

        public string GetAddrName(string s)
        {
            string ret = "";
            char[] trim_char = { '"', ' ' };

            if (s.Contains("<sip:"))
            {
                int po = s.LastIndexOf("<sip:");
                if (po != 0)
                {
                    ret = s.Substring(0, po);
                    ret.Trim();
                    ret.TrimEnd(trim_char);
                    ret.TrimStart(trim_char);
                }
            }
            return ret;
        }

        public static string GetSIPAddressInfo(int flag, string sipAddr)
        {
            if (sipAddr == null)
                return "";

            if (sipAddr.Length == 0)
                return "";

            //a fix for google andriod phone bad implementation
            if (sipAddr.IndexOf("<sip:") == -1 && sipAddr.IndexOf("sip:") >= 0)
            {
                int idx1 = sipAddr.IndexOf("sip:");
                if (idx1 == 0)
                {
                    sipAddr = "<" + sipAddr + ">";
                }
                else
                {
                    sipAddr = sipAddr.Substring(0, idx1) + "<" + sipAddr.Substring(idx1) + ">";
                }
            }

            int nPos = 0;
            int nPos1 = 0;

            if (flag == 0) //display name
            {
                nPos = sipAddr.IndexOf("<sip:");
                if (nPos == -1 || nPos == 0)
                    return "";
                else
                    return sipAddr.Substring(0, nPos);
            }
            else if (flag == 1) //user name
            {
                nPos = sipAddr.IndexOf("<sip:");
                if (nPos == -1)
                    return "";
                else
                {
                    nPos += 5;

                    nPos1 = sipAddr.IndexOf('@', nPos);
                    if (nPos1 == -1)
                        return "";
                    else
                        return sipAddr.Substring(nPos, nPos1 - nPos);
                }
            }
            else if (flag == 2) //ip address
            {
                nPos = sipAddr.IndexOf('@');
                if (nPos == -1)
                {
                    nPos = sipAddr.IndexOf("<sip:");
                    if (nPos == -1)
                        return "";
                    else
                        nPos += 5;
                }
                else
                    nPos += 1;

                nPos1 = sipAddr.IndexOf('>', nPos);

                string ipAddr = "";

                if (nPos1 == -1)
                    ipAddr = sipAddr.Substring(nPos);
                else
                    ipAddr = sipAddr.Substring(nPos, nPos1 - nPos);

                nPos = ipAddr.IndexOf(';');
                if (nPos != -1)
                    ipAddr = ipAddr.Substring(0, nPos);

                nPos = ipAddr.IndexOf(':');
                if (nPos != -1)
                    ipAddr = ipAddr.Substring(0, nPos);

                return ipAddr;
            }
            else if (flag == 3) //port
            {
                nPos = sipAddr.IndexOf('@');
                if (nPos == -1)
                {
                    nPos = sipAddr.IndexOf("<sip:");
                    if (nPos == -1)
                        return "";
                    else
                        nPos += 5;
                }
                else
                    nPos += 1;

                nPos1 = sipAddr.IndexOf('>', nPos);

                string ipAddr = "";

                if (nPos1 == -1)
                    ipAddr = sipAddr.Substring(nPos);
                else
                    ipAddr = sipAddr.Substring(nPos, nPos1 - nPos);

                nPos = ipAddr.IndexOf(';');
                if (nPos != -1)
                    ipAddr = ipAddr.Substring(0, nPos);

                nPos = ipAddr.IndexOf(':');
                if (nPos == -1)
                    ipAddr = "";
                else
                    ipAddr = ipAddr.Substring(nPos + 1);

                return ipAddr;
            }

            return "";
        }

        public string DoIDMapping(string s)
        {
            if (idMaps != null)
            {
                if (idMaps.Length > 0)
                {
                    for (int i = 0; i < idMaps.Length; i++)
                    {
                        if (idMaps[i].OrgID == s)
                        {
                            return idMaps[i].RepID;
                        }
                    }
                }
            }

            return s;
        }
        /*
        public string GetAddrID(string s)
        {
            string ret = "";

            try
            {
                if (s.Contains("sip:"))
                {
                    string sDisplayName = GetSIPAddressInfo(0, s);
                    string sUserName = GetSIPAddressInfo(1, s);

                    char[] trimChars = {'-', ' ', '\'', '"'};
                    sDisplayName = sDisplayName.Trim(trimChars);
                    sUserName = sUserName.Trim(trimChars);

                    sDisplayName = sDisplayName.Replace('\'', ' ');
                    sUserName = sUserName.Replace('\'', ' ');

                    sDisplayName = sDisplayName.Trim();
                    sUserName = DoIDMapping(sUserName.Trim());

                    if(sDisplayName.Length > 0)
                        ret = sDisplayName + "-" + sUserName;
                    else
                        ret = sUserName;

                    //int po = s.LastIndexOf("sip:");
                    //string s1 = s.Substring(po + 4);
                    //if (s1.Contains("@"))
                    //{
                    //    for (int i = po + 4; i < s.Length; i++)
                    //    {
                    //        if (s[i] != '@')
                    //            ret += s[i];
                    //        else
                    //            break;
                    //    }
                    //}
                }
                else
                    ret = DoIDMapping(s);
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, "Get ID Error From String: " + s);
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                ret = s;
            }

            if (ret.Length > 80)
                ret = ret.Substring(0, 80);

            return ret;
        }*/

        public string GetIDFromSIPAddr(string s)
        {
            string ret = "";

            try
            {
                if (s.Contains("sip:"))
                {
                    string sUserName = GetSIPAddressInfo(1, s);

                    char[] trimChars = { '-', ' ', '\'', '"' };

                    sUserName = sUserName.Trim(trimChars);

                    sUserName = sUserName.Replace('\'', ' ');

                    sUserName = DoIDMapping(sUserName.Trim());

                    ret = sUserName;
                }
                else
                    ret = DoIDMapping(s);
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, "Get UserName Error From String: " + s);
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                ret = s;
            }

            if (ret.Length > 80)
                ret = ret.Substring(0, 80);

            return ret;
        }

        public string GetDisplayNameFromSIPAddr(string s)
        {
            string ret = "";

            try
            {
                if (s.Contains("sip:"))
                {
                    string sDisplayName = GetSIPAddressInfo(0, s);

                    char[] trimChars = { '-', ' ', '\'', '"' };
                    sDisplayName = sDisplayName.Trim(trimChars);

                    sDisplayName = sDisplayName.Replace('\'', ' ');

                    sDisplayName = DoIDMapping(sDisplayName.Trim());

                    ret = sDisplayName;
                }
                else
                    ret = DoIDMapping(s);
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, "Get ID Error From String: " + s);
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                ret = s;
            }

            if (ret.Length > 80)
                ret = ret.Substring(0, 80);

            return ret;
        }

        public bool SaveCallDataToDB(VR2Channel call)
        {
            if (db_set == null)
            {
                VRAPIASM.VRAPIEnv.Log(3, "SaveCallDataToDB db_set is null!");
                return false;
            }

            if (!db_set.IsDBConnected())
            {
                if (!db_set.ConnectDB())
                {
                    VRAPIASM.VRAPIEnv.Log(3, "SaveCallDataToDB connect to DB failed!");
                    return false;
                }
            }

            SqlCommand myComm = null;

            string commandStr = "SELECT * FROM " + db_set.CallLogTableName + " where UniqueID = '" + call.UniqueID + "'";


            string P_Asserted_Identity = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "P-Asserted-Identity:");
            string P_Charging_Vector = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "P-Charging-Vector:");
            string Remote_Party_ID = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "Remote-Party-ID:");
            string SIPReason = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "Reason:");
            string SIPDate = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "Date:");
            string Caller_User_Agent = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "User-Agent:");
            string Called_User_Agent = VR2Channel.GetSIPHeaderValue(call.OrgSIPResponse, "User-Agent:");
            string Accept_Language = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "Accept-Language:");
            string x_caller = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "x-caller=");
            //string sip_call_id = VR2Channel.GetSIPHeaderValue(call.OrgSIPInvite, "Call-ID:");
            string last_sip_resp_code = call.Reason.ToString();

            if(call.Reason == 999999)
                last_sip_resp_code = "CALLER CANCEL";

            int caller_audio_codec = call.CallerAudioCodec;
            int called_audio_codec = call.CalleeAudioCodec;
            string caller_rtp_addr = call.CallerRTPAddr;
            string called_rtp_addr = call.CalleeRTPAddr;

            try
            {
                myComm = new SqlCommand(commandStr, db_set.myConn);
                myComm.CommandTimeout = 3;
                SqlDataReader myReader = myComm.ExecuteReader();

                if (myReader.HasRows)
                {
                    myReader.Close();
                    //myComm.CommandText = "UPDATE cfg_sys SET CfgValue = '" + cfgValue + "', ModTag = " + (bMod ? "1" : "0") + " WHERE CfgName = '" + cfgName + "'";

                    VRAPIASM.VRAPIEnv.Log(4, "Updating DB record");

                    //Second Step INSERT
                    commandStr = "UPDATE " + db_set.CallLogTableName + " SET ";

                    int chanid = call.ChanIndex + 1;
                    commandStr += "ChanID=" + chanid.ToString() + ", ";
                    if (call.CallConnected)
                        commandStr += "Succeed=1, ";
                    else
                        commandStr += "Succeed=0, ";

                    commandStr += "CallerIP='" + call.CallerIP + "', ";
                    commandStr += "CallerID='" + GetIDFromSIPAddr(call.CallerID) + "', ";
                    commandStr += "CallerName='', ";

                    commandStr += "CalleeIP='" + call.CalleeIP + "', ";
                    commandStr += "CalleeID='" + GetIDFromSIPAddr(call.CalleeID) + "', ";
                    commandStr += "CalleeName='', ";

                    commandStr += "TimeInit='" + GetSQLDateTime(call.InitTime) + "', ";
                    if (call.CallConnected)
                        commandStr += "TimeBegin='" + GetSQLDateTime(call.ConnectTime) + "', ";
                    else
                        commandStr += "TimeBegin=NULL, ";

                    commandStr += "TimeEnd='" + GetSQLDateTime(call.EndTime) + "', ";

                    if (call.CallConnected)
                    {
                        TimeSpan tsp = call.EndTime - call.ConnectTime;
                        int tsp_seconds = Convert.ToInt32(tsp.TotalSeconds);
                        /*int tsp_seconds = tsp.Days * 24 * 60 * 60 +
                                                  tsp.Hours * 60 * 60 +
                                                  tsp.Minutes * 60 +
                                                  tsp.Seconds;
                         */
                        commandStr += "Duration=" + tsp_seconds.ToString() + ", ";
                    }
                    else
                        commandStr += "Duration=0, ";

                    if (call.AudioFile.Length > 0)
                    {
                        if (!File.Exists(call.AudioFile))
                            VRAPIASM.VRAPIEnv.Log(4, call.AudioFile + " doesn't exist!");
                    }

                    if (call.CallConnected)
                    {
                        commandStr += "RecordPath='" + call.AudioFile + "', ";
                        commandStr += "RecordFileNum=" + call.AudioFileNum.ToString() + ", ";
                    }
                    else
                    {
                        //for 183 session progress, we still get the ringing and RTP in recording audio file, so still writing into the DB
                        commandStr += "RecordPath='" + call.AudioFile + "', ";
                        commandStr += "RecordFileNum=" + call.AudioFileNum.ToString() + ", ";
                        //commandStr += "RecordPath='', ";
                        //commandStr += "RecordFileNum=0, ";
                    }

                    if (call.CallDir < 0) call.CallDir = 0;

                    commandStr += "DIR=" + call.CallDir.ToString() + ", ";
                    commandStr += "DTMF='" + call.DTMFStr + "', ";
                    commandStr += "VRType=" + VRType.ToString() + ", ";
                    commandStr += "ChanName='" + call.ChanName + "' ";
                    commandStr += " WHERE UniqueID = '" + call.UniqueID + "'";
                    myComm.CommandText = commandStr;
                    if (myComm.ExecuteNonQuery() == 1)
                    {
                    }
                    else
                    {
                    }
                }
                else
                {
                    myReader.Close();

                    VRAPIASM.VRAPIEnv.Log(4, "Inserting DB record");

                    //Second Step INSERT
                    //commandStr = "INSERT INTO " + db_set.CallLogTableName + "(ChanID, Succeed, CallerIP, CallerID, CallerName, CalleeIP, CalleeID, CalleeName, TimeInit, TimeBegin, TimeEnd, Duration, UniqueID, RecordPath, RecordFileNum, DIR, DTMF, VRType, ChanName, PAssertedIdentity, PChargingVector, RemotePartyID, SIPReason, SIPDate, CallerSIPUserAgent, CalledSIPUserAgent, SIPCallID, AcceptLanguage, XCaller, LastSIPResponseCode, CallerAudioCodec, CalledAudioCodec, CallerRTPAddr, CalledRTPAddr) VALUES(";
                    commandStr = "INSERT INTO " + db_set.CallLogTableName + "(ChanID, Succeed, CallerIP, CallerID, CallerName, CalleeIP, CalleeID, CalleeName, TimeInit, TimeBegin, TimeEnd, Duration, UniqueID, RecordPath, RecordFileNum, DIR, DTMF, VRType, ChanName) VALUES(";

                    int chanid = call.ChanIndex + 1;
                    commandStr += chanid.ToString() + ", ";

                    if (call.CallConnected)
                        commandStr += "1, ";
                    else
                        commandStr += "0, ";

                    commandStr += "'" + call.CallerIP + "', ";
                    commandStr += "@Caller, ";
                    commandStr += "@CallerName, ";

                    commandStr += "'" + call.CalleeIP + "', ";
                    commandStr += "@Callee, ";
                    commandStr += "@CalleeName, ";

                    commandStr += "'" + GetSQLDateTime(call.InitTime) + "', ";
                    if (call.CallConnected)
                        commandStr += "'" + GetSQLDateTime(call.ConnectTime) + "', ";
                    else
                        commandStr += "NULL, ";

                    commandStr += "'" + GetSQLDateTime(call.EndTime) + "', ";

                    if (call.CallConnected)
                    {
                        TimeSpan tsp = call.EndTime - call.ConnectTime;
                        int tsp_seconds = Convert.ToInt32(tsp.TotalSeconds);
                        commandStr += tsp_seconds.ToString() + ", ";
                    }
                    else
                        commandStr += "0, ";

                    commandStr += "'" + call.UniqueID + "', ";

                    string audioFileName = call.AudioFile;

                    if (call.AudioFile.Length > 0)
                    {
                        if (!File.Exists(call.AudioFile))
                            VRAPIASM.VRAPIEnv.Log(4, call.AudioFile + " doesn't exist!");
                    }

                    if (call.CallConnected)
                    {
                        commandStr += "@AudioFN, ";
                        commandStr += call.AudioFileNum.ToString() + ", ";
                    }
                    else
                    {
                        commandStr += "@AudioFN, ";
                        commandStr += call.AudioFileNum.ToString() + ", ";

                        //commandStr += "@AudioFN, ";
                        //commandStr += "0, ";
                    }

                    if (call.CallDir < 0) call.CallDir = 0;
                    commandStr += call.CallDir.ToString() + ", ";
                    commandStr += "'" + call.DTMFStr + "', " + VRType.ToString() + ", '" + call.ChanName + "')"; //, @PAssertedIdentity, @PChargingVector, @RemotePartyID, @SIPReason, @SIPDate, @CallerSIPUserAgent, @CalledSIPUserAgent, @SIPCallID, @AcceptLanguage, @xcaller, @LastSIPResponseCode, @CallerAudioCodec, @CalledAudioCodec, @CallerRTPAddr, @CalledRTPAddr)";

                    myComm.CommandTimeout = 3;
                    myComm.CommandText = commandStr;

                    myComm.Parameters.AddWithValue("@Caller", GetIDFromSIPAddr(call.CallerID));
                    myComm.Parameters.AddWithValue("@CallerName", GetDisplayNameFromSIPAddr(call.CallerID));
                    myComm.Parameters.AddWithValue("@Callee", GetIDFromSIPAddr(call.CalleeID));
                    myComm.Parameters.AddWithValue("@CalleeName", GetDisplayNameFromSIPAddr(call.CalleeID));
                    myComm.Parameters.AddWithValue("@AudioFN", audioFileName);

                    /*


                    
                    myComm.Parameters.AddWithValue("@AcceptLanguage", Accept_Language);
                    myComm.Parameters.AddWithValue("@xcaller", x_caller);

                    myComm.Parameters.AddWithValue("@LastSIPResponseCode", last_sip_resp_code);
                    myComm.Parameters.AddWithValue("@CallerAudioCodec", caller_audio_codec);
                    myComm.Parameters.AddWithValue("@CalledAudioCodec", called_audio_codec);
                    myComm.Parameters.AddWithValue("@CallerRTPAddr", caller_rtp_addr);
                    myComm.Parameters.AddWithValue("@CalledRTPAddr", called_rtp_addr);*/

                    if (myComm.ExecuteNonQuery() == 1)
                    {
                    }
                    else
                    {
                    }

                    try
                    {
                        commandStr = "UPDATE " + db_set.CallLogTableName + " SET PAssertedIdentity=@PAssertedIdentity, PChargingVector=@PChargingVector, RemotePartyID=@RemotePartyID WHERE UniqueID='" + call.UniqueID + "'";
                        myComm.CommandTimeout = 3;
                        myComm.CommandText = commandStr;
                        myComm.Parameters.AddWithValue("@PAssertedIdentity", P_Asserted_Identity);
                        myComm.Parameters.AddWithValue("@PChargingVector", P_Charging_Vector);
                        myComm.Parameters.AddWithValue("@RemotePartyID", Remote_Party_ID);
                        if (myComm.ExecuteNonQuery() == 1)
                        {
                        }
                        else
                        {
                        }
                    }
                    catch (Exception e)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "SQL:" + commandStr);
                        VRAPIASM.VRAPIEnv.Log(1, e.ToString());
                        db_set.DisconnectDB();
                        return false;
                    }

                    try
                    {
                        commandStr = "UPDATE " + db_set.CallLogTableName + " SET SIPReason=@SIPReason, SIPDate=@SIPDate, CallerSIPUserAgent=@CallerSIPUserAgent, CalledSIPUserAgent=@CalledSIPUserAgent, SIPCallID=@SIPCallID  WHERE UniqueID='" + call.UniqueID + "'";
                        myComm.CommandTimeout = 3;
                        myComm.CommandText = commandStr;
                        myComm.Parameters.AddWithValue("@SIPReason", SIPReason);
                        myComm.Parameters.AddWithValue("@SIPDate", SIPDate);
                        myComm.Parameters.AddWithValue("@CallerSIPUserAgent", Caller_User_Agent);
                        myComm.Parameters.AddWithValue("@CalledSIPUserAgent", Called_User_Agent);
                        myComm.Parameters.AddWithValue("@SIPCallID", call.SIPCallID);
                        if (myComm.ExecuteNonQuery() == 1)
                        {
                        }
                        else
                        {
                        }
                    }
                    catch (Exception e)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "SQL:" + commandStr);
                        VRAPIASM.VRAPIEnv.Log(1, e.ToString());
                        db_set.DisconnectDB();
                        return false;
                    }

                    try
                    {
                        commandStr = "UPDATE " + db_set.CallLogTableName + " SET AcceptLanguage=@AcceptLanguage, XCaller=@XCaller, LastSIPResponseCode=@LastSIPResponseCode WHERE UniqueID='" + call.UniqueID + "'";
                        myComm.CommandTimeout = 3;
                        myComm.CommandText = commandStr;
                        myComm.Parameters.AddWithValue("@AcceptLanguage", Accept_Language);
                        myComm.Parameters.AddWithValue("@XCaller", x_caller);
                        myComm.Parameters.AddWithValue("@LastSIPResponseCode", last_sip_resp_code);

                        if (myComm.ExecuteNonQuery() == 1)
                        {
                        }
                        else
                        {
                        }
                    }
                    catch (Exception e)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "SQL:" + commandStr);
                        VRAPIASM.VRAPIEnv.Log(1, e.ToString());
                        db_set.DisconnectDB();
                        return false;
                    }

                    try
                    {
                        commandStr = "UPDATE " + db_set.CallLogTableName + " SET CallerAudioCodec=@CallerAudioCodec, CalledAudioCodec=@CalledAudioCodec, CallerRTPAddr=@CallerRTPAddr, CalledRTPAddr=@CalledRTPAddr WHERE UniqueID='" + call.UniqueID + "'";
                        myComm.CommandTimeout = 3;
                        myComm.CommandText = commandStr;
                        myComm.Parameters.AddWithValue("@CallerAudioCodec", caller_audio_codec);
                        myComm.Parameters.AddWithValue("@CalledAudioCodec", called_audio_codec);
                        myComm.Parameters.AddWithValue("@CallerRTPAddr", caller_rtp_addr);
                        myComm.Parameters.AddWithValue("@CalledRTPAddr", called_rtp_addr);

                        if (myComm.ExecuteNonQuery() == 1)
                        {
                        }
                        else
                        {
                        }
                    }
                    catch (Exception e)
                    {
                        VRAPIASM.VRAPIEnv.Log(1, "SQL:" + commandStr);
                        VRAPIASM.VRAPIEnv.Log(1, e.ToString());
                        db_set.DisconnectDB();
                        return false;
                    }

                }
            }
            catch (Exception e)
            {
                VRAPIASM.VRAPIEnv.Log(1, "SQL:" + commandStr);
                VRAPIASM.VRAPIEnv.Log(1, e.ToString());
                db_set.DisconnectDB();
                return false;
            }


            return true;
        }

        public string UpdateChannelToDB(VR2Channel chan)
        {
/*
            if (db_set == null || !updateChanStatusToDB)
                return false;

            //in the case that DB is down and can't be accessed, this attempt to connection will really take
            //long time(20 seconds), so the GUI is frozen. The best way is to jsut give up.
            if (!db_set.IsDBConnected())
                return false;
 */

            string sqlstr = "";

            sqlstr = "Update " + db_set.ChannelStatusTableName + " SET ";
            sqlstr += "CallerIP='" + chan.CallerIP + "', ";
            sqlstr += "CallerID='" + GetIDFromSIPAddr(chan.CallerID) + "', ";

            sqlstr += "CalleeIP='" + chan.CalleeIP + "', ";
            sqlstr += "CalleeID='" + GetIDFromSIPAddr(chan.CalleeID) + "', ";

            sqlstr += "TimeInit='" + GetSQLDateTime(chan.InitTime) + "', ";
            sqlstr += "TimeBegin='" + GetSQLDateTime(chan.ConnectTime) + "', ";
            sqlstr += "TimeEnd='" + GetSQLDateTime(chan.EndTime) + "', ";

            sqlstr += "UniqueID='" + chan.UniqueID + "', ";
            sqlstr += "RecordPath='" + chan.AudioFile + "', ";

            if (chan.CallDir < 0) chan.CallDir = 0;
            sqlstr += "DIR=" + chan.CallDir.ToString() + ", ";
            sqlstr += "CallConnected=" + (chan.CallConnected ? "1, " : "0, ");
            sqlstr += "ChanStatus=" + chan.ChanStatus.ToString() + ", ";
            sqlstr += "ChanName='" + chan.ChanName + "' ";
            sqlstr += " WHERE ChanID=" + chan.ChanIndex.ToString();

            sqlstr += ";";

            chan.ModTag = false;

/*
            try
            {
                SqlCommand catCMD = db_set.myConn.CreateCommand();
                catCMD.CommandTimeout = 3;
                catCMD.CommandText = sqlstr;
                if (catCMD.ExecuteNonQuery() == 1)
                {
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, "SQL:" + sqlstr);
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                return false;
            }
*/
            return sqlstr;
        }

        public bool ResetChannelsTable()
        {
            if (db_set == null || !updateChanStatusToDB)
                return false;

            if (!db_set.IsDBConnected())
            {
                if (!db_set.ConnectDB())
                    return false;
            }

            string sqlstr = "";
            try
            {
                SqlCommand catCMD = db_set.myConn.CreateCommand();
                catCMD.CommandTimeout = 3;
                catCMD.CommandText = "DELETE FROM " + db_set.ChannelStatusTableName;
                if (catCMD.ExecuteNonQuery() == 1)
                {
                }
            }
            catch (Exception ex)
            {
                VRAPIASM.VRAPIEnv.Log(1, "SQL: DELETE FROM " + db_set.ChannelStatusTableName);
                VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                return false;
            }

            for (int i = 0; i < MaxChanNum; i++)
            {
                VR2Channel chan = Channels[i];

                sqlstr = "INSERT INTO " + db_set.ChannelStatusTableName + "(ChanID, CallerIP, CallerID, CalleeIP, CalleeID, TimeInit, TimeBegin, TimeEnd, UniqueID, RecordPath, DIR, CallConnected, ChanStatus, ChanName) VALUES(";
                sqlstr += i.ToString() + ", ";
                sqlstr += "'" + chan.CallerIP + "', ";
                sqlstr += "'" + GetIDFromSIPAddr(chan.CallerID) + "', ";

                sqlstr += "'" + chan.CalleeIP + "', ";
                sqlstr += "'" + GetIDFromSIPAddr(chan.CalleeID) + "', ";

                sqlstr += "'" + GetSQLDateTime(chan.InitTime) + "', ";
                sqlstr += "'" + GetSQLDateTime(chan.ConnectTime) + "', ";
                sqlstr += "'" + GetSQLDateTime(chan.EndTime) + "', ";

                sqlstr += "'" + chan.UniqueID + "', ";
                sqlstr += "'" + chan.AudioFile + "', ";

                if (chan.CallDir < 0) chan.CallDir = 0;
                sqlstr += chan.CallDir.ToString() + ", ";
                sqlstr += chan.CallConnected ? "1, " : "0, ";
                sqlstr += chan.ChanStatus.ToString() +", '" + chan.ChanName + "')";

                try
                {
                    SqlCommand catCMD = db_set.myConn.CreateCommand();
                    catCMD.CommandTimeout = 3;
                    catCMD.CommandText = sqlstr;
                    if (catCMD.ExecuteNonQuery() == 1)
                    {
                    }
                }
                catch (Exception ex)
                {
                    VRAPIASM.VRAPIEnv.Log(1, "SQL:" + sqlstr);
                    VRAPIASM.VRAPIEnv.Log(1, ex.ToString());
                    return false;
                }
            }

            return true;

        }

///////////////////////TAPI
        void LogoutTapiCalls()
        {
            lock (TapiCalls)
            {
                foreach (TAPICDR cdr in TapiCalls)
                {
                    string logStr = "";
                    logStr += "guid:" + cdr.CallGuid + " ";
                    logStr += "UniqueID:" + cdr.UniqueID + " ";
                    logStr += "CallerID:" + cdr.CallerID + " ";
                    logStr += "CallerIDName:" + cdr.CallerIDName + " ";
                    logStr += "CalledID:" + cdr.CalledID + " ";
                    logStr += "CalledIDName:" + cdr.CalledIDName + " ";
                    logStr += "CallDone:" + cdr.CallDone.ToString()+ " ";

                    logStr += "CallStartTime:" + cdr.CallStartTime.ToString() + " ";
                    logStr += "CallConnectedTime:" + cdr.CallConnectedTime.ToString() + " ";
                    logStr += "CallEndTime:" + cdr.CallEndTime.ToString() + " ";

                    logStr += "CallConnected:" + cdr.CallConnected.ToString() + " ";

                    VRAPIASM.VRAPIEnv.Log(4, logStr);
                }
            }
        }

        // This event handler is called when a new incoming call is received.
        void OnIncomingCall(object sender, TapiEventArgs args)
        {
            // Display message in the log
            string msg;
            msg = String.Format("Incoming call from CallerIDName {0} CallerID {1} on line '{2}'.  CalledIDName {3}, CalledID {4}, Guid {5}",
                       args.Call.CallerIDName, args.Call.CallerID, args.Line.Name, args.Call.CalledIDName, args.Call.CalledID, args.Call.Guid.ToString());
            VRAPIASM.VRAPIEnv.Log(4, msg);

            lock (TapiCalls)
            {
                //First trying to find out if there is a call like that already in the cdr list
                bool fnd = false;
                foreach (TAPICDR cdr in TapiCalls)
                {
                    if (cdr.CallGuid.Length > 0 && cdr.CallGuid == args.Call.Guid.ToString())
                    {
                        //find it is same message as before
                        fnd = true;
                        break;
                    }
                    else
                    {
                        TimeSpan ts = DateTime.Now - cdr.CallStartTime;
                        if (ts.TotalSeconds < 2 && cdr.CallerID == args.Call.CallerID && cdr.CalledID == args.Line.Name && !cdr.CallDone && cdr.CallDir == 0)
                        {
                            //find it is same message as before
                            fnd = true;
                            break;
                        }
                    }
                }

                if (!fnd)
                {

                    TAPICDR cdr = new TAPICDR();
                    cdr.CallerIDName = args.Call.CallerIDName;
                    cdr.CallerID = args.Call.CallerID;
                    cdr.CalledIDName = args.Call.CalledIDName;
                    cdr.CalledID = args.Line.Name;
                    cdr.CallStartTime = cdr.CallConnectedTime = cdr.CallEndTime = DateTime.Now;
                    cdr.CallDir = 0;
                    cdr.CallDone = false;
                    cdr.CallGuid = args.Call.Guid.ToString();

                    TapiCalls.Add(cdr);

                    VRAPIASM.VRAPIEnv.Log(4, "Added TAPI call into CDR list");
                }
                else
                {
                    VRAPIASM.VRAPIEnv.Log(4, "TAPI call is already in CDR list");
                }
            }

            LogoutTapiCalls();
        }

        // This event handler is called when a new outgoing call is detected.
        void OnOutgoingCall(object sender, TapiEventArgs args)
        {
            // Display message in the log
            string msg;
            msg = String.Format("Outgoing call to CalledID {0} on line '{1}'. CalledIDName {2}, CallerID {3}, CallerIDName {4}, Guid {5}",
                       args.Call.CalledID, args.Line.Name, args.Call.CalledIDName, args.Call.CallerID, args.Call.CallerIDName, args.Call.Guid.ToString());
            VRAPIASM.VRAPIEnv.Log(4, msg);
            
            ///////////////////////////////////////////////////////////////////////////
            lock (TapiCalls)
            {
                //First trying to find out if there is a call like that already in the cdr list
                bool fnd = false;
                foreach (TAPICDR cdr in TapiCalls)
                {
                    if (cdr.CallGuid.Length > 0 && cdr.CallGuid == args.Call.Guid.ToString())
                    {
                        //find it is same message as before
                        fnd = true;
                        break;
                    }
                    else
                    {
                        TimeSpan ts = DateTime.Now - cdr.CallStartTime;
                        if (ts.TotalSeconds < 2 && cdr.CallerID == args.Line.Name && cdr.CalledID == args.Call.CalledID && !cdr.CallDone && cdr.CallDir == 1)
                        {
                            //find it is same message as before
                            fnd = true;
                            break;
                        }
                    }
                }

                if (!fnd)
                {
                    TAPICDR cdr = new TAPICDR();

                    //  [2016-02-23 19:50:33] Found incoming call in TAPI cdr list and set it to done!
                    //  [2016-02-23 19:50:33] Disconnected incoming call from 0117997720 on line 'DCS Line 312', CallerIDName , CalledID 0100106359, CalledIDName IP Phone 2, Guid b83d90d5-ea19-4aff-8e7e-3bbae6e88807

                    //  [2016-02-23 19:50:33] Outgoing call to CalledID Unavail on line 'DCS Line 311'. CalledIDName , CallerID 0117997720, CallerIDName , Guid 36bba37b-f65f-4d1a-9a84-8c43a7f7cfa0
                    // the case ringing on 312, but answered on 311


                    //[2016-02-23 20:29:19] Disconnected incoming call from 0117997720 on line 'DCS Line 312', CallerIDName , CalledID 0100106359, CalledIDName IP Phone 2, Guid 861a2325-528f-4de5-a069-a97628915a81
                    //[2016-02-23 20:29:19] Outgoing call to CalledID 0100106359 on line 'DCS Line 311'. CalledIDName , CallerID 0117997720, CallerIDName , Guid 6103a7cb-fde8-41e8-b38c-6d5c7f5f3fde
                    //[2016-02-23 20:29:19] Added TAPI call into CDR list
                    //[2016-02-23 20:29:19] Found the call in TAPI cdr list and set it to connected!
                    //[2016-02-23 20:29:19] Connected outgoing call to 0100106359 on line 'DCS Line 311', CalledIDName , CallerIDName , CallerID 0117997720, Guid 6103a7cb-fde8-41e8-b38c-6d5c7f5f3fde
                    //  [2016-02-23 21:19:24] Outgoing call to CalledID Unavail on line 'DCS Line 311'. CalledIDName , CallerID 0117997720, CallerIDName , Guid 00fc3d5a-6f91-4709-9619-47f936fa9ffc
                    //  [2016-02-25 15:57:46] Outgoing call to CalledID 0100106359 on line 'DCS Line 311'. CalledIDName , CallerID 0117997720, CallerIDName , Guid 65d34f5d-35d0-4597-ae69-97f37a6df24d

                    bool reverse = false;
                    foreach (TAPICDR cdr1 in TapiCalls)
                    {
                        TimeSpan ts1 = DateTime.Now - cdr1.CallEndTime;
                        if (cdr1.CallDone && cdr1.CallerID == args.Call.CallerID && ts1.TotalSeconds <= 1 && cdr1.CallDir == 0)
                        {
                            reverse = true;
                        }
                    }

                    if (reverse)
                    {
                        //it seemed in this case it is incoming call but for someone else, and this extension answered
                        cdr.CallerIDName = args.Call.CallerIDName;
                        cdr.CallerID = args.Call.CallerID;
                        cdr.CalledIDName = args.Call.CalledIDName;
                        cdr.CalledID = args.Line.Name;
                        cdr.CallDir = 0;
                        cdr.Reversed = true;

                        VRAPIASM.VRAPIEnv.Log(4, "OnOutgoingCall out2inbound");
                    }
                    else
                    {
                        /*
                        cdr.CallerIDName = args.Call.CallerIDName;
                        cdr.CallerID = args.Line.Name;
                        cdr.CalledIDName = args.Call.CalledIDName;
                        cdr.CalledID = args.Call.CalledID;*/

                        cdr.CallerIDName = args.Call.CalledIDName;
                        cdr.CallerID = args.Line.Name;
                        cdr.CalledIDName = args.Call.CallerIDName;
                        cdr.CalledID = args.Call.CallerID;

                        cdr.CallDir = 1;
                    }
                    cdr.CallStartTime = cdr.CallConnectedTime = cdr.CallEndTime = DateTime.Now;
                    cdr.CallDone = false;
                    cdr.CallGuid = args.Call.Guid.ToString();

                    TapiCalls.Add(cdr);

                    VRAPIASM.VRAPIEnv.Log(4, "Added TAPI call into CDR list");
                }
                else
                {
                    VRAPIASM.VRAPIEnv.Log(4, "TAPI call is already in CDR list");
                }
            }

            LogoutTapiCalls();
        }

        // This event handler is called when the call has been connected.
        void OnCallConnected(object sender, TapiEventArgs args)
        {
            string msg;
            if (args.Call.Direction == TapiCallDirection.Incoming)
            {
                msg = String.Format("Connected incoming call from {0} on line '{1}', CallerIDName {2}, CalledID {3}, CalledIDName {4}, Guid {5}",
                           args.Call.CallerID, args.Line.Name, args.Call.CallerIDName, args.Call.CalledID, args.Call.CalledIDName, args.Call.Guid.ToString());
                VRAPIASM.VRAPIEnv.Log(4, msg);

                lock (TapiCalls)
                {
                    //First trying to find out if there is a call like that already in the cdr list
                    //if (cdr.CallID == args.Call.CallID)  ####DO NOT USE CALLID, as it is always 0


                    foreach (TAPICDR cdr in TapiCalls)
                    {
                        if (cdr.CallGuid.Length > 0 && cdr.CallGuid == args.Call.Guid.ToString())
                        {
                            cdr.CallConnectedTime = DateTime.Now;
                            cdr.CallConnected = true;

                            cdr.CallerIDName = args.Call.CallerIDName;
                            cdr.CallerID = args.Call.CallerID;
                            cdr.CalledIDName = args.Call.CalledIDName;
                            cdr.CalledID = args.Line.Name;

                            VRAPIASM.VRAPIEnv.Log(4, "Found the call in TAPI cdr list and set it to connected!");
                            break;
                        }
                        else
                        {
                            if (cdr.CallDir == 0 && cdr.CallerID == args.Call.CallerID && cdr.CalledID == args.Line.Name && !cdr.CallDone)
                            {
                                cdr.CallConnectedTime = DateTime.Now;
                                cdr.CallConnected = true;

                                cdr.CallerIDName = args.Call.CallerIDName;
                                cdr.CallerID = args.Call.CallerID;
                                cdr.CalledIDName = args.Call.CalledIDName;
                                cdr.CalledID = args.Line.Name;

                                VRAPIASM.VRAPIEnv.Log(4, "Found the call in TAPI cdr list and set it to connected!");
                                break;
                            }
                        }
                    }
 

                }
            }
            else
            {
                msg = String.Format("Connected outgoing call to args.Call.CalledID '{0}' on line args.Line.Name '{1}', args.Call.CalledIDName {2}, args.Call.CallerIDName {3}, args.Call.CallerID {4}, Guid {5}",
                           args.Call.CalledID, args.Line.Name, args.Call.CalledIDName, args.Call.CallerIDName, args.Call.CallerID, args.Call.Guid.ToString());
                VRAPIASM.VRAPIEnv.Log(4, msg);

                //  [2016-05-17 09:29:22] Connected outgoing call to 221 on line 'DCS Line 221', CalledIDName , CallerIDName Cell Phone   NC, CallerID 7047749599, Guid 2c2bb350-cfb2-4239-8972-9a27a4cfadfe


                lock (TapiCalls)
                {
                    foreach (TAPICDR cdr in TapiCalls)
                    {
                        if (cdr.CallGuid.Length > 0 && cdr.CallGuid == args.Call.Guid.ToString())
                        {
                            cdr.CallConnectedTime = DateTime.Now;
                            cdr.CallConnected = true;

                            if (cdr.Reversed)
                            {
                                //it seemed in this case it is incoming call but for someone else, and this extension answered
                                cdr.CallerIDName = args.Call.CallerIDName;
                                cdr.CallerID = args.Call.CallerID;
                                cdr.CalledIDName = args.Call.CalledIDName;
                                cdr.CalledID = args.Line.Name;

                                VRAPIASM.VRAPIEnv.Log(2, "########*********** TAPI CDR Caller and Called ID switched, ATTENTION! cdr.CallerID:" + cdr.CallerID + " cdr.CalledID:" + cdr.CalledID + " guid:" + cdr.CallGuid); 
                            }
                            else
                            {
                                cdr.CallerIDName = args.Call.CalledIDName;
                                cdr.CallerID = args.Line.Name;
                                cdr.CalledIDName = args.Call.CallerIDName; 
                                cdr.CalledID = args.Call.CallerID;  //args.Call.CalledID;
                            }

                            if (cdr.CalledID == args.Call.CalledID)
                            {
                                VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR CalledID is already " + args.Call.CalledID + " guid:" + cdr.CallGuid);
                            }
                            else
                            {
                                if (cdr.CalledID == "Unavail" || cdr.CalledID == "")
                                {
                                    cdr.CalledID = args.Call.CalledID;
                                    VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR CalledID is updated to " + args.Call.CalledID + " guid:" + cdr.CallGuid);
                                }
                                else
                                {
                                    VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR CalledID is " + cdr.CalledID + " not matching " + args.Call.CalledID + " guid:" + cdr.CallGuid);
                                }
                            }


                            VRAPIASM.VRAPIEnv.Log(4, "Found the call in TAPI cdr list and set it to connected!");
                            break;
                        }
                        else
                        {
                            if (/*cdr.CallDir == 1 &&*/ ((cdr.CallerID == args.Line.Name && cdr.CalledID == args.Call.CalledID) || (cdr.CallerID == args.Call.CallerID && cdr.CalledID == args.Line.Name)) && !cdr.CallDone)
                            {
                                cdr.CallConnectedTime = DateTime.Now;
                                cdr.CallConnected = true;
                                if (cdr.Reversed)
                                {
                                    //it seemed in this case it is incoming call but for someone else, and this extension answered
                                    cdr.CallerIDName = args.Call.CallerIDName;
                                    cdr.CallerID = args.Call.CallerID;
                                    cdr.CalledIDName = args.Call.CalledIDName;
                                    cdr.CalledID = args.Line.Name;
                                }
                                else
                                {
                                    cdr.CallerIDName = args.Call.CalledIDName;
                                    cdr.CallerID = args.Line.Name;
                                    cdr.CalledIDName = args.Call.CallerIDName;
                                    cdr.CalledID = args.Call.CallerID;
                                }

                                VRAPIASM.VRAPIEnv.Log(4, "Found the call in TAPI cdr list and set it to connected!");
                                break;
                            }
                        }
                    }
                }
            }
            
            LogoutTapiCalls();

        }

        // This event handler is called when the call has been disconnected.
        void OnCallDisconnected(object sender, TapiEventArgs args)
        {
            string msg;
            //msg = String.Format("Disconnected the call on line '{0}', CallerID {1}, CallerIDName {2}, CalledID {3}, CalledIDName {4}, CallID {5}", args.Line.Name, args.Call.CallerID, args.Call.CallerIDName, args.Call.CalledID, args.Call.CalledIDName, args.Call.CallID);

            if (args.Call.Direction == TapiCallDirection.Incoming)
            {
                msg = String.Format("Disconnected incoming call from {0} on line '{1}', CallerIDName {2}, CalledID {3}, CalledIDName {4}, Guid {5}",
                           args.Call.CallerID, args.Line.Name, args.Call.CallerIDName, args.Call.CalledID, args.Call.CalledIDName, args.Call.Guid.ToString());
                VRAPIASM.VRAPIEnv.Log(4, msg);

                lock (TapiCalls)
                {
                    //First trying to find out if there is a call like that already in the cdr list
                    //if (cdr.CallID == args.Call.CallID)  ####DO NOT USE CALLID, as it is always 0
                    foreach (TAPICDR cdr in TapiCalls)
                    {
                        if (cdr.CallGuid.Length > 0 && cdr.CallGuid == args.Call.Guid.ToString())
                        {
                            cdr.CallDone = true;
                            cdr.CallEndTime = DateTime.Now;
                            VRAPIASM.VRAPIEnv.Log(4, "Found incoming call in TAPI cdr list and set it to done!");
                            break;
                        }
                        else
                        {
                            if (cdr.CallDir == 0 && cdr.CallerID == args.Call.CallerID && cdr.CalledID == args.Line.Name && !cdr.CallDone)
                            {
                                cdr.CallDone = true;
                                cdr.CallEndTime = DateTime.Now;
                                VRAPIASM.VRAPIEnv.Log(4, "Found incoming call in TAPI cdr list and set it to done!");
                                break;
                            }
                        }
                    }

                }
            }
            else
            {
                msg = String.Format("Disconnected outgoing call to {0} on line '{1}', CalledIDName {2}, CallerIDName {3}, CallerID {4}, Guid {5}",
                           args.Call.CalledID, args.Line.Name, args.Call.CalledIDName, args.Call.CallerIDName, args.Call.CallerID, args.Call.Guid.ToString());
                VRAPIASM.VRAPIEnv.Log(4, msg);

                lock (TapiCalls)
                {
                    foreach (TAPICDR cdr in TapiCalls)
                    {
                        if (cdr.CallGuid.Length > 0 && cdr.CallGuid == args.Call.Guid.ToString())
                        {
                            cdr.CallDone = true;
                            cdr.CallEndTime = DateTime.Now;
                            if (cdr.CalledID == args.Call.CalledID)
                            {
                                VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR CalledID is already " + args.Call.CalledID  + " guid:" + cdr.CallGuid);
                            }
                            else
                            {
                                if (cdr.CalledID == "Unavail" || cdr.CalledID == "")
                                {
                                    cdr.CalledID = args.Call.CalledID;
                                    VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR CalledID is updated to " + args.Call.CalledID + " guid:" + cdr.CallGuid);
                                }
                                else
                                {
                                    VRAPIASM.VRAPIEnv.Log(4, "TAPI CDR CalledID is " + cdr.CalledID + " not matching " + args.Call.CalledID + " guid:" + cdr.CallGuid);
                                }
                            }

                            VRAPIASM.VRAPIEnv.Log(4, "Found outgoing call in TAPI cdr list and set it to done! guid:" + cdr.CallGuid);
                            break;
                        }
                        else
                        {
                            if (/*cdr.CallDir == 1 &&*/ ((cdr.CallerID == args.Line.Name && cdr.CalledID == args.Call.CalledID) || (cdr.CallerID == args.Call.CallerID && cdr.CalledID == args.Line.Name)) && !cdr.CallDone)
                            {
                                cdr.CallDone = true;
                                cdr.CallEndTime = DateTime.Now;
                                VRAPIASM.VRAPIEnv.Log(4, "Found outgoing call in TAPI cdr list and set it to done!");
                                break;
                            }
                        }
                    }
                }
            }

            LogoutTapiCalls();
        }

        // This event handler is called when AddTapi error occurs asynchronously
        void OnTapiError(object sender, TapiErrorEventArgs args)
        {
            // Display error in the log
            string msg;
            if (args.Line != null)
            {
                msg = String.Format("TapiError event, line '{0}'. {1}",
                        args.Line.Name, args.Message);
            }
            else
            {
                msg = String.Format("TapiError event. {0}", args.Message);
            }
            VRAPIASM.VRAPIEnv.Log(1, msg);

            if(TAPIIsClosing == 0)
                RestartTAPIConnection();
        }

        // This event handler is called when new line has been added
        // while application is running, for example USB modem was connected.
        void OnLineAdded(object sender, TapiEventArgs args)
        {
            //UpdateLinesCombobox();
            string msg;
            msg = String.Format("LineAdded Event, line '{0}' was added", args.Line.Name);
            VRAPIASM.VRAPIEnv.Log(4, msg);

            if (TAPIIsClosing == 0)
                RestartTAPIConnection();
        }

        // This event handler is called when the line was forcibly closed
        // by Windows because of hardware error or configuration change.
        void OnLineClosed(object sender, TapiEventArgs args)
        {
            // Display message in the log
            string msg = String.Format("LineClosed event, line '{0}' was forcibly closed by Windows.",
                            args.Line.Name);

            VRAPIASM.VRAPIEnv.Log(4, msg);

            //UpdateLinesCombobox();

            if (TAPIIsClosing == 0)
                RestartTAPIConnection();
        }

        // This event handler is called when new line has been removed
        // while application is running, for example USB modem was disconnected.
        void OnLineRemoved(object sender, TapiEventArgs args)
        {
            //UpdateLinesCombobox();
            string msg;
            msg = String.Format("LineRemoved Event, line '{0}' was removed", args.Line.Name);
            VRAPIASM.VRAPIEnv.Log(4, msg);

            if (TAPIIsClosing == 0)
                RestartTAPIConnection();
        }

        void OnLineDeviceState(object sender, TapiLineDeviceStateEventArgs args)
        {
            string msg;
            msg = String.Format("LineDeviceState Event, line '{0}' " + args.LineDeviceState.ToString(), args.Line.Name);
            VRAPIASM.VRAPIEnv.Log(4, msg);

            if (args.LineDeviceState == TapiLineDeviceState.OutOfService || args.LineDeviceState == TapiLineDeviceState.InService || args.LineDeviceState == TapiLineDeviceState.Close || args.LineDeviceState == TapiLineDeviceState.Disconnected)
            {
                if (TAPIIsClosing == 0)
                    RestartTAPIConnection();
            }
        }
///////////////////////////

    }
}
