diff --git a/Application/App.config b/Application/App.config index e0826fc..a746db7 100644 --- a/Application/App.config +++ b/Application/App.config @@ -8,10 +8,11 @@
- - + + + @@ -27,6 +28,7 @@ + diff --git a/Application/Forms/MainForm.Designer.cs b/Application/Forms/MainForm.Designer.cs index 1242a71..2494dbd 100644 --- a/Application/Forms/MainForm.Designer.cs +++ b/Application/Forms/MainForm.Designer.cs @@ -30,6 +30,7 @@ private void InitializeComponent() this.viewInboxToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.checkMailNowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.tellMeAgainToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.lastEmailInfoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); @@ -41,12 +42,13 @@ private void InitializeComponent() // notifyIcon // this.notifyIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info; - this.notifyIcon.BalloonTipText = "You have no unread mail."; + this.notifyIcon.BalloonTipText = "n/a"; this.notifyIcon.BalloonTipTitle = "Gmail"; this.notifyIcon.ContextMenuStrip = this.contextMenuStrip; this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon"))); - this.notifyIcon.Text = "No unread mail"; + this.notifyIcon.Text = "No info available"; this.notifyIcon.Visible = true; + this.notifyIcon.BalloonTipClicked += new System.EventHandler(this.notifyIcon_BalloonTipClicked); this.notifyIcon.DoubleClick += new System.EventHandler(this.notifyIcon_DoubleClick); // // contextMenuStrip @@ -55,6 +57,7 @@ private void InitializeComponent() this.viewInboxToolStripMenuItem, this.checkMailNowToolStripMenuItem, this.tellMeAgainToolStripMenuItem, + this.lastEmailInfoToolStripMenuItem, this.optionsToolStripMenuItem, this.aboutToolStripMenuItem, this.toolStripMenuItem1, @@ -84,6 +87,13 @@ private void InitializeComponent() this.tellMeAgainToolStripMenuItem.Text = "Tell Me A&gain"; this.tellMeAgainToolStripMenuItem.Click += new System.EventHandler(this.tellMeAgainToolStripMenuItem_Click); // + // lastEmailInfoToolStripMenuItem + // + this.lastEmailInfoToolStripMenuItem.Name = "lastEmailInfoToolStripMenuItem"; + this.lastEmailInfoToolStripMenuItem.Size = new System.Drawing.Size(161, 22); + this.lastEmailInfoToolStripMenuItem.Text = "&Last email info"; + this.lastEmailInfoToolStripMenuItem.Click += new System.EventHandler(this.lastEmailInfoToolStripMenuItem_Click); + // // optionsToolStripMenuItem // this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; @@ -140,6 +150,7 @@ private void InitializeComponent() private System.Windows.Forms.Timer timer; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem lastEmailInfoToolStripMenuItem; } } diff --git a/Application/Forms/MainForm.cs b/Application/Forms/MainForm.cs index b5afdc5..f0a1071 100644 --- a/Application/Forms/MainForm.cs +++ b/Application/Forms/MainForm.cs @@ -15,8 +15,17 @@ public partial class MainForm : Form // Logger private static readonly ILog Logger = LogManager.GetLogger(typeof(MainForm)); + // Settings defaults + private const int m_notificationDelay_Min = 1; //seconds + private const int m_notificationDelay_Max = 60; + private const int m_notificationDelay_Default = 5; + private const int m_CheckInterval_Min = 1; //minutes + private const int m_CheckInterval_Max = 60; + private const int m_CheckInterval_Default = 1; + // These settings are configurable via the app.config file private int notificationDelay; + private String gmailUrl; // The current state of the inbox private int unreadCount; @@ -36,14 +45,15 @@ public MainForm() InitializeComponent(); // Load the configuration - this.notificationDelay = Convert.ToInt32(ConfigurationManager.AppSettings["NotificationDelay"]); + LoadConfig(); // Initialize the ATOM client + if (ConfigurationManager.AppSettings["AtomFeedUrl"].ToString() == string.Empty) + { + throw new ArgumentNullException("[AtomFeedUrl]", "Invalid config: [AtomFeedUrl] not set !"); + } this.atomMailChecker = new AtomMailChecker(ConfigurationManager.AppSettings["AtomFeedUrl"]); - // Set the timer interval from the config (convert minutes to milliseconds) - timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["CheckInterval"]) * 60 * 1000; - // Have we set the username/password already? if (string.IsNullOrEmpty(UserSettings.Default.Username)) { @@ -57,6 +67,39 @@ public MainForm() } } + // Loads the configuration + private void LoadConfig() + { + // Set the notification baloon delay + int a_notificationDelay = Convert.ToInt32(ConfigurationManager.AppSettings["NotificationDelay"]); + if (a_notificationDelay > m_notificationDelay_Max || a_notificationDelay < m_notificationDelay_Min) + { + Logger.Warn("Invalid config: [NotificationDelay] = " + a_notificationDelay.ToString() + " ! ...using default"); + a_notificationDelay = m_notificationDelay_Default; + } + this.notificationDelay = a_notificationDelay * 1000; // (convert seconds to milliseconds) + + // Set the timer interval from the config + int a_CheckInterval = Convert.ToInt32(ConfigurationManager.AppSettings["CheckInterval"]); + if (a_CheckInterval > 60 || a_CheckInterval < 1) + { + Logger.Warn("Invalid config: [CheckInterval] = " + a_CheckInterval.ToString() + " ! ...using default"); + a_CheckInterval = m_CheckInterval_Default; + } + timer.Interval = a_CheckInterval * 60 * 1000; // (convert seconds to milliseconds) + + //Gmail url + if (ConfigurationManager.AppSettings["GoogleMailUrl"].ToString().Length == 0) + { + Logger.Warn("Invalid config: [GoogleMailUrl] = " + ConfigurationManager.AppSettings["GoogleMailUrl"].ToString() + " ! ...using default"); + this.gmailUrl = "https://www.google.com/accounts/ServiceLogin?service=mail"; + } + else + { + this.gmailUrl = ConfigurationManager.AppSettings["GoogleMailUrl"].ToString(); + } + } + // This makes sure that this window is always hidden protected override void SetVisibleCore(bool value) { @@ -70,7 +113,7 @@ protected override void SetVisibleCore(bool value) } // Downloads the latest Atom feed to check for new mail - private void CheckMail() + private void CheckMail(bool showLast = false) { Logger.Debug("Checking mail..."); @@ -84,6 +127,12 @@ private void CheckMail() Logger.Warn("Missing credentials"); notifyIcon.Icon = SystrayIcons.SystrayIconError; notifyIcon.Text = "Please set username/password in Options"; + if (showLast) + { + notifyIcon.BalloonTipTitle = "Gmail"; + notifyIcon.BalloonTipText = "Please set username/password in Options"; + notifyIcon.ShowBalloonTip(notificationDelay); + } return; } @@ -101,20 +150,32 @@ private void CheckMail() // Show a notification if (unreadCount > 0) { + if (showLast) + lastMail = null; + var newEmails = atomMailChecker.GetNewEmails(lastMail); - if (newEmails.Count() == 1) + if (showLast) { - notifyIcon.BalloonTipTitle = "New mail from: " + newEmails.Single().From; - notifyIcon.BalloonTipText = newEmails.Single().Subject + Environment.NewLine + newEmails.Single().Preview; + notifyIcon.BalloonTipTitle = "Last mail from: " + newEmails.First().From; + notifyIcon.BalloonTipText = "[Subject:] " + newEmails.First().Subject + Environment.NewLine + "[Preview:] " + newEmails.First().Preview; notifyIcon.ShowBalloonTip(notificationDelay); } - if (newEmails.Count() > 1) + else { - notifyIcon.BalloonTipTitle = "You've got mail"; - notifyIcon.BalloonTipText = string.Format("You have {0} new emails", unreadCount); - notifyIcon.ShowBalloonTip(notificationDelay); - } + if (newEmails.Count() == 1) + { + notifyIcon.BalloonTipTitle = "New mail from: " + newEmails.Single().From; + notifyIcon.BalloonTipText = "[Subject:] " + newEmails.Single().Subject + Environment.NewLine + "[Preview:] " + newEmails.Single().Preview; + notifyIcon.ShowBalloonTip(notificationDelay); + } + if (newEmails.Count() > 1) + { + notifyIcon.BalloonTipTitle = "You've got mail"; + notifyIcon.BalloonTipText = string.Format("You have {0} new emails", unreadCount); + notifyIcon.ShowBalloonTip(notificationDelay); + } + } } else { @@ -158,6 +219,12 @@ private void ShowOptions() { if (optionsForm.DialogResult == DialogResult.OK) CheckMail(); + else if (string.IsNullOrEmpty(UserSettings.Default.Username) || string.IsNullOrEmpty(UserSettings.Default.Password)) + { + Logger.Warn("Missing credentials"); + notifyIcon.Icon = SystrayIcons.SystrayIconError; + notifyIcon.Text = "Please set username/password in Options"; + } optionsForm = null; }; @@ -186,13 +253,13 @@ private void ShowAbout() private void notifyIcon_DoubleClick(object sender, EventArgs e) { Logger.Debug("System tray icon: double click"); - Process.Start("https://mail.google.com"); + Process.Start(gmailUrl); } private void viewInboxToolStripMenuItem_Click(object sender, EventArgs e) { Logger.Debug("Context menu: view inbox"); - Process.Start("https://mail.google.com"); + Process.Start(gmailUrl); } private void checkMailNowToolStripMenuItem_Click(object sender, EventArgs e) @@ -224,6 +291,21 @@ private void exitToolStripMenuItem_Click(object sender, EventArgs e) Application.Exit(); } + private void lastEmailInfoToolStripMenuItem_Click(object sender, EventArgs e) + { + Logger.Debug("Context menu: show last email"); + CheckMail(true); + } + + private void notifyIcon_BalloonTipClicked(object sender, EventArgs e) + { + Logger.Debug("Baloon tooltip: clicked"); + if (unreadCount > 0) + { + Process.Start(gmailUrl); + } + } + #endregion } } diff --git a/Application/Forms/OptionsForm.Designer.cs b/Application/Forms/OptionsForm.Designer.cs index c79d010..90fb398 100644 --- a/Application/Forms/OptionsForm.Designer.cs +++ b/Application/Forms/OptionsForm.Designer.cs @@ -102,9 +102,9 @@ private void InitializeComponent() this.label3.AutoSize = true; this.label3.Location = new System.Drawing.Point(91, 61); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(212, 26); + this.label3.Size = new System.Drawing.Size(217, 26); this.label3.TabIndex = 6; - this.label3.Text = "Make sure you use an \r\nIt will not work with your account password!"; + this.label3.Text = "Make sure you use an \r\nIt may not work with your account password!"; // // appPasswordLink // @@ -119,6 +119,7 @@ private void InitializeComponent() // // OptionsForm // + this.AcceptButton = this.okButton; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancelButton; diff --git a/Application/Program.cs b/Application/Program.cs index ef14266..70c015b 100644 --- a/Application/Program.cs +++ b/Application/Program.cs @@ -21,7 +21,15 @@ static void Main() Application.ThreadException += HandleError; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new MainForm()); + try + { + Application.Run(new MainForm()); + } + catch (Exception ex) + { + Logger.Error("Error while running program!", ex); + MessageBox.Show("Error while running program!\nSee log for details.\nProgram will close.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } Logger.Info("Program closed."); } diff --git a/Application/Properties/AssemblyInfo.cs b/Application/Properties/AssemblyInfo.cs index 2ec8f1c..a45105c 100644 --- a/Application/Properties/AssemblyInfo.cs +++ b/Application/Properties/AssemblyInfo.cs @@ -31,8 +31,8 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.2.0")] -[assembly: AssemblyFileVersion("1.2.0")] +[assembly: AssemblyVersion("1.2.1")] +[assembly: AssemblyFileVersion("1.2.1")] // Initialize log4net [assembly: log4net.Config.XmlConfigurator(Watch = false)] \ No newline at end of file diff --git a/ReadMe.md b/ReadMe.md index 11948e0..29b2b2f 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -46,6 +46,22 @@ On the first run, you will be asked for credentials (these will be stored [secur Change Log =============================== +**1.2.1 - Mar 3, 2015** + [by yanoschik] + - (minor) added few comments to code and config + - config modifications: + - NotificationDelay key changed to represent seconds + - added key for Google mail url, which replaces the previously hardcoded one (used for opening mailbox in browser) + - default logging level set to INFO + - reading config moved to a separate method + - important config variables are checked for reasonable values, defaults used if failed + - added option to show last mail -info in baloon tooltip + - clicking on baloon now also opens the browser (like doubleclick on icon or menuitem) + - config dialog has the accept button OK assigned (pressing Enter = clicking OK) + - minor text changes in baloon tooltips + - general handling of exceptions from MainForm -> log & show message before exit + - some minor changes (initial texts for icon and baloontip; notification improved when credentials error occurs; etc.) + **1.2 - Mar 3, 2014** - Credentials now set via the Options dialog instead of directly in the config file, and stored securely using the Windows Data Protection API.