using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; using System.IO; using System.Diagnostics; using System.Web; using Microsoft.Win32; using Newtonsoft.Json; using FasdDesktopUi.Basics; using FasdDesktopUi.Basics.Models; using FasdDesktopUi.Basics.Helper; using FasdDesktopUi.Pages.CustomMessageBox; using FasdDesktopUi.Pages.DetailsPage.Models; using FasdDesktopUi.Pages.SplashScreenView; using FasdDesktopUi.Pages.M42AuthenticationPage; using FasdDesktopUi.Pages.SearchPage; using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; using C4IT.Logging; using C4IT.MultiLanguage; using C4IT.F4SD.TAPI; using static C4IT.Logging.cLogManager; namespace FasdDesktopUi { public class cAppStartUp { public const string constUrlProtocol = "F4SDSEND"; public const string constUrlCommand = "sendurl"; private static bool AreAppComponentsInitialized = false; private static SplashScreenView splashScreen; public static async Task StartAsync(string[] startArguments) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { #if isDemo cFasdCockpitCommunicationBase.Instance = new cFasdCockpitCommunicationDemo(); #else cFasdCockpitCommunicationBase.Instance = new cFasdCockpitCommunicationWeb(); #endif if (!startArguments.Contains("SilentStart", StringComparer.InvariantCultureIgnoreCase)) { splashScreen = new SplashScreenView(); splashScreen?.Show(); } var searchPageView = SearchPageView.Instance; var settingsPageView = FasdDesktopUi.Pages.SettingsPage.SettingsPageView.Create(); splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.CheckServerConnection")); if (!await InitializeCommunicationAsync()) { LogEntry("Error when initializing communication components.", LogLevels.Fatal); CustomMessageBox.Show("Error when initializing communication components.", "Fatal Error", enumHealthCardStateLevel.Error); Application.Current.Shutdown(); } if (cConnectionStatusHelper.Instance.ApiConnectionStatus >= cConnectionStatusHelper.enumOnlineStatus.illegalConfig) { splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.InitAppComponents")); if (!await InitializeUiElementsAsync()) return false; } cConnectionStatusHelper.ApiConnectionStatusChanged += ApiConnectionStatusChanged; // Aufruf der neuen Prominenteren Suche (work in progress) //var advancedPaged = new AdvancedSearchPage(); //advancedPaged.Show(); return true; } catch (Exception E) { LogException(E); } finally { splashScreen?.Hide(); LogMethodEnd(CM); } return false; } public static bool ProcessCommandLine(string[] Args) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (DefaultLogger.IsDebug) { var _msg = new List() { "command line arguments:" }; foreach (var _entry in Args) _msg.Add(_entry); DefaultLogger.LogList(LogLevels.Debug, _msg); } var Command = Args[0].ToLowerInvariant(); bool shouldShutdown = true; switch (Command) { case "search": if (Args.Length < 2) { LogEntry($"Missing search value on command line for command {Command}.", LogLevels.Error); break; } var Search = Args[1]; cAppStartUp.SendSearchValue(Search); break; case "phonesearch": try { if (Args.Length < 2) { LogEntry($"Missing search value on command line for command {Command}.", LogLevels.Error); break; } var searchInfo = new cPhoneSearchParameters { phone = Args[1] }; if (Args.Length >= 3) searchInfo.name = Args[2]; SendPhoneSearchValues(searchInfo); } catch (Exception E) { LogException(E); } break; case "computerdomainsearch": try { if (Args.Length < 2) { LogEntry($"Missing a search value on command line for command {Command}.", LogLevels.Error); break; } var searchInfo = new cComputerDomainSearchParameters() { name = Args[1], domain = "" }; if (Args.Length >= 3) searchInfo.domain = Args[2]; cAppStartUp.SendComputerDomainSearchValues(searchInfo); } catch (Exception E) { LogException(E); } break; case "usersidsearch": try { if (Args.Length < 2) { LogEntry($"Missing a search value on command line for command {Command}.", LogLevels.Error); break; } var searchInfo = new cUserSidSearchParameters() { name = Args[1], sids = "" }; if (Args.Length >= 3) searchInfo.sids = Args[2]; cAppStartUp.SendUserSidSearchValues(searchInfo); } catch (Exception E) { LogException(E); } break; case "ticketsearch": try { if (Args.Length < 4) { LogEntry($"Missing a search value on command line for command {Command}.", LogLevels.Error); break; } var searchInfo = new cTicketSearchParameters() { ticketName = Args[1], ticketId = Args[2], userName = Args[3], sids = "" }; if (Args.Length >= 5) searchInfo.sids = Args[4]; cAppStartUp.SendTicketSearchValues(searchInfo); } catch (Exception E) { LogException(E); } break; case constUrlCommand: if (Args.Length < 2) { LogEntry("Missing url on command line.", LogLevels.Error); break; } var Url = Args[1]; cAppStartUp.ProcessMessageUrl(Url); break; default: shouldShutdown = false; LogEntry($"Unknown command on commandline: {Command}", LogLevels.Warning); break; } return shouldShutdown; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } public static void ProcessMessageUrl(string url) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (url.Length <= constUrlProtocol.Length + 3) { LogEntry($"No valid {constUrlProtocol} message.", LogLevels.Warning); return; } var urlPrefix = url.Substring(0, constUrlProtocol.Length + 3).ToLowerInvariant(); if (urlPrefix != constUrlProtocol.ToLowerInvariant() + "://") { LogEntry($"Unknown protocol prefix {urlPrefix}. Should be {constUrlProtocol}://", LogLevels.Warning); return; } var arr1 = url.Split('?'); if (arr1.Length < 2) { LogEntry("No valid url parameters.", LogLevels.Warning); return; } var arrParams = arr1[1].Split('&'); var dicParams = new Dictionary(); foreach (var param in arrParams) { var arr2 = param.Split('='); if (arr2.Length != 2) { LogEntry($"Invalid url parameter: {param}", LogLevels.Warning); continue; } var name = HttpUtility.UrlDecode(arr2[0]).Trim().ToLowerInvariant(); var value = HttpUtility.UrlDecode(arr2[1]).Trim(); dicParams[name] = value; } if (!dicParams.TryGetValue("command", out var commandType)) { LogEntry("Missing command parameter in url.", LogLevels.Warning); return; } switch (commandType.ToLowerInvariant()) { case "search": if (!dicParams.TryGetValue("value", out var searchValue)) { LogEntry("Missing value parameter in url.", LogLevels.Warning); return; } SendSearchValue(searchValue); break; case "phonesearch": { if (!dicParams.TryGetValue("phone", out var searchPhone)) { LogEntry("Missing phone parameter in url.", LogLevels.Warning); return; } if (!dicParams.TryGetValue("name", out var searchName)) searchName = null; var searchInfo = new cPhoneSearchParameters() { phone = searchPhone, name = searchName }; SendPhoneSearchValues(searchInfo); } break; case "usersidsearch": { if (!dicParams.TryGetValue("name", out var searchName)) { LogEntry("Missing name parameter in url.", LogLevels.Warning); return; } if (!dicParams.TryGetValue("sids", out var searchSids)) searchSids = null; var searchInfo = new cUserSidSearchParameters() { name = searchName, sids = searchSids }; SendUserSidSearchValues(searchInfo); } break; case "computerdomainsearch": { if (!dicParams.TryGetValue("name", out var searchName)) { LogEntry("Missing name parameter in url.", LogLevels.Warning); return; } if (!dicParams.TryGetValue("domain", out var searchDomain)) searchDomain = null; var searchInfo = new cComputerDomainSearchParameters() { name = searchName, domain = searchDomain }; SendComputerDomainSearchValues(searchInfo); } break; case "ticketsearch": { if (!dicParams.TryGetValue("tname", out var _tname)) { LogEntry("Missing ticket name parameter in url.", LogLevels.Warning); return; } if (!dicParams.TryGetValue("tid", out var _tid)) { LogEntry("Missing ticket id parameter in url.", LogLevels.Warning); return; } if (!dicParams.TryGetValue("uname", out var _uname)) { LogEntry("Missing ticket id parameter in url.", LogLevels.Warning); return; } var searchInfo = new cTicketSearchParameters() { ticketName = _tname, ticketId = _tid, userName = _uname }; if (dicParams.TryGetValue("sids", out var _sids)) searchInfo.sids = _sids; SendTicketSearchValues(searchInfo); } break; default: LogEntry($"Unknown url command parameter: {commandType}.", LogLevels.Warning); break; } } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } public static void SendSearchValue(string searchValue) { cF4sdPipeClient.Send("search:" + searchValue, App.PipeName); } public static void SendPhoneSearchValues(cPhoneSearchParameters search) { var jsonSearch = JsonConvert.SerializeObject(search); cF4sdPipeClient.Send("phonesearch:" + jsonSearch, App.PipeName); } public static void SendComputerDomainSearchValues(cComputerDomainSearchParameters search) { var jsonSearch = JsonConvert.SerializeObject(search); cF4sdPipeClient.Send("computerdomainsearch:" + jsonSearch, App.PipeName); } public static void SendUserSidSearchValues(cUserSidSearchParameters search) { var jsonSearch = JsonConvert.SerializeObject(search); cF4sdPipeClient.Send("usersidsearch:" + jsonSearch, App.PipeName); } public static void SendTicketSearchValues(cTicketSearchParameters search) { var jsonSearch = JsonConvert.SerializeObject(search); cF4sdPipeClient.Send("ticketsearch:" + jsonSearch, App.PipeName); } private static async Task InitializeCommunicationAsync() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (!cFasdCockpitCommunicationBase.Instance.CheckConnectionInfo()) { CustomMessageBox.Show("No valid server URL found in registry.", "First Aid Service Desk", enumHealthCardStateLevel.Error); LogEntry("No valid server URL found in registry."); return false; } var _csh = new cConnectionStatusHelper(); _csh.M42FormBasedAuthentication += F4sdM42FormsAuthentication.M42FormBasedAuthenticationDelegate; cConnectionStatusHelper.Instance = _csh; await cConnectionStatusHelper.Instance.RunConnectionStatusCheckAsync(splashScreen); cConnectionStatusHelper.Instance.OnApiConnectionStatusChanged(); return true; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } private static async void ApiConnectionStatusChanged(cConnectionStatusHelper.enumOnlineStatus? Status) { try { if (AreAppComponentsInitialized || Status != cConnectionStatusHelper.enumOnlineStatus.online) return; await InitializeUiElementsAsync(); } catch (Exception E) { LogException(E); } } private static bool CheckSwyxIt() { try { var regObj = Registry.GetValue("HKEY_CLASSES_ROOT\\WOW6432Node\\CLSID\\{F8E552F8-4C00-11D3-80BC-00105A653379}\\VersionIndependentProgID", null, null); if ((regObj is string strObj) && (strObj.ToLowerInvariant() == "clmgr.clientlinemgr")) return true; regObj = Registry.GetValue("HKEY_CLASSES_ROOT\\CLSID\\{F8E552F8-4C00-11D3-80BC-00105A653379}\\VersionIndependentProgID", null, null); if ((regObj is string strObj2) && (strObj2.ToLowerInvariant() == "clmgr.clientlinemgr")) return true; } catch (Exception E) { LogException(E); } return false; } private static void TapiMessageHandler(C4TapiHelper.C4TapiLineInfo lineInfo) { try { if (lineInfo.eventType == C4TapiHelper.eTapiEventType.connected) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (lineInfo.IsOutbound && !cFasdCockpitConfig.Instance.PhoneSupport.SignalOutgoingCalls) { LogEntry("An outgoing call is signaled but signaling outgoing calls is not enabled."); return; } var phone = lineInfo.participantPhoneNumber; var phone2 = phone.Trim(); if (!string.IsNullOrEmpty(cFasdCockpitConfig.Instance.PhoneSupport.ExternalCallPrefix) && phone2.StartsWith(cFasdCockpitConfig.Instance.PhoneSupport.ExternalCallPrefix)) phone2 = phone2.Remove(0, cFasdCockpitConfig.Instance.PhoneSupport.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 phoneSearch = new cPhoneSearchParameters() { phone = phone3, name = lineInfo.participantName.Trim() }; SendPhoneSearchValues(phoneSearch); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } } catch (Exception E) { LogException(E); } } private static void StartPhoneCallMonitoring() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); // check phone support disabled if (cFasdCockpitConfig.Instance.PhoneSupport.DisablePhoneSupport) return; var disposeTapi = false; try { // get the TAPI lines lock (C4TapiHelper.InstanceLock) { C4TapiHelper.Instance = new C4TapiHelper(); disposeTapi = true; C4TapiHelper.Instance.Initialize(TapiMessageHandler); C4TapiHelper.Instance.GetLines(); } // check prefer swyxit if (cFasdCockpitConfig.Instance.PhoneSupport.PreferSwyxitNative && CheckSwyxIt()) { if (StartPhoneMonitorExternal("SwyxItNative")) return; } // check if we autoconnect TAPI lock (C4TapiHelper.InstanceLock) { string _tapiLine = null; if (C4TapiHelper.Lines != null && !string.IsNullOrEmpty(cFasdCockpitConfig.Instance.PhoneSupport.PreferedTapiLine) && C4TapiHelper.Lines.Contains(cFasdCockpitConfig.Instance.PhoneSupport.PreferedTapiLine)) _tapiLine = cFasdCockpitConfig.Instance.PhoneSupport.PreferedTapiLine; else if (C4TapiHelper.Lines != null && C4TapiHelper.Lines.Count == 1) _tapiLine = C4TapiHelper.Lines[0]; if (_tapiLine != null) { if (cFasdCockpitConfig.Instance.PhoneSupport.UseTapi32Bit) { if (StartPhoneMonitorExternal(_tapiLine)) return; } if (C4TapiHelper.Instance.ConnectLine(C4TapiHelper.Lines[0])) disposeTapi = false; } } } catch (Exception E) { LogException(E); } finally { lock (C4TapiHelper.InstanceLock) { if (disposeTapi) { C4TapiHelper.Instance.Dispose(); C4TapiHelper.Instance = null; } } LogMethodEnd(CM); } } private static bool StartPhoneMonitorExternal(string Line) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var ass = Assembly.GetEntryAssembly(); var path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(ass.Location)), "F4SD-PhoneMonitor.exe"); if (File.Exists(path)) { var preFix = cFasdCockpitConfig.Instance.PhoneSupport.ExternalCallPrefix ?? ""; var signalExtern = cFasdCockpitConfig.Instance.PhoneSupport.SignalOutgoingCalls ? "1" : "0"; var _cmd = "\"" + App.PipeName + "\" \"" + App.PhoneMonitorPipeName + "\" \"" + Line + "\" \"" + preFix + "\" \"" + signalExtern + "\""; var pr = Process.Start(path, _cmd); return true; } } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } private static async Task InitializeUiElementsAsync() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.LoadAppViews")); CheckHealthCardAvailability(); UpdateRegistryGeometryBasedOnFirstDataOfDataProvider(); // adjust notify icon menu cF4sdUserInfo userInfo; lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock) { userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo; } if (!string.IsNullOrEmpty(cCockpitConfiguration.Instance?.m42ServerConfiguration?.Server)) if (userInfo?.possibleLogons != null) { if (userInfo.possibleLogons.Contains(enumAdditionalAuthentication.M42WinLogon)) { if (App.M42OptionMenuItem != null) { App.M42OptionMenuItem.Visible = true; } } } await InitializeViewsAsync(); AreAppComponentsInitialized = true; var PhoneThread = new Thread(StartPhoneCallMonitoring); PhoneThread.Start(); return true; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } private static void CheckHealthCardAvailability() { try { if (!cHealthCardDataHelper.HasAvailableHealthCard(new List() { enumFasdInformationClass.Ticket })) LogEntry("No available Health Card for Tickets was found.", LogLevels.Info); if (!cHealthCardDataHelper.HasAvailableHealthCard(new List() { enumFasdInformationClass.Computer })) LogEntry("No available Health Card for computers was found.", LogLevels.Error); if (!cHealthCardDataHelper.HasAvailableHealthCard(new List() { enumFasdInformationClass.User })) LogEntry("No available Health Card for users was found.", LogLevels.Error); } catch (Exception E) { LogException(E); } } public static void Terminate() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { lock (C4TapiHelper.InstanceLock) { if (C4TapiHelper.Instance != null) { C4TapiHelper.Instance.Dispose(); C4TapiHelper.Instance = null; } } } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } #region Views & Geometry private static void UpdateRegistryGeometryBasedOnFirstDataOfDataProvider() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { //Get old geometry from registry DetailsPageGeometry lastGeometry = !string.IsNullOrEmpty(cFasdCockpitConfig.Instance.DetailsPageMaxGeometry) ? JsonConvert.DeserializeObject(cFasdCockpitConfig.Instance.DetailsPageMaxGeometry) : new DetailsPageGeometry() { DetailsCollectionGeometry = new DetailsPageDataHistoryCollectionGeometryModel() { SubtitleCount = new List() }, WidgetGeometryList = new List() }; //Get new geometry from DataList cHealthCard firstHealthCard = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.HealthCards.FirstOrDefault(healthCard => healthCard.Value.InformationClasses.Contains(enumFasdInformationClass.Computer)).Value; DetailsPageGeometry newGeometry = new DetailsPageGeometry() { DetailsCollectionGeometry = new DetailsPageDataHistoryCollectionGeometryModel() { SubtitleCount = new List() }, WidgetGeometryList = new List() }; foreach (var widgetData in firstHealthCard.CategoriesStatic.StateCategories) { if (widgetData.IsHidden) continue; newGeometry.WidgetGeometryList.Add(new DetailsPageWidgetGeometryModel() { WidgetTitleCount = widgetData.States.Count, WidgetDetailCount = widgetData.States.Count }); } newGeometry.DetailsCollectionGeometry.ColumnCount = firstHealthCard.MaxAgeInDays; foreach (var detailsData in firstHealthCard.CategoriesHistory.StateCategories) { if (detailsData.IsHidden) continue; var stateCount = detailsData.States.Count; foreach (var state in detailsData.States) { if (state.IsHidden) continue; if (state is cHealthCardStateAggregation aggregationState) stateCount += aggregationState.States.Count; } newGeometry.DetailsCollectionGeometry.SubtitleCount.Add(stateCount); } //Update new geometry var lastGeometryWidgetEnumerator = lastGeometry.WidgetGeometryList.GetEnumerator(); foreach (var widgetGeometry in newGeometry.WidgetGeometryList) { if (lastGeometryWidgetEnumerator.MoveNext()) { var lastWidgetGeometry = lastGeometryWidgetEnumerator.Current; widgetGeometry.WidgetTitleCount = cUtility.SmoothedInt(lastWidgetGeometry.WidgetTitleCount, widgetGeometry.WidgetTitleCount); widgetGeometry.WidgetDetailCount = cUtility.SmoothedInt(lastWidgetGeometry.WidgetDetailCount, widgetGeometry.WidgetDetailCount); } } newGeometry.DetailsCollectionGeometry.ColumnCount = cUtility.SmoothedInt(lastGeometry.DetailsCollectionGeometry.ColumnCount, newGeometry.DetailsCollectionGeometry.ColumnCount); var lastGeometryDetailsSubtitleEnumerator = lastGeometry.DetailsCollectionGeometry.SubtitleCount.GetEnumerator(); for (int i = 0; i < newGeometry.DetailsCollectionGeometry.SubtitleCount.Count; i++) { if (lastGeometryDetailsSubtitleEnumerator.MoveNext()) { int tempSubtitleCountValue = newGeometry.DetailsCollectionGeometry.SubtitleCount[i]; int newSubtitleCountValue = cUtility.SmoothedInt(lastGeometryDetailsSubtitleEnumerator.Current, tempSubtitleCountValue); newGeometry.DetailsCollectionGeometry.SubtitleCount[i] = newSubtitleCountValue; } } //Save new Geometry cFasdCockpitConfig.Instance.DetailsPageMaxGeometry = JsonConvert.SerializeObject(newGeometry); cFasdCockpitConfig.Instance.Save("DetailsPageMaxGeometry"); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } private static DetailsPageGeometry BaseDetailsPageGeometry() { try { string registryGeometryString = cFasdCockpitConfig.Instance.DetailsPageMaxGeometry; DetailsPageGeometry output = !string.IsNullOrEmpty(registryGeometryString) ? JsonConvert.DeserializeObject(registryGeometryString) : new DetailsPageGeometry() { DetailsCollectionGeometry = new DetailsPageDataHistoryCollectionGeometryModel() { SubtitleCount = new List() }, WidgetGeometryList = new List() }; return output; } catch (Exception E) { LogException(E); } finally { } return null; } private static async Task InitializeViewsAsync() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var _arrTasks = new List { Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.slimPage = new Pages.SlimPage.SlimPageView(); }, DispatcherPriority.Normal).Task, Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.detailsPage = new Pages.DetailsPage.DetailsPageView(); }, DispatcherPriority.Normal).Task }; await Task.WhenAll(_arrTasks); _arrTasks = new List { Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.detailsPage.SetGeometryValues(BaseDetailsPageGeometry()); }, DispatcherPriority.Normal).Task, Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.slimPage.SetZoomValue(cFasdCockpitConfig.Instance.SlimPageZoom); }, DispatcherPriority.Normal).Task, Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.detailsPage.SetZoomValue(cFasdCockpitConfig.Instance.DetailsPageZoom); }, DispatcherPriority.Normal).Task }; await Task.WhenAll(_arrTasks); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } #endregion } }