using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Windows.Forms; using Telerik.WinControls.UI; using Nini.Config; using System.Threading; using MotoTRBO_GW; using System.Net; using System.Diagnostics; using Telerik.WinControls; using SafeMobileLib; using System.Net.Sockets; using System.Collections; using MotoTRBO_XNL_Cmd; using System.IO; using SharedUI; using NAudio.Wave; using System.Runtime.InteropServices; //using NetFwTypeLib; namespace MotoTrbo_GW { public partial class Main : RadForm { // save the version of the application server in order to use it for the updater public static String APP_SERVER_VERSION = ""; public static TimeSpan timeDifference = new TimeSpan(0); public static int GWID = -1; public static bool TESTMODE = false; private static IConfigSource source = null; public static string CFG_FILE = "GWconfig.ini"; public static string ApplicationServer, DBServer, DBSchema, DBUser, DBPass, DBPort; // Audio related fields private static AudioManager _audioManager = null; BufferedWaveProvider _buffWaveProviderAsio = null; public static AudioDriverType AudioDriver; public static int bitdepth = 16; public static int bitdepthInBytes = 2; public static int sampleRate = 8000; public static int recordedBufferMiliseconds = 32; public static string asioDriverName = ""; private List _listOfRadioForms = new List(); private byte[] _bufferForAudio = null; private bool _connectedToAsioBoard = false; private System.Timers.Timer _timerCheckAsioBoard = null; // public static Boolean capacityPlus; public static int pingInterval = 5000; public static bool autoupdate = true; public static bool isDevelope = false; public static String masterRadioIP; public static String messageBusIP; public static String messageBusPort; private controlVoiceMain voiceMainCTRL; private LocationThread LocationConnection = null; private ARSThread ARSConnection = null; private EmergencyThread EmergencyConnection = null; private SMSReceiveThread SMSReceiveConnection = null; private SMSSendThread SMSSendConnection = null; private TallysmanReceiveThread TallysmanReceiveConnection = null; private TelemetryReceiveThread TelemetryReceiveConnection = null; private static TallysmanSendThread TallysmanSendConnection = null; private TelemetrySendThread TelemetrySendConnection = null; private RemoteStunThread RemoteStunConnection = null; public static Int32 SMSServicePort = 4007; public static Int32 ARSServicePort = 4005; public static Int32 LocationServicePort = 4001; public static Int32 EmergencyServicePort = 8002; public static Int32 TelemetryServicePort = 4008; public static Int32 TallysmanServicePort = 4010; //Non-IP Capable Peripheral Raw Data port private static Int32 TallysmanSendPort = 4069; //default time value for checking missign Id from database public static int TallysmanRequestInterval = 1; private static bool SEND_LOCATION_STOP = false; private Thread LocationThreadObj = null; private Thread SMSReceiveThreadObj = null; private Thread SMSSendThreadObj = null; private Thread TelemetryReceiveThreadObj = null; private Thread TelemetrySendThreadObj = null; private Thread TallysmanReceiveThreadObj = null; private Thread TallysmanSendThreadObj = null; private TcpClient client; private Int32 registrationPort = 5680; private Boolean registeredIP; private BackgroundWorker bgWorkerRegistration; private WaitingForm wf; public static bool wait4ack = true; public static int sms_sending_interval = 1200; public static int number_of_retries = 5; public static int retry_interval_sec = 180; private RouteManager routeManager; private Hashtable NetworkIDS_hash; public string YourIPaddress = ""; private Hashtable SMSReceiveThreadObjArr; private Hashtable RemoteStunThreadOBJArr; private Hashtable RemoteStunConnectionArr; private Hashtable EmergencyThreadObjArr; private Hashtable EmergencyConnectionArr; private Hashtable ARSThreadObjArr; public static Dictionary RadioComArr; public MessageBusHandler mbHandler; public static List gatewayRadios; //public static List GroupList; public static Dictionary smsConfirmForUnits = new Dictionary(); private System.Windows.Forms.Timer StatusCheckTimer; public static string LocalIP { get; private set; } = null; //this variable is used to prevent multiple start/end call processing from dispatchers while a gateway is in a patch public static Dictionary gatewayState = new Dictionary(); #region LINX #if LINXB LINX.TrboSipGateway _sipGateway = null; private bool _connectedToAsterisk; public bool ConnectedToAsterisk { get { return _connectedToAsterisk; } private set { if (value != _connectedToAsterisk) { _connectedToAsterisk = value; UpdateUIConnectionStatus(_connectedToAsterisk); } } } private int _minSipPort; private int _maxSipPort; #endif #endregion #region constructor + config file public Main() { //SafeMobileLib.Utils.WriteLine("Blalalalalalalalalala"); SM debug = new SM(); LoadConfig(); InitializeComponent(); StatusCheckTimer = new System.Windows.Forms.Timer(); StatusCheckTimer.Interval = 60 * 1000; StatusCheckTimer.Enabled = true; StatusCheckTimer.Tick += new System.EventHandler(StatusCheckTimerTick); RadMessageBox.SetThemeName("TelerikMetroBlue"); // customize the new FeedbackRadMessageBox FeedbackRadMessageBox.InteractionWaitSeconds = 7; FeedbackRadMessageBox.SetTheme("TelerikMetroBlue"); // register for restart event FeedbackRadMessageBox.OnRestartRequest += delegate() { RestartApp(); }; if (TESTMODE) this.Text = "!!!!Warning TEST MODE activated!!!!!"; // add firewall exception try { FireWallException fw = new FireWallException(); string name = System.AppDomain.CurrentDomain.FriendlyName; string path = Application.ExecutablePath; fw.checkFirewall(name, path); //bool result = fw.AuthorizeProgram(name, path, NET_FW_SCOPE_.NET_FW_SCOPE_ALL, NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY); //if (result) SafeMobileLib.Utils.WriteLine("Firewall exception added for:" + name + " path:" + path); //else SafeMobileLib.Utils.WriteLine("Firewall exception ERROR for:" + name + " path:" + path); } catch (Exception ex) { //SafeMobileLib.Utils.WriteLine("Firewall exception ERROR:",false); SafeMobileLib.Utils.WriteLine(ex.ToString()); RadMessageBox.Show("MotoTRBO GW could not add an exception to Windows Firewall.\r\nPlese manually add this exception or close Windows Firewall. ", "Windows Firewall exception.Please restart the application."); } //get version Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; lbVersion.Text = "Version: " + v.ToString(); tabVoice.Enabled = false; if (capacityPlus) { cbCapacityPlus.Checked = true; lbMasterIP.Text = "Master Radio IP:" + masterRadioIP; } else { cbCapacityPlus.Checked = false; lbMasterIP.Text = ""; } // Get the time from Internet and then save the difference in time between the local computer time // and the internet one from time.nist.gov Thread internetTimeThread = new Thread(new ThreadStart(delegate () { timeDifference = (DT.GetNetworkTime()).Subtract(DateTime.UtcNow); })); internetTimeThread.Start(); wf = new WaitingForm(); wf.Show(); bgWorkerRegistration = new BackgroundWorker(); bgWorkerRegistration.DoWork += new DoWorkEventHandler(bgWorkerRegistration_DoWork); bgWorkerRegistration.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorkerRegistration_RunWorkerCompleted); bgWorkerRegistration.RunWorkerAsync(); } private void AudioManager_AsioAudioAvailable(object sender, AsioAudioAvailableEventArgs e) { try { if (e.OutputBuffers.Length != 0) { _bufferForAudio = NAudio.Utils.BufferHelpers.Ensure(_bufferForAudio, e.SamplesPerBuffer * bitdepthInBytes); foreach (radioForm rf in _listOfRadioForms) { RadioComHandler rcHandler = rf.rcHandler; if (rcHandler != null && rcHandler.buffWaveProvider != null) { rcHandler.buffWaveProvider.Read(_bufferForAudio, 0, _bufferForAudio.Length); Marshal.Copy(_bufferForAudio, 0, e.OutputBuffers[rcHandler.OutDevIDProperty], _bufferForAudio.Length); } } } if (e.InputBuffers.Length != 0) { _bufferForAudio = NAudio.Utils.BufferHelpers.Ensure(_bufferForAudio, e.SamplesPerBuffer * bitdepthInBytes); foreach (radioForm rf in _listOfRadioForms) { RadioComHandler rcHandler = rf.rcHandler; if (rcHandler != null) { Marshal.Copy(e.InputBuffers[rcHandler.InDevIDProperty], _bufferForAudio, 0, e.SamplesPerBuffer * bitdepthInBytes); rcHandler.VoiceReceivedFromRadio(_bufferForAudio, _bufferForAudio.Length); } } } if (!_connectedToAsioBoard) { _connectedToAsioBoard = true; SafeMobileLib.Utils.WriteLine("---- ASIO: inside audio available event handler----"); //SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Asio audio available", EventLogEntryType.Information, 21777); } e.WrittenToOutputBuffers = true; } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error AudioManager_AsioAudioAvailable: " + ex.ToString(), ConsoleColor.Red); SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Error AudioManager_AsioAudioAvailable: " + ex.ToString(), EventLogEntryType.Error, 21778); } } private void AudioManager_PlaybackStopped(object sender, StoppedEventArgs e) { string msg = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nASIO playback stopped event\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; SafeMobileLib.Utils.WriteLine(msg, ConsoleColor.Red); SafeMobileLib.Utils.WriteEventLog("SafeMobile", msg, EventLogEntryType.Warning, 21779); } private void _timerCheckAsioBoard_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (_connectedToAsioBoard) { _connectedToAsioBoard = false; } else { // Instantiate again the asio class string msg = "ASIO board disconnected. Reconecting...."; SafeMobileLib.Utils.WriteLine(msg, ConsoleColor.Yellow); SafeMobileLib.Utils.WriteEventLog("SafeMobile", msg, EventLogEntryType.Warning, 21780); ClearAsioResources(); if (_audioManager == null) { try { InitAsioClassOnUIThread(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine(ex.ToString(), ConsoleColor.Red); } } } } /// /// Display a console message displaying the number of positions received in the last minute and the total number of positions /// since the gateway was started /// private void StatusCheckTimerTick(object sender, EventArgs e) { SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Received " + LocationThread.NumberOfPositionsSinceLastRead + " positions in last minute " + " [" + LocationThread.NumberOfPositions + " total]", EventLogEntryType.Information, 21522); } /// /// Restart the application and close other notify icons /// private void RestartApp() { SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Gateway is Restarting", EventLogEntryType.Warning, 21522); CloseNotifyIcon(); Program.isRunning = false; Thread p = new Thread(new ThreadStart(delegate () { //oldProcess.WaitForExit(8000); System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location, Program.isConsoleEnabled ? " -c" : ""); Process oldProcess = Process.GetCurrentProcess(); oldProcess.Kill(); System.Environment.Exit(0); })); p.Start(); } private void CloseNotifyIcon() { if (notifyIcon1 != null) { notifyIcon1.Visible = false; notifyIcon1.Icon = null; notifyIcon1.Dispose(); } } private void ContinueConstructor() { if (!registeredIP) { tabVoice.Enabled = false; DialogResult result = FeedbackRadMessageBox.ShowExclamation("Please register your copy of MotoTrbo Gateway using the Administrative Module.\n Your IP address is:" + YourIPaddress, "Info"); if (result == DialogResult.OK) Application.Exit(); } else if (registeredIP && !App.isValidVersion(APP_SERVER_VERSION, System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString())) { DialogResult dr = RadMessageBox.Show("Please update your version of software to the latest one required by Application Server. Do you wish to update now?", "Update required...", MessageBoxButtons.YesNo, RadMessageIcon.Exclamation); if (dr == DialogResult.Yes) { CheckForUpdate(true); Application.Exit(); } else Application.Exit(); } else { // Get Audio settings DBsettingsManager dbSettings = new DBsettingsManager(DBServer, DBSchema, DBUser, DBPass, DBPort); string tmpSamplaRate = dbSettings.getSettingValue(0, "sampleRate"); if (!string.IsNullOrEmpty(tmpSamplaRate)) sampleRate = int.Parse(tmpSamplaRate); else { SafeMobileLib.Utils.WriteLine("Invalid sample rate", ConsoleColor.Red); } string tmpBitDepth = dbSettings.getSettingValue(0, "bitDepth"); if (!string.IsNullOrEmpty(tmpSamplaRate)) { bitdepth = int.Parse(tmpBitDepth); bitdepthInBytes = bitdepth / 8; } else { SafeMobileLib.Utils.WriteLine("Invalid bit depth", ConsoleColor.Red); } string tmpBufferMilliseconds = dbSettings.getSettingValue(0, "bufferMilliseconds"); if (!string.IsNullOrEmpty(tmpBufferMilliseconds)) recordedBufferMiliseconds = int.Parse(tmpBufferMilliseconds); else { SafeMobileLib.Utils.WriteLine("Invalid bufferMilliseconds", ConsoleColor.Red); } //int asio driver object if (Main.AudioDriver == AudioDriverType.Asio) { try { if (_audioManager == null) { InitAsio(); InitAsioClassOnUIThread(); // Set up timer that checks if Asio board is connected _timerCheckAsioBoard = new System.Timers.Timer(2000); _timerCheckAsioBoard.Elapsed += _timerCheckAsioBoard_Elapsed; _timerCheckAsioBoard.Start(); } } catch (Exception ex) { //string msg = "Unable to instantiate asio driver. Please ensure your soundcard is connected or choose another driver from combobox.\n\r\n\r" + ex.Message; string msg = "Unable to instantiate asio driver. Do you want this time to use the default windows drivers instead?";//+".\n\r\n\r" + ex.Message; FeedbackRadMessageBox.InteractionWaitSeconds = 320; DialogResult result = FeedbackRadMessageBox.Show("Asio drivers issue", msg, MessageBoxButtons.YesNo, RadMessageIcon.Exclamation); if (result == DialogResult.Yes) { lblAsioDriverName.Visibility = cbAsio.Visibility = ElementVisibility.Hidden; Main.AudioDriver = AudioDriverType.Windows; } else { MainPanel.Text = "Unable to instantiate asio driver."; return; } } } //old code /*if (GWID == -1) { int id = getGWidFromDB(YourIPaddress); if (id == -1) { RadMessageBox.Show("Gateway IP not present in DB\n\r Please go to Administrative module and register this GW with IP:!!!" + YourIPaddress, "IP missing", MessageBoxButtons.OK, RadMessageIcon.Error); System.Environment.Exit(0); } else { GWID = id; source = new IniConfigSource(Main.CFG_FILE); source.Configs["Gateway"].Set("id", id); source.Save(); SafeMobileLib.Utils.WriteLine("ID:" + id +" saved to config file."); } }*/ //new code List listGW = new List(); try { listGW = getGWidFromDB(YourIPaddress); if (listGW.Count == 0) { if (DBServer.Contains("127.0.0.1") || (DBServer.ToUpper().Contains("LOCALHOST"))) listGW = getGWidFromDB("127.0.0.1"); } else { if (GWID != -1) { Boolean find = false; foreach (Gateway obj in listGW) if (obj.Id == GWID) { find = true; break; } if ((!find) && (DBServer.Contains("127.0.0.1") || (DBServer.ToUpper().Contains("LOCALHOST")))) listGW = getGWidFromDB("127.0.0.1"); } } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Ex on find automat the gateway ID:" + ex.ToString()); } try { if (listGW.Count == 0) { FeedbackRadMessageBox.ShowError("Gateway IP not present in DB\n\r Please go to Administrative module and register this GW with IP:!!!" + YourIPaddress, "IP missing"); System.Environment.Exit(0); return; } else { GWID = ((Gateway)listGW[0]).Id; source = new IniConfigSource(Main.CFG_FILE); source.Configs["Gateway"].Set("id", GWID); // source.Configs["NAI"].Set("peerID", ((Gateway)listGW[0]).Peer_id); source.Save(); SafeMobileLib.Utils.WriteLine("Gateway ID is " + GWID, ConsoleColor.Cyan); //SafeMobileLib.Utils.WriteLine("ID:" + GWID + " saved to config file."); btGWID.Text = GWID.ToString(); } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("DB error!!!"); SafeMobileLib.Utils.WriteLine(ex.ToString()); FeedbackRadMessageBox.ShowError("DB error.\n\rPlease turn down the firewall or add an exception for the Datebase in the firewall and try again!!!\n\r DB ip:" + YourIPaddress, "DB error"); System.Environment.Exit(0); //System.Windows.Forms.Application.Exit(); return; } //end of new code /*try { DBgroupsManager db4groups = new DBgroupsManager(DBServer, DBSchema, DBUser, DBPass, DBPort); GroupList = db4groups.GetAllGroups(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error on load groups: "+ex.ToString()); }*/ tabVoice.Enabled = true; radRibbonBar1.RibbonBarElement.QuickAccessToolBar.Visibility = Telerik.WinControls.ElementVisibility.Hidden; radRibbonBar1.Expanded = false; //test id app is already running testIfAlreadyRunning(); //start message bus handler mbHandler = new MessageBusHandler(messageBusIP, messageBusPort); #region LINX #if LINXB mbHandler.RefreshDatabaseCommandReceived += MbHandler_RefreshDatabaseCommandReceived; #endif #endregion routeManager = new RouteManager(); routeManager.OnRadioStatusUpdate += new RouteManager.RadioStatusUpdateDEl(routeManager_OnRadioStatusUpdate); routeManager.Start(); SMSReceiveThreadObjArr =new Hashtable(); RemoteStunThreadOBJArr = new Hashtable(); RemoteStunConnectionArr = new Hashtable(); EmergencyThreadObjArr = new Hashtable(); EmergencyConnectionArr = new Hashtable(); ARSThreadObjArr = new Hashtable(); RadioComArr = new Dictionary(); StartLocationService(); StartARSService(); StartSMSService(); //StartEmergencyService();moved to routeManager_OnRadioStatusUpdate StartTelemetryService(); StartTallysmanService(); StartRemoteStunService(); //for non Cap plus moved to routeManager_OnRadioStatusUpdate LoadRadioTab(true); #region LINX #if LINXB // Start sip registration bool errorOnRegister = false; _sipGateway = new LINX.TrboSipGateway(DBServer, DBSchema, DBUser, DBPass, DBPort, _minSipPort, _maxSipPort, out errorOnRegister); _sipGateway.ConnectionStatusChanded += _sipGateway_ConnectionStatusChanded; _sipGateway.LinxSendsInvite += _sipGateway_LinxSendsInvite; _sipGateway.DialogCreated += _sipGateway_DialogCreated; _sipGateway.DialogClosed += _sipGateway_DialogClosed; _sipGateway.ErrorOnCreatingDialog += _sipGateway_ErrorOnCreatingDialog; _sipGateway.VoiceReceived += _sipGateway_VoiceReceived; //_sipGateway.LinxHangtimeEnded += _sipGateway_LinxHangtimeEnded; _sipGateway.SmsFromLinxToRadio += _sipGateway_SmsReceived; _sipGateway.ShowUIMessage += _sipGateway_ShowUIMessage; ConnectedToAsterisk = _sipGateway.ConnectedToAstersisk; if (errorOnRegister) _sipGateway_ShowUIMessage("Not all the radios are connected to Linx server.Check sip ports range in config file"); #endif #endregion } SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Gateway turned on with ID " + GWID, EventLogEntryType.SuccessAudit, 21521); } private void InitAsioClassOnUIThread() { if (this.InvokeRequired) { this.Invoke((Action)(() => { InitAsioClass(); })); } else InitAsioClass(); } private void InitAsioClass() { _audioManager = new AudioManager(asioDriverName); int channels = _audioManager.AsioDriverInputChannelCount; _buffWaveProviderAsio = new BufferedWaveProvider(new NAudio.Wave.WaveFormat(sampleRate, bitdepth, channels)); _audioManager.AsioAudioAvailable += AudioManager_AsioAudioAvailable; _audioManager.PlaybackStopped += AudioManager_PlaybackStopped; _audioManager.Init(_buffWaveProviderAsio, channels, sampleRate); _audioManager.Play(); } #region TRBO Sip Gateway event handlers #if LINXB private void _sipGateway_ConnectionStatusChanded(bool connected) { this.ConnectedToAsterisk = connected; } private void _sipGateway_LinxSendsInvite(LINX.RadioSipInfo radioSipInfo, string callingLinxID) { // 1. Check if the corresponding base radio is available for call int radioGwID = int.Parse(radioSipInfo.ContactInfo.GWandRadioGW.Split('.')[1]); radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID); if (rf != null) { if (rf.rcHandler != null) { /* I MOVED THIS PART IN A FUNCTION IN RADIOCOMHANDLER.CS if (rf.rcHandler.IsPTTbussy) { // 2. If base radio is not available reject the invite. radioSipInfo.SipClass.Decline(callingLinxID); SafeMobileLib.Utils.WriteLine($@"Declined the inivite from sip id {callingLinxID} to radio {radioSipInfo.ContactInfo.Name} because base station {radioGwID} is ptt busy", ConsoleColor.Green); } else { bool groupCall = radioSipInfo.ContactInfo.Type == ContactType.GROUP; rf.rcHandler.LinxCallInfo = new LINX.LinxCall(callingLinxID, radioSipInfo.ContactInfo.SipId); if (groupCall) { RadioComArr[rf.RadioIP].SendCallType(0, radioSipInfo.ContactInfo.Id); // group radio ptt rf.rcHandler.RadioStatusProp = RADIO_STATUS.GroupCall_INIT; } else { RadioComArr[rf.RadioIP].SendCallType(1, radioSipInfo.ContactInfo.Id); // private radio ptt rf.rcHandler.RadioStatusProp = RADIO_STATUS.PrivateCall_INIT; } // start the tCheckStatus timer rf.rcHandler.StartCheckStatusTimer(); bool success = RadioComArr[rf.RadioIP].SendPTTon(); if (success) { // Linx Private Call - 1002 // Linx Group Call - 1003 rf.rcHandler.CallType = groupCall ? 1003 : 1002; } else { // Error on SendPTTon() // Reject the invite radioSipInfo.SipClass.Decline(callingLinxID); SafeMobileLib.Utils.WriteLine($@"Declined the inivite from sip id {callingLinxID} to radio {radioSipInfo.ContactInfo.Name} because base station {radioGwID} failed to send PTT", ConsoleColor.Red); } }*/ bool acceptInvite = rf.rcHandler.InviteFromLinx(callingLinxID, radioSipInfo.ContactInfo.SipId, radioSipInfo.ContactInfo.Id, radioSipInfo.ContactInfo.Type == ContactType.GROUP); if (!acceptInvite) radioSipInfo.SipClass.Decline(callingLinxID); } } } private void _sipGateway_DialogCreated(LINX.RadioSipInfo sipInfo, string linxID, bool fromRadioToLinx) { if (fromRadioToLinx) { // PTT initiated from radio // Notify RadioComHandler class that the dialog has been established int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]); radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID); if (rf != null) { if (rf.rcHandler != null) { rf.rcHandler.LinxReceivesPTTFromRadio(new LINX.LinxCall(linxID, sipInfo.ContactInfo.SipId)); } } } SafeMobileLib.Utils.WriteLine($"Dialog created between linx with sipID {linxID} and radio {sipInfo.ContactInfo.Name}", ConsoleColor.Green); } private void _sipGateway_DialogClosed(LINX.RadioSipInfo sipInfo, string linxID, bool fromRadioToLinx) { int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]); radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID); SafeMobileLib.Utils.WriteLine($"PTT ended between linx with sipID {linxID} and radio {sipInfo.ContactInfo.Name}", ConsoleColor.Green); if (rf != null) { if (rf.rcHandler != null) { if (rf.rcHandler.IsPTTbussy) { if (!fromRadioToLinx) { // Linx sent PTT rf.rcHandler.CallType = sipInfo.ContactInfo.Type == ContactType.GROUP ? 1003 : 1002; RadioComArr[rf.RadioIP].SendPTToff(); } } } } } private void _sipGateway_ErrorOnCreatingDialog(LINX.RadioSipInfo sipInfo, string linxID, bool fromRadioToLinx) { int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]); radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID); SafeMobileLib.Utils.WriteLine($"Error on creating dialog between {linxID} and radio {sipInfo.ContactInfo.Name}", ConsoleColor.Red); if (rf != null) { if (rf.rcHandler != null) { if (rf.rcHandler.IsPTTbussy) { if (!fromRadioToLinx) { // Linx sent PTT rf.rcHandler.CallType = sipInfo.ContactInfo.Type == ContactType.GROUP ? 1003 : 1002; RadioComArr[rf.RadioIP].SendPTToff(); } } } } } private void _sipGateway_VoiceReceived(LINX.RadioSipInfo sipInfo, byte[] buffer) { int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]); radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID); if (rf != null) { if (rf.rcHandler != null) { rf.rcHandler.buffWaveProvider.AddSamples(buffer, 0, buffer.Length); } } } private void _sipGateway_SmsReceived(ContactLinx remoteRadioIDInfo, string message, int linxRadioID) { // Sms received from linx // Just send it on mbus int radioGwID = int.Parse(remoteRadioIDInfo.GWandRadioGW.Split('.')[1]); radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID); if (rf != null) { if (rf.rcHandler != null) { // Generate string command to send on message bus // #seqID#Opcode#gatewayId.gatewayRadioId.remoteRadioId#message#scheduleTime#dispatcherID# string seqID = Utils.GenerateSeqID(linxRadioID); string cmd= $"#{(int)MessageBusCmds.SendSMSRequest}#{Main.GWID}.{rf.rcHandler.RadioID}.{remoteRadioIDInfo.Id}#Linx{linxRadioID}.{message}#{DateTime.Now.ToUniversalTime().DateTo70Format()}#{linxRadioID}#"; MessageBusHandler.SendOnMsgBuss(seqID, cmd); } } } private void _sipGateway_ShowUIMessage(string message) { if (this.InvokeRequired) { this.Invoke((Action)(() => ShowMessageBox(message))); } else ShowMessageBox(message); } private void ShowMessageBox(string message) { MessageBox.Show(message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } //private void _sipGateway_LinxHangtimeEnded(LINX.RadioSipInfo sipInfo, string linxID) //{ // // Clear linx call info in radioComHandler class // int radioGWID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]); // radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGWID); // if (rf != null) // { // if (rf.rcHandler != null) // { // rf.rcHandler.LinxCallInfo = LINX.LinxCall.DefaultValue; // default value. // } // } //} #endif #endregion #region Private functions for sip #if LINXB private void RcHandler_LinxCallEstablished(object sender, EventArgs e) { // Radio call established, accept the invite from LINX RadioComHandler rcHandler = (RadioComHandler)sender; LINX.LinxCall linxCallInfo; if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue) { _sipGateway.GetSipClass(linxCallInfo.RadioSipID).AcceptInvite(linxCallInfo.LinxSipID); } } private void RcHandler_LinxCallFailed(object sender, EventArgs e) { // Radio call failed, decline the invite from LINX RadioComHandler rcHandler = (RadioComHandler)sender; LINX.LinxCall linxCallInfo; if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue) { _sipGateway.GetSipClass(linxCallInfo.RadioSipID).Decline(linxCallInfo.LinxSipID); SafeMobileLib.Utils.WriteLine("Will reset linx call info from main because base radio could not call portable", ConsoleColor.DarkRed); rcHandler.ResetLinxCallInfoValue(); } } private void RcHandler_CallLinx(object sender, LINX.CallLinxEventArgs e) { RadioComHandler rcHandler = (RadioComHandler)sender; // Call linx and send voice LINX.LinxCall linxCallInfo; if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue) { _sipGateway.SendInvite(linxCallInfo.RadioSipID, linxCallInfo.LinxSipID); } else { int? linxSipID = null; // The call is not in response to a LINX call // Check if is group or private call // If group call, check if there is a LINX associated with this group call // If private call, check if there is a LINX that receives private call from this unit if (e.IsGroup) { // group call // Check if there is a LINX associated with this group call linxSipID = _sipGateway.GetLinxInRadioGroup(e.GroupID); if (linxSipID.HasValue) { int radioSipID = -1; if (_sipGateway.LinxSipIDisGroup(linxSipID.Value)) radioSipID = _sipGateway.GetSipIDFromRadioID(e.RadioID, false); else radioSipID = _sipGateway.GetSipIDFromRadioID(e.GroupID, true); _sipGateway.SendInvite(radioSipID, linxSipID.Value.ToString()); rcHandler.GroupCallInitiatedByRadio = true; } } else { // private call // If private call, check if there is a LINX that receives private call from this unit linxSipID = _sipGateway.GetLinxForPrivateCall(e.RadioID); if (linxSipID.HasValue) { int radioSipID = _sipGateway.GetSipIDFromRadioID(e.RadioID, false); _sipGateway.SendInvite(radioSipID, linxSipID.Value.ToString()); } } } } private void RcHandler_RadioEndsPTTtoLinx(object sender, EventArgs e) { // Radio has ended ptt RadioComHandler rcHandler = (RadioComHandler)sender; LINX.LinxCall linxCallInfo; if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue) { // get the sip class SipComponent.SipClientClass2 sipClass = _sipGateway.GetSipClass(linxCallInfo.RadioSipID); // end sip call if call is in progress or cancel invite if (sipClass.InDialogWith(linxCallInfo.LinxSipID)) sipClass.Close(linxCallInfo.LinxSipID); else sipClass.CancelInvite(linxCallInfo.LinxSipID); } } private void RcHandler_RadioVoiceToLinx(object sender, LINX.RadioVoiceToLinxEventArgs e) { RadioComHandler rcHandler = (RadioComHandler)sender; LINX.LinxCall linxCallInfo; if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue) { _sipGateway.GetSipClass(linxCallInfo.RadioSipID).SendAudio( linxCallInfo.LinxSipID, e.VoiceBuffer, e.BufferLength, SipComponent.AudioFormat.PCM); } } private int? RcHandler_LinxIDForPrivateCallRequested(int radioID) { return _sipGateway.GetLinxForPrivateCall(radioID); } private int RcHandler_RadioSipIDRequested(int radioID, bool isGroup) { return _sipGateway.GetSipIDFromRadioID(radioID, isGroup); } private void UpdateUIConnectionStatus(bool connectedToAsterisk) { System.Drawing.Color color; string textToDisplay; if (connectedToAsterisk) { color = System.Drawing.Color.Green; textToDisplay = "Connected to Asterisk"; } else { color = System.Drawing.Color.Red; textToDisplay = "Not connected to Asterisk"; } if (this.InvokeRequired) { this.Invoke((Action)(() => { ChangeConnectionLabel(color, textToDisplay); })); } else ChangeConnectionLabel(color, textToDisplay); } private void SMSReceiveConnection_PrivateCallRequestForLinxReceived(int remoteRadioID, int linxRadioID) { _sipGateway.PrivateCallRequestFromRadioReceived(remoteRadioID, linxRadioID); } private async void SMSReceiveConnection_SmsForLixReceived(string seqID, int remoteRadioID, int linxRadioID, string text) { bool smsReceivedByLinx = await _sipGateway.SendSmsToLinx(seqID, linxRadioID, remoteRadioID, text); // Send confirmation on mBus // #seqID#Opcode#state# // #seqID#242#1# or #seqID#242#0# int state = smsReceivedByLinx ? 1 : 0; MessageBusHandler.SendOnMsgBuss(seqID, $"#{(int)MessageBusCmds.FieldRadioReceivedSmsAck}#{state}#"); } private void MbHandler_RefreshDatabaseCommandReceived(object sender, EventArgs e) { _sipGateway?.ListOfSipIDHasChanged(); } private void ChangeConnectionLabel(System.Drawing.Color color, string text) { lblConnectedToAsterisk.ForeColor = color; lblConnectedToAsterisk.Text = text; } #endif #endregion #region asio events for main private void InitAsio() { lblAsioDriverName.Visibility = cbAsio.Visibility = ElementVisibility.Visible; LoadAsioDrivers(); } private void LoadAsioDrivers() { string[] driverList = AudioManager.GetAsioDriverNames(); foreach (String obj in driverList) { SafeMobileLib.Utils.WriteLine(obj, ConsoleColor.DarkMagenta); RadMenuItem tmp = new RadMenuItem(obj); tmp.Name = obj; cbAsio.Items.Add(tmp); tmp.Click += new System.EventHandler(DriverChangeEvent); } if (cbAsio.Items.Count > 0) { for (int i = 0; i < cbAsio.Items.Count; i++) { if (((RadMenuItem)cbAsio.Items[i]).Text == asioDriverName) { ((RadMenuItem)cbAsio.Items[i]).IsChecked = true; cbAsio.Text = ((RadMenuItem)cbAsio.Items[i]).Text; } } } if(cbAsio.Items.Count == 1 && ((RadMenuItem)cbAsio.Items[0]).Text != asioDriverName) { ((RadMenuItem)cbAsio.Items[0]).IsChecked = true; cbAsio.Text = asioDriverName = ((RadMenuItem)cbAsio.Items[0]).Text; source = new IniConfigSource(CFG_FILE); source.Configs["Voice"].Set("driverName", cbAsio.Text); source.Save(); } } private void DriverChangeEvent(object sender, EventArgs e) { if (((RadMenuItem)sender).Name != asioDriverName) { source = new IniConfigSource(CFG_FILE); source.Configs["Voice"].Set("driverName", ((RadMenuItem)sender).Name); source.Save(); FeedbackRadMessageBox.ShowInfo("Info: You need to restart gateway to work with selected driver", ""); } } #endregion void routeManager_OnRadioStatusUpdate(bool status, string ip) { SafeMobileLib.Utils.WriteLine(". . . . . . . . . . . routeManager_OnRadioStatusUpdate . . . . . . . . . ."); SafeMobileLib.Utils.WriteLine($". . . . . . . . . . . ip:{ip} status:{status}. . . . . . . . . ."); SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Radio gateway " + ip + " is now " + (status ? "online" : "offline"), EventLogEntryType.Information, 21521); //if (capacityPlus) //{ //return; //} if (status) { //start radio connection RadioConnection rc = null; rc = new RadioConnection(ip, EmergencyServicePort, "XNL_CMDS"); if (RadioComArr.ContainsKey(ip)) { RadioComArr[ip].Stop(); RadioComArr.Remove(ip); } RadioComArr.Add(ip, rc); rc.Start(); //start ARS if (!capacityPlus) { int Network_ID = Convert.ToInt32(RouteManager.NetworkIDs_Hash[ip]); RoutingUtils.UpdateRoutes_NonCapPlus(ip, RadioStuff.GetInterface(ip), Network_ID); GatewayID_IP ID_IP = new GatewayID_IP(); ID_IP.remoteIP = ip; ID_IP.localIP = RadioStuff.GetInterface(ip); ID_IP.ID = Network_ID.ToString(); if (!ARSThreadObjArr.ContainsKey(ip)) { ARSThread ARSConnection = new ARSThread(ID_IP, ARSServicePort, false, messageBusIP, messageBusPort); /*ARSConnection.OnArsReceived += delegate (Int64 radioID, bool isON) { // nothing for now here };*/ Thread ARSThreadObj = new Thread(new ThreadStart(ARSConnection.handleConnection)); ARSThreadObj.IsBackground = true; ARSThreadObj.Start(); ARSThreadObjArr.Add(ip, ARSThreadObj); } } else { //add route for cap plus RoutingUtils.UpdateRoutes(masterRadioIP, true); } if (!capacityPlus) { //start SMS for current ip if (!SMSReceiveThreadObjArr.ContainsKey(ip)) { SMSReceiveThread SMSReceiveConnection = new SMSReceiveThread(ip, SMSServicePort, messageBusIP, messageBusPort); Thread SMSReceiveThreadObj = new Thread(new ThreadStart(SMSReceiveConnection.handleConnection)); SMSReceiveThreadObj.IsBackground = true; SMSReceiveThreadObj.Start(); #if LINXB SMSReceiveConnection.SmsForLixReceived += SMSReceiveConnection_SmsForLixReceived; SMSReceiveConnection.PrivateCallRequestForLinxReceived += SMSReceiveConnection_PrivateCallRequestForLinxReceived; #endif SMSReceiveThreadObjArr.Add(ip, SMSReceiveThreadObj); } } int total_sleep = 0; while (!rc.AuthDone && Program.isRunning) { SafeMobileLib.Utils.WriteLine("Sleeping auth not completed!!!!"); Thread.Sleep(100); total_sleep++; if (total_sleep > 50)//after 5sec retry a new auth { total_sleep = 0; SafeMobileLib.Utils.WriteLine("Stopping current AUTH atempt and retry in 5 seconds"); rc.Stop(); int c = 0; while(c < 50 && Program.isRunning) { c++; Thread.Sleep(100); } rc = new RadioConnection(ip, EmergencyServicePort, "XNL_CMDS"); RadioComArr[ip] = rc; rc.Start(); } } //start remote stun if (!RemoteStunThreadOBJArr.ContainsKey(ip)) { int radioID = Convert.ToInt32(RouteManager.RadioGW_IDs[ip]); RemoteStunThread RemoteStunConnection = new RemoteStunThread(rc, ip, radioID, EmergencyServicePort, messageBusIP, messageBusPort); Thread RemoteStunThreadOBJ = new Thread(new ThreadStart(RemoteStunConnection.handleConnection)); RemoteStunThreadOBJ.IsBackground = true; RemoteStunThreadOBJ.Start(); RemoteStunThreadOBJArr.Add(ip, RemoteStunThreadOBJ); RemoteStunConnectionArr.Add(ip, RemoteStunConnection); } //start emergency if (!EmergencyThreadObjArr.ContainsKey(ip)) { EmergencyThread EmergencyConnection = new EmergencyThread(rc, ip, EmergencyServicePort, messageBusIP, messageBusPort); Thread EmergencyThreadObj = new Thread(new ThreadStart(EmergencyConnection.handleConnection)); EmergencyThreadObj.IsBackground = true; EmergencyThreadObj.Start(); EmergencyThreadObjArr.Add(ip, EmergencyThreadObj); EmergencyConnectionArr.Add(ip, EmergencyConnection); } } else { SafeMobileLib.Utils.WriteLine("routeManager_OnRadioStatusUpdate status:" + status + " ip:" + ip); //remove connections from EMERGEBCY REMOTESTUN radioConnection HASHTABLES PingOffFallowUP(ip); } } private void PingOffFallowUP(string ip) { if (EmergencyThreadObjArr.ContainsKey(ip)) { ((EmergencyThread)EmergencyConnectionArr[ip]).Disconnect(); EmergencyThreadObjArr[ip] = null; EmergencyThreadObjArr.Remove(ip); EmergencyConnectionArr.Remove(ip); } if (RemoteStunThreadOBJArr.ContainsKey(ip)) { ((RemoteStunThread)RemoteStunConnectionArr[ip]).Disconnect(); RemoteStunThreadOBJArr[ip] = null; RemoteStunThreadOBJArr.Remove(ip); RemoteStunConnectionArr.Remove(ip); } if (RadioComArr.ContainsKey(ip)) { RadioComArr[ip].Stop(); RadioComArr.Remove(ip); } } #region bg worker registration events void bgWorkerRegistration_DoWork(object sender, DoWorkEventArgs e) { registeredIP = getRegistration(); } void bgWorkerRegistration_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (wf != null) if (wf.IsInitialized) if (wf.IsLoaded) { SafeMobileLib.Utils.WriteLine("Shuting down waiting form"); wf.Close(); } if (appServerMissing) { FeedbackRadMessageBox.ShowError("Could not reach Application Server. Please check the connection and try again!!!", "Connection Error"); Application.Exit(); } ContinueConstructor(); } #endregion private bool appServerMissing = false; private Boolean getRegistration() { Boolean toReturn = false; try { client = new TcpClient(); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(Main.ApplicationServer), registrationPort); client.Connect(serverEndPoint); NetworkStream clientStream = client.GetStream(); YourIPaddress = (client.Client.LocalEndPoint.ToString().Split(':'))[0]; Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; UTF8Encoding encoding = new UTF8Encoding(); byte[] buffer = encoding.GetBytes("200"); //encryption doesn't work, to be added when working //byte[] encodedBuffer = Encryption.Encrypt(buffer); clientStream.Write(buffer, 0, buffer.Length); SafeMobileLib.Utils.WriteLine("Sent registration request to server, waiting..."); byte[] message = new byte[128]; //set read timeout to 10s clientStream.ReadTimeout = 10000; int result = clientStream.Read(message, 0, message.Length); //close waiting thread //byte[] decodedMessage = Encryption.Decrypt(message); String decodedString = encoding.GetString(message).Trim('\0'); String[] options = decodedString.Split(';'); SafeMobileLib.Utils.WriteLine($"Received registration from server {decodedString}") ; if (options[0].Equals("201")) { if (options[1].StartsWith("invalid")) { toReturn = false; } else { APP_SERVER_VERSION = options[1].Replace("valid-", ""); messageBusIP = options[2]; messageBusPort = options[3]; DBServer = options[4]; DBSchema = options[5]; DBUser = options[6]; DBPass = options[7]; DBPort = options[8]; toReturn = true; } } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Exception in gateway:getRegistration():" + ex.ToString(), ConsoleColor.Red); appServerMissing = true; } return toReturn; } /*private int getGWidFromDB(string currentIP) { DBgatewaysManager dbmanager = new DBgatewaysManager(Main.DBServer, Main.DBSchema, Main.DBUser, Main.DBPass, Main.DBPort); List list = dbmanager.getAllGateways(); foreach (Gateway g in list) { if (g.Ip == currentIP) { SafeMobileLib.Utils.WriteLine("Gateway IP found in registration tabel. ID:"+g.Id); return g.Id; } } SafeMobileLib.Utils.WriteLine("Gateway IP not found in registration tabel!!!"); return -1; }*/ private List getGWidFromDB(string currentIP) { DBgatewaysManager dbmanager = new DBgatewaysManager(Main.DBServer, Main.DBSchema, Main.DBUser, Main.DBPass, Main.DBPort); List list = dbmanager.getAllGateways(); List listtoreturn = new List(); foreach (Gateway g in list) { if (g.Ip == currentIP) { SafeMobileLib.Utils.WriteLine("Gateway IP found in registration tabel. ID:" + g.Id); listtoreturn.Add(g); } } return listtoreturn; } void StartLocationService() { // create thread to listen UDP LocationConnection = new LocationThread(LocationServicePort, messageBusIP, messageBusPort); LocationThreadObj = new Thread(new ThreadStart(LocationConnection.handleConnection)); LocationThreadObj.IsBackground = true; LocationThreadObj.Start(); } void StartSMSService() { //create thread for sending SMSs to the radios SMSSendConnection = new SMSSendThread(SMSServicePort, messageBusIP, messageBusPort); SMSSendThreadObj = new Thread(new ThreadStart(SMSSendConnection.handleConnection)); SMSSendThreadObj.IsBackground = true; SMSSendThreadObj.Start(); Thread.Sleep(1000); if (capacityPlus) { SafeMobileLib.Utils.WriteLine("StartSMSService for cap plus"); SMSReceiveConnection = new SMSReceiveThread(masterRadioIP, SMSServicePort, messageBusIP, messageBusPort, SMSSendConnection.udpClientSMS); SMSReceiveThreadObj = new Thread(new ThreadStart(SMSReceiveConnection.handleConnection)); SMSReceiveThreadObj.IsBackground = true; SMSReceiveThreadObj.Start(); #if LINXB SMSReceiveConnection.SmsForLixReceived += SMSReceiveConnection_SmsForLixReceived; SMSReceiveConnection.PrivateCallRequestForLinxReceived += SMSReceiveConnection_PrivateCallRequestForLinxReceived; #endif } } void StartTelemetryService() { //create thread for receiving telemetry notifications from the radios TelemetryReceiveConnection = new TelemetryReceiveThread(TelemetryServicePort, messageBusIP, messageBusPort); TelemetryReceiveThreadObj = new Thread(new ThreadStart(TelemetryReceiveConnection.handleConnection)); TelemetryReceiveThreadObj.IsBackground = true; TelemetryReceiveThreadObj.Start(); //create thread for sending telemetry commands to the radios TelemetrySendConnection = new TelemetrySendThread(TelemetryServicePort, messageBusIP, messageBusPort); TelemetrySendThreadObj = new Thread(new ThreadStart(TelemetrySendConnection.handleConnection)); TelemetrySendThreadObj.IsBackground = true; TelemetrySendThreadObj.Start(); } void StartTallysmanService() { //create thread for receiving tallysman notifications from the radios TallysmanReceiveConnection = new TallysmanReceiveThread(TallysmanServicePort, messageBusIP, messageBusPort); TallysmanReceiveThreadObj = new Thread(new ThreadStart(TallysmanReceiveConnection.handleConnection)); TallysmanReceiveThreadObj.IsBackground = true; TallysmanReceiveThreadObj.Start(); //create thread for sending commands to the radios TallysmanSendConnection = new TallysmanSendThread(TallysmanSendPort, messageBusIP, messageBusPort, TallysmanRequestInterval); TallysmanSendThreadObj = new Thread(new ThreadStart(TallysmanSendConnection.handleConnection)); TallysmanSendThreadObj.IsBackground = true; TallysmanSendThreadObj.Start(); } public static void resetTallysmanCheckTimer(int newvalue) { TallysmanSendConnection.resetCheckTimer(newvalue); } void StartARSService() { if (capacityPlus) { SafeMobileLib.Utils.WriteLine("StartARSService for cap plus"); RoutingUtils.UpdateRoutes( masterRadioIP, true); GatewayID_IP radioID_IP = new GatewayID_IP(); ARSConnection = new ARSThread(radioID_IP, ARSServicePort, true, messageBusIP, messageBusPort); Thread ARSThreadObj = new Thread(new ThreadStart(ARSConnection.handleConnection)); ARSThreadObj.IsBackground = true; ARSThreadObj.Start(); } } RadioConnection rc_cap_plus = null; void StartRemoteStunService() { if (capacityPlus) { SafeMobileLib.Utils.WriteLine("StartRemoteStunService for cap plus"); //start radio connection rc_cap_plus = new RadioConnection(masterRadioIP, EmergencyServicePort, "XNL_CMDS"); if (RadioComArr.ContainsKey(masterRadioIP)) { RadioComArr[masterRadioIP].Stop(); RadioComArr.Remove(masterRadioIP); } RadioComArr.Add(masterRadioIP, rc_cap_plus); rc_cap_plus.Start(); //start remote stun if (!RemoteStunThreadOBJArr.ContainsKey(masterRadioIP)) { int radioID = Convert.ToInt32(RouteManager.RadioGW_IDs[masterRadioIP]); RemoteStunThread RemoteStunConnection = new RemoteStunThread(rc_cap_plus, masterRadioIP, radioID, EmergencyServicePort, messageBusIP, messageBusPort); Thread RemoteStunThreadOBJ = new Thread(new ThreadStart(RemoteStunConnection.handleConnection)); RemoteStunThreadOBJ.IsBackground = true; RemoteStunThreadOBJ.Start(); RemoteStunThreadOBJArr.Add(masterRadioIP, RemoteStunThreadOBJ); RemoteStunConnectionArr.Add(masterRadioIP, RemoteStunConnection); } } } private void LoadConfig() { try { if (!File.Exists(CFG_FILE)) { SafeMobileLib.Utils.WriteLine("Config file doesn't exist. Creating it...", ConsoleColor.Yellow); try { using (FileStream fs = File.Create(CFG_FILE)) { } } catch (Exception) { SafeMobileLib.Utils.WriteLine("Application ended!!!! " + CFG_FILE + " could not be created"); SafeMobileLib.Utils.WriteLine("Press any key to exit..."); Console.ReadKey(); System.Environment.Exit(0); } } source = new IniConfigSource(CFG_FILE); if (source.Configs["Gateway"] == null) source.Configs.Add("Gateway"); GWID = GetInt32Value("Gateway", "id", -1); registrationPort = GetInt32Value("Gateway", "regPort", 5680); pingInterval = GetInt32Value("Gateway", "pingInterval", 10000); TESTMODE = GetBooleanValue("Gateway", "testmode", false); LocalIP = GetStringValue("Gateway", "localIP", ""); SMSServicePort = GetInt32Value("Gateway", "smsPort", 4007); LocationServicePort = GetInt32Value("Gateway", "locationPort", 4001); ARSServicePort = GetInt32Value("Gateway", "arsPort", 4005); /* GWID = Convert.ToInt32(source.Configs["Gateway"].Get("id")); registrationPort = Convert.ToInt32(source.Configs["Gateway"].Get("regPort")); pingInterval = Convert.ToInt32(source.Configs["Gateway"].Get("pingInterval")); TESTMODE = Convert.ToBoolean(source.Configs["Gateway"].Get("testmode")); */ if (source.Configs["Database"] == null) source.Configs.Add("Database"); ApplicationServer = GetStringValue("Server", "IP", "127.0.0.1"); if (ApplicationServer.Equals("localhost")) ApplicationServer = "127.0.0.1"; //DBSchema = GetStringValue("Database", "Schema", "safedispatchdb"); //DBUser = GetStringValue("Database", "User", "postgres"); //DBPass = GetStringValue("Database", "Passwd", "wizdemo26"); //DBPort = GetStringValue("Database", "Port", "5432"); /* DBServer = source.Configs["Database"].Get("IP"); if (DBServer.Equals("localhost")) DBServer = "127.0.0.1"; DBSchema = source.Configs["Database"].Get("Schema"); DBUser = source.Configs["Database"].Get("User"); DBPort = source.Configs["Database"].Get("Port"); DBPass = source.Configs["Database"].Get("Passwd"); */ if (source.Configs["ARS Service"] == null) source.Configs.Add("ARS Service"); capacityPlus = GetBooleanValue("ARS Service", "CapacityPlusEnabled", false); masterRadioIP = GetStringValue("ARS Service", "MasterRadioIP", "192.168.10.1"); GetBooleanValue("ARS Service", "Scan for SU presence at statup", false); GetInt32Value("ARS Service", "Invalidate SU after", 200); GetInt32Value("ARS Service", "Refresh status", 1); GetBooleanValue("ARS Service", "Start service at startup", true); asioDriverName = GetStringValue("Voice", "driverName", "N/A"); /* capacityPlus = Convert.ToBoolean(source.Configs["ARS Service"].Get("CapacityPlusEnabled")); masterRadioIP = source.Configs["ARS Service"].Get("MasterRadioIP"); */ if (source.Configs["MessageBus"] == null) source.Configs.Add("MessageBus"); //messageBusIP = GetStringValue("MessageBus", "ip", "224.30.0.1"); //messageBusPort = GetStringValue("MessageBus", "port", "17233"); /* messageBusIP = source.Configs["MessageBus"].Get("ip"); messageBusPort = source.Configs["MessageBus"].Get("port"); */ if (source.Configs["Tallysman"] == null) source.Configs.Add("Tallysman"); TallysmanServicePort = (ushort)GetInt32Value("Tallysman", "port", 4010); /* try { TallysmanServicePort = Convert.ToUInt16(source.Configs["Tallysman"].Get("port")); } catch { TallysmanServicePort = 4010; }*/ TallysmanRequestInterval = GetInt32Value("Tallysman", "checkInterval", -1); if (source.Configs["SMS"] == null) source.Configs.Add("SMS"); wait4ack = GetBooleanValue("SMS", "wait4ack", true); sms_sending_interval = GetInt32Value("SMS", "sending_interval", 1200); number_of_retries = GetInt32Value("SMS", "number_of_retries", 3); retry_interval_sec = GetInt32Value("SMS", "retry_interval_sec", 180); /* wait4ack = Convert.ToBoolean(source.Configs["SMS"].Get("wait4ack")); sms_sending_interval = Convert.ToInt32(source.Configs["SMS"].Get("sending_interval")); number_of_retries = Convert.ToInt32(source.Configs["SMS"].Get("number_of_retries")); if (source.Configs["SMS"].Contains("retry_interval_sec")) retry_interval_sec = Convert.ToInt32(source.Configs["SMS"].Get("retry_interval_sec")); */ if (source.Configs["Update"] == null) source.Configs.Add("Update"); autoupdate = GetBooleanValue("Update", "autoupdate", true); if (source.Configs["Update"].Contains("develop")) isDevelope = source.Configs["Update"].GetBoolean("develop"); GetStringValue("Update", "Version", "1.0.0.2"); GetBooleanValue("Update", "Enable", true); /* try { if (!source.Configs["Update"].Contains("autoupdate")) source.Configs["Update"].Set("autoupdate", true); autoupdate = source.Configs["Update"].GetBoolean("autoupdate"); if (source.Configs["Update"].Contains("develop")) isDevelope = source.Configs["Update"].GetBoolean("develop"); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("AUTOUPDATE " + ex.ToString(), ConsoleColor.Red); } */ if (source.Configs["Voice"] == null) source.Configs.Add("Voice"); GetBooleanValue("Voice", "onOFF", false); GetStringValue("Voice", "SelectedOutDevice", ""); GetStringValue("Voice", "SelectedInDevice", ""); GetStringValue("Voice", "RadioIP", "192.168.10.40"); GetStringValue("Voice", "MulticastIP", "224.30.0.1"); GetInt32Value("Voice", "Port", 17234); string audioDriver = GetStringValue("Voice", "driver", "windows"); if (audioDriver.ToLower() == "asio") AudioDriver = AudioDriverType.Asio; else AudioDriver = AudioDriverType.Windows; //GetInt32Value("Voice", "radioNr", 0); /* [Voice] SelectedOutDevice = Speakers(USB VoIP Device) SelectedInDevice = Microphone(USB VoIP Device) RadioIP = 192.168.10.40 MulticastIP = 224.30.0.1 onOFF = false port = 17234*/ source.Save(); SafeMobileLib.Utils.WriteLine("Gateway ID:" + GWID, ConsoleColor.Green); SafeMobileLib.Utils.WriteLine("Ping Interval:" + pingInterval, ConsoleColor.Green); #region LINX #if LINXB _minSipPort = GetInt32Value("LINX", "minSipPort", 3024); _maxSipPort = GetInt32Value("LINX", "maxSipPort", 3999); if (_maxSipPort <= _minSipPort) { // Error in config file. Get back to defaults _minSipPort = 3024; _maxSipPort = 3999; } SafeMobileLib.Utils.WriteLine($"Sip Ports Range: {_minSipPort} - {_maxSipPort}", ConsoleColor.Green); #endif #endregion if (TESTMODE) { SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"); SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"); SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"); SafeMobileLib.Utils.WriteLine("---------------------------------------"); SafeMobileLib.Utils.WriteLine("!!!!Warning TEST MODE activated!!!!!"); SafeMobileLib.Utils.WriteLine("If this is a live GW please go to config and mask GATEWAY->testmode = false;"); SafeMobileLib.Utils.WriteLine("---------------------------------------"); SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"); SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"); SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"); } } catch (Exception e) { SafeMobileLib.Utils.WriteLine("LoadConfig Exception" + e.ToString(), ConsoleColor.Red); } } /// /// Get an int value from the configuration file. The desired value is identifiec by /// the key and the header under which is placed is pointed by the header. Also a default /// value can be set in case the value doesn't exist and needs to be created before /// beeing returned /// /// Header unde which the desired config parameter is placed /// The Key that designates the desired config parameter /// A default value that will be used and returned in case the /// config file doesn't have a value for the parameter /// Parameter value from the config file, or the default value in case it doesn't /// exist private Int32 GetInt32Value(String header, String key, Int32 defaultValue) { if (!source.Configs[header].Contains(key)) source.Configs[header].Set(key, defaultValue); return source.Configs[header].GetInt(key); } /// /// Get a string value from the configuration file. The desired value is identifiec by /// the key and the header under which is placed is pointed by the header. Also a default /// value can be set in case the value doesn't exist and needs to be created before /// beeing returned /// /// Header unde which the desired config parameter is placed /// The Key that designates the desired config parameter /// A default value that will be used and returned in case the /// config file doesn't have a value for the parameter /// Parameter value from the config file, or the default value in case it doesn't /// exist private String GetStringValue(String header, String key, String defaultValue) { if (!source.Configs[header].Contains(key)) source.Configs[header].Set(key, defaultValue); return source.Configs[header].GetString(key); } /// /// Get a boolean value from the configuration file. The desired value is identifiec by /// the key and the header under which is placed is pointed by the header. Also a default /// value can be set in case the value doesn't exist and needs to be created before /// beeing returned /// /// Header unde which the desired config parameter is placed /// The Key that designates the desired config parameter /// A default value that will be used and returned in case the /// config file doesn't have a value for the parameter /// Parameter value from the config file, or the default value in case it doesn't /// exist private Boolean GetBooleanValue(String header, String key, Boolean defaultValue) { if (!source.Configs[header].Contains(key)) source.Configs[header].Set(key, defaultValue); return source.Configs[header].GetBoolean(key); } private void testIfAlreadyRunning() { Process[] processlist = Process.GetProcesses(); Process curentP = Process.GetCurrentProcess(); int count = 0; foreach (Process theprocess in processlist) { if (theprocess.ProcessName == curentP.ProcessName) { count++; } } if (count > 1) { SafeMobileLib.Utils.WriteLine("App already running!!!"); FeedbackRadMessageBox.ShowError("Aplication already running!!", "error"); foreach (Process theprocess in processlist) { if (theprocess.ProcessName == curentP.ProcessName) { SafeMobileLib.Utils.WriteLine($"Process: {theprocess.ProcessName} ID: {theprocess.Id}"); SafeMobileLib.Utils.WriteLine($"Curent Process: {curentP.ProcessName} ID: {curentP.Id}"); if (theprocess.Id != curentP.Id) { SafeMobileLib.Utils.WriteLine($"Killing Process: {theprocess.ProcessName} ID: {theprocess.Id}"); theprocess.Kill(); } } } Thread.Sleep(1000); } } #endregion #region tabs load functions private void radRibbonBar1_CommandTabSelected(object sender, Telerik.WinControls.UI.CommandTabEventArgs args) { if (args.CommandTab == tabVoice) { SafeMobileLib.Utils.WriteLine("Why load Voice Tab here???", ConsoleColor.Magenta); //LoadVoiceTab(true); } } private void LoadRadioTab(bool mainTab) { if (mainTab) { voiceMainCTRL = new controlVoiceMain(); voiceMainCTRL.Dock = System.Windows.Forms.DockStyle.Fill; MainPanel.Controls.Clear(); MainPanel.Controls.Add(voiceMainCTRL); _listOfRadioForms = voiceMainCTRL.radiosFormList; #if LINXB foreach (radioForm radioF in voiceMainCTRL.radiosFormList) { radioF.StartedRadioComHandler += RadioF_StartedRadioComHandler; radioF.StoppingRadioComHandler += RadioF_StoppingRadioComHandler; } #endif } } #endregion private void btnVoiceAdd_Click(object sender, EventArgs e) { //voiceMainCTRL.AddNewRadio(); } private void btnVoiceRemove_Click(object sender, EventArgs e) { //voiceMainCTRL.RemoveRadio(); } private void Main_FormClosing(object sender, FormClosingEventArgs e) { wf?.Close(); Program.isRunning = false; SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Gateway Closing", EventLogEntryType.Information, 21523); if (voiceMainCTRL != null) { voiceMainCTRL.SaveConfigForRadios(); try { // Clear voice resources ClearAsioResources(); foreach (radioForm r in voiceMainCTRL.radiosFormList) { if (r.rcHandler != null) { //if (r.rcHandler.nVOice != null) // r.rcHandler.nVOice.Dispose(); //if (r.rcHandler.waveOutClass != null) //{ // r.rcHandler.waveOutClass.Dispose(); // r.rcHandler.waveOutClass = null; //} //if (r.rcHandler.waveInClass != null) //{ // r.rcHandler.waveInClass.DataAvailable -= r.rcHandler.waveInClass_DataAvailable; // r.rcHandler.waveInClass.Dispose(); // r.rcHandler.waveInClass = null; //} r.rcHandler.ClearVoiceResources(); } } #region LINX #if LINXB if (_sipGateway != null) { _sipGateway.Stop(); } #endif #endregion } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Main_FormClosing: " + ex.ToString(), ConsoleColor.Red); } } } private void ClearAsioResources() { if (_audioManager != null) { _audioManager.AsioAudioAvailable -= AudioManager_AsioAudioAvailable; _audioManager.PlaybackStopped -= AudioManager_PlaybackStopped; _audioManager.Dispose(); _audioManager = null; } } /// /// Close necessary things before closing the app /// private void CloseApp() { // close necessary things in the app Main_FormClosing(null, null); Process oldProcess = Process.GetCurrentProcess(); oldProcess.Kill(); Application.Exit(); } /// /// Update a specific config file parameter from a desired category. /// /// Category in which the parameter is located /// Parameter which needs to be updated /// New value for the desired parameter public static void UpdateConfigParameter(string category, string option, string value) { try { source = new IniConfigSource(CFG_FILE); //DataBase source.Configs[category].Set(option, value); // Save the INI file source.Save(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine(ex.ToString()); } } private void Main_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { this.Visible = false; notifyIcon1.Visible = true; } } private void notifyIcon1_DoubleClick(object sender, EventArgs e) { this.Visible = true; this.WindowState = FormWindowState.Normal; notifyIcon1.Visible = false; } private void radCheckBoxElement1_Click(object sender, EventArgs e) { try { if (!cbCapacityPlus.Checked) { CapacityPlusIP tmp = new CapacityPlusIP(masterRadioIP); tmp.ShowDialog(); System.Threading.Timer tCheckSTATUS = new System.Threading.Timer(UncheckCapPlus, null, 500, System.Threading.Timeout.Infinite); } else { lbMasterIP.Text = ""; RestoreDefaulCapacityConfig(); } } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error on click capacityPuls:"+ex.ToString(), ConsoleColor.Red); } } private void Main_Load(object sender, EventArgs e) { ContextMenu contextMenu = new ContextMenu(); contextMenu.MenuItems.Add("Check for updates...", (s, e2) => { UpdateForm uf = new UpdateForm(App.GW_TRBO, true) { IsDevelop = Main.isDevelope }; uf.Show(); }); contextMenu.MenuItems.Add("Exit", (s, e2) => CloseApp()); notifyIcon1.ContextMenu = contextMenu; // check for a new version if available if(Main.isDevelope) CheckForUpdate(false); } #region UPDATE /// /// Check for new version release on SafeMobile Portal /// The check is done by comparing Current Assembly Version with the one /// written in a xml file on the portal. /// private void CheckForUpdate(bool isModal) { App appType = App.GW_TRBO; if (isModal) { UpdateForm uf = new UpdateForm(appType, true) { IsDevelop = Main.isDevelope }; uf.ShowDialog(); } else { AutoUpdate au = new AutoUpdate(appType) { IsDevelop = Main.isDevelope }; au.OnNewVersionAvailable += delegate (string version) { if (APP_SERVER_VERSION.Split('.')[2].Equals(version.Split('.')[2])) { notifyIcon1.Text = "New version available"; notifyIcon1.ShowBalloonTip(2500, $"{App.GetAppName(appType)} version {version} available", $"Press to download and install the latest version of {App.GetAppName(appType)}.", ToolTipIcon.Info); notifyIcon1.BalloonTipClicked += delegate (object sender, EventArgs e) { if (notifyIcon1.Text.Equals("New version available")) { UpdateForm uf = new UpdateForm(appType, true) { IsDevelop = Main.isDevelope }; uf.Show(); } }; } else SafeMobileLib.Utils.WriteLine("New version available but AppServer is an old version stil"); }; // call method to check for new updated au.CheckUpdate(); } } #endregion private void UncheckCapPlus(Object state) { try { cbCapacityPlus.Checked = false; } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Unable to uncheck capacityPuls:"+ex.ToString(), ConsoleColor.Red); } } public void RestoreDefaulCapacityConfig() { source = new IniConfigSource(Main.CFG_FILE); source.Configs["ARS Service"].Set("MasterRadioIP", "192.168.10.40"); source.Configs["ARS Service"].Set("CapacityPlusEnabled", "False"); source.Save(); } internal static List GetAsioInputDevices() { return _audioManager?.GetAsioInputDevices(); } internal static List GetAsioOutputDevices() { return _audioManager?.GetAsioOutputDevices(); } private void Main_FormClosed(object sender, FormClosedEventArgs e) { try { //System.Environment.Exit(0); Application.Exit(); } catch (Exception ex) { SafeMobileLib.Utils.WriteLine("Error on closing: "+ex.ToString(), ConsoleColor.Red); } } private void settingsRibbon_Click(object sender, EventArgs e) { SettingsForm sf = new SettingsForm(); sf.ShowDialog(); } private void RadioF_StoppingRadioComHandler(object sender, RadioComHandler rcHandler) { #if LINXB // Remove event halders rcHandler.LinxCallEstablished -= RcHandler_LinxCallEstablished; rcHandler.CallLinx -= RcHandler_CallLinx; rcHandler.RadioEndsPTTtoLinx -= RcHandler_RadioEndsPTTtoLinx; rcHandler.RadioVoiceToLinx -= RcHandler_RadioVoiceToLinx; rcHandler.RadioSipIDRequested -= RcHandler_RadioSipIDRequested; rcHandler.LinxIDForPrivateCallRequested -= RcHandler_LinxIDForPrivateCallRequested; rcHandler.LinxCallFailed -= RcHandler_LinxCallFailed; #endif } private void RadioF_StartedRadioComHandler(object sender, RadioComHandler rcHandler) { #if LINXB // Add event handlers rcHandler.LinxCallEstablished += RcHandler_LinxCallEstablished; rcHandler.CallLinx += RcHandler_CallLinx; rcHandler.RadioEndsPTTtoLinx += RcHandler_RadioEndsPTTtoLinx; rcHandler.RadioVoiceToLinx += RcHandler_RadioVoiceToLinx; rcHandler.RadioSipIDRequested += RcHandler_RadioSipIDRequested; rcHandler.LinxIDForPrivateCallRequested += RcHandler_LinxIDForPrivateCallRequested; rcHandler.LinxCallFailed += RcHandler_LinxCallFailed; #endif } } public class ShapeNew : ShapedForm { public Boolean typeRadio = true; public Int32 ID = 0; public Boolean Selected = false; public Boolean VoiceON = true; } public enum AudioDriverType { Windows, Asio, Unknown } }