public UpdateInfo(String releaseVersion, String releaseType, String html, out DialogResult dr) { InitializeComponent(); log.Info("Showing new release information."); version = releaseVersion; dr = DialogResult.Cancel; try { lTitle.Text = "A new " + (releaseType == "alpha" ? "alpha " : "") + "release of OGCS is available"; lSummary.Text = "Would you like to upgrade to v" + releaseVersion + " now?"; if (html == null) { String githubReleaseNotes = "https://github.com/phw198/OutlookGoogleCalendarSync/blob/master/docs/Release%20Notes.md"; anchorRequested = "v" + releaseVersion.Replace(".", "") + "---" + releaseType; log.Debug("Browser anchor: " + anchorRequested); webBrowser.DocumentCompleted += WebBrowser_DocumentCompleted; webBrowser.Navigate(githubReleaseNotes); } else { html = html.TrimStart("< ![CDATA[".ToCharArray()); html = html.TrimEnd("]]>".ToCharArray()); html = htmlHead + html + "</body></html>"; webBrowser.DocumentText = html; } dr = ShowDialog(); } catch (System.Exception ex) { log.Debug("A problem was encountered showing the release notes."); OGCSexception.Analyse(ex); dr = OgcsMessageBox.Show("A new " + (releaseType == "alpha" ? "alpha " : "") + "release of OGCS is available.\nWould you like to upgrade to v" + releaseVersion + " now?", "OGCS Update Available", MessageBoxButtons.YesNo, MessageBoxIcon.Information); } }
public UpdateInfo(String releaseVersion, String releaseType, String html, out DialogResult dr) { InitializeComponent(); log.Info("Showing new release information."); version = releaseVersion; dr = DialogResult.Cancel; try { lTitle.Text = "A new " + (releaseType == "alpha" ? "alpha " : "") + "release of OGCS is available"; lSummary.Text = "Would you like to upgrade to v" + releaseVersion + " now?"; if (html == null) { String githubReleaseNotes = Program.OgcsWebsite + "/release-notes"; anchorRequested = "v" + releaseVersion.Replace(".", "") + "---" + releaseType; log.Debug("Browser anchor: " + anchorRequested); llViewOnGithub.Tag = githubReleaseNotes + "#" + anchorRequested; llViewOnGithub.Visible = true; } else { llViewOnGithub.Visible = false; html = html.TrimStart("< ![CDATA[".ToCharArray()); html = html.TrimEnd("]]>".ToCharArray()); html = htmlHead + html + "</body></html>"; webBrowser.DocumentText = html; } dr = ShowDialog(); } catch (System.Exception ex) { log.Debug("A problem was encountered showing the release notes."); OGCSexception.Analyse(ex); dr = OgcsMessageBox.Show("A new " + (releaseType == "alpha" ? "alpha " : "") + "release of OGCS is available.\nWould you like to upgrade to v" + releaseVersion + " now?", "OGCS Update Available", MessageBoxButtons.YesNo, MessageBoxIcon.Information); } }
private MAPIFolder getSharedCalendar(NameSpace oNS, String sharedURI) { if (string.IsNullOrEmpty(sharedURI)) { return(null); } Recipient sharer = null; MAPIFolder sharedCalendar = null; try { sharer = oNS.CreateRecipient(sharedURI); sharer.Resolve(); if (sharer.DisplayType == OlDisplayType.olDistList) { throw new System.Exception("User selected a distribution list!"); } sharedCalendar = oNS.GetSharedDefaultFolder(sharer, OlDefaultFolders.olFolderCalendar); if (sharedCalendar.DefaultItemType != OlItemType.olAppointmentItem) { log.Debug(sharer.Name + " does not have a calendar shared."); throw new System.Exception("Wrong default item type."); } calendarFolders.Add(sharer.Name, sharedCalendar); return(sharedCalendar); } catch (System.Exception ex) { log.Error("Failed to get shared calendar from " + sharedURI + ". " + ex.Message); OgcsMessageBox.Show("Could not find a shared calendar for '" + sharer.Name + "'.", "No shared calendar found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return(null); } finally { sharer = (Recipient)OutlookOgcs.Calendar.ReleaseObject(sharer); } }
private static void addRegKey(String startupDelay = null) { Microsoft.Win32.RegistryKey startupKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(startupKeyPath, true); String keyValue = startupKey.GetValue(Application.ProductName, "").ToString(); String delayedStartup = ""; if (Convert.ToInt16(startupDelay ?? Settings.Instance.StartupDelay.ToString()) > 0) { delayedStartup = " /d:" + (startupDelay ?? Settings.Instance.StartupDelay.ToString()); } String cliArgs = string.Join(" ", Environment.GetCommandLineArgs().Skip(1).Where(a => "l,s".Contains(a.Substring(1, 1).ToLower()))); cliArgs = (" " + cliArgs).TrimEnd(); if (keyValue == "" || keyValue != (Application.ExecutablePath + delayedStartup + cliArgs)) { log.Debug("Startup registry key " + (keyValue == "" ? "created" : "updated") + "."); try { startupKey.SetValue(Application.ProductName, Application.ExecutablePath + delayedStartup + cliArgs); } catch (System.UnauthorizedAccessException ex) { log.Warn("Could not create/update registry key. " + ex.Message); Settings.Instance.StartOnStartup = false; if (OgcsMessageBox.Show("You don't have permission to update the registry, so the application can't be set to run on startup.\r\n" + "Try manually adding a shortcut to the 'Startup' folder in Windows instead?", "Permission denied", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { System.Diagnostics.Process.Start(System.Windows.Forms.Application.StartupPath); System.Diagnostics.Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.Startup)); } } } startupKey.Close(); }
/// <summary> /// Check if there is a new release of the application. /// </summary> /// <param name="updateButton">The button that triggered this, if manually called.</param> public async void CheckForUpdate(Button updateButton = null) { if (string.IsNullOrEmpty(nonGitHubReleaseUri) && Program.InDeveloperMode) { return; } bt = updateButton; log.Debug((isManualCheck ? "Manual" : "Automatic") + " update check requested."); if (isManualCheck) { updateButton.Text = "Checking..."; } try { if (!string.IsNullOrEmpty(nonGitHubReleaseUri) || Program.IsInstalled) { try { if (await githubCheck()) { log.Info("Restarting OGCS."); try { System.Diagnostics.Process.Start(restartUpdateExe, "--processStartAndWait OutlookGoogleCalendarSync.exe"); } catch (System.Exception ex) { OGCSexception.Analyse(ex, true); } try { Forms.Main.Instance.NotificationTray.ExitItem_Click(null, null); } catch (System.Exception ex) { log.Error("Failed to exit via the notification tray icon. " + ex.Message); log.Debug("NotificationTray is " + (Forms.Main.Instance.NotificationTray == null ? "null" : "not null")); Forms.Main.Instance.Close(); } } } finally { if (isManualCheck) { updateButton.Text = "Check For Update"; } } } else { zipChecker(); } } catch (ApplicationException ex) { log.Error(ex.Message + " " + ex.InnerException.Message); if (OgcsMessageBox.Show("The upgrade failed.\nWould you like to get the latest version from the project website manually?", "Upgrade Failed", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { System.Diagnostics.Process.Start("https://phw198.github.io/OutlookGoogleCalendarSync/"); } } catch (System.Exception ex) { log.Fail("Failure checking for update. " + ex.Message); if (isManualCheck) { OgcsMessageBox.Show("Unable to check for new version.", "Check Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } }
private void btOK_Click(object sender, EventArgs e) { log.Fine("Checking no duplicate mappings exist."); SettingsStore.Calendar profile = Forms.Main.Instance.ActiveCalendarProfile; try { List <String> oColValues = new List <String>(); List <String> gColValues = new List <String>(); foreach (DataGridViewRow row in colourGridView.Rows) { oColValues.Add(row.Cells["OutlookColour"].Value.ToString()); gColValues.Add(row.Cells["GoogleColour"].Value.ToString()); } String oDuplicates = string.Join("\r\n", oColValues.GroupBy(v => v).Where(g => g.Count() > 1).Select(s => "- " + s.Key).ToList()); String gDuplicates = string.Join("\r\n", gColValues.GroupBy(v => v).Where(g => g.Count() > 1).Select(s => "- " + s.Key).ToList()); if (!string.IsNullOrEmpty(oDuplicates) && (profile.SyncDirection.Id == Sync.Direction.OutlookToGoogle.Id || profile.SyncDirection.Id == Sync.Direction.Bidirectional.Id)) { OgcsMessageBox.Show("The following Outlook categories cannot be mapped more than once:-\r\n\r\n" + oDuplicates, "Duplicate Outlook Mappings", MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } else if (!string.IsNullOrEmpty(gDuplicates) && (profile.SyncDirection.Id == Sync.Direction.GoogleToOutlook.Id || profile.SyncDirection.Id == Sync.Direction.Bidirectional.Id)) { OgcsMessageBox.Show("The following Google colours cannot be mapped more than once:-\r\n\r\n" + gDuplicates, "Duplicate Google Mappings", MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } } catch (System.Exception ex) { OGCSexception.Analyse("Failed looking for duplicating mappings before storing in Settings.", ex); OgcsMessageBox.Show("An error was encountered storing your custom mappings.", "Cannot save mappings", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } try { log.Fine("Storing colour mappings in Settings."); profile.ColourMaps.Clear(); foreach (DataGridViewRow row in colourGridView.Rows) { if (row.Cells["OutlookColour"].Value == null || row.Cells["OutlookColour"].Value.ToString().Trim() == "") { continue; } try { profile.ColourMaps.Add(row.Cells["OutlookColour"].Value.ToString(), GoogleOgcs.EventColour.Palette.GetColourId(row.Cells["GoogleColour"].Value.ToString())); } catch (System.ArgumentException ex) { if (OGCSexception.GetErrorCode(ex) == "0x80070057") { //An item with the same key has already been added } else { throw; } } } } catch (System.Exception ex) { OGCSexception.Analyse("Could not save colour/category mappings to Settings.", ex); } finally { this.Close(); } }
public static void Facebook_like() { if (OgcsMessageBox.Show("Please click the 'Like' button on the project website, which will now open in your browser.", "Like on Facebook", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK) { Helper.OpenBrowser("https://phw198.github.io/OutlookGoogleCalendarSync"); } }
private static void isNewVersion(Boolean isSquirrelInstall) { string settingsVersion = string.IsNullOrEmpty(Settings.Instance.Version) ? "Unknown" : Settings.Instance.Version; if (settingsVersion != Application.ProductVersion) { log.Info("New version detected - upgraded from " + settingsVersion + " to " + Application.ProductVersion); try { Program.ManageStartupRegKey(recreate: true); } catch (System.Exception ex) { if (ex is System.Security.SecurityException) { OGCSexception.LogAsFail(ref ex); //User doesn't have rights to access registry } OGCSexception.Analyse("Failed accessing registry for startup key.", ex); } Settings.Instance.Version = Application.ProductVersion; if (Application.ProductVersion.EndsWith(".0")) //Release notes not updated for hotfixes. { System.Diagnostics.Process.Start("https://github.com/phw198/OutlookGoogleCalendarSync/blob/master/docs/Release%20Notes.md"); if (isSquirrelInstall) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.upgrade, "from=" + settingsVersion + ";to=" + Application.ProductVersion); } } } //Check upgrade to Squirrel release went OK try { if (isSquirrelInstall) { Int32 upgradedFrom = Int16.MaxValue; String expectedInstallDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); expectedInstallDir = Path.Combine(expectedInstallDir, "OutlookGoogleCalendarSync"); String paddedVersion = ""; if (settingsVersion != "Unknown") { foreach (String versionBit in settingsVersion.Split('.')) { paddedVersion += versionBit.PadLeft(2, '0'); } upgradedFrom = Convert.ToInt32(paddedVersion); } if ((settingsVersion == "Unknown" || upgradedFrom < 2050000) && !System.Windows.Forms.Application.ExecutablePath.ToString().StartsWith(expectedInstallDir)) { log.Warn("OGCS is running from " + System.Windows.Forms.Application.ExecutablePath.ToString()); OgcsMessageBox.Show("A suspected improper install location has been detected.\r\n" + "Click 'OK' for further details.", "Improper Install Location", MessageBoxButtons.OK, MessageBoxIcon.Warning); System.Diagnostics.Process.Start("https://github.com/phw198/OutlookGoogleCalendarSync/issues/265"); } } } catch (System.Exception ex) { log.Warn("Failed to determine if OGCS is installed in the correct location."); log.Error(ex.Message); } }
private void findCalendars(Folders folders, Dictionary <string, MAPIFolder> calendarFolders, String excludeDeletedFolder, MAPIFolder defaultCalendar = null) { //Initiate progress bar (red line underneath "Getting calendars" text) System.Drawing.Graphics g = Forms.Main.Instance.tabOutlook.CreateGraphics(); System.Drawing.Pen p = new System.Drawing.Pen(System.Drawing.Color.Red, 3); System.Drawing.Point startPoint = new System.Drawing.Point(Forms.Main.Instance.lOutlookCalendar.Location.X, Forms.Main.Instance.lOutlookCalendar.Location.Y + Forms.Main.Instance.lOutlookCalendar.Size.Height + 3); double stepSize = Forms.Main.Instance.lOutlookCalendar.Size.Width / folders.Count; int fldCnt = 0; foreach (MAPIFolder folder in folders) { fldCnt++; System.Drawing.Point endPoint = new System.Drawing.Point(Forms.Main.Instance.lOutlookCalendar.Location.X + Convert.ToInt16(fldCnt * stepSize), Forms.Main.Instance.lOutlookCalendar.Location.Y + Forms.Main.Instance.lOutlookCalendar.Size.Height + 3); try { g.DrawLine(p, startPoint, endPoint); } catch { /*May get GDI+ error if g has been repainted*/ } System.Windows.Forms.Application.DoEvents(); try { OlItemType defaultItemType = folder.DefaultItemType; if (defaultItemType == OlItemType.olAppointmentItem) { if (defaultCalendar == null || (folder.EntryID != defaultCalendar.EntryID)) { calendarFolderAdd(folder.Name, folder); } } if (folder.EntryID != excludeDeletedFolder && folder.Folders.Count > 0) { findCalendars(folder.Folders, calendarFolders, excludeDeletedFolder, defaultCalendar); } } catch (System.Exception ex) { OGCSexception.Analyse(ex); if (oApp.Session.ExchangeConnectionMode.ToString().Contains("Disconnected") || ex.Message.StartsWith("Network problems are preventing connection to Microsoft Exchange.") || OGCSexception.GetErrorCode(ex, 0x000FFFFF) == "0x00040115") { log.Info("Currently disconnected from Exchange - unable to retrieve MAPI folders."); Forms.Main.Instance.ToolTips.SetToolTip(Forms.Main.Instance.cbOutlookCalendars, "The Outlook calendar to synchonize with.\nSome may not be listed as you are currently disconnected."); } else { log.Error("Failed to recurse MAPI folders."); log.Error(ex.Message); OgcsMessageBox.Show("A problem was encountered when searching for Outlook calendar folders.", "Calendar Folders", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } } p.Dispose(); try { g.Clear(System.Drawing.Color.White); } catch { } g.Dispose(); System.Windows.Forms.Application.DoEvents(); }
private void ColourPicker_Enter(object sender, EventArgs e) { if (Forms.Main.Instance.ActiveCalendarProfile.UseGoogleCalendar == null || string.IsNullOrEmpty(Forms.Main.Instance.ActiveCalendarProfile.UseGoogleCalendar.Id)) { OgcsMessageBox.Show("You need to select a Google Calendar first on the 'Settings' tab.", "Configuration Required", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } ToolTip loading = new ToolTip(); try { GoogleOgcs.EventColour.Palette currentSelection = null; if (GoogleOgcs.Calendar.IsInstanceNull || !GoogleOgcs.Calendar.Instance.ColourPalette.IsCached()) { loading.SetToolTip(this, "Retrieving colours from Google..."); loading.ShowAlways = true; loading.InitialDelay = 0; loading.Show("Retrieving colours from Google...", this, this.FindForm().PointToClient(this.Parent.PointToScreen(this.Location))); GoogleOgcs.Calendar.Instance.ColourPalette.Get(); currentSelection = (GoogleOgcs.EventColour.Palette)SelectedItem; loading.Hide(this); } if (Items.Count != GoogleOgcs.Calendar.Instance.ColourPalette.ActivePalette.Count) { while (Items.Count > 0) { Items.RemoveAt(0); } AddPaletteColours(true); } foreach (GoogleOgcs.EventColour.Palette pInfo in Items) { if (pInfo.Id == currentSelection?.Id) { SelectedItem = pInfo; break; } } } catch (System.Exception ex) { OGCSexception.Analyse("ColourPicker_Enter()", ex); } finally { loading.Hide(this); loading.RemoveAll(); } if (Items.Count > 1 && SelectedIndex == -1) { SelectedIndex = 0; } }
public void OgcsUserStatus() { if (!checkedOgcsUserStatus) { UserSubscriptionCheck(); userDonationCheck(); checkedOgcsUserStatus = true; if (Settings.Instance.UserIsBenefactor() && Settings.Instance.HideSplashScreen == null) { DialogResult dr = OgcsMessageBox.Show("Thank you for your support of OGCS!\r\nWould you like the splash screen to be hidden from now on?", "Hide Splash Screen?", MessageBoxButtons.YesNo, MessageBoxIcon.Question); Settings.Instance.HideSplashScreen = (dr == DialogResult.Yes); } } }
private static void onAppUninstall(Version version) { try { using (var mgr = new Squirrel.UpdateManager(null, "OutlookGoogleCalendarSync")) { log.Info("Removing shortcuts."); mgr.RemoveShortcutsForExecutable(Path.GetFileName(System.Windows.Forms.Application.ExecutablePath), Squirrel.ShortcutLocation.Desktop | Squirrel.ShortcutLocation.StartMenu); String startMenuFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), "Paul Woolcock"); Directory.Delete(startMenuFolder); log.Debug("Removing registry uninstall keys."); mgr.RemoveUninstallerRegistryEntry(); } Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.uninstall, version.ToString()); if (OgcsMessageBox.Show("Sorry to see you go!\nCould you spare 30 seconds for some feedback?", "Uninstalling OGCS", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { log.Debug("User opted to give feedback."); Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.uninstall, Application.ProductVersion + "-feedback"); System.Diagnostics.Process.Start("https://docs.google.com/forms/d/e/1FAIpQLSfRWYFdgyfbFJBMQ0dz14patu195KSKxdLj8lpWvLtZn-GArw/viewform?entry.1161230174=v" + Application.ProductVersion); } else { log.Debug("User opted not to give feedback."); } log.Info("Deleting directory " + Path.GetDirectoryName(Settings.ConfigFile)); try { log.Logger.Repository.Shutdown(); log4net.LogManager.Shutdown(); Directory.Delete(Path.GetDirectoryName(Settings.ConfigFile), true); } catch (System.Exception ex) { try { log.Error(ex.Message); } catch { } } } catch (System.Exception ex) { log.Error("Problem encountered on app uninstall."); OGCSexception.Analyse(ex, true); } }
/// <returns>True if the user has upgraded</returns> private async Task <Boolean> githubCheck() { log.Debug("Checking for Squirrel update..."); UpdateManager updateManager = null; isBusy = true; try { String installRootDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); if (string.IsNullOrEmpty(nonGitHubReleaseUri)) { updateManager = await Squirrel.UpdateManager.GitHubUpdateManager("https://github.com/phw198/OutlookGoogleCalendarSync", "OutlookGoogleCalendarSync", installRootDir, new Squirrel.FileDownloader(new Extensions.OgcsWebClient()), prerelease : Settings.Instance.AlphaReleases); } else { updateManager = new Squirrel.UpdateManager(nonGitHubReleaseUri, "OutlookGoogleCalendarSync", installRootDir); } UpdateInfo updates = await updateManager.CheckForUpdate(); if (updates.ReleasesToApply.Any()) { if (updates.CurrentlyInstalledVersion != null) { log.Info("Currently installed version: " + updates.CurrentlyInstalledVersion.Version.ToString()); } log.Info("Found " + updates.ReleasesToApply.Count() + " newer releases available."); log.Info("Download directory = " + updates.PackageDirectory); DialogResult dr = DialogResult.Cancel; String squirrelAnalyticsLabel = ""; String releaseNotes = ""; String releaseVersion = ""; String releaseType = ""; foreach (ReleaseEntry update in updates.ReleasesToApply.OrderBy(x => x.Version).Reverse()) { log.Info("New " + update.Version.SpecialVersion + " version available: " + update.Version.Version.ToString()); if (!this.isManualCheck && update.Version.Version.ToString() == Settings.Instance.SkipVersion) { log.Info("The user has previously requested to skip this version."); break; } String localFile = updates.PackageDirectory + "\\" + update.Filename; if (updateManager.CheckIfAlreadyDownloaded(update, localFile)) { log.Debug("This has already been downloaded."); } else { try { //"https://github.com/phw198/OutlookGoogleCalendarSync/releases/download/v2.8.6-alpha" String nupkgUrl = "https://github.com/phw198/OutlookGoogleCalendarSync/releases/download/v" + update.Version + "/" + update.Filename; log.Debug("Downloading " + nupkgUrl); new Extensions.OgcsWebClient().DownloadFile(nupkgUrl, localFile); log.Debug("Download complete."); } catch (System.Exception ex) { OGCSexception.Analyse("Failed downloading release file for " + update.Version, ex); throw new ApplicationException("Failed upgrading OGCS.", ex); } } if (string.IsNullOrEmpty(releaseNotes)) { log.Debug("Retrieving release notes."); releaseNotes = update.GetReleaseNotes(updates.PackageDirectory); releaseVersion = update.Version.Version.ToString(); releaseType = update.Version.SpecialVersion; squirrelAnalyticsLabel = "from=" + Application.ProductVersion + ";to=" + update.Version.Version.ToString(); } } var t = new System.Threading.Thread(() => new Forms.UpdateInfo(releaseVersion, releaseType, releaseNotes, out dr)); t.SetApartmentState(System.Threading.ApartmentState.STA); t.Start(); t.Join(); if (dr == DialogResult.No) { log.Info("User chose not to upgrade right now."); Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.upgrade, squirrelAnalyticsLabel + ";later"); } else if (dr == DialogResult.Ignore) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.upgrade, squirrelAnalyticsLabel + ";skipped"); } else if (dr == DialogResult.Yes) { try { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";successful"); log.Info("Applying the updated release(s)..."); //updateManager.UpdateApp().Wait(); int ApplyAttempt = 1; while (ApplyAttempt <= 5) { try { updateManager.ApplyReleases(updates).Wait(); break; } catch (System.AggregateException ex) { ApplyAttempt++; if (OGCSexception.GetErrorCode(ex.InnerException) == "0x80070057") //File does not exist //File does not exist: C:\Users\Paul\AppData\Local\OutlookGoogleCalendarSync\packages\OutlookGoogleCalendarSync-2.8.4-alpha-full.nupkg //Extract the nupkg filename { String regexMatch = ".*" + updates.PackageDirectory.Replace(@"\", @"\\") + @"\\(.*?([\d\.]+-\w+).*)$"; System.Text.RegularExpressions.Match match = System.Text.RegularExpressions.Regex.Match(ex.InnerException.Message, regexMatch); if (match?.Groups?.Count == 3) { log.Warn("Could not update as missing file " + match.Groups[1]); String nupkgUrl = "https://github.com/phw198/OutlookGoogleCalendarSync/releases/download/v" + match.Groups[2] + "/" + match.Groups[1]; log.Debug("Downloading " + nupkgUrl); new Extensions.OgcsWebClient().DownloadFile(nupkgUrl, updates.PackageDirectory + "\\" + match.Groups[1]); log.Debug("Download complete."); } } else { throw; } } } log.Info("The application has been successfully updated."); OgcsMessageBox.Show("The application has been updated and will now restart.", "OGCS successfully updated!", MessageBoxButtons.OK, MessageBoxIcon.Information); restartUpdateExe = updateManager.RootAppDirectory + "\\Update.exe"; return(true); } catch (System.AggregateException ae) { foreach (System.Exception ex in ae.InnerExceptions) { OGCSexception.Analyse(ex, true); ex.Data.Add("analyticsLabel", squirrelAnalyticsLabel); throw new ApplicationException("Failed upgrading OGCS.", ex); } } catch (System.Exception ex) { OGCSexception.Analyse(ex, true); ex.Data.Add("analyticsLabel", squirrelAnalyticsLabel); throw new ApplicationException("Failed upgrading OGCS.", ex); } } } else { log.Info("Already running the latest version of OGCS."); if (this.isManualCheck) //Was a manual check, so give feedback { OgcsMessageBox.Show("You are already running the latest version of OGCS.", "Latest Version", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } catch (ApplicationException ex) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, ex.Data["analyticsLabel"] + ";failed"); throw; } catch (System.AggregateException ae) { log.Fail("Failed checking for update."); foreach (System.Exception ex in ae.InnerExceptions) { OGCSexception.Analyse(OGCSexception.LogAsFail(ex), true); throw; } } catch (System.Exception ex) { OGCSexception.Analyse("Failed checking for update.", OGCSexception.LogAsFail(ex), true); throw; } finally { isBusy = false; updateManager.Dispose(); } return(false); }
private static void parseArgumentsAndInitialise(string[] args) { //We're interested in non-Squirrel arguments here, ie ones which don't start with Linux-esque dashes (--squirrel) StartedWithFileArgs = (args.Length != 0 && args.Count(a => a.StartsWith("/") && !a.StartsWith("/d")) != 0); if (args.Contains("/?") || args.Contains("/help", StringComparer.OrdinalIgnoreCase)) { OgcsMessageBox.Show("Command line parameters:-\r\n" + " /?\t\tShow options\r\n" + " /l:OGcalsync.log\tFile to log to\r\n" + " /s:settings.xml\tSettings file to use.\r\n\t\tFile created with defaults if it doesn't exist\r\n" + " /d:60\t\tSeconds startup delay\r\n" + " /t:\"Config A\"\tAppend custom text to application title", "OGCS command line parameters", MessageBoxButtons.OK, MessageBoxIcon.Information); Environment.Exit(0); } Dictionary <String, String> loggingArg = parseArgument(args, 'l'); initialiseLogger(loggingArg["Filename"], loggingArg["Directory"], bootstrap: true); Dictionary <String, String> settingsArg = parseArgument(args, 's'); Settings.InitialiseConfigFile(settingsArg["Filename"], settingsArg["Directory"]); log.Info("Storing user files in directory: " + MaskFilePath(UserFilePath)); //Before settings have been loaded, early config of cloud logging GoogleOgcs.ErrorReporting.UpdateLogUuId(); Boolean cloudLogSetting = false; String cloudLogXmlSetting = XMLManager.ImportElement("CloudLogging", Settings.ConfigFile); if (!string.IsNullOrEmpty(cloudLogXmlSetting)) { cloudLogSetting = Boolean.Parse(cloudLogXmlSetting); } GoogleOgcs.ErrorReporting.SetThreshold(cloudLogSetting); if (!StartedWithFileArgs) { //Now let's confirm files are actually in the right place Boolean keepPortable = (XMLManager.ImportElement("Portable", Settings.ConfigFile) ?? "false").Equals("true"); if (keepPortable) { if (UserFilePath != System.Windows.Forms.Application.StartupPath) { log.Info("File storage location is incorrect according to " + Settings.ConfigFile); MakePortable(true); } } else { if (UserFilePath != Program.RoamingProfileOGCS) { log.Info("File storage location is incorrect according to " + Settings.ConfigFile); MakePortable(false); } } } string logLevel = XMLManager.ImportElement("LoggingLevel", Settings.ConfigFile); Settings.configureLoggingLevel(logLevel ?? "FINE"); if (args.Contains("--delay")) //Format up to and including v2.7.1 { log.Info("Converting old --delay parameter to /d"); try { String delay = args[Array.IndexOf(args, "--delay") + 1]; log.Debug("Delay of " + delay + "s being migrated."); addRegKey(delay); delayStartup(delay); } catch (System.Exception ex) { log.Error(ex.Message); } } Dictionary <String, String> delayArg = parseArgument(args, 'd'); if (delayArg["Value"] != null) { delayStartup(delayArg["Value"]); } Dictionary <String, String> titleArg = parseArgument(args, 't'); Title = titleArg["Value"]; }
private async Task <bool> getAuthenticated(ClientSecrets cs) { log.Debug("Authenticating with Google calendar service..."); FileDataStore tokenStore = new FileDataStore(Program.UserFilePath); tokenFullPath = Path.Combine(tokenStore.FolderPath, TokenFile); log.Debug("Google credential file location: " + tokenFullPath); if (!tokenFileExists) { log.Info("No Google credentials file available - need user authorisation for OGCS to manage their calendar."); } string[] scopes = new[] { "https://www.googleapis.com/auth/calendar", "email" }; UserCredential credential = null; try { //This will open the authorisation process in a browser, if required credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(cs, scopes, "user", CancelTokenSource.Token, tokenStore); if (tokenFileExists) { log.Debug("User has provided authorisation and credential file saved."); } } catch (Google.Apis.Auth.OAuth2.Responses.TokenResponseException ex) { //OGCSexception.AnalyseTokenResponse(ex); if (ex.Error.Error == "access_denied") { String noAuthGiven = "Sorry, but this application will not work if you don't allow it access to your Google Calendar :("; log.Warn("User did not provide authorisation code. Sync will not be able to work."); OgcsMessageBox.Show(noAuthGiven, "Authorisation not given", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); throw new ApplicationException(noAuthGiven); } else { Forms.Main.Instance.Console.UpdateWithError("Unable to authenticate with Google. The following error occurred:", ex); } } catch (OperationCanceledException) { Forms.Main.Instance.Console.Update("Unable to authenticate with Google. The operation was cancelled.", Console.Markup.warning); } catch (System.Exception ex) { OGCSexception.Analyse(ex); Forms.Main.Instance.Console.UpdateWithError("Unable to authenticate with Google. The following error occurred:", ex); } if (credential.Token.AccessToken != "" && credential.Token.RefreshToken != "") { log.Info("Refresh and Access token successfully retrieved."); log.Debug("Access token expires " + credential.Token.IssuedUtc.AddSeconds(credential.Token.ExpiresInSeconds.Value).ToLocalTime().ToString()); } GoogleOgcs.Calendar.Instance.Service = new CalendarService(new Google.Apis.Services.BaseClientService.Initializer() { HttpClientInitializer = credential }); if (Settings.Instance.Proxy.Type == "Custom") { GoogleOgcs.Calendar.Instance.Service.HttpClient.DefaultRequestHeaders.Add("user-agent", Settings.Instance.Proxy.BrowserUserAgent); } if (credential.Token.IssuedUtc.AddSeconds(credential.Token.ExpiresInSeconds.Value) < DateTime.UtcNow.AddMinutes(-1)) { log.Debug("Access token needs refreshing."); //This will happen automatically when using the calendar service //But we need a valid token before we call getGaccountEmail() which doesn't use the service int backoff = 0; while (backoff < Calendar.BackoffLimit) { try { GoogleOgcs.Calendar.Instance.Service.Settings.Get("useKeyboardShortcuts").Execute(); break; } catch (Google.GoogleApiException ex) { switch (Calendar.HandleAPIlimits(ref ex, null)) { case Calendar.ApiException.throwException: throw; case Calendar.ApiException.freeAPIexhausted: OGCSexception.LogAsFail(ref ex); OGCSexception.Analyse(ex); System.ApplicationException aex = new System.ApplicationException(Calendar.Instance.SubscriptionInvite); OGCSexception.LogAsFail(ref aex); authenticated = false; return(authenticated); case Calendar.ApiException.backoffThenRetry: backoff++; if (backoff == Calendar.BackoffLimit) { log.Fail("API limit backoff was not successful. Retrieving useKeyboardShortcuts setting failed."); authenticated = false; return(authenticated); } else { log.Warn("API rate limit reached. Backing off " + backoff + "sec before retry."); System.Threading.Thread.Sleep(backoff * 1000); } break; } } catch (System.Exception ex) { if (ex is Google.Apis.Auth.OAuth2.Responses.TokenResponseException) { OGCSexception.AnalyseTokenResponse(ex as Google.Apis.Auth.OAuth2.Responses.TokenResponseException, false); } else { OGCSexception.Analyse(ex); Forms.Main.Instance.Console.Update("Unable to communicate with Google services. " + (ex.InnerException != null ? ex.InnerException.Message : ex.Message), Console.Markup.warning); } authenticated = false; return(authenticated); } } log.Debug("Access token refreshed."); } getGaccountEmail(credential.Token.AccessToken); authenticated = true; Forms.Main.Instance.Console.Update("Handshake successful.", verbose: true); return(authenticated); }
public void Sync_Requested(object sender = null, EventArgs e = null) { ManualForceCompare = false; if (sender != null && sender.GetType().ToString().EndsWith("Timer")) //Automated sync { Forms.Main.Instance.NotificationTray.UpdateItem("delayRemove", enabled: false); Timer aTimer = sender as Timer; Object timerProfile = null; if (aTimer.Tag.ToString() == "PushTimer" && aTimer is PushSyncTimer) { timerProfile = (aTimer as PushSyncTimer).owningProfile; } else if (aTimer.Tag.ToString() == "AutoSyncTimer" && aTimer is SyncTimer) { timerProfile = (aTimer as SyncTimer).owningProfile; } if (JobQueue.Add(new Job(aTimer.Tag.ToString(), timerProfile))) { aTimer.Stop(); } else { log.Warn("Sync of profile '" + Settings.Profile.Name(timerProfile) + "' requested by " + aTimer.Tag.ToString() + " already previously queued."); } } else //Manual sync { if (Forms.Main.Instance.bSyncNow.Text == "Start Sync" || Forms.Main.Instance.bSyncNow.Text == "Start Full Sync") { log.Info("Manual sync requested."); if (SyncingNow) { log.Info("Already busy syncing, cannot accept another sync request."); OgcsMessageBox.Show("A sync is already running. Please wait for it to complete and then try again.", "Sync already running", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } if (Control.ModifierKeys == Keys.Shift) { if (Forms.Main.Instance.ActiveCalendarProfile.SyncDirection == Direction.Bidirectional) { OgcsMessageBox.Show("Forcing a full sync is not allowed whilst in 2-way sync mode.\r\nPlease temporarily chose a direction to sync in first.", "2-way full sync not allowed", MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } log.Info("Shift-click has forced a compare of all items"); ManualForceCompare = true; } this.ActiveProfile = Forms.Main.Instance.ActiveCalendarProfile; Start(manualIgnition: true, updateSyncSchedule: false); } else if (Forms.Main.Instance.bSyncNow.Text == "Stop Sync") { GoogleOgcs.Calendar.Instance.Authenticator.CancelTokenSource.Cancel(); if (!SyncingNow) { return; } if (!bwSync.CancellationPending) { Forms.Main.Instance.Console.Update("Sync cancellation requested.", Console.Markup.warning); bwSync.CancelAsync(); } else { Forms.Main.Instance.Console.Update("Repeated cancellation requested - forcefully aborting sync!", Console.Markup.warning); AbortSync(); } if (this.JobQueue.Count() > 0) { if (OgcsMessageBox.Show("There are " + this.JobQueue.Count() + " sync(s) still queued to run. Would you like to cancel these too?", "Clear queued syncs?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { log.Info("User requested clear down of sync queue."); this.JobQueue.Clear(); } } } } }
private void checkForZip(object sender, DoWorkEventArgs e) { string releaseURL = null; string releaseVersion = null; string releaseType = null; log.Debug("Checking for ZIP update..."); string html = ""; String errorDetails = ""; try { html = new Extensions.OgcsWebClient().DownloadString("https://github.com/phw198/OutlookGoogleCalendarSync/blob/master/docs/latest_zip_release.md"); } catch (System.Net.WebException ex) { if (OGCSexception.GetErrorCode(ex) == "0x80131509") { log.Warn("Failed to retrieve data (no network?): " + ex.Message); } else { OGCSexception.Analyse("Failed to retrieve data", ex); } } catch (System.Exception ex) { OGCSexception.Analyse("Failed to retrieve data: ", ex); } if (!string.IsNullOrEmpty(html)) { log.Debug("Finding Beta release..."); MatchCollection release = getRelease(html, @"<strong>Beta</strong>: <a href=""(.*?)"">v([\d\.]+)</a>"); if (release.Count > 0) { releaseType = "Beta"; releaseURL = release[0].Result("$1"); releaseVersion = release[0].Result("$2"); } if (Settings.Instance.AlphaReleases) { log.Debug("Finding Alpha release..."); release = getRelease(html, @"<strong>Alpha</strong>: <a href=""(.*?)"">v([\d\.]+)</a>"); if (release.Count > 0) { releaseType = "Alpha"; releaseURL = release[0].Result("$1"); releaseVersion = release[0].Result("$2"); } } } if (releaseVersion != null) { String paddedVersion = ""; foreach (String versionBit in releaseVersion.Split('.')) { paddedVersion += versionBit.PadLeft(2, '0'); } Int32 releaseNum = Convert.ToInt32(paddedVersion); paddedVersion = ""; foreach (String versionBit in Application.ProductVersion.Split('.')) { paddedVersion += versionBit.PadLeft(2, '0'); } Int32 myReleaseNum = Convert.ToInt32(paddedVersion); if (releaseNum > myReleaseNum) { log.Info("New " + releaseType + " ZIP release found: " + releaseVersion); DialogResult dr = OgcsMessageBox.Show("A new " + releaseType + " release is available for OGCS. Would you like to upgrade to v" + releaseVersion + "?", "New OGCS Release Available", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (dr == DialogResult.Yes) { System.Diagnostics.Process.Start(releaseURL); } } else { log.Info("Already on latest ZIP release."); if (isManualCheck) { OgcsMessageBox.Show("You are already on the latest release", "No Update Required", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } else { log.Info("Did not find ZIP release."); if (isManualCheck) { OgcsMessageBox.Show("Failed to check for ZIP release." + (string.IsNullOrEmpty(errorDetails) ? "" : "\r\n" + errorDetails), "Update Check Failed", MessageBoxButtons.OK, MessageBoxIcon.Information); } } }
private void getGaccountEmail(String accessToken) { String jsonString = ""; log.Debug("Retrieving email address associated with Google account."); try { jsonString = new Extensions.OgcsWebClient().DownloadString("https://www.googleapis.com/oauth2/v2/userinfo?fields=email&access_token=" + accessToken); JObject jo = Newtonsoft.Json.Linq.JObject.Parse(jsonString); JToken jtEmail = jo["email"]; String email = jtEmail.ToString(); if (Settings.Instance.GaccountEmail != email) { if (!String.IsNullOrEmpty(Settings.Instance.GaccountEmail)) { log.Debug("Looks like the Google account username value has been tampering with? :-O"); } Settings.Instance.GaccountEmail = email; Forms.Main.Instance.SetControlPropertyThreadSafe(Forms.Main.Instance.tbConnectedAcc, "Text", email); log.Debug("Updating Google account username: "******"Inner exception: " + ex.InnerException.Message); } if (ex.Response != null) { log.Debug("Reading response."); System.IO.Stream stream = ex.Response.GetResponseStream(); System.IO.StreamReader sr = new System.IO.StreamReader(stream); log.Error(sr.ReadToEnd()); } if (OGCSexception.GetErrorCode(ex) == "0x80131509") { log.Warn(ex.Message); System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex(@"\b(403|Forbidden|Prohibited|Insufficient Permission)\b", System.Text.RegularExpressions.RegexOptions.IgnoreCase); if (rgx.IsMatch(ex.Message)) { if (Settings.Instance.UsingPersonalAPIkeys()) { String msg = "If you are using your own API keys, you must also enable the Google+ API."; OgcsMessageBox.Show(msg, "Missing API Service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Exclamation); throw new System.ApplicationException(msg); } else { if (getEmailAttempts > 1) { log.Error("Failed to retrieve Google account username."); log.Debug("Using previously retrieved username: "******"", (ex.InnerException != null ? ex.InnerException : ex)); throw; } } OGCSexception.Analyse(ex); if (ex.Message.ToLower().Contains("access denied")) { Forms.Main.Instance.Console.Update("Failed to obtain Calendar access from Google - it's possible your access has been revoked." + "<br/>Try disconnecting your Google account and reauthorising OGCS.", Console.Markup.error); } else if (ex.Message.ToLower().Contains("prohibited") && Settings.Instance.UsingPersonalAPIkeys()) { Forms.Main.Instance.Console.Update("If you are using your own API keys, you must also enable the Google+ API.", Console.Markup.warning); } throw; } catch (System.Exception ex) { log.Debug("JSON: " + jsonString); log.Error("Failed to retrieve Google account username."); OGCSexception.Analyse(ex); log.Debug("Using previously retrieved username: " + Settings.Instance.GaccountEmail_masked()); } }
public static void UpdateGoogleExceptions(AppointmentItem ai, Event ev, Boolean dirtyCache) { if (ai.IsRecurring) { RecurrencePattern rp = null; Exceptions excps = null; try { rp = ai.GetRecurrencePattern(); excps = rp.Exceptions; if (excps.Count > 0) { log.Debug(OutlookOgcs.Calendar.GetEventSummary(ai)); log.Debug("This is a recurring appointment with " + excps.Count + " exceptions that will now be iteratively compared."); for (int e = 1; e <= excps.Count; e++) { Microsoft.Office.Interop.Outlook.Exception oExcp = null; AppointmentItem aiExcp = null; try { oExcp = excps[e]; int excp_itemModified = 0; //Check the exception falls in the date range being synced Boolean oIsDeleted = exceptionIsDeleted(oExcp); String logDeleted = oIsDeleted ? " deleted and" : ""; DateTime oExcp_currDate; if (oIsDeleted) { oExcp_currDate = oExcp.OriginalDate; } else { aiExcp = oExcp.AppointmentItem; oExcp_currDate = aiExcp.Start; aiExcp = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(aiExcp); } if (oExcp_currDate < Settings.Instance.SyncStart.Date || oExcp_currDate > Settings.Instance.SyncEnd.Date) { log.Fine("Exception is" + logDeleted + " outside date range being synced: " + oExcp_currDate.Date.ToString("dd/MM/yyyy")); continue; } Event gExcp = Recurrence.Instance.getGoogleInstance(ref oExcp, ev.RecurringEventId ?? ev.Id, OutlookOgcs.Calendar.Instance.IOutlook.GetGlobalApptID(ai), dirtyCache); if (gExcp != null) { log.Debug("Matching Google Event recurrence found."); if (gExcp.Status == "cancelled") { log.Debug("It is deleted in Google, so cannot compare items."); if (!oIsDeleted) { log.Warn("Outlook is NOT deleted though - a mismatch has occurred somehow!"); String syncDirectionTip = (Settings.Instance.SyncDirection == Sync.Direction.Bidirectional) ? "<br/><i>Ensure you <b>first</b> set OGCS to one-way sync O->G.</i>" : ""; Forms.Main.Instance.Console.Update(OutlookOgcs.Calendar.GetEventSummary(ai) + "<br/>" + "The occurrence on " + oExcp.OriginalDate.ToShortDateString() + " does not exist in Google, but does in Outlook.<br/>" + "This can happen if, for example, you declined the occurrence (which is synced to Google) and proposed a new time that is subsequently accepted by the organiser.<br/>" + "<u>Suggested fix</u>: delete the entire series in Google and let OGCS recreate it." + syncDirectionTip, Console.Markup.warning); } continue; } else if (oIsDeleted && gExcp.Status != "cancelled") { gExcp.Status = "cancelled"; log.Debug("Exception deleted."); excp_itemModified++; } else { try { aiExcp = oExcp.AppointmentItem; //Force a compare of the exception if both G and O have been modified in last 24 hours TimeSpan modifiedDiff = (TimeSpan)(gExcp.Updated - aiExcp.LastModificationTime); log.Fine("Difference in days between G and O exception: " + modifiedDiff); Boolean forceCompare = modifiedDiff < TimeSpan.FromDays(1); GoogleOgcs.Calendar.Instance.UpdateCalendarEntry(aiExcp, gExcp, ref excp_itemModified, forceCompare); } catch (System.Exception ex) { log.Error(ex.Message); log.Error(ex.StackTrace); throw; } } if (excp_itemModified > 0) { try { GoogleOgcs.Calendar.Instance.UpdateCalendarEntry_save(ref gExcp); } catch (System.Exception ex) { Forms.Main.Instance.Console.UpdateWithError("Updated event exception failed to save.", ex); OGCSexception.Analyse(ex, true); if (OgcsMessageBox.Show("Updated Google event exception failed to save. Continue with synchronisation?", "Sync item failed", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { continue; } else { throw new UserCancelledSyncException("User chose not to continue sync."); } } } } else { log.Debug("No matching Google Event recurrence found."); if (oIsDeleted) { log.Debug("The Outlook appointment is deleted, so not a problem."); } } } finally { aiExcp = (AppointmentItem)OutlookOgcs.Calendar.ReleaseObject(aiExcp); oExcp = (Microsoft.Office.Interop.Outlook.Exception)OutlookOgcs.Calendar.ReleaseObject(oExcp); } } } } finally { excps = (Exceptions)OutlookOgcs.Calendar.ReleaseObject(excps); rp = (RecurrencePattern)OutlookOgcs.Calendar.ReleaseObject(rp); } } }
/// <returns>True if the user has upgraded</returns> private async Task <Boolean> githubCheck() { log.Debug("Checking for Squirrel update..."); UpdateManager updateManager = null; isBusy = true; try { String installRootDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); if (string.IsNullOrEmpty(nonGitHubReleaseUri)) { updateManager = await Squirrel.UpdateManager.GitHubUpdateManager("https://github.com/phw198/OutlookGoogleCalendarSync", "OutlookGoogleCalendarSync", installRootDir, new Squirrel.FileDownloader(new Extensions.OgcsWebClient()), prerelease : Settings.Instance.AlphaReleases); } else { updateManager = new Squirrel.UpdateManager(nonGitHubReleaseUri, "OutlookGoogleCalendarSync", installRootDir); } UpdateInfo updates = await updateManager.CheckForUpdate(); if (updates.ReleasesToApply.Any()) { if (updates.CurrentlyInstalledVersion != null) { log.Info("Currently installed version: " + updates.CurrentlyInstalledVersion.Version.ToString()); } log.Info("Found " + updates.ReleasesToApply.Count() + " newer releases available."); foreach (ReleaseEntry update in updates.ReleasesToApply.OrderBy(x => x.Version).Reverse()) { log.Info("Found a new " + update.Version.SpecialVersion + " version: " + update.Version.Version.ToString()); if (!this.isManualCheck && update.Version.Version.ToString() == Settings.Instance.SkipVersion) { log.Info("The user has previously requested to skip this version."); break; } String releaseNotes = ""; if (nonGitHubReleaseUri != null) { releaseNotes = update.GetReleaseNotes(nonGitHubReleaseUri); } else { //Somewhat annoyingly we have to download the release in order to get the release notes, as they are embedded in the .nupkg upgrade file(s) try { updateManager.DownloadReleases(new[] { update }).Wait(30 * 1000); System.Collections.Generic.Dictionary <ReleaseEntry, String> allReleaseNotes = updates.FetchReleaseNotes(); releaseNotes = allReleaseNotes[update]; } catch (System.Exception ex) { OGCSexception.Analyse(ex); log.Error("Failed pre-fetching release notes. " + ex.Message); releaseNotes = null; } } DialogResult dr = DialogResult.Cancel; if (!string.IsNullOrEmpty(releaseNotes)) { log.Debug("Release notes retrieved."); } var t = new System.Threading.Thread(() => new Forms.UpdateInfo(update.Version.Version.ToString(), update.Version.SpecialVersion, releaseNotes, out dr)); t.SetApartmentState(System.Threading.ApartmentState.STA); t.Start(); t.Join(); String squirrelAnalyticsLabel = "from=" + Application.ProductVersion + ";to=" + update.Version.Version.ToString(); if (dr == DialogResult.No) { log.Info("User chose not to upgrade right now."); Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.upgrade, squirrelAnalyticsLabel + ";later"); } else if (dr == DialogResult.Ignore) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.upgrade, squirrelAnalyticsLabel + ";skipped"); } else if (dr == DialogResult.Yes) { log.Debug("Download started..."); if (!updateManager.DownloadReleases(new[] { update }).Wait(60 * 1000)) { log.Warn("The download failed to completed within 60 seconds."); Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";timedout"); if (OgcsMessageBox.Show("The update failed to download.", "Download timed out", MessageBoxButtons.RetryCancel, MessageBoxIcon.Exclamation) == DialogResult.Retry) { if (!updateManager.DownloadReleases(new[] { update }).Wait(60 * 1000)) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";retry-timedout"); if (OgcsMessageBox.Show("The update failed to download again.\nTo download from the project website, click Yes.", "Download timed out", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";from-website"); System.Diagnostics.Process.Start("https://phw198.github.io/OutlookGoogleCalendarSync/"); } else { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";gave-up"); } break; } } else { if (OgcsMessageBox.Show("Would you like to download directly from the project website?", "Go to OGCS website", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";from-website"); System.Diagnostics.Process.Start("https://phw198.github.io/OutlookGoogleCalendarSync/"); } else { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";gave-up"); } break; } } try { log.Debug("Download complete."); Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, squirrelAnalyticsLabel + ";successful"); log.Info("Applying the updated release..."); updateManager.ApplyReleases(updates).Wait(); log.Info("The application has been successfully updated."); OgcsMessageBox.Show("The application has been updated and will now restart.", "OGCS successfully updated!", MessageBoxButtons.OK, MessageBoxIcon.Information); restartUpdateExe = updateManager.RootAppDirectory + "\\Update.exe"; return(true); } catch (System.AggregateException ae) { foreach (System.Exception ex in ae.InnerExceptions) { OGCSexception.Analyse(ex, true); ex.Data.Add("analyticsLabel", squirrelAnalyticsLabel); throw new ApplicationException("Failed upgrading OGCS.", ex); } } catch (System.Exception ex) { OGCSexception.Analyse(ex, true); ex.Data.Add("analyticsLabel", squirrelAnalyticsLabel); throw new ApplicationException("Failed upgrading OGCS.", ex); } } break; } } else { log.Info("Already running the latest version of OGCS."); if (this.isManualCheck) //Was a manual check, so give feedback { OgcsMessageBox.Show("You are already running the latest version of OGCS.", "Latest Version", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } catch (ApplicationException ex) { Telemetry.Send(Analytics.Category.squirrel, Analytics.Action.download, ex.Data["analyticsLabel"] + ";failed"); throw; } catch (System.AggregateException ae) { log.Fail("Failed checking for update."); foreach (System.Exception ex in ae.InnerExceptions) { OGCSexception.Analyse(OGCSexception.LogAsFail(ex), true); throw; } } catch (System.Exception ex) { OGCSexception.Analyse("Failed checking for update.", OGCSexception.LogAsFail(ex), true); throw; } finally { isBusy = false; updateManager.Dispose(); } return(false); }