using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.IO;
using System.Threading;
using Microsoft.Win32;
using Johnvey.GmailAgent;
using JCMLib;
namespace Johnvey.GmailAgent.Applet
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class BaseWindow : System.Windows.Forms.Form
{
protected BaseWindow self;
public GmailAdapter gmail;
public GmailSessionCollection accounts;
// refresh interval in minutes
private int refreshInterval;
private DateTime lastRefresh = new DateTime(0);
private Hashtable lastTimestamp = new Hashtable();
private Hashtable latestMessage = new Hashtable();
private System.Windows.Forms.ListView sessionList;
private System.Windows.Forms.GroupBox accountStatus;
private System.Windows.Forms.Label newThreadsLabel;
private System.Windows.Forms.ListBox newThreadsList;
private System.Windows.Forms.Label threadPreviewLabel;
private System.Windows.Forms.ContextMenu notifyIconContextMenu;
private JCMLib.NotifyIconEx notifyIcon;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.ImageList imageList;
private System.Windows.Forms.Button gmailButton;
private System.Windows.Forms.TextBox threadPreviewText;
private System.Windows.Forms.Button refreshButton;
private System.Timers.Timer refreshTimer;
private System.Windows.Forms.TextBox refreshIntervalBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox lastCheckedText;
private System.ComponentModel.IContainer components;
#region Default form code
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#endregion
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(BaseWindow));
this.sessionList = new System.Windows.Forms.ListView();
this.imageList = new System.Windows.Forms.ImageList(this.components);
this.accountStatus = new System.Windows.Forms.GroupBox();
this.lastCheckedText = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.threadPreviewText = new System.Windows.Forms.TextBox();
this.newThreadsList = new System.Windows.Forms.ListBox();
this.threadPreviewLabel = new System.Windows.Forms.Label();
this.newThreadsLabel = new System.Windows.Forms.Label();
this.notifyIconContextMenu = new System.Windows.Forms.ContextMenu();
this.notifyIcon = new JCMLib.NotifyIconEx();
this.closeButton = new System.Windows.Forms.Button();
this.gmailButton = new System.Windows.Forms.Button();
this.refreshButton = new System.Windows.Forms.Button();
this.refreshTimer = new System.Timers.Timer();
this.refreshIntervalBox = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.accountStatus.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.refreshTimer)).BeginInit();
this.SuspendLayout();
//
// sessionList
//
this.sessionList.Activation = System.Windows.Forms.ItemActivation.OneClick;
this.sessionList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
this.sessionList.HideSelection = false;
this.sessionList.LargeImageList = this.imageList;
this.sessionList.Location = new System.Drawing.Point(8, 8);
this.sessionList.MultiSelect = false;
this.sessionList.Name = "sessionList";
this.sessionList.Size = new System.Drawing.Size(104, 368);
this.sessionList.SmallImageList = this.imageList;
this.sessionList.TabIndex = 0;
this.sessionList.Click += new System.EventHandler(this.sessionList_onItemClick);
//
// imageList
//
this.imageList.ImageSize = new System.Drawing.Size(32, 32);
this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream")));
this.imageList.TransparentColor = System.Drawing.Color.Transparent;
//
// accountStatus
//
this.accountStatus.Controls.Add(this.lastCheckedText);
this.accountStatus.Controls.Add(this.label3);
this.accountStatus.Controls.Add(this.threadPreviewText);
this.accountStatus.Controls.Add(this.newThreadsList);
this.accountStatus.Controls.Add(this.threadPreviewLabel);
this.accountStatus.Controls.Add(this.newThreadsLabel);
this.accountStatus.Location = new System.Drawing.Point(128, 8);
this.accountStatus.Name = "accountStatus";
this.accountStatus.Size = new System.Drawing.Size(272, 368);
this.accountStatus.TabIndex = 1;
this.accountStatus.TabStop = false;
this.accountStatus.Text = "Current Status";
//
// lastCheckedText
//
this.lastCheckedText.BackColor = System.Drawing.SystemColors.Control;
this.lastCheckedText.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.lastCheckedText.Location = new System.Drawing.Point(96, 32);
this.lastCheckedText.Name = "lastCheckedText";
this.lastCheckedText.Size = new System.Drawing.Size(160, 13);
this.lastCheckedText.TabIndex = 6;
this.lastCheckedText.Text = "Never";
//
// label3
//
this.label3.Location = new System.Drawing.Point(16, 32);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(88, 16);
this.label3.TabIndex = 5;
this.label3.Text = "Last Checked:";
//
// threadPreviewText
//
this.threadPreviewText.BackColor = System.Drawing.Color.White;
this.threadPreviewText.Location = new System.Drawing.Point(16, 208);
this.threadPreviewText.Multiline = true;
this.threadPreviewText.Name = "threadPreviewText";
this.threadPreviewText.ReadOnly = true;
this.threadPreviewText.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.threadPreviewText.Size = new System.Drawing.Size(240, 144);
this.threadPreviewText.TabIndex = 4;
this.threadPreviewText.Text = "";
//
// newThreadsList
//
this.newThreadsList.Location = new System.Drawing.Point(16, 72);
this.newThreadsList.Name = "newThreadsList";
this.newThreadsList.ScrollAlwaysVisible = true;
this.newThreadsList.SelectionMode = System.Windows.Forms.SelectionMode.None;
this.newThreadsList.Size = new System.Drawing.Size(240, 108);
this.newThreadsList.TabIndex = 0;
//
// threadPreviewLabel
//
this.threadPreviewLabel.Location = new System.Drawing.Point(16, 192);
this.threadPreviewLabel.Name = "threadPreviewLabel";
this.threadPreviewLabel.Size = new System.Drawing.Size(168, 23);
this.threadPreviewLabel.TabIndex = 3;
this.threadPreviewLabel.Text = "New Thread Previews";
//
// newThreadsLabel
//
this.newThreadsLabel.Location = new System.Drawing.Point(16, 56);
this.newThreadsLabel.Name = "newThreadsLabel";
this.newThreadsLabel.Size = new System.Drawing.Size(152, 16);
this.newThreadsLabel.TabIndex = 2;
this.newThreadsLabel.Text = "New Thread Counts";
//
// notifyIcon
//
this.notifyIcon.ContextMenu = this.notifyIconContextMenu;
this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon")));
this.notifyIcon.Text = "Gmail Agent";
this.notifyIcon.Visible = true;
//
// closeButton
//
this.closeButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.closeButton.Location = new System.Drawing.Point(320, 440);
this.closeButton.Name = "closeButton";
this.closeButton.TabIndex = 2;
this.closeButton.Text = "Close";
this.closeButton.Click += new System.EventHandler(this.close_onClick);
//
// gmailButton
//
this.gmailButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.gmailButton.Location = new System.Drawing.Point(208, 440);
this.gmailButton.Name = "gmailButton";
this.gmailButton.Size = new System.Drawing.Size(104, 23);
this.gmailButton.TabIndex = 3;
this.gmailButton.Text = "Open Gmail";
this.gmailButton.Click += new System.EventHandler(this.launchGmail_onClick);
//
// refreshButton
//
this.refreshButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.refreshButton.Location = new System.Drawing.Point(8, 440);
this.refreshButton.Name = "refreshButton";
this.refreshButton.TabIndex = 4;
this.refreshButton.Text = "Refresh";
this.refreshButton.Click += new System.EventHandler(this.refresh_onClick);
//
// refreshTimer
//
this.refreshTimer.Enabled = true;
this.refreshTimer.SynchronizingObject = this;
//
// refreshIntervalBox
//
this.refreshIntervalBox.Location = new System.Drawing.Point(186, 397);
this.refreshIntervalBox.MaxLength = 2;
this.refreshIntervalBox.Name = "refreshIntervalBox";
this.refreshIntervalBox.Size = new System.Drawing.Size(24, 20);
this.refreshIntervalBox.TabIndex = 5;
this.refreshIntervalBox.Text = "";
this.refreshIntervalBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
this.refreshIntervalBox.Leave += new System.EventHandler(this.refresh_onLeave);
//
// label1
//
this.label1.Location = new System.Drawing.Point(24, 400);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(168, 16);
this.label1.TabIndex = 6;
this.label1.Text = "Check for new messages every";
//
// label2
//
this.label2.Location = new System.Drawing.Point(213, 400);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(51, 16);
this.label2.TabIndex = 7;
this.label2.Text = "minutes.";
//
// groupBox1
//
this.groupBox1.Location = new System.Drawing.Point(8, 384);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(392, 40);
this.groupBox1.TabIndex = 8;
this.groupBox1.TabStop = false;
//
// BaseWindow
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(410, 483);
this.ControlBox = false;
this.Controls.Add(this.refreshIntervalBox);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.refreshButton);
this.Controls.Add(this.gmailButton);
this.Controls.Add(this.closeButton);
this.Controls.Add(this.accountStatus);
this.Controls.Add(this.sessionList);
this.Controls.Add(this.groupBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "BaseWindow";
this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.Text = "Gmail Agent 0.5";
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.accountStatus.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.refreshTimer)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new BaseWindow());
}
/// <summary>
/// Main form logic.
/// </summary>
public BaseWindow() {
// Required for Windows Form Designer support
InitializeComponent();
// Create the system tray icon
notifyIcon.Click += new EventHandler(notifyIcon_onClick);
notifyIcon.BalloonClick += new EventHandler(notifyIcon_onBalloonClick);
// Create the system tray context menu
notifyIconContextMenu.MenuItems.Add(new MenuItem("Contacts...", new EventHandler(menuContacts_onClick)));
notifyIconContextMenu.MenuItems.Add("-");
notifyIconContextMenu.MenuItems.Add(new MenuItem("Accounts...", new EventHandler(menuAccounts_onClick)));
notifyIconContextMenu.MenuItems.Add(new MenuItem("Status...", new EventHandler(menuProperties_onClick)));
notifyIconContextMenu.MenuItems.Add("-");
notifyIconContextMenu.MenuItems.Add(new MenuItem("About", new EventHandler(menuAbout_onClick)));
notifyIconContextMenu.MenuItems.Add(new MenuItem("Exit", new EventHandler(menuExit_onClick)));
// instantiate the Gmail components
this.gmail = new GmailAdapter();
this.accounts = new GmailSessionCollection();
// refresh login info
RefreshLoginInfo();
// contact refresh delegate to get info from Gmail
RefreshAllSessionsDelegate refresher = new RefreshAllSessionsDelegate(this.RefreshAllSessions);
IAsyncResult ar = refresher.BeginInvoke(new AsyncCallback(RefreshAllCallback), refresher);
this.lastRefresh = DateTime.Now;
// repeat the refresh as per user settings
refreshTimer.Interval = 5000;
refreshTimer.AutoReset = true;
refreshTimer.Elapsed += new System.Timers.ElapsedEventHandler(refreshTimer_onElapsed);
// hide the window
this.Hide();
}
/// <summary>
/// Reads stored login information in registry and initializes session objects
/// </summary>
public void RefreshLoginInfo() {
// reset account info
this.accounts.Clear();
this.sessionList.Items.Clear();
// get the account logins
RegistryKey workingRegistry = Application.UserAppDataRegistry;
RegistryKey accountsKey = workingRegistry.CreateSubKey("Accounts");
// read refresh interval (or set to default)
if(workingRegistry.GetValue("RefreshInterval") != null) {
this.refreshInterval = (int)workingRegistry.GetValue("RefreshInterval");
} else {
workingRegistry.SetValue("RefreshInterval", 2);
this.refreshInterval = 2;
}
this.refreshIntervalBox.Text = this.refreshInterval.ToString();
// read the stored accounts and initialize
foreach(string accountName in accountsKey.GetValueNames()) {
GmailSession tmpSession = new GmailSession();
tmpSession.Username = accountName;
tmpSession.Password = SimpleEncryption.Decrypt(accountsKey.GetValue(accountName).ToString(), "GmailAgent0500");
tmpSession.NewMessageEventHandler += new GmailSession.EventHandler(NotifyNewMessages);
this.accounts.Add(tmpSession);
this.sessionList.Items.Add(new ListViewItem(tmpSession.Username, 0));
}
}
/// <summary>
/// Requests a mailbox update for all currently active GmailSessions in 'accounts'
/// </summary>
protected void RefreshAllSessions() {
bool accountsHaveNewMessages = false;
foreach(GmailSession session in this.accounts) {
// refresh mailbox info
GmailAdapter.RequestResponseType loginResult = gmail.Refresh(session);
if(loginResult == GmailAdapter.RequestResponseType.LoginFailed) {
notifyIcon.ShowBalloon("Gmail login failed!", "The login information for " + session.Username + " is incorrect. Verify your account information in the Accounts page.", NotifyIconEx.NotifyInfoFlags.Error, 10000);
break;
}
if(loginResult == GmailAdapter.RequestResponseType.RefreshFailed) {
notifyIcon.ShowBalloon("Gmail refresh failed!", "GmailAgent was unable to refresh the mailbox information for " + session.Username + ".", NotifyIconEx.NotifyInfoFlags.Warning, 10000);
break;
}
// save the timestamp to determine whether new messages have appeared since last refresh
this.lastTimestamp[session.Username] = session.ThreadListTimestamp;
// flag new messages from any account
if((int)session.DefaultSearchCounts["Inbox"] > 0) {
this.latestMessage[session.Username] = ((GmailThread)session.UnreadThreads[0]).ThreadID;
accountsHaveNewMessages = true;
}
}
this.lastRefresh = DateTime.Now;
if(!accountsHaveNewMessages) {
// change the icon
try {
Stream iconStream = this.GetType().Assembly.GetManifestResourceStream("Johnvey.GmailAgent.Applet.gmail.ico");
Icon newIcon = new Icon(iconStream);
notifyIcon.Icon = newIcon;
iconStream.Close();
} catch(Exception ex) {
MessageBox.Show(ex.Message);
}
notifyIcon.Text = "Gmail Agent";
}
}
/// <summary>
/// Generates traditional and balloon tooltips for a new message event.
/// </summary>
/// <param name="sender"></param>
protected void NotifyNewMessages(object sender) {
GmailSession currentSession = (GmailSession)sender;
GmailThread newestThread = (GmailThread)currentSession.UnreadThreads[0];
if(newestThread.ThreadID != (string)this.latestMessage[currentSession.Username]) {
string threadSummary = Utilities.CleanHtml(newestThread.AuthorsHtml)
+ " - " + Utilities.CleanHtml(newestThread.DateHtml)
+ "\n" + Utilities.CleanHtml(newestThread.SubjectHtml)
+ "\n\n" + Utilities.CleanHtml(newestThread.SnippetHtml);
if(newestThread.IsStarred) threadSummary = "*" + threadSummary;
string title = currentSession.Username + " - "
+ currentSession.DefaultSearchCounts["Inbox"].ToString()
+ ((int)currentSession.DefaultSearchCounts["Inbox"] == 1 ? " unread Gmail thread" : " unread Gmail threads");
notifyIcon.ShowBalloon(title, threadSummary, NotifyIconEx.NotifyInfoFlags.Info, 10000);
// change the icon
try {
Stream iconStream = this.GetType().Assembly.GetManifestResourceStream("Johnvey.GmailAgent.Applet.gmail-new.ico");
Icon newIcon = new Icon(iconStream);
notifyIcon.Icon = newIcon;
iconStream.Close();
} catch(Exception ex) {
MessageBox.Show(ex.Message);
}
// update the tooltip text
this.notifyIcon.Text = title;
}
}
#region Delegate declarations
/// <summary>
/// Delegate to refresh all current Gmail sessions.
/// </summary>
public delegate void RefreshAllSessionsDelegate();
/// <summary>
/// Callback function for RefreshAllSessionsDelegate().
/// </summary>
/// <param name="ar"></param>
static void RefreshAllCallback(IAsyncResult ar) {
// Retrieve the delegate.
BaseWindow.RefreshAllSessionsDelegate dlgt = (BaseWindow.RefreshAllSessionsDelegate)ar.AsyncState;
// Call EndInvoke to retrieve the results.
dlgt.EndInvoke(ar);
}
#endregion
#region UI event handlers
// open the properties page
private void menuProperties_onClick(object sender, System.EventArgs e) {
this.Show();
this.WindowState = FormWindowState.Normal;
this.Activate();
}
// open the contacts page
private void menuContacts_onClick(object sender, System.EventArgs e) {
Contacts co = new Contacts(this);
co.ShowDialog();
}
// open the accounts page
private void menuAccounts_onClick(object sender, System.EventArgs e) {
Accounts ac = new Accounts();
ac.RealParentForm = this;
ac.ShowDialog();
}
// open the about page
private void menuAbout_onClick(object sender, System.EventArgs e) {
About ab = new About();
ab.ShowDialog();
}
// exit Gmail Agent
private void menuExit_onClick(object sender, System.EventArgs e) {
Application.Exit();
}
// open the status page when clicking the icon
private void notifyIcon_onClick(object sender, EventArgs e) {
this.Show();
this.WindowState = FormWindowState.Normal;
this.Activate();
}
// open Gmail on a balloon click
private void notifyIcon_onBalloonClick(object sender, EventArgs e) {
System.Diagnostics.Process.Start(GmailAdapter.GMAIL_HOST_URL + "/gmail");
}
// handle the close button
private void close_onClick(object sender, System.EventArgs e) {
this.Hide();
this.lastCheckedText.Text = "Click account to update";
this.threadPreviewText.Text = "";
this.newThreadsList.Items.Clear();
}
// Updates the status page for the selected Gmail account.
private void sessionList_onItemClick(object sender, EventArgs e) {
ListViewItem selectedAccount = ((ListView)sender).SelectedItems[0];
string accountName = selectedAccount.Text;
foreach(GmailSession session in this.accounts) {
if(session.Username == accountName) {
// write last checked timestamp
if(session.LastRefreshTime > new DateTime(0)) {
this.lastCheckedText.Text = session.LastRefreshTime.ToString();
} else {
this.lastCheckedText.Text = "Never";
}
// write new message counts
this.newThreadsList.Items.Clear();
this.newThreadsList.Items.Add("Inbox: " + session.DefaultSearchCounts["Inbox"].ToString());
foreach(DictionaryEntry pair in session.CategoryCounts) {
if((int)pair.Value > 0) {
this.newThreadsList.Items.Add(pair.Key + ": " + pair.Value);
}
}
// write thread summaries
string output = "";
for(int i = 0; i < session.UnreadThreads.Count; i++) {
output += (i + 1) + ". ";
GmailThread msg = (GmailThread)session.UnreadThreads[i];
output += Utilities.CleanHtml(msg.AuthorsHtml) + " - " + Utilities.CleanHtml(msg.DateHtml) + "\r\n";
output += "[" + Utilities.CleanHtml(msg.SubjectHtml) + "]\r\n";
output += Utilities.CleanHtml(msg.SnippetHtml) + "\r\n";
output += "\r\n";
}
this.threadPreviewText.Text = output;
// stop looping through accounts
break;
}
}
}
// open Gmail browser window from the status page
private void launchGmail_onClick(object sender, System.EventArgs e) {
System.Diagnostics.Process.Start(GmailAdapter.GMAIL_HOST_URL + "/gmail");
}
// refresh all accounts
private void refresh_onClick(object sender, System.EventArgs e) {
RefreshAllSessionsDelegate refresher = new RefreshAllSessionsDelegate(this.RefreshAllSessions);
IAsyncResult ar = refresher.BeginInvoke(new AsyncCallback(RefreshAllCallback), refresher);
this.sessionList.Refresh();
this.threadPreviewText.Clear();
this.newThreadsList.Items.Clear();
this.lastCheckedText.Text = "Click account to update";
}
// auto refresh event handler
private void refreshTimer_onElapsed(object sender, System.Timers.ElapsedEventArgs e) {
TimeSpan diff = DateTime.Now - this.lastRefresh;
if(diff > new TimeSpan(0,this.refreshInterval,0)) {
RefreshAllSessionsDelegate refresher = new RefreshAllSessionsDelegate(this.RefreshAllSessions);
IAsyncResult ar = refresher.BeginInvoke(new AsyncCallback(RefreshAllCallback), refresher);
}
}
private void refresh_onLeave(object sender, System.EventArgs e) {
if(Convert.ToInt32(((TextBox)sender).Text) < 2 || Convert.ToInt32(((TextBox)sender).Text) > 60) {
MessageBox.Show("The refresh interval can only be between 2 and 60 minutes.", "Invalid Refresh Interval", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
((TextBox)sender).Undo();
((TextBox)sender).SelectAll();
((TextBox)sender).Focus();
} else {
// update refresh interval setting
RegistryKey workingRegistry = Application.UserAppDataRegistry;
workingRegistry.SetValue("RefreshInterval", Convert.ToInt32(this.refreshIntervalBox.Text));
this.refreshInterval = Convert.ToInt32(this.refreshIntervalBox.Text);
}
}
#endregion
}
}