public ConfigForm()
        {
            InitializeComponent();
            FormConsoleAppender.appendMethod += addLogLine;

            if (Properties.Settings.Default.Crashed)
            {
                DialogResult res = MessageBox.Show("SkypeBot appears to have crashed last time it was run.\nDo you wish to send a log to the developers for debugging purposes?", "SkypeBot appears to have crashed", MessageBoxButtons.YesNo);

                if (res == DialogResult.Yes)
                {
                    ReportForm rf = new ReportForm(from p in plugins select p.name());
                    rf.Show();
                }

                Properties.Settings.Default.Crashed = false;
                Properties.Settings.Default.Save();
            }

            plugins.Sort(
                delegate(Plugin p1, Plugin p2) {
                return(Comparer <String> .Default.Compare(p1.name(), p2.name()));
            }
                );

            PluginListBox.ItemCheck += (obj, e) =>
            {
                if (e.NewValue == CheckState.Checked)
                {
                    log.Debug("Loading " + plugins[e.Index].name());
                    loadPlugin(plugins[e.Index]);
                }
                else
                {
                    log.Debug("Unloading " + plugins[e.Index].name());
                    unloadPlugin(plugins[e.Index]);
                }
            };

            PluginListBox.SelectedIndexChanged += (obj, e) =>
            {
                int selected = PluginListBox.SelectedIndex;
                if (selected == -1)
                {
                    DescriptionBox.Text  = "";
                    ConfigButton.Visible = false;
                }
                else
                {
                    Plugin plugin = plugins[selected];
                    DescriptionBox.Text  = plugin.description();
                    ConfigButton.Visible = plugin.canConfig();
                }
            };

            if (Properties.Settings.Default.LoadedPlugins == null)
            {
                log.Debug("Creating LoadedPlugins property.");
                Properties.Settings.Default.LoadedPlugins = new System.Collections.Specialized.StringCollection();
            }
            if (Properties.Settings.Default.Whitelist == null)
            {
                log.Debug("Creating LoadedPlugins property.");
                Properties.Settings.Default.Whitelist = new System.Collections.Specialized.StringCollection();
            }

            log.Debug("Initiating connection to Skype...");
            skype = new Skype();
            if (!skype.Client.IsRunning)
            {
                log.Debug("Skype is not running; starting...");
                skype.Client.Start(false, false);
            }

            bool attached = false;

            do
            {
                try {
                    log.Debug("Attaching to Skype...");
                    skype.Attach(9, true);
                    attached = true;
                } catch (COMException) {
                    DialogResult res = MessageBox.Show("Please remember to click \"Allow Access\" in the popup you get in Skype.", "Failed to attach to Skype", MessageBoxButtons.RetryCancel);
                    if (res == DialogResult.Cancel)
                    {
                        System.Windows.Forms.Application.Exit();
                    }
                }
            } while (!attached);

            log.Debug("Attached to Skype.");

            skype.MessageStatus += (ChatMessage message, TChatMessageStatus status) =>
            {
                if (Properties.Settings.Default.UseWhitelist ^
                    Properties.Settings.Default.Whitelist.Contains(message.Chat.Name))
                {
                    return;
                }

                Boolean isBlocked = blocked.Contains(
                    skype.CurrentUser.Handle + " :: " + message.ChatName
                    );

                if ((status.Equals(TChatMessageStatus.cmsReceived) || status.Equals(TChatMessageStatus.cmsSent) ||
                     (status.Equals(TChatMessageStatus.cmsRead) && message.Id > lastId)) && !isBlocked)
                {
                    log.Info(String.Format("{0}MSG: {1}", status.Equals(TChatMessageStatus.cmsRead) ? "r" :
                                           status.Equals(TChatMessageStatus.cmsSent) ? "s" : "", message.Body));

                    lastId = message.Id;

                    // Ignore messages older than 1 hour.
                    if (message.Timestamp.CompareTo(DateTime.Now.AddHours(-1.0)) < 0)
                    {
                        log.Debug("Message too old; not going to react.");
                    }

                    Match output = Regex.Match(message.Body, @"^!help", RegexOptions.IgnoreCase);
                    if (output.Success)
                    {
                        String outputMsg = "Help for the bot can be found at http://mathemaniac.org/apps/skypebot/help/.";
                        message.Chat.SendMessage(outputMsg);

                        return;
                    }

                    output = Regex.Match(message.Body, @"^!loaded", RegexOptions.IgnoreCase);
                    if (output.Success)
                    {
                        String outputMsg = "";
                        foreach (Plugin p in plugins)
                        {
                            if (isLoaded(p))
                            {
                                outputMsg += (outputMsg == "" ? "" : ", ");
                                outputMsg += Regex.Replace(p.name(), @"\sPlugin$", "", RegexOptions.IgnoreCase);
                            }
                        }
                        outputMsg = "The following plugins are loaded:\n" + outputMsg;

                        message.Chat.SendMessage(outputMsg);

                        return;
                    }

                    output = Regex.Match(message.Body, @"^!version", RegexOptions.IgnoreCase);
                    if (output.Success && System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
                    {
                        message.Chat.SendMessage(
                            "Running Dynamic Skype Bot v" + System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CurrentVersion
                            + " (http://mathemaniac.org/wp/dynamic-skype-bot/)"
                            );
                        return;
                    }

                    if (onSkypeMessage.GetInvocationList().Length != Properties.Settings.Default.LoadedPlugins.Count)
                    {
                        // Let's fix up the loaded plugins list.
                        log.Info("Loaded plugin list seems to be off. Correcting...");
                        PluginListBox.Enabled = false;
                        onSkypeMessage        = null;
                        Properties.Settings.Default.LoadedPlugins.Clear();
                        Properties.Settings.Default.LoadedPlugins.AddRange(
                            this.plugins.Where((p, i) => PluginListBox.CheckedIndices.Contains(i))
                            .Select((p) => {
                            onSkypeMessage += new _ISkypeEvents_MessageStatusEventHandler(p.Skype_MessageStatus);
                            return(p.name());
                        })
                            .ToArray()
                            );
                        Properties.Settings.Default.Save();
                        PluginListBox.Enabled = true;
                        log.Info("Loaded plugin list corrected.");
                    }

                    if (onSkypeMessage != null)
                    {
                        BackgroundWorker bw = new BackgroundWorker();
                        bw.DoWork += (obj, e) => onSkypeMessage(message, status);
                        bw.RunWorkerAsync();
                    }
                }
            };

            populatePluginList();

            blocked = "";
            BackgroundWorker baw = new BackgroundWorker();

            baw.DoWork += (obj, e) => {
                log.Debug("Fetching list of blocked people/chat combinations...");
                WebRequest webReq = WebRequest.Create("http://mathemaniac.org/apps/skypebot/blocked.txt");
                try {
                    webReq.Timeout = 10000;
                    WebResponse response = webReq.GetResponse();
                    blocked = new StreamReader(response.GetResponseStream()).ReadToEnd();
                } catch (Exception ex) {
                    log.Warn("Failed to fetch list of blocked people/chat combinations.", ex);
                }
            };
            baw.RunWorkerAsync();

            // Update check
            if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed &&
                Properties.Settings.Default.UpdateCheck)
            {
                updateTimer          = new Timer();
                updateTimer.Interval = Properties.Settings.Default.UpdateCheckInterval * 60 * 1000;
                updateTimer.Tick    += (obj, e) => {
                    log.Info("Checking for updates...");
                    try {
                        if (System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CheckForUpdate())
                        {
                            log.Info("Update available for download!");
                            if (taskIcon.Visible)
                            {
                                taskIcon.BalloonTipTitle = "Skype Bot";
                                taskIcon.BalloonTipText  = "A new version of the Skype Bot is ready for download.";
                                taskIcon.BalloonTipIcon  = ToolTipIcon.Info;
                                taskIcon.ShowBalloonTip(Properties.Settings.Default.UpdateCheckInterval * 60 * 1000);
                            }
                            else
                            {
                                updateTimer.Stop();
                                MessageBox.Show("A new version is ready for download!");
                            }
                        }
                        else
                        {
                            log.Info("No updates found.");
                        }
                    } catch (Exception ex) {
                        log.Warn("Exception arose while checking for update.", ex);
                    }
                };
                updateTimer.Start();
            }
        }
 protected override void OnAfterLoad()
 {
     messageStatusEventHandler = Skype_MessageStatus;
 }
        public ConfigForm() {
            InitializeComponent();
            FormConsoleAppender.appendMethod += addLogLine;

            if (Properties.Settings.Default.Crashed) {
                DialogResult res = MessageBox.Show("SkypeBot appears to have crashed last time it was run.\nDo you wish to send a log to the developers for debugging purposes?", "SkypeBot appears to have crashed", MessageBoxButtons.YesNo);

                if (res == DialogResult.Yes) {
                    ReportForm rf = new ReportForm(from p in plugins select p.name());
                    rf.Show();
                }

                Properties.Settings.Default.Crashed = false;
                Properties.Settings.Default.Save();
            }

            plugins.Sort(
                delegate(Plugin p1, Plugin p2) {
                    return Comparer<String>.Default.Compare(p1.name(), p2.name());
                }
            );

            PluginListBox.ItemCheck += (obj, e) =>
            {
                if (e.NewValue == CheckState.Checked) {
                    log.Debug("Loading " + plugins[e.Index].name());
                    loadPlugin(plugins[e.Index]);
                } else {
                    log.Debug("Unloading " + plugins[e.Index].name());
                    unloadPlugin(plugins[e.Index]);
                }
            };

            PluginListBox.SelectedIndexChanged += (obj, e) =>
            {
                int selected = PluginListBox.SelectedIndex;
                if (selected == -1) {
                    DescriptionBox.Text = "";
                    ConfigButton.Visible = false;
                }
                else {
                    Plugin plugin = plugins[selected];
                    DescriptionBox.Text = plugin.description();
                    ConfigButton.Visible = plugin.canConfig();
                }
                
            };

            if (Properties.Settings.Default.LoadedPlugins == null) {
                log.Debug("Creating LoadedPlugins property.");
                Properties.Settings.Default.LoadedPlugins = new System.Collections.Specialized.StringCollection();
            }
            if (Properties.Settings.Default.Whitelist == null) {
                log.Debug("Creating LoadedPlugins property.");
                Properties.Settings.Default.Whitelist = new System.Collections.Specialized.StringCollection();
            }

            log.Debug("Initiating connection to Skype...");
            skype = new Skype();
            if (!skype.Client.IsRunning) {
                log.Debug("Skype is not running; starting...");
                skype.Client.Start(false, false);
            }

            bool attached = false;
            do {
                try {
                    log.Debug("Attaching to Skype...");
                    skype.Attach(9, true);
                    attached = true;
                } catch (COMException) {
                    DialogResult res = MessageBox.Show("Please remember to click \"Allow Access\" in the popup you get in Skype.", "Failed to attach to Skype", MessageBoxButtons.RetryCancel);
                    if (res == DialogResult.Cancel) {
                        System.Windows.Forms.Application.Exit();
                    }
                }
            } while (!attached);

            log.Debug("Attached to Skype.");

            skype.MessageStatus += (ChatMessage message, TChatMessageStatus status) =>
            {
                if (Properties.Settings.Default.UseWhitelist ^
                    Properties.Settings.Default.Whitelist.Contains(message.Chat.Name)) {
                    return;
                }

                Boolean isBlocked = blocked.Contains(
                        skype.CurrentUser.Handle + " :: " + message.ChatName
                    );

                if ((status.Equals(TChatMessageStatus.cmsReceived) || status.Equals(TChatMessageStatus.cmsSent) ||
                    (status.Equals(TChatMessageStatus.cmsRead) && message.Id > lastId) ) && !isBlocked) {
                    
                    log.Info(String.Format("{0}MSG: {1}", status.Equals(TChatMessageStatus.cmsRead) ? "r" :
                                                          status.Equals(TChatMessageStatus.cmsSent) ? "s" : "", message.Body));

                    lastId = message.Id;

                    // Ignore messages older than 1 hour.
                    if (message.Timestamp.CompareTo(DateTime.Now.AddHours(-1.0)) < 0) {
                        log.Debug("Message too old; not going to react.");
                    }

                    Match output = Regex.Match(message.Body, @"^!help", RegexOptions.IgnoreCase);
                    if (output.Success) {
                        String outputMsg = "Help for the bot can be found at http://mathemaniac.org/apps/skypebot/help/.";
                        message.Chat.SendMessage(outputMsg);
                        
                        return;
                    }

                    output = Regex.Match(message.Body, @"^!loaded", RegexOptions.IgnoreCase);
                    if (output.Success) {
                        String outputMsg = "";
                        foreach (Plugin p in plugins) {
                            if (isLoaded(p)) {
                                outputMsg += (outputMsg == "" ? "" : ", ");
                                outputMsg += Regex.Replace(p.name(), @"\sPlugin$", "", RegexOptions.IgnoreCase);
                            }
                        }
                        outputMsg = "The following plugins are loaded:\n" + outputMsg;

                        message.Chat.SendMessage(outputMsg);

                        return;
                    }

                    output = Regex.Match(message.Body, @"^!version", RegexOptions.IgnoreCase);
                    if (output.Success && System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) {
                        message.Chat.SendMessage(
                            "Running Dynamic Skype Bot v" + System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CurrentVersion
                            + " (http://mathemaniac.org/wp/dynamic-skype-bot/)"
                        );
                        return;
                    }

                    if (onSkypeMessage.GetInvocationList().Length != Properties.Settings.Default.LoadedPlugins.Count) {
                        // Let's fix up the loaded plugins list.
                        log.Info("Loaded plugin list seems to be off. Correcting...");
                        PluginListBox.Enabled = false;
                        onSkypeMessage = null;
                        Properties.Settings.Default.LoadedPlugins.Clear();
                        Properties.Settings.Default.LoadedPlugins.AddRange(
                            this.plugins.Where((p, i) => PluginListBox.CheckedIndices.Contains(i))
                                        .Select((p) => {
                                            onSkypeMessage += new _ISkypeEvents_MessageStatusEventHandler(p.Skype_MessageStatus);
                                            return p.name();
                                        })
                                        .ToArray()
                        );
                        Properties.Settings.Default.Save();
                        PluginListBox.Enabled = true;
                        log.Info("Loaded plugin list corrected.");
                    }

                    if (onSkypeMessage != null) {
                        BackgroundWorker bw = new BackgroundWorker();
                        bw.DoWork += (obj, e) => onSkypeMessage(message, status);
                        bw.RunWorkerAsync();
                    }
                }
            };

            populatePluginList();

            blocked = "";
            BackgroundWorker baw = new BackgroundWorker();
            baw.DoWork += (obj, e) => {
                log.Debug("Fetching list of blocked people/chat combinations...");
                WebRequest webReq = WebRequest.Create("http://mathemaniac.org/apps/skypebot/blocked.txt");
                try {
                    webReq.Timeout = 10000;
                    WebResponse response = webReq.GetResponse();
                    blocked = new StreamReader(response.GetResponseStream()).ReadToEnd();
                } catch (Exception ex) {
                    log.Warn("Failed to fetch list of blocked people/chat combinations.", ex);
                }
            };
            baw.RunWorkerAsync();

            // Update check
            if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed &&
                Properties.Settings.Default.UpdateCheck) {
                updateTimer = new Timer();
                updateTimer.Interval = Properties.Settings.Default.UpdateCheckInterval * 60 * 1000;
                updateTimer.Tick += (obj, e) => {
                    log.Info("Checking for updates...");
                    try {
                        if (System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CheckForUpdate()) {
                            log.Info("Update available for download!");
                            if (taskIcon.Visible) {
                                taskIcon.BalloonTipTitle = "Skype Bot";
                                taskIcon.BalloonTipText = "A new version of the Skype Bot is ready for download.";
                                taskIcon.BalloonTipIcon = ToolTipIcon.Info;
                                taskIcon.ShowBalloonTip(Properties.Settings.Default.UpdateCheckInterval * 60 * 1000);
                            } else {
                                updateTimer.Stop();
                                MessageBox.Show("A new version is ready for download!");
                            }
                        } else {
                            log.Info("No updates found.");
                        }
                    } catch(Exception ex) {
                        log.Warn("Exception arose while checking for update.", ex);
                    }
                };
                updateTimer.Start();
            }
        }