using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Pipes; using System.Text; using System.Diagnostics; using Microsoft.Win32; using Newtonsoft.Json; using C4IT.Logging; using C4IT.F4SD.TAPI; using static C4IT.Logging.cLogManager; using FasdDesktopUi.Basics; namespace F4SD_PhoneMonitor { static class Program { public static string sendPipeName = null; public static string listenPipeName = null; public static string tapiLine = null; public static bool SignalOutgoingCall = false; public static string ExternalCallPrefix = ""; public static bool IsSimulation = false; public static int SendError = 0; public static cCLMgrEvents lmg = null; public static System.Timers.Timer timerPolling = new System.Timers.Timer(100); public static cF4sdPipeServer pipeServer = null; public static bool StopImmediate = false; [STAThread] static int Main(string[] args) { try { cLogManagerFile.CreateInstance(false, SubFolder: "Logs"); cLogManager.DefaultLogger.LogAssemblyInfo(); } catch { return 1; } var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (args.Length < 3 || args.Length > 6) { LogEntry("No valid pipe names at command line. Terminating...", LogLevels.Fatal); return -1; } sendPipeName = args[0]; listenPipeName = args[1]; tapiLine = args[2]; if (args.Length >= 4) ExternalCallPrefix = args[3]; if (args.Length >= 5) { if (args[4] == "1") SignalOutgoingCall = true; } if (args.Length >= 6) { if (args[5] == "simulation") IsSimulation = true; } if (tapiLine.ToLowerInvariant() == "swyxitnative") { if (!ConnectSwyxit()) return -1; } else { if (!ConnectTapi(tapiLine)) { System.Environment.Exit(-1); } } timerPolling.Elapsed += TimerPolling_Elapsed; timerPolling.Start(); var SessionId = 0; try { SessionId = Process.GetCurrentProcess().SessionId; } catch { } pipeServer = new cF4sdPipeServer(); pipeServer.PipeMessage += PipeServer_PipeMessage; pipeServer.Listen(listenPipeName, MaxSize: 255, LowerIntegrity: true); LogEntry($"Start listening on named pipe '{listenPipeName}'...", LogLevels.Debug); SystemEvents.SessionEnding += SystemEvents_SessionEnding; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ApplicationExit += OnApplicationExit; Application.Run(); return 0; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return -1; } static bool ConnectSwyxit() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var regObj = Registry.GetValue("HKEY_CLASSES_ROOT\\CLSID\\{F8E552F8-4C00-11D3-80BC-00105A653379}\\VersionIndependentProgID", null, null); if (!(regObj is string strObj) || strObj.ToLowerInvariant() != "clmgr.clientlinemgr") { LogEntry("SwyxIt client seems not to be installed. Terminating...", LogLevels.Fatal); return false; } lmg = new cCLMgrEvents(); if (!lmg.Initialize()) return false; lmg.ActiveCallHandler += ActiveCallMessage; return true; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } static bool ConnectTapi(string Line) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { C4TapiHelper.Instance = new C4TapiHelper(); C4TapiHelper.Instance.Initialize(TapiMessageHandler); C4TapiHelper.Instance.GetLines(); if (C4TapiHelper.Instance.ConnectLine(Line)) return true; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } private static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) { LogEntry("User logout detected. Terminating...", LogLevels.Debug); Application.Exit(); } private static void TimerPolling_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { timerPolling.Stop(); if (StopImmediate) { Application.Exit(); return; } timerPolling.Interval = 10000; bool res = false; lock (sendPipeName) { res = Send("Hello", sendPipeName); }; if (res) SendError = 0; else { SendError++; if (SendError == 2) Application.Exit(); } } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } timerPolling.Start(); } static private void OnApplicationExit(object sender, EventArgs e) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { timerPolling.Stop(); try { if (lmg != null) { lmg.ActiveCallHandler -= ActiveCallMessage; lmg.Disconnect(); } } catch { } try { if (C4TapiHelper.Instance != null) { C4TapiHelper.Instance.Dispose(); C4TapiHelper.Instance = null; } } catch { } if (pipeServer != null) { LogEntry("stopping pipe server...", LogLevels.Debug); pipeServer.Stop(); pipeServer.Dispose(); pipeServer = null; LogEntry("...finished.", LogLevels.Debug); } //Application.ApplicationExit -= OnApplicationExit; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } static void ActiveCallMessage(string phone, string name, bool isOutgoing) { if (isOutgoing && !SignalOutgoingCall) { LogEntry("An outgoing call is signaled but signaling outgoing calls is not enabled."); return; } if (sendPipeName == null) return; if (string.IsNullOrWhiteSpace(phone)) return; if (name == null) name = ""; var phone2 = phone.Trim(); if (!string.IsNullOrEmpty(ExternalCallPrefix) && phone2.StartsWith(ExternalCallPrefix)) phone2 = phone2.Remove(0,ExternalCallPrefix.Length); if (phone2.StartsWith("+")) { var _r = Math.Min(phone2.Length, 3); phone2 = phone2.Remove(0, _r); } else if (phone2.StartsWith("00")) { var _r = Math.Min(phone2.Length, 4); phone2 = phone2.Remove(0, _r); } if (phone2.StartsWith("0")) phone2 = phone2.Remove(0, 1); var phone3 = ""; foreach (var C in phone2) if ((C >= '0') && (C <= '9')) phone3 += C; var name2 = name.Trim(); var _strDir = isOutgoing ? "outgoing" : "incoming"; LogEntry($"Signaling {_strDir} call: phone={phone2}, name={name2}", LogLevels.Debug); var Info = JsonConvert.SerializeObject(new cPhoneSearchParameters() { phone = phone3, name = name2 }); lock (sendPipeName) { Send($"phonesearch: {Info}", sendPipeName); } } static public bool Send(string SendStr, string PipeName, int TimeOut = 1000) { try { if (IsSimulation) { LogEntry($"simulatied pipe send: {SendStr}"); return true; } NamedPipeClientStream pipeStream = new NamedPipeClientStream (".", PipeName, PipeDirection.Out, PipeOptions.WriteThrough); // The connect function will indefinitely wait for the pipe to become available // If that is not acceptable specify a maximum waiting time (in ms) pipeStream.Connect(TimeOut); byte[] _buffer = Encoding.UTF8.GetBytes(SendStr); pipeStream.Write(_buffer, 0, _buffer.Length); pipeStream.Flush(); pipeStream.Close(); pipeStream.Dispose(); return true; } catch (TimeoutException oEX) { if (DefaultLogger.IsDebug) cLogManager.DefaultLogger.LogException(oEX); } return false; } static private void PipeServer_PipeMessage(string Reply) { if (Reply.ToLowerInvariant() == "stop") { timerPolling.Stop(); StopImmediate = true; timerPolling.Interval = 100; timerPolling.Start(); } } private static void TapiMessageHandler(C4TapiHelper.C4TapiLineInfo lineInfo) { if (lineInfo.eventType == C4TapiHelper.eTapiEventType.connected) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { ActiveCallMessage(lineInfo.participantPhoneNumber, lineInfo.participantName, lineInfo.IsOutbound); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } } public class cPhoneSearchParameters { public string phone { get; set; } public string name { get; set; } = null; } } }