/// <summary>Validate the current options</summary> public override Exception Validate() { return (m_ass.Length == 0 ? new Exception($"Assembly parameter not given") : !Path_.FileExists(m_ass) ? new FileNotFoundException($"Assembly file '{m_ass}' not found") : null); }
public ScriptUI(Model model, string name, string filepath, Guid context_id) { InitializeComponent(); DockControl = new DockControl(this, $"Script-{context_id}") { ShowTitle = false, TabText = name, TabToolTip = filepath, TabCMenu = TabCMenu(), DestroyOnClose = true, }; LastUpdateTime = TimeSpan.Zero; Context = new Context(model, name, context_id); LdrAutoComplete = new View3d.AutoComplete(); Filepath = filepath; Editor = m_editor; Render = Command.Create(this, RenderInternal); SaveScript = Command.Create(this, SaveScriptInternal); RemoveObjects = Command.Create(this, RemoveObjectsInternal); CloseScript = Command.Create(this, CloseScriptInternal); IndentSelection = Command.Create(this, IndentSelectionInternal); CommentOutSelection = Command.Create(this, CommentOutSelectionInternal); UncommentSelection = Command.Create(this, UncommentSelectionInternal); // If the temporary script exists, load it if (Path_.FileExists(Filepath)) { LoadFile(); } DataContext = this; }
/// <summary> /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. /// </summary> /// <param name="cancellationToken">A cancellation token to monitor for initialization cancellation, which can occur when VS is shutting down.</param> /// <param name="progress">A provider for progress updates.</param> /// <returns>A task representing the async work of package initialization, or an already completed task if there is none. Do not return null from this method.</returns> protected override void Initialize() { var root = Path_.Directory(Assembly.GetExecutingAssembly().Location); AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; Assembly?CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { var path = Path_.CombinePath(root, new AssemblyName(args.Name).Name + ".dll"); if (!Path_.FileExists(path)) { return(null); } return(Assembly.LoadFrom(path)); } // When initialized asynchronously, the current thread may be a background thread at this point. // Do any initialization that requires the UI thread after switching to the UI thread. //await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); base.Initialize(); // Add our command handlers for menu if (GetService <IMenuCommandService>() is OleMenuCommandService mcs) { mcs.AddCommand(new AlignMenuCommand(this)); mcs.AddCommand(new UnalignMenuCommand(this)); } }
/// <summary>Load the keys data for the given username and password</summary> private EResult GetKeys(out XElement keys) { keys = null; // Get the key file name. This is an encrypted XML file if (!Path_.FileExists(KeysFilepath)) { return(EResult.NotFound); } // Read the file contents into memory and decrypt it try { // This code throw a CryptographicException when the 'User' has an incorrect password. // This is not an error, it's just that CrytographicException are not disabled by default // in the debugger exception settings. var keys_xml = string.Empty; using (var fs = new FileStream(KeysFilepath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var cs = new CryptoStream(fs, Decryptor, CryptoStreamMode.Read)) using (var sr = new StreamReader(cs)) keys_xml = sr.ReadToEnd(); keys = XElement.Parse(keys_xml, LoadOptions.None); return(EResult.Success); } catch { // If the xml is not valid, assume bad password return(EResult.BadPassword); } }
/// <summary>Upload a local file to the host. The remote file will be named 'remote_filename' on the host</summary> public void Upload(string local_filepath, string remote_filename, ResumeBehaviour resume = ResumeBehaviour.DontResume) { Trace(string.Format("Uploading: {0} to {1}/{2}/{3}", local_filepath, Settings.RemoteHost, Settings.RemotePath, remote_filename)); Reply reply; // Check the local filepath exists first if (!Path_.FileExists(local_filepath)) { throw new FileNotFoundException("Upload failed", local_filepath); } // Upload the file using (var input = new FileStream(local_filepath, FileMode.Open, FileAccess.Read)) { if (resume != ResumeBehaviour.DontResume) { // Some servers may not support resumed uploading. long offset = RemoteFileSize(remote_filename); if (SendCommand("REST " + offset).Code == Status.PendingFurtherInfo) { Trace("Resuming file upload from offset " + offset); input.Seek(offset, SeekOrigin.Begin); } else if (resume == ResumeBehaviour.Resume) { // The caller specifically wanted resuming but it's // not supported, throw so they can choose what to do. Trace("Resuming not supported. Aborting."); throw new NotSupportedException("Resumed upload not supported by server"); } else { Trace("Resuming not supported. Restarting."); input.Seek(0, SeekOrigin.Begin); } } // Store the file reply = SendCommand("STOR " + remote_filename); if (reply.Code != Status.DataConnectionAlreadyOpen && reply.Code != Status.DataConnectionOpenning) { throw new IOException(reply.Message); } // Write the file to the data channel using (BinaryWriter w = new BinaryWriter(ConnectDataStream())) input.CopyTo(w.BaseStream); } // Confirm done reply = ReadReply(); if (reply.Code != Status.DataConnectionClosing && reply.Code != Status.RequestedActionOkay) { throw new IOException(reply.Message); } }
/// <summary>Run the command</summary> public override int Run() { // If a file is given, load the data from it if (m_filepath.HasValue()) { if (!Path_.FileExists(m_filepath)) { throw new Exception($"File '{m_filepath}' doesn't exist"); } m_data = File.ReadAllText(m_filepath); } // If no data is available, error if (!m_data.HasValue()) { throw new Exception("No data to generate key from"); } // No private key? if (!m_pk.HasValue() || !Path_.FileExists(m_pk)) { throw new Exception($"Private key '{m_pk}' doesn't exist"); } var priv = File.ReadAllText(m_pk); var code = ActivationCode.Generate(m_data, priv); var key = Convert.ToBase64String(code); // Save to the system clipboard if (m_outclip) { Clipboard.SetText(key); } // Save to a file if (m_outfile.HasValue()) { key.ToFile(m_outfile); } // Write to StdOut Console.WriteLine(key); return(0); }
/// <summary>Notify observers about the changed items</summary> public bool NotifyChanged() { // Scan the directory and notify about created, deleted, or changed files var current_files = Path_.EnumFileSystem(Path, SearchOption.TopDirectoryOnly, exclude: FileAttributes.Hidden | FileAttributes.Directory) .Select(x => x.FullName).ToList(); var existing = current_files .ToHashSet(x => x.ToLowerInvariant()); foreach (var path in current_files) { // If there is an existing watcher for the file, simply check for changed if (m_files.TryGetValue(path.ToLowerInvariant(), out var file)) { // File unchanged if (!file.HasChanged) { continue; } // File changed, but change not handled if (!file.NotifyChanged()) { continue; } // File no longer exists, remove from 'm_files' if (!Path_.FileExists(file.Path)) { m_files.Remove(file.Path.ToLowerInvariant()); } continue; } // If this is a new file, notify then add file = new WatchedFile(path, m_onchange, Id, m_ctx); if (file.NotifyChanged()) { m_files[path.ToLowerInvariant()] = file; } } return(true); }
/// <summary>Load a pattern set from file</summary> public static PatternSet Load(string filepath) { if (!Path_.FileExists(filepath)) { throw new Exception($"Pattern set file '{filepath}' does not exist"); } var root = XDocument.Load(filepath).Root; if (root == null) { throw new Exception("Pattern set has no root xml node"); } return(new PatternSet(root) { Name = Path_.FileTitle(filepath) }); }
// Notes: // - This is the main logic object for the ED Trade Advisor. // - Generally speaking, it does the following: // - Maintain the database of systems, stations, commodities, price data, etc // - Monitor for changes in the player's location (using the ED journal files) // - Finds the best (ish) trades around the current player location public Advisor(Action <Action> run_on_main_thread) { Settings.Instance.SettingChange += HandleSettingChange; m_marshal_to_main_thread = run_on_main_thread; RebuildStaticData = !Path_.FileExists(EliteDataProvider.Filepath); Shutdown = new CancellationTokenSource(); TradeRoutes = new List <TradeRoute>(); m_find_trade_routes = new AutoResetEvent(false); Web = new Web(Shutdown.Token); Src = new EliteDataProvider(Web, Shutdown.Token); JournalMonitor = new EDJournalMonitor(Shutdown.Token); RunOnMainThread(new Action(() => { Settings.Instance.NotifySettingChanged(nameof(Settings.UseCurrentLocation)); Settings.Instance.NotifySettingChanged(nameof(Settings.ReadCargoCapacityFromLoadout)); Settings.Instance.NotifySettingChanged(nameof(Settings.ReadMaxJumpRangeFromLoadout)); })); }
/// <summary>Sets and saves the ADB file path</summary> private void SetAdbPath(string path) { // Reject invalid paths if (!Path_.FileExists(path)) { return; } // If hint text is shown, clear it first if (m_edit_adb_fullpath.ForeColor == Color.LightGray) { m_edit_adb_fullpath.ForeColor = Color.Black; m_edit_adb_fullpath.Text = string.Empty; } // Only set when different if (m_edit_adb_fullpath.Text != path) { m_edit_adb_fullpath.Text = path; PopulateUsingAdb(); } }
/// <summary>Load settings from AppData</summary> public override void LoadSettingsFromStorage() { // Note: the 'LoadSettingsFromXml' and 'SaveSettingsToXml' methods are // only used when the user Exports or Imports their settings. // To/From storage are used for normal saving. try { var filepath = SettingsFilepath; if (!Path_.FileExists(filepath)) { return; } // Load the settings XML file var root = XDocument.Load(filepath).Root; var grps = root.Elements(nameof(Groups), nameof(AlignGroup)).Select(x => x.As <AlignGroup>()); Groups.Assign(grps); // Load other settings AlignStyle = root.Element(nameof(AlignStyle)).As <EAlignCharacters>(EAlignCharacters.Spaces); } catch { } // Don't allow anything to throw from here, otherwise VS locks up... :-/ }
public Licence(string lic_file) : this() { if (!Path_.FileExists(lic_file)) { throw new FileNotFoundException($"Licence file '{lic_file}' not found"); } // Load the licence file var root = XDocument.Load(lic_file, LoadOptions.None).Root; if (root == null) { throw new InvalidDataException("licence file invalid"); } LicenceHolder = root.Element(nameof(LicenceHolder)).As(LicenceHolder); EmailAddress = root.Element(nameof(EmailAddress)).As(EmailAddress); Company = root.Element(nameof(Company)).As(Company); VersionMask = root.Element(nameof(VersionMask)).As(VersionMask); ActivationCode = root.Element(nameof(ActivationCode)).As(ActivationCode); Changed = false; }
public void Execute(object _) { // Prompt for a log file var fd = new OpenFileDialog { Title = "Open a Log File", Filter = Constants.LogFileFilter, Multiselect = false, CheckFileExists = true, }; if (fd.ShowDialog(m_ui) != true) { return; } var filepath = fd.FileName; try { // Validate if (!Path_.FileExists(filepath)) { throw new FileNotFoundException($"File '{filepath}' does not exist"); } // Add the file to the recent files m_ui.AddToRecentFiles(filepath); // Create a log data source from the log file m_main.LogDataSource = new SingleFileSource(filepath, m_settings); } catch (Exception ex) { m_report.ErrorPopup($"Failed to open file {filepath} due to an error.", ex); m_main.LogDataSource = null; } }
public Licence(string lic_file) : this() { try { if (Path_.FileExists(lic_file)) { // Load the licence file var root = XDocument.Load(lic_file, LoadOptions.None).Root; if (root == null) { throw new InvalidDataException("licence file invalid"); } LicenceHolder = root.Element(XmlTag.LicenceHolder).As(LicenceHolder); EmailAddress = root.Element(XmlTag.EmailAddr).As(EmailAddress); Company = root.Element(XmlTag.Company).As(Company); VersionMask = root.Element(XmlTag.VersionMask).As(VersionMask); ActivationCode = root.Element(XmlTag.ActivationCode).As(ActivationCode); } } catch (FileNotFoundException) { Log.Write(ELogLevel.Info, "Licence file not found"); } catch (Exception ex) { Log.Write(ELogLevel.Error, ex, "Licence file invalid"); } Changed = false; }
/// <summary>Handle unhandled exceptions</summary> private static void HandleTheUnhandled(Exception ex) { var res = MsgBox.Show(null, $"{Application.ProductName} has shutdown with the following error.\r\n"+ $"Error: {ex.GetType().Name}\r\n"+ $"\r\n"+ $"Deleting the applications settings file, '{StartupOptions?.SettingsPath ?? Path_.FileName(Settings.Default.Filepath)}', might prevent this problem.\r\n"+ $"\r\n"+ $"Generating a report and sending it to {Util.GetAssemblyAttribute<AssemblyCompanyAttribute>().Company} will aid in the resolution of this issue. "+ $"The generated report is a plain text file that you can review before sending.\r\n"+ $"\r\n"+ $"Would you like to generate the report?\r\n"+ $"\r\n"+ $"Alternatively, please contact {Constants.SupportEmail} with information about this error so that it can be fixed.\r\n"+ $"\r\n"+ $"Apologies for any inconvenience caused.\r\n", "Unexpected Termination", MessageBoxButtons.YesNo, MessageBoxIcon.Error); if (res == DialogResult.Yes) { var dg = new SaveFileDialog{Title = "Save Crash Report", FileName = Application.ProductName+"CrashReport", Filter = Util.FileDialogFilter("Crash Report Files","*.txt", "All files","*.*"), DefaultExt = "txt", CheckPathExists = true}; if (dg.ShowDialog() == DialogResult.OK) { var settings = "Settings filepath unknown"; if (StartupOptions != null && Path_.FileExists(StartupOptions.SettingsPath)) settings = File.ReadAllText(StartupOptions.SettingsPath); var sb = new StringBuilder() .Append(Application.ProductName).Append(" - Crash Report - ").Append(DateTime.UtcNow).AppendLine() .AppendLine("---------------------------------------------------------------") .AppendLine("[Unhandled Exception Type]") .AppendLine(ex.MessageFull()) .AppendLine() .AppendLine("[Settings File Contents]") .AppendLine(settings) .AppendLine() .AppendLine("[General]") .AppendLine($"Application Version: {Util.AssemblyVersion()}") .AppendLine(Environment.OSVersion.VersionString) .AppendLine(StartupOptions?.Dump() ?? string.Empty) .AppendLine() .AppendLine("[Additional Comments]") .AppendLine("Any additional information about what you were doing when this crash occurred would be extremely helpful and appreciated"); File.WriteAllText(dg.FileName, sb.ToString()); try { if (MsgBox.Show(null, "Preview the report before sending?", "Review Report", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) Process.Start(dg.FileName); } catch {} try { // Try to create an email with the attachment ready to go var email = new MailMessage(); email.From = new MailAddress(Constants.SupportEmail); email.To.Add(Constants.SupportEmail); email.Subject = $"{Util.AppProductName} crash report"; email.Priority = MailPriority.Normal; email.IsBodyHtml = false; email.Body = $"To {Util.AppCompany},\r\n" + $"\r\n" + $"Attached is a crash report generated on {DateTime.Now}.\r\n" + $"A brief description of how the application was being used at the time follows:\r\n" + $"\r\n\r\n\r\n\r\n" + $"Regards,\r\n" + $"A Helpful User"; email.Attachments.Add(new Attachment(dg.FileName)); // Try to send it var smtp = new SmtpClient(); smtp.Send(email); } catch {} } } Environment.ExitCode = 1; }
/// <summary>Starts a worker thread to read bytes from a memory mapped file</summary> public static ManualResetEventSlim BeginRead(string filepath, WaitHandle stop, Action <ArraySegment <byte> > data_cb, int block_size = 1024) { // Use: // var stop = new ManualResetEventSlim(false); // var done = FileContent.BeginRead(filepath, stop, s => UseBytes(s)); // ... // stop.Set(); // done.WaitOne(); var done = new ManualResetEventSlim(false); ThreadPool.QueueUserWorkItem(async _ => { var sr = (Stream?)null; var mmf = (MemoryMappedFile?)null; try { var buffer = new byte[block_size]; for (; ; Thread.Yield()) { // Create the memory mapped file after the monitored file is created if (sr == null) { try { // Cancelled already? if (stop.WaitOne(0)) { break; } // Wait for the file to appear. // 'MemoryMappedFile.CreateFromFile' fails for null or zero-length files if (!Path_.FileExists(filepath) || Path_.FileLength(filepath) == 0) { Thread.Sleep(100); continue; } // Once the file exists, create a memory mapped file from it mmf = mmf ?? MemoryMappedFile.CreateFromFile(filepath, FileMode.Open, Path_.SanitiseFileName($"FileContent-{filepath}"), 0, MemoryMappedFileAccess.Read); sr = mmf.CreateViewStream(); } catch (UnauthorizedAccessException) { Thread.Sleep(100); continue; } } // Read blocks of data from the file var read = await sr.ReadAsync(buffer, 0, buffer.Length); if (read != 0) { data_cb(new ArraySegment <byte>(buffer, 0, read)); continue; } // Only test for exit if no data was read if (stop.WaitOne(0)) { break; } // If no data was read from the file, wait a bit longer Thread.Sleep(10); } } finally { sr?.Dispose(); mmf?.Dispose(); done.Set(); } }); return(done); }
/// <summary>Load and parse the startup options</summary> public StartupOptions(string[] args) { var exe_dir = Util.ResolveAppPath(); if (!Directory.Exists(exe_dir)) { throw new ArgumentException("Cannot determine the current executable directory"); } // Check the command line options for (int i = 0, iend = args.Length; i != iend; ++i) { var arg = args[i].ToLowerInvariant(); // No option character implies the file to load if (arg[0] != '-' && arg[0] != '/') { if (FileToLoad != null) { throw new ArgumentException("Command line should specify a single file path only. If the file path contains white space, remember to use quotes. e.g. RyLogViewer \"my file.txt\""); } FileToLoad = arg; continue; } // Helper for comparing option strings bool IsOption(string opt) => string.CompareOrdinal(arg, 0, opt, 0, opt.Length) == 0; // (order these by longest option first) if (IsOption(CmdLineOption.RDelim)) { RowDelim = arg.Substring(CmdLineOption.RDelim.Length); } else if (IsOption(CmdLineOption.CDelim)) { ColDelim = arg.Substring(CmdLineOption.CDelim.Length); } else if (IsOption(CmdLineOption.NoGUI)) { NoGUI = true; } else if (IsOption(CmdLineOption.Silent)) { Silent = true; } else if (IsOption(CmdLineOption.PatternSet)) { PatternSetFilepath = arg.Substring(CmdLineOption.PatternSet.Length); } else if (IsOption(CmdLineOption.SettingsPath)) { SettingsPath = arg.Substring(CmdLineOption.SettingsPath.Length); } else if (IsOption(CmdLineOption.LogFilePath)) { LogFilePath = arg.Substring(CmdLineOption.LogFilePath.Length); } else if (IsOption(CmdLineOption.Export)) { ExportPath = arg.Substring(CmdLineOption.Export.Length); } else if (IsOption(CmdLineOption.Portable)) { PortableMode = true; } else if (IsOption(CmdLineOption.ShowHelp)) { ShowHelp = true; } else if (IsOption(CmdLineOption.ShowHelp2)) { ShowHelp = true; } else { throw new ArgumentException("Unknown command line option '" + arg + "'."); } } // Determine whether to run the app in portable mode PortableMode |= Path_.FileExists(Path.Combine(exe_dir, "portable")); // Set the UserDataDir based on whether we're running in portable mode or not UserDataDir = Path.GetFullPath(PortableMode ? exe_dir : Util.ResolveUserDocumentsPath(Application.CompanyName, Application.ProductName)); // If we're in portable mode, check that we have write access to the local directory if (PortableMode) { if (!Path_.DirExists(UserDataDir) || (new DirectoryInfo(UserDataDir).Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { throw new IOException("Unable to run in portable mode as the directory ('" + UserDataDir + "') is readonly."); } } // If not in portable mode, check the UserDataDir directory exists (or can be created) else { if (!Path_.DirExists(UserDataDir)) { Directory.CreateDirectory(UserDataDir); } } // If the export option is given, a 'FileToLoad' must also be given if (ExportPath != null && FileToLoad == null) { throw new ArgumentException("A file to export must be given if the '-e' option is used"); } // If a settings path has not been given, use the defaults if (SettingsPath == null) { SettingsPath = Path.Combine(UserDataDir, "settings.xml"); } // Set the licence file path LicenceFilepath = PortableMode ? Path.Combine(exe_dir, "licence.xml") : Path.Combine(UserDataDir, "licence.xml"); // If no licence file exists, create the free one if (!Path_.FileExists(LicenceFilepath)) { new Licence().WriteLicenceFile(LicenceFilepath); } }
/// <summary>Checks for the existence of a file without blocking the UI</summary> public static bool FileExists(Form parent, string filepath) { // Check that the file exists, this can take ages if 'filepath' is a network file bool file_exists = false; var dlg = new ProgressForm("Open File", "Opening file...", null, ProgressBarStyle.Marquee, (s, a, cb) => file_exists = Path_.FileExists(filepath)); using (dlg) dlg.ShowDialog(parent, 500); return(file_exists); }
/// <summary>Starts a worker thread to read lines from the file</summary> public static ManualResetEventSlim BeginReadLines(string filepath, WaitHandle stop, Action <string> lines_cb, Encoding?encoding = null) { // Use: // var stop = new ManualResetEventSlim(false); // var done = FileContent.BeginReadLines(filepath, stop, s => UseLine(s)); // ... // stop.Set(); // done.WaitOne(); var done = new ManualResetEventSlim(false); ThreadPool.QueueUserWorkItem(async _ => { var sr = (StreamReader?)null; var mmf = (MemoryMappedFile?)null; try { for (; ; Thread.Yield()) { // Create the memory mapped file after the monitored file is created if (sr == null) { // Cancelled already? if (stop.WaitOne(0)) { break; } // Wait for the file to appear. // 'MemoryMappedFile.CreateFromFile' fails for null or zero-length files if (!Path_.FileExists(filepath) || Path_.FileLength(filepath) == 0) { Thread.Sleep(100); continue; } // Once the file exists, create a memory mapped file from it mmf = mmf ?? MemoryMappedFile.CreateFromFile(filepath, FileMode.Open, Path_.SanitiseFileName($"FileContent-{filepath}"), 0, MemoryMappedFileAccess.Read); sr = new StreamReader(mmf.CreateViewStream(), encoding ?? Encoding.UTF8); } // Read lines from the file var line = await sr.ReadLineAsync(); if (line != null) { lines_cb(line.Trim('\0')); continue; } // Only test for exit if no data was read if (stop.WaitOne(0)) { break; } // If no data was read from the file, wait a bit longer Thread.Sleep(10); } } finally { sr?.Dispose(); mmf?.Dispose(); done.Set(); } }); return(done); }
/// <summary>Browse to the licence file</summary> private void LocateLicenceFile() { // Prompt for the user to find the licence file var filepath = (string)null; using (var dlg = new OpenFileDialog { Title = "Locate Licence File", Filter = "RyLogViewer Licence File|licence.xml" }) { if (dlg.ShowDialog(this) != DialogResult.OK) { return; } filepath = dlg.FileName; } try { // Check the licence var lic = new Licence(filepath); if (lic.Valid) { // If there is an existing licence file, confirm overwrite if (Path_.FileExists(m_main.StartupOptions.LicenceFilepath)) { // Read the existing licence var existing_lic = (Licence)null; try { existing_lic = new Licence(m_main.StartupOptions.LicenceFilepath); } catch { } if (existing_lic != null && existing_lic.Valid) { // Prompt if about to override an existing valid licence var res = MsgBox.Show(this, $"An existing valid licence already exists:\r\n" + $"Licence Holder: {existing_lic.LicenceHolder}\r\n" + $"Email Address: {existing_lic.EmailAddress}\r\n" + "\r\n" + "Do you want to replace this licence?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (res != DialogResult.Yes) { return; } } // Write the licence to the expected location lic.WriteLicenceFile(m_main.StartupOptions.LicenceFilepath); UpdateUI(); // Say thank you MsgBox.Show(this, "Thank you for activating " + Application.ProductName + ".\r\n" + "Your support is greatly appreciated." , "Activation Successful" , MessageBoxButtons.OK, MessageBoxIcon.Information); } return; } // Valid licence but not for this version if (lic.NotForThisVersion) { MsgBox.Show(this, "This licence is for an older version of " + Application.ProductName + ".\r\n" + "\r\n" + "Please consider purchasing a new licence for this version.\r\n" + "If you believe this to be an error, please contact '" + Constants.SupportEmail + "' for support." , "Licence Out of Date" , MessageBoxButtons.OK, MessageBoxIcon.Information); return; } // Do nothing with free licences if (lic.IsFreeLicence) { MsgBox.Show(this, "This licence is the free edition licence.\r\n" + "\r\n" + "Please consider purchasing a licence for this version.\r\n" + "If you believe this to be an error, please contact '" + Constants.SupportEmail + "' for support." , "Free Edition Licence" , MessageBoxButtons.OK, MessageBoxIcon.Information); return; } // Licence is invalid MsgBox.Show(this, "This licence file is invalid.\r\n" + "\r\n" + "If you believe this to be an error, please contact '" + Constants.SupportEmail + "' for support." , "Activation Failed" , MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (Exception ex) { MsgBox.Show(this, $"Failed to locate and import a valid licence file\r\n{ex.Message}", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
/// <summary> /// Delete a directory and all contained files/subdirectories. /// Returns true if successful and not interrupted</summary> public static bool DelTree(string root, EDelTreeOpts opts, Func <string, EAbortIgnoreRetry> prompt, int timeout_ms = 1000) { prompt = prompt ?? (_ => EAbortIgnoreRetry.Abort); for (;;) { try { // Generate a list of all contained files var files = Directory.GetFiles(root, "*", SearchOption.AllDirectories); if (files.Length != 0) { if (!opts.HasFlag(EDelTreeOpts.FilesOnly) && !opts.HasFlag(EDelTreeOpts.EvenIfNotEmpty)) { throw new IOException($"Cannot delete {root}, directory still contains {files.Length} files"); } // Check for processes holding locks on the files for (;;) { // Find the lock holding processes/services var lockers = FileLockHolders(files); if (!lockers.Any()) { break; } // Prompt the user, Abort, Retry or Ignore var r = prompt( $"The following processes hold locks on files within {root}:\r\n" + $"\t{string.Join("\r\n\t", lockers.Select(x => x.ProcessName))}"); if (r == EAbortIgnoreRetry.Abort) { return(false); } if (r == EAbortIgnoreRetry.Ignore) { break; } } // Delete the contained files if (opts.HasFlag(EDelTreeOpts.FilesOnly) || opts.HasFlag(EDelTreeOpts.EvenIfNotEmpty)) { foreach (var file in files) { if (Path_.FileExists(file)) { File.Delete(file); } } } } // Try to delete the root directory. This can fail because the file system // doesn't necessarily update as soon as the files are deleted. Try to delete, // if that fails, wait a bit, then try again. If that fails, defer to the user. const int Attempts = 3; for (int retries = Attempts; retries-- != 0;) { try { if (opts.HasFlag(EDelTreeOpts.DeleteRoot)) { Directory.Delete(root, true); } else { // Delete the contained directories var dirs = System.IO.Directory.GetDirectories(root, "*", SearchOption.TopDirectoryOnly); foreach (var dir in dirs) { if (Path_.DirExists(dir)) { Directory.Delete(dir, true); } } } return(true); } catch (IOException) { if (retries == 0) { throw; } Thread.Sleep(Math.Max(100, timeout_ms / Attempts)); } } } catch (Exception ex) { var r = prompt( $"Failed to delete directory '{root}'\r\n" + $"{ex.Message}\r\n"); if (r == EAbortIgnoreRetry.Abort) { return(false); } if (r == EAbortIgnoreRetry.Ignore) { return(true); } } } }
/// <summary> /// Smart copy from 'src' to 'dst'. Loosely like XCopy. /// 'src' can be a single file, a comma separated list of files, or a directory<para/> /// 'dst' can be a /// if 'src' is a directory, </summary> public static void Copy(string src, string dst, bool overwrite = false, bool only_if_modified = false, bool ignore_non_existing = false, Action <string>?feedback = null, bool show_unchanged = false) { var src_is_dir = Path_.IsDirectory(src); var dst_is_dir = Path_.IsDirectory(dst) || dst.EndsWith("/") || dst.EndsWith("\\") || src_is_dir; // Find the names of the source files to copy var files = new List <string>(); if (src_is_dir) { files = Path_.EnumFileSystem(src, SearchOption.AllDirectories).Select(x => x.FullName).ToList(); } else if (Path_.FileExists(src)) { files = new List <string>() { src } } ; else if (src.Contains('*') || src.Contains('?')) { files = Path_.EnumFileSystem(src, SearchOption.AllDirectories, new Pattern(EPattern.Wildcard, src).RegexString).Select(x => x.FullName).ToList(); } else if (!ignore_non_existing) { throw new FileNotFoundException($"'{src}' does not exist"); } // If the 'src' represents multiple files, 'dst' must be a directory if (src_is_dir || files.Count > 1) { // if 'dst' doesn't exist, assume it's a directory if (!Path_.DirExists(dst)) { dst_is_dir = true; } // or if it does exist, check that it is actually a directory else if (!dst_is_dir) { throw new FileNotFoundException($"'{dst}' is not a valid directory"); } } // Ensure that 'dstdir' exists. (Canonicalise fixes the case where 'dst' is a drive, e.g. 'C:\') var dstdir = Path_.Canonicalise((dst_is_dir ? dst : Path_.Directory(dst)).TrimEnd('/', '\\')); if (!Path_.DirExists(dstdir)) { Directory.CreateDirectory(dstdir); } // Copy the file(s) to 'dst' foreach (var srcfile in files) { // If 'dst' is a directory, use the same filename from 'srcfile' var dstfile = string.Empty; if (dst_is_dir) { var spath = src_is_dir ? Path_.RelativePath(src, srcfile) : Path_.FileName(srcfile); dstfile = Path_.CombinePath(dstdir, spath); } else { dstfile = dst; } // If 'srcfile' is a directory, ensure the directory exists at the destination if (Path_.IsDirectory(srcfile)) { if (!dst_is_dir) { throw new Exception($"ERROR: {dst} is not a directory"); } // Create the directory at the destination if (!Path_.DirExists(dstfile)) { System.IO.Directory.CreateDirectory(dstfile); } if (feedback != null) { feedback(srcfile + " --> " + dstfile); } } else { // Copy if modified or always based on the flag if (only_if_modified && !Path_.DiffContent(srcfile, dstfile)) { if (feedback != null && show_unchanged) { feedback(srcfile + " --> unchanged"); } continue; } // Ensure the directory path exists var d = Path_.Directory(dstfile); var f = Path_.FileName(dstfile); if (!Path_.DirExists(d)) { System.IO.Directory.CreateDirectory(d); } if (feedback != null) { feedback(srcfile + " --> " + dstfile); } File.Copy(srcfile, dstfile, overwrite); } } }
/// <summary>Pull 'filename' from EDDB. Returns true if the file was downloaded, and the output filepath</summary> public async Task <DownloadFileResult> DownloadFile(string file_url, string output_dir, TimeSpan?maximum_age = null) { var filename = Path_.FileName(file_url); var output_path = Path_.CombinePath(Path_.CreateDirs(output_dir), filename); using (StatusStack.NewStatusMessage($"Downloading '{filename}'...")) { try { HttpRequestMessage req; HttpResponseMessage resp; // Request the head information about the target file Log.Write(ELogLevel.Info, $"Checking size and timestamp of '{filename}'"); req = new HttpRequestMessage(HttpMethod.Head, file_url); resp = await Client.SendAsync(req, Shutdown); if (!resp.IsSuccessStatusCode) { Log.Write(ELogLevel.Error, $"Downloading information for '{filename}' failed: {resp.StatusCode} {resp.ReasonPhrase}"); throw new HttpRequestException($"{resp.ReasonPhrase} ({resp.StatusCode})"); } // Only download if the server version is newer. if (maximum_age != null && Path_.FileExists(output_path)) { var time_diff = new FileInfo(output_path).LastWriteTime - resp.Content.Headers.LastModified; if (time_diff > -maximum_age.Value) { Log.Write(ELogLevel.Info, $"Local copy of '{filename}' is less than {Settings.Instance.DataAge.ToPrettyString(trailing_zeros:false)} older than the latest version"); return(new DownloadFileResult(file_url, output_path, false)); } } // Get the download size (remember it might be compressed) var length = resp.Content.Headers.ContentLength; // The server version is newer, download the whole file Log.Write(ELogLevel.Info, $"Downloading '{filename}' ({length} bytes)"); using (Scope.Create(() => Downloading = true, () => Downloading = false)) { // Make the web request req = new HttpRequestMessage(HttpMethod.Get, file_url); resp = await Client.SendAsync(req, Shutdown); if (!resp.IsSuccessStatusCode) { Log.Write(ELogLevel.Error, $"Downloading '{filename}' failed: {resp.StatusCode} {resp.ReasonPhrase}"); throw new HttpRequestException($"{resp.ReasonPhrase} ({resp.StatusCode})"); } // Read the response content into a file using (var file = new FileStream(output_path, FileMode.Create, FileAccess.Write, FileShare.Read)) { // Decompress if the content is compressed if (resp.Content.Headers.ContentEncoding.Any(x => x == "gzip")) { using (var content = await resp.Content.ReadAsStreamAsync()) using (var gzip = new GZipStream(content, CompressionMode.Decompress)) await gzip.CopyToAsync(file); } else { await resp.Content.CopyToAsync(file); } Log.Write(ELogLevel.Info, $"Download complete '{filename}'"); return(new DownloadFileResult(file_url, output_path, true)); } } } catch { Log.Write(ELogLevel.Error, $"Data file '{filename}' was not available from {file_url}."); return(new DownloadFileResult(file_url, output_path, false)); } } }
// Notes: // - Parsed command line options public StartupOptions(string[] args) { FilesToLoad = new List <string>(); SettingsPath = null !; var exe_dir = Util.ResolveAppPath(); if (!Path_.DirExists(exe_dir)) { throw new ArgumentException("Cannot determine the current executable directory"); } // Check the command line options for (int i = 0, iend = args.Length; i != iend; ++i) { var arg = args[i].ToLowerInvariant(); // No option character implies the file to load if (arg[0] != '-' && arg[0] != '/') { FilesToLoad.Add(arg); continue; } // Helper for comparing option strings bool IsOption(string opt) => string.CompareOrdinal(arg, 0, opt, 0, opt.Length) == 0; // (order these by longest option first) if (IsOption(CmdLine.SettingsPath)) { SettingsPath = arg.Substring(CmdLine.SettingsPath.Length); } else if (IsOption(CmdLine.Portable)) { PortableMode = true; } else if (IsOption(CmdLine.ShowHelp)) { ShowHelp = true; } else if (IsOption(CmdLine.ShowHelp2)) { ShowHelp = true; } else { throw new ArgumentException($"Unknown command line option '{arg}'."); } } // Determine whether to run the app in portable mode PortableMode |= Path_.FileExists(Path_.CombinePath(exe_dir, "portable")); // Set the UserDataDir based on whether we're running in portable mode or not UserDataDir = Path.GetFullPath(PortableMode ? Path_.CombinePath(exe_dir, "UserData") : Util.ResolveUserDocumentsPath("Rylogic", "LDraw")); Path_.CreateDirs(UserDataDir); // Check that we have write access to the user data directory if (!Path_.DirExists(UserDataDir) || (new DirectoryInfo(UserDataDir).Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { throw new IOException($"The user data directory ('{UserDataDir}') is readonly."); } // If a settings path has not been given, use the defaults SettingsPath ??= Path_.CombinePath(UserDataDir, "settings2.xml"); }
/// <summary>Performs an export from the command line</summary> public static void ExportToFile(StartupOptions startup_options) { string tmp_settings_path = Path.Combine(Path.GetTempPath(), "rylog_settings_" + Guid.NewGuid() + ".xml"); try { // Copy the settings to a tmp file so that we don't trash the normal settings if (Path_.FileExists(startup_options.SettingsPath)) { File.Copy(startup_options.SettingsPath, tmp_settings_path); } else { new Settings().Save(tmp_settings_path); } startup_options.SettingsPath = tmp_settings_path; // Load an instance of the app and the options. var m = new Main(startup_options); // Override settings passed on the command line if (startup_options.RowDelim != null) { m.Settings.RowDelimiter = startup_options.RowDelim; } if (startup_options.ColDelim != null) { m.Settings.ColDelimiter = startup_options.ColDelim; } if (startup_options.PatternSetFilepath != null) { // Specifying a pattern set implies the filters and transforms should be enabled m.Settings.Patterns = PatternSet.Load(startup_options.PatternSetFilepath); m.Settings.FiltersEnabled = true; m.Settings.TransformsEnabled = true; } // Do the export using (var outp = new StreamWriter(new FileStream(startup_options.ExportPath, FileMode.Create, FileAccess.Write, FileShare.Read))) { try { var d = new BLIData(m, new SingleFile(startup_options.FileToLoad)); using (d.file) { var rng = new[] { new RangeI(0, long.MaxValue) }; var row_delimiter = Misc.Robitise(m.Settings.RowDelimiter); var col_delimiter = Misc.Robitise(m.Settings.ColDelimiter); if (startup_options.NoGUI) { using (var done = new ManualResetEvent(false)) { ThreadPool.QueueUserWorkItem(x => { d.progress = (c, l) => true; DoExport(d, rng, row_delimiter, col_delimiter, outp); done.Set(); }); done.WaitOne(); if (!startup_options.Silent) { Console.WriteLine("Export completed successfully."); } } } else { if (m.DoExportWithProgress(d, rng, row_delimiter, col_delimiter, outp)) { if (!startup_options.Silent) { Console.WriteLine("Export completed successfully."); } } } } } catch (Exception ex) { Environment.ExitCode = 1; if (!startup_options.Silent) { Console.WriteLine($"Export failed.\r\n{ex.Message}"); } } } } finally { if (Path_.FileExists(tmp_settings_path)) { File.Delete(tmp_settings_path); } } }
/// <summary>Search for the full path of adb.exe</summary> private void AutoDetectAdbPath() { // If the full path is saved in the settings, use that (if it's valid) if (Path_.FileExists(m_settings.AdbFullPath)) { SetAdbPath(m_settings.AdbFullPath); return; } // Quick check the most likely spot var likely_path = Path.Combine(Environment.GetEnvironmentVariable("ANDROID_HOME") ?? string.Empty, @"platform-tools\adb.exe"); if (Path_.FileExists(likely_path)) { SetAdbPath(likely_path); return; } // Not found? longer search... const string msg = "Searching for the Android Debugging Bridge application...\r\n" + "\r\n" + "Trying Path: {0}...\r\n" + "\r\n" + "Click cancel to locate it manually."; var adb_path = string.Empty; var search_paths = new[] { Environment.GetEnvironmentVariable("ANDROID_HOME"), Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Android\android-sdk\platform-tools", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Android\android-sdk\platform-tools", @"D:\Program Files (x86)\Android\android-sdk\platform-tools", @"D:\Program Files\Android\android-sdk\platform-tools", @"E:\Program Files (x86)\Android\android-sdk\platform-tools", @"E:\Program Files\Android\android-sdk\platform-tools", Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"C:\" }; var res = DialogResult.Cancel; try { // Search for 'adb.exe' var find_adb = new ProgressForm("Locating 'adb.exe'...", string.Format(msg, string.Empty), Icon, ProgressBarStyle.Marquee, (s, a, cb) => { foreach (var path in search_paths) { if (s.CancelPending || adb_path.HasValue()) { break; } if (path == null || !Directory.Exists(path)) { continue; } cb(new ProgressForm.UserState { Description = string.Format(msg, path), ForceLayout = false }); Func <string, bool> progress = dir => { cb(ProgressForm.UserState.Empty); return(!s.CancelPending); }; foreach (var fi in Path_.EnumFileSystem(path, SearchOption.AllDirectories, regex_filter:@"adb\.exe", progress:progress)) { // Found one! adb_path = fi.FullName; return; } } }) { StartPosition = FormStartPosition.CenterParent, ClientSize = new Size(640, 280), }; using (find_adb) res = find_adb.ShowDialog(this); } catch (OperationCanceledException) {} catch (Exception ex) { Misc.ShowMessage(this, "An error occurred while searching for 'adb.exe'", "Locating 'adb.exe' failed", MessageBoxIcon.Error, ex); } if (res != DialogResult.OK) { return; } SetAdbPath(adb_path); }