using System; using System.ComponentModel; using System.Reflection; using System.Threading; using System.Windows.Forms; namespace embroideryReader { class EmbroideryReaderUpdates { public enum versionImportance { unknownOrUnavailable, bugfix, feature, critical, }; System.Net.WebClient downloader = new System.Net.WebClient(); NJCrawford.StringIniReader updateInfo; System.Uri updateURI; string lastError = ""; private bool isInfoReady = false; private BackgroundWorker internalThread; private string updateURL; private const string VERSION = "version"; private const string RELEASE_DATE = "release date"; private const string MORE_INFO_URL = "more info url"; public const string SETTINGS_SECTION_NAME = "update info"; public const string SETTINGS_NEWER_VERSION = "newer version available"; public const string SETTINGS_MORE_INFO = "more info url"; public const string SETTINGS_RELEASE_DATE = "release date"; public const string SETTINGS_LAST_CHECK = "last update check"; private Mutex infoReadyMutex; private Version callerVersion; private string callerName; private NJCrawford.IniFile appSettings; public delegate void callbackFunctionType(); private callbackFunctionType callbackFunction; public EmbroideryReaderUpdates(string updateLocation, NJCrawford.IniFile settingsFile, callbackFunctionType callback) { callbackFunction = callback; appSettings = settingsFile; infoReadyMutex = new Mutex(); updateURL = updateLocation; callerVersion = Assembly.GetCallingAssembly().GetName().Version; callerName = Assembly.GetCallingAssembly().GetName().Name; //internalThread = new Thread(new ThreadStart(internalThreadFunction)); internalThread = new BackgroundWorker(); internalThread.DoWork += new DoWorkEventHandler(internalThread_DoWork); internalThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(internalThread_RunWorkerCompleted); internalThread.RunWorkerAsync(); } void internalThread_DoWork(object sender, DoWorkEventArgs e) { string downloadString = ""; updateURI = new Uri(updateURL); downloader.Headers.Add("user-agent", "UpdateCheck/" + Assembly.GetExecutingAssembly().GetName().Version + " " + callerName + "/" + callerVersion); try { downloadString = downloader.DownloadString(updateURI); updateInfo = new NJCrawford.StringIniReader(downloadString); } catch (Exception ex) { //don't complain, just remember it for later lastError = ex.Message; } // I suspect that this will prevent a race condition infoReadyMutex.WaitOne(); isInfoReady = true; infoReadyMutex.ReleaseMutex(); } void internalThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (appSettings != null) { if (IsInfoValid()) { appSettings.setValue(SETTINGS_SECTION_NAME, SETTINGS_NEWER_VERSION, VersionAvailable().ToString()); appSettings.setValue(SETTINGS_SECTION_NAME, SETTINGS_MORE_INFO, getMoreInfoURL()); appSettings.setValue(SETTINGS_SECTION_NAME, SETTINGS_RELEASE_DATE, getReleaseDate().ToShortDateString()); } appSettings.setValue(SETTINGS_SECTION_NAME, SETTINGS_LAST_CHECK, DateTime.Now.ToShortDateString()); } if (callbackFunction != null) { callbackFunction(); } } /*Returns null if not available for any reason.*/ public Version VersionAvailable() { Version retval = null; string versionString = updateInfo.getValue(VERSION, ""); if (!String.IsNullOrEmpty(versionString)) { try { retval = new Version(versionString); } catch (FormatException fex) { lastError = fex.Message; } } return retval; } public bool IsUpdateAvailable() { bool retval = false; Version currentVersion = Assembly.GetCallingAssembly().GetName().Version; if (VersionAvailable() != null) { retval = (VersionAvailable() > currentVersion); } return retval; } public string GetLastError() { return lastError; } public void ResetLastError() { lastError = ""; } /*Returns the date and possibly time * the latest update was released. Returns DateTime.MinValue * if not available. */ public DateTime getReleaseDate() { DateTime retval = DateTime.MinValue; try { retval = Convert.ToDateTime(updateInfo.getValue(RELEASE_DATE, "")); } catch (FormatException fx) { lastError = fx.Message; } return retval; } // gets 'more info url' public string getMoreInfoURL() { return updateInfo.getValue(MORE_INFO_URL, ""); } public bool IsInfoReady() { bool retval; // I suspect that this will prevent a race condition infoReadyMutex.WaitOne(); retval = isInfoReady; infoReadyMutex.ReleaseMutex(); return retval; } public void waitForInfo() { while (!isInfoReady) { System.Threading.Thread.Sleep(100); Application.DoEvents(); } } public bool IsInfoValid() { string versionString = updateInfo.getValue(VERSION, ""); if (String.IsNullOrEmpty(versionString)) { lastError = "Missing version in update info"; return false; } else { // Make sure the version is valid // Check for 4 int16s seperated by dots string[] parts = versionString.Split('.'); bool versionOK = true; if (parts.Length == 4) { Int16 junk; for (int i = 0; i < 4; i++) { if (!Int16.TryParse(parts[i], out junk)) { versionOK = false; } } } else { versionOK = false; } if (!versionOK) { lastError = "Invalid version format"; return false; } } string releaseDateString = updateInfo.getValue(RELEASE_DATE, ""); if (String.IsNullOrEmpty(releaseDateString)) { lastError = "Missing release date in update info"; return false; } else { // Make sure the date is valid DateTime junk; if (!DateTime.TryParse(releaseDateString, out junk)) { lastError = "Invalid release date"; return false; } } string moreInfoURL = updateInfo.getValue(MORE_INFO_URL, ""); if (String.IsNullOrEmpty(moreInfoURL)) { lastError = "Missing 'more info url' in update info"; return false; } else { // Make sure url is valid if(!Uri.IsWellFormedUriString(moreInfoURL, UriKind.Absolute)) { lastError = "Invalid 'more info url'"; return false; } } return true; } } }