/// <summary> /// Shows the appropriate edit dialog for each setup instruction. /// </summary> /// <param name="currentVariables">Currently used variables (for use in textboxes)</param> /// <returns>true, if the user did not cancel</returns> public static bool ShowDialog(IWin32Window parent, SetupInstruction instruction, string[] currentVariables, ApplicationJob application) { InstructionBaseDialog dialog = null; if (instruction is StartProcessInstruction) { dialog = new StartProcessInstructionDialog(); } else if (instruction is CopyFileInstruction) { dialog = new CopyFileInstructionDialog(); } else if (instruction is CustomSetupInstruction) { dialog = new CustomSetupInstructionDialog(); } else if (instruction is CloseProcessInstruction) { dialog = new CloseProcessInstructionDialog(); } if (dialog != null) { dialog.Application = application; dialog.SetupInstruction = instruction; dialog.VariableNames = currentVariables; if (dialog.ShowDialog(parent) == DialogResult.OK) { return true; } } return false; }
public static void Log(ApplicationJob job, string text) { if (job == null) { Log(text); } else { Log(job.Name + ": " + text); } }
/// <summary> /// Executes the command. /// </summary> /// <param name="targetFileName">Content for variable "{url:...}"</param> public virtual int Execute(ApplicationJob application, string targetFileName) { switch (Type) { case ScriptType.CS: UserCSScript script = new UserCSScript(this.Text); script.Execute(application); break; default: return ExecuteBatchCommand(application, this.Text, targetFileName); } return 0; }
/// <summary> /// Shows a dialog asking the user whether or not to delete the applications /// and deletes them if wanted. /// </summary> /// <returns>true if the application has been deleted, false otherwise</returns> public static bool Show(IWin32Window owner, ApplicationJob[] applications) { if (applications == null || applications.Length == 0) return false; using (DeleteApplicationDialog dialog = new DeleteApplicationDialog()) { if (applications.Length == 1) { dialog.lblQuestion.Text = string.Format(dialog.lblQuestion.Text, applications[0].Name); } else { dialog.lblQuestion.Text = "Do you really want to delete the selected applications from the list?"; } switch (dialog.ShowDialog(owner)) { case DialogResult.OK: // "Delete application" foreach (ApplicationJob application in applications) { application.Delete(); } return true; case DialogResult.Yes: // "Delete application and file" foreach (ApplicationJob application in applications) { PathEx.TryDeleteFiles(application.CurrentLocation); application.Delete(); } return true; case DialogResult.Cancel: default: return false; } } }
private void cmnuEdit_Click(object sender, EventArgs e) { ApplicationJob job = olvJobs.SelectedObject as ApplicationJob; EditJob(job); }
private void cmnuOpenFile_Click(object sender, EventArgs e) { ApplicationJob job = olvJobs.SelectedObject as ApplicationJob; OpenFile(job); }
/// <summary> /// Replaces this variable within a string with the given content. /// Applies functions if necessary. /// </summary> private string Replace(string formatString, string content, ApplicationJob context = null) { return(Replace(formatString, this.Name, content, context ?? this.Parent?.Parent)); }
/// <summary> /// Returns the current status of a given application. /// </summary> /// <returns>Idle by default</returns> public Status GetStatus(ApplicationJob job) { if (m_Status == null || !m_Status.ContainsKey(job)) return Status.Idle; return m_Status[job]; }
/// <summary> /// Executes the actual download from an URL. Does not handle exceptions, /// but takes care of proper cleanup. /// </summary> /// <exception cref="NonBinaryFileException">This exception is thrown, if the resulting file is not of a binary type</exception> /// <exception cref="TargetPathInvalidException">This exception is thrown, if the resulting target path of an application is not valid</exception> /// <param name="job">The job to process</param> /// <param name="urlToRequest">URL from which should be downloaded</param> /// <returns>true, if a new update has been found and downloaded, false otherwise</returns> protected Status DoDownload(ApplicationJob job, Uri urlToRequest) { // Lower security policies try { ServicePointManager.CheckCertificateRevocationList = false; } catch (PlatformNotSupportedException) { // .NET bug under special circumstances } ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; }; // If we want to download multiple files simultaneously // from the same server, we need to "remove" the connection limit. ServicePointManager.DefaultConnectionLimit = 50; job.Variables.ResetDownloadCount(); WebRequest.RegisterPrefix("sf", new ScpWebRequestCreator()); WebRequest.RegisterPrefix("httpx", new HttpxRequestCreator()); WebRequest req = WebRequest.CreateDefault(WebClient.FixNoProtocolUri(urlToRequest)); AddRequestToCancel(req); req.Timeout = Convert.ToInt32(Settings.GetValue("ConnectionTimeout", 10)) * 1000; // 10 seconds by default HttpWebRequest httpRequest = req as HttpWebRequest; if (httpRequest != null) { // Store cookies for future requests. Some sites // check for previously stored cookies before allowing to download. if (httpRequest.CookieContainer == null) { httpRequest.CookieContainer = m_Cookies; } else { httpRequest.CookieContainer.Add(m_Cookies.GetCookies(httpRequest.RequestUri)); } // If we have an HTTP request, some sites may require a correct referer // for the download. // If there are variables defined (from which most likely the download link // or version is being extracted), we'll just use the first variable's URL as referer. // The user still has the option to set a custom referer. // Note: Some websites don't "like" certain referers if (!m_NoAutoReferer.Contains(GetBaseHost(req.RequestUri))) { foreach (UrlVariable urlVar in job.Variables.Values) { httpRequest.Referer = urlVar.Url; break; } } if (!string.IsNullOrEmpty(job.HttpReferer)) { httpRequest.Referer = job.Variables.ReplaceAllInString(job.HttpReferer); } LogDialog.Log(job, "Using referer: " + (string.IsNullOrEmpty(httpRequest.Referer) ? "(none)" : httpRequest.Referer)); httpRequest.UserAgent = (string.IsNullOrEmpty(job.UserAgent) ? WebClient.UserAgent : job.UserAgent); // PAD files may be compressed httpRequest.AutomaticDecompression = (DecompressionMethods.GZip | DecompressionMethods.Deflate); } using (WebResponse response = WebClient.GetResponse(req)) { LogDialog.Log(job, "Server source file: " + req.RequestUri.AbsolutePath); // Occasionally, websites are not available and an error page is encountered // For the case that the content type is just plain wrong, ignore it if the size is higher than 500KB HttpWebResponse httpResponse = response as HttpWebResponse; if (httpResponse != null && response.ContentLength < 500000) { if (response.ContentType.StartsWith("text/xml") || response.ContentType.StartsWith("application/xml")) { // If an XML file is served, maybe we have a PAD file ApplicationJob padJob = ApplicationJob.ImportFromPad(httpResponse); if (padJob != null) { job.CachedPadFileVersion = padJob.CachedPadFileVersion; return DoDownload(job, new Uri(padJob.FixedDownloadUrl)); } } if (response.ContentType.StartsWith("text/html")) { throw NonBinaryFileException.Create(response.ContentType, httpResponse.StatusCode); } } long fileSize = GetContentLength(response); if (fileSize == 0) { throw new IOException("Source file on server is empty (ContentLength = 0)."); } string targetFileName = job.GetTargetFile(response, urlToRequest.AbsoluteUri); LogDialog.Log(job, "Determined target file name: " + targetFileName); // Only download, if the file size or date has changed if (!ForceDownload && !job.RequiresDownload(response, targetFileName)) { // If file already exists (created by user), // the download is not necessary. We still need to // set the file name. // If the file exists, but not at the target location // (after renaming), do not reset the previous location. if (File.Exists(targetFileName)) { job.PreviousLocation = targetFileName; } job.Save(); return Status.NoUpdate; } // Skip downloading! // Installing also requires a forced download if (!ForceDownload && !m_InstallUpdated && (m_OnlyCheck || (job.CheckForUpdatesOnly && !IgnoreCheckForUpdatesOnly))) { LogDialog.Log(job, "Skipped downloading updates"); return Status.UpdateAvailable; } // Execute: Default pre-update command string defaultPreCommand = Settings.GetValue("PreUpdateCommand", "") as string; // For starting external download managers: {preupdate-url} defaultPreCommand = UrlVariable.Replace(defaultPreCommand, "preupdate-url", urlToRequest.ToString()); ScriptType defaultPreCommandType = Command.ConvertToScriptType(Settings.GetValue("PreUpdateCommandType", ScriptType.Batch.ToString()) as string); int exitCode = new Command(defaultPreCommand, defaultPreCommandType).Execute(job, targetFileName); if (exitCode == 1) { LogDialog.Log(job, "Default pre-update command returned '1', download aborted"); throw new CommandErrorException(); } else if (exitCode == 2) { LogDialog.Log(job, "Default pre-update command returned '2', download skipped"); return Status.UpdateAvailable; } // Execute: Application pre-update command exitCode = new Command(UrlVariable.Replace(job.ExecutePreCommand, "preupdate-url", urlToRequest.ToString()), job.ExecutePreCommandType).Execute(job, targetFileName); if (exitCode == 1) { LogDialog.Log(job, "Pre-update command returned '1', download aborted"); throw new CommandErrorException(); } else if (exitCode == 2) { LogDialog.Log(job, "Pre-update command returned '2', download skipped"); return Status.UpdateAvailable; } else if (exitCode == 3) { LogDialog.Log(job, "Pre-update command returned '3', external download"); job.LastUpdated = DateTime.Now; job.Save(); return Status.UpdateSuccessful; } // Read all file contents to a temporary location string tmpLocation = Path.GetTempFileName(); // Read contents from the web and put into file using (Stream sourceFile = response.GetResponseStream()) { using (FileStream targetFile = File.Create(tmpLocation)) { long byteCount = 0; int readBytes = 0; m_Size[job] = fileSize; do { if (m_CancelUpdates) break; // Some adjustment for SCP download: Read only up to the max known bytes int maxRead = (fileSize > 0) ? (int)Math.Min(fileSize - byteCount, 1024) : 1024; if (maxRead == 0) break; byte[] buffer = new byte[maxRead]; readBytes = sourceFile.Read(buffer, 0, maxRead); if (readBytes > 0) targetFile.Write(buffer, 0, readBytes); byteCount += readBytes; OnProgressChanged(byteCount, fileSize, job); } while (readBytes > 0); } } if (m_CancelUpdates) { m_Progress[job] = 0; OnStatusChanged(job); return Status.Failure; } // If each version has a different file name (version number), // we might only want to keep one of them. Also, we might // want to free some space on the target location. if (job.DeletePreviousFile) { PathEx.TryDeleteFiles(job.PreviousLocation); } try { File.SetLastWriteTime(tmpLocation, ApplicationJob.GetLastModified(response)); } catch (ArgumentException) { // Invalid file date. Ignore and just use DateTime.Now } try { FileInfo downloadedFileInfo = new FileInfo(tmpLocation); job.LastFileSize = downloadedFileInfo.Length; job.LastFileDate = downloadedFileInfo.LastWriteTime; } catch (Exception ex) { LogDialog.Log(job, ex); } try { // Before copying, we might have to create the directory Directory.CreateDirectory(Path.GetDirectoryName(targetFileName)); // Copying might fail if variables have been replaced with bad values. // However, we cannot rely on functions to clean up the path, since they // might actually parse the path incorrectly and return an even worse path. File.Copy(tmpLocation, targetFileName, true); } catch (ArgumentException) { throw new TargetPathInvalidException(targetFileName); } catch (NotSupportedException) { throw new TargetPathInvalidException(targetFileName); } File.Delete(tmpLocation); // At this point, the update is complete job.LastUpdated = DateTime.Now; job.PreviousLocation = targetFileName; } job.Save(); job.ExecutePostUpdateCommands(); return Status.UpdateSuccessful; }
public ApplicationJobError(ApplicationJob job, Exception error) { this.RequestedUrl = string.Empty; this.ApplicationJob = job; this.Error = error; }
/// <summary> /// Executes the command. /// </summary> public virtual int Execute(ApplicationJob application) { return(Execute(application, null)); }
public ApplicationJobError(ApplicationJob job, Exception error) { m_ApplicationJob = job; m_Error = error; }
public ApplicationJobError(ApplicationJob job, Exception error, string requestedUrl) { m_ApplicationJob = job; m_Error = error; m_RequestedUrl = requestedUrl; }
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { int openVariable = 0; switch (keyData) { case Keys.Control | Keys.F: ShowSearch(); return(true); case Keys.Escape: if (this.searchPanel.Visible) { HideSearch(); return(true); } break; // Open specific variable in browser case Keys.Control | Keys.D1: openVariable = 1; break; case Keys.Control | Keys.D2: openVariable = 2; break; case Keys.Control | Keys.D3: openVariable = 3; break; case Keys.Control | Keys.D4: openVariable = 4; break; case Keys.Control | Keys.D5: openVariable = 5; break; case Keys.Control | Keys.D6: openVariable = 6; break; case Keys.Control | Keys.D7: openVariable = 7; break; case Keys.Control | Keys.D8: openVariable = 8; break; case Keys.Control | Keys.D9: openVariable = 9; break; } // Open specific variable in browser if (openVariable > 0) { ApplicationJob job = SelectedObject as ApplicationJob; if (job != null) { int count = 0; foreach (UrlVariable variable in job.Variables.Values) { count++; if (count == openVariable) { try { if (variable.VariableType == UrlVariable.Type.Textual) { System.Diagnostics.Process.Start(variable.GetExpandedTextualContent(DateTime.MinValue)); } else { System.Diagnostics.Process.Start(variable.ExpandedUrl); } } catch (Exception) { } break; } } return(true); } } return(base.ProcessCmdKey(ref msg, keyData)); }
public KetarinProtocolProvider(ApplicationJob job, CookieContainer cookies) { this.job = job; this.cookies = cookies; }
/// <summary> /// Executes a given command for the given application (also resolves variables). /// </summary> /// <returns>Exit code of the command, if not run in background</returns> private static int ExecuteBatchCommand(ApplicationJob job, string commandText, string targetFileName) { // Ignore empty commands if (string.IsNullOrEmpty(commandText)) { return(0); } commandText = commandText.Replace("\r\n", "\n"); // Job specific data commandText = job != null?job.Variables.ReplaceAllInString(commandText, DateTime.MinValue, targetFileName, false) : UrlVariable.GlobalVariables.ReplaceAllInString(commandText); // Replace variable: root try { commandText = UrlVariable.Replace(commandText, "root", Path.GetPathRoot(Application.StartupPath), job); } catch (ArgumentException) { } // Feed cmd.exe with our commands ProcessStartInfo cmdExe = new ProcessStartInfo("cmd.exe") { RedirectStandardInput = true, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true }; bool executeBackground = commandText.EndsWith("&"); commandText = commandText.TrimEnd('&'); using (Process proc = Process.Start(cmdExe)) { StringBuilder commandResult = new StringBuilder(); // Set the event handler to asynchronously read the command output. proc.OutputDataReceived += delegate(object sendingProcess, DataReceivedEventArgs outLine) { if (!string.IsNullOrEmpty(outLine.Data)) { commandResult.AppendLine(outLine.Data); } }; proc.ErrorDataReceived += delegate(object sendingProcess, DataReceivedEventArgs outLine) { if (!string.IsNullOrEmpty(outLine.Data)) { commandResult.AppendLine(outLine.Data); } }; // Start the asynchronous read of the command output stream. proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); // Input commands using (proc.StandardInput) { string[] commands = commandText.Split('\n'); foreach (string command in commands) { if (!string.IsNullOrEmpty(command)) { LogDialog.Log(job, "Executing command: " + command); } proc.StandardInput.WriteLine(command); } } // Read output if (!executeBackground) { proc.WaitForExit(); string commandResultString = commandResult.ToString(); if (!string.IsNullOrEmpty(commandResultString)) { LogDialog.Log(job, "Command result: " + commandResultString); } return(proc.ExitCode); } } return(0); }
private void cmnuCopy_Click(object sender, EventArgs e) { List <ApplicationJob> jobs = this.olvJobs.SelectedObjects.OfType <ApplicationJob>().ToList(); SafeClipboard.SetData(ApplicationJob.GetXml(jobs, false, Encoding.UTF8), false); }
public JobProgressChangedEventArgs(int progressPercentage, ApplicationJob job) : base(progressPercentage, null) { m_Job = job; }
/// <summary> /// Edits an application job. It is possible to edit multiple jobs at the same time. /// </summary> private void EditJob(ApplicationJob job) { if (job == null) return; if (this.openApps.ContainsKey(job)) { this.openApps[job].BringToFront(); } else { ApplicationJobDialog dialog = new ApplicationJobDialog(); dialog.ApplicationJob = job; this.openApps[job] = dialog; dialog.Show(this); dialog.FormClosed += new FormClosedEventHandler(delegate(object sender, FormClosedEventArgs e) { if (dialog.DialogResult == DialogResult.OK) { dialog.ApplicationJob.Save(); olvJobs.RefreshObject(job); UpdateNumByStatus(); } this.openApps.Remove(job); dialog.Dispose(); }); } }
static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // Set an error handler (just a message box) for unexpected exceptions in threads AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; // Parse command line arguments CommandlineArguments arguments = new CommandlineArguments(args); // Is a database path set per command line? if (!string.IsNullOrEmpty(arguments["database"])) { DbManager.DatabasePath = arguments["database"]; } // Initialise database try { DbManager.CreateOrUpgradeDatabase(); WebRequest.DefaultWebProxy = DbManager.Proxy; if (Settings.GetValue("AuthorGuid") == null) { Settings.SetValue("AuthorGuid", Guid.NewGuid().ToString("B")); } } catch (Exception ex) { MessageBox.Show("Could not create or load the database file: " + ex.Message); return; } // Initialisation of protocols. WebRequest.RegisterPrefix("sf", new ScpWebRequestCreator()); WebRequest.RegisterPrefix("httpx", new HttpxRequestCreator()); // Either run silently on command line... if (arguments["silent"] != null) { Kernel32.ManagedAttachConsole(Kernel32.ATTACH_PARENT_PROCESS); ApplicationJob[] jobs = DbManager.GetJobs(); // Filter by application name and category. string categoryFilter = arguments["category"]; if (!string.IsNullOrEmpty(categoryFilter)) { jobs = jobs.Where(x => string.Equals(x.Category, categoryFilter, StringComparison.OrdinalIgnoreCase)).ToArray(); } string appFilter = arguments["appname"]; if (!string.IsNullOrEmpty(appFilter)) { jobs = jobs.Where(x => LikeOperator.LikeString(x.Name, appFilter, Microsoft.VisualBasic.CompareMethod.Text)).ToArray(); } Updater updater = new Updater(); updater.StatusChanged += updater_StatusChanged; updater.ProgressChanged += updater_ProgressChanged; updater.BeginUpdate(jobs, false, false); if (arguments["notify"] != null) { m_Icon = new NotifyIcon { Icon = System.Drawing.Icon.FromHandle(Properties.Resources.Restart.GetHicon()), Text = "Ketarin is working...", Visible = true }; } while (updater.IsBusy) { Thread.Sleep(1000); } m_Icon?.Dispose(); Kernel32.FreeConsole(); } // ...perform database operations... else if (arguments["update"] != null && arguments["appguid"] != null) { // Update properties of an application in the database ApplicationJob job = DbManager.GetJob(new Guid(arguments["appguid"])); if (job == null) { return; } if (arguments["PreviousLocation"] != null) { job.PreviousLocation = arguments["PreviousLocation"]; } job.Save(); } else if (arguments["export"] != null) { ApplicationJob[] jobs = DbManager.GetJobs(); string exportedXml = ApplicationJob.GetXml(jobs, false, System.Text.Encoding.UTF8); try { File.WriteAllText(arguments["export"], exportedXml, System.Text.Encoding.UTF8); } catch (Exception ex) { Console.WriteLine("Could not export to the specified location: " + ex.Message); } } else if (arguments["import"] != null) { string sourceFile = arguments["import"]; try { if (arguments["clear"] != null) { ApplicationJob.DeleteAll(); } ApplicationJob.ImportFromXml(sourceFile); } catch (Exception ex) { Console.WriteLine("Could not import from the specified location: " + ex.Message); } } else if (arguments["install"] != null) { try { // Install all applications in the given XML ApplicationJob[] appsToInstall; string path = arguments["install"]; if (Uri.IsWellFormedUriString(path, UriKind.Absolute)) { using (WebClient client = new WebClient()) { appsToInstall = ApplicationJob.ImportFromXmlString(client.DownloadString(path), false); } } else { appsToInstall = ApplicationJob.ImportFromXml(path); } InstallingApplicationsDialog dialog = new InstallingApplicationsDialog { Applications = appsToInstall, ShowIcon = true, ShowInTaskbar = true, AutoClose = (arguments["exit"] != null) }; Application.Run(dialog); } catch (Exception ex) { MessageBox.Show("Setup cannot be started: " + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); } } // ...or launch the GUI. else { Application.Run(new MainForm()); } string logFile = arguments["log"]; if (!string.IsNullOrEmpty(logFile)) { try { logFile = UrlVariable.GlobalVariables.ReplaceAllInString(logFile); LogDialog.SaveLogToFile(logFile); } catch (Exception) { // ignore errors } } }
/// <summary> /// Fires the StatusChanged event. /// </summary> protected virtual void OnStatusChanged(ApplicationJob job) { if (StatusChanged != null) { StatusChanged(this, new JobStatusChangedEventArgs(job, GetStatus(job))); } }
private static void OpenFile(ApplicationJob job) { try { System.Diagnostics.Process.Start(job.CurrentLocation); } catch (Exception) { // ignore if fails for whatever reason } }
/// <summary> /// Returns the download size of a given application in bytes. /// </summary> /// <returns>-1 if the size cannot be determined, -2 if no file size has been determined yet</returns> public long GetDownloadSize(ApplicationJob job) { if (m_Size == null || !m_Size.ContainsKey(job)) return -1; return m_Size[job]; }
private static void OpenDownloadFolder(ApplicationJob job) { try { if (job != null) { System.Diagnostics.Process.Start("explorer", " /select," + job.CurrentLocation); } } catch (Exception) { // ignore if fails for whatever reason } }
/// <summary> /// Checks for which of the given applications updates /// are available asynchronously. /// </summary> public void BeginCheckForOnlineUpdates(ApplicationJob[] jobs) { DateTime lastUpdate = (DateTime)Settings.GetValue("LastUpdateCheck", DateTime.MinValue); if (lastUpdate.Date == DateTime.Now.Date) { // Only check once a day return; } Settings.SetValue("LastUpdateCheck", DateTime.Now); Thread thread = new Thread(new ParameterizedThreadStart(CheckForOnlineUpdates)); thread.IsBackground = true; thread.Start(jobs); }
private void ExecuteHotkey(Hotkey hotkey, ApplicationJob job) { ApplicationJob[] jobs = olvJobs.SelectedApplications; switch (hotkey.Name) { case "OpenWebsite": OpenWebsite(job); break; case "Edit": EditJob(job); break; case "Update": RunJobs(jobs, false, false, false); break; case "ForceDownload": RunJobs(jobs, false, true, false); break; case "InstallSelected": InstallSelectedApplications(); break; case "OpenFile": OpenFile(job); break; case "OpenFolder": OpenDownloadFolder(job); break; case "CheckUpdate": RunJobs(jobs, true, false, false); break; case "UpdateAndInstall": RunJobs(jobs, false, false, true); break; } }
/// <summary> /// Returns a sorted list of all existing application jobs. /// </summary> public static ApplicationJob[] GetJobs() { Dictionary<Guid, List<UrlVariable>> allVariables = new Dictionary<Guid, List<UrlVariable>>(); using (IDbCommand command = Connection.CreateCommand()) { command.CommandText = "SELECT * FROM variables"; using (IDataReader reader = command.ExecuteReader()) { while (reader.Read()) { UrlVariable variable = new UrlVariable(); variable.Hydrate(reader); Guid jobGuid = new Guid(reader["JobGuid"] as string); if (!allVariables.ContainsKey(jobGuid)) { allVariables[jobGuid] = new List<UrlVariable>(); } allVariables[jobGuid].Add(variable); } } } using (IDbCommand command = Connection.CreateCommand()) { command.CommandText = "SELECT * FROM jobs ORDER BY ApplicationName"; List<ApplicationJob> result = new List<ApplicationJob>(); using (IDataReader reader = command.ExecuteReader()) { while (reader.Read()) { ApplicationJob job = new ApplicationJob(); job.Hydrate(reader); if (allVariables.ContainsKey(job.Guid)) { foreach (UrlVariable var in allVariables[job.Guid]) { job.Variables[var.Name] = var; } } result.Add(job); } } return result.ToArray(); } }
private void SaveAndShowJob(ApplicationJob job) { job.Save(); olvJobs.AddObject(job); olvJobs.SelectedObject = job; olvJobs.EnsureVisible(olvJobs.SelectedIndex); UpdateStatusbar(); }
private void RunJobs(ApplicationJob[] jobs, bool onlyCheck, bool forceDownload, bool installUpdated) { if (m_Updater.IsBusy) return; bRun.Text = "Cancel"; bRun.SplitMenu = null; bRun.Image = null; bInstall.Enabled = false; cmnuImportFile.Enabled = false; mnuExportSelected.Enabled = false; mnuExportAll.Enabled = false; mnuImport.Enabled = false; m_Updater.ForceDownload = forceDownload; m_Updater.BeginUpdate(jobs, onlyCheck, installUpdated); olvJobs.RefreshObjects(jobs); }
/// <summary> /// Executes the actual download from an URL. Does not handle exceptions, /// but takes care of proper cleanup. /// </summary> /// <exception cref="NonBinaryFileException">This exception is thrown, if the resulting file is not of a binary type</exception> /// <exception cref="TargetPathInvalidException">This exception is thrown, if the resulting target path of an application is not valid</exception> /// <param name="job">The job to process</param> /// <param name="urlToRequest">URL from which should be downloaded</param> /// <returns>true, if a new update has been found and downloaded, false otherwise</returns> protected Status DoDownload(ApplicationJob job, Uri urlToRequest) { // Determine number of segments to create int segmentCount = Convert.ToInt32(Settings.GetValue("SegmentCount", 1)); job.Variables.ResetDownloadCount(); WebRequest req = KetarinProtocolProvider.CreateRequest(urlToRequest, job, this.m_Cookies); AddRequestToCancel(req); using (WebResponse response = WebClient.GetResponse(req)) { LogDialog.Log(job, "Server source file: " + req.RequestUri.AbsolutePath); // Occasionally, websites are not available and an error page is encountered // For the case that the content type is just plain wrong, ignore it if the size is higher than 500KB HttpWebResponse httpResponse = response as HttpWebResponse; if (httpResponse != null && response.ContentLength < 500000) { if (response.ContentType.StartsWith("text/xml") || response.ContentType.StartsWith("application/xml")) { // If an XML file is served, maybe we have a PAD file ApplicationJob padJob = ApplicationJob.ImportFromPad(httpResponse); if (padJob != null) { job.CachedPadFileVersion = padJob.CachedPadFileVersion; return(this.DoDownload(job, new Uri(padJob.FixedDownloadUrl))); } } if (response.ContentType.StartsWith("text/html")) { bool avoidNonBinary = (bool)Settings.GetValue("AvoidDownloadingNonBinaryFiles", true); if (httpResponse.StatusCode != HttpStatusCode.OK || avoidNonBinary) { throw NonBinaryFileException.Create(response.ContentType, httpResponse.StatusCode); } } } long fileSize = GetContentLength(response); if (fileSize == 0) { throw new IOException("Source file on server is empty (ContentLength = 0)."); } string targetFileName = job.GetTargetFile(response, urlToRequest.AbsoluteUri); LogDialog.Log(job, "Determined target file name: " + targetFileName); // Only download, if the file size or date has changed if (!ForceDownload && !job.RequiresDownload(response, targetFileName)) { // If file already exists (created by user), // the download is not necessary. We still need to // set the file name. // If the file exists, but not at the target location // (after renaming), do not reset the previous location. if (File.Exists(targetFileName)) { job.PreviousLocation = targetFileName; } job.Save(); return(Status.NoUpdate); } // Skip downloading! // Installing also requires a forced download if (!ForceDownload && !m_InstallUpdated && (m_OnlyCheck || (job.CheckForUpdatesOnly && !IgnoreCheckForUpdatesOnly))) { LogDialog.Log(job, "Skipped downloading updates"); return(Status.UpdateAvailable); } // Execute: Default pre-update command string defaultPreCommand = Settings.GetValue("PreUpdateCommand", "") as string; // For starting external download managers: {preupdate-url} defaultPreCommand = UrlVariable.Replace(defaultPreCommand, "preupdate-url", urlToRequest.ToString(), job); ScriptType defaultPreCommandType = Command.ConvertToScriptType(Settings.GetValue("PreUpdateCommandType", ScriptType.Batch.ToString()) as string); int exitCode = new Command(defaultPreCommand, defaultPreCommandType).Execute(job, targetFileName); if (exitCode == 1) { LogDialog.Log(job, "Default pre-update command returned '1', download aborted"); throw new CommandErrorException(); } else if (exitCode == 2) { LogDialog.Log(job, "Default pre-update command returned '2', download skipped"); return(Status.UpdateAvailable); } // Execute: Application pre-update command exitCode = new Command(UrlVariable.Replace(job.ExecutePreCommand, "preupdate-url", urlToRequest.ToString(), job), job.ExecutePreCommandType).Execute(job, targetFileName); if (exitCode == 1) { LogDialog.Log(job, "Pre-update command returned '1', download aborted"); throw new CommandErrorException(); } else if (exitCode == 2) { LogDialog.Log(job, "Pre-update command returned '2', download skipped"); return(Status.UpdateAvailable); } else if (exitCode == 3) { LogDialog.Log(job, "Pre-update command returned '3', external download"); job.LastUpdated = DateTime.Now; job.Save(); return(Status.UpdateSuccessful); } // Read all file contents to a temporary location string tmpLocation = Path.GetTempFileName(); DateTime lastWriteTime = ApplicationJob.GetLastModified(response); // Only use segmented downloader with more than one segment. if (segmentCount > 1) { // Response can be closed now, new one will be created. response.Dispose(); m_Size[job] = fileSize; Downloader d = new Downloader(new ResourceLocation { Url = urlToRequest.AbsoluteUri, ProtocolProvider = new KetarinProtocolProvider(job, m_Cookies) }, null, tmpLocation, segmentCount); d.Start(); while (d.State < DownloaderState.Ended) { if (m_CancelUpdates) { d.Pause(); break; } this.OnProgressChanged(d.Segments.Sum(x => x.Transfered), fileSize, job); Thread.Sleep(250); } if (d.State == DownloaderState.EndedWithError) { throw d.LastError; } } else { // Read contents from the web and put into file using (Stream sourceFile = response.GetResponseStream()) { using (FileStream targetFile = File.Create(tmpLocation)) { long byteCount = 0; int readBytes; m_Size[job] = fileSize; // Only create buffer once and re-use. const int bufferSize = 1024 * 1024; byte[] buffer = new byte[bufferSize]; do { if (m_CancelUpdates) { break; } // Some adjustment for SCP download: Read only up to the max known bytes int maxRead = (fileSize > 0) ? (int)Math.Min(fileSize - byteCount, bufferSize) : bufferSize; if (maxRead == 0) { break; } readBytes = sourceFile.Read(buffer, 0, maxRead); if (readBytes > 0) { targetFile.Write(buffer, 0, readBytes); } byteCount += readBytes; this.OnProgressChanged(byteCount, fileSize, job); } while (readBytes > 0); } } } if (m_CancelUpdates) { m_Progress[job] = 0; OnStatusChanged(job); return(Status.Failure); } // If each version has a different file name (version number), // we might only want to keep one of them. Also, we might // want to free some space on the target location. if (job.DeletePreviousFile) { PathEx.TryDeleteFiles(job.PreviousLocation); } try { File.SetLastWriteTime(tmpLocation, lastWriteTime); } catch (ArgumentException) { // Invalid file date. Ignore and just use DateTime.Now } // File downloaded. Now let's check if the hash value is valid or abort otherwise! if (!string.IsNullOrEmpty(job.HashVariable) && job.HashType != HashType.None) { string varName = job.HashVariable.Trim('{', '}'); string expectedHash = job.Variables.ReplaceAllInString("{" + varName + "}").Trim(); // Compare online hash with actual current hash. if (!string.IsNullOrEmpty(expectedHash)) { string currentHash = job.GetFileHash(tmpLocation); if (string.Compare(expectedHash, currentHash, StringComparison.OrdinalIgnoreCase) != 0) { LogDialog.Log(job, string.Format("File downloaded, but hash of downloaded file {0} does not match the expected hash {1}.", currentHash, expectedHash)); File.Delete(tmpLocation); throw new IOException("Hash verification failed."); } } } try { FileInfo downloadedFileInfo = new FileInfo(tmpLocation); job.LastFileSize = downloadedFileInfo.Length; job.LastFileDate = downloadedFileInfo.LastWriteTime; } catch (Exception ex) { LogDialog.Log(job, ex); } try { // Before copying, we might have to create the directory Directory.CreateDirectory(Path.GetDirectoryName(targetFileName)); // Copying might fail if variables have been replaced with bad values. // However, we cannot rely on functions to clean up the path, since they // might actually parse the path incorrectly and return an even worse path. File.Copy(tmpLocation, targetFileName, true); } catch (ArgumentException) { throw new TargetPathInvalidException(targetFileName); } catch (NotSupportedException) { throw new TargetPathInvalidException(targetFileName); } File.Delete(tmpLocation); // At this point, the update is complete job.LastUpdated = DateTime.Now; job.PreviousLocation = targetFileName; } job.Save(); job.ExecutePostUpdateCommands(); return(Status.UpdateSuccessful); }
private void cmnuPaste_Click(object sender, EventArgs e) { try { ApplicationJob[] jobs = null; try { jobs = ApplicationJob.LoadFromXml(SafeClipboard.GetData(DataFormats.Text) as string); } catch (Exception) { jobs = new ApplicationJob[] { ApplicationJob.ImportFromTemplateOrXml(this, SafeClipboard.GetData(DataFormats.Text) as string, m_Jobs, true) }; } if (jobs == null || jobs.Length == 0) return; foreach (ApplicationJob job in jobs) { job.Guid = Guid.NewGuid(); job.PreviousLocation = null; job.CanBeShared = true; job.Save(); olvJobs.AddObject(job); } // Go to last job olvJobs.EnsureVisible(olvJobs.IndexOf(jobs[jobs.Length - 1])); olvJobs.SelectedObject = jobs[jobs.Length - 1]; UpdateStatusbar(); } catch (Exception) { } }
private void cmnuOpenFolder_Click(object sender, EventArgs e) { ApplicationJob job = olvJobs.SelectedObject as ApplicationJob; OpenDownloadFolder(job); }
/// <summary> /// Opens the website of a specified application. /// </summary> private static void OpenWebsite(ApplicationJob job) { try { System.Diagnostics.Process.Start(job.ExpandedWebsiteUrl); } catch (Exception) { } }
public MainForm() { InitializeComponent(); olvJobs.Initialize(); olvJobs.ContextMenu = cmnuJobs; colName.AspectGetter = x => ((ApplicationJob)x).Name; colName.GroupKeyGetter = delegate(object x) { ApplicationJob job = (ApplicationJob)x; if (job.Name.Length == 0) { return(string.Empty); } return(job.Name[0].ToString().ToUpper()); }; // Gray out disabled jobs olvJobs.RowFormatter = delegate(OLVListItem item) { item.ForeColor = !((ApplicationJob)item.RowObject).Enabled ? Color.Gray : olvJobs.ForeColor; }; colName.ImageGetter = delegate(object x) { ApplicationJob job = (ApplicationJob)x; // Gray icon if disabled if (!job.Enabled && !string.IsNullOrEmpty(job.CurrentLocation) && m_Updater.GetStatus(job) == Updater.Status.Idle) { try { string disabledKey = job.CurrentLocation + "|Disabled"; if (!imlStatus.Images.ContainsKey(disabledKey)) { // No icon if no file exists if (!File.Exists(job.CurrentLocation)) { return(0); } Icon programIcon = IconReader.GetFileIcon(job.CurrentLocation, IconReader.IconSize.Small, false); imlStatus.Images.Add(disabledKey, MakeGrayscale(programIcon.ToBitmap())); } return(disabledKey); } catch (ArgumentException) { // no icon could be determined, use default } } // If available and idle, use the program icon if (m_Updater.GetStatus(job) == Updater.Status.Idle && !string.IsNullOrEmpty(job.CurrentLocation)) { try { if (!imlStatus.Images.ContainsKey(job.CurrentLocation)) { // No icon if no file exists if (!File.Exists(job.CurrentLocation)) { return(0); } Icon programIcon = IconReader.GetFileIcon(job.CurrentLocation, IconReader.IconSize.Small, false); imlStatus.Images.Add(job.CurrentLocation, programIcon); } return(job.CurrentLocation); } catch (ArgumentException) { // no icon could be determined, use default } } return((int)m_Updater.GetStatus(job)); }; colStatus.AspectGetter = x => this.m_Updater.GetStatus(x as ApplicationJob); colStatus.AspectToStringConverter = delegate(object x) { switch ((Updater.Status)x) { case Updater.Status.Downloading: return("Downloading"); case Updater.Status.Failure: return("Failed"); case Updater.Status.Idle: return("Idle"); case Updater.Status.NoUpdate: return("No update"); case Updater.Status.UpdateSuccessful: return("Updated"); case Updater.Status.UpdateAvailable: return("Update available"); } return(string.Empty); }; colTarget.AspectGetter = delegate(object x) { ApplicationJob job = x as ApplicationJob; return(job.Variables.ReplaceAllInString(job.TargetPath, DateTime.MinValue, null, true)); }; colTarget.GroupKeyGetter = x => ((ApplicationJob)x).TargetPath.ToLower(); colLastUpdate.AspectGetter = x => ((ApplicationJob)x).LastUpdated; colLastUpdate.AspectToStringFormat = "{0:g}"; colLastUpdate.GroupKeyGetter = delegate(object x) { ApplicationJob job = (ApplicationJob)x; if (job.LastUpdated == null) { return(DateTime.MinValue); } return(job.LastUpdated.Value.Date); }; colLastUpdate.GroupKeyToTitleConverter = delegate(object x) { if ((DateTime)x == DateTime.MinValue) { return(string.Empty); } return(((DateTime)x).ToString("d")); }; colProgress.AspectGetter = x => this.m_Updater.GetProgress(x as ApplicationJob); colProgress.Renderer = new ApplicationJobsListView.ProgressRenderer(m_Updater, 0, 100); m_Updater.ProgressChanged += this.m_Updater_ProgressChanged; m_Updater.StatusChanged += this.m_Updater_StatusChanged; m_Updater.UpdateCompleted += this.m_Updater_UpdateCompleted; m_Updater.UpdatesFound += this.m_Updater_UpdatesFound; LogDialog.Instance.VisibleChanged += delegate { mnuLog.Checked = LogDialog.Instance.Visible; }; this.olvJobs.FilterChanged += this.olvJobs_FilterChanged; imlStatus.Images.Add(Resources.Document); imlStatus.Images.Add(Resources.Import); imlStatus.Images.Add(Resources.New); imlStatus.Images.Add(Resources.NewDownloaded); imlStatus.Images.Add(Resources.Symbol_Check); imlStatus.Images.Add(Resources.Symbol_Delete); imlStatus.Images.Add(Resources.Document_Restricted); }
/// <summary> /// Replaces this variable within a string with the given content. /// Applies functions if necessary. /// </summary> private string Replace(string formatString, string content, ApplicationJob context = null) { return(Replace(formatString, m_Name, content, context)); }
private void UpdateAndInstallApp(DoWorkEventArgs e, ApplicationJob job, ref int count) { // Check: Are actually some instructions defined? if (job.SetupInstructions.Count == 0) { LogInfo(job.Name + ": Skipped since no setup instructions exist", LogItemType.Warning); return; } if (bgwSetup.CancellationPending) return; // Force update if no file exists if (this.UpdateApplications || !job.FileExists) { UpdateStatus(string.Format("Updating application {0} of {1}: {2}", count, this.Applications.Length, job.Name)); Updater updater = new Updater(); updater.IgnoreCheckForUpdatesOnly = true; updater.BeginUpdate(new ApplicationJob[] { job }, false, false); // Wait until finished while (updater.IsBusy) { updater.ProgressChanged += new EventHandler<Updater.JobProgressChangedEventArgs>(updater_ProgressChanged); if (bgwSetup.CancellationPending) { updater.Cancel(); return; } Thread.Sleep(500); } this.Invoke((MethodInvoker)delegate() { progressBar.Style = ProgressBarStyle.Marquee; }); // Did update fail? Install if {file} is present. if (updater.Errors.Length > 0) { if (job.FileExists) { LogInfo(job.Name + ": Update failed, installing previously available version", LogItemType.Warning); } else { LogInfo(job.Name + ": Update failed", LogItemType.Error); return; } } } UpdateStatus(string.Format("Installing application {0} of {1}: {2}", count, this.Applications.Length, job.Name)); job.Install(bgwSetup); LogInfo(job.Name + ": Installed successfully", LogItemType.Info); this.installCounter++; count++; }
/// <summary> /// Replaces a variable with the given name within a string /// with the given content. /// Applies functions if necessary. /// </summary> public static string Replace(string formatString, string varname, string content, ApplicationJob context = null) { if (content == null) { content = string.Empty; } if (formatString == null) { return(string.Empty); } int pos, length; string functionPart; int startAt = 0; // We need to "rematch" multiple times if the string changes while (GetVariablePosition(formatString, varname, startAt, out pos, out length, out functionPart)) { formatString = formatString.Remove(pos, length); try { string replaceValue = ReplaceFunction(functionPart, content, context); startAt = pos + replaceValue.Length; formatString = formatString.Insert(pos, replaceValue); } catch (VariableIsEmptyException ex) { throw new VariableIsEmptyException(string.Format("Variable \"{0}\" is empty.", varname)); } } return(formatString); }
/// <summary> /// Shows the appropriate edit dialog for each setup instruction. /// </summary> /// <param name="currentVariables">Currently used variables (for use in textboxes)</param> /// <returns>true, if the user did not cancel</returns> public static bool ShowDialog(IWin32Window parent, SetupInstruction instruction, string[] currentVariables, ApplicationJob application) { InstructionBaseDialog dialog = null; if (instruction is StartProcessInstruction) { dialog = new StartProcessInstructionDialog(); } else if (instruction is CopyFileInstruction) { dialog = new CopyFileInstructionDialog(); } else if (instruction is CustomSetupInstruction) { dialog = new CustomSetupInstructionDialog(); } else if (instruction is CloseProcessInstruction) { dialog = new CloseProcessInstructionDialog(); } if (dialog != null) { dialog.Application = application; dialog.SetupInstruction = instruction; dialog.VariableNames = currentVariables; if (dialog.ShowDialog(parent) == DialogResult.OK) { return(true); } } return(false); }
/// <summary> /// Applies a function (if given) to content and returns the /// modified content. /// </summary> /// <param name="function">A function specification, for example "replace:a:b"</param> /// <param name="content">The usual variable content</param> /// <param name="context">ApplicationJob context for referencing values of other variables</param> private static string ReplaceFunction(string function, string content, ApplicationJob context = null) { function = function.TrimStart(':'); if (string.IsNullOrEmpty(function)) { return(content); } string[] parts = SplitEscaped(function, ':'); if (parts.Length == 0) { return(content); } switch (parts[0]) { case "runpowershell": case "ps": try { if (context != null && !context.CanBeShared) { LogDialog.Log(context, "PowerShell command of downloaded application is not executed for security reasons."); return(string.Empty); } PowerShellScript psScript = new PowerShellScript(content); psScript.Execute(context); return(psScript.LastOutput); } catch { return(string.Empty); } case "empty": // Useful, if you want to load, but not use a variable return(string.Empty); case "ifempty": if (string.IsNullOrEmpty(content) && context != null && parts.Length > 1) { return(context.Variables.ReplaceAllInString("{" + parts[1] + "}")); } return(content); case "ifemptythenerror": if (string.IsNullOrEmpty(content)) { throw new VariableIsEmptyException(); } return(content); case "regexreplace": try { if (parts.Length > 2) { Regex regex = new Regex(parts[1], RegexOptions.Singleline | RegexOptions.IgnoreCase); return(regex.Replace(content, delegate(Match match) { string result = parts[2]; for (int i = 0; i < match.Groups.Count; i++) { result = result.Replace("$" + i, match.Groups[i].Value); } return result; })); } } catch (ArgumentException ex) { LogDialog.Log("Could not process the function 'regexreplace'.", ex); } return(string.Empty); case "multireplace": case "multireplacei": if (parts.Length > 3) { if (string.IsNullOrEmpty(parts[1])) { break; } // Exmaple: multireplace:,:a,b,c:1,2,3 char delimiter = parts[1][0]; string[] search = parts[2].Split(delimiter); string[] replace = parts[3].Split(delimiter); for (int i = 0; i < search.Length; i++) { string replaceValue = (replace.Length > i) ? replace[i] : string.Empty; content = parts[0] == "multireplacei" ? ReplaceEx(content, search[i], replaceValue) : content.Replace(search[i], replaceValue); } return(content); } break; case "regex": try { Regex regex = new Regex(parts[1], RegexOptions.Singleline); Match match = regex.Match(content); if (parts.Length > 2) { int groupNum = Conversion.ToInt(parts[2]); if (groupNum >= 0 && groupNum < match.Groups.Count) { return(match.Groups[groupNum].Value); } } return((match.Success) ? match.Value : string.Empty); } catch (ArgumentException ex) { LogDialog.Log("Could not process the function 'regex'.", ex); return(string.Empty); } case "regexrandom": try { Regex regex = new Regex(parts[1], RegexOptions.Singleline); MatchCollection matches = regex.Matches(content); if (matches.Count > 0) { int randomPos = random.Next(0, matches.Count - 1); int groupNum = (parts.Length > 2) ? Conversion.ToInt(parts[2]) : -1; if (groupNum >= 0 && groupNum < matches[randomPos].Groups.Count) { return(matches[randomPos].Groups[groupNum].Value); } else { return(matches[randomPos].Value); } } return(string.Empty); } catch (ArgumentException ex) { LogDialog.Log("Could not process the function 'regex'.", ex); return(string.Empty); } case "ext": return(Path.GetExtension(content).TrimStart('.')); case "basefile": return(Path.GetFileNameWithoutExtension(content)); case "directory": try { if (content.StartsWith("\"") && content.EndsWith("\"")) { return("\"" + Path.GetDirectoryName(content.Trim('"')) + "\""); } else { return(Path.GetDirectoryName(content.Trim('"'))); } } catch { return(content); } case "filename": try { return(Path.GetFileName(content)); } catch { return(content); } case "filenameWithoutExtension": try { return(Path.GetFileNameWithoutExtension(content)); } catch { return(content); } case "toupper": return(content.ToUpper()); case "tolower": return(content.ToLower()); case "split": if (parts.Length >= 3) { string[] contentParts = content.Split(parts[1][0]); int partNum; if (Int32.TryParse(parts[2], out partNum)) { if (partNum < 0) { // Negative number: Count from the end partNum = contentParts.Length + partNum; } if (partNum >= 0 && partNum < contentParts.Length) { return(contentParts[partNum]); } } } break; case "trim": if (parts.Length >= 2) { return(content.Trim(parts[1].ToCharArray())); } else { return(content.Trim()); } case "padleft": if (parts.Length == 3) { return(content.PadLeft(Conversion.ToInt(parts[1]), parts[2][0])); } else if (parts.Length == 2) { return(content.PadLeft(Conversion.ToInt(parts[1]), ' ')); } return(content); case "padright": if (parts.Length == 3) { return(content.PadRight(Conversion.ToInt(parts[1]), parts[2][0])); } else if (parts.Length == 2) { return(content.PadRight(Conversion.ToInt(parts[1]), ' ')); } return(content); case "trimend": if (parts.Length >= 2) { return(content.TrimEnd(parts[1].ToCharArray())); } else { return(content.TrimEnd()); } case "trimstart": if (parts.Length >= 2) { return(content.TrimStart(parts[1].ToCharArray())); } else { return(content.TrimStart()); } case "replace": if (parts.Length >= 3) { return(content.Replace(parts[1], parts[2])); } break; case "formatfilesize": return(FormatFileSize.Format(Conversion.ToInt(content))); case "startuppath": return(Application.StartupPath); case "urldecode": return(HttpUtility.UrlDecode(content)); case "urlencode": return(HttpUtility.UrlEncode(content)); } return(content); }
public ApplicationJobError(ApplicationJob job, Exception error, string requestedUrl) { this.ApplicationJob = job; this.Error = error; this.RequestedUrl = requestedUrl; }
private void UpdateAndInstallApp(DoWorkEventArgs e, ApplicationJob job, ref int count) { // Check: Are actually some instructions defined? if (job.SetupInstructions.Count == 0) { LogInfo(job.Name + ": Skipped since no setup instructions exist", LogItemType.Warning); return; } if (bgwSetup.CancellationPending) { return; } // Force update if no file exists if (this.UpdateApplications || !job.FileExists) { UpdateStatus(string.Format("Updating application {0} of {1}: {2}", count, this.Applications.Length, job.Name)); Updater updater = new Updater { IgnoreCheckForUpdatesOnly = true }; updater.BeginUpdate(new[] { job }, false, false); // Wait until finished while (updater.IsBusy) { updater.ProgressChanged += this.updater_ProgressChanged; if (bgwSetup.CancellationPending) { updater.Cancel(); return; } Thread.Sleep(500); } this.Invoke((MethodInvoker) delegate() { progressBar.Style = ProgressBarStyle.Marquee; }); // Did update fail? Install if {file} is present. if (updater.Errors.Length > 0) { if (job.FileExists) { LogInfo(job.Name + ": Update failed, installing previously available version", LogItemType.Warning); } else { LogInfo(job.Name + ": Update failed", LogItemType.Error); return; } } } UpdateStatus(string.Format("Installing application {0} of {1}: {2}", count, this.Applications.Length, job.Name)); job.Install(bgwSetup); LogInfo(job.Name + ": Installed successfully", LogItemType.Info); this.installCounter++; count++; }
/// <summary> /// Fires the ProgressChangedEvent. Only fires if the progress value /// has changed significantly to prevent (for example) too frequent GUI updates. /// </summary> /// <param name="pos">Current position of the stream</param> /// <param name="length">Total length of the stream</param> /// <param name="job">Current ApplicationJob</param> protected virtual void OnProgressChanged(long pos, long length, ApplicationJob job) { if (length == -1) { // Cannot report progress if no info given if (ProgressChanged != null) { if (m_NoProgressCounter > 100) m_NoProgressCounter = 0; m_Progress[job] = m_NoProgressCounter; ProgressChanged(this, new JobProgressChangedEventArgs(m_NoProgressCounter++, job)); } return; } double progress = (double)pos / length * 100.0; byte progressInt = Convert.ToByte(Math.Round(progress)); if (progressInt != m_LastProgress) { if (ProgressChanged != null) { ProgressChanged(this, new JobProgressChangedEventArgs(progressInt, job)); } m_Progress[job] = progressInt; m_LastProgress = progressInt; } }
static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // Set an error handler (just a message box) for unexpected exceptions in threads AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); // Parse command line arguments CommandlineArguments arguments = new CommandlineArguments(args); // Is a database path set per command line? if (!string.IsNullOrEmpty(arguments["database"])) { DbManager.DatabasePath = arguments["database"]; } // Initialise database try { DbManager.CreateOrUpgradeDatabase(); WebRequest.DefaultWebProxy = DbManager.Proxy; if (Settings.GetValue("AuthorGuid") == null) { Settings.SetValue("AuthorGuid", Guid.NewGuid().ToString("B")); } } catch (Exception ex) { MessageBox.Show("Could not create or load the database file: " + ex.Message); return; } // Either run silently on command line... if (arguments["silent"] != null) { Kernel32.ManagedAttachConsole(Kernel32.ATTACH_PARENT_PROCESS); ApplicationJob[] jobs = DbManager.GetJobs(); Updater updater = new Updater(); updater.StatusChanged += new EventHandler <Updater.JobStatusChangedEventArgs>(updater_StatusChanged); updater.ProgressChanged += new EventHandler <Updater.JobProgressChangedEventArgs>(updater_ProgressChanged); updater.BeginUpdate(jobs, false, false); if (arguments["notify"] != null) { m_Icon = new NotifyIcon(); m_Icon.Icon = System.Drawing.Icon.FromHandle(Properties.Resources.Restart.GetHicon()); m_Icon.Text = "Ketarin is working..."; m_Icon.Visible = true; } while (updater.IsBusy) { Thread.Sleep(1000); } if (m_Icon != null) { m_Icon.Dispose(); } Kernel32.FreeConsole(); } // ...perform database operations... else if (arguments["update"] != null && arguments["appguid"] != null) { // Update properties of an application in the database ApplicationJob job = DbManager.GetJob(new Guid(arguments["appguid"])); if (job == null) { return; } if (arguments["PreviousLocation"] != null) { job.PreviousLocation = arguments["PreviousLocation"]; } job.Save(); } else if (arguments["export"] != null) { ApplicationJob[] jobs = DbManager.GetJobs(); string exportedXml = ApplicationJob.GetXml(jobs, false, System.Text.Encoding.UTF8); try { File.WriteAllText(arguments["export"] as string, exportedXml, System.Text.Encoding.UTF8); } catch (Exception ex) { Console.WriteLine("Could export to the specified location: " + ex.Message); } } else if (arguments["install"] != null) { try { // Install all applications in the given XML ApplicationJob[] appsToInstall = null; string path = arguments["install"] as string; if (Uri.IsWellFormedUriString(path, UriKind.Absolute)) { using (WebClient client = new WebClient()) { appsToInstall = ApplicationJob.ImportFromXmlString(client.DownloadString(path), false); } } else { appsToInstall = ApplicationJob.ImportFromXml(path); } InstallingApplicationsDialog dialog = new InstallingApplicationsDialog(); dialog.Applications = appsToInstall; dialog.ShowIcon = true; dialog.ShowInTaskbar = true; dialog.AutoClose = (arguments["exit"] != null); Application.Run(dialog); } catch (Exception ex) { MessageBox.Show("Setup cannot be started: " + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); } } // ...or launch the GUI. else { Application.Run(new MainForm()); } string logFile = arguments["log"]; if (!string.IsNullOrEmpty(logFile)) { try { logFile = UrlVariable.GlobalVariables.ReplaceAllInString(logFile); LogDialog.SaveLogToFile(logFile); } catch (Exception) { // ignore errors } } }
public JobStatusChangedEventArgs(ApplicationJob job, Status newStatus) { m_Job = job; m_NewStatus = newStatus; }
private void bOK_Click(object sender, EventArgs e) { Cursor = Cursors.WaitCursor; try { foreach (RpcApplication app in olvApplications.SelectedObjects) { IKetarinRpc proxy = XmlRpcProxyGen.Create<IKetarinRpc>(); string xml = proxy.GetApplication(app.ShareId); ApplicationJob resultJob = ApplicationJob.LoadOneFromXml(xml); // For security reasons, we remove some of the properties // if it's not the users own job if (!DbManager.ApplicationExists(resultJob.Guid)) { resultJob.CanBeShared = false; } resultJob.Save(); m_ImportedApplication = resultJob; // Real value is determined while saving if (!resultJob.CanBeShared) { resultJob.DownloadDate = app.UpdatedAtDate; resultJob.ExecuteCommand = string.Empty; resultJob.TargetPath = string.Empty; resultJob.PreviousLocation = string.Empty; // If possible, determine some values based on the default // values for a new application. string defaultXml = Settings.GetValue("DefaultApplication", "") as string; if (!string.IsNullOrEmpty(defaultXml)) { ApplicationJob defaultApp = ApplicationJob.LoadOneFromXml(defaultXml); if (defaultApp != null) { resultJob.TargetPath = defaultApp.TargetPath; resultJob.ExecuteCommand = defaultApp.ExecuteCommand; resultJob.ExecutePreCommand = defaultApp.ExecutePreCommand; } } resultJob.Save(); } } } catch (XmlRpcException ex) { MessageBox.Show(this, "An error occured while importing applications: " + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); DialogResult = DialogResult.None; } catch (WebException ex) { MessageBox.Show(this, "Could not connect to the online database: " + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); DialogResult = DialogResult.None; } finally { Cursor = Cursors.Default; } }
/// <summary> /// Returns the progress of the given application. /// </summary> /// <returns>-1 for no progress yet, otherwise 0 to 100</returns> public short GetProgress(ApplicationJob job) { if (m_Progress == null || !m_Progress.ContainsKey(job)) return -1; return m_Progress[job]; }
private void bOK_Click(object sender, EventArgs e) { // Check that name is not empty if (string.IsNullOrEmpty(this.txtApplicationName.Text)) { MessageBox.Show(this, "The application name must not be empty.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.None; return; } // Check for valid URL if (this.rbFixedUrl.Checked && string.IsNullOrEmpty(this.txtFixedUrl.Text)) { MessageBox.Show(this, "You did not enter a download URL. The application will not be downloaded as long as no URL is specified.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { // Check that a target location is given if (string.IsNullOrEmpty(this.txtTarget.Text)) { MessageBox.Show(this, "You did not specify a target location.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.None; return; } } if (this.rbFileHippo.Checked && String.IsNullOrEmpty(this.txtFileHippoId.Text)) { MessageBox.Show(this, "You did not specify a FileHippo ID.\r\nYou can paste the desired URL from the FileHippo.com website, the ID will be extracted automatically.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.None; return; } this.WriteApplication(); // All good. If necessary, now start a thread // which is going to share the application online. ApplicationJob job = this.ApplicationJob; if (job.ShareApplication) { this.Cursor = Cursors.WaitCursor; try { IKetarinRpc proxy = XmlRpcProxyGen.Create <IKetarinRpc>(); proxy.Timeout = 10000; RpcApplication[] existingApps = proxy.GetSimilarApplications(job.Name, job.Guid.ToString()); if (existingApps.Length > 0) { // Prevent similar entries by asking the author // to reconsider his choice of name. SimilarApplicationsDialog dialog = new SimilarApplicationsDialog { ApplicationJob = job, Applications = existingApps }; if (dialog.ShowDialog(this) != DialogResult.OK) { return; } } // Everything is fine, upload now. Thread thread = new Thread(ShareOnline) { IsBackground = true }; thread.Start(job); } catch (WebException ex) { MessageBox.Show(this, "Your application could not be submitted to the online database because of an connection error: " + ex.Message, "Connection error", MessageBoxButtons.OK, MessageBoxIcon.Warning); } finally { this.Cursor = Cursors.Default; } } // Required for non modal call this.Close(); }
/// <summary> /// Starts one or more threads which update the given /// applications asynchronously. /// </summary> /// <param name="onlyCheck">Specifies whether or not to download the updates</param> public void BeginUpdate(ApplicationJob[] jobs, bool onlyCheck, bool installUpdated) { m_IsBusy = true; m_Jobs = jobs; m_ThreadLimit = Convert.ToInt32(Settings.GetValue("ThreadCount", 2)); m_OnlyCheck = onlyCheck; m_InstallUpdated = installUpdated; m_Requests.Clear(); // Initialise progress and status m_Progress = new Dictionary<ApplicationJob, short>(); foreach (ApplicationJob job in m_Jobs) { m_Progress[job] = (short)((ForceDownload || job.Enabled) ? 0 : -1); bool res = m_Progress.ContainsKey(job); m_Status[job] = Status.Idle; m_Size[job] = -2; } m_Threads.Clear(); Thread thread = new Thread(UpdateApplications); thread.Start(); }
public static void ImportFromFile(string filename) { XmlDocument doc = new XmlDocument(); doc.Load(filename); // Import settings from file as dictionary XmlElement settingsElem = doc.SelectSingleNode("//Settings/dictionary") as XmlElement ?? doc.SelectSingleNode("//dictionary") as XmlElement; if (settingsElem != null) { XmlSerializer serializer = new XmlSerializer(typeof(SerializableDictionary <string, string>)); using (StringReader textReader = new StringReader(settingsElem.OuterXml)) { DbManager.SetSettings(serializer.Deserialize(textReader) as Dictionary <string, string>); } } // Import global variables XmlElement varNodes = doc.SelectSingleNode("//GlobalVariables") as XmlElement; if (varNodes != null) { UrlVariable.GlobalVariables.Clear(); foreach (XmlElement varElem in doc.SelectNodes("//GlobalVariables/Variable")) { UrlVariable newVar = new UrlVariable { Name = varElem.GetAttribute("Name"), CachedContent = varElem.GetAttribute("Content") }; UrlVariable.GlobalVariables[newVar.Name] = newVar; } UrlVariable.GlobalVariables.Save(); } // Import code snippets XmlElement snippetNodes = doc.SelectSingleNode("//CodeSnippets") as XmlElement; if (snippetNodes != null) { using (SQLiteCommand comm = DbManager.Connection.CreateCommand()) { comm.CommandText = "DELETE FROM snippets"; comm.ExecuteNonQuery(); } foreach (XmlElement snippetElem in doc.SelectNodes("//CodeSnippets/Snippet")) { Snippet snippet = new Snippet { Guid = new Guid(snippetElem.GetAttribute("Guid")), Name = snippetElem.GetAttribute("Name"), Type = (ScriptType)Convert.ToInt32(snippetElem.GetAttribute("Type")), Text = snippetElem.InnerText }; snippet.Save(); } } XmlElement setupNodes = doc.SelectSingleNode("//SetupLists") as XmlElement; if (setupNodes != null) { using (IDbCommand command = DbManager.Connection.CreateCommand()) { command.CommandText = @"DELETE FROM setuplists_applications"; command.ExecuteNonQuery(); } using (IDbCommand command = DbManager.Connection.CreateCommand()) { command.CommandText = @"DELETE FROM setuplists"; command.ExecuteNonQuery(); } foreach (XmlElement listElem in doc.SelectNodes("//SetupLists/List")) { ApplicationList list = new ApplicationList { Name = listElem.GetAttribute("Name"), Guid = new Guid(listElem.GetAttribute("Guid")) }; foreach (XmlElement appListElem in listElem.SelectNodes("Applications/Application")) { Guid guid = new Guid(appListElem.GetAttribute("Guid")); ApplicationJob job = DbManager.GetJob(guid); if (job != null) { list.Applications.Add(job); } } list.Save(); } } }
/// <summary> /// Executes the actual download (determines the URL to download from). Does not handle exceptions, /// but takes care of proper cleanup. /// </summary> /// <param name="job">The job to process</param> /// <param name="requestedUrl">The URL from which has been downloaded</param> /// <returns>true, if a new update has been found and downloaded, false otherwise</returns> protected Status DoDownload(ApplicationJob job, out string requestedUrl) { string downloadUrl = string.Empty; if (job.DownloadSourceType == ApplicationJob.SourceType.FileHippo) { downloadUrl = ExternalServices.FileHippoDownloadUrl(job.FileHippoId, job.AvoidDownloadBeta); } else { downloadUrl = job.FixedDownloadUrl; // Now replace variables downloadUrl = job.Variables.ReplaceAllInString(downloadUrl); } requestedUrl = downloadUrl; if (string.IsNullOrEmpty(downloadUrl)) { // No download URL specified, only check if update is required if (job.RequiresDownload(null, null)) { return Status.UpdateAvailable; } else { return Status.NoUpdate; } } Uri url = new Uri(downloadUrl); return DoDownload(job, url); }
private void bOK_Click(object sender, EventArgs e) { this.Cursor = Cursors.WaitCursor; try { foreach (RpcApplication app in this.olvApplications.SelectedObjects) { IKetarinRpc proxy = XmlRpcProxyGen.Create <IKetarinRpc>(); string xml = proxy.GetApplication(app.ShareId); ApplicationJob resultJob = ApplicationJob.LoadOneFromXml(xml); // For security reasons, we remove some of the properties // if it's not the users own job if (!DbManager.ApplicationExists(resultJob.Guid)) { resultJob.CanBeShared = false; } resultJob.Save(); this.ImportedApplications.Add(resultJob); // Real value is determined while saving if (!resultJob.CanBeShared) { resultJob.DownloadDate = app.UpdatedAtDate; resultJob.ExecuteCommand = string.Empty; resultJob.ExecutePreCommand = string.Empty; resultJob.TargetPath = string.Empty; resultJob.PreviousLocation = string.Empty; // If possible, determine some values based on the default // values for a new application. string defaultXml = Settings.GetValue("DefaultApplication", "") as string; if (!string.IsNullOrEmpty(defaultXml)) { ApplicationJob defaultApp = ApplicationJob.LoadOneFromXml(defaultXml); if (defaultApp != null) { resultJob.TargetPath = defaultApp.TargetPath; resultJob.ExecuteCommand = defaultApp.ExecuteCommand; resultJob.ExecutePreCommand = defaultApp.ExecutePreCommand; } } resultJob.Save(); } } } catch (XmlRpcException ex) { MessageBox.Show(this, "An error occured while importing applications: " + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.None; } catch (WebException ex) { MessageBox.Show(this, "Could not connect to the online database: " + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); this.DialogResult = DialogResult.None; } finally { this.Cursor = Cursors.Default; } }
public static void Log(ApplicationJob job, Exception ex) { Log(job.Name + ": Failed, " + ex.Message); }
/// <summary> /// Returns an application from the database which has the specified GUID. /// </summary> public static ApplicationJob GetJob(Guid appGuid) { ApplicationJob job = null; using (IDbCommand command = Connection.CreateCommand()) { command.CommandText = "SELECT * FROM jobs WHERE JobGuid = @JobGuid"; command.Parameters.Add(new SQLiteParameter("@JobGuid", FormatGuid(appGuid))); using (IDataReader reader = command.ExecuteReader()) { if (reader.Read()) { job = new ApplicationJob(); job.Hydrate(reader); } } } if (job != null) { using (IDbCommand command = Connection.CreateCommand()) { command.CommandText = @"SELECT * FROM variables WHERE JobGuid = @JobGuid"; command.Parameters.Add(new SQLiteParameter("@JobGuid", DbManager.FormatGuid(appGuid))); using (IDataReader reader = command.ExecuteReader()) { while (reader.Read()) { UrlVariable variable = new UrlVariable(job.Variables); variable.Hydrate(reader); job.Variables.Add(variable.Name, variable); } } } } return job; }
/// <summary> /// Performs the actual update check for the current applications. /// Starts multiple threads if necessary. /// </summary> private void UpdateApplications() { m_CancelUpdates = false; m_Errors = new List <ApplicationJobError>(); LogDialog.Log(string.Format("Update started with {0} application(s)", m_Jobs.Length)); try { ApplicationJob previousJob = null; foreach (ApplicationJob job in m_Jobs) { // Skip if disabled if (!job.Enabled && m_Jobs.Length > 1) { continue; } // Wait until we can start a new thread: // - Thread limit is not reached // - The next application is not to be downloaded exclusively // - The application previously started is not to be downloaded exclusively // - Setup is taking place while (m_Threads.Count >= m_ThreadLimit || (m_Threads.Count > 0 && (m_InstallUpdated || job.ExclusiveDownload || (previousJob != null && previousJob.ExclusiveDownload)))) { Thread.Sleep(200); foreach (Thread activeThread in m_Threads) { if (!activeThread.IsAlive) { m_Threads.Remove(activeThread); break; } } } // Stop if cancelled if (m_CancelUpdates) { break; } Thread newThread = new Thread(this.StartNewThread); previousJob = job; newThread.Start(job); m_Threads.Add(newThread); } // Now, wait until all threads have finished while (m_Threads.Count > 0) { Thread.Sleep(200); foreach (Thread activeThread in m_Threads) { if (!activeThread.IsAlive) { m_Threads.Remove(activeThread); break; } } } try { string postUpdateCommand = Settings.GetValue("PostUpdateCommand", "") as string; ScriptType postUpdateCommandType = Command.ConvertToScriptType(Settings.GetValue("PostUpdateCommandType", ScriptType.Batch.ToString()) as string); new Command(postUpdateCommand, postUpdateCommandType).Execute(null); } catch (ApplicationException ex) { LogDialog.Log("Post update command failed.", ex); } LogDialog.Log("Update finished"); } finally { IsBusy = false; m_Progress.Clear(); m_Size.Clear(); OnUpdateCompleted(); } }
public void Execute(ApplicationJob argument) { CompilerErrorCollection errors; Assembly assembly = Compile(out errors); if (errors.HasErrors) { throw new ApplicationException("Script cannot be compiled: " + errors[0].ErrorText); } // Now that we have a compiled script, lets run them foreach (Type type in assembly.GetExportedTypes()) { foreach (Type iface in type.GetInterfaces()) { if (iface != typeof(ICustomSetupScript)) continue; // yay, we found a script interface, lets create it and run it! // Get the constructor for the current type // you can also specify what creation parameter types you want to pass to it, // so you could possibly pass in data it might need, or a class that it can use to query the host application ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes); if (constructor != null && constructor.IsPublic) { // lets be friendly and only do things legitimitely by only using valid constructors // we specified that we wanted a constructor that doesn't take parameters, so don't pass parameters ICustomSetupScript scriptObject = constructor.Invoke(null) as ICustomSetupScript; if (scriptObject != null) { scriptObject.Execute(null, argument); } else { // hmmm, for some reason it didn't create the object // this shouldn't happen, as we have been doing checks all along, but we should // inform the user something bad has happened, and possibly request them to send // you the script so you can debug this problem // floele: Should not occur without an exception anyway. } } else { // and even more friendly and explain that there was no valid constructor // found and thats why this script object wasn't run // floele: Our scripts will automatically have a valid constructor. } } } }
/// <summary> /// Performs the update process of a single application. /// Catches most exceptions and stores them for later use. /// </summary> private void StartNewThread(object paramJob) { ApplicationJob job = paramJob as ApplicationJob; m_Status[job] = Status.Downloading; OnStatusChanged(job); string requestedUrl = string.Empty; int numTries = 0; int maxTries = Convert.ToInt32(Settings.GetValue("RetryCount", 1)); try { while (numTries < maxTries) { try { numTries++; m_Status[job] = DoDownload(job, out requestedUrl); // If there is a custom column variable, and it has not been been downloaded yet, // make sure that we fetch it now "unnecessarily" so that the column contains a current value. Dictionary <string, string> customColumns = SettingsDialog.CustomColumns; foreach (KeyValuePair <string, string> column in customColumns) { if (!string.IsNullOrEmpty(column.Value) && !job.Variables.HasVariableBeenDownloaded(column.Value)) { job.Variables.ReplaceAllInString("{" + column.Value.TrimStart('{').TrimEnd('}') + "}"); } } if (customColumns.Count > 0) { job.Save(); // cached variable content } // Install if updated if (m_InstallUpdated && m_Status[job] == Status.UpdateSuccessful) { job.Install(null); } // If no exception happened, we immediately leave the loop break; } catch (SQLiteException ex) { // If "locked" exception (slow USB device eg.) continue trying if (ex.ErrorCode == (int)SQLiteErrorCode.Locked) { numTries--; LogDialog.Log(job, ex); } else { throw; } } catch (Exception ex) { WebException webException = ex as WebException; if (webException != null && webException.Status == WebExceptionStatus.RequestCanceled) { // User cancelled the process -> Do nothing m_Status[job] = Status.Failure; break; } // Only throw an exception if we have run out of tries if (numTries == maxTries) { throw; } else { LogDialog.Log(job, ex); } } } } catch (WebException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex, (ex.Response != null) ? ex.Response.ResponseUri.ToString() : requestedUrl)); } catch (FileNotFoundException ex) { // Executing command failed LogDialog.Log(job, ex); m_Errors.Add(new ApplicationJobError(job, ex)); } catch (Win32Exception ex) { // Executing command failed LogDialog.Log(job, ex); m_Errors.Add(new ApplicationJobError(job, ex)); } catch (IOException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex)); } catch (UnauthorizedAccessException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex)); } catch (UriFormatException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex, requestedUrl)); } catch (NotSupportedException ex) { // Invalid URI prefix LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex, requestedUrl)); } catch (NonBinaryFileException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex, requestedUrl)); } catch (TargetPathInvalidException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex, requestedUrl)); } catch (CommandErrorException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex, requestedUrl)); } catch (ApplicationException ex) { // Error executing custom C# script LogDialog.Log(job, ex); m_Errors.Add(new ApplicationJobError(job, ex)); } catch (SQLiteException ex) { LogDialog.Log(job, ex); this.HandleUpdateFailed(job, new ApplicationJobError(job, ex, requestedUrl)); } m_Progress[job] = 100; OnStatusChanged(job); }