325 lines
11 KiB
C#
325 lines
11 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Cache;
|
|
using System.Net.Mime;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using Mk0.Software.OnlineUpdater.Properties;
|
|
|
|
namespace Mk0.Software.OnlineUpdater
|
|
{
|
|
internal partial class DownloadUpdateDialog : Form
|
|
{
|
|
private readonly string _downloadURL;
|
|
|
|
private string _tempFile;
|
|
|
|
private MyWebClient _webClient;
|
|
|
|
private DateTime _startedAt;
|
|
|
|
public DownloadUpdateDialog(string downloadURL)
|
|
{
|
|
InitializeComponent();
|
|
|
|
_downloadURL = downloadURL;
|
|
|
|
if (AutoUpdater.Mandatory && AutoUpdater.UpdateMode == Mode.ForcedDownload)
|
|
{
|
|
ControlBox = false;
|
|
}
|
|
}
|
|
|
|
private void DownloadUpdateDialogLoad(object sender, EventArgs e)
|
|
{
|
|
var uri = new Uri(_downloadURL);
|
|
|
|
if (uri.Scheme.Equals(Uri.UriSchemeFtp))
|
|
{
|
|
_webClient = new MyWebClient { Credentials = AutoUpdater.FtpCredentials };
|
|
}
|
|
else
|
|
{
|
|
_webClient = new MyWebClient();
|
|
|
|
if (uri.Scheme.Equals(Uri.UriSchemeHttp) || uri.Scheme.Equals(Uri.UriSchemeHttps))
|
|
{
|
|
if (AutoUpdater.BasicAuthDownload != null)
|
|
{
|
|
_webClient.Headers[HttpRequestHeader.Authorization] = AutoUpdater.BasicAuthDownload.ToString();
|
|
}
|
|
|
|
_webClient.Headers[HttpRequestHeader.UserAgent] = AutoUpdater.GetUserAgent();
|
|
}
|
|
}
|
|
|
|
_webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
|
|
|
|
if (AutoUpdater.Proxy != null)
|
|
{
|
|
_webClient.Proxy = AutoUpdater.Proxy;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(AutoUpdater.DownloadPath))
|
|
{
|
|
_tempFile = Path.GetTempFileName();
|
|
}
|
|
else
|
|
{
|
|
_tempFile = Path.Combine(AutoUpdater.DownloadPath, $"{Guid.NewGuid().ToString()}.tmp");
|
|
if (!Directory.Exists(AutoUpdater.DownloadPath))
|
|
{
|
|
Directory.CreateDirectory(AutoUpdater.DownloadPath);
|
|
}
|
|
}
|
|
|
|
_webClient.DownloadProgressChanged += OnDownloadProgressChanged;
|
|
|
|
_webClient.DownloadFileCompleted += WebClientOnDownloadFileCompleted;
|
|
|
|
_webClient.DownloadFileAsync(uri, _tempFile);
|
|
}
|
|
|
|
private void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
|
|
{
|
|
if (_startedAt == default(DateTime))
|
|
{
|
|
_startedAt = DateTime.Now;
|
|
}
|
|
else
|
|
{
|
|
var timeSpan = DateTime.Now - _startedAt;
|
|
long totalSeconds = (long)timeSpan.TotalSeconds;
|
|
if (totalSeconds > 0)
|
|
{
|
|
var bytesPerSecond = e.BytesReceived / totalSeconds;
|
|
labelInformation.Text =
|
|
string.Format(Resources.DownloadSpeedMessage, BytesToString(bytesPerSecond));
|
|
}
|
|
}
|
|
|
|
labelSize.Text = $@"{BytesToString(e.BytesReceived)} / {BytesToString(e.TotalBytesToReceive)}";
|
|
progressBar.Value = e.ProgressPercentage;
|
|
}
|
|
|
|
private void WebClientOnDownloadFileCompleted(object sender, AsyncCompletedEventArgs asyncCompletedEventArgs)
|
|
{
|
|
if (asyncCompletedEventArgs.Cancelled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (asyncCompletedEventArgs.Error != null)
|
|
{
|
|
MessageBox.Show(asyncCompletedEventArgs.Error.Message,
|
|
asyncCompletedEventArgs.Error.GetType().ToString(), MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
_webClient = null;
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(AutoUpdater.Checksum))
|
|
{
|
|
if (!CompareChecksum(_tempFile, AutoUpdater.Checksum))
|
|
{
|
|
_webClient = null;
|
|
Close();
|
|
return;
|
|
}
|
|
}
|
|
|
|
ContentDisposition contentDisposition = null;
|
|
if (_webClient.ResponseHeaders["Content-Disposition"] != null)
|
|
{
|
|
contentDisposition = new ContentDisposition(_webClient.ResponseHeaders["Content-Disposition"]);
|
|
}
|
|
|
|
var fileName = string.IsNullOrEmpty(contentDisposition?.FileName)
|
|
? Path.GetFileName(_webClient.ResponseUri.LocalPath)
|
|
: contentDisposition.FileName;
|
|
|
|
var tempPath =
|
|
Path.Combine(
|
|
string.IsNullOrEmpty(AutoUpdater.DownloadPath) ? Path.GetTempPath() : AutoUpdater.DownloadPath,
|
|
fileName);
|
|
|
|
try
|
|
{
|
|
if (File.Exists(tempPath))
|
|
{
|
|
File.Delete(tempPath);
|
|
}
|
|
|
|
File.Move(_tempFile, tempPath);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBox.Show(e.Message, e.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
_webClient = null;
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
AutoUpdater.InstallerArgs = AutoUpdater.InstallerArgs.Replace("%path%",
|
|
Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName));
|
|
|
|
var processStartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = tempPath,
|
|
UseShellExecute = true,
|
|
Arguments = AutoUpdater.InstallerArgs
|
|
};
|
|
|
|
var extension = Path.GetExtension(tempPath);
|
|
if (extension.Equals(".zip", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
string installerPath = Path.Combine(Path.GetDirectoryName(tempPath), "ZipExtractor.exe");
|
|
|
|
try
|
|
{
|
|
File.WriteAllBytes(installerPath, Resources.Unzipper);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBox.Show(e.Message, e.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
_webClient = null;
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
StringBuilder arguments =
|
|
new StringBuilder($"\"{tempPath}\" \"{Process.GetCurrentProcess().MainModule.FileName}\"");
|
|
string[] args = Environment.GetCommandLineArgs();
|
|
for (int i = 1; i < args.Length; i++)
|
|
{
|
|
if (i.Equals(1))
|
|
{
|
|
arguments.Append(" \"");
|
|
}
|
|
|
|
arguments.Append(args[i]);
|
|
arguments.Append(i.Equals(args.Length - 1) ? "\"" : " ");
|
|
}
|
|
|
|
processStartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = installerPath,
|
|
UseShellExecute = true,
|
|
Arguments = arguments.ToString()
|
|
};
|
|
}
|
|
else if (extension.Equals(".msi", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
processStartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = "msiexec",
|
|
Arguments = $"/i \"{tempPath}\""
|
|
};
|
|
if (!string.IsNullOrEmpty(AutoUpdater.InstallerArgs))
|
|
{
|
|
processStartInfo.Arguments += " " + AutoUpdater.InstallerArgs;
|
|
}
|
|
}
|
|
|
|
if (AutoUpdater.RunUpdateAsAdmin)
|
|
{
|
|
processStartInfo.Verb = "runas";
|
|
}
|
|
|
|
try
|
|
{
|
|
Process.Start(processStartInfo);
|
|
}
|
|
catch (Win32Exception exception)
|
|
{
|
|
_webClient = null;
|
|
if (exception.NativeErrorCode != 1223)
|
|
throw;
|
|
}
|
|
|
|
Close();
|
|
}
|
|
|
|
private static String BytesToString(long byteCount)
|
|
{
|
|
string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
|
|
if (byteCount == 0)
|
|
return "0" + suf[0];
|
|
long bytes = Math.Abs(byteCount);
|
|
int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
|
|
double num = Math.Round(bytes / Math.Pow(1024, place), 1);
|
|
return $"{(Math.Sign(byteCount) * num).ToString(CultureInfo.InvariantCulture)} {suf[place]}";
|
|
}
|
|
|
|
private static bool CompareChecksum(string fileName, string checksum)
|
|
{
|
|
using (var hashAlgorithm = HashAlgorithm.Create(AutoUpdater.HashingAlgorithm))
|
|
{
|
|
using (var stream = File.OpenRead(fileName))
|
|
{
|
|
if (hashAlgorithm != null)
|
|
{
|
|
var hash = hashAlgorithm.ComputeHash(stream);
|
|
var fileChecksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLowerInvariant();
|
|
|
|
if (fileChecksum == checksum.ToLower()) return true;
|
|
|
|
MessageBox.Show(Resources.FileIntegrityCheckFailedMessage,
|
|
Resources.FileIntegrityCheckFailedCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
else
|
|
{
|
|
if (AutoUpdater.ReportErrors)
|
|
{
|
|
MessageBox.Show(Resources.HashAlgorithmNotSupportedMessage,
|
|
Resources.HashAlgorithmNotSupportedCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DownloadUpdateDialog_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (_webClient == null)
|
|
{
|
|
DialogResult = DialogResult.Cancel;
|
|
}
|
|
else if (_webClient.IsBusy)
|
|
{
|
|
_webClient.CancelAsync();
|
|
DialogResult = DialogResult.Cancel;
|
|
}
|
|
else
|
|
{
|
|
DialogResult = DialogResult.OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public class MyWebClient : WebClient
|
|
{
|
|
/// <summary>
|
|
/// Response Uri after any redirects.
|
|
/// </summary>
|
|
public Uri ResponseUri;
|
|
|
|
/// <inheritdoc />
|
|
protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
|
|
{
|
|
WebResponse webResponse = base.GetWebResponse(request, result);
|
|
ResponseUri = webResponse.ResponseUri;
|
|
return webResponse;
|
|
}
|
|
}
|
|
}
|