using CefSharp; using CefSharp.WinForms; using System; using System.Diagnostics; using System.IO; using System.Linq; using TweetDuck.Application; using TweetDuck.Browser; using TweetDuck.Browser.Handling; using TweetDuck.Browser.Handling.General; using TweetDuck.Configuration; using TweetDuck.Dialogs; using TweetDuck.Management; using TweetDuck.Plugins; using TweetDuck.Resources; using TweetDuck.Utils; using TweetLib.Core; using TweetLib.Core.Collections; using TweetLib.Core.Utils; using Win = System.Windows.Forms; namespace TweetDuck{ static class Program{ public const string BrandName = Lib.BrandName; public const string VersionTag = Version.Tag; public const string Website = "https://tweetduck.chylex.com"; public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory; public static readonly string ExecutablePath = Win.Application.ExecutablePath; public static readonly bool IsPortable = File.Exists(Path.Combine(ProgramPath, "makeportable")); public static readonly string ScriptPath = Path.Combine(ProgramPath, "scripts"); public static readonly string PluginPath = Path.Combine(ProgramPath, "plugins"); public static readonly string StoragePath = IsPortable ? Path.Combine(ProgramPath, "portable", "storage") : GetDataStoragePath(); public static readonly string PluginDataPath = Path.Combine(StoragePath, "TD_Plugins"); public static readonly string InstallerPath = Path.Combine(StoragePath, "TD_Updates"); private static readonly string CefDataPath = Path.Combine(StoragePath, "TD_Chromium"); public static string UserConfigFilePath => Path.Combine(StoragePath, "TD_UserConfig.cfg"); public static string SystemConfigFilePath => Path.Combine(StoragePath, "TD_SystemConfig.cfg"); public static string PluginConfigFilePath => Path.Combine(StoragePath, "TD_PluginConfig.cfg"); public static string AnalyticsFilePath => Path.Combine(StoragePath, "TD_Analytics.cfg"); private static string ErrorLogFilePath => Path.Combine(StoragePath, "TD_Log.txt"); private static string ConsoleLogFilePath => Path.Combine(StoragePath, "TD_Console.txt"); public static uint WindowRestoreMessage; private static readonly LockManager LockManager = new LockManager(Path.Combine(StoragePath, ".lock")); private static bool HasCleanedUp; public static Reporter Reporter { get; } public static ConfigManager Config { get; } public static ScriptLoader Resources { get; } static Program(){ Reporter = new Reporter(ErrorLogFilePath); Reporter.SetupUnhandledExceptionHandler("TweetDuck Has Failed :("); Config = new ConfigManager(); #if DEBUG Resources = new ScriptLoaderDebug(); #else Resources = new ScriptLoader(); #endif Lib.Initialize(new App.Builder{ ErrorHandler = Reporter, SystemHandler = new SystemHandler(), ResourceHandler = Resources }); } internal static void SetupWinForms(){ Win.Application.EnableVisualStyles(); Win.Application.SetCompatibleTextRenderingDefault(false); } [STAThread] private static void Main(){ SetupWinForms(); Cef.EnableHighDPISupport(); WindowRestoreMessage = NativeMethods.RegisterWindowMessage("TweetDuckRestore"); if (!FileUtils.CheckFolderWritePermission(StoragePath)){ FormMessage.Warning("Permission Error", "TweetDuck does not have write permissions to the storage folder: " + StoragePath, FormMessage.OK); return; } if (!LockManager.Lock(Arguments.HasFlag(Arguments.ArgRestart))){ return; } Config.LoadAll(); if (Arguments.HasFlag(Arguments.ArgImportCookies)){ ProfileManager.ImportCookies(); } else if (Arguments.HasFlag(Arguments.ArgDeleteCookies)){ ProfileManager.DeleteCookies(); } if (Arguments.HasFlag(Arguments.ArgUpdated)){ WindowsUtils.TryDeleteFolderWhenAble(InstallerPath, 8000); WindowsUtils.TryDeleteFolderWhenAble(Path.Combine(StoragePath, "Service Worker"), 4000); BrowserCache.TryClearNow(); } try{ ResourceRequestHandlerBase.LoadResourceRewriteRules(Arguments.GetValue(Arguments.ArgFreeze)); }catch(Exception e){ FormMessage.Error("Resource Freeze", "Error parsing resource rewrite rules: " + e.Message, FormMessage.OK); return; } BrowserCache.RefreshTimer(); CefSharpSettings.WcfEnabled = false; CefSharpSettings.LegacyJavascriptBindingEnabled = true; CefSettings settings = new CefSettings{ UserAgent = BrowserUtils.UserAgentChrome, BrowserSubprocessPath = Path.Combine(ProgramPath, BrandName + ".Browser.exe"), CachePath = StoragePath, UserDataPath = CefDataPath, LogFile = ConsoleLogFilePath, #if !DEBUG LogSeverity = Arguments.HasFlag(Arguments.ArgLogging) ? LogSeverity.Info : LogSeverity.Disable #endif }; var pluginScheme = new PluginSchemeFactory(); settings.RegisterScheme(new CefCustomScheme{ SchemeName = PluginSchemeFactory.Name, IsStandard = false, IsSecure = true, IsCorsEnabled = true, IsCSPBypassing = true, SchemeHandlerFactory = pluginScheme }); CommandLineArgs.ReadCefArguments(Config.User.CustomCefArgs).ToDictionary(settings.CefCommandLineArgs); BrowserUtils.SetupCefArgs(settings.CefCommandLineArgs); Cef.Initialize(settings, false, new BrowserProcessHandler()); Win.Application.ApplicationExit += (sender, args) => ExitCleanup(); FormBrowser mainForm = new FormBrowser(pluginScheme); Resources.Initialize(mainForm); Win.Application.Run(mainForm); if (mainForm.UpdateInstaller != null){ ExitCleanup(); if (mainForm.UpdateInstaller.Launch()){ Win.Application.Exit(); } else{ RestartWithArgsInternal(Arguments.GetCurrentClean()); } } } private static string GetDataStoragePath(){ string custom = Arguments.GetValue(Arguments.ArgDataFolder); if (custom != null && (custom.Contains(Path.DirectorySeparatorChar) || custom.Contains(Path.AltDirectorySeparatorChar))){ if (Path.GetInvalidPathChars().Any(custom.Contains)){ Reporter.HandleEarlyFailure("Data Folder Invalid", "The data folder contains invalid characters:\n" + custom); } else if (!Path.IsPathRooted(custom)){ Reporter.HandleEarlyFailure("Data Folder Invalid", "The data folder has to be either a simple folder name, or a full path:\n" + custom); } return Environment.ExpandEnvironmentVariables(custom); } else{ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), custom ?? BrandName); } } public static void Restart(params string[] extraArgs){ CommandLineArgs args = Arguments.GetCurrentClean(); CommandLineArgs.ReadStringArray('-', extraArgs, args); RestartWithArgs(args); } public static void RestartWithArgs(CommandLineArgs args){ FormBrowser browserForm = FormManager.TryFind<FormBrowser>(); if (browserForm != null){ browserForm.ForceClose(); ExitCleanup(); RestartWithArgsInternal(args); } } private static void RestartWithArgsInternal(CommandLineArgs args){ args.AddFlag(Arguments.ArgRestart); Process.Start(ExecutablePath, args.ToString()); Win.Application.Exit(); } private static void ExitCleanup(){ if (HasCleanedUp){ return; } Config.SaveAll(); Cef.Shutdown(); BrowserCache.Exit(); LockManager.Unlock(); HasCleanedUp = true; } } }